/*
* This program is part of the OpenLMIS logistics management information
* system platform software.
*
* Copyright © 2016 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 com.google.inject.Inject;
import org.apache.commons.lang3.ArrayUtils;
import org.openlmis.core.LMISApp;
import org.openlmis.core.R;
import org.openlmis.core.exceptions.LMISException;
import org.openlmis.core.manager.MovementReasonManager;
import org.openlmis.core.manager.SharedPreferenceMgr;
import org.openlmis.core.model.LotOnHand;
import org.openlmis.core.model.StockCard;
import org.openlmis.core.model.StockMovementItem;
import org.openlmis.core.model.repository.StockRepository;
import org.openlmis.core.utils.DateUtil;
import org.openlmis.core.view.BaseView;
import org.openlmis.core.view.viewmodel.LotMovementViewModel;
import org.openlmis.core.view.viewmodel.StockMovementViewModel;
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 lombok.Getter;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
public class NewStockMovementPresenter extends Presenter {
@Inject
StockRepository stockRepository;
@Getter
final StockMovementViewModel viewModel = new StockMovementViewModel();
@Getter
private StockCard stockCard;
@Getter
private List<MovementReasonManager.MovementReason> movementReasons;
private String[] reasonDescriptionList;
NewStockMovementView view;
@Override
public void attachView(BaseView v) {
this.view = (NewStockMovementView) v;
}
public void loadData(Long stockCardId, MovementReasonManager.MovementType movementType, boolean isKit) {
try {
movementReasons = MovementReasonManager.getInstance().buildReasonListForMovementType(movementType);
stockCard = stockRepository.queryStockCardById(stockCardId);
viewModel.setProduct(stockCard.getProduct());
viewModel.setMovementType(movementType);
viewModel.setKit(isKit);
} catch (LMISException e) {
e.reportToFabric();
}
loadExistingLotMovementViewModels(movementType);
}
public void saveStockMovement() {
Subscription subscription = getSaveMovementObservable().subscribe(new Action1<StockMovementViewModel>() {
@Override
public void call(StockMovementViewModel viewModel) {
view.goToStockCard();
}
});
subscriptions.add(subscription);
}
protected Observable<StockMovementViewModel> getSaveMovementObservable() {
return Observable.create(new Observable.OnSubscribe<StockMovementViewModel>() {
@Override
public void call(Subscriber<? super StockMovementViewModel> subscriber) {
convertViewModelToDataModelAndSave();
subscriber.onNext(viewModel);
subscriber.onCompleted();
}
}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io());
}
private void convertViewModelToDataModelAndSave() {
viewModel.populateStockExistence(stockCard.getStockOnHand());
StockMovementItem stockMovementItem = viewModel.convertViewToModel(stockCard);
stockCard.setStockOnHand(stockMovementItem.getStockOnHand());
stockRepository.addStockMovementAndUpdateStockCard(stockMovementItem);
if (stockCard.getStockOnHand() == 0 && !stockCard.getProduct().isActive()) {
SharedPreferenceMgr.getInstance().setIsNeedShowProductsUpdateBanner(true, stockCard.getProduct().getPrimaryName());
}
}
private void loadExistingLotMovementViewModels(final MovementReasonManager.MovementType movementType) {
List<LotMovementViewModel> lotMovementViewModels = FluentIterable.from(stockCard.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(), movementType);
}
}).filter(new Predicate<LotMovementViewModel>() {
@Override
public boolean apply(LotMovementViewModel lotMovementViewModel) {
for (LotMovementViewModel existingLot : viewModel.getExistingLotMovementViewModelList()) {
if (existingLot.getLotNumber().equals(lotMovementViewModel.getLotNumber())) {
return false;
}
}
return true;
}
}).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));
}
});
viewModel.getExistingLotMovementViewModelList().addAll(lotMovementViewModels);
}
public MovementReasonManager.MovementType getMovementType() {
return viewModel.getMovementType();
}
public boolean isKit() {
return viewModel.isKit();
}
public String[] getMovementReasonDescriptionList() {
if (ArrayUtils.isEmpty(reasonDescriptionList)) {
reasonDescriptionList = FluentIterable.from(movementReasons).transform(new Function<MovementReasonManager.MovementReason, String>() {
@Override
public String apply(MovementReasonManager.MovementReason movementReason) {
return movementReason.getDescription();
}
}).toArray(String.class);
}
return reasonDescriptionList;
}
public boolean shouldLoadKitMovementPage() {
return !(isKit() && SharedPreferenceMgr.getInstance().shouldSyncLastYearStockData());
}
public boolean validateKitQuantity() {
MovementReasonManager.MovementType movementType = viewModel.getTypeQuantityMap().keySet().iterator().next();
if (quantityIsLargerThanSoh(viewModel.getTypeQuantityMap().get(movementType), movementType)) {
view.showQuantityErrors(LMISApp.getContext().getString(R.string.msg_invalid_quantity));
return false;
}
return true;
}
public boolean quantityIsLargerThanSoh(String quantity, MovementReasonManager.MovementType type) {
return (MovementReasonManager.MovementType.ISSUE.equals(type) || MovementReasonManager.MovementType.NEGATIVE_ADJUST.equals(type)) && Long.parseLong(quantity) > stockCard.getStockOnHand();
}
public Date getLastMovementDate() {
return stockCard.getLastStockMovementDate();
}
public interface NewStockMovementView extends BaseView {
void clearErrorAlerts();
void showQuantityErrors(String errorMsg);
void goToStockCard();
}
}