feat: Enhance Supply Chain Module with Analytic Move Line Features

- Added support for analytic move lines in InvoiceServiceSupplychainImpl.
- Implemented methods to check for missing analytic move lines in PurchaseOrderController and PurchaseRequestController.
- Introduced budget distribution line generation in PurchaseOrderController.
- Updated SaleOrderController to generate analytic move lines.
- Enhanced StockMoveController with budget distribution line generation.
- Modified StockMoveLineController to include analytic account and axis handling.
- Updated domain models to include references to analytic accounts and axes in Partner, StockLocation, and StockMoveLine.
- Created unit tests for StockMoveLineServiceSupplychainImpl to ensure proper functionality of new features.
- Added MockQuery class for testing purposes.
This commit is contained in:
BACHIR SOULDI
2026-02-17 15:13:17 +01:00
parent 9eb959f07a
commit 6881c439b2
74 changed files with 2975 additions and 930 deletions

View File

@@ -18,18 +18,84 @@
package com.axelor.apps.stock.db.repo;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.service.BarcodeGeneratorService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.stock.db.StockLocationLine;
import com.axelor.apps.stock.service.WeightedAveragePriceService;
import com.axelor.apps.tool.service.TranslationService;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.axelor.meta.MetaFiles;
import com.axelor.meta.db.MetaFile;
import com.google.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import javax.validation.ValidationException;
public class StockLocationLineStockRepository extends StockLocationLineRepository {
@Inject private MetaFiles metaFiles;
@Inject protected AppBaseService appBaseService;
@Inject protected TranslationService translationService;
protected static final String FULL_NAME_FORMAT = "[%s] %s";
@Inject protected BarcodeGeneratorService barcodeGeneratorService;
@Override
public StockLocationLine save(StockLocationLine entity) {
Product product = entity.getProduct();
if (entity.getIsAvgPriceChanged()) {
Beans.get(WeightedAveragePriceService.class).computeAvgPriceForProduct(product);
}
if (entity.getBarCodeSeq() == null
&& appBaseService.getAppBase().getActivateBarCodeGeneration()
&& entity.getDetailsStockLocation() != null) {
try {
boolean addPadding = false;
InputStream inStream;
if (!appBaseService.getAppBase().getEditProductBarcodeType()) {
inStream =
barcodeGeneratorService.createBarCode(
String.valueOf(entity.getProduct().getId())
+ "-"
+ String.valueOf(entity.getDetailsStockLocation().getId())
+ "-"
+ String.valueOf(entity.getTrackingNumber().getId()),
appBaseService.getAppBase().getBarcodeTypeConfig(),
addPadding);
} else {
System.out.println(
String.valueOf(entity.getProduct().getId())
+ "-"
+ String.valueOf(entity.getDetailsStockLocation().getId())
+ "-"
+ String.valueOf(entity.getTrackingNumber().getId()));
inStream =
barcodeGeneratorService.createBarCode(
String.valueOf(entity.getProduct().getId())
+ "-"
+ String.valueOf(entity.getDetailsStockLocation().getId())
+ "-"
+ String.valueOf(entity.getTrackingNumber().getId()),
appBaseService.getAppBase().getBarcodeTypeConfig(),
addPadding);
}
if (inStream != null) {
MetaFile barcodeFile =
metaFiles.upload(
inStream, String.format("StockLocationLineCode%d.png", entity.getId()));
entity.setBarCodeSeq(barcodeFile);
}
} catch (IOException e) {
e.printStackTrace();
} catch (AxelorException e) {
throw new ValidationException(e.getMessage());
}
}
return super.save(entity);
}
}

View File

@@ -0,0 +1,57 @@
package com.axelor.apps.stock.db.repo;
import com.axelor.apps.base.service.BarcodeGeneratorService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.stock.db.StockMoveLineLocation;
import com.axelor.apps.tool.service.TranslationService;
import com.axelor.exception.AxelorException;
import com.axelor.meta.MetaFiles;
import com.axelor.meta.db.MetaFile;
import com.google.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import javax.validation.ValidationException;
public class StockMoveLineLocationStockRepository extends StockMoveLineLocationRepository {
@Inject private MetaFiles metaFiles;
@Inject protected AppBaseService appBaseService;
@Inject protected TranslationService translationService;
protected static final String FULL_NAME_FORMAT = "[%s] %s";
@Inject protected BarcodeGeneratorService barcodeGeneratorService;
@Override
public StockMoveLineLocation save(StockMoveLineLocation entity) {
if (entity.getBarCodeSeq() == null
&& appBaseService.getAppBase().getActivateBarCodeGeneration()) {
try {
boolean addPadding = false;
InputStream inStream;
if (!appBaseService.getAppBase().getEditProductBarcodeType()) {
inStream =
barcodeGeneratorService.createBarCode(
entity.getCode(), appBaseService.getAppBase().getBarcodeTypeConfig(), addPadding);
} else {
inStream =
barcodeGeneratorService.createBarCode(
entity.getCode(), appBaseService.getAppBase().getBarcodeTypeConfig(), addPadding);
}
if (inStream != null) {
MetaFile barcodeFile =
metaFiles.upload(
inStream, String.format("StockMoveLineLocationCode%d.png", entity.getId()));
entity.setBarCodeSeq(barcodeFile);
}
} catch (IOException e) {
e.printStackTrace();
} catch (AxelorException e) {
throw new ValidationException(e.getMessage());
}
}
return super.save(entity);
}
}

View File

