org.openlmis.restapi.service.RestRequisitionService.java Source code

Java tutorial

Introduction

Here is the source code for org.openlmis.restapi.service.RestRequisitionService.java

Source

/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright  2013 VillageReach
 *
 * 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.restapi.service;

import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import lombok.NoArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.Transformer;
import org.apache.log4j.Logger;
import org.apache.lucene.util.CollectionUtil;
import org.openlmis.core.domain.*;
import org.openlmis.core.exception.DataException;
import org.openlmis.core.service.FacilityApprovedProductService;
import org.openlmis.core.service.FacilityService;
import org.openlmis.core.service.ProcessingPeriodService;
import org.openlmis.core.service.ProgramService;
import org.openlmis.order.service.OrderService;
import org.openlmis.restapi.domain.ReplenishmentDTO;
import org.openlmis.restapi.domain.Report;
import org.openlmis.rnr.domain.*;
import org.openlmis.rnr.search.criteria.RequisitionSearchCriteria;
import org.openlmis.rnr.service.RequisitionService;
import org.openlmis.rnr.service.RnrTemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import static java.util.Arrays.asList;
import static org.apache.commons.collections.CollectionUtils.find;
import static org.openlmis.restapi.domain.ReplenishmentDTO.prepareForREST;

/**
 * This service exposes methods for creating, approving a requisition.
 */

@Service
@NoArgsConstructor
public class RestRequisitionService {

    public static final boolean EMERGENCY = false;
    private static final Logger logger = Logger.getLogger(RestRequisitionService.class);
    @Autowired
    private RequisitionService requisitionService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private FacilityService facilityService;
    @Autowired
    private ProgramService programService;
    @Autowired
    private RnrTemplateService rnrTemplateService;
    @Autowired
    private RestRequisitionCalculator restRequisitionCalculator;
    @Autowired
    private ProcessingPeriodService processingPeriodService;
    @Autowired
    private FacilityApprovedProductService facilityApprovedProductService;
    private List<FacilityTypeApprovedProduct> nonFullSupplyFacilityApprovedProductByFacilityAndProgram;

    @Transactional
    public Rnr submitReport(Report report, Long userId) {
        report.validate();

        Facility reportingFacility = facilityService.getOperativeFacilityByCode(report.getAgentCode());
        Program reportingProgram = programService.getValidatedProgramByCode(report.getProgramCode());

        restRequisitionCalculator.validatePeriod(reportingFacility, reportingProgram);

        Rnr rnr = requisitionService.initiate(reportingFacility, reportingProgram, userId, EMERGENCY, null);

        restRequisitionCalculator.validateProducts(report.getProducts(), rnr);

        markSkippedLineItems(rnr, report);

        if (reportingFacility.getVirtualFacility())
            restRequisitionCalculator.setDefaultValues(rnr);

        copyRegimens(rnr, report);

        requisitionService.save(rnr);

        updateClientFields(report, rnr);
        insertPatientQuantificationLineItems(report, rnr);

        insertRnrSignatures(report, rnr, userId);

        rnr = requisitionService.submit(rnr);

        return requisitionService.authorize(rnr);
    }

    private void updateClientFields(Report report, Rnr rnr) {
        Date clientSubmittedTime = report.getClientSubmittedTime();
        rnr.setClientSubmittedTime(clientSubmittedTime);

        String clientSubmittedNotes = report.getClientSubmittedNotes();
        rnr.setClientSubmittedNotes(clientSubmittedNotes);

        requisitionService.updateClientFields(rnr);
    }

