com.global.api.gateways.bill_pay.requests.BillPayRequestBase Maven / Gradle / Ivy
package com.global.api.gateways.bill_pay.requests;
import java.math.BigDecimal;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.global.api.builders.AuthorizationBuilder;
import com.global.api.builders.ManagementBuilder;
import com.global.api.entities.Address;
import com.global.api.entities.Customer;
import com.global.api.entities.HostedPaymentData;
import com.global.api.entities.billing.Bill;
import com.global.api.entities.billing.Credentials;
import com.global.api.entities.enums.AccountType;
import com.global.api.entities.enums.BillPresentment;
import com.global.api.entities.enums.CheckType;
import com.global.api.entities.enums.EmvFallbackCondition;
import com.global.api.entities.enums.EmvLastChipRead;
import com.global.api.entities.enums.HostedPaymentType;
import com.global.api.entities.enums.PaymentMethodType;
import com.global.api.entities.exceptions.BuilderException;
import com.global.api.entities.exceptions.UnsupportedTransactionException;
import com.global.api.paymentMethods.CreditCardData;
import com.global.api.paymentMethods.IPaymentMethod;
import com.global.api.paymentMethods.ITokenizable;
import com.global.api.paymentMethods.TransactionReference;
import com.global.api.paymentMethods.eCheck;
import com.global.api.utils.Element;
import com.global.api.utils.ElementTree;
import com.global.api.utils.StringUtils;
public abstract class BillPayRequestBase {
private int version = 3092;
private int applicationId = 3;
protected String browserType = "Java SDK";
protected final ElementTree et;
public BillPayRequestBase(ElementTree et) {
this.et = et;
}
///
/// Builds the credentials element
///
/// The element to add children elements under
/// The credential object containing merchant credentials to authenticate the request
protected void buildCredentials(Element parent, Credentials credentials) {
et.subElement(parent, "bdms:BollettaVersion", version);
Element credential = et.subElement(parent, "bdms:Credential");
et.subElement(credential, "bdms:ApiKey", credentials.getApiKey());
et.subElement(credential, "bdms:ApplicationID", applicationId);
et.subElement(credential, "bdms:Password", credentials.getPassword());
et.subElement(credential, "bdms:UserName", credentials.getUserName());
et.subElement(credential, "bdms:MerchantName", credentials.getMerchantName());
}
///
/// Builds the ACH Account section of the request
///
///
///
///
///
protected void buildACHAccount(Element parent, eCheck eCheck, BigDecimal amountToCharge) throws UnsupportedTransactionException {
buildACHAccount(parent, eCheck, amountToCharge, null);
}
protected void buildACHAccount(
Element parent,
eCheck eCheck,
BigDecimal amountToCharge,
BigDecimal feeAmount
) throws UnsupportedTransactionException {
Element achAccounts = et.subElement(parent, "bdms:ACHAccountsToCharge");
Element achAccount = et.subElement(achAccounts, "bdms:ACHAccountToCharge");
et.subElement(achAccount, "bdms:Amount", amountToCharge);
et.subElement(achAccount, "bdms:ExpectedFeeAmount", feeAmount == null ? new BigDecimal(0) : feeAmount);
// PLACEHOLDER: ACHReturnEmailAddress
et.subElement(achAccount, "bdms:ACHStandardEntryClass", eCheck.getSecCode());
et.subElement(achAccount, "bdms:AccountNumber", eCheck.getAccountNumber());
if (eCheck.getCheckType() != null) {
et.subElement(achAccount, "bdms:AccountType", getDepositType(eCheck.getCheckType()));
}
if (eCheck.getAccountType() != null) {
et.subElement(achAccount, "bdms:DepositType", getACHAccountType(eCheck.getAccountType()));
}
// PLACEHOLDER: DocumentID
// PLACEHOLDER: InternalAccountNumber
et.subElement(achAccount, "bdms:PayorName", eCheck.getCheckHolderName());
et.subElement(achAccount, "bdms:RoutingNumber", eCheck.getRoutingNumber());
// PLACEHOLDER: SendEmailOnReturn
// PLACEHOLDER: SubmitDate
// PLACEHOLDER: TrackingNumber
}
///
/// Builds a list of BillPay Bill Transactions from a list of Bills
///
///
///
protected void buildBillTransactions(Element parent, List bills, String billLabel, String amountLabel) {
for (Bill bill : bills) {
Element billTransaction = et.subElement(parent, billLabel);
et.subElement(billTransaction, "bdms:BillType", bill.getBillType());
et.subElement(billTransaction, "bdms:ID1", bill.getIdentifier1());
et.subElement(billTransaction, "bdms:ID2", bill.getIdentifier2());
et.subElement(billTransaction, "bdms:ID3", bill.getIdentifier3());
et.subElement(billTransaction, "bdms:ID4", bill.getIdentifier4());
et.subElement(billTransaction, amountLabel, bill.getAmount());
}
}
///
/// Builds a BillPay ClearTextCredit card from CreditCardData
///
///
///
///
///
protected void buildClearTextCredit(Element parent, CreditCardData card, BigDecimal amountToCharge) {
buildClearTextCredit(parent, card, amountToCharge, null, null, null, null);
}
protected void buildClearTextCredit(Element parent, CreditCardData card, BigDecimal amountToCharge, BigDecimal feeAmount) {
buildClearTextCredit(parent, card, amountToCharge, feeAmount, null, null, null);
}
protected void buildClearTextCredit(Element parent, CreditCardData card, BigDecimal amountToCharge, BigDecimal feeAmount, EmvFallbackCondition condition) {
buildClearTextCredit(parent, card, amountToCharge, feeAmount, condition, null, null);
}
protected void buildClearTextCredit(Element parent, CreditCardData card, BigDecimal amountToCharge, BigDecimal feeAmount, EmvFallbackCondition condition, EmvLastChipRead lastRead) {
buildClearTextCredit(parent, card, amountToCharge, feeAmount, condition, lastRead, null);
}
protected void buildClearTextCredit(Element parent, CreditCardData card, BigDecimal amountToCharge, BigDecimal feeAmount, EmvFallbackCondition condition, EmvLastChipRead lastRead, Address address) {
boolean isEmvFallback = condition != null && condition.equals(EmvFallbackCondition.ChipReadFailure);
boolean isPreviousEmvFallback = lastRead != null && lastRead.equals(EmvLastChipRead.FAILED);
Element clearTextCards = et.subElement(parent, "bdms:ClearTextCreditCardsToCharge");
Element clearTextCard = et.subElement(clearTextCards, "bdms:ClearTextCardToCharge");
et.subElement(clearTextCard, "bdms:Amount", amountToCharge);
et.subElement(clearTextCard, "bdms:CardProcessingMethod", "Credit");
et.subElement(clearTextCard, "bdms:ExpectedFeeAmount", feeAmount == null ? new BigDecimal(0) : feeAmount);
Element clearTextCredit = et.subElement(clearTextCard, "bdms:ClearTextCreditCard");
Element cardHolder = et.subElement(clearTextCredit, "pos:CardHolderData");
buildAccountHolderData(cardHolder,
address,
card.getCardHolderName());
et.subElement(clearTextCredit, "pos:CardNumber", card.getNumber());
et.subElement(clearTextCredit, "pos:ExpirationMonth", card.getExpMonth());
et.subElement(clearTextCredit, "pos:ExpirationYear", card.getExpYear());
et.subElement(clearTextCredit, "pos:IsEmvFallback", serializeBooleanValues(isEmvFallback));
et.subElement(clearTextCredit, "pos:PreviousEmvAlsoFallback", serializeBooleanValues(isPreviousEmvFallback));
et.subElement(clearTextCredit, "pos:VerificationCode", card.getCvn());
}
///
/// Builds the account billing information
///
/// The XML element to attatch to
/// The billing address of the customer
/// The name on the payment account
// private void BuildAccountHolderData(Element parent, RecurringPaymentMethod recurringPaymentMethod)
protected void buildAccountHolderData(Element parent, Address address, String nameOnAccount) {
et.subElement(parent, "pos:NameOnCard", nameOnAccount);
if (address != null) {
et.subElement(parent, "pos:City", address.getCity());
et.subElement(parent, "pos:Address", address.getStreetAddress1());
et.subElement(parent, "pos:State", address.getState());
et.subElement(parent, "pos:Zip", address.getPostalCode());
}
}
///
/// Builds a BillPay token to charge from any payment method
///
/// The parent XML element to attatch to
/// The token to pay
/// The amount to charge
/// The expected fee amount to charge
protected void buildTokenToCharge(Element parent, IPaymentMethod paymentMethod, BigDecimal amount) {
buildTokenToCharge(parent, paymentMethod, amount, null);
}
protected void buildTokenToCharge(Element parent, IPaymentMethod paymentMethod, BigDecimal amount, BigDecimal feeAmount) {
Element tokensToCharge = et.subElement(parent, "bdms:TokensToCharge");
Element tokenToCharge = et.subElement(tokensToCharge, "bdms:TokenToCharge");
et.subElement(tokenToCharge, "bdms:Amount", amount);
et.subElement(tokenToCharge, "bdms:CardProcessingMethod", getCardProcessingMethod(paymentMethod.getPaymentMethodType()));
et.subElement(tokenToCharge, "bdms:ExpectedFeeAmount", feeAmount);
if (paymentMethod instanceof eCheck) {
et.subElement(tokenToCharge, "bdms:ACHStandardEntryClass", ((eCheck) paymentMethod).getSecCode());
}
et.subElement(tokenToCharge, "bdms:Token", ((ITokenizable) paymentMethod).getToken());
}
///
/// Builds the BillPay transaction object
///
///
protected void buildTransaction(Element parent, AuthorizationBuilder builder) {
Element transaction = et.subElement(parent, "bdms:Transaction");
et.subElement(transaction, "bdms:Amount", builder.getAmount());
et.subElement(transaction, "bdms:FeeAmount", builder.getConvenienceAmount());
et.subElement(transaction, "bdms:MerchantInvoiceNumber", builder.getInvoiceNumber());
et.subElement(transaction, "bdms:MerchantTransactionDescription", builder.getDescription());
et.subElement(transaction, "bdms:MerchantTransactionID", builder.getClientTransactionId());
if (builder.getCustomer() == null) {
return;
}
Customer customer = builder.getCustomer();
et.subElement(transaction, "bdms:PayorEmailAddress", customer.getEmail());
et.subElement(transaction, "bdms:PayorFirstName", customer.getFirstName());
et.subElement(transaction, "bdms:PayorLastName", customer.getLastName());
et.subElement(transaction, "bdms:PayorPhoneNumber", customer.getHomePhone());
if (customer.getAddress() == null) {
return;
}
Address address = customer.getAddress();
et.subElement(transaction, "bdms:PayorAddress", address.getStreetAddress1());
et.subElement(transaction, "bdms:PayorCity", address.getCity());
et.subElement(transaction, "bdms:PayorCountry", address.getCountry());
et.subElement(transaction, "bdms:PayorPostalCode", address.getPostalCode());
et.subElement(transaction, "bdms:PayorState", address.getState());
}
protected void buildCustomer(Element parent, Customer customer) {
et.subElement(parent, "bdms:EmailAddress", customer.getEmail());
et.subElement(parent, "bdms:FirstName", customer.getFirstName());
et.subElement(parent, "bdms:LastName", customer.getLastName());
et.subElement(parent, "bdms:MerchantCustomerID", customer.getId()); // Should we create the guid or throw an error?
et.subElement(parent, "bdms:MobilePhone", customer.getMobilePhone());
et.subElement(parent, "bdms:Phone", customer.getHomePhone());
if (customer.getAddress() == null) {
return;
}
Address address = customer.getAddress();
et.subElement(parent, "bdms:Address", address.getStreetAddress1());
et.subElement(parent, "bdms:City", address.getCity());
et.subElement(parent, "bdms:Country", address.getCountry());
et.subElement(parent, "bdms:Postal", address.getPostalCode());
et.subElement(parent, "bdms:State", address.getState());
}
///
/// Validates that the AuthorizationBuilder is configured correctly for a Bill Payment
///
protected void validateTransaction(AuthorizationBuilder builder) throws BuilderException {
ArrayList validationErrors = new ArrayList<>();
if (builder.getBills() == null || builder.getBills().isEmpty()) {
validationErrors.add("Bill Payments must have at least one bill to pay.");
} else {
BigDecimal billSum = new BigDecimal(0);
for (Bill bill : builder.getBills()) {
billSum = billSum.add(bill.getAmount());
}
if (!builder.getAmount().equals(billSum)) {
validationErrors.add("The sum of the bill amounts must match the amount charged.");
}
}
if (!builder.getCurrency().equals("USD")) {
validationErrors.add("Bill Pay only supports currency USD.");
}
if (!validationErrors.isEmpty()) {
throwBuilderException(validationErrors);
}
}
protected void validateBills(List bills) throws BuilderException {
ArrayList validationErrors = new ArrayList<>();
if (bills == null || bills.isEmpty()) {
validationErrors.add("At least one Bill required to Load Bills.");
} else {
for (Bill bill : bills) {
int comparison = bill.getAmount().compareTo(new BigDecimal(0));
if (comparison <= 0) {
validationErrors.add("Bills require an amount greater than zero.");
break;
}
}
}
if (!validationErrors.isEmpty()) {
throwBuilderException(validationErrors);
}
}
protected void validateReversal(ManagementBuilder builder) throws BuilderException {
ArrayList validationErrors = new ArrayList<>();
if (!(builder.getPaymentMethod() instanceof TransactionReference) || StringUtils.isNullOrEmpty(((TransactionReference) builder.getPaymentMethod()).getTransactionId())) {
validationErrors.add("A transaction to reverse must be provided.");
} else {
if (Integer.parseInt(((TransactionReference) builder.getPaymentMethod()).getTransactionId()) < 1) {
validationErrors.add("The transaction id to reverse must be a positive integer.");
}
}
if (builder.getBills() != null && !builder.getBills().isEmpty()) {
BigDecimal billSum = new BigDecimal(0);
for (Bill bill : builder.getBills()) {
billSum = billSum.add(bill.getAmount());
}
if (!builder.getAmount().equals(billSum)) {
validationErrors.add("The sum of the bill amounts must match the amount to reverse.");
}
}
if (!validationErrors.isEmpty()) {
throwBuilderException(validationErrors);
}
}
protected void validateLoadSecurePay(HostedPaymentData hostedPaymentData) throws BuilderException {
ArrayList validationErrors = new ArrayList<>();
if (hostedPaymentData == null) {
validationErrors.add("HostedPaymentData Required");
} else {
if (hostedPaymentData.getBills() == null || hostedPaymentData.getBills().isEmpty()) {
validationErrors.add("At least one Bill required to Load Bills.");
} else {
for (Bill bill : hostedPaymentData.getBills()) {
int comparison = bill.getAmount().compareTo(new BigDecimal(0));
if (comparison <= 0) {
validationErrors.add("Bills require an amount greater than zero.");
break;
}
}
}
if (hostedPaymentData.getHostedPaymentType() == null || hostedPaymentData.getHostedPaymentType().equals(HostedPaymentType.NONE)) {
validationErrors.add("You must set a valid HostedPaymentType.");
}
}
if (!validationErrors.isEmpty()) {
throwBuilderException(validationErrors);
}
}
protected String getDateFormatted(Date date) {
// Override format/parse methods to handle differences in `X` and `Z` format identifiers
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") {
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
StringBuffer rfcFormat = super.format(date, toAppendTo, pos);
return rfcFormat.insert(rfcFormat.length() - 2, ":");
}
@Override
public Date parse(String text, ParsePosition pos) {
if (text.length() > 3) {
text = text.substring(0, text.length() - 3) + text.substring(text.length() - 2);
}
return super.parse(text, pos);
}
};
return dateFormat.format(date).replace("::", ":");
}
///
/// These methods are here to convert SDK enums
/// Into values that BillPay will recognize
///
///
///
protected String getBillPresentmentType(BillPresentment billPresentment) throws UnsupportedTransactionException {
switch (billPresentment) {
case FULL:
return "Full";
default:
throw new UnsupportedTransactionException(String.format("Bill Presentment Type of %s is not supported", billPresentment.getValue()));
}
}
protected String getDepositType(CheckType deposit) throws UnsupportedTransactionException {
switch (deposit) {
case Business:
return "Business";
case Personal:
return "Personal";
case Payroll:
default:
throw new UnsupportedTransactionException(String.format("eCheck Deposit Type of %s is not supported.", deposit.getValue()));
}
}
protected String getACHAccountType(AccountType accountType) throws UnsupportedTransactionException {
switch (accountType) {
case Checking:
return "Checking";
case Savings:
return "Savings";
default:
throw new UnsupportedTransactionException(String.format("eCheck Account Type of %s is not supported", accountType.getValue()));
}
}
protected String getCardProcessingMethod(PaymentMethodType paymentMethodType) {
switch (paymentMethodType) {
case Credit:
return "Credit";
case Debit:
return "Debit";
// Need to differentiate PINDebit
default:
return "Unassigned";
}
}
protected String getPaymentMethodType(PaymentMethodType paymentMethodType) throws UnsupportedTransactionException {
switch (paymentMethodType) {
case Credit:
return "Credit";
case Debit:
return "Debit";
case ACH:
return "ACH";
default:
throw new UnsupportedTransactionException();
}
}
protected String serializeBooleanValues(boolean value) {
return value ? "true" : "false";
}
protected void throwBuilderException(ArrayList messages) throws BuilderException {
StringBuilder messageBuilder = new StringBuilder();
for (String m: messages) {
messageBuilder.append(m + " ");
}
throw new BuilderException(messageBuilder.toString().trim());
}
protected void buildQuickPayCardToCharge(Element parent, CreditCardData card, BigDecimal amountToCharge, BigDecimal feeAmount, Address address) {
Element cardToCharge = et.subElement(parent, "bdms:QuickPayCardToCharge");
et.subElement(cardToCharge, "bdms:Amount", amountToCharge);
et.subElement(cardToCharge, "bdms:CardProcessingMethod", "Credit");
et.subElement(cardToCharge, "bdms:ExpectedFeeAmount", feeAmount);
Element cardHolder = et.subElement(cardToCharge, "pos:CardHolderData");
buildAccountHolderData(cardHolder,
address,
card.getCardHolderName());
et.subElement(cardToCharge, "bdms:ExpirationMonth", card.getExpMonth());
et.subElement(cardToCharge, "bdms:ExpirationYear", card.getExpYear());
et.subElement(cardToCharge, "bdms:QuickPayToken", card.getToken());
et.subElement(cardToCharge, "bdms:VerificationCode", card.getCvn());
}
protected void buildQuickPayACHAccountToCharge(Element parent, eCheck eCheck, BigDecimal amountToCharge, BigDecimal feeAmount) throws UnsupportedTransactionException {
Element achAccount = et.subElement(parent, "bdms:QuickPayACHAccountToCharge");
et.subElement(achAccount, "bdms:ACHStandardEntryClass", eCheck.getSecCode());
et.subElement(achAccount, "bdms:AccountType",getDepositType(eCheck.getCheckType()));
et.subElement(achAccount, "bdms:Amount", amountToCharge);
et.subElement(achAccount, "bdms:DepositType", getACHAccountType(eCheck.getAccountType()));
et.subElement(achAccount, "bdms:ExpectedFeeAmount", feeAmount);
et.subElement(achAccount, "bdms:PayorName", eCheck.getCheckHolderName());
et.subElement(achAccount, "bdms:QuickPayToken", eCheck.getToken());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy