blob: 2cca46413cde7c19f959deddfa79388ea85857a4 [file] [log] [blame]
/*******************************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.accounting.agreement;
import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.UtilMisc;
import org.apache.ofbiz.base.util.UtilNumber;
import org.apache.ofbiz.base.util.UtilProperties;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericEntityException;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.entity.util.EntityQuery;
import org.apache.ofbiz.service.DispatchContext;
import org.apache.ofbiz.service.ModelService;
import org.apache.ofbiz.service.ServiceUtil;
/**
* Services for Agreement (Accounting)
*/
public class AgreementServices {
public static final String module = AgreementServices.class.getName();
// set some BigDecimal properties
private static BigDecimal ZERO = BigDecimal.ZERO;
private static int decimals = -1;
private static int rounding = -1;
static {
decimals = UtilNumber.getBigDecimalScale("invoice.decimals");
rounding = UtilNumber.getBigDecimalRoundingMode("invoice.rounding");
// set zero to the proper scale
if (decimals != -1) ZERO = ZERO.setScale(decimals, rounding);
}
public static final String resource = "AccountingUiLabels";
/**
* Determines commission receiving parties and amounts for the provided product, price, and quantity
* @param ctx The DispatchContext that this service is operating in.
* @param context Map containing the input parameters.
* productId String Product Id
* 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
* commission BigDecimal Commission
* days Long term days
* currencyUomId String Currency
* productId String Product Id
*/
public static Map<String, Object> getCommissionForProduct(DispatchContext ctx, Map<String, Object> context) {
Delegator delegator = ctx.getDelegator();
Locale locale = (Locale) context.get("locale");
String errMsg = null;
List<Map<String, Object>> commissions = new LinkedList<Map<String,Object>>();
try {
BigDecimal amount = ((BigDecimal)context.get("amount"));
BigDecimal quantity = (BigDecimal)context.get("quantity");
quantity = quantity == null ? BigDecimal.ONE : quantity;
boolean negative = amount.signum() < 0;
// Ensure that price and quantity are positive since the terms may not be linear.
amount = amount.abs();
quantity = quantity.abs();
String productId = (String) context.get("productId");
String invoiceItemTypeId = (String) context.get("invoiceItemTypeId");
String invoiceItemSeqId = (String) context.get("invoiceItemSeqId");
String invoiceId = (String) context.get("invoiceId");
// Collect agreementItems applicable to this orderItem/returnItem
// TODO: partyIds should be part of this query!
List<GenericValue> agreementItems = EntityQuery.use(delegator).from("AgreementItemAndProductAppl")
.where("productId", productId, "agreementItemTypeId", "AGREEMENT_COMMISSION")
.cache().filterByDate().queryList();
// Try the first available virtual product if this is a variant product
if (agreementItems.size() == 0) {
GenericValue productAssoc = EntityQuery.use(delegator).from("ProductAssoc")
.where("productIdTo", productId, "productAssocTypeId", "PRODUCT_VARIANT")
.cache().filterByDate().queryFirst();
if (productAssoc != null) {
agreementItems = EntityQuery.use(delegator).from("AgreementItemAndProductAppl")
.where("productId", productAssoc.getString("productId"), "agreementItemTypeId", "AGREEMENT_COMMISSION")
.cache().filterByDate().queryList();
}
}
for (GenericValue agreementItem : agreementItems) {
List<GenericValue> terms = EntityQuery.use(delegator).from("AgreementTerm")
.where("agreementId", agreementItem.getString("agreementId"),
"agreementItemSeqId", agreementItem.getString("agreementItemSeqId"),
"invoiceItemTypeId", invoiceItemTypeId)
.cache().queryList();
if (terms.size() > 0) {
BigDecimal commission = ZERO;
BigDecimal min = new BigDecimal("-1e12"); // Limit to 1 trillion commission
BigDecimal max = new BigDecimal("1e12");
// number of days due for commission, which will be the lowest termDays of all the AgreementTerms
long days = -1;
for (GenericValue term : terms) {
String termTypeId = term.getString("termTypeId");
BigDecimal termValue = term.getBigDecimal("termValue");
if (termValue != null) {
if (termTypeId.equals("FIN_COMM_FIXED")) {
commission = commission.add(termValue);
} 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;
} else if (termTypeId.equals("FIN_COMM_MAX")) {
max = termValue;
}
// TODO: Add other type of terms and handling here
}
// see if we need to update the number of days for paying commission
Long termDays = term.getLong("termDays");
if (termDays != null) {
// if days is greater than zero, then it has been set with another value, so we use the lowest term days
// if days is less than zero, then it has not been set yet.
if (days > 0) {
days = Math.min(days, termDays.longValue());
} else {
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);
Map<String, Object> partyCommissionResult = UtilMisc.toMap(
"partyIdFrom", agreementItem.getString("partyIdFrom"),
"partyIdTo", agreementItem.getString("partyIdTo"),
"invoiceItemSeqId", invoiceItemSeqId,
"invoiceId", invoiceId,
"commission", commission,
"quantity", quantity,
"currencyUomId", agreementItem.getString("currencyUomId"),
"productId", productId);
if (days >= 0) {
partyCommissionResult.put("days", Long.valueOf(days));
}
if (!commissions.contains(partyCommissionResult)) {
commissions.add(partyCommissionResult);
}
}
}
} catch (GenericEntityException e) {
Debug.logWarning(e, module);
Map<String, String> messageMap = UtilMisc.toMap("errMessage", e.getMessage());
errMsg = UtilProperties.getMessage("CommonUiLabels", "CommonDatabaseProblem", messageMap, locale);
return ServiceUtil.returnError(errMsg);
}
return UtilMisc.toMap(
"commissions", commissions,
ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
}
}