private I_DD_OrderLine createDD_OrderLine( final IMRPContext mrpContext, final I_DD_Order order, final I_DD_NetworkDistributionLine networkLine, final I_M_Locator locatorFrom, final I_M_Locator locatorTo, final BigDecimal qtyToMove, final Timestamp supplyDateFinishSchedule, final IMRPCreateSupplyRequest request) { final I_M_Product product = mrpContext.getM_Product(); final int bpartnerId = request.getMRPDemandBPartnerId(); final int orderLineSOId = request.getMRPDemandOrderLineSOId(); // // Create DD Order Line final I_DD_OrderLine ddOrderline = InterfaceWrapperHelper.newInstance(I_DD_OrderLine.class, order); ddOrderline.setAD_Org_ID(order.getAD_Org_ID()); ddOrderline.setDD_Order(order); ddOrderline.setC_BPartner_ID(bpartnerId); ddOrderline.setC_OrderLineSO_ID(orderLineSOId); // // Locator From/To ddOrderline.setM_Locator(locatorFrom); ddOrderline.setM_LocatorTo(locatorTo); // // Product, UOM, Qty // NOTE: we assume qtyToMove is in "mrpContext.getC_UOM()" which shall be the Product's stocking // UOM ddOrderline.setM_Product(product); ddOrderline.setC_UOM(mrpContext.getC_UOM()); ddOrderline.setQtyEntered(qtyToMove); ddOrderline.setQtyOrdered(qtyToMove); ddOrderline.setTargetQty(qtyToMove); // // Dates ddOrderline.setDateOrdered(order.getDateOrdered()); ddOrderline.setDatePromised(order.getDatePromised()); // // Other flags ddOrderline.setIsInvoiced(false); ddOrderline.setDD_AllowPush(networkLine.isDD_AllowPush()); ddOrderline.setIsKeepTargetPlant(networkLine.isKeepTargetPlant()); // // Save DD Order Line InterfaceWrapperHelper.save(ddOrderline); // // Create DD_OrderLine_Alternatives // NOTE: demand MRP line is available only in lot-for-lot order policy // TODO: i think we shall get all MRP demands, retrieve their alternatives, aggregate them and // create DD_OrderLine_Alternatives final I_PP_MRP parentMRPDemand = request.getMRPDemandRecordOrNull(); if (parentMRPDemand != null) { final List<I_PP_MRP_Alternative> mrpAlternatives = mrpDAO.retrieveMRPAlternativesQuery(parentMRPDemand).create().list(); for (final I_PP_MRP_Alternative mrpAlternative : mrpAlternatives) { createDD_OrderLine_Alternative(mrpContext, ddOrderline, mrpAlternative); } } // // Set Correct Planning Dates final int durationDays = calculateDurationDays(mrpContext, networkLine); final Timestamp supplyDateStartSchedule = TimeUtil.addDays(supplyDateFinishSchedule, 0 - durationDays); final List<I_PP_MRP> mrpList = mrpDAO.retrieveMRPRecords(ddOrderline); for (final I_PP_MRP mrp : mrpList) { mrp.setDateStartSchedule(supplyDateStartSchedule); mrp.setDateFinishSchedule(supplyDateFinishSchedule); InterfaceWrapperHelper.save(mrp); } return ddOrderline; }
@Override public void createSupply(final IMRPCreateSupplyRequest request) { final IMRPContext mrpContext = request.getMRPContext(); final IMRPExecutor executor = request.getMRPExecutor(); final Properties ctx = mrpContext.getCtx(); final I_PP_Product_Planning productPlanningData = mrpContext.getProductPlanning(); final I_AD_Org org = mrpContext.getAD_Org(); final I_S_Resource plant = mrpContext.getPlant(); final Timestamp supplyDateFinishSchedule = TimeUtil.asTimestamp(request.getDemandDate()); // QtyToSupply: qty for which we need to produce the supply final BigDecimal qtyToSupply = request.getQtyToSupply(); // TODO vpj-cd I need to create logic for DRP-040 Shipment Due Action Notice // Indicates that a shipment for a Order Distribution is due. // Action should be taken at the source warehouse to ensure that the order is received on time. // TODO vpj-cd I need to create logic for DRP-050 Shipment Pas Due Action Notice // Indicates that a shipment for a Order Distribution is past due. You should either delay the // orders created the requirement for the product // or expedite them when the product does arrive. if (productPlanningData.getDD_NetworkDistribution_ID() <= 0) { // Indicates that the Product Planning Data for this product does not specify a valid network // distribution. executor.newMRPNote(mrpContext, ERR_DRP_060_NoSourceOfSupply).collect(); // return; } final I_DD_NetworkDistribution network = productPlanningData.getDD_NetworkDistribution(); final List<I_DD_NetworkDistributionLine> networkLines = Services.get(IDistributionNetworkDAO.class) .retrieveNetworkLinesByTargetWarehouse( network, productPlanningData.getM_Warehouse_ID()); if (networkLines.isEmpty()) { // No network lines were found for our target warehouse final I_M_Warehouse warehouseTo = productPlanningData.getM_Warehouse(); executor .newMRPNote(mrpContext, ERR_DRP_060_NoSourceOfSupply) .setComment("@NotFound@ @DD_NetworkDistributionLine_ID@") .addParameter( I_DD_NetworkDistribution.COLUMNNAME_DD_NetworkDistribution_ID, network == null ? "?" : network.getName()) .addParameter("M_Warehouse_Dest_ID", warehouseTo == null ? "?" : warehouseTo.getName()) .collect(); // return; } int M_Shipper_ID = -1; I_DD_Order order = null; BigDecimal qtyToSupplyRemaining = qtyToSupply; for (final I_DD_NetworkDistributionLine networkLine : networkLines) { // // Check: if we created DD Orders for all qty that needed to be supplied, stop here if (qtyToSupplyRemaining.signum() <= 0) { break; } // get supply source warehouse and locator final I_M_Warehouse warehouseFrom = networkLine.getM_WarehouseSource(); final I_M_Locator locatorFrom = Services.get(IWarehouseBL.class).getDefaultLocator(warehouseFrom); // get supply target warehouse and locator final I_M_Warehouse warehouseTo = networkLine.getM_Warehouse(); final I_M_Locator locatorTo = Services.get(IWarehouseBL.class).getDefaultLocator(warehouseTo); if (locatorFrom == null || locatorTo == null) { executor .newMRPNote(mrpContext, "DRP-001") // FIXME: DRP-001 error code does not exist .addParameter( I_DD_NetworkDistribution.COLUMNNAME_DD_NetworkDistribution_ID, network == null ? "?" : network.getName()) .addParameter( I_DD_NetworkDistributionLine.COLUMNNAME_M_WarehouseSource_ID, warehouseFrom.getName()) .addParameter( I_DD_NetworkDistributionLine.COLUMNNAME_M_Warehouse_ID, warehouseTo.getName()) .setComment("No locators found for source or target warehouse") .collect(); // continue; } // // Get the warehouse in transit final I_M_Warehouse warehouseInTrasit = retrieveInTransitWarehouse(ctx, warehouseFrom.getAD_Org_ID()); if (warehouseInTrasit == null) { // DRP-010: Do not exist Transit Warehouse to this Organization executor .newMRPNote(mrpContext, ERR_DRP_010_InTransitWarehouseNotFound) .addParameter(I_AD_Org.COLUMNNAME_AD_Org_ID, org.getName()) .collect(); // continue; } // // DRP-030: Do not exist Shipper for Create Distribution Order if (networkLine.getM_Shipper_ID() <= 0) { executor .newMRPNote(mrpContext, "DRP-030") .addParameter( I_DD_NetworkDistribution.COLUMNNAME_DD_NetworkDistribution_ID, network == null ? "?" : network.getName()) .addParameter( I_DD_NetworkDistributionLine.COLUMNNAME_DD_NetworkDistributionLine_ID, networkLine) .collect(); // continue; } if (M_Shipper_ID != networkLine.getM_Shipper_ID()) { // Org Must be linked to BPartner final I_AD_Org locatorToOrg = locatorTo.getAD_Org(); final IBPartnerOrgBL bpartnerOrgBL = Services.get(IBPartnerOrgBL.class); final I_C_BPartner orgBPartner = bpartnerOrgBL.retrieveLinkedBPartner(locatorToOrg); if (orgBPartner == null) { // DRP-020: Target Org has no BP linked to it executor .newMRPNote(mrpContext, "DRP-020") .addParameter(I_AD_Org.COLUMNNAME_AD_Org_ID, locatorToOrg.getName()) .collect(); // continue; } final I_C_BPartner_Location orgBPLocation = bpartnerOrgBL.retrieveOrgBPLocation( mrpContext.getCtx(), locatorToOrg.getAD_Org_ID(), ITrx.TRXNAME_None); // // Try found some DD_Order with Shipper , Business Partner and Doc Status = Draft // Consolidate the demand in a single order for each Shipper , Business Partner , // DemandDateStartSchedule order = getDDOrderFromCache( org, plant, warehouseInTrasit, networkLine.getM_Shipper_ID(), orgBPartner.getC_BPartner_ID(), supplyDateFinishSchedule); if (order == null) { order = InterfaceWrapperHelper.newInstance(I_DD_Order.class, mrpContext); order.setMRP_Generated(true); order.setMRP_AllowCleanup(true); order.setAD_Org_ID(warehouseTo.getAD_Org_ID()); order.setPP_Plant(plant); order.setC_BPartner(orgBPartner); order.setC_BPartner_Location(orgBPLocation); // order.setAD_User_ID(productPlanningData.getPlanner_ID()); // FIXME: improve // performances/cache and retrive Primary BP's User order.setSalesRep_ID(productPlanningData.getPlanner_ID()); final int docTypeDO_ID = getC_DocType_ID(mrpContext, X_C_DocType.DOCBASETYPE_DistributionOrder); order.setC_DocType_ID(docTypeDO_ID); order.setM_Warehouse(warehouseInTrasit); order.setDocStatus(X_DD_Order.DOCSTATUS_Drafted); order.setDocAction(X_DD_Order.DOCACTION_Complete); order.setDateOrdered(mrpContext.getDateAsTimestamp()); order.setDatePromised(supplyDateFinishSchedule); order.setM_Shipper_ID(networkLine.getM_Shipper_ID()); order.setIsInDispute(false); order.setIsInTransit(false); InterfaceWrapperHelper.save(order); executor.addGeneratedSupplyDocument(order); addToCache(order); } M_Shipper_ID = networkLine.getM_Shipper_ID(); } // // Crate DD order line final BigDecimal qtyToMove = calculateQtyToMove(qtyToSupplyRemaining, networkLine.getPercent()); createDD_OrderLine( mrpContext, order, networkLine, locatorFrom, locatorTo, qtyToMove, supplyDateFinishSchedule, request); qtyToSupplyRemaining = qtyToSupplyRemaining.subtract(qtyToMove); } // // Check: remaining qtyToSupply shall be ZERO if (qtyToSupplyRemaining.signum() != 0) { // TODO: introduce DRP-XXX notice throw new LiberoException( "Cannot create DD Order for required Qty To Supply." + "\nQtyToSupply: " + qtyToSupply + "\nQtyToSupply (remaining): " + qtyToSupplyRemaining + "\n@DD_NetworkDistribution_ID@: " + network + "\n@DD_NetworkDistributionLine_ID@: " + networkLines + "\nMRPContext: " + mrpContext); } }