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:
@@ -22,8 +22,10 @@ import com.axelor.apps.account.db.AccountManagement;
|
|||||||
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
|
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
|
||||||
import com.axelor.apps.account.db.FiscalPosition;
|
import com.axelor.apps.account.db.FiscalPosition;
|
||||||
import com.axelor.apps.account.db.FixedAssetCategory;
|
import com.axelor.apps.account.db.FixedAssetCategory;
|
||||||
|
import com.axelor.apps.account.db.repo.AccountManagementRepository;
|
||||||
import com.axelor.apps.account.exception.IExceptionMessage;
|
import com.axelor.apps.account.exception.IExceptionMessage;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.FamilleProduit;
|
||||||
import com.axelor.apps.base.db.Product;
|
import com.axelor.apps.base.db.Product;
|
||||||
import com.axelor.apps.base.service.tax.AccountManagementServiceImpl;
|
import com.axelor.apps.base.service.tax.AccountManagementServiceImpl;
|
||||||
import com.axelor.apps.base.service.tax.FiscalPositionService;
|
import com.axelor.apps.base.service.tax.FiscalPositionService;
|
||||||
@@ -31,8 +33,11 @@ import com.axelor.apps.base.service.tax.TaxService;
|
|||||||
import com.axelor.exception.AxelorException;
|
import com.axelor.exception.AxelorException;
|
||||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||||
import com.axelor.i18n.I18n;
|
import com.axelor.i18n.I18n;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
import com.axelor.meta.CallMethod;
|
import com.axelor.meta.CallMethod;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -222,4 +227,55 @@ public class AccountManagementServiceAccountImpl extends AccountManagementServic
|
|||||||
|
|
||||||
return fixedAssetCategory;
|
return fixedAssetCategory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
|
public void setAccountManagementForProduct(Product product,Company company) {
|
||||||
|
FamilleProduit familleProduit = product.getFamilleProduit();
|
||||||
|
FamilleProduit sousFamilleProduit = product.getSousFamilleProduit();
|
||||||
|
|
||||||
|
if (product == null || familleProduit == null || company == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (product.getAccountManagementList() == null || product.getAccountManagementList().isEmpty()) {
|
||||||
|
AccountManagement accountManagement = new AccountManagement();
|
||||||
|
accountManagement.setCompany(company);
|
||||||
|
accountManagement.setProduct(product);
|
||||||
|
|
||||||
|
// Use sousFamilleProduit accounts if they exist, otherwise fallback to familleProduit
|
||||||
|
accountManagement.setPurchaseAccount(
|
||||||
|
(sousFamilleProduit != null && sousFamilleProduit.getPurchaseAccount() != null) ?
|
||||||
|
sousFamilleProduit.getPurchaseAccount() :
|
||||||
|
familleProduit.getPurchaseAccount()
|
||||||
|
);
|
||||||
|
|
||||||
|
accountManagement.setStockAccount(
|
||||||
|
(sousFamilleProduit != null && sousFamilleProduit.getStockAccount() != null) ?
|
||||||
|
sousFamilleProduit.getStockAccount() :
|
||||||
|
familleProduit.getStockAccount()
|
||||||
|
);
|
||||||
|
|
||||||
|
accountManagement.setConsumptionAccount(
|
||||||
|
(sousFamilleProduit != null && sousFamilleProduit.getConsumptionAccount() != null) ?
|
||||||
|
sousFamilleProduit.getConsumptionAccount() :
|
||||||
|
familleProduit.getConsumptionAccount()
|
||||||
|
);
|
||||||
|
|
||||||
|
accountManagement.setSaleAccount(
|
||||||
|
(sousFamilleProduit != null && sousFamilleProduit.getSaleAccount() != null) ?
|
||||||
|
sousFamilleProduit.getSaleAccount() :
|
||||||
|
familleProduit.getSaleAccount()
|
||||||
|
);
|
||||||
|
|
||||||
|
accountManagement.setPurchFixedAssetsAccount(
|
||||||
|
(sousFamilleProduit != null && sousFamilleProduit.getPurchFixedAssetsAccount() != null) ?
|
||||||
|
sousFamilleProduit.getPurchFixedAssetsAccount() :
|
||||||
|
familleProduit.getPurchFixedAssetsAccount()
|
||||||
|
);
|
||||||
|
|
||||||
|
accountManagement.setTypeSelect(1); // Product type
|
||||||
|
Beans.get(AccountManagementRepository.class).save(accountManagement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ package com.axelor.apps.account.service.invoice;
|
|||||||
import com.axelor.apps.account.db.Account;
|
import com.axelor.apps.account.db.Account;
|
||||||
import com.axelor.apps.account.db.AccountConfig;
|
import com.axelor.apps.account.db.AccountConfig;
|
||||||
import com.axelor.apps.account.db.AccountingSituation;
|
import com.axelor.apps.account.db.AccountingSituation;
|
||||||
|
import com.axelor.apps.account.db.AnalyticJournal;
|
||||||
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
import com.axelor.apps.account.db.Invoice;
|
import com.axelor.apps.account.db.Invoice;
|
||||||
import com.axelor.apps.account.db.InvoiceLine;
|
import com.axelor.apps.account.db.InvoiceLine;
|
||||||
import com.axelor.apps.account.db.InvoicePayment;
|
import com.axelor.apps.account.db.InvoicePayment;
|
||||||
@@ -36,6 +38,7 @@ import com.axelor.apps.account.db.repo.MoveRepository;
|
|||||||
import com.axelor.apps.account.db.repo.PaymentModeRepository;
|
import com.axelor.apps.account.db.repo.PaymentModeRepository;
|
||||||
import com.axelor.apps.account.exception.IExceptionMessage;
|
import com.axelor.apps.account.exception.IExceptionMessage;
|
||||||
import com.axelor.apps.account.service.AccountingSituationService;
|
import com.axelor.apps.account.service.AccountingSituationService;
|
||||||
|
import com.axelor.apps.account.service.AnalyticMoveLineService;
|
||||||
import com.axelor.apps.account.service.app.AppAccountService;
|
import com.axelor.apps.account.service.app.AppAccountService;
|
||||||
import com.axelor.apps.account.service.config.AccountConfigService;
|
import com.axelor.apps.account.service.config.AccountConfigService;
|
||||||
import com.axelor.apps.account.service.invoice.factory.CancelFactory;
|
import com.axelor.apps.account.service.invoice.factory.CancelFactory;
|
||||||
@@ -46,6 +49,7 @@ import com.axelor.apps.account.service.invoice.generator.invoice.RefundInvoice;
|
|||||||
import com.axelor.apps.account.service.invoice.print.InvoicePrintService;
|
import com.axelor.apps.account.service.invoice.print.InvoicePrintService;
|
||||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolService;
|
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolService;
|
||||||
import com.axelor.apps.base.db.Alarm;
|
import com.axelor.apps.base.db.Alarm;
|
||||||
|
import com.axelor.apps.base.db.AppBudget;
|
||||||
import com.axelor.apps.base.db.BankDetails;
|
import com.axelor.apps.base.db.BankDetails;
|
||||||
import com.axelor.apps.base.db.CancelReason;
|
import com.axelor.apps.base.db.CancelReason;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
@@ -53,6 +57,7 @@ import com.axelor.apps.base.db.Currency;
|
|||||||
import com.axelor.apps.base.db.Partner;
|
import com.axelor.apps.base.db.Partner;
|
||||||
import com.axelor.apps.base.db.PriceList;
|
import com.axelor.apps.base.db.PriceList;
|
||||||
import com.axelor.apps.base.db.Sequence;
|
import com.axelor.apps.base.db.Sequence;
|
||||||
|
import com.axelor.apps.base.db.repo.AppBudgetRepository;
|
||||||
import com.axelor.apps.base.db.repo.BankDetailsRepository;
|
import com.axelor.apps.base.db.repo.BankDetailsRepository;
|
||||||
import com.axelor.apps.base.db.repo.PriceListRepository;
|
import com.axelor.apps.base.db.repo.PriceListRepository;
|
||||||
import com.axelor.apps.base.service.PartnerService;
|
import com.axelor.apps.base.service.PartnerService;
|
||||||
@@ -102,6 +107,7 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
protected PartnerService partnerService;
|
protected PartnerService partnerService;
|
||||||
protected InvoiceLineService invoiceLineService;
|
protected InvoiceLineService invoiceLineService;
|
||||||
protected AccountConfigService accountConfigService;
|
protected AccountConfigService accountConfigService;
|
||||||
|
protected AnalyticMoveLineService analyticMoveLineService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public InvoiceServiceImpl(
|
public InvoiceServiceImpl(
|
||||||
@@ -113,7 +119,8 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
AppAccountService appAccountService,
|
AppAccountService appAccountService,
|
||||||
PartnerService partnerService,
|
PartnerService partnerService,
|
||||||
InvoiceLineService invoiceLineService,
|
InvoiceLineService invoiceLineService,
|
||||||
AccountConfigService accountConfigService) {
|
AccountConfigService accountConfigService,
|
||||||
|
AnalyticMoveLineService analyticMoveLineService) {
|
||||||
|
|
||||||
this.validateFactory = validateFactory;
|
this.validateFactory = validateFactory;
|
||||||
this.ventilateFactory = ventilateFactory;
|
this.ventilateFactory = ventilateFactory;
|
||||||
@@ -124,6 +131,7 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
this.partnerService = partnerService;
|
this.partnerService = partnerService;
|
||||||
this.invoiceLineService = invoiceLineService;
|
this.invoiceLineService = invoiceLineService;
|
||||||
this.accountConfigService = accountConfigService;
|
this.accountConfigService = accountConfigService;
|
||||||
|
this.analyticMoveLineService = analyticMoveLineService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WKF
|
// WKF
|
||||||
@@ -445,7 +453,10 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
public void setSequence(Invoice invoice) throws AxelorException {
|
public void setSequence(Invoice invoice) throws AxelorException {
|
||||||
|
|
||||||
if (invoice.getId() != null && Strings.isNullOrEmpty(invoice.getInvoiceId())) {
|
if (invoice.getId() != null && Strings.isNullOrEmpty(invoice.getInvoiceId())) {
|
||||||
invoice.setInvoiceId(Beans.get(SequenceService.class).getSequenceNumber(getSequence(invoice), Beans.get(AppBaseService.class).getTodayDate()));
|
invoice.setInvoiceId(
|
||||||
|
Beans.get(SequenceService.class)
|
||||||
|
.getSequenceNumber(
|
||||||
|
getSequence(invoice), Beans.get(AppBaseService.class).getTodayDate()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,13 +472,15 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
return accountConfigService.getSuppRefSequence(accountConfig);
|
return accountConfigService.getSuppRefSequence(accountConfig);
|
||||||
|
|
||||||
case InvoiceRepository.OPERATION_TYPE_CLIENT_SALE:
|
case InvoiceRepository.OPERATION_TYPE_CLIENT_SALE:
|
||||||
if(invoice.getOperationSubTypeSelect() == InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_DISCOUNT){
|
if (invoice.getOperationSubTypeSelect()
|
||||||
|
== InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_DISCOUNT) {
|
||||||
return accountConfigService.getFinancialCustInvSequence(accountConfig);
|
return accountConfigService.getFinancialCustInvSequence(accountConfig);
|
||||||
} else {
|
} else {
|
||||||
return accountConfigService.getCustInvSequence(accountConfig);
|
return accountConfigService.getCustInvSequence(accountConfig);
|
||||||
}
|
}
|
||||||
case InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND:
|
case InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND:
|
||||||
if(invoice.getOperationSubTypeSelect() == InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_REFUNDS){
|
if (invoice.getOperationSubTypeSelect()
|
||||||
|
== InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_REFUNDS) {
|
||||||
return accountConfigService.getFinancialCustRefSequence(accountConfig);
|
return accountConfigService.getFinancialCustRefSequence(accountConfig);
|
||||||
} else {
|
} else {
|
||||||
return accountConfigService.getCustRefSequence(accountConfig);
|
return accountConfigService.getCustRefSequence(accountConfig);
|
||||||
@@ -482,7 +495,6 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Invoice mergeInvoiceProcess(
|
public Invoice mergeInvoiceProcess(
|
||||||
List<Invoice> invoiceList,
|
List<Invoice> invoiceList,
|
||||||
Company company,
|
Company company,
|
||||||
@@ -1016,4 +1028,55 @@ public class InvoiceServiceImpl extends InvoiceRepository implements InvoiceServ
|
|||||||
.getResultList()
|
.getResultList()
|
||||||
.size();
|
.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> checkInconsistentAnalyticDistribution(Invoice invoice)
|
||||||
|
throws AxelorException {
|
||||||
|
List<InvoiceLine> invoiceLines = invoice.getInvoiceLineList();
|
||||||
|
List<String> products = new ArrayList<>();
|
||||||
|
for (InvoiceLine invoiceLine : invoiceLines) {
|
||||||
|
BigDecimal sumPourcentagePerLine =
|
||||||
|
invoiceLine
|
||||||
|
.getAnalyticMoveLineList()
|
||||||
|
.stream()
|
||||||
|
.map(AnalyticMoveLine::getPercentage)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
if (sumPourcentagePerLine.compareTo(BigDecimal.valueOf(100.0)) > 0) {
|
||||||
|
products.add(invoiceLine.getProductName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return products;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isMissingAnalyticMoveLine(Invoice invoice) {
|
||||||
|
Boolean isMissing = false;
|
||||||
|
for (InvoiceLine invoiceLine : invoice.getInvoiceLineList()) {
|
||||||
|
if (invoiceLine.getAnalyticMoveLineList().isEmpty()) {
|
||||||
|
isMissing = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isMissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void generateAnalyticMoveLines(Invoice invoice) {
|
||||||
|
List<InvoiceLine> invoiceLines = invoice.getInvoiceLineList();
|
||||||
|
for (InvoiceLine invoiceLine : invoiceLines) {
|
||||||
|
AnalyticMoveLine aml = new AnalyticMoveLine();
|
||||||
|
AppBudget AppBudget = Beans.get(AppBudgetRepository.class).all().fetchOne();
|
||||||
|
AnalyticJournal deAnalyticJournal = AppBudget.getDefaultAnalyticJournal();
|
||||||
|
if (invoice.getAnalyticJournal() != null) {
|
||||||
|
aml.setAnalyticJournal(invoice.getAnalyticJournal());
|
||||||
|
} else {
|
||||||
|
aml.setAnalyticJournal(deAnalyticJournal);
|
||||||
|
}
|
||||||
|
aml.setAnalyticAccount(invoice.getAnalyticAccount());
|
||||||
|
aml.setAnalyticAxis(invoice.getAnalyticAxis());
|
||||||
|
aml.setPercentage(BigDecimal.valueOf(100));
|
||||||
|
analyticMoveLineService.updateAnalyticMoveLine(
|
||||||
|
aml, invoiceLine.getCompanyExTaxTotal(), invoice.getInvoiceDate());
|
||||||
|
invoiceLine.addAnalyticMoveLineListItem(aml);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,13 +319,15 @@ public class VentilateState extends WorkflowInvoice {
|
|||||||
return accountConfigService.getSuppRefSequence(accountConfig);
|
return accountConfigService.getSuppRefSequence(accountConfig);
|
||||||
|
|
||||||
case InvoiceRepository.OPERATION_TYPE_CLIENT_SALE:
|
case InvoiceRepository.OPERATION_TYPE_CLIENT_SALE:
|
||||||
if(invoice.getOperationSubTypeSelect() == InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_DISCOUNT){
|
if (invoice.getOperationSubTypeSelect()
|
||||||
|
== InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_DISCOUNT) {
|
||||||
return accountConfigService.getFinancialCustInvSequence(accountConfig);
|
return accountConfigService.getFinancialCustInvSequence(accountConfig);
|
||||||
} else {
|
} else {
|
||||||
return accountConfigService.getCustInvSequence(accountConfig);
|
return accountConfigService.getCustInvSequence(accountConfig);
|
||||||
}
|
}
|
||||||
case InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND:
|
case InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND:
|
||||||
if(invoice.getOperationSubTypeSelect() == InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_REFUNDS){
|
if (invoice.getOperationSubTypeSelect()
|
||||||
|
== InvoiceRepository.OPERATION_SUB_TYPE_FINANCIAL_REFUNDS) {
|
||||||
return accountConfigService.getFinancialCustRefSequence(accountConfig);
|
return accountConfigService.getFinancialCustRefSequence(accountConfig);
|
||||||
} else {
|
} else {
|
||||||
return accountConfigService.getCustRefSequence(accountConfig);
|
return accountConfigService.getCustRefSequence(accountConfig);
|
||||||
|
|||||||
@@ -38,14 +38,13 @@ import com.axelor.apps.account.exception.IExceptionMessage;
|
|||||||
import com.axelor.apps.account.service.AccountManagementAccountService;
|
import com.axelor.apps.account.service.AccountManagementAccountService;
|
||||||
import com.axelor.apps.account.service.AnalyticMoveLineService;
|
import com.axelor.apps.account.service.AnalyticMoveLineService;
|
||||||
import com.axelor.apps.account.service.FiscalPositionAccountService;
|
import com.axelor.apps.account.service.FiscalPositionAccountService;
|
||||||
import com.axelor.apps.account.service.ReconcileServiceImpl;
|
|
||||||
import com.axelor.apps.account.service.TaxAccountService;
|
import com.axelor.apps.account.service.TaxAccountService;
|
||||||
import com.axelor.apps.account.service.TaxPaymentMoveLineService;
|
import com.axelor.apps.account.service.TaxPaymentMoveLineService;
|
||||||
import com.axelor.apps.account.service.app.AppAccountService;
|
import com.axelor.apps.account.service.app.AppAccountService;
|
||||||
import com.axelor.apps.account.service.config.AccountConfigService;
|
import com.axelor.apps.account.service.config.AccountConfigService;
|
||||||
import com.axelor.apps.account.service.invoice.InvoiceToolService;
|
import com.axelor.apps.account.service.invoice.InvoiceToolService;
|
||||||
import com.axelor.apps.account.service.payment.PaymentService;
|
import com.axelor.apps.account.service.payment.PaymentService;
|
||||||
import com.axelor.apps.account.service.payment.PaymentServiceImpl;
|
import com.axelor.apps.account.util.MoveLineKey;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
import com.axelor.apps.base.db.Currency;
|
import com.axelor.apps.base.db.Currency;
|
||||||
import com.axelor.apps.base.db.Partner;
|
import com.axelor.apps.base.db.Partner;
|
||||||
@@ -488,26 +487,29 @@ public class MoveLineService {
|
|||||||
invoiceLine.getProductName());
|
invoiceLine.getProductName());
|
||||||
if (invoiceLine.getAnalyticDistributionTemplate() != null)
|
if (invoiceLine.getAnalyticDistributionTemplate() != null)
|
||||||
moveLine.setAnalyticDistributionTemplate(invoiceLine.getAnalyticDistributionTemplate());
|
moveLine.setAnalyticDistributionTemplate(invoiceLine.getAnalyticDistributionTemplate());
|
||||||
if (invoiceLine.getAnalyticMoveLineList() != null
|
// if (invoiceLine.getAnalyticMoveLineList() != null
|
||||||
&& !invoiceLine.getAnalyticMoveLineList().isEmpty()) {
|
// && !invoiceLine.getAnalyticMoveLineList().isEmpty()) {
|
||||||
for (AnalyticMoveLine invoiceAnalyticMoveLine : invoiceLine.getAnalyticMoveLineList()) {
|
// for (AnalyticMoveLine invoiceAnalyticMoveLine : invoiceLine.getAnalyticMoveLineList()) {
|
||||||
System.out.println("-----------------invoiceAnalyticMoveLine.getAccount().getName()----------------------------");
|
// System.out.println(
|
||||||
System.out.println(invoiceAnalyticMoveLine.getAccount());
|
// "-----------------invoiceAnalyticMoveLine.getAccount().getName()----------------------------");
|
||||||
AnalyticMoveLine analyticMoveLine =
|
// System.out.println(invoiceAnalyticMoveLine.getId());
|
||||||
analyticMoveLineRepository.copy(invoiceAnalyticMoveLine, false);
|
// System.out.println(invoiceAnalyticMoveLine.toString());
|
||||||
analyticMoveLine.setTypeSelect(AnalyticMoveLineRepository.STATUS_REAL_ACCOUNTING);
|
// System.out.println( "-----------------invoiceAnalyticMoveLine.getAccount().getName()----------------------------");
|
||||||
analyticMoveLine.setInvoiceLine(null);
|
// AnalyticMoveLine analyticMoveLine =
|
||||||
analyticMoveLine.setAccount(moveLine.getAccount());
|
// analyticMoveLineRepository.copy(invoiceAnalyticMoveLine, false);
|
||||||
analyticMoveLine.setAccountType(moveLine.getAccount().getAccountType());
|
// analyticMoveLine.setTypeSelect(AnalyticMoveLineRepository.STATUS_REAL_ACCOUNTING);
|
||||||
analyticMoveLineService.updateAnalyticMoveLine(
|
// analyticMoveLine.setInvoiceLine(null);
|
||||||
analyticMoveLine,
|
// analyticMoveLine.setAccount(moveLine.getAccount());
|
||||||
moveLine.getDebit().add(moveLine.getCredit()),
|
// analyticMoveLine.setAccountType(moveLine.getAccount().getAccountType());
|
||||||
moveLine.getDate());
|
// analyticMoveLineService.updateAnalyticMoveLine(
|
||||||
moveLine.addAnalyticMoveLineListItem(analyticMoveLine);
|
// analyticMoveLine,
|
||||||
}
|
// moveLine.getDebit().add(moveLine.getCredit()),
|
||||||
} else {
|
// moveLine.getDate());
|
||||||
|
// moveLine.addAnalyticMoveLineListItem(analyticMoveLine);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
generateAnalyticMoveLines(moveLine);
|
generateAnalyticMoveLines(moveLine);
|
||||||
}
|
// }
|
||||||
|
|
||||||
TaxLine taxLine = invoiceLine.getTaxLine();
|
TaxLine taxLine = invoiceLine.getTaxLine();
|
||||||
if (taxLine != null) {
|
if (taxLine != null) {
|
||||||
@@ -655,65 +657,60 @@ public class MoveLineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MoveLine findConsolidateMoveLine(
|
public MoveLine findConsolidateMoveLine(
|
||||||
Map<List<Object>, MoveLine> map, MoveLine moveLine, List<Object> keys) {
|
Map<MoveLineKey, MoveLine> map, MoveLine moveLine, MoveLineKey keys) {
|
||||||
if (map != null && !map.isEmpty()) {
|
|
||||||
|
|
||||||
Map<List<Object>, MoveLine> copyMap = new HashMap<List<Object>, MoveLine>(map);
|
if (map == null || map.isEmpty()) {
|
||||||
while (!copyMap.isEmpty()) {
|
return null;
|
||||||
|
|
||||||
if (map.containsKey(keys)) {
|
|
||||||
|
|
||||||
MoveLine moveLineIt = map.get(keys);
|
|
||||||
int count = 0;
|
|
||||||
if (moveLineIt.getAnalyticMoveLineList() == null
|
|
||||||
&& moveLine.getAnalyticMoveLineList() == null) {
|
|
||||||
return moveLineIt;
|
|
||||||
} else if (moveLineIt.getAnalyticMoveLineList() == null
|
|
||||||
|| moveLine.getAnalyticMoveLineList() == null) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
List<AnalyticMoveLine> list1 = moveLineIt.getAnalyticMoveLineList();
|
|
||||||
|
// Quick lookup by composite key (account, taxLine, template)
|
||||||
|
MoveLine existing = map.get(keys);
|
||||||
|
if (existing == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast exit if both have no analytic lines
|
||||||
|
List<AnalyticMoveLine> list1 = existing.getAnalyticMoveLineList();
|
||||||
List<AnalyticMoveLine> list2 = moveLine.getAnalyticMoveLineList();
|
List<AnalyticMoveLine> list2 = moveLine.getAnalyticMoveLineList();
|
||||||
List<AnalyticMoveLine> copyList = new ArrayList<AnalyticMoveLine>(list1);
|
if ((list1 == null || list1.isEmpty()) && (list2 == null || list2.isEmpty())) {
|
||||||
if (list1.size() == list2.size()) {
|
return existing;
|
||||||
for (AnalyticMoveLine analyticDistributionLine : list2) {
|
|
||||||
for (AnalyticMoveLine analyticDistributionLineIt : copyList) {
|
|
||||||
if (analyticDistributionLine
|
|
||||||
.getAnalyticAxis()
|
|
||||||
.equals(analyticDistributionLineIt.getAnalyticAxis())
|
|
||||||
&& analyticDistributionLine
|
|
||||||
.getAnalyticAccount()
|
|
||||||
.equals(analyticDistributionLineIt.getAnalyticAccount())
|
|
||||||
&& analyticDistributionLine
|
|
||||||
.getAccount()
|
|
||||||
.equals(analyticDistributionLineIt.getAccount())
|
|
||||||
&& analyticDistributionLine
|
|
||||||
.getPercentage()
|
|
||||||
.equals(analyticDistributionLineIt.getPercentage())
|
|
||||||
&& ((analyticDistributionLine.getAnalyticJournal() == null
|
|
||||||
&& analyticDistributionLineIt.getAnalyticJournal() == null)
|
|
||||||
|| analyticDistributionLine
|
|
||||||
.getAnalyticJournal()
|
|
||||||
.equals(analyticDistributionLineIt.getAnalyticJournal()))) {
|
|
||||||
copyList.remove(analyticDistributionLineIt);
|
|
||||||
count++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
// If one has analytics but not the other → not same
|
||||||
if (count == list1.size()) {
|
if ((list1 == null || list1.isEmpty()) ^ (list2 == null || list2.isEmpty())) {
|
||||||
return moveLineIt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⚙️ Build lightweight hash sets for quick equality check
|
||||||
|
Set<String> set1 = new HashSet<>(list1.size());
|
||||||
|
Set<String> set2 = new HashSet<>(list2.size());
|
||||||
|
|
||||||
|
for (AnalyticMoveLine a1 : list1) {
|
||||||
|
set1.add(buildAnalyticKey(a1));
|
||||||
}
|
}
|
||||||
|
for (AnalyticMoveLine a2 : list2) {
|
||||||
|
set2.add(buildAnalyticKey(a2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare as sets — same content, order doesn’t matter
|
||||||
|
if (set1.equals(set2)) {
|
||||||
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Build a lightweight key for an AnalyticMoveLine to avoid deep equals. */
|
||||||
|
private static String buildAnalyticKey(AnalyticMoveLine a) {
|
||||||
|
Long axisId = a.getAnalyticAxis() != null ? a.getAnalyticAxis().getId() : null;
|
||||||
|
Long accId = a.getAnalyticAccount() != null ? a.getAnalyticAccount().getId() : null;
|
||||||
|
Long glId = a.getAccount() != null ? a.getAccount().getId() : null;
|
||||||
|
BigDecimal pct = a.getPercentage() != null ? a.getPercentage() : BigDecimal.ZERO;
|
||||||
|
Long journalId = a.getAnalyticJournal() != null ? a.getAnalyticJournal().getId() : null;
|
||||||
|
|
||||||
|
return axisId + ":" + accId + ":" + glId + ":" + pct + ":" + journalId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consolider des lignes d'écritures par compte comptable.
|
* Consolider des lignes d'écritures par compte comptable.
|
||||||
*
|
*
|
||||||
@@ -721,16 +718,12 @@ public class MoveLineService {
|
|||||||
*/
|
*/
|
||||||
public List<MoveLine> consolidateMoveLines(List<MoveLine> moveLines) {
|
public List<MoveLine> consolidateMoveLines(List<MoveLine> moveLines) {
|
||||||
|
|
||||||
Map<List<Object>, MoveLine> map = new HashMap<List<Object>, MoveLine>();
|
Map<MoveLineKey, MoveLine> map = new HashMap<>();
|
||||||
MoveLine consolidateMoveLine = null;
|
MoveLine consolidateMoveLine = null;
|
||||||
|
|
||||||
for (MoveLine moveLine : moveLines) {
|
for (MoveLine moveLine : moveLines) {
|
||||||
|
|
||||||
List<Object> keys = new ArrayList<Object>();
|
MoveLineKey keys = new MoveLineKey(moveLine);
|
||||||
|
|
||||||
keys.add(moveLine.getAccount());
|
|
||||||
keys.add(moveLine.getTaxLine());
|
|
||||||
keys.add(moveLine.getAnalyticDistributionTemplate());
|
|
||||||
|
|
||||||
consolidateMoveLine = this.findConsolidateMoveLine(map, moveLine, keys);
|
consolidateMoveLine = this.findConsolidateMoveLine(map, moveLine, keys);
|
||||||
if (consolidateMoveLine != null) {
|
if (consolidateMoveLine != null) {
|
||||||
|
|||||||
@@ -1026,9 +1026,7 @@ public class PaymentVoucherConfirmService {
|
|||||||
@Transactional(rollbackOn = {Exception.class})
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
public void confirmCashPayment(PaymentVoucher paymentVoucher) throws AxelorException {
|
public void confirmCashPayment(PaymentVoucher paymentVoucher) throws AxelorException {
|
||||||
if (paymentVoucher.getGeneratedMoveList().size() > 0) {
|
if (paymentVoucher.getGeneratedMoveList().size() > 0) {
|
||||||
throw new AxelorException(
|
throw new AxelorException(TraceBackRepository.CATEGORY_INCONSISTENCY, "Already ventilated.");
|
||||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
|
||||||
"Already ventilated.");
|
|
||||||
}
|
}
|
||||||
PaymentMode paymentMode = paymentVoucher.getPaymentMode();
|
PaymentMode paymentMode = paymentVoucher.getPaymentMode();
|
||||||
Company company = paymentVoucher.getCompany();
|
Company company = paymentVoucher.getCompany();
|
||||||
@@ -1038,8 +1036,7 @@ public class PaymentVoucherConfirmService {
|
|||||||
// LocalDate paymentDate = paymentVoucher.getPaymentDate();
|
// LocalDate paymentDate = paymentVoucher.getPaymentDate();
|
||||||
LocalDate paymentDate = paymentVoucher.getPaymentEmissionDate();
|
LocalDate paymentDate = paymentVoucher.getPaymentEmissionDate();
|
||||||
|
|
||||||
Account paymentModeAccount =
|
Account paymentModeAccount = paymentVoucher.getCashAccountConfig().getAccount();
|
||||||
paymentVoucher.getCashAccountConfig().getAccount();
|
|
||||||
|
|
||||||
Move move =
|
Move move =
|
||||||
moveService
|
moveService
|
||||||
@@ -1095,7 +1092,9 @@ public class PaymentVoucherConfirmService {
|
|||||||
move.getMoveLineList().add(moveLine2);
|
move.getMoveLineList().add(moveLine2);
|
||||||
|
|
||||||
String label = paymentVoucher.getLabel() != null ? paymentVoucher.getLabel() : "";
|
String label = paymentVoucher.getLabel() != null ? paymentVoucher.getLabel() : "";
|
||||||
String fullName = (paymentVoucher.getRecipientPartner() != null && paymentVoucher.getRecipientPartner().getFullName() != null)
|
String fullName =
|
||||||
|
(paymentVoucher.getRecipientPartner() != null
|
||||||
|
&& paymentVoucher.getRecipientPartner().getFullName() != null)
|
||||||
? paymentVoucher.getRecipientPartner().getFullName()
|
? paymentVoucher.getRecipientPartner().getFullName()
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
@@ -1120,8 +1119,10 @@ public class PaymentVoucherConfirmService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackOn = {Exception.class})
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
public void updateCashRegisterTheoricalSolde(PaymentVoucher paymentVoucher,Boolean isDebitCredit,BigDecimal amount) {
|
public void updateCashRegisterTheoricalSolde(
|
||||||
System.out.println("updateCashRegisterTheoricalSolde : : : " + paymentVoucher.getCashAccountConfig());
|
PaymentVoucher paymentVoucher, Boolean isDebitCredit, BigDecimal amount) {
|
||||||
|
System.out.println(
|
||||||
|
"updateCashRegisterTheoricalSolde : : : " + paymentVoucher.getCashAccountConfig());
|
||||||
if (paymentVoucher.getCashAccountConfig() != null || paymentVoucher.getPartner() != null) {
|
if (paymentVoucher.getCashAccountConfig() != null || paymentVoucher.getPartner() != null) {
|
||||||
CashRegisterRepository casRegisterRepository = Beans.get(CashRegisterRepository.class);
|
CashRegisterRepository casRegisterRepository = Beans.get(CashRegisterRepository.class);
|
||||||
CashRegister cashRegister = casRegisterRepository.all().order("-createdOn").fetchOne();
|
CashRegister cashRegister = casRegisterRepository.all().order("-createdOn").fetchOne();
|
||||||
@@ -1208,6 +1209,4 @@ public class PaymentVoucherConfirmService {
|
|||||||
Beans.get(MoveCancelService.class).cancel(move);
|
Beans.get(MoveCancelService.class).cancel(move);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.axelor.apps.base.service.administration.SequenceService;
|
|||||||
import com.axelor.exception.AxelorException;
|
import com.axelor.exception.AxelorException;
|
||||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||||
import com.axelor.i18n.I18n;
|
import com.axelor.i18n.I18n;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
@@ -58,9 +59,18 @@ public class PaymentVoucherSequenceService {
|
|||||||
Company company = paymentVoucher.getCompany();
|
Company company = paymentVoucher.getCompany();
|
||||||
// Sequence seq = Beans.get(SequenceRepository.class).find(new Long("126"));
|
// Sequence seq = Beans.get(SequenceRepository.class).find(new Long("126"));
|
||||||
|
|
||||||
return sequenceService.getSequenceNumber(
|
String sequence = "";
|
||||||
|
if (paymentVoucher.getOperationTypeSelect() == 9) {
|
||||||
|
sequence = sequenceService
|
||||||
|
.getSequenceNumber("CashSequence", paymentVoucher.getCompany());
|
||||||
|
} else {
|
||||||
|
sequence = sequenceService.getSequenceNumber(
|
||||||
paymentModeService.getPaymentModeSequence(
|
paymentModeService.getPaymentModeSequence(
|
||||||
paymentMode, company, paymentVoucher.getCompanyBankDetails()));
|
paymentMode, company, paymentVoucher.getCompanyBankDetails()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sequence;
|
||||||
// return sequenceService.getSequenceNumber(seq);
|
// return sequenceService.getSequenceNumber(seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.axelor.apps.account.util;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.MoveLine;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class MoveLineKey {
|
||||||
|
private final Long accountId;
|
||||||
|
private final Long taxLineId;
|
||||||
|
private final Long analyticTemplateId;
|
||||||
|
|
||||||
|
public MoveLineKey(MoveLine line) {
|
||||||
|
this.accountId = line.getAccount() != null ? line.getAccount().getId() : null;
|
||||||
|
this.taxLineId = line.getTaxLine() != null ? line.getTaxLine().getId() : null;
|
||||||
|
this.analyticTemplateId =
|
||||||
|
line.getAnalyticDistributionTemplate() != null
|
||||||
|
? line.getAnalyticDistributionTemplate().getId()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof MoveLineKey)) return false;
|
||||||
|
MoveLineKey that = (MoveLineKey) o;
|
||||||
|
return Objects.equals(accountId, that.accountId)
|
||||||
|
&& Objects.equals(taxLineId, that.taxLineId)
|
||||||
|
&& Objects.equals(analyticTemplateId, that.analyticTemplateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(accountId, taxLineId, analyticTemplateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.axelor.apps.account.web;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.service.AccountManagementAccountService;
|
||||||
|
import com.axelor.apps.account.service.AccountManagementServiceAccountImpl;
|
||||||
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.Product;
|
||||||
|
import com.axelor.apps.base.db.repo.ProductRepository;
|
||||||
|
import com.axelor.auth.AuthUtils;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
|
import com.axelor.rpc.ActionRequest;
|
||||||
|
import com.axelor.rpc.ActionResponse;
|
||||||
|
import com.axelor.rpc.Context;
|
||||||
|
|
||||||
|
public class AccountManagementController {
|
||||||
|
public void searchMoveLine(ActionRequest request, ActionResponse response) {
|
||||||
|
Product product = request.getContext().asType(Product.class);
|
||||||
|
product = Beans.get(ProductRepository.class).find(product.getId());
|
||||||
|
Company company = AuthUtils.getUser().getActiveCompany();
|
||||||
|
Beans.get(AccountManagementServiceAccountImpl.class).setAccountManagementForProduct(product, company);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,6 @@ import com.axelor.rpc.ActionRequest;
|
|||||||
import com.axelor.rpc.ActionResponse;
|
import com.axelor.rpc.ActionResponse;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -27,8 +26,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
public class CashInventoryController {
|
public class CashInventoryController {
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||||
@Inject
|
@Inject private final ConvertNumberToFrenchWordsService convertService;
|
||||||
private final ConvertNumberToFrenchWordsService convertService;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CashInventoryController(ConvertNumberToFrenchWordsService convertService) {
|
public CashInventoryController(ConvertNumberToFrenchWordsService convertService) {
|
||||||
@@ -52,7 +50,8 @@ public class CashInventoryController {
|
|||||||
name += " " + cashInventory.getRef();
|
name += " " + cashInventory.getRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
String fileLink = ReportFactory.createReport(
|
String fileLink =
|
||||||
|
ReportFactory.createReport(
|
||||||
String.format(IReport.CASH_INVENTORY, cashInventory.getOperationTypeSelect()),
|
String.format(IReport.CASH_INVENTORY, cashInventory.getOperationTypeSelect()),
|
||||||
name + "-${date}")
|
name + "-${date}")
|
||||||
.addParam("cashInventoryId", cashInventory.getId())
|
.addParam("cashInventoryId", cashInventory.getId())
|
||||||
@@ -102,8 +101,10 @@ public class CashInventoryController {
|
|||||||
public void computeToTals(ActionRequest request, ActionResponse response) {
|
public void computeToTals(ActionRequest request, ActionResponse response) {
|
||||||
|
|
||||||
CashInventory cashInventory = request.getContext().asType(CashInventory.class);
|
CashInventory cashInventory = request.getContext().asType(CashInventory.class);
|
||||||
if(cashInventory.getCashInventoryLines() != null && cashInventory.getCashInventoryLines().size() != 0){
|
if (cashInventory.getCashInventoryLines() != null
|
||||||
Map<String, BigDecimal> map = Beans.get(CashInventoryService.class).computeToTals(cashInventory);
|
&& cashInventory.getCashInventoryLines().size() != 0) {
|
||||||
|
Map<String, BigDecimal> map =
|
||||||
|
Beans.get(CashInventoryService.class).computeToTals(cashInventory);
|
||||||
response.setValues(map);
|
response.setValues(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,9 +116,11 @@ public class CashInventoryController {
|
|||||||
* @param response The action response to set the theoretical solde value.
|
* @param response The action response to set the theoretical solde value.
|
||||||
*/
|
*/
|
||||||
public void getLastCashData(ActionRequest request, ActionResponse response) {
|
public void getLastCashData(ActionRequest request, ActionResponse response) {
|
||||||
CashInventory lastCashInventory = Beans.get(CashInventoryRepository.class).all().order("-id").fetchOne();
|
CashInventory lastCashInventory =
|
||||||
|
Beans.get(CashInventoryRepository.class).all().order("-id").fetchOne();
|
||||||
|
|
||||||
List<PaymentVoucher> cashVouchers = Beans.get(PaymentVoucherRepository.class)
|
List<PaymentVoucher> cashVouchers =
|
||||||
|
Beans.get(PaymentVoucherRepository.class)
|
||||||
.all()
|
.all()
|
||||||
.filter("self.operationTypeSelect = 9 and self.cashStatusSelect = 3")
|
.filter("self.operationTypeSelect = 9 and self.cashStatusSelect = 3")
|
||||||
.fetch();
|
.fetch();
|
||||||
@@ -142,18 +145,21 @@ public class CashInventoryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate sequence for cash inventory
|
// generate sequence for cash inventory
|
||||||
public void generateSequence(ActionRequest request, ActionResponse response) throws AxelorException {
|
public void generateSequence(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
CashInventory cashInventory = request.getContext().asType(CashInventory.class);
|
CashInventory cashInventory = request.getContext().asType(CashInventory.class);
|
||||||
if (cashInventory.getRef() == null || cashInventory.getRef().isEmpty()) {
|
if (cashInventory.getRef() == null || cashInventory.getRef().isEmpty()) {
|
||||||
String sequence = Beans.get(CashInventoryService.class).getCashInventorySequence(cashInventory);
|
String sequence =
|
||||||
|
Beans.get(CashInventoryService.class).getCashInventorySequence(cashInventory);
|
||||||
response.setValue("ref", sequence);
|
response.setValue("ref", sequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void approveCashInventory(ActionRequest request, ActionResponse response)
|
||||||
public void approveCashInventory(ActionRequest request, ActionResponse response) throws AxelorException{
|
throws AxelorException {
|
||||||
CashInventory cashInventoryContext = request.getContext().asType(CashInventory.class);
|
CashInventory cashInventoryContext = request.getContext().asType(CashInventory.class);
|
||||||
CashInventory cashInventory = Beans.get(CashInventoryRepository.class).find(cashInventoryContext.getId());
|
CashInventory cashInventory =
|
||||||
|
Beans.get(CashInventoryRepository.class).find(cashInventoryContext.getId());
|
||||||
Beans.get(CashInventoryService.class).approveCashInventory(cashInventory);
|
Beans.get(CashInventoryService.class).approveCashInventory(cashInventory);
|
||||||
response.setReload(true);
|
response.setReload(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ import com.axelor.apps.account.db.PaymentMode;
|
|||||||
import com.axelor.apps.account.db.PaymentVoucher;
|
import com.axelor.apps.account.db.PaymentVoucher;
|
||||||
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
||||||
import com.axelor.apps.account.exception.IExceptionMessage;
|
import com.axelor.apps.account.exception.IExceptionMessage;
|
||||||
import com.axelor.apps.account.report.IReport;
|
|
||||||
import com.axelor.apps.account.service.AccountingSituationService;
|
import com.axelor.apps.account.service.AccountingSituationService;
|
||||||
import com.axelor.apps.account.service.IrrecoverableService;
|
import com.axelor.apps.account.service.IrrecoverableService;
|
||||||
import com.axelor.apps.account.service.app.AppAccountService;
|
import com.axelor.apps.account.service.app.AppAccountService;
|
||||||
import com.axelor.apps.account.service.invoice.InvoiceService;
|
import com.axelor.apps.account.service.invoice.InvoiceService;
|
||||||
|
import com.axelor.apps.account.service.invoice.InvoiceServiceImpl;
|
||||||
import com.axelor.apps.account.service.invoice.InvoiceToolService;
|
import com.axelor.apps.account.service.invoice.InvoiceToolService;
|
||||||
import com.axelor.apps.account.service.invoice.print.InvoicePrintService;
|
import com.axelor.apps.account.service.invoice.print.InvoicePrintService;
|
||||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
|
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
|
||||||
@@ -1100,4 +1100,40 @@ public class InvoiceController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void isMissingAnalyticMoveLine(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
Invoice invoice = request.getContext().asType(Invoice.class);
|
||||||
|
Invoice inv = Beans.get(InvoiceRepository.class).find(invoice.getId());
|
||||||
|
Boolean isMissingAnalyticMoveLine =
|
||||||
|
Beans.get(InvoiceServiceImpl.class).isMissingAnalyticMoveLine(inv);
|
||||||
|
if (isMissingAnalyticMoveLine) {
|
||||||
|
throw new AxelorException(
|
||||||
|
invoice,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"The analytic account is missing on one of the lines.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateAnalyticMoveLines(ActionRequest request, ActionResponse response) {
|
||||||
|
Invoice invoice = request.getContext().asType(Invoice.class);
|
||||||
|
Invoice inv = Beans.get(InvoiceRepository.class).find(invoice.getId());
|
||||||
|
Beans.get(InvoiceServiceImpl.class).generateAnalyticMoveLines(inv);
|
||||||
|
response.setAlert("The analytic move lines have been generated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkInconsistentAnalyticDistribution(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
Context context = request.getContext();
|
||||||
|
Invoice invoice = context.asType(Invoice.class);
|
||||||
|
invoice = Beans.get(InvoiceRepository.class).find(invoice.getId());
|
||||||
|
List<String> products =
|
||||||
|
Beans.get(InvoiceServiceImpl.class).checkInconsistentAnalyticDistribution(invoice);
|
||||||
|
if (products.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setAlert(
|
||||||
|
"The analytic distribution of at least one invoice line is inconsistent with the total amount of the line. Please check the analytic distribution of each invoice line."
|
||||||
|
+ String.join(", ", products));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -495,8 +495,8 @@ public class PaymentVoucherController {
|
|||||||
.map());
|
.map());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateCashPaymentVoucher(
|
public void validateCashPaymentVoucher(ActionRequest request, ActionResponse response)
|
||||||
ActionRequest request, ActionResponse response) throws AxelorException {
|
throws AxelorException {
|
||||||
PaymentVoucher paymentVoucher = request.getContext().asType(PaymentVoucher.class);
|
PaymentVoucher paymentVoucher = request.getContext().asType(PaymentVoucher.class);
|
||||||
paymentVoucher = Beans.get(PaymentVoucherRepository.class).find(paymentVoucher.getId());
|
paymentVoucher = Beans.get(PaymentVoucherRepository.class).find(paymentVoucher.getId());
|
||||||
|
|
||||||
@@ -508,9 +508,8 @@ public class PaymentVoucherController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void cancelCashPaymentVoucher(ActionRequest request, ActionResponse response)
|
||||||
public void cancelCashPaymentVoucher(
|
throws AxelorException {
|
||||||
ActionRequest request, ActionResponse response) throws AxelorException {
|
|
||||||
PaymentVoucher paymentVoucher = request.getContext().asType(PaymentVoucher.class);
|
PaymentVoucher paymentVoucher = request.getContext().asType(PaymentVoucher.class);
|
||||||
paymentVoucher = Beans.get(PaymentVoucherRepository.class).find(paymentVoucher.getId());
|
paymentVoucher = Beans.get(PaymentVoucherRepository.class).find(paymentVoucher.getId());
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,8 @@
|
|||||||
]]>
|
]]>
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
<boolean name="isActive" title="Is active" default="true"/>
|
||||||
|
|
||||||
<unique-constraint columns="code,name,analyticAxis,parent" />
|
<unique-constraint columns="code,name,analyticAxis,parent" />
|
||||||
</entity>
|
</entity>
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
public static final int STATUS_FORECAST_ORDER = 1;
|
public static final int STATUS_FORECAST_ORDER = 1;
|
||||||
public static final int STATUS_FORECAST_INVOICE = 2;
|
public static final int STATUS_FORECAST_INVOICE = 2;
|
||||||
public static final int STATUS_REAL_ACCOUNTING = 3;
|
public static final int STATUS_REAL_ACCOUNTING = 3;
|
||||||
|
public static final int STATUS_PURCHASE_REQUEST = 4;
|
||||||
|
public static final int STATUS_STOCK_MOVE = 5;
|
||||||
|
|
||||||
]]></extra-code>
|
]]></extra-code>
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,15 @@
|
|||||||
<boolean name="manageMultiBudget" title="Manage multi budgets on lines"/>
|
<boolean name="manageMultiBudget" title="Manage multi budgets on lines"/>
|
||||||
<boolean name="budgetRequiredOnPO" title="Budget required on purchase order lines"/>
|
<boolean name="budgetRequiredOnPO" title="Budget required on purchase order lines"/>
|
||||||
|
|
||||||
|
<many-to-one ref="com.axelor.apps.account.db.AnalyticJournal" name="defaultAnalyticJournal" />
|
||||||
|
<many-to-one ref="com.axelor.apps.account.db.AnalyticJournal" name="defaultPurchaseAnalyticJournal" />
|
||||||
|
<many-to-one ref="com.axelor.apps.account.db.AnalyticJournal" name="defaultSaleAnalyticJournal" />
|
||||||
|
|
||||||
<track>
|
<track>
|
||||||
<field name="checkAvailableBudget" on="UPDATE"/>
|
<field name="checkAvailableBudget" on="UPDATE"/>
|
||||||
<field name="manageMultiBudget" on="UPDATE"/>
|
<field name="manageMultiBudget" on="UPDATE"/>
|
||||||
<field name="budgetRequiredOnPO" on="UPDATE"/>
|
<field name="budgetRequiredOnPO" on="UPDATE"/>
|
||||||
|
<field name="defaultAnalyticJournal" on="UPDATE"/>
|
||||||
</track>
|
</track>
|
||||||
</entity>
|
</entity>
|
||||||
</domain-models>
|
</domain-models>
|
||||||
|
|||||||
@@ -20,9 +20,12 @@
|
|||||||
<decimal name="amountForGeneration" title="Amount for each line"/>
|
<decimal name="amountForGeneration" title="Amount for each line"/>
|
||||||
<boolean name="checkAvailableBudget" title="Check available budget"/>
|
<boolean name="checkAvailableBudget" title="Check available budget"/>
|
||||||
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic account"/>
|
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic account"/>
|
||||||
|
<string name="accountAccountCode" title="Account code"/>
|
||||||
|
<boolean name="isGrouped" title="Is grouped"/>
|
||||||
|
<boolean name="isActive" title="Is active"/>
|
||||||
|
|
||||||
<finder-method name="findByAnalyticAccount" using="analyticAccount"/>
|
<finder-method name="findByAnalyticAccount" using="analyticAccount"/>
|
||||||
|
<finder-method name="findByAnalyticAccountAndAccountCode" using="analyticAccount,accountAccountCode,isActive"/>
|
||||||
|
|
||||||
<extra-code><![CDATA[
|
<extra-code><![CDATA[
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?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="base" package="com.axelor.apps.base.db"/>
|
||||||
|
|
||||||
|
<entity name="FamilleProduit">
|
||||||
|
|
||||||
|
<many-to-one name="purchaseAccount" ref="com.axelor.apps.account.db.Account" title="Purchase account"/>
|
||||||
|
<many-to-one name="saleAccount" ref="com.axelor.apps.account.db.Account" title="Sale account"/>
|
||||||
|
<many-to-one name="stockAccount" ref="com.axelor.apps.account.db.Account" title="Stock account"/>
|
||||||
|
<many-to-one name="consumptionAccount" ref="com.axelor.apps.account.db.Account" title="Consumption account"/>
|
||||||
|
<many-to-one name="purchFixedAssetsAccount" ref="com.axelor.apps.account.db.Account" title="Account of purchase fixed assets"/>
|
||||||
|
<many-to-one name="purchaseTax" ref="com.axelor.apps.account.db.Tax" title="Purchase Tax"/>
|
||||||
|
<many-to-one name="saleTax" ref="com.axelor.apps.account.db.Tax" title="Sale Tax"/>
|
||||||
|
<many-to-one name="tax" ref="com.axelor.apps.account.db.Tax" title="Tax"/>
|
||||||
|
|
||||||
|
<track>
|
||||||
|
<field name="purchaseAccount"/>
|
||||||
|
<field name="saleAccount"/>
|
||||||
|
<field name="stockAccount"/>
|
||||||
|
<field name="consumptionAccount"/>
|
||||||
|
<field name="purchFixedAssetsAccount"/>
|
||||||
|
<field name="purchaseTax"/>
|
||||||
|
<field name="saleTax"/>
|
||||||
|
<field name="tax"/>
|
||||||
|
</track>
|
||||||
|
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
</domain-models>
|
||||||
@@ -155,6 +155,10 @@
|
|||||||
<many-to-one name="deliveryPartner" ref="com.axelor.apps.base.db.Partner" title="Delivery Supplier"/>
|
<many-to-one name="deliveryPartner" ref="com.axelor.apps.base.db.Partner" title="Delivery Supplier"/>
|
||||||
|
|
||||||
|
|
||||||
|
<many-to-one name="analyticJournal" ref="com.axelor.apps.account.db.AnalyticJournal" title="Analytic journal"/>
|
||||||
|
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic account"/>
|
||||||
|
<many-to-one name="analyticAxis" ref="com.axelor.apps.account.db.AnalyticAxis" title="Analytic axis" />
|
||||||
|
|
||||||
<unique-constraint columns="invoiceId,company"/>
|
<unique-constraint columns="invoiceId,company"/>
|
||||||
|
|
||||||
<extra-code><![CDATA[
|
<extra-code><![CDATA[
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
package com.axelor.apps.account.web;
|
package com.axelor.apps.account.web;
|
||||||
|
|
||||||
import org.junit.Before;
|
import static org.junit.Assert.assertEquals;
|
||||||
import org.junit.Test;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
import com.axelor.apps.account.db.CashInventory;
|
import com.axelor.apps.account.db.CashInventory;
|
||||||
import com.axelor.apps.base.service.ConvertNumberToFrenchWordsService;
|
import com.axelor.apps.base.service.ConvertNumberToFrenchWordsService;
|
||||||
import com.axelor.inject.Beans;
|
|
||||||
import com.axelor.rpc.ActionRequest;
|
import com.axelor.rpc.ActionRequest;
|
||||||
import com.axelor.rpc.ActionResponse;
|
import com.axelor.rpc.ActionResponse;
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
public class CashInventoryControllerTest {
|
public class CashInventoryControllerTest {
|
||||||
|
|
||||||
@@ -42,7 +41,6 @@ public class CashInventoryControllerTest {
|
|||||||
when(cashInventory.getTheoricalSolde()).thenReturn(new BigDecimal("1234.56"));
|
when(cashInventory.getTheoricalSolde()).thenReturn(new BigDecimal("1234.56"));
|
||||||
when(convertService.convert(1234L)).thenReturn("mille deux cent trente-quatre");
|
when(convertService.convert(1234L)).thenReturn("mille deux cent trente-quatre");
|
||||||
when(convertService.convert(56L)).thenReturn("cinquante-six");
|
when(convertService.convert(56L)).thenReturn("cinquante-six");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -52,7 +50,6 @@ public class CashInventoryControllerTest {
|
|||||||
when(convertService.convert(1000L)).thenReturn("mille");
|
when(convertService.convert(1000L)).thenReturn("mille");
|
||||||
when(convertService.convert(0L)).thenReturn("zéro");
|
when(convertService.convert(0L)).thenReturn("zéro");
|
||||||
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
@@ -68,7 +65,6 @@ public class CashInventoryControllerTest {
|
|||||||
// when(convertService.convert(42L)).thenReturn("quarante-deux");
|
// when(convertService.convert(42L)).thenReturn("quarante-deux");
|
||||||
// when(convertService.convert(0L)).thenReturn("zéro");
|
// when(convertService.convert(0L)).thenReturn("zéro");
|
||||||
|
|
||||||
|
|
||||||
// // Then
|
// // Then
|
||||||
// ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
|
// ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
// ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
|
// ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class ProductBaseRepository extends ProductRepository {
|
|||||||
FULL_NAME_FORMAT, product.getCode(), product.getName());
|
FULL_NAME_FORMAT, product.getCode(), product.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
product = super.save(product);
|
// product = super.save(product);
|
||||||
if (product.getBarCode() == null
|
if (product.getBarCode() == null
|
||||||
&& appBaseService.getAppBase().getActivateBarCodeGeneration()) {
|
&& appBaseService.getAppBase().getActivateBarCodeGeneration()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
<many-to-one name="familleParente" ref="FamilleProduit" title="Famille Parente"/>
|
<many-to-one name="familleParente" ref="FamilleProduit" title="Famille Parente"/>
|
||||||
<integer name="niveau" title="Niveau" />
|
<integer name="niveau" title="Niveau" />
|
||||||
<many-to-many name="parente" ref="com.axelor.apps.base.db.FamilleProduit" title="Famille Parente"/>
|
<many-to-many name="parente" ref="com.axelor.apps.base.db.FamilleProduit" title="Famille Parente"/>
|
||||||
|
<boolean name="usableOnImmobilisation" title="Usable on immobilisation" />
|
||||||
|
|
||||||
</entity>
|
</entity>
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.axelor.apps.ReportFactory;
|
|||||||
import com.axelor.apps.account.db.Invoice;
|
import com.axelor.apps.account.db.Invoice;
|
||||||
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
||||||
import com.axelor.apps.account.exception.IExceptionMessage;
|
import com.axelor.apps.account.exception.IExceptionMessage;
|
||||||
|
import com.axelor.apps.account.service.AnalyticMoveLineService;
|
||||||
import com.axelor.apps.account.service.app.AppAccountService;
|
import com.axelor.apps.account.service.app.AppAccountService;
|
||||||
import com.axelor.apps.account.service.config.AccountConfigService;
|
import com.axelor.apps.account.service.config.AccountConfigService;
|
||||||
import com.axelor.apps.account.service.invoice.InvoiceLineService;
|
import com.axelor.apps.account.service.invoice.InvoiceLineService;
|
||||||
@@ -52,7 +53,8 @@ public class InvoiceServiceProjectImpl extends InvoiceServiceSupplychainImpl {
|
|||||||
AppAccountService appAccountService,
|
AppAccountService appAccountService,
|
||||||
PartnerService partnerService,
|
PartnerService partnerService,
|
||||||
InvoiceLineService invoiceLineService,
|
InvoiceLineService invoiceLineService,
|
||||||
AccountConfigService accountConfigService) {
|
AccountConfigService accountConfigService,
|
||||||
|
AnalyticMoveLineService analyticMoveLineService) {
|
||||||
super(
|
super(
|
||||||
validateFactory,
|
validateFactory,
|
||||||
ventilateFactory,
|
ventilateFactory,
|
||||||
@@ -62,7 +64,8 @@ public class InvoiceServiceProjectImpl extends InvoiceServiceSupplychainImpl {
|
|||||||
appAccountService,
|
appAccountService,
|
||||||
partnerService,
|
partnerService,
|
||||||
invoiceLineService,
|
invoiceLineService,
|
||||||
accountConfigService);
|
accountConfigService,
|
||||||
|
analyticMoveLineService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> editInvoiceAnnex(Invoice invoice, String invoiceIds, boolean toAttach)
|
public List<String> editInvoiceAnnex(Invoice invoice, String invoiceIds, boolean toAttach)
|
||||||
|
|||||||
@@ -792,8 +792,10 @@ public class ManufOrderStockMoveService {
|
|||||||
stockConfigService.getProductionVirtualStockLocation(stockConfig);
|
stockConfigService.getProductionVirtualStockLocation(stockConfig);
|
||||||
stockMove.setToStockLocation(virtualStockLocation);
|
stockMove.setToStockLocation(virtualStockLocation);
|
||||||
stockMove.setPartner(manufOrder.getCompany().getPartner());
|
stockMove.setPartner(manufOrder.getCompany().getPartner());
|
||||||
for (BillOfMaterialConsumption billOfMaterialConsumption : manufOrder.getBillOfMaterialConsumptionList()) {
|
for (BillOfMaterialConsumption billOfMaterialConsumption :
|
||||||
StockMoveLine stockMoveLine = stockMoveLineService.createStockMoveLine(
|
manufOrder.getBillOfMaterialConsumptionList()) {
|
||||||
|
StockMoveLine stockMoveLine =
|
||||||
|
stockMoveLineService.createStockMoveLine(
|
||||||
billOfMaterialConsumption.getProduct(),
|
billOfMaterialConsumption.getProduct(),
|
||||||
billOfMaterialConsumption.getProduct().getName(),
|
billOfMaterialConsumption.getProduct().getName(),
|
||||||
billOfMaterialConsumption.getProduct().getDescription(),
|
billOfMaterialConsumption.getProduct().getDescription(),
|
||||||
@@ -812,8 +814,7 @@ public class ManufOrderStockMoveService {
|
|||||||
if (stockMove.getStockMoveLineList() != null && !stockMove.getStockMoveLineList().isEmpty()) {
|
if (stockMove.getStockMoveLineList() != null && !stockMove.getStockMoveLineList().isEmpty()) {
|
||||||
stockMoveService.plan(stockMove);
|
stockMoveService.plan(stockMove);
|
||||||
manufOrder.addOutStockMoveListItem(stockMove);
|
manufOrder.addOutStockMoveListItem(stockMove);
|
||||||
|
manufOrder.setRealEndDateT(LocalDateTime.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -771,9 +771,7 @@ public class ManufOrderController {
|
|||||||
manufOrders =
|
manufOrders =
|
||||||
Beans.get(ManufOrderRepository.class)
|
Beans.get(ManufOrderRepository.class)
|
||||||
.all()
|
.all()
|
||||||
.filter(
|
.filter("self.id in ?1", context.get("_ids"))
|
||||||
"self.id in ?1",
|
|
||||||
context.get("_ids"))
|
|
||||||
.fetch();
|
.fetch();
|
||||||
}
|
}
|
||||||
for (ManufOrder manufOrder : manufOrders) {
|
for (ManufOrder manufOrder : manufOrders) {
|
||||||
|
|||||||
@@ -730,10 +730,17 @@ public class PurchaseOrderLineServiceImpl implements PurchaseOrderLineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PurchaseOrderLine createPurchaseOrderLine(PurchaseOrder purchaseOrder, Product product, String productName,
|
public PurchaseOrderLine createPurchaseOrderLine(
|
||||||
String description, BigDecimal qty, Unit unit, PurchaseRequestLine purchaseRequestLine) throws AxelorException {
|
PurchaseOrder purchaseOrder,
|
||||||
PurchaseOrderLine purchaseOrderLine = this.createPurchaseOrderLine(purchaseOrder, product, productName, description, qty, unit);
|
Product product,
|
||||||
|
String productName,
|
||||||
|
String description,
|
||||||
|
BigDecimal qty,
|
||||||
|
Unit unit,
|
||||||
|
PurchaseRequestLine purchaseRequestLine)
|
||||||
|
throws AxelorException {
|
||||||
|
PurchaseOrderLine purchaseOrderLine =
|
||||||
|
this.createPurchaseOrderLine(purchaseOrder, product, productName, description, qty, unit);
|
||||||
return purchaseOrderLine;
|
return purchaseOrderLine;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ public class PurchaseRequestPrintServiceImpl implements PurchaseRequestPrintServ
|
|||||||
ReportSettings reportSetting =
|
ReportSettings reportSetting =
|
||||||
ReportFactory.createReport(IReport.PURCHASE_REQUEST, title + " - ${date}");
|
ReportFactory.createReport(IReport.PURCHASE_REQUEST, title + " - ${date}");
|
||||||
|
|
||||||
|
|
||||||
return reportSetting
|
return reportSetting
|
||||||
.addParam("PurchaseRequestId", purchaseRequest.getId())
|
.addParam("PurchaseRequestId", purchaseRequest.getId())
|
||||||
.addParam("Locale", locale)
|
.addParam("Locale", locale)
|
||||||
@@ -103,8 +102,6 @@ public class PurchaseRequestPrintServiceImpl implements PurchaseRequestPrintServ
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFileName(PurchaseRequest purchaseRequest) {
|
public String getFileName(PurchaseRequest purchaseRequest) {
|
||||||
return I18n.get("Purchase request")
|
return I18n.get("Purchase request") + " " + purchaseRequest.getPurchaseRequestSeq();
|
||||||
+ " "
|
|
||||||
+ purchaseRequest.getPurchaseRequestSeq();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,12 @@
|
|||||||
|
|
||||||
<boolean name="isWithoutPayment" title="Is Without Payment"/>
|
<boolean name="isWithoutPayment" title="Is Without Payment"/>
|
||||||
|
|
||||||
|
<boolean name="authorizeBudget" title="Authoriser depassement budget"/>
|
||||||
|
|
||||||
|
<boolean name="budgetChecked" title="Budget checked" default="false"/>
|
||||||
|
<many-to-one name="verifiedByUser" ref="com.axelor.auth.db.User" readonly="true" title="Verified by"/>
|
||||||
|
<date name="budgetVerificationDate" title="Budget verification date" readonly="true"/>
|
||||||
|
|
||||||
<unique-constraint columns="purchaseOrderSeq,company"/>
|
<unique-constraint columns="purchaseOrderSeq,company"/>
|
||||||
|
|
||||||
<extra-code>
|
<extra-code>
|
||||||
|
|||||||
@@ -43,6 +43,12 @@
|
|||||||
|
|
||||||
<integer name="limitPo" title="limit Po" default="1"/>
|
<integer name="limitPo" title="limit Po" default="1"/>
|
||||||
|
|
||||||
|
<boolean name="budgetChecked" title="Budget checked"/>
|
||||||
|
<many-to-one name="verifiedByUser" ref="com.axelor.auth.db.User" readonly="true" title="Verified by"/>
|
||||||
|
<date name="budgetVerificationDate" title="Budget verification date" readonly="true"/>
|
||||||
|
<date name="budgetRejectionDate" title="Budget rejection date" readonly="true"/>
|
||||||
|
|
||||||
|
|
||||||
<unique-constraint columns="purchaseRequestSeq"/>
|
<unique-constraint columns="purchaseRequestSeq"/>
|
||||||
|
|
||||||
<extra-code>
|
<extra-code>
|
||||||
@@ -63,6 +69,7 @@
|
|||||||
<field name="statusSelect"/>
|
<field name="statusSelect"/>
|
||||||
<field name="supplierUser"/>
|
<field name="supplierUser"/>
|
||||||
<field name="purchaseRequestSeq" />
|
<field name="purchaseRequestSeq" />
|
||||||
|
<field name="budgetChecked" />
|
||||||
</track>
|
</track>
|
||||||
|
|
||||||
</entity>
|
</entity>
|
||||||
|
|||||||
@@ -18,18 +18,84 @@
|
|||||||
package com.axelor.apps.stock.db.repo;
|
package com.axelor.apps.stock.db.repo;
|
||||||
|
|
||||||
import com.axelor.apps.base.db.Product;
|
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.db.StockLocationLine;
|
||||||
import com.axelor.apps.stock.service.WeightedAveragePriceService;
|
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.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 {
|
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
|
@Override
|
||||||
public StockLocationLine save(StockLocationLine entity) {
|
public StockLocationLine save(StockLocationLine entity) {
|
||||||
Product product = entity.getProduct();
|
Product product = entity.getProduct();
|
||||||
if (entity.getIsAvgPriceChanged()) {
|
if (entity.getIsAvgPriceChanged()) {
|
||||||
Beans.get(WeightedAveragePriceService.class).computeAvgPriceForProduct(product);
|
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);
|
return super.save(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ import java.lang.invoke.MethodHandles;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -80,6 +81,15 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
this.wapHistoryRepo = wapHistoryRepo;
|
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
|
@Override
|
||||||
@Transactional(rollbackOn = { Exception.class })
|
@Transactional(rollbackOn = { Exception.class })
|
||||||
public void updateLocation(
|
public void updateLocation(
|
||||||
@@ -106,6 +116,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
lastFutureStockMoveDate);
|
lastFutureStockMoveDate);
|
||||||
|
|
||||||
if (trackingNumber != null) {
|
if (trackingNumber != null) {
|
||||||
|
LOG.debug("trackingNumber != null in updateLocation ****** ");
|
||||||
this.updateDetailLocation(
|
this.updateDetailLocation(
|
||||||
stockLocation,
|
stockLocation,
|
||||||
product,
|
product,
|
||||||
@@ -117,6 +128,8 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
lastFutureStockMoveDate,
|
lastFutureStockMoveDate,
|
||||||
trackingNumber);
|
trackingNumber);
|
||||||
}
|
}
|
||||||
|
LOG.debug("updateLocation passed qll updateLocation ");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -132,20 +145,34 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
LocalDate lastFutureStockMoveDate)
|
LocalDate lastFutureStockMoveDate)
|
||||||
throws AxelorException {
|
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) {
|
if (stockLocationLine == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.debug(
|
||||||
|
"Mise à jour du stock : Entrepot? {}, Produit? {}, Quantité? {}, Actuel? {}, Futur? {}, Incrément? {}, Date? {} ",
|
||||||
|
stockLocation.getName(),
|
||||||
|
product.getCode());
|
||||||
|
|
||||||
|
// bypassing labo
|
||||||
|
if (!isNoUnitConversionLocation(stockLocation)) {
|
||||||
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
||||||
Unit stockLocationLineUnit = stockLocationLine.getUnit();
|
Unit stockLocationLineUnit = stockLocationLine.getUnit();
|
||||||
|
|
||||||
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
|
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
|
||||||
qty =
|
qty = unitConversionService.convert(
|
||||||
unitConversionService.convert(
|
|
||||||
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
|
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Mise à jour du stock : Entrepot? {}, Produit? {}, Quantité? {}, Actuel? {}, Futur? {}, Incrément? {}, Date? {} ",
|
"Mise à jour du stock : Entrepot? {}, Produit? {}, Quantité? {}, Actuel? {}, Futur? {}, Incrément? {}, Date? {} ",
|
||||||
@@ -163,6 +190,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
maxStockRules(product, qty, stockLocationLine, current, future);
|
maxStockRules(product, qty, stockLocationLine, current, future);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stockLocationLine =
|
stockLocationLine =
|
||||||
this.updateLocation(
|
this.updateLocation(
|
||||||
stockLocationLine,
|
stockLocationLine,
|
||||||
@@ -176,6 +204,9 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
|
|
||||||
this.checkStockMin(stockLocationLine, false);
|
this.checkStockMin(stockLocationLine, false);
|
||||||
|
|
||||||
|
LOG.debug("updateLocation passed min max stock rules ");
|
||||||
|
|
||||||
|
|
||||||
stockLocationLineRepo.save(stockLocationLine);
|
stockLocationLineRepo.save(stockLocationLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,21 +296,34 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
TrackingNumber trackingNumber)
|
TrackingNumber trackingNumber)
|
||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
|
|
||||||
StockLocationLine detailLocationLine =
|
StockLocationLine detailLocationLine;
|
||||||
this.getOrCreateDetailLocationLine(stockLocation, product, trackingNumber);
|
|
||||||
|
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) {
|
if (detailLocationLine == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isNoUnitConversionLocation(stockLocation)) {
|
||||||
|
|
||||||
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
||||||
Unit stockLocationLineUnit = detailLocationLine.getUnit();
|
Unit stockLocationLineUnit = detailLocationLine.getUnit();
|
||||||
|
|
||||||
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
|
if (stockLocationLineUnit != null && !stockLocationLineUnit.equals(stockMoveLineUnit)) {
|
||||||
qty =
|
qty = unitConversionService.convert(
|
||||||
unitConversionService.convert(
|
|
||||||
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
|
stockMoveLineUnit, stockLocationLineUnit, qty, qty.scale(), product);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Mise à jour du detail du stock : Entrepot? {}, Produit? {}, Quantité? {}, Actuel? {}, Futur? {}, Incrément? {}, Date? {}, Num de suivi? {} ",
|
"Mise à jour du detail du stock : Entrepot? {}, Produit? {}, Quantité? {}, Actuel? {}, Futur? {}, Incrément? {}, Date? {}, Num de suivi? {} ",
|
||||||
@@ -426,8 +470,13 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
StockLocationLine detailLocationLine =
|
StockLocationLine detailLocationLine =
|
||||||
this.getDetailLocationLine(detailLocation, product, trackingNumber);
|
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);
|
detailLocationLine = this.createDetailLocationLine(detailLocation, product, trackingNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,8 +530,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
.filter(
|
.filter(
|
||||||
"self.detailsStockLocation.id = :_stockLocationId "
|
"self.detailsStockLocation.id = :_stockLocationId "
|
||||||
+ "AND self.product.id = :_productId "
|
+ "AND self.product.id = :_productId "
|
||||||
+ "AND self.trackingNumber.id = :_trackingNumberId "
|
+ "AND self.trackingNumber.id = :_trackingNumberId ")
|
||||||
)
|
|
||||||
.bind("_stockLocationId", stockLocation.getId())
|
.bind("_stockLocationId", stockLocation.getId())
|
||||||
.bind("_productId", product.getId())
|
.bind("_productId", product.getId())
|
||||||
.bind("_trackingNumberId", trackingNumber.getId())
|
.bind("_trackingNumberId", trackingNumber.getId())
|
||||||
@@ -564,8 +612,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
BigDecimal oldAvgPrice = stockLocationLine.getAvgPrice();
|
BigDecimal oldAvgPrice = stockLocationLine.getAvgPrice();
|
||||||
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
||||||
|
|
||||||
BigDecimal currentQty =
|
BigDecimal currentQty = unitConversionService.convert(
|
||||||
unitConversionService.convert(
|
|
||||||
stockLocationUnit,
|
stockLocationUnit,
|
||||||
productUnit,
|
productUnit,
|
||||||
stockLocationLine.getCurrentQty(),
|
stockLocationLine.getCurrentQty(),
|
||||||
@@ -586,14 +633,14 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
return stockLocationLine;
|
return stockLocationLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final String STOCK_MOVE_LINE_FILTER =
|
protected static final String STOCK_MOVE_LINE_FILTER = "(self.stockMove.archived IS NULL OR self.archived IS FALSE) "
|
||||||
"(self.stockMove.archived IS NULL OR self.archived IS FALSE) "
|
|
||||||
+ "AND self.stockMove.statusSelect = :planned "
|
+ "AND self.stockMove.statusSelect = :planned "
|
||||||
+ "AND self.product.id = :productId ";
|
+ "AND self.product.id = :productId ";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigDecimal computeFutureQty(StockLocationLine stockLocationLine) throws AxelorException {
|
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.
|
// incoming stock move lines.
|
||||||
|
|
||||||
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
UnitConversionService unitConversionService = Beans.get(UnitConversionService.class);
|
||||||
@@ -601,30 +648,35 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
|
|
||||||
BigDecimal futureQty = stockLocationLine.getCurrentQty();
|
BigDecimal futureQty = stockLocationLine.getCurrentQty();
|
||||||
|
|
||||||
List<StockMoveLine> incomingStockMoveLineList =
|
List<StockMoveLine> incomingStockMoveLineList = findIncomingPlannedStockMoveLines(stockLocationLine);
|
||||||
findIncomingPlannedStockMoveLines(stockLocationLine);
|
List<StockMoveLine> outgoingStockMoveLineList = findOutgoingPlannedStockMoveLines(stockLocationLine);
|
||||||
List<StockMoveLine> outgoingStockMoveLineList =
|
|
||||||
findOutgoingPlannedStockMoveLines(stockLocationLine);
|
|
||||||
|
|
||||||
for (StockMoveLine incomingStockMoveLine : incomingStockMoveLineList) {
|
for (StockMoveLine incomingStockMoveLine : incomingStockMoveLineList) {
|
||||||
BigDecimal qtyToAdd =
|
// bypassing labo
|
||||||
unitConversionService.convert(
|
BigDecimal qtyToAdd = incomingStockMoveLine.getRealQty();
|
||||||
|
if(!isNoUnitConversionLocation(stockLocationLine.getStockLocation())){
|
||||||
|
qtyToAdd = unitConversionService.convert(
|
||||||
incomingStockMoveLine.getUnit(),
|
incomingStockMoveLine.getUnit(),
|
||||||
stockLocationLine.getUnit(),
|
stockLocationLine.getUnit(),
|
||||||
incomingStockMoveLine.getRealQty(),
|
incomingStockMoveLine.getRealQty(),
|
||||||
incomingStockMoveLine.getRealQty().scale(),
|
incomingStockMoveLine.getRealQty().scale(),
|
||||||
product);
|
product);
|
||||||
|
}
|
||||||
futureQty = futureQty.add(qtyToAdd);
|
futureQty = futureQty.add(qtyToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (StockMoveLine outgoingStockMoveLine : outgoingStockMoveLineList) {
|
for (StockMoveLine outgoingStockMoveLine : outgoingStockMoveLineList) {
|
||||||
BigDecimal qtyToSubtract =
|
BigDecimal qtyToSubtract = outgoingStockMoveLine.getRealQty();
|
||||||
unitConversionService.convert(
|
|
||||||
|
if(!isNoUnitConversionLocation(stockLocationLine.getStockLocation())){
|
||||||
|
|
||||||
|
qtyToSubtract = unitConversionService.convert(
|
||||||
outgoingStockMoveLine.getUnit(),
|
outgoingStockMoveLine.getUnit(),
|
||||||
stockLocationLine.getUnit(),
|
stockLocationLine.getUnit(),
|
||||||
outgoingStockMoveLine.getRealQty(),
|
outgoingStockMoveLine.getRealQty(),
|
||||||
outgoingStockMoveLine.getRealQty().scale(),
|
outgoingStockMoveLine.getRealQty().scale(),
|
||||||
product);
|
product);
|
||||||
|
}
|
||||||
futureQty = futureQty.subtract(qtyToSubtract);
|
futureQty = futureQty.subtract(qtyToSubtract);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,14 +686,12 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
protected List<StockMoveLine> findIncomingPlannedStockMoveLines(
|
protected List<StockMoveLine> findIncomingPlannedStockMoveLines(
|
||||||
StockLocationLine stockLocationLine) {
|
StockLocationLine stockLocationLine) {
|
||||||
boolean isDetailsStockLocationLine = stockLocationLine.getDetailsStockLocation() != null;
|
boolean isDetailsStockLocationLine = stockLocationLine.getDetailsStockLocation() != null;
|
||||||
String incomingStockMoveLineFilter =
|
String incomingStockMoveLineFilter = STOCK_MOVE_LINE_FILTER
|
||||||
STOCK_MOVE_LINE_FILTER + "AND self.stockMove.toStockLocation.id = :stockLocationId";
|
+ "AND self.stockMove.toStockLocation.id = :stockLocationId";
|
||||||
if (isDetailsStockLocationLine) {
|
if (isDetailsStockLocationLine) {
|
||||||
incomingStockMoveLineFilter =
|
incomingStockMoveLineFilter = incomingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
|
||||||
incomingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
|
|
||||||
}
|
}
|
||||||
Query<StockMoveLine> stockMoveLineQuery =
|
Query<StockMoveLine> stockMoveLineQuery = stockMoveLineRepository
|
||||||
stockMoveLineRepository
|
|
||||||
.all()
|
.all()
|
||||||
.filter(incomingStockMoveLineFilter)
|
.filter(incomingStockMoveLineFilter)
|
||||||
.bind("planned", StockMoveRepository.STATUS_PLANNED)
|
.bind("planned", StockMoveRepository.STATUS_PLANNED)
|
||||||
@@ -659,14 +709,12 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
protected List<StockMoveLine> findOutgoingPlannedStockMoveLines(
|
protected List<StockMoveLine> findOutgoingPlannedStockMoveLines(
|
||||||
StockLocationLine stockLocationLine) {
|
StockLocationLine stockLocationLine) {
|
||||||
boolean isDetailsStockLocationLine = stockLocationLine.getDetailsStockLocation() != null;
|
boolean isDetailsStockLocationLine = stockLocationLine.getDetailsStockLocation() != null;
|
||||||
String outgoingStockMoveLineFilter =
|
String outgoingStockMoveLineFilter = STOCK_MOVE_LINE_FILTER
|
||||||
STOCK_MOVE_LINE_FILTER + "AND self.stockMove.fromStockLocation.id = :stockLocationId";
|
+ "AND self.stockMove.fromStockLocation.id = :stockLocationId";
|
||||||
if (isDetailsStockLocationLine) {
|
if (isDetailsStockLocationLine) {
|
||||||
outgoingStockMoveLineFilter =
|
outgoingStockMoveLineFilter = outgoingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
|
||||||
outgoingStockMoveLineFilter + " AND self.trackingNumber.id = :trackingNumberId";
|
|
||||||
}
|
}
|
||||||
Query<StockMoveLine> stockMoveLineQuery =
|
Query<StockMoveLine> stockMoveLineQuery = stockMoveLineRepository
|
||||||
stockMoveLineRepository
|
|
||||||
.all()
|
.all()
|
||||||
.filter(outgoingStockMoveLineFilter)
|
.filter(outgoingStockMoveLineFilter)
|
||||||
.bind("planned", StockMoveRepository.STATUS_PLANNED)
|
.bind("planned", StockMoveRepository.STATUS_PLANNED)
|
||||||
@@ -686,8 +734,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
public String getStockLocationLineListForAProduct(
|
public String getStockLocationLineListForAProduct(
|
||||||
Long productId, Long companyId, Long stockLocationId) {
|
Long productId, Long companyId, Long stockLocationId) {
|
||||||
|
|
||||||
String query =
|
String query = "self.product.id = "
|
||||||
"self.product.id = "
|
|
||||||
+ productId
|
+ productId
|
||||||
+ " AND self.stockLocation.typeSelect != "
|
+ " AND self.stockLocation.typeSelect != "
|
||||||
+ StockLocationRepository.TYPE_VIRTUAL;
|
+ StockLocationRepository.TYPE_VIRTUAL;
|
||||||
@@ -695,14 +742,11 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
if (companyId != 0L) {
|
if (companyId != 0L) {
|
||||||
query += " AND self.stockLocation.company.id = " + companyId;
|
query += " AND self.stockLocation.company.id = " + companyId;
|
||||||
if (stockLocationId != 0L) {
|
if (stockLocationId != 0L) {
|
||||||
StockLocation stockLocation =
|
StockLocation stockLocation = Beans.get(StockLocationRepository.class).find(stockLocationId);
|
||||||
Beans.get(StockLocationRepository.class).find(stockLocationId);
|
List<StockLocation> stockLocationList = Beans.get(StockLocationService.class)
|
||||||
List<StockLocation> stockLocationList =
|
|
||||||
Beans.get(StockLocationService.class)
|
|
||||||
.getAllLocationAndSubLocation(stockLocation, false);
|
.getAllLocationAndSubLocation(stockLocation, false);
|
||||||
if (!stockLocationList.isEmpty() && stockLocation.getCompany().getId().equals(companyId)) {
|
if (!stockLocationList.isEmpty() && stockLocation.getCompany().getId().equals(companyId)) {
|
||||||
query +=
|
query += " AND self.stockLocation.id IN ("
|
||||||
" AND self.stockLocation.id IN ("
|
|
||||||
+ StringTool.getIdListString(stockLocationList)
|
+ StringTool.getIdListString(stockLocationList)
|
||||||
+ ") ";
|
+ ") ";
|
||||||
}
|
}
|
||||||
@@ -714,8 +758,7 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
@Override
|
@Override
|
||||||
public String getAvailableStockForAProduct(Long productId, Long companyId, Long stockLocationId) {
|
public String getAvailableStockForAProduct(Long productId, Long companyId, Long stockLocationId) {
|
||||||
String query = this.getStockLocationLineListForAProduct(productId, companyId, stockLocationId);
|
String query = this.getStockLocationLineListForAProduct(productId, companyId, stockLocationId);
|
||||||
query +=
|
query += " AND (self.currentQty != 0 OR self.futureQty != 0) "
|
||||||
" AND (self.currentQty != 0 OR self.futureQty != 0) "
|
|
||||||
+ " AND (self.stockLocation.isNotInCalculStock = false OR self.stockLocation.isNotInCalculStock IS NULL)";
|
+ " AND (self.stockLocation.isNotInCalculStock = false OR self.stockLocation.isNotInCalculStock IS NULL)";
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
@@ -750,8 +793,8 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
@Override
|
@Override
|
||||||
public BigDecimal getTrackingNumberAvailableQty(
|
public BigDecimal getTrackingNumberAvailableQty(
|
||||||
StockLocation stockLocation, TrackingNumber trackingNumber) {
|
StockLocation stockLocation, TrackingNumber trackingNumber) {
|
||||||
StockLocationLine detailStockLocationLine =
|
StockLocationLine detailStockLocationLine = getDetailLocationLine(stockLocation, trackingNumber.getProduct(),
|
||||||
getDetailLocationLine(stockLocation, trackingNumber.getProduct(), trackingNumber);
|
trackingNumber);
|
||||||
|
|
||||||
BigDecimal availableQty = BigDecimal.ZERO;
|
BigDecimal availableQty = BigDecimal.ZERO;
|
||||||
|
|
||||||
@@ -760,4 +803,88 @@ public class StockLocationLineServiceImpl implements StockLocationLineService {
|
|||||||
}
|
}
|
||||||
return availableQty;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,38 +470,53 @@ public class StockMoveLineServiceImpl implements StockMoveLineService {
|
|||||||
lastFutureStockMoveDate,
|
lastFutureStockMoveDate,
|
||||||
stockMoveLine.getTrackingNumber(),
|
stockMoveLine.getTrackingNumber(),
|
||||||
stockMoveLine.getInternalTrackingNumber());
|
stockMoveLine.getInternalTrackingNumber());
|
||||||
if (fromStockLocation.getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL) {
|
|
||||||
|
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);
|
this.updateAveragePriceLocationLine(toStockLocation, stockMoveLine, fromStatus, toStatus);
|
||||||
weightedAveragePriceService.computeAvgPriceForProduct(stockMoveLine.getProduct());
|
weightedAveragePriceService.computeAvgPriceForProduct(stockMoveLine.getProduct());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
List<Long> listOfIds = Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L, 50L);
|
List<Long> listOfIds = Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L, 50L);
|
||||||
if (toStatus == StockMoveRepository.STATUS_REALIZED) {
|
if (toStatus == StockMoveRepository.STATUS_REALIZED) {
|
||||||
if (stockMoveLine.getTrackingNumber() != null && stockMoveLine.getRealQty().compareTo(BigDecimal.ZERO) != 0) {
|
if (stockMoveLine.getTrackingNumber() != null && stockMoveLine.getRealQty().compareTo(BigDecimal.ZERO) != 0) {
|
||||||
if (stockMoveLine.getStockMove() != null) {
|
if (stockMoveLine.getStockMove() != null) {
|
||||||
if (stockMoveLine.getStockMove().getTypeSelect() == StockMoveRepository.TYPE_INCOMING) {
|
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());
|
toStockLocation, product, stockMoveLine.getTrackingNumber());
|
||||||
// TODO WMS
|
// TODO WMS
|
||||||
if (toStockLocationLine != null) {
|
if (toStockLocationLine != null) {
|
||||||
// if(listOfIds.contains(fromStockLocation.getId())){
|
// if(listOfIds.contains(fromStockLocation.getId())){
|
||||||
if (stockMoveLine.getStockMove().getPartner().getId() != 853L) {
|
if (stockMoveLine.getStockMove().getPartner().getId() != 853L) {
|
||||||
toStockLocationLine.setConformitySelect(StockLocationRepository.TYPE_QUARANTINE);
|
toStockLocationLine.setConformitySelect(
|
||||||
|
StockLocationRepository.TYPE_QUARANTINE);
|
||||||
Beans.get(StockLocationLineRepository.class).save(toStockLocationLine);
|
Beans.get(StockLocationLineRepository.class).save(toStockLocationLine);
|
||||||
} else {
|
} else {
|
||||||
if(stockMoveLine.getRealQty().compareTo(toStockLocationLine.getCurrentQty()) == 0){
|
if (stockMoveLine.getRealQty().compareTo(toStockLocationLine.getCurrentQty())
|
||||||
toStockLocationLine.setConformitySelect(StockLocationRepository.TYPE_QUARANTINE);
|
== 0) {
|
||||||
|
toStockLocationLine.setConformitySelect(
|
||||||
|
StockLocationRepository.TYPE_QUARANTINE);
|
||||||
Beans.get(StockLocationLineRepository.class).save(toStockLocationLine);
|
Beans.get(StockLocationLineRepository.class).save(toStockLocationLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (stockMoveLine.getStockMove().getTypeSelect() == StockMoveRepository.TYPE_INTERNAL) {
|
} else if (stockMoveLine.getStockMove().getTypeSelect() == StockMoveRepository.TYPE_INTERNAL) {
|
||||||
StockLocationLine fromStockLocationLine = Beans.get(StockLocationLineService.class).getDetailLocationLine(
|
StockLocationLine fromStockLocationLine = Beans.get(StockLocationLineService.class)
|
||||||
fromStockLocation, product, stockMoveLine.getTrackingNumber() );
|
.getDetailLocationLine(fromStockLocation, product, stockMoveLine.getTrackingNumber());
|
||||||
StockLocationLine toStockLocationLine = Beans.get(StockLocationLineService.class).getDetailLocationLine(
|
StockLocationLine toStockLocationLine = Beans.get(StockLocationLineService.class)
|
||||||
toStockLocation, product, stockMoveLine.getTrackingNumber());
|
.getDetailLocationLine(toStockLocation, product, stockMoveLine.getTrackingNumber());
|
||||||
log.debug(
|
log.debug(
|
||||||
"fromStockLocationLine: {}, toStockLocationLine: {}, fromStockLocationLineConformity: {}, toStockLocationLineConformity: {}",
|
"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) {
|
if (toStockLocationLine != null && toStockLocationLine.getCurrentQty().compareTo(BigDecimal.ZERO) != 0) {
|
||||||
toStockLocationLine.setConformitySelect(fromStockLocationLine.getConformitySelect());
|
toStockLocationLine.setConformitySelect(fromStockLocationLine.getConformitySelect());
|
||||||
@@ -513,6 +528,8 @@ public class StockMoveLineServiceImpl implements StockMoveLineService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,5 +247,4 @@ public interface StockMoveService {
|
|||||||
public void massPlan(List<Long> requestIds) throws AxelorException;
|
public void massPlan(List<Long> requestIds) throws AxelorException;
|
||||||
|
|
||||||
public void massRealize(List<Long> requestIds) throws AxelorException;
|
public void massRealize(List<Long> requestIds) throws AxelorException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.axelor.apps.stock.db.StockLocation;
|
|||||||
import com.axelor.apps.stock.db.StockMove;
|
import com.axelor.apps.stock.db.StockMove;
|
||||||
import com.axelor.apps.stock.db.StockMoveLine;
|
import com.axelor.apps.stock.db.StockMoveLine;
|
||||||
import com.axelor.apps.stock.db.StockMoveLineLocationLine;
|
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.InternalTrackingNumberRepository;
|
||||||
import com.axelor.apps.stock.db.repo.InventoryLineRepository;
|
import com.axelor.apps.stock.db.repo.InventoryLineRepository;
|
||||||
import com.axelor.apps.stock.db.repo.InventoryRepository;
|
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.exception.db.repo.TraceBackRepository;
|
||||||
import com.axelor.i18n.I18n;
|
import com.axelor.i18n.I18n;
|
||||||
import com.axelor.inject.Beans;
|
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.MoreObjects;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -79,9 +78,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -421,16 +418,34 @@ public class StockMoveServiceImpl implements StockMoveService {
|
|||||||
System.out.println("Checking oooo...................");
|
System.out.println("Checking oooo...................");
|
||||||
|
|
||||||
// checking .....
|
// checking .....
|
||||||
if (stockMove.getFromStockLocation().getTypeSelect() != StockLocationRepository.TYPE_VIRTUAL)
|
if (stockMove.getFromStockLocation().getTypeSelect() != StockLocationRepository.TYPE_VIRTUAL) {
|
||||||
{
|
List<Long> listOfIds =
|
||||||
List<Long> listOfIds = Arrays.asList(10L, 11L, 13L, 14L, 15L, 16L, 13L, 12L, 54L, 55L, 58L,50L);
|
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 (listOfIds.contains(stockMove.getToStockLocation().getId())) {
|
if (listOfIds.contains(stockMove.getToStockLocation().getId())) {
|
||||||
checkIfQuarantine(stockMove);
|
StockConfig stockConfig =
|
||||||
checkIfNonConformityTag(stockMove);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,26 +473,35 @@ public class StockMoveServiceImpl implements StockMoveService {
|
|||||||
Long familleId = line.getProduct().getFamilleProduit().getId();
|
Long familleId = line.getProduct().getFamilleProduit().getId();
|
||||||
BigDecimal realQty = line.getRealQty();
|
BigDecimal realQty = line.getRealQty();
|
||||||
|
|
||||||
if (!partnerId.equals(853L) && (familleId == 59L || familleId == 67L || familleId == 68L)) {
|
if (!partnerId.equals(853L)
|
||||||
System.out.println("****!partnerId.equals(853L) && (familleId == 59L || familleId == 67L || familleId == 68L)");
|
&& (familleId == 59L || familleId == 67L || familleId == 68L)) {
|
||||||
InternalTrackingNumberService internalTrackingNumberService = Beans.get(InternalTrackingNumberService.class);
|
System.out.println(
|
||||||
InternalTrackingNumberRepository internalTrackingNumberRepo = Beans.get(InternalTrackingNumberRepository.class);
|
"****!partnerId.equals(853L) && (familleId == 59L || familleId == 67L || familleId == 68L)");
|
||||||
StockMoveLineRepository stockMoveLineRepo = Beans.get(StockMoveLineRepository.class);
|
InternalTrackingNumberService internalTrackingNumberService =
|
||||||
|
Beans.get(InternalTrackingNumberService.class);
|
||||||
|
InternalTrackingNumberRepository internalTrackingNumberRepo =
|
||||||
|
Beans.get(InternalTrackingNumberRepository.class);
|
||||||
|
StockMoveLineRepository stockMoveLineRepo =
|
||||||
|
Beans.get(StockMoveLineRepository.class);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InternalTrackingNumber internalTrackingNumber = internalTrackingNumberService.getInternalTrackingNumber(
|
InternalTrackingNumber internalTrackingNumber =
|
||||||
|
internalTrackingNumberService.getInternalTrackingNumber(
|
||||||
line.getProduct(), line.getTrackingNumber());
|
line.getProduct(), line.getTrackingNumber());
|
||||||
|
|
||||||
if (realQty.compareTo(BigDecimal.ZERO) > 0) {
|
if (realQty.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
if (internalTrackingNumber == null) {
|
if (internalTrackingNumber == null) {
|
||||||
InternalTrackingNumber internal = internalTrackingNumberService.createInternalTrackingNumber(
|
InternalTrackingNumber internal =
|
||||||
|
internalTrackingNumberService.createInternalTrackingNumber(
|
||||||
line.getProduct(),
|
line.getProduct(),
|
||||||
line.getStockMove().getCompany(),
|
line.getStockMove().getCompany(),
|
||||||
stockMove.getEstimatedDate(),
|
stockMove.getEstimatedDate(),
|
||||||
line.getTrackingNumber());
|
line.getTrackingNumber());
|
||||||
System.out.println("***********************************internal***************");
|
System.out.println(
|
||||||
|
"***********************************internal***************");
|
||||||
System.out.println(internal);
|
System.out.println(internal);
|
||||||
System.out.println("***********************************internal**********************");
|
System.out.println(
|
||||||
|
"***********************************internal**********************");
|
||||||
|
|
||||||
line.setInternalTrackingNumber(internal);
|
line.setInternalTrackingNumber(internal);
|
||||||
internalTrackingNumberRepo.save(internal);
|
internalTrackingNumberRepo.save(internal);
|
||||||
@@ -485,17 +509,20 @@ public class StockMoveServiceImpl implements StockMoveService {
|
|||||||
} else {
|
} else {
|
||||||
LocalDate createdDate = internalTrackingNumber.getReceptionDate();
|
LocalDate createdDate = internalTrackingNumber.getReceptionDate();
|
||||||
LocalDate estimatedDate = stockMove.getEstimatedDate();
|
LocalDate estimatedDate = stockMove.getEstimatedDate();
|
||||||
System.out.println("***********************************internal not null***************");
|
System.out.println(
|
||||||
|
"***********************************internal not null***************");
|
||||||
System.out.println(internalTrackingNumber);
|
System.out.println(internalTrackingNumber);
|
||||||
System.out.println(createdDate);
|
System.out.println(createdDate);
|
||||||
System.out.println(estimatedDate);
|
System.out.println(estimatedDate);
|
||||||
System.out.println("***********************************internal noy null**********************");
|
System.out.println(
|
||||||
|
"***********************************internal noy null**********************");
|
||||||
|
|
||||||
if (createdDate.equals(estimatedDate)) {
|
if (createdDate.equals(estimatedDate)) {
|
||||||
line.setInternalTrackingNumber(internalTrackingNumber);
|
line.setInternalTrackingNumber(internalTrackingNumber);
|
||||||
stockMoveLineRepo.save(line);
|
stockMoveLineRepo.save(line);
|
||||||
} else {
|
} else {
|
||||||
InternalTrackingNumber internal = internalTrackingNumberService.createInternalTrackingNumber(
|
InternalTrackingNumber internal =
|
||||||
|
internalTrackingNumberService.createInternalTrackingNumber(
|
||||||
line.getProduct(),
|
line.getProduct(),
|
||||||
line.getStockMove().getCompany(),
|
line.getStockMove().getCompany(),
|
||||||
stockMove.getEstimatedDate(),
|
stockMove.getEstimatedDate(),
|
||||||
@@ -511,7 +538,6 @@ public class StockMoveServiceImpl implements StockMoveService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setRealizedStatus(stockMove);
|
setRealizedStatus(stockMove);
|
||||||
@@ -1591,48 +1617,75 @@ public class StockMoveServiceImpl implements StockMoveService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkIfQuarantine(StockMove stockMove, List<Long> excludedProductIds)
|
||||||
public void checkIfQuarantine(StockMove stockMove)
|
|
||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
|
|
||||||
Query sql =
|
StringBuilder queryBuilder = new StringBuilder();
|
||||||
JPA.em()
|
queryBuilder.append(
|
||||||
.createNativeQuery(
|
"SELECT LINE.ID"
|
||||||
"SELECT LINE.ID"+
|
+ " FROM STOCK_STOCK_MOVE_LINE LINE"
|
||||||
" 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"+
|
+ " LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON"
|
||||||
" where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.CONFORMITY_SELECT != 2 AND LOCATION_LINE.CONFORMITY_SELECT != 5 AND LINE.STOCK_MOVE = ?2");
|
+ " 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");
|
||||||
|
|
||||||
|
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
|
||||||
|
queryBuilder.append(" AND LINE.product NOT IN (:excludedProducts)");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("checkIfQuarantine query : ");
|
||||||
|
System.out.println(queryBuilder.toString());
|
||||||
|
|
||||||
|
Query sql = JPA.em().createNativeQuery(queryBuilder.toString());
|
||||||
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.getId());
|
sql.setParameter(2, stockMove.getId());
|
||||||
|
|
||||||
System.out.println("*****************checkIfQuarantine******************");
|
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
|
||||||
System.out.println(sql.getResultList().size() > 0);
|
sql.setParameter("excludedProducts", excludedProductIds);
|
||||||
System.out.println("******************checkIfQuarantine*****************");
|
}
|
||||||
if (sql.getResultList().size() > 0) {
|
|
||||||
|
if (!sql.getResultList().isEmpty()) {
|
||||||
throw new AxelorException(
|
throw new AxelorException(
|
||||||
stockMove,
|
stockMove,
|
||||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
"Vous avez une ligne en etat qurantaine");
|
"Vous avez une ligne en état quarantaine");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkIfNonConformityTag(StockMove stockMove)
|
public void checkIfNonConformityTag(StockMove stockMove, List<Long> excludedProductIds)
|
||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
|
|
||||||
Query sql =
|
StringBuilder queryBuilder = new StringBuilder();
|
||||||
JPA.em()
|
queryBuilder.append(
|
||||||
.createNativeQuery(
|
"SELECT LINE.ID"
|
||||||
"SELECT LINE.ID" +
|
+ " FROM STOCK_STOCK_MOVE_LINE LINE"
|
||||||
" 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" +
|
+ " LEFT JOIN STOCK_STOCK_LOCATION_LINE LOCATION_LINE ON"
|
||||||
" where LOCATION_LINE.DETAILS_STOCK_LOCATION = :location AND LOCATION_LINE.is_conform_tag is not true AND LINE.STOCK_MOVE = :move");
|
+ " 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("location", stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter("move", stockMove.getId());
|
sql.setParameter("move", stockMove.getId());
|
||||||
|
|
||||||
System.out.println("*****************checkIfNonConformityTag*****************");
|
if (excludedProductIds != null && !excludedProductIds.isEmpty()) {
|
||||||
System.out.println(sql.getResultList().size() > 0);
|
sql.setParameter("excludedProducts", excludedProductIds);
|
||||||
System.out.println("*****************checkIfNonConformityTag****************");
|
}
|
||||||
|
|
||||||
if (sql.getResultList().size() > 0) {
|
if (!sql.getResultList().isEmpty()) {
|
||||||
throw new AxelorException(
|
throw new AxelorException(
|
||||||
stockMove,
|
stockMove,
|
||||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
@@ -1689,9 +1742,72 @@ public class StockMoveServiceImpl implements StockMoveService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public boolean isProductExcluded(StockMove stockMove){
|
// public boolean isExcludedFromWorkflow(StockMove stockMove){
|
||||||
// StockConfig stockConfig =
|
// StockConfig stockConfig =
|
||||||
// Beans.get(StockConfigRepository.class).all().filter("self.company = ?", stockMove.getCompany()).fetchOne();
|
// Beans.get(StockConfigRepository.class).all().filter("self.company = ?",
|
||||||
// stockConfig.getExludedProductsFromWrkFlw();
|
// 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é");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,18 +20,24 @@ package com.axelor.apps.stock.web;
|
|||||||
import com.axelor.apps.base.db.CancelReason;
|
import com.axelor.apps.base.db.CancelReason;
|
||||||
import com.axelor.apps.base.db.PrintingSettings;
|
import com.axelor.apps.base.db.PrintingSettings;
|
||||||
import com.axelor.apps.base.db.Product;
|
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.BarcodeGeneratorService;
|
||||||
import com.axelor.apps.base.service.TradingNameService;
|
import com.axelor.apps.base.service.TradingNameService;
|
||||||
import com.axelor.apps.base.service.app.AppBaseService;
|
import com.axelor.apps.base.service.app.AppBaseService;
|
||||||
import com.axelor.apps.report.engine.ReportSettings;
|
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.StockMove;
|
||||||
import com.axelor.apps.stock.db.StockMoveLine;
|
import com.axelor.apps.stock.db.StockMoveLine;
|
||||||
import com.axelor.apps.stock.db.StockMoveLineLocation;
|
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.StockMoveLineLocationRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
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.exception.IExceptionMessage;
|
||||||
import com.axelor.apps.stock.service.StockMoveService;
|
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.StockMoveToolService;
|
||||||
import com.axelor.apps.stock.service.stockmove.print.ConformityCertificatePrintService;
|
import com.axelor.apps.stock.service.stockmove.print.ConformityCertificatePrintService;
|
||||||
import com.axelor.apps.stock.service.stockmove.print.PickingStockMovePrintService;
|
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");
|
List<Long> requestIds = (List<Long>) request.getContext().get("_ids");
|
||||||
CancelReason raison = (CancelReason) request.getContext().get("cancelRaison");
|
CancelReason raison = (CancelReason) request.getContext().get("cancelRaison");
|
||||||
String raisonStr = (String) request.getContext().get("cancelRaisonStr");
|
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("*********************************************");
|
||||||
System.out.println(raisonStr);
|
System.out.println(raisonStr);
|
||||||
System.out.println(raison);
|
System.out.println(raison);
|
||||||
System.out.println(stockMove.getCancelReason());
|
// System.out.println(stockMove.getCancelReason());
|
||||||
System.out.println(stockMove.getCancelReasonStr());
|
// System.out.println(stockMove.getCancelReasonStr());
|
||||||
System.out.println("*********************************************");
|
System.out.println("*********************************************");
|
||||||
|
|
||||||
if (requestIds == null || requestIds.isEmpty()) {
|
if (requestIds == null || requestIds.isEmpty()) {
|
||||||
@@ -824,9 +829,9 @@ public class StockMoveController {
|
|||||||
Query sql =
|
Query sql =
|
||||||
JPA.em()
|
JPA.em()
|
||||||
.createNativeQuery(
|
.createNativeQuery(
|
||||||
"SELECT LINE.ID"+
|
"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"+
|
+ " 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");
|
+ " 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(1, stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.getId());
|
sql.setParameter(2, stockMove.getId());
|
||||||
logger.debug("sql.getResultList().size()", sql.getResultList().size());
|
logger.debug("sql.getResultList().size()", sql.getResultList().size());
|
||||||
@@ -846,8 +851,8 @@ public class StockMoveController {
|
|||||||
Query sql =
|
Query sql =
|
||||||
JPA.em()
|
JPA.em()
|
||||||
.createNativeQuery(
|
.createNativeQuery(
|
||||||
"SELECT LINE.ID " +
|
"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"
|
+ " 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");
|
+ " 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(1, stockMove.getToStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.getId());
|
sql.setParameter(2, stockMove.getId());
|
||||||
@@ -900,4 +905,38 @@ public class StockMoveController {
|
|||||||
public void showPopup(ActionRequest request, ActionResponse response) {
|
public void showPopup(ActionRequest request, ActionResponse response) {
|
||||||
response.setAlert("Hello words!!");
|
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 ......... ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<entity name="StockLocation" lang="java">
|
<entity name="StockLocation" lang="java">
|
||||||
|
|
||||||
|
<string name="code" title="Code"/>
|
||||||
<string name="name" title="Name" required="true"/>
|
<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="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"/>
|
<many-to-one name="company" ref="com.axelor.apps.base.db.Company" title="Company" required="true"/>
|
||||||
|
|||||||
@@ -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="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>
|
<track>
|
||||||
<field name="conformitySelect"/>
|
<field name="conformitySelect"/>
|
||||||
<field name="isConformTag"/>
|
<field name="isConformTag"/>
|
||||||
|
|||||||
@@ -53,12 +53,21 @@
|
|||||||
|
|
||||||
<string name="name" title="Ref.">
|
<string name="name" title="Ref.">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
if (stockMove != null && stockMove.getStockMoveSeq() != null){
|
if(name == null)
|
||||||
return stockMove.getStockMoveSeq()+ "-" +Integer.toString(sequence);
|
{if (sequence == null) {
|
||||||
|
return "0";
|
||||||
}
|
}
|
||||||
else {
|
if (stockMove == null) {
|
||||||
return Integer.toString(sequence);
|
return Integer.toString(sequence);
|
||||||
}
|
}
|
||||||
|
String stockMoveSeq = stockMove.getStockMoveSeq();
|
||||||
|
if (stockMoveSeq == null) {
|
||||||
|
return Integer.toString(sequence);
|
||||||
|
}
|
||||||
|
return stockMoveSeq + "-" + Integer.toString(sequence);
|
||||||
|
}else{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
]]>
|
]]>
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,36 @@
|
|||||||
package com.axelor.apps.suppliermanagement.db.repo;
|
package com.axelor.apps.suppliermanagement.db.repo;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.BudgetDistribution;
|
||||||
|
import com.axelor.apps.suppliermanagement.db.PurchaseOrderSupplierLine;
|
||||||
|
import com.axelor.apps.supplychain.service.BudgetSupplychainService;
|
||||||
|
import com.axelor.inject.Beans;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.axelor.apps.account.db.BudgetDistribution;
|
public class PurchaseOrderSupplierLineManagementRepository
|
||||||
import com.axelor.apps.suppliermanagement.db.PurchaseOrderSupplierLine;
|
extends PurchaseOrderSupplierLineRepository {
|
||||||
|
|
||||||
public class PurchaseOrderSupplierLineManagementRepository extends PurchaseOrderSupplierLineRepository {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
|
public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
|
||||||
Long supplierLine = (Long) json.get("id");
|
Long supplierLine = (Long) json.get("id");
|
||||||
PurchaseOrderSupplierLine line = find(supplierLine);
|
PurchaseOrderSupplierLine line = find(supplierLine);
|
||||||
List<BudgetDistribution> budgetDistributiList = line.getPurchaseOrderLine().getBudgetDistributionList();
|
List<BudgetDistribution> budgetDistributiList =
|
||||||
|
line.getPurchaseOrderLine().getBudgetDistributionList();
|
||||||
BigDecimal totalBudgetAmountAvailable = BigDecimal.ZERO;
|
BigDecimal totalBudgetAmountAvailable = BigDecimal.ZERO;
|
||||||
|
BigDecimal budgetRemainingAmountAfterValidation = BigDecimal.ZERO;
|
||||||
for (BudgetDistribution budgetDistribution : budgetDistributiList) {
|
for (BudgetDistribution budgetDistribution : budgetDistributiList) {
|
||||||
totalBudgetAmountAvailable = totalBudgetAmountAvailable.add(budgetDistribution.getBudgetAmountAvailable());
|
Beans.get(BudgetSupplychainService.class)
|
||||||
|
.computeBudgetDistributionSumAmount(
|
||||||
|
budgetDistribution, line.getPurchaseOrderLine().getPurchaseOrder().getOrderDate());
|
||||||
|
totalBudgetAmountAvailable =
|
||||||
|
totalBudgetAmountAvailable.add(budgetDistribution.getBudgetAmountAvailable());
|
||||||
}
|
}
|
||||||
|
budgetRemainingAmountAfterValidation =
|
||||||
|
totalBudgetAmountAvailable.subtract(line.getInTaxTotal());
|
||||||
json.put("budgetRemainingAmount", totalBudgetAmountAvailable);
|
json.put("budgetRemainingAmount", totalBudgetAmountAvailable);
|
||||||
|
json.put("budgetRemainingAmountAfterValidation", budgetRemainingAmountAfterValidation);
|
||||||
|
|
||||||
return super.populate(json, context);
|
return super.populate(json, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,16 +99,18 @@ public class PurchaseOrderSupplierLineService {
|
|||||||
purchaseOrderSupplierLine.setAcceptanceDate(appPurchaseService.getTodayDate());
|
purchaseOrderSupplierLine.setAcceptanceDate(appPurchaseService.getTodayDate());
|
||||||
purchaseOrderSupplierLine.setAcceptedByUser(AuthUtils.getUser());
|
purchaseOrderSupplierLine.setAcceptedByUser(AuthUtils.getUser());
|
||||||
|
|
||||||
if(!purchaseOrderLine.getBudgetDistributionList().isEmpty()){
|
poSupplierLineRepo.save(purchaseOrderSupplierLine);
|
||||||
Beans.get(PurchaseOrderLineServiceSupplychainImpl.class)
|
|
||||||
.computeBudgetDistributionSumAmount(purchaseOrderLine, purchaseOrderLine.getPurchaseOrder());
|
// Budget Module
|
||||||
}
|
// if(!purchaseOrderLine.getBudgetDistributionList().isEmpty()){
|
||||||
|
// Beans.get(PurchaseOrderLineServiceSupplychainImpl.class)
|
||||||
|
// .computeBudgetDistributionSumAmount(purchaseOrderLine,purchaseOrderLine.getPurchaseOrder());
|
||||||
|
// }
|
||||||
|
|
||||||
if(!purchaseOrderLine.getAnalyticMoveLineList().isEmpty()){
|
if(!purchaseOrderLine.getAnalyticMoveLineList().isEmpty()){
|
||||||
Beans.get(PurchaseOrderLineServiceSupplychainImpl.class).computeAnalyticDistribution(purchaseOrderLine);
|
Beans.get(PurchaseOrderLineServiceSupplychainImpl.class).computeAnalyticDistribution(purchaseOrderLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
poSupplierLineRepo.save(purchaseOrderSupplierLine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackOn = {Exception.class})
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
|
|||||||
@@ -17,6 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.suppliermanagement.service;
|
package com.axelor.apps.suppliermanagement.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
|
import com.axelor.apps.account.db.Budget;
|
||||||
|
import com.axelor.apps.account.db.BudgetDistribution;
|
||||||
|
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
|
||||||
|
import com.axelor.apps.account.db.repo.BudgetDistributionRepository;
|
||||||
import com.axelor.apps.base.db.Blocking;
|
import com.axelor.apps.base.db.Blocking;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
import com.axelor.apps.base.db.Partner;
|
import com.axelor.apps.base.db.Partner;
|
||||||
@@ -33,7 +38,6 @@ import com.axelor.apps.purchase.db.SupplierCatalog;
|
|||||||
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
|
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
|
||||||
import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository;
|
import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository;
|
||||||
import com.axelor.apps.purchase.db.repo.PurchaseRequestRepository;
|
import com.axelor.apps.purchase.db.repo.PurchaseRequestRepository;
|
||||||
import com.axelor.apps.purchase.service.PurchaseOrderLineService;
|
|
||||||
import com.axelor.apps.purchase.service.app.AppPurchaseService;
|
import com.axelor.apps.purchase.service.app.AppPurchaseService;
|
||||||
import com.axelor.apps.stock.service.StockLocationService;
|
import com.axelor.apps.stock.service.StockLocationService;
|
||||||
import com.axelor.apps.suppliermanagement.db.PurchaseOrderSupplierLine;
|
import com.axelor.apps.suppliermanagement.db.PurchaseOrderSupplierLine;
|
||||||
@@ -231,9 +235,9 @@ public class PurchaseOrderSupplierService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// PurchaseOrderNew.setStatusSelect(0);//Approuve
|
// PurchaseOrderNew.setStatusSelect(0);//Approuve
|
||||||
createPurchaseOrderSupplierLineTCO(
|
// createPurchaseOrderSupplierLineTCO(
|
||||||
PurchaseOrderNew.getPurchaseOrderLineList(),
|
// PurchaseOrderNew.getPurchaseOrderLineList(),
|
||||||
purchaseOrderLinesBySupplierPartner.get(supplierPartner));
|
// purchaseOrderLinesBySupplierPartner.get(supplierPartner));
|
||||||
}
|
}
|
||||||
|
|
||||||
purchaseRequest.setPurchaseOrderSet(hash_Set);
|
purchaseRequest.setPurchaseOrderSet(hash_Set);
|
||||||
@@ -323,7 +327,8 @@ public class PurchaseOrderSupplierService {
|
|||||||
"Création d'une ligne de commande fournisseur pour le produit : {}",
|
"Création d'une ligne de commande fournisseur pour le produit : {}",
|
||||||
new Object[] {purchaseOrderLine.getProductName()});
|
new Object[] {purchaseOrderLine.getProductName()});
|
||||||
|
|
||||||
return purchaseOrderLineServiceSupplychainImpl.createPurchaseOrderLineFromSplit(purchaseOrderLine);
|
return purchaseOrderLineServiceSupplychainImpl.createPurchaseOrderLineFromSplit(
|
||||||
|
purchaseOrderLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackOn = {Exception.class})
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
@@ -392,8 +397,23 @@ public class PurchaseOrderSupplierService {
|
|||||||
"SOPHAL Création d'une ligne de commande fournisseur pour le produit : {}",
|
"SOPHAL Création d'une ligne de commande fournisseur pour le produit : {}",
|
||||||
new Object[] {purchaseOrderLine.getProductName()});
|
new Object[] {purchaseOrderLine.getProductName()});
|
||||||
|
|
||||||
PurchaseOrderLine PurchaseOrderLineNew =
|
PurchaseOrderLine PurchaseOrderLineNew = purchaseOrderLineServiceSupplychainImpl.createPurchaseOrderLineFromSplit(purchaseOrderLine);
|
||||||
purchaseOrderLineServiceSupplychainImpl.createPurchaseOrderLineFromSplit(purchaseOrderLine);
|
|
||||||
|
// List<AnalyticMoveLine> analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
||||||
|
// List<BudgetDistribution> budgetDistributions = purchaseOrderLine.getBudgetDistributionList();
|
||||||
|
|
||||||
|
// if (analyticMoveLines.size() != 0) {
|
||||||
|
// for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
|
// AnalyticMoveLine analyticMoveLineCopy = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
||||||
|
// PurchaseOrderLineNew.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (budgetDistributions.size() != 0) {
|
||||||
|
// for (BudgetDistribution budgetDistribution : budgetDistributions) {
|
||||||
|
// BudgetDistribution budgetDistributionCopy = Beans.get(BudgetDistributionRepository.class).copy(budgetDistribution, false);
|
||||||
|
// PurchaseOrderLineNew.addBudgetDistributionListItem(budgetDistributionCopy);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
PurchaseOrderLineNew.setPrice(purchaseOrderLine.getPrice());
|
PurchaseOrderLineNew.setPrice(purchaseOrderLine.getPrice());
|
||||||
PurchaseOrderLineNew.setInTaxPrice(purchaseOrderLine.getInTaxPrice());
|
PurchaseOrderLineNew.setInTaxPrice(purchaseOrderLine.getInTaxPrice());
|
||||||
@@ -424,27 +444,29 @@ public class PurchaseOrderSupplierService {
|
|||||||
.fetch();
|
.fetch();
|
||||||
|
|
||||||
for (PurchaseOrderSupplierLine poLineSupplierParnet : PurchaseOrderSupplierLineParnetList) {
|
for (PurchaseOrderSupplierLine poLineSupplierParnet : PurchaseOrderSupplierLineParnetList) {
|
||||||
|
PurchaseOrderSupplierLine po =
|
||||||
|
Beans.get(PurchaseOrderSupplierLineRepository.class).copy(poLineSupplierParnet, false);
|
||||||
|
|
||||||
PurchaseOrderSupplierLine po = new PurchaseOrderSupplierLine();
|
// PurchaseOrderSupplierLine po = new PurchaseOrderSupplierLine();
|
||||||
po.setPrice(poLineSupplierParnet.getPrice());
|
// po.setPrice(poLineSupplierParnet.getPrice());
|
||||||
po.setExTaxTotal(poLineSupplierParnet.getExTaxTotal());
|
// po.setExTaxTotal(poLineSupplierParnet.getExTaxTotal());
|
||||||
po.setInTaxTotal(poLineSupplierParnet.getInTaxTotal());
|
// po.setInTaxTotal(poLineSupplierParnet.getInTaxTotal());
|
||||||
po.setTaxTotal(poLineSupplierParnet.getTaxTotal());
|
// po.setTaxTotal(poLineSupplierParnet.getTaxTotal());
|
||||||
po.setAvailableQty(poLineSupplierParnet.getAvailableQty());
|
// po.setAvailableQty(poLineSupplierParnet.getAvailableQty());
|
||||||
po.setPurchaseOrderLine(purchaseOrderLineNew.get(index));
|
po.setPurchaseOrderLine(purchaseOrderLineNew.get(index));
|
||||||
po.setStateSelect(poLineSupplierParnet.getStateSelect());
|
// po.setStateSelect(poLineSupplierParnet.getStateSelect());
|
||||||
po.setTaxLine(poLineSupplierParnet.getTaxLine());
|
// po.setTaxLine(poLineSupplierParnet.getTaxLine());
|
||||||
po.setSupplierPartner(poLineSupplierParnet.getSupplierPartner());
|
// po.setSupplierPartner(poLineSupplierParnet.getSupplierPartner());
|
||||||
po.setComments(poLineSupplierParnet.getComments());
|
// po.setComments(poLineSupplierParnet.getComments());
|
||||||
po.setArchived(poLineSupplierParnet.getArchived());
|
// po.setArchived(poLineSupplierParnet.getArchived());
|
||||||
po.setEstimatedDelivDate(poLineSupplierParnet.getEstimatedDelivDate());
|
// po.setEstimatedDelivDate(poLineSupplierParnet.getEstimatedDelivDate());
|
||||||
po.setAcceptanceDate(poLineSupplierParnet.getAcceptanceDate());
|
// po.setAcceptanceDate(poLineSupplierParnet.getAcceptanceDate());
|
||||||
po.setAcceptedByUser(poLineSupplierParnet.getAcceptedByUser());
|
// po.setAcceptedByUser(poLineSupplierParnet.getAcceptedByUser());
|
||||||
po.setRefusalDate(poLineSupplierParnet.getRefusalDate());
|
// po.setRefusalDate(poLineSupplierParnet.getRefusalDate());
|
||||||
po.setRefusedByUser(poLineSupplierParnet.getRefusedByUser());
|
// po.setRefusedByUser(poLineSupplierParnet.getRefusedByUser());
|
||||||
po.setAttrs(poLineSupplierParnet.getAttrs());
|
// po.setAttrs(poLineSupplierParnet.getAttrs());
|
||||||
po.setCurrency(poLineSupplierParnet.getCurrency());
|
// po.setCurrency(poLineSupplierParnet.getCurrency());
|
||||||
po.setPriceDiscounted(poLineSupplierParnet.getPriceDiscounted());
|
// po.setPriceDiscounted(poLineSupplierParnet.getPriceDiscounted());
|
||||||
// LOG.debug("purchaseOrderLineNew.getId(): {}",purchaseOrderLineNew.get(index).getId());
|
// LOG.debug("purchaseOrderLineNew.getId(): {}",purchaseOrderLineNew.get(index).getId());
|
||||||
Beans.get(PurchaseOrderSupplierLineRepository.class).save(po);
|
Beans.get(PurchaseOrderSupplierLineRepository.class).save(po);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,9 +95,8 @@ public class PurchaseOrderController {
|
|||||||
PurchaseOrderLineRepository purchaseOrderLineRepo =
|
PurchaseOrderLineRepository purchaseOrderLineRepo =
|
||||||
Beans.get(PurchaseOrderLineRepository.class);
|
Beans.get(PurchaseOrderLineRepository.class);
|
||||||
for (HashMap map : selectedPurchaseOrderLineMapList) {
|
for (HashMap map : selectedPurchaseOrderLineMapList) {
|
||||||
PurchaseOrderLine purchaseOrderLine =
|
PurchaseOrderLine poline = (PurchaseOrderLine) Mapper.toBean(PurchaseOrderLine.class, map);
|
||||||
(PurchaseOrderLine) Mapper.toBean(PurchaseOrderLine.class, map);
|
purchaseOrderLineList.add(purchaseOrderLineRepo.find(poline.getId()));
|
||||||
purchaseOrderLineList.add(purchaseOrderLineRepo.find(purchaseOrderLine.getId()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (purchaseOrderLineList.isEmpty()) {
|
if (purchaseOrderLineList.isEmpty()) {
|
||||||
@@ -121,6 +120,7 @@ public class PurchaseOrderController {
|
|||||||
Beans.get(PurchaseOrderSupplierLineService.class)
|
Beans.get(PurchaseOrderSupplierLineService.class)
|
||||||
.setPurchaseOrderLinesPartner(purchaseOrderLineList, partner);
|
.setPurchaseOrderLinesPartner(purchaseOrderLineList, partner);
|
||||||
response.setCanClose(true);
|
response.setCanClose(true);
|
||||||
|
response.setAlert(String.format(I18n.get("Purchase order lines set successfully to partner %s"),partner.getName()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TraceBackService.trace(response, e);
|
TraceBackService.trace(response, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.axelor.apps.suppliermanagement.db.repo.PurchaseOrderSupplierLineRepos
|
|||||||
import com.axelor.apps.suppliermanagement.service.PurchaseOrderSupplierLineService;
|
import com.axelor.apps.suppliermanagement.service.PurchaseOrderSupplierLineService;
|
||||||
import com.axelor.apps.supplychain.service.PurchaseOrderServiceSupplychainImpl;
|
import com.axelor.apps.supplychain.service.PurchaseOrderServiceSupplychainImpl;
|
||||||
import com.axelor.exception.service.TraceBackService;
|
import com.axelor.exception.service.TraceBackService;
|
||||||
|
import com.axelor.i18n.I18n;
|
||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
import com.axelor.meta.schema.actions.ActionView;
|
import com.axelor.meta.schema.actions.ActionView;
|
||||||
import com.axelor.rpc.ActionRequest;
|
import com.axelor.rpc.ActionRequest;
|
||||||
@@ -66,6 +67,17 @@ public class PurchaseOrderSupplierLineController {
|
|||||||
|
|
||||||
public void accept(ActionRequest request, ActionResponse response) {
|
public void accept(ActionRequest request, ActionResponse response) {
|
||||||
|
|
||||||
|
// check if budgetRemainingAmountAfterValidation is less than zero then throw error
|
||||||
|
if (request.getContext().get("budgetRemainingAmountAfterValidation") != null) {
|
||||||
|
BigDecimal budgetRemainingAmountAfterValidation =
|
||||||
|
new BigDecimal(
|
||||||
|
String.valueOf(request.getContext().get("budgetRemainingAmountAfterValidation")));
|
||||||
|
if (budgetRemainingAmountAfterValidation.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
response.setNotify(I18n.get(
|
||||||
|
"The budget remaining amount after validation is less than zero. Cannot accept the supplier line."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PurchaseOrderSupplierLine purchaseOrderSupplierLine =
|
PurchaseOrderSupplierLine purchaseOrderSupplierLine =
|
||||||
Beans.get(PurchaseOrderSupplierLineRepository.class)
|
Beans.get(PurchaseOrderSupplierLineRepository.class)
|
||||||
.find(request.getContext().asType(PurchaseOrderSupplierLine.class).getId());
|
.find(request.getContext().asType(PurchaseOrderSupplierLine.class).getId());
|
||||||
@@ -289,12 +301,13 @@ public class PurchaseOrderSupplierLineController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void computeBudgetDistribution(ActionRequest request, ActionResponse response) {
|
public void computeBudgetDistribution(ActionRequest request, ActionResponse response) {
|
||||||
|
|
||||||
PurchaseOrderSupplierLine purchaseOrderSupplierLine = Beans.get(PurchaseOrderSupplierLineRepository.class)
|
PurchaseOrderSupplierLine purchaseOrderSupplierLine =
|
||||||
|
Beans.get(PurchaseOrderSupplierLineRepository.class)
|
||||||
.find(request.getContext().asType(PurchaseOrderSupplierLine.class).getId());
|
.find(request.getContext().asType(PurchaseOrderSupplierLine.class).getId());
|
||||||
Beans.get(PurchaseOrderServiceSupplychainImpl.class).computeBudgetDistribution(purchaseOrderSupplierLine.getPurchaseOrderLine());
|
Beans.get(PurchaseOrderServiceSupplychainImpl.class)
|
||||||
|
.computeBudgetDistribution(purchaseOrderSupplierLine.getPurchaseOrderLine());
|
||||||
response.setReload(true);
|
response.setReload(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,6 @@ dependencies {
|
|||||||
compile project(":modules:axelor-sale")
|
compile project(":modules:axelor-sale")
|
||||||
compile project(":modules:axelor-stock")
|
compile project(":modules:axelor-stock")
|
||||||
compile project(":modules:axelor-account")
|
compile project(":modules:axelor-account")
|
||||||
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
testImplementation 'org.mockito:mockito-core:4.8.0'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import com.axelor.db.JPA;
|
|||||||
import com.axelor.db.Query;
|
import com.axelor.db.Query;
|
||||||
import com.axelor.exception.AxelorException;
|
import com.axelor.exception.AxelorException;
|
||||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||||
|
import com.axelor.exception.service.TraceBackService;
|
||||||
import com.axelor.i18n.I18n;
|
import com.axelor.i18n.I18n;
|
||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -773,19 +774,39 @@ public class AccountingCutOffServiceImpl implements AccountingCutOffService {
|
|||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> massGenerationMove(List<Long> ids) throws AxelorException {
|
public Map<String, List<Long>> massGenerationMove(List<Long> ids) {
|
||||||
|
|
||||||
List<Long> movesId = new ArrayList<>();
|
List<Long> successMoves = new ArrayList<>();
|
||||||
|
List<Long> failedStockMoves = new ArrayList<>();
|
||||||
|
|
||||||
for (Long id : ids) {
|
for (Long id : ids) {
|
||||||
|
try {
|
||||||
StockMove stockMove = Beans.get(StockMoveRepository.class).find(id);
|
StockMove stockMove = Beans.get(StockMoveRepository.class).find(id);
|
||||||
|
|
||||||
Move move = this.generateStockAccountMove(stockMove);
|
Move move = this.generateStockAccountMove(stockMove);
|
||||||
movesId.add(move.getId());
|
successMoves.add(move.getId());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
// Log technical error
|
||||||
|
TraceBackService.trace(e);
|
||||||
|
|
||||||
|
// Mark stock move as failed
|
||||||
|
failedStockMoves.add(id);
|
||||||
|
|
||||||
|
// IMPORTANT: continue loop
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
;
|
|
||||||
return movesId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, List<Long>> result = new HashMap<>();
|
||||||
|
result.put("success", successMoves);
|
||||||
|
result.put("failed", failedStockMoves);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isDebit(StockMove stockMove) throws AxelorException {
|
public boolean isDebit(StockMove stockMove) throws AxelorException {
|
||||||
boolean isDebit;
|
boolean isDebit;
|
||||||
// stockMove.getToStockLocation().getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL
|
// stockMove.getToStockLocation().getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
public class AnalyticMoveLineServiceImpl {
|
||||||
|
public BigDecimal computeAmount(AnalyticMoveLine analyticMoveLine) {
|
||||||
|
|
||||||
|
return analyticMoveLine
|
||||||
|
.getPercentage()
|
||||||
|
.multiply(analyticMoveLine.getPurchaseOrderLine().getExTaxTotal())
|
||||||
|
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,14 +60,29 @@ public class BudgetSupplychainService extends BudgetService {
|
|||||||
Beans.get(BudgetDistributionRepository.class)
|
Beans.get(BudgetDistributionRepository.class)
|
||||||
.all()
|
.all()
|
||||||
.filter(
|
.filter(
|
||||||
"self.budget.id = ?1 AND self.purchaseOrderLine.purchaseOrder.statusSelect in (?2,?3)",
|
"self.budget.id = ?1 AND (self.purchaseOrderLine.purchaseOrder.statusSelect in (?2,?3) OR self.saleOrderLine.saleOrder.statusSelect in (?2,?3) )",
|
||||||
budget.getId(),
|
budget.getId(),
|
||||||
PurchaseOrderRepository.STATUS_VALIDATED,
|
PurchaseOrderRepository.STATUS_VALIDATED,
|
||||||
PurchaseOrderRepository.STATUS_FINISHED)
|
PurchaseOrderRepository.STATUS_FINISHED)
|
||||||
.fetch();
|
.fetch();
|
||||||
|
System.out.println("*********************************");
|
||||||
|
System.out.println(budgetDistributionList);
|
||||||
|
System.out.println("*********************************");
|
||||||
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
|
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
|
||||||
LocalDate orderDate =
|
LocalDate orderDate = LocalDate.now();
|
||||||
budgetDistribution.getPurchaseOrderLine().getPurchaseOrder().getOrderDate();
|
if (budgetDistribution.getSaleOrderLine() != null)
|
||||||
|
orderDate =
|
||||||
|
budgetDistribution
|
||||||
|
.getSaleOrderLine()
|
||||||
|
.getSaleOrder()
|
||||||
|
.getConfirmationDateTime()
|
||||||
|
.toLocalDate();
|
||||||
|
else
|
||||||
|
orderDate = budgetDistribution.getPurchaseOrderLine().getPurchaseOrder().getOrderDate();
|
||||||
|
System.out.println("*********************************");
|
||||||
|
System.out.println(orderDate);
|
||||||
|
System.out.println(orderDate);
|
||||||
|
System.out.println("*********************************");
|
||||||
if (orderDate != null) {
|
if (orderDate != null) {
|
||||||
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
|
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
|
||||||
LocalDate fromDate = budgetLine.getFromDate();
|
LocalDate fromDate = budgetLine.getFromDate();
|
||||||
@@ -132,6 +147,9 @@ public class BudgetSupplychainService extends BudgetService {
|
|||||||
budgetAmountAvailable = budgetAmountAvailable.add(amount);
|
budgetAmountAvailable = budgetAmountAvailable.add(amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
System.out.println("$$$$$$$$$$$$$$$$$$$$$$$budgetAmountAvailable$$$$$$$$$$$$$$$$$$$$$$$$$$$");
|
||||||
|
System.out.println(budgetAmountAvailable);
|
||||||
|
System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$budgetAmountAvailable$$$$$$$$$$$$$$$$$$$$$$$$$$");
|
||||||
budgetDistribution.setBudgetAmountAvailable(budgetAmountAvailable);
|
budgetDistribution.setBudgetAmountAvailable(budgetAmountAvailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,27 +336,36 @@ public class ImportationFolderServiceImpl {
|
|||||||
stockMovesMap
|
stockMovesMap
|
||||||
.values()
|
.values()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(t ->
|
.filter(
|
||||||
|
t ->
|
||||||
t.get(0)
|
t.get(0)
|
||||||
.getStockMoveLineList()
|
.getStockMoveLineList()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(line -> line.getRealQty() != null && line.getRealQty().compareTo(BigDecimal.ZERO) > 0)
|
.filter(
|
||||||
|
line ->
|
||||||
|
line.getRealQty() != null
|
||||||
|
&& line.getRealQty().compareTo(BigDecimal.ZERO) > 0)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.isPresent())
|
.isPresent())
|
||||||
.mapToDouble(t ->
|
.mapToDouble(
|
||||||
|
t ->
|
||||||
t.get(0)
|
t.get(0)
|
||||||
.getStockMoveLineList()
|
.getStockMoveLineList()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(line -> line.getRealQty() != null && line.getRealQty().compareTo(BigDecimal.ZERO) > 0)
|
.filter(
|
||||||
|
line ->
|
||||||
|
line.getRealQty() != null
|
||||||
|
&& line.getRealQty().compareTo(BigDecimal.ZERO) > 0)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(line -> line.getFreight()
|
.map(
|
||||||
|
line ->
|
||||||
|
line.getFreight()
|
||||||
.multiply(stockMoveLines.get(0).getCurrencyRate())
|
.multiply(stockMoveLines.get(0).getCurrencyRate())
|
||||||
.setScale(2, RoundingMode.HALF_EVEN)
|
.setScale(2, RoundingMode.HALF_EVEN)
|
||||||
.doubleValue())
|
.doubleValue())
|
||||||
.orElse(0.0)) // In case no valid line found, fallback to 0.0
|
.orElse(0.0)) // In case no valid line found, fallback to 0.0
|
||||||
.sum());
|
.sum());
|
||||||
|
|
||||||
|
|
||||||
System.out.println("*****************freight**************************************");
|
System.out.println("*****************freight**************************************");
|
||||||
System.out.println(freight);
|
System.out.println(freight);
|
||||||
System.out.println("*******************************************************");
|
System.out.println("*******************************************************");
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.supplychain.service;
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.AccountManagement;
|
||||||
import com.axelor.apps.account.db.AnalyticAccount;
|
import com.axelor.apps.account.db.AnalyticAccount;
|
||||||
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
|
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
|
||||||
import com.axelor.apps.account.db.AnalyticMoveLine;
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
@@ -43,6 +44,7 @@ import com.axelor.exception.db.repo.TraceBackRepository;
|
|||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
@@ -111,6 +113,7 @@ public class PurchaseOrderLineServiceSupplychainImpl extends PurchaseOrderLineSe
|
|||||||
return purchaseOrderLine;
|
return purchaseOrderLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public PurchaseOrderLine createPurchaseOrderLine(
|
public PurchaseOrderLine createPurchaseOrderLine(
|
||||||
PurchaseOrder purchaseOrder,
|
PurchaseOrder purchaseOrder,
|
||||||
@@ -123,37 +126,69 @@ public class PurchaseOrderLineServiceSupplychainImpl extends PurchaseOrderLineSe
|
|||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
|
|
||||||
PurchaseOrderLine purchaseOrderLine =
|
PurchaseOrderLine purchaseOrderLine =
|
||||||
super.createPurchaseOrderLine(purchaseOrder, product, productName, description, qty, unit,purchaseRequestLine);
|
super.createPurchaseOrderLine(
|
||||||
|
purchaseOrder, product, productName, description, qty, unit, purchaseRequestLine);
|
||||||
|
|
||||||
List<AnalyticMoveLine> analyticMoveLines = purchaseRequestLine.getAnalyticMoveLineList();
|
List<AnalyticMoveLine> analyticMoveLines = purchaseRequestLine.getAnalyticMoveLineList();
|
||||||
|
List<AccountManagement> accountManagementList =
|
||||||
|
purchaseRequestLine.getProduct().getAccountManagementList();
|
||||||
|
if (accountManagementList == null || accountManagementList.size() == 0) {
|
||||||
|
throw new AxelorException(
|
||||||
|
purchaseRequestLine.getPurchaseRequest(),
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"Vous avez une lignes expression des besoins sans Compte d'achat défini sur le produit");
|
||||||
|
|
||||||
// if(analyticMoveLines.size() == 0){
|
} else if (accountManagementList.get(0).getPurchaseAccount() == null) {
|
||||||
// throw new AxelorException(
|
throw new AxelorException(
|
||||||
// purchaseRequestLine.getPurchaseRequest(),
|
purchaseRequestLine.getPurchaseRequest(),
|
||||||
// TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
// "Vous avez une lignes expression des besoins sans Compte analytique");
|
"Vous avez une lignes expression des besoins sans Compte d'achat défini sur le produit");
|
||||||
// }
|
}
|
||||||
|
String accountCode =
|
||||||
|
accountManagementList.get(0).getPurchaseAccount().getCode().substring(0, 2);
|
||||||
|
|
||||||
|
if(analyticMoveLines.size() == 0){
|
||||||
|
throw new AxelorException(
|
||||||
|
purchaseRequestLine.getPurchaseRequest(),
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"Vous avez une lignes expression des besoins sans Compte analytique");
|
||||||
|
}
|
||||||
|
|
||||||
if (analyticMoveLines.size() != 0) {
|
if (analyticMoveLines.size() != 0) {
|
||||||
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
AnalyticMoveLine analyticMoveLineCopy = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
AnalyticMoveLine analyticMoveLineCopy = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
||||||
System.out.println("**************************************************");
|
purchaseOrderLine.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
||||||
|
this.computeBudgetDistributionSumAmount(purchaseOrderLine, purchaseOrder);
|
||||||
|
|
||||||
|
System.out.println("*********************createPurchaseOrderLine*****************************");
|
||||||
System.out.println(analyticMoveLine.getAnalyticAccount());
|
System.out.println(analyticMoveLine.getAnalyticAccount());
|
||||||
System.out.println(analyticMoveLine.getAnalyticAccount().getParent());
|
System.out.println(analyticMoveLine.getAnalyticAccount().getParent());
|
||||||
// Budget budget = Beans.get(BudgetRepository.class).findByAnalyticAccount(analyticMoveLine.getAnalyticAccount());
|
|
||||||
Budget budget = findBudgetRecursive(analyticMoveLine.getAnalyticAccount());
|
Budget budget = findBudgetRecursive(analyticMoveLine.getAnalyticAccount(), accountCode);
|
||||||
System.out.println(budget);
|
System.out.println(budget);
|
||||||
System.out.println("**************************************************");
|
System.out.println(analyticMoveLineCopy);
|
||||||
|
System.out.println("***************************createPurchaseOrderLine***********************");
|
||||||
if (budget != null) {
|
if (budget != null) {
|
||||||
BudgetDistribution newBudgetDistribution = new BudgetDistribution();
|
BudgetDistribution newBudgetDistribution = new BudgetDistribution();
|
||||||
newBudgetDistribution.setAmount(purchaseOrderLine.getCompanyExTaxTotal().multiply(analyticMoveLine.getPercentage()).divide(new BigDecimal("100")).setScale(2, RoundingMode.HALF_EVEN));
|
newBudgetDistribution.setAmount(BigDecimal.ZERO);
|
||||||
newBudgetDistribution.setBudget(budget);
|
newBudgetDistribution.setBudget(budget);
|
||||||
newBudgetDistribution.setPurchaseOrderLine(purchaseOrderLine);
|
newBudgetDistribution.setPurchaseOrderLine(purchaseOrderLine);
|
||||||
newBudgetDistribution.setAnalyticMoveLine(analyticMoveLineCopy);
|
newBudgetDistribution.setAnalyticMoveLine(analyticMoveLineCopy);
|
||||||
|
Beans.get(BudgetSupplychainService.class)
|
||||||
|
.computeBudgetDistributionSumAmount(newBudgetDistribution, purchaseOrder.getOrderDate());
|
||||||
|
|
||||||
Beans.get(BudgetDistributionRepository.class).save(newBudgetDistribution);
|
Beans.get(BudgetDistributionRepository.class).save(newBudgetDistribution);
|
||||||
Beans.get(PurchaseOrderLineServiceSupplychainImpl.class).computeBudgetDistributionSumAmount(purchaseOrderLine, purchaseOrder);
|
purchaseOrderLine.addBudgetDistributionListItem(newBudgetDistribution);
|
||||||
|
}else{
|
||||||
|
// throw new AxelorException(
|
||||||
|
// purchaseRequestLine.getPurchaseRequest(),
|
||||||
|
// TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
// "Vous n'avez pas de budget défini pour le compte analytique : "
|
||||||
|
// + analyticMoveLine.getAnalyticAccount().getCode()
|
||||||
|
// + " et le compte comptable : "
|
||||||
|
// + accountCode);
|
||||||
}
|
}
|
||||||
purchaseOrderLine.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,11 +199,11 @@ public class PurchaseOrderLineServiceSupplychainImpl extends PurchaseOrderLineSe
|
|||||||
return purchaseOrderLine;
|
return purchaseOrderLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PurchaseOrderLine createPurchaseOrderLineFromSplit(
|
public PurchaseOrderLine createPurchaseOrderLineFromSplit(PurchaseOrderLine purchaseOrderLine)
|
||||||
PurchaseOrderLine purchaseOrderLine)
|
|
||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
|
|
||||||
PurchaseOrderLine purchaseOrderLineNew = Beans.get(PurchaseOrderLineRepository.class).copy(purchaseOrderLine, true);
|
PurchaseOrderLine purchaseOrderLineNew =
|
||||||
|
Beans.get(PurchaseOrderLineRepository.class).copy(purchaseOrderLine, true);
|
||||||
|
|
||||||
List<AnalyticMoveLine> analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
List<AnalyticMoveLine> analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
||||||
|
|
||||||
@@ -180,7 +215,8 @@ public class PurchaseOrderLineServiceSupplychainImpl extends PurchaseOrderLineSe
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
// for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
// AnalyticMoveLine analyticMoveLineCopy = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
// AnalyticMoveLine analyticMoveLineCopy =
|
||||||
|
// Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
||||||
// purchaseOrderLineNew.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
// purchaseOrderLineNew.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -259,6 +295,7 @@ public class PurchaseOrderLineServiceSupplychainImpl extends PurchaseOrderLineSe
|
|||||||
return BigDecimal.ZERO;
|
return BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void computeBudgetDistributionSumAmount(
|
public void computeBudgetDistributionSumAmount(
|
||||||
PurchaseOrderLine purchaseOrderLine, PurchaseOrder purchaseOrder) {
|
PurchaseOrderLine purchaseOrderLine, PurchaseOrder purchaseOrder) {
|
||||||
List<BudgetDistribution> budgetDistributionList = purchaseOrderLine.getBudgetDistributionList();
|
List<BudgetDistribution> budgetDistributionList = purchaseOrderLine.getBudgetDistributionList();
|
||||||
@@ -268,32 +305,29 @@ public class PurchaseOrderLineServiceSupplychainImpl extends PurchaseOrderLineSe
|
|||||||
if (budgetDistributionList != null && !budgetDistributionList.isEmpty()) {
|
if (budgetDistributionList != null && !budgetDistributionList.isEmpty()) {
|
||||||
|
|
||||||
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
|
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
|
||||||
budgetDistributionSumAmount =
|
System.out.println("???????????????????????????????? budgetDistribution");
|
||||||
budgetDistributionSumAmount.add(budgetDistribution.getAmount());
|
System.out.println(budgetDistribution);
|
||||||
|
System.out.println("???????????????????????????????? budgetDistribution");
|
||||||
|
budgetDistribution.setAmount(purchaseOrderLine.getExTaxTotal().multiply(budgetDistribution.getAnalyticMoveLine().getPercentage().divide(new BigDecimal("100"))).setScale(2, RoundingMode.HALF_EVEN));
|
||||||
|
budgetDistributionSumAmount = budgetDistributionSumAmount.add(budgetDistribution.getAmount());
|
||||||
Beans.get(BudgetSupplychainService.class)
|
Beans.get(BudgetSupplychainService.class)
|
||||||
.computeBudgetDistributionSumAmount(budgetDistribution, computeDate);
|
.computeBudgetDistributionSumAmount(budgetDistribution, computeDate);
|
||||||
|
Beans.get(BudgetDistributionRepository.class).save(budgetDistribution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
purchaseOrderLine.setBudgetDistributionSumAmount(budgetDistributionSumAmount);
|
purchaseOrderLine.setBudgetDistributionSumAmount(budgetDistributionSumAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Budget findBudgetRecursive(AnalyticAccount account, String accountCode) {
|
||||||
private Budget findBudgetRecursive(AnalyticAccount account) {
|
|
||||||
while (account != null) {
|
while (account != null) {
|
||||||
System.out.println("???????????????????????????????? while loop");
|
Budget budget =
|
||||||
Budget budget = Beans.get(BudgetRepository.class)
|
Beans.get(BudgetRepository.class)
|
||||||
.findByAnalyticAccount(account);
|
.findByAnalyticAccountAndAccountCode(account, accountCode,true);
|
||||||
if (budget != null) {
|
if (budget != null) {
|
||||||
System.out.println("???????????????????????????????? while loop inside if");
|
|
||||||
System.out.println(account);
|
|
||||||
System.out.println(budget);
|
|
||||||
|
|
||||||
return budget; // found budget, stop here
|
return budget; // found budget, stop here
|
||||||
}
|
}
|
||||||
account = account.getParent(); // go up one level
|
account = account.getParent(); // go up one level
|
||||||
}
|
}
|
||||||
return null; // no budget found in hierarchy
|
return null; // no budget found in hierarchy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.supplychain.service;
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.AccountManagement;
|
||||||
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
import com.axelor.apps.account.db.Budget;
|
import com.axelor.apps.account.db.Budget;
|
||||||
import com.axelor.apps.account.db.BudgetDistribution;
|
import com.axelor.apps.account.db.BudgetDistribution;
|
||||||
import com.axelor.apps.account.db.BudgetLine;
|
import com.axelor.apps.account.db.BudgetLine;
|
||||||
@@ -58,6 +60,7 @@ import com.google.inject.persist.Transactional;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -120,8 +123,8 @@ public class PurchaseOrderServiceSupplychainImpl extends PurchaseOrderServiceImp
|
|||||||
externalReference,
|
externalReference,
|
||||||
supplierPartner.getFullName());
|
supplierPartner.getFullName());
|
||||||
|
|
||||||
|
System.out.println(
|
||||||
System.out.println("Création d'une commande fournisseur : Société = {}, Reference externe = {}, Fournisseur = {}");
|
"Création d'une commande fournisseur : Société = {}, Reference externe = {}, Fournisseur = {}");
|
||||||
|
|
||||||
PurchaseOrder purchaseOrder =
|
PurchaseOrder purchaseOrder =
|
||||||
super.createPurchaseOrder(
|
super.createPurchaseOrder(
|
||||||
@@ -437,7 +440,8 @@ public class PurchaseOrderServiceSupplychainImpl extends PurchaseOrderServiceImp
|
|||||||
public void finishSockMoves(
|
public void finishSockMoves(
|
||||||
PurchaseOrder purchaseOrder, CancelReason raison, String cancelReasonStr)
|
PurchaseOrder purchaseOrder, CancelReason raison, String cancelReasonStr)
|
||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
Beans.get(PurchaseOrderStockServiceImpl.class).cancelReceiptWithRaison(purchaseOrder, raison, cancelReasonStr);
|
Beans.get(PurchaseOrderStockServiceImpl.class)
|
||||||
|
.cancelReceiptWithRaison(purchaseOrder, raison, cancelReasonStr);
|
||||||
this.finishPurchaseOrder(purchaseOrder, cancelReasonStr);
|
this.finishPurchaseOrder(purchaseOrder, cancelReasonStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,9 +450,75 @@ public class PurchaseOrderServiceSupplychainImpl extends PurchaseOrderServiceImp
|
|||||||
List<BudgetDistribution> budgetDistributionList = purchaseOrderLine.getBudgetDistributionList();
|
List<BudgetDistribution> budgetDistributionList = purchaseOrderLine.getBudgetDistributionList();
|
||||||
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
|
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
|
||||||
BigDecimal percent = budgetDistribution.getAnalyticMoveLine().getPercentage();
|
BigDecimal percent = budgetDistribution.getAnalyticMoveLine().getPercentage();
|
||||||
budgetDistribution.setAmount(purchaseOrderLine.getCompanyExTaxTotal().multiply(percent).setScale(2).divide(new BigDecimal("100")));
|
budgetDistribution.setAmount(
|
||||||
|
purchaseOrderLine
|
||||||
|
.getCompanyExTaxTotal()
|
||||||
|
.multiply(percent)
|
||||||
|
.setScale(2)
|
||||||
|
.divide(new BigDecimal("100")));
|
||||||
Beans.get(BudgetDistributionRepository.class).save(budgetDistribution);
|
Beans.get(BudgetDistributionRepository.class).save(budgetDistribution);
|
||||||
Beans.get(PurchaseOrderLineServiceSupplychainImpl.class).computeBudgetDistributionSumAmount(purchaseOrderLine, purchaseOrderLine.getPurchaseOrder());
|
Beans.get(PurchaseOrderLineServiceSupplychainImpl.class)
|
||||||
|
.computeBudgetDistributionSumAmount(
|
||||||
|
purchaseOrderLine, purchaseOrderLine.getPurchaseOrder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMissingAnalyticMoveLine(PurchaseOrder purchaseOrder) {
|
||||||
|
boolean isMissing = false;
|
||||||
|
List<PurchaseOrderLine> prLines = purchaseOrder.getPurchaseOrderLineList();
|
||||||
|
for (PurchaseOrderLine prLine : prLines) {
|
||||||
|
if (prLine.getAnalyticMoveLineList().isEmpty()) {
|
||||||
|
isMissing = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isMissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void generateBudgetDistributionLines(PurchaseOrder purchaseOrder) throws AxelorException {
|
||||||
|
List<PurchaseOrderLine> prLines = purchaseOrder.getPurchaseOrderLineList();
|
||||||
|
for (PurchaseOrderLine pOrderLine : prLines) {
|
||||||
|
List<AccountManagement> accountManagementList = pOrderLine.getProduct().getAccountManagementList();
|
||||||
|
String accountCode = accountManagementList.get(0).getPurchaseAccount().getCode().substring(0, 2);
|
||||||
|
List<AnalyticMoveLine> analyticMoveLines = pOrderLine.getAnalyticMoveLineList();
|
||||||
|
if(analyticMoveLines.size() == 0){
|
||||||
|
throw new AxelorException(
|
||||||
|
purchaseOrder,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
I18n.get("One of the purchase order line has no analytic move line associated with it. Please make sure that the product has an analytic account and a purchase account defined."),
|
||||||
|
purchaseOrder.getPurchaseOrderSeq());
|
||||||
|
}
|
||||||
|
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
|
Budget budget = Beans.get(PurchaseOrderLineServiceSupplychainImpl.class).findBudgetRecursive(analyticMoveLine.getAnalyticAccount(), accountCode);
|
||||||
|
if (budget != null) {
|
||||||
|
BudgetDistribution newBudgetDistribution = new BudgetDistribution();
|
||||||
|
newBudgetDistribution.setAmount(
|
||||||
|
pOrderLine
|
||||||
|
.getCompanyExTaxTotal()
|
||||||
|
.multiply(analyticMoveLine.getPercentage())
|
||||||
|
.divide(new BigDecimal("100"))
|
||||||
|
.setScale(2, RoundingMode.HALF_EVEN));
|
||||||
|
newBudgetDistribution.setBudget(budget);
|
||||||
|
newBudgetDistribution.setPurchaseOrderLine(pOrderLine);
|
||||||
|
newBudgetDistribution.setAnalyticMoveLine(analyticMoveLine);
|
||||||
|
Beans.get(BudgetSupplychainService.class)
|
||||||
|
.computeBudgetDistributionSumAmount(newBudgetDistribution, purchaseOrder.getOrderDate());
|
||||||
|
|
||||||
|
Beans.get(BudgetDistributionRepository.class).save(newBudgetDistribution);
|
||||||
|
pOrderLine.addBudgetDistributionListItem(newBudgetDistribution);
|
||||||
|
}else{
|
||||||
|
throw new AxelorException(
|
||||||
|
purchaseOrder.getPurchaseOrderSeq(),
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"Vous n'avez pas de budget défini pour le compte analytique : "
|
||||||
|
+ analyticMoveLine.getAnalyticAccount().getCode()
|
||||||
|
+ " et le compte comptable : "
|
||||||
|
+ accountCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -340,11 +341,13 @@ public class PurchaseOrderStockServiceImpl implements PurchaseOrderStockService
|
|||||||
} else if (purchaseOrderLine.getIsTitleLine()) {
|
} else if (purchaseOrderLine.getIsTitleLine()) {
|
||||||
stockMoveLine = createTitleStockMoveLine(purchaseOrderLine, stockMove);
|
stockMoveLine = createTitleStockMoveLine(purchaseOrderLine, stockMove);
|
||||||
}
|
}
|
||||||
stockMoveLine.setAnalyticDistributionTemplate(purchaseOrderLine.getAnalyticDistributionTemplate());
|
stockMoveLine.setAnalyticDistributionTemplate(
|
||||||
|
purchaseOrderLine.getAnalyticDistributionTemplate());
|
||||||
List<AnalyticMoveLine> analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
List<AnalyticMoveLine> analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
||||||
if (analyticMoveLines.size() != 0) {
|
if (analyticMoveLines.size() != 0) {
|
||||||
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
AnalyticMoveLine analyticMoveLineCopy = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
AnalyticMoveLine analyticMoveLineCopy =
|
||||||
|
Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
||||||
stockMoveLine.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
stockMoveLine.addAnalyticMoveLineListItem(analyticMoveLineCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,6 +392,12 @@ public class PurchaseOrderStockServiceImpl implements PurchaseOrderStockService
|
|||||||
RoundingMode.HALF_EVEN);
|
RoundingMode.HALF_EVEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Long> stockMoveLineIdList =
|
||||||
|
Arrays.asList(
|
||||||
|
12L, 97L, 99L, 103L, 105L); // Dummy list to illustrate existing stock move lines
|
||||||
|
if (!stockMoveLineIdList.contains(stockMove.getToStockLocation().getId())) {
|
||||||
|
LOG.info("Stock move line not laboratory.");
|
||||||
|
|
||||||
if (unit != null && !unit.equals(purchaseOrderLine.getUnit())) {
|
if (unit != null && !unit.equals(purchaseOrderLine.getUnit())) {
|
||||||
qty =
|
qty =
|
||||||
unitConversionService.convert(
|
unitConversionService.convert(
|
||||||
@@ -410,6 +419,7 @@ public class PurchaseOrderStockServiceImpl implements PurchaseOrderStockService
|
|||||||
appBaseService.getNbDecimalDigitForUnitPrice(),
|
appBaseService.getNbDecimalDigitForUnitPrice(),
|
||||||
product);
|
product);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BigDecimal shippingCoef =
|
BigDecimal shippingCoef =
|
||||||
shippingCoefService.getShippingCoef(
|
shippingCoefService.getShippingCoef(
|
||||||
|
|||||||
@@ -17,10 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.supplychain.service;
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
import java.util.List;
|
import com.axelor.apps.account.db.AnalyticJournal;
|
||||||
|
|
||||||
import com.axelor.apps.account.db.AnalyticMoveLine;
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
|
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
|
||||||
|
import com.axelor.apps.base.db.AppBudget;
|
||||||
|
import com.axelor.apps.base.db.repo.AppBudgetRepository;
|
||||||
import com.axelor.apps.purchase.db.PurchaseOrder;
|
import com.axelor.apps.purchase.db.PurchaseOrder;
|
||||||
import com.axelor.apps.purchase.db.PurchaseOrderLine;
|
import com.axelor.apps.purchase.db.PurchaseOrderLine;
|
||||||
import com.axelor.apps.purchase.db.PurchaseRequest;
|
import com.axelor.apps.purchase.db.PurchaseRequest;
|
||||||
@@ -31,6 +32,9 @@ import com.axelor.apps.stock.db.repo.StockLocationRepository;
|
|||||||
import com.axelor.exception.AxelorException;
|
import com.axelor.exception.AxelorException;
|
||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.persist.Transactional;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class PurchaseRequestServiceSupplychainImpl extends PurchaseRequestServiceImpl {
|
public class PurchaseRequestServiceSupplychainImpl extends PurchaseRequestServiceImpl {
|
||||||
|
|
||||||
@@ -57,12 +61,49 @@ public class PurchaseRequestServiceSupplychainImpl extends PurchaseRequestServic
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPurchaseOrderLineAnalyticMoveLine(PurchaseRequestLine purchaseRequestLine,PurchaseOrderLine purchaseOrderLine){
|
public void setPurchaseOrderLineAnalyticMoveLine(
|
||||||
|
PurchaseRequestLine purchaseRequestLine, PurchaseOrderLine purchaseOrderLine) {
|
||||||
List<AnalyticMoveLine> analyticMoveLines = purchaseRequestLine.getAnalyticMoveLineList();
|
List<AnalyticMoveLine> analyticMoveLines = purchaseRequestLine.getAnalyticMoveLineList();
|
||||||
|
|
||||||
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
AnalyticMoveLine aml = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, true);
|
AnalyticMoveLine aml =
|
||||||
|
Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, true);
|
||||||
purchaseOrderLine.addAnalyticMoveLineListItem(aml);
|
purchaseOrderLine.addAnalyticMoveLineListItem(aml);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if there is missing analytic move line in one of purchase request line when there is no
|
||||||
|
// in purchase request
|
||||||
|
public boolean isMissingAnalyticMoveLine(PurchaseRequest purchaseRequest) {
|
||||||
|
boolean isMissing = false;
|
||||||
|
List<PurchaseRequestLine> prLines = purchaseRequest.getPurchaseRequestLineList();
|
||||||
|
for (PurchaseRequestLine prLine : prLines) {
|
||||||
|
if (prLine.getAnalyticMoveLineList().isEmpty()) {
|
||||||
|
isMissing = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isMissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate analytic move line in purchase request line from purchase request analytic account and
|
||||||
|
// axis
|
||||||
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
|
public void generateAnalyticMoveLines(PurchaseRequest purchaseRequest) {
|
||||||
|
List<PurchaseRequestLine> prLines = purchaseRequest.getPurchaseRequestLineList();
|
||||||
|
for (PurchaseRequestLine prLine : prLines) {
|
||||||
|
prLine.getAnalyticMoveLineList().clear();
|
||||||
|
if(prLine.getAnalyticMoveLineList().isEmpty()){
|
||||||
|
AnalyticMoveLine aml = new AnalyticMoveLine();
|
||||||
|
AppBudget AppBudget = Beans.get(AppBudgetRepository.class).all().fetchOne();
|
||||||
|
AnalyticJournal deAnalyticJournal = AppBudget.getDefaultAnalyticJournal();
|
||||||
|
aml.setAnalyticJournal(deAnalyticJournal);
|
||||||
|
aml.setAnalyticAccount(purchaseRequest.getAnalyticAccount());
|
||||||
|
aml.setAnalyticAxis(purchaseRequest.getAnalyticAxis());
|
||||||
|
aml.setAmount(BigDecimal.ZERO);
|
||||||
|
aml.setPercentage(BigDecimal.valueOf(100));
|
||||||
|
prLine.addAnalyticMoveLineListItem(aml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import com.axelor.inject.Beans;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.persist.Transactional;
|
import com.google.inject.persist.Transactional;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -794,8 +795,13 @@ public class ReservedQtyServiceImpl implements ReservedQtyService {
|
|||||||
Unit startUnit, Unit endUnit, BigDecimal qtyToConvert, Product product)
|
Unit startUnit, Unit endUnit, BigDecimal qtyToConvert, Product product)
|
||||||
throws AxelorException {
|
throws AxelorException {
|
||||||
if (startUnit != null && !startUnit.equals(endUnit)) {
|
if (startUnit != null && !startUnit.equals(endUnit)) {
|
||||||
|
List<Long> listOfCategoryIds = Arrays.asList(58L, 60L, 61L, 62L, 63L, 153L, 169L, 173L);
|
||||||
|
if(listOfCategoryIds.contains(product.getFamilleProduit().getId())){
|
||||||
|
return qtyToConvert;
|
||||||
|
}else{
|
||||||
return unitConversionService.convert(
|
return unitConversionService.convert(
|
||||||
startUnit, endUnit, qtyToConvert, qtyToConvert.scale(), product);
|
startUnit, endUnit, qtyToConvert, qtyToConvert.scale(), product);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return qtyToConvert;
|
return qtyToConvert;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.supplychain.service;
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.AnalyticJournal;
|
||||||
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
|
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
|
||||||
|
import com.axelor.apps.base.db.AppBudget;
|
||||||
import com.axelor.apps.base.db.AppSupplychain;
|
import com.axelor.apps.base.db.AppSupplychain;
|
||||||
import com.axelor.apps.base.db.CancelReason;
|
import com.axelor.apps.base.db.CancelReason;
|
||||||
import com.axelor.apps.base.db.Partner;
|
import com.axelor.apps.base.db.Partner;
|
||||||
|
import com.axelor.apps.base.db.repo.AppBudgetRepository;
|
||||||
import com.axelor.apps.base.db.repo.PriceListRepository;
|
import com.axelor.apps.base.db.repo.PriceListRepository;
|
||||||
import com.axelor.apps.base.service.PartnerPriceListService;
|
import com.axelor.apps.base.service.PartnerPriceListService;
|
||||||
import com.axelor.apps.base.service.PartnerService;
|
import com.axelor.apps.base.service.PartnerService;
|
||||||
@@ -250,4 +255,36 @@ public class SaleOrderServiceSupplychainImpl extends SaleOrderServiceImpl {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate analytic move line in purchase request line from purchase request analytic account and
|
||||||
|
// axis
|
||||||
|
@Transactional(rollbackOn = {Exception.class})
|
||||||
|
public void generateAnalyticMoveLines(SaleOrder saleOrder) throws AxelorException {
|
||||||
|
AppBudget AppBudget = Beans.get(AppBudgetRepository.class).all().fetchOne();
|
||||||
|
AnalyticJournal deAnalyticJournal = AppBudget.getDefaultSaleAnalyticJournal();
|
||||||
|
List<SaleOrderLine> saleOrderLines = saleOrder.getSaleOrderLineList();
|
||||||
|
if (deAnalyticJournal == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
saleOrder,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"There is no default sale analytic journal defined in Budget app settings.");
|
||||||
|
}
|
||||||
|
if (saleOrder.getClientPartner().getAnalyticAccount() == null
|
||||||
|
|| saleOrder.getClientPartner().getAnalyticAxis() == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
saleOrder,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"The client partner does not have analytic account or analytic axis defined.");
|
||||||
|
}
|
||||||
|
for (SaleOrderLine saleOrderLine : saleOrderLines) {
|
||||||
|
AnalyticMoveLine aml = new AnalyticMoveLine();
|
||||||
|
aml.setAnalyticJournal(deAnalyticJournal);
|
||||||
|
aml.setAnalyticAccount(saleOrder.getClientPartner().getAnalyticAccount());
|
||||||
|
aml.setAnalyticAxis(saleOrder.getClientPartner().getAnalyticAxis());
|
||||||
|
aml.setAmount(saleOrderLine.getInTaxTotal());
|
||||||
|
aml.setPercentage(BigDecimal.valueOf(100));
|
||||||
|
aml.setTypeSelect(AnalyticMoveLineRepository.STATUS_FORECAST_ORDER);
|
||||||
|
saleOrderLine.addAnalyticMoveLineListItem(aml);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ public class StockConfigService {
|
|||||||
return stockConfig;
|
return stockConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StockLocation getWarehouseNonCompliant(StockConfig stockConfig)
|
public StockLocation getWarehouseNonCompliant(StockConfig stockConfig) throws AxelorException {
|
||||||
throws AxelorException {
|
|
||||||
if (stockConfig.getPickupDefaultStockLocation() == null) {
|
if (stockConfig.getPickupDefaultStockLocation() == null) {
|
||||||
throw new AxelorException(
|
throw new AxelorException(
|
||||||
stockConfig,
|
stockConfig,
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ package com.axelor.apps.supplychain.service;
|
|||||||
import com.axelor.apps.account.db.AnalyticMoveLine;
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
|
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.Period;
|
||||||
import com.axelor.apps.base.db.Product;
|
import com.axelor.apps.base.db.Product;
|
||||||
import com.axelor.apps.base.db.Unit;
|
import com.axelor.apps.base.db.Unit;
|
||||||
|
import com.axelor.apps.base.db.repo.PeriodRepository;
|
||||||
import com.axelor.apps.base.db.repo.ProductRepository;
|
import com.axelor.apps.base.db.repo.ProductRepository;
|
||||||
import com.axelor.apps.base.service.PriceListService;
|
import com.axelor.apps.base.service.PriceListService;
|
||||||
import com.axelor.apps.base.service.UnitConversionService;
|
import com.axelor.apps.base.service.UnitConversionService;
|
||||||
@@ -35,13 +37,15 @@ import com.axelor.apps.purchase.service.PurchaseOrderLineService;
|
|||||||
import com.axelor.apps.purchase.service.PurchaseOrderLineServiceImpl;
|
import com.axelor.apps.purchase.service.PurchaseOrderLineServiceImpl;
|
||||||
import com.axelor.apps.purchase.service.PurchaseOrderServiceImpl;
|
import com.axelor.apps.purchase.service.PurchaseOrderServiceImpl;
|
||||||
import com.axelor.apps.sale.db.SaleOrderLine;
|
import com.axelor.apps.sale.db.SaleOrderLine;
|
||||||
import com.axelor.apps.stock.db.InternalTrackingNumber;
|
import com.axelor.apps.stock.db.Inventory;
|
||||||
|
import com.axelor.apps.stock.db.InventoryLine;
|
||||||
import com.axelor.apps.stock.db.StockLocation;
|
import com.axelor.apps.stock.db.StockLocation;
|
||||||
import com.axelor.apps.stock.db.StockLocationLine;
|
import com.axelor.apps.stock.db.StockLocationLine;
|
||||||
import com.axelor.apps.stock.db.StockMove;
|
import com.axelor.apps.stock.db.StockMove;
|
||||||
import com.axelor.apps.stock.db.StockMoveLine;
|
import com.axelor.apps.stock.db.StockMoveLine;
|
||||||
import com.axelor.apps.stock.db.TrackingNumber;
|
import com.axelor.apps.stock.db.TrackingNumber;
|
||||||
import com.axelor.apps.stock.db.TrackingNumberConfiguration;
|
import com.axelor.apps.stock.db.TrackingNumberConfiguration;
|
||||||
|
import com.axelor.apps.stock.db.repo.InventoryRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockLocationLineRepository;
|
import com.axelor.apps.stock.db.repo.StockLocationLineRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockLocationRepository;
|
import com.axelor.apps.stock.db.repo.StockLocationRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
||||||
@@ -68,6 +72,7 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.persist.Transactional;
|
import com.google.inject.persist.Transactional;
|
||||||
import com.google.inject.servlet.RequestScoped;
|
import com.google.inject.servlet.RequestScoped;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -153,6 +158,7 @@ public class StockMoveLineServiceSupplychainImpl extends StockMoveLineServiceImp
|
|||||||
stockMoveLine.setPvg(saleOrderLine.getPvg());
|
stockMoveLine.setPvg(saleOrderLine.getPvg());
|
||||||
stockMoveLine.setStklim(saleOrderLine.getStklim());
|
stockMoveLine.setStklim(saleOrderLine.getStklim());
|
||||||
stockMoveLine.setUg(saleOrderLine.getUg());
|
stockMoveLine.setUg(saleOrderLine.getUg());
|
||||||
|
this.inheretAccountAnalyticMoveLine(null, saleOrderLine, stockMoveLine);
|
||||||
}
|
}
|
||||||
TrackingNumberConfiguration trackingNumberConfiguration =
|
TrackingNumberConfiguration trackingNumberConfiguration =
|
||||||
product.getTrackingNumberConfiguration();
|
product.getTrackingNumberConfiguration();
|
||||||
@@ -180,11 +186,27 @@ public class StockMoveLineServiceSupplychainImpl extends StockMoveLineServiceImp
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
private void inheretAccountAnalyticMoveLine(PurchaseOrderLine purchaseOrderLine, StockMoveLine stockMoveLine) {
|
private void inheretAccountAnalyticMoveLine(
|
||||||
List<AnalyticMoveLine> analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
PurchaseOrderLine purchaseOrderLine,
|
||||||
|
SaleOrderLine saleOrderLine,
|
||||||
|
StockMoveLine stockMoveLine) {
|
||||||
|
List<AnalyticMoveLine> analyticMoveLines = new ArrayList<>();
|
||||||
|
if (purchaseOrderLine != null) {
|
||||||
|
analyticMoveLines = purchaseOrderLine.getAnalyticMoveLineList();
|
||||||
|
} else {
|
||||||
|
analyticMoveLines = saleOrderLine.getAnalyticMoveLineList();
|
||||||
|
}
|
||||||
if (analyticMoveLines.size() != 0) {
|
if (analyticMoveLines.size() != 0) {
|
||||||
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
for (AnalyticMoveLine analyticMoveLine : analyticMoveLines) {
|
||||||
AnalyticMoveLine aml = Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
AnalyticMoveLine aml =
|
||||||
|
Beans.get(AnalyticMoveLineRepository.class).copy(analyticMoveLine, false);
|
||||||
|
if (purchaseOrderLine != null) {
|
||||||
|
aml.setPurchaseOrderLine(purchaseOrderLine);
|
||||||
|
}
|
||||||
|
if (saleOrderLine != null) {
|
||||||
|
aml.setSaleOrderLine(saleOrderLine);
|
||||||
|
}
|
||||||
|
aml.setDate(LocalDate.now());
|
||||||
aml.setStockMoveLine(stockMoveLine);
|
aml.setStockMoveLine(stockMoveLine);
|
||||||
stockMoveLine.addAnalyticMoveLineListItem(aml);
|
stockMoveLine.addAnalyticMoveLineListItem(aml);
|
||||||
}
|
}
|
||||||
@@ -845,6 +867,45 @@ public class StockMoveLineServiceSupplychainImpl extends StockMoveLineServiceImp
|
|||||||
return qtyTot;
|
return qtyTot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BigDecimal getOnHandAtDate(Product product,Company company,LocalDate fromDate,Boolean excludeValorisationStocklocation) {
|
||||||
|
|
||||||
|
// 1) current on-hand (today)
|
||||||
|
BigDecimal currentQty = getTotalQty(product, company, excludeValorisationStocklocation);
|
||||||
|
|
||||||
|
// 2) movements since fromDate up to today (inclusive)
|
||||||
|
List<StockMoveLine> moves =
|
||||||
|
stockMoveLineRepository
|
||||||
|
.all()
|
||||||
|
.filter(
|
||||||
|
"self.product = ?1 "
|
||||||
|
+ "AND self.stockMove.realDate >= ?2 "
|
||||||
|
+ "AND self.stockMove.realDate <= ?3 "
|
||||||
|
+ "AND self.stockMove.statusSelect = ?4 "
|
||||||
|
+ "AND self.realQty > 0",
|
||||||
|
product,
|
||||||
|
fromDate,
|
||||||
|
LocalDate.now(),
|
||||||
|
StockMoveRepository.STATUS_REALIZED)
|
||||||
|
.order("stockMove.realDate")
|
||||||
|
.order("id")
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
BigDecimal incoming = BigDecimal.ZERO;
|
||||||
|
BigDecimal outgoing = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
for (StockMoveLine line : moves) {
|
||||||
|
if (isIncoming(line)) {
|
||||||
|
incoming = incoming.add(line.getRealQty());
|
||||||
|
} else if (isOutgoing(line)) {
|
||||||
|
outgoing = outgoing.add(line.getRealQty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) reverse the delta to go back in time
|
||||||
|
// qtyAtStart = current - incoming + outgoing
|
||||||
|
return currentQty.subtract(incoming).add(outgoing);
|
||||||
|
}
|
||||||
|
|
||||||
// lines
|
// lines
|
||||||
public List<StockMoveLine> lines = new ArrayList<>();
|
public List<StockMoveLine> lines = new ArrayList<>();
|
||||||
|
|
||||||
@@ -954,4 +1015,450 @@ public class StockMoveLineServiceSupplychainImpl extends StockMoveLineServiceImp
|
|||||||
}
|
}
|
||||||
return slicedLines;
|
return slicedLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* PART 1 — Helper methods
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
private boolean isNc1(StockLocation loc) {
|
||||||
|
if (loc == null) return false;
|
||||||
|
Boolean flag = loc.getExcludeValorisation();
|
||||||
|
return flag != null && flag == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if movement INCREASES usable stock
|
||||||
|
private boolean isIncoming(StockMoveLine line) {
|
||||||
|
StockLocation from = line.getStockMove().getFromStockLocation();
|
||||||
|
StockLocation to = line.getStockMove().getToStockLocation();
|
||||||
|
|
||||||
|
boolean fromNc1 = isNc1(from);
|
||||||
|
boolean toNc1 = isNc1(to);
|
||||||
|
|
||||||
|
// NC1 → Normal = incoming
|
||||||
|
if (fromNc1 && !toNc1) return true;
|
||||||
|
|
||||||
|
// 2) Supplier arrival (partner != 853) = incoming & WAP update
|
||||||
|
if (from.getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL) {
|
||||||
|
return true; // Supplier incoming
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if movement DECREASES usable stock
|
||||||
|
private boolean isOutgoing(StockMoveLine line) {
|
||||||
|
StockLocation from = line.getStockMove().getFromStockLocation();
|
||||||
|
StockLocation to = line.getStockMove().getToStockLocation();
|
||||||
|
|
||||||
|
boolean fromNc1 = isNc1(from);
|
||||||
|
boolean toNc1 = isNc1(to);
|
||||||
|
|
||||||
|
// Normal → NC1 = outgoing
|
||||||
|
if (!fromNc1 && toNc1) return true;
|
||||||
|
|
||||||
|
// Normal → supplier / virtual = outgoing
|
||||||
|
if (to.getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WAP formula
|
||||||
|
private BigDecimal computeWap(
|
||||||
|
BigDecimal oldQty,
|
||||||
|
BigDecimal oldWap,
|
||||||
|
BigDecimal incomingQty,
|
||||||
|
BigDecimal incomingPrice,
|
||||||
|
int scale) {
|
||||||
|
|
||||||
|
if (incomingQty.compareTo(BigDecimal.ZERO) <= 0) return oldWap;
|
||||||
|
|
||||||
|
return oldQty
|
||||||
|
.multiply(oldWap)
|
||||||
|
.add(incomingQty.multiply(incomingPrice))
|
||||||
|
.divide(oldQty.add(incomingQty), scale, RoundingMode.HALF_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract initial Qty + WAP from inventory or last movement
|
||||||
|
private InitialWapState getInitialStateForPeriod(
|
||||||
|
Product product, LocalDate periodStart, Company company) throws AxelorException {
|
||||||
|
|
||||||
|
InitialWapState state = new InitialWapState();
|
||||||
|
state.quantity = BigDecimal.ZERO;
|
||||||
|
state.wap = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
// 1) INVENTORY (highest priority)
|
||||||
|
// -------------------------------------------------
|
||||||
|
Inventory lastInventory =
|
||||||
|
Beans.get(InventoryRepository.class)
|
||||||
|
.all()
|
||||||
|
.filter(
|
||||||
|
"self.period.statusSelect = ?1 AND self.statusSelect = ?2 AND self.period.toDate < ?3",
|
||||||
|
PeriodRepository.STATUS_CLOSED,
|
||||||
|
InventoryRepository.STATUS_VALIDATED,
|
||||||
|
periodStart)
|
||||||
|
.order("-id")
|
||||||
|
.fetchOne();
|
||||||
|
|
||||||
|
if (lastInventory != null) {
|
||||||
|
List<InventoryLine> invLines =
|
||||||
|
lastInventory
|
||||||
|
.getInventoryLineList()
|
||||||
|
.stream()
|
||||||
|
.filter(l -> l.getProduct() != null && l.getProduct().getId().equals(product.getId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (!invLines.isEmpty()) {
|
||||||
|
|
||||||
|
// 1) Sum quantities
|
||||||
|
BigDecimal totalQty = BigDecimal.ZERO;
|
||||||
|
for (InventoryLine l : invLines) {
|
||||||
|
if (l.getRealQty() != null) {
|
||||||
|
totalQty = totalQty.add(l.getRealQty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Take PMP from any line (same for all)
|
||||||
|
BigDecimal pmp = invLines.get(0).getGapValue();
|
||||||
|
if (pmp == null) {
|
||||||
|
pmp = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.quantity = totalQty;
|
||||||
|
state.wap = pmp;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
// 2) LAST MOVEMENT BEFORE PERIOD
|
||||||
|
// -------------------------------------------------
|
||||||
|
StockMoveLine lastBefore =
|
||||||
|
stockMoveLineRepository
|
||||||
|
.all()
|
||||||
|
.filter(
|
||||||
|
"self.product = ?1 AND self.stockMove.realDate < ?2 AND self.realQty > 0 "
|
||||||
|
+ "AND self.stockMove.statusSelect = ?3",
|
||||||
|
product,
|
||||||
|
periodStart,
|
||||||
|
StockMoveRepository.STATUS_REALIZED)
|
||||||
|
.order("-stockMove.realDate")
|
||||||
|
.order("-id")
|
||||||
|
.fetchOne();
|
||||||
|
|
||||||
|
if (lastBefore != null) {
|
||||||
|
state.wap =
|
||||||
|
lastBefore.getWapPrice() != null
|
||||||
|
? lastBefore.getWapPrice()
|
||||||
|
: lastBefore.getUnitPriceUntaxed();
|
||||||
|
|
||||||
|
// Quantity at that date = physical stock
|
||||||
|
// state.quantity = getTotalQty(product, company, false);
|
||||||
|
state.quantity = getOnHandAtDate(product, company, periodStart, false);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
// 3) NO INVENTORY + NO PREVIOUS MOVE
|
||||||
|
// → TAKE FIRST SUPPLIER RECEPTION OF THE PERIOD
|
||||||
|
// -------------------------------------------------
|
||||||
|
StockMoveLine firstReception =
|
||||||
|
stockMoveLineRepository
|
||||||
|
.all()
|
||||||
|
.filter(
|
||||||
|
"self.product = ?1 "
|
||||||
|
+ "AND self.stockMove.realDate >= ?2 "
|
||||||
|
+ "AND self.stockMove.statusSelect = ?3 "
|
||||||
|
+ "AND self.realQty > 0 "
|
||||||
|
+ "AND self.stockMove.partner IS NOT NULL "
|
||||||
|
+ "AND self.stockMove.partner.id != 853 "
|
||||||
|
+ "AND self.stockMove.typeSelect != ?4",
|
||||||
|
product,
|
||||||
|
periodStart,
|
||||||
|
StockMoveRepository.STATUS_REALIZED,
|
||||||
|
StockMoveRepository.TYPE_INTERNAL)
|
||||||
|
.order("stockMove.realDate")
|
||||||
|
.order("id")
|
||||||
|
.fetchOne();
|
||||||
|
|
||||||
|
if (firstReception != null) {
|
||||||
|
state.quantity = firstReception.getRealQty();
|
||||||
|
state.wap = firstReception.getUnitPriceUntaxed();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
// 4) ABSOLUTE FALLBACK (rare, but safe)
|
||||||
|
// -------------------------------------------------
|
||||||
|
state.quantity = BigDecimal.ZERO;
|
||||||
|
state.wap = BigDecimal.ZERO;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper struct
|
||||||
|
private static class InitialWapState {
|
||||||
|
BigDecimal quantity;
|
||||||
|
BigDecimal wap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* PART 2 — Rewritten valorize() for a single movement
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void valorizeRewritten(
|
||||||
|
Long productId,
|
||||||
|
Long stockMoveId,
|
||||||
|
LocalDate toDateTime,
|
||||||
|
BigDecimal incomingPrice,
|
||||||
|
Boolean updatePo,
|
||||||
|
Boolean excludeValorisation)
|
||||||
|
throws AxelorException {
|
||||||
|
|
||||||
|
Product product = Beans.get(ProductRepository.class).find(productId);
|
||||||
|
StockMove currentMove = Beans.get(StockMoveRepository.class).find(stockMoveId);
|
||||||
|
|
||||||
|
int scale = appBaseService.getNbDecimalDigitForUnitPrice();
|
||||||
|
|
||||||
|
// Retrieve all movements up to the target date
|
||||||
|
List<StockMoveLine> allLines =
|
||||||
|
getStockMoveLines(product, toDateTime, currentMove, excludeValorisation);
|
||||||
|
|
||||||
|
// Slice movements from the current one forward
|
||||||
|
List<StockMoveLine> affected = sliceStockMoveLines(allLines, stockMoveId, product);
|
||||||
|
|
||||||
|
if (affected.isEmpty()) return;
|
||||||
|
|
||||||
|
InitialWapState state = new InitialWapState();
|
||||||
|
state.quantity = getTotalQty(product, currentMove.getCompany(), excludeValorisation);
|
||||||
|
state.wap = getPreviousWap(affected.get(0), excludeValorisation);
|
||||||
|
|
||||||
|
// Apply current movement WAP update
|
||||||
|
for (StockMoveLine line : affected) {
|
||||||
|
|
||||||
|
boolean incoming = isIncoming(line);
|
||||||
|
boolean outgoing = isOutgoing(line);
|
||||||
|
|
||||||
|
BigDecimal qty = line.getRealQty();
|
||||||
|
|
||||||
|
System.out.println("Processing line Code"+ line.getProduct().getCode() +" qty " + qty + " | " + line.getProductName() + " | incoming : " + incoming + " | outgoing : " + outgoing + " | stockmove : " + line.getStockMove().getStockMoveSeq());
|
||||||
|
System.out.println("qty before : " + state.quantity + " | wap before : " + state.wap + " | qty : " + qty + " | incomingPrice : " + incomingPrice);
|
||||||
|
if (incoming) {
|
||||||
|
// Recalculate WAP
|
||||||
|
state.wap = computeWap(state.quantity, state.wap, qty, incomingPrice, scale);
|
||||||
|
state.quantity = state.quantity.add(qty);
|
||||||
|
|
||||||
|
line.setWapPrice(state.wap);
|
||||||
|
line.setUnitPriceUntaxed(state.wap);
|
||||||
|
line.setUnitPriceTaxed(state.wap);
|
||||||
|
line.setCompanyUnitPriceUntaxed(state.wap);
|
||||||
|
line.setIsWapUpdated(true);
|
||||||
|
|
||||||
|
} else if (outgoing) {
|
||||||
|
// Outgoing takes last WAP but does not change it
|
||||||
|
line.setWapPrice(state.wap);
|
||||||
|
line.setUnitPriceUntaxed(state.wap);
|
||||||
|
line.setUnitPriceTaxed(state.wap);
|
||||||
|
line.setCompanyUnitPriceUntaxed(state.wap);
|
||||||
|
|
||||||
|
state.quantity = state.quantity.subtract(qty);
|
||||||
|
line.setIsWapUpdated(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Beans.get(StockMoveLineRepository.class).save(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update product and all stock locations
|
||||||
|
product.setAvgPrice(state.wap);
|
||||||
|
Beans.get(ProductRepository.class).save(product);
|
||||||
|
|
||||||
|
List<StockLocationLine> locLines =
|
||||||
|
Beans.get(StockLocationLineServiceImpl.class).getStockLocationLines(product);
|
||||||
|
for (StockLocationLine loc : locLines) {
|
||||||
|
loc.setAvgPrice(state.wap);
|
||||||
|
Beans.get(StockLocationLineRepository.class).save(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
* PART 3 — Full period valorization
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void valorizeCurrentPeriod(Long productCategoryId, Company company, Long productId)
|
||||||
|
throws AxelorException {
|
||||||
|
Period period =
|
||||||
|
Beans.get(PeriodRepository.class)
|
||||||
|
.all()
|
||||||
|
.filter("self.statusSelect = ?1", PeriodRepository.STATUS_OPENED)
|
||||||
|
.order("-id")
|
||||||
|
.fetchOne();
|
||||||
|
LocalDate start = period.getFromDate();
|
||||||
|
LocalDate end = period.getToDate();
|
||||||
|
List<Product> products = new ArrayList<>();
|
||||||
|
|
||||||
|
if (productId != null) {
|
||||||
|
// Valorize specific product only
|
||||||
|
Product p = Beans.get(ProductRepository.class).find(productId);
|
||||||
|
if (p == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||||
|
String.format("Product with id %s not found", productId));
|
||||||
|
}
|
||||||
|
products.add(p);
|
||||||
|
} else {
|
||||||
|
// Valorize all products in category
|
||||||
|
products =
|
||||||
|
Beans.get(ProductRepository.class)
|
||||||
|
.all()
|
||||||
|
.filter("self.familleProduit.id = ?1 and (self.archived is null OR self.archived is false) ", productCategoryId)
|
||||||
|
.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(products.size());
|
||||||
|
int all = products.size();
|
||||||
|
int size = products.size();
|
||||||
|
|
||||||
|
int BATCH_SIZE = 10; // start with 10 (safe)
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (Product product : products) {
|
||||||
|
|
||||||
|
// 1) Get initial state
|
||||||
|
InitialWapState state = getInitialStateForPeriod(product, start, company);
|
||||||
|
System.out.println(String.valueOf(size) + "/" + String.valueOf(all));
|
||||||
|
size--;
|
||||||
|
// 2) Fetch chronological movements within the period
|
||||||
|
List<StockMoveLine> moves =
|
||||||
|
stockMoveLineRepository
|
||||||
|
.all()
|
||||||
|
.filter(
|
||||||
|
"self.product = ?1 AND self.stockMove.realDate >= ?2 "
|
||||||
|
+ "AND self.stockMove.realDate <= ?3 AND self.realQty > 0 AND self.stockMove.statusSelect = ?4",
|
||||||
|
product,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
StockMoveRepository.STATUS_REALIZED)
|
||||||
|
.order("stockMove.realDate")
|
||||||
|
.order("id")
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
int scale = appBaseService.getNbDecimalDigitForUnitPrice();
|
||||||
|
|
||||||
|
// 3) Loop through period movements
|
||||||
|
for (StockMoveLine line : moves) {
|
||||||
|
|
||||||
|
boolean incoming = isIncoming(line);
|
||||||
|
boolean outgoing = isOutgoing(line);
|
||||||
|
BigDecimal qty = line.getRealQty();
|
||||||
|
|
||||||
|
BigDecimal price = line.getUnitPriceUntaxed();
|
||||||
|
|
||||||
|
System.out.println("Processing line Code"+ line.getProduct().getCode() +" qty " + qty + " | " + line.getProductName() + " | incoming : " + incoming + " | outgoing : " + outgoing + " | stockmove : " + line.getStockMove().getStockMoveSeq());
|
||||||
|
System.out.println("qty before : " + state.quantity + " | wap before : " + state.wap + " | qty : " + qty + " | incomingPrice : " + price);
|
||||||
|
|
||||||
|
if (incoming) {
|
||||||
|
boolean isSupplierIncoming =
|
||||||
|
line.getStockMove().getPartner() != null
|
||||||
|
&& line.getStockMove().getPartner().getId() != 853;
|
||||||
|
|
||||||
|
if (isSupplierIncoming) {
|
||||||
|
// TRUE WAP UPDATE
|
||||||
|
state.wap = computeWap(state.quantity, state.wap, qty, price, scale);
|
||||||
|
}
|
||||||
|
state.quantity = state.quantity.add(qty);
|
||||||
|
|
||||||
|
line.setWapPrice(state.wap);
|
||||||
|
if (!isSupplierIncoming) {
|
||||||
|
line.setUnitPriceUntaxed(state.wap);
|
||||||
|
line.setUnitPriceTaxed(state.wap);
|
||||||
|
line.setCompanyUnitPriceUntaxed(state.wap);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (outgoing) {
|
||||||
|
|
||||||
|
line.setWapPrice(state.wap);
|
||||||
|
line.setUnitPriceUntaxed(state.wap);
|
||||||
|
line.setUnitPriceTaxed(state.wap);
|
||||||
|
line.setCompanyUnitPriceUntaxed(state.wap);
|
||||||
|
|
||||||
|
state.quantity = state.quantity.subtract(qty);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
line.setWapPrice(state.wap);
|
||||||
|
line.setUnitPriceUntaxed(state.wap);
|
||||||
|
line.setUnitPriceTaxed(state.wap);
|
||||||
|
line.setCompanyUnitPriceUntaxed(state.wap);
|
||||||
|
}
|
||||||
|
|
||||||
|
line.setIsWapUpdated(true);
|
||||||
|
Beans.get(StockMoveLineRepository.class).save(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) Update product & stock locations at end of valorization
|
||||||
|
JPA.em()
|
||||||
|
.createQuery("UPDATE Product p SET p.avgPrice = :wap WHERE p.id = :id")
|
||||||
|
.setParameter("wap", state.wap)
|
||||||
|
.setParameter("id", product.getId())
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
|
||||||
|
JPA.em()
|
||||||
|
.createQuery(
|
||||||
|
"UPDATE StockLocationLine s SET s.avgPrice = :wap WHERE s.product.id = :pid")
|
||||||
|
.setParameter("wap", state.wap)
|
||||||
|
.setParameter("pid", product.getId())
|
||||||
|
.executeUpdate();
|
||||||
|
|
||||||
|
// ---- BATCH CONTROL ----
|
||||||
|
i++;
|
||||||
|
if (i % BATCH_SIZE == 0) {
|
||||||
|
JPA.em().flush();
|
||||||
|
JPA.em().clear(); // 🔥 THIS IS CRITICAL
|
||||||
|
System.out.println("Batch flushed at product " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Final flush
|
||||||
|
JPA.em().flush();
|
||||||
|
JPA.em().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void valorizeCurrentPeriod(){
|
||||||
|
// List<Product> products = Beans.get(StockLocationLineRepository.class)
|
||||||
|
// .all()
|
||||||
|
// .filter("self.stockLocation.isNotInCalculStock = false")
|
||||||
|
// .fetch()
|
||||||
|
// .stream()
|
||||||
|
// .map(t -> t.getProduct())
|
||||||
|
// .distinct()
|
||||||
|
// .collect(Collectors.toList());
|
||||||
|
|
||||||
|
// Period lastPeriod = Beans.get(PeriodRepository.class).all().filter("self.statusSelect =
|
||||||
|
// ?1",PeriodRepository.STATUS_CLOSED).order("-id").fetchOne();
|
||||||
|
|
||||||
|
// Inventory lastIventory = Beans.get(InventoryRepository.class).all()
|
||||||
|
// .filter("self.period = ?1 AND self.statusSelect =
|
||||||
|
// ?2",PeriodRepository.STATUS_CLOSED,InventoryRepository.STATUS_VALIDATED)
|
||||||
|
// .fetchOne();
|
||||||
|
|
||||||
|
// List<Product> inventoriedProducts = lastIventory.getInventoryLineList()
|
||||||
|
// .stream()
|
||||||
|
// .map(t -> t.getProduct())
|
||||||
|
// .distinct()
|
||||||
|
// .collect(Collectors.toList());
|
||||||
|
|
||||||
|
// for (Product product : products) {
|
||||||
|
// stockMoveLineRepository.all()
|
||||||
|
// .filter("self.product = ?1 and self.stockMove.estimatedDate BETWEEN ?1 AND ?2 and
|
||||||
|
// self.stockMove.statusSelect = ?3 AND self.realQty >
|
||||||
|
// 0",product,lastPeriod.getFromDate(),lastPeriod.getToDate(),StockMoveRepository.STATUS_REALIZED)
|
||||||
|
// .order("stockMove.realDate")
|
||||||
|
// .order("id")
|
||||||
|
// .fetch();
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,17 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.supplychain.service;
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import com.axelor.apps.account.db.Account;
|
||||||
|
import com.axelor.apps.account.db.AccountManagement;
|
||||||
|
import com.axelor.apps.account.db.AnalyticAccount;
|
||||||
|
import com.axelor.apps.account.db.AnalyticJournal;
|
||||||
|
import com.axelor.apps.account.db.AnalyticMoveLine;
|
||||||
|
import com.axelor.apps.account.db.Budget;
|
||||||
|
import com.axelor.apps.account.db.repo.BudgetRepository;
|
||||||
|
import com.axelor.apps.account.service.AnalyticMoveLineService;
|
||||||
|
import com.axelor.apps.base.db.AppBudget;
|
||||||
import com.axelor.apps.base.db.AppSupplychain;
|
import com.axelor.apps.base.db.AppSupplychain;
|
||||||
|
import com.axelor.apps.base.db.repo.AppBudgetRepository;
|
||||||
import com.axelor.apps.base.db.repo.ProductRepository;
|
import com.axelor.apps.base.db.repo.ProductRepository;
|
||||||
import com.axelor.apps.base.service.UnitConversionService;
|
import com.axelor.apps.base.service.UnitConversionService;
|
||||||
import com.axelor.apps.base.service.app.AppBaseService;
|
import com.axelor.apps.base.service.app.AppBaseService;
|
||||||
@@ -31,6 +41,7 @@ import com.axelor.apps.sale.db.repo.SaleOrderRepository;
|
|||||||
import com.axelor.apps.stock.db.StockMove;
|
import com.axelor.apps.stock.db.StockMove;
|
||||||
import com.axelor.apps.stock.db.StockMoveLine;
|
import com.axelor.apps.stock.db.StockMoveLine;
|
||||||
import com.axelor.apps.stock.db.TrackingNumber;
|
import com.axelor.apps.stock.db.TrackingNumber;
|
||||||
|
import com.axelor.apps.stock.db.repo.StockLocationRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
||||||
import com.axelor.apps.stock.service.PartnerProductQualityRatingService;
|
import com.axelor.apps.stock.service.PartnerProductQualityRatingService;
|
||||||
@@ -49,6 +60,7 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.persist.Transactional;
|
import com.google.inject.persist.Transactional;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -168,6 +180,10 @@ public class StockMoveServiceSupplychainImpl extends StockMoveServiceImpl
|
|||||||
update.executeUpdate();
|
update.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stockMove.getToStockLocation().getTypeSelect() == StockLocationRepository.TYPE_VIRTUAL) {
|
||||||
|
// this.generateAnalyticMoveLinesAndBudgetStockMoveLine(stockMove);
|
||||||
|
}
|
||||||
|
|
||||||
return newStockSeq;
|
return newStockSeq;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,4 +524,106 @@ public class StockMoveServiceSupplychainImpl extends StockMoveServiceImpl
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void generateAnalyticMoveLinesAndBudgetStockMoveLine(StockMove stockMove)
|
||||||
|
throws AxelorException {
|
||||||
|
AppBudget AppBudget = Beans.get(AppBudgetRepository.class).all().fetchOne();
|
||||||
|
AnalyticJournal deAnalyticJournal = AppBudget.getDefaultAnalyticJournal();
|
||||||
|
|
||||||
|
for (StockMoveLine stockMoveLine : stockMove.getStockMoveLineList()) {
|
||||||
|
AnalyticAccount analyticAccount = stockMove.getAnalyticAccount();
|
||||||
|
List<AccountManagement> accountManagementList =
|
||||||
|
stockMoveLine.getProduct().getAccountManagementList();
|
||||||
|
if (accountManagementList == null || accountManagementList.size() == 0) {
|
||||||
|
throw new AxelorException(
|
||||||
|
stockMove.getStockMoveSeq(),
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"Vous avez une lignes de stock sans compte de consommation défini sur le produit");
|
||||||
|
|
||||||
|
} else if (accountManagementList.get(0).getConsumptionAccount() == null) {
|
||||||
|
throw new AxelorException(
|
||||||
|
stockMove,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"Vous avez une lignes de stock sans compte de consommation sur le produit");
|
||||||
|
}
|
||||||
|
String accountCode =
|
||||||
|
accountManagementList.get(0).getConsumptionAccount().getCode().substring(0, 3);
|
||||||
|
|
||||||
|
AnalyticMoveLine analyticMoveLine =
|
||||||
|
this.generateAnalyticMoveLines(
|
||||||
|
stockMoveLine,
|
||||||
|
accountManagementList.get(0).getConsumptionAccount(),
|
||||||
|
deAnalyticJournal);
|
||||||
|
|
||||||
|
// Budget budget = findBudgetRecursive(analyticAccount,accountCode);
|
||||||
|
// if(budget != null){
|
||||||
|
// BudgetDistribution budgetDistribution = new BudgetDistribution();
|
||||||
|
//
|
||||||
|
// budgetDistribution.setAmount(stockMoveLine.getCompanyUnitPriceUntaxed().multiply(stockMoveLine.getRealQty()).setScale(2, RoundingMode.HALF_EVEN));
|
||||||
|
// budgetDistribution.setBudget(budget);
|
||||||
|
// budgetDistribution.setStockMoveLine(stockMoveLine);
|
||||||
|
// budgetDistribution.setAnalyticMoveLine(analyticMoveLine);
|
||||||
|
//
|
||||||
|
// Beans.get(BudgetSupplychainService.class).computeBudgetDistributionSumAmount(budgetDistribution, stockMove.getEstimatedDate());
|
||||||
|
// Beans.get(BudgetDistributionRepository.class).save(budgetDistribution);
|
||||||
|
// }else{
|
||||||
|
// throw new AxelorException(
|
||||||
|
// stockMove,
|
||||||
|
// TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
// "Aucun budget trouvé pour le compte comptable "+ accountCode + " et
|
||||||
|
// le compte analytique "+ analyticAccount.getName());
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Budget findBudgetRecursive(AnalyticAccount account, String accountCode) {
|
||||||
|
AnalyticAccount current = account;
|
||||||
|
while (current != null) {
|
||||||
|
// capture id in a local effectively-final variable for use in the lambda
|
||||||
|
Long currentAnalyticAccountId = current.getId();
|
||||||
|
Optional<Budget> budget =
|
||||||
|
Beans.get(BudgetRepository.class)
|
||||||
|
.all()
|
||||||
|
.fetch()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
t -> {
|
||||||
|
String accCode = t.getAccountAccountCode();
|
||||||
|
Long analyticId =
|
||||||
|
t.getAnalyticAccount() != null ? t.getAnalyticAccount().getId() : null;
|
||||||
|
return Objects.equals(accCode, accountCode)
|
||||||
|
&& Objects.equals(analyticId, currentAnalyticAccountId);
|
||||||
|
})
|
||||||
|
.findAny();
|
||||||
|
|
||||||
|
if (budget.isPresent()) {
|
||||||
|
return budget.get(); // found budget, stop here
|
||||||
|
}
|
||||||
|
current = current.getParent(); // go up one level
|
||||||
|
}
|
||||||
|
return null; // no budget found in hierarchy
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public AnalyticMoveLine generateAnalyticMoveLines(
|
||||||
|
StockMoveLine stockMoveLine, Account consumptionAccount, AnalyticJournal deAnalyticJournal)
|
||||||
|
throws AxelorException {
|
||||||
|
AnalyticMoveLine aml = new AnalyticMoveLine();
|
||||||
|
aml.setAnalyticJournal(deAnalyticJournal);
|
||||||
|
aml.setAnalyticAccount(stockMoveLine.getStockMove().getAnalyticAccount());
|
||||||
|
aml.setAnalyticAxis(stockMoveLine.getStockMove().getAnalyticAxis());
|
||||||
|
aml.setPercentage(BigDecimal.valueOf(100));
|
||||||
|
aml.setAccount(consumptionAccount);
|
||||||
|
Beans.get(AnalyticMoveLineService.class)
|
||||||
|
.updateAnalyticMoveLine(
|
||||||
|
aml,
|
||||||
|
stockMoveLine
|
||||||
|
.getCompanyUnitPriceUntaxed()
|
||||||
|
.multiply(stockMoveLine.getRealQty())
|
||||||
|
.setScale(2, RoundingMode.HALF_EVEN),
|
||||||
|
stockMoveLine.getStockMove().getEstimatedDate());
|
||||||
|
stockMoveLine.addAnalyticMoveLineListItem(aml);
|
||||||
|
return aml;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.axelor.apps.account.db.InvoiceLine;
|
|||||||
import com.axelor.apps.account.db.MoveLine;
|
import com.axelor.apps.account.db.MoveLine;
|
||||||
import com.axelor.apps.account.db.repo.InvoiceLineRepository;
|
import com.axelor.apps.account.db.repo.InvoiceLineRepository;
|
||||||
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
||||||
|
import com.axelor.apps.account.service.AnalyticMoveLineService;
|
||||||
import com.axelor.apps.account.service.app.AppAccountService;
|
import com.axelor.apps.account.service.app.AppAccountService;
|
||||||
import com.axelor.apps.account.service.config.AccountConfigService;
|
import com.axelor.apps.account.service.config.AccountConfigService;
|
||||||
import com.axelor.apps.account.service.invoice.InvoiceLineService;
|
import com.axelor.apps.account.service.invoice.InvoiceLineService;
|
||||||
@@ -64,7 +65,8 @@ public class InvoiceServiceSupplychainImpl extends InvoiceServiceImpl
|
|||||||
AppAccountService appAccountService,
|
AppAccountService appAccountService,
|
||||||
PartnerService partnerService,
|
PartnerService partnerService,
|
||||||
InvoiceLineService invoiceLineService,
|
InvoiceLineService invoiceLineService,
|
||||||
AccountConfigService accountConfigService) {
|
AccountConfigService accountConfigService,
|
||||||
|
AnalyticMoveLineService analyticMoveLineService) {
|
||||||
super(
|
super(
|
||||||
validateFactory,
|
validateFactory,
|
||||||
ventilateFactory,
|
ventilateFactory,
|
||||||
@@ -74,7 +76,8 @@ public class InvoiceServiceSupplychainImpl extends InvoiceServiceImpl
|
|||||||
appAccountService,
|
appAccountService,
|
||||||
partnerService,
|
partnerService,
|
||||||
invoiceLineService,
|
invoiceLineService,
|
||||||
accountConfigService);
|
accountConfigService,
|
||||||
|
analyticMoveLineService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -444,4 +444,28 @@ public class PurchaseOrderController {
|
|||||||
TraceBackService.trace(response, e);
|
TraceBackService.trace(response, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void isMissingAnalyticMoveLine(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
PurchaseOrder purchaseOrder = request.getContext().asType(PurchaseOrder.class);
|
||||||
|
PurchaseOrder pr = Beans.get(PurchaseOrderRepository.class).find(purchaseOrder.getId());
|
||||||
|
Boolean isMissingAnalyticMoveLine =
|
||||||
|
Beans.get(PurchaseOrderServiceSupplychainImpl.class).isMissingAnalyticMoveLine(pr);
|
||||||
|
if (isMissingAnalyticMoveLine) {
|
||||||
|
throw new AxelorException(
|
||||||
|
pr,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"The analytic account is missing on one of the lines.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void generateBudgetDistributionLines(ActionRequest request, ActionResponse response) throws AxelorException {
|
||||||
|
PurchaseOrder purchaseOrder = request.getContext().asType(PurchaseOrder.class);
|
||||||
|
purchaseOrder = Beans.get(PurchaseOrderRepository.class).find(purchaseOrder.getId());
|
||||||
|
Beans.get(PurchaseOrderServiceSupplychainImpl.class)
|
||||||
|
.generateBudgetDistributionLines(purchaseOrder);
|
||||||
|
response.setAlert(I18n.get("Budget distribution lines generated successfully"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,11 @@
|
|||||||
package com.axelor.apps.supplychain.web;
|
package com.axelor.apps.supplychain.web;
|
||||||
|
|
||||||
import com.axelor.apps.purchase.db.PurchaseRequest;
|
import com.axelor.apps.purchase.db.PurchaseRequest;
|
||||||
|
import com.axelor.apps.purchase.db.repo.PurchaseRequestRepository;
|
||||||
import com.axelor.apps.stock.service.StockLocationService;
|
import com.axelor.apps.stock.service.StockLocationService;
|
||||||
|
import com.axelor.apps.supplychain.service.PurchaseRequestServiceSupplychainImpl;
|
||||||
|
import com.axelor.exception.AxelorException;
|
||||||
|
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
import com.axelor.rpc.ActionRequest;
|
import com.axelor.rpc.ActionRequest;
|
||||||
import com.axelor.rpc.ActionResponse;
|
import com.axelor.rpc.ActionResponse;
|
||||||
@@ -37,4 +41,25 @@ public class PurchaseRequestController {
|
|||||||
.getDefaultReceiptStockLocation(purchaseRequest.getCompany()));
|
.getDefaultReceiptStockLocation(purchaseRequest.getCompany()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void isMissingAnalyticMoveLine(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
PurchaseRequest purchaseRequest = request.getContext().asType(PurchaseRequest.class);
|
||||||
|
PurchaseRequest pr = Beans.get(PurchaseRequestRepository.class).find(purchaseRequest.getId());
|
||||||
|
Boolean isMissingAnalyticMoveLine =
|
||||||
|
Beans.get(PurchaseRequestServiceSupplychainImpl.class).isMissingAnalyticMoveLine(pr);
|
||||||
|
if (isMissingAnalyticMoveLine) {
|
||||||
|
throw new AxelorException(
|
||||||
|
pr,
|
||||||
|
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||||
|
"The analytic account is missing on one of the lines.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateAnalyticMoveLines(ActionRequest request, ActionResponse response) {
|
||||||
|
PurchaseRequest purchaseRequest = request.getContext().asType(PurchaseRequest.class);
|
||||||
|
PurchaseRequest pr = Beans.get(PurchaseRequestRepository.class).find(purchaseRequest.getId());
|
||||||
|
Beans.get(PurchaseRequestServiceSupplychainImpl.class).generateAnalyticMoveLines(pr);
|
||||||
|
response.setAlert("The analytic move lines have been generated.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -861,4 +861,12 @@ public class SaleOrderController {
|
|||||||
TraceBackService.trace(response, e, ResponseMessageType.ERROR);
|
TraceBackService.trace(response, e, ResponseMessageType.ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateAnalyticMoveLines(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
SaleOrder saleOrder = request.getContext().asType(SaleOrder.class);
|
||||||
|
SaleOrder so = Beans.get(SaleOrderRepository.class).find(saleOrder.getId());
|
||||||
|
Beans.get(SaleOrderServiceSupplychainImpl.class).generateAnalyticMoveLines(so);
|
||||||
|
// response.setAlert("The analytic move lines have been generated.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package com.axelor.apps.supplychain.web;
|
|||||||
|
|
||||||
import com.axelor.apps.base.db.Company;
|
import com.axelor.apps.base.db.Company;
|
||||||
import com.axelor.apps.sale.db.SaleOrder;
|
import com.axelor.apps.sale.db.SaleOrder;
|
||||||
import com.axelor.apps.stock.db.StockLocation;
|
|
||||||
import com.axelor.apps.stock.db.StockMove;
|
import com.axelor.apps.stock.db.StockMove;
|
||||||
import com.axelor.apps.stock.db.StockMoveLine;
|
import com.axelor.apps.stock.db.StockMoveLine;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
||||||
@@ -27,7 +26,6 @@ import com.axelor.apps.supplychain.db.SupplyChainConfig;
|
|||||||
import com.axelor.apps.supplychain.exception.IExceptionMessage;
|
import com.axelor.apps.supplychain.exception.IExceptionMessage;
|
||||||
import com.axelor.apps.supplychain.service.SaleOrderReservedQtyService;
|
import com.axelor.apps.supplychain.service.SaleOrderReservedQtyService;
|
||||||
import com.axelor.apps.supplychain.service.SaleOrderStockService;
|
import com.axelor.apps.supplychain.service.SaleOrderStockService;
|
||||||
import com.axelor.apps.supplychain.service.StockConfigService;
|
|
||||||
import com.axelor.apps.supplychain.service.StockMoveServiceSupplychain;
|
import com.axelor.apps.supplychain.service.StockMoveServiceSupplychain;
|
||||||
import com.axelor.apps.supplychain.service.StockMoveServiceSupplychainImpl;
|
import com.axelor.apps.supplychain.service.StockMoveServiceSupplychainImpl;
|
||||||
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
|
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
|
||||||
@@ -40,13 +38,10 @@ import com.axelor.i18n.I18n;
|
|||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
import com.axelor.rpc.ActionRequest;
|
import com.axelor.rpc.ActionRequest;
|
||||||
import com.axelor.rpc.ActionResponse;
|
import com.axelor.rpc.ActionResponse;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -160,9 +155,9 @@ public class StockMoveController {
|
|||||||
Query sql =
|
Query sql =
|
||||||
JPA.em()
|
JPA.em()
|
||||||
.createNativeQuery(
|
.createNativeQuery(
|
||||||
"SELECT LINE.ID"+
|
"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"+
|
+ " 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");
|
+ " 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(1, stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.getId());
|
sql.setParameter(2, stockMove.getId());
|
||||||
logger.debug("sql.getResultList().size()", sql.getResultList().size());
|
logger.debug("sql.getResultList().size()", sql.getResultList().size());
|
||||||
@@ -182,9 +177,9 @@ public class StockMoveController {
|
|||||||
Query sql =
|
Query sql =
|
||||||
JPA.em()
|
JPA.em()
|
||||||
.createNativeQuery(
|
.createNativeQuery(
|
||||||
"SELECT LINE.ID" +
|
"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" +
|
+ " 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 != 3 AND LINE.STOCK_MOVE = ?2");
|
+ " where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.CONFORMITY_SELECT != 3 AND LINE.STOCK_MOVE = ?2");
|
||||||
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.getId());
|
sql.setParameter(2, stockMove.getId());
|
||||||
logger.debug("sql.getResultList().size()", sql.getResultList().size());
|
logger.debug("sql.getResultList().size()", sql.getResultList().size());
|
||||||
@@ -204,17 +199,15 @@ public class StockMoveController {
|
|||||||
Query sql =
|
Query sql =
|
||||||
JPA.em()
|
JPA.em()
|
||||||
.createNativeQuery(
|
.createNativeQuery(
|
||||||
"SELECT LINE.ID" +
|
"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" +
|
+ " 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 = 3 AND LINE.STOCK_MOVE = ?2");
|
+ " where LOCATION_LINE.DETAILS_STOCK_LOCATION = ?1 AND LOCATION_LINE.CONFORMITY_SELECT = 3 AND LINE.STOCK_MOVE = ?2");
|
||||||
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.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) {
|
if (sql.getResultList().size() > 0) {
|
||||||
throw new AxelorException(
|
throw new AxelorException(
|
||||||
stockMove,
|
stockMove, TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, "vous avez une ligne NC");
|
||||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
|
||||||
"vous avez une ligne NC");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,9 +219,9 @@ public class StockMoveController {
|
|||||||
Query sql =
|
Query sql =
|
||||||
JPA.em()
|
JPA.em()
|
||||||
.createNativeQuery(
|
.createNativeQuery(
|
||||||
"SELECT LINE.ID" +
|
"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" +
|
+ " 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");
|
+ " 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.getFromStockLocation().getId());
|
sql.setParameter(1, stockMove.getFromStockLocation().getId());
|
||||||
sql.setParameter(2, stockMove.getId());
|
sql.setParameter(2, stockMove.getId());
|
||||||
logger.debug("sql.getResultList().size {}", sql.getResultList().size());
|
logger.debug("sql.getResultList().size {}", sql.getResultList().size());
|
||||||
@@ -240,4 +233,9 @@ public class StockMoveController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateBudgetDistributionLines(ActionRequest request, ActionResponse response)
|
||||||
|
throws AxelorException {
|
||||||
|
StockMove stockMoveFromContext = request.getContext().asType(StockMove.class);
|
||||||
|
StockMove stockMove = Beans.get(StockMoveRepository.class).find(stockMoveFromContext.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.axelor.apps.supplychain.web;
|
package com.axelor.apps.supplychain.web;
|
||||||
|
|
||||||
import com.axelor.apps.base.db.repo.FamilleProduitRepository;
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||||
import com.axelor.apps.stock.db.StockMoveLine;
|
import com.axelor.apps.stock.db.StockMoveLine;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
|
||||||
import com.axelor.apps.supplychain.service.StockMoveLineServiceSupplychainImpl;
|
import com.axelor.apps.supplychain.service.StockMoveLineServiceSupplychainImpl;
|
||||||
@@ -32,8 +33,6 @@ import java.time.LocalDate;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.xpath.operations.Bool;
|
|
||||||
|
|
||||||
public class StockMoveLineController {
|
public class StockMoveLineController {
|
||||||
|
|
||||||
public void getProductPrice(ActionRequest request, ActionResponse response) {
|
public void getProductPrice(ActionRequest request, ActionResponse response) {
|
||||||
@@ -195,32 +194,55 @@ public class StockMoveLineController {
|
|||||||
if (request.getContext().get("updatePo") != null) {
|
if (request.getContext().get("updatePo") != null) {
|
||||||
updatePo = (Boolean) request.getContext().get("updatePo");
|
updatePo = (Boolean) request.getContext().get("updatePo");
|
||||||
}
|
}
|
||||||
Beans.get(StockMoveLineServiceSupplychainImpl.class).resetValorization(productId, stockMoveId, fromDateTime,false);
|
Beans.get(StockMoveLineServiceSupplychainImpl.class)
|
||||||
Beans.get(StockMoveLineServiceSupplychainImpl.class).fillStockMoveLines(productId, fromDateTime, stockMoveId,false);
|
.resetValorization(productId, stockMoveId, fromDateTime, false);
|
||||||
Beans.get(StockMoveLineServiceSupplychainImpl.class).valorize(productId, stockMoveId, fromDateTime, val,updatePo,false);
|
Beans.get(StockMoveLineServiceSupplychainImpl.class)
|
||||||
|
.fillStockMoveLines(productId, fromDateTime, stockMoveId, false);
|
||||||
|
Beans.get(StockMoveLineServiceSupplychainImpl.class)
|
||||||
|
.valorize(productId, stockMoveId, fromDateTime, val, updatePo, false);
|
||||||
response.setNotify("Recalcul Terminé");
|
response.setNotify("Recalcul Terminé");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TraceBackService.trace(response, e);
|
TraceBackService.trace(response, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
public void valorizeAll(ActionRequest request, ActionResponse response) {
|
public void valorizeAll(ActionRequest request, ActionResponse response) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
LocalDate fromDateTime = LocalDate.parse(request.getContext().get("fromDateTime").toString());
|
// ---------------------------
|
||||||
Long productCategoryId = new Long((Integer) ((Map) request.getContext().get("productCategory")).get("id"));
|
// 1. Extract parameters
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
Context ctx = request.getContext();
|
||||||
|
|
||||||
|
Long productCategoryId = null;
|
||||||
|
if (ctx.get("productCategory") != null) {
|
||||||
|
productCategoryId = Long.valueOf((Integer) ((Map) ctx.get("productCategory")).get("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Long productId = null;
|
||||||
|
if (ctx.get("product") != null) {
|
||||||
|
productId = Long.valueOf((Integer) ((Map) ctx.get("product")).get("id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Long companyId = ((Company) ctx.get("company")).getId();
|
||||||
|
Company company = Beans.get(CompanyRepository.class).find(companyId);
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// 2. Call valorization
|
||||||
|
// ---------------------------
|
||||||
|
|
||||||
|
Beans.get(StockMoveLineServiceSupplychainImpl.class)
|
||||||
|
.valorizeCurrentPeriod(productCategoryId, company, productId);
|
||||||
|
|
||||||
|
response.setNotify("Recalcul terminé avec succès.");
|
||||||
|
|
||||||
Beans.get(StockMoveLineServiceSupplychainImpl.class).valorizeAll(fromDateTime,productCategoryId);
|
|
||||||
response.setNotify("Recalcul Terminé");
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
TraceBackService.trace(response, e);
|
TraceBackService.trace(response, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
public void showLines(ActionRequest request, ActionResponse response) {
|
public void showLines(ActionRequest request, ActionResponse response) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import com.axelor.rpc.ActionResponse;
|
|||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -83,32 +84,50 @@ public class SupplychainBatchController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void massGenerationMove(ActionRequest request, ActionResponse response) {
|
public void massGenerationMove(ActionRequest request, ActionResponse response) {
|
||||||
|
|
||||||
|
List<Long> ids;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Long> ids =
|
List<?> rawIds = (List<?>) request.getContext().get("_ids");
|
||||||
(List)
|
|
||||||
(((List) request.getContext().get("_ids"))
|
|
||||||
.stream()
|
|
||||||
.filter(ObjectUtils::notEmpty)
|
|
||||||
.map(input -> Long.parseLong(input.toString()))
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
List<Long> moveList = Beans.get(AccountingCutOffServiceImpl.class).massGenerationMove(ids);
|
|
||||||
|
|
||||||
if (moveList != null && !moveList.isEmpty()) {
|
ids =
|
||||||
|
rawIds.stream()
|
||||||
|
.filter(ObjectUtils::notEmpty)
|
||||||
|
.map(id -> Long.parseLong(id.toString()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
TraceBackService.trace(response, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<Long>> result =
|
||||||
|
Beans.get(AccountingCutOffServiceImpl.class).massGenerationMove(ids);
|
||||||
|
|
||||||
|
List<Long> success = result.get("success");
|
||||||
|
List<Long> failed = result.get("failed");
|
||||||
|
|
||||||
|
if (!success.isEmpty()) {
|
||||||
response.setView(
|
response.setView(
|
||||||
ActionView.define(I18n.get(IExceptionMessage.MOVE_TEMPLATE_3))
|
ActionView.define(I18n.get(IExceptionMessage.MOVE_TEMPLATE_3))
|
||||||
.model(Move.class.getName())
|
.model(Move.class.getName())
|
||||||
.add("grid", "move-grid")
|
.add("grid", "move-grid")
|
||||||
.add("form", "move-form")
|
.add("form", "move-form")
|
||||||
.domain("self.id in (" + Joiner.on(",").join(moveList) + ")")
|
.domain("self.id in (" + Joiner.on(",").join(success) + ")")
|
||||||
.map());
|
.map());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
TraceBackService.trace(response, e);
|
if (!failed.isEmpty()) {
|
||||||
|
response.setFlash(
|
||||||
|
String.format(
|
||||||
|
"%d stock moves skipped due to configuration issues: %s",
|
||||||
|
failed.size(),
|
||||||
|
Joiner.on(", ").join(failed)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void generateInventoryLineMove(ActionRequest request, ActionResponse response) {
|
public void generateInventoryLineMove(ActionRequest request, ActionResponse response) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<many-to-one name="purchaseOrderLine" ref="com.axelor.apps.purchase.db.PurchaseOrderLine"/>
|
<many-to-one name="purchaseOrderLine" ref="com.axelor.apps.purchase.db.PurchaseOrderLine"/>
|
||||||
<many-to-one name="purchaseRequestLine" ref="com.axelor.apps.purchase.db.PurchaseRequestLine"/>
|
<many-to-one name="purchaseRequestLine" ref="com.axelor.apps.purchase.db.PurchaseRequestLine"/>
|
||||||
<many-to-one name="stockMoveLine" ref="com.axelor.apps.stock.db.StockMoveLine"/>
|
<many-to-one name="stockMoveLine" ref="com.axelor.apps.stock.db.StockMoveLine"/>
|
||||||
|
<many-to-one name="saleOrderLine" ref="com.axelor.apps.sale.db.SaleOrderLine"/>
|
||||||
<decimal name="budgetAmountAvailable"/>
|
<decimal name="budgetAmountAvailable"/>
|
||||||
<string name="description" title="Description"/>
|
<string name="description" title="Description"/>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
<entity name="Partner" lang="java">
|
<entity name="Partner" lang="java">
|
||||||
<one-to-many name="supplierRatingList" title="Supplier Rating List" ref="com.axelor.apps.supplychain.db.SupplierRating" mappedBy="supplierPartner"/>
|
<one-to-many name="supplierRatingList" title="Supplier Rating List" ref="com.axelor.apps.supplychain.db.SupplierRating" mappedBy="supplierPartner"/>
|
||||||
|
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic account"/>
|
||||||
|
<many-to-one name="analyticAxis" ref="com.axelor.apps.account.db.AnalyticAxis" title="Analytic axis" />
|
||||||
</entity>
|
</entity>
|
||||||
|
|
||||||
</domain-models>
|
</domain-models>
|
||||||
@@ -12,6 +12,10 @@
|
|||||||
<boolean name="usableOnSaleOrder" title="Usable on sale order" />
|
<boolean name="usableOnSaleOrder" title="Usable on sale order" />
|
||||||
<boolean name="isNotInCalculStock" title="Don't take in consideration for the stock calcul" />
|
<boolean name="isNotInCalculStock" title="Don't take in consideration for the stock calcul" />
|
||||||
<boolean name="isNotInMrp" title="Don't take in consideration on MRP" />
|
<boolean name="isNotInMrp" title="Don't take in consideration on MRP" />
|
||||||
|
<boolean name="usableOnImmobilisation" title="Usable on immobilisation" />
|
||||||
|
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic account"/>
|
||||||
|
<many-to-one name="analyticAxis" ref="com.axelor.apps.account.db.AnalyticAxis" title="Analytic axis" />
|
||||||
|
|
||||||
|
|
||||||
</entity>
|
</entity>
|
||||||
</domain-models>
|
</domain-models>
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic Acc."/>
|
<many-to-one name="analyticAccount" ref="com.axelor.apps.account.db.AnalyticAccount" title="Analytic Acc."/>
|
||||||
<many-to-one name="analyticAxis" ref="com.axelor.apps.account.db.AnalyticAxis" title="Analytic axis" />
|
<many-to-one name="analyticAxis" ref="com.axelor.apps.account.db.AnalyticAxis" title="Analytic axis" />
|
||||||
|
|
||||||
|
<decimal name="budgetDistributionSumAmount" title="Total amount attributed"/>
|
||||||
|
<one-to-many name="budgetDistributionList" ref="com.axelor.apps.account.db.BudgetDistribution" title="Budget Distribution" mappedBy="stockMoveLine"/>
|
||||||
|
|
||||||
<finder-method name="findAllBySaleOrder"
|
<finder-method name="findAllBySaleOrder"
|
||||||
using="com.axelor.apps.sale.db.SaleOrder:saleOrder" all="true"
|
using="com.axelor.apps.sale.db.SaleOrder:saleOrder" all="true"
|
||||||
|
|||||||
@@ -2,25 +2,14 @@ package com.axelor.apps.supplychain;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.axelor.app.AxelorModule;
|
import com.axelor.app.AxelorModule;
|
||||||
import com.axelor.apps.base.db.repo.ProductRepository;
|
import com.axelor.apps.base.db.repo.ProductRepository;
|
||||||
import com.axelor.apps.base.module.AdminModule;
|
import com.axelor.apps.base.module.AdminModule;
|
||||||
import com.axelor.apps.base.module.BaseModule;
|
import com.axelor.apps.base.module.BaseModule;
|
||||||
import com.axelor.apps.base.service.ProductService;
|
|
||||||
import com.axelor.apps.base.service.ProductServiceImpl;
|
|
||||||
import com.axelor.apps.base.service.user.UserService;
|
|
||||||
import com.axelor.apps.message.module.MessageModule;
|
import com.axelor.apps.message.module.MessageModule;
|
||||||
import com.axelor.apps.stock.module.StockModule;
|
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
||||||
import com.axelor.apps.stock.service.StockMoveService;
|
|
||||||
import com.axelor.apps.supplychain.TestStockMove.MyModule;
|
import com.axelor.apps.supplychain.TestStockMove.MyModule;
|
||||||
import com.axelor.apps.tool.module.ToolModule;
|
import com.axelor.apps.tool.module.ToolModule;
|
||||||
import com.axelor.db.JPA;
|
|
||||||
import com.axelor.db.JpaModule;
|
import com.axelor.db.JpaModule;
|
||||||
import com.axelor.exception.AxelorException;
|
import com.axelor.exception.AxelorException;
|
||||||
import com.axelor.inject.Beans;
|
import com.axelor.inject.Beans;
|
||||||
@@ -29,10 +18,11 @@ import com.axelor.test.GuiceModules;
|
|||||||
import com.axelor.test.GuiceRunner;
|
import com.axelor.test.GuiceRunner;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.persist.Transactional;
|
import org.junit.BeforeClass;
|
||||||
import com.axelor.apps.stock.db.StockMove;
|
import org.junit.Test;
|
||||||
import com.axelor.apps.stock.db.repo.StockMoveRepository;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@RunWith(GuiceRunner.class)
|
@RunWith(GuiceRunner.class)
|
||||||
@GuiceModules({MyModule.class})
|
@GuiceModules({MyModule.class})
|
||||||
@@ -40,11 +30,9 @@ public class TestStockMove {
|
|||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
|
||||||
static ProductRepository productRepository;
|
static ProductRepository productRepository;
|
||||||
|
|
||||||
@Inject
|
@Inject public StockMoveRepository stockMoveRepository;
|
||||||
public StockMoveRepository stockMoveRepository;
|
|
||||||
|
|
||||||
public static class MyModule extends AxelorModule {
|
public static class MyModule extends AxelorModule {
|
||||||
|
|
||||||
@@ -61,15 +49,10 @@ protected final Logger log = LoggerFactory.getLogger(getClass());
|
|||||||
}
|
}
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUpBeforeClass() throws Exception {
|
public static void setUpBeforeClass() throws Exception {}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFunc() throws AxelorException {
|
public void testFunc() throws AxelorException {
|
||||||
assertNotNull(productRepository.all().fetch().get(0));
|
assertNotNull(productRepository.all().fetch().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MockQuery<T> {
|
||||||
|
|
||||||
|
private List<T> data;
|
||||||
|
|
||||||
|
public MockQuery(List<T> data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MockQuery<T> filter(String s, Object... params) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MockQuery<T> order(String s) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> fetch() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T fetchOne() {
|
||||||
|
return data.isEmpty() ? null : data.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
package com.axelor.apps.supplychain.service;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import com.axelor.apps.base.db.Company;
|
||||||
|
import com.axelor.apps.base.db.Product;
|
||||||
|
import com.axelor.apps.base.service.PriceListService;
|
||||||
|
import com.axelor.apps.base.service.UnitConversionService;
|
||||||
|
import com.axelor.apps.base.service.app.AppBaseService;
|
||||||
|
import com.axelor.apps.base.service.tax.AccountManagementService;
|
||||||
|
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
|
||||||
|
import com.axelor.apps.purchase.service.PurchaseOrderLineService;
|
||||||
|
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.repo.StockMoveLineRepository;
|
||||||
|
import com.axelor.apps.stock.db.repo.TrackingNumberRepository;
|
||||||
|
import com.axelor.apps.stock.service.StockLocationLineService;
|
||||||
|
import com.axelor.apps.stock.service.StockMoveToolService;
|
||||||
|
import com.axelor.apps.stock.service.TrackingNumberService;
|
||||||
|
import com.axelor.apps.stock.service.WeightedAveragePriceService;
|
||||||
|
import com.axelor.db.Query;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
public class StockMoveLineServiceSupplychainImplTest {
|
||||||
|
|
||||||
|
@Mock private StockMoveLineRepository stockMoveLineRepo;
|
||||||
|
@Mock private StockLocationLineService stockLocationLineService;
|
||||||
|
@Mock private AppBaseService appBaseService;
|
||||||
|
|
||||||
|
// Additional required dependencies
|
||||||
|
@Mock private TrackingNumberService trackingNumberService;
|
||||||
|
@Mock private StockMoveToolService stockMoveToolService;
|
||||||
|
@Mock private UnitConversionService unitConversionService;
|
||||||
|
@Mock private WeightedAveragePriceService weightedAveragePriceService;
|
||||||
|
@Mock private TrackingNumberRepository trackingNumberRepo;
|
||||||
|
@Mock private AccountManagementService accountManagementService;
|
||||||
|
@Mock private PurchaseOrderLineRepository purchaseOrderLineRepo;
|
||||||
|
@Mock private PurchaseOrderLineService purchaseOrderLineService;
|
||||||
|
@Mock private PriceListService priceListService;
|
||||||
|
|
||||||
|
private StockMoveLineServiceSupplychainImpl service;
|
||||||
|
private MockedStatic<Beans> beansMock;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
when(appBaseService.getNbDecimalDigitForUnitPrice()).thenReturn(2);
|
||||||
|
|
||||||
|
beansMock = mockStatic(Beans.class);
|
||||||
|
beansMock
|
||||||
|
.when(() -> Beans.get(StockLocationLineService.class))
|
||||||
|
.thenReturn(stockLocationLineService);
|
||||||
|
beansMock.when(() -> Beans.get(StockMoveLineRepository.class)).thenReturn(stockMoveLineRepo);
|
||||||
|
|
||||||
|
service =
|
||||||
|
new StockMoveLineServiceSupplychainImpl(
|
||||||
|
trackingNumberService,
|
||||||
|
appBaseService,
|
||||||
|
null,
|
||||||
|
stockMoveToolService,
|
||||||
|
stockMoveLineRepo,
|
||||||
|
stockLocationLineService,
|
||||||
|
unitConversionService,
|
||||||
|
weightedAveragePriceService,
|
||||||
|
trackingNumberRepo,
|
||||||
|
accountManagementService,
|
||||||
|
purchaseOrderLineRepo,
|
||||||
|
purchaseOrderLineService,
|
||||||
|
priceListService);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to invoke private method computeWap()
|
||||||
|
private BigDecimal callComputeWap(
|
||||||
|
BigDecimal oldQty,
|
||||||
|
BigDecimal oldWap,
|
||||||
|
BigDecimal incomingQty,
|
||||||
|
BigDecimal incomingPrice,
|
||||||
|
int digits)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
Method m =
|
||||||
|
StockMoveLineServiceSupplychainImpl.class.getDeclaredMethod(
|
||||||
|
"computeWap",
|
||||||
|
BigDecimal.class,
|
||||||
|
BigDecimal.class,
|
||||||
|
BigDecimal.class,
|
||||||
|
BigDecimal.class,
|
||||||
|
int.class);
|
||||||
|
|
||||||
|
m.setAccessible(true);
|
||||||
|
return (BigDecimal) m.invoke(service, oldQty, oldWap, incomingQty, incomingPrice, digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to invoke private boolean methods
|
||||||
|
private boolean callBooleanMethod(String methodName, StockMoveLine line) throws Exception {
|
||||||
|
Method m =
|
||||||
|
StockMoveLineServiceSupplychainImpl.class.getDeclaredMethod(
|
||||||
|
methodName, StockMoveLine.class);
|
||||||
|
m.setAccessible(true);
|
||||||
|
return (boolean) m.invoke(service, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Test
|
||||||
|
public void testComputeWapIncoming() throws Exception {
|
||||||
|
BigDecimal wap =
|
||||||
|
callComputeWap(
|
||||||
|
new BigDecimal("10"),
|
||||||
|
new BigDecimal("20"),
|
||||||
|
new BigDecimal("5"),
|
||||||
|
new BigDecimal("30"),
|
||||||
|
2);
|
||||||
|
|
||||||
|
assertEquals("23.33", wap.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Test
|
||||||
|
public void testOutgoingUsesExistingWap() throws Exception {
|
||||||
|
StockMove move = new StockMove();
|
||||||
|
|
||||||
|
StockLocation from = new StockLocation();
|
||||||
|
from.setExcludeValorisation(false);
|
||||||
|
StockLocation to = new StockLocation();
|
||||||
|
to.setTypeSelect(2); // virtual → outgoing
|
||||||
|
move.setFromStockLocation(from);
|
||||||
|
move.setToStockLocation(to);
|
||||||
|
|
||||||
|
StockMoveLine line = new StockMoveLine();
|
||||||
|
line.setStockMove(move);
|
||||||
|
|
||||||
|
boolean outgoing = callBooleanMethod("isOutgoing", line);
|
||||||
|
|
||||||
|
assertTrue(outgoing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Test
|
||||||
|
public void testIncomingFromNc1() throws Exception {
|
||||||
|
StockMove move = new StockMove();
|
||||||
|
|
||||||
|
StockLocation from = new StockLocation();
|
||||||
|
from.setExcludeValorisation(true);
|
||||||
|
StockLocation to = new StockLocation();
|
||||||
|
to.setExcludeValorisation(false);
|
||||||
|
move.setFromStockLocation(from);
|
||||||
|
move.setToStockLocation(to);
|
||||||
|
|
||||||
|
StockMoveLine line = new StockMoveLine();
|
||||||
|
line.setStockMove(move);
|
||||||
|
|
||||||
|
assertTrue(callBooleanMethod("isIncoming", line));
|
||||||
|
assertFalse(callBooleanMethod("isOutgoing", line));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Test
|
||||||
|
public void testOutgoingToNc1() throws Exception {
|
||||||
|
StockMove move = new StockMove();
|
||||||
|
|
||||||
|
StockLocation from = new StockLocation();
|
||||||
|
from.setExcludeValorisation(false);
|
||||||
|
StockLocation to = new StockLocation();
|
||||||
|
to.setExcludeValorisation(true);
|
||||||
|
move.setFromStockLocation(from);
|
||||||
|
move.setToStockLocation(to);
|
||||||
|
|
||||||
|
StockMoveLine line = new StockMoveLine();
|
||||||
|
line.setStockMove(move);
|
||||||
|
|
||||||
|
assertTrue(callBooleanMethod("isOutgoing", line));
|
||||||
|
assertFalse(callBooleanMethod("isIncoming", line));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Test
|
||||||
|
public void testInitialWapFromLastMovement() throws Exception {
|
||||||
|
Product p = new Product();
|
||||||
|
p.setId(10L);
|
||||||
|
|
||||||
|
Company company = new Company();
|
||||||
|
|
||||||
|
LocalDate start = LocalDate.of(2024, 1, 1);
|
||||||
|
|
||||||
|
StockMoveLine last = new StockMoveLine();
|
||||||
|
last.setWapPrice(new BigDecimal("55"));
|
||||||
|
|
||||||
|
// Mock Query
|
||||||
|
Query<StockMoveLine> query = mock(Query.class);
|
||||||
|
when(stockMoveLineRepo.all()).thenReturn(query);
|
||||||
|
when(query.fetch()).thenReturn(Arrays.asList(last));
|
||||||
|
|
||||||
|
Method getInitial =
|
||||||
|
StockMoveLineServiceSupplychainImpl.class.getDeclaredMethod(
|
||||||
|
"getInitialStateForPeriod", Product.class, LocalDate.class, Company.class);
|
||||||
|
getInitial.setAccessible(true);
|
||||||
|
|
||||||
|
Object state = getInitial.invoke(service, p, start, company);
|
||||||
|
|
||||||
|
// Access private field 'wap'
|
||||||
|
BigDecimal wap = (BigDecimal) state.getClass().getField("wap").get(state);
|
||||||
|
|
||||||
|
assertEquals("55", wap.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
@Test
|
||||||
|
public void testPeriodSequence() throws Exception {
|
||||||
|
StockMoveLine in1 =
|
||||||
|
mockMovement(false, false, false, false, new BigDecimal("10"), new BigDecimal("20"));
|
||||||
|
|
||||||
|
StockMoveLine out = mockMovement(false, false, false, true, new BigDecimal("4"), null);
|
||||||
|
|
||||||
|
StockMoveLine in2 =
|
||||||
|
mockMovement(false, false, false, false, new BigDecimal("6"), new BigDecimal("30"));
|
||||||
|
|
||||||
|
Query<StockMoveLine> q = mock(Query.class);
|
||||||
|
when(stockMoveLineRepo.all()).thenReturn(q);
|
||||||
|
when(q.fetch()).thenReturn(Arrays.asList(in1, out, in2));
|
||||||
|
|
||||||
|
BigDecimal wap1 =
|
||||||
|
callComputeWap(
|
||||||
|
BigDecimal.ZERO, BigDecimal.ZERO, new BigDecimal("10"), new BigDecimal("20"), 2);
|
||||||
|
|
||||||
|
assertEquals("20.00", wap1.toString());
|
||||||
|
|
||||||
|
BigDecimal wap2 =
|
||||||
|
callComputeWap(
|
||||||
|
new BigDecimal("6"),
|
||||||
|
new BigDecimal("20"),
|
||||||
|
new BigDecimal("6"),
|
||||||
|
new BigDecimal("30"),
|
||||||
|
2);
|
||||||
|
|
||||||
|
assertEquals("25.00", wap2.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private StockMoveLine mockMovement(
|
||||||
|
boolean fromNc1,
|
||||||
|
boolean toNc1,
|
||||||
|
boolean incomingVirtual,
|
||||||
|
boolean outgoingVirtual,
|
||||||
|
BigDecimal qty,
|
||||||
|
BigDecimal price) {
|
||||||
|
|
||||||
|
StockMove move = new StockMove();
|
||||||
|
|
||||||
|
StockLocation from = new StockLocation();
|
||||||
|
from.setExcludeValorisation(fromNc1);
|
||||||
|
from.setTypeSelect(incomingVirtual ? 2 : 0);
|
||||||
|
|
||||||
|
StockLocation to = new StockLocation();
|
||||||
|
to.setExcludeValorisation(toNc1);
|
||||||
|
to.setTypeSelect(outgoingVirtual ? 2 : 0);
|
||||||
|
|
||||||
|
move.setFromStockLocation(from);
|
||||||
|
move.setToStockLocation(to);
|
||||||
|
|
||||||
|
StockMoveLine line = new StockMoveLine();
|
||||||
|
line.setStockMove(move);
|
||||||
|
line.setRealQty(qty);
|
||||||
|
if (price != null) line.setUnitPriceUntaxed(price);
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user