From d421ce00e2c4a0f06bfe0b1a959ed41756491096 Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Wed, 13 Nov 2013 22:05:39 +0800 Subject: [PATCH 1/3] 1003475 IDEMPIERE-1530 Allow Material Receipt Line with Quantity Receipt more then Purchase Order Line's Quantity Ordered --- .../oracle/201311131356_IDEMPIERE-1530.sql | 25 ++++++++ .../201311131356_IDEMPIERE-1530.sql | 21 +++++++ .../src/org/compiere/model/I_M_InOutLine.java | 13 +++++ .../src/org/compiere/model/MInOut.java | 57 ++++++++++++++++--- .../src/org/compiere/model/MMatchPO.java | 24 ++++---- .../src/org/compiere/model/MSysConfig.java | 1 + .../src/org/compiere/model/X_M_InOutLine.java | 22 ++++++- 7 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 migration/i1.0c/oracle/201311131356_IDEMPIERE-1530.sql create mode 100644 migration/i1.0c/postgresql/201311131356_IDEMPIERE-1530.sql diff --git a/migration/i1.0c/oracle/201311131356_IDEMPIERE-1530.sql b/migration/i1.0c/oracle/201311131356_IDEMPIERE-1530.sql new file mode 100644 index 0000000000..558d33875b --- /dev/null +++ b/migration/i1.0c/oracle/201311131356_IDEMPIERE-1530.sql @@ -0,0 +1,25 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + + +-- Nov 13, 2013 5:26:33 PM MYT +-- Make validation of purchase order quantity against invoice and receipt quantity optional +INSERT INTO AD_SysConfig (AD_SysConfig_ID,ConfigurationLevel,Value,Description,AD_SysConfig_UU,Created,Updated,AD_Org_ID,CreatedBy,IsActive,UpdatedBy,Name,AD_Client_ID,EntityType) VALUES (200039,'C','Y','Set this to false (N) to allow material receipt and invoice with quantity more than purchase order quantity.','f473c472-1285-4936-8bb8-2f36f68de12e',TO_DATE('2013-11-13 17:26:26','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2013-11-13 17:26:26','YYYY-MM-DD HH24:MI:SS'),0,100,'Y',100,'VALIDATE_MATCHING_TO_ORDERED_QTY',0,'D') +; + +-- Nov 13, 2013 7:44:29 PM MYT +-- Make validation of purchase order quantity against invoice and receipt quantity optional +INSERT INTO AD_Element (ColumnName,AD_Element_ID,Help,Name,Description,PrintName,AD_Element_UU,Created,Updated,CreatedBy,AD_Org_ID,UpdatedBy,IsActive,AD_Client_ID,EntityType) VALUES ('QtyOverReceipt',202627,'Calculated: Receipt - ordered quantity','Over Receipt','Over Receipt Quantity','Over Receipt','6872e34a-74bc-4590-b8e3-da15b6d365ba',TO_DATE('2013-11-13 19:44:25','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2013-11-13 19:44:25','YYYY-MM-DD HH24:MI:SS'),100,0,100,'Y',0,'D') +; + +-- Nov 13, 2013 7:45:25 PM MYT +INSERT INTO AD_Column (SeqNoSelection,IsSyncDatabase,Version,AD_Table_ID,AD_Column_ID,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsParent,FieldLength,IsSelectionColumn,AD_Reference_ID,IsKey,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsUpdateable,ColumnName,Description,DefaultValue,Help,Name,IsAllowCopy,Updated,CreatedBy,AD_Org_ID,IsActive,Created,UpdatedBy,IsToolbarButton,IsAlwaysUpdateable,AD_Client_ID,EntityType,IsEncrypted,AD_Element_ID,IsSecure) VALUES (0,'N',1,320,210888,'N','N','N',0,'N',22,'N',29,'N','N','Y','8a1f15d1-412e-464e-9797-b547a152b54b','Y','QtyOverReceipt','Over Receipt Quantity','0','Calculated: Receipt - ordered quantity','Over Receipt','N',TO_DATE('2013-11-13 19:45:22','YYYY-MM-DD HH24:MI:SS'),100,0,'Y',TO_DATE('2013-11-13 19:45:22','YYYY-MM-DD HH24:MI:SS'),100,'N','N',0,'D','N',202627,'N') +; + +-- Nov 13, 2013 7:45:55 PM MYT +ALTER TABLE M_InOutLine ADD QtyOverReceipt NUMBER DEFAULT 0 +; + +SELECT register_migration_script('201311131356_IDEMPIERE-1530.sql') FROM dual +; + diff --git a/migration/i1.0c/postgresql/201311131356_IDEMPIERE-1530.sql b/migration/i1.0c/postgresql/201311131356_IDEMPIERE-1530.sql new file mode 100644 index 0000000000..c17e8d25ee --- /dev/null +++ b/migration/i1.0c/postgresql/201311131356_IDEMPIERE-1530.sql @@ -0,0 +1,21 @@ +-- Nov 13, 2013 5:26:33 PM MYT +-- Make validation of purchase order quantity against invoice and receipt quantity optional +INSERT INTO AD_SysConfig (AD_SysConfig_ID,ConfigurationLevel,Value,Description,AD_SysConfig_UU,Created,Updated,AD_Org_ID,CreatedBy,IsActive,UpdatedBy,Name,AD_Client_ID,EntityType) VALUES (200039,'C','Y','Set this to false (N) to allow material receipt and invoice with quantity more than purchase order quantity.','f473c472-1285-4936-8bb8-2f36f68de12e',TO_TIMESTAMP('2013-11-13 17:26:26','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2013-11-13 17:26:26','YYYY-MM-DD HH24:MI:SS'),0,100,'Y',100,'VALIDATE_MATCHING_TO_ORDERED_QTY',0,'D') +; + +-- Nov 13, 2013 7:44:29 PM MYT +-- Make validation of purchase order quantity against invoice and receipt quantity optional +INSERT INTO AD_Element (ColumnName,AD_Element_ID,Help,Name,Description,PrintName,AD_Element_UU,Created,Updated,CreatedBy,AD_Org_ID,UpdatedBy,IsActive,AD_Client_ID,EntityType) VALUES ('QtyOverReceipt',202627,'Calculated: Receipt - ordered quantity','Over Receipt','Over Receipt Quantity','Over Receipt','6872e34a-74bc-4590-b8e3-da15b6d365ba',TO_TIMESTAMP('2013-11-13 19:44:25','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2013-11-13 19:44:25','YYYY-MM-DD HH24:MI:SS'),100,0,100,'Y',0,'D') +; + +-- Nov 13, 2013 7:45:25 PM MYT +INSERT INTO AD_Column (SeqNoSelection,IsSyncDatabase,Version,AD_Table_ID,AD_Column_ID,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsParent,FieldLength,IsSelectionColumn,AD_Reference_ID,IsKey,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsUpdateable,ColumnName,Description,DefaultValue,Help,Name,IsAllowCopy,Updated,CreatedBy,AD_Org_ID,IsActive,Created,UpdatedBy,IsToolbarButton,IsAlwaysUpdateable,AD_Client_ID,EntityType,IsEncrypted,AD_Element_ID,IsSecure) VALUES (0,'N',1,320,210888,'N','N','N',0,'N',22,'N',29,'N','N','Y','8a1f15d1-412e-464e-9797-b547a152b54b','Y','QtyOverReceipt','Over Receipt Quantity','0','Calculated: Receipt - ordered quantity','Over Receipt','N',TO_TIMESTAMP('2013-11-13 19:45:22','YYYY-MM-DD HH24:MI:SS'),100,0,'Y',TO_TIMESTAMP('2013-11-13 19:45:22','YYYY-MM-DD HH24:MI:SS'),100,'N','N',0,'D','N',202627,'N') +; + +-- Nov 13, 2013 7:45:55 PM MYT +ALTER TABLE M_InOutLine ADD COLUMN QtyOverReceipt NUMERIC DEFAULT 0 +; + +SELECT register_migration_script('201311131356_IDEMPIERE-1530.sql') FROM dual +; + diff --git a/org.adempiere.base/src/org/compiere/model/I_M_InOutLine.java b/org.adempiere.base/src/org/compiere/model/I_M_InOutLine.java index 4b555d9c22..ed764d7c6d 100644 --- a/org.adempiere.base/src/org/compiere/model/I_M_InOutLine.java +++ b/org.adempiere.base/src/org/compiere/model/I_M_InOutLine.java @@ -434,6 +434,19 @@ public interface I_M_InOutLine */ public BigDecimal getQtyEntered(); + /** Column name QtyOverReceipt */ + public static final String COLUMNNAME_QtyOverReceipt = "QtyOverReceipt"; + + /** Set Over Receipt. + * Over Receipt Quantity + */ + public void setQtyOverReceipt (BigDecimal QtyOverReceipt); + + /** Get Over Receipt. + * Over Receipt Quantity + */ + public BigDecimal getQtyOverReceipt(); + /** Column name Ref_InOutLine_ID */ public static final String COLUMNNAME_Ref_InOutLine_ID = "Ref_InOutLine_ID"; diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 7f154cb003..d68b400cdc 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -758,6 +758,10 @@ public class MInOut extends X_M_InOut implements DocAction line.setM_RMALine_ID(peer.getRef_RMALine_ID()); } } + else if (!isSOTrx()) + { + line.setQtyOverReceipt(fromLine.getQtyOverReceipt()); + } // line.setProcessed(false); if (line.save(get_TrxName())) @@ -1287,7 +1291,6 @@ public class MInOut extends X_M_InOut implements DocAction if (MovementType.charAt(1) == '-') // C- Customer Shipment - V- Vendor Return Qty = Qty.negate(); BigDecimal QtySO = Env.ZERO; - BigDecimal QtyPO = Env.ZERO; // Update Order Line MOrderLine oLine = null; @@ -1298,8 +1301,6 @@ public class MInOut extends X_M_InOut implements DocAction + ", Delivered=" + oLine.getQtyDelivered()); if (isSOTrx()) QtySO = sLine.getMovementQty(); - else - QtyPO = sLine.getMovementQty(); } @@ -1334,6 +1335,27 @@ public class MInOut extends X_M_InOut implements DocAction sameWarehouse = oLine.getM_Warehouse_ID()==getM_Warehouse_ID(); } // + BigDecimal overReceipt = BigDecimal.ZERO; + if (!isSOTrx()) + { + if (!isReversal()) + { + BigDecimal toDelivered = oLine.getQtyOrdered().subtract(oLine.getQtyDelivered()); + if (sLine.getMovementQty().compareTo(toDelivered) > 0) + overReceipt = sLine.getMovementQty().subtract(toDelivered); + if (overReceipt.signum() != 0) + { + sLine.setQtyOverReceipt(overReceipt); + sLine.saveEx(); + } + } + else + { + overReceipt = sLine.getQtyOverReceipt(); + } + } + BigDecimal orderedQtyToUpdate = sLine.getMovementQty().subtract(overReceipt); + // if (sLine.getM_AttributeSetInstance_ID() == 0) { MInOutLineMA mas[] = MInOutLineMA.get(getCtx(), @@ -1349,9 +1371,22 @@ public class MInOut extends X_M_InOut implements DocAction if (sLine.getC_OrderLine_ID() != 0) { if (isSOTrx()) + { reservedDiff = ma.getMovementQty().negate(); + } else - orderedDiff = ma.getMovementQty().negate(); + { + if (ma.getMovementQty().compareTo(orderedQtyToUpdate) >= 0) + { + orderedQtyToUpdate = orderedQtyToUpdate.subtract(ma.getMovementQty()); + orderedDiff = ma.getMovementQty().negate(); + } + else + { + orderedDiff = orderedQtyToUpdate.negate(); + orderedQtyToUpdate = BigDecimal.ZERO; + } + } } // Update Storage - see also VMatch.createMatchRecord @@ -1435,7 +1470,7 @@ public class MInOut extends X_M_InOut implements DocAction if (mtrx == null) { BigDecimal reservedDiff = sameWarehouse ? QtySO.negate() : Env.ZERO; - BigDecimal orderedDiff = sameWarehouse ? QtyPO.negate(): Env.ZERO; + BigDecimal orderedDiff = sameWarehouse ? orderedQtyToUpdate.negate(): Env.ZERO; // Fallback: Update Storage - see also VMatch.createMatchRecord if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(), @@ -1482,11 +1517,11 @@ public class MInOut extends X_M_InOut implements DocAction return DocAction.STATUS_Invalid; } } - if (QtyPO.signum() != 0) { + if (orderedQtyToUpdate.signum() != 0) { if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(), sLine.getM_Product_ID(), sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID, - QtyPO.negate(), false, get_TrxName())) + orderedQtyToUpdate.negate(), false, get_TrxName())) { m_processMsg = "Cannot correct Inventory Ordered [" + product.getValue() + "]"; return DocAction.STATUS_Invalid; @@ -1509,7 +1544,12 @@ public class MInOut extends X_M_InOut implements DocAction // Correct Order Line if (product != null && oLine != null) // other in VMatch.createMatchRecord - oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty())); + { + if (isSOTrx()) + oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty())); + else + oLine.setQtyReserved(oLine.getQtyReserved().subtract(sLine.getMovementQty().subtract(sLine.getQtyOverReceipt()))); + } // Update Sales Order Line if (oLine != null) @@ -2174,6 +2214,7 @@ public class MInOut extends X_M_InOut implements DocAction MInOutLine rLine = rLines[i]; rLine.setQtyEntered(rLine.getQtyEntered().negate()); rLine.setMovementQty(rLine.getMovementQty().negate()); + rLine.setQtyOverReceipt(rLine.getQtyOverReceipt().negate()); rLine.setM_AttributeSetInstance_ID(sLines[i].getM_AttributeSetInstance_ID()); // Goodwill: store original (voided/reversed) document line rLine.setReversalLine_ID(sLines[i].getM_InOutLine_ID()); diff --git a/org.adempiere.base/src/org/compiere/model/MMatchPO.java b/org.adempiere.base/src/org/compiere/model/MMatchPO.java index 7c25af7b5d..0cd62f966e 100644 --- a/org.adempiere.base/src/org/compiere/model/MMatchPO.java +++ b/org.adempiere.base/src/org/compiere/model/MMatchPO.java @@ -911,17 +911,21 @@ public class MMatchPO extends X_M_MatchPO if (getC_OrderLine_ID() > 0) { - MOrderLine line = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName()); - BigDecimal invoicedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID > 0 and C_OrderLine_ID=?" , getC_OrderLine_ID()); - if (invoicedQty != null && invoicedQty.compareTo(line.getQtyOrdered()) > 0) + boolean validateOrderedQty = MSysConfig.getBooleanValue(MSysConfig.VALIDATE_MATCHING_TO_ORDERED_QTY, true, Env.getAD_Client_ID(Env.getCtx())); + if (validateOrderedQty) { - throw new IllegalStateException("Total matched invoiced qty > ordered qty. MatchedInvoicedQty="+invoicedQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line); - } - - BigDecimal deliveredQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE M_InOutLine_ID > 0 and C_OrderLine_ID=?" , getC_OrderLine_ID()); - if (deliveredQty != null && deliveredQty.compareTo(line.getQtyOrdered()) > 0) - { - throw new IllegalStateException("Total matched delivered qty > ordered qty. MatchedDeliveredQty="+deliveredQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line); + MOrderLine line = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName()); + BigDecimal invoicedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID > 0 and C_OrderLine_ID=?" , getC_OrderLine_ID()); + if (invoicedQty != null && invoicedQty.compareTo(line.getQtyOrdered()) > 0) + { + throw new IllegalStateException("Total matched invoiced qty > ordered qty. MatchedInvoicedQty="+invoicedQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line); + } + + BigDecimal deliveredQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE M_InOutLine_ID > 0 and C_OrderLine_ID=?" , getC_OrderLine_ID()); + if (deliveredQty != null && deliveredQty.compareTo(line.getQtyOrdered()) > 0) + { + throw new IllegalStateException("Total matched delivered qty > ordered qty. MatchedDeliveredQty="+deliveredQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line); + } } } } diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index 715871b255..b4dffa697d 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -118,6 +118,7 @@ public class MSysConfig extends X_AD_SysConfig public static final String ZK_MAX_UPLOAD_SIZE = "ZK_MAX_UPLOAD_SIZE"; public static final String CALENDAR_ALTERNATE_TIMEZONE = "CALENDAR_ALTERNATE_TIMEZONE"; public static final String ZK_REPORT_JASPER_OUTPUT_TYPE = "ZK_REPORT_JASPER_OUTPUT_TYPE"; + public static final String VALIDATE_MATCHING_TO_ORDERED_QTY = "VALIDATE_MATCHING_TO_ORDERED_QTY"; /** * Standard Constructor diff --git a/org.adempiere.base/src/org/compiere/model/X_M_InOutLine.java b/org.adempiere.base/src/org/compiere/model/X_M_InOutLine.java index e46aee3bdf..2dfc258e64 100644 --- a/org.adempiere.base/src/org/compiere/model/X_M_InOutLine.java +++ b/org.adempiere.base/src/org/compiere/model/X_M_InOutLine.java @@ -32,7 +32,7 @@ public class X_M_InOutLine extends PO implements I_M_InOutLine, I_Persistent /** * */ - private static final long serialVersionUID = 20130626L; + private static final long serialVersionUID = 20131113L; /** Standard Constructor */ public X_M_InOutLine (Properties ctx, int M_InOutLine_ID, String trxName) @@ -704,6 +704,26 @@ public class X_M_InOutLine extends PO implements I_M_InOutLine, I_Persistent return bd; } + /** Set Over Receipt. + @param QtyOverReceipt + Over Receipt Quantity + */ + public void setQtyOverReceipt (BigDecimal QtyOverReceipt) + { + set_Value (COLUMNNAME_QtyOverReceipt, QtyOverReceipt); + } + + /** Get Over Receipt. + @return Over Receipt Quantity + */ + public BigDecimal getQtyOverReceipt () + { + BigDecimal bd = (BigDecimal)get_Value(COLUMNNAME_QtyOverReceipt); + if (bd == null) + return Env.ZERO; + return bd; + } + /** Set Referenced Shipment Line. @param Ref_InOutLine_ID Referenced Shipment Line */ public void setRef_InOutLine_ID (int Ref_InOutLine_ID) From b9c3f19c841d5b194897924d30e36f6b3cf6121f Mon Sep 17 00:00:00 2001 From: Elaine Tan Date: Thu, 14 Nov 2013 12:39:44 +0800 Subject: [PATCH 2/3] Support "trim" attribute at the element. It is an optional attribute and is defaulted to true (i.e. trimmable). --- .../src/org/adempiere/pipo2/PackInHandler.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/org.adempiere.pipo/src/org/adempiere/pipo2/PackInHandler.java b/org.adempiere.pipo/src/org/adempiere/pipo2/PackInHandler.java index 0b2cfa5381..07cbe8593e 100644 --- a/org.adempiere.pipo/src/org/adempiere/pipo2/PackInHandler.java +++ b/org.adempiere.pipo/src/org/adempiere/pipo2/PackInHandler.java @@ -301,8 +301,12 @@ public class PackInHandler extends DefaultHandler { { if (e.contents.toString().length() != e.contents.toString().trim().length()) { - String s = e.contents.toString().trim(); - e.contents = new StringBuffer(s); + String trim = e.attributes.getValue("trim"); + if (!(trim != null && trim.equals("false"))) + { + String s = e.contents.toString().trim(); + e.contents = new StringBuffer(s); + } } } if (stack.isEmpty()) From 0a29fdcae05457ede19dcd1ffcd5d2b33455857d Mon Sep 17 00:00:00 2001 From: Heng Sin Low Date: Thu, 14 Nov 2013 14:50:35 +0800 Subject: [PATCH 3/3] 1003475 IDEMPIERE-1530 Allow Material Receipt Line with Quantity Receipt more then Purchase Order Line's Quantity Ordered. Move migration script from i1.0c to i2.0 since i1.0c is closed. --- migration/{i1.0c => i2.0}/oracle/201311131356_IDEMPIERE-1530.sql | 0 .../{i1.0c => i2.0}/postgresql/201311131356_IDEMPIERE-1530.sql | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename migration/{i1.0c => i2.0}/oracle/201311131356_IDEMPIERE-1530.sql (100%) rename migration/{i1.0c => i2.0}/postgresql/201311131356_IDEMPIERE-1530.sql (100%) diff --git a/migration/i1.0c/oracle/201311131356_IDEMPIERE-1530.sql b/migration/i2.0/oracle/201311131356_IDEMPIERE-1530.sql similarity index 100% rename from migration/i1.0c/oracle/201311131356_IDEMPIERE-1530.sql rename to migration/i2.0/oracle/201311131356_IDEMPIERE-1530.sql diff --git a/migration/i1.0c/postgresql/201311131356_IDEMPIERE-1530.sql b/migration/i2.0/postgresql/201311131356_IDEMPIERE-1530.sql similarity index 100% rename from migration/i1.0c/postgresql/201311131356_IDEMPIERE-1530.sql rename to migration/i2.0/postgresql/201311131356_IDEMPIERE-1530.sql