com.tegik.pcobro.module.FIN_AddPaymentTegik.java Source code

Java tutorial

Introduction

Here is the source code for com.tegik.pcobro.module.FIN_AddPaymentTegik.java

Source

/*
 *************************************************************************
 * The contents of this file are subject to the Openbravo  Public  License
 * Version  1.0  (the  "License"),  being   the  Mozilla   Public  License
 * Version 1.1  with a permitted attribution clause; you may not  use this
 * file except in compliance with the License. You  may  obtain  a copy of
 * the License at http://www.openbravo.com/legal/license.html
 * Software distributed under the License  is  distributed  on  an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific  language  governing  rights  and  limitations
 * under the License.
 * The Original Code is Openbravo ERP.
 * The Initial Developer of the Original Code is Openbravo SLU
 * All portions are Copyright (C) 2010-2011 Openbravo SLU
 * All Rights Reserved.
 * Contributor(s):  ______________________________________.
 *************************************************************************
 */
package com.tegik.pcobro.module;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.servlet.ServletException;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.openbravo.advpaymentmngt.dao.AdvPaymentMngtDao;
import org.openbravo.advpaymentmngt.utility.FIN_Utility;
import org.openbravo.base.exception.OBException;
import org.openbravo.base.secureApp.VariablesSecureApp;
import org.openbravo.base.session.OBPropertiesProvider;
import org.openbravo.dal.core.DalUtil;
import org.openbravo.dal.core.OBContext;
import org.openbravo.dal.service.OBCriteria;
import org.openbravo.dal.service.OBDal;
import org.openbravo.data.FieldProvider;
import org.openbravo.database.ConnectionProvider;
import org.openbravo.erpCommon.utility.FieldProviderFactory;
import org.openbravo.erpCommon.utility.OBError;
import org.openbravo.erpCommon.utility.Utility;
import org.openbravo.model.common.businesspartner.BusinessPartner;
import org.openbravo.model.common.currency.Currency;
import org.openbravo.model.common.enterprise.DocumentType;
import org.openbravo.model.common.enterprise.Organization;
import org.openbravo.model.common.invoice.Invoice;
import org.openbravo.model.common.plm.Product;
import org.openbravo.model.financialmgmt.gl.GLItem;
import org.openbravo.model.financialmgmt.payment.FIN_FinancialAccount;
import org.openbravo.model.financialmgmt.payment.FIN_Payment;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentDetail;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentMethod;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentPropDetail;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentProposal;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentSchedule;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentScheduleDetail;
import org.openbravo.model.financialmgmt.payment.FinAccPaymentMethod;
import org.openbravo.model.marketing.Campaign;
import org.openbravo.model.materialmgmt.cost.ABCActivity;
import org.openbravo.model.project.Project;
import org.openbravo.model.sales.SalesRegion;
import org.openbravo.scheduling.ProcessBundle;

public class FIN_AddPaymentTegik {
    private static AdvPaymentMngtDao dao;