    @Transactional
    public Rnr submitSdpReport(Report report, Long userId) {
        report.validate();

        Facility reportingFacility = facilityService.getOperativeFacilityByCode(report.getAgentCode());
        Program reportingProgram = programService.getValidatedProgramByCode(report.getProgramCode());
        ProcessingPeriod period = processingPeriodService.getById(report.getPeriodId());

        Rnr rnr;
        List<Rnr> rnrs = null;

        RequisitionSearchCriteria searchCriteria = new RequisitionSearchCriteria();
        searchCriteria.setProgramId(reportingProgram.getId());
        searchCriteria.setFacilityId(reportingFacility.getId());
        searchCriteria.setWithoutLineItems(true);
        searchCriteria.setUserId(userId);

        if (report.getPeriodId() != null) {
            //check if the requisition has already been initiated / submitted / authorized.
            restRequisitionCalculator.validateCustomPeriod(reportingFacility, reportingProgram, period, userId);
            rnrs = requisitionService.getRequisitionsFor(searchCriteria, asList(period));
        }

        if (rnrs != null && rnrs.size() > 0) {
            rnr = requisitionService.getFullRequisitionById(rnrs.get(0).getId());

        } else {
            rnr = requisitionService.initiate(reportingFacility, reportingProgram, userId, report.getEmergency(),
                    period);
        }

        List<RnrLineItem> fullSupplyProducts = new ArrayList<>();
        List<RnrLineItem> nonFullSupplyProducts = new ArrayList<>();
        Iterator<RnrLineItem> iterator = report.getProducts().iterator();
        nonFullSupplyFacilityApprovedProductByFacilityAndProgram = facilityApprovedProductService
                .getNonFullSupplyFacilityApprovedProductByFacilityAndProgram(reportingFacility.getId(),
                        reportingProgram.getId());

        // differentiate between full supply and non full supply products
        while (iterator.hasNext()) {
            final RnrLineItem lineItem = iterator.next();
            if (lineItem.getFullSupply()) {
                fullSupplyProducts.add(lineItem);
            } else {

                setNonFullSupplyCreatorFields(lineItem);
                nonFullSupplyProducts.add(lineItem);
            }
        }
        report.setProducts(fullSupplyProducts);
        report.setNonFullSupplyProducts(nonFullSupplyProducts);
        restRequisitionCalculator.validateProducts(report.getProducts(), rnr);

        markSkippedLineItems(rnr, report);

        copyRegimens(rnr, report);
        // if you have come this far, then do it, it is your day. make the submission.
        // i cannot believe we do all of these three at the same time.
        // but then this is what zambia specifically asked.
        requisitionService.save(rnr);
        rnr = requisitionService.submit(rnr);
        return requisitionService.authorize(rnr);
    }

    private void setNonFullSupplyCreatorFields(final RnrLineItem lineItem) {

        FacilityTypeApprovedProduct p = (FacilityTypeApprovedProduct) find(
                nonFullSupplyFacilityApprovedProductByFacilityAndProgram, new Predicate() {
                    @Override
                    public boolean evaluate(Object product) {
                        return ((FacilityTypeApprovedProduct) product).getProgramProduct().getProduct().getCode()
                                .equals(lineItem.getProductCode());
                    }
                });
        if (p == null) {
            return;
        }
        lineItem.setDispensingUnit(p.getProgramProduct().getProduct().getDispensingUnit());
        lineItem.setMaxMonthsOfStock(p.getMaxMonthsOfStock());
        lineItem.setDosesPerMonth(p.getProgramProduct().getDosesPerMonth());
        lineItem.setDosesPerDispensingUnit(p.getProgramProduct().getProduct().getDosesPerDispensingUnit());
        lineItem.setPackSize(p.getProgramProduct().getProduct().getPackSize());
        lineItem.setRoundToZero(p.getProgramProduct().getProduct().getRoundToZero());
        lineItem.setPackRoundingThreshold(p.getProgramProduct().getProduct().getPackRoundingThreshold());
        lineItem.setPrice(p.getProgramProduct().getCurrentPrice());
    }

    private void copyRegimens(Rnr rnr, Report report) {
        if (report.getRegimens() != null) {
            for (RegimenLineItem regimenLineItem : report.getRegimens()) {
                RegimenLineItem correspondingRegimenLineItem = rnr
                        .findCorrespondingRegimenLineItem(regimenLineItem);
                if (correspondingRegimenLineItem == null)
                    throw new DataException("error.invalid.regimen");
                correspondingRegimenLineItem.populate(regimenLineItem);
            }
        }
    }

    private void insertPatientQuantificationLineItems(Report report, Rnr rnr) {
        if (report.getPatientQuantifications() != null) {
            rnr.setPatientQuantifications(report.getPatientQuantifications());
            requisitionService.insertPatientQuantificationLineItems(rnr);
        }
    }

