/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 Adempiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * *****************************************************************************/ package org.compiere.pos; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Locale; import java.util.Properties; import java.util.logging.Level; import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; import javax.swing.border.TitledBorder; import net.miginfocom.swing.MigLayout; import org.adempiere.plaf.AdempierePLAF; import org.compiere.apps.ADialog; import org.compiere.apps.AppsAction; import org.compiere.model.MCurrency; import org.compiere.model.MLookup; import org.compiere.model.MLookupFactory; import org.compiere.model.MPOS; import org.compiere.model.MPOSKey; import org.compiere.model.MPayment; import org.compiere.model.MPaymentValidate; import org.compiere.swing.CButton; import org.compiere.swing.CCheckBox; import org.compiere.swing.CComboBox; import org.compiere.swing.CDialog; import org.compiere.swing.CLabel; import org.compiere.swing.CPanel; import org.compiere.swing.CTextField; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Language; import org.compiere.util.Msg; import org.compiere.util.ValueNamePair; public class PosPayment extends CDialog implements PosKeyListener, ActionListener { private static final long serialVersionUID = 1961106531807910948L; // TODO - review this formatter (added by red1) //private NumberFormat formatter = new DecimalFormat("#0.00"); //red1 - parser to remove commas or dots separator for above '000s. private Locale locale = Language.getLoginLanguage().getLocale(); private NumberFormat nf = NumberFormat.getInstance(locale); /** Logger */ private static CLogger log = CLogger.getCLogger(PosPayment.class); @Override public void actionPerformed(ActionEvent e) { if ( e.getSource().equals(fTenderAmt) || e.getSource().equals(fPayAmt) ) { //red1 - remove commas from thousand value BigDecimal tender = Env.ZERO; BigDecimal pay = Env.ZERO; try { tender = BigDecimal.valueOf(nf.parse(fTenderAmt.getText()).doubleValue()); pay = BigDecimal.valueOf(nf.parse(fPayAmt.getText()).doubleValue()); } catch (ParseException n) { n.printStackTrace(); } if ( tender.compareTo(Env.ZERO) != 0 ) { fReturnAmt.setValue(tender.subtract(pay)); } return; } if ( e.getSource().equals(f_bProcess)) { processPayment(); } if ( e.getSource().equals(f_bCancel)) { paid = false; dispose(); return; } setTotals(); } private void processPayment() { try { String tenderType = ((ValueNamePair) tenderTypePick.getValue()).getID(); String tenderAmt = fTenderAmt.getText().equals("") ? "0" : fTenderAmt.getText(); BigDecimal amt = BigDecimal.valueOf(nf.parse(tenderAmt).doubleValue()); BigDecimal pay = BigDecimal.valueOf(nf.parse(fPayAmt.getText()).doubleValue()); if (amt.compareTo(BigDecimal.ZERO) <= 0) return; if (amt.compareTo(pay) > 0) { amt = pay; } if ( tenderType.equals(MPayment.TENDERTYPE_Cash) ) { p_posPanel.m_order.payCash(amt); tenderTypePick.removeItem(accountKey); } else if ( tenderType.equals(MPayment.TENDERTYPE_Check) ) { p_posPanel.m_order.payCheck(amt,fCheckAccountNo.getText(), fCheckRouteNo.getText(), fCheckNo.getText(), fCheckAccountName.getText()); tenderTypePick.removeItem(accountKey); } else if ( tenderType.equals(MPayment.TENDERTYPE_CreditCard) ) { String error = null; error = MPaymentValidate.validateCreditCardExp(fCCardMonth.getText()); if ( error != null && !error.isEmpty() ) { ADialog.warn(0, p_posPanel, error); return; } int month = MPaymentValidate.getCreditCardExpMM(fCCardMonth.getText()); int year = MPaymentValidate.getCreditCardExpYY(fCCardMonth.getText()); String type = ((ValueNamePair) fCCardType.getSelectedItem()).getValue(); error = MPaymentValidate.validateCreditCardNumber(fCCardNo.getText(), type); if ( error != null && !error.isEmpty() ) { ADialog.warn(0, p_posPanel, error); return; } p_posPanel.m_order.payCreditCard(amt, fCCardName.getText(), month, year, fCCardNo.getText(), fCCardVC.getText(), type); tenderTypePick.removeItem(accountKey); } else if ( tenderType.equals(MPayment.TENDERTYPE_Account) ) { p_posPanel.m_order.setPaidFromAccount(); p_posPanel.m_order.set_ValueOfColumn("PrintShipment", fPrintShipment.isSelected()); } else { ADialog.warn(0, this, "Unsupported payment type"); } //setTotals(); } catch (Exception e ) { ADialog.warn(0, this, "Payment processing failed: " + e.getMessage()); } } private PosBasePanel p_posPanel; private MPOS p_pos; private Properties p_ctx; private PosOrderModel p_order; private CTextField fTotal = new CTextField(10); private CTextField fBalance = new CTextField(10); private CComboBox tenderTypePick = new CComboBox(); private PosTextField fPayAmt; private CLabel lPayAmt; private CButton f_bProcess; private boolean paid = false; private BigDecimal balance = Env.ZERO; private PosTextField fCheckAccountNo; private PosTextField fCheckAccountName; private PosTextField fCheckNo; private PosTextField fCheckRouteNo; private PosTextField fCCardNo; private PosTextField fCCardName; private CComboBox fCCardType; private PosTextField fCCardMonth; private PosTextField fCCardVC; private CLabel lCheckNo; private CLabel lCheckAccountNo; private CLabel lCheckAccountName; private CLabel lCheckRouteNo; private CLabel lCCardNo; private CLabel lCCardName; private CLabel lCCardType; private CLabel lCCardMonth; private CLabel lCCardVC; private PosTextField fTenderAmt; private CLabel lTenderAmt; private PosTextField fReturnAmt; private CLabel lReturnAmt; private CButton f_bCancel; private CComboBox fCPaymentTerm = new CComboBox(); private CLabel lCPaymentTerm; private CCheckBox fPrintShipment = new CCheckBox(); private ValueNamePair accountKey; public PosPayment(PosBasePanel posPanel) { super(Env.getFrame(posPanel),true); p_posPanel = posPanel; p_pos = posPanel.p_pos; p_ctx = p_pos.getCtx(); p_order = p_posPanel.m_order; p_order.clearPayments(); if ( p_order == null ) dispose(); init(); pack(); setLocationByPlatform(true); } private void init() { Font font = AdempierePLAF.getFont_Field().deriveFont(18f); // North CPanel mainPanel = new CPanel(new MigLayout("hidemode 3", "[100:100:300, trailing]20[200:200:300,grow, trailing]")); getContentPane().add(mainPanel); mainPanel.setBorder(new TitledBorder(Msg.translate(p_ctx, "Payment"))); CLabel gtLabel = new CLabel(Msg.translate(p_ctx, "GrandTotal")); mainPanel.add(gtLabel, "growx"); mainPanel.add(fTotal, "wrap, growx"); fTotal.setEditable(false); fTotal.setFont(font); fTotal.setHorizontalAlignment(JTextField.TRAILING); mainPanel.add(new CLabel(Msg.translate(p_ctx, "Balance")), "growx"); mainPanel.add(fBalance, "wrap, growx"); fBalance.setEditable(false); fBalance.setFont(font); fBalance.setHorizontalAlignment(JTextField.TRAILING); mainPanel.add(new CLabel(Msg.translate(p_ctx, "TenderType"), "growx")); // Payment type selection int AD_Column_ID = 8416; //C_Payment_v.TenderType MLookup lookup = MLookupFactory.get(Env.getCtx(), 0, 0, AD_Column_ID, DisplayType.List); ArrayList<Object> types = lookup.getData(true, false, true, true); DefaultComboBoxModel typeModel = new DefaultComboBoxModel(types.toArray()); tenderTypePick.setModel(typeModel); // default to cash payment for (Object obj : types) { if ( obj instanceof ValueNamePair ) { ValueNamePair key = (ValueNamePair) obj; if ( key.getID().equals("X")) { // Cash tenderTypePick.setSelectedItem(key); } if (!"CDKXT".contains(key.getID())) { tenderTypePick.removeItem(key); } if ( key.getID().equals("T")) { // Account accountKey = key; } } } tenderTypePick.setFont(font); tenderTypePick.addActionListener(this); tenderTypePick.setName("tenderTypePick"); //red1 for ID purpuse during testing tenderTypePick.setRenderer(new ListCellRenderer() { protected DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer(); public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel renderer = (JLabel) defaultRenderer .getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); renderer.setPreferredSize(new Dimension(50, 50)); renderer.setHorizontalAlignment(JLabel.CENTER); return renderer; } }); mainPanel.add(tenderTypePick, "wrap, h 50!, growx"); /** * Load Payment Terms */ String sql = "SELECT C_PaymentTerm_ID, Name " + " FROM C_PaymentTerm " + " WHERE IsActive='Y' AND AD_Client_ID=? ORDER BY Name"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, Env.getAD_Client_ID(p_ctx)); rs = pstmt.executeQuery(); while (rs.next()) { int key = rs.getInt(1); String name = rs.getString(2); KeyNamePair pp = new KeyNamePair(key, name); fCPaymentTerm.addItem(pp); } } catch (SQLException e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } fCPaymentTerm.setFont(font); lCPaymentTerm = new CLabel(Msg.translate(p_ctx, "PaymentTerms")); mainPanel.add(lCPaymentTerm, "growx"); mainPanel.add(fCPaymentTerm, "wrap, h 50!, growx"); fPayAmt = new PosTextField(Msg.translate(p_ctx, "PayAmt"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), DisplayType.getNumberFormat(DisplayType.Amount)); lPayAmt = new CLabel(Msg.translate(p_ctx, "PayAmt")); mainPanel.add(lPayAmt, "growx"); fPayAmt.setFont(font); fPayAmt.setEditable(false); fPayAmt.setHorizontalAlignment(JTextField.TRAILING); fPayAmt.addActionListener(this); mainPanel.add(fPayAmt, "wrap, growx"); fTenderAmt = new PosTextField(Msg.translate(p_ctx, "AmountTendered"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), DisplayType.getNumberFormat(DisplayType.Amount)); lTenderAmt = new CLabel(Msg.translate(p_ctx, "AmountTendered")); mainPanel.add(lTenderAmt, "growx"); fTenderAmt.addActionListener(this); fTenderAmt.setFont(font); fTenderAmt.setHorizontalAlignment(JTextField.TRAILING); mainPanel.add(fTenderAmt, "wrap, growx"); fReturnAmt = new PosTextField(Msg.translate(p_ctx, "AmountReturned"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), DisplayType.getNumberFormat(DisplayType.Amount)); lReturnAmt = new CLabel(Msg.translate(p_ctx, "AmountReturned")); mainPanel.add(lReturnAmt, "growx"); fReturnAmt.setFont(font); fReturnAmt.setHorizontalAlignment(JTextField.TRAILING); mainPanel.add(fReturnAmt, "wrap, growx"); fReturnAmt.setEditable(false); fCheckRouteNo = new PosTextField(Msg.translate(p_ctx, "RoutingNo"), p_posPanel, p_pos.getOSNP_KeyLayout_ID()); lCheckRouteNo = new CLabel(Msg.translate(p_ctx, "RoutingNo")); mainPanel.add(lCheckRouteNo, "growx"); mainPanel.add(fCheckRouteNo, "wrap, growx"); fCheckRouteNo.setFont(font); fCheckRouteNo.setHorizontalAlignment(JTextField.TRAILING); fCheckAccountNo = new PosTextField(Msg.translate(p_ctx, "AccountNo"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), new DecimalFormat("#")); lCheckAccountNo = new CLabel(Msg.translate(p_ctx, "AccountNo")); mainPanel.add(lCheckAccountNo, "growx"); mainPanel.add(fCheckAccountNo, "wrap, growx"); fCheckAccountNo.setFont(font); fCheckAccountNo.setHorizontalAlignment(JTextField.TRAILING); fCheckNo = new PosTextField(Msg.translate(p_ctx, "CheckNo"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), new DecimalFormat("#")); lCheckNo = new CLabel(Msg.translate(p_ctx, "CheckNo")); mainPanel.add(lCheckNo, "growx"); mainPanel.add(fCheckNo, "wrap, growx"); fCheckNo.setFont(font); fCheckNo.setHorizontalAlignment(JTextField.TRAILING); fCheckAccountName = new PosTextField(Msg.translate(p_ctx, "A_Name"), p_posPanel, p_pos.getOSNP_KeyLayout_ID()); lCheckAccountName = new CLabel(Msg.translate(p_ctx, "A_Name")); mainPanel.add(lCheckAccountName, "growx"); mainPanel.add(fCheckAccountName, "wrap, growx"); fCheckAccountName.setFont(font); fCheckAccountName.setHorizontalAlignment(JTextField.TRAILING); /** * Load Credit Cards */ ValueNamePair[] ccs = p_order.getCreditCards((BigDecimal) fPayAmt.getValue()); // Set Selection fCCardType = new CComboBox(ccs); fCCardType.setName("cardType"); //red1 Id for testing fCCardType.setRenderer(new ListCellRenderer() { protected DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer(); public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel renderer = (JLabel) defaultRenderer .getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); renderer.setPreferredSize(new Dimension(50, 50)); renderer.setHorizontalAlignment(JLabel.CENTER); return renderer; } }); lCCardType = new CLabel(Msg.translate(p_ctx, "CreditCardType")); mainPanel.add(lCCardType, "growx"); mainPanel.add(fCCardType, "h 50, wrap, growx"); fCCardType.setFont(font); fCCardNo = new PosTextField(Msg.translate(p_ctx, "CreditCardNumber"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), new DecimalFormat("#")); lCCardNo = new CLabel(Msg.translate(p_ctx, "CreditCardNumber")); fCCardNo.setName("cardNo"); mainPanel.add(lCCardNo, "growx"); mainPanel.add(fCCardNo, "wrap, growx"); fCCardNo.setFont(font); fCCardNo.setHorizontalAlignment(JTextField.TRAILING); fCCardName = new PosTextField(Msg.translate(p_ctx, "Name"), p_posPanel, p_pos.getOSK_KeyLayout_ID()); lCCardName = new CLabel(Msg.translate(p_ctx, "Name")); mainPanel.add(lCCardName, "growx"); mainPanel.add(fCCardName, "wrap, growx"); fCCardName.setFont(font); fCCardName.setHorizontalAlignment(JTextField.TRAILING); fCCardMonth = new PosTextField(Msg.translate(p_ctx, "Expires"), p_posPanel, p_pos.getOSNP_KeyLayout_ID()); lCCardMonth = new CLabel(Msg.translate(p_ctx, "Expires")); fCCardMonth.setName("expiry"); mainPanel.add(lCCardMonth, "growx"); mainPanel.add(fCCardMonth, "wrap, w 75!"); fCCardMonth.setFont(font); fCCardMonth.setHorizontalAlignment(JTextField.TRAILING); fCCardVC = new PosTextField(Msg.translate(p_ctx, "CVC"), p_posPanel, p_pos.getOSNP_KeyLayout_ID(), new DecimalFormat("#")); lCCardVC = new CLabel(Msg.translate(p_ctx, "CVC")); mainPanel.add(lCCardVC, "growx"); mainPanel.add(fCCardVC, "wrap, w 75!"); fCCardVC.setFont(font); fCCardVC.setHorizontalAlignment(JTextField.TRAILING); fPrintShipment.setText("Imprimir Remito"); fPrintShipment.setSelected(true); mainPanel.add(fPrintShipment, "skip, wrap, growx"); AppsAction actCancel = new AppsAction("Cancel", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), false); actCancel.setDelegate(this); f_bCancel = (CButton)actCancel.getButton(); f_bCancel.setFocusable(false); mainPanel.add (f_bCancel, "h 50!, w 50!, skip, split 2, trailing"); AppsAction act = new AppsAction("Ok", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), false); act.setDelegate(this); f_bProcess = (CButton)act.getButton(); f_bProcess.setFocusable(false); mainPanel.add (f_bProcess, "h 50!, w 50!"); pack(); setTotals(); } // init private void setTotals() { String tenderType = ((ValueNamePair) tenderTypePick.getValue()).getID(); boolean cash = MPayment.TENDERTYPE_Cash.equals(tenderType); boolean check = MPayment.TENDERTYPE_Check.equals(tenderType); boolean creditcard = MPayment.TENDERTYPE_CreditCard.equals(tenderType); boolean account = MPayment.TENDERTYPE_Account.equals(tenderType); fTenderAmt.setVisible(cash || check || creditcard); fReturnAmt.setVisible(cash); lTenderAmt.setVisible(cash || check || creditcard); lReturnAmt.setVisible(cash); fCheckAccountNo.setVisible(check); fCheckNo.setVisible(check); fCheckRouteNo.setVisible(check); fCheckAccountName.setVisible(check); lCheckAccountNo.setVisible(check); lCheckNo.setVisible(check); lCheckRouteNo.setVisible(check); lCheckAccountName.setVisible(check); fCCardMonth.setVisible(creditcard); fCCardName.setVisible(creditcard); fCCardNo.setVisible(creditcard); fCCardType.setVisible(creditcard); fCCardVC.setVisible(creditcard); lCCardMonth.setVisible(creditcard); lCCardName.setVisible(creditcard); lCCardNo.setVisible(creditcard); lCCardType.setVisible(creditcard); lCCardVC.setVisible(creditcard); fCPaymentTerm.setVisible(account); lCPaymentTerm.setVisible(account); fPayAmt.setVisible(!account); lPayAmt.setVisible(!account); fPrintShipment.setVisible(account); fTotal.setValue(nf.format(p_order.getGrandTotal())); BigDecimal received = p_order.getPaidAmt(); balance = p_order.getGrandTotal().subtract(received); balance = balance.setScale(MCurrency.getStdPrecision(p_ctx, p_order.getC_Currency_ID())); log.info(String.format("TenderType=%s Received=%f Balace=%f", tenderType, received.doubleValue(), balance.doubleValue())); if (balance.compareTo(Env.ZERO) <= 0) { paid = true; if (balance.compareTo(Env.ZERO) < 0) { ADialog.warn(0, this, Msg.getMsg(p_ctx, "Change") + ": " + balance); } dispose(); } fBalance.setValue(nf.format(balance)); fPayAmt.setValue(balance); fTenderAmt.setValue(balance); fTenderAmt.requestFocusInWindow(); SwingUtilities.invokeLater(new Runnable() { public void run() { fTenderAmt.selectAll(); } }); pack(); } public void keyReturned(MPOSKey key) { String text = key.getText(); String payAmt = fPayAmt.getText(); String selected = fPayAmt.getSelectedText(); if ( selected != null && !selected.isEmpty() ) { payAmt = payAmt.replaceAll(selected, ""); } if ( text != null && !text.isEmpty() ) { if ( text.equals(".") && payAmt.indexOf(".") == -1 ) { fPayAmt.setText(payAmt + text); return; } try { Integer.parseInt(text); // test if number fPayAmt.setText(payAmt + text); } catch (NumberFormatException e) { // ignore non-numbers } } } public static boolean pay(PosBasePanel posPanel) { PosPayment pay = new PosPayment(posPanel); pay.setVisible(true); return pay.isPaid(); } private boolean isPaid() { return paid ; } }