    /**
     * Saves the payment and the payment details based on the given Payment Schedule Details. If no
     * FIN_Payment is given it creates a new one.
     * 
     * If the Payment Scheduled Detail is not completely paid and the difference is not written a new
     * Payment Schedule Detail is created with the difference.
     * 
     * If a Refund Amount is given an extra Payment Detail will be created with it.
     * 
     * @param _payment
     *          FIN_Payment where new payment details will be saved.
     * @param isReceipt
     *          boolean to define if the Payment is a Receipt Payment (true) or a Payable Payment
     *          (false). Used when no FIN_Payment is given.
     * @param docType
     *          DocumentType of the Payment. Used when no FIN_Payment is given.
     * @param strPaymentDocumentNo
     *          String with the Document Number of the new payment. Used when no FIN_Payment is given.
     * @param businessPartner
     *          BusinessPartner of the new Payment. Used when no FIN_Payment is given.
     * @param paymentMethod
     *          FIN_PaymentMethod of the new Payment. Used when no FIN_Payment is given.
     * @param finAccount
     *          FIN_FinancialAccount of the new Payment. Used when no FIN_Payment is given.
     * @param strPaymentAmount
     *          String with the Payment Amount of the new Payment. Used when no FIN_Payment is given.
     * @param paymentDate
     *          Date when the Payment is done. Used when no FIN_Payment is given.
     * @param organization
     *          Organization of the new Payment. Used when no FIN_Payment is given.
     * @param selectedPaymentScheduleDetails
     *          List of FIN_PaymentScheduleDetail to be included in the Payment. If one of the items
     *          is contained in other payment the method will throw an exception. Prevent
     *          invoice/order to be paid several times.
     * @param selectedPaymentScheduleDetailsAmounts
     *          HashMap with the Amount to be paid for each Scheduled Payment Detail.
     * @param isWriteoff
     *          Boolean to write off the difference when the payment amount is lower than the Payment
     *          Scheduled PAyment Detail amount.
     * @param isRefund
     *          Not used.
     * @param paymentCurrency
     *          The currency that the payment is being made in. Will default to financial account
     *          currency if not specified
     * @param finTxnConvertRate
     *          Exchange rate to convert between payment currency and financial account currency for
     *          this payment. Defaults to 1.0 if not supplied
     * @param finTxnAmount
     *          Amount of payment in currency of financial account
     * @return The FIN_Payment OBObject containing all the Payment Details.
     */
    public static FIN_Payment savePayment(FIN_Payment _payment, boolean isReceipt, DocumentType docType,
            String strPaymentDocumentNo, BusinessPartner businessPartner, FIN_PaymentMethod paymentMethod,
            FIN_FinancialAccount finAccount, String strPaymentAmount, Date paymentDate, Organization organization,
            String referenceNo, List<FIN_PaymentScheduleDetail> selectedPaymentScheduleDetails,
            HashMap<String, BigDecimal> selectedPaymentScheduleDetailsAmounts, boolean isWriteoff, boolean isRefund,
            Currency paymentCurrency, BigDecimal finTxnConvertRate, BigDecimal finTxnAmount) {
        dao = new AdvPaymentMngtDao();

        BigDecimal assignedAmount = BigDecimal.ZERO;
        final FIN_Payment payment;
        if (_payment != null)
            payment = _payment;
        else {
            payment = dao.getNewPayment(isReceipt, organization, docType, strPaymentDocumentNo, businessPartner,
                    paymentMethod, finAccount, strPaymentAmount, paymentDate, referenceNo, paymentCurrency,
                    finTxnConvertRate, finTxnAmount);
            OBDal.getInstance().flush();
        }

        for (FIN_PaymentDetail paymentDetail : payment.getFINPaymentDetailList())
            assignedAmount = assignedAmount.add(paymentDetail.getAmount());
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        OBContext.setAdminMode();
        try {
            for (FIN_PaymentScheduleDetail paymentScheduleDetail : selectedPaymentScheduleDetails) {
                // Payment Schedule Detail already linked to a payment detail.
                if (paymentScheduleDetail.getPaymentDetails() != null) {
                    throw new OBException(String.format(FIN_Utility.messageBD("APRM_PsdInSeveralPayments"),
                            paymentScheduleDetail.getIdentifier()));
                }
                BigDecimal paymentDetailAmount = selectedPaymentScheduleDetailsAmounts
                        .get(paymentScheduleDetail.getId());
                BigDecimal amountDifference = paymentScheduleDetail.getAmount().subtract(paymentDetailAmount);
                if (amountDifference.compareTo(BigDecimal.ZERO) != 0) {
                    if (!isWriteoff) {
                        dao.duplicateScheduleDetail(paymentScheduleDetail, amountDifference);
                        amountDifference = BigDecimal.ZERO;
                    } else
                        paymentScheduleDetail.setWriteoffAmount(amountDifference);
                    paymentScheduleDetail.setAmount(paymentDetailAmount);
                }
                assignedAmount = assignedAmount.add(paymentDetailAmount);
                dao.getNewPaymentDetail(payment, paymentScheduleDetail, paymentDetailAmount, amountDifference,
                        false, null);
            }
            if (assignedAmount.compareTo(payment.getAmount()) == -1) {
                FIN_PaymentScheduleDetail refundScheduleDetail = dao.getNewPaymentScheduleDetail(
                        payment.getOrganization(), payment.getAmount().subtract(assignedAmount));
                dao.getNewPaymentDetail(payment, refundScheduleDetail, payment.getAmount().subtract(assignedAmount),
                        BigDecimal.ZERO, false, null);
            }
        } catch (final Exception e) {
            e.printStackTrace(System.err);
            throw new OBException(e);
        } finally {
            OBContext.restorePreviousMode();
        }

        return payment;
    }

    /*
     * Temporary method to supply defaults for exchange Rate and converted amount
     */
    public static FIN_Payment savePayment(FIN_Payment _payment, boolean isReceipt, DocumentType docType,
            String strPaymentDocumentNo, BusinessPartner businessPartner, FIN_PaymentMethod paymentMethod,
            FIN_FinancialAccount finAccount, String strPaymentAmount, Date paymentDate, Organization organization,
            String referenceNo, List<FIN_PaymentScheduleDetail> selectedPaymentScheduleDetails,
            HashMap<String, BigDecimal> selectedPaymentScheduleDetailsAmounts, boolean isWriteoff,
            boolean isRefund) {
        return savePayment(_payment, isReceipt, docType, strPaymentDocumentNo, businessPartner, paymentMethod,
                finAccount, strPaymentAmount, paymentDate, organization, referenceNo,
                selectedPaymentScheduleDetails, selectedPaymentScheduleDetailsAmounts, isWriteoff, isRefund, null,
                null, null);
    }

    public static FIN_Payment setFinancialTransactionAmountAndRate(FIN_Payment payment,
            BigDecimal finTxnConvertRate, BigDecimal finTxnAmount) {
        if (payment == null) {
            return payment;
        }

        BigDecimal paymentAmount = payment.getAmount();
        if (paymentAmount == null) {
            paymentAmount = BigDecimal.ZERO;
        }

        if (finTxnConvertRate == null || finTxnConvertRate.compareTo(BigDecimal.ZERO) <= 0) {
            finTxnConvertRate = BigDecimal.ONE;
        }
        if (finTxnAmount == null || finTxnAmount.compareTo(BigDecimal.ZERO) == 0) {
            finTxnAmount = paymentAmount.multiply(finTxnConvertRate);
        } else if (paymentAmount.compareTo(BigDecimal.ZERO) != 0) {
            // Correct exchange rate for rounding that occurs in UI
            finTxnConvertRate = finTxnAmount.divide(paymentAmount, MathContext.DECIMAL64);
        }

        payment.setFinancialTransactionAmount(finTxnAmount);
        payment.setFinancialTransactionConvertRate(finTxnConvertRate);

        return payment;
    }

    public static FIN_Payment createRefundPayment(ConnectionProvider conProvider, VariablesSecureApp vars,
            FIN_Payment payment, BigDecimal refundAmount) {
        return createRefundPayment(conProvider, vars, payment, refundAmount, null);
    }

