Search in sources :

Example 16 with PaymentGroup

use of org.kuali.kfs.pdp.businessobject.PaymentGroup in project cu-kfs by CU-CommunityApps.

the class CuDisbursementVoucherExtractionHelperServiceImpl method createPaymentGroup.

@Override
public PaymentGroup createPaymentGroup(DisbursementVoucherDocument document, Date processRunDate) {
    if (LOG.isDebugEnabled()) {
        LOG.debug("createPaymentGroupForDisbursementVoucher() started");
    }
    PaymentGroup pg = new PaymentGroup();
    pg.setCombineGroups(Boolean.TRUE);
    pg.setCampusAddress(Boolean.FALSE);
    CuDisbursementVoucherPayeeDetail pd = businessObjectService.findBySinglePrimaryKey(CuDisbursementVoucherPayeeDetail.class, document.getDocumentNumber());
    String rc = pd.getDisbVchrPaymentReasonCode();
    if (KFSConstants.PaymentPayeeTypes.CUSTOMER.equals(document.getDvPayeeDetail().getDisbursementVoucherPayeeTypeCode())) {
        pg.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.CUSTOMER);
        pg.setTaxablePayment(Boolean.FALSE);
    } else // If the payee is an employee, set these flags accordingly
    if ((pd.isVendor() && SpringContext.getBean(VendorService.class).isVendorInstitutionEmployee(pd.getDisbVchrVendorHeaderIdNumberAsInteger())) || document.getDvPayeeDetail().isEmployee()) {
        pg.setEmployeeIndicator(Boolean.TRUE);
        pg.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.EMPLOYEE);
        pg.setTaxablePayment(!/*REFACTORME*/
        getParameterEvaluatorService().getParameterEvaluator(DisbursementVoucherDocument.class, DisbursementVoucherConstants.RESEARCH_PAYMENT_REASONS_PARM_NM, rc).evaluationSucceeds() && !getParameterService().getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.PAYMENT_REASON_CODE_RENTAL_PAYMENT_PARM_NM).equals(rc) && !getParameterService().getParameterValueAsString(DisbursementVoucherDocument.class, DisbursementVoucherConstants.PAYMENT_REASON_CODE_ROYALTIES_PARM_NM).equals(rc));
    } else // If the payee is an alumni or student, set these flags accordingly
    if (pd.isStudent() || pd.isAlumni()) {
        pg.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.ENTITY);
        // All payments are taxable except research participant, rental & royalties
        pg.setTaxablePayment(!SpringContext.getBean(ParameterEvaluatorService.class).getParameterEvaluator(CuDisbursementVoucherDocument.class, DisbursementVoucherConstants.RESEARCH_PAYMENT_REASONS_PARM_NM, rc).evaluationSucceeds() && !CuDisbursementVoucherConstants.PaymentReasonCodes.RENTAL_PAYMENT.equals(rc) && !CuDisbursementVoucherConstants.PaymentReasonCodes.ROYALTIES.equals(rc));
    } else {
        // These are taxable
        VendorDetail vendDetail = getVendorService().getVendorDetail(pd.getDisbVchrVendorHeaderIdNumberAsInteger(), pd.getDisbVchrVendorDetailAssignedIdNumberAsInteger());
        String vendorOwnerCode = vendDetail.getVendorHeader().getVendorOwnershipCode();
        String vendorOwnerCategoryCode = vendDetail.getVendorHeader().getVendorOwnershipCategoryCode();
        String payReasonCode = pd.getDisbVchrPaymentReasonCode();
        pg.setPayeeIdTypeCd(PdpConstants.PayeeIdTypeCodes.VENDOR_ID);
        // Assume it is not taxable until proven otherwise
        pg.setTaxablePayment(Boolean.FALSE);
        pg.setPayeeOwnerCd(vendorOwnerCode);
        ParameterEvaluator parameterEvaluator1 = /*REFACTORME*/
        getParameterEvaluatorService().getParameterEvaluator(DvToPdpExtractStep.class, PdpParameterConstants.TAXABLE_PAYMENT_REASON_CODES_BY_OWNERSHIP_CODES_PARAMETER_NAME, PdpParameterConstants.NON_TAXABLE_PAYMENT_REASON_CODES_BY_OWNERSHIP_CODES_PARAMETER_NAME, vendorOwnerCode, payReasonCode);
        ParameterEvaluator parameterEvaluator2 = /*REFACTORME*/
        getParameterEvaluatorService().getParameterEvaluator(DvToPdpExtractStep.class, PdpParameterConstants.TAXABLE_PAYMENT_REASON_CODES_BY_CORPORATION_OWNERSHIP_TYPE_CATEGORY_PARAMETER_NAME, PdpParameterConstants.NON_TAXABLE_PAYMENT_REASON_CODES_BY_CORPORATION_OWNERSHIP_TYPE_CATEGORY_PARAMETER_NAME, vendorOwnerCategoryCode, payReasonCode);
        if (parameterEvaluator1.evaluationSucceeds()) {
            pg.setTaxablePayment(Boolean.TRUE);
        } else if (getParameterService().getParameterValueAsString(DvToPdpExtractStep.class, PdpParameterConstants.CORPORATION_OWNERSHIP_TYPE_PARAMETER_NAME).equals("CP") && StringUtils.isEmpty(vendorOwnerCategoryCode) && /*REFACTORME*/
        getParameterEvaluatorService().getParameterEvaluator(DvToPdpExtractStep.class, PdpParameterConstants.TAXABLE_PAYMENT_REASON_CODES_FOR_BLANK_CORPORATION_OWNERSHIP_TYPE_CATEGORIES_PARAMETER_NAME, payReasonCode).evaluationSucceeds()) {
            pg.setTaxablePayment(Boolean.TRUE);
        } else if (getParameterService().getParameterValueAsString(DvToPdpExtractStep.class, PdpParameterConstants.CORPORATION_OWNERSHIP_TYPE_PARAMETER_NAME).equals("CP") && !StringUtils.isEmpty(vendorOwnerCategoryCode) && parameterEvaluator2.evaluationSucceeds()) {
            pg.setTaxablePayment(Boolean.TRUE);
        }
    }
    pg.setCity(pd.getDisbVchrPayeeCityName());
    pg.setCountry(pd.getDisbVchrPayeeCountryCode());
    pg.setLine1Address(pd.getDisbVchrPayeeLine1Addr());
    pg.setLine2Address(pd.getDisbVchrPayeeLine2Addr());
    pg.setPayeeName(pd.getDisbVchrPayeePersonName());
    pg.setPayeeId(pd.getDisbVchrPayeeIdNumber());
    pg.setState(pd.getDisbVchrPayeeStateCode());
    pg.setZipCd(pd.getDisbVchrPayeeZipCode());
    pg.setPaymentDate(document.getDisbursementVoucherDueDate());
    pg.setProcessImmediate(document.isImmediatePaymentIndicator());
    pg.setPymtAttachment(document.isDisbVchrAttachmentCode());
    pg.setPymtSpecialHandling(document.isDisbVchrSpecialHandlingCode());
    pg.setNraPayment(pd.isDisbVchrAlienPaymentCode());
    pg.setBankCode(document.getDisbVchrBankCode());
    pg.setPaymentStatusCode(PdpConstants.PaymentStatusCodes.OPEN);
    // now add the payment detail
    final PaymentDetail paymentDetail = buildPaymentDetail(document, processRunDate);
    pg.addPaymentDetails(paymentDetail);
    paymentDetail.setPaymentGroup(pg);
    return pg;
}
Also used : PaymentGroup(org.kuali.kfs.pdp.businessobject.PaymentGroup) VendorService(org.kuali.kfs.vnd.document.service.VendorService) VendorDetail(org.kuali.kfs.vnd.businessobject.VendorDetail) CuDisbursementVoucherDocument(edu.cornell.kfs.fp.document.CuDisbursementVoucherDocument) CuDisbursementVoucherPayeeDetail(edu.cornell.kfs.fp.businessobject.CuDisbursementVoucherPayeeDetail) PaymentDetail(org.kuali.kfs.pdp.businessobject.PaymentDetail) ParameterEvaluator(org.kuali.rice.core.api.parameter.ParameterEvaluator) DvToPdpExtractStep(org.kuali.kfs.fp.batch.DvToPdpExtractStep) RecurringDisbursementVoucherDocument(edu.cornell.kfs.fp.document.RecurringDisbursementVoucherDocument) DisbursementVoucherDocument(org.kuali.kfs.fp.document.DisbursementVoucherDocument) CuDisbursementVoucherDocument(edu.cornell.kfs.fp.document.CuDisbursementVoucherDocument)

