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;
}
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);
}
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());
}
}
}
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);
}
}
}
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);
}
}
}
}
Aggregations