    public static FIN_Payment createRefundPayment(ConnectionProvider conProvider, VariablesSecureApp vars,
            FIN_Payment payment, BigDecimal refundAmount, BigDecimal conversionRate) {
        dao = new AdvPaymentMngtDao();
        FIN_Payment refundPayment;
        if (payment.getFINPaymentDetailList().isEmpty())
            refundPayment = payment;
        else {
            refundPayment = (FIN_Payment) DalUtil.copy(payment, false);
            String strDescription = Utility.messageBD(conProvider, "APRM_RefundPayment", vars.getLanguage());
            strDescription += ": " + payment.getDocumentNo();
            refundPayment.setDescription(strDescription);
            refundPayment.setGeneratedCredit(BigDecimal.ZERO);
            final String strDocumentNo = FIN_Utility.getDocumentNo(payment.getOrganization(),
                    payment.getDocumentType().getDocumentCategory(), "DocumentNo_FIN_Payment");
            refundPayment.setDocumentNo(strDocumentNo);
        }
        refundPayment.setProcessed(false);
        refundPayment.setStatus("RPAP");
        OBDal.getInstance().save(refundPayment);
        OBDal.getInstance().flush();
        refundPayment.setAmount(refundAmount);
        refundPayment.setUsedCredit(refundAmount.negate());

        setFinancialTransactionAmountAndRate(refundPayment, conversionRate, null);

        FIN_PaymentScheduleDetail refundScheduleDetail = dao.getNewPaymentScheduleDetail(payment.getOrganization(),
                refundAmount);
        dao.getNewPaymentDetail(refundPayment, refundScheduleDetail, refundAmount, BigDecimal.ZERO, true, null);

        return refundPayment;
    }

    /**
     * Adds new Details to the given Payment Proposal based on the List of Payment Schedule Details.
     * 
     * @param paymentProposal
     *          FIN_PaymentProposal where new Details are added.
     * @param paymentAmount
     *          Total amount to be paid.
     * @param selectedPaymentScheduleDetails
     *          List of FIN_PaymentScheduleDetail that needs to be added to the Payment Proposal.
     * @param selectedPaymentScheduleDetailAmounts
     *          HashMap with the Amount to be paid for each Scheduled Payment Detail.
     * @param writeOffAmt
     *          Total amount to be written off.
     */
    public static void savePaymentProposal(FIN_PaymentProposal paymentProposal, BigDecimal paymentAmount,
            List<FIN_PaymentScheduleDetail> selectedPaymentScheduleDetails,
            HashMap<String, BigDecimal> selectedPaymentScheduleDetailAmounts, BigDecimal writeOffAmt) {
        dao = new AdvPaymentMngtDao();
        paymentProposal.setAmount(paymentAmount);
        paymentProposal.setWriteoffAmount((writeOffAmt != null) ? writeOffAmt : BigDecimal.ZERO);
        BigDecimal convertRate = paymentProposal.getFinancialTransactionConvertRate();
        if (BigDecimal.ONE.equals(convertRate)) {
            paymentProposal.setFinancialTransactionAmount(paymentAmount);
        } else {
            Currency finAccountCurrency = paymentProposal.getAccount().getCurrency();
            BigDecimal finAccountTxnAmount = paymentAmount.multiply(convertRate);
            long faPrecision = finAccountCurrency.getStandardPrecision();
            finAccountTxnAmount = finAccountTxnAmount.setScale((int) faPrecision, RoundingMode.HALF_UP);

            paymentProposal.setFinancialTransactionAmount(finAccountTxnAmount);
        }

        for (FIN_PaymentScheduleDetail paymentScheduleDetail : selectedPaymentScheduleDetails) {
            BigDecimal detailWriteOffAmt = null;
            if (writeOffAmt != null)
                detailWriteOffAmt = paymentScheduleDetail.getAmount()
                        .subtract(selectedPaymentScheduleDetailAmounts.get(paymentScheduleDetail.getId()));

            dao.getNewPaymentProposalDetail(paymentProposal.getOrganization(), paymentProposal,
                    paymentScheduleDetail, selectedPaymentScheduleDetailAmounts.get(paymentScheduleDetail.getId()),
                    detailWriteOffAmt, null);
        }
    }

    /**
     * It adds to the Payment a new Payment Detail with the given GL Item and amount.
     * 
     * @param payment
     *          Payment where the new Payment Detail needs to be added.
     * @param glitemAmount
     *          Amount of the new Payment Detail.
     * @param glitem
     *          GLItem to be set in the new Payment Detail.
     */
    public static void saveGLItem(FIN_Payment payment, BigDecimal glitemAmount, GLItem glitem) {
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        dao = new AdvPaymentMngtDao();
        OBContext.setAdminMode();
        try {
            FIN_PaymentScheduleDetail psd = dao.getNewPaymentScheduleDetail(payment.getOrganization(),
                    glitemAmount);
            FIN_PaymentDetail pd = dao.getNewPaymentDetail(payment, psd, glitemAmount, BigDecimal.ZERO, false,
                    glitem);
            pd.setFinPayment(payment);
            OBDal.getInstance().save(pd);
            OBDal.getInstance().save(payment);
        } finally {
            OBContext.restorePreviousMode();
        }
    }

