diff --git a/migration/i1.0a-release/oracle/201303061816_TICKET-1002354.sql b/migration/i1.0a-release/oracle/201303061816_TICKET-1002354.sql new file mode 100644 index 0000000000..bdcf041bf7 --- /dev/null +++ b/migration/i1.0a-release/oracle/201303061816_TICKET-1002354.sql @@ -0,0 +1,22 @@ +-- Mar 6, 2013 5:52:10 PM SGT +-- Ticket 1002354: Price List Enhancement +INSERT INTO AD_Ref_List (AD_Client_ID,AD_Ref_List_ID,AD_Reference_ID,EntityType,Name,AD_Ref_List_UU,Value,CreatedBy,Created,Updated,UpdatedBy,IsActive,AD_Org_ID) VALUES (0,200134,194,'D','Product Cost','ee848c2c-1648-441e-a33a-c064e6fb0203','P',100,TO_DATE('2013-03-06 17:52:08','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2013-03-06 17:52:08','YYYY-MM-DD HH24:MI:SS'),100,'Y',0) +; + +-- Mar 6, 2013 5:52:11 PM SGT +-- Ticket 1002354: Price List Enhancement +INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy,AD_Ref_List_Trl_UU ) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy,Generate_UUID() FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=200134 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID) +; + +-- Mar 6, 2013 7:08:02 PM SGT +-- Ticket 1002354: Price List Enhancement +INSERT INTO AD_ModelValidator (SeqNo,AD_ModelValidator_ID,Help,ModelValidationClass,EntityType,Description,Name,AD_ModelValidator_UU,AD_Client_ID,AD_Org_ID,Created,CreatedBy,Updated,UpdatedBy,IsActive) VALUES (0,200002,'Auto sync corresponding price list with the base price list','org.adempiere.model.ProductPriceValidator','D','Product Price','Model Validator to Product Price','cc9a0a8e-8749-45be-a38d-61e9e61aab3d',0,0,TO_DATE('2013-03-06 19:07:59','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2013-03-06 19:07:59','YYYY-MM-DD HH24:MI:SS'),100,'N') +; + +-- Mar 6, 2013 7:08:42 PM SGT +-- Ticket 1002354: Price List Enhancement +UPDATE AD_ModelValidator SET SeqNo=1,Updated=TO_DATE('2013-03-06 19:08:42','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_ModelValidator_ID=200002 +; + +SELECT register_migration_script('201303061816_TICKET-1002354.sql') FROM dual +; diff --git a/migration/i1.0a-release/postgresql/201303061816_TICKET-1002354.sql b/migration/i1.0a-release/postgresql/201303061816_TICKET-1002354.sql new file mode 100644 index 0000000000..62bff2228a --- /dev/null +++ b/migration/i1.0a-release/postgresql/201303061816_TICKET-1002354.sql @@ -0,0 +1,22 @@ +-- Mar 6, 2013 5:52:10 PM SGT +-- Ticket 1002354: Price List Enhancement +INSERT INTO AD_Ref_List (AD_Client_ID,AD_Ref_List_ID,AD_Reference_ID,EntityType,Name,AD_Ref_List_UU,Value,CreatedBy,Created,Updated,UpdatedBy,IsActive,AD_Org_ID) VALUES (0,200134,194,'D','Product Cost','ee848c2c-1648-441e-a33a-c064e6fb0203','P',100,TO_TIMESTAMP('2013-03-06 17:52:08','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2013-03-06 17:52:08','YYYY-MM-DD HH24:MI:SS'),100,'Y',0) +; + +-- Mar 6, 2013 5:52:11 PM SGT +-- Ticket 1002354: Price List Enhancement +INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy,AD_Ref_List_Trl_UU ) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy,Generate_UUID() FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=200134 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID) +; + +-- Mar 6, 2013 7:08:02 PM SGT +-- Ticket 1002354: Price List Enhancement +INSERT INTO AD_ModelValidator (SeqNo,AD_ModelValidator_ID,Help,ModelValidationClass,EntityType,Description,Name,AD_ModelValidator_UU,AD_Client_ID,AD_Org_ID,Created,CreatedBy,Updated,UpdatedBy,IsActive) VALUES (0,200002,'Auto sync corresponding price list with the base price list','org.adempiere.model.ProductPriceValidator','D','Product Price','Model Validator to Product Price','cc9a0a8e-8749-45be-a38d-61e9e61aab3d',0,0,TO_TIMESTAMP('2013-03-06 19:07:59','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2013-03-06 19:07:59','YYYY-MM-DD HH24:MI:SS'),100,'N') +; + +-- Mar 6, 2013 7:08:42 PM SGT +-- Ticket 1002354: Price List Enhancement +UPDATE AD_ModelValidator SET SeqNo=1,Updated=TO_TIMESTAMP('2013-03-06 19:08:42','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_ModelValidator_ID=200002 +; + +SELECT register_migration_script('201303061816_TICKET-1002354.sql') FROM dual +; diff --git a/org.adempiere.base.process/src/org/compiere/process/M_PriceList_Create.java b/org.adempiere.base.process/src/org/compiere/process/M_PriceList_Create.java index 352bbb82da..422d5f8b4a 100644 --- a/org.adempiere.base.process/src/org/compiere/process/M_PriceList_Create.java +++ b/org.adempiere.base.process/src/org/compiere/process/M_PriceList_Create.java @@ -19,6 +19,7 @@ package org.compiere.process; +import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -27,6 +28,12 @@ import java.util.Iterator; import java.util.Vector; import java.util.logging.Level; +import org.compiere.model.MAcctSchema; +import org.compiere.model.MClientInfo; +import org.compiere.model.MDiscountSchemaLine; +import org.compiere.model.MProduct; +import org.compiere.model.MProductPrice; +import org.compiere.model.ProductCost; import org.compiere.util.AdempiereSystemError; import org.compiere.util.AdempiereUserError; import org.compiere.util.CLogger; @@ -613,6 +620,75 @@ public class M_PriceList_Create extends SvrProcess { raiseError("Update M_ProductPrice ", sqlupd.toString()); totu += cntu; if (log.isLoggable(Level.FINE)) log.fine("Updated " + cntu); + + /** + * Product Cost overwrite + * Elaine 2009/12/24 + */ + if(rsDiscountLine.getString(MDiscountSchemaLine.COLUMNNAME_List_Base).equals(MDiscountSchemaLine.LIST_BASE_ProductCost) || + rsDiscountLine.getString(MDiscountSchemaLine.COLUMNNAME_Std_Base).equals(MDiscountSchemaLine.STD_BASE_ProductCost) || + rsDiscountLine.getString(MDiscountSchemaLine.COLUMNNAME_Limit_Base).equals(MDiscountSchemaLine.LIMIT_BASE_ProductCost)) + { + MClientInfo m_clientInfo = MClientInfo.get(getCtx(), rsCurgen.getInt("AD_Client_ID"), get_TrxName()); + MAcctSchema as = new MAcctSchema(getCtx(), m_clientInfo.getC_AcctSchema1_ID(), get_TrxName()); + + StringBuilder sqlpc = new StringBuilder("SELECT p.M_Product_ID "); + sqlpc.append(" FROM M_ProductPrice p"); + sqlpc.append(" WHERE M_PriceList_Version_ID=").append(p_PriceList_Version_ID); + sqlpc.append(" AND EXISTS (SELECT * FROM T_Selection s"); + sqlpc.append(" WHERE s.T_Selection_ID=p.M_Product_ID"); + sqlpc.append(" AND s.AD_PInstance_ID=").append(m_AD_PInstance_ID + ")"); + + PreparedStatement ps = DB.prepareStatement(sqlpc.toString(), get_TrxName()); + ResultSet rs = ps.executeQuery(); + while(rs.next()) + { + int M_Product_ID = rs.getInt(MProductPrice.COLUMNNAME_M_Product_ID); + ProductCost m_productCost = new ProductCost (getCtx(), M_Product_ID, 0, get_TrxName()); + m_productCost.setQty(BigDecimal.ONE); + BigDecimal costs = m_productCost.getProductCosts(as, rsCurgen.getInt("AD_Org_ID"), null, 0, false); + + if (costs == null || costs.signum() == 0) // zero costs OK + { + MProduct product = new MProduct(getCtx(), M_Product_ID, get_TrxName()); + if (product.isStocked()) + log.log(Level.WARNING, "No Costs for " + product.getName()); + } + else + { + sqlupd = new StringBuilder("UPDATE M_ProductPrice p "); + sqlupd.append(" SET PriceList = (DECODE('").append(rsDiscountLine.getString(MDiscountSchemaLine.COLUMNNAME_List_Base)).append("', 'P', ?, PriceList) + ?) * (1 - ?/100), "); + sqlupd.append(" PriceStd = (DECODE('").append(rsDiscountLine.getString(MDiscountSchemaLine.COLUMNNAME_Std_Base)).append("', 'P', ?, PriceStd) + ?) * (1 - ?/100),"); + sqlupd.append(" PriceLimit = (DECODE('").append(rsDiscountLine.getString(MDiscountSchemaLine.COLUMNNAME_Limit_Base)).append("', 'P', ?, PriceLimit) + ?) * (1 - ?/100)"); + sqlupd.append(" WHERE M_PriceList_Version_ID=").append(p_PriceList_Version_ID); + sqlupd.append(" AND M_Product_ID = ?"); + sqlupd.append(" AND EXISTS (SELECT * FROM T_Selection s"); + sqlupd.append(" WHERE s.T_Selection_ID=p.M_Product_ID"); + sqlupd.append(" AND s.AD_PInstance_ID=").append(m_AD_PInstance_ID + ")"); + + pstmu = DB.prepareStatement(sqlupd.toString(), + ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_UPDATABLE, get_TrxName()); + + pstmu.setBigDecimal(1, costs); + pstmu.setDouble(2, rsDiscountLine.getDouble(MDiscountSchemaLine.COLUMNNAME_List_AddAmt)); + pstmu.setDouble(3, rsDiscountLine.getDouble(MDiscountSchemaLine.COLUMNNAME_List_Discount)); + pstmu.setBigDecimal(4, costs); + pstmu.setDouble(5, rsDiscountLine.getDouble(MDiscountSchemaLine.COLUMNNAME_Std_AddAmt)); + pstmu.setDouble(6, rsDiscountLine.getDouble(MDiscountSchemaLine.COLUMNNAME_Std_Discount)); + pstmu.setBigDecimal(7, costs); + pstmu.setDouble(8, rsDiscountLine.getDouble(MDiscountSchemaLine.COLUMNNAME_Limit_AddAmt)); + pstmu.setDouble(9, rsDiscountLine.getDouble(MDiscountSchemaLine.COLUMNNAME_Limit_Discount)); + pstmu.setInt(10, M_Product_ID); + + cntu = pstmu.executeUpdate(); + + if (cntu == -1) + raiseError("Update M_ProductPrice ", sqlupd.toString()); + if (log.isLoggable(Level.FINE)) log.fine("Updated " + cntu); + } + } + } // //Rounding (AD_Reference_ID=155) diff --git a/org.adempiere.base/src/org/adempiere/model/ProductPriceValidator.java b/org.adempiere.base/src/org/adempiere/model/ProductPriceValidator.java new file mode 100644 index 0000000000..fad0de8a46 --- /dev/null +++ b/org.adempiere.base/src/org/adempiere/model/ProductPriceValidator.java @@ -0,0 +1,140 @@ +/****************************************************************************** + * Copyright (C) 2013 Elaine Tan * + * Copyright (C) 2013 Trek Global * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. 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., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + *****************************************************************************/ +package org.adempiere.model; + +import java.math.BigDecimal; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.logging.Level; + +import org.compiere.model.MClient; +import org.compiere.model.MPriceListVersion; +import org.compiere.model.MProductPrice; +import org.compiere.model.ModelValidationEngine; +import org.compiere.model.ModelValidator; +import org.compiere.model.PO; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; + +/** + * Auto sync corresponding price list with the price list schema and base price list. + * @author Elaine + * + */ +public class ProductPriceValidator implements ModelValidator { + + private static CLogger log = CLogger.getCLogger(ProductPriceValidator.class); + private int m_AD_Client_ID; + + public int getAD_Client_ID() { + return m_AD_Client_ID; + } + + public void initialize(ModelValidationEngine engine, MClient client) { + engine.addModelChange(MProductPrice.Table_Name, this); + if (client != null) + m_AD_Client_ID = client.getAD_Client_ID(); + } + + public String login(int AD_Org_ID, int AD_Role_ID, int AD_User_ID) { + return null; + } + + public String modelChange(PO po, int type) throws Exception { + if (po instanceof MProductPrice) { + if (type == TYPE_AFTER_CHANGE || type == TYPE_AFTER_NEW || type == TYPE_AFTER_DELETE) { + MProductPrice pp = (MProductPrice) po; + + int M_PriceList_Version_ID = pp.getM_PriceList_Version_ID(); + if(M_PriceList_Version_ID > 0) + { + MPriceListVersion plv = new MPriceListVersion(Env.getCtx(), M_PriceList_Version_ID, null); + int M_Pricelist_Version_Base_ID = plv.getM_Pricelist_Version_Base_ID(); + + if(M_Pricelist_Version_Base_ID > 0) // base price list + { + int M_Product_ID = pp.getM_Product_ID(); + BigDecimal priceLimit = pp.getPriceLimit(); + BigDecimal priceList = pp.getPriceList(); + BigDecimal priceStd = pp.getPriceStd(); + boolean isActive = pp.isActive(); + + StringBuilder sql = new StringBuilder(); + sql.append("SELECT * FROM M_PriceList_Version "); + sql.append("WHERE IsActive = 'Y' AND AD_Client_ID = ? "); + sql.append("AND M_DiscountSchema_ID = ? "); // match price list schema + sql.append("AND M_Pricelist_Version_Base_ID = ? "); // match base price list + sql.append("AND M_PriceList_Version_ID <> ? "); + + PreparedStatement pstmt = null; + ResultSet rs = null; + try + { + pstmt = DB.prepareStatement(sql.toString(), po.get_TrxName()); + int count = 1; + pstmt.setInt(count++, Env.getAD_Client_ID(Env.getCtx())); + pstmt.setInt(count++, plv.getM_DiscountSchema_ID()); + pstmt.setInt(count++, M_Pricelist_Version_Base_ID); + pstmt.setInt(count++, M_PriceList_Version_ID); + + rs = pstmt.executeQuery(); + while (rs.next()) + { + MPriceListVersion plv1 = new MPriceListVersion(Env.getCtx(), rs, po.get_TrxName()); + MProductPrice pp1 = MProductPrice.get(Env.getCtx(), plv1.getM_PriceList_Version_ID(), M_Product_ID, po.get_TrxName()); + + if (type == TYPE_AFTER_CHANGE || type == TYPE_AFTER_NEW) + { + if(pp1 == null) + pp1 = new MProductPrice(Env.getCtx(), plv1.getM_PriceList_Version_ID(), M_Product_ID, po.get_TrxName()); + + if(priceList.compareTo(pp1.getPriceList()) != 0 + || priceStd.compareTo(pp1.getPriceStd()) != 0 + || priceLimit.compareTo(pp1.getPriceLimit()) != 0 + || isActive != pp1.isActive()) + { + pp1.setPrices(priceList, priceStd, priceLimit); + pp1.setIsActive(isActive); + pp1.save(po.get_TrxName()); + } + } + else if (type == TYPE_AFTER_DELETE) + { + if(pp1 != null) + pp1.delete(false, po.get_TrxName()); + } + } + } + catch (SQLException ex) + { + log.log(Level.SEVERE, sql.toString(), ex); + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + } + } + } + } + return null; + } + + public String docValidate(PO po, int timing) { + return null; + } +} \ No newline at end of file diff --git a/org.adempiere.base/src/org/compiere/model/X_M_DiscountSchemaLine.java b/org.adempiere.base/src/org/compiere/model/X_M_DiscountSchemaLine.java index ce2fdaeaad..df91111f55 100644 --- a/org.adempiere.base/src/org/compiere/model/X_M_DiscountSchemaLine.java +++ b/org.adempiere.base/src/org/compiere/model/X_M_DiscountSchemaLine.java @@ -33,7 +33,7 @@ public class X_M_DiscountSchemaLine extends PO implements I_M_DiscountSchemaLine /** * */ - private static final long serialVersionUID = 20121031L; + private static final long serialVersionUID = 20130306L; /** Standard Constructor */ public X_M_DiscountSchemaLine (Properties ctx, int M_DiscountSchemaLine_ID, String trxName) @@ -251,6 +251,8 @@ public class X_M_DiscountSchemaLine extends PO implements I_M_DiscountSchemaLine public static final String LIMIT_BASE_LimitPOPrice = "X"; /** Fixed Price = F */ public static final String LIMIT_BASE_FixedPrice = "F"; + /** Product Cost = P */ + public static final String LIMIT_BASE_ProductCost = "P"; /** Set Limit price Base. @param Limit_Base Base price for calculation of the new price @@ -415,6 +417,8 @@ public class X_M_DiscountSchemaLine extends PO implements I_M_DiscountSchemaLine public static final String LIST_BASE_LimitPOPrice = "X"; /** Fixed Price = F */ public static final String LIST_BASE_FixedPrice = "F"; + /** Product Cost = P */ + public static final String LIST_BASE_ProductCost = "P"; /** Set List price Base. @param List_Base Price used as the basis for price list calculations @@ -728,6 +732,8 @@ public class X_M_DiscountSchemaLine extends PO implements I_M_DiscountSchemaLine public static final String STD_BASE_LimitPOPrice = "X"; /** Fixed Price = F */ public static final String STD_BASE_FixedPrice = "F"; + /** Product Cost = P */ + public static final String STD_BASE_ProductCost = "P"; /** Set Standard price Base. @param Std_Base Base price for calculating new standard price