/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, 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. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * *****************************************************************************/ package org.compiere.process; import java.io.File; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import org.adempiere.base.event.EventManager; import org.adempiere.base.event.EventProperty; import org.adempiere.base.event.IEventTopics; import org.adempiere.exceptions.AdempiereException; import org.compiere.acct.Doc; import org.compiere.model.MAcctSchema; import org.compiere.model.MAllocationHdr; import org.compiere.model.MBankStatement; import org.compiere.model.MBankTransfer; import org.compiere.model.MCash; import org.compiere.model.MClient; import org.compiere.model.MColumn; import org.compiere.model.MInOut; import org.compiere.model.MInventory; import org.compiere.model.MInvoice; import org.compiere.model.MJournal; import org.compiere.model.MJournalBatch; import org.compiere.model.MMovement; import org.compiere.model.MOrder; import org.compiere.model.MPayment; import org.compiere.model.MProduction; import org.compiere.model.MRMA; import org.compiere.model.MRole; import org.compiere.model.MTable; import org.compiere.model.PO; import org.compiere.model.SystemIDs; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Util; import org.eevolution.model.I_DD_Order; import org.eevolution.model.I_HR_Process; import org.eevolution.model.I_PP_Cost_Collector; import org.eevolution.model.I_PP_Order; import org.osgi.service.event.Event; import org.compiere.model.MDepositBatch; /** * Document Action Engine * * @author Jorg Janke * @author Karsten Thiemann FR [ 1782412 ] * @author victor.perez@e-evolution.com www.e-evolution.com FR [ 1866214 ] https://sourceforge.net/p/adempiere/feature-requests/298/ * @version $Id: DocumentEngine.java,v 1.2 2006/07/30 00:54:44 jjanke Exp $ */ public class DocumentEngine implements DocAction { /** * When client accounting is immediate, set this PO attribute to override the default of immediate posting after complete of document */ public static final String DOCUMENT_POST_IMMEDIATE_AFTER_COMPLETE = "Document.PostImmediateAfterComplete"; /** * Doc Engine (Drafted) * @param po document */ public DocumentEngine (DocAction po) { this (po, STATUS_Drafted); } // DocActionEngine /** * Doc Engine * @param po document * @param docStatus initial document status */ public DocumentEngine (DocAction po, String docStatus) { m_document = po; if (docStatus != null) m_status = docStatus; } // DocActionEngine /** Persistent Document */ private DocAction m_document; /** Document Status */ private String m_status = STATUS_Drafted; /** Process Message */ private String m_message = null; /** Actual Doc Action */ private String m_action = null; /** Logger */ private static CLogger log = CLogger.getCLogger(DocumentEngine.class); /** * Get Doc Status * @return document status */ @Override public String getDocStatus() { return m_status; } // getDocStatus /** * Set Doc Status - Ignored * @param ignored Status is not set directly * @see org.compiere.process.DocAction#setDocStatus(String) */ @Override public void setDocStatus(String ignored) { } // setDocStatus /** * Is current Document Status is Drafted * @return true if current status is drafted */ public boolean isDrafted() { return STATUS_Drafted.equals(m_status); } // isDrafted /** * Is current Document Status is Invalid * @return true if current status is Invalid */ public boolean isInvalid() { return STATUS_Invalid.equals(m_status); } // isInvalid /** * Is current Document Status is In Progress * @return true if current status is In Progress */ public boolean isInProgress() { return STATUS_InProgress.equals(m_status); } // isInProgress /** * Is current Document Status is Approved * @return true if current status is Approved */ public boolean isApproved() { return STATUS_Approved.equals(m_status); } // isApproved /** * Is current Document Status is Not Approved * @return true if current status is Not Approved */ public boolean isNotApproved() { return STATUS_NotApproved.equals(m_status); } // isNotApproved /** * Is current Document Status is Waiting Payment or Confirmation * @return true if current status is Waiting Payment */ public boolean isWaiting() { return STATUS_WaitingPayment.equals(m_status) || STATUS_WaitingConfirmation.equals(m_status); } // isWaitingPayment /** * Is current Document Status is Completed * @return true if current status is Completed */ public boolean isCompleted() { return STATUS_Completed.equals(m_status); } // isCompleted /** * Is current Document Status is Reversed * @return true if current status is Reversed */ public boolean isReversed() { return STATUS_Reversed.equals(m_status); } // isReversed /** * Is current Document Status is Closed * @return true if current status is Closed */ public boolean isClosed() { return STATUS_Closed.equals(m_status); } // isClosed /** * Is current Document Status is Voided * @return true if current status is Voided */ public boolean isVoided() { return STATUS_Voided.equals(m_status); } // isVoided /** * Is current Document Status is Unknown * @return true if current status is unknown */ public boolean isUnknown() { return STATUS_Unknown.equals(m_status) || !(isDrafted() || isInvalid() || isInProgress() || isNotApproved() || isApproved() || isWaiting() || isCompleted() || isReversed() || isClosed() || isVoided() ); } // isUnknown /** * Process document action.
* Checks if user (document) action is valid and then process action.
* Calls the individual actions which call the document action. * @param processAction document action value from workflow * @param docAction document action value from document (PO) * @return true if performed */ public boolean processIt (String processAction, String docAction) { //ensure doc status not change by other session if (m_document instanceof PO) { PO docPO = (PO) m_document; if (docPO.get_ID() > 0 && docPO.get_TrxName() != null && docPO.get_ValueOld("DocStatus") != null) { DB.getDatabase().forUpdate(docPO, 30); String docStatusOriginal = (String) docPO.get_ValueOld("DocStatus"); String statusSql = "SELECT DocStatus FROM " + docPO.get_TableName() + " WHERE " + docPO.get_KeyColumns()[0] + " = ? "; String currentStatus = DB.getSQLValueString((String)null, statusSql, docPO.get_ID()); if (!docStatusOriginal.equals(currentStatus) && currentStatus != null) { currentStatus = DB.getSQLValueString(docPO.get_TrxName(), statusSql, docPO.get_ID()); if (!docStatusOriginal.equals(currentStatus)) { throw new IllegalStateException(Msg.getMsg(docPO.getCtx(), "DocStatusChanged") + " " + docPO.toString()); } } } } m_message = null; m_action = null; // Std User Workflows - see MWFNodeNext.isValidFor if (isValidAction(processAction)) // WF Selection first m_action = processAction; // else if (isValidAction(docAction)) // User Selection second m_action = docAction; // Nothing to do else if (processAction.equals(ACTION_None) || docAction.equals(ACTION_None)) { if (m_document != null) m_document.get_Logger().info ("**** No Action (Prc=" + processAction + "/Doc=" + docAction + ") " + m_document); return true; } else { throw new IllegalStateException("Status=" + getDocStatus() + " - Invalid Actions: Process=" + processAction + ", Doc=" + docAction); } if (m_document != null && m_document.get_Logger().isLoggable(Level.INFO)) m_document.get_Logger().info ("**** Action=" + m_action + " (Prc=" + processAction + "/Doc=" + docAction + ") " + m_document); boolean success = processIt (m_action); if (m_document != null && m_document.get_Logger().isLoggable(Level.FINE)) m_document.get_Logger().fine("**** Action=" + m_action + " - Success=" + success); return success; } // process /** * Process document action - internal API, do not call directly.
* Calls the individual actions which call the document action. * @param action document action * @return true if performed */ @Override public boolean processIt (String action) { m_message = null; m_action = action; // if (ACTION_Unlock.equals(m_action)) return unlockIt(); if (ACTION_Invalidate.equals(m_action)) return invalidateIt(); if (ACTION_Prepare.equals(m_action)) return STATUS_InProgress.equals(prepareIt()); if (ACTION_Approve.equals(m_action)) return approveIt(); if (ACTION_Reject.equals(m_action)) return rejectIt(); if (ACTION_Complete.equals(m_action) || ACTION_WaitComplete.equals(m_action)) { String status = null; if (isDrafted() || isInvalid()) // prepare if not prepared yet { status = prepareIt(); if (!STATUS_InProgress.equals(status)) return false; } status = completeIt(); boolean ok = STATUS_Completed.equals(status) || STATUS_InProgress.equals(status) || STATUS_WaitingPayment.equals(status) || STATUS_WaitingConfirmation.equals(status); if (m_document != null && ok) { // PostProcess documents when invoice or inout (this is to postprocess the generated MatchPO and MatchInv if any) List docsPostProcess = new ArrayList(); if (m_document instanceof IDocsPostProcess) { docsPostProcess = ((IDocsPostProcess) m_document).getDocsPostProcess(); } if (m_document instanceof PO && docsPostProcess.size() > 0) { // Process (this is to update the ProcessedOn flag with a timestamp after the original document) for (PO docafter : docsPostProcess) { docafter.setProcessedOn("Processed", true, false); docafter.saveEx(); } } if (STATUS_Completed.equals(status) && MClient.isClientAccountingImmediate()) { boolean postNow = true; if (m_document instanceof PO) { Object attribute = ((PO) m_document).get_Attribute(DOCUMENT_POST_IMMEDIATE_AFTER_COMPLETE); if (attribute != null && attribute instanceof Boolean) { postNow = (boolean) attribute; } } if (postNow) { m_document.saveEx(); postIt(); if (m_document instanceof PO && docsPostProcess.size() > 0) { for (PO docafter : docsPostProcess) { if (docafter.get_ValueAsBoolean("Posted")) continue; String ignoreError = DocumentEngine.postImmediate(docafter.getCtx(), docafter.getAD_Client_ID(), docafter.get_Table_ID(), docafter.get_ID(), true, docafter.get_TrxName()); if (!Util.isEmpty(ignoreError, true)) { log.warning("Error posting " + docafter + ". Error="+ignoreError); } else { docafter.load(docafter.get_TrxName()); } } } } } } return ok; } if (ACTION_ReActivate.equals(m_action)) return reActivateIt(); if (ACTION_Reverse_Accrual.equals(m_action) || ACTION_Reverse_Correct.equals(m_action)) { boolean ok = false; if (ACTION_Reverse_Accrual.equals(m_action)) ok = reverseAccrualIt(); else if (ACTION_Reverse_Correct.equals(m_action)) ok = reverseCorrectIt(); if (m_document != null && ok) { if (MClient.isClientAccountingImmediate() && m_document instanceof IDocsPostProcess && m_document instanceof PO) { List docsPostProcess = ((IDocsPostProcess) m_document).getDocsPostProcess(); if (docsPostProcess.size() > 0) { if (((PO) m_document).get_ValueAsBoolean("Posted")) { for (PO docafter : docsPostProcess) { if (docafter.get_ValueAsBoolean("Posted")) continue; String ignoreError = DocumentEngine.postImmediate(docafter.getCtx(), docafter.getAD_Client_ID(), docafter.get_Table_ID(), docafter.get_ID(), true, docafter.get_TrxName()); if (!Util.isEmpty(ignoreError, true)) { log.warning("Error posting " + docafter + ". Error="+ignoreError); } else { docafter.load(docafter.get_TrxName()); } } } } } } return ok; } if (ACTION_Close.equals(m_action)) return closeIt(); if (ACTION_Void.equals(m_action)) return voidIt(); if (ACTION_Post.equals(m_action)) return postIt(); // return false; } // processDocument /** * Unlock Document.
* Status: Drafted. * @return true if success * @see org.compiere.process.DocAction#unlockIt() */ @Override public boolean unlockIt() { if (!isValidAction(ACTION_Unlock)) return false; if (m_document != null) { if (m_document.unlockIt()) { m_status = STATUS_Drafted; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Drafted; return true; } // unlockIt /** * Invalidate Document.
* Status: Invalid. * @return true if success * @see org.compiere.process.DocAction#invalidateIt() */ @Override public boolean invalidateIt() { if (!isValidAction(ACTION_Invalidate)) return false; if (m_document != null) { if (m_document.invalidateIt()) { m_status = STATUS_Invalid; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Invalid; return true; } // invalidateIt /** * Prepare Document.
* Status is set by document action method. * @return new status (In Progress or Invalid) * @see org.compiere.process.DocAction#prepareIt() */ @Override public String prepareIt() { if (!isValidAction(ACTION_Prepare)) return m_status; if (m_document != null) { m_status = m_document.prepareIt(); m_document.setDocStatus(m_status); } return m_status; } // processIt /** * Approve Document.
* Status: Approved. * @return true if success * @see org.compiere.process.DocAction#approveIt() */ @Override public boolean approveIt() { if (!isValidAction(ACTION_Approve)) return false; if (m_document != null) { if (m_document.approveIt()) { m_status = STATUS_Approved; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Approved; return true; } // approveIt /** * Reject Approval.
* Status: Not Approved. * @return true if success * @see org.compiere.process.DocAction#rejectIt() */ @Override public boolean rejectIt() { if (!isValidAction(ACTION_Reject)) return false; if (m_document != null) { if (m_document.rejectIt()) { m_status = STATUS_NotApproved; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_NotApproved; return true; } // rejectIt /** * Complete Document.
* Status is set by document action method. * @return new document status (Complete, In Progress, Invalid, Waiting ..) * @see org.compiere.process.DocAction#completeIt() */ @Override public String completeIt() { if (!isValidAction(ACTION_Complete)) return m_status; if (m_document != null) { m_status = m_document.completeIt(); m_document.setDocStatus(m_status); } return m_status; } // completeIt /** * Post Document.
* Does not change status. * @return true if success */ public boolean postIt() { if (!isValidAction(ACTION_Post) || m_document == null) return false; String error = DocumentEngine.postImmediate(Env.getCtx(), m_document.getAD_Client_ID(), m_document.get_Table_ID(), m_document.get_ID(), true, m_document.get_TrxName()); if (ACTION_Post.equals(m_action)) { // forced post via process - throw exception to inform the caller about the error if (! Util.isEmpty(error)) { throw new AdempiereException(error); } } return (error == null); } // postIt /** * Void Document.
* Status: Voided. * @return true if success * @see org.compiere.process.DocAction#voidIt() */ @Override public boolean voidIt() { if (!isValidAction(ACTION_Void)) return false; if (m_document != null) { if (m_document.voidIt()) { m_status = STATUS_Voided; if (!m_document.getDocStatus().equals(STATUS_Reversed)) m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Voided; return true; } // voidIt /** * Close Document.
* Status: Closed. * @return true if success * @see org.compiere.process.DocAction#closeIt() */ @Override public boolean closeIt() { if (m_document != null // orders can be closed any time && m_document.get_Table_ID() == MOrder.Table_ID) ; else if (!isValidAction(ACTION_Close)) return false; if (m_document != null) { if (m_document.closeIt()) { m_status = STATUS_Closed; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Closed; return true; } // closeIt /** * Reverse Correct Document.
* Status: Reversed. * @return true if success * @see org.compiere.process.DocAction#reverseCorrectIt() */ @Override public boolean reverseCorrectIt() { if (!isValidAction(ACTION_Reverse_Correct)) return false; if (m_document != null) { if (m_document.reverseCorrectIt()) { m_status = STATUS_Reversed; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Reversed; return true; } // reverseCorrectIt /** * Reverse Accrual Document.
* Status: Reversed. * @return true if success * @see org.compiere.process.DocAction#reverseAccrualIt() */ @Override public boolean reverseAccrualIt() { if (!isValidAction(ACTION_Reverse_Accrual)) return false; if (m_document != null) { if (m_document.reverseAccrualIt()) { m_status = STATUS_Reversed; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_Reversed; return true; } // reverseAccrualIt /** * Re-activate Document.
* Status: In Progress. * @return true if success * @see org.compiere.process.DocAction#reActivateIt() */ @Override public boolean reActivateIt() { if (!isValidAction(ACTION_ReActivate)) return false; if (m_document != null) { if (m_document.reActivateIt()) { m_status = STATUS_InProgress; m_document.setDocStatus(m_status); return true; } return false; } m_status = STATUS_InProgress; return true; } // reActivateIt /** * Set Document Status to new Status * @param newStatus new status */ protected void setStatus (String newStatus) { m_status = newStatus; } // setStatus /** * Get available Document Actions based on current Document Status. * @return array of actions */ public String[] getActionOptions() { if (isInvalid()) return new String[] {ACTION_Prepare, ACTION_Invalidate, ACTION_Unlock, ACTION_Void}; if (isDrafted()) return new String[] {ACTION_Prepare, ACTION_Invalidate, ACTION_Complete, ACTION_Unlock, ACTION_Void}; if (isInProgress() || isApproved()) return new String[] {ACTION_Complete, ACTION_WaitComplete, ACTION_Approve, ACTION_Reject, ACTION_Unlock, ACTION_Void, ACTION_Prepare}; if (isNotApproved()) return new String[] {ACTION_Reject, ACTION_Prepare, ACTION_Unlock, ACTION_Void}; if (isWaiting()) return new String[] {ACTION_Complete, ACTION_WaitComplete, ACTION_ReActivate, ACTION_Void, ACTION_Close}; if (isCompleted()) return new String[] {ACTION_Close, ACTION_ReActivate, ACTION_Reverse_Accrual, ACTION_Reverse_Correct, ACTION_Post, ACTION_Void}; if (isClosed()) return new String[] {ACTION_Post, ACTION_ReActivate}; if (isReversed() || isVoided()) return new String[] {ACTION_Post}; return new String[] {}; } // getActionOptions /** * Is The Action Valid based on current document status. * @param action action * @return true if valid */ public boolean isValidAction (String action) { String[] options = getActionOptions(); for (int i = 0; i < options.length; i++) { if (options[i].equals(action)) return true; } return false; } // isValidAction /** * Get Process Message * @return clear text error message */ @Override public String getProcessMsg () { return m_message; } // getProcessMsg /** * Set Process Message * @param msg clear text error message */ public void setProcessMsg (String msg) { m_message = msg; } // setProcessMsg /** Document Exception Message */ private static String EXCEPTION_MSG = "Document Engine is no Document"; /** * Not applicable, throw exception */ @Override public String getSummary() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public String getDocumentNo() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public String getDocumentInfo() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public int getDoc_User_ID() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public int getC_Currency_ID() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public BigDecimal getApprovalAmt() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public int getAD_Client_ID() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public int getAD_Org_ID() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Get Doc Action * @return Document Action */ @Override public String getDocAction() { return m_action; } /** * Not applicable, throw exception */ @Override public boolean save() { throw new IllegalStateException(EXCEPTION_MSG); } /** * Not applicable, throw exception */ @Override public void saveEx() throws AdempiereException { throw new IllegalStateException(EXCEPTION_MSG); } /** * Get Context * @return context */ @Override public Properties getCtx() { if (m_document != null) return m_document.getCtx(); throw new IllegalStateException(EXCEPTION_MSG); } // getCtx /** * Get ID of record * @return ID */ @Override public int get_ID() { if (m_document != null) return m_document.get_ID(); throw new IllegalStateException(EXCEPTION_MSG); } // get_ID /** * Get AD_Table_ID * @return AD_Table_ID */ @Override public int get_Table_ID() { if (m_document != null) return m_document.get_Table_ID(); throw new IllegalStateException(EXCEPTION_MSG); } // get_Table_ID /** * Get Logger * @return logger */ @Override public CLogger get_Logger() { if (m_document != null) return m_document.get_Logger(); throw new IllegalStateException(EXCEPTION_MSG); } // get_Logger /** * Get Transaction * @return trx name */ @Override public String get_TrxName() { return null; } // get_TrxName /** * CreatePDF * @return null */ @Override public File createPDF () { return null; } /** * Get list of valid document action into the options array parameter.
* Set default document action into the docAction array parameter. * @param docStatus * @param processing * @param orderType * @param isSOTrx * @param AD_Table_ID * @param docAction * @param options * @param periodOpen - flag indicating if the period is Open - to avoid including Void and ReverseCorrect options in the list * @return End index of valid options[] (exclusive) */ public static int getValidActions(String docStatus, Object processing, String orderType, String isSOTrx, int AD_Table_ID, String[] docAction, String[] options, boolean periodOpen, PO po) { if (options == null) throw new IllegalArgumentException("Option array parameter is null"); if (docAction == null) throw new IllegalArgumentException("Doc action array parameter is null"); int index = 0; // Locked if (processing != null) { boolean locked = "Y".equals(processing); if (!locked && processing instanceof Boolean) locked = ((Boolean)processing).booleanValue(); if (locked) options[index++] = DocumentEngine.ACTION_Unlock; } // Approval required .. NA if (docStatus.equals(DocumentEngine.STATUS_NotApproved)) { options[index++] = DocumentEngine.ACTION_Prepare; options[index++] = DocumentEngine.ACTION_Void; } // Draft/In Process/Invalid .. DR/IP/IN else if (docStatus.equals(DocumentEngine.STATUS_Drafted) || docStatus.equals(DocumentEngine.STATUS_InProgress) || docStatus.equals(DocumentEngine.STATUS_Invalid)) { options[index++] = DocumentEngine.ACTION_Complete; options[index++] = DocumentEngine.ACTION_Prepare; options[index++] = DocumentEngine.ACTION_Void; } // Approved .. AP else if (docStatus.equals(DocumentEngine.STATUS_Approved)) { options[index++] = DocumentEngine.ACTION_Complete; options[index++] = DocumentEngine.ACTION_Void; } // Complete .. CO else if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Close; } // Waiting Payment else if (docStatus.equals(DocumentEngine.STATUS_WaitingPayment) || docStatus.equals(DocumentEngine.STATUS_WaitingConfirmation)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_Prepare; } /******************** * Order */ if (AD_Table_ID == MOrder.Table_ID) { // Draft .. DR/IP/IN if (docStatus.equals(DocumentEngine.STATUS_Drafted) || docStatus.equals(DocumentEngine.STATUS_InProgress) || docStatus.equals(DocumentEngine.STATUS_Invalid)) { // Draft Sales Order Quote/Proposal - Process if ("Y".equals(isSOTrx) && ("OB".equals(orderType) || "ON".equals(orderType))) docAction[0] = DocumentEngine.ACTION_Prepare; } // Complete .. CO else if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_ReActivate; } else if (docStatus.equals(DocumentEngine.STATUS_WaitingPayment)) { options[index++] = DocumentEngine.ACTION_ReActivate; options[index++] = DocumentEngine.ACTION_Close; } } /******************** * Shipment */ else if (AD_Table_ID == MInOut.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } /******************** * Invoice */ else if (AD_Table_ID == MInvoice.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } /******************** * Payment */ else if (AD_Table_ID == MPayment.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; options[index++] = DocumentEngine.ACTION_ReActivate; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } /******************** * GL Journal */ else if (AD_Table_ID == MJournal.Table_ID || AD_Table_ID == MJournalBatch.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; options[index++] = DocumentEngine.ACTION_ReActivate; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } /******************** * Allocation */ else if (AD_Table_ID == MAllocationHdr.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } //[ 1782412 ] /******************** * Cash */ else if (AD_Table_ID == MCash.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; } } /******************** * Bank Statement */ else if (AD_Table_ID == MBankStatement.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_ReActivate; options[index++] = DocumentEngine.ACTION_Void; } } } /******************** * Inventory Movement, Physical Inventory */ else if (AD_Table_ID == MMovement.Table_ID || AD_Table_ID == MInventory.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } /******************** * Manufacturing Order */ else if (AD_Table_ID == I_PP_Order.Table_ID) { if (docStatus.equals(DocumentEngine.STATUS_Drafted) || docStatus.equals(DocumentEngine.STATUS_InProgress) || docStatus.equals(DocumentEngine.STATUS_Invalid)) { options[index++] = DocumentEngine.ACTION_Close; } // Complete .. CO else if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_ReActivate; } } /******************** * Production */ else if (AD_Table_ID == MProduction.Table_ID) { // Complete .. CO if (docStatus.equals(DocumentEngine.STATUS_Completed)) { if (periodOpen) { options[index++] = DocumentEngine.ACTION_Reverse_Correct; } options[index++] = DocumentEngine.ACTION_Reverse_Accrual; } } /******************** * Manufacturing Cost Collector */ else if (AD_Table_ID == I_PP_Cost_Collector.Table_ID) { if (docStatus.equals(DocumentEngine.STATUS_Drafted) || docStatus.equals(DocumentEngine.STATUS_InProgress) || docStatus.equals(DocumentEngine.STATUS_Invalid)) { options[index++] = DocumentEngine.ACTION_Close; } // Complete .. CO else if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_Reverse_Correct; } } /******************** * Distribution Order */ else if (AD_Table_ID == I_DD_Order.Table_ID) { if (docStatus.equals(DocumentEngine.STATUS_Drafted) || docStatus.equals(DocumentEngine.STATUS_InProgress) || docStatus.equals(DocumentEngine.STATUS_Invalid)) { options[index++] = DocumentEngine.ACTION_Close; } // Complete .. CO else if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_ReActivate; } } /******************** * Payroll Process */ else if (AD_Table_ID == I_HR_Process.Table_ID) { if (docStatus.equals(DocumentEngine.STATUS_Drafted) || docStatus.equals(DocumentEngine.STATUS_InProgress) || docStatus.equals(DocumentEngine.STATUS_Invalid)) { options[index++] = DocumentEngine.ACTION_Close; } // Complete .. CO else if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_ReActivate; } } /******************** * RMA Process */ else if (AD_Table_ID == MRMA.Table_ID) { if(docStatus.equals(DocumentEngine.STATUS_Completed)) { // IDEMPIERE-98 - Implement void for completed RMAs - Diego Ruiz - globalqss options[index++] = DocumentEngine.ACTION_Void; } } /******************** * Bank Transfer Process */ else if (AD_Table_ID == MBankTransfer.Table_ID) { if(docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; } } /******************** * Deposit Batch */ else if (AD_Table_ID == MDepositBatch.Table_ID) { // Complete if (docStatus.equals(DocumentEngine.STATUS_Completed)) { options[index++] = DocumentEngine.ACTION_Void; options[index++] = DocumentEngine.ACTION_ReActivate; } } if (po instanceof DocOptions) index = ((DocOptions) po).customizeValidActions(docStatus, processing, orderType, isSOTrx, AD_Table_ID, docAction, options, index); AtomicInteger indexObj = new AtomicInteger(index); ArrayList docActionsArray = new ArrayList(Arrays.asList(docAction)); ArrayList optionsArray = new ArrayList(Arrays.asList(options)); DocActionEventData eventData = new DocActionEventData(docStatus, processing, orderType, isSOTrx, AD_Table_ID, docActionsArray, optionsArray, indexObj, po); Event event = EventManager.newEvent(IEventTopics.DOCACTION, new EventProperty(EventManager.EVENT_DATA, eventData), new EventProperty(EventManager.TABLE_NAME_PROPERTY, po.get_TableName())); EventManager.getInstance().sendEvent(event); index = indexObj.get(); for (int i = 0; i < optionsArray.size(); i++) options[i] = optionsArray.get(i); for (int i = 0; i < docActionsArray.size(); i++) docAction[i] = docActionsArray.get(i); return index; } /** * Fill lists with DocAction Ref_List(135) values * @param v_value * @param v_name * @param v_description */ public static void readReferenceList(ArrayList v_value, ArrayList v_name, ArrayList v_description) { if (v_value == null) throw new IllegalArgumentException("v_value parameter is null"); if (v_name == null) throw new IllegalArgumentException("v_name parameter is null"); if (v_description == null) throw new IllegalArgumentException("v_description parameter is null"); String sql; if (Env.isBaseLanguage(Env.getCtx(), "AD_Ref_List")) sql = "SELECT Value, Name, Description FROM AD_Ref_List " + "WHERE AD_Reference_ID=? ORDER BY Name"; else sql = "SELECT l.Value, t.Name, t.Description " + "FROM AD_Ref_List l, AD_Ref_List_Trl t " + "WHERE l.AD_Ref_List_ID=t.AD_Ref_List_ID" + " AND t.AD_Language='" + Env.getAD_Language(Env.getCtx()) + "'" + " AND l.AD_Reference_ID=? ORDER BY t.Name"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, DocAction.AD_REFERENCE_ID); rs = pstmt.executeQuery(); while (rs.next()) { String value = rs.getString(1); String name = rs.getString(2); String description = rs.getString(3); if (description == null) description = ""; // v_value.add(value); v_name.add(name); v_description.add(description); } } catch (SQLException e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } } /** * Checks the access rights of the given role/client for the given document actions. * @param clientId * @param roleId * @param docTypeId * @param options * @param maxIndex * @return End index of valid options[] (exclusive) */ public static int checkActionAccess(int clientId, int roleId, int docTypeId, String[] options, int maxIndex) { return MRole.get(Env.getCtx(), roleId).checkActionAccess(clientId, docTypeId, options, maxIndex); } /** * Perform immediate posting of document * * @param ctx Client Context * @param AD_Client_ID Client ID of Document * @param AD_Table_ID Table ID of Document * @param Record_ID Record ID of this document * @param force force posting * @param trxName ignore, retained for backward compatibility * @return null, if success or error message */ public static String postImmediate (Properties ctx, int AD_Client_ID, int AD_Table_ID, int Record_ID, boolean force, String trxName) { // Ensure the table has Posted column / i.e. GL_JournalBatch can be completed but not posted if (MColumn.getColumn_ID(MTable.getTableName(ctx, AD_Table_ID), "Posted") <= 0) return null; String error = null; if (log.isLoggable(Level.INFO)) log.info ("Table=" + AD_Table_ID + ", Record=" + Record_ID); MAcctSchema[] ass = MAcctSchema.getClientAcctSchema(ctx, AD_Client_ID); error = Doc.postImmediate(ass, AD_Table_ID, Record_ID, force, trxName); return error; } // postImmediate /** * Process document action. This replaces DocAction.processIt(). * @param doc * @param processAction * @return true if performed */ public static boolean processIt(DocAction doc, String processAction) { boolean success = false; DocumentEngine engine = new DocumentEngine(doc, doc.getDocStatus()); success = engine.processIt(processAction, doc.getDocAction()); return success; } /** * Fill lists with DocAction Ref_List(131) values * @param v_value * @param v_name * @param v_description */ public static void readStatusReferenceList(ArrayList v_value, ArrayList v_name, ArrayList v_description) { if (v_value == null) throw new IllegalArgumentException("v_value parameter is null"); if (v_name == null) throw new IllegalArgumentException("v_name parameter is null"); if (v_description == null) throw new IllegalArgumentException("v_description parameter is null"); String sql; if (Env.isBaseLanguage(Env.getCtx(), "AD_Ref_List")) sql = "SELECT Value, Name, Description FROM AD_Ref_List " + "WHERE AD_Reference_ID=? ORDER BY Name"; else sql = "SELECT l.Value, t.Name, t.Description " + "FROM AD_Ref_List l, AD_Ref_List_Trl t " + "WHERE l.AD_Ref_List_ID=t.AD_Ref_List_ID" + " AND t.AD_Language='" + Env.getAD_Language(Env.getCtx()) + "'" + " AND l.AD_Reference_ID=? ORDER BY t.Name"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, null); pstmt.setInt(1, SystemIDs.REFERENCE_DOCUMENTSTATUS); rs = pstmt.executeQuery(); while (rs.next()) { String value = rs.getString(1); String name = rs.getString(2); String description = rs.getString(3); if (description == null) description = ""; // v_value.add(value); v_name.add(name); v_description.add(description); } } catch (SQLException e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } } } // DocumentEnine