    /**
     * It adds to the Payment a new Payment Detail with the given GL Item, amount and accounting
     * dimensions
     * 
     * @param payment
     *          Payment where the new Payment Detail needs to be added.
     * @param glitemAmount
     *          Amount of the new Payment Detail.
     * @param glitem
     *          GLItem to be set in the new Payment Detail.
     * @param businessPartner
     *          accounting dimension
     * @param product
     *          accounting dimension
     * @param project
     *          accounting dimension
     * @param campaign
     *          accounting dimension
     * @param activity
     *          accounting dimension
     * @param salesRegion
     *          accounting dimension
     */
    public static void saveGLItem(FIN_Payment payment, BigDecimal glitemAmount, GLItem glitem,
            BusinessPartner businessPartner, Product product, Project project, Campaign campaign,
            ABCActivity activity, SalesRegion salesRegion) {
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        dao = new AdvPaymentMngtDao();
        OBContext.setAdminMode();
        try {
            FIN_PaymentScheduleDetail psd = dao.getNewPaymentScheduleDetail(payment.getOrganization(), glitemAmount,
                    businessPartner, product, project, campaign, activity, salesRegion);
            FIN_PaymentDetail pd = dao.getNewPaymentDetail(payment, psd, glitemAmount, BigDecimal.ZERO, false,
                    glitem);
            pd.setFinPayment(payment);
            OBDal.getInstance().save(pd);
            OBDal.getInstance().save(payment);
        } finally {
            OBContext.restorePreviousMode();
        }
    }

    /**
     * Removes the Payment Detail from the Payment when the Detail is related to a GLItem
     * 
     * @param payment
     *          FIN_Payment that contains the Payment Detail.
     * @param paymentDetail
     *          FIN_PaymentDetail to be removed.
     */
    public static void removeGLItem(FIN_Payment payment, FIN_PaymentDetail paymentDetail) {
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        dao = new AdvPaymentMngtDao();
        OBContext.setAdminMode();
        try {
            List<FIN_PaymentDetail> pdl = payment.getFINPaymentDetailList();
            if (paymentDetail != null) {
                pdl.remove(paymentDetail);
                OBDal.getInstance().remove(paymentDetail);
            } else {
                List<String> pdlIDs = new ArrayList<String>();
                for (FIN_PaymentDetail deletePaymentDetail : pdl)
                    pdlIDs.add(deletePaymentDetail.getId());

                for (String pdlID : pdlIDs) {
                    pdl.remove(dao.getObject(FIN_PaymentDetail.class, pdlID));
                    OBDal.getInstance().remove(dao.getObject(FIN_PaymentDetail.class, pdlID));
                }
            }
            payment.setFINPaymentDetailList(pdl);
            OBDal.getInstance().save(payment);
            OBDal.getInstance().flush();
        } finally {
            OBContext.restorePreviousMode();
        }
    }

    /**
     * It adds to the scheduledPaymentDetails List the FIN_PaymentScheduleDetails given in the
     * strSelectedPaymentDetailsIds comma separated String of Id's that are not yet included on it.
     * 
     * @param scheduledPaymentDetails
     *          List of FIN_PaymentScheduleDetail.
     * @param strSelectedPaymentDetailsIds
     *          String of comma separated id's that needs to be included in the List if they are not
     *          present.
     * @return returns a List of FIN_PaymentScheduleDetail including all the Payment Schedule Details.
     */
    public static List<FIN_PaymentScheduleDetail> getSelectedPaymentDetails(
            List<FIN_PaymentScheduleDetail> scheduledPaymentDetails, String strSelectedPaymentDetailsIds) {
        final List<FIN_PaymentScheduleDetail> selectedScheduledPaymentDetails;
        if (scheduledPaymentDetails == null)
            selectedScheduledPaymentDetails = new ArrayList<FIN_PaymentScheduleDetail>();
        else
            selectedScheduledPaymentDetails = scheduledPaymentDetails;
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        OBContext.setAdminMode();
        try {
            // selected scheduled payments list
            final List<FIN_PaymentScheduleDetail> tempSelectedScheduledPaymentDetails = FIN_Utility
                    .getOBObjectList(FIN_PaymentScheduleDetail.class, strSelectedPaymentDetailsIds);
            for (FIN_PaymentScheduleDetail tempPaymentScheduleDetail : tempSelectedScheduledPaymentDetails) {
                if (!selectedScheduledPaymentDetails.contains(tempPaymentScheduleDetail))
                    selectedScheduledPaymentDetails.add(tempPaymentScheduleDetail);

            }
        } finally {
            OBContext.restorePreviousMode();
        }
        return selectedScheduledPaymentDetails;
    }

    /**
     * Creates a HashMap with the FIN_PaymentScheduleDetail id's and the amount gotten from the
     * Session.
     * 
     * The amounts are stored in Session like "inpPaymentAmount"+paymentScheduleDetail.Id
     * 
     * @param vars
     *          VariablseSecureApp with the session data.
     * @param selectedPaymentScheduleDetails
     *          List of FIN_PaymentScheduleDetails that need to be included in the HashMap.
     * @return A HashMap mapping the FIN_PaymentScheduleDetail's Id with the corresponding amount.
     */
    public static HashMap<String, BigDecimal> getSelectedPaymentDetailsAndAmount(VariablesSecureApp vars,
            List<FIN_PaymentScheduleDetail> selectedPaymentScheduleDetails) throws ServletException {
        HashMap<String, BigDecimal> selectedPaymentScheduleDetailsAmounts = new HashMap<String, BigDecimal>();

        for (FIN_PaymentScheduleDetail paymentScheduleDetail : selectedPaymentScheduleDetails) {
            selectedPaymentScheduleDetailsAmounts.put(paymentScheduleDetail.getId(), new BigDecimal(
                    vars.getNumericParameter("inpPaymentAmount" + paymentScheduleDetail.getId(), "")));
        }
        return selectedPaymentScheduleDetailsAmounts;
    }

