com.sfs.whichdoctor.dao.PaymentDAOImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.sfs.whichdoctor.dao.PaymentDAOImpl.java

Source

/*******************************************************************************
 * Copyright (c) 2009 David Harrison.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * Contributors:
 *     David Harrison - initial API and implementation
 ******************************************************************************/
package com.sfs.whichdoctor.dao;

import com.sfs.beans.FinancialTypeBean;
import com.sfs.beans.PrivilegesBean;
import com.sfs.beans.UserBean;
import com.sfs.dao.FinancialTypeDAO;
import com.sfs.whichdoctor.beans.DebitBean;
import com.sfs.whichdoctor.beans.OrganisationBean;
import com.sfs.whichdoctor.beans.PaymentBean;
import com.sfs.whichdoctor.beans.PersonBean;
import com.sfs.whichdoctor.beans.ReceiptBean;
import com.sfs.whichdoctor.beans.SearchBean;
import com.sfs.whichdoctor.beans.SearchResultsBean;
import com.sfs.whichdoctor.search.SearchDAO;
import com.sfs.whichdoctor.search.WhichDoctorSearchDaoException;

import java.net.URL;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.StringTokenizer;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.codehaus.xfire.client.Client;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.RowMapper;

/**
 * The Class PaymentDAOImpl.
 */
public class PaymentDAOImpl extends WhichDoctorBaseDAOImpl implements PaymentDAO {

    /** The Constant MINIMUM_RANGE. */
    private static final double MINIMUM_RANGE = 0.01;

    /** The Constant MAXIMUM_RANGE. */
    private static final double MAXIMUM_RANGE = 999999999;

    /** The data logger. */
    private static Logger dataLogger = Logger.getLogger(PaymentDAOImpl.class);

    /** The payment url. */
    private String paymentUrl;

    /** The access id. */
    private String accessId;

    /** The secret. */
    private String secret;

    /** The debit dao. */
    @Resource
    private DebitDAO debitDAO;

    /** The financial type dao. */
    @Resource
    private FinancialTypeDAO financialTypeDAO;

    /** The search dao. */
    @Resource
    private SearchDAO searchDAO;

    /** The search index dao. */
    @Resource
    private SearchIndexDAO searchIndexDAO;

    /**
     * Sets the payment url.
     *
     * @param paymentUrlVal the new payment url
     */
    public final void setPaymentUrl(final String paymentUrlVal) {
        this.paymentUrl = paymentUrlVal;
    }

    /**
     * Sets the access id for the web service.
     *
     * @param accessIdVal the new access id
     */
    public final void setAccessId(final String accessIdVal) {
        this.accessId = accessIdVal;
    }

    /**
     * Sets the secret for the web service.
     *
     * @param secretVal the new secret
     */
    public final void setSecret(final String secretVal) {
        this.secret = secretVal;
    }

