/******************************************************************************
* 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.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.KeyboardFocusManager;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import net.miginfocom.swing.MigLayout;
import org.compiere.apps.ADialog;
import org.compiere.apps.SwingWorker;
import org.compiere.apps.form.FormFrame;
import org.compiere.model.MDocType;
import org.compiere.model.MInOut;
import org.compiere.model.MInvoice;
import org.compiere.model.MPInstance;
import org.compiere.model.MPOS;
import org.compiere.model.PO;
import org.compiere.model.Query;
import org.compiere.process.ProcessInfo;
import org.compiere.process.ProcessInfoParameter;
import org.compiere.swing.CPanel;
import org.compiere.util.CLogger;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import ar.com.ergio.model.FiscalDocumentPrint;
import ar.com.ergio.print.fiscal.view.AInfoFiscalPrinter;
import ar.com.ergio.print.fiscal.view.AInfoFiscalPrinter.DialogActionListener;
import ar.com.ergio.process.PosOrderGlobalVoiding;
/**
* Point of Sales Main Window.
*
* @author Comunidad de Desarrollo OpenXpertya
* *Basado en Codigo Original Modificado, Revisado y Optimizado de:
* *Copyright (c) Jorg Janke
* @version $Id: PosPanel.java,v 1.10 2004/07/12 04:10:04 jjanke Exp $
*/
public class PosBasePanel extends CPanel
//implements FormPanel
{
/**
*
*/
private static final long serialVersionUID = -3010214392188209281L;
// TODO - Review transaction usage
private String trxName = null; //Trx.createTrxName("GUIPOSTesting_"); --red1 won't persist trx for recall in display
//trxName for not committing test so tests does not impact DB.. temporary halt due to above issue.
/**
* Constructor - see init
*/
public PosBasePanel()
{
super (new MigLayout(" fill","[560!]10[300:350:, fill]",""));
originalKeyboardFocusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
m_focusMgr = new PosKeyboardFocusManager();
KeyboardFocusManager.setCurrentKeyboardFocusManager(m_focusMgr);
} // PosPanel
/** Window No */
private int m_WindowNo = 0;
/** FormFrame */
private FormFrame m_frame;
/** Logger */
private CLogger log = CLogger.getCLogger(getClass());
/** Context */
private Properties m_ctx = Env.getCtx();
/** Sales Rep */
private int m_SalesRep_ID = 0;
/** POS Model */
protected MPOS p_pos = null;
/** Keyoard Focus Manager */
private PosKeyboardFocusManager m_focusMgr = null;
/** Order Panel */
protected SubOrder f_order;
/** Current Line */
protected SubCurrentLine f_curLine;
/** Function Keys */
protected SubFunctionKeys f_functionKeys;
protected CashSubFunctions f_cashfunctions;
private javax.swing.Timer logoutTimer;
PosOrderModel m_order = null;
// Today's (login) date */
private Timestamp m_today = Env.getContextAsDate(m_ctx, "#Date");
private KeyboardFocusManager originalKeyboardFocusManager;
private boolean debug = true;
private HashMap<Integer, POSKeyboard> keyboards = new HashMap<Integer, POSKeyboard>();
/** LAR - fiscal printer control window */
protected AInfoFiscalPrinter infoFiscalPrinter;
public String getTrxName(){
return trxName;
}
/**
* Initialize Panel
* @param WindowNo window
* @param frame parent frame
*/
public void init (int WindowNo, FormFrame frame)
{
m_frame = frame;
m_frame.setJMenuBar(null);
if ( debug )
m_frame.setPreferredSize(new Dimension(1024,768));
else
{
m_frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
m_frame.setResizable(false);
}
m_SalesRep_ID = Env.getAD_User_ID(m_ctx);
log.info("init - SalesRep_ID=" + m_SalesRep_ID);
m_WindowNo = WindowNo;
//
try
{
if (!dynInit())
{
dispose();
frame.dispose();
return;
}
m_frame.getContentPane().add(this, BorderLayout.CENTER);
}
catch(Exception e)
{
log.log(Level.SEVERE, "init", e);
}
log.config( "PosPanel.init - " + getPreferredSize());
if ( p_pos.getAutoLogoutDelay() > 0 && logoutTimer == null )
{
logoutTimer = new javax.swing.Timer(1000, new ActionListener() {
PointerInfo pi = null;
long lastMouseMove = System.currentTimeMillis();
long lastKeyboardEvent = System.currentTimeMillis();
@Override
public void actionPerformed(ActionEvent e)
{
long now = e.getWhen();
PointerInfo newPi = MouseInfo.getPointerInfo();
// mouse moved
if ( newPi != null && pi != null
&& !pi.getLocation().equals(newPi.getLocation()) )
{
lastMouseMove = now;
}
pi = newPi;
lastKeyboardEvent = m_focusMgr.getLastWhen();
if ( p_pos.getAutoLogoutDelay()*1000 < now - Math.max(lastKeyboardEvent, lastMouseMove) )
{
// new PosLogin(this);
}
}
});
logoutTimer.start();
}
m_focusMgr.start();
} // init
/**
* Dispose - Free Resources
*/
public void dispose()
{
keyboards.clear();
keyboards = null;
if ( logoutTimer != null )
logoutTimer.stop();
logoutTimer = null;
if (m_focusMgr != null)
m_focusMgr.stop();
m_focusMgr = null;
KeyboardFocusManager.setCurrentKeyboardFocusManager(originalKeyboardFocusManager);
//
if (f_order != null)
f_order.dispose();
f_order = null;
if (f_curLine != null)
{
// if ( m_order != null )
// m_order.deleteOrder();
f_curLine.dispose();
}
f_curLine = null;
if (f_functionKeys != null)
f_functionKeys.dispose();
f_functionKeys = null;
if (f_cashfunctions != null)
f_cashfunctions.dispose();
f_cashfunctions = null;
if (m_frame != null)
m_frame.dispose();
m_frame = null;
m_ctx = null;
infoFiscalPrinter = null;
} // dispose
/**************************************************************************
* Dynamic Init.
* PosPanel has a GridBagLayout.
* The Sub Panels return their position
*/
private boolean dynInit()
{
if (!setMPOS())
return false;
m_frame.setTitle("Adempiere POS: " + p_pos.getName());
// Create Sub Panels
f_order = new SubOrder (this);
add (f_order, "split 2, flowy, growx, spany");
//
f_curLine = new SubCurrentLine (this);
add (f_curLine, "h 300, growx, growy, gaptop 10");
f_functionKeys = new SubFunctionKeys (this);
add (f_functionKeys, "aligny top, h 500, growx, growy, flowy, split 2");
// LAR - Fiscal printer implementation
createInfoFiscalPrinter();
return true;
} // dynInit
/**
* Set MPOS
* @return true if found/set
*/
private boolean setMPOS()
{
MPOS[] poss = null;
if (m_SalesRep_ID == 100) // superUser
poss = getPOSs (0);
else
poss = getPOSs (m_SalesRep_ID);
//
if (poss.length == 0)
{
ADialog.error(m_WindowNo, m_frame, "NoPOSForUser");
return false;
}
else if (poss.length == 1)
{
p_pos = poss[0];
return true;
}
// Select POS
String msg = Msg.getMsg(m_ctx, "SelectPOS");
String title = Env.getHeader(m_ctx, m_WindowNo);
Object selection = JOptionPane.showInputDialog(m_frame, msg, title,
JOptionPane.QUESTION_MESSAGE, null, poss, poss[0]);
if (selection != null)
{
p_pos = (MPOS)selection;
Env.setContext(m_ctx, Env.POS_ID, p_pos.get_ID());
return true;
}
return false;
} // setMPOS
/**
* Get POSs for specific Sales Rep and Org
* @param SalesRep_ID
* @return array of POS
*/
private MPOS[] getPOSs(int SalesRep_ID)
{
String whereClause = "AD_Org_ID=?";
Object[] params = new Object[] { Env.getAD_Org_ID(m_ctx) };
List<MPOS> list = new Query(m_ctx, MPOS.Table_Name, whereClause, null)
.setParameters(params)
.setOnlyActiveRecords(true)
.list();
return list.toArray(new MPOS[list.size()]);
} // getPOSs
/**************************************************************************
* Get Today's date
* @return date
*/
public Timestamp getToday()
{
return m_today;
} // getToday
/**
* New Order
*
*/
public void newOrder()
{
log.info( "PosPanel.newOrder");
f_order.setC_BPartner_ID(0);
m_order = null;
// TODO - Review: avoid create an order with default BPartner
//m_order = PosOrderModel.createOrder(p_pos, f_order.getBPartner(), trxName);
f_curLine.newLine();
f_order.f_bpName.requestFocusInWindow();
updateInfo();
// LAR - Fiscal printer implementation
infoFiscalPrinter.setVisible(false);
infoFiscalPrinter.clearDetail();
} // newOrder
/**
* Get the number of the window for the function calls that it needs
*
* @return the window number
*/
public int getWindowNo()
{
return m_WindowNo;
}
/**
* Get the properties for the process calls that it needs
*
* @return getProperties m_ctx
*/
public Properties getCtx()
{
return m_ctx;
}
public void updateInfo()
{
// reload order
if (m_order != null) {
m_order.reload();
}
if (f_curLine != null) {
f_curLine.updateTable(m_order);
}
if (f_order != null) {
f_order.updateOrder();
}
}
/**
* @param m_c_order_id
*/
public void setOldOrder(int m_c_order_id)
{
if ( m_order != null )
m_order.deleteOrder();
if ( m_c_order_id == 0 )
m_order = null;
else
m_order = new PosOrderModel(m_ctx , m_c_order_id, trxName, p_pos);
updateInfo();
}
/**
* @param m_c_order_id
*/
public void setOrder(int m_c_order_id)
{
if ( m_c_order_id == 0 )
m_order = null;
else
m_order = new PosOrderModel(m_ctx , m_c_order_id, trxName, p_pos);
}
public POSKeyboard getKeyboard(int keyLayoutId) {
if ( keyboards.containsKey(keyLayoutId) )
return keyboards.get(keyLayoutId);
else
{
POSKeyboard keyboard = new POSKeyboard(this, keyLayoutId);
keyboards.put(keyLayoutId, keyboard);
return keyboard;
}
}
/**********************************************************************************************
* LAR Fiscal Printing Implementation
**********************************************************************************************/
///////////////////////////////////////////////////////////////////////////
// TODO - Abstract Fiscal Printing behavior in order to avoid
// duplicate code with InvoiceFiscalPrinting class
///////////////////////////////////////////////////////////////////////////
protected void startGlassPane(final String AD_Message)
{
m_frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
String waitMsg = Msg.getMsg(m_ctx, AD_Message) + ", " + Msg.getMsg(m_ctx, "PleaseWait");
m_frame.setBusyMessage(waitMsg);
m_frame.setBusyTimer(4);
m_frame.setBusy(true);
}
protected void stopGlassPane()
{
m_frame.setBusy(false);
m_frame.setCursor(Cursor.getDefaultCursor());
}
protected boolean printFiscalTicket(final PO document)
{
log.info("Printing fiscal ticket for " + document);
final SwingWorker worker = new SwingWorker()
{
@Override
public Object construct()
{
boolean success = true;
int c_DocType_ID = document.get_ValueAsInt("C_DocType_ID");
try {
final MDocType docType = new MDocType(m_ctx, c_DocType_ID, null);
int lar_Fiscal_Printer_ID = docType.get_ValueAsInt("LAR_Fiscal_Printer_ID");
log.info("doc type asociated " + docType);
final FiscalDocumentPrint fdp = new FiscalDocumentPrint(lar_Fiscal_Printer_ID,
infoFiscalPrinter, infoFiscalPrinter);
log.info("fiscal document print created: " + fdp);
infoFiscalPrinter.setFiscalDocumentPrint(fdp);
success = printDocument(fdp, document);
} catch (Exception e) {
log.log(Level.SEVERE, "Fiscal printing error", e);
success = false;
}
return Boolean.valueOf(success);
}
@Override
public void finished() {
boolean result = (Boolean) getValue();
log.info("Finish fiscal printing thread. Printed Ok?: " + result);
if (result) {
newOrder();
}
}
};
worker.start();
infoFiscalPrinter.setVisible(true); // Thread stops here until fiscal printing finished
return (Boolean) worker.get();
} // printFiscalTicket
/**
* Imprime el tipo de documento correspondiende según el tipo de orden
*/
private boolean printDocument(final FiscalDocumentPrint fdp, final PO document)
{
if (document instanceof MInOut)
return fdp.printShipmentDocument(document);
else if (document instanceof MInvoice)
{
return fdp.printDocument(document);
}
else
throw new AdempierePOSException("Sub tipo de orden de POS incorrecto");
} // printDocument
private void createInfoFiscalPrinter()
{
// Fiscal printing action listener
final DialogActionListener dialogActionListener = new DialogActionListener()
{
@Override
public void actionVoidPerformed()
{
// Anulación de los documentos.
voidDocuments();
}
@Override
public void actionReprintFinished()
{
// Al finalizar una reimpresión de ticket, se
// reestablece la interfaz para un nuevo pedido
newOrder();
stopGlassPane();
}
};
// Fiscal Printing status window
infoFiscalPrinter = new AInfoFiscalPrinter(dialogActionListener,
getWindowNo(), Msg.parseTranslation(Env.getCtx(), "@PrintingFiscalDocument@"));
log.info("info fiscal printer windows created");
infoFiscalPrinter.setReprintButtonActive(true);
infoFiscalPrinter.setVoidButtonActive(true);
infoFiscalPrinter.setOkButtonActive(false);
}
/**
* Invoca la anulación de los documentos generados debido a un error en la
* impresión fiscal
*/
private void voidDocuments()
{
SwingWorker worker = new SwingWorker()
{
private String errorMsg = null;
@Override
public Object construct()
{
// Crea parámetro que se enviará al proceso
final ProcessInfoParameter param = new ProcessInfoParameter("C_Order_ID", m_order.getC_Order_ID(), "", "", "");
// Crea información del proceso
int AD_Process_ID = 3000037;
final ProcessInfo pi = new ProcessInfo("PosOrderGlobalVoiding", AD_Process_ID);
pi.setParameter(new ProcessInfoParameter[]{ param });
// Crea una instancia de proceso (para registro y sincronizacion)
final MPInstance pinstance = new MPInstance(m_ctx, 0, null);
pinstance.setAD_Process_ID(AD_Process_ID);
pinstance.setRecord_ID(0);
pinstance.save();
// Conecta el proceso con la instancia de proceso
pi.setAD_PInstance_ID(pinstance.get_ID());
// Crea el proceso a ejecutar
final PosOrderGlobalVoiding process = new PosOrderGlobalVoiding();
log.info("Iniciando proceso global de anulaci\u00f3n");
return process.startProcess(m_ctx, pi, null);
}
@Override
public void finished()
{
boolean success = (Boolean) getValue();
if (!success) {
ADialog.error(getWindowNo(), PosBasePanel.this, errorMsg);
if (ADialog.ask(getWindowNo(), PosBasePanel.this,
Msg.parseTranslation(m_ctx, "@RetryVoidInvoice@"))) {
// Re intenta anular los documentos.
voidDocuments();
} else {
newOrder();
stopGlassPane();
}
} else {
newOrder();
stopGlassPane();
}
}
}; // new SwingWorker
startGlassPane("VoidingInvoice");
worker.start();
} // voidDocuments
} // PosPanel