    /**
     * Builds a FieldProvider with a set of Payment Schedule Details based on the
     * selectedScheduledPaymentDetails and filteredScheduledPaymentDetails Lists. When the firstLoad
     * parameter is true the "paymentAmount" field is loaded from the corresponding Payment Proposal
     * Detail if it exists, when false it gets the amount from session.
     * 
     * @param vars
     *          VariablesSecureApp containing the Session data.
     * @param selectedScheduledPaymentDetails
     *          List of FIN_PaymentScheduleDetails that need to be selected by default.
     * @param filteredScheduledPaymentDetails
     *          List of FIN_PaymentScheduleDetails that need to be unselected by default.
     * @param firstLoad
     *          Boolean to set if the PaymentAmount is gotten from the PaymentProposal (true) or from
     *          Session (false)
     * @param paymentProposal
     *          PaymentProposal used to get the amount when firstLoad is true.
     * @return a FieldProvider object with all the given FIN_PaymentScheduleDetails.
     */
    public static FieldProvider[] getShownScheduledPaymentDetails(VariablesSecureApp vars,
            List<FIN_PaymentScheduleDetail> selectedScheduledPaymentDetails,
            List<FIN_PaymentScheduleDetail> filteredScheduledPaymentDetails, boolean firstLoad,
            FIN_PaymentProposal paymentProposal) throws ServletException {
        dao = new AdvPaymentMngtDao();
        final List<FIN_PaymentScheduleDetail> shownScheduledPaymentDetails = new ArrayList<FIN_PaymentScheduleDetail>();
        shownScheduledPaymentDetails.addAll(selectedScheduledPaymentDetails);
        shownScheduledPaymentDetails.addAll(filteredScheduledPaymentDetails);
        FIN_PaymentScheduleDetail[] FIN_PaymentScheduleDetails = new FIN_PaymentScheduleDetail[0];
        FIN_PaymentScheduleDetails = shownScheduledPaymentDetails.toArray(FIN_PaymentScheduleDetails);
        // FieldProvider[] data = FieldProviderFactory.getFieldProviderArray(FIN_PaymentSchedules);

        // FieldProvider[] data = new FieldProviderFactory[selectedScheduledPayments.size()];
        FieldProvider[] data = FieldProviderFactory.getFieldProviderArray(shownScheduledPaymentDetails);
        String dateFormat = OBPropertiesProvider.getInstance().getOpenbravoProperties()
                .getProperty("dateFormat.java");
        SimpleDateFormat dateFormater = new SimpleDateFormat(dateFormat);
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        OBContext.setAdminMode();
        try {

            for (int i = 0; i < data.length; i++) {
                FieldProviderFactory.setField(data[i], "finSelectedPaymentDetailId",
                        (selectedScheduledPaymentDetails.contains(FIN_PaymentScheduleDetails[i]))
                                ? FIN_PaymentScheduleDetails[i].getId()
                                : "");
                FieldProviderFactory.setField(data[i], "finScheduledPaymentDetailId",
                        FIN_PaymentScheduleDetails[i].getId());
                if (FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule() != null)
                    FieldProviderFactory.setField(data[i], "orderNr",
                            FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule().getOrder().getDocumentNo());
                else
                    FieldProviderFactory.setField(data[i], "orderNr", "");
                if (FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule() != null)
                    FieldProviderFactory.setField(data[i], "invoiceNr",
                            FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule().getInvoice().getDocumentNo());
                else
                    FieldProviderFactory.setField(data[i], "invoiceNr", "");
                if (FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule() != null) {
                    FieldProviderFactory.setField(data[i], "dueDate",
                            dateFormater
                                    .format(FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule().getDueDate())
                                    .toString());
                    FieldProviderFactory.setField(data[i], "transactionDate", dateFormater.format(
                            FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule().getInvoice().getInvoiceDate())
                            .toString());
                    FieldProviderFactory.setField(data[i], "invoicedAmount", FIN_PaymentScheduleDetails[i]
                            .getInvoicePaymentSchedule().getInvoice().getGrandTotalAmount().toString());
                    FieldProviderFactory.setField(data[i], "expectedAmount",
                            FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule().getAmount().toString());

                    // Truncate Business Partner
                    String businessPartner = FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule().getInvoice()
                            .getBusinessPartner().getIdentifier();
                    FieldProviderFactory.setField(data[i], "businessPartnerId", FIN_PaymentScheduleDetails[i]
                            .getInvoicePaymentSchedule().getInvoice().getBusinessPartner().getId());
                    String truncateBusinessPartner = (businessPartner.length() > 18)
                            ? businessPartner.substring(0, 15).concat("...").toString()
                            : businessPartner;
                    FieldProviderFactory.setField(data[i], "businessPartnerName",
                            (businessPartner.length() > 18) ? businessPartner : "");
                    FieldProviderFactory.setField(data[i], "businessPartnerNameTrunc", truncateBusinessPartner);

                    // Truncate Payment Method
                    String paymentMethodName = FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule()
                            .getFinPaymentmethod().getName();
                    String truncatePaymentMethodName = (paymentMethodName.length() > 18)
                            ? paymentMethodName.substring(0, 15).concat("...").toString()
                            : paymentMethodName;
                    FieldProviderFactory.setField(data[i], "paymentMethodName",
                            (paymentMethodName.length() > 18) ? paymentMethodName : "");
                    FieldProviderFactory.setField(data[i], "paymentMethodNameTrunc", truncatePaymentMethodName);

                    if (FIN_PaymentScheduleDetails[i].getInvoicePaymentSchedule().getFINPaymentPriority() != null) {
                        FieldProviderFactory.setField(data[i], "gridLineColor", FIN_PaymentScheduleDetails[i]
                                .getInvoicePaymentSchedule().getFINPaymentPriority().getColor());
                    }
                } else {
                    FieldProviderFactory.setField(data[i], "dueDate",
                            dateFormater
                                    .format(FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule().getDueDate())
                                    .toString());
                    FieldProviderFactory.setField(data[i], "transactionDate", dateFormater.format(
                            FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule().getOrder().getOrderDate())
                            .toString());
                    FieldProviderFactory.setField(data[i], "invoicedAmount", "");
                    FieldProviderFactory.setField(data[i], "expectedAmount",
                            FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule().getAmount().toString());

                    // Truncate Business Partner
                    String businessPartner = FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule().getOrder()
                            .getBusinessPartner().getIdentifier();
                    FieldProviderFactory.setField(data[i], "businessPartnerId", FIN_PaymentScheduleDetails[i]
                            .getOrderPaymentSchedule().getOrder().getBusinessPartner().getId());
                    String truncateBusinessPartner = (businessPartner.length() > 18)
                            ? businessPartner.substring(0, 15).concat("...").toString()
                            : businessPartner;
                    FieldProviderFactory.setField(data[i], "businessPartnerName",
                            (businessPartner.length() > 18) ? businessPartner : "");
                    FieldProviderFactory.setField(data[i], "businessPartnerNameTrunc", truncateBusinessPartner);

                    // Truncate Payment Method
                    String paymentMethodName = FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule()
                            .getFinPaymentmethod().getName();
                    String truncatePaymentMethodName = (paymentMethodName.length() > 18)
                            ? paymentMethodName.substring(0, 15).concat("...").toString()
                            : paymentMethodName;
                    FieldProviderFactory.setField(data[i], "paymentMethodName",
                            (paymentMethodName.length() > 18) ? paymentMethodName : "");
                    FieldProviderFactory.setField(data[i], "paymentMethodNameTrunc", truncatePaymentMethodName);

                    if (FIN_PaymentScheduleDetails[i].getOrderPaymentSchedule().getFINPaymentPriority() != null) {
                        FieldProviderFactory.setField(data[i], "gridLineColor", FIN_PaymentScheduleDetails[i]
                                .getOrderPaymentSchedule().getFINPaymentPriority().getColor());
                    }
                }
                FieldProviderFactory.setField(data[i], "outstandingAmount",
                        FIN_PaymentScheduleDetails[i].getAmount().toString());

                String strPaymentAmt = "";
                String strDifference = "";
                if (firstLoad && (selectedScheduledPaymentDetails.contains(FIN_PaymentScheduleDetails[i]))
                        && paymentProposal != null)
                    strPaymentAmt = dao.getPaymentProposalDetailAmount(FIN_PaymentScheduleDetails[i],
                            paymentProposal);
                else
                    strPaymentAmt = vars
                            .getNumericParameter("inpPaymentAmount" + FIN_PaymentScheduleDetails[i].getId(), "");
                if (!"".equals(strPaymentAmt))
                    strDifference = FIN_PaymentScheduleDetails[i].getAmount()
                            .subtract(new BigDecimal(strPaymentAmt)).toString();
                FieldProviderFactory.setField(data[i], "paymentAmount", strPaymentAmt);
                FieldProviderFactory.setField(data[i], "difference", strDifference);
                FieldProviderFactory.setField(data[i], "rownum", String.valueOf(i));

            }
        } finally {
            OBContext.restorePreviousMode();
        }
        return data;
    }

