public static Map createCommissionInvoices()

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;
    }