@@ -47,6 +47,7 @@ import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -80,8 +81,17 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
this.wapHistoryRepo = wapHistoryRepo;
}
private static final List<Long> NO_UNIT_CONVERSION_LOCATION_IDS = Arrays.asList(12L,97L, 98L, 99L, 100L, 103L, 104L, 105L,
106L);
private boolean isNoUnitConversionLocation(StockLocation location) {
return location != null
&& location.getId() != null
&& NO_UNIT_CONVERSION_LOCATION_IDS.contains(location.getId());
}
@Override
@Transactional(rollbackOn = {Exception.class})
@Transactional(rollbackOn = { Exception.class })
public void updateLocation(
StockLocation stockLocation,
Product product,
@@ -105,7 +115,8 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
isIncrement,
lastFutureStockMoveDate);
if (trackingNumber != null ) {
if (trackingNumber != null) {
LOG.debug("trackingNumber != null in updateLocation ****** ");
this.updateDetailLocation(
stockLocation,
product,
@@ -117,10 +128,12 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
lastFutureStockMoveDate,
trackingNumber);
}
LOG.debug("updateLocation passed qll updateLocation ");
}
@Override
@Transactional(rollbackOn = {Exception.class})
@Transactional(rollbackOn = { Exception.class })
public void updateLocation(
StockLocation stockLocation,
Product product,
@@ -132,19 +145,33 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
LocalDate lastFutureStockMoveDate)
throws AxelorException {
StockLocationLine stockLocationLine = this.getOrCreateStockLocationLine(stockLocation, product);
StockLocationLine stockLocationLine;
if (isNoUnitConversionLocation(stockLocation)) {
LOG.debug("updateLocation ** isNoUnitConversionLocation");
stockLocationLine = this.getOrCreateStockLocationLine(stockLocation, product, product.getUnit());
} else {
stockLocationLine = this.getOrCreateStockLocationLine(stockLocation, product);
}
if (stockLocationLine == null) {
return;
}
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
Unit stockLocationLineUnit = stockLocationLine.getUnit();
LOG.debug(
"Mise à jour du stock : Entrepot? {}, Produit? {}, Quantité? {}, Actuel? {}, Futur? {}, Incrément? {}, Date? {} ",
stockLocation.getName(),
product.getCode());
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
qty =
unitConversionService.convert(
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
// bypassing labo
if (!isNoUnitConversionLocation(stockLocation)) {
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
Unit stockLocationLineUnit = stockLocationLine.getUnit();
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
qty = unitConversionService.convert(
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
}
}
LOG.debug(
@@ -163,6 +190,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
maxStockRules(product, qty, stockLocationLine, current, future);
}
stockLocationLine =
this.updateLocation(
stockLocationLine,
@@ -176,6 +204,9 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
this.checkStockMin(stockLocationLine, false);
LOG.debug("updateLocation passed min max stock rules ");
stockLocationLineRepo.save(stockLocationLine);
}
@@ -265,20 +296,33 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
TrackingNumber trackingNumber)
throws AxelorException {
StockLocationLine detailLocationLine =
this.getOrCreateDetailLocationLine(stockLocation, product, trackingNumber);
StockLocationLine detailLocationLine;
if (isNoUnitConversionLocation(stockLocation)) {
detailLocationLine = this.getDetailLocationLineUnit(
stockLocation, product, trackingNumber, product.getUnit());
if (detailLocationLine == null) {
detailLocationLine = this.createDetailLocationLine(stockLocation, product, trackingNumber);
detailLocationLine.setUnit(stockMoveLineUnit);
}
} else {
detailLocationLine = this.getOrCreateDetailLocationLine(stockLocation, product, trackingNumber);
}
if (detailLocationLine == null) {
return;
}
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
Unit stockLocationLineUnit = detailLocationLine.getUnit();
if (!isNoUnitConversionLocation(stockLocation)) {
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
qty =
unitConversionService.convert(
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
Unit stockLocationLineUnit = detailLocationLine.getUnit();
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
qty = unitConversionService.convert(
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
}
}
LOG.debug(
@@ -426,8 +470,13 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
StockLocationLine detailLocationLine =
this.getDetailLocationLine(detailLocation, product, trackingNumber);
if (detailLocationLine == null) {
List<Long> listOfIds = Arrays.asList(12L, 97L, 98L, 99L, 100L, 103L, 104L, 105L, 106L);
if (listOfIds.contains(detailLocation.getId())) {
detailLocationLine = this.getDetailLocationLineUnit(detailLocation, product, trackingNumber, product.getUnit());
}
if (detailLocationLine == null) {
detailLocationLine = this.createDetailLocationLine(detailLocation, product, trackingNumber);
}
@@ -476,17 +525,16 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
public StockLocationLine getDetailLocationLine(
StockLocation stockLocation, Product product, TrackingNumber trackingNumber) {
return stockLocationLineRepo
.all()
.filter(
"self.detailsStockLocation.id = :_stockLocationId "
+ "AND self.product.id = :_productId "
+ "AND self.trackingNumber.id = :_trackingNumberId "
)
.bind("_stockLocationId", stockLocation.getId())
.bind("_productId", product.getId())
.bind("_trackingNumberId", trackingNumber.getId())
.fetchOne();
return stockLocationLineRepo
.all()
.filter(
"self.detailsStockLocation.id = :_stockLocationId "
+ "AND self.product.id = :_productId "
+ "AND self.trackingNumber.id = :_trackingNumberId ")
.bind("_stockLocationId", stockLocation.getId())
.bind("_productId", product.getId())
.bind("_trackingNumberId", trackingNumber.getId())
.fetchOne();
}
@Override
@@ -544,7 +592,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
}
@Override
@Transactional(rollbackOn = {Exception.class})
@Transactional(rollbackOn = { Exception.class })
public void updateStockLocationFromProduct(StockLocationLine stockLocationLine, Product product)
throws AxelorException {
@@ -564,13 +612,12 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
BigDecimal oldAvgPrice = stockLocationLine.getAvgPrice();
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
BigDecimal currentQty =
unitConversionService.convert(
stockLocationUnit,
productUnit,
stockLocationLine.getCurrentQty(),
stockLocationLine.getCurrentQty().scale(),
product);
BigDecimal currentQty = unitConversionService.convert(
stockLocationUnit,
productUnit,
stockLocationLine.getCurrentQty(),
stockLocationLine.getCurrentQty().scale(),
product);
stockLocationLine.setCurrentQty(currentQty);
stockLocationLine.setUnit(product.getUnit());
@@ -586,14 +633,14 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
return stockLocationLine;
}
protected static final String STOCK_MOVE_LINE_FILTER =
"(self.stockMove.archived IS NULL OR self.archived IS FALSE) "
+ "AND self.stockMove.statusSelect = :planned "
+ "AND self.product.id = :productId ";
protected static final String STOCK_MOVE_LINE_FILTER = "(self.stockMove.archived IS NULL OR self.archived IS FALSE) "
+ "AND self.stockMove.statusSelect = :planned "
+ "AND self.product.id = :productId ";
@Override
public BigDecimal computeFutureQty(StockLocationLine stockLocationLine) throws AxelorException {
// future quantity is current quantity minus planned outgoing stock move lines plus planned
// future quantity is current quantity minus planned outgoing stock move lines
// plus planned
// incoming stock move lines.
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
@@ -601,31 +648,36 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
BigDecimal futureQty = stockLocationLine.getCurrentQty();
List<StockMoveLine> incomingStockMoveLineList =
findIncomingPlannedStockMoveLines(stockLocationLine);
List<StockMoveLine> outgoingStockMoveLineList =
findOutgoingPlannedStockMoveLines(stockLocationLine);
List<StockMoveLine> incomingStockMoveLineList = findIncomingPlannedStockMoveLines(stockLocationLine);
List<StockMoveLine> outgoingStockMoveLineList = findOutgoingPlannedStockMoveLines(stockLocationLine);
for (StockMoveLine incomingStockMoveLine : incomingStockMoveLineList) {
BigDecimal qtyToAdd =
unitConversionService.convert(
incomingStockMoveLine.getUnit(),
stockLocationLine.getUnit(),
incomingStockMoveLine.getRealQty(),
incomingStockMoveLine.getRealQty().scale(),
product);
// bypassing labo
BigDecimal qtyToAdd = incomingStockMoveLine.getRealQty();
if(!isNoUnitConversionLocation(stockLocationLine.getStockLocation())){
qtyToAdd = unitConversionService.convert(
incomingStockMoveLine.getUnit(),
stockLocationLine.getUnit(),
incomingStockMoveLine.getRealQty(),
incomingStockMoveLine.getRealQty().scale(),
product);
}
futureQty = futureQty.add(qtyToAdd);
}
for (StockMoveLine outgoingStockMoveLine : outgoingStockMoveLineList) {
BigDecimal qtyToSubtract =
unitConversionService.convert(
outgoingStockMoveLine.getUnit(),
stockLocationLine.getUnit(),
outgoingStockMoveLine.getRealQty(),
outgoingStockMoveLine.getRealQty().scale(),
product);
futureQty = futureQty.subtract(qtyToSubtract);
BigDecimal qtyToSubtract = outgoingStockMoveLine.getRealQty();
if(!isNoUnitConversionLocation(stockLocationLine.getStockLocation())){
qtyToSubtract = unitConversionService.convert(
outgoingStockMoveLine.getUnit(),
stockLocationLine.getUnit(),
outgoingStockMoveLine.getRealQty(),
outgoingStockMoveLine.getRealQty().scale(),
product);
}
futureQty = futureQty.subtract(qtyToSubtract);
}
return futureQty;
@@ -634,18 +686,16 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
protected List<StockMoveLine> findIncomingPlannedStockMoveLines(
StockLocationLine stockLocationLine) {
boolean isDetailsStockLocationLine = stockLocationLine.getDetailsStockLocation() != null;
String incomingStockMoveLineFilter =
STOCK_MOVE_LINE_FILTER + "AND self.stockMove.toStockLocation.id = :stockLocationId";
String incomingStockMoveLineFilter = STOCK_MOVE_LINE_FILTER
+ "AND self.stockMove.toStockLocation.id = :stockLocationId";
if (isDetailsStockLocationLine) {
incomingStockMoveLineFilter =
incomingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
incomingStockMoveLineFilter = incomingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
}
Query<StockMoveLine> stockMoveLineQuery =
stockMoveLineRepository
.all()
.filter(incomingStockMoveLineFilter)
.bind("planned", StockMoveRepository.STATUS_PLANNED)
.bind("productId", stockLocationLine.getProduct().getId());
Query<StockMoveLine> stockMoveLineQuery = stockMoveLineRepository
.all()
.filter(incomingStockMoveLineFilter)
.bind("planned", StockMoveRepository.STATUS_PLANNED)
.bind("productId", stockLocationLine.getProduct().getId());
if (isDetailsStockLocationLine) {
stockMoveLineQuery
.bind("stockLocationId", stockLocationLine.getDetailsStockLocation().getId())
@@ -659,18 +709,16 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
protected List<StockMoveLine> findOutgoingPlannedStockMoveLines(
StockLocationLine stockLocationLine) {
boolean isDetailsStockLocationLine = stockLocationLine.getDetailsStockLocation() != null;
String outgoingStockMoveLineFilter =
STOCK_MOVE_LINE_FILTER + "AND self.stockMove.fromStockLocation.id = :stockLocationId";
String outgoingStockMoveLineFilter = STOCK_MOVE_LINE_FILTER
+ "AND self.stockMove.fromStockLocation.id = :stockLocationId";
if (isDetailsStockLocationLine) {
outgoingStockMoveLineFilter =
outgoingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
outgoingStockMoveLineFilter = outgoingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
}
Query<StockMoveLine> stockMoveLineQuery =
stockMoveLineRepository
.all()
.filter(outgoingStockMoveLineFilter)
.bind("planned", StockMoveRepository.STATUS_PLANNED)
.bind("productId", stockLocationLine.getProduct().getId());
Query<StockMoveLine> stockMoveLineQuery = stockMoveLineRepository
.all()
.filter(outgoingStockMoveLineFilter)
.bind("planned", StockMoveRepository.STATUS_PLANNED)
.bind("productId", stockLocationLine.getProduct().getId());
if (isDetailsStockLocationLine) {
stockMoveLineQuery
@@ -686,25 +734,21 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
public String getStockLocationLineListForAProduct(
Long productId, Long companyId, Long stockLocationId) {
String query =
"self.product.id = "
+ productId
+ " AND self.stockLocation.typeSelect != "
+ StockLocationRepository.TYPE_VIRTUAL;
String query = "self.product.id = "
+ productId
+ " AND self.stockLocation.typeSelect != "
+ StockLocationRepository.TYPE_VIRTUAL;
if (companyId != 0L) {
query += " AND self.stockLocation.company.id = " + companyId;
if (stockLocationId != 0L) {
StockLocation stockLocation =
Beans.get(StockLocationRepository.class).find(stockLocationId);
List<StockLocation> stockLocationList =
Beans.get(StockLocationService.class)
.getAllLocationAndSubLocation(stockLocation, false);
StockLocation stockLocation = Beans.get(StockLocationRepository.class).find(stockLocationId);
List<StockLocation> stockLocationList = Beans.get(StockLocationService.class)
.getAllLocationAndSubLocation(stockLocation, false);
if (!stockLocationList.isEmpty() && stockLocation.getCompany().getId().equals(companyId)) {
query +=
" AND self.stockLocation.id IN ("
+ StringTool.getIdListString(stockLocationList)
+ ") ";
query += " AND self.stockLocation.id IN ("
+ StringTool.getIdListString(stockLocationList)
+ ") ";
}
}
}
@@ -714,9 +758,8 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
@Override
public String getAvailableStockForAProduct(Long productId, Long companyId, Long stockLocationId) {
String query = this.getStockLocationLineListForAProduct(productId, companyId, stockLocationId);
query +=
" AND (self.currentQty != 0 OR self.futureQty != 0) "
+ " AND (self.stockLocation.isNotInCalculStock = false OR self.stockLocation.isNotInCalculStock IS NULL)";
query += " AND (self.currentQty != 0 OR self.futureQty != 0) "
+ " AND (self.stockLocation.isNotInCalculStock = false OR self.stockLocation.isNotInCalculStock IS NULL)";
return query;
}
@@ -750,8 +793,8 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
@Override
public BigDecimal getTrackingNumberAvailableQty(
StockLocation stockLocation, TrackingNumber trackingNumber) {
StockLocationLine detailStockLocationLine =
getDetailLocationLine(stockLocation, trackingNumber.getProduct(), trackingNumber);
StockLocationLine detailStockLocationLine = getDetailLocationLine(stockLocation, trackingNumber.getProduct(),
trackingNumber);
BigDecimal availableQty = BigDecimal.ZERO;
@@ -760,4 +803,88 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
}
return availableQty;
}
public StockLocationLine getStockLocationLineUnit(StockLocation stockLocation, Product product, Unit unit) {
if (product == null || !product.getStockManaged()) {
return null;
}
return stockLocationLineRepo
.all()
.filter("self.stockLocation.id = :_stockLocationId " + " AND self.product.id = :_productId "
+ " AND self.unit.id = :_unitId")
.bind("_stockLocationId", stockLocation.getId())
.bind("_productId", product.getId())
.bind("_unitId", unit.getId())
.fetchOne();
}
public StockLocationLine getDetailLocationLineUnit(
StockLocation stockLocation, Product product, TrackingNumber trackingNumber, Unit unit) {
return stockLocationLineRepo
.all()
.filter(
"self.detailsStockLocation.id = :_stockLocationId "
+ "AND self.product.id = :_productId "
+ "AND self.trackingNumber.id = :_trackingNumberId "
+ "AND self.unit.id = :_unitId ")
.bind("_stockLocationId", stockLocation.getId())
.bind("_productId", product.getId())
.bind("_trackingNumberId", trackingNumber.getId())
.bind("_unitId", unit.getId())
.fetchOne();
}
public StockLocationLine createLocationLineUnit(StockLocation stockLocation, Product product, Unit unit) {
LOG.debug(
"Création d'une ligne de stock : Entrepot? {}, Produit? {} ",
stockLocation.getName(),
product.getCode());
StockLocationLine stockLocationLine = new StockLocationLine();
stockLocationLine.setStockLocation(stockLocation);
stockLocation.addStockLocationLineListItem(stockLocationLine);
stockLocationLine.setProduct(product);
stockLocationLine.setUnit(unit);
stockLocationLine.setCurrentQty(BigDecimal.ZERO);
stockLocationLine.setFutureQty(BigDecimal.ZERO);
stockLocationLine.setConformitySelect(4); // Quarantine
return stockLocationLine;
}
public StockLocationLine getOrCreateStockLocationLine(
StockLocation stockLocation, Product product, Unit stockMoveLineUnit) {
if (!product.getStockManaged()) {
return null;
}
StockLocationLine line;
if (isNoUnitConversionLocation(stockLocation)) {
LOG.debug("getOrCreateStockLocationLine stockMoveLineUnit ** isNoUnitConversionLocation");
// 🔥 STRICT (location + product + unit)
line = getStockLocationLineUnit(stockLocation, product, product.getUnit());
if (line == null) {
LOG.debug("getOrCreateStockLocationLine stockMoveLineUnit ** isNoUnitConversionLocation line == null");
line = createLocationLineUnit(stockLocation, product, product.getUnit());
}
} else {
// 🧠 Default Axelor behavior
line = getStockLocationLine(stockLocation, product);
if (line == null) {
line = createLocationLine(stockLocation, product);
}
}
return line;
}
}

View File

@@ -470,39 +470,54 @@ public class StockMoveLineServiceImpl implements StockMoveLineService {
lastFutureStockMoveDate,
stockMoveLine.getTrackingNumber(),
stockMoveLine.getInternalTrackingNumber());
if (fromStockLocation.getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL) {
this.updateAveragePriceLocationLine(toStockLocation, stockMoveLine, fromStatus, toStatus);
weightedAveragePriceService.computeAvgPriceForProduct(stockMoveLine.getProduct());
}
List<Long> listOfIds = Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L,50L);
if(toStatus == StockMoveRepository.STATUS_REALIZED){
log.debug("locations updated succes*******");
List<Long> listOfIdsLab = Arrays.asList(97L, 98L, 99L, 100L, 103L, 104L, 105L, 106L);
if(!listOfIdsLab.contains(toStockLocation.getId())){
if (fromStockLocation.getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL && stockMoveLine.getStockMove().getPartner() != null) {
if(stockMoveLine.getStockMove().getPartner().getId() != 853L){
this.updateAveragePriceLocationLine(toStockLocation, stockMoveLine, fromStatus, toStatus);
weightedAveragePriceService.computeAvgPriceForProduct(stockMoveLine.getProduct());
}
}
List<Long> listOfIds = Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L, 50L);
if (toStatus == StockMoveRepository.STATUS_REALIZED) {
if (stockMoveLine.getTrackingNumber() != null && stockMoveLine.getRealQty().compareTo(BigDecimal.ZERO) != 0) {
if (stockMoveLine.getStockMove() != null) {
if (stockMoveLine.getStockMove().getTypeSelect() == StockMoveRepository.TYPE_INCOMING) {
StockLocationLine toStockLocationLine = Beans.get(StockLocationLineService.class).getDetailLocationLine(
StockLocationLine toStockLocationLine =
Beans.get(StockLocationLineService.class)
.getDetailLocationLine(
toStockLocation, product, stockMoveLine.getTrackingNumber());
// TODO WMS
// TODO WMS
if (toStockLocationLine != null) {
// if(listOfIds.contains(fromStockLocation.getId())){
if(stockMoveLine.getStockMove().getPartner().getId() != 853L){
toStockLocationLine.setConformitySelect(StockLocationRepository.TYPE_QUARANTINE);
if (stockMoveLine.getStockMove().getPartner().getId() != 853L) {
toStockLocationLine.setConformitySelect(
StockLocationRepository.TYPE_QUARANTINE);
Beans.get(StockLocationLineRepository.class).save(toStockLocationLine);
}else{
if(stockMoveLine.getRealQty().compareTo(toStockLocationLine.getCurrentQty()) == 0){
toStockLocationLine.setConformitySelect(StockLocationRepository.TYPE_QUARANTINE);
} else {
if (stockMoveLine.getRealQty().compareTo(toStockLocationLine.getCurrentQty())
== 0) {
toStockLocationLine.setConformitySelect(
StockLocationRepository.TYPE_QUARANTINE);
Beans.get(StockLocationLineRepository.class).save(toStockLocationLine);
}
}
}
} else if (stockMoveLine.getStockMove().getTypeSelect() == StockMoveRepository.TYPE_INTERNAL) {
StockLocationLine fromStockLocationLine = Beans.get(StockLocationLineService.class).getDetailLocationLine(
fromStockLocation, product, stockMoveLine.getTrackingNumber() );
StockLocationLine toStockLocationLine = Beans.get(StockLocationLineService.class).getDetailLocationLine(
toStockLocation, product, stockMoveLine.getTrackingNumber());
StockLocationLine fromStockLocationLine = Beans.get(StockLocationLineService.class)
.getDetailLocationLine(fromStockLocation, product, stockMoveLine.getTrackingNumber());
StockLocationLine toStockLocationLine = Beans.get(StockLocationLineService.class)
.getDetailLocationLine(toStockLocation, product, stockMoveLine.getTrackingNumber());
log.debug(
"fromStockLocationLine: {}, toStockLocationLine: {}, fromStockLocationLineConformity: {}, toStockLocationLineConformity: {}",
fromStockLocationLine,toStockLocationLine,fromStockLocationLine.getConformitySelect(),toStockLocationLine.getConformitySelect());
fromStockLocationLine,
toStockLocationLine,
fromStockLocationLine.getConformitySelect(),
toStockLocationLine.getConformitySelect());
if (toStockLocationLine != null && toStockLocationLine.getCurrentQty().compareTo(BigDecimal.ZERO) != 0) {
toStockLocationLine.setConformitySelect(fromStockLocationLine.getConformitySelect());
toStockLocationLine.setAnalysisFolderValidated(fromStockLocationLine.getAnalysisFolderValidated());
@@ -513,7 +528,9 @@ public class StockMoveLineServiceImpl implements StockMoveLineService {
}
}
}
}
}
}
}

View File

@@ -241,11 +241,10 @@ public interface StockMoveService {
public void massCancel(List<Long> requestIds, CancelReason raison, String raisonStr)
throws AxelorException;
public void massDraft(List<Long> requestIds) throws AxelorException;
public void massPlan(List<Long> requestIds) throws AxelorException;
public void massDraft(List<Long> requestIds) throws AxelorException;
public void massRealize(List<Long> requestIds) throws AxelorException;
public void massPlan(List<Long> requestIds) throws AxelorException;
public void massRealize(List<Long> requestIds) throws AxelorException;
}

View File

@@ -45,6 +45,7 @@ import com.axelor.apps.stock.db.StockLocation;
import com.axelor.apps.stock.db.StockMove;
import com.axelor.apps.stock.db.StockMoveLine;
import com.axelor.apps.stock.db.StockMoveLineLocationLine;
import com.axelor.apps.stock.db.TrackingNumber;
import com.axelor.apps.stock.db.repo.InternalTrackingNumberRepository;
import com.axelor.apps.stock.db.repo.InventoryLineRepository;
import com.axelor.apps.stock.db.repo.InventoryRepository;
@@ -60,8 +61,6 @@ import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.inject.Inject;
@@ -79,9 +78,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -421,22 +418,40 @@ public class StockMoveServiceImpl implements StockMoveService {
System.out.println("Checking oooo...................");
// checking .....
if (stockMove.getFromStockLocation().getTypeSelect() != StockLocationRepository.TYPE_VIRTUAL)
{
List<Long> listOfIds = Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L, 13L, 12L, 54L, 55L, 58L,50L);
System.out.println("Checking...................");
System.out.println(listOfIds.contains(stockMove.getToStockLocation().getId()));
System.out.println("Checking...................");
if (stockMove.getFromStockLocation().getTypeSelect() != StockLocationRepository.TYPE_VIRTUAL) {
List<Long> listOfIds =
Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L, 13L, 12L, 54L, 55L, 58L, 50L);
if(listOfIds.contains(stockMove.getToStockLocation().getId())){
checkIfQuarantine(stockMove);
checkIfNonConformityTag(stockMove);
}
if (listOfIds.contains(stockMove.getToStockLocation().getId())) {
StockConfig stockConfig =
Beans.get(StockConfigRepository.class)
.all()
.filter("self.company = ?", stockMove.getCompany())
.fetchOne();
List<Product> excludedProducts =
stockConfig != null
? stockConfig.getExludedProductsFromWrkFlw()
: Collections.emptyList();
List<Long> excludedProductIds =
excludedProducts
.stream()
.filter(Objects::nonNull)
.map(Product::getId)
.collect(Collectors.toList());
System.out.println("***********************************excludedProductIds***************");
System.out.println(excludedProductIds);
checkIfQuarantine(stockMove, excludedProductIds);
checkIfNonConformityTag(stockMove, excludedProductIds);
}
}
checkExpirationDates(stockMove);
if (stockMove.getTypeSelect() == StockMoveRepository.TYPE_INCOMING) {
if (stockMove.getTypeSelect() == StockMoveRepository.TYPE_INCOMING) {
partnerProductQualityRatingService.calculate(stockMove);
stockMove
@@ -454,64 +469,75 @@ public class StockMoveServiceImpl implements StockMoveService {
stockMoveLineLocationLine.setTrackingNumber(line.getTrackingNumber());
st.addStockMoveLineLocationLineSetItem(stockMoveLineLocationLine);
});
Long partnerId = stockMove.getPartner().getId();
Long familleId = line.getProduct().getFamilleProduit().getId();
BigDecimal realQty = line.getRealQty();
Long partnerId = stockMove.getPartner().getId();
Long familleId = line.getProduct().getFamilleProduit().getId();
BigDecimal realQty = line.getRealQty();
if (!partnerId.equals(853L) && (familleId == 59L || familleId == 67L || familleId == 68L)) {
System.out.println("****!partnerId.equals(853L) && (familleId == 59L || familleId == 67L || familleId == 68L)");
InternalTrackingNumberService internalTrackingNumberService = Beans.get(InternalTrackingNumberService.class);
InternalTrackingNumberRepository internalTrackingNumberRepo = Beans.get(InternalTrackingNumberRepository.class);
StockMoveLineRepository stockMoveLineRepo = Beans.get(StockMoveLineRepository.class);
if (!partnerId.equals(853L)
&& (familleId == 59L || familleId == 67L || familleId == 68L)) {
System.out.println(
"****!partnerId.equals(853L) && (familleId == 59L || familleId == 67L || familleId == 68L)");
InternalTrackingNumberService internalTrackingNumberService =
Beans.get(InternalTrackingNumberService.class);
InternalTrackingNumberRepository internalTrackingNumberRepo =
Beans.get(InternalTrackingNumberRepository.class);
StockMoveLineRepository stockMoveLineRepo =
Beans.get(StockMoveLineRepository.class);
try {
InternalTrackingNumber internalTrackingNumber = internalTrackingNumberService.getInternalTrackingNumber(
line.getProduct(), line.getTrackingNumber());
try {
InternalTrackingNumber internalTrackingNumber =
internalTrackingNumberService.getInternalTrackingNumber(
line.getProduct(), line.getTrackingNumber());
if (realQty.compareTo(BigDecimal.ZERO) > 0) {
if (realQty.compareTo(BigDecimal.ZERO) > 0) {
if (internalTrackingNumber == null) {
InternalTrackingNumber internal = internalTrackingNumberService.createInternalTrackingNumber(
line.getProduct(),
line.getStockMove().getCompany(),
stockMove.getEstimatedDate(),
line.getTrackingNumber());
System.out.println("***********************************internal***************");
System.out.println(internal);
System.out.println("***********************************internal**********************");
InternalTrackingNumber internal =
internalTrackingNumberService.createInternalTrackingNumber(
line.getProduct(),
line.getStockMove().getCompany(),
stockMove.getEstimatedDate(),
line.getTrackingNumber());
System.out.println(
"***********************************internal***************");
System.out.println(internal);
System.out.println(
"***********************************internal**********************");
line.setInternalTrackingNumber(internal);
internalTrackingNumberRepo.save(internal);
line.setInternalTrackingNumber(internal);
internalTrackingNumberRepo.save(internal);
} else {
LocalDate createdDate = internalTrackingNumber.getReceptionDate();
LocalDate estimatedDate = stockMove.getEstimatedDate();
System.out.println("***********************************internal not null***************");
System.out.println(internalTrackingNumber);
System.out.println(createdDate);
System.out.println(estimatedDate);
System.out.println("***********************************internal noy null**********************");
LocalDate createdDate = internalTrackingNumber.getReceptionDate();
LocalDate estimatedDate = stockMove.getEstimatedDate();
System.out.println(
"***********************************internal not null***************");
System.out.println(internalTrackingNumber);
System.out.println(createdDate);
System.out.println(estimatedDate);
System.out.println(
"***********************************internal noy null**********************");
if (createdDate.equals(estimatedDate)) {
line.setInternalTrackingNumber(internalTrackingNumber);
stockMoveLineRepo.save(line);
}else{
InternalTrackingNumber internal = internalTrackingNumberService.createInternalTrackingNumber(
line.getProduct(),
line.getStockMove().getCompany(),
stockMove.getEstimatedDate(),
line.getTrackingNumber());
if (createdDate.equals(estimatedDate)) {
line.setInternalTrackingNumber(internalTrackingNumber);
stockMoveLineRepo.save(line);
} else {
InternalTrackingNumber internal =
internalTrackingNumberService.createInternalTrackingNumber(
line.getProduct(),
line.getStockMove().getCompany(),
stockMove.getEstimatedDate(),
line.getTrackingNumber());
line.setInternalTrackingNumber(internal);
stockMoveLineRepo.save(line);
}
line.setInternalTrackingNumber(internal);
stockMoveLineRepo.save(line);
}
}
}
} catch (AxelorException e) {
e.printStackTrace(); // Consider logging this instead of printing.
}
} catch (AxelorException e) {
e.printStackTrace(); // Consider logging this instead of printing.
}
}
});
}
});
}
setRealizedStatus(stockMove);
@@ -1507,7 +1533,7 @@ public class StockMoveServiceImpl implements StockMoveService {
newStockMoveLine.setPpa(moveLine.getPpa());
newStockMoveLine.setPvg(moveLine.getPvg());
newStockMoveLine.setStklim(moveLine.getStklim());
newStockMoveLine.setShp(moveLine.getShp());
newStockMoveLine.setShp(moveLine.getShp());
newStockMoveLine.setRealQty(moveLine.getQty());
newStockMoveLine.setProductTypeSelect(moveLine.getProductTypeSelect());
// add stock move line
@@ -1591,57 +1617,84 @@ public class StockMoveServiceImpl implements StockMoveService {
}
}
public void checkIfQuarantine(StockMove stockMove)
public void checkIfQuarantine(StockMove stockMove, List<Long> excludedProductIds)
throws AxelorException {
Query sql =
JPA.em()
.createNativeQuery(
"SELECT LINE.ID"+
" FROM STOCK_STOCK_MOVE_LINE LINE LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER and LINE.INTERNAL_TRACKING_NUMBER = LOCATION_LINE.INTERNAL_TRACKING_NUMBER and LINE.product = LOCATION_LINE.product"+
" where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.CONFORMITY_SELECT != 2 AND LOCATION_LINE.CONFORMITY_SELECT != 5 AND LINE.STOCK_MOVE = ?2");
sql.setParameter(1, stockMove.getFromStockLocation().getId());
sql.setParameter(2, stockMove.getId());
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append(
"SELECT LINE.ID"
+ " FROM STOCK_STOCK_MOVE_LINE LINE"
+ " LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON"
+ " LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER"
+
// " AND LINE.INTERNAL_TRACKING_NUMBER = LOCATION_LINE.INTERNAL_TRACKING_NUMBER" +
" AND LINE.product = LOCATION_LINE.product"
+ " WHERE LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1"
+ " AND LOCATION_LINE.CONFORMITY_SELECT != 2"
+ " AND LOCATION_LINE.CONFORMITY_SELECT != 5"
+ " AND LINE.STOCK_MOVE = ?2");
System.out.println("*****************checkIfQuarantine******************");
System.out.println(sql.getResultList().size() > 0);
System.out.println("******************checkIfQuarantine*****************");
if (sql.getResultList().size() > 0) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"Vous avez une ligne en etat qurantaine");
}
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
queryBuilder.append(" AND LINE.product NOT IN (:excludedProducts)");
}
public void checkIfNonConformityTag(StockMove stockMove)
throws AxelorException {
Query sql =
JPA.em()
.createNativeQuery(
"SELECT LINE.ID" +
" FROM STOCK_STOCK_MOVE_LINE LINE LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER and LINE.INTERNAL_TRACKING_NUMBER = LOCATION_LINE.INTERNAL_TRACKING_NUMBER and LINE.product = LOCATION_LINE.product" +
" where LOCATION_LINE.DETAILS_STOCK_LOCATION = :location AND LOCATION_LINE.is_conform_tag is not true AND LINE.STOCK_MOVE = :move");
sql.setParameter("location", stockMove.getFromStockLocation().getId());
sql.setParameter("move", stockMove.getId());
System.out.println("checkIfQuarantine query : ");
System.out.println(queryBuilder.toString());
System.out.println("*****************checkIfNonConformityTag*****************");
System.out.println(sql.getResultList().size() > 0);
System.out.println("*****************checkIfNonConformityTag****************");
Query sql = JPA.em().createNativeQuery(queryBuilder.toString());
sql.setParameter(1, stockMove.getFromStockLocation().getId());
sql.setParameter(2, stockMove.getId());
if (sql.getResultList().size() > 0) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"Vous avez une ligne non étiquetée");
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
sql.setParameter("excludedProducts", excludedProductIds);
}
if (!sql.getResultList().isEmpty()) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"Vous avez une ligne en état quarantaine");
}
}
@Override
public void massPlan(List<Long> moveIds) throws AxelorException {
public void checkIfNonConformityTag(StockMove stockMove, List<Long> excludedProductIds)
throws AxelorException {
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append(
"SELECT LINE.ID"
+ " FROM STOCK_STOCK_MOVE_LINE LINE"
+ " LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON"
+ " LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER"
+
// " AND LINE.INTERNAL_TRACKING_NUMBER = LOCATION_LINE.INTERNAL_TRACKING_NUMBER" +
" AND LINE.product = LOCATION_LINE.product"
+ " WHERE LOCATION_LINE.DETAILS_STOCK_LOCATION = :location"
+ " AND (LOCATION_LINE.is_conform_tag IS NULL OR LOCATION_LINE.is_conform_tag != TRUE)"
+ " AND LINE.STOCK_MOVE = :move");
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
queryBuilder.append(" AND LINE.product NOT IN (:excludedProducts)");
}
Query sql = JPA.em().createNativeQuery(queryBuilder.toString());
sql.setParameter("location", stockMove.getFromStockLocation().getId());
sql.setParameter("move", stockMove.getId());
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
sql.setParameter("excludedProducts", excludedProductIds);
}
if (!sql.getResultList().isEmpty()) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"Vous avez une ligne non étiquetée");
}
}
@Override
public void massPlan(List<Long> moveIds) throws AxelorException {
if (moveIds == null || moveIds.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_MISSING_FIELD, "Please Select at least one StockMove");
@@ -1654,10 +1707,10 @@ public class StockMoveServiceImpl implements StockMoveService {
this.plan(stockMove);
}
}
}
}
@Override
public void massRealize(List<Long> moveIds) throws AxelorException {
@Override
public void massRealize(List<Long> moveIds) throws AxelorException {
if (moveIds == null || moveIds.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_MISSING_FIELD, "Please Select at least one StockMove");
@@ -1670,11 +1723,11 @@ public class StockMoveServiceImpl implements StockMoveService {
this.realize(stockMove);
}
}
}
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void massDraft(List<Long> moveIds) throws AxelorException {
@Override
@Transactional(rollbackOn = {Exception.class})
public void massDraft(List<Long> moveIds) throws AxelorException {
if (moveIds == null || moveIds.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_MISSING_FIELD, "Please Select at least one StockMove");
@@ -1687,11 +1740,74 @@ public class StockMoveServiceImpl implements StockMoveService {
stockMove.setStatusSelect(StockMoveRepository.STATUS_DRAFT);
}
}
}
}
// public boolean isProductExcluded(StockMove stockMove){
// public boolean isExcludedFromWorkflow(StockMove stockMove){
// StockConfig stockConfig =
// Beans.get(StockConfigRepository.class).all().filter("self.company = ?", stockMove.getCompany()).fetchOne();
// stockConfig.getExludedProductsFromWrkFlw();
// Beans.get(StockConfigRepository.class).all().filter("self.company = ?",
// stockMove.getCompany()).fetchOne();
// List<Product> producs = stockConfig.getExludedProductsFromWrkFlw();
// // all of stockmove lines products should be in the excluded products to say that the
// stockmove is excluded from workflow
// for (StockMoveLine line : stockMove.getStockMoveLineList()) {
// if(!producs.contains(line.getProduct())){
// return false;
// }
// }
// return true;
// }
@Transactional
public void createStockMoveLine(
StockMove stockMove,
Product product,
StockLocation stockLocation,
TrackingNumber trackingNumber)
throws AxelorException {
if (stockMove.getFromStockLocation() == stockLocation) {
System.out.println("yes ***********************");
}
StockMoveLine stockMoveLine =
Beans.get(StockMoveLineService.class)
.createStockMoveLine(
product,
product.getName(),
"",
BigDecimal.ZERO,
product.getAvgPrice(),
product.getAvgPrice(),
product.getAvgPrice(),
product.getUnit(),
stockMove,
trackingNumber);
stockMove.addStockMoveLineListItem(stockMoveLine);
Beans.get(StockMoveRepository.class).save(stockMove);
}
public void checkIfNonValidationFolder(StockMove stockMove) throws AxelorException {
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append(
"SELECT LINE.ID"
+ " FROM STOCK_STOCK_MOVE_LINE LINE"
+ " LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON"
+ " LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER"
+
// " AND LINE.INTERNAL_TRACKING_NUMBER = LOCATION_LINE.INTERNAL_TRACKING_NUMBER" +
" AND LINE.product = LOCATION_LINE.product"
+ " WHERE LOCATION_LINE.DETAILS_STOCK_LOCATION = :location"
+ " AND (LOCATION_LINE.analysisFolderValidated IS NULL OR LOCATION_LINE.analysisFolderValidated != TRUE)"
+ " AND LINE.STOCK_MOVE = :move");
Query sql = JPA.em().createNativeQuery(queryBuilder.toString());
sql.setParameter("location", stockMove.getFromStockLocation().getId());
sql.setParameter("move", stockMove.getId());
if (!sql.getResultList().isEmpty()) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"Vous avez une ligne de mouvement sans dossier d'analyse validé");
}
}
}

