diff --git a/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java b/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java index 96ac1b80ac..6b1924a889 100644 --- a/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java +++ b/org.adempiere.base.process/src/org/compiere/process/ReplenishReportProduction.java @@ -22,6 +22,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import org.compiere.model.MBPartner; @@ -35,6 +36,7 @@ import org.compiere.model.MOrg; import org.compiere.model.MProduct; import org.compiere.model.MProduction; import org.compiere.model.MProductionLine; +import org.compiere.model.MReplenish; import org.compiere.model.MRequisition; import org.compiere.model.MRequisitionLine; import org.compiere.model.MStorage; @@ -758,7 +760,7 @@ public class ReplenishReportProduction extends SvrProcess } } // create Distribution Order /** - * Create Requisition + * Create Production */ private void createProduction() { @@ -775,24 +777,47 @@ public class ReplenishReportProduction extends SvrProcess X_T_Replenish replenish = replenishs[i]; if (wh == null || wh.getM_Warehouse_ID() != replenish.getM_Warehouse_ID()) wh = MWarehouse.get(getCtx(), replenish.getM_Warehouse_ID()); - production = new MProduction (getCtx(), 0, get_TrxName()); - production.setDescription(Msg.getMsg(getCtx(), "Replenishment")); - // Set Org/WH - production.setAD_Org_ID(wh.getAD_Org_ID()); - production.setM_Locator_ID(wh.getDefaultLocator().get_ID()); - production.setM_Product_ID(replenish.getM_Product_ID()); - production.setProductionQty(replenish.getQtyToOrder()); - production.setMovementDate(Env.getContextAsDate(getCtx(), "#Date")); - production.saveEx(); - - production.createLines(false); + BigDecimal batchQty = null; - production.setIsCreated("Y"); - production.save(get_TrxName()); - log.fine(production.toString()); - noProds++; - info += " - " + production.getDocumentNo(); + for (MReplenish rep : MReplenish.getForProduct(getCtx(), replenish.getM_Product_ID(), get_TrxName())) + { + if ( rep.getM_Warehouse_ID() == replenish.getM_Warehouse_ID()) + batchQty = rep.getQtyBatchSize(); + } + + BigDecimal qtyToProduce = replenish.getQtyToOrder(); + + while ( qtyToProduce.compareTo(Env.ZERO) > 0) + { + BigDecimal qty = qtyToProduce; + if ( batchQty != null && batchQty.compareTo(Env.ZERO) > 0 && qtyToProduce.compareTo(batchQty) > 0) + { + qty = batchQty; + qtyToProduce = qtyToProduce.subtract(batchQty); + } + else + { + qtyToProduce = Env.ZERO; + } + production = new MProduction (getCtx(), 0, get_TrxName()); + production.setDescription(Msg.getMsg(getCtx(), "Replenishment")); + // Set Org/WH + production.setAD_Org_ID(wh.getAD_Org_ID()); + production.setM_Locator_ID(wh.getDefaultLocator().get_ID()); + production.setM_Product_ID(replenish.getM_Product_ID()); + production.setProductionQty(qty); + production.setMovementDate(Env.getContextAsDate(getCtx(), "#Date")); + production.saveEx(); + + production.createLines(false); + + production.setIsCreated("Y"); + production.save(get_TrxName()); + log.fine(production.toString()); + noProds++; + info += " - " + production.getDocumentNo(); + } } m_info = "#" + noProds + info; diff --git a/org.adempiere.base/src/org/compiere/model/MProduction.java b/org.adempiere.base/src/org/compiere/model/MProduction.java index feca130b33..6d4dd107ed 100644 --- a/org.adempiere.base/src/org/compiere/model/MProduction.java +++ b/org.adempiere.base/src/org/compiere/model/MProduction.java @@ -27,6 +27,8 @@ public class MProduction extends X_M_Production { /** Log */ private static CLogger m_log = CLogger.getCLogger (MProduction.class); private static final long serialVersionUID = 1L; + private int lineno; + private int count; public MProduction(Properties ctx, int M_Production_ID, String trxName) { super(ctx, M_Production_ID, trxName); @@ -90,17 +92,13 @@ public class MProduction extends X_M_Production { public int createLines(boolean mustBeStocked) { - int defaultLocator = 0; - - int lineno = 100; - int count = 0; + lineno = 100; + + count = 0; + // product to be produced MProduct finishedProduct = new MProduct(getCtx(), getM_Product_ID(), get_TrxName()); - MLocator finishedLocator = MLocator.get(getCtx(), getM_Locator_ID()); - int M_Warehouse_ID = finishedLocator.getM_Warehouse_ID(); - - int asi = 0; MProductionLine line = new MProductionLine( this ); line.setLine( lineno ); @@ -111,10 +109,25 @@ public class MProduction extends X_M_Production { line.save(); count++; + + createLines(mustBeStocked, finishedProduct, getProductionQty()); + + return count; + } + + private int createLines(boolean mustBeStocked, MProduct finishedProduct, BigDecimal requiredQty) { + + int defaultLocator = 0; + + MLocator finishedLocator = MLocator.get(getCtx(), getM_Locator_ID()); + + int M_Warehouse_ID = finishedLocator.getM_Warehouse_ID(); + + int asi = 0; // products used in production String sql = "SELECT M_ProductBom_ID, BOMQty" + " FROM M_Product_BOM" - + " WHERE M_Product_ID=" + getM_Product_ID() + " ORDER BY Line"; + + " WHERE M_Product_ID=" + finishedProduct.getM_Product_ID() + " ORDER BY Line"; PreparedStatement pstmt = null; ResultSet rs = null; @@ -128,149 +141,158 @@ public class MProduction extends X_M_Production { lineno = lineno + 10; int BOMProduct_ID = rs.getInt(1); BigDecimal BOMQty = rs.getBigDecimal(2); - BigDecimal BOMMovementQty = BOMQty.multiply(getProductionQty()); + BigDecimal BOMMovementQty = BOMQty.multiply(requiredQty); MProduct bomproduct = new MProduct(Env.getCtx(), BOMProduct_ID, get_TrxName()); - defaultLocator = bomproduct.getM_Locator_ID(); - if ( defaultLocator == 0 ) - defaultLocator = getM_Locator_ID(); - - if (!bomproduct.isStocked()) - { - MProductionLine BOMLine = null; - BOMLine = new MProductionLine( this ); - BOMLine.setLine( lineno ); - BOMLine.setM_Product_ID( BOMProduct_ID ); - BOMLine.setM_Locator_ID( defaultLocator ); - BOMLine.setQtyUsed(BOMMovementQty ); - BOMLine.setPlannedQty( BOMMovementQty ); - BOMLine.save(get_TrxName()); - lineno = lineno + 10; - count++; - } - else if (BOMMovementQty.signum() == 0) + if ( bomproduct.isPhantom() ) { - MProductionLine BOMLine = null; - BOMLine = new MProductionLine( this ); - BOMLine.setLine( lineno ); - BOMLine.setM_Product_ID( BOMProduct_ID ); - BOMLine.setM_Locator_ID( defaultLocator ); - BOMLine.setQtyUsed( BOMMovementQty ); - BOMLine.setPlannedQty( BOMMovementQty ); - BOMLine.save(get_TrxName()); - - lineno = lineno + 10; - count++; + createLines(mustBeStocked, bomproduct, BOMMovementQty); } else { - - // BOM stock info - MStorage[] storages = null; - MProduct usedProduct = MProduct.get(getCtx(), BOMProduct_ID); - defaultLocator = usedProduct.getM_Locator_ID(); + + defaultLocator = bomproduct.getM_Locator_ID(); if ( defaultLocator == 0 ) defaultLocator = getM_Locator_ID(); - if (usedProduct == null || usedProduct.get_ID() == 0) - return 0; - - MClient client = MClient.get(getCtx()); - MProductCategory pc = MProductCategory.get(getCtx(), - usedProduct.getM_Product_Category_ID()); - String MMPolicy = pc.getMMPolicy(); - if (MMPolicy == null || MMPolicy.length() == 0) - { - MMPolicy = client.getMMPolicy(); - } - - storages = MStorage.getWarehouse(getCtx(), M_Warehouse_ID, BOMProduct_ID, 0, null, - MProductCategory.MMPOLICY_FiFo.equals(MMPolicy), true, 0, get_TrxName()); - MProductionLine BOMLine = null; - int prevLoc = -1; - int previousAttribSet = -1; - // Create lines from storage until qty is reached - for (int sl = 0; sl < storages.length; sl++) { - - BigDecimal lineQty = storages[sl].getQtyOnHand(); - if (lineQty.signum() != 0) { - if (lineQty.compareTo(BOMMovementQty) > 0) - lineQty = BOMMovementQty; - - - int loc = storages[sl].getM_Locator_ID(); - int slASI = storages[sl].getM_AttributeSetInstance_ID(); - int locAttribSet = new MAttributeSetInstance(getCtx(), asi, - get_TrxName()).getM_AttributeSet_ID(); - - // roll up costing attributes if in the same locator - if (locAttribSet == 0 && previousAttribSet == 0 - && prevLoc == loc) { - BOMLine.setQtyUsed(BOMLine.getQtyUsed() - .add(lineQty)); - BOMLine.setPlannedQty(BOMLine.getQtyUsed()); - BOMLine.save(get_TrxName()); - - } - // otherwise create new line - else { - BOMLine = new MProductionLine( this ); - BOMLine.setLine( lineno ); - BOMLine.setM_Product_ID( BOMProduct_ID ); - BOMLine.setM_Locator_ID( loc ); - BOMLine.setQtyUsed( lineQty); - BOMLine.setPlannedQty( lineQty); - if ( slASI != 0 && locAttribSet != 0 ) // ie non costing attribute - BOMLine.setM_AttributeSetInstance_ID(slASI); - BOMLine.save(get_TrxName()); - - lineno = lineno + 10; - count++; - } - prevLoc = loc; - previousAttribSet = locAttribSet; - // enough ? - BOMMovementQty = BOMMovementQty.subtract(lineQty); - if (BOMMovementQty.signum() == 0) - break; + if (!bomproduct.isStocked()) + { + MProductionLine BOMLine = null; + BOMLine = new MProductionLine( this ); + BOMLine.setLine( lineno ); + BOMLine.setM_Product_ID( BOMProduct_ID ); + BOMLine.setM_Locator_ID( defaultLocator ); + BOMLine.setQtyUsed(BOMMovementQty ); + BOMLine.setPlannedQty( BOMMovementQty ); + BOMLine.save(get_TrxName()); + + lineno = lineno + 10; + count++; + } + else if (BOMMovementQty.signum() == 0) + { + MProductionLine BOMLine = null; + BOMLine = new MProductionLine( this ); + BOMLine.setLine( lineno ); + BOMLine.setM_Product_ID( BOMProduct_ID ); + BOMLine.setM_Locator_ID( defaultLocator ); + BOMLine.setQtyUsed( BOMMovementQty ); + BOMLine.setPlannedQty( BOMMovementQty ); + BOMLine.save(get_TrxName()); + + lineno = lineno + 10; + count++; + } + else + { + + // BOM stock info + MStorage[] storages = null; + MProduct usedProduct = MProduct.get(getCtx(), BOMProduct_ID); + defaultLocator = usedProduct.getM_Locator_ID(); + if ( defaultLocator == 0 ) + defaultLocator = getM_Locator_ID(); + if (usedProduct == null || usedProduct.get_ID() == 0) + return 0; + + MClient client = MClient.get(getCtx()); + MProductCategory pc = MProductCategory.get(getCtx(), + usedProduct.getM_Product_Category_ID()); + String MMPolicy = pc.getMMPolicy(); + if (MMPolicy == null || MMPolicy.length() == 0) + { + MMPolicy = client.getMMPolicy(); } - } // for available storages - - // fallback - if (BOMMovementQty.signum() != 0 ) { - if (!mustBeStocked) - { - - // roll up costing attributes if in the same locator - if ( previousAttribSet == 0 - && prevLoc == defaultLocator) { - BOMLine.setQtyUsed(BOMLine.getQtyUsed() - .add(BOMMovementQty)); - BOMLine.setPlannedQty(BOMLine.getQtyUsed()); - BOMLine.save(get_TrxName()); - + + storages = MStorage.getWarehouse(getCtx(), M_Warehouse_ID, BOMProduct_ID, 0, null, + MProductCategory.MMPOLICY_FiFo.equals(MMPolicy), true, 0, get_TrxName()); + + MProductionLine BOMLine = null; + int prevLoc = -1; + int previousAttribSet = -1; + // Create lines from storage until qty is reached + for (int sl = 0; sl < storages.length; sl++) { + + BigDecimal lineQty = storages[sl].getQtyOnHand(); + if (lineQty.signum() != 0) { + if (lineQty.compareTo(BOMMovementQty) > 0) + lineQty = BOMMovementQty; + + + int loc = storages[sl].getM_Locator_ID(); + int slASI = storages[sl].getM_AttributeSetInstance_ID(); + int locAttribSet = new MAttributeSetInstance(getCtx(), asi, + get_TrxName()).getM_AttributeSet_ID(); + + // roll up costing attributes if in the same locator + if (locAttribSet == 0 && previousAttribSet == 0 + && prevLoc == loc) { + BOMLine.setQtyUsed(BOMLine.getQtyUsed() + .add(lineQty)); + BOMLine.setPlannedQty(BOMLine.getQtyUsed()); + BOMLine.save(get_TrxName()); + + } + // otherwise create new line + else { + BOMLine = new MProductionLine( this ); + BOMLine.setLine( lineno ); + BOMLine.setM_Product_ID( BOMProduct_ID ); + BOMLine.setM_Locator_ID( loc ); + BOMLine.setQtyUsed( lineQty); + BOMLine.setPlannedQty( lineQty); + if ( slASI != 0 && locAttribSet != 0 ) // ie non costing attribute + BOMLine.setM_AttributeSetInstance_ID(slASI); + BOMLine.save(get_TrxName()); + + lineno = lineno + 10; + count++; + } + prevLoc = loc; + previousAttribSet = locAttribSet; + // enough ? + BOMMovementQty = BOMMovementQty.subtract(lineQty); + if (BOMMovementQty.signum() == 0) + break; } - // otherwise create new line - else { - - BOMLine = new MProductionLine( this ); - BOMLine.setLine( lineno ); - BOMLine.setM_Product_ID( BOMProduct_ID ); - BOMLine.setM_Locator_ID( defaultLocator ); - BOMLine.setQtyUsed( BOMMovementQty); - BOMLine.setPlannedQty( BOMMovementQty); - BOMLine.save(get_TrxName()); - - lineno = lineno + 10; - count++; + } // for available storages + + // fallback + if (BOMMovementQty.signum() != 0 ) { + if (!mustBeStocked) + { + + // roll up costing attributes if in the same locator + if ( previousAttribSet == 0 + && prevLoc == defaultLocator) { + BOMLine.setQtyUsed(BOMLine.getQtyUsed() + .add(BOMMovementQty)); + BOMLine.setPlannedQty(BOMLine.getQtyUsed()); + BOMLine.save(get_TrxName()); + + } + // otherwise create new line + else { + + BOMLine = new MProductionLine( this ); + BOMLine.setLine( lineno ); + BOMLine.setM_Product_ID( BOMProduct_ID ); + BOMLine.setM_Locator_ID( defaultLocator ); + BOMLine.setQtyUsed( BOMMovementQty); + BOMLine.setPlannedQty( BOMMovementQty); + BOMLine.save(get_TrxName()); + + lineno = lineno + 10; + count++; + } + + } + else + { + throw new AdempiereUserError("Not enough stock of " + BOMProduct_ID); } - - } - else - { - throw new AdempiereUserError("Not enough stock of " + BOMProduct_ID); } } }