@Override public int calculateQtyLUForTotalQtyCUs( final I_M_HU_LUTU_Configuration lutuConfiguration, final BigDecimal qtyCUsTotal, final I_C_UOM qtyCUsTotalUOM) { Check.assumeNotNull(lutuConfiguration, "lutuConfiguration not null"); if (qtyCUsTotal == null || qtyCUsTotal.signum() <= 0) { return 0; } if (isNoLU(lutuConfiguration)) { return 0; } // // Calculate how many CUs we need for an LU final BigDecimal qtyCUsPerLU = lutuConfiguration.getQtyCU().multiply(lutuConfiguration.getQtyTU()); if (qtyCUsPerLU.signum() <= 0) { return 0; } // // Convert the total QtyCU to our internal capacity UOM, to be able to compute using same UOM. final Quantity qtyCUsTotal_Converted = convertQtyToLUTUConfigurationUOM(qtyCUsTotal, qtyCUsTotalUOM, lutuConfiguration); // // Calculate how many LUs we need for given total QtyCU (converted to our capacity UOM) final int qtyLUs = qtyCUsTotal_Converted.getQty().divide(qtyCUsPerLU, 0, RoundingMode.UP).intValueExact(); return qtyLUs; }
@Override public Quantity convertQtyToLUTUConfigurationUOM( final BigDecimal qtyValue, final I_C_UOM qtyUOM, final I_M_HU_LUTU_Configuration lutuConfiguration) { final IUOMConversionBL uomConversionBL = Services.get(IUOMConversionBL.class); final IUOMConversionContext uomConversionCtx = uomConversionBL.createConversionContext(lutuConfiguration.getM_Product()); final Quantity qty = new Quantity(qtyValue, qtyUOM); final I_C_UOM uomTo = lutuConfiguration.getC_UOM(); return qty.convertTo(uomConversionCtx, uomTo); }
@Override public int calculateQtyLUForTotalQtyTUs( final I_M_HU_LUTU_Configuration lutuConfiguration, final BigDecimal qtyTUsTotal) { Check.assumeNotNull(lutuConfiguration, "lutuConfiguration not null"); if (qtyTUsTotal == null || qtyTUsTotal.signum() <= 0) { return 0; } if (isNoLU(lutuConfiguration)) { return 0; } final BigDecimal qtyTUsPerLU = lutuConfiguration.getQtyTU(); if (qtyTUsPerLU.signum() == 0) { // Qty TU not available => cannot compute return 0; } final int qtyLU = qtyTUsTotal.divide(qtyTUsPerLU, 0, RoundingMode.UP).intValueExact(); return qtyLU; }
@Override public ILUTUProducerAllocationDestination createLUTUProducerAllocationDestination( final I_M_HU_LUTU_Configuration lutuConfiguration) { Check.assumeNotNull(lutuConfiguration, "lutuConfiguration not null"); final IHandlingUnitsBL handlingUnitsBL = Services.get(IHandlingUnitsBL.class); final ILUTUProducerAllocationDestination luProducerDestination = new LUTUProducerDestination(); luProducerDestination.setM_HU_LUTU_Configuration(lutuConfiguration); // // LU Configuration final I_M_HU_PI_Item luPIItem = lutuConfiguration.getM_LU_HU_PI_Item(); final int qtyLU = lutuConfiguration.getQtyLU().intValueExact(); final boolean qtyLUInfinite = lutuConfiguration.isInfiniteQtyLU(); final int qtyTU = lutuConfiguration.getQtyTU().intValueExact(); final boolean qtyTUInfinite = lutuConfiguration.isInfiniteQtyTU(); if (!handlingUnitsBL.isNoPI(luPIItem)) { final I_M_HU_PI luPI = luPIItem.getM_HU_PI_Version().getM_HU_PI(); luProducerDestination.setLUItemPI(luPIItem); luProducerDestination.setLUPI(luPI); if (qtyLUInfinite) { luProducerDestination.setMaxLUsInfinite(); // // 07378: Fix behavior when max LUs are infinite, created max TUs are the ones we specify // (otherwise we end up creating infinite HUs for 3 x Tomatoes) luProducerDestination.setMaxTUsForRemainingQty(qtyTU); } else { luProducerDestination.setMaxLUs(qtyLU); } // TU configuration Check.assume(!qtyTUInfinite, "qtyTUInfinite shall be false when dealing with concrete LUs"); luProducerDestination.setMaxTUsPerLU(qtyTU); luProducerDestination.setCreateTUsForRemainingQty(false); } else { luProducerDestination.setLUItemPI(null); luProducerDestination.setLUPI(null); luProducerDestination.setMaxLUs(0); // TU configuration // luProducerDestination.setMaxTUsPerLU(0); // no need to set luProducerDestination.setCreateTUsForRemainingQty(true); // we will create only TUs if (qtyTUInfinite) { luProducerDestination.setMaxTUsForRemainingQtyInfinite(); } else { luProducerDestination.setMaxTUsForRemainingQty(qtyTU); } } // // TU Configuration final I_M_HU_PI tuPI = lutuConfiguration.getM_TU_HU_PI(); luProducerDestination.setTUPI(tuPI); // TU Capacity final I_M_Product cuProduct = lutuConfiguration.getM_Product(); final I_C_UOM cuUOM = lutuConfiguration.getC_UOM(); final boolean qtyCUInfinite = lutuConfiguration.isInfiniteQtyCU(); final BigDecimal qtyCUPerTU = qtyCUInfinite ? IHUCapacityDefinition.INFINITY : lutuConfiguration.getQtyCU(); luProducerDestination.addTUCapacity(cuProduct, qtyCUPerTU, cuUOM); // // Misc configuration luProducerDestination.setC_BPartner(lutuConfiguration.getC_BPartner()); luProducerDestination.setC_BPartner_Location_ID(lutuConfiguration.getC_BPartner_Location_ID()); luProducerDestination.setHUStatus(lutuConfiguration.getHUStatus()); luProducerDestination.setM_Locator(lutuConfiguration.getM_Locator()); // // Return it return luProducerDestination; }
@Override public void adjustForTotalQtyTUsAndCUs( final I_M_HU_LUTU_Configuration lutuConfiguration, final BigDecimal qtyTUsTotal, final BigDecimal qtyCUsTotal) { Check.assumeNotNull(qtyTUsTotal, "qtyTUsTotal not null"); Check.assumeNotNull(qtyCUsTotal, "qtyCUsTotal not null"); // // Case: Infinite Qty CU // e.g. we are receiving virtual PIs if (lutuConfiguration.isInfiniteQtyCU()) { lutuConfiguration.setIsInfiniteQtyCU(false); lutuConfiguration.setQtyCU(qtyCUsTotal); lutuConfiguration.setIsInfiniteQtyTU(false); lutuConfiguration.setQtyTU(BigDecimal.ONE); lutuConfiguration.setIsInfiniteQtyLU(false); if (isNoLU(lutuConfiguration)) { lutuConfiguration.setQtyLU(BigDecimal.ZERO); } else { lutuConfiguration.setQtyLU(BigDecimal.ONE); } // NOTE: we are returning here, because this is a corner case which we handled separatelly // from other cases return; } Check.assume( !lutuConfiguration.isInfiniteQtyCU(), "Infinite QtyCU not allowed for {}", lutuConfiguration); final BigDecimal qtyCUsPerTU = lutuConfiguration.getQtyCU(); // // Case: QtyTUs/LU is finite if (!lutuConfiguration.isInfiniteQtyTU()) { final BigDecimal qtyTUsPerLU = lutuConfiguration.getQtyTU(); Check.assume(qtyTUsPerLU.signum() > 0, "QtyTU shall be positive: {}", qtyTUsPerLU); // // Calculate how many LUs we will have based on Order's QtyTU final BigDecimal qtyLUs_Effective = qtyTUsTotal.divide(qtyTUsPerLU, 0, RoundingMode.UP); // // Calculate how many TUs we will have // NOTE: this is covering the case when for example your LU accepts 96xTUs but in your order // you have just 10xTUs. // In this case, QtyTUs shall be only 10. final BigDecimal qtyTUs_Effective = qtyTUsPerLU.min(qtyTUsTotal); // // Calculate how many CUs we will have // NOTE: this is covering the case when for example your TU accepts 50xCUs but you have only // 10xCUs. // In this case, QtyCUs shall only 10. final BigDecimal qtyCUs_Effective = qtyCUsPerTU.min(qtyCUsTotal); lutuConfiguration.setIsInfiniteQtyLU( false); // since we calculated it, we're not considering it infinite any longer lutuConfiguration.setQtyLU(qtyLUs_Effective); lutuConfiguration.setIsInfiniteQtyTU( false); // since we calculated it, we're not considering it infinite any longer lutuConfiguration.setQtyTU(qtyTUs_Effective); lutuConfiguration.setIsInfiniteQtyCU( false); // since we calculated it, we're not considering it infinite any longer lutuConfiguration.setQtyCU(qtyCUs_Effective); } // // Case: QtyTUs/LU is infinite else { Check.assume( !lutuConfiguration.isInfiniteQtyLU(), "LU cannot be infinite when TU already is infinite for {}", lutuConfiguration); final BigDecimal qtyTUs_Effective = qtyTUsTotal; final BigDecimal qtyCUs_Effective = qtyCUsPerTU.min(qtyCUsTotal); lutuConfiguration.setIsInfiniteQtyTU( false); // since we calculated it, we're not considering it infinite any longer lutuConfiguration.setQtyTU(qtyTUs_Effective); lutuConfiguration.setIsInfiniteQtyCU( false); // since we calculated it, we're not considering it infinite any longer lutuConfiguration.setQtyCU(qtyCUs_Effective); } }
private ArrayKey createKeyForHUProducer(final I_M_HU_LUTU_Configuration lutuConfiguration) { Check.assumeNotNull(lutuConfiguration, "lutuConfiguration not null"); final List<Object> keyItems = new ArrayList<Object>(); // // LU: PI final int luPIItemId = lutuConfiguration.getM_LU_HU_PI_Item_ID(); final boolean hasLU; if (luPIItemId > 0) { final int luPIId = lutuConfiguration.getM_LU_HU_PI_ID(); Check.assume(luPIId > 0, "LU PI ID shall be set for {}", lutuConfiguration); keyItems.add(luPIItemId); // LU M_HU_PI_Item_ID keyItems.add(luPIId); // LU M_HU_PI_ID hasLU = true; } else { keyItems.add(-1); // LU M_HU_PI_Item_ID keyItems.add(-1); // LU M_HU_PI_ID hasLU = false; } // // LU: Qty // NOTE: we skip QtyLU because it's not relevant when we check if the configuration is still // compliant with an HU // // TU: PI final int tuPIId = lutuConfiguration.getM_TU_HU_PI_ID(); if (tuPIId > 0) { keyItems.add(tuPIId); // TU M_HU_PI_ID } else { keyItems.add(-1); // TU M_HU_PI_ID } // // TU: Qty if (lutuConfiguration.isInfiniteQtyTU()) { keyItems.add(true); // IsInfiniteQtyTU keyItems.add(0); // Qty TU } // case: there is no LU. In this case we can ignore the QtyTU because it's not relevant when we // check if configuration is still compiant with an HU else if (!hasLU) { keyItems.add(false); // IsInfiniteQtyTU keyItems.add("QtyTU_NA"); // Qty TU: N/A } else { keyItems.add(false); // IsInfiniteQtyTU keyItems.add(lutuConfiguration.getQtyTU().intValue()); // Qty TU } // // CU final int productId = lutuConfiguration.getM_Product_ID(); final int uomId = lutuConfiguration.getC_UOM_ID(); keyItems.add(productId > 0 ? productId : -1); keyItems.add(uomId > 0 ? uomId : -1); if (lutuConfiguration.isInfiniteQtyCU()) { keyItems.add(true); // IsInfiniteQtyCU keyItems.add(BigDecimal.ZERO); // Qty CU } else { final BigDecimal qtyCU = NumberUtils.stripTrailingDecimalZeros(lutuConfiguration.getQtyCU()); keyItems.add(false); // IsInfiniteQtyCU keyItems.add(qtyCU); // Qty CU } // // Misc final int locatorId = lutuConfiguration.getM_Locator_ID(); final int bpartnerId = lutuConfiguration.getC_BPartner_ID(); final int bpartnerLocationId = lutuConfiguration.getC_BPartner_Location_ID(); final String huStatus = lutuConfiguration.getHUStatus(); keyItems.add(locatorId > 0 ? locatorId : -1); keyItems.add(bpartnerId > 0 ? bpartnerId : -1); keyItems.add(bpartnerLocationId > 0 ? bpartnerLocationId : -1); keyItems.add(huStatus); keyItems.add(lutuConfiguration.isActive()); return Util.mkKey(keyItems.toArray()); }
@Override public boolean isNoLU(final I_M_HU_LUTU_Configuration lutuConfiguration) { Check.assumeNotNull(lutuConfiguration, "lutuConfiguration not null"); return lutuConfiguration.getM_LU_HU_PI_Item_ID() <= 0; }
@Override public I_M_HU_LUTU_Configuration createLUTUConfiguration( final I_M_HU_PI_Item_Product tuPIItemProduct, final I_M_Product cuProduct, final I_C_UOM cuUOM, final org.compiere.model.I_C_BPartner bpartner) { Check.assumeNotNull(tuPIItemProduct, "tuPIItemProduct not null"); Check.assumeNotNull(cuProduct, "cuProduct not null"); Check.assumeNotNull(cuUOM, "cuUOM not null"); // Services used: final ITrxManager trxManager = Services.get(ITrxManager.class); final IHandlingUnitsDAO handlingUnitsDAO = Services.get(IHandlingUnitsDAO.class); final IHUCapacityBL huCapacityBL = Services.get(IHUCapacityBL.class); // // Context final Properties ctx = InterfaceWrapperHelper.getCtx(tuPIItemProduct); final IContextAware contextProvider; final String threadTrxName = trxManager.getThreadInheritedTrxName(); if (trxManager.isNull(threadTrxName)) { contextProvider = new PlainContextAware(ctx, ITrx.TRXNAME_None); } else { contextProvider = trxManager.createThreadContextAware(ctx); } // // LU/TU configuration (draft) final I_M_HU_LUTU_Configuration lutuConfiguration = InterfaceWrapperHelper.newInstance(I_M_HU_LUTU_Configuration.class, contextProvider); lutuConfiguration.setC_BPartner(bpartner); lutuConfiguration.setIsActive(true); // // TU Configuration final I_M_HU_PI tuPI = tuPIItemProduct.getM_HU_PI_Item().getM_HU_PI_Version().getM_HU_PI(); final IHUCapacityDefinition tuCapacity = huCapacityBL.getCapacity(tuPIItemProduct, cuProduct, cuUOM); // lutuConfiguration.setM_HU_PI_Item_Product(tuPIItemProduct); lutuConfiguration.setM_TU_HU_PI(tuPI); lutuConfiguration.setM_Product(cuProduct); lutuConfiguration.setC_UOM(cuUOM); if (tuCapacity.isInfiniteCapacity()) { lutuConfiguration.setIsInfiniteQtyCU(true); lutuConfiguration.setQtyCU(BigDecimal.ZERO); } else { lutuConfiguration.setIsInfiniteQtyCU(false); lutuConfiguration.setQtyCU(tuCapacity.getCapacity()); } // // LU Configuration final I_M_HU_PI_Item luPIItem = handlingUnitsDAO.retrieveDefaultParentPIItem( tuPI, X_M_HU_PI_Version.HU_UNITTYPE_LoadLogistiqueUnit, bpartner); if (luPIItem != null) { final I_M_HU_PI luPI = luPIItem.getM_HU_PI_Version().getM_HU_PI(); lutuConfiguration.setM_LU_HU_PI(luPI); lutuConfiguration.setM_LU_HU_PI_Item(luPIItem); lutuConfiguration.setIsInfiniteQtyLU(true); // we produce as many as needed lutuConfiguration.setQtyLU(BigDecimal.ZERO); final int qtyTU = luPIItem.getQty().intValueExact(); lutuConfiguration.setIsInfiniteQtyTU(false); lutuConfiguration.setQtyTU(BigDecimal.valueOf(qtyTU)); } else { lutuConfiguration.setM_LU_HU_PI(null); lutuConfiguration.setM_LU_HU_PI_Item(null); lutuConfiguration.setIsInfiniteQtyLU(false); lutuConfiguration.setQtyLU(BigDecimal.ZERO); lutuConfiguration.setIsInfiniteQtyTU(true); // as many as needed lutuConfiguration.setQtyTU(BigDecimal.ZERO); } return lutuConfiguration; }