    /**
     * Used to get a Collection of PaymentBeans for a specified GUID number.
     *
     * @param guid the guid
     * @param fullResults the full results
     *
     * @return the collection< payment bean>
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final Collection<PaymentBean> load(final int guid, final boolean fullResults)
            throws WhichDoctorDaoException {

        dataLogger.info("Payments for GUID: " + guid + " requested");

        final String loadPayment = getSQL().getValue("payment/load")
                + " WHERE payment.Active = true AND payment.ReferenceGUID = ?"
                + " AND (invoice.Active IS null OR invoice.Active = true)"
                + " ORDER BY payment.PersonId, payment.InvoiceId";

        Collection<PaymentBean> payments = new ArrayList<PaymentBean>();

        try {
            payments = this.getJdbcTemplateReader().query(loadPayment, new Object[] { guid }, new RowMapper() {
                public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                    return loadPayment(rs);
                }
            });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for this search:" + ie.getMessage());
        }
        return payments;
    }

    /**
     * Used to get a PaymentBean for a specified PaymentId.
     *
     * @param paymentId the payment id
     *
     * @return the payment bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final PaymentBean load(final int paymentId) throws WhichDoctorDaoException {

        dataLogger.info("PaymentId: " + paymentId + " requested");

        final String loadPaymentId = getSQL().getValue("payment/load") + " WHERE payment.PaymentId = ?";

        PaymentBean payment = null;

        try {
            payment = (PaymentBean) this.getJdbcTemplateReader().queryForObject(loadPaymentId,
                    new Object[] { paymentId }, new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadPayment(rs);
                        }
                    });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for this search:" + ie.getMessage());
        }
        return payment;
    }

    /**
     * Used to get a PaymentBean for a specified GUID.
     *
     * @param guid the payment guid
     *
     * @return the payment bean
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    @SuppressWarnings("unchecked")
    public final PaymentBean loadGUID(final int guid) throws WhichDoctorDaoException {

        dataLogger.info("Payment GUID: " + guid + " requested");

        final String loadPaymentGUID = getSQL().getValue("payment/load")
                + " WHERE payment.Active = true AND payment.GUID = ?";

        PaymentBean payment = null;

        try {
            payment = (PaymentBean) this.getJdbcTemplateReader().queryForObject(loadPaymentGUID,
                    new Object[] { guid }, new RowMapper() {
                        public Object mapRow(final ResultSet rs, final int rowNum) throws SQLException {
                            return loadPayment(rs);
                        }
                    });

        } catch (IncorrectResultSizeDataAccessException ie) {
            dataLogger.debug("No results found for this search:" + ie.getMessage());
        }
        return payment;
    }

    /**
     * Load outstanding debits.
     *
     * @param payment the payment
     * @param user the user
     *
     * @return the collection< debit bean>
     */
    public final Collection<DebitBean> loadOutstandingDebits(final PaymentBean payment, final UserBean user) {
        Collection<DebitBean> debits = new ArrayList<DebitBean>();

        if (payment.getPerson() != null || payment.getOrganisation() != null) {
            SearchBean search = this.searchDAO.initiate("debit", user);
            search.setLimit(0);

            DebitBean criteria = (DebitBean) search.getSearchCriteria();
            DebitBean constraints = (DebitBean) search.getSearchConstraints();
            // No cancelled debits
            criteria.setCancelled(false);
            constraints.setCancelled(false);
            // Debits with a positive outstanding value
            criteria.setOutstandingValue(MINIMUM_RANGE);
            constraints.setOutstandingValue(MAXIMUM_RANGE);

            if (payment.getPerson() != null && payment.getPerson().getGUID() > 0) {
                criteria.setPersonId(payment.getPerson().getGUID());
            }
            if (payment.getOrganisation() != null && payment.getOrganisation().getGUID() > 0) {
                criteria.setOrganisationId(payment.getOrganisation().getGUID());
            }
            search.setSearchCriteria(criteria);
            search.setSearchConstraints(constraints);

            try {
                // Perform the search
                SearchResultsBean results = this.searchDAO.search(search);
                if (results.getSearchResults() != null) {
                    for (Object objResult : results.getSearchResults()) {
                        DebitBean debit = (DebitBean) objResult;
                        debits.add(debit);
                    }
                }
            } catch (WhichDoctorSearchDaoException wse) {
                dataLogger.error("Error performing search for outstanding " + "debits: " + wse.getMessage());
            }
        }
        return debits;
    }

