/** * Axelor Business Solutions * * Copyright (C) 2016 Axelor (<http://axelor.com>). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.axelor.apps.sale.service; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.axelor.apps.account.db.TaxLine; import com.axelor.apps.base.db.IAdministration; import com.axelor.apps.base.db.IPriceListLine; import com.axelor.apps.base.db.PriceList; import com.axelor.apps.base.db.PriceListLine; import com.axelor.apps.base.db.Product; import com.axelor.apps.base.db.Unit; import com.axelor.apps.base.db.repo.GeneralRepository; import com.axelor.apps.base.service.CurrencyService; import com.axelor.apps.base.service.PriceListService; import com.axelor.apps.base.service.administration.GeneralService; import com.axelor.apps.base.service.tax.AccountManagementService; import com.axelor.apps.sale.db.SaleOrder; import com.axelor.apps.sale.db.SaleOrderLine; import com.axelor.exception.AxelorException; import com.axelor.inject.Beans; import com.google.inject.Inject; public class SaleOrderLineServiceImpl implements SaleOrderLineService { private final Logger logger = LoggerFactory.getLogger(getClass()); @Inject private CurrencyService currencyService; @Inject private PriceListService priceListService; @Inject protected GeneralService generalService; /** * Compute the excluded tax total amount of a sale order line. * * @param quantity * The quantity. * @param price * The unit price. * @return * The excluded tax total amount. */ public BigDecimal computeAmount(SaleOrderLine saleOrderLine) { BigDecimal price = this.computeDiscount(saleOrderLine); BigDecimal amount = computeAmount(saleOrderLine.getQty(), price); return amount; } public BigDecimal computeAmount(BigDecimal quantity, BigDecimal price) { BigDecimal amount = quantity.multiply(price).setScale(IAdministration.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_EVEN); logger.debug("Calcul du montant HT avec une quantité de {} pour {} : {}", new Object[] { quantity, price, amount }); return amount; } public BigDecimal getUnitPrice(SaleOrder saleOrder, SaleOrderLine saleOrderLine, TaxLine taxLine) throws AxelorException { Product product = saleOrderLine.getProduct(); BigDecimal price = this.convertUnitPrice(product, taxLine, product.getSalePrice(), saleOrder); return currencyService.getAmountCurrencyConverted( product.getSaleCurrency(), saleOrder.getCurrency(), price, saleOrder.getCreationDate()) .setScale(generalService.getNbDecimalDigitForUnitPrice(), RoundingMode.HALF_UP); } public TaxLine getTaxLine(SaleOrder saleOrder, SaleOrderLine saleOrderLine) throws AxelorException { return Beans.get(AccountManagementService.class).getTaxLine( saleOrder.getCreationDate(), saleOrderLine.getProduct(), saleOrder.getCompany(), saleOrder.getClientPartner().getFiscalPosition(), false); } public BigDecimal getAmountInCompanyCurrency(BigDecimal exTaxTotal, SaleOrder saleOrder) throws AxelorException { return currencyService.getAmountCurrencyConverted( saleOrder.getCurrency(), saleOrder.getCompany().getCurrency(), exTaxTotal, saleOrder.getCreationDate()) .setScale(IAdministration.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_UP); } public BigDecimal getCompanyCostPrice(SaleOrder saleOrder, SaleOrderLine saleOrderLine) throws AxelorException { Product product = saleOrderLine.getProduct(); return currencyService.getAmountCurrencyConverted( product.getPurchaseCurrency(), saleOrder.getCompany().getCurrency(), product.getCostPrice(), saleOrder.getCreationDate()) .setScale(IAdministration.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_UP); } public PriceListLine getPriceListLine(SaleOrderLine saleOrderLine, PriceList priceList) { return priceListService.getPriceListLine(saleOrderLine.getProduct(), saleOrderLine.getQty(), priceList); } public BigDecimal computeDiscount(SaleOrderLine saleOrderLine) { return priceListService.computeDiscount(saleOrderLine.getPrice(), saleOrderLine.getDiscountTypeSelect(),saleOrderLine.getDiscountAmount()); } public BigDecimal convertUnitPrice(Product product, TaxLine taxLine, BigDecimal price, SaleOrder saleOrder){ if(taxLine == null) { return price; } if(product.getInAti() && !saleOrder.getInAti()){ price = price.divide(taxLine.getValue().add(BigDecimal.ONE), 2, BigDecimal.ROUND_HALF_UP); } else if(!product.getInAti() && saleOrder.getInAti()){ price = price.add(price.multiply(taxLine.getValue())); } return price; } public Map<String,Object> getDiscount(SaleOrder saleOrder, SaleOrderLine saleOrderLine, BigDecimal price) { PriceList priceList = saleOrder.getPriceList(); if(priceList != null) { int discountTypeSelect = 0; PriceListLine priceListLine = this.getPriceListLine(saleOrderLine, priceList); if(priceListLine != null){ discountTypeSelect = priceListLine.getTypeSelect(); } Map<String, Object> discounts = priceListService.getDiscounts(priceList, priceListLine, price); if(discounts != null){ int computeMethodDiscountSelect = generalService.getGeneral().getComputeMethodDiscountSelect(); if((computeMethodDiscountSelect == GeneralRepository.INCLUDE_DISCOUNT_REPLACE_ONLY && discountTypeSelect == IPriceListLine.TYPE_REPLACE) || computeMethodDiscountSelect == GeneralRepository.INCLUDE_DISCOUNT) { price = priceListService.computeDiscount(price, (int) discounts.get("discountTypeSelect"), (BigDecimal) discounts.get("discountAmount")); discounts.put("price", price); } } return discounts; } return null; } public int getDiscountTypeSelect(SaleOrder saleOrder, SaleOrderLine saleOrderLine){ PriceList priceList = saleOrder.getPriceList(); if(priceList != null) { PriceListLine priceListLine = this.getPriceListLine(saleOrderLine, priceList); return priceListLine.getTypeSelect(); } return 0; } public Unit getSaleUnit(SaleOrderLine saleOrderLine) { Unit unit = saleOrderLine.getProduct().getSalesUnit(); if(unit == null){ unit = saleOrderLine.getProduct().getUnit(); } return unit; } public boolean unitPriceShouldBeUpdate(SaleOrder saleOrder, Product product) { if(product != null && product.getInAti() != saleOrder.getInAti()) { return true; } return false; } }