add mrp (CBN)

This commit is contained in:
2023-02-20 08:38:13 +01:00
parent badd4fb987
commit 535d181d82
6 changed files with 326 additions and 0 deletions

View File

@@ -19,7 +19,9 @@ package com.axelor.apps.production.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.ProductRepository;
import com.axelor.apps.base.service.UnitConversionService;
import com.axelor.apps.production.db.BillOfMaterial;
import com.axelor.apps.production.db.ManufOrder;
import com.axelor.apps.production.db.OperationOrder;
@@ -36,11 +38,14 @@ import com.axelor.apps.stock.db.repo.StockRulesRepository;
import com.axelor.apps.stock.service.StockLocationService;
import com.axelor.apps.stock.service.StockRulesService;
import com.axelor.apps.supplychain.db.Mrp;
import com.axelor.apps.supplychain.db.MrpForecast;
import com.axelor.apps.supplychain.db.MrpLine;
import com.axelor.apps.supplychain.db.MrpLineOrigin;
import com.axelor.apps.supplychain.db.MrpLineSophal;
import com.axelor.apps.supplychain.db.MrpLineType;
import com.axelor.apps.supplychain.db.repo.MrpForecastRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineSophalRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineTypeRepository;
import com.axelor.apps.supplychain.db.repo.MrpRepository;
import com.axelor.apps.supplychain.service.MrpLineService;
@@ -48,12 +53,18 @@ import com.axelor.apps.supplychain.service.MrpServiceImpl;
import com.axelor.apps.tool.StringTool;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -437,4 +448,106 @@ public class MrpServiceProductionImpl extends MrpServiceImpl {
this.createManufOrderMrpLines();
return mrp;
}
@Override
public void createAvailableMrpLineSophal(Mrp mrp) throws AxelorException{
super.createAvailableMrpLineSophal(mrp);
}
@Transactional
@Override
public void createMrpLineSophal(Mrp mrp, Product product,Unit unit,BigDecimal qty,List<MrpForecast> mrpForecastList, Map<Long, Double> productQty) throws AxelorException{
if(mrp.getIncludeBOM()){
BillOfMaterial defaultBillOfMaterial = product.getDefaultBillOfMaterial();
if (defaultBillOfMaterial != null) {
for (BillOfMaterial billOfMaterial : defaultBillOfMaterial.getBillOfMaterialSet()) {
List<MrpForecast> forecastList = mrpForecastList.stream().filter(t -> t.getProduct() == product).collect(Collectors.toList());
Product subProduct = billOfMaterial.getProduct();
if (this.isMrpProduct(subProduct)) {
Double prodQty = productQty.get(subProduct.getId()) == null ? Double.parseDouble("0") : productQty.get(subProduct.getId());
BigDecimal reelQty =new BigDecimal(prodQty);
createMrpLineSophalProd(mrp, subProduct,product, reelQty ,billOfMaterial.getQty(),defaultBillOfMaterial.getQty(),forecastList);
}
}
}
}else{
super.createMrpLineSophal(mrp, product,unit, qty, mrpForecastList,productQty);
}
}
@Transactional
public void createMrpLineSophalProd(Mrp mrp,Product product,Product parentProduct,BigDecimal qty,BigDecimal reorderdQty,BigDecimal defaultQty, List<MrpForecast> forecastList){
MrpLineSophal mrpLineSophal = new MrpLineSophal();
mrpLineSophal.setQty(qty);
BigDecimal reelQty = qty;
BigDecimal sumQty = BigDecimal.ZERO;
for (MrpForecast forecast : forecastList) {
if(forecast.getProduct().getId() == parentProduct.getId()){
BigDecimal dividedQty = (forecast.getQty().multiply(reorderdQty)).divide(defaultQty);
reelQty = reelQty.subtract(dividedQty);
sumQty = sumQty.add(dividedQty);
BigDecimal displayedQty = reelQty;
switch (forecast.getMonthSelect()) {
case 1:
mrpLineSophal.setJanuary(displayedQty);
break;
case 2:
mrpLineSophal.setFebruary(displayedQty);
break;
case 3:
mrpLineSophal.setMarch(displayedQty);
break;
case 4:
mrpLineSophal.setApril(displayedQty);
case 5:
mrpLineSophal.setMay(displayedQty);
case 6:
mrpLineSophal.setJuin(displayedQty);
break;
case 7:
mrpLineSophal.setJuly(displayedQty);
break;
case 8:
mrpLineSophal.setAugust(displayedQty);
break;
case 9:
mrpLineSophal.setSeptember(displayedQty);
break;
case 10:
mrpLineSophal.setOctober(displayedQty);
break;
case 11:
mrpLineSophal.setNovember(displayedQty);
break;
case 12:
mrpLineSophal.setDecember(displayedQty);
break;
default:
break;
}
}
}
mrpLineSophal.setMrp(mrp);
mrpLineSophal.setProduct(product);
mrpLineSophal.setUnit(product.getPurchasesUnit());
mrpLineSophal.setProductOrigin(parentProduct);
Stream<MrpForecast> filter = forecastList.stream().filter(t -> t.getProduct().getId() == parentProduct.getId());
Long totalForecast = filter.count();
mrpLineSophal.setSecurityStock(sumQty.divide(new BigDecimal(totalForecast) ,5, RoundingMode.HALF_EVEN));
Beans.get(MrpLineSophalRepository.class).save(mrpLineSophal);
}
}

