[OFBiz] SVN: r7786 - in trunk/applications/accounting: config servicedef src/org/ofbiz/accounting/agreement src/org/ofbiz/accounting/invoice
sichen@svn.ofbiz.org
sichen at svn.ofbiz.org
Tue Jun 13 11:16:03 CDT 2006
Author: sichen
Date: 2006-06-13 11:15:54 -0500 (Tue, 13 Jun 2006)
New Revision: 7786
Modified:
trunk/applications/accounting/config/AccountingUiLabels.properties
trunk/applications/accounting/servicedef/secas.xml
trunk/applications/accounting/servicedef/services_agreement.xml
trunk/applications/accounting/servicedef/services_invoice.xml
trunk/applications/accounting/src/org/ofbiz/accounting/agreement/AgreementServices.java
trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java
Log:
New code to create commissions invoices based on Agreements. From OFBIZ-853 by Vinay Agarwal
Modified: trunk/applications/accounting/config/AccountingUiLabels.properties
===================================================================
--- trunk/applications/accounting/config/AccountingUiLabels.properties 2006-06-13 16:14:36 UTC (rev 7785)
+++ trunk/applications/accounting/config/AccountingUiLabels.properties 2006-06-13 16:15:54 UTC (rev 7786)
@@ -538,7 +538,6 @@
AccountingInvoiceCommissionErrorItem=Error creating invoice item for commission invoice
AccountingInvoiceCommissionInvalid=This type of invoice has no commission, not creating commission invoice
AccountingInvoiceCommissionMultHeader=Multiple orders or returns, not handled.
-AccountingInvoiceCommissionNoHeader=No order or return header, not creating commission invoice
AccountingInvoiceCommissionNoItems=No order or return items, not creating commission invoice
AccountingInvoiceCommissionEntityDataProblem=Entity/data problem creating commission invoice: ${reason}
Modified: trunk/applications/accounting/servicedef/secas.xml
===================================================================
--- trunk/applications/accounting/servicedef/secas.xml 2006-06-13 16:14:36 UTC (rev 7785)
+++ trunk/applications/accounting/servicedef/secas.xml 2006-06-13 16:15:54 UTC (rev 7786)
@@ -30,7 +30,12 @@
<eca service="createPaymentApplication" event="commit">
<condition field-name="invoiceId" operator="is-not-empty"/>
<action service="checkInvoicePaymentApplications" mode="sync"/>
+ <action service="createCommissionInvoices" mode="sync"/>
</eca>
+ <eca service="createCommissionInvoices" event="commit">
+ <condition field-name="invoicesCreated" operator="is-not-empty"/>
+ <action service="readyInvoices" mode="sync"/>
+ </eca>
<eca service="createPartyPostalAddress" event="commit">
<condition field-name="paymentMethodId" operator="is-not-empty"/>
<action service="setPaymentMethodAddress" mode="sync"/>
Modified: trunk/applications/accounting/servicedef/services_agreement.xml
===================================================================
--- trunk/applications/accounting/servicedef/services_agreement.xml 2006-06-13 16:14:36 UTC (rev 7785)
+++ trunk/applications/accounting/servicedef/services_agreement.xml 2006-06-13 16:15:54 UTC (rev 7786)
@@ -105,17 +105,20 @@
</service>
<service name="getCommissionForProduct" engine="java"
location="org.ofbiz.accounting.agreement.AgreementServices" invoke="getCommissionForProduct" auth="true">
- <description>Get commission receiving parties and amounts for a product. Returns a List of Maps each containing <br/>
+ <description>Get commission receiving parties and amounts for a product. <br/>
+ amount input is for the entire quantity. <br/><br/>
+ Returns a List of Maps each containing <br/>
partyIdFrom String commission paying party <br/>
partyIdTo String commission receiving party <br/>
- amount BigDecimal Commission <br/>
+ commission BigDecimal Commission <br/>
days Long term days <br/>
currencyUomId String Currency <br/>
productId String Product Id <br/>
Will use the virtual product if no agreement is found for a variant product. If no quantity is specified, defaults to one (1).
</description>
<attribute name="productId" type="String" mode="IN" optional="false"/>
- <attribute name="price" type="BigDecimal" mode="IN" optional="false"/>
+ <attribute name="invoiceItemTypeId" type="String" mode="IN" optional="false"/>
+ <attribute name="amount" type="BigDecimal" mode="IN" optional="false"/>
<attribute name="quantity" type="BigDecimal" mode="IN" optional="true"/>
<attribute name="commissions" type="List" mode="OUT" optional="false"/>
</service>
Modified: trunk/applications/accounting/servicedef/services_invoice.xml
===================================================================
--- trunk/applications/accounting/servicedef/services_invoice.xml 2006-06-13 16:14:36 UTC (rev 7785)
+++ trunk/applications/accounting/servicedef/services_invoice.xml 2006-06-13 16:15:54 UTC (rev 7786)
@@ -166,6 +166,25 @@
<attribute name="shipmentReceiptsToBill" type="List" mode="IN" optional="false"/>
<attribute name="invoiceId" type="String" mode="OUT" optional="true"/>
</service>
+ <service name="createCommissionInvoices" engine="java"
+ location="org.ofbiz.accounting.invoice.InvoiceServices" invoke="createCommissionInvoices">
+ <description>
+ Create commission invoices from an order or return invoice. It
+ does not create any OrderItemBilling or ReturnItemBilling entities for partial commissions. Therefore, correct value
+ of the amountApplied needs to be supplied.
+ </description>
+ <attribute name="invoiceId" type="String" mode="IN" optional="false"/>
+ <attribute name="invoiceItemSeqId" type="String" mode="IN" optional="true"/>
+ <attribute name="amountApplied" type="Double" mode="IN" optional="false"/>
+ <attribute name="invoicesCreated" type="List" mode="OUT" optional="true"/>
+ </service>
+ <service name="readyInvoices" engine="java"
+ location="org.ofbiz.accounting.invoice.InvoiceServices" invoke="readyInvoices">
+ <description>
+ Sets status of each invoice in the list of invoices to INVOICE_READY.
+ </description>
+ <attribute name="invoicesCreated" type="List" mode="IN" optional="false"/>
+ </service>
<service name="createInvoicesFromShipment" engine="java"
location="org.ofbiz.accounting.invoice.InvoiceServices" invoke="createInvoicesFromShipment">
<description>
Modified: trunk/applications/accounting/src/org/ofbiz/accounting/agreement/AgreementServices.java
===================================================================
--- trunk/applications/accounting/src/org/ofbiz/accounting/agreement/AgreementServices.java 2006-06-13 16:14:36 UTC (rev 7785)
+++ trunk/applications/accounting/src/org/ofbiz/accounting/agreement/AgreementServices.java 2006-06-13 16:15:54 UTC (rev 7786)
@@ -66,13 +66,14 @@
* @param ctx The DispatchContext that this service is operating in.
* @param context Map containing the input parameters.
* productId String Product Id
- * price BigDecimal Price for entire quantity
+ * invoiceItemTypeId String Invoice Type
+ * amount BigDecimal Entire amount
* quantity BigDecimal Quantity
* @return Map with the result of the service, the output parameters.
* commissions List List of Maps each containing
* partyIdFrom String commission paying party
* partyIdTo String commission receiving party
- * amount BigDecimal Commission
+ * commission BigDecimal Commission
* days Long term days
* currencyUomId String Currency
* productId String Product Id
@@ -91,14 +92,15 @@
if (result.size() > 0)
return result;
try {
- BigDecimal price = ((BigDecimal)context.get("price"));
+ BigDecimal amount = ((BigDecimal)context.get("amount"));
BigDecimal quantity = (BigDecimal)context.get("quantity");
quantity = quantity == null ? new BigDecimal("1") : quantity;
- boolean negative = price.signum() < 0;
+ boolean negative = amount.signum() < 0;
// Ensure that price and quantity are positive since the terms may not be linear.
- price = price.abs();
+ amount = amount.abs();
quantity = quantity.abs();
String productId = (String) context.get("productId");
+ String invoiceItemTypeId = (String) context.get("invoiceItemTypeId");
// Collect agreementItems applicable to this orderItem/returnItem
// Use the view entity to reduce database access and cache to improve performance
List agreementItems = delegator.findByAndCache("AgreementItemAndProductAppl", UtilMisc.toMap(
@@ -122,48 +124,51 @@
GenericValue agreementItem = (GenericValue) it.next();
List terms = delegator.findByAndCache("AgreementTerm", UtilMisc.toMap(
"agreementId", agreementItem.getString("agreementId"),
- "agreementItemSeqId", agreementItem.getString("agreementItemSeqId")));
- BigDecimal commission = ZERO;
- BigDecimal min = new BigDecimal("-1e12"); // Limit to 1 trillion commission
- BigDecimal max = new BigDecimal("1e12");
- long days = 0;
- Iterator itt = terms.iterator();
- while (itt.hasNext()) {
- GenericValue elem = (GenericValue) itt.next();
- String termTypeId = elem.getString("termTypeId");
- BigDecimal termValue = elem.getBigDecimal("termValue");
- if (termValue != null) {
- if (termTypeId.equals("FIN_COMM_FIXED")) {
- commission = commission.add(termValue.multiply(quantity));
- } else if (termTypeId.equals("FIN_COMM_VARIABLE")) {
- // if variable percentage commission, need to divide by 100, because 5% is stored as termValue of 5.0
- commission = commission.add(termValue.multiply(price).divide(new BigDecimal("100"), 12, rounding));
- } else if (termTypeId.equals("FIN_COMM_MIN")) {
- min = termValue.multiply(quantity);
- } else if (termTypeId.equals("FIN_COMM_MAX")) {
- max = termValue.multiply(quantity);
+ "agreementItemSeqId", agreementItem.getString("agreementItemSeqId"),
+ "invoiceItemTypeId", invoiceItemTypeId));
+ if (terms.size() > 0) {
+ BigDecimal commission = ZERO;
+ BigDecimal min = new BigDecimal("-1e12"); // Limit to 1 trillion commission
+ BigDecimal max = new BigDecimal("1e12");
+ long days = 0;
+ Iterator itt = terms.iterator();
+ while (itt.hasNext()) {
+ GenericValue elem = (GenericValue) itt.next();
+ String termTypeId = elem.getString("termTypeId");
+ BigDecimal termValue = elem.getBigDecimal("termValue");
+ if (termValue != null) {
+ if (termTypeId.equals("FIN_COMM_FIXED")) {
+ commission = commission.add(termValue.multiply(quantity));
+ } else if (termTypeId.equals("FIN_COMM_VARIABLE")) {
+ // if variable percentage commission, need to divide by 100, because 5% is stored as termValue of 5.0
+ commission = commission.add(termValue.multiply(amount).divide(new BigDecimal("100"), 12, rounding));
+ } else if (termTypeId.equals("FIN_COMM_MIN")) {
+ min = termValue.multiply(quantity);
+ } else if (termTypeId.equals("FIN_COMM_MAX")) {
+ max = termValue.multiply(quantity);
+ }
+ // TODO: Add other type of terms and handling here
}
- // TODO: Add other type of terms and handling here
+ Long termDays = elem.getLong("termDays");
+ if (termDays != null) {
+ days = Math.min(days, termDays.longValue());
+ }
}
- Long termDays = elem.getLong("termDays");
- if (termDays != null) {
- days = Math.min(days, termDays.longValue());
- }
+ if (commission.compareTo(min) < 0)
+ commission = min;
+ if (commission.compareTo(max) > 0)
+ commission = max;
+ commission = negative ? commission.negate() : commission;
+ commission = commission.setScale(decimals, rounding);
+ days = Math.max(0, days);
+ commissions.add(UtilMisc.toMap(
+ "partyIdFrom", agreementItem.getString("partyIdFrom"),
+ "partyIdTo", agreementItem.getString("partyIdTo"),
+ "commission", commission,
+ "days", new Long(days),
+ "currencyUomId", agreementItem.getString("currencyUomId"),
+ "productId", productId));
}
- if (commission.compareTo(min) < 0)
- commission = min;
- if (commission.compareTo(max) > 0)
- commission = max;
- commission = negative ? commission.negate() : commission;
- commission = commission.setScale(decimals, rounding);
- days = Math.max(0, days);
- commissions.add(UtilMisc.toMap(
- "partyIdFrom", agreementItem.getString("partyIdFrom"),
- "partyIdTo", agreementItem.getString("partyIdTo"),
- "amount", commission,
- "days", new Long(days),
- "currencyUomId", agreementItem.getString("currencyUomId"),
- "productId", productId));
}
} catch (GenericEntityException e) {
Debug.logWarning(e, module);
Modified: trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java
===================================================================
--- trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java 2006-06-13 16:14:36 UTC (rev 7785)
+++ trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java 2006-06-13 16:15:54 UTC (rev 7786)
@@ -27,6 +27,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import javolution.util.FastList;
import javolution.util.FastMap;
@@ -45,11 +46,13 @@
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.condition.EntityOperator;
import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.util.EntityUtil;
import org.ofbiz.order.order.OrderReadHelper;
import org.ofbiz.product.product.ProductWorker;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.GenericServiceException;
import org.ofbiz.service.LocalDispatcher;
+import org.ofbiz.service.ModelService;
import org.ofbiz.service.ServiceUtil;
/**
@@ -627,7 +630,198 @@
return ServiceUtil.returnError(errMsg);
}
}
-
+
+ // Service for creating commission invoices
+ public static Map createCommissionInvoices(DispatchContext dctx, Map context) {
+ GenericDelegator delegator = dctx.getDelegator();
+ LocalDispatcher dispatcher = dctx.getDispatcher();
+ GenericValue userLogin = (GenericValue) context.get("userLogin");
+ Locale locale = (Locale) context.get("locale");
+ List invoicesCreated = FastList.newInstance();
+ // Determine order or return
+ String invoiceIdIn = (String) context.get("invoiceId");
+ String invoiceItemSeqIdIn = (String) context.get("invoiceItemSeqId");
+ BigDecimal amountTotal = InvoiceWorker.getInvoiceTotalBd(delegator, invoiceIdIn);
+
+ try {
+ // Change this when amountApplied is BigDecimal, 18 digit scale to keep all the precision
+ BigDecimal appliedFraction = new BigDecimal(((Double)context.get("amountApplied")).doubleValue()).divide(amountTotal, 12, rounding);
+ Map inMap = UtilMisc.toMap("invoiceId", invoiceIdIn);
+ GenericValue invoice = delegator.findByPrimaryKey("Invoice", inMap);
+ String invoiceTypeId = invoice.getString("invoiceTypeId");
+ boolean isReturn = false;
+ if ("SALES_INVOICE".equals(invoiceTypeId)) {
+ isReturn = false;
+ } else if ("CUST_RTN_INVOICE".equals(invoiceTypeId)) {
+ isReturn = true;
+ } else {
+ Debug.logVerbose("This type of invoice has no commission; returning success", module);
+ return ServiceUtil.returnSuccess(UtilProperties.getMessage(resource,"AccountingInvoiceCommissionInvalid",locale));
+ }
+
+ if (invoiceItemSeqIdIn != null) {
+ inMap.put("invoiceItemSeqId", invoiceItemSeqIdIn);
+ }
+ List invoiceItems = delegator.findByAnd("InvoiceItem", inMap);
+
+ // Map of commission Lists (of Maps) for each party
+ Map commissionParties = FastMap.newInstance();
+ // Determine commissions for various parties
+ Iterator itemIter = invoiceItems.iterator();
+ while (itemIter.hasNext()) {
+ GenericValue invoiceItem = (GenericValue) itemIter.next();
+ BigDecimal amount = ZERO;
+ BigDecimal quantity = ZERO;
+ quantity = invoiceItem.getBigDecimal("quantity");
+ amount = invoiceItem.getBigDecimal("amount");
+ amount = isReturn ? amount.negate() : amount;
+ String productId = invoiceItem.getString("productId");
+
+ // Determine commission parties for this invoiceItem
+ if (productId != null && productId.length() > 0) {
+ Map outMap = dispatcher.runSync("getCommissionForProduct", UtilMisc.toMap(
+ "productId", productId,
+ "invoiceItemTypeId", invoiceItem.getString("invoiceItemTypeId"),
+ "amount", amount,
+ "quantity", quantity,
+ "userLogin", userLogin));
+ if (ServiceUtil.isError(outMap)) {
+ return outMap;
+ }
+ List itemComms = (List) outMap.get("commissions");
+ if (itemComms != null && itemComms.size() > 0) {
+ Iterator it = itemComms.iterator();
+ while (it.hasNext()) {
+ Map commMap = (Map)it.next();
+ String partyIdFromTo = (String) commMap.get("partyIdFrom") + (String) commMap.get("partyIdTo");
+ if (!commissionParties.containsKey(partyIdFromTo)) {
+ commissionParties.put(partyIdFromTo, UtilMisc.toList(commMap));
+ } else {
+ ((List)commissionParties.get(partyIdFromTo)).add(commMap);
+ }
+ }
+ }
+ }
+ }
+
+ String invoiceType = "COMMISSION_INVOICE";
+ Timestamp now = UtilDateTime.nowTimestamp();
+
+ // Create invoice for each commission receiving party
+ Iterator it = commissionParties.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry pair = (Map.Entry)it.next();
+ List toStore = FastList.newInstance();
+ List commList = (List)pair.getValue();
+ // get the billing parties
+ // From and To are reversed between commission and invoice
+ if (commList == null || commList.size() == 0)
+ continue;
+ String partyIdBillTo = (String) ((Map)commList.get(0)).get("partyIdFrom");
+ String partyIdBillFrom = (String) ((Map)commList.get(0)).get("partyIdTo");
+ Long termDays = (Long) ((Map)commList.get(0)).get("termDays");
+ termDays = termDays == null ? new Long(0) : termDays;
+ Timestamp dueDate = UtilDateTime.getDayEnd(now, termDays.intValue());
+
+ // create the invoice record
+ // To and From are in commission's sense, opposite for invoice
+ Map createInvoiceContext = FastMap.newInstance();
+ createInvoiceContext.put("partyId", partyIdBillTo);
+ createInvoiceContext.put("partyIdFrom", partyIdBillFrom);
+ createInvoiceContext.put("invoiceDate", now);
+ createInvoiceContext.put("dueDate", dueDate);
+ createInvoiceContext.put("invoiceTypeId", invoiceType);
+ // start with INVOICE_IN_PROCESS, in the INVOICE_READY we can't change the invoice (or shouldn't be able to...)
+ createInvoiceContext.put("statusId", "INVOICE_IN_PROCESS");
+ createInvoiceContext.put("currencyUomId", invoice.getString("currencyUomId"));
+ createInvoiceContext.put("userLogin", userLogin);
+
+ // store the invoice first
+ Map createInvoiceResult = dispatcher.runSync("createInvoice", createInvoiceContext);
+ if (ServiceUtil.isError(createInvoiceResult)) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource,"AccountingInvoiceCommissionError",locale), null, null, createInvoiceResult);
+ }
+ 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
+ List contactMechs = delegator.findByAnd("PartyContactMechPurpose", UtilMisc.toMap("partyId", partyIdBillTo, "contactMechPurposeTypeId", "BILLING_LOCATION"));
+ if ((contactMechs != null) && (contactMechs.size() > 0)) {
+ GenericValue address = (GenericValue) contactMechs.get(0);
+ GenericValue payToCm = delegator.makeValue("InvoiceContactMech", UtilMisc.toMap(
+ "invoiceId", invoiceId,
+ "contactMechId", address.getString("contactMechId"),
+ "contactMechPurposeTypeId", "BILLING_LOCATION"));
+ toStore.add(payToCm);
+ }
+ contactMechs = delegator.findByAnd("PartyContactMechPurpose", UtilMisc.toMap("partyId", partyIdBillFrom, "contactMechPurposeTypeId", "PAYMENT_LOCATION"));
+ if ((contactMechs != null) && (contactMechs.size() > 0)) {
+ GenericValue address = (GenericValue) contactMechs.get(0);
+ GenericValue payToCm = delegator.makeValue("InvoiceContactMech", UtilMisc.toMap(
+ "invoiceId", invoiceId,
+ "contactMechId", address.getString("contactMechId"),
+ "contactMechPurposeTypeId", "PAYMENT_LOCATION"));
+ toStore.add(payToCm);
+ }
+
+ // create the item records
+ Iterator itt = commList.iterator();
+ while (itt.hasNext()) {
+ Map elem = (Map) itt.next();
+ BigDecimal elemAmount = ((BigDecimal)elem.get("commission")).multiply(appliedFraction);
+ elemAmount = elemAmount.setScale(decimals, rounding);
+ Map resMap = dispatcher.runSync("createInvoiceItem", UtilMisc.toMap(
+ "invoiceId", invoiceId,
+ "productId", elem.get("productId"),
+ "invoiceItemTypeId", "COMM_INV_ITEM",
+ "amount", new Double(elemAmount.doubleValue()),
+ "userLogin", userLogin));
+ if (ServiceUtil.isError(resMap)) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource,"AccountingInvoiceCommissionErrorItem",locale), null, null, resMap);
+ }
+ }
+ // store value objects
+ delegator.storeAll(toStore);
+ invoicesCreated.add(invoiceId);
+ }
+ Map resp = ServiceUtil.returnSuccess();
+ resp.put("invoicesCreated", invoicesCreated);
+ return resp;
+ } catch (GenericEntityException e) {
+ String errMsg = UtilProperties.getMessage(resource,"AccountingInvoiceCommissionEntityDataProblem",UtilMisc.toMap("reason",e.toString()),locale);
+ Debug.logError(e, errMsg, module);
+ return ServiceUtil.returnError(errMsg);
+ } catch (GenericServiceException e) {
+ String errMsg = UtilProperties.getMessage(resource,"AccountingInvoiceCommissionEntityDataProblem",UtilMisc.toMap("reason",e.toString()),locale);
+ Debug.logError(e, errMsg, module);
+ return ServiceUtil.returnError(errMsg);
+ }
+ }
+
+ public static Map readyInvoices(DispatchContext dctx, Map context) {
+ GenericDelegator delegator = dctx.getDelegator();
+ LocalDispatcher dispatcher = dctx.getDispatcher();
+ GenericValue userLogin = (GenericValue) context.get("userLogin");
+ Locale locale = (Locale) context.get("locale");
+ // Get invoices to make ready
+ List invoicesCreated = (List) context.get("invoicesCreated");
+ String nextStatusId = "INVOICE_READY";
+ Iterator it = invoicesCreated.iterator();
+ try {
+ while (it.hasNext()) {
+ String invoiceId = (String) it.next();
+ Map setInvoiceStatusResult = dispatcher.runSync("setInvoiceStatus", UtilMisc.toMap("invoiceId", invoiceId, "statusId", nextStatusId, "userLogin", userLogin));
+ if (ServiceUtil.isError(setInvoiceStatusResult)) {
+ return ServiceUtil.returnError(UtilProperties.getMessage(resource,"AccountingInvoiceCommissionError",locale), null, null, setInvoiceStatusResult);
+ }
+ }
+ } catch (GenericServiceException e) {
+ String errMsg = UtilProperties.getMessage(resource,"AccountingInvoiceCommissionEntityDataProblem",UtilMisc.toMap("reason",e.toString()),locale);
+ Debug.logError(e, errMsg, module);
+ return ServiceUtil.returnError(errMsg);
+ }
+ return ServiceUtil.returnSuccess();
+ }
+
public static Map createInvoicesFromShipment(DispatchContext dctx, Map context) {
//GenericDelegator delegator = dctx.getDelegator();
LocalDispatcher dispatcher = dctx.getDispatcher();
More information about the Svn
mailing list