Example 17 with PaymentGroup

use of org.kuali.kfs.pdp.businessobject.PaymentGroup in project cu-kfs by CU-CommunityApps.

the class PaymentFileServiceImpl method loadPayments.

/**
 * @see org.kuali.kfs.pdp.service.PaymentFileService#loadPayments(java.lang.String)
 */
@Override
public void loadPayments(PaymentFileLoad paymentFile, LoadPaymentStatus status, String incomingFileName) {
    status.setChart(paymentFile.getChart());
    status.setUnit(paymentFile.getUnit());
    status.setSubUnit(paymentFile.getSubUnit());
    status.setCreationDate(paymentFile.getCreationDate());
    status.setDetailCount(paymentFile.getActualPaymentCount());
    status.setDetailTotal(paymentFile.getCalculatedPaymentTotalAmount());
    // create batch record for payment load
    Batch batch = createNewBatch(paymentFile, getBaseFileName(incomingFileName));
    businessObjectService.save(batch);
    paymentFile.setBatchId(batch.getId());
    status.setBatchId(batch.getId());
    // do warnings and set defaults
    List<String> warnings = paymentFileValidationService.doSoftEdits(paymentFile);
    status.setWarnings(warnings);
    // store groups
    for (PaymentGroup paymentGroup : paymentFile.getPaymentGroups()) {
        businessObjectService.save(paymentGroup);
    }
    // send list of warnings
    paymentFileEmailService.sendLoadEmail(paymentFile, warnings);
    if (paymentFile.isTaxEmailRequired()) {
        paymentFileEmailService.sendTaxEmail(paymentFile);
    }
    removeDoneFile(incomingFileName);
    LOG.debug("loadPayments() was successful");
    status.setLoadStatus(LoadPaymentStatus.LoadStatus.SUCCESS);
}
Also used : PaymentGroup(org.kuali.kfs.pdp.businessobject.PaymentGroup) Batch(org.kuali.kfs.pdp.businessobject.Batch)

