org.openlmis.fulfillment.web.util.StockEventBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.openlmis.fulfillment.web.util.StockEventBuilder.java

Source

/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright  2017 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.fulfillment.web.util;

import static org.openlmis.fulfillment.i18n.MessageKeys.EVENT_MISSING_SOURCE_DESTINATION;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.openlmis.fulfillment.domain.ProofOfDelivery;
import org.openlmis.fulfillment.domain.ProofOfDeliveryLineItem;
import org.openlmis.fulfillment.domain.Shipment;
import org.openlmis.fulfillment.domain.ShipmentLineItem;
import org.openlmis.fulfillment.service.ConfigurationSettingService;
import org.openlmis.fulfillment.service.referencedata.FacilityDto;
import org.openlmis.fulfillment.service.referencedata.FacilityReferenceDataService;
import org.openlmis.fulfillment.service.referencedata.OrderableDto;
import org.openlmis.fulfillment.service.referencedata.OrderableReferenceDataService;
import org.openlmis.fulfillment.service.stockmanagement.ValidDestinationsStockManagementService;
import org.openlmis.fulfillment.service.stockmanagement.ValidSourceDestinationsStockManagementService;
import org.openlmis.fulfillment.service.stockmanagement.ValidSourcesStockManagementService;
import org.openlmis.fulfillment.util.AuthenticationHelper;
import org.openlmis.fulfillment.util.DateHelper;
import org.openlmis.fulfillment.web.ValidationException;
import org.openlmis.fulfillment.web.stockmanagement.StockEventDto;
import org.openlmis.fulfillment.web.stockmanagement.StockEventLineItemDto;
import org.openlmis.fulfillment.web.stockmanagement.ValidSourceDestinationDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;
import org.slf4j.profiler.Profiler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class StockEventBuilder {
    private static final XLogger XLOGGER = XLoggerFactory.getXLogger(StockEventBuilder.class);
    private static final Logger LOGGER = LoggerFactory.getLogger(StockEventBuilder.class);

    @Autowired
    private FacilityReferenceDataService facilityReferenceDataService;

    @Autowired
    private ValidDestinationsStockManagementService validDestinationsStockManagementService;

    @Autowired
    private ValidSourcesStockManagementService validSourcesStockManagementService;

    @Autowired
    private ConfigurationSettingService configurationSettingService;

    @Autowired
    private AuthenticationHelper authenticationHelper;

    @Autowired
    private OrderableReferenceDataService orderableReferenceDataService;

    @Autowired
    private DateHelper dateHelper;

    /**
     * Builds a stock event DTO from the given shipment.
     */
    public StockEventDto fromShipment(Shipment shipment) {
        XLOGGER.entry(shipment);
        Profiler profiler = new Profiler("BUILD_STOCK_EVENT_FROM_SHIPMENT");
        profiler.setLogger(XLOGGER);

        LOGGER.debug("Building stock events for shipment: {}", shipment.getId());

        profiler.start("BUILD_STOCK_EVENT");
        StockEventDto stockEventDto = new StockEventDto(shipment.getProgramId(), shipment.getSupplyingFacilityId(),
                getLineItems(shipment, profiler), shipment.getShippedById());

        profiler.stop().log();
        XLOGGER.exit(stockEventDto);
        return stockEventDto;
    }

    /**
     * Builds a stock event DTO from the given proof of delivery.
     */
    public StockEventDto fromProofOfDelivery(ProofOfDelivery proofOfDelivery) {
        XLOGGER.entry(proofOfDelivery);
        Profiler profiler = new Profiler("BUILD_STOCK_EVENT_FROM_POD");
        profiler.setLogger(XLOGGER);

        LOGGER.debug("Building stock events for proof of delivery: {}", proofOfDelivery.getId());

        profiler.start("BUILD_STOCK_EVENT");
        StockEventDto stockEventDto = new StockEventDto(proofOfDelivery.getProgramId(),
                proofOfDelivery.getReceivingFacilityId(), getLineItems(proofOfDelivery, profiler),
                authenticationHelper.getCurrentUser().getId());

        profiler.stop().log();
        XLOGGER.exit(stockEventDto);
        return stockEventDto;
    }

    private List<StockEventLineItemDto> getLineItems(Shipment shipment, Profiler profiler) {
        profiler.start("GET_ORDERABLE_IDS");
        Set<UUID> orderableIds = shipment.getLineItems().stream().map(ShipmentLineItem::getOrderableId)
                .collect(Collectors.toSet());

        profiler.start("GET_ORDERABLES_BY_IDS");
        Map<UUID, OrderableDto> orderables = getOrderables(orderableIds);

        profiler.start("GET_DESTINATION_ID");
        UUID destinationId = getDestinationId(shipment.getSupplyingFacilityId(), shipment.getReceivingFacilityId(),
                shipment.getProgramId());

        profiler.start("CREATE_STOCK_EVENT_LINE_ITEMS");
        return shipment.getLineItems().stream().map(lineItem -> createLineItem(lineItem, orderables, destinationId))
                .collect(Collectors.toList());
    }

    private List<StockEventLineItemDto> getLineItems(ProofOfDelivery proofOfDelivery, Profiler profiler) {
        profiler.start("GET_ORDERABLE_IDS");
        Set<UUID> orderableIds = proofOfDelivery.getLineItems().stream()
                .map(ProofOfDeliveryLineItem::getOrderableId).collect(Collectors.toSet());

        profiler.start("GET_ORDERABLES_BY_IDS");
        Map<UUID, OrderableDto> orderables = getOrderables(orderableIds);

        profiler.start("GET_SOURCE_ID");
        UUID sourceId = getSourceId(proofOfDelivery.getReceivingFacilityId(),
                proofOfDelivery.getSupplyingFacilityId(), proofOfDelivery.getProgramId());

        profiler.start("CREATE_STOCK_EVENT_LINE_ITEMS");
        return proofOfDelivery.getLineItems().stream()
                .map(lineItem -> createLineItem(proofOfDelivery, lineItem, orderables, sourceId))
                .collect(Collectors.toList());
    }

    private StockEventLineItemDto createLineItem(ShipmentLineItem lineItem, Map<UUID, OrderableDto> orderables,
            UUID destinationId) {
        StockEventLineItemDto dto = new StockEventLineItemDto();
        dto.setOccurredDate(dateHelper.getCurrentDate());
        dto.setDestinationId(destinationId);

        lineItem.export(dto);
        convertQuantityToDispensingUnits(dto, orderables);

        return dto;
    }

    private StockEventLineItemDto createLineItem(ProofOfDelivery proofOfDelivery, ProofOfDeliveryLineItem lineItem,
            Map<UUID, OrderableDto> orderables, UUID sourceId) {
        StockEventLineItemDto dto = new StockEventLineItemDto();
        dto.setOccurredDate(proofOfDelivery.getReceivedDate());
        dto.setSourceId(sourceId);
        dto.setReasonId(configurationSettingService.getTransferInReasonId());

        lineItem.export(dto);
        convertQuantityToDispensingUnits(dto, orderables);

        return dto;
    }

    private Map<UUID, OrderableDto> getOrderables(Set<UUID> orderableUuids) {
        return orderableReferenceDataService.findByIds(orderableUuids).stream()
                .collect(Collectors.toMap(OrderableDto::getId, orderable -> orderable));
    }

    private void convertQuantityToDispensingUnits(StockEventLineItemDto dto, Map<UUID, OrderableDto> orderables) {
        orderables.computeIfPresent(dto.getOrderableId(), (id, orderable) -> {
            Long netContent = orderables.get(dto.getOrderableId()).getNetContent();
            dto.setQuantity((int) (dto.getQuantity() * netContent));
            return orderable;
        });
    }

    private UUID getDestinationId(UUID source, UUID destination, UUID programId) {
        return getNodeId(source, destination, programId, validDestinationsStockManagementService);
    }

    private UUID getSourceId(UUID destination, UUID source, UUID programId) {
        return getNodeId(destination, source, programId, validSourcesStockManagementService);
    }

    private UUID getNodeId(UUID fromFacilityId, UUID toFacilityId, UUID programId,
            ValidSourceDestinationsStockManagementService service) {
        FacilityDto fromFacility = facilityReferenceDataService.findOne(fromFacilityId);
        FacilityDto toFacility = facilityReferenceDataService.findOne(toFacilityId);

        Optional<ValidSourceDestinationDto> response = service.search(programId, fromFacility.getType().getId(),
                toFacility.getId());

        if (response.isPresent()) {
            return response.get().getNode().getId();
        }

        throw new ValidationException(EVENT_MISSING_SOURCE_DESTINATION, toFacility.getCode());
    }

}