View File

@@ -133,14 +133,14 @@ public class StockMoveToolServiceImpl implements StockMoveToolService {
break;
case StockMoveRepository.TYPE_INCOMING_CLIENT:
ref = sequenceService.getSequenceNumber(SequenceRepository.INCOMING_CLIENT, company);
if (ref == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.STOCK_MOVE_3),
company.getName());
}
break;
ref = sequenceService.getSequenceNumber(SequenceRepository.INCOMING_CLIENT, company);
if (ref == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.STOCK_MOVE_3),
company.getName());
}
break;
case StockMoveRepository.TYPE_OUTGOING_CLIENT:
ref = sequenceService.getSequenceNumber(SequenceRepository.OUTGOING_CLIENT, company);
@@ -217,7 +217,7 @@ public class StockMoveToolServiceImpl implements StockMoveToolService {
}
// sequence for production request
public String getInternalSequence(int internalSequenceType, Company company ,LocalDate date)
public String getInternalSequence(int internalSequenceType, Company company, LocalDate date)
throws AxelorException {
String ref = "";

View File

@@ -20,18 +20,24 @@ package com.axelor.apps.stock.web;
import com.axelor.apps.base.db.CancelReason;
import com.axelor.apps.base.db.PrintingSettings;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.base.service.BarcodeGeneratorService;
import com.axelor.apps.base.service.TradingNameService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.stock.db.StockLocation;
import com.axelor.apps.stock.db.StockMove;
import com.axelor.apps.stock.db.StockMoveLine;
import com.axelor.apps.stock.db.StockMoveLineLocation;
import com.axelor.apps.stock.db.TrackingNumber;
import com.axelor.apps.stock.db.repo.StockLocationRepository;
import com.axelor.apps.stock.db.repo.StockMoveLineLocationRepository;
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
import com.axelor.apps.stock.db.repo.StockMoveRepository;
import com.axelor.apps.stock.db.repo.TrackingNumberRepository;
import com.axelor.apps.stock.exception.IExceptionMessage;
import com.axelor.apps.stock.service.StockMoveService;
import com.axelor.apps.stock.service.StockMoveServiceImpl;
import com.axelor.apps.stock.service.StockMoveToolService;
import com.axelor.apps.stock.service.stockmove.print.ConformityCertificatePrintService;
import com.axelor.apps.stock.service.stockmove.print.PickingStockMovePrintService;
@@ -181,14 +187,13 @@ public class StockMoveController {
List<Long> requestIds = (List<Long>) request.getContext().get("_ids");
CancelReason raison = (CancelReason) request.getContext().get("cancelRaison");
String raisonStr = (String) request.getContext().get("cancelRaisonStr");
StockMove stockMove = request.getContext().asType(StockMove.class);
// StockMove stockMove = request.getContext().asType(StockMove.class);
System.out.println("*********************************************");
System.out.println(raisonStr);
System.out.println(raison);
System.out.println(stockMove.getCancelReason());
System.out.println(stockMove.getCancelReasonStr());
// System.out.println(stockMove.getCancelReason());
// System.out.println(stockMove.getCancelReasonStr());
System.out.println("*********************************************");
if (requestIds == null || requestIds.isEmpty()) {
@@ -205,7 +210,7 @@ public class StockMoveController {
}
}
public void massPlan(ActionRequest request, ActionResponse response) {
public void massPlan(ActionRequest request, ActionResponse response) {
@SuppressWarnings("unchecked")
List<Long> requestIds = (List<Long>) request.getContext().get("_ids");
@@ -224,7 +229,7 @@ public class StockMoveController {
}
}
public void massRealize(ActionRequest request, ActionResponse response) {
public void massRealize(ActionRequest request, ActionResponse response) {
@SuppressWarnings("unchecked")
List<Long> requestIds = (List<Long>) request.getContext().get("_ids");
@@ -824,12 +829,12 @@ public class StockMoveController {
Query sql =
JPA.em()
.createNativeQuery(
"SELECT LINE.ID"+
" FROM STOCK_STOCK_MOVE_LINE LINE LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER and LINE.product = LOCATION_LINE.product"+
" where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.CONFORMITY_SELECT != 2 AND LOCATION_LINE.CONFORMITY_SELECT != 5 AND LINE.STOCK_MOVE = ?2");
"SELECT LINE.ID"
+ " FROM STOCK_STOCK_MOVE_LINE LINE LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER and LINE.product = LOCATION_LINE.product"
+ " where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.CONFORMITY_SELECT != 2 AND LOCATION_LINE.CONFORMITY_SELECT != 5 AND LINE.STOCK_MOVE = ?2");
sql.setParameter(1, stockMove.getFromStockLocation().getId());
sql.setParameter(2, stockMove.getId());
logger.debug("sql.getResultList().size()",sql.getResultList().size());
logger.debug("sql.getResultList().size()", sql.getResultList().size());
if (sql.getResultList().size() > 0) {
throw new AxelorException(
stockMove,
@@ -838,25 +843,25 @@ public class StockMoveController {
}
}
public void checkIfNonConformityTag(ActionRequest request, ActionResponse response)
public void checkIfNonConformityTag(ActionRequest request, ActionResponse response)
throws AxelorException {
StockMove stockMoveFromContext = request.getContext().asType(StockMove.class);
StockMove stockMove = Beans.get(StockMoveRepository.class).find(stockMoveFromContext.getId());
Query sql =
JPA.em()
.createNativeQuery(
"SELECT LINE.ID " +
" FROM STOCK_STOCK_MOVE_LINE LINE LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER and LINE.product = LOCATION_LINE.product"
+" where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.is_conform_tag is not true AND LINE.STOCK_MOVE = ?2");
sql.setParameter(1, stockMove.getToStockLocation().getId());
sql.setParameter(2, stockMove.getId());
logger.debug("sql.getResultList().size()",sql.getResultList().size());
if (sql.getResultList().size() > 0) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"vous avez une ligne non étiqueté");
StockMove stockMoveFromContext = request.getContext().asType(StockMove.class);
StockMove stockMove = Beans.get(StockMoveRepository.class).find(stockMoveFromContext.getId());
Query sql =
JPA.em()
.createNativeQuery(
"SELECT LINE.ID "
+ " FROM STOCK_STOCK_MOVE_LINE LINE LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON LINE.TRACKING_NUMBER = LOCATION_LINE.TRACKING_NUMBER and LINE.product = LOCATION_LINE.product"
+ " where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.is_conform_tag is not true AND LINE.STOCK_MOVE = ?2");
sql.setParameter(1, stockMove.getToStockLocation().getId());
sql.setParameter(2, stockMove.getId());
logger.debug("sql.getResultList().size()", sql.getResultList().size());
if (sql.getResultList().size() > 0) {
throw new AxelorException(
stockMove,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"vous avez une ligne non étiqueté");
}
}
@@ -900,4 +905,38 @@ public class StockMoveController {
public void showPopup(ActionRequest request, ActionResponse response) {
response.setAlert("Hello words!!");
}
public void createStockMoveLine(ActionRequest request, ActionResponse response)
throws AxelorException {
Context context = request.getContext();
String stockLocationLineStr = context.get("productHolder").toString();
if (stockLocationLineStr != null && !stockLocationLineStr.isEmpty()) {
String[] stockLocationLineArr = stockLocationLineStr.split("-");
String productId = stockLocationLineArr[0];
String locationId = stockLocationLineArr[1];
String trackingId = stockLocationLineArr[2];
Product product = Beans.get(ProductRepository.class).find(Long.valueOf(productId));
StockLocation stockLocation =
Beans.get(StockLocationRepository.class).find(Long.valueOf(locationId));
TrackingNumber trackingNumber =
Beans.get(TrackingNumberRepository.class).find(Long.valueOf(trackingId));
StockMove stockMove = context.asType(StockMove.class);
stockMove = Beans.get(StockMoveRepository.class).find(stockMove.getId());
if (stockMove.getFromStockLocation() == stockLocation) {
System.out.println("yes ***********************");
}
Beans.get(StockMoveServiceImpl.class)
.createStockMoveLine(stockMove, product, stockLocation, trackingNumber);
response.setReload(true);
}
}
public void checkIfNonValidationFolder(ActionRequest request, ActionResponse response)
throws AxelorException {
StockMove stockMoveFromContext = request.getContext().asType(StockMove.class);
StockMove stockMove = Beans.get(StockMoveRepository.class).find(stockMoveFromContext.getId());
Beans.get(StockMoveServiceImpl.class).checkIfNonValidationFolder(stockMove);
logger.debug("checkIfNonValidationFolder ......... ");
}
}

View File

@@ -7,6 +7,7 @@
<entity name="StockLocation" lang="java">
<string name="code" title="Code"/>
<string name="name" title="Name" required="true"/>
<many-to-one name="parentStockLocation" ref="com.axelor.apps.stock.db.StockLocation" title="Parent stock location"/>
<many-to-one name="company" ref="com.axelor.apps.base.db.Company" title="Company" required="true"/>

View File

@@ -36,6 +36,8 @@
<many-to-one name="internalTrackingNumber" ref="com.axelor.apps.stock.db.InternalTrackingNumber" title="Internal tracking Nbr" readonly="true"/>
<many-to-one name="barCodeSeq" title="Barcode" ref="com.axelor.meta.db.MetaFile" />
<track>
<field name="conformitySelect"/>
<field name="isConformTag"/>

View File

@@ -52,14 +52,23 @@
<integer name="sequence" title="Seq."/>
<string name="name" title="Ref.">
<![CDATA[
if (stockMove != null && stockMove.getStockMoveSeq() != null){
return stockMove.getStockMoveSeq()+ "-" +Integer.toString(sequence);
}
else {
return Integer.toString(sequence);
}
]]>
<![CDATA[
if(name == null)
{if (sequence == null) {
return "0";
}
if (stockMove == null) {
return Integer.toString(sequence);
}
String stockMoveSeq = stockMove.getStockMoveSeq();
if (stockMoveSeq == null) {
return Integer.toString(sequence);
}
return stockMoveSeq + "-" + Integer.toString(sequence);
}else{
return name;
}
]]>
</string>
<many-to-one name="customsCodeNomenclature" ref="com.axelor.apps.stock.db.CustomsCodeNomenclature"/>
@@ -104,16 +113,16 @@
public static final int CONFORMITY_NON_COMPLIANT = 3;
public static final int TYPE_NORMAL = 0;
public static final int TYPE_TITLE = 1;
public static final int TYPE_PACK = 2;
public static final int PACK_PRICE_ONLY = 0;
public static final int SUBLINE_PRICE_ONLY = 1;
// AVAILABLE STATUS SELECT
public static final int STATUS_AVAILABLE = 1;
public static final int STATUS_AVAILABLE_FOR_PRODUCT = 2;
public static final int STATUS_MISSING = 3;
public static final int TYPE_TITLE = 1;
public static final int TYPE_PACK = 2;
public static final int PACK_PRICE_ONLY = 0;
public static final int SUBLINE_PRICE_ONLY = 1;
// AVAILABLE STATUS SELECT
public static final int STATUS_AVAILABLE = 1;
public static final int STATUS_AVAILABLE_FOR_PRODUCT = 2;
public static final int STATUS_MISSING = 3;
]]></extra-code>
<track>