Example 18 with PaymentGroup

use of org.kuali.kfs.pdp.businessobject.PaymentGroup in project cu-kfs by CU-CommunityApps.

the class PaymentSourceExtractionServiceImpl method addPayment.

/**
 * This method creates a payment group from the disbursement voucher and batch provided and persists that group to the database.
 *
 * @param document The document used to build a payment group detail.
 * @param batch The batch file used to build a payment group and detail.
 * @param processRunDate The date the batch file is to post.
 */
protected void addPayment(PaymentSource document, Batch batch, Date processRunDate, boolean immediate) {
    LOG.info("addPayment() started for document number=" + document.getDocumentNumber());
    final java.sql.Date sqlProcessRunDate = new java.sql.Date(processRunDate.getTime());
    PaymentGroup pg = getPaymentSourceToExtractService().createPaymentGroup(document, sqlProcessRunDate);
    if (pg != null) {
        // the payment source returned null instead of a PaymentGroup?  I guess it didn't want to be paid for some reason (for instance, a 0 amount document or doc which didn't have a travel advance, etc)
        pg.setBatch(batch);
        // so, copy over for now.
        if (document instanceof DisbursementVoucherDocument) {
            if (pg.isPayableByACH()) {
                pg.setDisbursementTypeCode(PdpConstants.DisbursementTypeCodes.ACH);
            } else {
                pg.setDisbursementTypeCode(PdpConstants.DisbursementTypeCodes.CHECK);
            }
        }
        if (immediate) {
            pg.setProcessImmediate(Boolean.TRUE);
        }
        this.businessObjectService.save(pg);
        if (!testMode) {
            getPaymentSourceToExtractService().markAsExtracted(document, sqlProcessRunDate, pg.getId());
        }
    }
}
Also used : PaymentGroup(org.kuali.kfs.pdp.businessobject.PaymentGroup) Date(java.util.Date) DisbursementVoucherDocument(org.kuali.kfs.fp.document.DisbursementVoucherDocument)

Example 19 with PaymentGroup

use of org.kuali.kfs.pdp.businessobject.PaymentGroup in project cu-kfs by CU-CommunityApps.

the class CuAchAdviceNotificationServiceImpl method sendAdviceNotifications.

/**
 * Set to NonTransactional so the payment advice email sent date will be updated and saved after the email is sent
 *
 * @see org.kuali.kfs.pdp.batch.service.AchAdviceNotificationService#sendAdviceNotifications()
 */
@NonTransactional
public void sendAdviceNotifications() {
    if (achBundlerHelperService.shouldBundleAchPayments()) {
        // ACH payments were bundled so the corresponding advice email notifications should also be bundled
        HashSet<Integer> disbNbrs = achBundlerAdviceDao.getDistinctDisbursementNumbersForAchPaymentsNeedingAdviceNotification();
        for (Iterator<Integer> disbIter = disbNbrs.iterator(); disbIter.hasNext(); ) {
            Integer disbursementNbr = disbIter.next();
            // get all payment details to include in the advice based on disbursement number which is associated to a single vendor
            List<PaymentDetail> paymentDetails = achBundlerAdviceDao.getAchPaymentDetailsNeedingAdviceNotificationByDisbursementNumber(disbursementNbr);
            // get one payment detail record so that we can get the needed payment group record, since all payment details are for the same vendor, all payment group records should match
            Iterator<PaymentDetail> paymentDetailsIter = paymentDetails.iterator();
            PaymentDetail payDetail = paymentDetailsIter.next();
            PaymentGroup payGroup = payDetail.getPaymentGroup();
            CustomerProfile customer = payGroup.getBatch().getCustomerProfile();
            // verify the customer profile is setup to create advices
            if (customer.getAdviceCreate()) {
                pdpEmailService.sendAchAdviceEmail(payGroup, paymentDetails, customer);
            }
            // update sent date on the payment, must loop through all payment details because payment groups could be unique.
            for (Iterator<PaymentDetail> paymentDetailsIter2 = paymentDetails.iterator(); paymentDetailsIter2.hasNext(); ) {
                PaymentDetail pd = paymentDetailsIter2.next();
                PaymentGroup pg = pd.getPaymentGroup();
                pg.setAdviceEmailSentDate(dateTimeService.getCurrentTimestamp());
                businessObjectService.save(pg);
            }
        }
    // for each disb number
    } else {
        // Execute the original KFS code to send unbundled ACH advice email notifications with a
        // change to the looping on the payment detail records as noted below with notation KFSPTS-1460
        // get list of payments to send notification for
        List<PaymentGroup> paymentGroups = paymentGroupService.getAchPaymentsNeedingAdviceNotification();
        for (PaymentGroup paymentGroup : paymentGroups) {
            CustomerProfile customer = paymentGroup.getBatch().getCustomerProfile();
            // verify the customer profile is setup to create advices
            if (customer.getAdviceCreate()) {
                // KFSPTS-1460 - for loop removed
                // for (PaymentDetail paymentDetail : paymentGroup.getPaymentDetails()) {
                // pdpEmailService.sendAchAdviceEmail(paymentGroup, paymentDetail, customer);
                // }
                List<PaymentDetail> paymentDetails = paymentGroup.getPaymentDetails();
                pdpEmailService.sendAchAdviceEmail(paymentGroup, paymentDetails, customer);
            }
            // update advice sent date on payment
            paymentGroup.setAdviceEmailSentDate(dateTimeService.getCurrentTimestamp());
            businessObjectService.save(paymentGroup);
        }
    }
}
Also used : PaymentGroup(org.kuali.kfs.pdp.businessobject.PaymentGroup) PaymentDetail(org.kuali.kfs.pdp.businessobject.PaymentDetail) CustomerProfile(org.kuali.kfs.pdp.businessobject.CustomerProfile) NonTransactional(org.kuali.kfs.sys.service.NonTransactional)

