/**
   * Procédure permettant de récupérer l'objet de gestion déjà créé lors du prélèvement d'une autre
   * facture
   *
   * @param mlList La liste des lignes d'écriture de facture à prélever
   * @param ml Une ligne d'écriture de facture ) prélever
   * @return L'objet de gestion trouvé
   */
  public DirectDebitManagement getDirectDebitManagement(
      List<MoveLine> moveLineList, MoveLine ml, long directDebitManagementMaxId) {

    Partner partner = ml.getPartner();

    log.debug("Récupération de l'objet de prélèvement du tiers {}", partner.getFullName());

    List<MoveLine> moveLineListResult =
        moveLineRepo
            .all()
            .filter("self IN (?1) and self.partner = ?2", moveLineList, partner)
            .fetch();

    for (MoveLine moveLine : moveLineListResult) {
      Invoice invoice = cfonbExportService.getInvoice(moveLine);

      DirectDebitManagement directDebitManagement = invoice.getDirectDebitManagement();
      if (directDebitManagement != null
          && directDebitManagement.getId() > directDebitManagementMaxId) {

        log.debug("Objet de prélèvement trouvé : {} pour le tiers {}", partner.getFullName());
        return invoice.getDirectDebitManagement();
      }
    }

    log.debug("Aucun objet de prélèvement trouvé pour le tiers {}", partner.getFullName());

    return null;
  }
  @Override
  protected void process() {

    for (Invoice invoice : invoices(batch.getInvoiceBatch(), true)) {

      try {

        invoiceService.validate(invoiceRepo.find(invoice.getId()));
        updateInvoice(invoiceRepo.find(invoice.getId()));

      } catch (AxelorException e) {

        TraceBackService.trace(
            new AxelorException(
                String.format(I18n.get("Facture") + " %s", invoice.getInvoiceId()),
                e,
                e.getcategory()),
            IException.INVOICE_ORIGIN,
            batch.getId());
        incrementAnomaly();

      } catch (Exception e) {

        TraceBackService.trace(
            new Exception(String.format(I18n.get("Facture") + " %s", invoice.getInvoiceId()), e),
            IException.INVOICE_ORIGIN,
            batch.getId());
        incrementAnomaly();

      } finally {

        JPA.clear();
      }
    }
  }
  public void testBankDetails(Invoice invoice) throws AxelorException {
    BankDetails bankDetails = partnerService.getDefaultBankDetails(invoice.getPartner());

    if (bankDetails == null) {
      throw new AxelorException(
          String.format(
              I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_2),
              GeneralServiceImpl.EXCEPTION,
              invoice.getPartner().getName()),
          IException.CONFIGURATION_ERROR);
    } else {
      cfonbExportService.testBankDetailsField(bankDetails);
    }
  }
  /**
   * Methode permettant de mettre à jour les informations de la facture
   *
   * @param moveLine
   * @param paymentMove
   * @param pse
   * @param mlList
   * @return
   * @throws AxelorException
   */
  public Invoice updateInvoice(
      MoveLine moveLine,
      Move paymentMove,
      List<MoveLine> mlList,
      BigDecimal amountExported,
      long directDebitManagementMaxId)
      throws AxelorException {

    Invoice invoice = cfonbExportService.getInvoice(moveLine);

    this.testBankDetails(invoice);

    Company company = invoice.getCompany();

    // Mise à jour du champ 'Ecriture de paiement' sur la facture
    log.debug(
        "generateAllExportInvoice - Mise à jour du champ 'Ecriture de paiement' sur la facture");
    invoice.setPaymentMove(paymentMove);

    // Mise à jour du montant prélever
    invoice.setDirectDebitAmount(amountExported);

    // Mise à jour du Numéro de prélèvement sur la facture
    log.debug("Mise à jour du Numéro de prélèvement sur la facture");

    if (this.hasOtherInvoice(mlList, moveLine)) {
      DirectDebitManagement directDebitManagement =
          this.getDirectDebitManagement(mlList, moveLine, directDebitManagementMaxId);
      if (directDebitManagement == null) {
        directDebitManagement =
            this.createDirectDebitManagement(this.getDirectDebitSequence(company), company);
      }
      invoice.setDirectDebitManagement(directDebitManagement);
      invoice.setDebitNumber(null);
      directDebitManagement.getInvoiceSet().add(invoice);
      directDebitManagementRepo.save(directDebitManagement);
    } else {
      invoice.setDebitNumber(this.getDirectDebitSequence(company));
      invoice.setDirectDebitManagement(null);
    }
    return invoice;
  }
  public List<MoveLine> getInvoiceToExport(
      Company company, LocalDate scheduleDate, Currency currency) {

    List<MoveLine> moveLineInvoiceList = new ArrayList<MoveLine>();

    PaymentMode paymentMode = company.getAccountConfig().getDirectDebitPaymentMode();

    /**
     * Selection des lignes d'écritures dont : - l'état est validé - la société est celle
     * selectionnée sur l'objet export - le compte est lettrable - le montant restant à payer est
     * supérieur à 0 et débit supérieur à 0 (équivaut à une facture et non un avoir) - le mode de
     * règlement de la facture est en prélèvement - la date d'échéance est passée - la facture est
     * remplie sur l'écriture - la facture n'est pas selectionnée sur un échéancier
     */
    List<MoveLine> moveLineList =
        moveLineRepo
            .all()
            .filter(
                "self.move.statusSelect = ?1 AND self.exportedDirectDebitOk = 'false' "
                    + "AND self.move.company = ?2 "
                    + "AND self.account.reconcileOk = ?3 AND self.amountRemaining > 0 "
                    + "AND self.debit > 0 "
                    + "AND self.dueDate <= ?5 AND self.move.invoice IS NOT NULL "
                    + "AND self.move.invoice.paymentMode = ?4 "
                    + "AND self.move.invoice.schedulePaymentOk = 'false' "
                    + "AND self.move.invoice.currency = ?5",
                MoveRepository.STATUS_VALIDATED,
                company,
                true,
                paymentMode,
                currency)
            .fetch();

    // Ajout des factures
    for (MoveLine moveLine : moveLineList) {
      if (!this.isDebitBlocking(moveLine.getMove().getInvoice())) {
        moveLineInvoiceList.add(moveLine);
      }
    }

    // Récupération des factures rejetées
    List<Invoice> invoiceRejectList =
        invoiceRepo
            .all()
            .filter(
                "self.rejectMoveLine IS NOT NULL AND self.rejectMoveLine.amountRemaining > 0 AND self.rejectMoveLine.debit > 0"
                    + " AND self.paymentMode = ?1 AND self.company = ?2 AND self.rejectMoveLine.exportedDirectDebitOk = 'false' AND self.move.statusSelect = ?3"
                    + " AND self.rejectMoveLine.account.reconcileOk = 'true' "
                    + " AND self.rejectMoveLine.invoiceReject IS NOT NULL"
                    + " AND self.currency = ?4",
                paymentMode,
                company,
                MoveRepository.STATUS_VALIDATED,
                currency)
            .fetch();

    // Ajout des factures rejetées
    for (Invoice invoice : invoiceRejectList) {

      if (!this.isDebitBlocking(invoice)) {
        moveLineInvoiceList.add(invoice.getRejectMoveLine());
      }
    }

    return moveLineInvoiceList;
  }
  public boolean isDebitBlocking(Invoice invoice) {

    return blockingService.isDebitBlockingBlocking(invoice.getPartner(), invoice.getCompany());
  }