use of org.kuali.kfs.pdp.businessobject.CustomerProfile 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);
}
}
}
}
use of org.kuali.kfs.pdp.businessobject.CustomerProfile in project cu-kfs by CU-CommunityApps.
the class CuExtractPaymentServiceImpl method writeExtractCheckFileMellonBankFastTrack.
// This method is called by the method that generates the XML file for checks to be printed by BNY Mellon
protected void writeExtractCheckFileMellonBankFastTrack(PaymentStatus extractedStatus, PaymentProcess p, String filename, Integer processId, List<String> notificationEmailAddresses) {
// Used in the Fast Track file HEADER record
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
// Used in the Fast Track file PAY01000 record
SimpleDateFormat sdfPAY1000Rec = new SimpleDateFormat("yyyyMMdd");
// Used in the issuance file
SimpleDateFormat sdfIDate = new SimpleDateFormat("yyMMdd");
// Used in the issuance file (NO SECONDS)
SimpleDateFormat sdfITime = new SimpleDateFormat("HHmm");
Date processDate = dateTimeService.getCurrentDate();
BufferedWriter os = null;
BufferedWriter osI = null;
// 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 = "";
String divisionCode = "";
boolean specialHandlingCode = false;
boolean attachmentCode = false;
boolean immediateCheckCode = false;
String PreparerInfoText = "";
String altAddrSendTo = "";
String altAddrAddr1 = "";
String altAddrAddr2 = "";
String altAddrAddr3 = "";
String altAddrAddr4 = "";
String altAddrCity = "";
String altAddrState = "";
String altAddrZip = "";
String altCountryName = "";
// this is needed because the notes combine these into one field
String altAddrCityStateZip = "";
String altRefQualifer = "";
int NumOfAltAddressLines = 0;
int SendToPrefLength = 0;
// Note lines that are not the alternate address
String RefDesc1 = "";
// Note lines that are not the alternate address
String RefDesc2 = "";
// Note lines that are not the alternate address
String RefDesc3 = "";
// Note lines that are not the alternate address
String RefDesc4 = "";
String FirstNoteAfterAddressInfo = "";
String SecondNoteAfterAddressInfo = "";
String ThirdNoteAfterAddressInfo = "";
String Ref1Qualifier = "";
String Ref2Qualifier = "";
String Ref3Qualifier = "";
String Ref4Qualifier = "";
String dateQualifier = "";
// Filename for the Fast Track file generated by this method
String ftFilename = "";
// Filename for the issuance (or account reconciliation) file generated by this method for immediate payments
String arFilename = "";
// The total number of "add" issues (see record #6)
int arNumOfAddIssues = 0;
// The total number of issuance records
int numOfIssuanceRecords = 0;
// The total dollar amount of the add issues for the issuance file.
KualiDecimal arTotalOfAddIssues = KualiDecimal.ZERO;
boolean wroteMellonIssuanceHeaderRecords = false;
boolean wroteMellonFastTrackHeaderRecords = false;
CustomerProfile cp = null;
String sCountryName = "";
String CheckNumber = "";
boolean MissingCommaFromSpecialHandlingAddress = false;
int totalRecordCount = 0;
KualiDecimal totalPaymentAmounts = KualiDecimal.ZERO;
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";
// Change the filename so that it ends in .txt instead of .xml
ftFilename = filename.replace(".xml", ".txt");
arFilename = ftFilename.replace("check", "check_immediate");
// Obtain the bank account number from the check information provided
List<String> bankCodes1 = paymentGroupService.getDistinctBankCodesForProcessAndType(processId, PdpConstants.DisbursementTypeCodes.CHECK);
if (!bankCodes1.isEmpty()) {
List<Integer> disbNbrs1 = paymentGroupService.getDisbursementNumbersByDisbursementTypeAndBankCode(processId, PdpConstants.DisbursementTypeCodes.CHECK, bankCodes1.get(0));
if (!disbNbrs1.isEmpty()) {
Iterator<PaymentDetail> myPds = paymentDetailService.getByDisbursementNumber(disbNbrs1.get(0));
if (myPds.hasNext()) {
PaymentDetail myPd = myPds.next();
PaymentGroup myPg = myPd.getPaymentGroup();
if (ObjectUtils.isNotNull(myPg)) {
ourBankAccountNumber = myPg.getBank().getBankAccountNumber().replace("-", "");
ourBankRoutingNumber = myPg.getBank().getBankRoutingNumber();
} else {
LOG.error("No Payment group information exists for requisition number: " + myPd.getRequisitionNbr() + ". Payee name is: " + myPg.getPayeeName());
throw new Exception("No Payment group information exists for requisition number: " + myPd.getRequisitionNbr() + ". Payee name is: " + myPg.getPayeeName());
}
}
}
}
// At this point we will start looping through all the checks and write the PAY01000 record (one for each payee),
// two (2) PDT2010 records (one for the Payer & Payee) and as many REM3020 records as needed for each amount being
// paid to this payee.
List<String> bankCodes = paymentGroupService.getDistinctBankCodesForProcessAndType(processId, PdpConstants.DisbursementTypeCodes.CHECK);
for (String bankCode : bankCodes) {
List<Integer> disbNbrs = paymentGroupService.getDisbursementNumbersByDisbursementTypeAndBankCode(processId, PdpConstants.DisbursementTypeCodes.CHECK, bankCode);
for (Iterator<Integer> iter = disbNbrs.iterator(); iter.hasNext(); ) {
Integer disbursementNbr = iter.next();
// If this payee has multiple checks coming to them, this ensures we only generate 1 PAY01000 record
boolean first = true;
KualiDecimal totalNetAmount = new KualiDecimal(0);
// We continue to need this for the FastTrack file as well since the total net amount is needed on the PAY01000 record for each payee
Iterator<PaymentDetail> i2 = paymentDetailService.getByDisbursementNumber(disbursementNbr, processId, PdpConstants.DisbursementTypeCodes.CHECK, bankCode);
while (i2.hasNext()) {
PaymentDetail pd = i2.next();
totalNetAmount = totalNetAmount.add(pd.getNetPaymentAmount());
}
Iterator<PaymentDetail> paymentDetails = paymentDetailService.getByDisbursementNumber(disbursementNbr, processId, PdpConstants.DisbursementTypeCodes.CHECK, bankCode);
while (paymentDetails.hasNext()) {
PaymentDetail pd = paymentDetails.next();
PaymentGroup pg = pd.getPaymentGroup();
// We save these values to the DB AFTER we know that this check has passed all validation and has actually been written
pg.setDisbursementDate(new java.sql.Date(processDate.getTime()));
pg.setPaymentStatus(extractedStatus);
// Get immediate (a.k.a. local print, a.k.a. manual) check indicator
immediateCheckCode = pg.getProcessImmediate();
// If it exists, get the check (a.k.a. disbursement number)
CheckNumber = (ObjectUtils.isNotNull(pg.getDisbursementNbr()) ? pg.getDisbursementNbr().toString() : "");
// Parse Notes
Iterator<PaymentNoteText> ix = pd.getNotes().iterator();
NumOfAltAddressLines = 0;
altAddrSendTo = "";
altAddrAddr1 = "";
altAddrAddr2 = "";
altAddrAddr3 = "";
altAddrAddr4 = "";
altAddrCity = "";
altAddrState = "";
altAddrZip = "";
altCountryName = "";
altAddrCityStateZip = "";
PreparerInfoText = "";
SendToPrefLength = 0;
FirstNoteAfterAddressInfo = "";
SecondNoteAfterAddressInfo = "";
ThirdNoteAfterAddressInfo = "";
MissingCommaFromSpecialHandlingAddress = false;
while (ix.hasNext()) {
PaymentNoteText note = (PaymentNoteText) ix.next();
String NoteLine = note.getCustomerNoteText();
if (NoteLine.contains(CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_PREPARER)) {
SendToPrefLength = CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_NAME.length();
PreparerInfoText = NoteLine;
} else if (NoteLine.contains(CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_NAME)) {
SendToPrefLength = CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_NAME.length();
altAddrSendTo = NoteLine.substring(SendToPrefLength);
NumOfAltAddressLines = NumOfAltAddressLines + 1;
} else if (NoteLine.contains(CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS1)) {
SendToPrefLength = CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS1.length();
altAddrAddr1 = NoteLine.substring(SendToPrefLength);
NumOfAltAddressLines = NumOfAltAddressLines + 1;
} else if (NoteLine.contains(CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS2)) {
SendToPrefLength = CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS2.length();
altAddrAddr2 = NoteLine.substring(SendToPrefLength);
NumOfAltAddressLines = NumOfAltAddressLines + 1;
} else if (NoteLine.contains(CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS3)) {
SendToPrefLength = CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS3.length();
if (NoteLine.contains(",")) {
altAddrCityStateZip = NoteLine.substring(SendToPrefLength);
// sTemp will be the string we modify as we go along
String sTemp = altAddrCityStateZip;
int spaceForZip = 0;
spaceForZip = sTemp.lastIndexOf(" ");
if (spaceForZip == -1) {
// ZIP is missing so set it to "" per discussion with Marcia
altAddrZip = "";
LOG.warn("WARNING: No zip code was provided. Changing it to blanks for check number: " + CheckNumber);
} else {
if (sTemp.substring(spaceForZip).trim().toLowerCase().equals("null")) {
// Use the space between the state and zip to obtain the "null" zip
altAddrZip = sTemp.substring(spaceForZip);
// Remove the "null" zip characters from sTemp
sTemp = sTemp.replace(altAddrZip, "");
// Since ZIP is missing set it to "" per discussion with Marcia
altAddrZip = "";
LOG.warn("WARNING: No zip code was provided. Changing it to blanks for check number: " + CheckNumber);
} else {
// Use the space between the state and zip to obtain the zip
altAddrZip = sTemp.substring(spaceForZip);
// Remove the space + Zip characters from sTemp
sTemp = sTemp.replace(altAddrZip, "");
// Trim any leading or trailing blanks
altAddrZip = altAddrZip.trim();
}
}
// Use the comma to find the where the state starts
altAddrState = sTemp.substring(sTemp.lastIndexOf(",") + 1);
// Remove what we found from sTemp
sTemp = sTemp.replace(altAddrState, "");
// Trim any leading or trailing blanks
altAddrState = altAddrState.trim();
// There should only be one comma. If commas are in the city name, that will be an issue
altAddrCity = sTemp.replace(",", "");
// Trim any leading or trailing blanks.
altAddrCity = altAddrCity.trim();
NumOfAltAddressLines = NumOfAltAddressLines + 1;
} else {
// We can't find a comma, so we won't know where the city ends and the state begins so as per discussion,
// log it as a warning and move on to the next NoteLine because we may have notes that we want to process.
LOG.warn("WARNING: No comma was provided separating the city and state for check number: " + CheckNumber);
MissingCommaFromSpecialHandlingAddress = true;
continue;
}
} else // if ( NoteLine.contains(CuDisbursementVoucherConstants.DV_EXTRACT_NOTE_PREFIX_SPECIAL_HANDLING_ADDRESS3) )
// Retrieve up to 3 subsequent note lines and only the first 72 characters as per the BNY Mellon spec.
{
// the next line until we either run out of lines or reach the max number to take (which is 3).
if (NoteLine.length() >= 2) {
if (NoteLine.substring(0, 2).contains(CuDisbursementVoucherConstants.DV_EXTRACT_TYPED_NOTE_PREFIX_IDENTIFIER)) {
// Trim the first two characters from the note and assign it as the first user typed note line
NoteLine = NoteLine.substring(2);
FirstNoteAfterAddressInfo = (NoteLine.length() <= 72) ? NoteLine : NoteLine.substring(0, 72);
// See if we have a second user typed note line. If so, then get it.
if (ix.hasNext()) {
note = (PaymentNoteText) ix.next();
NoteLine = note.getCustomerNoteText();
if (NoteLine.length() >= 2) {
if (NoteLine.substring(0, 2).contains(CuDisbursementVoucherConstants.DV_EXTRACT_TYPED_NOTE_PREFIX_IDENTIFIER)) {
NoteLine = NoteLine.substring(2);
SecondNoteAfterAddressInfo = (NoteLine.length() <= 72) ? NoteLine : NoteLine.substring(0, 72);
// Try to get the third user typed note line
if (ix.hasNext()) {
note = (PaymentNoteText) ix.next();
NoteLine = note.getCustomerNoteText();
if (NoteLine.length() >= 2) {
if (NoteLine.substring(0, 2).contains(CuDisbursementVoucherConstants.DV_EXTRACT_TYPED_NOTE_PREFIX_IDENTIFIER)) {
NoteLine = NoteLine.substring(2);
ThirdNoteAfterAddressInfo = (NoteLine.length() <= 72) ? NoteLine : NoteLine.substring(0, 72);
// Break here because the Mellon spec only allows us to use the first three user typed note lines
break;
} else
// Since we're on our potentially last note if this isn't a user types note, then we're done with the while loop
break;
} else
// Since this is the last potential user note and it doesn't contain :: break out of the while loop
break;
} else
// Out of all notes, so break out of the while loop
break;
} else
// Getting here means that we ran into a note line that doesn't have the :: in front. Continuing will over write the first notes we did capture, so
break;
} else
// Interspersed system generated notes can't occur (yet) so break out since we've already processed 1 user entered note.
break;
} else
// We've processed the first user entered note, but now we find a system generated note, so break out since this would mean that user notes are done as they are contiguous
break;
} else
// Getting here means this is not a user note and since we haven't found the first user note, keep looking
continue;
} else
// Getting here means this is not a user note, so since we still haven't found the first user note keep on looking.
continue;
}
// else (user notes section of this code)
}
if (MissingCommaFromSpecialHandlingAddress)
break;
// 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());
break;
}
else {
LOG.error("No customer profile exists for payee name: " + pg.getPayeeName());
break;
}
}
if (first && !immediateCheckCode) {
if (!wroteMellonFastTrackHeaderRecords) {
// Open the file
os = new BufferedWriter(new FileWriter(ftFilename));
// Write the Fast Track header record (FIL00010)
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
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(processDate) + // File Date and Time - 14 Bytes
cDelim + // Reserved Field - 3 Bytes
cDelim + // Filler - 872 bytes
"\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();
// write (FIL00020) record for each email address
os.write("FIL00020" + cDelim + emailAddress + cDelim + cDelim + "\n");
totalRecordCount = totalRecordCount + 1;
}
wroteMellonFastTrackHeaderRecords = true;
}
// Get country name
int CountryNameMaxLength = 15;
Country country = null;
if (StringUtils.isNotBlank(pg.getCountry())) {
country = countryService.getCountry(pg.getCountry());
}
if (country != null)
sCountryName = country.getName().substring(0, ((country.getName().length() >= CountryNameMaxLength) ? CountryNameMaxLength : country.getName().length()));
else if (ObjectUtils.isNotNull(pg.getCountry()))
sCountryName = pg.getCountry().substring(0, ((pg.getCountry().length() >= CountryNameMaxLength) ? CountryNameMaxLength : pg.getCountry().length()));
else
// Do this only if both the getPostalCountryName() AND getCountry() are empty
sCountryName = "";
// Do final country name processing per requirements from BNY Mellon.
if (sCountryName.toUpperCase().contains("UNITED STATES"))
sCountryName = "";
// Get special handling indicator
specialHandlingCode = pg.getPymtSpecialHandling();
// Get attachment indicator
attachmentCode = pg.getPymtAttachment();
// Determines the division code based on special handling indicator and attachment indicator
int dvCodeInt = 0;
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);
Date DisbursementDate;
if (ObjectUtils.isNotNull(pg.getDisbursementDate()))
DisbursementDate = pg.getDisbursementDate();
else {
LOG.error("Disbursement Date is NULL for Disbursement Number: " + CheckNumber);
break;
}
// Write the Fast Track PAY01000 record (only one per payee)
os.write(// Record Type - 8 bytes
"PAY01000" + cDelim + "7" + // 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 + "CHK" + // CHK=Check (Payment method - 3 Bytes)
cDelim + "PBC" + // PBC is used for checks (Payment Format - 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 + "2150532082" + // Originating company identifier - 10 bytes This has to be different for this file than it is for ACH payments per BNY Mellon
cDelim + // Receiving bank id qualifier - 2 bytes
cDelim + // Receiving bank id - 12 bytes
cDelim + // Receiving account number qualifier - 3 bytes
cDelim + // Receiving account number - 35 bytes
cDelim + sdfPAY1000Rec.format(DisbursementDate) + // Effective date - 8 bytes - YYMMDD format
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 + // Filler
cDelim + "\n");
totalPaymentAmounts = totalPaymentAmounts.add(totalNetAmount);
// Write the Fast Track Payer Detail(PDT02010) record (only one per payee)
os.write(// Record Type - 8 bytes
"PDT02010" + cDelim + "PR" + // Name qualifier - 3 bytes (PR = Payer)
cDelim + // ID code qualifier - 2 bytes
cDelim + // ID code - 80 bytes
cDelim + PAYER_NAME + // Name - 35 bytes
cDelim + // Additional name 1 - 60 bytes
cDelim + // Additional name 2 - 60 bytes
cDelim + PAYER_ADDRESS_LINE1 + // Address line 1 - 35 bytes
cDelim + PAYER_ADDRESS_LINE2 + // Address line 2 - 35 bytes
cDelim + // Address line 3 - 35 bytes
cDelim + // Address line 4 - 35 bytes
cDelim + // Address line 5 - 35 bytes
cDelim + // Address line 6 - 35 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 Fast Track initial payee detail (PDT02010) record
int AddrMaxLength = 35;
int CityMaxLength = 30;
int StateMaxLength = 2;
int ZipMaxLength = 15;
int PayeeNameMaxLength = 35;
int PayeeIdMaxLength = 18;
String PayeeName = "";
String PayeeId = "";
String PayeeIdQualifier = "";
String AddrLine1 = "";
String AddrLine2 = "";
String AddrLine3 = "";
String AddrLine4 = "";
String AddrCity = "";
String AddrState = "";
String AddrZip = "";
if (ObjectUtils.isNotNull(pg.getPayeeName()))
PayeeName = pg.getPayeeName().substring(0, ((pg.getPayeeName().length() >= PayeeNameMaxLength) ? PayeeNameMaxLength : pg.getPayeeName().length()));
if (ObjectUtils.isNotNull(pg.getPayeeId())) {
PayeeId = pg.getPayeeId().substring(0, ((pg.getPayeeId().length() >= PayeeIdMaxLength) ? PayeeIdMaxLength : pg.getPayeeId().length()));
PayeeIdQualifier = "ZZ";
}
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()))
AddrCity = pg.getCity().substring(0, ((pg.getCity().length() >= CityMaxLength) ? CityMaxLength : pg.getCity().length()));
if (ObjectUtils.isNotNull(pg.getState()))
AddrState = pg.getState().substring(0, ((pg.getState().length() >= StateMaxLength) ? StateMaxLength : pg.getState().length()));
if (ObjectUtils.isNotNull(pg.getZipCd()))
AddrZip = (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 (PE = Payee) This record's data prints on the check
cDelim + PayeeIdQualifier + // ID code qualifier - 2 bytes
cDelim + PayeeId + // ID code - 80 bytes
cDelim + PayeeName + // Name - 35 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 + AddrCity + // City - 30 bytes
cDelim + AddrState + // State/Province - 2 bytes
cDelim + AddrZip + // Postal code - 15 bytes
cDelim + // Country code - 3 bytes
cDelim + sCountryName + // Country name - 15 bytes (do not use if Country Code is used)
cDelim + // Ref qualifier 1 - 3 bytes (not used)
cDelim + // Ref ID 1 - 50 bytes (not used)
cDelim + // Ref description 1 - 80 bytes (not used)
cDelim + // Ref qualifier 1 - 3 bytes (not used)
cDelim + // Ref ID 1 - 50 bytes (not used)
cDelim + // Ref description 1 - 80 bytes (not used)
cDelim + cDelim + "\n");
// If no alternate address is provided, we must populate with the customer address
if (NumOfAltAddressLines == 0) {
// If we were not provided an alternate address to mail the check to, then assign the same values
// in the third PDT02010 record the same exact values as the second PDT02010 record.
altAddrSendTo = PayeeName;
altAddrAddr1 = AddrLine1;
altAddrAddr2 = AddrLine2;
altAddrAddr3 = AddrLine3;
altAddrAddr4 = AddrLine4;
altAddrCity = AddrCity;
altAddrState = AddrState;
altAddrZip = AddrZip;
altAddrCityStateZip = altAddrCity + ", " + altAddrState + " " + altAddrZip;
altCountryName = sCountryName;
altRefQualifer = "ZZ";
} else {
altAddrZip = altAddrZip.replace("-", "");
// If we have two addresses, an original and an alternate, make sure the alternate does not inherit the original's country name!
altCountryName = "";
}
// Write the Fast Track second payee detail (PDT02010) record (for alternate addressing (special handling addressing case)
os.write(// Record Type - 8 bytes
"PDT02010" + cDelim + "FE" + // Name qualifier - 3 bytes (FE = Remit) This record's data prints on the remittance
cDelim + PayeeIdQualifier + // ID code qualifier - 2 bytes
cDelim + PayeeId + // ID code - 80 bytes
cDelim + altAddrSendTo + // Name - 35 bytes
cDelim + // Additional name 1 - 60 bytes
cDelim + // Additional name 2 - 60 bytes
cDelim + altAddrAddr1 + // Address line 1 - 35 bytes
cDelim + altAddrAddr2 + // Address line 2 - 35 bytes
cDelim + altAddrAddr3 + // Address line 3 - 35 bytes
cDelim + altAddrAddr4 + // Address line 4 - 35 bytes
cDelim + // Address line 5 - 35 bytes
cDelim + // Address line 6 - 35 bytes
cDelim + altAddrCity + // City - 30 bytes
cDelim + altAddrState + // State/Province - 2 bytes
cDelim + altAddrZip + // Postal code - 15 bytes
cDelim + // Country code - 3 bytes
cDelim + altCountryName + // Country name - 30 15 bytes (do not use if Country Code is used) Alternate addresses are never outside the USA.
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 three for the PDT02010 records
totalRecordCount = totalRecordCount + 4;
// Set this here so it is only executed once per payee
first = false;
}
// if (first && !immediateCheckCode)
// Write the Fast Track REM03020 records
// Up to 3 characters
String remittanceIdCode = "";
// Up to 22 characters
String remittanceIdText = "";
// Here we will NOT have an invoice number but we will have an eDoc number and NO PO number
if (subUnitCode.equals(CuDisbursementVoucherConstants.DV_EXTRACT_SUB_UNIT_CODE)) {
remittanceIdCode = "TN";
// Here, we are guaranteed to have a pd.getCustPaymentDocNbr
remittanceIdText = "Doc No:" + pd.getCustPaymentDocNbr();
// Assign RefDesc1
RefDesc1 = "";
} else // Here we will have an invoice number and an eDoc number and a PO number
if (subUnitCode.equals("PRAP")) {
remittanceIdCode = "IV";
// Here, we are guaranteed to have a pd.getInvoiceNbr
remittanceIdText = pd.getInvoiceNbr();
// Assign RefDesc1
if (ObjectUtils.isNotNull(pd.getPurchaseOrderNbr()))
RefDesc1 = "PO:" + pd.getPurchaseOrderNbr() + ", Doc No:" + pd.getCustPaymentDocNbr();
else
RefDesc1 = "Doc No:" + pd.getCustPaymentDocNbr();
} else // Here we will have an invoice number and an eDoc number but we will NOT have PO number
if (!subUnitCode.equals(CuDisbursementVoucherConstants.DV_EXTRACT_SUB_UNIT_CODE) && !subUnitCode.equals("PRAP")) {
remittanceIdCode = "IV";
// Here, we are guaranteed to have a pd.getInvoiceNbr
remittanceIdText = pd.getInvoiceNbr();
// Assign RefDesc1
RefDesc1 = "Doc No:" + pd.getCustPaymentDocNbr();
}
// Assign the RefDesc fields.
if (!PreparerInfoText.isEmpty())
if (RefDesc1.isEmpty()) {
if (FirstNoteAfterAddressInfo.isEmpty()) {
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// no notes
RefDesc1 = PreparerInfoText;
RefDesc2 = "";
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note3
RefDesc1 = PreparerInfoText;
RefDesc2 = ThirdNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
}
} else {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note2
RefDesc1 = PreparerInfoText;
RefDesc2 = SecondNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note2, Note3
RefDesc1 = PreparerInfoText;
RefDesc2 = SecondNoteAfterAddressInfo;
RefDesc3 = ThirdNoteAfterAddressInfo;
RefDesc4 = "";
}
}
} else {
// Note1
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1
RefDesc1 = PreparerInfoText;
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note1, Note3
RefDesc1 = PreparerInfoText;
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = ThirdNoteAfterAddressInfo;
RefDesc4 = "";
}
} else {
// Note2
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1, Note2
RefDesc1 = PreparerInfoText;
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = SecondNoteAfterAddressInfo;
RefDesc4 = "";
} else {
// Note1, Note2, Note3
RefDesc1 = PreparerInfoText;
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = SecondNoteAfterAddressInfo;
RefDesc4 = ThirdNoteAfterAddressInfo;
}
}
}
} else {
// RefDesc1 contains text
if (FirstNoteAfterAddressInfo.isEmpty()) {
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// no notes
RefDesc2 = PreparerInfoText;
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note3
RefDesc2 = PreparerInfoText;
RefDesc3 = ThirdNoteAfterAddressInfo;
RefDesc4 = "";
}
} else {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note2
RefDesc2 = PreparerInfoText;
RefDesc3 = SecondNoteAfterAddressInfo;
RefDesc4 = "";
} else {
// Note2, Note3
RefDesc2 = PreparerInfoText;
RefDesc3 = SecondNoteAfterAddressInfo;
RefDesc4 = ThirdNoteAfterAddressInfo;
}
}
} else {
// Note1
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1
RefDesc2 = PreparerInfoText;
RefDesc3 = FirstNoteAfterAddressInfo;
RefDesc4 = "";
} else {
// Note1, Note3
RefDesc2 = PreparerInfoText;
RefDesc3 = FirstNoteAfterAddressInfo;
RefDesc4 = ThirdNoteAfterAddressInfo;
}
} else {
// Note2
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1, Note2
RefDesc2 = PreparerInfoText;
RefDesc3 = FirstNoteAfterAddressInfo;
RefDesc4 = SecondNoteAfterAddressInfo;
} else {
// Note1, Note2, Note3
RefDesc2 = PreparerInfoText;
RefDesc3 = FirstNoteAfterAddressInfo;
RefDesc4 = SecondNoteAfterAddressInfo;
}
}
}
}
else // PreparerInfoText is empty
if (RefDesc1.isEmpty())
if (FirstNoteAfterAddressInfo.isEmpty()) {
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// no notes
RefDesc1 = "";
RefDesc2 = "";
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note3
RefDesc1 = ThirdNoteAfterAddressInfo;
RefDesc2 = "";
RefDesc3 = "";
RefDesc4 = "";
}
} else {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note2
RefDesc1 = SecondNoteAfterAddressInfo;
RefDesc2 = "";
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note2, Note3
RefDesc1 = SecondNoteAfterAddressInfo;
RefDesc2 = ThirdNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
}
}
} else {
// Note1
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1
RefDesc1 = FirstNoteAfterAddressInfo;
RefDesc2 = "";
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note1, Note3
RefDesc1 = FirstNoteAfterAddressInfo;
RefDesc2 = ThirdNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
}
} else {
// Note2
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1, Note2
RefDesc1 = FirstNoteAfterAddressInfo;
RefDesc2 = SecondNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note1, Note2, Note3
RefDesc1 = FirstNoteAfterAddressInfo;
RefDesc2 = SecondNoteAfterAddressInfo;
RefDesc3 = ThirdNoteAfterAddressInfo;
RefDesc4 = "";
}
}
}
else // RefDesc1 contains text
if (FirstNoteAfterAddressInfo.isEmpty()) {
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// no notes
RefDesc2 = "";
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note3
RefDesc2 = ThirdNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
}
} else {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note2
RefDesc2 = SecondNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note2, Note3
RefDesc2 = SecondNoteAfterAddressInfo;
RefDesc3 = ThirdNoteAfterAddressInfo;
RefDesc4 = "";
}
}
} else {
// Note1
if (SecondNoteAfterAddressInfo.isEmpty()) {
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = "";
RefDesc4 = "";
} else {
// Note1, Note3
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = ThirdNoteAfterAddressInfo;
RefDesc4 = "";
}
} else {
// Note2
if (ThirdNoteAfterAddressInfo.isEmpty()) {
// Note1, Note2
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = SecondNoteAfterAddressInfo;
RefDesc4 = "";
} else {
// Note1, Note2, Note3
RefDesc2 = FirstNoteAfterAddressInfo;
RefDesc3 = SecondNoteAfterAddressInfo;
RefDesc4 = ThirdNoteAfterAddressInfo;
}
}
}
// If we have something in RefDesc1 then RefQualifier must be "ZZ" according to Mellon's spec.
if (!RefDesc1.isEmpty())
Ref1Qualifier = "ZZ";
else
Ref1Qualifier = "";
// If we have something in RefDesc2 then RefQualifier must be "ZZ" according to Mellon's spec.
if (!RefDesc2.isEmpty())
Ref2Qualifier = "ZZ";
else
Ref2Qualifier = "";
// If we have something in RefDesc3 then RefQualifier must be "ZZ" according to Mellon's spec.
if (!RefDesc3.isEmpty())
Ref3Qualifier = "ZZ";
else
Ref3Qualifier = "";
// If we have something in RefDesc4 then RefQualifier must be "ZZ" according to Mellon's spec.
if (!RefDesc4.isEmpty())
Ref4Qualifier = "ZZ";
else
Ref4Qualifier = "";
// Only perform the following if this is an immediate check
if (immediateCheckCode) {
if (!wroteMellonIssuanceHeaderRecords) {
// Open the File
osI = new BufferedWriter(new FileWriter(arFilename));
// Write the Mellon issuance header record
osI.write(//
"1" + //
repeatThis(" ", 2) + //
"MELLONBANK" + //
"CORNELL " + //
sdfIDate.format(processDate) + //
sdfITime.format(processDate) + repeatThis(" ", 209) + //
"\n");
// Write the BNY Mellon issuance service record
osI.write(//
"2" + //
repeatThis(" ", 30) + //
"100" + //
"242" + //
"0242" + //
"1" + repeatThis(" ", 200) + //
"\n");
// 2 issuance records added here.
numOfIssuanceRecords = numOfIssuanceRecords + 2;
wroteMellonIssuanceHeaderRecords = true;
}
String arPayeeName = "";
String arLine1Address = "";
if (ObjectUtils.isNotNull(pg.getPayeeName()))
arPayeeName = pg.getPayeeName();
if (ObjectUtils.isNotNull(pg.getLine1Address()))
arLine1Address = pg.getLine1Address();
// Write the BNY Mellon issuance detail (regular format) record
CheckNumber = repeatThis("0", 10 - pg.getDisbursementNbr().toString().length()) + pg.getDisbursementNbr().toString();
String AmountOfCheck = totalNetAmount.toString().replace(".", "");
AmountOfCheck = repeatThis("0", 10 - AmountOfCheck.length()) + AmountOfCheck;
osI.write(// Record Type - 1 Byte
"6" + // Status Code-> 2: Add Issue, 6: Void Issue - 1 Byte
"2" + // Origin - Company Name - 10 Bytes
"CORNELL " + // Destination - Identification of receiving location: MELLONWEST, MELLONEAST, MELLONTRUS, BOSTONNOW - 10 bytes
"MELLONWEST" + repeatThis("0", 10 - ourBankAccountNumber.length()) + // Checking account number - 10 Bytes
ourBankAccountNumber + // Check Serial Number (check number) - 10 Bytes
CheckNumber + // Check Amount: Format $$$$$$$$cc - 10 Bytes
AmountOfCheck + // Issue Date: Format YYMMDD - 6 Bytes
sdfIDate.format(processDate) + // Additional Data (Optional) - 10 bytes
repeatThis(" ", 10) + // Register Information (Optional) - 5 Bytes
repeatThis(" ", 5) + // Not used - 49 bytes
repeatThis(" ", 49) + // Payee Line 1 - Payee Name (Required) - 60 Bytes
String.format("%-60.60s", arPayeeName.toUpperCase()) + String.format("%-60.60s", arLine1Address.toUpperCase()) + // Payee Line 2 - Payee Name or first line of address (Required) - 60 Bytes
"\n");
// Totals the number of add issues across ALL checks issued not just for this one payee.
arNumOfAddIssues = arNumOfAddIssues + 1;
// Same as for the count but for the total dollar amount.
arTotalOfAddIssues = arTotalOfAddIssues.add(totalNetAmount);
// Add to the total number of issuance records
numOfIssuanceRecords = numOfIssuanceRecords + 1;
} else // if (immediateCheckCode)
{
// 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 for check number " + CheckNumber);
break;
}
}
if (ObjectUtils.isNotNull(pd.getOrigInvoiceAmount())) {
ftTotalAmount = pd.getOrigInvoiceAmount().toString();
if (ftTotalAmount.length() > 18) {
LOG.error("Original Invoice Amount is more than 18 bytes for check number " + CheckNumber);
break;
}
}
if (ObjectUtils.isNotNull(pd.getInvTotDiscountAmount())) {
ftDiscountAmt = pd.getInvTotDiscountAmount().toString();
if (ftDiscountAmt.length() > 18) {
LOG.error("Discount Amount is more than 18 bytes for check number " + CheckNumber);
break;
}
}
String InvoiceDate = "";
if (ObjectUtils.isNotNull(pd.getInvoiceDate())) {
InvoiceDate = pd.getInvoiceDate().toString().replace("-", "");
dateQualifier = "003";
} else {
LOG.error("Invoice date is blank for check number " + CheckNumber);
break;
}
// Write the Fast Track REM03020 record
os.write(// Record type - 8 bytes
"REM03020" + cDelim + remittanceIdCode + // Remittance qualifier code - 3 bytes
cDelim + remittanceIdText + // Remittance ID - 22 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
cDelim + // Note 2 - 80 bytes
cDelim + Ref1Qualifier + // Ref qualifier 1
cDelim + // Ref ID 1
cDelim + RefDesc1 + // Ref description 1 (up to 72 bytes)
cDelim + Ref2Qualifier + // Ref qualifier 2
cDelim + // Ref ID 2 (not used)
cDelim + RefDesc2 + // Ref description 2 (up to 72 bytes)
cDelim + Ref3Qualifier + // Ref qualifier 3
cDelim + // Ref ID 3 (not used)
cDelim + RefDesc3 + // Ref description 3 (up to 72 bytes)
cDelim + Ref4Qualifier + // Ref qualifier 4
cDelim + // Ref ID 4 (not used)
cDelim + RefDesc4 + // Ref description 4 (up to 72 bytes)
cDelim + dateQualifier + // Date qualifier 1
cDelim + InvoiceDate + // Date 1
cDelim + // Date qualifier 2 (not used)
cDelim + // Date 2 (not used)
cDelim + // Date qualifier 3 (not used)
cDelim + // Date 3 (not used)
cDelim + // Date qualifier 4 (not used)
cDelim + // Date 4 (not used)
cDelim + "\n");
// One for the REM03020 records
totalRecordCount = totalRecordCount + 1;
}
// Copied from the above XML generating method since this is the method that needs to record what was processed and what was not.
if (!testMode) {
pg.setDisbursementDate(new java.sql.Date(processDate.getTime()));
pg.setPaymentStatus(extractedStatus);
this.businessObjectService.save(pg);
}
}
// while (paymentDetails.hasNext())
}
// for (Iterator<Integer> iter = disbNbrs.iterator(); iter.hasNext();)
}
// for (String bankCode : bankCodes)
// Need to update the total record count here to make sure it includes the trailer record
totalRecordCount = totalRecordCount + 1;
if (wroteMellonIssuanceHeaderRecords) {
// Write the BNY Mellon issuance service total record
String NumOfAddIssues = repeatThis("0", 10 - Integer.toString(arNumOfAddIssues).length()) + Integer.toString(arNumOfAddIssues);
String TotalAmountOfAddIssues = arTotalOfAddIssues.toString().replace(".", "");
TotalAmountOfAddIssues = repeatThis("0", 12 - TotalAmountOfAddIssues.length()) + TotalAmountOfAddIssues;
osI.write(// Record Type
"8" + // Total Number of Add Issues, 10 Bytes, numeric only, right justified, prefixed with zeros as needed to make length
NumOfAddIssues + // Total Amount of Add Issues, 12 Bytes, numeric only (no decimals) right justified, prefixed with zeros as needed to make length
TotalAmountOfAddIssues + // Total number of voided checks, 10 Bytes for voided checks which at this point we don't do.
repeatThis("0", 10) + // Total amount of voided checks, 12 Bytes for the total voided amounts
repeatThis("0", 12) + repeatThis(" ", 197) + // Required Filler
"\n");
// This is to account for record #8 above
numOfIssuanceRecords = numOfIssuanceRecords + 1;
// Write the BNY Mellon issuance trailer record
// Need to add an issuance record here to account for the trailer record
numOfIssuanceRecords = numOfIssuanceRecords + 1;
String numberOfIssuanceRecords = repeatThis("0", 6 - Integer.toString(numOfIssuanceRecords).length()) + Integer.toString(numOfIssuanceRecords);
osI.write(// Record Type
"9" + // Total Number of Records, 6 bytes, numeric only, right justified, prefixed with zeros
numberOfIssuanceRecords + repeatThis(" ", 235) + // Required Filler
"\n");
}
if (wroteMellonFastTrackHeaderRecords) {
// Fast Track 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("IO Exception with writeExtractCheckFileMellonBankFastTrack() Problem reading file: " + ftFilename, ie);
throw new IllegalArgumentException("Error writing to output file: " + ie.getMessage());
} catch (Exception ex) {
LOG.error("General Exception with writeExtractCheckFileMellonBankFastTrack(). 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(ftFilename, ftFilename + ".READY");
} catch (IOException ie) {
// Not much we can do now
LOG.error("IOException encountered in writeExtractCheckFileMellonBankFastTrack. Message is: " + ie.getMessage());
}
}
// osI.close();
if (osI != null) {
try {
osI.close();
// Rename the resulting file to have a .READY at the end
// Need to do this at the end to indicate that the file is ready after it is closed.
renameFile(arFilename, arFilename + ".READY");
} catch (IOException ie) {
// Not much we can do now
LOG.error("IOException encountered in writeExtractAchFile. Message is: " + ie.getMessage());
}
}
}
}
use of org.kuali.kfs.pdp.businessobject.CustomerProfile in project cu-kfs by CU-CommunityApps.
the class CuExtractPaymentServiceImpl method writePayeeSpecificsToAchFile.
/*
* New method created due to refactoring the code from ExtractPaymentServiceImpl and AchBundlerExtractPaymnetServiceImpl.
* Method writes all tags and data for a single payee from open ach to close of customerProfile.
*/
protected void writePayeeSpecificsToAchFile(BufferedWriter os, PaymentGroup paymentGroup, Date processDate, SimpleDateFormat sdf) throws IOException {
try {
writeOpenTagAttribute(os, 2, "ach", "disbursementNbr", paymentGroup.getDisbursementNbr().toString());
PaymentProcess paymentProcess = paymentGroup.getProcess();
writeTag(os, 4, "processCampus", paymentProcess.getCampusCode());
writeTag(os, 4, "processId", paymentProcess.getId().toString());
writeBank(os, 4, paymentGroup.getBank());
writeTag(os, 4, "disbursementDate", sdf.format(processDate));
writeTag(os, 4, "netAmount", paymentGroup.getNetPaymentAmount().toString());
writePayeeAch(os, 4, paymentGroup);
writeTag(os, 4, "paymentDate", sdf.format(paymentGroup.getPaymentDate()));
CustomerProfile cp = paymentGroup.getBatch().getCustomerProfile();
writeCustomerProfile(os, 4, cp);
writeOpenTag(os, 4, "payments");
} catch (IOException ioe) {
LOG.error("writePayeeSpecificsToAchFile(): Problem writing to file - IOException caught and rethrown.");
throw ioe;
}
}
use of org.kuali.kfs.pdp.businessobject.CustomerProfile in project cu-kfs by CU-CommunityApps.
the class CuPendingTransactionServiceImpl method populatePaymentGeneralLedgerPendingEntry.
/**
* Populates and stores a new GLPE for each account detail in the payment group.
*
* @param paymentGroup payment group to generate entries for
* @param achFdocTypeCode doc type for ach disbursements
* @param checkFdocTypeCod doc type for check disbursements
* @param reversal boolean indicating if this is a reversal
*/
protected void populatePaymentGeneralLedgerPendingEntry(PaymentGroup paymentGroup, String achFdocTypeCode, String checkFdocTypeCod, boolean reversal) {
List<PaymentAccountDetail> accountListings = new ArrayList<PaymentAccountDetail>();
GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
for (PaymentDetail paymentDetail : paymentGroup.getPaymentDetails()) {
accountListings.addAll(paymentDetail.getAccountDetail());
}
// GeneralLedgerPendingEntrySequenceHelper sequenceHelper = new GeneralLedgerPendingEntrySequenceHelper();
for (PaymentAccountDetail paymentAccountDetail : accountListings) {
GlPendingTransaction glPendingTransaction = new GlPendingTransaction();
glPendingTransaction.setSequenceNbr(new KualiInteger(sequenceHelper.getSequenceCounter()));
if (StringUtils.isNotBlank(paymentAccountDetail.getPaymentDetail().getFinancialSystemOriginCode()) && StringUtils.isNotBlank(paymentAccountDetail.getPaymentDetail().getFinancialDocumentTypeCode())) {
glPendingTransaction.setFdocRefTypCd(paymentAccountDetail.getPaymentDetail().getFinancialDocumentTypeCode());
glPendingTransaction.setFsRefOriginCd(paymentAccountDetail.getPaymentDetail().getFinancialSystemOriginCode());
} else {
glPendingTransaction.setFdocRefTypCd(PdpConstants.PDP_FDOC_TYPE_CODE);
glPendingTransaction.setFsRefOriginCd(PdpConstants.PDP_FDOC_ORIGIN_CODE);
}
glPendingTransaction.setFinancialBalanceTypeCode(org.kuali.kfs.sys.KFSConstants.BALANCE_TYPE_ACTUAL);
Date transactionTimestamp = new Date(dateTimeService.getCurrentDate().getTime());
glPendingTransaction.setTransactionDt(transactionTimestamp);
AccountingPeriod fiscalPeriod = accountingPeriodService.getByDate(new java.sql.Date(transactionTimestamp.getTime()));
glPendingTransaction.setUniversityFiscalYear(fiscalPeriod.getUniversityFiscalYear());
glPendingTransaction.setUnivFiscalPrdCd(fiscalPeriod.getUniversityFiscalPeriodCode());
glPendingTransaction.setAccountNumber(paymentAccountDetail.getAccountNbr());
glPendingTransaction.setSubAccountNumber(paymentAccountDetail.getSubAccountNbr());
glPendingTransaction.setChartOfAccountsCode(paymentAccountDetail.getFinChartCode());
if (paymentGroup.getDisbursementType().getCode().equals(PdpConstants.DisbursementTypeCodes.ACH)) {
glPendingTransaction.setFinancialDocumentTypeCode(achFdocTypeCode);
} else if (paymentGroup.getDisbursementType().getCode().equals(PdpConstants.DisbursementTypeCodes.CHECK)) {
glPendingTransaction.setFinancialDocumentTypeCode(checkFdocTypeCod);
}
glPendingTransaction.setFsOriginCd(PdpConstants.PDP_FDOC_ORIGIN_CODE);
glPendingTransaction.setFdocNbr(paymentGroup.getDisbursementNbr().toString());
// if stale
if (StringUtils.equals(FDOC_TYP_CD_STALE_CHECK, checkFdocTypeCod)) {
ParameterService parameterService = SpringContext.getBean(ParameterService.class);
String clAcct = parameterService.getParameterValueAsString(CheckReconciliationImportStep.class, CRConstants.CLEARING_ACCOUNT);
String obCode = parameterService.getParameterValueAsString(CheckReconciliationImportStep.class, CRConstants.CLEARING_OBJECT_CODE);
String coaCode = parameterService.getParameterValueAsString(CheckReconciliationImportStep.class, CRConstants.CLEARING_COA);
// Use clearing parameters if stale
glPendingTransaction.setAccountNumber(clAcct);
glPendingTransaction.setFinancialObjectCode(obCode);
glPendingTransaction.setChartOfAccountsCode(coaCode);
glPendingTransaction.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
// KFSUPGRADE-943
glPendingTransaction.setSubAccountNumber(KFSConstants.getDashSubAccountNumber());
} else {
Boolean relieveLiabilities = paymentGroup.getBatch().getCustomerProfile().getRelieveLiabilities();
if ((relieveLiabilities != null) && (relieveLiabilities.booleanValue()) && paymentAccountDetail.getPaymentDetail().getFinancialDocumentTypeCode() != null) {
OffsetDefinition offsetDefinition = SpringContext.getBean(OffsetDefinitionService.class).getByPrimaryId(glPendingTransaction.getUniversityFiscalYear(), glPendingTransaction.getChartOfAccountsCode(), paymentAccountDetail.getPaymentDetail().getFinancialDocumentTypeCode(), glPendingTransaction.getFinancialBalanceTypeCode());
glPendingTransaction.setFinancialObjectCode(offsetDefinition != null ? offsetDefinition.getFinancialObjectCode() : paymentAccountDetail.getFinObjectCode());
glPendingTransaction.setFinancialSubObjectCode(KFSConstants.getDashFinancialSubObjectCode());
} else {
glPendingTransaction.setFinancialObjectCode(paymentAccountDetail.getFinObjectCode());
glPendingTransaction.setFinancialSubObjectCode(paymentAccountDetail.getFinSubObjectCode());
}
}
glPendingTransaction.setProjectCd(paymentAccountDetail.getProjectCode());
glPendingTransaction.setDebitCrdtCd(pdpUtilService.isDebit(paymentAccountDetail, reversal) ? KFSConstants.GL_DEBIT_CODE : KFSConstants.GL_CREDIT_CODE);
glPendingTransaction.setAmount(paymentAccountDetail.getAccountNetAmount().abs());
// Changes for Research Participant Upload
String trnDesc = StringUtils.EMPTY;
CustomerProfile customerProfile = paymentGroup.getBatch().getCustomerProfile();
// KFSUPGRADE-973
if (researchParticipantPaymentValidationService.isResearchParticipantPayment(customerProfile)) {
BusinessObjectEntry businessObjectEntry = dataDictionaryService.getDataDictionary().getBusinessObjectEntry(PaymentDetail.class.getName());
AttributeDefinition attributeDefinition = businessObjectEntry.getAttributeDefinition("paymentGroup.payeeName");
AttributeSecurity originalPayeeNameAttributeSecurity = attributeDefinition.getAttributeSecurity();
// This is a temporary work around for an issue introduced with KFSCNTRB-705.
if (ObjectUtils.isNotNull(originalPayeeNameAttributeSecurity)) {
String maskLiteral = ((MaskFormatterLiteral) originalPayeeNameAttributeSecurity.getMaskFormatter()).getLiteral();
trnDesc = maskLiteral;
}
} else {
String payeeName = paymentGroup.getPayeeName();
if (StringUtils.isNotBlank(payeeName)) {
trnDesc = payeeName.length() > 40 ? payeeName.substring(0, 40) : StringUtils.rightPad(payeeName, 40);
}
if (reversal) {
String poNbr = paymentAccountDetail.getPaymentDetail().getPurchaseOrderNbr();
if (StringUtils.isNotBlank(poNbr)) {
trnDesc += " " + (poNbr.length() > 9 ? poNbr.substring(0, 9) : StringUtils.rightPad(poNbr, 9));
}
String invoiceNbr = paymentAccountDetail.getPaymentDetail().getInvoiceNbr();
if (StringUtils.isNotBlank(invoiceNbr)) {
trnDesc += " " + (invoiceNbr.length() > 14 ? invoiceNbr.substring(0, 14) : StringUtils.rightPad(invoiceNbr, 14));
}
if (trnDesc.length() > 40) {
trnDesc = trnDesc.substring(0, 40);
}
}
}
glPendingTransaction.setDescription(trnDesc);
glPendingTransaction.setOrgDocNbr(paymentAccountDetail.getPaymentDetail().getOrganizationDocNbr());
glPendingTransaction.setOrgReferenceId(paymentAccountDetail.getOrgReferenceId());
glPendingTransaction.setFdocRefNbr(paymentAccountDetail.getPaymentDetail().getCustPaymentDocNbr());
// update the offset account if necessary
SpringContext.getBean(FlexibleOffsetAccountService.class).updateOffset(glPendingTransaction);
this.businessObjectService.save(glPendingTransaction);
sequenceHelper.increment();
if (bankService.isBankSpecificationEnabled()) {
this.populateBankOffsetEntry(paymentGroup, glPendingTransaction, sequenceHelper);
}
}
}
use of org.kuali.kfs.pdp.businessobject.CustomerProfile in project cu-kfs by CU-CommunityApps.
the class CuFormatAction method start.
@Override
public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
CuFormatForm formatForm = (CuFormatForm) form;
Person kualiUser = GlobalVariables.getUserSession().getPerson();
FormatSelection formatSelection = formatService.getDataForFormat(kualiUser);
DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
formatForm.setCampus(kualiUser.getCampusCode());
// no data for format because another format process is already running
if (formatSelection.getStartDate() != null) {
GlobalVariables.getMessageMap().putError(KFSConstants.GLOBAL_ERRORS, PdpKeyConstants.Format.ERROR_PDP_FORMAT_PROCESS_ALREADY_RUNNING, dateTimeService.toDateTimeString(formatSelection.getStartDate()));
} else {
List<CustomerProfile> customers = formatSelection.getCustomerList();
for (CustomerProfile element : customers) {
if (formatSelection.getCampus().equals(element.getDefaultPhysicalCampusProcessingCode())) {
element.setSelectedForFormat(Boolean.TRUE);
} else {
element.setSelectedForFormat(Boolean.FALSE);
}
}
formatForm.setPaymentDate(dateTimeService.toDateString(dateTimeService.getCurrentTimestamp()));
formatForm.setPaymentTypes(PdpConstants.PaymentTypes.ALL);
formatForm.setPaymentDistribution(CUPdpConstants.PaymentDistributions.PROCESS_ALL);
formatForm.setCustomers(customers);
formatForm.setRanges(formatSelection.getRangeList());
}
return mapping.findForward(PdpConstants.MAPPING_SELECTION);
}
Aggregations