    /**
     * Returns a List of FIN_PaymentScheduleDetails related to the Proposal Details of the given
     * Payment Proposal.
     * 
     * @param paymentProposal
     */
    public static List<FIN_PaymentScheduleDetail> getSelectedPendingPaymentsFromProposal(
            FIN_PaymentProposal paymentProposal) {
        List<FIN_PaymentScheduleDetail> existingPaymentScheduleDetail = new ArrayList<FIN_PaymentScheduleDetail>();
        for (FIN_PaymentPropDetail proposalDetail : paymentProposal.getFINPaymentPropDetailList())
            existingPaymentScheduleDetail.add(proposalDetail.getFINPaymentScheduledetail());

        return existingPaymentScheduleDetail;
    }

    /**
     * This method groups several payment schedule details by {PaymentDetails, OrderPaymenSchedule,
     * InvoicePaymentSchedule}.
     * 
     * @param psd
     *          Payment Schedule Detail base. The amount will be updated here.
     */
    public static void mergePaymentScheduleDetails(FIN_PaymentScheduleDetail psd) {
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done

        OBContext.setAdminMode();
        try {
            OBCriteria<FIN_PaymentScheduleDetail> psdFilter = OBDal.getInstance()
                    .createCriteria(FIN_PaymentScheduleDetail.class);
            psdFilter.add(Restrictions.eq(FIN_PaymentScheduleDetail.PROPERTY_CLIENT, psd.getClient()));
            psdFilter.add(Restrictions.eq(FIN_PaymentScheduleDetail.PROPERTY_ORGANIZATION, psd.getOrganization()));
            psdFilter.add(Restrictions.isNull(FIN_PaymentScheduleDetail.PROPERTY_PAYMENTDETAILS));
            if (psd.getOrderPaymentSchedule() == null)
                psdFilter.add(Restrictions.isNull(FIN_PaymentScheduleDetail.PROPERTY_ORDERPAYMENTSCHEDULE));
            else
                psdFilter.add(Restrictions.eq(FIN_PaymentScheduleDetail.PROPERTY_ORDERPAYMENTSCHEDULE,
                        psd.getOrderPaymentSchedule()));
            if (psd.getInvoicePaymentSchedule() == null)
                psdFilter.add(Restrictions.isNull(FIN_PaymentScheduleDetail.PROPERTY_INVOICEPAYMENTSCHEDULE));
            else
                psdFilter.add(Restrictions.eq(FIN_PaymentScheduleDetail.PROPERTY_INVOICEPAYMENTSCHEDULE,
                        psd.getInvoicePaymentSchedule()));

            // Update amount and remove payment schedule detail
            final List<String> removedPDSIds = new ArrayList<String>();
            for (FIN_PaymentScheduleDetail psdToRemove : psdFilter.list()) {
                psd.setAmount(psd.getAmount().add(psdToRemove.getAmount()));
                // TODO: Set 0 as default value for writeoffamt column in FIN_Payment_ScheduleDetail table
                BigDecimal sum1 = (psd.getWriteoffAmount() == null) ? BigDecimal.ZERO : psd.getWriteoffAmount();
                BigDecimal sum2 = (psdToRemove.getWriteoffAmount() == null) ? BigDecimal.ZERO
                        : psdToRemove.getWriteoffAmount();
                psd.setWriteoffAmount(sum1.add(sum2));

                OBDal.getInstance().save(psdToRemove);
                removedPDSIds.add(psdToRemove.getId());
            }

            for (String pdToRm : removedPDSIds) {
                OBDal.getInstance().remove(OBDal.getInstance().get(FIN_PaymentScheduleDetail.class, pdToRm));
            }

            psd.setAmount(psd.getAmount()
                    .add((psd.getWriteoffAmount() == null) ? BigDecimal.ZERO : psd.getWriteoffAmount()));
            psd.setWriteoffAmount(BigDecimal.ZERO);
            psd.setPaymentDetails(null);
            OBDal.getInstance().save(psd);
            OBDal.getInstance().flush();
            OBDal.getInstance().getSession().refresh(psd);

        } catch (Exception e) {
            throw new OBException(e);
        } finally {
            OBContext.restorePreviousMode();
        }
    }

