<commit_before>/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2019 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.supplychain.service;

import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.Unit;
import com.axelor.apps.base.db.repo.CompanyRepository;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.base.service.UnitConversionService;
import com.axelor.apps.purchase.db.IPurchaseOrder;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.stock.db.StockLocation;
import com.axelor.apps.stock.db.StockLocationLine;
import com.axelor.apps.stock.db.repo.StockLocationRepository;
import com.axelor.apps.stock.service.StockLocationService;
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
import com.axelor.apps.tool.StringTool;
import com.axelor.common.StringUtils;
import com.axelor.exception.AxelorException;
import com.axelor.rpc.filter.Filter;
import com.axelor.rpc.filter.JPQLFilter;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProductStockLocationServiceImpl implements ProductStockLocationService {

  protected UnitConversionService unitConversionService;
  protected AppSupplychainService appSupplychainService;
  protected ProductRepository productRepository;
  protected CompanyRepository companyRepository;
  protected StockLocationRepository stockLocationRepository;
  protected StockLocationService stockLocationService;
  protected StockLocationServiceSupplychain stockLocationServiceSupplychain;

  @Inject
  public ProductStockLocationServiceImpl(
      UnitConversionService unitConversionService,
      AppSupplychainService appSupplychainService,
      ProductRepository productRepository,
      CompanyRepository companyRepository,
      StockLocationRepository stockLocationRepository,
      StockLocationService stockLocationService,
      StockLocationServiceSupplychain stockLocationServiceSupplychain) {
    super();
    this.unitConversionService = unitConversionService;
    this.appSupplychainService = appSupplychainService;
    this.productRepository = productRepository;
    this.companyRepository = companyRepository;
    this.stockLocationRepository = stockLocationRepository;
    this.stockLocationService = stockLocationService;
    this.stockLocationServiceSupplychain = stockLocationServiceSupplychain;
  }

  @Override
  public Map<String, Object> computeIndicators(Long productId, Long companyId, Long stockLocationId)
      throws AxelorException {
    Map<String, Object> map = new HashMap<>();
    Product product = productRepository.find(productId);
    Company company = companyRepository.find(companyId);
    StockLocation stockLocation = stockLocationRepository.find(stockLocationId);
    if (stockLocationId != 0L) {
      List<StockLocation> stockLocationList =
          stockLocationService.getAllLocationAndSubLocation(stockLocation, false);
      if (!stockLocationList.isEmpty()) {
        BigDecimal realQty = BigDecimal.ZERO;
        BigDecimal futureQty = BigDecimal.ZERO;
        BigDecimal reservedQty = BigDecimal.ZERO;
        BigDecimal requestedReservedQty = BigDecimal.ZERO;
        BigDecimal saleOrderQty = BigDecimal.ZERO;
        BigDecimal purchaseOrderQty = BigDecimal.ZERO;
        BigDecimal availableQty = BigDecimal.ZERO;

        for (StockLocation sl : stockLocationList) {
          realQty = realQty.add(stockLocationService.getRealQty(productId, sl.getId(), companyId));
          futureQty =
              futureQty.add(stockLocationService.getFutureQty(productId, sl.getId(), companyId));
          reservedQty =
              reservedQty.add(
                  stockLocationServiceSupplychain.getReservedQty(productId, sl.getId(), companyId));
          requestedReservedQty =
              requestedReservedQty.add(this.getRequestedReservedQty(product, company, sl));
          saleOrderQty = saleOrderQty.add(this.getSaleOrderQty(product, company, sl));
          purchaseOrderQty = purchaseOrderQty.add(this.getPurchaseOrderQty(product, company, sl));
          availableQty = availableQty.add(this.getAvailableQty(product, company, sl));
        }
        map.put("$realQty", realQty.setScale(2));
        map.put("$futureQty", futureQty.setScale(2));
        map.put("$reservedQty", reservedQty.setScale(2));
        map.put("$requestedReservedQty", requestedReservedQty.setScale(2));
        map.put("$saleOrderQty", saleOrderQty.setScale(2));
        map.put("$purchaseOrderQty", purchaseOrderQty.setScale(2));
        map.put("$availableQty", availableQty.subtract(reservedQty).setScale(2));

        return map;
      }
    }
    BigDecimal reservedQty =
        stockLocationServiceSupplychain
            .getReservedQty(productId, stockLocationId, companyId)
            .setScale(2);
    map.put(
        "$realQty",
        stockLocationService.getRealQty(productId, stockLocationId, companyId).setScale(2));
    map.put(
        "$futureQty",
        stockLocationService.getFutureQty(productId, stockLocationId, companyId).setScale(2));
    map.put("$reservedQty", reservedQty);
    map.put(
        "$requestedReservedQty",
        this.getRequestedReservedQty(product, company, stockLocation).setScale(2));
    map.put("$saleOrderQty", this.getSaleOrderQty(product, company, stockLocation).setScale(2));
    map.put(
        "$purchaseOrderQty", this.getPurchaseOrderQty(product, company, stockLocation).setScale(2));
    map.put(
        "$availableQty",
        this.getAvailableQty(product, company, stockLocation).subtract(reservedQty).setScale(2));
    return map;
  }

  protected BigDecimal getRequestedReservedQty(
      Product product, Company company, StockLocation stockLocation) throws AxelorException {
    if (product == null || product.getUnit() == null) {
      return BigDecimal.ZERO;
    }
    // JPQL request
    List<Filter> queryFilter =
        Lists.newArrayList(
            new JPQLFilter(
                "self.product = :product AND self.stockLocation.typeSelect != :typeSelect "));
    if (company != null) {
      queryFilter.add(new JPQLFilter("self.stockLocation.company = :company "));
    }
    if (stockLocation != null) {
      queryFilter.add(new JPQLFilter("self.stockLocation = :stockLocation"));
    }

    List<StockLocationLine> stockLocationLineList =
        Filter.and(queryFilter)
            .build(StockLocationLine.class)
            .bind("product", product)
            .bind("company", company)
            .bind("stockLocation", stockLocation)
            .fetch();

    // Compute
    BigDecimal sumRequestedReservedQty = BigDecimal.ZERO;
    if (!stockLocationLineList.isEmpty()) {
      BigDecimal requestedReservedQty = BigDecimal.ZERO;
      Unit unitConversion = product.getUnit();

      for (StockLocationLine stockLocationLine : stockLocationLineList) {
        requestedReservedQty = stockLocationLine.getRequestedReservedQty();
        if (!stockLocationLine.getUnit().equals(unitConversion)) {
          requestedReservedQty =
              unitConversionService.convert(
                  stockLocationLine.getUnit(),
                  unitConversion,
                  requestedReservedQty,
                  requestedReservedQty.scale(),
                  product);
        }
        sumRequestedReservedQty = sumRequestedReservedQty.add(requestedReservedQty);
      }
    }

    return sumRequestedReservedQty;
  }

  protected BigDecimal getSaleOrderQty(
      Product product, Company company, StockLocation stockLocation) throws AxelorException {
    if (product == null || product.getUnit() == null) {
      return BigDecimal.ZERO;<commit_msg>RM18200: fix requested reserved qty indicator<commit_after>/*
 * Axelor Business Solutions
 *
 * Copyright (C) 2019 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.supplychain.service;

import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.Unit;
import com.axelor.apps.base.db.repo.CompanyRepository;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.base.service.UnitConversionService;
import com.axelor.apps.purchase.db.IPurchaseOrder;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.stock.db.StockLocation;
import com.axelor.apps.stock.db.StockLocationLine;
import com.axelor.apps.stock.db.repo.StockLocationRepository;
import com.axelor.apps.stock.service.StockLocationService;
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
import com.axelor.apps.tool.StringTool;
import com.axelor.common.StringUtils;
import com.axelor.exception.AxelorException;
import com.axelor.rpc.filter.Filter;
import com.axelor.rpc.filter.JPQLFilter;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ProductStockLocationServiceImpl implements ProductStockLocationService {

  protected UnitConversionService unitConversionService;
  protected AppSupplychainService appSupplychainService;
  protected ProductRepository productRepository;
  protected CompanyRepository companyRepository;
  protected StockLocationRepository stockLocationRepository;
  protected StockLocationService stockLocationService;
  protected StockLocationServiceSupplychain stockLocationServiceSupplychain;

  @Inject
  public ProductStockLocationServiceImpl(
      UnitConversionService unitConversionService,
      AppSupplychainService appSupplychainService,
      ProductRepository productRepository,
      CompanyRepository companyRepository,
      StockLocationRepository stockLocationRepository,
      StockLocationService stockLocationService,
      StockLocationServiceSupplychain stockLocationServiceSupplychain) {
    super();
    this.unitConversionService = unitConversionService;
    this.appSupplychainService = appSupplychainService;
    this.productRepository = productRepository;
    this.companyRepository = companyRepository;
    this.stockLocationRepository = stockLocationRepository;
    this.stockLocationService = stockLocationService;
    this.stockLocationServiceSupplychain = stockLocationServiceSupplychain;
  }

  @Override
  public Map<String, Object> computeIndicators(Long productId, Long companyId, Long stockLocationId)
      throws AxelorException {
    Map<String, Object> map = new HashMap<>();
    Product product = productRepository.find(productId);
    Company company = companyRepository.find(companyId);
    StockLocation stockLocation = stockLocationRepository.find(stockLocationId);
    if (stockLocationId != 0L) {
      List<StockLocation> stockLocationList =
          stockLocationService.getAllLocationAndSubLocation(stockLocation, false);
      if (!stockLocationList.isEmpty()) {
        BigDecimal realQty = BigDecimal.ZERO;
        BigDecimal futureQty = BigDecimal.ZERO;
        BigDecimal reservedQty = BigDecimal.ZERO;
        BigDecimal requestedReservedQty = BigDecimal.ZERO;
        BigDecimal saleOrderQty = BigDecimal.ZERO;
        BigDecimal purchaseOrderQty = BigDecimal.ZERO;
        BigDecimal availableQty = BigDecimal.ZERO;

        for (StockLocation sl : stockLocationList) {
          realQty = realQty.add(stockLocationService.getRealQty(productId, sl.getId(), companyId));
          futureQty =
              futureQty.add(stockLocationService.getFutureQty(productId, sl.getId(), companyId));
          reservedQty =
              reservedQty.add(
                  stockLocationServiceSupplychain.getReservedQty(productId, sl.getId(), companyId));
          requestedReservedQty =
              requestedReservedQty.add(this.getRequestedReservedQty(product, company, sl));
          saleOrderQty = saleOrderQty.add(this.getSaleOrderQty(product, company, sl));
          purchaseOrderQty = purchaseOrderQty.add(this.getPurchaseOrderQty(product, company, sl));
          availableQty = availableQty.add(this.getAvailableQty(product, company, sl));
        }
        map.put("$realQty", realQty.setScale(2));
        map.put("$futureQty", futureQty.setScale(2));
        map.put("$reservedQty", reservedQty.setScale(2));
        map.put("$requestedReservedQty", requestedReservedQty.setScale(2));
        map.put("$saleOrderQty", saleOrderQty.setScale(2));
        map.put("$purchaseOrderQty", purchaseOrderQty.setScale(2));
        map.put("$availableQty", availableQty.subtract(reservedQty).setScale(2));

        return map;
      }
    }
    BigDecimal reservedQty =
        stockLocationServiceSupplychain
            .getReservedQty(productId, stockLocationId, companyId)
            .setScale(2);
    map.put(
        "$realQty",
        stockLocationService.getRealQty(productId, stockLocationId, companyId).setScale(2));
    map.put(
        "$futureQty",
        stockLocationService.getFutureQty(productId, stockLocationId, companyId).setScale(2));
    map.put("$reservedQty", reservedQty);
    map.put(
        "$requestedReservedQty",
        this.getRequestedReservedQty(product, company, stockLocation).setScale(2));
    map.put("$saleOrderQty", this.getSaleOrderQty(product, company, stockLocation).setScale(2));
    map.put(
        "$purchaseOrderQty", this.getPurchaseOrderQty(product, company, stockLocation).setScale(2));
    map.put(
        "$availableQty",
        this.getAvailableQty(product, company, stockLocation).subtract(reservedQty).setScale(2));
    return map;
  }

  protected BigDecimal getRequestedReservedQty(
      Product product, Company company, StockLocation stockLocation) throws AxelorException {
    if (product == null || product.getUnit() == null) {
      return BigDecimal.ZERO;
    }
    // JPQL request
    List<Filter> queryFilter =
        Lists.newArrayList(
            new JPQLFilter(
                "self.product = :product AND self.stockLocation.typeSelect != :typeSelect "));
    if (company != null) {
      queryFilter.add(new JPQLFilter("self.stockLocation.company = :company "));
    }
    if (stockLocation != null) {
      queryFilter.add(new JPQLFilter("self.stockLocation = :stockLocation"));
    }

    List<StockLocationLine> stockLocationLineList =
        Filter.and(queryFilter)
            .build(StockLocationLine.class)
            .bind("product", product)
            .bind("company", company)
            .bind("typeSelect", StockLocationRepository.TYPE_VIRTUAL)
            .bind("stockLocation", stockLocation)
            .fetch();

    // Compute
    BigDecimal sumRequestedReservedQty = BigDecimal.ZERO;
    if (!stockLocationLineList.isEmpty()) {
      BigDecimal requestedReservedQty = BigDecimal.ZERO;
      Unit unitConversion = product.getUnit();

      for (StockLocationLine stockLocationLine : stockLocationLineList) {
        requestedReservedQty = stockLocationLine.getRequestedReservedQty();
        if (!stockLocationLine.getUnit().equals(unitConversion)) {
          requestedReservedQty =
              unitConversionService.convert(
                  stockLocationLine.getUnit(),
                  unitConversion,
                  requestedReservedQty,
                  requestedReservedQty.scale(),
                  product);
        }
        sumRequestedReservedQty = sumRequestedReservedQty.add(requestedReservedQty);
      }
    }

    return sumRequestedReservedQty;
  }

  protected BigDecimal getSaleOrderQty(
      Product product, Company company, StockLocation stockLocation) throws AxelorException {
    if (product == null || product.getUnit() == null) {
      return BigDecimal.ZERO;
{'fraction_non_alphanumeric': 0.09320188008712599, 'fraction_numerical': 0.0025793878252894646, 'mean_word_length': 3.843697945585786, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4561054', 'n_tokens_mistral': 4948, 'n_tokens_neox': 4840, 'n_words': 936}