Example 20 with PaymentGroup

use of org.kuali.kfs.pdp.businessobject.PaymentGroup in project cu-kfs by CU-CommunityApps.

the class CuExtractPaymentServiceImpl method writeExtractAchFileMellonBankFastTrack.

// Adjusted the code in this method to deal with the output of the payment details based upon
// payee with multiple payments in the same payment group.
protected void writeExtractAchFileMellonBankFastTrack(PaymentStatus extractedStatus, String filename, Date processDate, SimpleDateFormat sdf, List<String> notificationEmailAddresses) {
    BufferedWriter os = null;
    // Used in the Fast Track file HEADER record
    sdf = new SimpleDateFormat("yyyyMMddHHmmss");
    // headerDate must be day after processDate to prevent additional cost for same day ACH payments
    Date headerDate = calculateHeaderDate(processDate);
    // Used in the Fast Track file PAY01000 record
    SimpleDateFormat sdfPAY1000Rec = new SimpleDateFormat("yyyyMMdd");
    // column delimiter: Per BNY Mellon FastTrack spec, your choices are: "^" or ",".  If you change this make sure you change the associated name on the next line!
    String cDelim = "^";
    // column delimiter name: Per BNY Mellon FastTrack spec, your choices are: FFCARET and FFCOMMA for variable record types
    String cDname = "FFCARET";
    // record type: Per BNY Mellon's FastTrack spec, can be either V for variable or F for fixed.
    String hdrRecType = "V";
    // For Mellon Fast Track files - indicates whether the generated file is for (T)est or for (P)roduction
    String testIndicator;
    String ourBankAccountNumber = "";
    String ourBankRoutingNumber = "";
    String subUnitCode = "";
    boolean specialHandlingCode = false;
    boolean attachmentCode = false;
    String divisionCode = "";
    String achCode = "";
    String dateQualifer = "";
    boolean wroteFastTrackHeaderRecords = false;
    // Change the filename so that it ends in .txt instead of .xml.
    filename = filename.replace(".xml", ".txt");
    int totalRecordCount = 0;
    KualiDecimal totalPaymentAmounts = KualiDecimal.ZERO;
    CustomerProfile cp = null;
    String sCountryName = "";
    try {
        // Establish whether we are in a TEST or PRODUCTION environment.  This will change the indicator in the Mellon header record
        if (isProduction())
            testIndicator = "P";
        else
            testIndicator = "T";
        HashSet<String> bankCodes = this.getAchBundlerHelperService().getDistinctBankCodesForPendingAchPayments();
        for (String bankCode : bankCodes) {
            HashSet<Integer> disbNbrs = this.getAchBundlerHelperService().getDistinctDisbursementNumbersForPendingAchPaymentsByBankCode(bankCode);
            for (Iterator<Integer> iter = disbNbrs.iterator(); iter.hasNext(); ) {
                Integer disbursementNbr = iter.next();
                boolean first = true;
                // compute total net amount as it is needed on first payment detail
                KualiDecimal totalNetAmount = new KualiDecimal(0);
                Iterator<PaymentDetail> payDetailIter = this.getAchBundlerHelperService().getPendingAchPaymentDetailsByDisbursementNumberAndBank(disbursementNbr, bankCode);
                while (payDetailIter.hasNext()) {
                    PaymentDetail pd = payDetailIter.next();
                    totalNetAmount = totalNetAmount.add(pd.getNetPaymentAmount());
                }
                Iterator<PaymentDetail> paymentDetails = this.getAchBundlerHelperService().getPendingAchPaymentDetailsByDisbursementNumberAndBank(disbursementNbr, bankCode);
                while (paymentDetails.hasNext()) {
                    PaymentDetail pd = paymentDetails.next();
                    PaymentGroup pg = pd.getPaymentGroup();
                    // Get our Bank Account Number and our bank routing number
                    ourBankAccountNumber = pg.getBank().getBankAccountNumber().replace("-", "");
                    ourBankRoutingNumber = pg.getBank().getBankRoutingNumber();
                    if (!wroteFastTrackHeaderRecords) {
                        // open the file for writing
                        os = new BufferedWriter(new FileWriter(filename));
                        // Write the Fast Track header record (FIL00010) once for each file
                        os.write(// Record Type
                        "FIL00010" + cDelim + hdrRecType + // Variable (V) or Fixed (F) flag
                        cDelim + cDname + // Delimiter name - Must be either FFCARET or FFCOMMA.  Others are allowed but BNY Mellon will have to be contacted first.
                        cDelim + "CORNELLUNIVKFS" + // Customer Id - a unique identifier for the customer.  This has to be different for ACH than it is for CHECKS per BNY Mellon.
                        cDelim + testIndicator + // Test Indicator:  T = Test run, P = Production Run
                        cDelim + "820" + // EDI Document Id (3 Bytes)
                        cDelim + "043000261" + // Our Mellon bank id (15 Bytes)
                        cDelim + // Customer Division Id - 35 bytes - Optional
                        cDelim + sdf.format(headerDate) + // File Date and Time - 14 Bytes  YYMMDD format
                        cDelim + // Reserved Field - 3 Bytes
                        cDelim + "\n");
                        totalRecordCount = 1;
                        // Write the Fast Track email records (FIL00020) once for each file
                        for (Iterator<String> emailIter = notificationEmailAddresses.iterator(); emailIter.hasNext(); ) {
                            String emailAddress = emailIter.next();
                            os.write("FIL00020" + cDelim + emailAddress + cDelim + cDelim + "\n");
                            totalRecordCount = totalRecordCount + 1;
                        }
                        wroteFastTrackHeaderRecords = true;
                    }
                    if (first) {
                        // Get country name for code
                        int CountryNameMaxLength = 15;
                        Country country = null;
                        // KFSUPGRADE-859 check if the country name is not blank, otherwise country service will throw exception
                        if (StringUtils.isNotBlank(pg.getCountry())) {
                            country = this.getCountryService().getCountry(pg.getCountry());
                        }
                        if (country != null) {
                            sCountryName = country.getName().substring(0, ((country.getName().length() >= CountryNameMaxLength) ? CountryNameMaxLength : country.getName().length()));
                            if (sCountryName.toUpperCase().contains("UNITED STATES"))
                                sCountryName = "";
                        } else if (ObjectUtils.isNotNull(pg.getCountry()))
                            sCountryName = pg.getCountry().substring(0, ((pg.getCountry().length() >= CountryNameMaxLength) ? CountryNameMaxLength : pg.getCountry().length()));
                        if (sCountryName.toUpperCase().contains("UNITED STATES"))
                            sCountryName = "";
                        else
                            sCountryName = "";
                        int dvCodeInt = 0;
                        // Get customer profile information
                        if (ObjectUtils.isNotNull(pg.getBatch())) {
                            cp = pg.getBatch().getCustomerProfile();
                            if (ObjectUtils.isNotNull(cp))
                                if (ObjectUtils.isNotNull(cp.getSubUnitCode()))
                                    subUnitCode = cp.getSubUnitCode();
                                else
                                    LOG.error("No Sub Unit Code provided for requisition number: " + pd.getRequisitionNbr());
                            else
                                LOG.error("No customer profile exists for payee name: " + pg.getPayeeName());
                        }
                        // Get special handling indicator
                        specialHandlingCode = pg.getPymtSpecialHandling();
                        // Get attachment indicator
                        attachmentCode = pg.getPymtAttachment();
                        if (specialHandlingCode == false && attachmentCode == false) {
                            dvCodeInt = CUPdpConstants.DivisionCodes.US_MAIL;
                        }
                        if (specialHandlingCode == true && attachmentCode == false) {
                            dvCodeInt = CUPdpConstants.DivisionCodes.US_MAIL;
                        }
                        if (specialHandlingCode == false && attachmentCode == true) {
                            dvCodeInt = CUPdpConstants.DivisionCodes.CU_MAIL_SERVICES;
                        }
                        if (specialHandlingCode == true && attachmentCode == true) {
                            dvCodeInt = CUPdpConstants.DivisionCodes.CU_MAIL_SERVICES;
                        }
                        divisionCode = String.format(String.format("%%0%dd", 3), dvCodeInt);
                        // Determine the ACH Code to send down.  Here are the rules:
                        // 1.  If they are a vendor and they've selected checking account, the ACH code is CTX (vendors can only have ACH to checking)
                        // 2.  If they are a vendor and they've selected savings account, the ACH code is PPD (sometimes sole proprietors are vendors and they use personal not corporate accounts)
                        // 3.  If they are NOT a vendor, then the ACH code is always PPD (allows employees to have their's deposited in checking or savings)
                        // Determine which ACH code to use: CTX for corporate accounts, or PPD for Personal accounts
                        // String payeeId = paymentGroup.getPayeeId();                          // Returns the ID of the payee and is the vendor number if the next var indicates that
                        // String payeeIdTypeDesc = paymentGroup.getPayeeIdTypeDesc();          // Returns "Vendor Number" if the payeeID is a vendor number
                        String AchBankRoutingNbr = "";
                        String AchAccountType = "DA";
                        String AchBankAccountNumber = "";
                        String CheckNumber = "";
                        // payeeIdTypeCode returns a "V" if it is a vendor
                        boolean isVendor = (pg.getPayeeIdTypeCd().equals("V")) ? true : false;
                        String kfsAccountType = "";
                        if (ObjectUtils.isNotNull(pg.getAchAccountType()))
                            // Returns either a 22 for checking or a 32 for Savings account
                            kfsAccountType = pg.getAchAccountType();
                        // For Mellon this converts to either DA (checking) or SG (savings)
                        if (kfsAccountType.startsWith("22")) {
                            AchAccountType = "DA";
                        }
                        if (kfsAccountType.startsWith("32")) {
                            AchAccountType = "SG";
                        }
                        if (kfsAccountType.contains("PPD")) {
                            achCode = "PPD";
                        }
                        if (kfsAccountType.contains("CTX")) {
                            achCode = "CTX";
                        }
                        if (ObjectUtils.isNotNull(pg.getAchBankRoutingNbr()))
                            AchBankRoutingNbr = pg.getAchBankRoutingNbr();
                        if (ObjectUtils.isNotNull(pg.getAchAccountNumber().getAchBankAccountNbr()))
                            AchBankAccountNumber = pg.getAchAccountNumber().getAchBankAccountNbr().toString();
                        if (ObjectUtils.isNotNull(pg.getDisbursementNbr().toString()))
                            CheckNumber = pg.getDisbursementNbr().toString();
                        // Write only 1 PAY01000 record for each payee
                        os.write(// Record Type - 8 bytes
                        "PAY01000" + cDelim + "1" + // 7=Payment and Electronic Advice (Transaction handling code - 2 bytes)
                        cDelim + totalNetAmount.toString() + // Total amount of check (Payment amount - 18 bytes)
                        cDelim + "C" + // C=Credit, D=Debit (Credit or debit Flag - 1 Byte)
                        cDelim + "ACH" + // ACH= ACH Payment method - 3 Bytes
                        cDelim + achCode + // PPD is used for ACH payments to a personal bank account - 10 bytes
                        cDelim + "01" + // Originators bank id qualifier - 2 bytes
                        cDelim + ourBankRoutingNumber + // Originators bank id - 12 bytes
                        cDelim + "DA" + // Originating account number Qualifier - 3 bytes
                        cDelim + ourBankAccountNumber + // Originating account number - 35 bytes
                        cDelim + "1150532082" + // Originating company identifier - 10 bytes - This has to be different for ACH than it is for CHECKS per BNY Mellon
                        cDelim + "01" + // Receiving bank id qualifier - 2 bytes
                        cDelim + AchBankRoutingNbr + // Receiving bank id - 12 bytes
                        cDelim + AchAccountType + // Receiving account number qualifier - 3 bytes - must be DA for checking or SG for savings.
                        cDelim + AchBankAccountNumber + // Receiving account number - 35 bytes
                        cDelim + sdfPAY1000Rec.format(processDate) + // Effective date - 8 bytes - YYMMDDHHMMSS
                        cDelim + // Business function code - 3 bytes
                        cDelim + CheckNumber + // Trace number (check number) - 50 bytes
                        cDelim + divisionCode + // Division code - 50 bytes
                        cDelim + // Currency code - 3 bytes
                        cDelim + // Note 1 - 80 bytes
                        cDelim + // Note 2 - 80 bytes
                        cDelim + // Note 3 - 80 bytes
                        cDelim + // Note 4 - 80 bytes
                        cDelim + cDelim + "\n");
                        totalPaymentAmounts = totalPaymentAmounts.add(totalNetAmount);
                        // Write the Payer Detail(PDT02010) record for the payer (us) (only one per payee)
                        os.write(// Record Type - 8 bytes
                        "PDT02010" + cDelim + "PR" + // Name qualifier - 3 bytes
                        cDelim + // ID code qualifier - 2 bytes
                        cDelim + // ID code - 80 bytes
                        cDelim + PAYER_NAME + // Name - 60 bytes
                        cDelim + // Additional name 1 - 60 bytes
                        cDelim + // Additional name 2 - 60 bytes
                        cDelim + PAYER_ADDRESS_LINE1 + // Address line 1 - 55 bytes
                        cDelim + PAYER_ADDRESS_LINE2 + // Address line 2 - 55 bytes
                        cDelim + // Address line 3 - 55 bytes
                        cDelim + // Address line 4 - 55 bytes
                        cDelim + // Address line 5 - 55 bytes
                        cDelim + // Address line 6 - 55 bytes
                        cDelim + PAYER_CITY + // City - 30 bytes
                        cDelim + PAYER_STATE + // State/Province - 2 bytes
                        cDelim + PAYER_ZIP_CODE + // Postal code - 15 bytes
                        cDelim + // Country code - 3 bytes
                        cDelim + // Country name - 30 bytes
                        cDelim + // Ref qualifier 1 - 3 bytes
                        cDelim + // Ref ID 1 - 50 bytes
                        cDelim + // Ref description 1 - 80 bytes
                        cDelim + // Ref qualifier 1 - 3 bytes
                        cDelim + // Ref ID 1 - 50 bytes
                        cDelim + // Ref description 1 - 80 bytes
                        cDelim + cDelim + "\n");
                        // Write the payee detail (PDT02010) record for the payee (them) (only one per payee)
                        // temp variables to observe length limitations
                        int AddrMaxLength = 35;
                        int CityMaxLength = 30;
                        int StateMaxLength = 2;
                        int ZipMaxLength = 15;
                        int PayeeNameMaxLength = 35;
                        String PayeeName = "";
                        String AddrLine1 = "";
                        String AddrLine2 = "";
                        String AddrLine3 = "";
                        String AddrLine4 = "";
                        String City = "";
                        String State = "";
                        String Zip = "";
                        if (ObjectUtils.isNotNull(pg.getPayeeName()))
                            PayeeName = pg.getPayeeName().substring(0, ((pg.getPayeeName().length() >= PayeeNameMaxLength) ? PayeeNameMaxLength : pg.getPayeeName().length()));
                        if (ObjectUtils.isNotNull(pg.getLine1Address()))
                            AddrLine1 = pg.getLine1Address().substring(0, ((pg.getLine1Address().length() >= AddrMaxLength) ? AddrMaxLength : pg.getLine1Address().length()));
                        if (ObjectUtils.isNotNull(pg.getLine2Address()))
                            AddrLine2 = pg.getLine2Address().substring(0, ((pg.getLine2Address().length() >= AddrMaxLength) ? AddrMaxLength : pg.getLine2Address().length()));
                        if (ObjectUtils.isNotNull(pg.getLine3Address()))
                            AddrLine3 = pg.getLine3Address().substring(0, ((pg.getLine3Address().length() >= AddrMaxLength) ? AddrMaxLength : pg.getLine3Address().length()));
                        if (ObjectUtils.isNotNull(pg.getLine4Address()))
                            AddrLine4 = pg.getLine4Address().substring(0, ((pg.getLine4Address().length() >= AddrMaxLength) ? AddrMaxLength : pg.getLine4Address().length()));
                        if (ObjectUtils.isNotNull(pg.getCity()))
                            City = pg.getCity().substring(0, ((pg.getCity().length() >= CityMaxLength) ? CityMaxLength : pg.getCity().length()));
                        if (ObjectUtils.isNotNull(pg.getState()))
                            State = pg.getState().substring(0, ((pg.getState().length() >= StateMaxLength) ? StateMaxLength : pg.getState().length()));
                        if (ObjectUtils.isNotNull(pg.getZipCd()))
                            Zip = (pg.getZipCd().substring(0, ((pg.getZipCd().length() >= ZipMaxLength) ? ZipMaxLength : pg.getZipCd().length()))).replace("-", "");
                        os.write(// Record Type - 8 bytes
                        "PDT02010" + cDelim + "PE" + // Name qualifier - 3 bytes
                        cDelim + // ID code qualifier - 2 bytes
                        cDelim + // ID code - 80 bytes
                        cDelim + PayeeName + // Name - 30 bytes
                        cDelim + // Additional name 1 - 60 bytes
                        cDelim + // Additional name 2 - 60 bytes
                        cDelim + AddrLine1 + // Address line 1 - 35 bytes
                        cDelim + AddrLine2 + // Address line 2 - 35 bytes
                        cDelim + AddrLine3 + // Address line 3 - 35 bytes
                        cDelim + AddrLine4 + // Address line 4 - 35 bytes
                        cDelim + // Address line 5 - 35 bytes
                        cDelim + // Address line 6 - 35 bytes
                        cDelim + City + // City - 30 bytes
                        cDelim + State + // State/Province - 2 bytes
                        cDelim + Zip + // Postal code - 15 bytes
                        cDelim + // Country code - 3 bytes
                        cDelim + sCountryName + // Country name - 30 bytes  (do not use is Country Code is used)
                        cDelim + // Ref qualifier 1 - 3 bytes
                        cDelim + // Ref ID 1 - 50 bytes
                        cDelim + // Ref description 1 - 80 bytes
                        cDelim + // Ref qualifier 1 - 3 bytes
                        cDelim + // Ref ID 1 - 50 bytes
                        cDelim + // Ref description 1 - 80 bytes
                        cDelim + cDelim + "\n");
                        // One for the PAY01000 record and one for each PDT02010 record
                        totalRecordCount = totalRecordCount + 3;
                        // Set this here so it is only executed once per payee
                        first = false;
                    }
                    // If (first)
                    // Write the REM03020 record
                    // Set up remittanceIdCode and remittanceIdText based on whether its a DV or something else.
                    String remittanceIdCode = (subUnitCode.equals(CuDisbursementVoucherConstants.DV_EXTRACT_SUB_UNIT_CODE)) ? "TN" : "IV";
                    String remittanceIdText = (subUnitCode.equals(CuDisbursementVoucherConstants.DV_EXTRACT_SUB_UNIT_CODE)) ? ObjectUtils.isNotNull(pd.getCustPaymentDocNbr()) ? "Doc No:" + pd.getCustPaymentDocNbr() : "" : ObjectUtils.isNotNull(pd.getInvoiceNbr()) ? pd.getInvoiceNbr() : "";
                    // All of these are limited to 18 bytes in Fast Track.
                    String ftNetPayAmount = "";
                    String ftTotalAmount = "";
                    String ftDiscountAmt = "";
                    if (ObjectUtils.isNotNull(pd.getNetPaymentAmount())) {
                        ftNetPayAmount = pd.getNetPaymentAmount().toString();
                        if (ftNetPayAmount.length() > 18) {
                            LOG.error("Net Payment Amount is more than 18 bytes");
                            break;
                        }
                    }
                    if (ObjectUtils.isNotNull(pd.getOrigInvoiceAmount())) {
                        ftTotalAmount = pd.getOrigInvoiceAmount().toString();
                        if (ftTotalAmount.length() > 18) {
                            LOG.error("Original Invoice Amount is more than 18 bytes");
                            break;
                        }
                    }
                    if (ObjectUtils.isNotNull(pd.getInvTotDiscountAmount())) {
                        ftDiscountAmt = pd.getInvTotDiscountAmount().toString();
                        if (ftDiscountAmt.length() > 18) {
                            LOG.error("Discount Amount is more than 18 bytes");
                            break;
                        }
                    }
                    String InvoiceDate = "";
                    if (ObjectUtils.isNotNull(pd.getInvoiceDate())) {
                        InvoiceDate = pd.getInvoiceDate().toString().replace("-", "");
                        dateQualifer = "003";
                    }
                    os.write(// Record type - 8 bytes
                    "REM03020" + cDelim + remittanceIdCode + // Remittance qualifier code - 3 bytes
                    cDelim + remittanceIdText + // Remittance ID - 50 bytes
                    cDelim + ftNetPayAmount + // Net invoice amount - 18 bytes
                    cDelim + ftTotalAmount + // Total invoice amount - 18 bytes
                    cDelim + ftDiscountAmt + // Discount amount - 18 bytes
                    cDelim + // Note 1 - 80 bytes - NOT USED PER SPEC
                    cDelim + // Note 2 - 80 bytes - NOT USED PER SPEC
                    cDelim + // Ref qualifier 1
                    cDelim + // Ref ID 1
                    cDelim + // Ref description 1
                    cDelim + // Ref qualifier 2
                    cDelim + // Ref ID 2
                    cDelim + // Ref description 2
                    cDelim + // Ref qualifier 3
                    cDelim + // Ref ID 3
                    cDelim + // Ref description 3
                    cDelim + // Ref qualifier 4
                    cDelim + // Ref ID 4
                    cDelim + // Ref description 4
                    cDelim + dateQualifer + // Date qualifier 1
                    cDelim + InvoiceDate + // Date 1
                    cDelim + // Date qualifier 2
                    cDelim + // Date 2
                    cDelim + // Date qualifier 3
                    cDelim + // Date 3
                    cDelim + // Date qualifier 4
                    cDelim + cDelim + "\n");
                    // One for the REM03020 record
                    totalRecordCount = totalRecordCount + 1;
                }
            // while there are payment details
            }
        // for each disbNbr
        }
        if (wroteFastTrackHeaderRecords) {
            // Need to update the total record count here to make sure it includes the trailer record
            totalRecordCount = totalRecordCount + 1;
            // Now write the trailer record
            os.write(// Record Type
            "TRL09000" + cDelim + totalRecordCount + // Total # of records in the file including header and trailer. 15 bytes numeric only
            cDelim + totalPaymentAmounts + // Total amount of all net payments for the file.  25 bytes numeric only
            cDelim + // EOR
            "\n");
        }
    }// try
     catch (IOException ie) {
        LOG.error("extractAchPayments() Problem reading file:  " + filename, ie);
        throw new IllegalArgumentException("Error writing to output file: " + ie.getMessage());
    } catch (Exception ex) {
        LOG.error("General Exception with writeExtractBundledAchFileMellonBankFastTrack().  Error is:  " + ex.getMessage(), ex);
    } finally {
        // Close file
        if (os != null) {
            try {
                os.close();
                // Need to do this at the end to indicate that the file is ready after it is closed.
                renameFile(filename, filename + ".READY");
            } catch (IOException ie) {
                // Not much we can do now
                LOG.error("IOException in extractAchPayments():  " + filename, ie);
            }
        }
    }
}
Also used : PaymentGroup(org.kuali.kfs.pdp.businessobject.PaymentGroup) FileWriter(java.io.FileWriter) CustomerProfile(org.kuali.kfs.pdp.businessobject.CustomerProfile) IOException(java.io.IOException) Date(java.util.Date) IOException(java.io.IOException) BufferedWriter(java.io.BufferedWriter) KualiInteger(org.kuali.rice.core.api.util.type.KualiInteger) PaymentDetail(org.kuali.kfs.pdp.businessobject.PaymentDetail) KualiDecimal(org.kuali.rice.core.api.util.type.KualiDecimal) Country(org.kuali.rice.location.api.country.Country) SimpleDateFormat(java.text.SimpleDateFormat)

Aggregations

PaymentGroup (org.kuali.kfs.pdp.businessobject.PaymentGroup)25 PaymentDetail (org.kuali.kfs.pdp.businessobject.PaymentDetail)11 KualiDecimal (org.kuali.rice.core.api.util.type.KualiDecimal)9 HashMap (java.util.HashMap)7 KualiInteger (org.kuali.rice.core.api.util.type.KualiInteger)7 Date (java.util.Date)6 BufferedWriter (java.io.BufferedWriter)5 IOException (java.io.IOException)5 CustomerProfile (org.kuali.kfs.pdp.businessobject.CustomerProfile)5 FileWriter (java.io.FileWriter)4 Timestamp (java.sql.Timestamp)4 Iterator (java.util.Iterator)4 List (java.util.List)4 SimpleDateFormat (java.text.SimpleDateFormat)3 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 Map (java.util.Map)3 PaymentStatus (org.kuali.kfs.pdp.businessobject.PaymentStatus)3 VendorDetail (org.kuali.kfs.vnd.businessobject.VendorDetail)3 CuDisbursementVoucherDocument (edu.cornell.kfs.fp.document.CuDisbursementVoucherDocument)2