/**
   * Méthode permettant de lettrer une écriture au débit avec une écriture au crédit
   *
   * @param debitMoveLine
   * @param creditMoveLine
   * @throws AxelorException
   */
  public void reconcile(
      MoveLine debitMoveLine, MoveLine creditMoveLine, boolean updateCustomerAccount)
      throws AxelorException {

    BigDecimal amount = debitMoveLine.getAmountRemaining().min(creditMoveLine.getAmountRemaining());
    Reconcile reconcile = this.createReconcile(debitMoveLine, creditMoveLine, amount);
    this.confirmReconcile(reconcile, updateCustomerAccount);
  }
  /**
   * Procédure permettant d'exporter des factures
   *
   * @param company Une société
   * @param pse Un Export des prélèvement
   * @param pm Un mode de paiement
   * @throws AxelorException
   */
  @Transactional(rollbackOn = {AxelorException.class, Exception.class})
  public Invoice exportInvoice(
      MoveLine moveLine,
      List<MoveLine> moveLineList,
      Company company,
      long directDebitManagementMaxId)
      throws AxelorException {

    /**
     * Important : Doit être executé avant la méthode 'createPaymentMove()' afin de récupérer le
     * montant restant à prélever *
     */
    BigDecimal amountExported = moveLine.getAmountRemaining();

    this.testBankDetails(moveLine.getPartner());

    // creation d'une ecriture de paiement
    Invoice invoice =
        this.updateInvoice(
            moveLine,
            this.createPaymentMove(
                company, moveLine, company.getAccountConfig().getDirectDebitPaymentMode()),
            moveLineList,
            amountExported,
            directDebitManagementMaxId);

    invoiceRepo.save(invoice);

    return invoice;
  }
  public void createPaymentMoveLine(Move paymentMove, MoveLine moveLine, int ref)
      throws AxelorException {
    BigDecimal amountExported = moveLine.getAmountRemaining();

    // On assigne le montant exporté pour pouvoir l'utiliser lors de la création du fichier d'export
    // CFONB
    moveLine.setAmountExportedInDirectDebit(amountExported);

    // creation d'une ecriture de paiement

    log.debug("generateAllExportInvoice - Création de la première ligne d'écriture");
    String invoiceName = "";
    if (moveLine.getMove().getInvoice() != null) {
      invoiceName = moveLine.getMove().getInvoice().getInvoiceId();
    }
    MoveLine moveLineGenerated =
        moveLineServices.createMoveLine(
            paymentMove,
            moveLine.getPartner(),
            moveLine.getAccount(),
            amountExported,
            false,
            today,
            ref,
            invoiceName);

    paymentMove.getMoveLineList().add(moveLineGenerated);

    moveLineRepo.save(moveLineGenerated);

    // Lettrage de la ligne 411 avec la ligne 411 de la facture
    log.debug("Creation du lettrage de la ligne 411 avec la ligne 411 de la facture");

    reconcileService.reconcile(moveLine, moveLineGenerated);

    log.debug("generateAllExportInvoice - Sauvegarde de l'écriture");

    moveRepo.save(paymentMove);
  }
  /**
   * Procédure permettant de créer une écriture de paiement d'une facture
   *
   * @param company Une société
   * @param moveLine Une ligne d'écriture
   * @param pm Un mode de paiement
   * @param pse Un Export des prélèvement
   * @throws AxelorException
   */
  public Move createPaymentMove(Company company, MoveLine moveLine, PaymentMode paymentMode)
      throws AxelorException {

    log.debug("Create payment move");

    Move paymentMove =
        moveService
            .getMoveCreateService()
            .createMove(
                paymentModeService.getPaymentModeJournal(paymentMode, company),
                company,
                null,
                null,
                paymentMode);

    BigDecimal amountExported = moveLine.getAmountRemaining();

    this.createPaymentMoveLine(paymentMove, moveLine, 1);

    log.debug("Create payment move line");

    Account paymentModeAccount = paymentModeService.getCompanyAccount(paymentMode, company);

    String invoiceName = "";
    if (moveLine.getMove().getInvoice() != null) {
      invoiceName = moveLine.getMove().getInvoice().getInvoiceId();
    }
    MoveLine moveLineGenerated2 =
        moveLineServices.createMoveLine(
            paymentMove, null, paymentModeAccount, amountExported, true, today, 2, invoiceName);

    paymentMove.getMoveLineList().add(moveLineGenerated2);
    moveLineRepo.save(moveLineGenerated2);

    moveService.getMoveValidateService().validateMove(paymentMove);
    moveRepo.save(paymentMove);

    return paymentMove;
  }
  /**
   * 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");
  }