    /**
     * Creates the PaymentBean.
     *
     * @param payment the payment
     * @param receipt the receipt
     * @param checkUser the check user
     * @param privileges the privileges
     *
     * @return the int
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final int create(final PaymentBean payment, final ReceiptBean receipt, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {
        payment.setActive(true);
        return save(payment, receipt, checkUser, privileges, "create");
    }

    /**
     * Modify the PaymentBean.
     *
     * @param payment the payment
     * @param receipt the receipt
     * @param checkUser the check user
     * @param privileges the privileges
     *
     * @return the int
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final int modify(final PaymentBean payment, final ReceiptBean receipt, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {
        payment.setActive(true);
        return save(payment, receipt, checkUser, privileges, "modify");
    }

    /**
     * Delete the PaymentBean.
     *
     * @param payment the payment
     * @param receipt the receipt
     * @param checkUser the check user
     * @param privileges the privileges
     *
     * @return true, if successful
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    public final boolean delete(final PaymentBean payment, final ReceiptBean receipt, final UserBean checkUser,
            final PrivilegesBean privileges) throws WhichDoctorDaoException {
        boolean success = false;

        payment.setActive(false);
        int paymentId = save(payment, receipt, checkUser, privileges, "delete");
        if (paymentId > 0) {
            success = true;
        }
        return success;
    }

    /**
     * Process a credit card payment.
     *
     * @param cardNumber the card number
     * @param cardHolder the card holder
     * @param expiryMonth the expiry month
     * @param expiryYear the expiry year
     * @param securityCode the security code
     * @param totalValue the total value
     * @param description the description
     * @param purchaseComment the purchase comment
     * @return the string[] where:
     *       string[0] = success/error,
     *       string[1] = transaction reference,
     *       string[2] = error message,
     *       string[3] = extended error log
     */
    public final String[] processCreditCardPayment(final String cardNumber, final String cardHolder,
            final int expiryMonth, final int expiryYear, final int securityCode, final double totalValue,
            final String description, final String purchaseComment) {

        String success = "", reference = "", message = "", logMessage = "";

        /* Perform a web service call using XFire libraries */
        try {
            Client client = new Client(new URL(this.paymentUrl));

            dataLogger.debug("Processing payment");

            Object[] result = client.invoke("process", new Object[] { accessId, secret, cardNumber, cardHolder,
                    expiryMonth, expiryYear, securityCode, totalValue, 0, "", description, purchaseComment });

            dataLogger.info("Payment processing complete. Results Object[]: " + result);

            String resultString = (String) result[0];

            StringTokenizer st = new StringTokenizer(resultString, ",");
            int i = 0;
            while (st.hasMoreTokens()) {
                String token = st.nextToken();
                if (StringUtils.startsWith(token, "'")) {
                    token = StringUtils.substring(token, 1, token.length());
                }
                if (StringUtils.endsWith(token, "'")) {
                    token = StringUtils.substring(token, 0, token.length() - 1);
                }

                switch (i) {
                case 0:
                    success = token;
                    break;
                case 1:
                    reference = token;
                    break;
                case 2:
                    message = token;
                    break;
                case 3:
                    logMessage = token;
                    break;
                }

                i++;
            }

            dataLogger.info("Payment result: " + success + ", reference: " + reference + ", message: " + message);
        } catch (Exception e) {
            dataLogger.error("Error performing payment process web service lookup: " + e.getMessage(), e);
        }

        return new String[] { success, reference, message, logMessage };
    }

