/* * This program is part of the OpenLMIS logistics management information * system platform software. * * Copyright © 2015 ThoughtWorks, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. This program is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. You should * have received a copy of the GNU Affero General Public License along with * this program. If not, see http://www.gnu.org/licenses. For additional * information contact info@OpenLMIS.org */ package org.openlmis.core.presenter; import android.content.Context; import android.text.TextUtils; import com.google.inject.Inject; import org.openlmis.core.LMISApp; import org.openlmis.core.R; import org.openlmis.core.exceptions.LMISException; import org.openlmis.core.exceptions.ViewNotMatchException; import org.openlmis.core.model.KitProduct; import org.openlmis.core.model.Product; import org.openlmis.core.model.RnRForm; import org.openlmis.core.model.RnrFormItem; import org.openlmis.core.model.StockCard; import org.openlmis.core.model.StockMovementItem; import org.openlmis.core.model.helper.RnrFormHelper; import org.openlmis.core.model.repository.ProductRepository; import org.openlmis.core.model.repository.RnrFormItemRepository; import org.openlmis.core.model.repository.RnrFormRepository; import org.openlmis.core.model.repository.StockMovementRepository; import org.openlmis.core.model.repository.StockRepository; import org.openlmis.core.model.repository.VIARepository; import org.openlmis.core.utils.ToastUtil; import org.openlmis.core.view.BaseView; import org.openlmis.core.view.fragment.VIARequisitionFragment; import org.openlmis.core.view.viewmodel.RequisitionFormItemViewModel; import org.openlmis.core.view.viewmodel.RnRFormItemAdjustmentViewModel; import org.openlmis.core.view.viewmodel.ViaKitsViewModel; import org.roboguice.shaded.goole.common.base.Function; import org.roboguice.shaded.goole.common.base.Predicate; import org.roboguice.shaded.goole.common.collect.FluentIterable; import org.roboguice.shaded.goole.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Date; import java.util.List; import lombok.Getter; import lombok.Setter; import roboguice.RoboGuice; import roboguice.inject.ContextSingleton; import rx.Observable; import rx.Subscriber; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import static org.openlmis.core.model.Product.IsKit; import static org.roboguice.shaded.goole.common.collect.FluentIterable.from; @ContextSingleton public class VIARequisitionPresenter extends BaseRequisitionPresenter { @Inject Context context; @Inject ProductRepository productRepository; @Inject StockRepository stockRepository; VIARequisitionFragment view; @Getter protected List<RequisitionFormItemViewModel> requisitionFormItemViewModels; @Getter @Setter private ViaKitsViewModel viaKitsViewModel; @Inject RnrFormItemRepository rnrFormItemRepository; @Inject private RnrFormHelper rnrFormHelper; @Inject private StockMovementRepository stockMovementRepository; public VIARequisitionPresenter() { requisitionFormItemViewModels = new ArrayList<>(); viaKitsViewModel = new ViaKitsViewModel(); } @Override public void loadData(long formId, Date periodEndDate) { this.periodEndDate = periodEndDate; view.loading(); Subscription subscription = getRnrFormObservable(formId).subscribe(loadDataOnNextAction, loadDataOnErrorAction); subscriptions.add(subscription); } public void loadEmergencyData(final List<StockCard> stockCards, final Date periodEndDate) { this.periodEndDate = periodEndDate; view.loading(); Subscription subscription = Observable.create(new Observable.OnSubscribe<RnRForm>() { @Override public void call(Subscriber<? super RnRForm> subscriber) { try { RnRForm rnrForm = initEmergencyRnr(stockCards, periodEndDate); convertRnrToViewModel(rnrForm); subscriber.onNext(rnrForm); subscriber.onCompleted(); } catch (LMISException e) { e.reportToFabric(); subscriber.onError(e); } } }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(loadDataOnNextAction, loadDataOnErrorAction); subscriptions.add(subscription); } protected RnRForm initEmergencyRnr(List<StockCard> stockCards, Date periodEndDate) throws LMISException { return rnrFormRepository.initEmergencyRnrForm(periodEndDate, stockCards); } @Override protected RnrFormRepository initRnrFormRepository() { return RoboGuice.getInjector(LMISApp.getContext()).getInstance(VIARepository.class); } @Override public void attachView(BaseView baseView) throws ViewNotMatchException { if (baseView instanceof VIARequisitionView) { this.view = (VIARequisitionFragment) baseView; } else { throw new ViewNotMatchException("required VIARequisitionView"); } super.attachView(baseView); } protected List<RequisitionFormItemViewModel> getViewModelsFromRnrForm(RnRForm form) throws LMISException { if (requisitionFormItemViewModels.size() > 0) { return requisitionFormItemViewModels; } return from(form.getRnrItems(IsKit.No)).transform(new Function<RnrFormItem, RequisitionFormItemViewModel>() { @Override public RequisitionFormItemViewModel apply(RnrFormItem item) { RequisitionFormItemViewModel requisitionFormItemViewModel = new RequisitionFormItemViewModel(item); if (!isHistoryForm()) { adjustTheoretical(requisitionFormItemViewModel); } return requisitionFormItemViewModel; } }).toList(); } private List<RequisitionFormItemViewModel> transformDataItemsToViewModels(List<RnrFormItem> additionalItems) throws LMISException { return from(additionalItems).transform(new Function<RnrFormItem, RequisitionFormItemViewModel>() { @Override public RequisitionFormItemViewModel apply(RnrFormItem rnrFormItem) { return new RequisitionFormItemViewModel(rnrFormItem); } }).toList(); } private void adjustTheoretical(RequisitionFormItemViewModel requisitionFormItemViewModel) { Product product = requisitionFormItemViewModel.getItem().getProduct(); requisitionFormItemViewModel.setAdjustmentViewModels(generateAdjustInfo(product)); } private List<RnRFormItemAdjustmentViewModel> generateAdjustInfo(Product product) { List<RnRFormItemAdjustmentViewModel> list = new ArrayList<>(); try { List<KitProduct> kitProducts = productRepository.queryKitProductByProductCode(product.getCode()); for (KitProduct kitProduct : kitProducts) { Product kit = productRepository.getByCode(kitProduct.getKitCode()); long kitSOH = getKitSOH(kit); if (kitSOH != 0) { list.add(new RnRFormItemAdjustmentViewModel(kitSOH, kitProduct.getQuantity(), kit.getPrimaryName())); } } } catch (LMISException e) { e.reportToFabric(); } return list; } private long getKitSOH(Product kit) throws LMISException { if (stockRepository.queryStockCardByProductId(kit.getId()) == null) { return 0; } return stockRepository.queryStockCardByProductId(kit.getId()).getStockOnHand(); } @Override protected Observable<RnRForm> getRnrFormObservable(final long formId) { return Observable.create(new Observable.OnSubscribe<RnRForm>() { @Override public void call(Subscriber<? super RnRForm> subscriber) { try { RnRForm rnrForm = getRnrForm(formId); convertRnrToViewModel(rnrForm); subscriber.onNext(rnrForm); subscriber.onCompleted(); } catch (LMISException e) { e.reportToFabric(); subscriber.onError(e); } } }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()); } @Override protected int getCompleteErrorMessage() { return R.string.hint_requisition_complete_failed; } private void convertRnrToViewModel(RnRForm rnrForm) throws LMISException { requisitionFormItemViewModels.clear(); requisitionFormItemViewModels.addAll(getViewModelsFromRnrForm(rnrForm)); viaKitsViewModel.convertRnrKitItemsToViaKit(rnrForm.getRnrItems(IsKit.Yes)); } public void populateAdditionalDrugsViewModels(List<RnrFormItem> addedDrugInVIAs, Date periodBegin) { try { List<RnrFormItem> additionalProducts = generateRnrItemsForAdditionalProducts(addedDrugInVIAs, periodBegin); requisitionFormItemViewModels.addAll(transformDataItemsToViewModels(additionalProducts)); } catch (LMISException e) { e.reportToFabric(); } } public void deleteRnRItemFromViewModel(final RnrFormItem rnrFormItem) { List<RequisitionFormItemViewModel> requisitionFormItemViewModelList = FluentIterable.from(requisitionFormItemViewModels).filter(new Predicate<RequisitionFormItemViewModel>() { @Override public boolean apply(RequisitionFormItemViewModel requisitionFormItemViewModel) { return !requisitionFormItemViewModel.getFmn().equals(rnrFormItem.getProduct().getCode()); } }).toList(); requisitionFormItemViewModels.clear(); requisitionFormItemViewModels.addAll(requisitionFormItemViewModelList); view.refreshRequisitionForm(rnRForm); } private List<RnrFormItem> generateRnrItemsForAdditionalProducts(List<RnrFormItem> addedDrugInVIAs, final Date periodBegin) { List<RnrFormItem> rnrFormItemList = FluentIterable.from(addedDrugInVIAs).transform(new Function<RnrFormItem, RnrFormItem>() { @Override public RnrFormItem apply(RnrFormItem addedDrugInVIA) { Product product = addedDrugInVIA.getProduct(); RnrFormItem rnrFormItem = new RnrFormItem(); rnrFormItem.setProduct(product); rnrFormItem.setForm(rnRForm); rnrFormItem.setManualAdd(true); rnrFormItem.setRequestAmount(addedDrugInVIA.getRequestAmount()); rnrFormItem.setApprovedAmount(rnrFormItem.getRequestAmount()); try { if (product.isArchived()) { populateRnrItemWithQuantities(rnrFormItem, periodBegin, periodEndDate); } } catch (LMISException e) { e.reportToFabric(); } return rnrFormItem; } }).toList(); return rnrFormItemList; } private void populateRnrItemWithQuantities(RnrFormItem rnrFormItem, Date periodBegin, Date periodEnd) throws LMISException { StockCard stockCard = stockRepository.queryStockCardByProductId(rnrFormItem.getProduct().getId()); List<StockMovementItem> stockMovementItems = stockMovementRepository.queryStockItemsByCreatedDate(stockCard.getId(), periodBegin, periodEnd); if (stockMovementItems.size() > 0) { rnrFormItem.setInitialAmount(stockMovementItems.get(0).calculatePreviousSOH()); rnrFormHelper.assignTotalValues(rnrFormItem, stockMovementItems); } } @Override public void updateUIAfterSubmit() { view.highLightApprovedAmount(); view.refreshRequisitionForm(rnRForm); view.setProcessButtonName(context.getResources().getString(R.string.btn_complete)); } @Override public void updateFormUI() { if (rnRForm.isDraft()) { view.setProcessButtonName(context.getResources().getString(R.string.btn_submit)); view.highLightRequestAmount(); } else if (rnRForm.isSubmitted()) { view.setProcessButtonName(context.getString(R.string.btn_complete)); view.highLightApprovedAmount(); } view.refreshRequisitionForm(rnRForm); } protected boolean validateForm() { if (rnRForm.isEmergency()) { return validateRnrFormItems(); } else { return view.validateConsultationNumber() && validateRnrFormItems(); } } protected boolean validateRnrFormItems() { for (int i = 0; i < requisitionFormItemViewModels.size(); i++) { RequisitionFormItemViewModel itemViewModel = requisitionFormItemViewModels.get(i); if (TextUtils.isEmpty(itemViewModel.getRequestAmount()) || TextUtils.isEmpty(itemViewModel.getApprovedAmount())) { view.showListInputError(i); return false; } } return true; } @Override public void submitRequisition() { if (rnRForm.isEmergency()) { updateUIAfterSubmit(); return; } super.submitRequisition(); } public boolean processRequisition(String consultationNumbers) { if (!validateForm()) { return false; } if (!validateFormPeriod()) { ToastUtil.show(R.string.msg_requisition_not_unique); return false; } dataViewToModel(consultationNumbers); return true; } private void dataViewToModel(String consultationNumbers) { List<RnrFormItem> rnrFormItems = new ArrayList<>(); rnrFormItems.addAll(convertRnrItemViewModelsToRnrItems()); rnrFormItems.addAll(viaKitsViewModel.getKitItems()); rnRForm.setRnrFormItemListWrapper(rnrFormItems); if (!TextUtils.isEmpty(consultationNumbers)) { rnRForm.getBaseInfoItemListWrapper().get(0).setValue(Long.valueOf(consultationNumbers).toString()); } } public Observable<RnRForm> getSaveFormObservable(final String consultationNumbers) { return Observable.create(new Observable.OnSubscribe<RnRForm>() { @Override public void call(Subscriber<? super RnRForm> subscriber) { try { dataViewToModel(consultationNumbers); rnrFormRepository.createOrUpdateWithItems(rnRForm); subscriber.onNext(rnRForm); subscriber.onCompleted(); } catch (LMISException e) { e.reportToFabric(); subscriber.onError(e); } } }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()); } private ImmutableList<RnrFormItem> convertRnrItemViewModelsToRnrItems() { return from(requisitionFormItemViewModels).transform(new Function<RequisitionFormItemViewModel, RnrFormItem>() { @Override public RnrFormItem apply(RequisitionFormItemViewModel requisitionFormItemViewModel) { return requisitionFormItemViewModel.toRnrFormItem(); } }).toList(); } public String getConsultationNumbers() { if (rnRForm != null && !rnRForm.getBaseInfoItemListWrapper().isEmpty()) { return rnRForm.getBaseInfoItemListWrapper().get(0).getValue(); } return null; } public void setConsultationNumbers(String consultationNumbers) { if (rnRForm != null && !rnRForm.getBaseInfoItemListWrapper().isEmpty()) { rnRForm.getBaseInfoItemListWrapper().get(0).setValue(consultationNumbers); } } @Override protected Observable<Void> createOrUpdateRnrForm() { return Observable.create(new Observable.OnSubscribe<Void>() { @Override public void call(Subscriber<? super Void> subscriber) { try { rnrFormRepository.createOrUpdateWithItems(rnRForm); subscriber.onNext(null); subscriber.onCompleted(); } catch (LMISException e) { e.reportToFabric(); subscriber.onError(e); } finally { stockService.monthlyUpdateAvgMonthlyConsumption(); } } }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()); } public void createStockCardsOrUnarchiveAndAddToFormForAdditionalRnrItems() { try { for (RnrFormItem rnrFormItem : rnrFormItemRepository.listAllNewRnrItems()) { if (rnrFormItem.getProduct().isArchived()) { rnrFormItem.getProduct().setArchived(false); productRepository.updateProduct(rnrFormItem.getProduct()); } else { StockCard newStockCard = new StockCard(); newStockCard.setProduct(rnrFormItem.getProduct()); stockRepository.createOrUpdateStockCardWithStockMovement(newStockCard); } rnrFormItem.setForm(rnRForm); rnRForm.getRnrFormItemListWrapper().add(rnrFormItem); } } catch (LMISException e) { e.reportToFabric(); } } public Observable<Void> removeRnrItem(final RnrFormItem rnrFormItem) { return Observable.create(new Observable.OnSubscribe<Void>() { @Override public void call(Subscriber<? super Void> subscriber) { try { rnrFormItemRepository.deleteRnrItem(rnrFormItem); } catch (LMISException e) { e.reportToFabric(); subscriber.onError(e); } subscriber.onCompleted(); } }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()); } }