in applications/accounting/src/main/java/org/apache/ofbiz/accounting/invoice/InvoiceServices.java [2685:3479]
public static Map<String, Object> updatePaymentApplicationDefBd(DispatchContext dctx, Map<String, Object> context) {
Delegator delegator = dctx.getDelegator();
Locale locale = (Locale) context.get("locale");
if (DECIMALS == -1 || ROUNDING == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingAritmeticPropertiesNotConfigured", locale));
}
if (!context.containsKey("useHighestAmount")) {
context.put("useHighestAmount", "Y");
}
String defaultInvoiceProcessing = EntityUtilProperties.getPropertyValue("accounting", "invoiceProcessing", delegator);
boolean debug = true; // show processing messages in the log..or not....
// a 'y' in invoiceProssesing will reverse the default processing
String changeProcessing = (String) context.get("invoiceProcessing");
String invoiceId = (String) context.get("invoiceId");
String invoiceItemSeqId = (String) context.get("invoiceItemSeqId");
String paymentId = (String) context.get("paymentId");
String toPaymentId = (String) context.get("toPaymentId");
String paymentApplicationId = (String) context.get("paymentApplicationId");
BigDecimal amountApplied = (BigDecimal) context.get("amountApplied");
String billingAccountId = (String) context.get("billingAccountId");
String taxAuthGeoId = (String) context.get("taxAuthGeoId");
String useHighestAmount = (String) context.get("useHighestAmount");
List<String> errorMessageList = new LinkedList<>();
if (debug) {
Debug.logInfo("updatePaymentApplicationDefBd input parameters..."
+ " defaultInvoiceProcessing: " + defaultInvoiceProcessing
+ " changeDefaultInvoiceProcessing: " + changeProcessing
+ " useHighestAmount: " + useHighestAmount
+ " paymentApplicationId: " + paymentApplicationId
+ " PaymentId: " + paymentId
+ " InvoiceId: " + invoiceId
+ " InvoiceItemSeqId: " + invoiceItemSeqId
+ " BillingAccountId: " + billingAccountId
+ " toPaymentId: " + toPaymentId
+ " amountApplied: " + amountApplied
+ " TaxAuthGeoId: " + taxAuthGeoId, MODULE);
}
if (changeProcessing == null) {
changeProcessing = "N"; // not provided, so no change
}
boolean invoiceProcessing = true;
if ("YY".equals(defaultInvoiceProcessing)) {
invoiceProcessing = true;
} else if ("NN".equals(defaultInvoiceProcessing)) {
invoiceProcessing = false;
} else if ("Y".equals(defaultInvoiceProcessing)) {
invoiceProcessing = !"Y".equals(changeProcessing);
} else if ("N".equals(defaultInvoiceProcessing)) {
invoiceProcessing = "Y".equals(changeProcessing);
}
// on a new paymentApplication check if only billing or invoice or tax
// id is provided not 2,3... BUT a combination of billingAccountId and invoiceId is permitted - that's how you use a
// Billing Account to pay for an Invoice
if (paymentApplicationId == null) {
int count = 0;
if (invoiceId != null) {
count++;
}
if (toPaymentId != null) {
count++;
}
if (billingAccountId != null) {
count++;
}
if (taxAuthGeoId != null) {
count++;
}
if ((billingAccountId != null) && (invoiceId != null)) {
count--;
}
if (count != 1) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingSpecifyInvoiceToPaymentBillingAccountTaxGeoId", locale));
}
}
// avoid null pointer exceptions.
if (amountApplied == null) {
amountApplied = BigDecimal.ZERO;
}
// makes no sense to have an item numer without an invoice number
if (invoiceId == null) {
invoiceItemSeqId = null;
}
// retrieve all information and perform checking on the retrieved info.....
// Payment.....
BigDecimal paymentApplyAvailable = BigDecimal.ZERO;
// amount available on the payment reduced by the already applied amounts
GenericValue payment = null;
String currencyUomId = null;
if (paymentId == null || "".equals(paymentId)) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingPaymentIdBlankNotSupplied", locale));
} else {
try {
payment = EntityQuery.use(delegator).from("Payment").where("paymentId", paymentId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (payment == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentRecordNotFound", UtilMisc.toMap("paymentId", paymentId), locale));
return ServiceUtil.returnError(errorMessageList);
}
paymentApplyAvailable = payment.getBigDecimal("amount").subtract(PaymentWorker.getPaymentApplied(payment)).setScale(DECIMALS, ROUNDING);
if ("PMNT_CANCELLED".equals(payment.getString("statusId"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentCancelled", UtilMisc.toMap("paymentId", paymentId), locale));
}
if ("PMNT_CONFIRMED".equals(payment.getString("statusId"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentConfirmed", UtilMisc.toMap("paymentId", paymentId), locale));
}
currencyUomId = payment.getString("currencyUomId");
}
// the "TO" Payment.....
BigDecimal toPaymentApplyAvailable = BigDecimal.ZERO;
GenericValue toPayment = null;
if (toPaymentId != null && !"".equals(toPaymentId)) {
try {
toPayment = EntityQuery.use(delegator).from("Payment").where("paymentId", toPaymentId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (toPayment == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentRecordNotFound", UtilMisc.toMap("paymentId", toPaymentId), locale));
return ServiceUtil.returnError(errorMessageList);
}
toPaymentApplyAvailable = toPayment.getBigDecimal("amount").subtract(PaymentWorker.getPaymentApplied(toPayment)).setScale(DECIMALS,
ROUNDING);
if ("PMNT_CANCELLED".equals(toPayment.getString("statusId"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentCancelled", UtilMisc.toMap("paymentId", paymentId), locale));
}
if ("PMNT_CONFIRMED".equals(toPayment.getString("statusId"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentConfirmed", UtilMisc.toMap("paymentId", paymentId), locale));
}
if (paymentApplicationId == null) {
// only check for new application records, update on existing records is checked in the paymentApplication section
if (toPaymentApplyAvailable.signum() == 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentAlreadyApplied", UtilMisc.toMap("paymentId", toPaymentId), locale));
} else {
// check here for too much application if a new record is
// added (paymentApplicationId == null)
if (amountApplied.compareTo(toPaymentApplyAvailable) > 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentLessRequested",
UtilMisc.<String, Object>toMap("paymentId", toPaymentId,
"paymentApplyAvailable", toPaymentApplyAvailable,
"amountApplied", amountApplied, "isoCode", currencyUomId), locale));
}
}
}
// check if at least one send is the same as one receiver on the other payment
if (!payment.getString("partyIdFrom").equals(toPayment.getString("partyIdTo"))
&& !payment.getString("partyIdTo").equals(toPayment.getString("partyIdFrom"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingFromPartySameToParty", locale));
}
if (debug) {
Debug.logInfo("toPayment info retrieved and checked...", MODULE);
}
}
// assign payment to billing account if the invoice is assigned to this billing account
if (invoiceId != null) {
GenericValue invoice = null;
try {
invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (invoice == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceNotFound", UtilMisc.toMap("invoiceId", invoiceId), locale));
} else {
if (invoice.getString("billingAccountId") != null) {
billingAccountId = invoice.getString("billingAccountId");
}
}
}
// billing account
GenericValue billingAccount = null;
if (billingAccountId != null && !"".equals(billingAccountId)) {
try {
billingAccount = EntityQuery.use(delegator).from("BillingAccount").where("billingAccountId", billingAccountId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (billingAccount == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingBillingAccountNotFound", UtilMisc.toMap("billingAccountId", billingAccountId), locale));
return ServiceUtil.returnError(errorMessageList);
}
// check the currency
if (billingAccount.get("accountCurrencyUomId") != null && currencyUomId != null
&& !billingAccount.getString("accountCurrencyUomId").equals(currencyUomId)) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingBillingAccountCurrencyProblem",
UtilMisc.toMap("billingAccountId", billingAccountId,
"accountCurrencyUomId", billingAccount.getString("accountCurrencyUomId"),
"paymentId", paymentId, "paymentCurrencyUomId", currencyUomId), locale));
}
if (debug) {
Debug.logInfo("Billing Account info retrieved and checked...", MODULE);
}
}
// get the invoice (item) information
BigDecimal invoiceApplyAvailable = BigDecimal.ZERO;
// amount available on the invoice reduced by the already applied amounts
BigDecimal invoiceItemApplyAvailable = BigDecimal.ZERO;
// amount available on the invoiceItem reduced by the already applied amounts
GenericValue invoice = null;
GenericValue invoiceItem = null;
if (invoiceId != null) {
try {
invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", invoiceId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (invoice == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceNotFound", UtilMisc.toMap("invoiceId", invoiceId), locale));
} else { // check the invoice and when supplied the invoice item...
if ("INVOICE_CANCELLED".equals(invoice.getString("statusId"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCancelledCannotApplyTo", UtilMisc.toMap("invoiceId", invoiceId), locale));
}
// check the currency
if (currencyUomId != null && invoice.get("currencyUomId") != null
&& !currencyUomId.equals(invoice.getString("currencyUomId"))) {
Debug.logInfo(UtilProperties.getMessage(RESOURCE, "AccountingInvoicePaymentCurrencyProblem",
UtilMisc.toMap("invoiceCurrency", invoice.getString("currencyUomId"), "paymentCurrency", payment.getString(
"currencyUomId")), locale), MODULE);
Debug.logInfo("will try to apply payment on the actualCurrency amount on payment", MODULE);
if (payment.get("actualCurrencyAmount") == null || payment.get("actualCurrencyUomId") == null) {
errorMessageList.add("Actual amounts are required in the currency of the invoice to make this work....");
} else {
currencyUomId = payment.getString("actualCurrencyUomId");
if (!currencyUomId.equals(invoice.getString("currencyUomId"))) {
errorMessageList.add("actual currency on payment (" + currencyUomId + ") not the same as original invoice currency ("
+ invoice.getString("currencyUomId") + ")");
}
}
paymentApplyAvailable =
payment.getBigDecimal("actualCurrencyAmount").subtract(PaymentWorker.getPaymentApplied(payment))
.setScale(DECIMALS, ROUNDING);
}
// check if the invoice already covered by payments
BigDecimal invoiceTotal = InvoiceWorker.getInvoiceTotal(invoice);
invoiceApplyAvailable = InvoiceWorker.getInvoiceNotApplied(invoice);
if (invoiceTotal.signum() == 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceTotalZero", UtilMisc.toMap("invoiceId", invoiceId), locale));
} else if (paymentApplicationId == null) {
// only check for new records here...updates are checked in the paymentApplication section
if (invoiceApplyAvailable.signum() == 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCompletelyApplied", UtilMisc.toMap("invoiceId", invoiceId), locale));
// check here for too much application if a new record(s) are
// added (paymentApplicationId == null)
} else if (amountApplied.compareTo(invoiceApplyAvailable) > 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingInvoiceLessRequested",
UtilMisc.<String, Object>toMap("invoiceId", invoiceId,
"invoiceApplyAvailable", invoiceApplyAvailable,
"amountApplied", amountApplied,
"isoCode", invoice.getString("currencyUomId")), locale));
}
}
// check if at least one sender is the same as one receiver on the invoice
if (!payment.getString("partyIdFrom").equals(invoice.getString("partyId"))
&& !payment.getString("partyIdTo").equals(invoice.getString("partyIdFrom"))) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingFromPartySameToParty", locale));
}
if (debug) {
Debug.logInfo("Invoice info retrieved and checked ...", MODULE);
}
}
// if provided check the invoice item.
if (invoiceItemSeqId != null) {
// when itemSeqNr not provided delay checking on invoiceItemSeqId
try {
invoiceItem = EntityQuery.use(delegator).from("InvoiceItem").where("invoiceId", invoiceId, "invoiceItemSeqId",
invoiceItemSeqId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (invoiceItem == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceItemNotFound",
UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId), locale));
} else {
if (invoice.get("currencyUomId") != null && currencyUomId != null && !invoice.getString("currencyUomId").equals(currencyUomId)) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoicePaymentCurrencyProblem",
UtilMisc.toMap("paymentCurrencyId", currencyUomId,
"itemCurrency", invoice.getString("currencyUomId")), locale));
}
// get the invoice item applied value
BigDecimal quantity = null;
if (invoiceItem.get("quantity") == null) {
quantity = BigDecimal.ONE;
} else {
quantity = invoiceItem.getBigDecimal("quantity").setScale(DECIMALS, ROUNDING);
}
invoiceItemApplyAvailable =
invoiceItem.getBigDecimal("amount").multiply(quantity).setScale(DECIMALS, ROUNDING)
.subtract(InvoiceWorker.getInvoiceItemApplied(invoiceItem));
// check here for too much application if a new record is added
if (paymentApplicationId == null && amountApplied.compareTo(invoiceItemApplyAvailable) > 0) {
// new record
errorMessageList.add("Invoice(" + invoiceId + ") item(" + invoiceItemSeqId + ") has " + invoiceItemApplyAvailable + " to "
+ "apply but " + amountApplied + " is requested\n");
String uomId = invoice.getString("currencyUomId");
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingInvoiceItemLessRequested",
UtilMisc.<String, Object>toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId,
"invoiceItemApplyAvailable", invoiceItemApplyAvailable,
"amountApplied", amountApplied, "isoCode", uomId), locale));
}
}
if (debug) {
Debug.logInfo("InvoiceItem info retrieved and checked against the Invoice (currency and amounts) ...", MODULE);
}
}
}
// check this at the end because the invoice can change the currency.......
if (paymentApplicationId == null) {
// only check for new application records, update on existing records is checked in the paymentApplication section
if (paymentApplyAvailable.signum() == 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentAlreadyApplied", UtilMisc.toMap("paymentId", paymentId), locale));
} else {
// check here for too much application if a new record is
// added (paymentApplicationId == null)
if (amountApplied.compareTo(paymentApplyAvailable) > 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingPaymentLessRequested",
UtilMisc.<String, Object>toMap("paymentId", paymentId,
"paymentApplyAvailable", paymentApplyAvailable,
"amountApplied", amountApplied, "isoCode", currencyUomId), locale));
}
}
}
// get the application record if the applicationId is supplied if not
// create empty record.
BigDecimal newInvoiceApplyAvailable = invoiceApplyAvailable;
// amount available on the invoice taking into account if the invoiceItemnumber has changed
BigDecimal newInvoiceItemApplyAvailable = invoiceItemApplyAvailable;
// amount available on the invoiceItem taking into account if the itemnumber has changed
BigDecimal newToPaymentApplyAvailable = toPaymentApplyAvailable;
BigDecimal newPaymentApplyAvailable = paymentApplyAvailable;
GenericValue paymentApplication = null;
if (paymentApplicationId == null) {
paymentApplication = delegator.makeValue("PaymentApplication");
// prepare for creation
} else { // retrieve existing paymentApplication
try {
paymentApplication =
EntityQuery.use(delegator).from("PaymentApplication").where("paymentApplicationId", paymentApplicationId).queryOne();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (paymentApplication == null) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentApplicationNotFound",
UtilMisc.toMap("paymentApplicationId", paymentApplicationId), locale));
paymentApplicationId = null;
} else {
// if both invoiceId and BillingId is entered there was
// obviously a change
// only take the newly entered item, same for tax authority and toPayment
if (paymentApplication.get("invoiceId") == null && invoiceId != null) {
billingAccountId = null;
taxAuthGeoId = null;
toPaymentId = null;
} else if (paymentApplication.get("toPaymentId") == null && toPaymentId != null) {
invoiceId = null;
invoiceItemSeqId = null;
taxAuthGeoId = null;
billingAccountId = null;
} else if (paymentApplication.get("billingAccountId") == null && billingAccountId != null) {
invoiceId = null;
invoiceItemSeqId = null;
toPaymentId = null;
taxAuthGeoId = null;
} else if (paymentApplication.get("taxAuthGeoId") == null && taxAuthGeoId != null) {
invoiceId = null;
invoiceItemSeqId = null;
toPaymentId = null;
billingAccountId = null;
}
// check if the payment for too much application if an existing
// application record is changed
if (paymentApplyAvailable.compareTo(BigDecimal.ZERO) == 0) {
newPaymentApplyAvailable =
paymentApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied).setScale(DECIMALS,
ROUNDING);
} else {
newPaymentApplyAvailable = paymentApplyAvailable.add(paymentApplyAvailable).subtract(amountApplied).setScale(DECIMALS, ROUNDING);
}
if (newPaymentApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentNotEnough",
UtilMisc.<String, Object>toMap("paymentId", paymentId,
"paymentApplyAvailable", paymentApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied")),
"amountApplied", amountApplied), locale));
}
if (invoiceId != null) {
// only when we are processing an invoice on existing paymentApplication check invoice item for to much application if the invoice
// number did not change
if (invoiceId.equals(paymentApplication.getString("invoiceId"))) {
// check if both the itemNumbers are null then this is a
// record for the whole invoice
if (invoiceItemSeqId == null && paymentApplication.get("invoiceItemSeqId") == null) {
newInvoiceApplyAvailable =
invoiceApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied")).subtract(amountApplied)
.setScale(DECIMALS, ROUNDING);
if (invoiceApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceNotEnough",
UtilMisc.<String, Object>toMap("tooMuch", newInvoiceApplyAvailable.negate(),
"invoiceId", invoiceId), locale));
}
} else if (invoiceItemSeqId == null && paymentApplication.get("invoiceItemSeqId") != null) {
// check if the item number changed from a real Item number to a null value
newInvoiceApplyAvailable =
invoiceApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied"))
.subtract(amountApplied).setScale(DECIMALS, ROUNDING);
if (invoiceApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceNotEnough",
UtilMisc.<String, Object>toMap("tooMuch", newInvoiceApplyAvailable.negate(),
"invoiceId", invoiceId), locale));
}
} else if (paymentApplication.get("invoiceItemSeqId") == null) {
// check if the item number changed from a null value to
// a real Item number
newInvoiceItemApplyAvailable = invoiceItemApplyAvailable.subtract(amountApplied).setScale(DECIMALS, ROUNDING);
if (newInvoiceItemApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingItemInvoiceNotEnough",
UtilMisc.<String, Object>toMap("tooMuch", newInvoiceItemApplyAvailable.negate(),
"invoiceId", invoiceId,
"invoiceItemSeqId", invoiceItemSeqId), locale));
}
} else if (invoiceItemSeqId.equals(paymentApplication.getString("invoiceItemSeqId"))) {
// check if the real item numbers the same
// item number the same numeric value
newInvoiceItemApplyAvailable =
invoiceItemApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied"))
.subtract(amountApplied).setScale(DECIMALS, ROUNDING);
if (newInvoiceItemApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingItemInvoiceNotEnough",
UtilMisc.<String, Object>toMap("tooMuch", newInvoiceItemApplyAvailable.negate(),
"invoiceId", invoiceId,
"invoiceItemSeqId", invoiceItemSeqId), locale));
}
} else {
// item number changed only check new item
newInvoiceItemApplyAvailable = invoiceItemApplyAvailable.add(amountApplied).setScale(DECIMALS, ROUNDING);
if (newInvoiceItemApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingItemInvoiceNotEnough",
UtilMisc.<String, Object>toMap("tooMuch", newInvoiceItemApplyAvailable.negate(),
"invoiceId", invoiceId,
"invoiceItemSeqId", invoiceItemSeqId), locale));
}
}
// if the amountApplied = 0 give it the higest possible
// value
if (amountApplied.signum() == 0) {
if (newInvoiceItemApplyAvailable.compareTo(newPaymentApplyAvailable) < 0) {
amountApplied = newInvoiceItemApplyAvailable;
// from the item number
} else {
amountApplied = newPaymentApplyAvailable;
// from the payment
}
}
// check the invoice
newInvoiceApplyAvailable =
invoiceApplyAvailable.add(paymentApplication.getBigDecimal("amountApplied")
.subtract(amountApplied)).setScale(DECIMALS, ROUNDING);
if (newInvoiceApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceNotEnough",
UtilMisc.<String, Object>toMap("tooMuch", invoiceApplyAvailable.add(paymentApplication.getBigDecimal(
"amountApplied")).subtract(amountApplied),
"invoiceId", invoiceId), locale));
}
}
}
// check the toPayment account when only the amountApplied has
// changed,
if (toPaymentId != null && toPaymentId.equals(paymentApplication.getString("toPaymentId"))) {
newToPaymentApplyAvailable =
toPaymentApplyAvailable.subtract(paymentApplication.getBigDecimal("amountApplied"))
.add(amountApplied).setScale(DECIMALS, ROUNDING);
if (newToPaymentApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentNotEnough",
UtilMisc.<String, Object>toMap("paymentId", toPaymentId,
"paymentApplyAvailable", newToPaymentApplyAvailable,
"amountApplied", amountApplied), locale));
}
} else if (toPaymentId != null) {
// billing account entered number has changed so we have to
// check the new billing account number.
newToPaymentApplyAvailable = toPaymentApplyAvailable.add(amountApplied).setScale(DECIMALS, ROUNDING);
if (newToPaymentApplyAvailable.compareTo(BigDecimal.ZERO) < 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE,
"AccountingPaymentNotEnough",
UtilMisc.<String, Object>toMap("paymentId", toPaymentId,
"paymentApplyAvailable", newToPaymentApplyAvailable,
"amountApplied", amountApplied), locale));
}
}
}
if (debug) {
Debug.logInfo("paymentApplication record info retrieved and checked...", MODULE);
}
}
// show the maximumus what can be added in the payment application file.
String toMessage = null; // prepare for success message
if (debug) {
String extra = "";
if (invoiceItemSeqId != null) {
extra = " Invoice item(" + invoiceItemSeqId + ") amount not yet applied: " + newInvoiceItemApplyAvailable;
}
Debug.logInfo("checking finished, start processing with the following data... ", MODULE);
if (invoiceId != null) {
Debug.logInfo(" Invoice(" + invoiceId + ") amount not yet applied: " + newInvoiceApplyAvailable + extra + " Payment("
+ paymentId + ") amount not yet applied: " + newPaymentApplyAvailable + " Requested amount to apply:" + amountApplied,
MODULE);
toMessage = UtilProperties.getMessage(RESOURCE,
"AccountingApplicationToInvoice",
UtilMisc.toMap("invoiceId", invoiceId), locale);
if (!extra.isEmpty()) {
toMessage = UtilProperties.getMessage(RESOURCE,
"AccountingApplicationToInvoiceItem",
UtilMisc.toMap("invoiceId", invoiceId, "invoiceItemSeqId", invoiceItemSeqId), locale);
}
}
if (toPaymentId != null) {
Debug.logInfo(" toPayment(" + toPaymentId + ") amount not yet applied: " + newToPaymentApplyAvailable + " Payment(" + paymentId
+ ") amount not yet applied: " + newPaymentApplyAvailable + " Requested amount to apply:" + amountApplied, MODULE);
toMessage = UtilProperties.getMessage(RESOURCE,
"AccountingApplicationToPayment",
UtilMisc.toMap("paymentId", toPaymentId), locale);
}
if (taxAuthGeoId != null) {
Debug.logInfo(" taxAuthGeoId(" + taxAuthGeoId + ") Payment(" + paymentId + ") amount not yet applied: " + newPaymentApplyAvailable
+ " Requested amount to apply:" + amountApplied, MODULE);
toMessage = UtilProperties.getMessage(RESOURCE,
"AccountingApplicationToTax",
UtilMisc.toMap("taxAuthGeoId", taxAuthGeoId), locale);
}
}
// if the amount to apply was not provided or was zero fill it with the maximum possible and provide information to the user
if (amountApplied.signum() == 0 && "Y".equals(useHighestAmount)) {
amountApplied = newPaymentApplyAvailable;
if (invoiceId != null && newInvoiceApplyAvailable.compareTo(amountApplied) < 0) {
amountApplied = newInvoiceApplyAvailable;
toMessage = UtilProperties.getMessage(RESOURCE,
"AccountingApplicationToInvoice",
UtilMisc.toMap("invoiceId", invoiceId), locale);
}
if (toPaymentId != null && newToPaymentApplyAvailable.compareTo(amountApplied) < 0) {
amountApplied = newToPaymentApplyAvailable;
toMessage = UtilProperties.getMessage(RESOURCE,
"AccountingApplicationToPayment",
UtilMisc.toMap("paymentId", toPaymentId), locale);
}
}
String successMessage = null;
if (amountApplied.signum() == 0) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingNoAmount", locale));
} else {
successMessage = UtilProperties.getMessage(RESOURCE,
"AccountingPaymentApplicationSuccess",
UtilMisc.<String, Object>toMap("amountApplied", amountApplied,
"paymentId", paymentId,
"isoCode", currencyUomId,
"toMessage", toMessage), locale);
}
// report error messages if any
if (!errorMessageList.isEmpty()) {
return ServiceUtil.returnError(errorMessageList);
}
// ============ start processing ======================
// if the application is specified it is easy, update the existing record only
if (paymentApplicationId != null) {
// record is already retrieved previously
if (debug) {
Debug.logInfo("Process an existing paymentApplication record: " + paymentApplicationId, MODULE);
}
// update the current record
paymentApplication.set("invoiceId", invoiceId);
paymentApplication.set("invoiceItemSeqId", invoiceItemSeqId);
paymentApplication.set("paymentId", paymentId);
paymentApplication.set("toPaymentId", toPaymentId);
paymentApplication.set("amountApplied", amountApplied);
paymentApplication.set("billingAccountId", billingAccountId);
paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
return storePaymentApplication(delegator, paymentApplication, locale);
}
// if no invoice sequence number is provided it assumed the requested paymentAmount will be
// spread over the invoice starting with the lowest sequence number if
// itemprocessing is on otherwise create one record
if (invoiceId != null && paymentId != null && (invoiceItemSeqId == null)) {
if (invoiceProcessing) {
// create only a single record with a null seqId
if (debug) {
Debug.logInfo("Try to allocate the payment to the invoice as a whole", MODULE);
}
paymentApplication.set("paymentId", paymentId);
paymentApplication.set("toPaymentId", null);
paymentApplication.set("invoiceId", invoiceId);
paymentApplication.set("invoiceItemSeqId", null);
paymentApplication.set("toPaymentId", null);
paymentApplication.set("amountApplied", amountApplied);
paymentApplication.set("billingAccountId", billingAccountId);
paymentApplication.set("taxAuthGeoId", null);
if (debug) {
Debug.logInfo("creating new paymentapplication", MODULE);
}
return storePaymentApplication(delegator, paymentApplication, locale);
}
if (debug) {
Debug.logInfo("Try to allocate the payment to the itemnumbers of the invoice", MODULE);
}
// get the invoice items
List<GenericValue> invoiceItems = null;
try {
invoiceItems = EntityQuery.use(delegator).from("InvoiceItem").where("invoiceId", invoiceId).queryList();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (invoiceItems.isEmpty()) {
errorMessageList.add(UtilProperties.getMessage(RESOURCE, "AccountingNoInvoiceItemsFoundForInvoice", UtilMisc.toMap("invoiceId",
invoiceId), locale));
return ServiceUtil.returnError(errorMessageList);
}
// check if the user want to apply a smaller amount than the maximum possible on the payment
if (amountApplied.signum() != 0 && amountApplied.compareTo(paymentApplyAvailable) < 0) {
paymentApplyAvailable = amountApplied;
}
for (GenericValue currentInvoiceItem : invoiceItems) {
if (paymentApplyAvailable.compareTo(BigDecimal.ZERO) > 0) {
break;
}
if (debug) {
Debug.logInfo("Start processing item: " + currentInvoiceItem.getString("invoiceItemSeqId"), MODULE);
}
BigDecimal itemQuantity = BigDecimal.ONE;
if (currentInvoiceItem.get("quantity") != null && currentInvoiceItem.getBigDecimal("quantity").signum() != 0) {
itemQuantity = new BigDecimal(currentInvoiceItem.getString("quantity")).setScale(DECIMALS, ROUNDING);
}
BigDecimal itemAmount = currentInvoiceItem.getBigDecimal("amount").setScale(DECIMALS, ROUNDING);
BigDecimal itemTotal = itemAmount.multiply(itemQuantity).setScale(DECIMALS, ROUNDING);
// get the application(s) already allocated to this
// item, if available
List<GenericValue> paymentApplications = null;
try {
paymentApplications = currentInvoiceItem.getRelated("PaymentApplication", null, null, false);
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
BigDecimal tobeApplied = BigDecimal.ZERO;
// item total amount - already applied (if any)
BigDecimal alreadyApplied = BigDecimal.ZERO;
if (UtilValidate.isNotEmpty(paymentApplications)) {
// application(s) found, add them all together
Iterator<GenericValue> p = paymentApplications.iterator();
while (p.hasNext()) {
paymentApplication = p.next();
alreadyApplied = alreadyApplied.add(paymentApplication.getBigDecimal("amountApplied").setScale(DECIMALS, ROUNDING));
}
tobeApplied = itemTotal.subtract(alreadyApplied).setScale(DECIMALS, ROUNDING);
} else {
// no application connected yet
tobeApplied = itemTotal;
}
if (debug) {
Debug.logInfo("tobeApplied:(" + tobeApplied + ") = " + "itemTotal(" + itemTotal + ") - alreadyApplied(" + alreadyApplied + ") "
+ "but not more then (nonapplied) paymentAmount(" + paymentApplyAvailable + ")", MODULE);
}
if (tobeApplied.signum() == 0) {
// invoiceItem already fully applied so look at the next one....
continue;
}
if (paymentApplyAvailable.compareTo(tobeApplied) > 0) {
paymentApplyAvailable = paymentApplyAvailable.subtract(tobeApplied);
} else {
tobeApplied = paymentApplyAvailable;
paymentApplyAvailable = BigDecimal.ZERO;
}
// create application payment record but check currency
// first if supplied
if (invoice.get("currencyUomId") != null && currencyUomId != null && !invoice.getString("currencyUomId").equals(currencyUomId)) {
errorMessageList.add("Payment currency (" + currencyUomId + ") and invoice currency(" + invoice.getString("currencyUomId") + ")"
+ " not the same\n");
} else {
paymentApplication.set("paymentApplicationId", null);
// make sure we get a new record
paymentApplication.set("invoiceId", invoiceId);
paymentApplication.set("invoiceItemSeqId", currentInvoiceItem.getString("invoiceItemSeqId"));
paymentApplication.set("paymentId", paymentId);
paymentApplication.set("toPaymentId", toPaymentId);
paymentApplication.set("amountApplied", tobeApplied);
paymentApplication.set("billingAccountId", billingAccountId);
paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
storePaymentApplication(delegator, paymentApplication, locale);
}
}
if (!errorMessageList.isEmpty()) {
return ServiceUtil.returnError(errorMessageList);
}
if (successMessage != null) {
return ServiceUtil.returnSuccess(successMessage);
}
return ServiceUtil.returnSuccess();
}
// if no paymentApplicationId supplied create a new record with the data
// supplied...
paymentApplication.set("paymentApplicationId", paymentApplicationId);
paymentApplication.set("invoiceId", invoiceId);
paymentApplication.set("invoiceItemSeqId", invoiceItemSeqId);
paymentApplication.set("paymentId", paymentId);
paymentApplication.set("toPaymentId", toPaymentId);
paymentApplication.set("amountApplied", amountApplied);
paymentApplication.set("billingAccountId", billingAccountId);
paymentApplication.set("taxAuthGeoId", taxAuthGeoId);
return storePaymentApplication(delegator, paymentApplication, locale);
}