in applications/accounting/src/main/java/org/apache/ofbiz/accounting/invoice/InvoiceServices.java [953:1189]
public static Map<String, Object> createCommissionInvoices(DispatchContext dctx, Map<String, Object> context) {
Delegator delegator = dctx.getDelegator();
LocalDispatcher dispatcher = dctx.getDispatcher();
GenericValue userLogin = (GenericValue) context.get("userLogin");
Locale locale = (Locale) context.get("locale");
List<String> salesInvoiceIds = UtilGenerics.cast(context.get("invoiceIds"));
List<Map<String, String>> invoicesCreated = new LinkedList<>();
Map<String, List<Map<String, Object>>> commissionParties = new HashMap<>();
for (String salesInvoiceId : salesInvoiceIds) {
List<String> salesRepPartyIds = UtilGenerics.cast(context.get("partyIds"));
BigDecimal amountTotal = InvoiceWorker.getInvoiceTotal(delegator, salesInvoiceId);
if (amountTotal.signum() == 0) {
Debug.logWarning("Invoice [" + salesInvoiceId + "] has an amount total of [" + amountTotal + "], so no commission invoice will be "
+ "created", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCommissionZeroInvoiceAmount", locale));
}
BigDecimal appliedFraction = amountTotal.divide(amountTotal, 12, ROUNDING);
GenericValue invoice = null;
boolean isReturn = false;
List<String> billFromVendorInvoiceRoles;
List<GenericValue> invoiceItems;
try {
List<EntityExpr> invoiceRoleConds = UtilMisc.toList(
EntityCondition.makeCondition("invoiceId", EntityOperator.EQUALS, salesInvoiceId),
EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, "BILL_FROM_VENDOR"));
EntityQuery roleQuery = EntityQuery.use(delegator).select("partyId").from("InvoiceRole").where(invoiceRoleConds);
billFromVendorInvoiceRoles = EntityUtil.getFieldListFromEntityList(roleQuery.queryList(), "partyId", true);
invoiceRoleConds = UtilMisc.toList(
EntityCondition.makeCondition("invoiceId", EntityOperator.EQUALS, salesInvoiceId),
EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, "SALES_REP"));
// if the receiving parties is empty then we will create commission invoices for all sales agent associated to sales invoice.
if (UtilValidate.isEmpty(salesRepPartyIds)) {
salesRepPartyIds = EntityUtil.getFieldListFromEntityList(roleQuery.where(invoiceRoleConds).queryList(), "partyId", true);
if (UtilValidate.isEmpty(salesRepPartyIds)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"No party found with role sales representative for sales invoice " + salesInvoiceId, locale));
}
} else {
List<String> salesInvoiceRolePartyIds = EntityUtil.getFieldListFromEntityList(roleQuery.where(invoiceRoleConds).queryList(),
"partyId", true);
if (UtilValidate.isNotEmpty(salesInvoiceRolePartyIds)) {
salesRepPartyIds = UtilGenerics.cast(CollectionUtils.intersection(salesRepPartyIds, salesInvoiceRolePartyIds));
}
}
invoice = EntityQuery.use(delegator).from("Invoice").where("invoiceId", salesInvoiceId).queryOne();
String invoiceTypeId = invoice.getString("invoiceTypeId");
if ("CUST_RTN_INVOICE".equals(invoiceTypeId)) {
isReturn = true;
} else if (!"SALES_INVOICE".equals(invoiceTypeId)) {
Debug.logWarning("This type of invoice has no commission; returning success", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCommissionInvalid", locale));
}
invoiceItems = EntityQuery.use(delegator).from("InvoiceItem").where("invoiceId", salesInvoiceId).queryList();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
// Map of commission Lists (of Maps) for each party.
// Determine commissions for various parties.
for (GenericValue invoiceItem : invoiceItems) {
BigDecimal amount = BigDecimal.ZERO;
BigDecimal quantity = invoiceItem.getBigDecimal("quantity");
amount = invoiceItem.getBigDecimal("amount");
amount = isReturn ? amount.negate() : amount;
String productId = invoiceItem.getString("productId");
String invoiceItemSeqId = invoiceItem.getString("invoiceItemSeqId");
String invoiceId = invoiceItem.getString("invoiceId");
// Determine commission parties for this invoiceItem
if (UtilValidate.isNotEmpty(productId)) {
Map<String, Object> resultMap = null;
try {
resultMap = dispatcher.runSync("getCommissionForProduct", UtilMisc.<String, Object>toMap(
"productId", productId,
"invoiceId", invoiceId,
"invoiceItemSeqId", invoiceItemSeqId,
"invoiceItemTypeId", invoiceItem.getString("invoiceItemTypeId"),
"amount", amount,
"quantity", quantity,
"userLogin", userLogin));
if (ServiceUtil.isError(resultMap)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(resultMap));
}
} catch (GenericServiceException e) {
return ServiceUtil.returnError(e.getMessage());
}
// build a Map of partyIds (both to and from) in a commission and the amounts
// Note that getCommissionForProduct returns a List of Maps with a lot values. See services.xml definition for reference.
List<Map<String, Object>> itemCommissions = UtilGenerics.cast(resultMap.get("commissions"));
if (UtilValidate.isNotEmpty(itemCommissions)) {
for (Map<String, Object> commissionMap : itemCommissions) {
commissionMap.put("invoice", invoice);
commissionMap.put("appliedFraction", appliedFraction);
if (!billFromVendorInvoiceRoles.contains(commissionMap.get("partyIdFrom"))
|| !salesRepPartyIds.contains(commissionMap.get("partyIdTo"))) {
continue;
}
String partyIdFromTo = (String) commissionMap.get("partyIdFrom") + (String) commissionMap.get("partyIdTo");
if (!commissionParties.containsKey(partyIdFromTo)) {
commissionParties.put(partyIdFromTo, UtilMisc.toList(commissionMap));
} else {
List<Map<String, Object>> commissionPartiesPartyIdFromTo = commissionParties.get(partyIdFromTo);
commissionPartiesPartyIdFromTo.add(commissionMap);
}
}
}
}
}
}
Timestamp now = UtilDateTime.nowTimestamp();
// Create invoice for each commission receiving party
for (Map.Entry<String, List<Map<String, Object>>> commissionParty : commissionParties.entrySet()) {
List<GenericValue> toStore = new LinkedList<>();
List<Map<String, Object>> commList = commissionParty.getValue();
// get the billing parties
if (UtilValidate.isEmpty(commList)) {
continue;
}
// From and To are reversed between commission and invoice
String partyIdBillTo = (String) (commList.get(0)).get("partyIdFrom");
String partyIdBillFrom = (String) (commList.get(0)).get("partyIdTo");
GenericValue invoice = (GenericValue) (commList.get(0)).get("invoice");
BigDecimal appliedFraction = (BigDecimal) (commList.get(0)).get("appliedFraction");
Long days = (Long) (commList.get(0)).get("days");
// create the invoice record
// To and From are in commission's sense, opposite for invoice
Map<String, Object> createInvoiceMap = new HashMap<>();
createInvoiceMap.put("partyId", partyIdBillTo);
createInvoiceMap.put("partyIdFrom", partyIdBillFrom);
createInvoiceMap.put("invoiceDate", now);
// if there were days associated with the commission agreement, then set a dueDate for the invoice.
if (days != null) {
createInvoiceMap.put("dueDate", UtilDateTime.getDayEnd(now, days));
}
createInvoiceMap.put("invoiceTypeId", "COMMISSION_INVOICE");
// start with INVOICE_IN_PROCESS, in the INVOICE_READY we can't change the invoice (or shouldn't be able to...)
createInvoiceMap.put("statusId", "INVOICE_IN_PROCESS");
createInvoiceMap.put("currencyUomId", invoice.getString("currencyUomId"));
createInvoiceMap.put("userLogin", userLogin);
// store the invoice first
Map<String, Object> createInvoiceResult;
try {
createInvoiceResult = dispatcher.runSync("createInvoice", createInvoiceMap);
if (ServiceUtil.isError(createInvoiceResult)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCommissionError", locale), null, null, null);
}
} catch (GenericServiceException e) {
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCommissionError", locale), null, null, null);
}
String invoiceId = (String) createInvoiceResult.get("invoiceId");
// create the bill-from (or pay-to) contact mech as the primary PAYMENT_LOCATION of the party from the store
GenericValue partyContactMechPurpose = null;
try {
partyContactMechPurpose = EntityQuery.use(delegator).from("PartyContactMechPurpose")
.where("partyId", partyIdBillTo, "contactMechPurposeTypeId", "BILLING_LOCATION").queryFirst();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (partyContactMechPurpose != null) {
GenericValue invoiceContactMech = delegator.makeValue("InvoiceContactMech", UtilMisc.toMap(
"invoiceId", invoiceId,
"contactMechId", partyContactMechPurpose.getString("contactMechId"),
"contactMechPurposeTypeId", "BILLING_LOCATION"));
toStore.add(invoiceContactMech);
}
try {
partyContactMechPurpose = EntityQuery.use(delegator).from("PartyContactMechPurpose")
.where("partyId", partyIdBillTo, "contactMechPurposeTypeId", "PAYMENT_LOCATION").queryFirst();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (partyContactMechPurpose != null) {
GenericValue invoiceContactMech = delegator.makeValue("InvoiceContactMech", UtilMisc.toMap(
"invoiceId", invoiceId,
"contactMechId", partyContactMechPurpose.getString("contactMechId"),
"contactMechPurposeTypeId", "PAYMENT_LOCATION"));
toStore.add(invoiceContactMech);
}
// create the item records
for (Map<String, Object> commissionMap : commList) {
BigDecimal elemAmount = ((BigDecimal) commissionMap.get("commission")).multiply(appliedFraction);
BigDecimal quantity = (BigDecimal) commissionMap.get("quantity");
String invoiceIdFrom = (String) commissionMap.get("invoiceId");
String invoiceItemSeqIdFrom = (String) commissionMap.get("invoiceItemSeqId");
elemAmount = elemAmount.setScale(DECIMALS, ROUNDING);
Map<String, Object> resMap = null;
try {
resMap = dispatcher.runSync("createInvoiceItem", UtilMisc.toMap("invoiceId", invoiceId,
"productId", commissionMap.get("productId"),
"invoiceItemTypeId", "COMM_INV_ITEM",
"quantity", quantity,
"amount", elemAmount,
"userLogin", userLogin));
if (ServiceUtil.isError(resMap)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCommissionErrorItem", locale), null, null, resMap);
}
resMap = dispatcher.runSync("createInvoiceItemAssoc", UtilMisc.toMap("invoiceIdFrom", invoiceIdFrom,
"invoiceItemSeqIdFrom", invoiceItemSeqIdFrom,
"invoiceIdTo", invoiceId,
"invoiceItemSeqIdTo", resMap.get("invoiceItemSeqId"),
"invoiceItemAssocTypeId", "COMMISSION_INVOICE",
"partyIdFrom", partyIdBillFrom,
"partyIdTo", partyIdBillTo,
"quantity", quantity,
"amount", elemAmount,
"userLogin", userLogin));
if (ServiceUtil.isError(resMap)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(resMap));
}
} catch (GenericServiceException e) {
return ServiceUtil.returnError(e.getMessage());
}
}
// store value objects
try {
delegator.storeAll(toStore);
} catch (GenericEntityException e) {
Debug.logError(e, "Entity/data problem creating commission invoice: " + e.toString(), MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RESOURCE,
"AccountingInvoiceCommissionEntityDataProblem",
UtilMisc.toMap("reason", e.toString()), locale));
}
invoicesCreated.add(UtilMisc.<String, String>toMap("commissionInvoiceId", invoiceId, "salesRepresentative ", partyIdBillFrom));
}
String invCreated = Integer.toString(invoicesCreated.size());
Map<String, Object> result = ServiceUtil.returnSuccess(UtilProperties.getMessage(RESOURCE,
"AccountingCommissionInvoicesCreated",
UtilMisc.toMap("invoicesCreated", invCreated), locale));
Debug.logInfo("Created Commission invoices for each commission receiving parties "
+ invCreated, MODULE);
result.put("invoicesCreated", invoicesCreated);
return result;
}