@Inject
  public MrpLineServiceImpl(
      GeneralService generalService,
      UserService userService,
      PurchaseOrderServiceSupplychainImpl purchaseOrderServiceSupplychainImpl,
      PurchaseOrderLineService purchaseOrderLineService,
      PurchaseOrderRepository purchaseOrderRepo,
      MinStockRulesService minStockRulesService) {

    this.purchaseOrderServiceSupplychainImpl = purchaseOrderServiceSupplychainImpl;
    this.purchaseOrderLineService = purchaseOrderLineService;
    this.purchaseOrderRepo = purchaseOrderRepo;
    this.minStockRulesService = minStockRulesService;

    this.today = generalService.getTodayDate();
    this.user = userService.getUser();
  }
  @Inject
  public PaymentScheduleExportService(
      MoveService moveService,
      MoveRepository moveRepo,
      MoveLineService moveLineServices,
      MoveLineRepository moveLineRepo,
      ReconcileService reconcileService,
      SequenceService sequenceService,
      PaymentModeService paymentModeService,
      CfonbExportService cfonbExportService,
      PaymentService paymentService,
      BlockingService blockingService,
      AccountConfigService accountConfigService,
      PaymentScheduleLineRepository paymentScheduleLineRepo,
      DirectDebitManagementRepository directDebitManagementRepo,
      InvoiceService invoiceService,
      InvoiceRepository invoiceRepo,
      GeneralService generalService,
      PartnerService partnerService) {

    this.moveService = moveService;
    this.moveRepo = moveRepo;
    this.moveLineServices = moveLineServices;
    this.moveLineRepo = moveLineRepo;
    this.reconcileService = reconcileService;
    this.sequenceService = sequenceService;
    this.paymentModeService = paymentModeService;
    this.cfonbExportService = cfonbExportService;
    this.paymentService = paymentService;
    this.blockingService = blockingService;
    this.accountConfigService = accountConfigService;
    this.paymentScheduleLineRepo = paymentScheduleLineRepo;
    this.directDebitManagementRepo = directDebitManagementRepo;
    this.invoiceService = invoiceService;
    this.invoiceRepo = invoiceRepo;
    this.partnerService = partnerService;

    this.today = generalService.getTodayDate();
  }
  /**
   * Permet de déréconcilier
   *
   * @param reconcile Une reconciliation
   * @return L'etat de la réconciliation
   * @throws AxelorException
   */
  @Transactional(rollbackOn = {AxelorException.class, Exception.class})
  public String unreconcile(Reconcile reconcile) throws AxelorException {

    LOG.debug("In unreconcile ....");
    LOG.debug("Credit .... {} " + reconcile.getLineCredit().getAmountPaid());
    LOG.debug("Debit .... {}" + reconcile.getLineDebit().getAmountPaid());

    if (reconcile.getState().equals("2")) {
      if (reconcile.getLineCredit() != null && reconcile.getLineDebit() != null) {
        // Change the state
        reconcile.setState("3");
        // Add the reconciled amount to the reconciled amount in the move line
        reconcile
            .getLineCredit()
            .setAmountPaid(
                reconcile.getLineCredit().getAmountPaid().subtract(reconcile.getAmount()));
        reconcile
            .getLineDebit()
            .setAmountPaid(
                reconcile.getLineDebit().getAmountPaid().subtract(reconcile.getAmount()));

        // Update amount remaining on invoice or refund
        if (reconcile.getLineDebit().getMove().getInvoice() != null) {
          reconcile
              .getLineDebit()
              .getMove()
              .getInvoice()
              .setInTaxTotalRemaining(
                  ms.getInTaxTotalRemaining(
                      reconcile.getLineDebit().getMove().getInvoice(),
                      reconcile.getLineDebit().getMove().getInvoice().getPartnerAccount()));
        }
        if (reconcile.getLineCredit().getMove().getInvoice() != null) {
          reconcile
              .getLineCredit()
              .getMove()
              .getInvoice()
              .setInTaxTotalRemaining(
                  ms.getInTaxTotalRemaining(
                      reconcile.getLineCredit().getMove().getInvoice(),
                      reconcile.getLineCredit().getMove().getInvoice().getPartnerAccount()));
        }

        reconcile.save();
        LOG.debug("End Unreconcile.");
        return reconcile.getState();
      } else {
        throw new AxelorException(
            String.format(
                "%s :\nReconciliation %s: Merci de renseigner les lignes d'écritures concernées.",
                GeneralService.getExceptionAccountingMsg(), reconcile.getFullName()),
            IException.CONFIGURATION_ERROR);
      }
    } else {
      throw new AxelorException(
          String.format(
              "%s :\nReconciliation %s: Vous ne pouvez pas délétrer en dehors de l'état 'Confirmée'.",
              GeneralService.getExceptionAccountingMsg(), reconcile.getFullName()),
          IException.CONFIGURATION_ERROR);
    }
  }
  @Inject
  public ReconcileService() {

    this.today = GeneralService.getTodayDate();
  }
  /**
   * Solder le trop-perçu si il respect les règles de seuil
   *
   * @param creditMoveLine
   * @param company
   * @throws AxelorException
   */
  public void balanceCredit(MoveLine creditMoveLine, Company company, boolean updateCustomerAccount)
      throws AxelorException {
    if (creditMoveLine != null) {
      BigDecimal creditAmountRemaining = creditMoveLine.getAmountRemaining();
      LOG.debug("Montant à payer / à lettrer au crédit : {}", creditAmountRemaining);

      if (creditAmountRemaining.compareTo(BigDecimal.ZERO) > 0) {
        if (creditAmountRemaining.plus().compareTo(company.getThresholdDistanceFromRegulation())
            < 0) {

          LOG.debug("Seuil respecté");

          Partner partner = creditMoveLine.getPartner();
          Account account = creditMoveLine.getAccount();

          if (company.getMiscOperationJournal() == null) {
            throw new AxelorException(
                String.format(
                    "%s :\n Veuillez configurer un journal des O.D. pour la société %s",
                    GeneralService.getExceptionAccountingMsg(), company.getName()),
                IException.CONFIGURATION_ERROR);
          }

          Move newMove =
              ms.createMove(company.getMiscOperationJournal(), company, null, partner, null, false);

          // Création de la ligne au crédit
          MoveLine newCreditMoveLine =
              mls.createMoveLine(
                  newMove,
                  partner,
                  company.getCashPositionVariationAccount(),
                  creditAmountRemaining,
                  false,
                  false,
                  today,
                  2,
                  false,
                  false,
                  false,
                  null);

          // Création de la ligne au débit
          MoveLine newDebitMoveLine =
              mls.createMoveLine(
                  newMove,
                  partner,
                  account,
                  creditAmountRemaining,
                  true,
                  false,
                  today,
                  1,
                  false,
                  false,
                  false,
                  null);

          newMove.getMoveLineList().add(newCreditMoveLine);
          newMove.getMoveLineList().add(newDebitMoveLine);
          ms.validateMove(newMove, updateCustomerAccount);
          newMove.save();

          // Création de la réconciliation
          Reconcile newReconcile =
              this.createReconcile(newDebitMoveLine, creditMoveLine, creditAmountRemaining);
          this.confirmReconcile(newReconcile, updateCustomerAccount);
          newReconcile.save();
        }
      }
    }
  }
  /**
   * Procédure permettant de gérer les écarts de règlement, check sur la case à cocher 'Peut être
   * soldé' Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
   * transitoire si le seuil est respecté
   *
   * @param reconcile Une reconciliation
   * @throws AxelorException
   */
  @Transactional(rollbackOn = {AxelorException.class, Exception.class})
  public void canBeZeroBalance(Reconcile reconcile) throws AxelorException {

    MoveLine debitMoveLine = reconcile.getLineDebit();

    BigDecimal debitAmountRemaining = debitMoveLine.getAmountRemaining();
    LOG.debug("Montant à payer / à lettrer au débit : {}", debitAmountRemaining);
    if (debitAmountRemaining.compareTo(BigDecimal.ZERO) > 0) {
      Company company = reconcile.getLineDebit().getMove().getCompany();
      if (debitAmountRemaining.plus().compareTo(company.getThresholdDistanceFromRegulation()) < 0
          || reconcile.getMustBeZeroBalanceOk()) {

        LOG.debug("Seuil respecté");

        Partner partner = debitMoveLine.getPartner();
        Account account = debitMoveLine.getAccount();

        if (company.getMiscOperationJournal() == null) {
          throw new AxelorException(
              String.format(
                  "%s :\n Veuillez configurer un journal des O.D. pour la société %s",
                  GeneralService.getExceptionAccountingMsg(), company.getName()),
              IException.CONFIGURATION_ERROR);
        }

        Move newMove =
            ms.createMove(company.getMiscOperationJournal(), company, null, partner, null, false);

        // Création de la ligne au crédit
        MoveLine newCreditMoveLine =
            mls.createMoveLine(
                newMove,
                partner,
                account,
                debitAmountRemaining,
                false,
                false,
                today,
                1,
                false,
                false,
                false,
                null);

        // Création de la ligne au debit
        MoveLine newDebitMoveLine =
            mls.createMoveLine(
                newMove,
                partner,
                company.getCashPositionVariationAccount(),
                debitAmountRemaining,
                true,
                false,
                today,
                2,
                false,
                false,
                false,
                null);

        newMove.getMoveLineList().add(newCreditMoveLine);
        newMove.getMoveLineList().add(newDebitMoveLine);
        ms.validateMove(newMove);
        newMove.save();

        // Création de la réconciliation
        Reconcile newReconcile =
            this.createReconcile(debitMoveLine, newCreditMoveLine, debitAmountRemaining);
        this.confirmReconcile(newReconcile);
        newReconcile.save();
      }
    }

    reconcile.setCanBeZeroBalanceOk(false);
    LOG.debug("Fin de la gestion des écarts de règlement");
  }
  /**
   * Permet de confirmer une réconciliation On ne peut réconcilier que des moveLine ayant le même
   * compte
   *
   * @param reconcile Une reconciliation
   * @return L'etat de la reconciliation
   * @throws AxelorException
   */
  @Transactional(rollbackOn = {AxelorException.class, Exception.class})
  public String confirmReconcile(Reconcile reconcile, boolean updateCustomerAccount)
      throws AxelorException {

    LOG.debug("In confirmReconcile ....");
    if (reconcile != null) {
      if (reconcile.getLineCredit() != null && reconcile.getLineDebit() != null) {
        // Check if move lines accounts are the same (debit and credit)
        LOG.debug(
            "Compte ligne de credit : {} , Compte ligne de debit : {}",
            reconcile.getLineCredit().getAccount(),
            reconcile.getLineDebit().getAccount());
        if (!reconcile.getLineCredit().getAccount().equals(reconcile.getLineDebit().getAccount())) {
          throw new AxelorException(
              String.format(
                  "%s :\nReconciliation %s: Les lignes d'écritures sélectionnées doivent concerner le même compte comptable.",
                  GeneralService.getExceptionAccountingMsg(), reconcile.getFullName()),
              IException.CONFIGURATION_ERROR);
        }
        // Check if the amount to reconcile is != zero
        else if (reconcile.getAmount() == null
            || reconcile.getAmount().compareTo(BigDecimal.ZERO) == 0) {
          throw new AxelorException(
              String.format(
                  "%s :\nReconciliation %s: Le montant réconcilié doit être différent de zéro.",
                  GeneralService.getExceptionAccountingMsg(), reconcile.getFullName()),
              IException.INCONSISTENCY);

        } else {
          // Check if the amount to reconcile is less than the 2 moves credit and debit
          LOG.debug("AMOUNT  : : : {}", reconcile.getAmount());
          LOG.debug(
              "credit - paid  : : : {}",
              reconcile
                  .getLineCredit()
                  .getCredit()
                  .subtract(reconcile.getLineCredit().getAmountPaid()));
          LOG.debug(
              "debit - paid  : : : {}",
              reconcile
                  .getLineDebit()
                  .getDebit()
                  .subtract(reconcile.getLineDebit().getAmountPaid()));

          if ((reconcile
                      .getAmount()
                      .compareTo(
                          reconcile
                              .getLineCredit()
                              .getCredit()
                              .subtract(reconcile.getLineCredit().getAmountPaid()))
                  > 0
              || (reconcile
                      .getAmount()
                      .compareTo(
                          reconcile
                              .getLineDebit()
                              .getDebit()
                              .subtract(reconcile.getLineDebit().getAmountPaid()))
                  > 0))) {
            throw new AxelorException(
                String.format(
                    "%s :\nReconciliation %s: Le montant réconcilié doit être inférieur ou égale au montant restant à réconcilier des lignes d'écritures.",
                    GeneralService.getExceptionAccountingMsg(), reconcile.getFullName()),
                IException.INCONSISTENCY);

          } else {

            // Add the reconciled amount to the reconciled amount in the move line
            reconcile
                .getLineCredit()
                .setAmountPaid(
                    reconcile.getLineCredit().getAmountPaid().add(reconcile.getAmount()));
            reconcile
                .getLineDebit()
                .setAmountPaid(reconcile.getLineDebit().getAmountPaid().add(reconcile.getAmount()));

            // Update amount remaining on invoice or refund
            if (reconcile.getLineDebit().getMove().getInvoice() != null) {
              reconcile
                  .getLineDebit()
                  .getMove()
                  .getInvoice()
                  .setInTaxTotalRemaining(
                      ms.getInTaxTotalRemaining(
                          reconcile.getLineDebit().getMove().getInvoice(),
                          reconcile.getLineDebit().getMove().getInvoice().getPartnerAccount()));
            }
            if (reconcile.getLineCredit().getMove().getInvoice() != null) {
              reconcile
                  .getLineCredit()
                  .getMove()
                  .getInvoice()
                  .setInTaxTotalRemaining(
                      ms.getInTaxTotalRemaining(
                          reconcile.getLineCredit().getMove().getInvoice(),
                          reconcile.getLineCredit().getMove().getInvoice().getPartnerAccount()));
            }

            this.updatePartnerAccountingSituation(reconcile, updateCustomerAccount);

            // Change the state
            reconcile.setState("2");

            if (reconcile.getCanBeZeroBalanceOk()) {
              // Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
              // transitoire si le seuil est respecté
              canBeZeroBalance(reconcile);
            }

            reconcile.save();

            LOG.debug("End confirmReconcile.");
            return reconcile.getState();
          }
        }
      } else {
        throw new AxelorException(
            String.format(
                "%s :\nReconciliation %s: Merci de renseigner les lignes d'écritures concernées.",
                GeneralService.getExceptionAccountingMsg(), reconcile.getFullName()),
            IException.CONFIGURATION_ERROR);
      }
    } else {
      LOG.debug("***************** ****** *** NO ID *** ****** **********************");
      return null;
    }
  }