diff --git a/migration/i9/oracle/202206271645_IDEMPIERE-5331.sql b/migration/i9/oracle/202206271645_IDEMPIERE-5331.sql new file mode 100644 index 0000000000..88d23653d2 --- /dev/null +++ b/migration/i9/oracle/202206271645_IDEMPIERE-5331.sql @@ -0,0 +1,22 @@ +-- IDEMPIERE-5331 Create Production from Order Lines +SELECT register_migration_script('202206271645_IDEMPIERE-5331.sql') FROM dual; + +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- Jun 27, 2022, 4:45:47 PM CEST +UPDATE AD_Process SET Name='Create Production from Order Line', Description='Create Production for single ordered product',Updated=TO_TIMESTAMP('2022-06-27 16:45:47','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200006 +; + +-- Jun 27, 2022, 4:46:09 PM CEST +UPDATE AD_Process SET Name='Create Shipment from Order Line',Updated=TO_TIMESTAMP('2022-06-27 16:46:09','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200007 +; + +-- Jun 27, 2022, 4:46:53 PM CEST +INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,ShowHelp,CopyFromProcess,AD_Process_UU) VALUES (200138,0,0,'Y',TO_TIMESTAMP('2022-06-27 16:46:53','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-06-27 16:46:53','YYYY-MM-DD HH24:MI:SS'),100,'Create Production from Order','Create Production for BOM ordered products','N','C_Order_CreateProduction','N','org.compiere.process.OrderCreateProduction','3','D',0,0,'N','S','N','4d1322d4-df18-4cab-a280-82b1c14f35fd') +; + +-- Jun 27, 2022, 4:51:04 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,AD_ToolBarButton_UU,Action,AD_Tab_ID,AD_Process_ID,DisplayLogic,SeqNo,EntityType) VALUES (0,0,TO_TIMESTAMP('2022-06-27 16:51:04','YYYY-MM-DD HH24:MI:SS'),100,'C_Order_CreateProduction','Y',200122,'C_Order_CreateProduction',TO_TIMESTAMP('2022-06-27 16:51:04','YYYY-MM-DD HH24:MI:SS'),100,'N','9ffb3433-7c04-4d35-bd31-681fa70feb29','W',186,200138,'@SQL=SELECT 1 FROM C_OrderLine ol JOIN M_Product p ON (ol.M_Product_ID=p.M_Product_ID) WHERE ol.C_Order_ID=@C_Order_ID:0@ AND ol.Processed=''Y'' AND p.IsBOM=''Y''',10,'D') +; + diff --git a/migration/i9/postgresql/202206271645_IDEMPIERE-5331.sql b/migration/i9/postgresql/202206271645_IDEMPIERE-5331.sql new file mode 100644 index 0000000000..ad50dddf76 --- /dev/null +++ b/migration/i9/postgresql/202206271645_IDEMPIERE-5331.sql @@ -0,0 +1,19 @@ +-- IDEMPIERE-5331 Create Production from Order Lines +SELECT register_migration_script('202206271645_IDEMPIERE-5331.sql') FROM dual; + +-- Jun 27, 2022, 4:45:47 PM CEST +UPDATE AD_Process SET Name='Create Production from Order Line', Description='Create Production for single ordered product',Updated=TO_TIMESTAMP('2022-06-27 16:45:47','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200006 +; + +-- Jun 27, 2022, 4:46:09 PM CEST +UPDATE AD_Process SET Name='Create Shipment from Order Line',Updated=TO_TIMESTAMP('2022-06-27 16:46:09','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200007 +; + +-- Jun 27, 2022, 4:46:53 PM CEST +INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,ShowHelp,CopyFromProcess,AD_Process_UU) VALUES (200138,0,0,'Y',TO_TIMESTAMP('2022-06-27 16:46:53','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2022-06-27 16:46:53','YYYY-MM-DD HH24:MI:SS'),100,'Create Production from Order','Create Production for BOM ordered products','N','C_Order_CreateProduction','N','org.compiere.process.OrderCreateProduction','3','D',0,0,'N','S','N','4d1322d4-df18-4cab-a280-82b1c14f35fd') +; + +-- Jun 27, 2022, 4:51:04 PM CEST +INSERT INTO AD_ToolBarButton (AD_Client_ID,AD_Org_ID,Created,CreatedBy,ComponentName,IsActive,AD_ToolBarButton_ID,Name,Updated,UpdatedBy,IsCustomization,AD_ToolBarButton_UU,"action",AD_Tab_ID,AD_Process_ID,DisplayLogic,SeqNo,EntityType) VALUES (0,0,TO_TIMESTAMP('2022-06-27 16:51:04','YYYY-MM-DD HH24:MI:SS'),100,'C_Order_CreateProduction','Y',200122,'C_Order_CreateProduction',TO_TIMESTAMP('2022-06-27 16:51:04','YYYY-MM-DD HH24:MI:SS'),100,'N','9ffb3433-7c04-4d35-bd31-681fa70feb29','W',186,200138,'@SQL=SELECT 1 FROM C_OrderLine ol JOIN M_Product p ON (ol.M_Product_ID=p.M_Product_ID) WHERE ol.C_Order_ID=@C_Order_ID:0@ AND ol.Processed=''Y'' AND p.IsBOM=''Y''',10,'D') +; + diff --git a/org.adempiere.base.process/src/org/compiere/process/OrderCreateProduction.java b/org.adempiere.base.process/src/org/compiere/process/OrderCreateProduction.java new file mode 100644 index 0000000000..eb8d1d461c --- /dev/null +++ b/org.adempiere.base.process/src/org/compiere/process/OrderCreateProduction.java @@ -0,0 +1,162 @@ +/*********************************************************************** + * This file is part of iDempiere ERP Open Source * + * http://www.idempiere.org * + * * + * Copyright (C) Contributors * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * + * MA 02110-1301, USA. * + * * + * Contributors: * + * - Carlos Ruiz - globalqss - bxservice * + **********************************************************************/ + +package org.compiere.process; + +import java.util.List; +import java.util.logging.Level; + +import org.compiere.model.MDocType; +import org.compiere.model.MOrder; +import org.compiere.model.MOrderLine; +import org.compiere.model.MProduct; +import org.compiere.model.MProduction; +import org.compiere.model.MWarehouse; +import org.compiere.model.Query; +import org.compiere.util.Env; +import org.compiere.util.Msg; + +/** + * + * @author Carlos Ruiz - globalqss - bxservice + * + */ +@org.adempiere.base.annotation.Process +public class OrderCreateProduction extends SvrProcess { + /** Order */ + private int p_C_Order_ID = 0; + + /** + * Prepare - e.g., get Parameters. + */ + protected void prepare() { + p_C_Order_ID = getRecord_ID(); + } // prepare + + /** + * Create Production for BOM products of an order + * + * @throws Exception + */ + protected String doIt() throws Exception { + if (log.isLoggable(Level.INFO)) + log.info("C_Order_ID=" + p_C_Order_ID); + if (p_C_Order_ID == 0) + throw new IllegalArgumentException("No Order"); + // + MOrder order = new MOrder(getCtx(), p_C_Order_ID, get_TrxName()); + if (order.get_ID() == 0) + throw new IllegalArgumentException("Order not found"); + if (!MOrder.DOCSTATUS_Completed.equals(order.getDocStatus())) + throw new IllegalArgumentException("Order not completed"); + + final String where = "C_OrderLine.C_Order_ID=?" + + " AND C_OrderLine.Processed='Y'" + + " AND p.IsBOM='Y'" + + " AND p.IsVerified='Y'" + + " AND NOT EXISTS (SELECT 1 FROM M_Production pr WHERE pr.C_OrderLine_ID=C_OrderLine.C_OrderLine_ID)"; + List lines = new Query(getCtx(), MOrderLine.Table_Name, where, get_TrxName()) + .addJoinClause("JOIN M_Product p ON (C_OrderLine.M_Product_ID=p.M_Product_ID)") + .setOnlyActiveRecords(true) + .setParameters(p_C_Order_ID) + .list(); + + MDocType doc = new MDocType(getCtx(), order.getC_DocType_ID(), get_TrxName()); + int cnt = 0; + for (MOrderLine line : lines) { + if ((line.getQtyOrdered().subtract(line.getQtyDelivered())).compareTo(Env.ZERO) <= 0) { + if (!doc.getDocSubTypeSO().equals("ON")) { // Consignment and stock orders both have subtype of ON + continue; + } + } + + MProduction production = new MProduction(line); + MProduct product = new MProduct(getCtx(), line.getM_Product_ID(), get_TrxName()); + + production.setM_Product_ID(line.getM_Product_ID()); + production.setProductionQty(line.getQtyOrdered().subtract(line.getQtyDelivered())); + production.setDatePromised(line.getDatePromised()); + production.setC_OrderLine_ID(line.getC_OrderLine_ID()); + + int locator = product.getM_Locator_ID(); + if (locator == 0) + locator = MWarehouse.get(getCtx(), line.getM_Warehouse_ID()).getDefaultLocator().get_ID(); + production.setM_Locator_ID(locator); + + if (line.getC_BPartner_ID() > 0) { + production.setC_BPartner_ID(order.getC_BPartner_ID()); + } + + if (line.getC_Project_ID() > 0) { + production.setC_Project_ID(line.getC_Project_ID()); + } else { + production.setC_Project_ID(order.getC_Project_ID()); + } + + if (line.getC_Campaign_ID() > 0) { + production.setC_Campaign_ID(line.getC_Campaign_ID()); + } else { + production.setC_Campaign_ID(order.getC_Campaign_ID()); + } + + if (line.getC_Activity_ID() > 0) { + production.setC_Activity_ID(line.getC_Activity_ID()); + } else { + production.setC_Activity_ID(order.getC_Activity_ID()); + } + + if (line.getUser1_ID() > 0) { + production.setUser1_ID(line.getUser1_ID()); + } else { + production.setUser1_ID(order.getUser1_ID()); + } + + if (line.getUser2_ID() > 0) { + production.setUser2_ID(line.getUser2_ID()); + } else { + production.setUser2_ID(order.getUser2_ID()); + } + + if (line.getAD_OrgTrx_ID() > 0) { + production.setAD_OrgTrx_ID(line.getAD_OrgTrx_ID()); + } else { + production.setAD_OrgTrx_ID(order.getAD_OrgTrx_ID()); + } + + production.saveEx(); + + production.createLines(false); + production.setIsCreated("Y"); + production.saveEx(); + + String msg = Msg.parseTranslation(getCtx(), "@M_Production_ID@ @Created@ " + production.getDocumentNo()); + addBufferLog(production.getM_Production_ID(), null, null, msg, MProduction.Table_ID, production.getM_Production_ID()); + cnt++; + } + + return "@Created@ " + cnt; + } + +} // OrderCreateShipment diff --git a/org.adempiere.base.process/src/org/compiere/process/OrderLineCreateProduction.java b/org.adempiere.base.process/src/org/compiere/process/OrderLineCreateProduction.java index 12e9eb8258..9f821365dc 100644 --- a/org.adempiere.base.process/src/org/compiere/process/OrderLineCreateProduction.java +++ b/org.adempiere.base.process/src/org/compiere/process/OrderLineCreateProduction.java @@ -16,7 +16,6 @@ *****************************************************************************/ package org.compiere.process; -import java.sql.Timestamp; import java.util.logging.Level; import org.compiere.model.MDocType; @@ -30,7 +29,7 @@ import org.compiere.util.Env; import org.compiere.util.Msg; /** - * Create (Generate) Invoice from Shipment + * Create (Generate) Production from OrderLine * * @author Jorg Janke * @version $Id: OrderLineCreateProduction.java,v 1.1 2007/07/23 05:34:35 mfuggle Exp $ @@ -38,35 +37,14 @@ import org.compiere.util.Msg; @org.adempiere.base.annotation.Process public class OrderLineCreateProduction extends SvrProcess { - /** Shipment */ + /** Order Line */ private int p_C_OrderLine_ID = 0; - private Timestamp p_MovementDate = null; - private boolean ignorePrevProduction = false; /** * Prepare - e.g., get Parameters. */ protected void prepare() { - ProcessInfoParameter[] para = getParameter(); - for (int i = 0; i < para.length; i++) - { - String name = para[i].getParameterName(); - if (para[i].getParameter() == null) - ; - if (name.equals("MovementDate")) - p_MovementDate = (Timestamp) para[i].getParameter(); - else if (name.equals("IgnorePrevProduction")) - ignorePrevProduction = "Y".equals(para[i].getParameter()); - else - log.log(Level.SEVERE, "Unknown Parameter: " + name); - } - - if (p_MovementDate == null) - p_MovementDate = Env.getContextAsDate(getCtx(), Env.DATE); - if ( p_MovementDate==null) - p_MovementDate = new Timestamp(System.currentTimeMillis()); - p_C_OrderLine_ID = getRecord_ID(); } // prepare @@ -97,20 +75,13 @@ public class OrderLineCreateProduction extends SvrProcess } } - - // If we don't ignore previous production, and there has been a previous one, - //throw an exception - if (!ignorePrevProduction) - { - String docNo = DB.getSQLValueString(get_TrxName(), - "SELECT max(DocumentNo) " + - "FROM M_Production WHERE C_OrderLine_ID = ?", - p_C_OrderLine_ID); - if (docNo != null) - { - throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "ProductionHasAlreadyBeenCreated", new String[] {docNo})); - - } + String docNo = DB.getSQLValueString(get_TrxName(), + "SELECT max(DocumentNo) " + + "FROM M_Production WHERE C_OrderLine_ID = ?", + p_C_OrderLine_ID); + if (docNo != null) + { + throw new IllegalArgumentException(Msg.getMsg(Env.getCtx(), "ProductionHasAlreadyBeenCreated", new String[] {docNo})); } MProduction production = new MProduction( line ); @@ -119,8 +90,6 @@ public class OrderLineCreateProduction extends SvrProcess production.setM_Product_ID(line.getM_Product_ID()); production.setProductionQty(line.getQtyOrdered().subtract(line.getQtyDelivered())); production.setDatePromised(line.getDatePromised()); - if ( product.getM_Locator_ID() > 0 ) - production.setM_Locator_ID(product.getM_Locator_ID()); production.setC_OrderLine_ID(p_C_OrderLine_ID); int locator = product.getM_Locator_ID(); @@ -177,6 +146,6 @@ public class OrderLineCreateProduction extends SvrProcess String msg = Msg.parseTranslation(getCtx(), "@M_Production_ID@ @Created@ " + production.getDocumentNo()); addLog(production.getM_Production_ID(), null, null, msg, MProduction.Table_ID, production.getM_Production_ID()); return "@OK@"; - } // OrderLineCreateShipment + } } // OrderLineCreateShipment diff --git a/org.adempiere.base/src/org/compiere/model/MProduction.java b/org.adempiere.base/src/org/compiere/model/MProduction.java index 96dbc45ed2..ddb4c7dd96 100644 --- a/org.adempiere.base/src/org/compiere/model/MProduction.java +++ b/org.adempiere.base/src/org/compiere/model/MProduction.java @@ -659,6 +659,9 @@ public class MProduction extends X_M_Production implements DocAction { return reverseCorrectIt(); } + if (getC_OrderLine_ID() > 0) + setC_OrderLine_ID(0); + // After Void m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID); if (m_processMsg != null) @@ -716,6 +719,9 @@ public class MProduction extends X_M_Production implements DocAction { reversalDate = new Timestamp(System.currentTimeMillis()); } + if (getC_OrderLine_ID() > 0) + setC_OrderLine_ID(0); + MPeriod.testPeriodOpen(getCtx(), reversalDate, Doc.DOCTYPE_MatProduction, getAD_Org_ID()); MProduction reversal = null; reversal = copyFrom (reversalDate);