View File

@@ -46,15 +46,18 @@ import com.axelor.apps.supplychain.db.MrpFamily;
import com.axelor.apps.supplychain.db.MrpForecast;
import com.axelor.apps.supplychain.db.MrpLine;
import com.axelor.apps.supplychain.db.MrpLineOrigin;
import com.axelor.apps.supplychain.db.MrpLineSophal;
import com.axelor.apps.supplychain.db.MrpLineType;
import com.axelor.apps.supplychain.db.repo.MrpForecastRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineSophalRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineTypeRepository;
import com.axelor.apps.supplychain.db.repo.MrpRepository;
import com.axelor.apps.supplychain.exception.IExceptionMessage;
import com.axelor.apps.tool.StringTool;
import com.axelor.db.JPA;
import com.axelor.db.Model;
import com.axelor.db.Query;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
@@ -66,12 +69,14 @@ import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
@@ -98,6 +103,7 @@ public class MrpServiceImpl implements MrpService {
protected List<StockLocation> stockLocationList;
protected Map<Long, Integer> productMap;
protected Map<Long, Double> productQty;
protected Mrp mrp;
protected LocalDate today;
@@ -171,6 +177,17 @@ public class MrpServiceImpl implements MrpService {
mrpRepository.save(mrp);
}
@Transactional
public void resetSophalLine(Mrp mrp) {
Beans.get(MrpLineSophalRepository.class).all().filter("self.mrp.id = ?1", mrp.getId()).remove();
mrp.setStatusSelect(MrpRepository.STATUS_DRAFT);
mrpRepository.save(mrp);
}
protected void completeMrp(Mrp mrp) throws AxelorException {
log.debug("Complete MRP");
@@ -1096,4 +1113,128 @@ public class MrpServiceImpl implements MrpService {
return mrp;
}
public void createAvailableMrpLineSophal(Mrp mrp) throws AxelorException {
this.resetSophalLine(mrp);
today = appBaseService.getTodayDate();
Set<StockLocation> slList2 = Sets.newHashSet();
this.mrp = mrp;
try {
this.assignProductAndLevel(this.getProductList());
} catch (AxelorException e) {
e.printStackTrace();
}
this.productQty = new HashMap<>();
try {
stockLocationLineRepository.all().filter("self.product.id in ?1 and self.stockLocation is not null and self.currentQty > 0 and self.stockLocation.isNotInMrp is false",this.productMap.keySet())
.fetch().forEach(t ->slList2.add(t.getStockLocation()));
this.productQty = stockLocationLineRepository.all()
.filter("self.product.id in (?1) and self.stockLocation is not null and self.currentQty > 0 and self.stockLocation.isNotInMrp is false",this.productMap.keySet())
.fetch().stream().filter(t -> !t.getStockLocation().getIsNotInMrp()).collect(Collectors.groupingBy(t -> t.getProduct().getId(),Collectors.summingDouble(o->o.getCurrentQty().doubleValue())));
} catch (Exception e) {
log.debug(e.toString());
}
List<MrpForecast> mrpForecastList = new ArrayList<>();
if (mrp.getMrpForecastSet().isEmpty()) {
Integer scenario = mrp.getScenario();
mrpForecastList.addAll(
mrpForecastRepository
.all()
.filter(
"self.product.id in (?1) AND self.stockLocation in (?2) AND self.forecastDate "+( scenario == 3 ? "<=" : ">=")+" ?3 AND self.statusSelect = ?4 AND self.scenario = ?5",
this.productMap.keySet(),
slList2.stream().collect(Collectors.toList()),
today,
MrpForecastRepository.STATUS_CONFIRMED,
scenario)
.order("monthSelect")
.fetch());
log.debug(mrpForecastList.toString());
}
for (Map.Entry<Long, Double> entry : productQty.entrySet()) {
Product product = productRepository.find(entry.getKey());
BigDecimal qty = new BigDecimal(entry.getValue());
if(this.productMap.get(product.getId()) == 0){
this.createMrpLineSophal(mrp, product,product.getUnit(), qty,mrpForecastList,productQty);
}
}
}
@Transactional
public void createMrpLineSophal(Mrp mrp, Product product,Unit unit,BigDecimal qty,List<MrpForecast> mrpForecastList, Map<Long, Double> productQty) throws AxelorException {
MrpLineSophal mrpLineSophal = new MrpLineSophal();
mrpLineSophal.setQty(qty);
BigDecimal reelQty = qty;
BigDecimal sumQty = BigDecimal.ZERO;
for (MrpForecast forecast : mrpForecastList) {
if(forecast.getProduct() == product){
reelQty = reelQty.subtract(forecast.getQty());
BigDecimal displayedQty = reelQty;
sumQty = sumQty.add(forecast.getQty());
switch (forecast.getMonthSelect()) {
case 1:
mrpLineSophal.setJanuary(displayedQty);
break;
case 2:
mrpLineSophal.setFebruary(displayedQty);
break;
case 3:
mrpLineSophal.setMarch(displayedQty);
break;
case 4:
mrpLineSophal.setApril(displayedQty);
case 5:
mrpLineSophal.setMay(displayedQty);
case 6:
mrpLineSophal.setJuin(displayedQty);
break;
case 7:
mrpLineSophal.setJuly(displayedQty);
break;
case 8:
mrpLineSophal.setAugust(displayedQty);
break;
case 9:
mrpLineSophal.setSeptember(displayedQty);
break;
case 10:
mrpLineSophal.setOctober(displayedQty);
break;
case 11:
mrpLineSophal.setNovember(displayedQty);
break;
case 12:
mrpLineSophal.setDecember(displayedQty);
break;
default:
break;
}
}
}
mrpLineSophal.setMrp(mrp);
mrpLineSophal.setProduct(product);
mrpLineSophal.setUnit(product.getUnit());
mrpLineSophal.setCompany(mrp.getStockLocation().getCompany());
Long totalForecast = mrpForecastList.stream().filter(t -> t.getProduct() == product).count();
mrpLineSophal.setSecurityStock(sumQty.divide(new BigDecimal(totalForecast),5, RoundingMode.HALF_EVEN));
Beans.get(MrpLineSophalRepository.class).save(mrpLineSophal);
}
}

View File

@@ -17,12 +17,25 @@
*/
package com.axelor.apps.supplychain.web;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.base.db.Function;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.supplychain.db.Mrp;
import com.axelor.apps.supplychain.db.repo.MrpForecastRepository;
import com.axelor.apps.supplychain.db.repo.MrpLineRepository;
import com.axelor.apps.supplychain.db.repo.MrpRepository;
import com.axelor.apps.supplychain.report.IReport;
import com.axelor.apps.supplychain.service.MrpLineServiceImpl;
import com.axelor.apps.supplychain.service.MrpService;
import com.axelor.apps.supplychain.service.MrpServiceImpl;
import com.axelor.exception.AxelorException;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
@@ -31,6 +44,9 @@ import com.axelor.meta.schema.actions.ActionView;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.Singleton;
import com.google.inject.persist.Transactional;
import com.axelor.apps.supplychain.db.MrpForecast;
import com.axelor.apps.supplychain.db.MrpLineSophal;
@Singleton
public class MrpController {
@@ -121,4 +137,16 @@ public class MrpController {
TraceBackService.trace(response, e);
}
}
/**
* @param request
* @param response
* @throws AxelorException
*/
public void calculationCbn(ActionRequest request, ActionResponse response) throws AxelorException {
Mrp mrp = Beans.get(MrpRepository.class).find(request.getContext().asType(Mrp.class).getId());
Beans.get(MrpServiceImpl.class).createAvailableMrpLineSophal(mrp);
response.setReload(true);
}
}