    /**
     * Update Payment Schedule amounts with the amount of the Payment Schedule Detail or Payment
     * Detail
     * 
     * @param paymentSchedule
     *          Payment Schedule to be updated
     * @param amount
     *          Amount of the Payment Schedule Detail or Payment Detail
     * @param writeOffAmount
     *          Write off amount, null or 0 if not applicable.
     */
    public static void updatePaymentScheduleAmounts(FIN_PaymentSchedule paymentSchedule, BigDecimal amount,
            BigDecimal writeOffAmount) {
        paymentSchedule.setPaidAmount(paymentSchedule.getPaidAmount().add(amount));
        paymentSchedule.setOutstandingAmount(paymentSchedule.getOutstandingAmount().subtract(amount));
        if (writeOffAmount != null && writeOffAmount.compareTo(BigDecimal.ZERO) != 0) {
            paymentSchedule.setPaidAmount(paymentSchedule.getPaidAmount().add(writeOffAmount));
            paymentSchedule.setOutstandingAmount(paymentSchedule.getOutstandingAmount().subtract(writeOffAmount));
        }
        OBDal.getInstance().save(paymentSchedule);
        if (paymentSchedule.getInvoice() != null) {
            updateInvoicePaymentMonitor(paymentSchedule.getInvoice(), paymentSchedule.getDueDate(), amount,
                    writeOffAmount);
        }
    }

    /**
     * Method used to update the payment monitor based on the payment made by the user.
     * 
     * @param invoice
     *          Invoice object going to be updated based on the payment. {Invoice}
     * @param amount
     *          Amount of the transaction.
     * @param writeOffAmount
     *          Amount that has been wrote off.
     */
    private static void updateInvoicePaymentMonitor(Invoice invoice, Date dueDate, BigDecimal amount,
            BigDecimal writeOffAmount) {
        boolean isDueDateFlag = dueDate.compareTo(new Date()) <= 0;
        invoice.setTotalPaid(invoice.getTotalPaid().add(amount));
        invoice.setLastCalculatedOnDate(new Date());
        invoice.setOutstandingAmount(invoice.getOutstandingAmount().subtract(amount));
        if (isDueDateFlag)
            invoice.setDueAmount(invoice.getDueAmount().subtract(amount));
        if (writeOffAmount != null && writeOffAmount.compareTo(BigDecimal.ZERO) != 0) {
            invoice.setTotalPaid(invoice.getTotalPaid().add(writeOffAmount));
            invoice.setOutstandingAmount(invoice.getOutstandingAmount().subtract(writeOffAmount));
            if (isDueDateFlag)
                invoice.setDueAmount(invoice.getDueAmount().subtract(writeOffAmount));
        }
        if (0 == invoice.getOutstandingAmount().compareTo(BigDecimal.ZERO)) {
            invoice.setPaymentComplete(true);
        } else
            invoice.setPaymentComplete(false);
        List<FIN_PaymentSchedule> paymentSchedList = invoice.getFINPaymentScheduleList();
        Date firstDueDate = null;
        for (FIN_PaymentSchedule paymentSchedule : paymentSchedList) {
            if (paymentSchedule.getOutstandingAmount().compareTo(BigDecimal.ZERO) > 0
                    && (firstDueDate == null || firstDueDate.after(paymentSchedule.getDueDate())))
                firstDueDate = paymentSchedule.getDueDate();
        }
        if (firstDueDate != null)
            invoice.setDaysTillDue(FIN_Utility.getDaysToDue(firstDueDate));
        else
            invoice.setDaysTillDue(0L);
        OBDal.getInstance().save(invoice);
    }