    /**
     * Save.
     *
     * @param payment the payment
     * @param receipt the receipt
     * @param checkUser the check user
     * @param privileges the privileges
     * @param action the action
     *
     * @return the int
     *
     * @throws WhichDoctorDaoException the which doctor dao exception
     */
    private int save(final PaymentBean payment, final ReceiptBean receipt, final UserBean checkUser,
            final PrivilegesBean privileges, final String action) throws WhichDoctorDaoException {

        /* Check required information within PaymentBean is present */
        if (payment.getReferenceGUID() == 0) {
            throw new WhichDoctorDaoException("Payment requires a valid " + "Reference GUID number");
        }
        if (receipt.getId() == 0) {
            throw new WhichDoctorDaoException("Payment requires a valid receipt");
        }
        if (!privileges.getPrivilege(checkUser, "payments", action)) {
            throw new WhichDoctorDaoException("Insufficient user credentials " + "to create new payment entry");
        }

        /* Get the Receipt TypeId */
        int typeId = 0;
        try {
            FinancialTypeBean financialObject = this.financialTypeDAO.load("Receipt", receipt.getTypeName(),
                    receipt.getClassName());
            typeId = financialObject.getFinancialTypeId();
        } catch (Exception e) {
            dataLogger.error("Error loading financial type for receipt: " + e.getMessage());
            throw new WhichDoctorDaoException("Error loading financial type " + "for receipt: " + e.getMessage());
        }

        if (payment.getIncomeStreamId() > 0 && payment.getNetValue() > 0) {
            // Debit should not exist if payment is negative This is because you
            // cannot attribute negative payment to a debit
            payment.setDebit(new DebitBean());

            // As it is a negative debit the net value should be negative
            payment.setNetValue(0 - payment.getNetValue());
            // Reset the value in order to recalculate GST (if applicable)
            payment.setValue(0);
        }

        int personGUID = 0;
        int organisationGUID = 0;
        if (payment.getPerson() != null) {
            personGUID = payment.getPerson().getGUID();
        }
        if (payment.getOrganisation() != null) {
            organisationGUID = payment.getOrganisation().getGUID();
        }

        int newDebitGUID = 0;
        if (payment.getDebit() != null) {
            // Load the debit to get the GST rate
            try {
                final DebitBean debit = this.debitDAO.loadGUID(payment.getDebit().getGUID());
                if (debit != null) {
                    payment.setGSTRate(debit.getGSTRate());
                    newDebitGUID = debit.getGUID();

                    if (personGUID == 0 && debit.getPerson() != null) {
                        personGUID = debit.getPerson().getGUID();
                    }
                    if (organisationGUID == 0 && debit.getOrganisation() != null) {
                        organisationGUID = debit.getOrganisation().getGUID();
                    }
                }
            } catch (WhichDoctorDaoException wde) {
                dataLogger.error("Error loading debit: " + wde.getMessage());
            }
        }

        int existingDebitGUID = 0;
        // Load the existing payment (if GUID > 0) to check if the
        // associated debit has changed.
        if (payment.getGUID() > 0) {
            try {
                final PaymentBean existingPayment = this.loadGUID(payment.getGUID());
                if (existingPayment.getDebit() != null) {
                    existingDebitGUID = existingPayment.getDebit().getGUID();
                }
            } catch (WhichDoctorDaoException wde) {
                dataLogger.error("Error loading existing payment: " + wde.getMessage());
            }
        }

        int paymentId = 0;

        Timestamp sqlTimeStamp = new Timestamp(Calendar.getInstance().getTimeInMillis());

        ArrayList<Object> parameters = new ArrayList<Object>();
        parameters.add(payment.getReferenceGUID());
        parameters.add(personGUID);
        parameters.add(organisationGUID);
        parameters.add(newDebitGUID);
        parameters.add(payment.getValue());
        parameters.add(payment.getNetValue());
        parameters.add(payment.getIncomeStreamId());
        parameters.add(payment.getGSTRate());
        parameters.add(payment.getActive());
        parameters.add(sqlTimeStamp);
        parameters.add(checkUser.getDN());
        parameters.add(payment.getLogMessage(action));

        try {
            Integer[] result = this.performUpdate("payment", payment.getGUID(), parameters, "Payment", checkUser,
                    action);
            /* Set the returned guid and id values */
            payment.setGUID(result[0]);
            paymentId = result[1];
        } catch (Exception e) {
            dataLogger.error("Error processing payment record: " + e.getMessage());
            throw new WhichDoctorDaoException("Error processing payment: " + e.getMessage());
        }

        if (paymentId > 0) {

            dataLogger.info(checkUser.getDN() + " created paymentId: " + paymentId);
            /* Get Issued Date */
            Date issued = new Date(Calendar.getInstance().getTimeInMillis());
            if (receipt.getIssued() != null) {
                issued = new Date(receipt.getIssued().getTime());
            }

            if (action.compareTo("delete") == 0) {
                /* Delete the financial summary */
                this.getJdbcTemplateWriter().update(this.getSQL().getValue("payment/deleteSummary"),
                        new Object[] { receipt.getGUID(), payment.getGUID() });

            } else {
                /* Create or modify financial summary entry */
                try {
                    this.getJdbcTemplateWriter().update(this.getSQL().getValue("payment/editSummary"),
                            new Object[] { receipt.getGUID(), typeId, receipt.getNumber(), receipt.getDescription(),
                                    payment.getValue(), payment.getNetValue(), receipt.getCancelled(), issued,
                                    personGUID, organisationGUID, payment.getGUID(),

                                    typeId, receipt.getDescription(), payment.getValue(), payment.getNetValue(),
                                    receipt.getCancelled(), issued, personGUID, organisationGUID });
                } catch (DataAccessException dae) {
                    dataLogger.error("Failed to modify the financial summary: " + dae.getMessage());
                    throw new WhichDoctorDaoException(
                            "Failed to modify the financial summary: " + dae.getMessage());
                }
            }

            /* Update the related debit's calculated values */
            if (existingDebitGUID > 0) {
                this.debitDAO.refreshDebitValues(existingDebitGUID);
            }
            if (newDebitGUID > 0 && newDebitGUID != existingDebitGUID) {
                this.debitDAO.refreshDebitValues(newDebitGUID);
            }

            /* Update the search index */
            if (organisationGUID > 0) {
                this.searchIndexDAO.updateCurrentBalanceIndex(organisationGUID, "organisation");
            } else {
                this.searchIndexDAO.updateCurrentBalanceIndex(personGUID, "person");
            }
        }
        return paymentId;
    }

