001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.accounting.agreement;
019:
020: import java.math.BigDecimal;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Locale;
024: import java.util.Map;
025: import javolution.util.FastList;
026: import javolution.util.FastMap;
027: import org.ofbiz.base.util.Debug;
028: import org.ofbiz.base.util.UtilMisc;
029: import org.ofbiz.base.util.UtilNumber;
030: import org.ofbiz.base.util.UtilProperties;
031: import org.ofbiz.entity.GenericDelegator;
032: import org.ofbiz.entity.GenericEntity;
033: import org.ofbiz.entity.GenericEntityException;
034: import org.ofbiz.entity.GenericValue;
035: import org.ofbiz.entity.util.EntityUtil;
036: import org.ofbiz.security.Security;
037: import org.ofbiz.service.DispatchContext;
038: import org.ofbiz.service.ModelService;
039: import org.ofbiz.service.ServiceUtil;
040:
041: /**
042: * Services for Agreement (Accounting)
043: */
044:
045: public class AgreementServices {
046:
047: public static final String module = AgreementServices.class
048: .getName();
049: // set some BigDecimal properties
050: private static BigDecimal ZERO = new BigDecimal("0");
051: private static int decimals = -1;
052: private static int rounding = -1;
053: static {
054: decimals = UtilNumber.getBigDecimalScale("invoice.decimals");
055: rounding = UtilNumber
056: .getBigDecimalRoundingMode("invoice.rounding");
057:
058: // set zero to the proper scale
059: if (decimals != -1)
060: ZERO = ZERO.setScale(decimals, rounding);
061: }
062: public static final String resource = "AccountingUiLabels";
063:
064: /**
065: * Determines commission receiving parties and amounts for the provided product, price, and quantity
066: * @param ctx The DispatchContext that this service is operating in.
067: * @param context Map containing the input parameters.
068: * productId String Product Id
069: * invoiceItemTypeId String Invoice Type
070: * amount BigDecimal Entire amount
071: * quantity BigDecimal Quantity
072: * @return Map with the result of the service, the output parameters.
073: * commissions List List of Maps each containing
074: * partyIdFrom String commission paying party
075: * partyIdTo String commission receiving party
076: * commission BigDecimal Commission
077: * days Long term days
078: * currencyUomId String Currency
079: * productId String Product Id
080: */
081: public static Map getCommissionForProduct(DispatchContext ctx,
082: Map context) {
083: Map result = FastMap.newInstance();
084: GenericDelegator delegator = ctx.getDelegator();
085: Security security = ctx.getSecurity();
086: GenericValue userLogin = (GenericValue) context
087: .get("userLogin");
088: Locale locale = (Locale) context.get("locale");
089: String errMsg = null;
090: List commissions = FastList.newInstance();
091:
092: // either ACCOUNTING_COMM_VIEW or ACCOUNTING_MANAGER should be allowed to see commission amounts
093: if (!security.hasEntityPermission("ACCOUNTING", "_COMM_VIEW",
094: userLogin)) {
095: result.put(ModelService.RESPONSE_MESSAGE,
096: ModelService.RESPOND_ERROR);
097: errMsg = UtilProperties.getMessage(ServiceUtil.resource,
098: "serviceUtil.no_permission_to_operation", locale)
099: + ".";
100: result.put(ModelService.ERROR_MESSAGE, errMsg);
101: return result;
102: }
103: try {
104: BigDecimal amount = ((BigDecimal) context.get("amount"));
105: BigDecimal quantity = (BigDecimal) context.get("quantity");
106: quantity = quantity == null ? new BigDecimal("1")
107: : quantity;
108: boolean negative = amount.signum() < 0;
109: // Ensure that price and quantity are positive since the terms may not be linear.
110: amount = amount.abs();
111: quantity = quantity.abs();
112: String productId = (String) context.get("productId");
113: String invoiceItemTypeId = (String) context
114: .get("invoiceItemTypeId");
115:
116: // Collect agreementItems applicable to this orderItem/returnItem
117: // TODO: partyIds should be part of this query!
118: List agreementItems = delegator.findByAndCache(
119: "AgreementItemAndProductAppl", UtilMisc.toMap(
120: "productId", productId,
121: "agreementItemTypeId",
122: "AGREEMENT_COMMISSION"));
123: // Try the first available virtual product if this is a variant product
124: if (agreementItems.size() == 0) {
125: List productAssocs = delegator.findByAndCache(
126: "ProductAssoc", UtilMisc.toMap("productIdTo",
127: productId, "productAssocTypeId",
128: "PRODUCT_VARIANT"));
129: if (productAssocs.size() > 0) {
130: GenericEntity productAssoc = EntityUtil
131: .getFirst(productAssocs);
132: agreementItems = delegator.findByAndCache(
133: "AgreementItemAndProductAppl", UtilMisc
134: .toMap("productId", productAssoc
135: .getString("productId"),
136: "agreementItemTypeId",
137: "AGREEMENT_COMMISSION"));
138: }
139: }
140: // this is not very efficient if there were many
141: agreementItems = EntityUtil.filterByDate(agreementItems);
142:
143: Iterator it = agreementItems.iterator();
144: while (it.hasNext()) {
145: GenericValue agreementItem = (GenericValue) it.next();
146: List terms = delegator
147: .findByAndCache(
148: "AgreementTerm",
149: UtilMisc
150: .toMap(
151: "agreementId",
152: agreementItem
153: .getString("agreementId"),
154: "agreementItemSeqId",
155: agreementItem
156: .getString("agreementItemSeqId"),
157: "invoiceItemTypeId",
158: invoiceItemTypeId));
159: if (terms.size() > 0) {
160: BigDecimal commission = ZERO;
161: BigDecimal min = new BigDecimal("-1e12"); // Limit to 1 trillion commission
162: BigDecimal max = new BigDecimal("1e12");
163:
164: // number of days due for commission, which will be the lowest termDays of all the AgreementTerms
165: long days = -1;
166: Iterator itt = terms.iterator();
167: while (itt.hasNext()) {
168: GenericValue elem = (GenericValue) itt.next();
169: String termTypeId = elem
170: .getString("termTypeId");
171: BigDecimal termValue = elem
172: .getBigDecimal("termValue");
173: if (termValue != null) {
174: if (termTypeId.equals("FIN_COMM_FIXED")) {
175: commission = commission.add(termValue
176: .multiply(quantity));
177: } else if (termTypeId
178: .equals("FIN_COMM_VARIABLE")) {
179: // if variable percentage commission, need to divide by 100, because 5% is stored as termValue of 5.0
180: commission = commission.add(termValue
181: .multiply(amount).divide(
182: new BigDecimal("100"),
183: 12, rounding));
184: } else if (termTypeId
185: .equals("FIN_COMM_MIN")) {
186: min = termValue.multiply(quantity);
187: } else if (termTypeId
188: .equals("FIN_COMM_MAX")) {
189: max = termValue.multiply(quantity);
190: }
191: // TODO: Add other type of terms and handling here
192: }
193:
194: // see if we need to update the number of days for paying commission
195: Long termDays = elem.getLong("termDays");
196: if (termDays != null) {
197: // if days is greater than zero, then it has been set with another value, so we use the lowest term days
198: // if days is less than zero, then it has not been set yet.
199: if (days > 0) {
200: days = Math.min(days, termDays
201: .longValue());
202: } else {
203: days = termDays.longValue();
204: }
205: }
206: }
207: if (commission.compareTo(min) < 0)
208: commission = min;
209: if (commission.compareTo(max) > 0)
210: commission = max;
211: commission = negative ? commission.negate()
212: : commission;
213: commission = commission
214: .setScale(decimals, rounding);
215:
216: Map partyCommissionResult = UtilMisc.toMap(
217: "partyIdFrom", agreementItem
218: .getString("partyIdFrom"),
219: "partyIdTo", agreementItem
220: .getString("partyIdTo"),
221: "commission", commission, "currencyUomId",
222: agreementItem.getString("currencyUomId"),
223: "productId", productId);
224: if (days >= 0) {
225: partyCommissionResult.put("days",
226: new Long(days));
227: }
228: commissions.add(partyCommissionResult);
229: }
230: }
231: } catch (GenericEntityException e) {
232: Debug.logWarning(e, module);
233: Map messageMap = UtilMisc.toMap("errMessage", e
234: .getMessage());
235: errMsg = UtilProperties.getMessage(resource,
236: "AccountingDataSourceError", messageMap, locale);
237: return ServiceUtil.returnError(errMsg);
238: }
239: return UtilMisc.toMap("commissions", commissions,
240: ModelService.RESPONSE_MESSAGE,
241: ModelService.RESPOND_SUCCESS);
242: }
243: }
|