package org.openlmis.core.presenter; import com.google.inject.Inject; import org.openlmis.core.LMISApp; import org.openlmis.core.exceptions.LMISException; import org.openlmis.core.manager.MovementReasonManager; import org.openlmis.core.model.DraftInventory; import org.openlmis.core.model.Inventory; import org.openlmis.core.model.LotOnHand; import org.openlmis.core.model.StockCard; import org.openlmis.core.model.StockMovementItem; import org.openlmis.core.model.service.StockService; import org.openlmis.core.utils.DateUtil; import org.openlmis.core.view.viewmodel.InventoryViewModel; import org.openlmis.core.view.viewmodel.LotMovementViewModel; import org.openlmis.core.view.viewmodel.PhysicalInventoryViewModel; 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 java.util.Comparator; import java.util.Date; import java.util.List; import rx.Observable; import rx.Subscriber; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import static org.roboguice.shaded.goole.common.collect.FluentIterable.from; public class PhysicalInventoryPresenter extends InventoryPresenter { @Inject StockService stockService; @Override public Observable<List<InventoryViewModel>> loadInventory() { return Observable.create(new Observable.OnSubscribe<List<InventoryViewModel>>() { @Override public void call(Subscriber<? super List<InventoryViewModel>> subscriber) { try { List<StockCard> validStockCardsForPhysicalInventory = getValidStockCardsForPhysicalInventory(); inventoryViewModelList.addAll(convertStockCardsToStockCardViewModels(validStockCardsForPhysicalInventory)); restoreDraftInventory(); subscriber.onNext(inventoryViewModelList); subscriber.onCompleted(); } catch (LMISException e) { subscriber.onError(e); } } }).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()); } private List<InventoryViewModel> convertStockCardsToStockCardViewModels(List<StockCard> validStockCardsForPhysicalInventory) { return FluentIterable.from(validStockCardsForPhysicalInventory).transform(new Function<StockCard, InventoryViewModel>() { @Override public InventoryViewModel apply(StockCard stockCard) { InventoryViewModel inventoryViewModel = new PhysicalInventoryViewModel(stockCard); setExistingLotViewModels(inventoryViewModel); return inventoryViewModel; } }).toList(); } protected List<StockCard> getValidStockCardsForPhysicalInventory() throws LMISException { return from(stockRepository.list()).filter(new Predicate<StockCard>() { @Override public boolean apply(StockCard stockCard) { return !stockCard.getProduct().isKit() && stockCard.getProduct().isActive() && !stockCard.getProduct().isArchived(); } }).toList(); } protected void restoreDraftInventory() throws LMISException { List<DraftInventory> draftList = inventoryRepository.queryAllDraft(); for (InventoryViewModel viewModel : inventoryViewModelList) { for (DraftInventory draftInventory : draftList) { if (viewModel.getStockCardId() == draftInventory.getStockCard().getId()) { ((PhysicalInventoryViewModel) viewModel).setDraftInventory(draftInventory); } } // This auto populate is added for tester if (LMISApp.getInstance().isQAEnabled()) { populateLotMovementModelWithExistingSoh(viewModel); } } } private void populateLotMovementModelWithExistingSoh(InventoryViewModel viewModel) { for (LotMovementViewModel lotMovementViewModel : viewModel.getExistingLotMovementViewModelList()) { lotMovementViewModel.setQuantity(lotMovementViewModel.getLotSoh()); } } protected StockMovementItem calculateAdjustment(InventoryViewModel model, StockCard stockCard) { Long inventory; inventory = model.getLotListQuantityTotalAmount(); long stockOnHand = model.getStockOnHand(); StockMovementItem item = new StockMovementItem(); item.setSignature(model.getSignature()); item.setMovementDate(new Date()); item.setMovementQuantity(Math.abs(inventory - stockOnHand)); item.setStockOnHand(inventory); item.setStockCard(stockCard); if (inventory > stockOnHand) { item.setReason(MovementReasonManager.INVENTORY_POSITIVE); item.setMovementType(MovementReasonManager.MovementType.POSITIVE_ADJUST); } else if (inventory < stockOnHand) { item.setReason(MovementReasonManager.INVENTORY_NEGATIVE); item.setMovementType(MovementReasonManager.MovementType.NEGATIVE_ADJUST); } else { item.setReason(MovementReasonManager.INVENTORY); item.setMovementType(MovementReasonManager.MovementType.PHYSICAL_INVENTORY); } item.populateLotAndResetStockOnHandOfLotAccordingPhysicalAdjustment(model.getExistingLotMovementViewModelList(), model.getNewLotMovementViewModelList()); return item; } public Observable<Object> saveDraftInventoryObservable() { return Observable.create(new Observable.OnSubscribe<Object>() { @Override public void call(Subscriber<? super Object> subscriber) { try { inventoryRepository.clearDraft(); for (InventoryViewModel model : inventoryViewModelList) { inventoryRepository.createDraft(new DraftInventory((PhysicalInventoryViewModel) model)); } subscriber.onNext(null); subscriber.onCompleted(); } catch (LMISException e) { subscriber.onError(e); e.reportToFabric(); } } }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); } public Observable<Object> doInventory(final String sign) { return Observable.create(new Observable.OnSubscribe<Object>() { @Override public void call(Subscriber<? super Object> subscriber) { try { for (InventoryViewModel viewModel : inventoryViewModelList) { viewModel.setSignature(sign); StockCard stockCard = viewModel.getStockCard(); stockCard.setStockOnHand(viewModel.getLotListQuantityTotalAmount()); if (stockCard.getStockOnHand() == 0) { stockCard.setExpireDates(""); } stockRepository.addStockMovementAndUpdateStockCard(calculateAdjustment(viewModel, stockCard)); } inventoryRepository.clearDraft(); sharedPreferenceMgr.setLatestPhysicInventoryTime(DateUtil.formatDate(new Date(), DateUtil.DATE_TIME_FORMAT)); saveInventoryDate(); subscriber.onNext(null); subscriber.onCompleted(); } catch (LMISException e) { subscriber.onError(e); e.reportToFabric(); } } }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); } private void saveInventoryDate() { inventoryRepository.save(new Inventory()); } private void setExistingLotViewModels(InventoryViewModel inventoryViewModel) { List<LotMovementViewModel> lotMovementViewModels = FluentIterable.from(inventoryViewModel.getStockCard().getNonEmptyLotOnHandList()).transform(new Function<LotOnHand, LotMovementViewModel>() { @Override public LotMovementViewModel apply(LotOnHand lotOnHand) { return new LotMovementViewModel(lotOnHand.getLot().getLotNumber(), DateUtil.formatDate(lotOnHand.getLot().getExpirationDate(), DateUtil.DATE_FORMAT_ONLY_MONTH_AND_YEAR), lotOnHand.getQuantityOnHand().toString(), MovementReasonManager.MovementType.RECEIVE); } }).toSortedList(new Comparator<LotMovementViewModel>() { @Override public int compare(LotMovementViewModel lot1, LotMovementViewModel lot2) { return DateUtil.parseString(lot1.getExpiryDate(), DateUtil.DATE_FORMAT_ONLY_MONTH_AND_YEAR).compareTo(DateUtil.parseString(lot2.getExpiryDate(), DateUtil.DATE_FORMAT_ONLY_MONTH_AND_YEAR)); } }); inventoryViewModel.setExistingLotMovementViewModelList(lotMovementViewModels); } public void updateAvgMonthlyConsumption() { stockService.immediatelyUpdateAvgMonthlyConsumption(); } public int getCompleteCount() { return FluentIterable.from(inventoryViewModelList).filter(new Predicate<InventoryViewModel>() { @Override public boolean apply(InventoryViewModel inventoryViewModel) { return ((PhysicalInventoryViewModel) inventoryViewModel).isDone(); } }).toList().size(); } }