    /**
     * Load payment.
     *
     * @param rs the rs
     *
     * @return the payment bean
     *
     * @throws SQLException the SQL exception
     */
    private PaymentBean loadPayment(final ResultSet rs) throws SQLException {
        PaymentBean payment = new PaymentBean();

        payment.setId(rs.getInt("PaymentId"));
        payment.setGUID(rs.getInt("GUID"));
        payment.setReferenceGUID(rs.getInt("ReferenceGUID"));
        if (rs.getInt("PersonId") != 0) {
            PersonBean person = new PersonBean();
            person.setGUID(rs.getInt("PersonId"));
            person.setPersonIdentifier(rs.getInt("PersonIdentifier"));
            person.setPreferredName(rs.getString("PreferredName"));
            person.setFirstName(rs.getString("FirstName"));
            person.setLastName(rs.getString("LastName"));
            person.setTitle(rs.getString("Title"));

            payment.setPerson(person);
        }
        if (rs.getInt("OrganisationId") > 0) {
            OrganisationBean organisation = new OrganisationBean();
            organisation.setGUID(rs.getInt("OrganisationId"));
            organisation.setName(rs.getString("OrganisationName"));
            payment.setOrganisation(organisation);
        }
        if (rs.getInt("IncomeStreamId") > 0) {
            /* Payment is a negative payment */
            payment.setNegativePayment(true);
            /* Create a 'positive' value */
            payment.setIncomeStream(rs.getString("IncomeStream"));
            payment.setIncomeStreamId(rs.getInt("IncomeStreamId"));
        } else {
            payment.setNegativePayment(false);
            /* See if 'positive' payment has attributed invoice */
            if (rs.getInt("InvoiceId") > 0) {
                DebitBean debit = new DebitBean();
                debit.setGUID(rs.getInt("InvoiceId"));
                debit.setDescription(rs.getString("Description"));
                debit.setTypeName(rs.getString("DebitType"));
                debit.setNumber(rs.getString("InvoiceNo"));
                debit.setAbbreviation(rs.getString("Abbreviation"));
                try {
                    debit.setIssued(rs.getDate("Issued"));
                } catch (Exception sqe) {
                    dataLogger.debug("Error parsing Issued value: " + sqe.getMessage());
                }
                debit.setGSTRate(rs.getDouble("InvoiceGSTRate"));
                debit.setCancelled(rs.getBoolean("InvoiceCancelled"));
                debit.setValue(rs.getDouble("InvoiceValue"));
                debit.setCreditValue(rs.getDouble("InvoiceCreditValue"));
                debit.setNetValue(rs.getDouble("InvoiceNetValue"));

                payment.setDebit(debit);
            }
        }
        payment.setValue(rs.getDouble("Value"));
        payment.setNetValue(rs.getDouble("NetValue"));
        payment.setGSTRate(rs.getDouble("GSTRate"));

        payment.setActive(rs.getBoolean("Active"));
        try {
            payment.setCreatedDate(rs.getTimestamp("CreatedDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error reading CreatedDate: " + sqe.getMessage());
        }
        payment.setCreatedBy(rs.getString("CreatedBy"));
        try {
            payment.setModifiedDate(rs.getTimestamp("ModifiedDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error reading ModifiedDate: " + sqe.getMessage());
        }
        payment.setModifiedBy(rs.getString("ModifiedBy"));
        try {
            payment.setExportedDate(rs.getTimestamp("ExportedDate"));
        } catch (SQLException sqe) {
            dataLogger.debug("Error reading ExportedDate: " + sqe.getMessage());
        }
        payment.setExportedBy(rs.getString("ExportedBy"));

        return payment;
    }
}