    /**
     * Returns true if a financial account transactions has to be automatically triggered after
     * payment is processed.
     * 
     * @param payment
     * @return Returns true if a financial account transactions has to be automatically triggered
     *         after payment is processed.
     */
    public static Boolean isForcedFinancialAccountTransaction(FIN_Payment payment) {
        OBCriteria<FinAccPaymentMethod> psdFilter = OBDal.getInstance().createCriteria(FinAccPaymentMethod.class);
        psdFilter.add(Restrictions.eq(FinAccPaymentMethod.PROPERTY_ACCOUNT, payment.getAccount()));
        psdFilter.add(Restrictions.eq(FinAccPaymentMethod.PROPERTY_PAYMENTMETHOD, payment.getPaymentMethod()));
        for (FinAccPaymentMethod paymentMethod : psdFilter.list()) {
            return payment.isReceipt() ? paymentMethod.isAutomaticDeposit() : paymentMethod.isAutomaticWithdrawn();
        }
        return false;
    }

    /**
     * Method used to get a list of payments identifiers associated to a payment proposal
     * 
     * @param paymentProposal
     * @return List of payment identifiers
     */
    @SuppressWarnings("unchecked")
    public static List<String> getPaymentFromPaymentProposal(FIN_PaymentProposal paymentProposal) {
        // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
        // removed when new security implementation is done
        OBContext.setAdminMode();
        try {
            StringBuilder hql = new StringBuilder();
            final Session session = OBDal.getInstance().getSession();
            hql.append("SELECT distinct(p." + FIN_Payment.PROPERTY_ID + ") ");
            hql.append("FROM " + FIN_PaymentPropDetail.TABLE_NAME + " as ppd ");
            hql.append("inner join ppd." + FIN_PaymentPropDetail.PROPERTY_FINPAYMENTSCHEDULEDETAIL + " as psd ");
            hql.append("inner join psd." + FIN_PaymentScheduleDetail.PROPERTY_PAYMENTDETAILS + " as pd ");
            hql.append("inner join pd." + FIN_PaymentDetail.PROPERTY_FINPAYMENT + " as p ");
            hql.append("WHERE ppd." + FIN_PaymentPropDetail.PROPERTY_FINPAYMENTPROPOSAL + "."
                    + FIN_PaymentProposal.PROPERTY_ID + "= ?");
            final Query obqPay = session.createQuery(hql.toString());
            obqPay.setParameter(0, paymentProposal.getId());

            return obqPay.list();

        } catch (Exception e) {
            throw new OBException(e);
        } finally {
            OBContext.restorePreviousMode();
        }
    }

    /**
     * It calls the PAyment Process for the given payment and action.
     * 
     * @param vars
     *          VariablesSecureApp with the session data.
     * @param conn
     *          ConnectionProvider with the connection being used.
     * @param strAction
     *          String with the action of the process. {P, D, R}
     * @param payment
     *          FIN_Payment that needs to be processed.
     * @return a OBError with the result message of the process.
     * @throws Exception
     */
    public static OBError processPayment(VariablesSecureApp vars, ConnectionProvider conn, String strAction,
            FIN_Payment payment) throws Exception {
        ProcessBundle pb = new ProcessBundle("6255BE488882480599C81284B70CD9B3", vars).init(conn);
        HashMap<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("action", strAction);
        parameters.put("Fin_Payment_ID", payment.getId());
        pb.setParams(parameters);
        OBError myMessage = null;
        //new FIN_PaymentProcess().execute(pb);
        myMessage = (OBError) pb.getResult();
        return myMessage;
    }

    /**
     * It calls the Payment Proposal Process for the given payment proposal and action.
     * 
     * @param vars
     *          VariablesSecureApp with the session data.
     * @param conn
     *          ConnectionProvider with the connection being used.
     * @param strProcessProposalAction
     *          String with the action of the process. {GSP, RE}
     * @param strFinPaymentProposalId
     *          String with FIN_PaymentProposal Id to be processed.
     * @return a OBError with the result message of the process.
     * @throws Exception
     */
    public static OBError processPaymentProposal(VariablesSecureApp vars, ConnectionProvider conn,
            String strProcessProposalAction, String strFinPaymentProposalId) throws Exception {
        ProcessBundle pb = new ProcessBundle("D16966FBF9604A3D91A50DC83C6EA8E3", vars).init(conn);
        HashMap<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("processProposalAction", strProcessProposalAction);
        parameters.put("Fin_Payment_Proposal_ID", strFinPaymentProposalId);
        pb.setParams(parameters);
        OBError myMessage = null;
        //new FIN_PaymentProposalProcess().execute(pb);
        myMessage = (OBError) pb.getResult();
        return myMessage;
    }

    /**
     * It calls the Bank Statement Process for the given bank statement and action.
     * 
     * @param vars
     *          VariablesSecureApp with the session data.
     * @param conn
     *          ConnectionProvider with the connection being used.
     * @param strBankStatementAction
     *          String with the action of the process. {P, R}
     * @param strBankStatementId
     *          String with FIN_BankStatement Id to be processed.
     * @return a OBError with the result message of the process.
     * @throws Exception
     */
    public static OBError processBankStatement(VariablesSecureApp vars, ConnectionProvider conn,
            String strBankStatementAction, String strBankStatementId) throws Exception {
        ProcessBundle pb = new ProcessBundle("58A9261BACEF45DDA526F29D8557272D", vars).init(conn);
        HashMap<String, Object> parameters = new HashMap<String, Object>();
        parameters.put("action", strBankStatementAction);
        parameters.put("FIN_Bankstatement_ID", strBankStatementId);
        pb.setParams(parameters);
        OBError myMessage = null;
        //new FIN_BankStatementProcess().execute(pb);
        myMessage = (OBError) pb.getResult();
        return myMessage;
    }
}