    private void insertRnrSignatures(Report report, Rnr rnr, final Long userId) {
        if (report.getRnrSignatures() != null) {

            List<Signature> rnrSignatures = new ArrayList(
                    CollectionUtils.collect(report.getRnrSignatures(), new Transformer() {
                        @Override
                        public Object transform(Object input) {
                            ((Signature) input).setCreatedBy(userId);
                            ((Signature) input).setModifiedBy(userId);
                            return input;
                        }
                    }));
            rnr.setRnrSignatures(rnrSignatures);
            requisitionService.insertRnrSignatures(rnr);
        }
    }

    @Transactional
    public void approve(Report report, Long requisitionId, Long userId) {
        Rnr requisition = report.getRequisition(requisitionId, userId);

        Rnr savedRequisition = requisitionService.getFullRequisitionById(requisition.getId());

        if (!savedRequisition.getFacility().getVirtualFacility()) {
            throw new DataException("error.approval.not.allowed");
        }

        if (savedRequisition.getNonSkippedLineItems().size() != report.getProducts().size()) {
            throw new DataException("error.number.of.line.items.mismatch");
        }

        restRequisitionCalculator.validateProducts(report.getProducts(), savedRequisition);

        requisitionService.save(requisition);
        requisitionService.approve(requisition, report.getApproverName());
    }

    public ReplenishmentDTO getReplenishmentDetails(Long id) {
        Rnr requisition = requisitionService.getFullRequisitionById(id);
        return prepareForREST(requisition, orderService.getOrder(id));
    }

    private void markSkippedLineItems(Rnr rnr, Report report) {

        ProgramRnrTemplate rnrTemplate = rnrTemplateService
                .fetchProgramTemplateForRequisition(rnr.getProgram().getId());

        List<RnrLineItem> savedLineItems = rnr.getFullSupplyLineItems();
        List<RnrLineItem> reportedProducts = report.getProducts();

        for (final RnrLineItem savedLineItem : savedLineItems) {
            RnrLineItem reportedLineItem = (RnrLineItem) find(reportedProducts, new Predicate() {
                @Override
                public boolean evaluate(Object product) {
                    return ((RnrLineItem) product).getProductCode().equals(savedLineItem.getProductCode());
                }
            });

            copyInto(savedLineItem, reportedLineItem, rnrTemplate);
        }

        savedLineItems = rnr.getNonFullSupplyLineItems();
        reportedProducts = report.getNonFullSupplyProducts();
        if (reportedProducts != null) {
            for (final RnrLineItem reportedLineItem : reportedProducts) {
                RnrLineItem savedLineItem = (RnrLineItem) find(savedLineItems, new Predicate() {
                    @Override
                    public boolean evaluate(Object product) {
                        return ((RnrLineItem) product).getProductCode().equals(reportedLineItem.getProductCode());
                    }
                });
                if (savedLineItem == null && reportedLineItem != null) {
                    rnr.getNonFullSupplyLineItems().add(reportedLineItem);
                } else {
                    copyInto(savedLineItem, reportedLineItem, rnrTemplate);
                }
            }
        }

    }

    private void copyInto(RnrLineItem savedLineItem, RnrLineItem reportedLineItem, ProgramRnrTemplate rnrTemplate) {
        if (reportedLineItem == null) {
            savedLineItem.setSkipped(true);
            return;
        }

        for (Column column : rnrTemplate.getColumns()) {
            if (!column.getVisible() || !rnrTemplate.columnsUserInput(column.getName()))
                continue;
            try {
                Field field = RnrLineItem.class.getDeclaredField(column.getName());
                field.setAccessible(true);

                Object reportedValue = field.get(reportedLineItem);
                Object toBeSavedValue = (reportedValue != null ? reportedValue : field.get(savedLineItem));
                field.set(savedLineItem, toBeSavedValue);
            } catch (Exception e) {
                logger.error("could not copy field: " + column.getName());
            }
        }
    }

    public List<Report> getRequisitionsByFacility(String facilityCode) {
        Facility facility = facilityService.getFacilityByCode(facilityCode);
        if (facility == null) {
            throw new DataException("error.facility.unknown");
        }

        List<Rnr> rnrList = requisitionService.getRequisitionsByFacility(facility);

        return FluentIterable.from(rnrList).transform(new Function<Rnr, Report>() {
            @Override
            public Report apply(Rnr input) {
                return Report.prepareForREST(input);
            }
        }).toList();
    }
}