View File

@@ -16,7 +16,10 @@
<datetime name="startDateTime" title="Calculation Start Date"/>
<datetime name="endDateTime" title="Calculation End Date"/>
<string name="mrpSeq" title="MRP number" readonly="true"/>
<integer name="scenario" title="Scenario" selection="mrp.scenario.select"/>
<boolean name="displayProductWithoutProposal" title="Display product without proposal" default="false"/>
<boolean name="includeBOM" title="Include Bom" default="false"/>
<extra-code><![CDATA[
// STATUS SELECT

View File

@@ -13,6 +13,8 @@
<string name="note" title="Note" large="true" multiline="true"/>
<many-to-one name="partner" ref="com.axelor.apps.base.db.Partner" title="Partner"/>
<integer name="statusSelect" title="Status" selection="supplychain.mrp.forecast.status.select" readonly="true" default="1"/>
<integer name="monthSelect" selection="iadministration.month.select"/>
<integer name="scenario" title="Scenario" selection="mrp.scenario.select"/>
<extra-code><![CDATA[

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="supplychain" package="com.axelor.apps.supplychain.db"/>
<entity name="MrpLineSophal" lang="java">
<many-to-one name="mrp" ref="com.axelor.apps.supplychain.db.Mrp" title="Mrp"/>
<many-to-one name="product" ref="com.axelor.apps.base.db.Product" title="Product"/>
<decimal name="qty" title="Qty"/>
<decimal name="january" title="January" />
<decimal name="february" title="February" />
<decimal name="march" title="March" />
<decimal name="april" title="April" />
<decimal name="may" title="May" />
<decimal name="juin" title="Juin" />
<decimal name="july" title="July" />
<decimal name="august" title="August" />
<decimal name="september" title="September" />
<decimal name="october" title="October" />
<decimal name="november" title="November" />
<decimal name="december" title="December" />
<!-- <integer name="scenario" title="Scenario" selection="mrp.scenario.select"/> -->
<many-to-one name="company" ref="com.axelor.apps.base.db.Company" title="Company" transient="true"/>
<many-to-one name="unit" ref="com.axelor.apps.base.db.Unit" title="Unit" transient="true"/>
<decimal name="securityStock" title="Security Stock" />
<many-to-one name="productOrigin" ref="com.axelor.apps.base.db.Product" title="Product Origin"/>
<extra-code><![CDATA[
// AVAILABLE SCENARIOS
public static final int MIN = 1;
public static final int MAX = 2;
public static final int HIST = 3;
]]></extra-code>
</entity>
</domain-models>