/** * Contains the code from the former jboss-aop aspect <code>de.metas.commission.aop.PriceListCreate * </code> * * @author ts * @task http://dewiki908/mediawiki/index.php/07286_get_rid_of_jboss-aop_for_good_%28104432455599%29 */ public class CommissionPlvCreationListener implements IPlvCreationListener { private static final Logger logger = LogManager.getLogger(CommissionPlvCreationListener.class); @Override public void onPlvCreation( final IContextAware ctxAware, final I_M_PriceList_Version targetPriceListVersion, final Iterator<I_M_ProductPrice> oldProductPrices, final org.compiere.model.I_M_DiscountSchemaLine dsl, final int adPinstanceId) { final I_M_DiscountSchemaLine dslToUse = InterfaceWrapperHelper.create(dsl, I_M_DiscountSchemaLine.class); if (targetPriceListVersion.getM_Pricelist_Version_Base_ID() == 0) { logger.info(targetPriceListVersion + " has M_Pricelist_Version_Base_ID=0; nothing to do"); // process.addLog("Only working with base price list version"); return; } final IPriceListBL plBL = Services.get(IPriceListBL.class); final int plCountryId = InterfaceWrapperHelper.create(targetPriceListVersion.getM_PriceList(), I_M_PriceList.class) .getC_Country_ID(); if (plCountryId <= 0) { if (dslToUse.isCommissionPoints_SubtractVAT()) { logger.info( "Ignoriere '@" + I_M_DiscountSchemaLine.COLUMNNAME_CommissionPoints_SubtractVAT + "@' fuer Produktpreise, da in der Preisliste " + targetPriceListVersion.getM_PriceList().getName() + " kein Land vermerkt ist.\n"); } } final String trxName = ctxAware.getTrxName(); plBL.updateCommissionPoints(targetPriceListVersion, dslToUse, adPinstanceId, trxName); plBL.updateSalcePriceCommissionPoints(targetPriceListVersion, dslToUse, adPinstanceId, trxName); return; } /** * Returns <code>10</code>. * * <p>From the orginal jboss-aop.xml file. * * <pre> * Make sure that the commission aspect is called before the swat aspect. * The this means that the commission aspect will be called around the swat aspect (which in turn will be called around the joinpoint). * This further means that the commission aspect can work with the results created by the swat aspect. * </pre> */ @Override public int getExecutionOrderSeqNo() { return 10; } }
/** * Issue Project (and Asset Link) * * @author Jorg Janke * @version $Id: MIssueProject.java,v 1.2 2006/07/30 00:58:18 jjanke Exp $ */ public class MIssueProject extends X_R_IssueProject { /** */ private static final long serialVersionUID = -9115162283984109370L; /** * Get/Set Project * * @param issue issue * @return project */ public static MIssueProject get(MIssue issue) { if (issue.getName() == null) return null; MIssueProject pj = null; String sql = "SELECT * FROM R_IssueProject WHERE Name=?"; PreparedStatement pstmt = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setString(1, issue.getName()); ResultSet rs = pstmt.executeQuery(); if (rs.next()) pj = new MIssueProject(issue.getCtx(), rs, null); rs.close(); pstmt.close(); pstmt = null; } catch (Exception e) { s_log.error(sql, e); } try { if (pstmt != null) pstmt.close(); pstmt = null; } catch (Exception e) { pstmt = null; } // New if (pj == null) { pj = new MIssueProject(issue.getCtx(), 0, null); pj.setName(issue.getName()); pj.setA_Asset_ID(issue); } pj.setSystemStatus(issue.getSystemStatus()); pj.setStatisticsInfo(issue.getStatisticsInfo()); pj.setProfileInfo(issue.getProfileInfo()); if (!pj.save()) return null; // Set issue.setR_IssueProject_ID(pj.getR_IssueProject_ID()); if (pj.getA_Asset_ID() != 0) issue.setA_Asset_ID(pj.getA_Asset_ID()); return pj; } // get /** Logger */ private static Logger s_log = LogManager.getLogger(MIssueProject.class); /** * ************************************************************************ Standard Constructor * * @param ctx context * @param R_IssueProject_ID id * @param trxName trx */ public MIssueProject(Properties ctx, int R_IssueProject_ID, String trxName) { super(ctx, R_IssueProject_ID, trxName); } // MIssueProject /** * Load Constructor * * @param ctx context * @param rs result set * @param trxName trx */ public MIssueProject(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MIssueProject /** * Set A_Asset_ID * * @param issue issue */ public void setA_Asset_ID(MIssue issue) { int A_Asset_ID = 0; String sql = "SELECT * FROM A_Asset a " + "WHERE EXISTS (SELECT * FROM A_Asset_Group ag " // Tracking Assets + "WHERE a.A_Asset_Group_ID=ag.A_Asset_Group_ID AND ag.IsTrackIssues='Y')" + " AND EXISTS (SELECT * FROM AD_User u " + "WHERE (a.C_BPartner_ID=u.C_BPartner_ID OR a.C_BPartnerSR_ID=u.C_BPartner_ID)" + " AND u.EMail=?)" // #1 EMail + " AND (SerNo IS NULL OR SerNo=?)"; // #2 Name super.setA_Asset_ID(A_Asset_ID); } // setA_Asset_ID /** * String Representation * * @return info */ public String toString() { StringBuffer sb = new StringBuffer("MIssueProject["); sb.append(get_ID()) .append("-") .append(getName()) .append(",A_Asset_ID=") .append(getA_Asset_ID()) .append(",C_Project_ID=") .append(getC_Project_ID()) .append("]"); return sb.toString(); } // toString } // MIssueProject
public class C_Order implements ModelValidator { private static final Logger logger = LogManager.getLogger(C_OrderLine.class); private static final String MSG_ORDER_DATE_ORDERED_CHANGE_FORBIDDEN_1P = "Order_DateOrdered_Change_Forbidden"; private int m_AD_Client_ID = -1; @Override public int getAD_Client_ID() { return m_AD_Client_ID; } @Override public void initialize(final ModelValidationEngine engine, final MClient client) { if (client != null) m_AD_Client_ID = client.getAD_Client_ID(); engine.addModelChange(I_C_Order.Table_Name, this); engine.addDocValidate(I_C_Order.Table_Name, this); } @Override public String login(final int AD_Org_ID, final int AD_Role_ID, final int AD_User_ID) { return null; } @Override public String modelChange(final PO po, final int type) throws Exception { if (type == TYPE_BEFORE_CHANGE) { final I_C_Order order = InterfaceWrapperHelper.create(po, I_C_Order.class); if (po.is_ValueChanged(I_C_Invoice_Candidate.COLUMNNAME_DateOrdered)) { final IOrderPA orderPA = Services.get(IOrderPA.class); final IInvoiceCandDAO invoiceCandDB = Services.get(IInvoiceCandDAO.class); for (final I_C_OrderLine ol : orderPA.retrieveOrderLines(order, I_C_OrderLine.class)) { for (final I_C_Invoice_Candidate icOfOl : invoiceCandDB.retrieveReferencing(ol)) { if (icOfOl.isToClear()) { // If the column was updatable, we would have to // *check if new and old term are the same // *check if ICAs need update, creation or deletion and do it; // *check which dataEntries' ActualQty needs update and make sure that they are not // yet // completed // *check is isToClear needs update; throw new AdempiereException( Env.getAD_Language(po.getCtx()), MSG_ORDER_DATE_ORDERED_CHANGE_FORBIDDEN_1P, new Object[] {ol.getLine()}); } } } } } return null; } // Note: this code used to be located in // /sw01_swat_it/src/java/org/adempiere/order/subscription/modelvalidator/OrderValidator.java @Override public String docValidate(final PO po, final int timing) { if (timing != TIMING_AFTER_COMPLETE && timing != TIMING_AFTER_REACTIVATE) { return null; } final String trxName = po.get_TrxName(); final I_C_Order order = InterfaceWrapperHelper.create(po, I_C_Order.class); final IOrderPA orderPA = Services.get(IOrderPA.class); for (final I_C_OrderLine ol : orderPA.retrieveOrderLines(order, I_C_OrderLine.class)) { if (ol.getC_Flatrate_Conditions_ID() <= 0) { logger.debug("Order line " + ol + " has no subscription"); continue; } if (timing == TIMING_AFTER_COMPLETE) { handleOrderLineComplete(order, ol, trxName); } else if (timing == TIMING_AFTER_REACTIVATE) { handleOrderLineReactivate(ol, trxName); } } return null; } private void handleOrderLineComplete( final I_C_Order order, final I_C_OrderLine ol, final String trxName) { final ISubscriptionDAO subscriptionDAO = Services.get(ISubscriptionDAO.class); final I_C_Flatrate_Term existingSc = subscriptionDAO.retrieveTermForOl(ol); if (existingSc != null) { logger.debug("{} has already {}", ol, existingSc); return; } logger.info("Creating new {} entry", I_C_Flatrate_Term.Table_Name); // Note that order.getDocStatus() might still return 'IP' at this point final I_C_Flatrate_Term newSc = Services.get(ISubscriptionBL.class).createSubscriptionTerm(ol, true, order); Check.assume( X_C_Flatrate_Term.DOCSTATUS_Completed.equals(newSc.getDocStatus()), "{} has DocStatus={}", newSc, newSc.getDocStatus()); logger.info("Created and completed {}", newSc); } /** * Make sure the orderLine still has processed='Y', even if the order is reactivated. <br> * This was apparently added in task 03152.<br> * I can guess that if an order line already has a C_Flatrate_Term, then we don't want that order * line to be editable, because it could create inconsistencies with the term. * * @param ol * @param trxName */ private void handleOrderLineReactivate(final I_C_OrderLine ol, final String trxName) { logger.info( "Setting processed status of subscription order line " + ol + " back to Processed='Y'"); final String sql = "UPDATE C_OrderLine SET Processed='Y' WHERE C_OrderLine_ID=?"; final int no = DB.executeUpdateEx(sql, new Object[] {ol.getC_OrderLine_ID()}, trxName); logger.trace("Update result: " + no); } }
/** * Order Line Model. <code> * MOrderLine ol = new MOrderLine(m_order); * ol.setM_Product_ID(wbl.getM_Product_ID()); * ol.setQtyOrdered(wbl.getQuantity()); * ol.setPrice(); * ol.setPriceActual(wbl.getPrice()); * ol.setTax(); * ol.save(); * * </code> * * @author Jorg Janke * @version $Id: MOrderLine.java,v 1.6 2006/10/02 05:18:39 jjanke Exp $ * @author Teo Sarca, SC ARHIPAC SERVICE SRL * <ul> * <li>BF [ 2588043 ] Insufficient message ProductNotOnPriceList * @author Michael Judd, www.akunagroup.com * <ul> * <li>BF [ 1733602 ] Price List including Tax Error - when a user changes the orderline or * invoice line for a product on a price list that includes tax, the net amount is * incorrectly calculated. */ public class MOrderLine extends X_C_OrderLine { /** */ private static final long serialVersionUID = 7305265800857547603L; public static final String MSG_PriceListVersionInvalid = "PriceListVersionInvalid"; /** * Get Order Unreserved Qty * * @param ctx context * @param M_Warehouse_ID wh * @param M_Product_ID product * @param M_AttributeSetInstance_ID asi * @param excludeC_OrderLine_ID exclude C_OrderLine_ID * @return Unreserved Qty */ public static BigDecimal getNotReserved( Properties ctx, int M_Warehouse_ID, int M_Product_ID, int M_AttributeSetInstance_ID, int excludeC_OrderLine_ID) { BigDecimal retValue = Env.ZERO; String sql = "SELECT SUM(ol.QtyOrdered-ol.QtyDelivered-ol.QtyReserved) " + "FROM C_OrderLine ol" + " INNER JOIN C_Order o ON (ol.C_Order_ID=o.C_Order_ID) " + "WHERE ol.M_Warehouse_ID=?" // #1 // metas: adding table alias "ol" to M_Product_ID to distinguish it from C_Order's // M_Product_ID + " AND ol.M_Product_ID=?" // #2 + " AND o.IsSOTrx='Y' AND o.DocStatus='DR'" + " AND ol.QtyOrdered-ol.QtyDelivered-ol.QtyReserved<>0" + " AND ol.C_OrderLine_ID<>?"; if (M_AttributeSetInstance_ID != 0) sql += " AND ol.M_AttributeSetInstance_ID=?"; PreparedStatement pstmt = null; try { pstmt = DB.prepareStatement(sql, ITrx.TRXNAME_None); pstmt.setInt(1, M_Warehouse_ID); pstmt.setInt(2, M_Product_ID); pstmt.setInt(3, excludeC_OrderLine_ID); if (M_AttributeSetInstance_ID != 0) pstmt.setInt(4, M_AttributeSetInstance_ID); ResultSet rs = pstmt.executeQuery(); if (rs.next()) retValue = rs.getBigDecimal(1); rs.close(); pstmt.close(); pstmt = null; } catch (Exception e) { s_log.error(sql, e); } try { if (pstmt != null) pstmt.close(); pstmt = null; } catch (Exception e) { pstmt = null; } if (retValue == null) s_log.debug("-"); else s_log.debug(retValue.toString()); return retValue; } // getNotReserved /** Logger */ private static Logger s_log = LogManager.getLogger(MOrderLine.class); /** * ************************************************************************ Default Constructor * * @param ctx context * @param C_OrderLine_ID order line to load * @param trxName trx name */ public MOrderLine(Properties ctx, int C_OrderLine_ID, String trxName) { super(ctx, C_OrderLine_ID, trxName); if (C_OrderLine_ID == 0) { // setC_Order_ID (0); // setLine (0); // setM_Warehouse_ID (0); // @M_Warehouse_ID@ // setC_BPartner_ID(0); // setC_BPartner_Location_ID (0); // @C_BPartner_Location_ID@ // setC_Currency_ID (0); // @C_Currency_ID@ // setDateOrdered (new Timestamp(System.currentTimeMillis())); // @DateOrdered@ // // setC_Tax_ID (0); // setC_UOM_ID (0); // setFreightAmt(Env.ZERO); setLineNetAmt(Env.ZERO); // setPriceEntered(Env.ZERO); setPriceActual(Env.ZERO); setPriceLimit(Env.ZERO); setPriceList(Env.ZERO); // setM_AttributeSetInstance_ID(0); // setQtyEntered(Env.ZERO); setQtyOrdered(Env.ZERO); // 1 setQtyDelivered(Env.ZERO); setQtyInvoiced(Env.ZERO); // task 09358: get rid of this; instead, update qtyReserved at one central place // setQtyReserved(Env.ZERO); // setIsDescription(false); // N setProcessed(false); setLine(0); } } // MOrderLine /** * Parent Constructor. * * <ul> * <li>ol.setM_Product_ID(wbl.getM_Product_ID()); * <li>ol.setQtyOrdered(wbl.getQuantity()); * <li>ol.setPrice(); * <li>ol.setPriceActual(wbl.getPrice()); * <li>ol.setTax(); * <li>ol.save(); * * @param order parent order */ public MOrderLine(MOrder order) { this(order.getCtx(), 0, order.get_TrxName()); if (order.get_ID() == 0) throw new IllegalArgumentException("Header not saved"); setC_Order_ID(order.getC_Order_ID()); // parent setOrder(order); } // MOrderLine /** * Load Constructor * * @param ctx context * @param rs result set record * @param trxName transaction */ public MOrderLine(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MOrderLine private int m_M_PriceList_ID = 0; // private boolean m_IsSOTrx = true; // Product Pricing private MProductPricing m_productPrice = null; /** Tax */ private MTax m_tax = null; /** Cached Currency Precision */ private Integer m_precision = null; /** Product */ private MProduct m_product = null; /** Charge */ private MCharge m_charge = null; /** * Set Defaults from Order. Does not set Parent !! * * @param order order */ public void setOrder(MOrder order) { setClientOrg(order); final boolean isDropShip = order.isDropShip(); final int C_BPartner_ID = isDropShip && order.getDropShip_BPartner_ID() > 0 ? order.getDropShip_BPartner_ID() : order.getC_BPartner_ID(); setC_BPartner_ID(C_BPartner_ID); final int C_BPartner_Location_ID = isDropShip && order.getDropShip_Location_ID() > 0 ? order.getDropShip_Location_ID() : order.getC_BPartner_Location_ID(); setC_BPartner_Location_ID(C_BPartner_Location_ID); // metas: begin: copy AD_User_ID final de.metas.interfaces.I_C_OrderLine oline = InterfaceWrapperHelper.create(this, de.metas.interfaces.I_C_OrderLine.class); final int AD_User_ID = isDropShip && order.getDropShip_User_ID() > 0 ? order.getDropShip_User_ID() : order.getAD_User_ID(); oline.setAD_User_ID(AD_User_ID); // metas: end oline.setM_PriceList_Version_ID( 0); // the current PLV might be add or'd with the new order's PL. setM_Warehouse_ID(order.getM_Warehouse_ID()); setDateOrdered(order.getDateOrdered()); setDatePromised(order.getDatePromised()); setC_Currency_ID(order.getC_Currency_ID()); // setHeaderInfo(order); // sets m_order // Don't set Activity, etc as they are overwrites } // setOrder /** * Set Header Info * * @param order order */ public void setHeaderInfo(final MOrder order) { final IOrderBL orderBL = Services.get(IOrderBL.class); m_precision = orderBL.getPrecision(order); m_M_PriceList_ID = orderBL.retrievePriceListId(order); m_IsSOTrx = order.isSOTrx(); } // setHeaderInfo /** * Get Parent * * @return parent */ public MOrder getParent() { return LegacyAdapters.convertToPO(getC_Order()); } // getParent /** * Set Price Entered/Actual. Use this Method if the Line UOM is the Product UOM * * @param PriceActual price */ public void setPrice(BigDecimal PriceActual) { setPriceEntered(PriceActual); setPriceActual(PriceActual); } // setPrice /** * Set Price Actual. (actual price is not updateable) * * @param PriceActual actual price */ @Override public void setPriceActual(BigDecimal PriceActual) { if (PriceActual == null) throw new IllegalArgumentException("PriceActual is mandatory"); set_ValueNoCheck("PriceActual", PriceActual); } // setPriceActual /** * Set Price for Product and PriceList. Use only if newly created. Uses standard price list of not * set by order constructor */ public void setPrice() { if (getM_Product_ID() <= 0) return; if (m_M_PriceList_ID <= 0) { throw new AdempiereException( "@NotFound@ @M_Pricelist_ID@ @C_BPartner_ID@ " + getC_BPartner().getName()); } setPrice(m_M_PriceList_ID); } // setPrice /** * Set Price for Product and PriceList * * @param M_PriceList_ID price list */ public void setPrice(int M_PriceList_ID) { if (getM_Product_ID() <= 0) return; // final de.metas.interfaces.I_C_OrderLine ol = InterfaceWrapperHelper.create(this, de.metas.interfaces.I_C_OrderLine.class); Services.get(IOrderLineBL.class).updatePrices(ol); } // setPrice /** * Get and calculate Product Pricing * * @param M_PriceList_ID id * @param M_PriceList_Version_ID * @return product pricing */ private MProductPricing getProductPricing(int M_PriceList_ID, int M_PriceList_Version_ID) { final I_M_PriceList_Version plv = InterfaceWrapperHelper.create( getCtx(), M_PriceList_Version_ID, I_M_PriceList_Version.class, get_TrxName()); if (M_PriceList_Version_ID > 0) { // If we have a pricelist version, make sure it belongs to the pricelist Check.assume( M_PriceList_ID == plv.getM_PriceList_ID(), Msg.getMsg(getCtx(), MSG_PriceListVersionInvalid)); } m_productPrice = new MProductPricing(getM_Product_ID(), getC_BPartner_ID(), getQtyOrdered(), m_IsSOTrx); m_productPrice.setReferencedObject( this); // 03152: setting the 'ol' to allow the subscription system to compute the right // price m_productPrice.setPriceDate( getDatePromised()); // important: need to use the data when the service will be provided, so // we make sure that we get the right PLV m_productPrice.setM_PriceList_ID(M_PriceList_ID); m_productPrice.setPriceDate(getDateOrdered()); m_productPrice.setM_PriceList_Version_ID(M_PriceList_Version_ID); // m_productPrice.calculatePrice(); return m_productPrice; } // getProductPrice /** * Set Tax * * @return true if tax is set */ public boolean setTax() { // metas: we need to fetch the Tax based on pricing tax category and not directly // int ii = Tax.get(getCtx(), getM_Product_ID(), getC_Charge_ID(), getDateOrdered(), // getDateOrdered(), // getAD_Org_ID(), // Services.get(IWarehouseAdvisor.class).evaluateWarehouse(this).getM_Warehouse_ID(), // getC_BPartner_Location_ID(), // should be bill to // getC_BPartner_Location_ID(), m_IsSOTrx); final int taxCategoryId = Services.get(IOrderLineBL.class).getC_TaxCategory_ID(this); if (taxCategoryId <= 0) { log.error("No Tax Category found"); return false; } final I_M_Warehouse warehouse = Services.get(IWarehouseAdvisor.class).evaluateWarehouse(this); final I_C_Location locationFrom = Services.get(IWarehouseBL.class).getC_Location(warehouse); final int countryFromId = locationFrom.getC_Country_ID(); final int taxId = Services.get(ITaxBL.class) .retrieveTaxIdForCategory( getCtx(), countryFromId, getAD_Org_ID(), getC_BPartner_Location(), // should be bill to getDateOrdered(), taxCategoryId, m_IsSOTrx, get_TrxName(), true); // throwEx if (taxId <= 0) { log.error("No Tax found"); return false; } setC_Tax_ID(taxId); final I_C_Tax tax = InterfaceWrapperHelper.create(getCtx(), taxId, I_C_Tax.class, ITrx.TRXNAME_None); final I_C_TaxCategory taxCategory = tax.getC_TaxCategory(); setC_TaxCategory(taxCategory); return true; } // setTax /** Calculate Extended Amt. May or may not include tax */ public void setLineNetAmt() { BigDecimal bd = getPriceActual().multiply(getQtyOrdered()); // metas: tsa: begin: 01459 // Line Net Amt shall be zero if the line is not active if (!isActive()) { bd = Env.ZERO; } // metas: tsa: end: 01459 final boolean documentLevel = getTax().isDocumentLevel(); final boolean isTaxIncluded = Services.get(IOrderLineBL.class).isTaxIncluded(this); final int taxPrecision = Services.get(IOrderLineBL.class).getPrecision(this); // juddm: Tax Exempt & Tax Included in Price List & not Document Level - Adjust Line Amount // http://sourceforge.net/tracker/index.php?func=detail&aid=1733602&group_id=176962&atid=879332 if (isTaxIncluded && !documentLevel) { BigDecimal taxStdAmt = Env.ZERO, taxThisAmt = Env.ZERO; MTax orderTax = getTax(); MTax stdTax = null; // get the standard tax if (getProduct() == null) { if (getCharge() != null) // Charge { stdTax = new MTax( getCtx(), ((MTaxCategory) getCharge().getC_TaxCategory()).getDefaultTax().getC_Tax_ID(), get_TrxName()); } } else // Product { // FIXME metas 05129 need proper concept (link between M_Product and C_TaxCategory_ID was // removed!!!!!) throw new AdempiereException( "Unsupported tax calculation when tax is included, but it's not on document level"); // stdTax = new MTax (getCtx(), // ((MTaxCategory) getProduct().getC_TaxCategory()).getDefaultTax().getC_Tax_ID(), // get_TrxName()); } if (stdTax != null) { log.debug("stdTax rate is " + stdTax.getRate()); log.debug("orderTax rate is " + orderTax.getRate()); final ITaxBL taxBL = Services.get(ITaxBL.class); taxThisAmt = taxThisAmt.add(taxBL.calculateTax(orderTax, bd, isTaxIncluded, taxPrecision)); taxStdAmt = taxStdAmt.add(taxBL.calculateTax(stdTax, bd, isTaxIncluded, taxPrecision)); bd = bd.subtract(taxStdAmt).add(taxThisAmt); log.debug( "Price List includes Tax and Tax Changed on Order Line: New Tax Amt: " + taxThisAmt + " Standard Tax Amt: " + taxStdAmt + " Line Net Amt: " + bd); } } if (bd.scale() > taxPrecision) bd = bd.setScale(taxPrecision, BigDecimal.ROUND_HALF_UP); super.setLineNetAmt(bd); } // setLineNetAmt /** * Get Charge * * @return product or null */ public MCharge getCharge() { if (m_charge == null && getC_Charge_ID() != 0) m_charge = MCharge.get(getCtx(), getC_Charge_ID()); return m_charge; } /** * Get Tax * * @return tax */ protected MTax getTax() { if (m_tax == null) m_tax = MTax.get(getCtx(), getC_Tax_ID()); return m_tax; } // getTax /** * Get Currency Precision from Currency * * @return precision */ public int getPrecision() { if (m_precision != null) { return m_precision; } // if (getC_Currency_ID() == 0) { setOrder(getParent()); if (m_precision != null) return m_precision; } if (getC_Currency_ID() > 0) { final I_C_Currency cur = Services.get(ICurrencyDAO.class).retrieveCurrency(getCtx(), getC_Currency_ID()); if (cur.getC_Currency_ID() != 0) { m_precision = cur.getStdPrecision(); return m_precision; } } // // Fallback // FIXME: drop this, i guess is not used AT ALL final String sql = "SELECT c.StdPrecision " + "FROM C_Currency c INNER JOIN C_Order x ON (x.C_Currency_ID=c.C_Currency_ID) " + "WHERE x.C_Order_ID=?"; m_precision = DB.getSQLValue(get_TrxName(), sql, getC_Order_ID()); return m_precision; } // getPrecision /** * Set Product * * @param product product */ public void setProduct(MProduct product) { Services.get(IOrderLineBL.class) .setM_Product_ID( InterfaceWrapperHelper.create(this, de.metas.interfaces.I_C_OrderLine.class), product.getM_Product_ID(), true); } // setProduct /** * Set M_Product_ID * * @param M_Product_ID product * @param setUOM set also UOM */ public void setM_Product_ID(int M_Product_ID, boolean setUOM) { if (setUOM) setProduct(MProduct.get(getCtx(), M_Product_ID)); else super.setM_Product_ID(M_Product_ID); setM_AttributeSetInstance_ID(0); } // setM_Product_ID /** * Set Product and UOM * * @param M_Product_ID product * @param C_UOM_ID uom */ public void setM_Product_ID(int M_Product_ID, int C_UOM_ID) { super.setM_Product_ID(M_Product_ID); if (C_UOM_ID != 0) super.setC_UOM_ID(C_UOM_ID); setM_AttributeSetInstance_ID(0); } // setM_Product_ID /** * Get Product * * @return product or null */ public MProduct getProduct() { if (m_product == null && getM_Product_ID() != 0) m_product = MProduct.get(getCtx(), getM_Product_ID()); return m_product; } // getProduct /** * Set M_AttributeSetInstance_ID * * @param M_AttributeSetInstance_ID id */ @Override public void setM_AttributeSetInstance_ID(int M_AttributeSetInstance_ID) { if (M_AttributeSetInstance_ID == 0) // 0 is valid ID set_Value("M_AttributeSetInstance_ID", new Integer(0)); else super.setM_AttributeSetInstance_ID(M_AttributeSetInstance_ID); } // setM_AttributeSetInstance_ID /** * Set Warehouse * * @param M_Warehouse_ID warehouse */ @Override public void setM_Warehouse_ID(int M_Warehouse_ID) { if (getM_Warehouse_ID() > 0 && getM_Warehouse_ID() != M_Warehouse_ID && !canChangeWarehouse( false) // trowEx=false for legacy purposes. We need to evaluate and consider to throw // exception ) { log.error("Ignored - Already Delivered/Invoiced/Reserved"); } else { super.setM_Warehouse_ID(M_Warehouse_ID); } } // setM_Warehouse_ID /** * Can Change Warehouse * * @param throwEx if <code>true</code> an exception will be thrown in case something is not valid * @return true if warehouse can be changed */ public final boolean canChangeWarehouse(final boolean throwEx) { if (getQtyDelivered().signum() != 0) { return new AdempiereException("@CannotChangeWarehouse@ @QtyDelivered@=" + getQtyDelivered()) .throwOrLogSevere(throwEx, log); } if (getQtyInvoiced().signum() != 0) { return new AdempiereException("@CannotChangeWarehouse@ @QtyInvoiced@=" + getQtyInvoiced()) .throwOrLogSevere(throwEx, log); } if (getQtyReserved().signum() != 0) { return new AdempiereException("@CannotChangeWarehouse@ @QtyReserved@=" + getQtyReserved()) .throwOrLogSevere(throwEx, log); } // We can change return true; } // canChangeWarehouse /** * Get C_Project_ID * * @return project */ @Override public int getC_Project_ID() { int ii = super.getC_Project_ID(); if (ii == 0) ii = getParent().getC_Project_ID(); return ii; } // getC_Project_ID /** * Get C_Activity_ID * * @return Activity */ @Override public int getC_Activity_ID() { int ii = super.getC_Activity_ID(); if (ii == 0) ii = getParent().getC_Activity_ID(); return ii; } // getC_Activity_ID /** * Get C_Campaign_ID * * @return Campaign */ @Override public int getC_Campaign_ID() { int ii = super.getC_Campaign_ID(); if (ii == 0) ii = getParent().getC_Campaign_ID(); return ii; } // getC_Campaign_ID /** * Get User2_ID * * @return User2 */ @Override public int getUser1_ID() { int ii = super.getUser1_ID(); if (ii == 0) ii = getParent().getUser1_ID(); return ii; } // getUser1_ID /** * Get User2_ID * * @return User2 */ @Override public int getUser2_ID() { int ii = super.getUser2_ID(); if (ii == 0) ii = getParent().getUser2_ID(); return ii; } // getUser2_ID /** * Get AD_OrgTrx_ID * * @return trx org */ @Override public int getAD_OrgTrx_ID() { int ii = super.getAD_OrgTrx_ID(); if (ii == 0) ii = getParent().getAD_OrgTrx_ID(); return ii; } // getAD_OrgTrx_ID /** * ************************************************************************ String Representation * * @return info */ @Override public String toString() { StringBuffer sb = new StringBuffer("MOrderLine[") .append(get_ID()) .append(", Line=") .append(getLine()) .append(", Ordered=") .append(getQtyOrdered()) .append(", Delivered=") .append(getQtyDelivered()) .append(", Invoiced=") .append(getQtyInvoiced()) .append(", Reserved=") .append(getQtyReserved()) .append(", LineNet=") .append(getLineNetAmt()) .append("]"); return sb.toString(); } // toString /** * Add to Description * * @param description text */ public void addDescription(String description) { String desc = getDescription(); if (desc == null) setDescription(description); else setDescription(desc + " | " + description); } // addDescription /** * Get Description Text. For jsp access (vs. isDescription) * * @return description */ public String getDescriptionText() { return super.getDescription(); } // getDescriptionText /** * Get Name * * @return get the name of the line (from Product) */ public String getName() { getProduct(); if (m_product != null) return m_product.getName(); if (getC_Charge_ID() != 0) { MCharge charge = MCharge.get(getCtx(), getC_Charge_ID()); return charge.getName(); } return ""; } // getName /** * Set C_Charge_ID * * @param C_Charge_ID charge */ @Override public void setC_Charge_ID(int C_Charge_ID) { super.setC_Charge_ID(C_Charge_ID); if (C_Charge_ID > 0) set_ValueNoCheck("C_UOM_ID", null); } // setC_Charge_ID /** Set Discount */ public void setDiscount() { BigDecimal list = getPriceList(); // No List Price if (Env.ZERO.compareTo(list) == 0) return; // final int precision = getPrecision(); final int precision = 1; // metas // TODO: metas: why we are using precision=1 instead of getPrecision()? BigDecimal discount = list.subtract(getPriceActual()) .multiply(new BigDecimal(100)) .divide(list, precision, BigDecimal.ROUND_HALF_UP); setDiscount(discount); } // setDiscount /** * Set Qty Entered/Ordered. Use this Method if the Line UOM is the Product UOM * * @param Qty QtyOrdered/Entered */ public void setQty(BigDecimal Qty) { super.setQtyEntered(Qty); super.setQtyOrdered(getQtyEntered()); } // setQty /** * Set Qty Entered - enforce entered UOM * * @param QtyEntered */ @Override public void setQtyEntered(BigDecimal QtyEntered) { if (QtyEntered != null && getC_UOM_ID() != 0) { int precision = MUOM.getPrecision(getCtx(), getC_UOM_ID()); QtyEntered = QtyEntered.setScale(precision, BigDecimal.ROUND_HALF_UP); } super.setQtyEntered(QtyEntered); } // setQtyEntered /** * Set Qty Ordered - enforce Product UOM * * @param QtyOrdered */ @Override public void setQtyOrdered(BigDecimal QtyOrdered) { MProduct product = getProduct(); if (QtyOrdered != null && product != null) { int precision = product.getUOMPrecision(); QtyOrdered = QtyOrdered.setScale(precision, BigDecimal.ROUND_HALF_UP); } super.setQtyOrdered(QtyOrdered); } // setQtyOrdered /** * ************************************************************************ Before Save * * @param newRecord * @return true if it can be saved */ @Override protected boolean beforeSave(boolean newRecord) { final boolean complete = getParent().isComplete(); if (newRecord && complete) { throw new AdempiereException("@ParentComplete@ @C_OrderLine_ID@"); } // In case our order is complete do nothing, don't update any field if (complete) { // TODO: make sure that only QtyDelivered, QtyInvoiced fields are updated. // The rest shall be forbidden. // NOTE: also please check if those are the only fields which are updated after an order is // completed return true; } // Get Defaults from Parent final I_M_Warehouse warehouse = Services.get(IWarehouseAdvisor.class).evaluateWarehouse(this); if (getC_BPartner_ID() <= 0 || getC_BPartner_Location_ID() <= 0 || warehouse == null || warehouse.getM_Warehouse_ID() <= 0 || getC_Currency_ID() <= 0) { setOrder(getParent()); } // metas: try to get the pl-id from our plv if (m_M_PriceList_ID <= 0) { final int plvId = get_ValueAsInt(de.metas.interfaces.I_C_OrderLine.COLUMNNAME_M_PriceList_Version_ID); if (plvId > 0) { m_M_PriceList_ID = DB.getSQLValueEx( get_TrxName(), "SELECT M_PriceList_ID FROM M_PriceList_Version WHERE M_PriceList_Version_ID=" + plvId); } } // metas: end if (m_M_PriceList_ID <= 0) setHeaderInfo(getParent()); // R/O Check - Product/Warehouse Change if (!newRecord && (is_ValueChanged("M_Product_ID") || is_ValueChanged("M_Warehouse_ID"))) { if (!canChangeWarehouse(true)) return false; } // Product Changed // Charge if (getC_Charge_ID() != 0 && getM_Product_ID() != 0) setM_Product_ID(0); // No Product if (getM_Product_ID() == 0) setM_AttributeSetInstance_ID(0); // Product else // Set/check Product Price { // Set Price if Actual = 0 if (m_productPrice == null && getPriceActual().signum() == 0 && getPriceList().signum() == 0) { setPrice(); } // Check if on Price list if (m_productPrice == null) getProductPricing( m_M_PriceList_ID, get_ValueAsInt(de.metas.interfaces.I_C_OrderLine.COLUMNNAME_M_PriceList_Version_ID)); if (!m_productPrice.isCalculated()) { throw new ProductNotOnPriceListException(m_productPrice, getLine()); } } // metas: Not allowed to save without (Product or Charge) and qty > 0 if (getM_Product_ID() == 0 && getC_Charge_ID() == 0 && getQtyEntered().intValue() > 0) throw new AdempiereException("@NotFound@ @M_Product_ID@/@C_Charge_ID@ (@QtyEntered@>0)"); // UOM if (getC_UOM_ID() == 0 && (getM_Product_ID() != 0 || getPriceEntered().compareTo(Env.ZERO) != 0 || getC_Charge_ID() != 0)) { int C_UOM_ID = MUOM.getDefault_UOM_ID(getCtx()); if (C_UOM_ID > 0) setC_UOM_ID(C_UOM_ID); } // Price_UOM task 06942 // note: we do not set the price-UOM, because that would only make sense if we also set the // prices themselves. // Qty Precision if (newRecord || is_ValueChanged("QtyEntered")) setQtyEntered(getQtyEntered()); if (newRecord || is_ValueChanged("QtyOrdered")) setQtyOrdered(getQtyOrdered()); // task 05295: commenting this out because also for ASI-Order-Lines it shall be allowed to order // qty that is not yet fully avalable on stock // // Qty on instance ASI for SO // if (m_IsSOTrx // && getM_AttributeSetInstance_ID() != 0 // && (newRecord || is_ValueChanged("M_Product_ID") // || is_ValueChanged("M_AttributeSetInstance_ID") // || is_ValueChanged("M_Warehouse_ID"))) // { // MProduct product = getProduct(); // if (product.isStocked()) // { // int M_AttributeSet_ID = product.getM_AttributeSet_ID(); // boolean isInstance = M_AttributeSet_ID != 0; // if (isInstance) // { // MAttributeSet mas = MAttributeSet.get(getCtx(), M_AttributeSet_ID); // isInstance = mas.isInstanceAttribute(); // } // // Max // if (isInstance) // { // MStorage[] storages = MStorage.getWarehouse(getCtx(), // Services.get(IWarehouseAdvisor.class).evaluateWarehouse(this).getM_Warehouse_ID(), // getM_Product_ID(), getM_AttributeSetInstance_ID(), // M_AttributeSet_ID, false, null, true, get_TrxName()); // BigDecimal qty = Env.ZERO; // for (int i = 0; i < storages.length; i++) // { // if (storages[i].getM_AttributeSetInstance_ID() == getM_AttributeSetInstance_ID()) // qty = qty.add(storages[i].getQtyOnHand()); // } // // if (getQtyOrdered().compareTo(qty) > 0) // { // log.warn("Qty - Stock=" + qty + ", Ordered=" + getQtyOrdered()); // log.error("QtyInsufficient", "=" + qty); // return false; // } // } // } // stocked // } // SO instance // FreightAmt Not used if (Env.ZERO.compareTo(getFreightAmt()) != 0) setFreightAmt(Env.ZERO); // Set Tax // metas: Steuer muss immer ermittelt werden, da durch eine Anschriftenaenderung im Kopf auch // Steueraenderungen in Positionen auftreten. // if (getC_Tax_ID() == 0) if (!setTax()) { return false; } // metas ende // Get Line No if (getLine() == 0) { String sql = "SELECT COALESCE(MAX(Line),0)+10 FROM C_OrderLine WHERE C_Order_ID=?"; int ii = DB.getSQLValue(get_TrxName(), sql, getC_Order_ID()); setLine(ii); } // Calculations & Rounding // FIXME: commented out because actually was doing nothing (see, it was updating another // instance of this order line, which is not saved), and more, setLineNetAmt is no longer called // from here // final I_C_OrderLine orderLine = InterfaceWrapperHelper.create(getCtx(), getC_OrderLine_ID(), // I_C_OrderLine.class, get_TrxName()); // Services.get(IOrderLineBL.class).setPrices(orderLine); // 07264 // commented out because we are not using this anymore // setLineNetAmt(); // extended Amount with or without tax // metas // setDiscount(); // metas ende return true; } // beforeSave /** * Before Delete * * @return true if it can be deleted */ @Override protected boolean beforeDelete() { // R/O Check - Something delivered. etc. if (Env.ZERO.compareTo(getQtyDelivered()) != 0) { throw new AdempiereException("@DeleteError@ @QtyDelivered@=" + getQtyDelivered()); } if (Env.ZERO.compareTo(getQtyInvoiced()) != 0) { throw new AdempiereException("@DeleteError@ @QtyInvoiced@=" + getQtyInvoiced()); } if (Env.ZERO.compareTo(getQtyReserved()) != 0) { // metas: attempt to unreserve stock BigDecimal oldVal = getQtyOrdered(); if (oldVal.signum() != 0) { setQty(Env.ZERO); setLineNetAmt(Env.ZERO); saveEx(get_TrxName()); } if (!getParent().reserveStock(null, new MOrderLine[] {this})) { throw new AdempiereException("@DeleteError@ @QtyReserved@=" + getQtyReserved()); } // metas end } // UnLink All Requisitions MRequisitionLine.unlinkC_OrderLine_ID(getCtx(), get_ID(), get_TrxName()); return true; } // beforeDelete /** * After Save * * @param newRecord new * @param success success * @return saved */ @Override protected boolean afterSave(boolean newRecord, boolean success) { if (!success) return success; if (!newRecord && is_ValueChanged("C_Tax_ID")) { // Recalculate Tax for old Tax if (!getParent().isProcessed()) if (!updateOrderTax(true)) return false; } return updateHeaderTax(); } // afterSave /** * After Delete * * @param success success * @return deleted */ @Override protected boolean afterDelete(boolean success) { if (!success) return success; if (getS_ResourceAssignment_ID() != 0) { MResourceAssignment ra = new MResourceAssignment(getCtx(), getS_ResourceAssignment_ID(), get_TrxName()); ra.delete(true); } return updateHeaderTax(); } // afterDelete /** * Recalculate order tax * * @param oldTax true if the old C_Tax_ID should be used * @return true if success, false otherwise * @author teo_sarca [ 1583825 ] */ private boolean updateOrderTax(final boolean oldTax) { // NOTE: keep in sync with org.compiere.model.MInvoiceLine.updateInvoiceTax(boolean) final String trxName = get_TrxName(); final int taxPrecision = getPrecision(); final MOrderTax tax = MOrderTax.get(this, taxPrecision, oldTax, trxName); if (tax == null) { return true; } if (!tax.calculateTaxFromLines()) { return false; } // // If tax has invoice lines behind => fine, save it if (tax.isActive()) { InterfaceWrapperHelper.save(tax, trxName); } // Tax has no longer any invoice lines behind => deleted it if it's not new else { if (!InterfaceWrapperHelper.isNew(tax)) { InterfaceWrapperHelper.delete(tax); } } return true; } /** * Update Tax & Header * * @return true if header updated */ private boolean updateHeaderTax() { // Recalculate Tax for this Tax if (!getParent().isProcessed()) { if (!updateOrderTax(false)) { return false; } } // task 08999: // Avoid a possible deadlock by updating the C_Order *after* the current transaction, because at // this point we might already hold a lot of locks to different objects. // The updates in updateHeader0 will try aggregate and obtain any number of additional shared // locks. // Concrete, we observed a deadlock between this code and // M_ReceiptSchedule.propagateQtysToOrderLine() final ITrxManager trxManager = Services.get(ITrxManager.class); trxManager .getTrxListenerManager(get_TrxName()) .registerListener( new TrxListenerAdapter() { @Override public void afterCommit(final ITrx trx) { trxManager.run( new TrxRunnableAdapter() { @Override public void run(final String localTrxName) throws Exception { updateHeader0(getC_Order_ID()); } }); } }); return true; } // updateHeaderTax /** * See the comment in {@link #updateHeaderTax()}. * * @param orderId */ private static void updateHeader0(final int orderId) { // Update Order Header: TotalLines { final String sql = "UPDATE C_Order i" + " SET TotalLines=" + "(SELECT COALESCE(SUM(LineNetAmt),0) FROM C_OrderLine il WHERE i.C_Order_ID=il.C_Order_ID) " + "WHERE C_Order_ID=" + orderId; final int no = DB.executeUpdateEx(sql, ITrx.TRXNAME_ThreadInherited); if (no != 1) { new AdempiereException("Updating TotalLines failed for C_Order_ID=" + orderId); } } // Update Order Header: GrandTotal { final String sql = "UPDATE C_Order i " + " SET GrandTotal=TotalLines+" // SUM up C_OrderTax.TaxAmt only for those lines which does not have Tax Included + "(SELECT COALESCE(SUM(TaxAmt),0) FROM C_OrderTax it WHERE i.C_Order_ID=it.C_Order_ID AND it.IsActive='Y' AND it.IsTaxIncluded='N') " + "WHERE C_Order_ID=" + orderId; final int no = DB.executeUpdateEx(sql, ITrx.TRXNAME_ThreadInherited); if (no != 1) { new AdempiereException("Updating GrandTotal failed for C_Order_ID=" + orderId); } } } } // MOrderLine
/** * Payment Validion Routines * * @author Jorg Janke * @version $Id: MPaymentValidate.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $ */ public class MPaymentValidate { /** Static Logger */ private static Logger s_log = LogManager.getLogger(MPaymentValidate.class); /** * Is this a valid Credit Card Exp Date? * * @param mmyy Exp in form of mmyy * @return "" or Error AD_Message */ public static String validateCreditCardExp(String mmyy) { String exp = checkNumeric(mmyy); if (exp.length() != 4) return "CreditCardExpFormat"; // String mmStr = exp.substring(0, 2); String yyStr = exp.substring(2, 4); // int mm = 0; int yy = 0; try { mm = Integer.parseInt(mmStr); yy = Integer.parseInt(yyStr); } catch (Exception e) { return "CreditCardExpFormat"; } return validateCreditCardExp(mm, yy); } // validateCreditCardExp /** * Return Month of Exp * * @param mmyy Exp in form of mmyy * @return month */ public static int getCreditCardExpMM(String mmyy) { String mmStr = mmyy.substring(0, 2); int mm = 0; try { mm = Integer.parseInt(mmStr); } catch (Exception e) { } return mm; } // getCreditCardExpMM /** * Return Year of Exp * * @param mmyy Exp in form of mmyy * @return year */ public static int getCreditCardExpYY(String mmyy) { String yyStr = mmyy.substring(2); int yy = 0; try { yy = Integer.parseInt(yyStr); } catch (Exception e) { } return yy; } // getCreditCardExpYY /** * Is this a valid Credit Card Exp Date? * * @param mm month * @param yy year * @return "" or Error AD_Message */ public static String validateCreditCardExp(int mm, int yy) { if (mm < 1 || mm > 12) return "CreditCardExpMonth"; // if (yy < 0 || yy > EXP_YEAR) // return "CreditCardExpYear"; // Today's date Calendar cal = Calendar.getInstance(); int year = cal.get(Calendar.YEAR) - 2000; // two digits int month = cal.get(Calendar.MONTH) + 1; // zero based // if (yy < year) return "CreditCardExpired"; else if (yy == year && mm < month) return "CreditCardExpired"; return ""; } // validateCreditCardExp /** * Validate Credit Card Number. - Based on LUHN formula * * @param creditCardNumber credit card number * @return "" or Error AD_Message */ public static String validateCreditCardNumber(String creditCardNumber) { if (creditCardNumber == null || creditCardNumber.length() == 0) return "CreditCardNumberError"; /** * 1: Double the value of alternate digits beginning with the first right-hand digit (low * order). 2: Add the individual digits comprising the products obtained in step 1 to each of * the unaffected digits in the original number. 3: Subtract the total obtained in step 2 from * the next higher number ending in 0 [this in the equivalent of calculating the "tens * complement" of the low order digit (unit digit) of the total]. If the total obtained in step * 2 is a number ending in zero (30, 40 etc.), the check digit is 0. Example: Account number: * 4992 73 9871 6 * * <p>4 9 9 2 7 3 9 8 7 1 6 x2 x2 x2 x2 x2 ------------------------------- 4 18 9 4 7 6 9 16 7 2 * 6 * * <p>4 + 1 + 8 + 9 + 4 + 7 + 6 + 9 + 1 + 6 + 7 + 2 + 6 = 70 70 % 10 = 0 */ // Clean up number String ccNumber1 = checkNumeric(creditCardNumber); int ccLength = ccNumber1.length(); // Reverse string StringBuffer buf = new StringBuffer(); for (int i = ccLength; i != 0; i--) buf.append(ccNumber1.charAt(i - 1)); String ccNumber = buf.toString(); int sum = 0; for (int i = 0; i < ccLength; i++) { int digit = Character.getNumericValue(ccNumber.charAt(i)); if (i % 2 == 1) { digit *= 2; if (digit > 9) digit -= 9; } sum += digit; } if (sum % 10 == 0) return ""; s_log.debug( "validateCreditCardNumber - " + creditCardNumber + " -> " + ccNumber + ", Luhn=" + sum); return "CreditCardNumberError"; } // validateCreditCardNumber /** * Validate Credit Card Number. - Check Card Type and Length * * @param creditCardNumber CC Number * @param creditCardType CC Type * @return "" or Error AD_Message */ public static String validateCreditCardNumber(String creditCardNumber, String creditCardType) { if (creditCardNumber == null || creditCardType == null) return "CreditCardNumberError"; // http://www.beachnet.com/~hstiles/cardtype.html // http://staff.semel.fi/~kribe/document/luhn.htm String ccStartList = ""; // comma separated list of starting numbers String ccLengthList = ""; // comma separated list of lengths // if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_MasterCard)) { ccStartList = "51,52,53,54,55"; ccLengthList = "16"; } else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Visa)) { ccStartList = "4"; ccLengthList = "13,16"; } else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Amex)) { ccStartList = "34,37"; ccLengthList = "15"; } else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Discover)) { ccStartList = "6011"; ccLengthList = "16"; } else if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Diners)) { ccStartList = "300,301,302,303,304,305,36,38"; ccLengthList = "14"; } else { // enRouteCard ccStartList = "2014,2149"; ccLengthList = "15"; // JCBCard ccStartList += ",3088,3096,3112,3158,3337,3528"; ccLengthList += ",16"; // JCBCard ccStartList += ",2131,1800"; ccLengthList += ",15"; } // Clean up number String ccNumber = checkNumeric(creditCardNumber); /** Check Length */ int ccLength = ccNumber.length(); boolean ccLengthOK = false; StringTokenizer st = new StringTokenizer(ccLengthList, ",", false); while (st.hasMoreTokens() && !ccLengthOK) { int l = Integer.parseInt(st.nextToken()); if (ccLength == l) ccLengthOK = true; } if (!ccLengthOK) { s_log.debug("validateCreditCardNumber Length=" + ccLength + " <> " + ccLengthList); return "CreditCardNumberError"; } /** Check Start Digits */ boolean ccIdentified = false; st = new StringTokenizer(ccStartList, ",", false); while (st.hasMoreTokens() && !ccIdentified) { if (ccNumber.startsWith(st.nextToken())) ccIdentified = true; } if (!ccIdentified) s_log.debug("validateCreditCardNumber Type=" + creditCardType + " <> " + ccStartList); // String check = validateCreditCardNumber(ccNumber); if (check.length() != 0) return check; if (!ccIdentified) return "CreditCardNumberProblem?"; return ""; } // validateCreditCardNumber /** * Validate Validation Code * * @param creditCardVV CC Verification Code * @return "" or Error AD_Message */ public static String validateCreditCardVV(String creditCardVV) { if (creditCardVV == null) return ""; int length = checkNumeric(creditCardVV).length(); if (length == 3 || length == 4) return ""; try { Integer.parseInt(creditCardVV); return ""; } catch (NumberFormatException ex) { s_log.debug("validateCreditCardVV - " + ex); } s_log.debug("validateCreditCardVV - length=" + length); return "CreditCardVVError"; } // validateCreditCardVV /** * Validate Validation Code * * @param creditCardVV CC Verification Code * @param creditCardType CC Type see CC_ * @return "" or Error AD_Message */ public static String validateCreditCardVV(String creditCardVV, String creditCardType) { // no data if (creditCardVV == null || creditCardVV.length() == 0 || creditCardType == null || creditCardType.length() == 0) return ""; int length = checkNumeric(creditCardVV).length(); // Amex = 4 digits if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Amex)) { if (length == 4) { try { Integer.parseInt(creditCardVV); return ""; } catch (NumberFormatException ex) { s_log.debug("validateCreditCardVV - " + ex); } } s_log.debug("validateCreditCardVV(4) CC=" + creditCardType + ", length=" + length); return "CreditCardVVError"; } // Visa & MasterCard - 3 digits if (creditCardType.equals(X_C_Payment.CREDITCARDTYPE_Visa) || creditCardType.equals(X_C_Payment.CREDITCARDTYPE_MasterCard)) { if (length == 3) { try { Integer.parseInt(creditCardVV); return ""; } catch (NumberFormatException ex) { s_log.debug("validateCreditCardVV - " + ex); } } s_log.debug("validateCreditCardVV(3) CC=" + creditCardType + ", length=" + length); return "CreditCardVVError"; } // Other return ""; } // validateCreditCardVV /** * ************************************************************************ Validate Routing * Number * * @param routingNo Routing No * @return "" or Error AD_Message */ public static String validateRoutingNo(String routingNo) { int length = checkNumeric(routingNo).length(); // US - length 9 // Germany - length 8 // Japan - 7 // CH - 5 // Issue: Bank account country if (length > 0) return ""; return "PaymentBankRoutingNotValid"; } // validateBankRoutingNo /** * Validate Account No * * @param AccountNo AccountNo * @return "" or Error AD_Message */ public static String validateAccountNo(String AccountNo) { int length = checkNumeric(AccountNo).length(); if (length > 0) return ""; return "PaymentBankAccountNotValid"; } // validateBankAccountNo /** * Validate Check No * * @param CheckNo CheckNo * @return "" or Error AD_Message */ public static String validateCheckNo(String CheckNo) { int length = checkNumeric(CheckNo).length(); if (length > 0) return ""; return "PaymentBankCheckNotValid"; } // validateBankCheckNo /** * Check Numeric * * @param data input * @return the digits of the data - ignore the rest */ public static String checkNumeric(String data) { if (data == null || data.length() == 0) return ""; // Remove all non Digits StringBuffer sb = new StringBuffer(); for (int i = 0; i < data.length(); i++) { if (Character.isDigit(data.charAt(i))) sb.append(data.charAt(i)); } return sb.toString(); } // checkNumeric } // MPaymentValidate
/** @author tsa */ public abstract class AbstractTerminalNumericField extends AbstractTerminalField<BigDecimal> implements ITerminalNumericField { private final transient Logger log = LogManager.getLogger(getClass()); private final String name; private final int displayType; private final float fontSize; private final boolean withButtons; private final boolean withLabel; private boolean editable = true; protected ITerminalButton bPlus; protected ITerminalButton bMinus; protected IContainer panel; protected ITerminalTextField fNumber; protected String constraints = SwingTerminalFactory.BUTTON_Constraints; private BigDecimal increment = Env.ONE; @Override public void setMinusRO(final boolean ro) { if (withButtons) { bMinus.setEnabled(!ro); } } @Override public void setPlusRO(final boolean ro) { if (withButtons) { bPlus.setEnabled(!ro); } } @Override public void setNumberRO(final boolean ro) { fNumber.setEditable(!ro); } private class MinusButtonAction implements PropertyChangeListener { @Override public void propertyChange(final PropertyChangeEvent evt) { decValue(); } } private class PlusButtonAction implements PropertyChangeListener { @Override public void propertyChange(final PropertyChangeEvent evt) { incValue(); } } private final PropertyChangeListener numberChangeListener = new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent evt) { if (ITerminalTextField.PROPERTY_ActionPerformed.equals(evt.getPropertyName())) { final BigDecimal valueOldBD = convertValueToType(evt.getOldValue()); final BigDecimal valueNewBD = convertValueToType(evt.getNewValue()); firePropertyChange(ITerminalField.ACTION_ValueChanged, valueOldBD, valueNewBD); } else if (ITerminalTextField.PROPERTY_FocusLost.equals(evt.getPropertyName())) { try { setValue(getValue(), true); } catch (final Exception ex) { showWarningAndRequestFocus(ex); } } } }; protected AbstractTerminalNumericField( final ITerminalContext tc, final String name, final int displayType) { this(tc, name, displayType, true, true); } protected AbstractTerminalNumericField( final ITerminalContext tc, final String name, final int displayType, final float fontSize, final boolean withButtons, final boolean withLabel, final String constr) { super(tc); this.name = name; this.displayType = displayType; if (fontSize > 0) { this.fontSize = fontSize; } else { this.fontSize = tc.getDefaultFontSize(); } this.withButtons = withButtons; this.withLabel = withLabel; if (!Check.isEmpty(constr, true)) { constraints = constr; } initComponents(); initUI(); setValue(Env.ZERO, false); } protected AbstractTerminalNumericField( final ITerminalContext tc, final String name, final int displayType, final boolean withButtons, final boolean withLabel, final String constr) { this(tc, name, displayType, 0f, withButtons, withLabel, constr); } protected AbstractTerminalNumericField( final ITerminalContext tc, final String name, final int displayType, final boolean withButtons, final boolean withLabel) { this(tc, name, displayType, withButtons, withLabel, null); } private void initComponents() { final ITerminalFactory factory = getTerminalFactory(); fNumber = factory.createTerminalTextField(getName(), getDisplayType(), getFontSize()); fNumber.addListener(numberChangeListener); final String panelColumnConstraints; if (withButtons) { bMinus = factory.createButtonAction(ITerminalNumericField.ACTION_Minus); bMinus.addListener(new MinusButtonAction()); bPlus = factory.createButtonAction(ITerminalNumericField.ACTION_Plus); bPlus.addListener(new PlusButtonAction()); panelColumnConstraints = "[][][]"; // 3 Columns: Minus button, Qty numeric field, Plus button } else { panelColumnConstraints = ""; // nothing, we have only the Qty numberic field } final String panelRowConstraints; if (withLabel) { panelRowConstraints = "[]" // Label row + "0" // gap between rows + "[shrink 0]"; // Qty field row } else { panelRowConstraints = "[shrink 0]"; // Qty field row only } final String panelLayoutConstraints = "insets 0"; panel = factory.createContainer( panelLayoutConstraints, // Layout Constraints panelColumnConstraints, // Column constraints panelRowConstraints // Row constrants ); } @Override public void setReadOnly(final boolean ro) { final boolean editable = !ro; setEditable(editable); } @Override public void setEditable(final boolean editable) { this.editable = editable; fNumber.setEditable(editable); if (withButtons) { bMinus.setEnabled(editable); bPlus.setEnabled(editable); } } @Override public boolean isEditable() { return editable; } protected abstract void initUI(); @Override protected BigDecimal getFieldValue() { String text = fNumber.getText(); if (text == null) { return BigDecimal.ZERO; } text = text.trim(); if (text.isEmpty()) { return BigDecimal.ZERO; } final Format format = fNumber.getFormat(); try { if (format == null) { return new BigDecimal(text); } else if (format instanceof DecimalFormat) { final DecimalFormat df = (DecimalFormat) format; df.setParseBigDecimal(true); final BigDecimal bd = (BigDecimal) df.parse(text); return bd; } else { log.info( "Invalid Format '{}' to be used to convert text '{}' to BigDecimal. Assuming ZERO.", new Object[] {format, text}); return Env.ZERO; } } catch (final Exception e) { throw new WrongValueException( this, "@" + ITerminalField.MSG_ErrorParsingText + "@ " + text, e); } } @Override protected BigDecimal convertValueToType(final Object value) { if (value == null) { return null; } else if (value instanceof BigDecimal) { return (BigDecimal) value; } else if (value instanceof Integer) { return BigDecimal.valueOf((Integer) value); } else if (value instanceof String) { final String valueStr = value.toString().trim(); if (valueStr.isEmpty()) { return null; } else { return new BigDecimal(valueStr); } } else { return new BigDecimal(value.toString()); } } @Override protected final void setFieldValue(final BigDecimal value, final boolean fireEvent) { final BigDecimal valueOld = this._valueOld; // backup for event // // Fix value to set final BigDecimal valueNew; if (value == null) { valueNew = Env.ZERO; } else { // Qty Editor it shall be a small component and we don't want to clutter it with pointless // trailing zeros (06112) valueNew = NumberUtils.stripTrailingDecimalZeros(value); } // // Get the number editor final ITerminalTextField fNumber = this.fNumber; if (isDisposed() || fNumber == null) { // shall not happen but we are throwing an exception because we got a weird case (FRESH-331) new TerminalException( "Atempt to set value but field is disposed." + "\n field: " + this + "\n value: " + valueOld + "->" + valueNew + "\n fireEvent: " + fireEvent + "\n fNumber: " + fNumber) .throwOrLogWarningIfDeveloperMode(log); return; } // // Actually setting the new value fNumber.setText(valueNew.toString()); this._valueOld = valueNew; // // Fire event if (fireEvent) { final boolean changed = valueOld == null || valueOld.compareTo(valueNew) != 0; if (changed) { firePropertyChange(ITerminalField.ACTION_ValueChanged, valueOld, valueNew); } } } private BigDecimal _valueOld = null; public void incValue() { setValue(getValue().add(increment)); } public void decValue() { setValue(getValue().subtract(increment)); } public BigDecimal getIncrement() { return increment; } public void setIncrement(final BigDecimal increment) { this.increment = increment; } @Override public String getName() { return name; } public int getDisplayType() { return displayType; } public float getFontSize() { return fontSize; } @Override public void requestFocus() { fNumber.requestFocus(); } public boolean isWithButtons() { return withButtons; } public boolean isWithLabel() { return withLabel; } @Override public void dispose() { super.dispose(); if (bMinus != null) { bMinus.dispose(); bMinus = null; } if (bPlus != null) { bPlus.dispose(); bPlus = null; } if (fNumber != null) { fNumber.removeListener(numberChangeListener); fNumber.dispose(); fNumber = null; } if (panel != null) { panel.dispose(); panel = null; } } }
/** * Performance Goal * * @author Jorg Janke * @version $Id: MGoal.java,v 1.2 2006/07/30 00:51:03 jjanke Exp $ * @author Teo Sarca, SC ARHIPAC SERVICE SRL * <li>BF [ 1887674 ] Deadlock when try to modify PA Goal's Measure Target * <li>BF [ 1760482 ] New Dashboard broke old functionality * <li>BF [ 1887691 ] I get NPE if the PA Goal's target is 0 */ public class MGoal extends X_PA_Goal { /** */ private static final long serialVersionUID = -4612113288233473730L; /** * Get User Goals * * @param ctx context * @param AD_User_ID user * @return array of goals */ public static MGoal[] getUserGoals(Properties ctx, int AD_User_ID) { if (AD_User_ID < 0) return getTestGoals(ctx); ArrayList<MGoal> list = new ArrayList<MGoal>(); String sql = "SELECT * FROM PA_Goal g " + "WHERE IsActive='Y'" + " AND AD_Client_ID=?" // #1 + " AND ((AD_User_ID IS NULL AND AD_Role_ID IS NULL)" + " OR AD_User_ID=?" // #2 + " OR EXISTS (SELECT * FROM AD_User_Roles ur " + "WHERE ur.AD_User_ID=? AND g.AD_Role_ID=ur.AD_Role_ID AND ur.IsActive='Y')) " + "ORDER BY SeqNo"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, Env.getAD_Client_ID(ctx)); pstmt.setInt(2, AD_User_ID); pstmt.setInt(3, AD_User_ID); rs = pstmt.executeQuery(); while (rs.next()) { MGoal goal = new MGoal(ctx, rs, null); goal.updateGoal(false); list.add(goal); } } catch (Exception e) { s_log.error(sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MGoal[] retValue = new MGoal[list.size()]; list.toArray(retValue); return retValue; } // getUserGoals /** * Get Accessible Goals * * @param ctx context * @return array of goals */ public static MGoal[] getGoals(Properties ctx) { ArrayList<MGoal> list = new ArrayList<MGoal>(); String sql = "SELECT * FROM PA_Goal WHERE IsActive='Y' " + "ORDER BY SeqNo"; sql = Env.getUserRolePermissions(ctx) .addAccessSQL(sql, "PA_Goal", false, true); // RW to restrict Access PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); rs = pstmt.executeQuery(); while (rs.next()) { MGoal goal = new MGoal(ctx, rs, null); goal.updateGoal(false); list.add(goal); } } catch (Exception e) { s_log.error(sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MGoal[] retValue = new MGoal[list.size()]; list.toArray(retValue); return retValue; } // getGoals /** * Create Test Goals * * @param ctx context * @return array of goals */ public static MGoal[] getTestGoals(Properties ctx) { MGoal[] retValue = new MGoal[4]; retValue[0] = new MGoal(ctx, "Test 1", "Description 1", new BigDecimal(1000), null); retValue[0].setMeasureActual(new BigDecimal(200)); retValue[1] = new MGoal(ctx, "Test 2", "Description 2", new BigDecimal(1000), null); retValue[1].setMeasureActual(new BigDecimal(900)); retValue[2] = new MGoal(ctx, "Test 3", "Description 3", new BigDecimal(1000), null); retValue[2].setMeasureActual(new BigDecimal(1200)); retValue[3] = new MGoal(ctx, "Test 4", "Description 4", new BigDecimal(1000), null); retValue[3].setMeasureActual(new BigDecimal(3200)); return retValue; } // getTestGoals /** * Get Goals with Measure * * @param ctx context * @param PA_Measure_ID measure * @return goals */ public static MGoal[] getMeasureGoals(Properties ctx, int PA_Measure_ID) { ArrayList<MGoal> list = new ArrayList<MGoal>(); String sql = "SELECT * FROM PA_Goal WHERE IsActive='Y' AND PA_Measure_ID=? " + "ORDER BY SeqNo"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, PA_Measure_ID); rs = pstmt.executeQuery(); while (rs.next()) list.add(new MGoal(ctx, rs, null)); } catch (Exception e) { s_log.error(sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MGoal[] retValue = new MGoal[list.size()]; list.toArray(retValue); return retValue; } // getMeasureGoals /** * Get Multiplier from Scope to Display * * @param goal goal * @return null if error or multiplier */ public static BigDecimal getMultiplier(MGoal goal) { String MeasureScope = goal.getMeasureScope(); String MeasureDisplay = goal.getMeasureDisplay(); if (MeasureDisplay == null || MeasureScope.equals(MeasureDisplay)) return Env.ONE; // 1:1 if (MeasureScope.equals(MEASURESCOPE_Total) || MeasureDisplay.equals(MEASUREDISPLAY_Total)) return null; // Error BigDecimal Multiplier = null; if (MeasureScope.equals(MEASURESCOPE_Year)) { if (MeasureDisplay.equals(MEASUREDISPLAY_Quarter)) Multiplier = new BigDecimal(1.0 / 4.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Month)) Multiplier = new BigDecimal(1.0 / 12.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Week)) Multiplier = new BigDecimal(1.0 / 52.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Day)) Multiplier = new BigDecimal(1.0 / 364.0); } else if (MeasureScope.equals(MEASURESCOPE_Quarter)) { if (MeasureDisplay.equals(MEASUREDISPLAY_Year)) Multiplier = new BigDecimal(4.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Month)) Multiplier = new BigDecimal(1.0 / 3.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Week)) Multiplier = new BigDecimal(1.0 / 13.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Day)) Multiplier = new BigDecimal(1.0 / 91.0); } else if (MeasureScope.equals(MEASURESCOPE_Month)) { if (MeasureDisplay.equals(MEASUREDISPLAY_Year)) Multiplier = new BigDecimal(12.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Quarter)) Multiplier = new BigDecimal(3.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Week)) Multiplier = new BigDecimal(1.0 / 4.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Day)) Multiplier = new BigDecimal(1.0 / 30.0); } else if (MeasureScope.equals(MEASURESCOPE_Week)) { if (MeasureDisplay.equals(MEASUREDISPLAY_Year)) Multiplier = new BigDecimal(52.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Quarter)) Multiplier = new BigDecimal(13.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Month)) Multiplier = new BigDecimal(4.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Day)) Multiplier = new BigDecimal(1.0 / 7.0); } else if (MeasureScope.equals(MEASURESCOPE_Day)) { if (MeasureDisplay.equals(MEASUREDISPLAY_Year)) Multiplier = new BigDecimal(364.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Quarter)) Multiplier = new BigDecimal(91.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Month)) Multiplier = new BigDecimal(30.0); else if (MeasureDisplay.equals(MEASUREDISPLAY_Week)) Multiplier = new BigDecimal(7.0); } return Multiplier; } // getMultiplier /** Logger */ private static Logger s_log = LogManager.getLogger(MGoal.class); /** * ************************************************************************ Standard Constructor * * @param ctx context * @param PA_Goal_ID id * @param trxName trx */ public MGoal(Properties ctx, int PA_Goal_ID, String trxName) { super(ctx, PA_Goal_ID, trxName); if (PA_Goal_ID == 0) { // setName (null); // setAD_User_ID (0); // setPA_ColorSchema_ID (0); setSeqNo(0); setIsSummary(false); setMeasureScope(MEASUREDISPLAY_Year); setGoalPerformance(Env.ZERO); setRelativeWeight(Env.ONE); setMeasureTarget(Env.ZERO); setMeasureActual(Env.ZERO); } } // MGoal /** * Load Constructor * * @param ctx context * @param rs result set * @param trxName trx */ public MGoal(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MGoal /** * Base Constructor * * @param ctx context * @param Name Name * @param Description Decsription * @param MeasureTarget target * @param trxName trx */ public MGoal( Properties ctx, String Name, String Description, BigDecimal MeasureTarget, String trxName) { super(ctx, 0, trxName); setName(Name); setDescription(Description); setMeasureTarget(MeasureTarget); } // MGoal /** Restrictions */ private MGoalRestriction[] m_restrictions = null; /** Performance Color */ private Color m_color = null; /** * Get Restriction Lines * * @param reload reload data * @return array of lines */ public MGoalRestriction[] getRestrictions(boolean reload) { if (m_restrictions != null && !reload) return m_restrictions; ArrayList<MGoalRestriction> list = new ArrayList<MGoalRestriction>(); // String sql = "SELECT * FROM PA_GoalRestriction " + "WHERE PA_Goal_ID=? AND IsActive='Y' " + "ORDER BY Org_ID, C_BPartner_ID, M_Product_ID"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, get_TrxName()); pstmt.setInt(1, getPA_Goal_ID()); rs = pstmt.executeQuery(); while (rs.next()) list.add(new MGoalRestriction(getCtx(), rs, get_TrxName())); } catch (Exception e) { log.error(sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // m_restrictions = new MGoalRestriction[list.size()]; list.toArray(m_restrictions); return m_restrictions; } // getRestrictions /** * Get Measure * * @return measure or null */ public MMeasure getMeasure() { if (getPA_Measure_ID() != 0) return MMeasure.get(getCtx(), getPA_Measure_ID()); return null; } // getMeasure /** * ************************************************************************ Update/save Goals for * the same measure * * @param force force to update goal (default once per day) * @return true if updated */ public boolean updateGoal(boolean force) { log.info("Force=" + force); MMeasure measure = MMeasure.get(getCtx(), getPA_Measure_ID()); if (force || getDateLastRun() == null || !TimeUtil.isSameHour(getDateLastRun(), null)) { measure.set_TrxName(get_TrxName()); if (measure.updateGoals()) // saves { load(get_ID(), get_TrxName()); return true; } } return false; } // updateGoal /** * Set Measure Actual * * @param MeasureActual actual */ @Override public void setMeasureActual(BigDecimal MeasureActual) { if (MeasureActual == null) return; super.setMeasureActual(MeasureActual); setDateLastRun(new Timestamp(System.currentTimeMillis())); setGoalPerformance(); } // setMeasureActual /** Calculate Performance Goal as multiplier */ public void setGoalPerformance() { BigDecimal MeasureTarget = getMeasureTarget(); BigDecimal MeasureActual = getMeasureActual(); BigDecimal GoalPerformance = Env.ZERO; if (MeasureTarget.signum() != 0) GoalPerformance = MeasureActual.divide(MeasureTarget, 6, BigDecimal.ROUND_HALF_UP); super.setGoalPerformance(GoalPerformance); m_color = null; } // setGoalPerformance /** * Get Goal Performance as Double * * @return performance as multipier */ public double getGoalPerformanceDouble() { BigDecimal bd = getGoalPerformance(); return bd.doubleValue(); } // getGoalPerformanceDouble /** * Get Goal Performance in Percent * * @return performance in percent */ public int getPercent() { BigDecimal bd = getGoalPerformance().multiply(Env.ONEHUNDRED); return bd.intValue(); } // getPercent /** * Get Color * * @return color - white if no target */ public Color getColor() { if (m_color == null) { if (getMeasureTarget().signum() == 0) m_color = Color.white; else m_color = MColorSchema.getColor(getCtx(), getPA_ColorSchema_ID(), getPercent()); } return m_color; } // getColor /** * Get the color schema for this goal. * * @return the color schema */ public MColorSchema getColorSchema() { return MColorSchema.get(getCtx(), getPA_ColorSchema_ID()); } /** * Get Measure Display * * @return Measure Display */ @Override public String getMeasureDisplay() { String s = super.getMeasureDisplay(); if (s == null) { if (MEASURESCOPE_Week.equals(getMeasureScope())) s = MEASUREDISPLAY_Week; else if (MEASURESCOPE_Day.equals(getMeasureScope())) s = MEASUREDISPLAY_Day; else s = MEASUREDISPLAY_Month; } return s; } // getMeasureDisplay /** * Get Measure Display Text * * @return Measure Display Text */ public String getXAxisText() { MMeasure measure = getMeasure(); if (measure != null && MMeasure.MEASUREDATATYPE_StatusQtyAmount.equals(measure.getMeasureDataType())) { if (MMeasure.MEASURETYPE_Request.equals(measure.getMeasureType())) return Msg.getElement(getCtx(), "R_Status_ID"); if (MMeasure.MEASURETYPE_Project.equals(measure.getMeasureType())) return Msg.getElement(getCtx(), "C_Phase_ID"); } String value = getMeasureDisplay(); String display = MRefList.getListName(getCtx(), MEASUREDISPLAY_AD_Reference_ID, value); return display == null ? value : display; } // getMeasureDisplayText /** * Goal has Target * * @return true if target */ public boolean isTarget() { return getMeasureTarget().signum() != 0; } // isTarget /** * String Representation * * @return info */ @Override public String toString() { StringBuffer sb = new StringBuffer("MGoal["); sb.append(get_ID()) .append("-") .append(getName()) .append(",") .append(getGoalPerformance()) .append("]"); return sb.toString(); } // toString /** * Before Save * * @param newRecord new * @return true */ @Override protected boolean beforeSave(boolean newRecord) { // if (getMultiplier(this) == null) // error // setMeasureDisplay(getMeasureScope()); // Measure required if nor Summary if (!isSummary() && getPA_Measure_ID() == 0) { throw new FillMandatoryException("PA_Measure_ID"); } if (isSummary() && getPA_Measure_ID() != 0) setPA_Measure_ID(0); // User/Role Check if ((newRecord || is_ValueChanged("AD_User_ID") || is_ValueChanged("AD_Role_ID")) && getAD_User_ID() != 0) { final List<IUserRolePermissions> roles = Services.get(IUserRolePermissionsDAO.class) .retrieveUserRolesPermissionsForUserWithOrgAccess( getCtx(), getAD_User_ID(), getAD_Org_ID()); if (roles.isEmpty()) // No Role { setAD_Role_ID(0); } else if (roles.size() == 1) // One { setAD_Role_ID(roles.get(0).getAD_Role_ID()); } else { int AD_Role_ID = getAD_Role_ID(); if (AD_Role_ID != 0) // validate { boolean found = false; for (IUserRolePermissions role : roles) { if (AD_Role_ID == role.getAD_Role_ID()) { found = true; break; } } if (!found) AD_Role_ID = 0; } if (AD_Role_ID == 0) // set to first one setAD_Role_ID(roles.get(0).getAD_Role_ID()); } // multiple roles } // user check return true; } // beforeSave /** * After Save * * @param newRecord new * @param success success * @return true */ @Override protected boolean afterSave(boolean newRecord, boolean success) { if (!success) return success; // Update Goal if Target / Scope Changed if (newRecord || is_ValueChanged("MeasureTarget") || is_ValueChanged("MeasureScope")) updateGoal(true); return success; } } // MGoal
/** * Factory used to create all sync objects that we are sending from metasfresh server to webui * server. * * @author metas-dev <*****@*****.**> */ public class SyncObjectsFactory { public static final SyncObjectsFactory newFactory(final Date date) { return new SyncObjectsFactory(date); } public static final SyncObjectsFactory newFactory() { return new SyncObjectsFactory(SystemTime.asDayTimestamp()); } // // services private static final Logger logger = LogManager.getLogger(SyncObjectsFactory.class); private final transient IBPartnerDAO bpartnerDAO = Services.get(IBPartnerDAO.class); private final transient IPMMContractsDAO pmmContractsDAO = Services.get(IPMMContractsDAO.class); private final transient IPMMProductDAO pmmProductDAO = Services.get(IPMMProductDAO.class); private final transient IPMMBPartnerDAO pmmbPartnerDAO = Services.get(IPMMBPartnerDAO.class); private final transient IPMM_RfQ_DAO pmmRfQDAO = Services.get(IPMM_RfQ_DAO.class); private final transient IPMM_RfQ_BL pmmRfQBL = Services.get(IPMM_RfQ_BL.class); // // parameters private final Date date; // // state/cache private final Map<Integer, I_C_BPartner> bpartners = new HashMap<>(); /** C_BPartner_ID to {@link I_C_Flatrate_Term}s */ private final Multimap<Integer, I_C_Flatrate_Term> _bpartnerId2contract = MultimapBuilder.hashKeys().arrayListValues().build(); private boolean _bpartnerId2contract_fullyLoaded = false; private boolean _bpartnerId2contract_fullyLoadedRequired = false; private final Multimap<Integer, I_C_RfQResponseLine> _bpartnerId2activeRfqResponseLines = MultimapBuilder.hashKeys().arrayListValues().build(); private boolean _bpartnerId2activeRfqResponseLines_fullyLoaded = false; private boolean _bpartnerId2activeRfqResponseLines_fullyLoadedRequired = false; private Cache<String, SyncProduct> syncProductsCache = CacheBuilder.newBuilder().build(); private SyncObjectsFactory(final Date date) { super(); Check.assumeNotNull(date, "date not null"); this.date = (Date) date.clone(); } private Properties getCtx() { return Env.getCtx(); } public List<SyncBPartner> createAllSyncBPartners() { // Optimization: setFlatrateTermsFullyLoadedRequired(); setActiveRfqResponsesFullyLoadedRequired(); final List<SyncBPartner> syncBPartners = new ArrayList<>(); for (final int bpartnerId : getAllBPartnerIds()) { final SyncBPartner syncBPartner = createSyncBPartner(bpartnerId); syncBPartners.add(syncBPartner); } return syncBPartners; } private SyncContract createSyncContract(final I_C_Flatrate_Term term) { final SyncContract syncContract = new SyncContract(); syncContract.setUuid(SyncUUIDs.toUUIDString(term)); syncContract.setDateFrom(term.getStartDate()); syncContract.setDateTo(term.getEndDate()); final int rfqResponseLineId = term.getC_RfQResponseLine_ID(); if (rfqResponseLineId > 0) { syncContract.setRfq_uuid(SyncUUIDs.toC_RfQReponseLine_UUID(rfqResponseLineId)); } // // Contract Line: 1 line for our PMM_Product { final I_PMM_Product pmmProduct = term.getPMM_Product(); if (pmmProduct == null) { logger.warn("Contract {} has no PMM_Product. Skip exporting.", term); return null; } final SyncProduct syncProduct = createSyncProduct(pmmProduct); if (syncProduct == null) { return null; } final SyncContractLine syncContractLine = new SyncContractLine(); syncContractLine.setUuid(syncContract.getUuid()); syncContractLine.setProduct(syncProduct); syncContract.getContractLines().add(syncContractLine); } return syncContract; } public SyncBPartner createSyncBPartner(final int bpartnerId) { // // Create SyncBPartner with Users populated final SyncBPartner syncBPartner = createSyncBPartnerWithoutContracts(bpartnerId); // // Populate contracts syncBPartner.setSyncContracts(true); for (final I_C_Flatrate_Term term : getC_Flatrate_Terms_ForBPartnerId(bpartnerId)) { final SyncContract syncContract = createSyncContract(term); if (syncContract == null) { continue; } syncBPartner.getContracts().add(syncContract); } // // Populate RfQs for (final I_C_RfQResponseLine rfqResponseLine : getActiveRfqResponseLines_ForBPartnerId(bpartnerId)) { final SyncRfQ syncRfQ = createSyncRfQ(rfqResponseLine); if (syncRfQ == null) { continue; } syncBPartner.getRfqs().add(syncRfQ); } return syncBPartner; } public SyncBPartner createSyncBPartnerWithoutContracts(final I_C_BPartner bpartner) { Check.assumeNotNull(bpartner, "bpartner not null"); return createSyncBPartnerWithoutContracts(bpartner.getC_BPartner_ID()); } private SyncBPartner createSyncBPartnerWithoutContracts(final int bpartnerId) { final I_C_BPartner bpartner = getC_BPartnerById(bpartnerId); final SyncBPartner syncBPartner = new SyncBPartner(); syncBPartner.setName(bpartner.getName()); syncBPartner.setUuid(SyncUUIDs.toUUIDString(bpartner)); // Contracts: we are not populating them here, so, for now we flag them as "do not sync" syncBPartner.setSyncContracts(false); // not a vendor: no need to look at the contacts. delete the bpartner. if (!bpartner.isVendor()) { syncBPartner.setDeleted(true); return syncBPartner; } final String adLanguage = bpartner.getAD_Language(); // // Fill Users final List<I_AD_User> contacts = InterfaceWrapperHelper.createList(bpartnerDAO.retrieveContacts(bpartner), I_AD_User.class); for (final I_AD_User contact : contacts) { final SyncUser syncUser = createSyncUser(contact, adLanguage); if (syncUser == null) { continue; } syncBPartner.getUsers().add(syncUser); } // no users: also delete the BPartner if (syncBPartner.getUsers().isEmpty()) { syncBPartner.setDeleted(true); } return syncBPartner; } private SyncUser createSyncUser(final I_AD_User contact, final String adLanguage) { if (!contact.isActive() || !contact.isIsMFProcurementUser()) { return null; } final String email = contact.getEMail(); final String password = contact.getPassword(); if (Check.isEmpty(email, true)) { return null; } final SyncUser syncUser = new SyncUser(); syncUser.setLanguage(adLanguage); syncUser.setUuid(SyncUUIDs.toUUIDString(contact)); syncUser.setEmail(email); syncUser.setPassword(password); return syncUser; } private final void setFlatrateTermsFullyLoadedRequired() { this._bpartnerId2contract_fullyLoadedRequired = true; } private Multimap<Integer, I_C_Flatrate_Term> getC_Flatrate_Terms_IndexedByBPartnerId() { if (_bpartnerId2contract_fullyLoadedRequired && !_bpartnerId2contract_fullyLoaded) { _bpartnerId2contract.clear(); // clear all first final List<I_C_Flatrate_Term> terms = pmmContractsDAO.retrieveAllRunningContractsOnDate(date); for (final I_C_Flatrate_Term term : terms) { final int bpartnerId = term.getDropShip_BPartner_ID(); _bpartnerId2contract.put(bpartnerId, term); } _bpartnerId2contract_fullyLoaded = true; } return _bpartnerId2contract; } private Set<Integer> getAllBPartnerIds() { final List<I_C_BPartner> bpartnersList = pmmbPartnerDAO.retrieveAllPartnersWithProcurementUsers(); for (final I_C_BPartner bpartner : bpartnersList) { bpartners.put(bpartner.getC_BPartner_ID(), bpartner); } return ImmutableSet.copyOf(bpartners.keySet()); } private I_C_BPartner getC_BPartnerById(final int bpartnerId) { I_C_BPartner bpartner = bpartners.get(bpartnerId); if (bpartner == null) { bpartner = InterfaceWrapperHelper.create( getCtx(), bpartnerId, I_C_BPartner.class, ITrx.TRXNAME_ThreadInherited); bpartners.put(bpartnerId, bpartner); } return bpartner; } private List<I_C_Flatrate_Term> getC_Flatrate_Terms_ForBPartnerId(final int bpartnerId) { final Multimap<Integer, I_C_Flatrate_Term> bpartnerId2contract = getC_Flatrate_Terms_IndexedByBPartnerId(); if (!bpartnerId2contract.containsKey(bpartnerId)) { final List<I_C_Flatrate_Term> contracts = pmmContractsDAO.retrieveRunningContractsOnDateForBPartner(date, bpartnerId); bpartnerId2contract.putAll(bpartnerId, contracts); } return ImmutableList.copyOf(bpartnerId2contract.get(bpartnerId)); } public SyncProduct createSyncProduct(final I_PMM_Product pmmProduct) { final String product_uuid = SyncUUIDs.toUUIDString(pmmProduct); try { final SyncProduct syncProduct = syncProductsCache.get( product_uuid, new Callable<SyncProduct>() { @Override public SyncProduct call() throws Exception { return createSyncProductNoCache(pmmProduct); } }); return syncProduct.copy(); } catch (final ExecutionException ex) { throw new RuntimeException( "Failed creating " + SyncProduct.class + " for " + pmmProduct, ex.getCause()); } } private final SyncProduct createSyncProductNoCache(final I_PMM_Product pmmProduct) { final String product_uuid = SyncUUIDs.toUUIDString(pmmProduct); final I_M_Product product = pmmProduct.getM_Product(); String productName = pmmProduct.getProductName(); // Fallback to M_Product.Name (shall not happen) if (Check.isEmpty(productName, true)) { productName = product == null ? null : product.getName(); } final SyncProduct syncProduct = new SyncProduct(); final boolean valid = pmmProduct.isActive() && pmmProduct.getM_Warehouse_ID() > 0 && pmmProduct.getM_Product_ID() > 0 && pmmProduct.getM_HU_PI_Item_Product_ID() > 0; syncProduct.setUuid(product_uuid); syncProduct.setName(productName); syncProduct.setPackingInfo(pmmProduct.getPackDescription()); syncProduct.setShared( pmmProduct.getC_BPartner_ID() <= 0); // share, unless it is assigned to a particular BPartner syncProduct.setDeleted(!valid); // // Translations { final Map<String, String> syncProductNamesTrl = syncProduct.getNamesTrl(); final IModelTranslationMap productTrls = InterfaceWrapperHelper.getModelTranslationMap(product); final PMMProductNameBuilder productNameTrlBuilder = PMMProductNameBuilder.newBuilder().setPMM_Product(pmmProduct); for (final IModelTranslation productLanguageTrl : productTrls.getAllTranslations().values()) { final String adLanguage = productLanguageTrl.getAD_Language(); final String productNamePartTrl = productLanguageTrl.getTranslation(I_M_Product.COLUMNNAME_Name); if (Check.isEmpty(productNamePartTrl, true)) { continue; } final String productNameTrl = productNameTrlBuilder.setProductNamePartIfUsingMProduct(productNamePartTrl).build(); if (Check.isEmpty(productNameTrl, true)) { continue; } syncProductNamesTrl.put(adLanguage, productNameTrl.trim()); } } return syncProduct; } public List<SyncProduct> createAllSyncProducts() { final List<I_PMM_Product> allPmmProducts = pmmProductDAO .retrieveAllPMMProductsValidOnDateQuery(date) .addEqualsFilter( I_PMM_Product.COLUMNNAME_C_BPartner_ID, null) // Not bound to a particular partner (i.e. C_BPartner_ID is null) // .orderBy() .addColumn(I_PMM_Product.COLUMN_PMM_Product_ID) // have a predictable order .endOrderBy() // .create() .list(); final List<SyncProduct> syncProducts = new ArrayList<SyncProduct>(allPmmProducts.size()); for (final I_PMM_Product pmmProduct : allPmmProducts) { final SyncProduct syncProduct = createSyncProduct(pmmProduct); if (syncProduct == null) { continue; } syncProducts.add(syncProduct); } return syncProducts; } public String createSyncInfoMessage() { return Services.get(IPMMMessageDAO.class).retrieveMessagesAsString(getCtx()); } private final void setActiveRfqResponsesFullyLoadedRequired() { this._bpartnerId2activeRfqResponseLines_fullyLoadedRequired = true; } private List<I_C_RfQResponseLine> getActiveRfqResponseLines_ForBPartnerId(final int bpartnerId) { final Multimap<Integer, I_C_RfQResponseLine> bpartnerId2activeRfqResponseLines = getActiveRfqResponseLines_IndexedByBPartnerId(); if (!bpartnerId2activeRfqResponseLines.containsKey(bpartnerId)) { final List<I_C_RfQResponseLine> rfqResponseLines = pmmRfQDAO.retrieveActiveResponseLines(getCtx(), bpartnerId); bpartnerId2activeRfqResponseLines.putAll(bpartnerId, rfqResponseLines); } return ImmutableList.copyOf(bpartnerId2activeRfqResponseLines.get(bpartnerId)); } private List<I_C_RfQResponseLine> getActiveRfqResponseLines_ForRfQResponse( final I_C_RfQResponse rfqResponse) { // NOTE: we are not using the cache because usually this method is called only for one RfQ // response, // and loading the lines for all RfQResponses (even for same partner) would not be very // performant. return pmmRfQDAO.retrieveResponseLines(rfqResponse); } private Multimap<Integer, I_C_RfQResponseLine> getActiveRfqResponseLines_IndexedByBPartnerId() { if (_bpartnerId2activeRfqResponseLines_fullyLoadedRequired && !_bpartnerId2activeRfqResponseLines_fullyLoaded) { _bpartnerId2activeRfqResponseLines.clear(); // clear all first final List<I_C_RfQResponseLine> rfqResponseLines = pmmRfQDAO.retrieveAllActiveResponseLines(getCtx()); for (final I_C_RfQResponseLine rfqResponseLine : rfqResponseLines) { final int bpartnerId = rfqResponseLine.getC_BPartner_ID(); _bpartnerId2activeRfqResponseLines.put(bpartnerId, rfqResponseLine); } _bpartnerId2activeRfqResponseLines_fullyLoaded = true; } return _bpartnerId2activeRfqResponseLines; } public List<SyncRfQ> createSyncRfQs(final I_C_RfQResponse rfqResponse) { final List<SyncRfQ> syncRfQs = new ArrayList<>(); for (final I_C_RfQResponseLine rfqResponseLine : getActiveRfqResponseLines_ForRfQResponse(rfqResponse)) { final SyncRfQ syncRfQ = createSyncRfQ(rfqResponseLine); if (syncRfQ == null) { continue; } syncRfQs.add(syncRfQ); } return syncRfQs; } private final SyncRfQ createSyncRfQ(final I_C_RfQResponseLine rfqResponseLine) { if (!pmmRfQBL.isDraft(rfqResponseLine)) { // shall not happen return null; } final SyncRfQ syncRfQ = new SyncRfQ(); syncRfQ.setUuid(SyncUUIDs.toUUIDString(rfqResponseLine)); syncRfQ.setDateStart(rfqResponseLine.getDateWorkStart()); syncRfQ.setDateEnd(rfqResponseLine.getDateWorkComplete()); syncRfQ.setDateClose(rfqResponseLine.getDateResponse()); syncRfQ.setBpartner_uuid(SyncUUIDs.toUUIDString(rfqResponseLine.getC_BPartner())); final I_PMM_Product pmmProduct = rfqResponseLine.getPMM_Product(); final SyncProduct syncProduct = createSyncProduct(pmmProduct); syncRfQ.setProduct(syncProduct); syncRfQ.setQtyRequested(rfqResponseLine.getQtyRequiered()); syncRfQ.setQtyCUInfo(rfqResponseLine.getC_UOM().getUOMSymbol()); syncRfQ.setCurrencyCode(rfqResponseLine.getC_Currency().getISO_Code()); return syncRfQ; } public SyncRfQCloseEvent createSyncRfQCloseEvent( final I_C_RfQResponseLine rfqResponseLine, final boolean winnerKnown) { if (!pmmRfQBL.isCompletedOrClosed(rfqResponseLine)) { logger.warn( "Skip creating close event for {} because it's not completed or closed", rfqResponseLine); return null; } final SyncRfQCloseEvent event = new SyncRfQCloseEvent(); event.setRfq_uuid(SyncUUIDs.toUUIDString(rfqResponseLine)); event.setWinnerKnown(winnerKnown); if (winnerKnown) { event.setWinner(rfqResponseLine.isSelectedWinner()); } if (winnerKnown && event.isWinner()) { final List<SyncProductSupply> plannedSyncProductSupplies = createPlannedSyncProductSupplies(rfqResponseLine); event.getPlannedSupplies().addAll(plannedSyncProductSupplies); } return event; } private List<SyncProductSupply> createPlannedSyncProductSupplies( final I_C_RfQResponseLine rfqResponseLine) { final I_C_Flatrate_Term contract = rfqResponseLine.getC_Flatrate_Term(); Check.assumeNotNull(contract, "contract not null"); final List<I_C_RfQResponseLineQty> rfqResponseLineQtys = pmmRfQDAO.retrieveResponseLineQtys(rfqResponseLine); if (rfqResponseLineQtys.isEmpty()) { return ImmutableList.of(); } final String bpartner_uuid = SyncUUIDs.toUUIDString(contract.getDropShip_BPartner()); final String contractLine_uuid = SyncUUIDs.toUUIDString(contract); final String product_uuid = SyncUUIDs.toUUIDString(contract.getPMM_Product()); final List<SyncProductSupply> plannedSyncProductSupplies = new ArrayList<>(rfqResponseLineQtys.size()); for (final I_C_RfQResponseLineQty rfqResponseLineQty : rfqResponseLineQtys) { final SyncProductSupply syncProductSupply = new SyncProductSupply(); syncProductSupply.setBpartner_uuid(bpartner_uuid); syncProductSupply.setContractLine_uuid(contractLine_uuid); syncProductSupply.setProduct_uuid(product_uuid); syncProductSupply.setDay(rfqResponseLineQty.getDatePromised()); syncProductSupply.setQty(rfqResponseLineQty.getQtyPromised()); plannedSyncProductSupplies.add(syncProductSupply); } return plannedSyncProductSupplies; } }
public final Logger getMRPLogger() { return LogManager.getLogger(IMRPContext.LOGGERNAME); }
public class InvoiceLineBL implements IInvoiceLineBL { private static final Logger logger = LogManager.getLogger(InvoiceLineBL.class); @Override public void setTaxAmtInfo( final Properties ctx, final I_C_InvoiceLine il, final String getTrxName) { final IInvoiceBL invoiceBL = Services.get(IInvoiceBL.class); final ITaxBL taxBL = Services.get(ITaxBL.class); final int taxId = il.getC_Tax_ID(); final boolean taxIncluded = invoiceBL.isTaxIncluded(il); final BigDecimal lineNetAmt = il.getLineNetAmt(); final int taxPrecision = invoiceBL.getPrecision(il); final I_C_Tax tax = MTax.get(ctx, taxId); final BigDecimal taxAmtInfo = taxBL.calculateTax(tax, lineNetAmt, taxIncluded, taxPrecision); il.setTaxAmtInfo(taxAmtInfo); } @Override public boolean setTax( final Properties ctx, final org.compiere.model.I_C_InvoiceLine il, final String trxName) { int taxCategoryId = il.getC_TaxCategory_ID(); if (taxCategoryId <= 0 && il.getM_Product_ID() > 0) { // NOTE: we can retrieve the tax category only if we have a product taxCategoryId = getC_TaxCategory_ID(il); il.setC_TaxCategory_ID(taxCategoryId); } if (il.getM_InOutLine_ID() <= 0) { logger.debug(il + "has M_InOutLine_ID=" + il.getM_InOutLine_ID() + ": returning"); return false; } if (il.getM_Product_ID() <= 0) { // this might be the case if a descriptional il refers to an iol. logger.debug(il + "has M_Product_ID=" + il.getM_Product_ID() + ": returning"); return false; } final I_M_InOut io = il.getM_InOutLine().getM_InOut(); final I_C_Location locationFrom = Services.get(IWarehouseBL.class).getC_Location(io.getM_Warehouse()); final int countryFromId = locationFrom.getC_Country_ID(); final I_C_BPartner_Location locationTo = InterfaceWrapperHelper.create(io.getC_BPartner_Location(), I_C_BPartner_Location.class); final Timestamp shipDate = io.getMovementDate(); final int taxId = Services.get(ITaxBL.class) .retrieveTaxIdForCategory( ctx, countryFromId, io.getAD_Org_ID(), locationTo, shipDate, taxCategoryId, il.getC_Invoice().isSOTrx(), trxName, false); if (taxId <= 0) { final I_C_Invoice invoice = il.getC_Invoice(); throw new TaxNotFoundException( taxCategoryId, io.isSOTrx(), shipDate, locationFrom.getC_Location_ID(), locationTo.getC_Location_ID(), invoice.getDateInvoiced(), locationFrom.getC_Location_ID(), invoice.getC_BPartner_Location().getC_Location_ID()); } final boolean taxChange = il.getC_Tax_ID() != taxId; if (taxChange) { logger.info("Changing C_Tax_ID to " + taxId + " for " + il); il.setC_Tax_ID(taxId); final I_C_Tax tax = il.getC_Tax(); il.setC_TaxCategory_ID(tax.getC_TaxCategory_ID()); } return taxChange; } @Override public boolean isPriceLocked(I_C_InvoiceLine invoiceLine) { // // Introduced by US1184, because having the same price on Order and Invoice // no - invoice does not generally have to have the same prive not generally // // is enforced by German Law // if (invoiceLine.getC_OrderLine_ID() > 0) // return true; // // return false; return false; } @Override public int getC_TaxCategory_ID(final org.compiere.model.I_C_InvoiceLine invoiceLine) { // FIXME: we need to retrieve the C_TaxCategory_ID by using Pricing Engine if (invoiceLine.getC_Charge_ID() > 0) { return invoiceLine.getC_Charge().getC_TaxCategory_ID(); } final I_C_Invoice invoice = invoiceLine.getC_Invoice(); final IPriceListDAO priceListDAO = Services.get(IPriceListDAO.class); final Boolean processedPLVFiltering = null; // task 09533: the user doesn't know about PLV's processed flag, so we can't filter by // it if (invoice.getM_PriceList_ID() != 100) // FIXME use PriceList_None constant { final I_M_PriceList priceList = invoice.getM_PriceList(); final I_M_PriceList_Version priceListVersion = priceListDAO.retrievePriceListVersionOrNull( priceList, invoice.getDateInvoiced(), processedPLVFiltering); Check.errorIf( priceListVersion == null, "Missing PLV for M_PriceList and DateInvoiced of {}", invoice); final int m_Product_ID = invoiceLine.getM_Product_ID(); Check.assume(m_Product_ID > 0, "M_Product_ID > 0 for {}", invoiceLine); final I_M_ProductPrice productPrice = priceListDAO.retrieveProductPrice(priceListVersion, m_Product_ID); return productPrice.getC_TaxCategory_ID(); } // Fallback: try getting from Order Line if (invoiceLine.getC_OrderLine_ID() > 0) { return invoiceLine.getC_OrderLine().getC_TaxCategory_ID(); } // Fallback: try getting from Invoice -> Order if (invoiceLine.getC_Invoice().getC_Order_ID() > 0) { final Properties ctx = InterfaceWrapperHelper.getCtx(invoiceLine); final String trxName = InterfaceWrapperHelper.getTrxName(invoiceLine); final I_C_Order order = InterfaceWrapperHelper.create( ctx, invoiceLine.getC_Invoice().getC_Order_ID(), I_C_Order.class, trxName); final I_M_PriceList priceList = order.getM_PriceList(); final I_M_PriceList_Version priceListVersion = priceListDAO.retrievePriceListVersionOrNull( priceList, invoice.getDateInvoiced(), processedPLVFiltering); Check.errorIf( priceListVersion == null, "Missing PLV for M_PriceList and DateInvoiced of {}", invoice); final int m_Product_ID = invoiceLine.getM_Product_ID(); Check.assume(m_Product_ID > 0, "M_Product_ID > 0 for {}", invoiceLine); final I_M_ProductPrice productPrice = priceListDAO.retrieveProductPrice(priceListVersion, m_Product_ID); return productPrice.getC_TaxCategory_ID(); } throw new AdempiereException( "@NotFound@ @C_TaxCategory_ID@ (" + "@C_InvoiceLine_ID@:" + invoiceLine + ")"); } @Override public void setQtyInvoicedInPriceUOM(final I_C_InvoiceLine invoiceLine) { final BigDecimal qtyInvoicedInPriceUOM = calculateQtyInvoicedInPriceUOM(invoiceLine); invoiceLine.setQtyInvoicedInPriceUOM(qtyInvoicedInPriceUOM); } private BigDecimal calculateQtyInvoicedInPriceUOM(final I_C_InvoiceLine invoiceLine) { Check.assumeNotNull(invoiceLine, "invoiceLine not null"); final BigDecimal qty = invoiceLine.getQtyInvoiced(); Check.assumeNotNull(qty, "qty not null"); final I_C_UOM priceUOM = invoiceLine.getPrice_UOM(); if (invoiceLine.getPrice_UOM_ID() <= 0) { return qty; } if (invoiceLine.getM_Product_ID() <= 0) { return qty; } final I_M_Product product = invoiceLine.getM_Product(); if (product.getC_UOM_ID() <= 0) { return qty; } final Properties ctx = InterfaceWrapperHelper.getCtx(invoiceLine); final BigDecimal qtyInPriceUOM = Services.get(IUOMConversionBL.class).convertFromProductUOM(ctx, product, priceUOM, qty); return qtyInPriceUOM; } @Override public IEditablePricingContext createPricingContext(final I_C_InvoiceLine invoiceLine) { final I_C_Invoice invoice = invoiceLine.getC_Invoice(); final int priceListId = invoice.getM_PriceList_ID(); final BigDecimal qtyInvoicedInPriceUOM = calculateQtyInvoicedInPriceUOM(invoiceLine); return createPricingContext(invoiceLine, priceListId, qtyInvoicedInPriceUOM); } public IEditablePricingContext createPricingContext( I_C_InvoiceLine invoiceLine, final int priceListId, final BigDecimal priceQty) { final org.compiere.model.I_C_Invoice invoice = invoiceLine.getC_Invoice(); final boolean isSOTrx = invoice.isSOTrx(); final int productId = invoiceLine.getM_Product_ID(); int bPartnerId = invoice.getC_BPartner_ID(); final Timestamp date = invoice.getDateInvoiced(); final IEditablePricingContext pricingCtx = Services.get(IPricingBL.class) .createInitialContext( productId, bPartnerId, invoiceLine.getPrice_UOM_ID(), priceQty, isSOTrx); pricingCtx.setPriceDate(date); // 03152: setting the 'ol' to allow the subscription system to compute the right price pricingCtx.setReferencedObject(invoiceLine); pricingCtx.setM_PriceList_ID(priceListId); // PLV is only accurate if PL selected in header // metas: relay on M_PriceList_ID only, don't use M_PriceList_Version_ID // pricingCtx.setM_PriceList_Version_ID(orderLine.getM_PriceList_Version_ID()); return pricingCtx; } @Override public void updateLineNetAmt(final I_C_InvoiceLine line, final BigDecimal qtyEntered) { if (qtyEntered != null) { final Properties ctx = InterfaceWrapperHelper.getCtx(line); final I_C_Invoice invoice = line.getC_Invoice(); final int priceListId = invoice.getM_PriceList_ID(); // // We need to get the quantity in the pricing's UOM (if different) final BigDecimal convertedQty = calculateQtyInvoicedInPriceUOM(line); // this code has been borrowed from // org.compiere.model.CalloutOrder.amt final int stdPrecision = MPriceList.getStandardPrecision(ctx, priceListId); BigDecimal lineNetAmt = convertedQty.multiply(line.getPriceActual()); if (lineNetAmt.scale() > stdPrecision) { lineNetAmt = lineNetAmt.setScale(stdPrecision, BigDecimal.ROUND_HALF_UP); } logger.info("LineNetAmt=" + lineNetAmt); line.setLineNetAmt(lineNetAmt); } } @Override public void updatePrices(final I_C_InvoiceLine invoiceLine) { // Product was not set yet. There is no point to calculate the prices if (invoiceLine.getM_Product_ID() <= 0) { return; } // // Calculate Pricing Result final IEditablePricingContext pricingCtx = createPricingContext(invoiceLine); final boolean usePriceUOM = InterfaceWrapperHelper.isNew(invoiceLine); pricingCtx.setConvertPriceToContextUOM(!usePriceUOM); pricingCtx.setManualPrice(invoiceLine.isManualPrice()); if (pricingCtx.isManualPrice()) { // Task 08908: do not calculate the prices in case the price is manually set return; } final IPricingResult pricingResult = Services.get(IPricingBL.class).calculatePrice(pricingCtx); if (!pricingResult.isCalculated()) { throw new ProductNotOnPriceListException(pricingCtx, invoiceLine.getLine()); } // // PriceList final BigDecimal priceList = pricingResult.getPriceList(); invoiceLine.setPriceList(priceList); invoiceLine.setPriceLimit(pricingResult.getPriceLimit()); invoiceLine.setPrice_UOM_ID(pricingResult.getPrice_UOM_ID()); invoiceLine.setPriceEntered(pricingResult.getPriceStd()); invoiceLine.setPriceActual(pricingResult.getPriceStd()); // // Discount invoiceLine.setDiscount(pricingResult.getDiscount()); // // Calculate PriceActual from PriceEntered and Discount calculatePriceActual(invoiceLine, pricingResult.getPrecision()); invoiceLine.setPrice_UOM_ID(pricingResult.getPrice_UOM_ID()); // } private void calculatePriceActual(final I_C_InvoiceLine invoiceLine, final int precision) { final BigDecimal discount = invoiceLine.getDiscount(); final BigDecimal priceEntered = invoiceLine.getPriceEntered(); BigDecimal priceActual; if (priceEntered.signum() == 0) { priceActual = priceEntered; } else { final int precisionToUse; if (precision >= 0) { precisionToUse = precision; } else { final I_C_Invoice invoice = invoiceLine.getC_Invoice(); precisionToUse = invoice.getM_PriceList().getPricePrecision(); } priceActual = subtractDiscount(priceEntered, discount, precisionToUse); } invoiceLine.setPriceActual(priceActual); } private BigDecimal subtractDiscount( final BigDecimal baseAmount, final BigDecimal discount, final int precision) { BigDecimal multiplier = Env.ONEHUNDRED.subtract(discount); multiplier = multiplier.divide(Env.ONEHUNDRED, precision * 3, RoundingMode.HALF_UP); final BigDecimal result = baseAmount.multiply(multiplier).setScale(precision, RoundingMode.HALF_UP); return result; } }
@Validator(I_C_BPartner.class) public class C_BPartner { private static final transient Logger logger = LogManager.getLogger(C_BPartner.class); /** * If the bpartner's <code>DocumentCopies</code> changes, then this method updates all unprocessed * C_Printing_Queues which reference the bpartner. The update is performed in a dedicated * transaction, after the MV's current trx is committed. * * @task * http://dewiki908/mediawiki/index.php/08958_Druck_Warteschlange_Sortierung_Massendruck_%28103271838939%29 */ @ModelChange( timings = {ModelValidator.TYPE_AFTER_CHANGE}, ifColumnsChanged = I_C_BPartner.COLUMNNAME_DocumentCopies) public void setCopiesFromBPartner(final I_C_BPartner bPartner) { final int documentCopies = bPartner.getDocumentCopies() > 0 ? bPartner.getDocumentCopies() : 1; // default final ITrxManager trxManager = Services.get(ITrxManager.class); trxManager .getTrxListenerManager(InterfaceWrapperHelper.getTrxName(bPartner)) .registerListener( new TrxListenerAdapter() { @Override public void afterCommit(final ITrx trx) { trxManager.run( new TrxRunnable() { @Override public void run(final String localTrxName) throws Exception { final Properties ctx = InterfaceWrapperHelper.getCtx(bPartner); final IQueryBL queryBL = Services.get(IQueryBL.class); // 08958: for the starts, we only update queue items that reference invoices final IQuery<I_C_DocType> invoicedocTypeQuery = queryBL .createQueryBuilder( I_C_DocType.class, ctx, ITrx.TRXNAME_ThreadInherited) .addOnlyActiveRecordsFilter() .addInArrayFilter( I_C_DocType.COLUMNNAME_DocBaseType, X_C_DocType.DOCBASETYPE_APCreditMemo, X_C_DocType.DOCBASETYPE_APInvoice, X_C_DocType.DOCBASETYPE_ARCreditMemo, X_C_DocType.DOCBASETYPE_ARInvoice, X_C_DocType.DOCBASETYPE_ARProFormaInvoice) .create(); final int updatedCount = queryBL .createQueryBuilder( I_C_Printing_Queue.class, ctx, ITrx.TRXNAME_ThreadInherited) .addOnlyActiveRecordsFilter() .addEqualsFilter( I_C_Printing_Queue.COLUMN_C_BPartner_ID, bPartner.getC_BPartner_ID()) .addEqualsFilter(I_C_Printing_Queue.COLUMN_Processed, false) .addInSubQueryFilter( I_C_Printing_Queue.COLUMN_C_DocType_ID, I_C_DocType.COLUMN_C_DocType_ID, invoicedocTypeQuery) .addNotEqualsFilter( I_C_Printing_Queue.COLUMN_Copies, documentCopies) .create() .updateDirectly() .addSetColumnValue( I_C_Printing_Queue.COLUMNNAME_Copies, documentCopies) .setExecuteDirectly(true) // just to be sure .execute(); logger.debug( "C_BPartner={}: set C_Printing_Queue.Copies={} for {} C_Printing_Queue records", new Object[] {bPartner, documentCopies, updatedCount}); } }); } }); } }
/** * Watches current test and dumps the database to console in case of failure. * * <p>To include in your tests, you need to declare a public field like this: * * <pre> * @Rule * public final {@link TestWatcher} testWatcher = new {@link AdempiereTestWatcher}() * </pre> */ public class AdempiereTestWatcher extends TestWatcher { private static final Logger logger = LogManager.getLogger(AdempiereTestWatcher.class); /** Context variables to be printed to screen in case the test fails */ private final Map<String, Object> context = new LinkedHashMap<>(); /** * Called after a test succeed. * * <p>Does nothing at this level. */ @Override protected void succeeded(final Description description) { // nothing } /** * Called after a test failed. It: * * <ul> * <li>dump database content * </ul> */ @Override protected void failed(final Throwable e, final Description description) { POJOLookupMap.get().dumpStatus("After test failed: " + description.getDisplayName()); // // Dump retained context values for (final Entry<String, Object> entry : context.entrySet()) { final String name = entry.getKey(); final Object value = entry.getValue(); System.out.println("\n" + name + ": " + value); } } /** * Called after a test finished (successful or not). It: * * <ul> * <li>clears database content * </ul> */ @Override protected void finished(final Description description) { POJOLookupMap.get().clear(); context.clear(); } /** * Put given variable to context. * * <p>In case the test will fail, all context variables will be printed to console. * * @param name * @param value */ public void putContext(final String name, final Object value) { Check.assumeNotEmpty(name, "name is not empty"); context.put(name, value); } /** * Convenient variant for {@link #putContext(String, Object)} which considers value's class name * as the context variable <code>name</code>. * * @param value value, not null. */ public void putContext(final Object value) { if (value == null) { logger.error( "Cannot put a null value to context. This is a development error. Skipped for now", new Exception("TRACE")); return; } final String name = value.getClass().getName(); putContext(name, value); } }
/** @author tsa */ public class PrinterRoutingBL implements IPrinterRoutingBL { private final Logger log = LogManager.getLogger(getClass()); private static final String DEFAULT_PrinterType = PRINTERTYPE_General; public IPrintingService findPrintingService(final ProcessInfo pi) { final Properties ctx = Env.getCtx(); final int AD_Client_ID = Env.getAD_Client_ID(ctx); final int AD_Org_ID = Env.getAD_Org_ID(ctx); final int AD_Role_ID = Env.getAD_Role_ID(ctx); final int AD_User_ID = Env.getAD_User_ID(ctx); final int AD_Process_ID = pi.getAD_Process_ID(); final int C_DocType_ID = Services.get(IDocActionBL.class).getC_DocType_ID(ctx, pi.getTable_ID(), pi.getRecord_ID()); final String printerType = null; return findPrintingService0( ctx, AD_Client_ID, AD_Org_ID, AD_Role_ID, AD_User_ID, C_DocType_ID, AD_Process_ID, printerType); } @Override public IPrintingService findPrintingService( final Properties ctx, final int C_DocType_ID, final int AD_Process_ID, final String printerType) { final int AD_Client_ID = Env.getAD_Client_ID(ctx); final int AD_Org_ID = Env.getAD_Org_ID(ctx); final int AD_Role_ID = Env.getAD_Role_ID(ctx); final int AD_User_ID = Env.getAD_User_ID(ctx); return findPrintingService0( ctx, AD_Client_ID, AD_Org_ID, AD_Role_ID, AD_User_ID, C_DocType_ID, AD_Process_ID, printerType); } // @Cached private IPrintingService findPrintingService0( @CacheCtx final Properties ctx, final int AD_Client_ID, final int AD_Org_ID, final int AD_Role_ID, final int AD_User_ID, final int C_DocType_ID, final int AD_Process_ID, final String printerType) { final IPrinterRoutingDAO dao = Services.get(IPrinterRoutingDAO.class); final List<I_AD_PrinterRouting> rs = dao.fetchPrinterRoutings( ctx, AD_Client_ID, AD_Org_ID, AD_Role_ID, AD_User_ID, C_DocType_ID, AD_Process_ID, printerType, I_AD_PrinterRouting.class); for (final I_AD_PrinterRouting route : rs) { final IPrintingService printingService = getPrintingService(route); if (printingService != null) { if (LogManager.isLevelFine()) { log.debug("Found: " + printingService); } return printingService; } } return getDefaultPrintingService(ctx, printerType); } // set it protected to make it testable private IPrintingService getPrintingService(final I_AD_PrinterRouting route) { if (LogManager.isLevelFine()) { log.debug("Checking route: " + route); } final I_AD_Printer printer = route.getAD_Printer(); if (LogManager.isLevelFine()) { log.debug("Printer: " + printer.getPrinterName()); } final PrintService systemPrintService = getSystemPrintService(printer.getPrinterName()); if (systemPrintService == null) { log.info("Printer not found in system: " + printer.getPrinterName()); return null; } if (LogManager.isLevelFine()) { log.debug("System Print Service: " + systemPrintService); } final String printerName = systemPrintService.getName(); Boolean isDirectPrint = null; if (isDirectPrint == null && route.getIsDirectPrint() != null) { isDirectPrint = X_AD_PrinterRouting.ISDIRECTPRINT_Yes.equals(route.getIsDirectPrint()); if (LogManager.isLevelFine()) { log.debug("IsDirectPrint: " + isDirectPrint + " (From: " + route + ")"); } } if (isDirectPrint == null) { isDirectPrint = isDirectPrint(printer); } final PrintingServiceImpl printingService = new PrintingServiceImpl(printerName, printer.getPrinterType(), isDirectPrint); if (LogManager.isLevelFine()) { log.debug("Printing Service: " + printingService); } return printingService; } @Cached /* package */ PrintService getSystemPrintService(final String printerName) { final PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); if (services == null || services.length == 0) { return null; } for (final PrintService service : services) { if (service.getName().equals(printerName)) { return service; } } return null; } private boolean isDirectPrint(final I_AD_Printer printer) { Boolean isDirectPrint = null; if (printer != null && printer.getIsDirectPrint() != null) { isDirectPrint = X_AD_Printer.ISDIRECTPRINT_Yes.equals(printer.getIsDirectPrint()); if (LogManager.isLevelFine()) { log.debug("IsDirectPrint for: " + isDirectPrint + " (From: " + printer + ")"); } } if (isDirectPrint == null) { isDirectPrint = !Ini.isPropertyBool(Ini.P_PRINTPREVIEW); if (LogManager.isLevelFine()) { log.debug("IsDirectPrint: " + isDirectPrint + " (From: ini)"); } } return isDirectPrint; } private IPrintingService getDefaultPrintingService(final Properties ctx, String printerType) { if (printerType == null) { printerType = DEFAULT_PrinterType; } final String printerName = getDefaultPrinterName(printerType); if (printerName == null) { throw new AdempiereException("No default printer found for type " + printerType); // TODO: trl } final I_AD_Printer printer = Services.get(IPrinterRoutingDAO.class).findPrinterByName(ctx, printerName); final boolean isDirectPrint = isDirectPrint(printer); return new PrintingServiceImpl(printerName, printerType, isDirectPrint); } @Override public String getDefaultPrinterName() { return getDefaultPrinterName(DEFAULT_PrinterType); } @Override public String getDefaultPrinterName(String printerType) { log.debug("Looking for printerType=" + printerType); if (printerType == null) { printerType = DEFAULT_PrinterType; } final String printerName; if (PRINTERTYPE_General.equals(printerType)) { printerName = getDefaultPrinterNameFromIni(Ini.P_PRINTER); } else if (PRINTERTYPE_Label.equals(printerType)) { printerName = getDefaultPrinterNameFromIni(Ini.P_LABELPRINTER); } else { // TODO: trl throw new AdempiereException( "No default printer logic defined for PrinterType " + printerType); } log.debug("PrinterName: " + printerName); return printerName; } private String getDefaultPrinterNameFromIni(final String propName) { log.debug("Looking for " + propName + " in ini file"); String printerName = Ini.getProperty(propName); if (!Check.isEmpty(printerName)) { log.debug("Found printerName: " + printerName); return printerName; } log.debug("Looking for machine's printers"); final PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); if (services == null || services.length == 0) { // [email protected]: so what? we don't need a printer to generate PDFs // log.warn("No default printer found on this machine"); return ""; } printerName = services[0].getName(); Ini.setProperty(propName, printerName); log.debug("Found printerName: " + printerName); return printerName; } @Override public String findPrinterName( final Properties ctx, final int C_DocType_ID, final int AD_Process_ID, final String printerType) { final IPrintingService printingService = findPrintingService(ctx, C_DocType_ID, AD_Process_ID, printerType); return printingService.getPrinterName(); } @Override public String findPrinterName(final ProcessInfo pi) { final IPrintingService printingService = findPrintingService(pi); return printingService.getPrinterName(); } }
/** * Default implementation of {@link IEntityTypesCache}, which is retrieving the entity types from * database. * * @author tsa */ public class EntityTypesCache implements IEntityTypesCache { /** Shared instance */ public static final transient EntityTypesCache instance = new EntityTypesCache(); // services private final transient Logger logger = LogManager.getLogger(getClass()); /** Cache: EntityType to {@link EntityTypeEntry} */ private final CCache<String, EntityTypeEntry> cache = new CCache<>( I_AD_EntityType.Table_Name + "#EntityTypeEntry" // cacheName , 50 // initialCapacity , 0 // NoExpire (NOTE: this is important because we don't want some of our records to get // stale, because we would never load them again partially) ); /** First Not System Entity ID 10=D, 20=C, 100=U, 110=CUST, 200=A, 210=EXT, 220=XX etc */ private static final int MAX_SystemMaintained_AD_EntityType_ID = 1000000; @VisibleForTesting EntityTypesCache() { super(); // NOTE: we are lazy loading the cache because it might be that initially we don't have a // database connection anyways // loadIfNeeded(); } @Override public String toString() { return "EntityTypesCache [cache=" + cache + "]"; } private void loadIfNeeded() { // // Check if it's loaded if (!cache.isEmpty()) { return; } // // Preload the cache will all entity types synchronized (cache) { if (cache.isEmpty()) { final Map<String, EntityTypeEntry> entityTypeEntries = retrieveEntityTypeEntries(); cache.clear(); cache.putAll(entityTypeEntries); } } } /** * Retrieves all entity types from underlying data source. * * @return all entity types as a map of EntityType to {@link EntityTypeEntry}. */ @VisibleForTesting Map<String, EntityTypeEntry> retrieveEntityTypeEntries() { final Map<String, EntityTypeEntry> entityTypeEntries = new HashMap<>(50); PreparedStatement pstmt = null; ResultSet rs = null; final String sql = "SELECT * FROM AD_EntityType WHERE IsActive=? ORDER BY AD_EntityType_ID"; final Object[] params = new Object[] {true}; try { pstmt = DB.prepareStatement(sql, ITrx.TRXNAME_None); DB.setParameters(pstmt, params); rs = pstmt.executeQuery(); while (rs.next()) { final EntityTypeEntry entry = loadEntityTypeEntry(rs); entityTypeEntries.put(entry.getEntityType(), entry); } } catch (SQLException e) { throw new DBException(e, sql, params); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } return entityTypeEntries; } private final EntityTypeEntry loadEntityTypeEntry(final ResultSet rs) throws SQLException { final String entityType = rs.getString(I_AD_EntityType.COLUMNNAME_EntityType); final String modelPackage = rs.getString(I_AD_EntityType.COLUMNNAME_ModelPackage); final String webUIServletListenerClass = rs.getString(I_AD_EntityType.COLUMNNAME_WebUIServletListenerClass); final boolean displayedInUI = DisplayType.toBoolean(rs.getString(I_AD_EntityType.COLUMNNAME_IsDisplayed)); final int adEntityTypeId = rs.getInt(I_AD_EntityType.COLUMNNAME_AD_EntityType_ID); final boolean systemMaintained = adEntityTypeId < MAX_SystemMaintained_AD_EntityType_ID; final EntityTypeEntry entry = EntityTypeEntry.builder() .setEntityType(entityType) .setModelPackage(modelPackage) .setWebUIServletListenerClass(webUIServletListenerClass) .setDisplayedInUI(displayedInUI) .setSystemMaintained(systemMaintained) .build(); return entry; } @Override public List<String> getEntityTypeNames() { loadIfNeeded(); return ImmutableList.copyOf(cache.keySet()); } private EntityTypeEntry getEntityTypeEntryOrNull(final String entityType) { Check.assumeNotEmpty( entityType, "entityType not empty"); // fail because in most of the cases is a development error loadIfNeeded(); final EntityTypeEntry entry = cache.get(entityType); return entry; } private EntityTypeEntry getEntityTypeEntry(final String entityType) { final EntityTypeEntry entry = getEntityTypeEntryOrNull(entityType); if (entry == null) { final AdempiereException ex = new AdempiereException( "No EntityType entry found for entity type: " + entityType + "\n Available EntityTypes are: " + cache.keySet()); logger.warn(ex.getLocalizedMessage(), ex); } return entry; } @Override public String getModelPackage(final String entityType) { final EntityTypeEntry entry = getEntityTypeEntry(entityType); if (entry == null) { return null; } return entry.getModelPackage(); } @Override public boolean isActive(final String entityType) { final EntityTypeEntry entry = getEntityTypeEntryOrNull(entityType); if (entry == null) { return false; } return true; } @Override public boolean isDisplayedInUI(final String entityType) { final EntityTypeEntry entry = getEntityTypeEntryOrNull(entityType); if (entry == null) { return false; } return entry.isDisplayedInUI(); } public final String getDisplayedInUIEntityTypeSQLWhereClause(final String joinEntityTypeColumn) { return "exists (select 1 from AD_EntityType et where et.EntityType=" + joinEntityTypeColumn + " and et.IsActive='Y'" // EntityType shall be active + " and et." + I_AD_EntityType.COLUMNNAME_IsDisplayed + "='Y'" // shall be displayed in UI + ")"; } public boolean isSystemMaintained(final String entityType) { return getEntityTypeEntry(entityType).isSystemMaintained(); } public String getWebUIServletListenerClass(final String entityType) { return getEntityTypeEntry(entityType).getWebUIServletListenerClass(); } public static final class EntityTypeEntry { @VisibleForTesting static final Builder builder() { return new Builder(); } private final String entityType; private final String modelPackage; private final boolean displayedInUI; private final boolean systemMaintained; private final String webUIServletListenerClass; private EntityTypeEntry(final Builder builder) { super(); this.entityType = builder.entityType; Check.assumeNotEmpty(entityType, "entityType not empty"); this.modelPackage = builder.modelPackage; this.displayedInUI = builder.displayedInUI; this.systemMaintained = builder.systemMaintained; this.webUIServletListenerClass = builder.webUIServletListenerClass; } @Override public String toString() { return "EntityTypeEntry [entityType=" + entityType + ", modelPackage=" + modelPackage + "]"; } public String getEntityType() { return entityType; } public String getModelPackage() { return modelPackage; } public boolean isDisplayedInUI() { return displayedInUI; } public String getWebUIServletListenerClass() { return webUIServletListenerClass; } /** * Is System Maintained. Any Entity Type with ID < 1000000. * * @return true if D/C/U/CUST/A/EXT/XX (ID < 1000000) */ public boolean isSystemMaintained() { return systemMaintained; } public static final class Builder { private String entityType; private String modelPackage; private boolean displayedInUI = true; // default true private boolean systemMaintained = false; public String webUIServletListenerClass; private Builder() { super(); } public EntityTypeEntry build() { return new EntityTypeEntry(this); } public Builder setEntityType(String entityType) { this.entityType = entityType; return this; } public Builder setModelPackage(String modelPackage) { this.modelPackage = modelPackage; return this; } public Builder setDisplayedInUI(boolean displayedInUI) { this.displayedInUI = displayedInUI; return this; } public Builder setSystemMaintained(boolean systemMaintained) { this.systemMaintained = systemMaintained; return this; } public Builder setWebUIServletListenerClass(String webUIServletListenerClass) { this.webUIServletListenerClass = webUIServletListenerClass; return this; } } } }
/** * Warehouse Locator Control * * @author Jorg Janke * @version $Id: VLocator.java,v 1.5 2006/07/30 00:51:27 jjanke Exp $ */ public class VLocator extends JComponent implements VEditor, ActionListener, IRefreshableEditor, IZoomableEditor, ICopyPasteSupportEditorAware { /** */ private static final long serialVersionUID = 1953277256988665242L; /** IDE Constructor */ public VLocator() { this("M_Locator_ID", false, false, true, null, 0); } // VLocator /** * Constructor * * @param columnName ColumnName * @param mandatory mandatory * @param isReadOnly read only * @param isUpdateable updateable * @param mLocator locator (lookup) model * @param WindowNo window no */ public VLocator( String columnName, boolean mandatory, boolean isReadOnly, boolean isUpdateable, MLocatorLookup mLocator, int WindowNo) { super(); super.setName(columnName); m_columnName = columnName; m_mLocator = mLocator; m_WindowNo = WindowNo; // LookAndFeel.installBorder(this, "TextField.border"); this.setLayout(new BorderLayout()); // // Text VEditorUtils.setupInnerTextComponentUI(m_text); m_text.setEditable(true); m_text.setFocusable(true); m_text.addActionListener(this); this.add(m_text, BorderLayout.CENTER); // // Button { m_button = VEditorUtils.createActionButton("Locator", m_text); m_button.addActionListener(this); VEditorDialogButtonAlign.addVEditorButtonUsingBorderLayout(getClass(), this, m_button); } // // Size VEditorUtils.setupVEditorDimensionFromInnerTextDimension(this, m_text); // ReadWrite if (isReadOnly || !isUpdateable) setReadWrite(false); else setReadWrite(true); setMandatory(mandatory); setDefault_Locator_ID(); // set default locator, teo_sarca [ 1661546 ] // // Create and bind the context menu new EditorContextPopupMenu(this); } // VLocator /** Dispose */ @Override public void dispose() { m_text = null; m_button = null; m_mLocator = null; } // dispose private CTextField m_text = new CTextField(VLookup.DISPLAY_LENGTH); private VEditorActionButton m_button = null; private MLocatorLookup m_mLocator; private Object m_value; // private final String m_columnName; private int m_WindowNo; private boolean mandatory = false; private boolean readWrite = true; /** Logger */ private static final Logger log = LogManager.getLogger(VLocator.class); private GridField m_mField; /** * Enable/disable * * @param value r/w */ @Override public void setReadWrite(boolean value) { this.readWrite = value; m_button.setReadWrite(value); setBackground(false); } // setReadWrite /** * IsReadWrite * * @return true if ReadWrite */ @Override public boolean isReadWrite() { return readWrite; } // isReadWrite /** * Set Mandatory (and back bolor) * * @param mandatory true if mandatory */ @Override public void setMandatory(boolean mandatory) { this.mandatory = mandatory; setBackground(false); } // setMandatory /** * Is it mandatory * * @return true if mandatory */ @Override public boolean isMandatory() { return mandatory; } // isMandatory /** * Set Background * * @param color color */ @Override public void setBackground(Color color) { if (!color.equals(m_text.getBackground())) m_text.setBackground(color); } // setBackground /** * Set Background based on editable / mandatory / error * * @param error if true, set background to error color, otherwise mandatory/editable */ @Override public void setBackground(boolean error) { if (error) setBackground(AdempierePLAF.getFieldBackground_Error()); else if (!isReadWrite()) setBackground(AdempierePLAF.getFieldBackground_Inactive()); else if (isMandatory()) setBackground(AdempierePLAF.getFieldBackground_Mandatory()); else setBackground(AdempierePLAF.getFieldBackground_Normal()); } // setBackground /** * Set Foreground * * @param fg color */ @Override public void setForeground(Color fg) { m_text.setForeground(fg); } // setForeground /** Request Focus */ @Override public void requestFocus() { m_text.requestFocus(); } // requestFocus /** * Set Editor to value * * @param value Integer */ @Override public void setValue(Object value) { setValue(value, false); } // setValue /** * Set Value * * @param value value * @param fire data binding */ private void setValue(Object value, boolean fire) { if (m_mLocator == null) { return; } if (value != null) { m_mLocator.setOnly_Warehouse_ID(getOnly_Warehouse_ID()); m_mLocator.setOnly_Product_ID(getOnly_Product_ID()); if (!m_mLocator.isValid(value)) value = null; } // m_value = value; m_text.setText(m_mLocator.getDisplay(value)); // loads value // Data Binding try { fireVetoableChange(m_columnName, null, value); } catch (PropertyVetoException pve) { } } // setValue /** * Property Change Listener * * @param evt PropertyChangeEvent */ @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(org.compiere.model.GridField.PROPERTY)) setValue(evt.getNewValue()); // metas: request focus (2009_0027_G131) if (evt.getPropertyName().equals(org.compiere.model.GridField.REQUEST_FOCUS)) requestFocus(); // metas end } // propertyChange /** * Return Editor value * * @return value */ @Override public Object getValue() { if (getM_Locator_ID() == 0) return null; return m_value; } // getValue /** * Get M_Locator_ID * * @return id */ public int getM_Locator_ID() { if (m_value != null && m_value instanceof Integer) return ((Integer) m_value).intValue(); return 0; } // getM_Locator_ID /** * Return Display Value * * @return display value */ @Override public String getDisplay() { return m_text.getText(); } // getDisplay @Override public void refreshValue() { if (m_mLocator != null) { m_mLocator.refresh(); } } /** * ActionListener * * @param e ActionEvent */ @Override public void actionPerformed(ActionEvent e) { // Warehouse/Product int only_Warehouse_ID = getOnly_Warehouse_ID(); int only_Product_ID = getOnly_Product_ID(); log.info("Only Warehouse_ID=" + only_Warehouse_ID + ", Product_ID=" + only_Product_ID); // Text Entry ok if (e.getSource() == m_text && actionText(only_Warehouse_ID, only_Product_ID)) return; // Button - Start Dialog int M_Locator_ID = 0; if (m_value instanceof Integer) M_Locator_ID = ((Integer) m_value).intValue(); // m_mLocator.setOnly_Warehouse_ID(only_Warehouse_ID); m_mLocator.setOnly_Product_ID(getOnly_Product_ID()); VLocatorDialog ld = new VLocatorDialog( Env.getFrame(this), Services.get(IMsgBL.class).translate(Env.getCtx(), m_columnName), m_mLocator, M_Locator_ID, isMandatory(), only_Warehouse_ID); // display ld.setVisible(true); m_mLocator.setOnly_Warehouse_ID(0); // redisplay if (!ld.isChanged()) return; setValue(ld.getValue(), true); } // actionPerformed /** * Hit Enter in Text Field * * @param only_Warehouse_ID if not 0 restrict warehouse * @param only_Product_ID of not 0 restricted product * @return true if found */ private boolean actionText(int only_Warehouse_ID, int only_Product_ID) { String text = m_text.getText(); log.debug(text); // Null if (text == null || text.length() == 0) { if (isMandatory()) return false; else { setValue(null, true); return true; } } if (text.endsWith("%")) text = text.toUpperCase(); else text = text.toUpperCase() + "%"; // Look up - see MLocatorLookup.run StringBuffer sql = new StringBuffer("SELECT M_Locator_ID FROM M_Locator ") .append(" WHERE IsActive='Y' AND UPPER(Value) LIKE ") .append(DB.TO_STRING(text)); if (getOnly_Warehouse_ID() != 0) sql.append(" AND M_Warehouse_ID=?"); if (getOnly_Product_ID() != 0) sql.append(" AND (IsDefault='Y' ") // Default Locator .append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator .append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)") .append("OR EXISTS (SELECT * FROM M_Storage s ") // Storage Locator .append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))"); String finalSql = Env.getUserRolePermissions() .addAccessSQL( sql.toString(), "M_Locator", IUserRolePermissions.SQL_NOTQUALIFIED, IUserRolePermissions.SQL_RO); // int M_Locator_ID = 0; PreparedStatement pstmt = null; try { pstmt = DB.prepareStatement(finalSql, null); int index = 1; if (only_Warehouse_ID != 0) pstmt.setInt(index++, only_Warehouse_ID); if (only_Product_ID != 0) { pstmt.setInt(index++, only_Product_ID); pstmt.setInt(index++, only_Product_ID); } ResultSet rs = pstmt.executeQuery(); if (rs.next()) { M_Locator_ID = rs.getInt(1); if (rs.next()) M_Locator_ID = 0; // more than one } rs.close(); pstmt.close(); pstmt = null; } catch (SQLException ex) { log.error(finalSql, ex); } try { if (pstmt != null) pstmt.close(); } catch (SQLException ex1) { } pstmt = null; if (M_Locator_ID == 0) return false; setValue(new Integer(M_Locator_ID), true); return true; } // actionText /** * Action Listener Interface * * @param listener listener */ @Override public void addActionListener(ActionListener listener) { m_text.addActionListener(listener); } // addActionListener @Override public void addMouseListener(final MouseListener l) { m_text.addMouseListener(l); } /** Action - Zoom */ @Override public void actionZoom() { int AD_Window_ID = MTable.get(Env.getCtx(), MLocator.Table_ID).getAD_Window_ID(); if (AD_Window_ID <= 0) AD_Window_ID = 139; // hardcoded window Warehouse & Locators log.info(""); // setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); AWindow frame = new AWindow(); MQuery zoomQuery = new MQuery(); zoomQuery.addRestriction(MLocator.COLUMNNAME_M_Locator_ID, Operator.EQUAL, getValue()); zoomQuery.setRecordCount(1); // guess if (!frame.initWindow(AD_Window_ID, zoomQuery)) return; AEnv.addToWindowManager(frame); AEnv.showCenterScreen(frame); frame = null; setCursor(Cursor.getDefaultCursor()); } // actionZoom /** * Set Field/WindowNo for ValuePreference (NOP) * * @param mField Model Field */ @Override public void setField(org.compiere.model.GridField mField) { this.m_mField = mField; EditorContextPopupMenu.onGridFieldSet(this); } // setField @Override public GridField getField() { return m_mField; } /** * Get Warehouse restriction if any. * * @return M_Warehouse_ID or 0 */ private int getOnly_Warehouse_ID() { String only_Warehouse = Env.getContext(Env.getCtx(), m_WindowNo, "M_Warehouse_ID", true); int only_Warehouse_ID = 0; try { if (only_Warehouse != null && only_Warehouse.length() > 0) only_Warehouse_ID = Integer.parseInt(only_Warehouse); } catch (Exception ex) { } return only_Warehouse_ID; } // getOnly_Warehouse_ID /** * Get Product restriction if any. * * @return M_Product_ID or 0 */ private int getOnly_Product_ID() { if (!Env.isSOTrx(Env.getCtx(), m_WindowNo)) return 0; // No product restrictions for PO // String only_Product = Env.getContext(Env.getCtx(), m_WindowNo, "M_Product_ID", true); int only_Product_ID = 0; try { if (only_Product != null && only_Product.length() > 0) only_Product_ID = Integer.parseInt(only_Product); } catch (Exception ex) { } return only_Product_ID; } // getOnly_Product_ID /** * Set the default locator if this field is mandatory and we have a warehouse restriction. * * @since 3.1.4 */ private void setDefault_Locator_ID() { // teo_sarca, FR [ 1661546 ] Mandatory locator fields should use defaults if (!isMandatory() || m_mLocator == null) { return; } int M_Warehouse_ID = getOnly_Warehouse_ID(); if (M_Warehouse_ID <= 0) { return; } MWarehouse wh = MWarehouse.get(Env.getCtx(), M_Warehouse_ID); if (wh == null || wh.get_ID() <= 0) { return; } MLocator loc = wh.getDefaultLocator(); if (loc == null || loc.get_ID() <= 0) { return; } setValue(Integer.valueOf(loc.get_ID())); } // metas @Override public boolean isAutoCommit() { return true; } @Override public ICopyPasteSupportEditor getCopyPasteSupport() { return m_text == null ? NullCopyPasteSupportEditor.instance : m_text.getCopyPasteSupport(); } } // VLocator
/** * @author ts * @see "<a * href='http://dewiki908/mediawiki/index.php/Transportverpackung_%282009_0022_G61%29'>(2009_0022_G61)</a>" */ public class BinPacker implements IBinPacker { private static final Logger logger = LogManager.getLogger(BinPacker.class); public void pack(final Properties ctx, final PackingTreeModel model, final String trxName) { final DefaultMutableTreeNode unallocRoot = model.getUnPackedItems(); final DefaultMutableTreeNode availBinRoot = model.getAvailableBins(); final List<DefaultMutableTreeNode> unallocNodes = mkSortedListBigToSmall(unallocRoot); final List<DefaultMutableTreeNode> availBins = mkSortedListBigToSmall(availBinRoot); final List<DefaultMutableTreeNode> usedBins = new ArrayList<DefaultMutableTreeNode>(); while (!unallocNodes.isEmpty()) { // make another bin available for using addBinForUsage(ctx, unallocNodes, availBins, usedBins, model, trxName); // try to put all our unallocated items into the currently available bins alloc(unallocNodes, usedBins, model, trxName); } } /** * Sums up the volume and weight of all items still unpacked, selects a bin from <code>availBins * </code> and updates <code>model</code> accordingly. * * <p>If there is no bin large enough for the summed up weight and volume, the largest bin * available is added. * * @param unallocNodes * @param availBins * @param usedBins * @param model * @param trxName */ private void addBinForUsage( final Properties ctx, final List<DefaultMutableTreeNode> unallocNodes, final List<DefaultMutableTreeNode> availBins, final List<DefaultMutableTreeNode> usedBins, final PackingTreeModel model, final String trxName) { logger.debug("Computing the overall volume and weight we still need to cover"); BigDecimal unallocVolumeSum = BigDecimal.ZERO; BigDecimal unallocWeightSum = BigDecimal.ZERO; BigDecimal unallocVolumeMax = BigDecimal.ZERO; BigDecimal unallocWeightMax = BigDecimal.ZERO; for (final DefaultMutableTreeNode currentNode : unallocNodes) { final LegacyPackingItem pi = getPI(currentNode); final BigDecimal volSingle = pi.retrieveVolumeSingle(trxName); final BigDecimal weightSingle = pi.retrieveWeightSingle(trxName); unallocVolumeSum = unallocVolumeSum.add(pi.getQtySum().multiply(volSingle)); unallocWeightSum = unallocWeightSum.add(pi.getQtySum().multiply(weightSingle)); if (unallocVolumeMax.compareTo(volSingle) < 0) { unallocVolumeMax = volSingle; } if (unallocWeightMax.compareTo(weightSingle) < 0) { unallocWeightMax = weightSingle; } } logger.debug( "Still required: volume-sum=" + unallocVolumeSum + "; volume-max=" + unallocVolumeMax + "; weight-sum:" + unallocWeightSum + "; weight-max=" + unallocWeightMax); removeUnavailableBins(availBins, unallocVolumeMax, unallocWeightMax); final DefaultMutableTreeNode nexBinToUseNode = findBinNode(availBins, unallocVolumeSum, unallocWeightSum); final AvailableBins foundBin = getBin(nexBinToUseNode); foundBin.setQtyAvail(foundBin.getQtyAvail() - 1); final I_M_PackagingContainer foundPC = foundBin.getPc(); final UsedBin newPack = new UsedBin(ctx, foundPC, trxName); logger.info("Adding " + newPack); final DefaultMutableTreeNode newPackNode = new DefaultMutableTreeNode(newPack); usedBins.add(newPackNode); model.insertNodeInto(newPackNode, model.getUsedBins(), model.getUsedBins().getChildCount()); } private void alloc( final List<DefaultMutableTreeNode> unallocNodes, final List<DefaultMutableTreeNode> usedBins, final PackingTreeModel model, final String trxName) { final Set<DefaultMutableTreeNode> packedNodes = new HashSet<DefaultMutableTreeNode>(); sortUsedBins(usedBins, trxName); Iterator<DefaultMutableTreeNode> itUsedBinNodes = usedBins.iterator(); boolean progressMade = false; for (final DefaultMutableTreeNode packedNode : unallocNodes) { if (!itUsedBinNodes.hasNext()) { break; } final DefaultMutableTreeNode usedBinNode = itUsedBinNodes.next(); final UsedBin usedPack = getPack(usedBinNode); // find out how much space we have left final BigDecimal maxVolume = usedPack.getPackagingContainer().getMaxVolume(); final BigDecimal usedVolume = PackingTreeModel.getUsedVolume(usedBinNode, trxName); final BigDecimal freeVolume = maxVolume.subtract(usedVolume); final LegacyPackingItem unpackedPi = getPI(packedNode); final BigDecimal singleVol = unpackedPi.retrieveVolumeSingle(trxName); final BigDecimal binFreeQty; if (singleVol.signum() > 0) { binFreeQty = freeVolume .divide(singleVol, BigDecimal.ROUND_FLOOR) .setScale(0, BigDecimal.ROUND_FLOOR); } else { binFreeQty = new BigDecimal(Long.MAX_VALUE); } if (binFreeQty.signum() <= 0) { // there is no space left in the bins that we are currently using break; } final BigDecimal requiredQty = unpackedPi.getQtySum(); if (binFreeQty.compareTo(requiredQty) >= 0) { // the pl fits completely into our bin model.insertNodeInto(packedNode, usedBinNode, usedBinNode.getChildCount()); packedNodes.add(packedNode); // sort the used bins again because the current bin might not be // the one with the biggest free volume anymore sortUsedBins(usedBins, trxName); itUsedBinNodes = usedBins.iterator(); } else { // split the current item and move a part into a new item to be // located in our bin final Map<I_M_ShipmentSchedule, BigDecimal> qtysToTransfer = unpackedPi.subtract(binFreeQty); final LegacyPackingItem newPi = new LegacyPackingItem(qtysToTransfer, trxName); final DefaultMutableTreeNode newItemNode = new DefaultMutableTreeNode(newPi); model.insertNodeInto(newItemNode, usedBinNode, usedBinNode.getChildCount()); } progressMade = true; } unallocNodes.removeAll(packedNodes); if (!progressMade) { throw new NoContainerException(false, false); } } /** * @param unallocRoot * @return list with the biggest first */ private List<DefaultMutableTreeNode> mkSortedListBigToSmall( final DefaultMutableTreeNode unallocRoot) { final List<DefaultMutableTreeNode> unallocNodes = mkList(unallocRoot); sortList(unallocNodes, -1); return unallocNodes; } /** * sort the used bins according to their free volume. The one with the biggest free volume comes * first. * * @param nodes * @param trxName */ private void sortUsedBins(final List<DefaultMutableTreeNode> nodes, final String trxName) { Collections.sort( nodes, new Comparator<DefaultMutableTreeNode>() { public int compare(final DefaultMutableTreeNode o1, final DefaultMutableTreeNode o2) { final BigDecimal usedVol1 = PackingTreeModel.getUsedVolume(o1, trxName); final BigDecimal usedVol2 = PackingTreeModel.getUsedVolume(o2, trxName); final BigDecimal freeVol1 = getPack(o1).getPackagingContainer().getMaxVolume().subtract(usedVol1); final BigDecimal freeVol2 = getPack(o2).getPackagingContainer().getMaxVolume().subtract(usedVol2); return freeVol2.compareTo(freeVol1); } }); } /** * @param unallocNodes * @param factor if factor is <0, the nodes are sorted in reverse order */ private void sortList(final List<DefaultMutableTreeNode> unallocNodes, final int factor) { Collections.sort( unallocNodes, new Comparator<DefaultMutableTreeNode>() { @SuppressWarnings("unchecked") public int compare(DefaultMutableTreeNode o1, DefaultMutableTreeNode o2) { final Comparable p1 = (Comparable) o1.getUserObject(); final Comparable p2 = (Comparable) o2.getUserObject(); return p1.compareTo(p2) * factor; } }); } @SuppressWarnings("unchecked") private List<DefaultMutableTreeNode> mkList(final DefaultMutableTreeNode unallocRoot) { final List<DefaultMutableTreeNode> unallocNodes = new ArrayList<DefaultMutableTreeNode>(unallocRoot.getChildCount()); final Enumeration<DefaultMutableTreeNode> unallocEnum = unallocRoot.children(); while (unallocEnum.hasMoreElements()) { unallocNodes.add(unallocEnum.nextElement()); } return unallocNodes; } private LegacyPackingItem getPI(DefaultMutableTreeNode o2) { return (LegacyPackingItem) o2.getUserObject(); } private UsedBin getPack(DefaultMutableTreeNode o2) { return (UsedBin) o2.getUserObject(); } private AvailableBins getBin(DefaultMutableTreeNode n) { return (AvailableBins) n.getUserObject(); } private void removeUnavailableBins( final List<DefaultMutableTreeNode> availBins, final BigDecimal requiredVolume, final BigDecimal requiredWeigth) { final Set<DefaultMutableTreeNode> nodesToRemove = new HashSet<DefaultMutableTreeNode>(); boolean insufficientVolume = false; boolean insufficientWeight = false; for (final DefaultMutableTreeNode binNode : availBins) { final AvailableBins bins = getBin(binNode); if (bins.getQtyAvail() <= 0) { logger.info("Bins '" + bins + "' are no longer available"); nodesToRemove.add(binNode); } if (bins.getPc().getMaxVolume().compareTo(requiredVolume) < 0) { logger.info("Payload volume of available bins '" + bins + "' is too small"); nodesToRemove.add(binNode); } if (bins.getPc().getMaxWeight().compareTo(requiredWeigth) < 0) { logger.info("Payload weight of available bins '" + bins + "' is too small"); nodesToRemove.add(binNode); } } availBins.removeAll(nodesToRemove); if (availBins.isEmpty()) { throw new NoContainerException(insufficientVolume, insufficientWeight); } } /** * @param availBins the bins to choose from. This method asserts that they are sorted in * descending order. * @param vol * @param weight * @return */ private DefaultMutableTreeNode findBinNode( final List<DefaultMutableTreeNode> availBins, final BigDecimal vol, final BigDecimal weight) { if (availBins.isEmpty()) { throw new NoContainerException(false, false); } // check if everything fits into one bin, starting with the smallest one for (int i = availBins.size() - 1; i >= 0; i--) { final DefaultMutableTreeNode packNode = availBins.get(i); final AvailableBins bin = (AvailableBins) packNode.getUserObject(); final I_M_PackagingContainer pc = bin.getPc(); if (pc.getMaxVolume().compareTo(vol) >= 0 && pc.getMaxWeight().compareTo(weight) >= 0 && bin.getQtyAvail() > 0) { return packNode; } } // no bin is big enough, return the biggest one we got return availBins.get(0); } }
/** * Persistent Column Model * * @author Jorg Janke * @version $Id: MColumn.java,v 1.6 2006/08/09 05:23:49 jjanke Exp $ */ public class MColumn extends X_AD_Column { /** */ private static final long serialVersionUID = 6543789555737635129L; /** * Get MColumn from Cache * * @param ctx context * @param AD_Column_ID id * @return MColumn */ public static MColumn get(Properties ctx, int AD_Column_ID) { Integer key = new Integer(AD_Column_ID); MColumn retValue = s_cache.get(key); if (retValue != null) return retValue; retValue = new MColumn(ctx, AD_Column_ID, null); if (retValue.get_ID() != 0) s_cache.put(key, retValue); return retValue; } // get /** * Get Column Name * * @param ctx context * @param AD_Column_ID id * @return Column Name or null */ public static String getColumnName(Properties ctx, int AD_Column_ID) { MColumn col = MColumn.get(ctx, AD_Column_ID); if (col == null || col.getAD_Column_ID() <= 0) return null; return col.getColumnName(); } // getColumnName /** Cache */ private static CCache<Integer, MColumn> s_cache = new CCache<>("AD_Column", 20); /** Static Logger */ private static Logger s_log = LogManager.getLogger(MColumn.class);; /** * ************************************************************************ Standard Constructor * * @param ctx context * @param AD_Column_ID * @param trxName transaction */ public MColumn(Properties ctx, int AD_Column_ID, String trxName) { super(ctx, AD_Column_ID, trxName); if (AD_Column_ID == 0) { // setAD_Element_ID (0); // setAD_Reference_ID (0); // setColumnName (null); // setName (null); // setEntityType (null); // U setIsAlwaysUpdateable(false); // N setIsEncrypted(false); setIsIdentifier(false); setIsKey(false); setIsMandatory(false); setIsParent(false); setIsSelectionColumn(false); setIsTranslated(false); setIsUpdateable(true); // Y setVersion(Env.ZERO); } } // MColumn /** * Load Constructor * * @param ctx context * @param rs result set * @param trxName transaction */ public MColumn(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MColumn /** * Parent Constructor * * @param parent table */ public MColumn(MTable parent) { this(parent.getCtx(), 0, parent.get_TrxName()); setClientOrg(parent); setAD_Table_ID(parent.getAD_Table_ID()); setEntityType(parent.getEntityType()); } // MColumn /** * Is Standard Column * * @return true for AD_Client_ID, etc. */ public boolean isStandardColumn() { String columnName = getColumnName(); if (columnName.equals("AD_Client_ID") || columnName.equals("AD_Org_ID") || columnName.equals("IsActive") || columnName.startsWith("Created") || columnName.startsWith("Updated")) return true; return false; } // isStandardColumn /** * Is Virtual Column * * @return true if virtual column * @deprecated please use {@link IADTableDAO#isVirtualColumn(I_AD_Column)} */ @Deprecated public boolean isVirtualColumn() { final IADTableDAO tableDAO = Services.get(IADTableDAO.class); return tableDAO.isVirtualColumn(this); } // isVirtualColumn /** * Is the Column Encrypted? * * @return true if encrypted */ public boolean isEncrypted() { String s = getIsEncrypted(); return "Y".equals(s); } // isEncrypted /** * Set Encrypted * * @param IsEncrypted encrypted */ public void setIsEncrypted(boolean IsEncrypted) { setIsEncrypted(IsEncrypted ? "Y" : "N"); } // setIsEncrypted /** * Before Save * * @param newRecord new * @return true */ @Override protected boolean beforeSave(boolean newRecord) { int displayType = getAD_Reference_ID(); if (DisplayType.isLOB(displayType)) // LOBs are 0 { if (getFieldLength() != 0) setFieldLength(0); } else if (getFieldLength() == 0) { if (DisplayType.isID(displayType)) setFieldLength(10); else if (DisplayType.isNumeric(displayType)) setFieldLength(14); else if (DisplayType.isDate(displayType)) setFieldLength(7); else { throw new FillMandatoryException(COLUMNNAME_FieldLength); } } /** * Views are not updateable UPDATE AD_Column c SET IsUpdateable='N', IsAlwaysUpdateable='N' * WHERE AD_Table_ID IN (SELECT AD_Table_ID FROM AD_Table WHERE IsView='Y') */ /* Diego Ruiz - globalqss - BF [1651899] - AD_Column: Avoid dup. SeqNo for IsIdentifier='Y' */ if (isIdentifier()) { int cnt = DB.getSQLValue( get_TrxName(), "SELECT COUNT(*) FROM AD_Column " + "WHERE AD_Table_ID=?" + " AND AD_Column_ID!=?" + " AND IsIdentifier='Y'" + " AND SeqNo=?", new Object[] {getAD_Table_ID(), getAD_Column_ID(), getSeqNo()}); if (cnt > 0) { throw new AdempiereException( "@SaveErrorNotUnique@ @" + COLUMNNAME_SeqNo + "@: " + getSeqNo()); } } // Virtual Column if (isVirtualColumn()) { // Make sure there are no context variables in ColumnSQL final String columnSql = getColumnSQL(); if (columnSql != null && columnSql.indexOf(CtxName.NAME_Marker) >= 0) { throw new AdempiereException( "Context variables are not allowed in ColumnSQL: " + columnSql); } if (isMandatory()) setIsMandatory(false); if (isUpdateable()) setIsUpdateable(false); } // Updateable if (isParent() || isKey()) setIsUpdateable(false); if (isAlwaysUpdateable() && !isUpdateable()) setIsAlwaysUpdateable(false); // Encrypted if (isEncrypted()) { int dt = getAD_Reference_ID(); if (isKey() || isParent() || isStandardColumn() || isVirtualColumn() || isIdentifier() || isTranslated() || DisplayType.isLookup(dt) || DisplayType.isLOB(dt) || "DocumentNo".equalsIgnoreCase(getColumnName()) || "Value".equalsIgnoreCase(getColumnName()) || "Name".equalsIgnoreCase(getColumnName())) { log.warn("Encryption not sensible - " + getColumnName()); setIsEncrypted(false); } } // Sync Terminology if ((newRecord || is_ValueChanged("AD_Element_ID")) && getAD_Element_ID() != 0) { M_Element element = new M_Element(getCtx(), getAD_Element_ID(), get_TrxName()); setColumnName(element.getColumnName()); setName(element.getName()); setDescription(element.getDescription()); setHelp(element.getHelp()); } return true; } // beforeSave /** * After Save * * @param newRecord new * @param success success * @return success */ @Override protected boolean afterSave(boolean newRecord, boolean success) { // Update Fields if (!newRecord) { if (is_ValueChanged(MColumn.COLUMNNAME_Name) || is_ValueChanged(MColumn.COLUMNNAME_Description) || is_ValueChanged(MColumn.COLUMNNAME_Help)) { StringBuffer sql = new StringBuffer("UPDATE AD_Field SET Name=") .append(DB.TO_STRING(getName())) .append(", Description=") .append(DB.TO_STRING(getDescription())) .append(", Help=") .append(DB.TO_STRING(getHelp())) .append(" WHERE AD_Column_ID=") .append(get_ID()) .append(" AND IsCentrallyMaintained='Y'"); int no = DB.executeUpdate(sql.toString(), get_TrxName()); log.debug("afterSave - Fields updated #" + no); } } return success; } // afterSave /** * Get SQL Add command * * @param table table * @return sql */ public String getSQLAdd(I_AD_Table table) { final String tableName = table.getTableName(); final StringBuilder sql = new StringBuilder("ALTER TABLE ") .append( "public.") // if the table is already DLM'ed then there is a view with the sale name // in the dlm schema. .append(tableName) .append(" ADD ") .append(getSQLDDL()); final String constraint = getConstraint(tableName); if (constraint != null && constraint.length() > 0) { sql.append(DB.SQLSTATEMENT_SEPARATOR) .append("ALTER TABLE ") .append(tableName) .append(" ADD ") .append(constraint); } return sql.toString(); } // getSQLAdd /** * Get SQL DDL * * @return columnName datataype .. */ public String getSQLDDL() { if (isVirtualColumn()) return null; StringBuffer sql = new StringBuffer(getColumnName()).append(" ").append(getSQLDataType()); // Default String defaultValue = getDefaultValue(); if (defaultValue != null && defaultValue.length() > 0 && defaultValue.indexOf('@') == -1 // no variables && (!(DisplayType.isID(getAD_Reference_ID()) && defaultValue.equals("-1")))) // not for ID's with default -1 { if (DisplayType.isText(getAD_Reference_ID()) || getAD_Reference_ID() == DisplayType.List || getAD_Reference_ID() == DisplayType.YesNo // Two special columns: Defined as Table but DB Type is String || getColumnName().equals("EntityType") || getColumnName().equals("AD_Language") || (getAD_Reference_ID() == DisplayType.Button && !(getColumnName().endsWith("_ID")))) { if (!defaultValue.startsWith("'") && !defaultValue.endsWith("'")) defaultValue = DB.TO_STRING(defaultValue); } sql.append(" DEFAULT ").append(defaultValue); } else { if (!isMandatory()) sql.append(" DEFAULT NULL "); defaultValue = null; } // Inline Constraint if (getAD_Reference_ID() == DisplayType.YesNo) sql.append(" CHECK (").append(getColumnName()).append(" IN ('Y','N'))"); // Null if (isMandatory()) sql.append(" NOT NULL"); return sql.toString(); } // getSQLDDL /** * Get SQL Modify command * * @param table table * @param setNullOption generate null / not null statement * @return sql separated by ; */ public String getSQLModify(final I_AD_Table table, final boolean setNullOption) { final String tableName = table.getTableName(); final String columnName = getColumnName(); final int displayType = getAD_Reference_ID(); String defaultValue = getDefaultValue(); final boolean mandatory = isMandatory(); final String sqlDataType = getSQLDataType(); final StringBuilder sql = new StringBuilder(); final StringBuilder sqlBase = new StringBuilder("ALTER TABLE ").append(tableName).append(" MODIFY ").append(columnName); // Default final StringBuilder sqlDefault = new StringBuilder(sqlBase).append(" ").append(sqlDataType); if (defaultValue != null && defaultValue.length() > 0 && defaultValue.indexOf('@') == -1 // no variables && (!(DisplayType.isID(displayType) && defaultValue.equals("-1")))) // not for ID's with default -1 { if (DisplayType.isText(displayType) || displayType == DisplayType.List || displayType == DisplayType.YesNo // Two special columns: Defined as Table but DB Type is String || columnName.equals("EntityType") || columnName.equals("AD_Language") || (displayType == DisplayType.Button && !(columnName.endsWith("_ID")))) { if (!defaultValue.startsWith("'") && !defaultValue.endsWith("'")) defaultValue = DB.TO_STRING(defaultValue); } sqlDefault.append(" DEFAULT ").append(defaultValue); } else { if (!mandatory) sqlDefault.append(" DEFAULT NULL "); defaultValue = null; } sql.append(DB.convertSqlToNative(sqlDefault.toString())); // Constraint // Null Values if (mandatory && defaultValue != null && defaultValue.length() > 0) { StringBuffer sqlSet = new StringBuffer("UPDATE ") .append(tableName) .append(" SET ") .append(columnName) .append("=") .append(defaultValue) .append(" WHERE ") .append(columnName) .append(" IS NULL"); sql.append(DB.SQLSTATEMENT_SEPARATOR).append(sqlSet); } // Null if (setNullOption) { StringBuffer sqlNull = new StringBuffer(sqlBase); if (mandatory) sqlNull.append(" NOT NULL"); else sqlNull.append(" NULL"); sql.append(DB.SQLSTATEMENT_SEPARATOR).append(DB.convertSqlToNative(sqlNull.toString())); } // return sql.toString(); } // getSQLModify /** * Get SQL Data Type * * @return e.g. NVARCHAR2(60) */ private String getSQLDataType() { final String columnName = getColumnName(); final int displayType = getAD_Reference_ID(); final int fieldLength = getFieldLength(); return DB.getSQLDataType(displayType, columnName, fieldLength); } // getSQLDataType /** * Get Table Constraint * * @param tableName table name * @return table constraint */ public String getConstraint(String tableName) { if (isKey()) { final String constraintName = tableName + "_Key"; return "CONSTRAINT " + constraintName + " PRIMARY KEY (" + getColumnName() + ")"; } else if (DisplayType.isID(getAD_Reference_ID()) && !isDDL_NoForeignKey()) { // gh #539 Add missing FK constraints // create a FK-constraint, using the same view we also used to "manually" create // FK-constraints in the past. // get an FK-constraint for this table, if any // this returns something like // "ALTER TABLE A_Asset_Change ADD CONSTRAINT ADepreciationCalcT_AAssetChang FOREIGN KEY // (A_Depreciation_Calc_Type) REFERENCES A_Depreciation_Method DEFERRABLE INITIALLY DEFERRED;" final String fkConstraintDDL = DB.getSQLValueStringEx( ITrx.TRXNAME_None, "SELECT SqlText FROM db_columns_fk WHERE TableName=? AND ColumnName=?", tableName, getColumnName()); if (!Check.isEmpty(fkConstraintDDL, true)) { // remove the "ALTER TABLE ... ADD" and the trailing ";" // the (?iu) means the the patters is created with Pattern.CASE_INSENSITIVE | // Pattern.UNICODE_CASE // thanks to https://blogs.oracle.com/xuemingshen/entry/case_insensitive_matching_in_java final String constraint = fkConstraintDDL .replaceFirst("(?iu)ALTER *TABLE *" + tableName + " *ADD *", "") .replaceFirst(";$", ""); return constraint; } } return ""; } // getConstraint /** * String Representation * * @return info */ @Override public String toString() { StringBuffer sb = new StringBuffer("MColumn["); sb.append(get_ID()).append("-").append(getColumnName()).append("]"); return sb.toString(); } // toString // begin vpj-cd e-evolution /** * get Column ID * * @param String windowName * @param String columnName * @return int retValue */ public static int getColumn_ID(String TableName, String columnName) { int m_table_id = MTable.getTable_ID(TableName); if (m_table_id == 0) return 0; int retValue = 0; String SQL = "SELECT AD_Column_ID FROM AD_Column WHERE AD_Table_ID = ? AND columnname = ?"; try { PreparedStatement pstmt = DB.prepareStatement(SQL, null); pstmt.setInt(1, m_table_id); pstmt.setString(2, columnName); ResultSet rs = pstmt.executeQuery(); if (rs.next()) retValue = rs.getInt(1); rs.close(); pstmt.close(); } catch (SQLException e) { s_log.error(SQL, e); retValue = -1; } return retValue; } // end vpj-cd e-evolution /** * Get Table Id for a column * * @param ctx context * @param AD_Column_ID id * @param trxName transaction * @return MColumn */ public static int getTable_ID(Properties ctx, int AD_Column_ID, String trxName) { String sqlStmt = "SELECT AD_Table_ID FROM AD_Column WHERE AD_Column_ID=?"; return DB.getSQLValue(trxName, sqlStmt, AD_Column_ID); } /** * Sync this column with the database * * @return */ public String syncDatabase() { MTable table = new MTable(getCtx(), getAD_Table_ID(), get_TrxName()); table.set_TrxName(get_TrxName()); // otherwise table.getSQLCreate may miss current column if (table.get_ID() == 0) throw new AdempiereException("@NotFound@ @AD_Table_ID@ " + getAD_Table_ID()); // Find Column in Database Connection conn = null; try { conn = DB.getConnectionRO(); DatabaseMetaData md = conn.getMetaData(); String catalog = DB.getDatabase().getCatalog(); String schema = DB.getDatabase().getSchema(); String tableName = table.getTableName(); if (md.storesUpperCaseIdentifiers()) { tableName = tableName.toUpperCase(); } else if (md.storesLowerCaseIdentifiers()) { tableName = tableName.toLowerCase(); } int noColumns = 0; String sql = null; // ResultSet rs = md.getColumns(catalog, schema, tableName, null); while (rs.next()) { noColumns++; String columnName = rs.getString("COLUMN_NAME"); if (!columnName.equalsIgnoreCase(getColumnName())) continue; // update existing column boolean notNull = DatabaseMetaData.columnNoNulls == rs.getInt("NULLABLE"); sql = getSQLModify(table, isMandatory() != notNull); break; } rs.close(); rs = null; // No Table if (noColumns == 0) sql = table.getSQLCreate(); // No existing column else if (sql == null) sql = getSQLAdd(table); if (sql == null) return "No sql"; int no = 0; if (sql.indexOf(DB.SQLSTATEMENT_SEPARATOR) == -1) { DB.executeUpdateEx(sql, get_TrxName()); } else { String statements[] = sql.split(DB.SQLSTATEMENT_SEPARATOR); for (int i = 0; i < statements.length; i++) { DB.executeUpdateEx(statements[i], get_TrxName()); } } return sql; } catch (SQLException e) { throw new AdempiereException(e); } finally { if (conn != null) { try { conn.close(); } catch (Exception e) { } } } } public static boolean isSuggestSelectionColumn(String columnName, boolean caseSensitive) { if (Check.isEmpty(columnName, true)) return false; // if (columnName.equals("Value") || (!caseSensitive && columnName.equalsIgnoreCase("Value"))) return true; else if (columnName.equals("Name") || (!caseSensitive && columnName.equalsIgnoreCase("Name"))) return true; else if (columnName.equals("DocumentNo") || (!caseSensitive && columnName.equalsIgnoreCase("DocumentNo"))) return true; else if (columnName.equals("Description") || (!caseSensitive && columnName.equalsIgnoreCase("Description"))) return true; else if (columnName.indexOf("Name") != -1 || (!caseSensitive && columnName.toUpperCase().indexOf("Name".toUpperCase()) != -1)) return true; else return false; } } // MColumn
/** * LDAP Server Model * * @author Jorg Janke * @version $Id$ */ public class MLdapProcessor extends X_AD_LdapProcessor implements AdempiereProcessor { /** */ private static final long serialVersionUID = 7577593682255409240L; /** * Get Active LDAP Server * * @return array of Servers */ public static MLdapProcessor[] getActive(Properties ctx) { ArrayList<MLdapProcessor> list = new ArrayList<MLdapProcessor>(); String sql = "SELECT * FROM AD_LdapProcessor WHERE IsActive='Y'"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); rs = pstmt.executeQuery(); while (rs.next()) list.add(new MLdapProcessor(ctx, rs, null)); } catch (Exception e) { log.error(sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MLdapProcessor[] retValue = new MLdapProcessor[list.size()]; list.toArray(retValue); return retValue; } // getActive /** Logger */ private static Logger log = LogManager.getLogger(MLdapProcessor.class); /** * ************************************************************************ Ldap Processor * * @param ctx context * @param AD_LdapProcessor_ID id * @param trxName transaction */ public MLdapProcessor(Properties ctx, int AD_LdapProcessor_ID, String trxName) { super(ctx, AD_LdapProcessor_ID, trxName); } // MLdapProcessor /** * Ldap Processor * * @param ctx context * @param rs result set * @param trxName transaction */ public MLdapProcessor(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MLdapProcessor /** Array of Clients */ private MClient[] m_clients = null; /** Array of Interest Areas */ private MInterestArea[] m_interests = null; private int m_auth = 0; private int m_ok = 0; private int m_error = 0; /** * Get Server ID * * @return id */ public String getServerID() { return "Ldap" + get_ID(); } // getServerID /** * Get Info * * @return info */ public String getInfo() { return "Auth=" + m_auth + ", OK=" + m_ok + ", Error=" + m_error; } // getInfo /** * Get Date Next Run * * @param requery requery * @return date next run */ public Timestamp getDateNextRun(boolean requery) { if (requery) load(get_TrxName()); return getDateNextRun(); } // getDateNextRun /** * Get Logs * * @return logs */ public AdempiereProcessorLog[] getLogs() { ArrayList<MLdapProcessorLog> list = new ArrayList<MLdapProcessorLog>(); String sql = "SELECT * " + "FROM AD_LdapProcessorLog " + "WHERE AD_LdapProcessor_ID=? " + "ORDER BY Created DESC"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, get_TrxName()); pstmt.setInt(1, getAD_LdapProcessor_ID()); rs = pstmt.executeQuery(); while (rs.next()) list.add(new MLdapProcessorLog(getCtx(), rs, get_TrxName())); } catch (Exception e) { log.error(sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } MLdapProcessorLog[] retValue = new MLdapProcessorLog[list.size()]; list.toArray(retValue); return retValue; } // getLogs /** * Delete old Request Log * * @return number of records */ public int deleteLog() { if (getKeepLogDays() < 1) return 0; String sql = "DELETE FROM AD_LdapProcessorLog " + "WHERE AD_LdapProcessor_ID=" + getAD_LdapProcessor_ID() + " AND (Created+" + getKeepLogDays() + ") < now()"; int no = DB.executeUpdate(sql, get_TrxName()); return no; } // deleteLog /** * Get Frequency (n/a) * * @return 1 */ public int getFrequency() { return 1; } // getFrequency /** * Get Frequency Type (n/a) * * @return minute */ public String getFrequencyType() { return X_R_RequestProcessor.FREQUENCYTYPE_Minute; } // getFrequencyType /** * String Representation * * @return info */ public String toString() { StringBuffer sb = new StringBuffer("MLdapProcessor["); sb.append(get_ID()) .append("-") .append(getName()) .append(",Port=") .append(getLdapPort()) .append("]"); return sb.toString(); } // toString /** * ************************************************************************ Authenticate and * Authorize * * @param ldapUser MLdapUser object * @param usr user name * @param o organization = Client Name * @param ou optional organization unit = Interest Group * @return ldapUser MLdapUser with updated information */ public MLdapUser authenticate(MLdapUser ldapUser, String usr, String o, String ou) { // Ensure something to return if (ldapUser == null) ldapUser = new MLdapUser(); String error = null; String info = null; // User if (usr == null || usr.trim().length() == 0) { error = "@NotFound@ User"; ldapUser.setErrorString(error); m_error++; log.warn(error); return ldapUser; } usr = usr.trim(); // Client if (o == null || o.length() == 0) { error = "@NotFound@ O"; ldapUser.setErrorString(error); m_error++; log.warn(error); return ldapUser; } int AD_Client_ID = findClient(o); if (AD_Client_ID == 0) { error = "@NotFound@ O=" + o; ldapUser.setErrorString(error); m_error++; log.info(error); return ldapUser; } // Optional Interest Area int R_InterestArea_ID = 0; if (ou != null && ou.length() > 0) { R_InterestArea_ID = findInterestArea(AD_Client_ID, ou); if (R_InterestArea_ID == 0) { error = "@NotFound@ OU=" + ou; ldapUser.setErrorString(error); m_error++; log.info(error); return ldapUser; } } m_auth++; // Query 1 - Validate User int AD_User_ID = 0; String Value = null; String LdapUser = null; String EMail = null; String Name = null; String Password = null; boolean IsActive = false; String EMailVerify = null; // is timestamp boolean isUnique = false; // String sql = "SELECT AD_User_ID, Value, LdapUser, EMail," // 1..4 + " Name, Password, IsActive, EMailVerify " + "FROM AD_User " + "WHERE AD_Client_ID=? AND (EMail=? OR Value=? OR LdapUser=?)"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, AD_Client_ID); pstmt.setString(2, usr); pstmt.setString(3, usr); pstmt.setString(4, usr); rs = pstmt.executeQuery(); if (rs.next()) { AD_User_ID = rs.getInt(1); Value = rs.getString(2); LdapUser = rs.getString(3); EMail = rs.getString(4); // Name = rs.getString(5); Password = rs.getString(6); IsActive = "Y".equals(rs.getString(7)); EMailVerify = rs.getString(8); isUnique = rs.next(); } } catch (Exception e) { log.error(sql, e); error = "System Error"; } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } if (error != null) { m_error++; ldapUser.setErrorString(error); return ldapUser; } // if (AD_User_ID == 0) { error = "@NotFound@ User="******"User not found - " + usr; } else if (!IsActive) { error = "@NotFound@ User="******"User not active - " + usr; } else if (EMailVerify == null) { error = "@UserNotVerified@ User="******"User EMail not verified - " + usr; } else if (usr.equalsIgnoreCase(LdapUser)) info = "User verified - Ldap=" + usr + (isUnique ? "" : " - Not Unique"); else if (usr.equalsIgnoreCase(Value)) info = "User verified - Value=" + usr + (isUnique ? "" : " - Not Unique"); else if (usr.equalsIgnoreCase(EMail)) info = "User verified - EMail=" + usr + (isUnique ? "" : " - Not Unique"); else info = "User verified ?? " + usr + " - Name=" + Name + ", Ldap=" + LdapUser + ", Value=" + Value + (isUnique ? "" : " - Not Unique"); // Error if (error != null) // should use Language of the User { logAccess(AD_Client_ID, AD_User_ID, R_InterestArea_ID, info, error); ldapUser.setErrorString(Msg.translate(getCtx(), error)); return ldapUser; } // Done if (R_InterestArea_ID == 0) { logAccess(AD_Client_ID, AD_User_ID, R_InterestArea_ID, info, null); ldapUser.setOrg(o); ldapUser.setOrgUnit(ou); ldapUser.setUserId(usr); ldapUser.setPassword(Password); return ldapUser; } // Query 2 - Validate Subscription String OptOutDate = null; boolean found = false; sql = "SELECT IsActive, OptOutDate " + "FROM R_ContactInterest " + "WHERE R_InterestArea_ID=? AND AD_User_ID=?"; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, R_InterestArea_ID); pstmt.setInt(2, AD_User_ID); rs = pstmt.executeQuery(); if (rs.next()) { found = true; IsActive = "Y".equals(rs.getString(1)); OptOutDate = rs.getString(2); isUnique = rs.next(); } } catch (Exception e) { log.error(sql, e); error = "System Error (2)"; } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // System Error if (error != null) { m_error++; ldapUser.setErrorString(error); return ldapUser; } if (!found) { error = "@UserNotSubscribed@ User="******"No User Interest - " + usr + " - R_InterestArea_ID=" + R_InterestArea_ID; } else if (OptOutDate != null) { error = "@UserNotSubscribed@ User="******" @OptOutDate@=" + OptOutDate; info = "Opted out - " + usr + " - OptOutDate=" + OptOutDate; } else if (!IsActive) { error = "@UserNotSubscribed@ User="******"User Interest Not Active - " + usr; } else info = "User subscribed - " + usr; if (error != null) // should use Language of the User { logAccess(AD_Client_ID, AD_User_ID, R_InterestArea_ID, info, error); ldapUser.setErrorString(Msg.translate(getCtx(), error)); return ldapUser; } // Done logAccess(AD_Client_ID, AD_User_ID, R_InterestArea_ID, info, null); ldapUser.setOrg(o); ldapUser.setOrgUnit(ou); ldapUser.setUserId(usr); ldapUser.setPassword(Password); return ldapUser; } // authenticate /** * Find Client * * @param client client name * @return AD_Client_ID */ private int findClient(String client) { if (m_clients == null) m_clients = MClient.getAll(getCtx()); for (int i = 0; i < m_clients.length; i++) { if ((client.equalsIgnoreCase(m_clients[i].getValue()))) return m_clients[i].getAD_Client_ID(); } return 0; } // findClient /** * Find Interest Area * * @param interset Name client name * @return AD_Client_ID */ private int findInterestArea(int AD_Client_ID, String interestArea) { if (m_interests == null) m_interests = MInterestArea.getAll(getCtx()); for (int i = 0; i < m_interests.length; i++) { if (AD_Client_ID == m_interests[i].getAD_Client_ID() && interestArea.equalsIgnoreCase(m_interests[i].getValue())) return m_interests[i].getR_InterestArea_ID(); } return 0; } // findInterestArea /** * Log Access * * @param AD_Client_ID client * @param AD_User_ID user * @param R_InterestArea_ID interest area * @param info info * @param error error */ private void logAccess( int AD_Client_ID, int AD_User_ID, int R_InterestArea_ID, String info, String error) { if (error != null) { log.info(info); m_error++; } else { log.info(info); m_ok++; } // MLdapAccess access = new MLdapAccess(getCtx(), 0, null); access.setAD_Client_ID(AD_Client_ID); access.setAD_User_ID(AD_User_ID); access.setR_InterestArea_ID(R_InterestArea_ID); access.setIsError(error != null); access.setSummary(info); access.save(); } // logAccess } // MLdapProcessor
public abstract class AbstractClientUIInvoker implements IClientUIInvoker { // Services protected static final transient Logger logger = LogManager.getLogger(AbstractClientUIInvoker.class); protected final transient IDeveloperModeBL developerModeBL = Services.get(IDeveloperModeBL.class); private final transient IClientUIInstance clientUI; private boolean invokeLater; private boolean longOperation; private boolean showGlassPane = false; private OnFail onFail = OnFail.ShowErrorPopup; private IExceptionHandler exceptionHandler; private Object parentComponent; private int parentWindowNo; // private Runnable runnable = null; public AbstractClientUIInvoker(final IClientUIInstance clientUI) { super(); Check.assumeNotNull(clientUI, "clientUI not null"); this.clientUI = clientUI; } @Override public String toString() { return ObjectUtils.toString(this); } @Override public final void invoke(final Runnable runnable) { setRunnable(runnable); invoke(); } @Override public final void invoke() { Runnable runnableWrapped = getRunnable(); Check.assumeNotNull(runnableWrapped, "runnable shall be configured"); // Wrap to Long Operation // NOTE: this needs to be wrapped BEFORE "invoke later" or "glass pane" because those will // execute the runnable asynchronously if (isLongOperation()) { runnableWrapped = asLongOperationRunnable(runnableWrapped); } // Wrap to Exception handled (if needed) runnableWrapped = asExceptionHandledRunnable(runnableWrapped); // Wrap to invoke later // NOTE: this needs to be wrapped after "exception handled" because else the exception won't be // catched. if (isInvokeLater()) { runnableWrapped = asInvokeLaterRunnable(runnableWrapped); } // Wrap to showing glass pane runnable // NOTE: this needs to be wrapped after "long operation", "exception handled" and "invoke later" if (isShowGlassPane()) { runnableWrapped = asShowGlassPaneRunnable(runnableWrapped); } // // Execute it runnableWrapped.run(); } protected abstract Runnable asInvokeLaterRunnable(final Runnable runnable); protected abstract Runnable asLongOperationRunnable(final Runnable runnable); protected abstract Runnable asShowGlassPaneRunnable(Runnable runnable); private final Runnable asExceptionHandledRunnable(final Runnable runnable) { final OnFail onFail = getOnFail(); if (OnFail.ThrowException == onFail) { return runnable; } return new Runnable() { @Override public String toString() { return "ExceptionHandled[" + runnable + "]"; } @Override public void run() { try { runnable.run(); } catch (Exception e) { handleException(e); } } }; } protected final void handleException(final Exception e) { final OnFail onFail = getOnFail(); if (OnFail.ThrowException == onFail) { throw AdempiereException.wrapIfNeeded(e); } else if (OnFail.ShowErrorPopup == onFail) { clientUI.error(getParentWindowNo(), e); } else if (OnFail.SilentlyIgnore == onFail) { // Ignore it silently. Don't do logging. // logger.warn("Got error while running: " + runnable + ". Ignored.", e); return; } else if (OnFail.UseHandler == onFail) { final IExceptionHandler exceptionHandler = getExceptionHandler(); if (exceptionHandler == null) { logger.warn( "No exception handler was configurated and OnFail=UseHandler. Throwing the exception"); // fallback throw AdempiereException.wrapIfNeeded(e); } else { exceptionHandler.handleException(e); } } // Fallback: throw the exception else { throw AdempiereException.wrapIfNeeded(e); } } @Override public final IClientUIInvoker setInvokeLater(final boolean invokeLater) { this.invokeLater = invokeLater; return this; } protected final boolean isInvokeLater() { return invokeLater; } @Override public final IClientUIInvoker setLongOperation(final boolean longOperation) { this.longOperation = longOperation; return this; } protected final boolean isLongOperation() { return longOperation; } @Override public IClientUIInvoker setShowGlassPane(final boolean showGlassPane) { this.showGlassPane = showGlassPane; return this; } protected final boolean isShowGlassPane() { return showGlassPane; } @Override public final IClientUIInvoker setOnFail(OnFail onFail) { Check.assumeNotNull(onFail, "onFail not null"); this.onFail = onFail; return this; } private final OnFail getOnFail() { return onFail; } @Override public final IClientUIInvoker setExceptionHandler(IExceptionHandler exceptionHandler) { Check.assumeNotNull(exceptionHandler, "exceptionHandler not null"); this.exceptionHandler = exceptionHandler; return this; } private final IExceptionHandler getExceptionHandler() { return exceptionHandler; } @Override public abstract IClientUIInvoker setParentComponent(final Object parentComponent); @Override public abstract IClientUIInvoker setParentComponentByWindowNo(final int windowNo); protected final void setParentComponent(final int windowNo, final Object component) { this.parentWindowNo = windowNo; this.parentComponent = component; } protected final Object getParentComponent() { return parentComponent; } protected final int getParentWindowNo() { return parentWindowNo; } @Override public final IClientUIInvoker setRunnable(final Runnable runnable) { this.runnable = runnable; return this; } private final Runnable getRunnable() { return runnable; } }
/** * Misc helper used when testing ASync module * * @author tsa */ public class Helper { private final Logger logger = LogManager.getLogger(getClass()); private Properties ctx; public Helper() { super(); this.ctx = Env.getCtx(); } public Properties getCtx() { return ctx; } public void assertNothingLocked() { final PlainLockManager lockManager = (PlainLockManager) Services.get(ILockManager.class); final PlainLockDatabase lockDatabase = lockManager.getLockDatabase(); Assert.assertTrue( "No locks expecteded\n" + lockDatabase.getLockedObjectsInfo(), lockDatabase.getLocks().isEmpty()); } public I_C_Queue_Processor createQueueProcessor( final String name, final int poolSize, final int maxPoolSize, final int keepAliveTimeMillis) { final I_C_Queue_Processor queueProcessorDef = InterfaceWrapperHelper.create(ctx, I_C_Queue_Processor.class, ITrx.TRXNAME_None); queueProcessorDef.setName(name); queueProcessorDef.setPoolSize(poolSize); queueProcessorDef.setKeepAliveTimeMillis(keepAliveTimeMillis); InterfaceWrapperHelper.save(queueProcessorDef); return queueProcessorDef; } public I_C_Queue_PackageProcessor createPackageProcessor( Properties ctx, Class<? extends IWorkpackageProcessor> packageProcessorClass, String trxName) { final I_C_Queue_PackageProcessor packageProcessorDef = InterfaceWrapperHelper.create(ctx, I_C_Queue_PackageProcessor.class, trxName); packageProcessorDef.setClassname(packageProcessorClass.getCanonicalName()); InterfaceWrapperHelper.save(packageProcessorDef); return packageProcessorDef; } public I_C_Queue_PackageProcessor createPackageProcessor( Properties ctx, Class<? extends IWorkpackageProcessor> packageProcessorClass) { return createPackageProcessor(ctx, packageProcessorClass, ITrx.TRXNAME_None); } public I_C_Queue_PackageProcessor assignPackageProcessor( I_C_Queue_Processor queueProcessorDef, Class<? extends IWorkpackageProcessor> packageProcessorClass) { final Properties ctx = InterfaceWrapperHelper.getCtx(queueProcessorDef); final String trxName = InterfaceWrapperHelper.getTrxName(queueProcessorDef); final I_C_Queue_PackageProcessor packageProcessorDef = createPackageProcessor(ctx, packageProcessorClass, trxName); assignPackageProcessor(queueProcessorDef, packageProcessorDef); return packageProcessorDef; } public void assignPackageProcessor( final I_C_Queue_Processor queueProcessorDef, final I_C_Queue_PackageProcessor packageProcessorDef) { final Properties ctx = InterfaceWrapperHelper.getCtx(queueProcessorDef); final String trxName = InterfaceWrapperHelper.getTrxName(queueProcessorDef); final I_C_Queue_Processor_Assign assignment = InterfaceWrapperHelper.create(ctx, I_C_Queue_Processor_Assign.class, trxName); assignment.setC_Queue_Processor(queueProcessorDef); assignment.setC_Queue_PackageProcessor(packageProcessorDef); InterfaceWrapperHelper.save(assignment); } public List<I_C_Queue_WorkPackage> createAndEnqueueWorkpackages( final IWorkPackageQueue workpackageQueue, final int count, final boolean markReadyForProcessing) { final I_C_Queue_Block block = workpackageQueue.enqueueBlock(ctx); final List<I_C_Queue_WorkPackage> workpackages = new ArrayList<I_C_Queue_WorkPackage>(count); for (int i = 1; i <= count; i++) { final I_C_Queue_WorkPackage wp = workpackageQueue.enqueueWorkPackage(block, IWorkPackageQueue.PRIORITY_AUTO); POJOWrapper.setInstanceName(wp, "workpackage-" + i); if (markReadyForProcessing) { workpackageQueue.markReadyForProcessing(wp); } workpackages.add(wp); } return workpackages; } public void markReadyForProcessing(List<I_C_Queue_WorkPackage> workpackages) { for (I_C_Queue_WorkPackage wp : workpackages) { wp.setIsReadyForProcessing(true); InterfaceWrapperHelper.save(wp); } } public void markReadyForProcessing(I_C_Queue_WorkPackage... workpackages) { Check.assumeNotNull(workpackages, "workpackages not null"); if (workpackages.length == 0) { return; } markReadyForProcessing(Arrays.asList(workpackages)); } /** * Mark the workpackage as ready for processing and wait until the workpackage gets processed * * @param workpackageQueue * @param workpackage * @throws TimeoutException * @throws ExecutionException * @throws InterruptedException */ public void markReadyForProcessingAndWait( final IWorkPackageQueue workpackageQueue, final I_C_Queue_WorkPackage workpackage) throws InterruptedException, ExecutionException, TimeoutException { Future<IWorkpackageProcessorExecutionResult> futureResult = workpackageQueue.markReadyForProcessingAndReturn(workpackage); futureResult.get(1, TimeUnit.MINUTES); } public void markUnprocessed(final I_C_Queue_WorkPackage workpackage) { workpackage.setIsReadyForProcessing(false); InterfaceWrapperHelper.save(workpackage); workpackage.setProcessed(false); workpackage.setIsError(false); workpackage.setSkippedAt(null); workpackage.setAD_Issue(null); InterfaceWrapperHelper.save(workpackage); } /** * Method waits until the given {@code list} has reached the given {@code targetSize} or if the * given {@code timeoutMillis} has passed. If the timeout has pased without the size beeing * reached, the method throws an Exception. * * @param list * @param targetSize * @param timeoutMillis how many millis to wait for result. If ZERO, we will wait forever * @throws InterruptedException * @throws TimeoutException if the timeout exceeded */ public void waitUntilSize(final List<?> list, final int targetSize, final long timeoutMillis) throws InterruptedException, TimeoutException { Thread.sleep( 100); // wait a bit, because the processor need not only to increase list.size(), but also // flag the package as "processed" int retryCount = 0; final long beginTS = SystemTime.millis(); int lastSize = -1; int size = list.size(); retryCount++; while (size < targetSize) { long currentTS = SystemTime.millis(); if (lastSize != -1 && timeoutMillis > 0) { final long elapsedMillis = currentTS - beginTS; if (elapsedMillis >= timeoutMillis) { throw new TimeoutException( "Timeout while waiting for " + list + "to have at least " + targetSize + " items"); } } Thread.sleep(200); size = list.size(); lastSize = size; retryCount++; logger.trace("Retry " + retryCount + " => size=" + size); } logger.trace("Finished after " + retryCount + " retries => size=" + size); Thread.sleep(200); // without further delay, the future we wait for might still not be "done" } }
/** * Class responsible for loading {@link PO}. * * @author tsa */ public final class TableModelLoader { public static final transient TableModelLoader instance = new TableModelLoader(); private static final Logger log = LogManager.getLogger(TableModelLoader.class); private final TableModelClassLoader tableModelClassLoader = TableModelClassLoader.instance; private TableModelLoader() { super(); } public PO newPO(final Properties ctx, final String tableName, final String trxName) { final int recordId = 0; // marker for new records final PO po = retrievePO(ctx, tableName, recordId, trxName); return po; } public PO getPO( final Properties ctx, final String tableName, final int Record_ID, final String trxName) { boolean checkCache = true; // Respect cache interceptor's temporary disabled flag if (CacheInterceptor.isCacheDisabled()) { checkCache = false; } return getPO(ctx, tableName, Record_ID, checkCache, trxName); } /** * @param Record_ID * @param checkCache true if object shall be checked in cache first * @param trxName * @return loaded PO */ public PO getPO( final Properties ctx, final String tableName, final int Record_ID, final boolean checkCache, final String trxName) { final IModelCacheService modelCacheService = Services.get(IModelCacheService.class); if (checkCache) { final PO poCached = modelCacheService.retrieveObject(ctx, tableName, Record_ID, trxName); if (poCached != null) { return poCached; } } final PO po = retrievePO(ctx, tableName, Record_ID, trxName); modelCacheService.addToCache(po); return po; } /** * Loads the PO from database. In case some errors were encountered, they will be logged and * <code>null</code> will be returned. * * @param ctx * @param tableName * @param Record_ID * @param trxName * @return PO or null */ private final PO retrievePO( final Properties ctx, final String tableName, int Record_ID, String trxName) { final POInfo poInfo = POInfo.getPOInfo(tableName); if (Record_ID > 0 && poInfo.getKeyColumnName() == null) { log.warn("(id) - Multi-Key " + tableName); return null; } final Class<?> clazz = tableModelClassLoader.getClass(tableName); if (clazz == null) { log.info("Using GenericPO for {}", tableName); final GenericPO po = new GenericPO(tableName, ctx, Record_ID, trxName); return po; } boolean errorLogged = false; try { final Constructor<?> constructor = tableModelClassLoader.getIDConstructor(clazz); final PO po = (PO) constructor.newInstance(ctx, Record_ID, trxName); if (po != null && po.get_ID() != Record_ID && Record_ID > 0) { return null; } return po; } catch (Exception e) { final Throwable cause = e.getCause() == null ? e : e.getCause(); log.error("(id) - Table=" + tableName + ",Class=" + clazz, cause); MetasfreshLastError.saveError(log, "Error", cause); errorLogged = true; } if (!errorLogged) { log.error("(id) - Not found - Table=" + tableName + ", Record_ID=" + Record_ID); } return null; } // getPO /** * Get PO Class Instance * * @param ctx * @param tableName * @param rs result set * @param trxName transaction * @return PO for Record; never return null */ public PO getPO(final Properties ctx, final String tableName, ResultSet rs, String trxName) { final PO po = retrievePO(ctx, tableName, rs, trxName); final IModelCacheService modelCacheService = Services.get(IModelCacheService.class); modelCacheService.addToCache(po); return po; } /** * Retrieve model from given result set. * * @param ctx * @param tableName * @param rs * @param trxName * @return loaded model; never return null */ private final PO retrievePO( final Properties ctx, final String tableName, final ResultSet rs, final String trxName) { final Class<?> clazz = tableModelClassLoader.getClass(tableName); if (clazz == null) { log.info("Using GenericPO for {}", tableName); final GenericPO po = new GenericPO(tableName, ctx, rs, trxName); return po; } try { final Constructor<?> constructor = tableModelClassLoader.getResultSetConstructor(clazz); final PO po = (PO) constructor.newInstance(ctx, rs, trxName); return po; } catch (final Exception e) { throw new AdempiereException( "Error while loading model from ResultSet" + "\n@TableName@: " + tableName + "\nClass: " + clazz, e); } } // getPO /** * Get PO Class Instance * * @param whereClause where clause * @param trxName transaction * @return PO for Record or null */ public PO getPO( final Properties ctx, final String tableName, String whereClause, String trxName) { final Object[] params = null; return getPO(ctx, tableName, whereClause, params, trxName); } // getPO /** * Get PO class instance * * @param whereClause * @param params * @param trxName * @return */ public PO getPO( final Properties ctx, final String tableName, String whereClause, Object[] params, String trxName) { final PO po = retrievePO(ctx, tableName, whereClause, params, trxName); if (po != null) { final IModelCacheService modelCacheService = Services.get(IModelCacheService.class); modelCacheService.addToCache(po); } return po; } private final PO retrievePO( final Properties ctx, final String tableName, final String whereClause, final Object[] params, final String trxName) { if (whereClause == null || whereClause.length() == 0) { return null; } // PO po = null; final POInfo info = POInfo.getPOInfo(tableName); if (info == null) { return null; } final StringBuilder sqlBuffer = info.buildSelect(); sqlBuffer.append(" WHERE ").append(whereClause); final String sql = sqlBuffer.toString(); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, trxName); DB.setParameters(pstmt, params); rs = pstmt.executeQuery(); if (rs.next()) { po = getPO(ctx, tableName, rs, trxName); } } catch (Exception e) { log.error(sql, e); MetasfreshLastError.saveError(log, "Error", e); } finally { DB.close(rs, pstmt); } return po; } public final <ModelType> ModelType retrieveModel( final Properties ctx, final String tableName, final Class<?> modelClass, final ResultSet rs, final String trxName) { final PO po = getPO(ctx, tableName, rs, trxName); // // Case: we have a modelClass specified if (modelClass != null) { final Class<? extends PO> poClass = po.getClass(); if (poClass.isAssignableFrom(modelClass)) { @SuppressWarnings("unchecked") final ModelType model = (ModelType) po; return model; } else { @SuppressWarnings("unchecked") final ModelType model = (ModelType) InterfaceWrapperHelper.create(po, modelClass); return model; } } // // Case: no "clazz" and no "modelClass" else { if (log.isDebugEnabled()) { final AdempiereException ex = new AdempiereException( "Query does not have a modelClass defined and no 'clazz' was specified as parameter." + "We need to avoid this case, but for now we are trying to do a force casting" + "\nQuery: " + this + "\nPO: " + po); log.debug(ex.getLocalizedMessage(), ex); } @SuppressWarnings("unchecked") final ModelType model = (ModelType) po; return model; } } }
/** * Customer Sub Panel * * @author Comunidad de Desarrollo OpenXpertya *Basado en Codigo Original Modificado, Revisado y * Optimizado de: *Copyright � Jorg Janke * @version $Id: SubBPartner.java,v 1.1 2004/07/12 04:10:04 jjanke Exp $ */ public class SubOrder extends PosSubPanel implements ActionListener, FocusListener { /** */ private static final long serialVersionUID = 5895558315889871887L; /** * Constructor * * @param posPanel POS Panel */ public SubOrder(PosBasePanel posPanel) { super(posPanel); } // PosSubCustomer private CButton f_history; private CTextField f_name; private CButton f_bNew; private CButton f_bSearch; private CComboBox f_location; private CComboBox f_user; private CButton f_cashPayment; private CButton f_process; private CButton f_print; private CTextField f_DocumentNo; private CButton f_logout; private JFormattedTextField f_net; private JFormattedTextField f_tax; private JFormattedTextField f_total; private CTextField f_RepName; /** The Business Partner */ private MBPartner m_bpartner; /** Price List Version to use */ private int m_M_PriceList_Version_ID = 0; private CTextField f_currency = new CTextField(); private CButton f_bEdit; private CButton f_bSettings; /** Logger */ private static Logger log = LogManager.getLogger(SubOrder.class); /** Initialize */ @Override public void init() { // Content MigLayout layout = new MigLayout("ins 0 0", "[fill|fill|fill|fill]", "[nogrid]unrel[||]"); setLayout(layout); Font bigFont = AdempierePLAF.getFont_Field().deriveFont(16f); String buttonSize = "w 50!, h 50!,"; // NEW f_bNew = createButtonAction("New", KeyStroke.getKeyStroke(KeyEvent.VK_F2, Event.F2)); add(f_bNew, buttonSize); // EDIT f_bEdit = createButtonAction("Edit", null); add(f_bEdit, buttonSize); f_bEdit.setEnabled(false); // HISTORY f_history = createButtonAction("History", null); add(f_history, buttonSize); // CANCEL f_process = createButtonAction("Cancel", null); add(f_process, buttonSize); f_process.setEnabled(false); // PAYMENT f_cashPayment = createButtonAction("Payment", null); f_cashPayment.setActionCommand("Cash"); add(f_cashPayment, buttonSize); f_cashPayment.setEnabled(false); // PRINT f_print = createButtonAction("Print", null); add(f_print, buttonSize); f_print.setEnabled(false); // Settings f_bSettings = createButtonAction("Preference", null); add(f_bSettings, buttonSize); // f_logout = createButtonAction("Logout", null); add(f_logout, buttonSize + ", gapx 25, wrap"); // DOC NO add(new CLabel(Msg.getMsg(Env.getCtx(), "DocumentNo")), ""); f_DocumentNo = new CTextField(""); f_DocumentNo.setName("DocumentNo"); f_DocumentNo.setEditable(false); add(f_DocumentNo, "growx, pushx"); CLabel lNet = new CLabel(Msg.translate(Env.getCtx(), "SubTotal")); add(lNet, ""); f_net = new JFormattedTextField(DisplayType.getNumberFormat(DisplayType.Amount)); f_net.setHorizontalAlignment(JTextField.TRAILING); f_net.setEditable(false); f_net.setFocusable(false); lNet.setLabelFor(f_net); add(f_net, "wrap, growx, pushx"); f_net.setValue(Env.ZERO); // /* // BPARTNER f_bSearch = createButtonAction ("BPartner", KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.SHIFT_MASK+Event.CTRL_MASK)); add (f_bSearch,buttonSize + ", spany 2"); */ /* * f_name.setName("Name"); f_name.addActionListener(this); f_name.addFocusListener(this); add (f_name, "wrap"); */ // SALES REP add(new CLabel(Msg.translate(Env.getCtx(), "SalesRep_ID")), ""); f_RepName = new CTextField(""); f_RepName.setName("SalesRep"); f_RepName.setEditable(false); add(f_RepName, "growx, pushx"); CLabel lTax = new CLabel(Msg.translate(Env.getCtx(), "TaxAmt")); add(lTax); f_tax = new JFormattedTextField(DisplayType.getNumberFormat(DisplayType.Amount)); f_tax.setHorizontalAlignment(JTextField.TRAILING); f_tax.setEditable(false); f_tax.setFocusable(false); lTax.setLabelFor(f_tax); add(f_tax, "wrap, growx, pushx"); f_tax.setValue(Env.ZERO); // /* f_location = new CComboBox(); add (f_location, " wrap"); */ // BP add(new CLabel(Msg.translate(Env.getCtx(), "C_BPartner_ID")), ""); f_name = new CTextField(); f_name.setEditable(false); f_name.setName("Name"); add(f_name, "growx, pushx"); // CLabel lTotal = new CLabel(Msg.translate(Env.getCtx(), "GrandTotal")); lTotal.setFont(bigFont); add(lTotal, ""); f_total = new JFormattedTextField(DisplayType.getNumberFormat(DisplayType.Amount)); f_total.setHorizontalAlignment(JTextField.TRAILING); f_total.setFont(bigFont); f_total.setEditable(false); f_total.setFocusable(false); lTotal.setLabelFor(f_total); add(f_total, "growx, pushx"); f_total.setValue(Env.ZERO); /* // f_user = new CComboBox(); add (f_user, "skip 1"); */ } // init /** Dispose - Free Resources */ @Override public void dispose() { if (f_name != null) f_name.removeFocusListener(this); f_name = null; removeAll(); super.dispose(); } // dispose /** * ************************************************************************ Action Listener * * @param e event */ @Override public void actionPerformed(ActionEvent e) { String action = e.getActionCommand(); if (action == null || action.length() == 0) return; log.info("PosSubCustomer - actionPerformed: " + action); // New if (action.equals("New")) { p_posPanel.newOrder(); // red1 New POS Order instead - B_Partner already has direct field return; } // Register if (action.equals("History")) { PosQuery qt = new QueryTicket(p_posPanel); qt.setVisible(true); return; } else if (action.equals("Cancel")) deleteOrder(); else if (action.equals("Cash")) payOrder(); else if (action.equals("Print")) printOrder(); else if (action.equals("BPartner")) { PosQuery qt = new QueryBPartner(p_posPanel); qt.setVisible(true); } // Logout else if (action.equals("Logout")) { p_posPanel.dispose(); return; } // Name else if (e.getSource() == f_name) findBPartner(); p_posPanel.updateInfo(); } // actionPerformed /** */ private void printOrder() { { if (isOrderFullyPaid()) { updateOrder(); printTicket(); openCashDrawer(); } } } /** */ private void payOrder() { // Check if order is completed, if so, print and open drawer, create an empty order and set // cashGiven to zero if (p_posPanel.m_order != null) { if (!p_posPanel.m_order.isProcessed() && !p_posPanel.m_order.processOrder()) { ADialog.warn(0, p_posPanel, "PosOrderProcessFailed"); return; } if (PosPayment.pay(p_posPanel)) { printTicket(); p_posPanel.setOrder(0); } } } /** */ private void deleteOrder() { if (p_posPanel != null && ADialog.ask(0, this, "Delete order?")) p_posPanel.m_order.deleteOrder(); // p_posPanel.newOrder(); } /** * Focus Gained * * @param e */ @Override public void focusGained(FocusEvent e) {} // focusGained /** * Focus Lost * * @param e */ @Override public void focusLost(FocusEvent e) { if (e.isTemporary()) return; log.info(e.toString()); findBPartner(); } // focusLost /** Find/Set BPartner */ private void findBPartner() { String query = f_name.getText(); if (query == null || query.length() == 0) return; // unchanged if (m_bpartner != null && m_bpartner.getName().equals(query)) return; query = query.toUpperCase(); // Test Number boolean allNumber = true; boolean noNumber = true; char[] qq = query.toCharArray(); for (int i = 0; i < qq.length; i++) { if (Character.isDigit(qq[i])) { noNumber = false; break; } } try { Integer.parseInt(query); } catch (Exception e) { allNumber = false; } String Value = query; String Name = (allNumber ? null : query); String EMail = (query.indexOf('@') != -1 ? query : null); String Phone = (noNumber ? null : query); String City = null; // // TODO: contact have been remove from rv_bpartner MBPartnerInfo[] results = MBPartnerInfo.find(p_ctx, Value, Name, /*Contact, */ null, EMail, Phone, City); // Set Result if (results.length == 0) { setC_BPartner_ID(0); } else if (results.length == 1) { setC_BPartner_ID(results[0].getC_BPartner_ID()); f_name.setText(results[0].getName()); } else // more than one { QueryBPartner qt = new QueryBPartner(p_posPanel); qt.setResults(results); qt.setVisible(true); } } // findBPartner /** * ************************************************************************ Set BPartner * * @param C_BPartner_ID id */ public void setC_BPartner_ID(int C_BPartner_ID) { log.debug("PosSubCustomer.setC_BPartner_ID=" + C_BPartner_ID); if (C_BPartner_ID == 0) m_bpartner = null; else { m_bpartner = new MBPartner(p_ctx, C_BPartner_ID, null); if (m_bpartner.get_ID() == 0) m_bpartner = null; } // Set Info if (m_bpartner != null) { f_name.setText(m_bpartner.getName()); } else { f_name.setText(null); } // Sets Currency m_M_PriceList_Version_ID = 0; getM_PriceList_Version_ID(); // fillCombos(); if (p_posPanel.m_order != null && m_bpartner != null) p_posPanel.m_order.setBPartner( m_bpartner); // added by ConSerTi to update the client in the request } // setC_BPartner_ID /** Fill Combos (Location, User) */ private void fillCombos() { Vector<KeyNamePair> locationVector = new Vector<KeyNamePair>(); if (m_bpartner != null) { MBPartnerLocation[] locations = m_bpartner.getLocations(false); for (int i = 0; i < locations.length; i++) locationVector.add( new KeyNamePair(locations[i].getC_BPartner_Location_ID(), locations[i].getName())); } DefaultComboBoxModel locationModel = new DefaultComboBoxModel(locationVector); f_location.setModel(locationModel); // Vector<KeyNamePair> userVector = new Vector<KeyNamePair>(); if (m_bpartner != null) { MUser[] users = m_bpartner.getContacts(false); for (int i = 0; i < users.length; i++) userVector.add(new KeyNamePair(users[i].getAD_User_ID(), users[i].getName())); } DefaultComboBoxModel userModel = new DefaultComboBoxModel(userVector); f_user.setModel(userModel); } // fillCombos /** * Get BPartner * * @return C_BPartner_ID */ public int getC_BPartner_ID() { if (m_bpartner != null) return m_bpartner.getC_BPartner_ID(); return 0; } // getC_BPartner_ID /** * Get BPartner * * @return BPartner */ public MBPartner getBPartner() { return m_bpartner; } // getBPartner /** * Get BPartner Location * * @return C_BPartner_Location_ID */ public int getC_BPartner_Location_ID() { if (m_bpartner != null) { KeyNamePair pp = (KeyNamePair) f_location.getSelectedItem(); if (pp != null) return pp.getKey(); } return 0; } // getC_BPartner_Location_ID /** * Get BPartner Contact * * @return AD_User_ID */ public int getAD_User_ID() { if (m_bpartner != null) { KeyNamePair pp = (KeyNamePair) f_user.getSelectedItem(); if (pp != null) return pp.getKey(); } return 0; } // getC_BPartner_Location_ID /** * Get M_PriceList_Version_ID. Set Currency * * @return plv */ public int getM_PriceList_Version_ID() { if (m_M_PriceList_Version_ID == 0) { int M_PriceList_ID = p_pos.getM_PriceList_ID(); if (m_bpartner != null && m_bpartner.getM_PriceList_ID() != 0) M_PriceList_ID = m_bpartner.getM_PriceList_ID(); // MPriceList pl = MPriceList.get(p_ctx, M_PriceList_ID, null); setCurrency(Services.get(ICurrencyDAO.class).getISO_Code(p_ctx, pl.getC_Currency_ID())); f_name.setToolTipText(pl.getName()); // MPriceListVersion plv = pl.getPriceListVersion(p_posPanel.getToday()); if (plv != null && plv.getM_PriceList_Version_ID() != 0) m_M_PriceList_Version_ID = plv.getM_PriceList_Version_ID(); } return m_M_PriceList_Version_ID; } // getM_PriceList_Version_ID /** * ************************************************************************* Set Currency * * @param currency currency */ public void setCurrency(String currency) { if (currency == null) f_currency.setText("---"); else f_currency.setText(currency); } // setCurrency /** * Print Ticket * * @author Comunidad de Desarrollo OpenXpertya *Basado en Codigo Original Modificado, Revisado y * Optimizado de: *Copyright � ConSerTi */ public void printTicket() { if (p_posPanel.m_order == null) return; MOrder order = p_posPanel.m_order; // int windowNo = p_posPanel.getWindowNo(); // Properties m_ctx = p_posPanel.getPropiedades(); if (order != null) { try { // TODO: drop it - https://github.com/metasfresh/metasfresh/issues/456 throw new UnsupportedOperationException(); // /* // if (p_pos.getAD_PrintLabel_ID() != 0) // PrintLabel.printLabelTicket(order.getC_Order_ID(), p_pos.getAD_PrintLabel_ID()); // */ // //print standard document // ReportCtl.startDocumentPrint(ReportEngine.ORDER, order.getC_Order_ID(), null, // Env.getWindowNo(this), true); } catch (Exception e) { log.error("PrintTicket - Error Printing Ticket"); } } } /** * Is order fully pay ? Calculates if the given money is sufficient to pay the order * * @author Comunidad de Desarrollo OpenXpertya *Basado en Codigo Original Modificado, Revisado y * Optimizado de: *Copyright � ConSerTi */ public boolean isOrderFullyPaid() { /*TODO BigDecimal given = new BigDecimal(f_cashGiven.getValue().toString()); boolean paid = false; if (p_posPanel != null && p_posPanel.f_curLine != null) { MOrder order = p_posPanel.f_curLine.getOrder(); BigDecimal total = new BigDecimal(0); if (order != null) total = order.getGrandTotal(); paid = given.doubleValue() >= total.doubleValue(); } return paid; */ return true; } /** * Display cash return Display the difference between tender amount and bill amount * * @author Comunidad de Desarrollo OpenXpertya *Basado en Codigo Original Modificado, Revisado y * Optimizado de: *Copyright � ConSerTi */ public void updateOrder() { if (p_posPanel != null) { MOrder order = p_posPanel.m_order; if (order != null) { f_DocumentNo.setText(order.getDocumentNo()); setC_BPartner_ID(order.getC_BPartner_ID()); f_bNew.setEnabled(order.getLines().length != 0); f_bEdit.setEnabled(true); f_history.setEnabled(order.getLines().length != 0); f_process.setEnabled(true); f_print.setEnabled(order.isProcessed()); f_cashPayment.setEnabled(order.getLines().length != 0); } else { f_DocumentNo.setText(null); setC_BPartner_ID(0); f_bNew.setEnabled(true); f_bEdit.setEnabled(false); f_history.setEnabled(true); f_process.setEnabled(false); f_print.setEnabled(false); f_cashPayment.setEnabled(false); } } } /** * Abrir caja Abre la caja registradora * * @author Comunidad de Desarrollo OpenXpertya *Basado en Codigo Original Modificado, Revisado y * Optimizado de: *Copyright � ConSerTi */ public void openCashDrawer() { String port = "/dev/lp"; byte data[] = new byte[] {0x1B, 0x40, 0x1C}; try { FileOutputStream m_out = null; if (m_out == null) { m_out = new FileOutputStream(port); // No poner append = true. } m_out.write(data); } catch (IOException e) { } } /** Set Sums from Table */ void setSums(PosOrderModel order) { int noLines = p_posPanel.f_curLine.m_table.getRowCount(); if (order == null || noLines == 0) { f_net.setValue(Env.ZERO); f_total.setValue(Env.ZERO); f_tax.setValue(Env.ZERO); } else { // order.getMOrder().prepareIt(); f_net.setValue(order.getSubtotal()); f_total.setValue(order.getGrandTotal()); f_tax.setValue(order.getTaxAmt()); } } // setSums } // PosSubCustomer
/** * Cost Engine * * @author [email protected] http://www.e-evolution.com */ public class CostEngine { /** Logger */ protected transient Logger log = LogManager.getLogger(getClass()); public String getCostingMethod() { return MCostElement.COSTINGMETHOD_StandardCosting; } public BigDecimal getResourceStandardCostRate( I_PP_Cost_Collector cc, int S_Resource_ID, CostDimension d, String trxName) { final Properties ctx = InterfaceWrapperHelper.getCtx(cc); final I_M_Product resourceProduct = MProduct.forS_Resource_ID(ctx, S_Resource_ID, ITrx.TRXNAME_None); return getProductStandardCostPrice( cc, resourceProduct, MAcctSchema.get(ctx, d.getC_AcctSchema_ID()), MCostElement.get(ctx, d.getM_CostElement_ID())); } public BigDecimal getResourceActualCostRate( I_PP_Cost_Collector cc, int S_Resource_ID, CostDimension d, String trxName) { if (S_Resource_ID <= 0) return Env.ZERO; final MProduct resourceProduct = MProduct.forS_Resource_ID(Env.getCtx(), S_Resource_ID, null); return getProductActualCostPrice( cc, resourceProduct, MAcctSchema.get(Env.getCtx(), d.getC_AcctSchema_ID()), MCostElement.get(Env.getCtx(), d.getM_CostElement_ID()), trxName); } public BigDecimal getProductActualCostPrice( final I_PP_Cost_Collector cc, final I_M_Product product, final I_C_AcctSchema as, final I_M_CostElement element, final String trxName) { final boolean failIfNoCostFound = true; return getProductActualCostPrice(cc, product, as, element, failIfNoCostFound, trxName); } public BigDecimal getProductActualCostPriceOrZero( final I_PP_Cost_Collector cc, final I_M_Product product, final I_C_AcctSchema as, final I_M_CostElement element, final String trxName) { final boolean failIfNoCostFound = false; final BigDecimal price = getProductActualCostPrice(cc, product, as, element, failIfNoCostFound, trxName); if (price == null) { return BigDecimal.ZERO; } return price; } /** * @param cc * @param product * @param as * @param element * @param failIfNoCostFound * @param trxName * @return cost price or null if no cost was found and <code>failIfNoCostFound</code> is <code> * true</code>. */ public BigDecimal getProductActualCostPrice( final I_PP_Cost_Collector cc, final I_M_Product product, final I_C_AcctSchema as, final I_M_CostElement element, final boolean failIfNoCostFound, final String trxName) { final CostDimension d = new CostDimension( product, as, as.getM_CostType_ID(), cc.getAD_Org_ID(), // AD_Org_ID, cc.getM_AttributeSetInstance_ID(), // M_ASI_ID, element.getM_CostElement_ID()); final I_M_Cost cost = d.toQuery(I_M_Cost.class, trxName).firstOnly(I_M_Cost.class); if (cost == null) { if (!failIfNoCostFound) { return null; } throw new LiberoException( "@NotFound@ @M_Cost@ - " + "@M_AcctSchema_ID@=" + as + ", @M_CostElement_ID@=" + element + ", @M_Product_ID@=" + product + ", Dimension=" + d); } final BigDecimal price = cost.getCurrentCostPrice().add(cost.getCurrentCostPriceLL()); return roundCost(price, as.getC_AcctSchema_ID()); } public BigDecimal getProductStandardCostPrice( I_PP_Cost_Collector cc, I_M_Product product, I_C_AcctSchema as, I_M_CostElement element) { final String trxName = InterfaceWrapperHelper.getTrxName(cc); final CostDimension d = new CostDimension( product, as, as.getM_CostType_ID(), 0, // AD_Org_ID, 0, // M_ASI_ID, element.getM_CostElement_ID()); final I_PP_Order_Cost oc = d.toQueryBuilder(I_PP_Order_Cost.class, trxName) .addEqualsFilter(I_PP_Order_Cost.COLUMNNAME_PP_Order_ID, cc.getPP_Order_ID()) .create() .firstOnly(I_PP_Order_Cost.class); if (oc == null) { return BigDecimal.ZERO; } final BigDecimal costs = oc.getCurrentCostPrice().add(oc.getCurrentCostPriceLL()); return roundCost(costs, as.getC_AcctSchema_ID()); } protected BigDecimal roundCost(BigDecimal price, int C_AcctSchema_ID) { // Fix Cost Precision int precision = MAcctSchema.get(Env.getCtx(), C_AcctSchema_ID).getCostingPrecision(); BigDecimal priceRounded = price; if (priceRounded.scale() > precision) { priceRounded = priceRounded.setScale(precision, RoundingMode.HALF_UP); } return priceRounded; } public Collection<MCost> getByElement( MProduct product, MAcctSchema as, int M_CostType_ID, int AD_Org_ID, int M_AttributeSetInstance_ID, int M_CostElement_ID) { CostDimension cd = new CostDimension( product, as, M_CostType_ID, AD_Org_ID, M_AttributeSetInstance_ID, M_CostElement_ID); return cd.toQuery(MCost.class, product.get_TrxName()).setOnlyActiveRecords(true).list(); } /** * Get Cost Detail * * @param model Model Inventory Line * @param as Account Schema * @param M_CostElement_ID Cost Element * @param M_AttributeSetInstance_ID * @return MCostDetail */ private MCostDetail getCostDetail( IDocumentLine model, MTransaction mtrx, I_C_AcctSchema as, int M_CostElement_ID) { final String whereClause = "AD_Client_ID=? AND AD_Org_ID=?" + " AND " + model.get_TableName() + "_ID=?" + " AND " + MCostDetail.COLUMNNAME_M_Product_ID + "=?" + " AND " + MCostDetail.COLUMNNAME_M_AttributeSetInstance_ID + "=?" + " AND " + MCostDetail.COLUMNNAME_C_AcctSchema_ID + "=?" // +" AND "+MCostDetail.COLUMNNAME_M_CostType_ID+"=?" + " AND " + MCostDetail.COLUMNNAME_M_CostElement_ID + "=?"; final Object[] params = new Object[] { mtrx.getAD_Client_ID(), mtrx.getAD_Org_ID(), model.get_ID(), mtrx.getM_Product_ID(), mtrx.getM_AttributeSetInstance_ID(), as.getC_AcctSchema_ID(), // as.getM_CostType_ID(), M_CostElement_ID, }; return new Query(mtrx.getCtx(), MCostDetail.Table_Name, whereClause, mtrx.get_TrxName()) .setParameters(params) .firstOnly(); } /** * Create Cost Detail (Material Issue, Material Receipt) * * @param model * @param mtrx Material Transaction */ public void createCostDetail(IDocumentLine model, MTransaction mtrx) { final I_PP_Cost_Collector cc = (model instanceof MPPCostCollector ? (MPPCostCollector) model : null); final Properties ctx = mtrx.getCtx(); for (I_C_AcctSchema as : getAcctSchema(mtrx)) { // Cost Detail final I_M_Product product = MProduct.get(ctx, mtrx.getM_Product_ID()); final String costingMethod = Services.get(IProductBL.class).getCostingMethod(product, as); // Check costing method if (!getCostingMethod().equals(costingMethod)) { throw new LiberoException("Costing method not supported - " + costingMethod); } // for (I_M_CostElement element : getCostElements(ctx)) { // // Delete Unprocessed zero Differences deleteCostDetail( model, as, element.getM_CostElement_ID(), mtrx.getM_AttributeSetInstance_ID()); // // Get Costs final BigDecimal qty = mtrx.getMovementQty(); final BigDecimal price = getProductActualCostPriceOrZero(cc, product, as, element, mtrx.get_TrxName()); final BigDecimal amt = roundCost(price.multiply(qty), as.getC_AcctSchema_ID()); // // Create / Update Cost Detail MCostDetail cd = getCostDetail(model, mtrx, as, element.getM_CostElement_ID()); if (cd == null) // createNew { cd = new MCostDetail( as, mtrx.getAD_Org_ID(), mtrx.getM_Product_ID(), mtrx.getM_AttributeSetInstance_ID(), element.getM_CostElement_ID(), amt, qty, model.getDescription(), mtrx.get_TrxName()); // cd.setMovementDate(mtrx.getMovementDate()); // if (cost != null) // { // cd.setCurrentCostPrice(cost.getCurrentCostPrice()); // cd.setCurrentCostPriceLL(cost.getCurrentCostPriceLL()); // } // else // { // cd.setCurrentCostPrice(Env.ZERO); // cd.setCurrentCostPriceLL(Env.ZERO); // } // cd.setM_CostType_ID(as.getM_CostType_ID()); // //cd.setCostingMethod(element.getCostingMethod()); // cd.setM_Transaction_ID(mtrx.get_ID()); if (cc != null) { cd.setPP_Cost_Collector_ID(cc.getPP_Cost_Collector_ID()); } } else { cd.setDeltaAmt(amt.subtract(cd.getAmt())); cd.setDeltaQty(mtrx.getMovementQty().subtract(cd.getQty())); if (cd.isDelta()) { cd.setProcessed(false); cd.setAmt(amt); cd.setQty(mtrx.getMovementQty()); } } cd.saveEx(); processCostDetail(cd); log.info("" + cd); } // for ELements } // Account Schema } private int deleteCostDetail( IDocumentLine model, I_C_AcctSchema as, int M_CostElement_ID, int M_AttributeSetInstance_ID) { // Delete Unprocessed zero Differences String sql = "DELETE FROM " + MCostDetail.Table_Name + " WHERE Processed='N' AND COALESCE(DeltaAmt,0)=0 AND COALESCE(DeltaQty,0)=0" + " AND " + model.get_TableName() + "_ID=?" + " AND " + MCostDetail.COLUMNNAME_C_AcctSchema_ID + "=?" + " AND " + MCostDetail.COLUMNNAME_M_AttributeSetInstance_ID + "=?" // + " AND "+MCostDetail.COLUMNNAME_M_CostType_ID+"=?" + " AND " + MCostDetail.COLUMNNAME_M_CostElement_ID + "=?"; Object[] parameters = new Object[] { model.get_ID(), as.getC_AcctSchema_ID(), M_AttributeSetInstance_ID, // as.getM_CostType_ID(), M_CostElement_ID }; int no = DB.executeUpdateEx(sql, parameters, model.get_TrxName()); if (no != 0) log.info("Deleted #" + no); return no; } private void processCostDetail(I_M_CostDetail cd) { if (!cd.isProcessed()) { final Properties ctx = InterfaceWrapperHelper.getCtx(cd); final I_C_AcctSchema as = MAcctSchema.get(ctx, cd.getC_AcctSchema_ID()); final I_AD_Client client = MClient.get(ctx, as.getAD_Client_ID()); if (client.isCostImmediate()) { final MCostDetail cdPO = LegacyAdapters.convertToPO(cd); cdPO.process(); } } } public static boolean isActivityControlElement(I_M_CostElement element) { String costElementType = element.getCostElementType(); return MCostElement.COSTELEMENTTYPE_Resource.equals(costElementType) || MCostElement.COSTELEMENTTYPE_Overhead.equals(costElementType) || MCostElement.COSTELEMENTTYPE_BurdenMOverhead.equals(costElementType); } private Collection<I_M_CostElement> getCostElements(Properties ctx) { return MCostElement.getByCostingMethod(ctx, getCostingMethod()); } private Collection<MAcctSchema> getAcctSchema(PO po) { int AD_Org_ID = po.getAD_Org_ID(); MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(po.getCtx(), po.getAD_Client_ID()); ArrayList<MAcctSchema> list = new ArrayList<MAcctSchema>(ass.length); for (MAcctSchema as : ass) { if (!as.isSkipOrg(AD_Org_ID)) list.add(as); } return list; } private MCostDetail getCostDetail(I_PP_Cost_Collector cc, int M_CostElement_ID) { final String whereClause = MCostDetail.COLUMNNAME_PP_Cost_Collector_ID + "=?" + " AND " + MCostDetail.COLUMNNAME_M_CostElement_ID + "=?"; final Properties ctx = InterfaceWrapperHelper.getCtx(cc); final String trxName = InterfaceWrapperHelper.getTrxName(cc); MCostDetail cd = new Query(ctx, MCostDetail.Table_Name, whereClause, trxName) .setParameters(new Object[] {cc.getPP_Cost_Collector_ID(), M_CostElement_ID}) .setOrderBy( MCostDetail.COLUMNNAME_Qty + " DESC") // TODO : fix this; we have 2 cost details; now we are taking the one // with bigger qty; we must find a proper way .first(); return cd; } private I_PP_Cost_Collector createVarianceCostCollector( I_PP_Cost_Collector cc, String CostCollectorType) { final I_PP_Cost_Collector ccv = InterfaceWrapperHelper.newInstance(I_PP_Cost_Collector.class, cc); InterfaceWrapperHelper.copyValues(cc, ccv); ccv.setProcessing(false); ccv.setProcessed(false); ccv.setDocStatus(X_PP_Cost_Collector.DOCSTATUS_Drafted); ccv.setDocAction(X_PP_Cost_Collector.DOCACTION_Complete); ccv.setCostCollectorType(CostCollectorType); ccv.setDocumentNo(null); // reset cc.setPP_Cost_Collector_Parent(cc); // link to parent InterfaceWrapperHelper.save(ccv); return ccv; } /** * Create & Proce Cost Detail for Variances * * @param ccv * @param amt * @param qty * @param cd (optional) * @param product * @param as * @param element * @return */ private MCostDetail createVarianceCostDetail( I_PP_Cost_Collector ccv, BigDecimal amt, BigDecimal qty, MCostDetail cd, I_M_Product product, I_C_AcctSchema as, I_M_CostElement element) { final Properties ctx = InterfaceWrapperHelper.getCtx(ccv); final String trxName = InterfaceWrapperHelper.getTrxName(ccv); final MCostDetail cdv = new MCostDetail(ctx, 0, trxName); if (cd != null) { MCostDetail.copyValues(cd, cdv); cdv.setProcessed(false); } if (product != null) { cdv.setM_Product_ID(product.getM_Product_ID()); cdv.setM_AttributeSetInstance_ID(0); } if (as != null) { cdv.setC_AcctSchema_ID(as.getC_AcctSchema_ID()); } if (element != null) { cdv.setM_CostElement_ID(element.getM_CostElement_ID()); } // cdv.setPP_Cost_Collector_ID(ccv.getPP_Cost_Collector_ID()); cdv.setAmt(amt); cdv.setQty(qty); cdv.saveEx(); processCostDetail(cdv); return cdv; } public void createActivityControl(MPPCostCollector cc) { if (!cc.isCostCollectorType(X_PP_Cost_Collector.COSTCOLLECTORTYPE_ActivityControl)) return; // final I_M_Product product = MProduct.forS_Resource_ID(cc.getCtx(), cc.getS_Resource_ID(), null); final RoutingService routingService = RoutingServiceFactory.get().getRoutingService(cc.getAD_Client_ID()); final BigDecimal qty = routingService.getResourceBaseValue(cc.getS_Resource_ID(), cc); for (MAcctSchema as : getAcctSchema(cc)) { for (I_M_CostElement element : getCostElements(cc.getCtx())) { if (!isActivityControlElement(element)) { continue; } final CostDimension d = new CostDimension( product, as, as.getM_CostType_ID(), 0, // AD_Org_ID, 0, // M_ASI_ID element.getM_CostElement_ID()); final BigDecimal price = getResourceActualCostRate(cc, cc.getS_Resource_ID(), d, cc.get_TrxName()); BigDecimal costs = price.multiply(qty); if (costs.scale() > as.getCostingPrecision()) costs = costs.setScale(as.getCostingPrecision(), RoundingMode.HALF_UP); // MCostDetail cd = new MCostDetail( as, 0, // AD_Org_ID, d.getM_Product_ID(), 0, // M_AttributeSetInstance_ID, element.getM_CostElement_ID(), costs.negate(), qty.negate(), "", // Description, cc.get_TrxName()); cd.setPP_Cost_Collector_ID(cc.getPP_Cost_Collector_ID()); cd.saveEx(); processCostDetail(cd); } } } public void createUsageVariances(MPPCostCollector ccuv) { // Apply only for material Usage Variance if (!ccuv.isCostCollectorType(X_PP_Cost_Collector.COSTCOLLECTORTYPE_UsegeVariance)) { throw new IllegalArgumentException("Cost Collector is not Material Usage Variance"); } // final I_M_Product product; final BigDecimal qty; if (ccuv.getPP_Order_BOMLine_ID() > 0) { product = MProduct.get(ccuv.getCtx(), ccuv.getM_Product_ID()); qty = ccuv.getMovementQty(); } else { product = MProduct.forS_Resource_ID(ccuv.getCtx(), ccuv.getS_Resource_ID(), null); final RoutingService routingService = RoutingServiceFactory.get().getRoutingService(ccuv.getAD_Client_ID()); qty = routingService.getResourceBaseValue(ccuv.getS_Resource_ID(), ccuv); } // for (I_C_AcctSchema as : getAcctSchema(ccuv)) { for (I_M_CostElement element : getCostElements(ccuv.getCtx())) { final BigDecimal price = getProductActualCostPrice(ccuv, product, as, element, ccuv.get_TrxName()); final BigDecimal amt = roundCost(price.multiply(qty), as.getC_AcctSchema_ID()); // // Create / Update Cost Detail createVarianceCostDetail( ccuv, amt, qty, null, // no original cost detail product, as, element); } // for ELements } // Account Schema } public void createRateVariances(MPPCostCollector cc) { final I_M_Product product; if (cc.isCostCollectorType(X_PP_Cost_Collector.COSTCOLLECTORTYPE_ActivityControl)) { final I_AD_WF_Node node = cc.getPP_Order_Node().getAD_WF_Node(); product = MProduct.forS_Resource_ID(cc.getCtx(), node.getS_Resource_ID(), null); } else if (cc.isCostCollectorType(X_PP_Cost_Collector.COSTCOLLECTORTYPE_ComponentIssue)) { final I_PP_Order_BOMLine bomLine = cc.getPP_Order_BOMLine(); product = MProduct.get(cc.getCtx(), bomLine.getM_Product_ID()); } else { return; } I_PP_Cost_Collector ccrv = null; // Cost Collector - Rate Variance for (MAcctSchema as : getAcctSchema(cc)) { for (I_M_CostElement element : getCostElements(cc.getCtx())) { final MCostDetail cd = getCostDetail(cc, element.getM_CostElement_ID()); if (cd == null) { continue; } // final BigDecimal qty = cd.getQty(); final BigDecimal priceStd = getProductStandardCostPrice(cc, product, as, element); final BigDecimal priceActual = getProductActualCostPriceOrZero(cc, product, as, element, cc.get_TrxName()); final BigDecimal amtStd = roundCost(priceStd.multiply(qty), as.getC_AcctSchema_ID()); final BigDecimal amtActual = roundCost(priceActual.multiply(qty), as.getC_AcctSchema_ID()); if (amtStd.compareTo(amtActual) == 0) { continue; } // if (ccrv == null) { ccrv = createVarianceCostCollector(cc, X_PP_Cost_Collector.COSTCOLLECTORTYPE_RateVariance); } // createVarianceCostDetail(ccrv, amtActual.negate(), qty.negate(), cd, null, as, element); createVarianceCostDetail(ccrv, amtStd, qty, cd, null, as, element); } } // if (ccrv != null) { Services.get(IDocActionBL.class) .processEx(ccrv, DocAction.ACTION_Complete, DocAction.STATUS_Completed); } } public void createMethodVariances(MPPCostCollector cc) { if (!cc.isCostCollectorType(X_PP_Cost_Collector.COSTCOLLECTORTYPE_ActivityControl)) return; // final int std_resource_id = cc.getPP_Order_Node().getAD_WF_Node().getS_Resource_ID(); final int actual_resource_id = cc.getS_Resource_ID(); if (std_resource_id == actual_resource_id) { return; } // I_PP_Cost_Collector ccmv = null; // Cost Collector - Method Change Variance final RoutingService routingService = RoutingServiceFactory.get().getRoutingService(cc.getAD_Client_ID()); for (I_C_AcctSchema as : getAcctSchema(cc)) { for (I_M_CostElement element : getCostElements(cc.getCtx())) { final I_M_Product resourcePStd = MProduct.forS_Resource_ID(cc.getCtx(), std_resource_id, null); final I_M_Product resourcePActual = MProduct.forS_Resource_ID(cc.getCtx(), actual_resource_id, null); final BigDecimal priceStd = getProductActualCostPrice(cc, resourcePStd, as, element, cc.get_TrxName()); final BigDecimal priceActual = getProductActualCostPrice(cc, resourcePActual, as, element, cc.get_TrxName()); if (priceStd.compareTo(priceActual) == 0) { continue; } // if (ccmv == null) { ccmv = createVarianceCostCollector( cc, X_PP_Cost_Collector.COSTCOLLECTORTYPE_MethodChangeVariance); } // final BigDecimal qty = routingService.getResourceBaseValue(cc.getS_Resource_ID(), cc); final BigDecimal amtStd = priceStd.multiply(qty); final BigDecimal amtActual = priceActual.multiply(qty); // createVarianceCostDetail(ccmv, amtActual, qty, null, resourcePActual, as, element); createVarianceCostDetail( ccmv, amtStd.negate(), qty.negate(), null, resourcePStd, as, element); } } // if (ccmv != null) { Services.get(IDocActionBL.class) .processEx(ccmv, DocAction.ACTION_Complete, DocAction.STATUS_Completed); } } public void createReversals(final I_PP_Cost_Collector reversalCostCollector) { Check.assumeNotNull(reversalCostCollector, "reversalCostCollector not null"); // // Get the original cost collector final I_PP_Cost_Collector costCollector = reversalCostCollector.getReversal(); Check.assumeNotNull(costCollector, "costCollector not null"); // // Get the original cost details final List<I_M_CostDetail> costDetails = Services.get(IPPCostCollectorDAO.class).retrieveCostDetails(costCollector); for (final I_M_CostDetail cd : costDetails) { createReversal(cd, reversalCostCollector); } } private final void createReversal( final I_M_CostDetail costDetail, final I_PP_Cost_Collector reversalCostCollector) { final I_M_CostDetail costDetailReversal = InterfaceWrapperHelper.newInstance(I_M_CostDetail.class, costDetail); InterfaceWrapperHelper.copyValues( costDetail, costDetailReversal, true); // honorIsCalculated=true costDetailReversal.setPP_Cost_Collector_ID(reversalCostCollector.getPP_Cost_Collector_ID()); costDetailReversal.setQty(costDetail.getQty().negate()); costDetailReversal.setAmt(costDetail.getAmt().negate()); costDetailReversal.setDeltaQty(costDetail.getDeltaQty().negate()); costDetailReversal.setDeltaAmt(costDetail.getDeltaAmt().negate()); costDetailReversal.setProcessed(false); InterfaceWrapperHelper.save(costDetailReversal); processCostDetail(costDetailReversal); } }
/** * Payment Processor Model * * @author Jorg Janke * @version $Id: MPaymentProcessor.java,v 1.3 2006/07/30 00:51:03 jjanke Exp $ */ public class MPaymentProcessor extends X_C_PaymentProcessor { /** */ private static final long serialVersionUID = 1825454310856682804L; public static MPaymentProcessor[] find( Properties ctx, String tender, String CCType, int AD_Client_ID, int AD_Org_ID, int C_Currency_ID, BigDecimal Amt, String trxName) { return find(ctx, tender, CCType, AD_Client_ID, C_Currency_ID, Amt, trxName); } /** * Get BankAccount & PaymentProcessor * * @param ctx context * @param tender optional Tender see TENDER_ * @param CCType optional CC Type see CC_ * @param AD_Client_ID Client * @param C_Currency_ID Currency (ignored) * @param Amt Amount (ignored) * @param trxName transaction * @return Array of BankAccount[0] & PaymentProcessor[1] or null */ protected static MPaymentProcessor[] find( Properties ctx, String tender, String CCType, int AD_Client_ID, int C_Currency_ID, BigDecimal Amt, String trxName) { ArrayList<MPaymentProcessor> list = new ArrayList<MPaymentProcessor>(); StringBuffer sql = new StringBuffer( "SELECT * " + "FROM C_PaymentProcessor " + "WHERE AD_Client_ID=? AND IsActive='Y'" // #1 + " AND (C_Currency_ID IS NULL OR C_Currency_ID=?)" // #2 + " AND (MinimumAmt IS NULL OR MinimumAmt = 0 OR MinimumAmt <= ?)"); // #3 if (MPayment.TENDERTYPE_DirectDeposit.equals(tender)) sql.append(" AND AcceptDirectDeposit='Y'"); else if (MPayment.TENDERTYPE_DirectDebit.equals(tender)) sql.append(" AND AcceptDirectDebit='Y'"); else if (MPayment.TENDERTYPE_Check.equals(tender)) sql.append(" AND AcceptCheck='Y'"); // CreditCards else if (MPayment.CREDITCARDTYPE_ATM.equals(CCType)) sql.append(" AND AcceptATM='Y'"); else if (MPayment.CREDITCARDTYPE_Amex.equals(CCType)) sql.append(" AND AcceptAMEX='Y'"); else if (MPayment.CREDITCARDTYPE_Visa.equals(CCType)) sql.append(" AND AcceptVISA='Y'"); else if (MPayment.CREDITCARDTYPE_MasterCard.equals(CCType)) sql.append(" AND AcceptMC='Y'"); else if (MPayment.CREDITCARDTYPE_Diners.equals(CCType)) sql.append(" AND AcceptDiners='Y'"); else if (MPayment.CREDITCARDTYPE_Discover.equals(CCType)) sql.append(" AND AcceptDiscover='Y'"); else if (MPayment.CREDITCARDTYPE_PurchaseCard.equals(CCType)) sql.append(" AND AcceptCORPORATE='Y'"); // try { PreparedStatement pstmt = DB.prepareStatement(sql.toString(), trxName); pstmt.setInt(1, AD_Client_ID); pstmt.setInt(2, C_Currency_ID); pstmt.setBigDecimal(3, Amt); ResultSet rs = pstmt.executeQuery(); while (rs.next()) list.add(new MPaymentProcessor(ctx, rs, trxName)); rs.close(); pstmt.close(); } catch (SQLException e) { s_log.error("find - " + sql, e); return null; } // if (list.size() == 0) s_log.warn( "find - not found - AD_Client_ID=" + AD_Client_ID + ", C_Currency_ID=" + C_Currency_ID + ", Amt=" + Amt); else s_log.debug( "find - #" + list.size() + " - AD_Client_ID=" + AD_Client_ID + ", C_Currency_ID=" + C_Currency_ID + ", Amt=" + Amt); MPaymentProcessor[] retValue = new MPaymentProcessor[list.size()]; list.toArray(retValue); return retValue; } // find /** Static Logger */ private static Logger s_log = LogManager.getLogger(MPaymentProcessor.class); /** * ************************************************************************ Payment Processor * Model * * @param ctx context * @param C_PaymentProcessor_ID payment processor * @param trxName transaction */ public MPaymentProcessor(Properties ctx, int C_PaymentProcessor_ID, String trxName) { super(ctx, C_PaymentProcessor_ID, trxName); if (C_PaymentProcessor_ID == 0) { // setC_BankAccount_ID (0); // Parent // setUserID (null); // setPassword (null); // setHostAddress (null); // setHostPort (0); setCommission(Env.ZERO); setAcceptVisa(false); setAcceptMC(false); setAcceptAMEX(false); setAcceptDiners(false); setCostPerTrx(Env.ZERO); setAcceptCheck(false); setRequireVV(false); setAcceptCorporate(false); setAcceptDiscover(false); setAcceptATM(false); setAcceptDirectDeposit(false); setAcceptDirectDebit(false); // setName (null); } } // MPaymentProcessor /** * Payment Processor Model * * @param ctx context * @param rs result set * @param trxName transaction */ public MPaymentProcessor(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MPaymentProcessor /** * String representation * * @return info */ public String toString() { StringBuffer sb = new StringBuffer("MPaymentProcessor[") .append(get_ID()) .append("-") .append(getName()) .append("]"); return sb.toString(); } // toString /** * Does Payment Processor accepts tender / CC * * @param TenderType tender type * @param CreditCardType credit card type * @return true if acceptes */ public boolean accepts(String TenderType, String CreditCardType) { if ((MPayment.TENDERTYPE_DirectDeposit.equals(TenderType) && isAcceptDirectDeposit()) || (MPayment.TENDERTYPE_DirectDebit.equals(TenderType) && isAcceptDirectDebit()) || (MPayment.TENDERTYPE_Check.equals(TenderType) && isAcceptCheck()) // || (MPayment.CREDITCARDTYPE_ATM.equals(CreditCardType) && isAcceptATM()) || (MPayment.CREDITCARDTYPE_Amex.equals(CreditCardType) && isAcceptAMEX()) || (MPayment.CREDITCARDTYPE_PurchaseCard.equals(CreditCardType) && isAcceptCorporate()) || (MPayment.CREDITCARDTYPE_Diners.equals(CreditCardType) && isAcceptDiners()) || (MPayment.CREDITCARDTYPE_Discover.equals(CreditCardType) && isAcceptDiscover()) || (MPayment.CREDITCARDTYPE_MasterCard.equals(CreditCardType) && isAcceptMC()) || (MPayment.CREDITCARDTYPE_Visa.equals(CreditCardType) && isAcceptVisa())) return true; return false; } // accepts } // MPaymentProcessor
@Immutable public class C_Order_CounterDocHandler extends CounterDocumentHandlerAdapter { private static final transient Logger logger = LogManager.getLogger(C_Order_CounterDocHandler.class); public static final ICounterDocHandler instance = new C_Order_CounterDocHandler(); private C_Order_CounterDocHandler() {} /** * Code taken from {@link org.compiere.model.MOrder}. * * @return <code>true</code> if <code>Ref_Order_ID() > 0</code>. */ @Override public boolean isCounterDocument(final DocAction document) { final I_C_Order order = InterfaceWrapperHelper.create(document, I_C_Order.class); return order.getRef_Order_ID() > 0; } /** * Creates a counter document for an order. The counter document is also processed, if there is a * {@link I_C_DocTypeCounter} with a <code>DocAction</code> configured. * * <p>This implementation partially uses legacy code. I didn't yet get to refactor/remove/replace * it all. */ @Override public DocAction createCounterDocument(final DocAction document) { final I_C_Order order = InterfaceWrapperHelper.create(document, I_C_Order.class); final MOrder orderPO = LegacyAdapters.convertToPO(order); final I_C_DocType counterDocType = retrieveCounterDocTypeOrNull(document); final I_AD_Org counterOrg = retrieveCounterOrgOrNull(document); final de.metas.adempiere.model.I_C_Order counterOrder = InterfaceWrapperHelper.newInstance( de.metas.adempiere.model.I_C_Order.class, document.getCtx()); final MOrder counterOrderPO = (MOrder) LegacyAdapters.convertToPO(counterOrder); counterOrder.setAD_Org(counterOrg); // 09700 // counterOrder.setC_DocTypeTarget(counterDocType); counterOrder.setIsSOTrx(counterDocType.isSOTrx()); // the new order needs to figure out the pricing by itself counterOrder.setM_PricingSystem(null); counterOrder.setM_PriceList(null); counterOrder.setDateOrdered(order.getDateOrdered()); counterOrder.setDateAcct(order.getDateAcct()); counterOrder.setDatePromised(order.getDatePromised()); counterOrder.setRef_Order_ID(order.getC_Order_ID()); final I_C_BPartner counterBP = retrieveCounterPartnerOrNull(document); counterOrderPO.setBPartner(counterBP); final I_M_Warehouse counterWarehouse = Services.get(IWarehouseAdvisor.class).evaluateOrderWarehouse(counterOrder); counterOrder.setM_Warehouse(counterWarehouse); // References (should not be required) counterOrder.setSalesRep_ID(order.getSalesRep_ID()); InterfaceWrapperHelper.save(counterOrder); // copy the order lines final boolean counter = true; final boolean copyASI = true; counterOrderPO.copyLinesFrom(orderPO, counter, copyASI); // Update copied lines final boolean requery = true; final MOrderLine[] counterLines = counterOrderPO.getLines(requery, null); for (int i = 0; i < counterLines.length; i++) { final MOrderLine counterLine = counterLines[i]; counterLine.setOrder(counterOrderPO); // copies header values (BP, etc.) counterLine.setPrice(); counterLine.setTax(); InterfaceWrapperHelper.save(counterLine); } logger.debug(counterOrder.toString()); // Document Action final MDocTypeCounter counterDT = MDocTypeCounter.getCounterDocType(document.getCtx(), order.getC_DocType_ID()); if (counterDT != null) { if (counterDT.getDocAction() != null) { counterOrder.setDocAction(counterDT.getDocAction()); Services.get(IDocActionBL.class) .processEx( counterOrder, counterDT.getDocAction(), null); // not expecting a particular docStatus (e.g. for prepay orders, it might be // "waiting to payment") } } return counterOrderPO; } @Override public String toString() { return "C_Order_CounterDocHandler[]"; } }
/** * Transaction Management. - Create new Transaction by Trx.get(name); - ..transactions.. - commit(); * ---- start(); ---- commit(); - close(); * * @author Jorg Janke * @author Low Heng Sin - added rollback(boolean) and commit(boolean) [20070105] - remove * unnecessary use of savepoint - use UUID for safer transaction name generation * @author Teo Sarca, http://www.arhipac.ro * <li>FR [ 2080217 ] Implement TrxRunnable * <li>BF [ 2876927 ] Oracle JDBC driver problem * https://sourceforge.net/tracker/?func=detail&atid=879332&aid=2876927&group_id=176962 * @author Teo Sarca, [email protected] * <li>BF [ 2849122 ] PO.AfterSave is not rollback on error - add releaseSavepoint method * https://sourceforge.net/tracker/index.php?func=detail&aid=2849122&group_id=176962&atid=879332# */ public class Trx extends AbstractTrx implements VetoableChangeListener { /** * trxName=null marker * * @deprecated Please use {@link ITrx#TRXNAME_None} instead */ // metas @Deprecated public static final String TRXNAME_None = ITrx.TRXNAME_None; /** * Get Transaction * * @param trxName trx name * @param createNew if false, null is returned if not found * @return Transaction or null */ public static synchronized Trx get(String trxName, boolean createNew) { final ITrx trx = Services.get(ITrxManager.class).get(trxName, createNew); return (Trx) trx; } // get /** * Create unique Transaction Name <b>and instantly create the new trx</b>. * * @param prefix optional prefix * @return unique name */ public static String createTrxName(final String prefix) { return Services.get(ITrxManager.class).createTrxName(prefix); } /** * Create unique Transaction Name * * @param prefix optional prefix * @return unique name */ public static String createTrxName(String prefix, final boolean createNew) { return Services.get(ITrxManager.class).createTrxName(prefix, createNew); } // createTrxName /** * Create unique Transaction Name * * @return unique name */ public static String createTrxName() { final String prefix = null; return Services.get(ITrxManager.class).createTrxName(prefix); } // createTrxName /** * ************************************************************************ Transaction * Constructor * * @param trxName unique name */ public Trx(final ITrxManager trxManager, final String trxName, final boolean autocommit) { this(trxManager, trxName, null, autocommit); // String threadName = Thread.currentThread().getName(); // for debugging } // Trx /** * Transaction Constructor * * @param trxName unique name * @param con optional connection ( ignore for remote transaction ) */ private Trx( final ITrxManager trxManager, final String trxName, final Connection con, final boolean autocommit) { super(trxManager, trxName, autocommit); setConnection(con); } // Trx /** Static Log */ // private static final Logger s_log = CLogMgt.getLogger(Trx.class); /** Logger */ private Logger log = LogManager.getLogger(getClass()); private Connection m_connection = null; /** * Get Connection * * @return connection */ public Connection getConnection() { log.trace("Active={}, Connection={}", new Object[] {isActive(), m_connection}); // metas: tsa: begin: Handle the case when the connection was already closed // Example: one case when we can get this is when we start a process with a transaction // and that process is commiting the transaction somewhere if (m_connection != null) { boolean isClosed = false; try { isClosed = m_connection.isClosed(); } catch (SQLException e) { log.error( "Error checking if the connection is closed. Assume closed - " + e.getLocalizedMessage(), e); isClosed = true; } if (isClosed) { log.info("Connection is closed. Trying to create another connection."); m_connection = null; } } // metas: tsa: end: if (m_connection == null) // get new Connection { setConnection(DB.createConnection(isAutoCommit(), Connection.TRANSACTION_READ_COMMITTED)); } if (!isActive()) { start(); } try { m_connection.setAutoCommit(isAutoCommit()); } catch (SQLException e) { throw DBException.wrapIfNeeded(e); } return m_connection; } // getConnection /** * Set Connection * * @param conn connection */ private void setConnection(Connection conn) { if (conn == null) { return; } m_connection = conn; log.trace("Connection={}", conn); // // Configure the connection try { m_connection.setAutoCommit(false); // // Get Connection's backend PID (if configured) if (getTrxManager().isDebugConnectionBackendId()) { final boolean throwDBException = true; // we expect everything to be in order to get a PID final String debugConnectionBackendId = DB.getDatabase().getConnectionBackendId(m_connection, throwDBException); setDebugConnectionBackendId(debugConnectionBackendId); } // NOTE: works with c3p0 from version 0.9.5 (released on 02.01.2015) m_connection.setClientInfo("ApplicationName", "adempiere/" + getTrxName()); // task 08353 } catch (Exception e) { log.error("connection", e); } } // setConnection @Override protected boolean isJustStarted() { if (!isActive()) { return false; } final boolean justStarted = m_connection == null; return justStarted; } @Override protected boolean rollbackNative(boolean throwException) throws SQLException { final String trxName = getTrxName(); // // Get current connection // NOTE: we are not calling getConnection() because we don't want to acquire a new connection in // case it was not used already. final Connection connection = m_connection; if (connection == null || connection.getAutoCommit()) { log.debug( "rollbackNative: doing nothing because we have a null or autocommit connection; this={}, connection={}", this, m_connection); // => consider this a success because if there was no open transaction then there is nothing // to rollback return true; } // Case: we really have something to rollback (because connection was acquired and used) if (connection != null) { try { connection.rollback(); log.debug("rollbackNative: OK - {}", trxName); return true; } catch (SQLException e) { log.error("rollbackNative: FAILED - {} (throwException={})", trxName, throwException, e); if (throwException) { throw e; } return false; } } // // Case: nothing was done on this transaction (because connection is null, so it was not // acquired) else { // => consider this a success because if nothing was done then there is nothing to rollback return true; } } // rollback @Override protected boolean rollbackNative(ITrxSavepoint savepoint) throws SQLException // metas: end: 02367 { if (m_connection == null || m_connection.getAutoCommit()) { log.debug( "rollbackNative: doing nothing because we have a null or autocomit connection; this={}, connection={}", this, m_connection); return false; } final String trxName = getTrxName(); final Savepoint jdbcSavepoint = (Savepoint) savepoint.getNativeSavepoint(); // local try { if (m_connection != null) { m_connection.rollback(jdbcSavepoint); log.debug("**** {}", trxName); return true; } } catch (SQLException e) { // Do nothing. The Savepoint might have been discarded because of an intermediate commit or // rollback // FIXME: track in AbstractTrx which savepoints where implicitly discarded in this way and // don't call rollbackNative in such a case. // log.error(trxName, e); // throw e; } return false; } // rollback @Override protected boolean commitNative(boolean throwException) throws SQLException { if (m_connection == null || m_connection.getAutoCommit()) { log.debug( "commitNative: doing nothing because we have an autocomit connection; this={}, connection={}", this, m_connection); return true; } final String trxName = getTrxName(); // // Get current connection // NOTE: we are not calling getConnection() because we don't want to acquire a new connection in // case it was not used already. final Connection connection = this.m_connection; // // Case: we really have something to commit (because connection was acquired and used) if (connection != null) { try { connection.commit(); log.debug("commitNative: OK - {}", trxName); // m_active = false; return true; } catch (SQLException e) { log.error("commitNative: FAILED - {} (throwException={})", trxName, throwException, e); if (throwException) { // m_active = false; throw e; } return false; } } // // Case: nothing was done on this transaction (because connection is null, so it was not // acquired) else { // => consider this a success because even if nothing was done on this transaction, nothing // failed neither return true; } } // commit @Override protected synchronized boolean closeNative() // metas: end: 02367 { if (m_connection == null) { return true; // nothing to do } // Close Connection try { // NOTE: let the org.compiere.db.DB_PostgreSQL_ConnectionCustomizer to update the // ApplicationName because // it will be performed in a separate thread so here we don't have to wait. // m_connection.setClientInfo("ApplicationName", "adempiere/CLOSED"); // task 08353 m_connection.close(); } catch (SQLException e) { log.error(getTrxName(), e); } m_connection = null; // m_active = false; return true; } // close /** * @param name * @return Savepoint * @throws SQLException @Deprecated Please use {@link #createTrxSavepoint(String)} */ @Deprecated public Savepoint setSavepoint(String name) throws SQLException { final ITrxSavepoint savepoint = createTrxSavepoint(name); final Savepoint jdbcSavepoint = (Savepoint) savepoint.getNativeSavepoint(); return jdbcSavepoint; } @Override protected ITrxSavepoint createTrxSavepointNative(final String name) throws Exception { if (m_connection == null) { getConnection(); } if (m_connection.getAutoCommit()) { log.debug( "createTrxSavepointNative: returning null because we have an autocomit connection; this={}, connection={}", this, m_connection); return null; } if (m_connection != null) { final Savepoint jdbcSavepoint; if (name != null) jdbcSavepoint = m_connection.setSavepoint(name); else jdbcSavepoint = m_connection.setSavepoint(); final JdbcTrxSavepoint savepoint = new JdbcTrxSavepoint(this, jdbcSavepoint); return savepoint; } else { return null; } } @Override protected boolean releaseSavepointNative(final ITrxSavepoint savepoint) throws Exception { final Savepoint jdbcSavepoint = (Savepoint) savepoint.getNativeSavepoint(); if (m_connection == null) { log.warn( "Cannot release savepoint " + savepoint + " because there is no active connection. Ignoring it."); return false; } if (m_connection.isClosed()) { log.warn( "Cannot release savepoint " + savepoint + " because the connection is closed. Ignoring it."); return false; } m_connection.releaseSavepoint(jdbcSavepoint); return true; } /** * Vetoable Change. Called from CCache to close connections * * @param evt event * @throws PropertyVetoException */ @Override public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { log.debug(evt.toString()); } // vetoableChange /** * @return Trx[] * @deprecated Please use {@link ITrxManager#getActiveTransactions()} */ @Deprecated public static ITrx[] getActiveTransactions() { return Services.get(ITrxManager.class).getActiveTransactions(); } /** * Delegates to {@link ITrxManager#run(TrxRunnable)}. * * @deprecated Please use {@link ITrxManager#run(TrxRunnable)} */ // metas: backward compatibility @Deprecated public static void run(TrxRunnable r) { Services.get(ITrxManager.class).run(r); } /** * Delegates to {@link ITrxManager#run(String, TrxRunnable)}. * * @deprecated Please use {@link ITrxManager#run(String, TrxRunnable)} */ // metas: backward compatibility @Deprecated public static void run(String trxName, TrxRunnable r) { Services.get(ITrxManager.class).run(trxName, r); } /** * Delegates to {@link ITrxManager#run(String, boolean, TrxRunnable)}. * * @deprecated Please use {@link ITrxManager#run(String, boolean, TrxRunnable)} */ // metas: added manageTrx parameter // metas: backward compatibility @Deprecated public static void run(String trxName, boolean manageTrx, TrxRunnable r) { Services.get(ITrxManager.class).run(trxName, manageTrx, r); } } // Trx
/** * Helper class to manage the shipments that might actually be created in the end. * * @author ts */ public class ShipmentCandidates implements IShipmentCandidates { static final Logger logger = LogManager.getLogger(ShipmentCandidates.class); /** List to store the shipments before it is decided if they are persisted to the database. */ private final List<MInOut> orderedCandidates = new ArrayList<MInOut>(); /** * Maps inOuts to their inOutLines. Usually this is done using the inOut's ID stored in the * inOutLine. But as the inOut hasn't been saved yet, it doesn't have an ID. */ private final Map<MInOut, List<MInOutLine>> inOut2Line = new HashMap<MInOut, List<MInOutLine>>(); private final Map<MInOutLine, MInOut> line2InOut = new HashMap<MInOutLine, MInOut>(); private final Map<MInOutLine, StringBuilder> line2StatusInfo = new HashMap<MInOutLine, StringBuilder>(); /** * Contains the quantities that would be delivered when postage free amount and order delivery * rules where ignored. */ private final Map<Integer, BigDecimal> olId2QtyDeliverable = new HashMap<Integer, BigDecimal>(); private final Map<MInOutLine, CompleteStatus> line2CompleteStatus = new HashMap<MInOutLine, CompleteStatus>(); private final Map<MInOutLine, PostageFreeStatus> line2PostageFreeStatus = new HashMap<MInOutLine, PostageFreeStatus>(); private final Map<MInOutLine, OverallStatus> line2OverallStatus = new HashMap<MInOutLine, OverallStatus>(); /** * Used to keep track of which inOutLine's order has which delivery rule. * * @see {@link #updateCompleteStatus()} */ private final Map<MOrder, Set<MInOutLine>> order2InOutLine = new HashMap<MOrder, Set<MInOutLine>>(); private final Map<Integer, MOrderLine> orderLineCache; private final Map<Integer, MInOutLine> orderLineId2InOutLine = new HashMap<Integer, MInOutLine>(); private final Map<MInOutLine, I_M_ShipmentSchedule> line2sched = new HashMap<MInOutLine, I_M_ShipmentSchedule>(); /** Used when multiple orders need to be consolidated to one shipment */ private final Map<ArrayKey, MInOut> shipperKey2Candidate = new HashMap<ArrayKey, MInOut>(); /** Used when one shipment per order is required */ private final Map<ArrayKey, MInOut> orderKey2Candidate = new HashMap<ArrayKey, MInOut>(); /** * Use this constructor if you won't need the method {@link * ShipmentCandidates#updatePostageFreeStatus(boolean)}. */ public ShipmentCandidates() { orderLineCache = null; } public ShipmentCandidates(final Map<Integer, I_C_OrderLine> myOrderLineCache) { orderLineCache = new HashMap<Integer, MOrderLine>(); for (final Integer orderLineId : myOrderLineCache.keySet()) { final I_C_OrderLine orderLine = myOrderLineCache.get(orderLineId); final MOrderLine orderLinePO = InterfaceWrapperHelper.getPO(orderLine); orderLineCache.put(orderLineId, orderLinePO); } } @Override public void addInOut(final I_M_InOut inOut) { if (inOut == null) { throw new NullPointerException("inOut"); } if (orderedCandidates.contains(inOut)) { throw new IllegalArgumentException("Each input may be added only once"); } orderedCandidates.add(getPO(inOut)); final ArrayKey shipperKey = Util.mkKey(inOut.getBPartnerAddress(), inOut.getM_Warehouse_ID(), inOut.getM_Shipper_ID()); shipperKey2Candidate.put(shipperKey, getPO(inOut)); final ArrayKey orderKey = Util.mkKey(inOut.getBPartnerAddress(), inOut.getM_Warehouse_ID(), inOut.getC_Order_ID()); orderKey2Candidate.put(orderKey, getPO(inOut)); final List<MInOutLine> inOutLines = new ArrayList<MInOutLine>(); inOut2Line.put(getPO(inOut), inOutLines); } private MInOut getPO(final I_M_InOut inOut) { final MInOut inOutPO = InterfaceWrapperHelper.getPO(inOut); return inOutPO; } @Override public void addLine( final I_M_InOut inOut, final I_M_InOutLine inOutLine, final I_M_ShipmentSchedule sched, final CompleteStatus completeStatus, final I_C_Order order) { Check.assumeNotNull(inOut, "inOut not null"); Check.assumeNotNull(inOutLine, "inOutLine not null"); Check.assumeNotNull(sched, "sched not null"); Check.assumeNotNull(completeStatus, "completeStatus not null"); if (!orderedCandidates.contains(inOut)) { throw new IllegalStateException( "inOut needs to be added using 'addInOut' first" + "\n InOut: " + inOut + "\n orderedCandidates: " + orderedCandidates); } if (inOutLine.getC_OrderLine_ID() < 1) { throw new IllegalStateException( "inOutLine needs to have a C_OrderLine_ID > 0" + "\n inOutLine: " + inOutLine); } if (CompleteStatus.INCOMPLETE_ORDER.equals(completeStatus)) { throw new IllegalArgumentException( "completeStatus may not be " + CompleteStatus.INCOMPLETE_ORDER + " (this will be figured out later by this class)"); } final MInOutLine inOutLinePO = getPO(inOutLine); final MInOut inOutPO = getPO(inOut); inOut2Line.get(inOutPO).add(inOutLinePO); line2InOut.put(inOutLinePO, inOutPO); // store the inoutLine's orderId and status as well to support our // later purge line2CompleteStatus.put(inOutLinePO, completeStatus); line2PostageFreeStatus.put(inOutLinePO, PostageFreeStatus.OK); final MOrder orderPO = InterfaceWrapperHelper.getPO(order); Set<MInOutLine> inOutLines = order2InOutLine.get(orderPO); if (inOutLines == null) { inOutLines = new HashSet<MInOutLine>(); order2InOutLine.put(orderPO, inOutLines); } inOutLines.add(inOutLinePO); // // C_OrderLine_ID to M_InOutLine mapping { final MInOutLine inOutLinePO_Old = orderLineId2InOutLine.put(inOutLine.getC_OrderLine_ID(), inOutLinePO); if (inOutLinePO_Old != null && inOutLinePO_Old != inOutLinePO) { throw new IllegalArgumentException( "An InOutLine was already set for order line in orderLineId2InOutLine mapping" + "\n InOutLine: " + inOutLinePO + "\n InOutLine (old): " + inOutLinePO_Old + "\n orderLineId2InOutLine (after change): " + orderLineId2InOutLine); } } line2sched.put(inOutLinePO, sched); } private MInOutLine getPO(final I_M_InOutLine inOutLine) { return InterfaceWrapperHelper.getPO(inOutLine); } public void removeLine(final I_M_InOutLine inOutLine) { if (inOutLine == null) { throw new NullPointerException("inOutLine"); } final MInOutLine inOutLinePO = getPO(inOutLine); final MInOut inOutPO = line2InOut.remove(inOutLinePO); if (inOutPO == null) { throw new IllegalStateException("inOutLine wasn't in line2InOut"); } boolean success = inOut2Line.get(inOutPO).remove(inOutLine); if (!success) { throw new IllegalStateException("inOutLine wasn't in inOut2Line"); } final int orderLineId = inOutLine.getC_OrderLine_ID(); success = orderLineId2InOutLine.remove(orderLineId) != null; if (!success) { throw new IllegalStateException( "inOutLine wasn't in orderLineId2InOutLine." + "\n orderLineId2InOutLine: " + orderLineId2InOutLine); } success = line2sched.remove(inOutLinePO) != null; if (!success) { throw new IllegalStateException( "inOutLine wasn't in line2sched" + "\n line2sched: " + line2sched); } } /** @return a copy of the list of {@link I_M_InOut}s stored in this instance. */ @Override public List<I_M_InOut> getCandidates() { final List<I_M_InOut> result = new ArrayList<I_M_InOut>(orderedCandidates.size()); for (final MInOut inOutPO : orderedCandidates) { result.add(InterfaceWrapperHelper.create(inOutPO, I_M_InOut.class)); } return result; } /** @return the number of {@link I_M_InOut}s this instance contains. */ @Override public int size() { return orderedCandidates.size(); } @Override public CompleteStatus getCompleteStatus(final I_M_InOutLine inOutLine) { if (inOutLine == null) { throw new NullPointerException("inOutLine"); } if (!line2CompleteStatus.containsKey(inOutLine)) { throw new IllegalArgumentException( "inOutLine " + inOutLine + " is not contained in this instance"); } return line2CompleteStatus.get(inOutLine); } @Override public PostageFreeStatus getPostageFreeStatus(final I_M_InOutLine inOutLine) { if (inOutLine == null) { throw new NullPointerException("inOutLine"); } if (!line2PostageFreeStatus.containsKey(inOutLine)) { throw new IllegalArgumentException( "inOutLine " + inOutLine + " is not contained in this instance"); } return line2PostageFreeStatus.get(inOutLine); } @Override public BigDecimal getQtyDeliverable(final int orderLineId) { if (olId2QtyDeliverable.containsKey(orderLineId)) { return olId2QtyDeliverable.get(orderLineId); } return BigDecimal.ZERO; } /** * @param inOut * @return a copy of the list of {@link I_M_InOutLine}s that belong to the given <code>inOut * </code>. * @throws NullPointerException if <code>inOut</code> is <code>null</code> */ @Override public List<I_M_InOutLine> getLines(final I_M_InOut inOut) { if (inOut == null) { throw new NullPointerException("inOut"); } final List<I_M_InOutLine> result = new ArrayList<I_M_InOutLine>(); for (final MInOutLine iol : inOut2Line.get(getPO(inOut))) { result.add(InterfaceWrapperHelper.create(iol, I_M_InOutLine.class)); } return result; } @Override public I_M_InOut getInOut(final I_M_InOutLine inOutLine) { final MInOut inoutPO = line2InOut.get(getPO(inOutLine)); if (inoutPO == null) { throw new IllegalArgumentException( "inOutLine " + inOutLine + " is not contained in this instance"); } return InterfaceWrapperHelper.create(inoutPO, I_M_InOut.class); } /** * @param inOut * @return <code>true</code> if the given inOut has no inOutLines * @throws NullPointerException if <code>inOut</code> is <code>null</code> or hasn't been added to * this instance using {@link #addInOut(I_M_InOut)} before. */ @Override public boolean hasNoLines(final I_M_InOut inOut) { if (inOut == null) { throw new NullPointerException("inOut"); } return inOut2Line.get(getPO(inOut)).isEmpty(); } /** * @param shipperId * @param bPartNerLocationId * @return the inOut with the given parameters * @throws IllegalStateException if no inOut with the given bPartnerLocationId and shipperId has * been added */ @Override public I_M_InOut getInOutForShipper( final int shipperId, final int warehouseId, final String bPartnerAddress) { final ArrayKey key = Util.mkKey(bPartnerAddress, warehouseId, shipperId); final MInOut inOutPO = shipperKey2Candidate.get(key); return InterfaceWrapperHelper.create(inOutPO, I_M_InOut.class); } @Override public I_M_InOut getInOutForOrderId( final int orderId, final int warehouseId, final String bPartnerAddress) { final ArrayKey key = Util.mkKey(bPartnerAddress, warehouseId, orderId); final MInOut inOutPO = orderKey2Candidate.get(key); return InterfaceWrapperHelper.create(inOutPO, I_M_InOut.class); } @Override public I_C_OrderLine getOrderLine(final int olId) { return InterfaceWrapperHelper.create(orderLineCache.get(olId), I_C_OrderLine.class); } /** * Updates the {@link CompleteStatus} and the {@link PostageFreeStatus} of the candidates. Also * sets the candidates' quantities to zero if this is implied by the status. */ public void afterFirstRun(final boolean ignorePostageFreeAmt) { resetQtyDeliverables(); updateCompleteStatus(); updatePostageFreeStatus(ignorePostageFreeAmt); } public I_M_InOutLine getInOutLineFor(final I_C_OrderLine orderLine) { final int orderLineId = orderLine.getC_OrderLine_ID(); return getInOutLineForOrderLine(orderLineId); } /** * Removes first the inoutLines with {@link I_M_InOutLine#getQtyEntered()} = 0 and afterwards the * inouts that have no more lines. */ public void purgeLinesEmpty() { int rmInOuts = 0, rmInOutLines = 0; // removing empty inOutLines for (final I_M_InOut inOut : getCandidates()) { for (final I_M_InOutLine inOutLine : getLines(inOut)) { if (inOutLine.getMovementQty().signum() <= 0) { removeLine(inOutLine); rmInOutLines++; } } } // removing empty inOuts for (final I_M_InOut inOut : getCandidates()) { if (hasNoLines(inOut)) { final ArrayKey key = Util.mkKey( inOut.getBPartnerAddress(), inOut.getM_Warehouse_ID(), inOut.getM_Shipper_ID()); shipperKey2Candidate.remove(key); inOut2Line.remove(inOut); orderedCandidates.remove(inOut); rmInOuts++; } } logger.info( "Removed " + rmInOuts + " MInOut instances and " + rmInOutLines + " MInOutLine instances"); } private void updateCompleteStatus() { for (final MOrder order : order2InOutLine.keySet()) { final String deliveryRule = order.getDeliveryRule(); if (X_C_Order.DELIVERYRULE_CompleteLine.equals(deliveryRule)) { // We only deliver if the line qty is same as the qty // ordered by the customer for (final MInOutLine inOutLinePO : order2InOutLine.get(order)) { if (CompleteStatus.INCOMPLETE_LINE.equals(line2CompleteStatus.get(inOutLinePO))) { inOutLinePO.setQtyEntered(BigDecimal.ZERO); inOutLinePO.setMovementQty(BigDecimal.ZERO); } } } else if (X_C_Order.DELIVERYRULE_CompleteOrder.equals(deliveryRule)) { // We only deliver any line at all if all line qtys as the // same as the qty ordered by the customer boolean removeAll = false; for (final MInOutLine inOutLinePO : order2InOutLine.get(order)) { if (CompleteStatus.INCOMPLETE_LINE.equals(line2CompleteStatus.get(inOutLinePO))) { removeAll = true; break; } } if (removeAll) { for (final MInOutLine inOutLinePO : order2InOutLine.get(order)) { inOutLinePO.setQtyEntered(BigDecimal.ZERO); inOutLinePO.setMovementQty(BigDecimal.ZERO); // update the status to show why we set the quantity to zero line2CompleteStatus.put(inOutLinePO, CompleteStatus.INCOMPLETE_ORDER); } } } else { for (MInOutLine inOutLinePO : order2InOutLine.get(order)) { // update the status to show that the "completeness" of this inOuLine is irrelevant line2CompleteStatus.put(inOutLinePO, CompleteStatus.OK); } } } } /** * Updated all inoutLines' PostageFreeStatus according to the respective bPartner's postage free * amount. * * @param ignorePostageFreeAmt if true, the lines qty is not set to {@link BigDecimal#ZERO}, even * if we are below the customer's postage free amount. However, the status is still set. */ @Override public void updatePostageFreeStatus(final boolean ignorePostageFreeAmt) { for (final I_M_InOut shipmentCandidate : getCandidates()) { final I_C_BPartner bPartner = InterfaceWrapperHelper.create(shipmentCandidate.getC_BPartner(), I_C_BPartner.class); final BigDecimal postageFree = (BigDecimal) bPartner.getPostageFreeAmt(); BigDecimal shipmentValue = BigDecimal.ZERO; // if ignorePostageFreeAmount is false and a postage free amount // is set, we need to check if the value of this shipment is // enough to make shipping profitable boolean sufficiantValue = postageFree == null; if (!sufficiantValue) { for (final I_M_InOutLine inOutLine : getLines(shipmentCandidate)) { // access orderLineCache instead of loading the line // from DB final MOrderLine orderLinePO = this.orderLineCache.get(inOutLine.getC_OrderLine_ID()); final BigDecimal lineValue = orderLinePO.getPriceActual().multiply(inOutLine.getQtyEntered()); shipmentValue = shipmentValue.add(lineValue); if (shipmentValue.compareTo(postageFree) >= 0) { sufficiantValue = true; break; } } } for (final I_M_InOutLine inOutLine : getLines(shipmentCandidate)) { final PostageFreeStatus status; if (sufficiantValue) { status = PostageFreeStatus.OK; } else { if (!ignorePostageFreeAmt) { inOutLine.setQtyEntered(BigDecimal.ZERO); inOutLine.setMovementQty(BigDecimal.ZERO); } status = PostageFreeStatus.BELOW_POSTAGEFREE_AMT; if (logger.isInfoEnabled()) { logger.info( "Shipment " + shipmentCandidate.getDocumentNo() + " has an insufficient value of " + shipmentValue.toPlainString() + " (minimum value is " + postageFree.toPlainString() + ")"); } } final MInOutLine inOutLinePO = getPO(inOutLine); line2PostageFreeStatus.put(inOutLinePO, status); } } } private void resetQtyDeliverables() { olId2QtyDeliverable.clear(); for (final MInOutLine inOutLine : line2InOut.keySet()) { if (inOutLine.getMovementQty().signum() != 0) { olId2QtyDeliverable.put(inOutLine.getC_OrderLine_ID(), inOutLine.getMovementQty()); } } } @Override public void setPostageFreeStatusOK(final I_M_InOut inOut) { for (final I_M_InOutLine inOutLine : getLines(inOut)) { final MInOutLine inOutLinePO = getPO(inOutLine); line2PostageFreeStatus.put(inOutLinePO, PostageFreeStatus.OK); } } @Override public I_M_InOutLine getInOutLineForOrderLine(final int orderLineId) { final MInOutLine inoutLine = orderLineId2InOutLine.get(orderLineId); return InterfaceWrapperHelper.create(inoutLine, I_M_InOutLine.class); } @Override public void setOverallStatus(final I_M_InOutLine inOutLine, final OverallStatus status) { final MInOutLine inOutLinePO = getPO(inOutLine); line2OverallStatus.put(inOutLinePO, status); } @Override public boolean isLineDiscarded(final I_M_InOutLine inOutLine) { return line2OverallStatus.containsKey(inOutLine) && OverallStatus.DISCARD.equals(line2OverallStatus.get(inOutLine)); } @Override public void addStatusInfo(final I_M_InOutLine inOutLine, final String string) { final MInOutLine inOutLinePO = getPO(inOutLine); StringBuilder currentInfos = line2StatusInfo.get(inOutLine); boolean firstInfo = false; if (currentInfos == null) { currentInfos = new StringBuilder(); line2StatusInfo.put(inOutLinePO, currentInfos); firstInfo = true; } if (!firstInfo) { currentInfos.append("; "); } currentInfos.append(string); } @Override public String getStatusInfos(final I_M_InOutLine inOutLine) { final StringBuilder statusInfos = line2StatusInfo.get(inOutLine); if (statusInfos == null) { return ""; } return statusInfos.toString(); } @Override public I_M_ShipmentSchedule getShipmentSchedule(final I_M_InOutLine inOutLine) { return line2sched.get(inOutLine); } @Override public Set<I_M_ShipmentSchedule> getAllShipmentSchedules() { // NOTE: we assume there are not duplicate instances for same M_ShipmentSchedule record. // Even if they are, we are returning them "twice" because the caller code will just iterate the // result and do the proper updates and we want to have everything updated. final Set<I_M_ShipmentSchedule> shipmentSchedules = new IdentityHashSet<I_M_ShipmentSchedule>(line2sched.size()); shipmentSchedules.addAll(line2sched.values()); return shipmentSchedules; } }