<?php

namespace Modules\TermeDePaiement\Controller;

use Entity\Model\CaLigne;
use Entity\Model\DaEntet;
use Entity\Model\DaLigne;
use Entity\Model\Fourniss;
use Entity\Model\TpEnt;
use Entity\Model\CaEntet;
use Entity\Model\TpEvt;
use Entity\Model\TpPevt;
use Entity\Model\TpPos;
use Entity\Model\TyEvtStp;
use Entity\Model\TpModeles;
use GuzzleHttp\Psr7\Response;
use Helpers\Log\LogSysteme;
use Helpers\Outil\ArrayHelper;
use Helpers\Outil\FloatHelper;
use Helpers\Pagination\PaginatorGestion;
use Helpers\User\User;
use Modules\Ajax\Repository\Listes;
use Modules\Commande\Repository\LigneCommande;
use Modules\Panier\Service\ValidationPanierService;
use Modules\Tables\MenuContextuel\EvenementTPContextuel;
use Modules\TermeDePaiement\Repository\TermPaieRepo;
use Modules\TermeDePaiement\Service\TermeDePaiementService;
use Skeleton\Controller\Controller;
use Helpers\Ariane\Ariane;
use Helpers\Trad\Trad;
use Helpers\Outil\Sql;
use Helpers\Parametres\Constante;
use Modules\DemandeAchat\MenuContextuel\GestionMenuContextuel as GestionMenuContextuelDemandeAchat;
use Modules\DemandeAchat\Repository\DemandeAchat;
use Modules\DemandeAchat\Repository\LigneDemandeAchat;
use Modules\Commande\MenuContextuel\GestionMenuContextuel;
use Modules\Commande\Repository\Commande;

use PDO;

class TermeDePaiementController extends Controller
{

    /**
     * Summary of listeUnitesDelai
     * @var string[]
     */
    private array $listeUnitesDelai;
    /**
     * Summary of listeUnitesDelaiForDB
     * @var string[]
     */
    private array $listeUnitesDelaiForDB;

    /**
     * Summary of parametrage
     * @var array<mixed>
     */
    private array $parametrage;

    public function init(): void
    {
        $trad                        = $this->getTranslationService();
        $this->listeUnitesDelai      = [
            'J' => $trad->t('Jours'),
            'M' => $trad->t('Mois'),
            'A' => $trad->t('Années'),
        ];
        $this->listeUnitesDelaiForDB = [
            'J' => '1',
            'M' => '2',
            'A' => '3',
            ''  => '',
        ];
        $this->parametrage           = [
            'AFFTTC' => Sql::paravrac($this->pdo, 'OXAPROC', 'AFFTTC') == 'O',
        ];
    }

    public function termeDePaiementAction(
        TermPaieRepo $termPaieRep,
        TermeDePaiementService $termeDePaiementService,
        Fourniss $fourniss,
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TyEvtStp $tyEvtStp,
        TpPos $tpPos,
        Commande $commandeRepo,
        ValidationPanierService $validationPanierService,
    ): string {
        $id      = $this->request->getAttribute('id');
        $post    = $this->request->getParsedBody();
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere');
        $trad    = $this->getTranslationService();

        $moduleForDB = match ($module) {
            'Commande'     => 'CA_ENTET',
            'DemandeAchat' => 'DA_ENTET',
            default        => $module
        };

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        // Récupération des TPs
        $tps = $tpEnt->findAll([
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);

        foreach ($tps as &$tp) {
            // TODO : merge queries
            $evts = $tpEvt->findAll([
                'NUM_TP'          => $tp['NUM_TP'],
                'NUM_CDE'         => $tp['NUM_CDE'],
                'TYPEOBJ'         => $moduleForDB,
                'CRITERE_REGROUP' => $critereRegroup,
            ]);
            if (\count($evts) > 0) {
                $mapTypeEvent = array_column(
                    $tyEvtStp->findAll([
                        'CODE_EVT' => array_column($evts, 'EVENEMENT'),
                    ]),
                    null,
                    'CODE_EVT',
                );

                $declencheurs = [];
                foreach ($evts as $evt) {
                    $type = $mapTypeEvent[$evt['EVENEMENT']];
                    if (!empty($type['LIB_EVT'])) {
                        $declencheurs[] = $trad->t($type['LIB_EVT']); // TODO: shoud be done in SQL
                    }
                }
                $tp['DECLENCHEUR'] = implode(', ', $declencheurs); // TODO: move to view
            }
        }
        unset($tp);

        // Mis en place de la strategie à adopter en fonction du module
        $strategy = $termeDePaiementService->getStrategy($module, $critereRegroup);

        $verifPourcTpGlobal = $strategy->verifPourcTp($id, $tps, [], $critereRegroup);

        // TODO: A voir si encore utilisé car les DA et les CDE passent par leurs propres module ?
        if ($module === 'DemandeAchat') {
            $purchaseRequest = (new DemandeAchat($this->pdo))
                ->demandeAchatEntete($id);

            $da = (new DemandeAchat($this->pdo))->getDaStatut($id);
            // On vérifie que la DA n'est ni terminé, ni refusé

            $purchaseRequest['menuContextuel'] = (new GestionMenuContextuelDemandeAchat(
                $this->pdo,
                $this->router,
                $this->getTranslationService(),
            ))->lightGenerate($purchaseRequest);
            $type                              = $module;
        } elseif ($module === 'Commande') {
            $commande = $commandeRepo->commandeEntete($id);

            $menuContextuel             = new GestionMenuContextuel($this->pdo, $this->router, $this->getTranslationService(), []);
            $commande['menuContextuel'] = $menuContextuel->lightGenerate($commande);
        }

        // Conditionnement divers affichage
        $codeFou = $strategy->getCodeFou($id);
        $RSFou   = $fourniss->find(['CODE' => $codeFou], ['RS'])['RS'] ?? '';

        $titre = match ($module) {
            /** @phpstan-ignore-next-line */
            'Commande'  => Trad::strBuild($trad->t('Liste des termes de paiement de la commande : @1@'), $id . (($commande['AVENANT'] ?? null) ? ' - ' . $commande['AVENANT'] : '')),
            'PanierDA'  => Trad::strBuild($trad->t("Liste des termes de paiement de la demande d'achat du fournisseur : @1@ (@2@)"), $RSFou, $codeFou),
            'PanierCDE' => Trad::strBuild($trad->t("Liste des termes de paiement de la commande du fournisseur : @1@ (@2@)"), $RSFou, $codeFou),
            // DemandeAchat
            default     => Trad::strBuild($trad->t('Liste des termes de paiement de la demande d\'achat : @1@'), $id),
        };

        $canEdit = match ($module) {
            'Commande'              => !in_array($commande['ETAT_CDE'] ?? '', ['E', 'V1', 'V2', 'L', 'S']),
            'PanierDA', 'PanierCDE' => true,
            // DemandeAchat
            default                 => !in_array($da['ETAT'] ?? '', ['R', 'T']),
        };

        $NO_DA = match ($module) {
            'Commande'              => 'CA_ENTET',
            'PanierDA', 'PanierCDE' => 'PANIER',
            // DemandeAchat
            default                 => 'DA_ENTET',
        };

        $inPanier = match ($module) {
            'PanierDA', 'PanierCDE' => true,
            default                 => false
        };

        // Gestions des fils d'arianes
        switch ($module) :
            case 'Commande':
                Ariane::generate(1, $trad->t('Termes de paiement'), $post);
                break;
            case 'PanierDA':
            case 'PanierCDE':
                Ariane::generate(1, $trad->t('Termes de paiement du panier'), $post);
                break;
            // DemandeAchat
            default:
                if ($_SESSION['navigation']['menuActive'] == 'eproc') {
                    Ariane::generate(1, $trad->t('Termes de paiement'), $post);
                    Ariane::setFocus($id);
                } else {
                    Ariane::generate(1, $trad->t('Termes de paiement'), $post);
                }
        endswitch;

        return $this->renderer->render('@TermeDePaiement/TermeDePaiement/termeDePaiement', [
            'NO_DA'         => $NO_DA,
            'id'            => $id,
            'critere'       => $critere,
            'post'          => $post,
            'tps'           => $tps,
            'devise'        => $strategy->getDevise($id),
            'MODULE'        => $module,
            'titre'         => $titre,
            'type'          => $type ?? 0,
            'commande'      => $commande ?? [],
            'da'            => $purchaseRequest ?? [],
            'canEdit'       => $canEdit,
            'verifPourcTp'  => $verifPourcTpGlobal,
            'listDelaiFact' => $this->listeUnitesDelaiForDB,
            'inPanier'      => $inPanier,
        ]);
    }

    /**
     * Summary of ajoutTermeDePaiementAction
     * @param array< mixed> $post
     * @return string
     */
    public function ajoutTermeDePaiementAction(?array $post = null): string
    {
        $id      = $this->request->getAttribute('id');
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere');
        $post    = $post ?? $this->request->getParsedBody();
        $NO_DA   = '';

        if (isset($post['encoded']) && $post['encoded'] != '') {
            if (isset($post['selected_evt'])) {
                $newEvts = $post['selected_evt'];
            }
            $post = array_merge($post, json_decode($post['encoded'], true));
            unset($post['selected_evt']);
            if (isset($newEvts)) {
                foreach ($newEvts as $evt) {
                    $evt = (new TyEvtStp($this->pdo))->find(['CODE_EVT' => $evt]);
                    if ($evt != null) {
                        $post['selected_evt'][] = $evt;
                    }
                }
            }
            unset($post['encoded']);
        }

        $trad = $this->getTranslationService();

        if ($module === 'DemandeAchat') {
            $titre        = Trad::strBuild($trad->t('Terme de paiement de la demande d\'achat : @1@'), $id);
            $daLigne      = (new LigneDemandeAchat($this->pdo))->getLigneDemandeAchat($id);
            $demandeAchat = (new DemandeAchat($this->pdo))->demandeAchatEntete($id);
            $NO_DA        = 'DA_ENTET';
        } elseif ($module === 'Commande') {
            $commande = (new Commande($this->pdo))->commandeEntete($id);
            $titre    = Trad::strBuild($trad->t('Terme de paiement de la commande : @1@'), (($commande['AVENANT'] ?? null) ? ' - ' . $commande['AVENANT'] : ''));
            $caLigne  = (new LigneCommande($this->pdo))->getLigneCommande($id);
            foreach ($caLigne as &$ligne) {
                $ligne['PU'] = number_format(floatval($ligne['PU']), 2);
            }
            $NO_DA = 'CA_ENTET';
        } else {
            if (isset((User::getUser())->getPanier()['XML'])) {
                $xmlName                    = (User::getUser())->getPanier()['XML'];
                $xmlContent                 = \Helpers\Fichier\Fichier::getContentFile($xmlName);
                $produitXml                 = new \SimpleXMLElement((string) $xmlContent);
                $critereRegroup             = str_replace(Constante::oxaPipe, '|', $critere);
                $validationPanierController = new ValidationPanierService($this->pdo, $this->getTranslationService());

                if ($module == 'PanierDA') {
                    $titre     = $trad->t('Terme de paiement de la demande d\'achat du panier');
                    $panierXml = $validationPanierController->getListe('DA');

                    $fournisseur = $panierXml->RSFourn ?? '';
                    $codeFourn   = $panierXml->CodeFourn ?? '';
                    $titre       = Trad::strBuild(
                        $trad->t("Liste des termes de paiement de la demande d'achat du fournisseur : @1@ (@2@)"),
                        $fournisseur,
                        $codeFourn,
                    );
                } elseif ($module == 'PanierCDE') {
                    $panierXml = $validationPanierController->getListe('CDE', $critereRegroup);

                    $noCde       = \count($panierXml->TypeDoc);
                    $fournisseur = $panierXml->RSFourn ?? '';
                    $codeFourn   = $panierXml->CodeFourn ?? '';
                    $titre       = Trad::strBuild(
                        $trad->t("Liste des termes de paiement de la commande @1@ du fournisseur : @2@ (@3@)"),
                        $noCde,
                        $fournisseur,
                        $codeFourn,
                    );
                }

                $mntBase = $this->parametrage['AFFTTC'] ? (string) ($panierXml->MontantTtc ?? 0) : (string) ($panierXml->Montant ?? 0);
            }
        }

        Ariane::generate(2, $trad->t('Nouveau terme de paiement'), $post);
        if ($_SESSION['navigation']['menuActive'] === 'eproc') {
            Ariane::setFocus($id);
        }

        $paramCde = [
            'CDE_AFF_CODE_ART'     => sql::paravrac($this->pdo, 'PARAMGEN', 'CDE_AFF_CODE_ART') == 'O' ? true : false,
            'CDE_AFF_CODE_REF_FAB' => sql::paravrac($this->pdo, 'PARAMGEN', 'CDE_AFF_CODE_REF_FAB') == 'O' ? true : false,
            'CDE_AFF_REF_ART_FOUR' => sql::paravrac($this->pdo, 'PARAMGEN', 'CDE_AFF_REF_ART_FOUR') == 'O' ? true : false,
        ];

        if ($module === 'DemandeAchat') {
            $devise = (new DaEntet($this->pdo))->find(['NO_DA' => $id], ['DEVISE'])['DEVISE'] ?? '';
        } elseif ($module === 'Commande') {
            $devise = (new CaEntet($this->pdo))->find(['NO_CDE' => $id], ['DEVISE'])['DEVISE'] ?? '';
        } else {
            $devise = $produitXml->Devise ?? '';
        }

        if (\count($post) > 0) {
            $post['encoded'] = json_encode($post);
        }

        return $this->renderer->render('@TermeDePaiement/TermeDePaiement/creationEntete', [
            'NO_DA'         => $NO_DA,
            'id'            => $id,
            'post'          => $post,
            'MODULE'        => $module,
            'titre'         => $titre ?? '',
            'critere'       => $critere,
            'demandeAchat'  => $demandeAchat ?? [],
            'commande'      => $commande ?? [],
            'listeLignesDa' => $daLigne ?? [],
            'listeLignesCa' => $caLigne ?? [],
            'typeDeDelai'   => $this->listeUnitesDelai,
            'mntBasePanier' => trim((string) ($mntBase ?? 0)),
            'panierXml'     => $panierXml ?? [],
            'paramCde'      => $paramCde,
            'devise'        => $devise ?? '',
            'user'          => User::getUser()->getCodeUser(),
            'ttc'           => $this->parametrage['AFFTTC'],
        ]);
    }

    public function deleteTermeDePaiementAction(): Response
    {
        $numtp   = $this->request->getAttribute('numtp');
        $id      = $this->request->getAttribute('id');
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere') ?? '';

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        $module = ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module);

        (new TpEnt($this->pdo))->delete([
            'NUM_TP'          => $numtp,
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);
        (new TpEvt($this->pdo))->delete([
            'NUM_TP'          => $numtp,
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);
        (new TpPos($this->pdo))->delete([
            'NUM_TP'          => $numtp,
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);
        (new TpPevt($this->pdo))->delete([
            'NOTP'            => $numtp,
            'NOCOMMAND'       => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);

        return new Response(200);
    }

    public function deleteAllTermeDePaiementAction(): Response
    {
        $id      = $this->request->getAttribute('id');
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere') ?? '';

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        $module = ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module);

        (new TpEnt($this->pdo))->delete([
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);
        (new TpEvt($this->pdo))->delete([
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);
        (new TpPos($this->pdo))->delete([
            'NUM_CDE'         => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);
        (new TpPevt($this->pdo))->delete([
            'NOCOMMAND'       => $id,
            'TYPEOBJ'         => $module,
            'CRITERE_REGROUP' => $critereRegroup,
        ]);

        return new Response(200);
    }

    /**
     * Summary of tpValidationCreateAction
     * @return Response
     */
    public function tpValidationCreateAction(): Response
    {
        $post    = $this->request->getParsedBody();
        $id      = $this->request->getAttribute('id');
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere') ?? '';

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        $errors = $this->validateForm($post);

        if (!empty($errors)) {
            return new Response(400, [], $errors);
        }

        $this->saveOrUpdateEntete(
            $module,
            $id,
            0,
            $post,
            $critereRegroup,
        );

        $bodyResponse = json_encode([
            'path' => $this->router->generateUri(
                'TermeDePaiement.TermeDePaiement.termeDePaiement',
                [
                    'MODULE' => $module,
                    'id'     => $id,
                ] + (!empty($critere) ? ['critere' => $critere] : [])
            ),
            'post' => [],
        ]);

        return new Response(
            200,
            [],
            $bodyResponse ?: null
        );
    }

    /**
     * Summary of termeDePaiementUpdateAction
     * @return string
     */
    public function termeDePaiementUpdateAction(
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TpPos $tpPos,
        TyEvtStp $tyEvtStp,
        TpPevt $tpPevt,
        CaLigne $caLigne,
        CaEntet $caEntet,
        DaEntet $daEntet,
        DaLigne $daLigne,
    ): string {
        $id      = $this->request->getAttribute('id');
        $numtp   = $this->request->getAttribute('numtp');
        $module  = $this->request->getAttribute('MODULE');
        $module  = ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module);
        $critere = $this->request->getAttribute('critere');
        $post    = $this->request->getParsedBody();

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        if (isset($post['encoded']) && $post['encoded'] != '') {
            if (isset($post['selected_evt'])) {
                $newEvts = $post['selected_evt'];
            }
            $post = array_merge($post, json_decode($post['encoded'], true));
            unset($post['selected_evt']);
            if (isset($newEvts)) {
                foreach ($newEvts as $evt) {
                    $evt = $tyEvtStp->find(['CODE_EVT' => $evt]);
                    if ($evt != null) {
                        $post['selected_evt'][] = $evt;
                    }
                }
            }
        } elseif (empty($post['selected_evt'])) {
            $allTpEvt             = $tpEvt->findAll(['NUM_CDE' => $id, 'TYPEOBJ' => $module, 'NUM_TP' => $numtp, 'CRITERE_REGROUP' => $critereRegroup]);
            $post['selected_evt'] = [];
            foreach ($allTpEvt as &$event) {
                $detail                 = $tyEvtStp->find(['CODE_EVT' => $event['EVENEMENT']]);
                $event['detailEvent']   = $detail;
                $post['selected_evt'][] = $event;
            }
            unset($event);
        }

        $trad = $this->getTranslationService();
        Ariane::generate(2, $trad->t('Modification du terme de paiement'), $post);

        if (isset($_SESSION['panier']['XML']) && \in_array($module, ['PanierDA', 'PanierCDE'])) {
            $validationPanierController = new ValidationPanierService($this->pdo, $this->getTranslationService());
            if ($module === 'PanierDA') {
                $panierXml = $validationPanierController->getListe('DA');
            } elseif ($module === 'PanierCDE') {
                $panierXml = $validationPanierController->getListe('CDE', $critereRegroup);
            }
        }
        $mntBase = $this->parametrage['AFFTTC'] ? (string) ($panierXml->MontantTtc ?? 0) : (string) ($panierXml->Montant ?? 0);

        if ($module === 'DA_ENTET') {
            $devise     = $daEntet->find(['NO_DA' => $id], ['DEVISE'])['DEVISE'] ?? '';
            $AllLigneDa = (new LigneDemandeAchat($this->pdo))->getLigneDemandeAchat($id);
        } elseif ($module === 'CA_ENTET') {
            $devise     = $caEntet->find(['NO_CDE' => $id], ['DEVISE'])['DEVISE'] ?? '';
            $AllLigneCa = (new LigneCommande($this->pdo))->getLigneCommande($id);
        }

        $critereArray        = ($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : [];
        $tp                  = $tpEnt->find(['NUM_CDE' => $id, 'NUM_TP' => $numtp, 'TYPEOBJ' => $module] + $critereArray);
        $tp['TYPEDELAIFACT'] = (string) array_search($tp['TYPEDELAIFACT'], $this->listeUnitesDelaiForDB);
        $allTpEvt            = $tpEvt->findAll(['NUM_CDE' => $id, 'TYPEOBJ' => $module, 'NUM_TP' => $numtp] + $critereArray);
        $allTpPos            = $tpPos->findAll(['NUM_CDE' => $id, 'NUM_TP' => $numtp, 'TYPEOBJ' => $module] + $critereArray);
        $allTpPevt           = $tpPevt->findAll(['NOCOMMAND' => $id, 'NOTP' => $numtp, 'TYPEOBJ' => $module] + $critereArray);
        $lignes              = [];
        foreach ($allTpEvt as &$event) {
            $event['detailEvent'] = $tyEvtStp->find(['CODE_EVT' => $event['EVENEMENT']]);
            $allLignesOnEvent     = $tpPevt->findAll(['NOCOMMAND' => (int) $id, 'TYPEOBJ' => $module, 'NOTP' => (int) $numtp, 'NOLIGTP' => (int) $event['NOL_TP']]);
            if ($module == 'CA_ENTET') {
                foreach ($allLignesOnEvent as $ligneOnEvent) {
                    $lignes[] = $caLigne->find(['NO_CDE' => $id, 'NO_PO' => $ligneOnEvent['NOPOCDE']]);
                }
            } elseif ($module == 'DA_ENTET') {
                foreach ($allLignesOnEvent as $ligneOnEvent) {
                    $lignes[] = $daLigne->find(['NO_DA' => $id, 'NO_PO' => $ligneOnEvent['NOPOCDE']]);
                }
            }
        }
        unset($event);
        $titre = $trad->t('Modification du terme de paiement');

        if (!isset($post['encoded'])) {
            // required for dynamic creations of seuils
            $allNewTpValue = [];
            foreach ($allTpEvt as $value) {
                $allNewTpValue[$value['NOL_TP']] = $value;
                foreach ($allTpPevt as $pevt) {
                    if (isset($allNewTpValue[$pevt['NOLIGTP']]['EVENEMENT']) && \is_array($pevt)) {
                        $keyValue                                    = $allNewTpValue[$pevt['NOLIGTP']]['EVENEMENT'];
                        $post['seuils'][$keyValue][$pevt['NOPOCDE']] = $pevt['POURCBUT'];
                    }
                }
            }
        }

        $post['encoded'] = json_encode($post);

        $module = $module === 'DA_ENTET' ? 'DemandeAchat' : ($module === 'CA_ENTET' ? 'Commande' : $module);

        return $this->renderer->render('@TermeDePaiement/TermeDePaiement/creationEntete', [
            'NO_DA'         => $module === 'DemandeAchat' ? 'DA_ENTET' : 'CA_ENTET',
            'id'            => $id,
            'numtp'         => $numtp,
            'post'          => $post,
            'MODULE'        => $module,
            'critere'       => $critere,
            'titre'         => $titre,
            'allTpPevt'     => $allTpPevt,
            'allTpEvt'      => $allTpEvt,
            'allTpPos'      => $allTpPos,
            'terme'         => $tp,
            'demandeAchat'  => $module === 'DemandeAchat' ? $daEntet->find(['NO_DA' => $id]) : [],
            'commande'      => $module === 'Commande' ? $caEntet->find(['NO_CDE' => $id]) : [],
            'update'        => true,
            'typeDeDelai'   => $this->listeUnitesDelai,
            'listeLignes'   => $lignes,
            'listeLignesDa' => $AllLigneDa ?? [],
            'listeLignesCa' => $AllLigneCa ?? [],
            'mntBasePanier' => trim((string) $mntBase),
            'panierXml'     => $panierXml ?? [],
            'devise'        => $devise ?? '',
            'user'          => User::getUser()->getCodeUser(),
        ]);
    }

    public function tpValidationUpdateAction(): Response
    {
        $post    = $this->request->getParsedBody();
        $id      = $this->request->getAttribute('id');
        $numtp   = $this->request->getAttribute('numtp');
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere');

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        $errors = $this->validateForm($post);
        if (empty($errors)) {
            $this->saveOrUpdateEntete(
                $module,
                $id,
                $numtp,
                $post,
                $critereRegroup,
            );

            $bodyResponse = json_encode([
                'path' => $this->router->generateUri(
                    'TermeDePaiement.TermeDePaiement.termeDePaiement',
                    [
                        'MODULE' => $module,
                        'id'     => $id,
                    ] + (!empty($critere) ? ['critere' => $critere] : [])
                ),
                'post' => [],
            ]);

            return new Response(
                200,
                [],
                $bodyResponse ?: null
            );
        }

        return new Response(400, [], $errors);
    }

    /**
     * Summary of listeModeleAction
     * @return string
     */
    public function listeModeleAction(
        TpModeles $tpModeles,
    ): string {
        $id      = $this->request->getAttribute('id');
        $module  = $this->request->getAttribute('MODULE');
        $critere = $this->request->getAttribute('critere');
        $post    = $this->request->getParsedBody();

        if (empty($post)) {
            $post['tri_LIB_MODELE'] = 'asc';
        }

        $modeles = $tpModeles->findAll(null, [], $post);

        Ariane::generate(3, $this->getTranslationService()->t('Liste des modèles de termes de paiement'));

        return $this->renderer->render('@TermeDePaiement/Modele/listeModeleTp', [
            'modeles' => $modeles,
            'MODULE'  => $module,
            'id'      => $id,
            'post'    => $post,
            'critere' => $critere,
        ]);
    }

    /**
     * Summary of ajaxLoadModeleAction, importer un modèle sur la création d'un nouveau TP
     * @return Response
     */
    public function ajaxLoadModeleAction(
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TpPos $tpPos,
        TpPevt $tpPevt,
        TyEvtStp $tyEvtStp,
        TermeDePaiementService $termeDePaiementService,
    ): Response {

        $idModele = $this->request->getAttribute('idModele');
        $id       = $this->request->getAttribute('id');
        $module   = $this->request->getAttribute('MODULE');
        $critere  = $this->request->getAttribute('critere') ?? '';

        $strategy = $termeDePaiementService->getStrategy($module, $critere);

        $pathRedirect = match ($module) {
            'PanierDA', 'PanierCDE' => 'TermeDePaiement.TermeDePaiement.termeDePaiement',
            'Commande'              => 'Commande.ModificationCommande.index',
            'DemandeAchat'          => 'DemandeAchat.ModificationDemandeAchat.index',
            default                 => ''
        };

        $paramsRedirect = match ($module) {
            'PanierDA'     => ['MODULE'     => $module, 'id'     => $id],
            'PanierCDE'    => ['MODULE'    => $module, 'id'    => $id, 'critere'    => $critere],
            'Commande'     => ['idCommande'     => $id, 'onglet'     => 'TermesDePaie'],
            'DemandeAchat' => ['idDA' => $id, 'mode' => 'modification', 'onglet' => 'items'],
            default        => []
        };

        $typeObj = match ($module) {
            'Commande'     => 'CA_ENTET',
            'DemandeAchat' => 'DA_ENTET',
            default        => $module
        };

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        $tpEnt->delete([
            'NUM_CDE' => $id,
            'TYPEOBJ' => $typeObj,
        ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));
        $tpEvt->delete([
            'NUM_CDE' => $id,
            'TYPEOBJ' => $typeObj,
        ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));
        $tpPos->delete([
            'NUM_CDE' => $id,
            'TYPEOBJ' => $typeObj,
        ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));
        $tpPevt->delete([
            'NOCOMMAND' => $id,
            'TYPEOBJ'   => $typeObj,
        ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));

        $allTpEnt = $tpEnt->findAll(['NUM_CDE' => $idModele, 'TYPEOBJ' => 'MODELE']);

        $allTypeEventManual    = $tyEvtStp->findAll(null, ['CODE_EVT'], ['filter_egal_HAPLUS' => Sql::boolSql2(false)]);
        $allTypeEventAvecPoste = $tyEvtStp->findAll(null, ['CODE_EVT'], ['filter_egal_PRO_POSTE' => Sql::boolSql2(true)]);

        $totalCmd = $strategy->getMontantTotal($id);

        foreach ($allTpEnt as &$ent) {
            $ent['NUM_CDE'] = $id;
            $ent['TYPEOBJ'] = $typeObj;
            unset($ent['CRITERE_REGROUP']);

            $ent['MNT_BASE'] = number_format(floatval(str_replace(' ', '', $totalCmd)), 2);
            $ent['POURC_TP'] = number_format(floatval(str_replace(' ', '', $ent['POURC_TP'])), 2);

            array_walk($ent, fn(&$val, $key): mixed => \in_array($key, $termeDePaiementService->getBoolCol('TP_ENT')) ? $val = Sql::setBoolSqlText($val) : $val);
            $tpEnt->insert($ent + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));

            $allTpEvt = $tpEvt->findAll(['NUM_CDE' => $idModele, 'TYPEOBJ' => 'MODELE', 'NUM_TP' => $ent['NUM_TP']]);

            foreach ($allTpEvt as &$evt) {
                $evt['NUM_CDE'] = $id;
                $evt['TYPEOBJ'] = $typeObj;
                unset($evt['CRITERE_REGROUP']);

                if (\count($allTypeEventManual) > 0) {
                    if (\in_array(
                        $evt['EVENEMENT'],
                        array_column($allTypeEventManual, 'CODE_EVT'),
                    )
                    ) {
                        $evt['RES_TP'] = User::getUser()->getCodeUser();
                    }
                }

                array_walk($evt, fn(&$val, $key): mixed => in_array($key, $termeDePaiementService->getBoolCol('TP_EVT')) ? $val = Sql::setBoolSqlText($val) : $val);
                $tpEvt->insert($evt + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));
            }

            foreach ($strategy->getAllDocArticles($id) as $article) {
                $tpPos->insert([
                    'NUM_CDE'   => $id,
                    'NUM_TP'    => $ent['NUM_TP'],
                    'NUM_PO_CD' => $article['NO_PO'],
                    'MNT_DE_FA' => 0,
                    'QTE_DE_FA' => 0,
                    'TYPEOBJ'   => $typeObj,
                ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));
            }

            if (\count($allTypeEventAvecPoste) > 0) {
                $allTpEvtInserted = $tpEvt->findAll([
                    'NUM_CDE' => $id,
                    'NUM_TP'  => $ent['NUM_TP'],
                    'TYPEOBJ' => $typeObj,
                ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));

                foreach ($allTpEvtInserted as $tpEvtInserted) {
                    if (\in_array(
                        $tpEvtInserted['EVENEMENT'],
                        array_column($allTypeEventAvecPoste, 'CODE_EVT'),
                    )
                    ) {
                        $pourcentageSeuil = $tpPevt->find([
                            'NOCOMMAND' => $idModele,
                            'NOTP'      => $tpEvtInserted['NUM_TP'],
                            'NOLIGTP'   => $tpEvtInserted['NOL_TP'],
                            'TYPEOBJ'   => 'MODELE',
                        ])['POURCBUT'] ?? 0;

                        foreach ($strategy->getAllDocArticles($id) as $article) {
                            $tpPevt->insert([
                                'NOCOMMAND' => $id,
                                'NOTP'      => $tpEvtInserted['NUM_TP'],
                                'NOLIGTP'   => $tpEvtInserted['NOL_TP'],
                                'NOPOCDE'   => $article['NO_PO'],
                                'TYPEOBJ'   => $typeObj,
                                'POURCBUT'  => $pourcentageSeuil,
                            ] + (($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critereRegroup] : []));
                        }
                    }
                }
            }
        }

        $uri = $this->router->generateUri($pathRedirect, $paramsRedirect);

        if (\in_array($module, ['DemandeAchat', 'Commande'])) {
            $uri .= '?onglet=termesdepaiement';
        }

        return $this->redirectLocation($uri);
    }

    /**
     * Summary of ajoutModeleTermeDePaiementAction
     * @return string
     */
    public function ajoutModeleTermeDePaiementAction(): string
    {
        $module  = $this->request->getAttribute('MODULE');
        $post    = $this->request->getParsedBody();
        $NO_DA   = '';
        $trad    = $this->getTranslationService();
        $referer = $this->request->getServerParams()['HTTP_REFERER'] ?? null;
        $id      = $this->request->getAttribute('id');
        $numtp   = $this->request->getAttribute('numtp');

        $titre = $trad->t('Modèles de termes de paiement');

        Ariane::setFocus('gestionModeleTp');

        Ariane::generate(3, $trad->t('Nouveau modèle de terme de paiement'), []);

        $listeUnitesDelai = [
            'J' => $trad->t('Jour'),
            'M' => $trad->t('Mois'),
            'A' => $trad->t('Année'),
        ];

        return $this->renderer->render('@TermeDePaiement/Modele/ajoutModeleTp', [
            'NO_DA'       => $NO_DA,
            'post'        => $post,
            'MODULE'      => $module,
            'referer'     => $referer,
            'titre'       => $titre,
            'id'          => $id,
            'numtp'       => $numtp,
            'path'        => 'TermeDePaiement.TermeDePaiement.ajoutModeleTermeDePaiement',
            'typeDeDelai' => $listeUnitesDelai,
        ]);
    }

    public function updateModeleTermeDePaiementAction(
        TpModeles $tpModeles,
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TpPevt $tpPevt,
        TyEvtStp $tyEvtStp,
    ): string {
        $module   = $this->request->getAttribute('MODULE');
        $idModele = $this->request->getAttribute('idModele');
        $trad     = $this->getTranslationService();
        $referer  = $this->request->getServerParams()['HTTP_REFERER'] ?? null;

        $modele = $tpModeles->find(['ID_MODELE' => $idModele]);
        $termes = $tpEnt->findAll(['NUM_CDE' => $idModele, 'TYPEOBJ' => 'MODELE']);

        foreach ($termes as $key => $terme) {
            $numTp                                = $terme["NUM_TP"];
            $formData[$numTp]['LIBELLE_TP']       = $terme['LIBELLE'] ?? '';
            $formData[$numTp]['DESCRIPTIF_TP']    = $terme['DESCRIPTIF'] ?? '';
            $formData[$numTp]['POURC_TP']         = $terme['POURC_TP'] ?? 0;
            $formData[$numTp]['DELAIFACT_TP']     = $terme['DELAIFACT'] ?? null;
            $formData[$numTp]['TYPEDELAIFACT_TP'] = (string) array_search($terme['TYPEDELAIFACT'] ?? '', $this->listeUnitesDelaiForDB);
            $formData[$numTp]['BASE_LIVR']        = Sql::toBool($terme['BASE_LIVR'] ?? false);
            $formData[$numTp]['FACTATERME']       = Sql::toBool($terme['FACTATERME'] ?? false);

            foreach ($tpEvt->findAll([
                'NUM_CDE' => $idModele,
                'TYPEOBJ' => 'MODELE',
                'NUM_TP'  => $numTp,
            ]) as $event) {
                $detailsEvent                       = $tyEvtStp->find(['CODE_EVT' => $event['EVENEMENT']]);
                $detailsEvent['seuil']              = $tpPevt->find(['NOCOMMAND' => $idModele, 'NOTP' => $numTp, 'NOLIGTP' => $event['NOL_TP'], 'TYPEOBJ' => 'MODELE'])['POURCBUT'] ?? 0;
                $formData[$numTp]['selected_evt'][] = $detailsEvent;
            }

            if (array_key_last($termes) == $key) {
                $lastNumTp = $numTp;
            }
        }
        Ariane::setFocus('gestionModeleTp');

        return $this->renderer->render('@TermeDePaiement/Modele/updateModeleTp', [
            'formData'    => $formData ?? [],
            'MODULE'      => $module,
            'referer'     => $referer,
            'path'        => 'TermeDePaiement.TermeDePaiement.updateModeleTermeDePaiement',
            'typeDeDelai' => $this->listeUnitesDelai,
            'modele'      => $modele,
            'termes'      => $termes,
            'idModele'    => $idModele,
            'lastNumTp'   => \intval($lastNumTp ?? 0),
        ]);
    }

    public function modeleValidationUpdateAction(
        TpModeles $tpModeles,
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TpPevt $tpPevt,
        TyEvtStp $tyEvtStp,
    ): Response {
        $post     = $this->request->getParsedBody();
        $idModele = intval($this->request->getAttribute('idModele'));
        $typeObj  = 'MODELE';

        $errors = $this->validateFormModele($post);

        if (!empty($errors)) {
            return new Response(400, [], $errors);
        }

        $tpModeles->update([
            'LIB_MODELE' => $post['MODELE_TP'],
            'DESCRIPTIF' => $post['DESCRIPTIF_MODELE'],
        ], ['ID_MODELE' => $idModele]);

        $tpEnt->delete(['NUM_CDE' => $idModele, 'TYPEOBJ' => $typeObj]);
        $tpEvt->delete(['NUM_CDE' => $idModele, 'TYPEOBJ' => $typeObj]);
        $tpPevt->delete(['NOCOMMAND' => $idModele, 'TYPEOBJ' => $typeObj]);

        $numTP = 1;
        foreach ($post['termeDePaiement'] as $termeDePaiement) {
            $libelle       = $termeDePaiement['LIBELLE_TP'] ?? '';
            $descriptif    = $termeDePaiement['DESCRIPTIF_TP'] ?? '';
            $pourcTp       = $termeDePaiement['POURC_TP'] ?? 0;
            $delaiFact     = $termeDePaiement['DELAIFACT_TP'] ?? 0;
            $typeDelaiFact = $termeDePaiement['TYPEDELAIFACT_TP'] ?? '';
            $baseLivr      = Sql::boolSql2(!empty($termeDePaiement['BASE_LIVR']));
            $factaterme    = Sql::boolSql2(!empty($termeDePaiement['FACTATERME']));

            $tpEnt->insert([
                'NUM_CDE'       => $idModele,
                'NUM_TP'        => $numTP,
                'LIBELLE'       => $libelle,
                'DELAIFACT'     => $delaiFact,
                'POURC_TP'      => $pourcTp,
                'BASE_LIVR'     => $baseLivr,
                'TP_FACT'       => Sql::boolSql2(false),
                'FACTATERME'    => $factaterme,
                'TYPEDELAIFACT' => $this->listeUnitesDelaiForDB[$typeDelaiFact],
                'DESCRIPTIF'    => $descriptif,
                'TYPEOBJ'       => $typeObj,
            ]);

            $nolTP = 1;
            foreach ($termeDePaiement['selected_evt'] as $selectedEvt) {
                [$codeEvt, $libelle, $haplus, $proposte] = explode('@', $selectedEvt);
                $tpEvt->insert([
                    'NUM_CDE'   => $idModele,
                    'NUM_TP'    => $numTP,
                    'NOL_TP'    => $nolTP,
                    'EVENEMENT' => $codeEvt,
                    // Note : ce champs est obsolete et doit etre remplacé par this.EVENEMENT->TYEVTSTP.LIB_EVT
                    // 'LIB_EVT' => $detailEvent['LIB_EVT'],
                    'EVT_OK'    => Sql::boolSql2(false),
                    'TYPEOBJ'   => $typeObj,
                ]);
                $detailEvent = $tyEvtStp->find(['CODE_EVT' => $codeEvt]);
                if (Sql::toBool($detailEvent['PRO_POSTE'])) {
                    $tpPevt->insert([
                        'NOCOMMAND' => $idModele,
                        'NOTP'      => $numTP,
                        'NOLIGTP'   => $nolTP,
                        'NOPOCDE'   => 0,
                        'POURCBUT'  => $termeDePaiement['seuils_evt'][$selectedEvt],
                        'TYPEOBJ'   => 'MODELE',
                    ]);
                }

                $nolTP++;
            }

            $numTP++;
        }

        return new Response(200);
    }
    public function deleteModeleAction(): Response
    {
        $idModele = $this->request->getAttribute('idModele');
        $typeObj  = 'MODELE';

        (new TpEnt($this->pdo))->delete(['NUM_CDE' => $idModele, 'TYPEOBJ' => $typeObj]);
        (new TpEvt($this->pdo))->delete(['NUM_CDE' => $idModele, 'TYPEOBJ' => $typeObj]);

        (new TpModeles($this->pdo))->delete(['ID_MODELE' => $idModele]);

        return new Response(200, [], (string) \json_encode([]));
    }

    /**
     * Summary of modeleValidationCreateAction
     * @return Response
     */
    public function modeleValidationCreateAction(
        TermPaieRepo $termPaieRepo,
        TpModeles $tpModeles,
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TpPevt $tpPevt,
        TyEvtStp $tyEvtStp,
    ): Response {
        $post    = $this->request->getParsedBody();
        $typeObj = 'MODELE';

        $errors = $this->validateFormModele($post);

        if (!empty($errors)) {
            return new Response(400, [], $errors);
        }

        $tpModeles->insert($modeleInserted = [
            // ID_MODELE est au autoincrement
            // 'ID_MODELE'  => \intval($tpModeles->getNextId()),
            'LIB_MODELE' => $post['MODELE_TP'],
            'DESCRIPTIF' => $post['DESCRIPTIF_MODELE'],
        ]);

        $idModele = $tpModeles->getLastID();
        $numTP    = 1;

        foreach ($post['termeDePaiement'] as $termeDePaiement) {
            $libelle       = $termeDePaiement['LIBELLE_TP'] ?? '';
            $descriptif    = $termeDePaiement['DESCRIPTIF_TP'] ?? '';
            $pourcTp       = $termeDePaiement['POURC_TP'] ?? 0;
            $delaiFact     = $termeDePaiement['DELAIFACT_TP'] ?? 0;
            $typeDelaiFact = $termeDePaiement['TYPEDELAIFACT_TP'] ?? '';
            $baseLivr      = Sql::boolSql2(!empty($termeDePaiement['BASE_LIVR']));
            $factaterme    = Sql::boolSql2(!empty($termeDePaiement['FACTATERME']));

            $tpEnt->insert([
                'NUM_CDE'       => $idModele,
                'NUM_TP'        => $numTP,
                'LIBELLE'       => $libelle,
                'DELAIFACT'     => $delaiFact,
                'POURC_TP'      => $pourcTp,
                'BASE_LIVR'     => $baseLivr,
                'TP_FACT'       => Sql::boolSql2(false),
                'FACTATERME'    => $factaterme,
                'TYPEDELAIFACT' => $this->listeUnitesDelaiForDB[$typeDelaiFact],
                'DESCRIPTIF'    => $descriptif,
                'TYPEOBJ'       => $typeObj,
            ]);

            $nolTP = 1;
            foreach ($termeDePaiement['selected_evt'] as $selectedEvt) {
                [$codeEvt, $libelle, $haplus, $proposte] = explode('@', $selectedEvt);

                $tpEvt->insert([
                    'NUM_CDE'   => $idModele,
                    'NUM_TP'    => $numTP,
                    'NOL_TP'    => $nolTP,
                    'EVENEMENT' => $codeEvt,
                    // Note : ce champs est obsolete et doit etre remplacé par this.EVENEMENT->TYEVTSTP.LIB_EVT
                    // 'LIB_EVT' => $detailEvent['LIB_EVT'],
                    'EVT_OK'    => Sql::boolSql2(false),
                    'TYPEOBJ'   => $typeObj,
                ]);

                $detailEvent = $tyEvtStp->find(['CODE_EVT' => $codeEvt]);
                if (Sql::toBool($detailEvent['PRO_POSTE'])) {
                    $tpPevt->insert([
                        'NOCOMMAND' => $idModele,
                        'NOTP'      => $numTP,
                        'NOLIGTP'   => $nolTP,
                        'NOPOCDE'   => 0,
                        'POURCBUT'  => $termeDePaiement['seuils_evt'][$selectedEvt],
                        'TYPEOBJ'   => 'MODELE',
                    ]);
                }

                $nolTP++;
            }



            $numTP++;
        }
        return new Response(200);
    }

    /**
     * Summary of validateForm
     * @param array<mixed> $post
     * @return string|null
     */
    public function validateForm(array &$post): ?string
    {
        $trad      = $this->getTranslationService();
        $validator = $this->createValidator();

        $validator->isStringAvecEspace($trad->t('Libellé'), $post['LIBELLE_TP'] ?? '', 1, 120);
        if (Sql::toBool($post["FACTATERME"] ?? '')) {
            $validator->isInteger($trad->t('Délai de facturation à terme'), $post['DELAIFACT_TP'], 0, 3);
            if (empty($post['DELAIFACT_TP'] ?? '') || $post['DELAIFACT_TP'] == 0) {
                $validator->setError($trad->t('Veuillez renseigner le délai de facturation à terme.'));
            }
            if (empty($post['TYPEDELAIFACT_TP'] ?? '')) {
                $validator->setError($trad->t('Veuillez sélectionner un type de délai de facturation à terme.'));
            }
        }

        $validator->isFloat($trad->t('Pourcentage à payer'), $post['POURC_TP'], Constante::formatMontant);
        if (empty($post['POURC_TP'] ?? '') || $post['POURC_TP'] == 0) {
            $validator->setError($trad->t('Veuillez renseigner le pourcentage à payer.'));
        }
        if ($post['POURC_TP'] > 100) {
            $validator->setError($trad->t('Le pourcentage à payer ne peut pas être supérieur à 100%.'));
        }

        if (empty($post['selected_lignes_data'])) {
            $validator->setError($trad->t('Veuillez sélectionner une ou plusieurs ligne(s).'));
        }

        if (empty($post['selected_evt'] ?? [])) {
            $validator->setError($trad->t('Vous devez renseigner au moins un événement pour ce terme de paiement.'));
        } else {
            foreach ($post['selected_evt'] as $detailsEvt) {
                [$codeEvt, $libelleEvt, $isHAPLUS, $hasPostes] = explode('|', $detailsEvt, 4);
                $detailEvent                                   = (new TyEvtStp($this->pdo))->find(['CODE_EVT' => $codeEvt]);
                if ($detailEvent === [] || $detailEvent === null) {
                    $validator->setError(Trad::strBuild($trad->t("L'événement @1@ (@2@) n\'existe pas."), $libelleEvt, $codeEvt));
                }
                if (!Sql::boolSql($detailEvent['HAPLUS'])) {
                    if ($post['responsable_tp_visible'][$codeEvt] == 1 && (!isset($post['RESPONSABLE_TP-' . $codeEvt]) || $post['RESPONSABLE_TP-' . $codeEvt] == '')) {
                        $validator->setError(Trad::strBuild($trad->t("Veuillez renseigner le responsable pour l'événement @1@ (@2@)."), $libelleEvt, $codeEvt));
                    } else {
                        $validator->zoom('Hastutil', $post['RESPONSABLE_TP-' . $codeEvt], $trad->t("Responsable"), $this->pdo);
                    }
                }
            }

            foreach ((array) ($post['seuils'] ?? []) as $codeEvent => $arrayLignesSeuils) {
                foreach ($arrayLignesSeuils as $numeroLigne => $valueSeuil) {
                    if (floatval($valueSeuil) < 0 || $valueSeuil == '') {
                        $validator->setError(Trad::strBuild($trad->t("Veuillez renseigner un seuil pour l'événement @1@ ligne @2@."), $codeEvent, $numeroLigne));
                    }
                    if (floatval($valueSeuil) > 100) {
                        $validator->setError(Trad::strBuild($trad->t("Le seuil pour l'événement @1@ ligne @2@ ne peut pas être supérieur à 100%."), $codeEvent, $numeroLigne));
                    }
                }
            }
        }

        if (!$validator->isValid()) {
            return $validator->getError();
        }

        return null;
    }


    /**
     * @param array<mixed> $post
     */
    public function validateFormModele(array $post): ?string
    {
        $trad      = $this->getTranslationService();
        $validator = $this->createValidator();

        $validator->isStringAvecEspace($trad->t('Nom du modèle'), $post['MODELE_TP'] ?? '', 1, 3000);
        $validator->isStringAvecEspace($trad->t('Descriptif du modèle'), $post['DESCRIPTIF_MODELE'] ?? '', 0, 3000);

        if (isset($post['termeDePaiement']) && \is_array($post['termeDePaiement']) && \count($post['termeDePaiement']) > 0) {
            $termes        = array_values($post['termeDePaiement']);
            $termesReindex = [];
            foreach ($termes as $i => $item) {
                $termesReindex[$i + 1] = $item;
            }
            foreach ($termesReindex as $key => $termeDePaiement) {
                $validator->isStringAvecEspace(
                    Trad::strBuild($trad->t('Libellé du terme de paiement n°@1@'), \strval($key)),
                    $termeDePaiement['LIBELLE_TP'],
                    1,
                    120,
                );
                $validator->isStringAvecEspace(
                    Trad::strBuild($trad->t('Descriptif du terme de paiement n°@1@'), \strval($key)),
                    $termeDePaiement['DESCRIPTIF_TP'] ?? '',
                    0,
                    3000,
                );
                $validator->isFloat(
                    Trad::strBuild($trad->t('Pourcentage à payer du terme de paiement n°@1@'), \strval($key)),
                    $termeDePaiement['POURC_TP'],
                    Constante::formatMontant,
                );
                if ($termeDePaiement['POURC_TP'] === '' || $termeDePaiement['POURC_TP'] === null || \intval($termeDePaiement['POURC_TP']) == 0) {
                    $validator->setError(
                        Trad::strBuild($trad->t('Veuillez renseigner le pourcentage à payer du terme de paiement n°@1@.'), \strval($key)),
                    );
                }
                if (\floatval($termeDePaiement['POURC_TP']) > 100) {
                    $validator->setError(Trad::strBuild($trad->t('Le pourcentage à payer ne peut pas être supérieur à 100% pour le terme de paiement n°@1@.'), \strval($key)));
                } elseif (\floatval($termeDePaiement['POURC_TP']) < 0) {
                    $validator->setError(Trad::strBuild($trad->t('Le pourcentage à payer ne peut pas être négatif pour le terme de paiement n°@1@.'), \strval($key)));
                }
                if (Sql::toBool($termeDePaiement['FACTATERME'] ?? '')) {
                    if (empty($termeDePaiement['DELAIFACT_TP'] ?? '') || $termeDePaiement['DELAIFACT_TP'] == 0) {
                        $validator->setError(Trad::strbuild($trad->t('Veuillez renseigner le délai de facturation à terme du terme de paiement n°@1@.'), \strval($key)));
                    }
                    if (empty($termeDePaiement['TYPEDELAIFACT_TP'] ?? '')) {
                        $validator->setError(Trad::strbuild($trad->t('Veuillez sélectionner un type de délai de facturation à terme du terme de paiement n°@1@.'), \strval($key)));
                    }
                }

                if (isset($termeDePaiement['selected_evt']) && \is_array($termeDePaiement['selected_evt']) && \count($termeDePaiement['selected_evt']) > 0) {
                    foreach ($termeDePaiement['selected_evt'] as $event) {
                        [$codeEvt, $libelle, $haplus, $proposte] = explode('@', $event);
                        $detailEvent                             = (new TyEvtStp($this->pdo))->find(['CODE_EVT' => $codeEvt]);
                        if ($detailEvent === [] | $detailEvent === null) {
                            $validator->setError(Trad::strbuild($trad->t('Le code événement @1@ (@2@) rajouté sur le terme de paiement n°@3@ n\'existe pas'), $codeEvt, $libelle, \strval($key)));
                        }
                        if (Sql::boolSql($detailEvent['PRO_POSTE'])) {
                            $validator->isFloat(
                                Trad::strBuild($trad->t('Seuil de l\'évènement @1@ du terme de paiement n°@2@'), $codeEvt, \strval($key)),
                                $termeDePaiement['seuils_evt'][$event],
                                Constante::formatMontant,
                            );
                            if ($termeDePaiement['seuils_evt'][$event] === '' || $termeDePaiement['seuils_evt'][$event] === null) {
                                $validator->setError(
                                    Trad::strBuild($trad->t('Veuillez renseigner le seuil de l\'évènement @1@ du terme de paiement n°@2@.'), $codeEvt, \strval($key)),
                                );
                            }
                            if (\floatval($termeDePaiement['seuils_evt'][$event]) > 100) {
                                $validator->setError(Trad::strBuild($trad->t('Le seuil de l\'évènement @1@ du terme de paiement n°@2@ ne peut pas être supérieur à 100%.'), $codeEvt, \strval($key)));
                            } elseif (\floatval($termeDePaiement['seuils_evt'][$event]) < 0) {
                                $validator->setError(Trad::strBuild($trad->t('Le seuil de l\'évènement @1@ du terme de paiement n°@2@ ne peut pas être négatif pour le terme de paiement n°@1@.'), $codeEvt, \strval($key)));
                            }
                        }
                    }
                } else {
                    $validator->setError(Trad::strbuild($trad->t('Veuillez rajouter au moins un déclenchement pour le terme de paiement n°@1@.'), \strval($key)));
                }
            }
        } else {
            $validator->setError($trad->t('Veuillez rajouter au moins un terme de paiement pour ce modèle.'));
        }

        return !$validator->isValid() ? $validator->getError() : null;
    }

    /**
     * Summary of suiviAvancementTpAction
     * @return string
     */
    public function suiviAvancementTpAction(
        TpEvt $tpEvt,
        TpEnt $tpEnt,
        TpPevt $tpPevt,
        TpPos $tpPos,
        TyEvtStp $tyEvtStp,
        TermeDePaiementService $termeDePaiementService,
        CaEntet $caEntet,
        Fourniss $fourniss,
    ): string {
        $id     = $this->request->getAttribute('id');
        $module = $this->request->getAttribute('MODULE');
        $post   = $this->request->getParsedBody();

        $trad = $this->getTranslationService();

        $trad->t('Suivi de l\'avancement du terme de paiement');

        if ($module == 'DemandeAchat') {
            $this->redirect('DemandeAchat.GestionDemandeAchat.index');
        } elseif ($module = 'Commande') {
            Ariane::generate(2, $trad->t('Suivi de l\'avancement du terme de paiement'), $post);

            $commande    = $caEntet->find(['NO_CDE' => $id]);
            $fournisseur = $fourniss->find(['CODE' => $commande['CODE_FOU']]);

            $titre = Trad::strBuild(
                $trad->t('Suivi de l\'avancement des termes de paiement de la commande : @1@ pour le fournisseur @2@ (@3@)'),
                $commande['NO_CDE'] . (($commande['AVENANT'] ?? null) ? ' - ' . $commande['AVENANT'] : ''),
                $fournisseur['RS'],
                $fournisseur['CODE'],
            );
        }

        $strategy = $termeDePaiementService->getStrategy('CA_ENTET', '');

        $allTpEnt = $tpEnt->findAll(['NUM_CDE' => $id, 'TYPEOBJ' => 'CA_ENTET']);

        $allTpEvent   = $tpEvt->findAll(['NUM_CDE' => $id, 'TYPEOBJ' => 'CA_ENTET']);
        $indexTpEvent = ArrayHelper::indexBy($allTpEvent, 'NUM_TP');

        foreach ($allTpEnt as &$entet) {
            $allTpPos             = $tpPos->findAll(['NUM_CDE' => $id, 'NUM_TP' => $entet['NUM_TP'], 'TYPEOBJ' => 'CA_ENTET']);
            $entet['lignesPoste'] = $strategy->getDetailLigneTpPos($id, $allTpPos);

            $entet['listTpEvent'] = $indexTpEvent[$entet['NUM_TP']] ?? [];

            foreach ($entet['listTpEvent'] as &$event) {
                $event['detailEvent'] = $tyEvtStp->find(['CODE_EVT' => $event['EVENEMENT']]);

                $allTpPevtForEvent   = $tpPevt->findAll(['NOCOMMAND' => $id, 'NOTP' => $event['NUM_TP'], 'NOLIGTP' => $event['NOL_TP'], 'TYPEOBJ' => 'CA_ENTET']);
                $event['listTpPevt'] = $strategy->getDetailLigneSeuil($id, $allTpPevtForEvent);
            }
            unset($event);
        }
        unset($entet);

        $paramCde = [
            'CDE_AFF_CODE_ART'     => sql::paravrac($this->pdo, 'PARAMGEN', 'CDE_AFF_CODE_ART') == 'O' ? true : false,
            'CDE_AFF_CODE_REF_FAB' => sql::paravrac($this->pdo, 'PARAMGEN', 'CDE_AFF_CODE_REF_FAB') == 'O' ? true : false,
            'CDE_AFF_REF_ART_FOUR' => sql::paravrac($this->pdo, 'PARAMGEN', 'CDE_AFF_REF_ART_FOUR') == 'O' ? true : false,
        ];

        return $this->renderer->render('@TermeDePaiement/TermeDePaiement/suiviAvancementTp', [
            'id'               => $id,
            'post'             => $post,
            'MODULE'           => $module,
            'titre'            => $titre ?? '',
            'allTpEnt'         => $allTpEnt,
            'devise'           => $strategy->getDevise($id),
            'paramCde'         => $paramCde,
            'listeUnitesDelai' => $this->listeUnitesDelai,
            'user'             => User::getUser()->getCodeUser(),
        ]);
    }

    /**
     * Summary of suiviAvancementTpAction
     * @return Response
     */
    public function ajaxSuiviAvancementTpAction(
        TermeDePaiementService $termeDePaiementService,
    ): Response {
        $id         = $this->request->getAttribute('id');
        $module     = $this->request->getAttribute('MODULE');
        $commandeId = $this->request->getAttribute('id');

        if ($module != "Commande") {
            $this->create404Response();
        }

        $caEntet = (new CaEntet($this->pdo))->find($commandeId);
        if (empty($caEntet)) {
            LogSysteme::prefixErrorLog((new \Exception('Invalid commande #' . $commandeId))->__tostring());
        }
        $caEntet['listTermPaie'] = $termeDePaiementService->getCommandeTermPaie($caEntet['NO_CDE']);

        if (!$termeDePaiementService->isCommandeModifiable($caEntet)) {
            LogSysteme::prefixErrorLog((new \Exception('Invalid commande #' . $commandeId . ' for TP update'))->__tostring());
        }

        $post = $this->request->getParsedBody();

        //___________________
        // Validation

        $validator = $this->createValidator();
        foreach (($post['termPaie'] ?? []) as $termPaieId => $listCondPaie) {
            foreach ($listCondPaie as $condPaieId => $condPaie) {
                $validator->isCheck($condPaie['EVT_OK']);
            }
        }
        if (!$validator->isValid()) {
            return new Response(400, [], $validator->getError());
        }

        //___________________
        // Update DB

        $entCondPaie = new TpEvt($this->pdo);
        foreach ($caEntet['listTermPaie'] as $tp) {
            $termPaieId = $tp['NUM_TP'];
            foreach ($tp['listCondPaie'] as $condPaie) {
                $condPaieId = $condPaie['NOL_TP'];
                if (isset($post['termPaie'][$termPaieId][$condPaieId]['EVT_OK'])) {
                    // Case : CondPaie not editable
                    if (Sql::toBool($condPaie['Evenement']['HAPLUS'])) {
                        continue;
                    }
                    $entCondPaie->update(
                        [
                            'EVT_OK' => Sql::toBool(
                                $post['termPaie']
                                [$termPaieId]
                                [$condPaieId]
                                ['EVT_OK'] ?? false
                            ),
                        ],
                        [
                            'NUM_CDE' => $caEntet['NO_CDE'],
                            'NUM_TP'  => $termPaieId,
                            'NOL_TP'  => $condPaieId,
                        ],
                    );
                }
            }
        }

        //___________________
        // Post process

        (new TermPaieRepo($this->pdo))->recalc($caEntet['NO_CDE'], 'CA_ENTET');

        return new Response();
    }

    /**
     * Summary of gestionModeleTpAction
     * @return string
     */
    public function gestionModeleTpAction()
    {
        $module = $this->request->getAttribute('MODULE');
        $id     = $this->request->getAttribute('id');
        $numtp  = $this->request->getAttribute('numtp') ?? 0;
        if (empty($id)) {
            $id = 1;
        }
        $post = $this->request->getParsedBody();
        $trad = $this->getTranslationService();

        if (empty($post)) {
            $post['tri_LIB_MODELE'] = 'asc';
        }

        $modeles        = (new TpModeles($this->pdo))->findAll(null, [], $post);
        $lignesTpModele = [];
        foreach ($modeles as $modele) {
            $idModele                  = $modele['ID_MODELE'];
            $lignesTpModele[$idModele] = ($module === 'eProc')
                ? (new TpEnt($this->pdo))->findAll([
                    'NUM_CDE'         => $idModele,
                    'TYPEOBJ'         => 'MODELE',
                    'CRITERE_REGROUP' => ['!=', null],
                ]) : (new TpEnt($this->pdo))->findAll([
                            'NUM_CDE' => $idModele,
                            'TYPEOBJ' => 'MODELE',
                        ]);
        }

        $trad = $this->getTranslationService();
        Ariane::generate(0, $trad->t('Gestion'), $post);

        return $this->renderer->render('@TermeDePaiement/Modele/gestionModeleTp', [
            'menuActive'     => $module == 'eProc' ? 'eproc' : 'CollecteBesoins',
            'modeles'        => $modeles,
            'lignesTpModele' => $lignesTpModele,
            'MODULE'         => $module,
            'id'             => $id,
            'numtp'          => $numtp,
            'titre'          => $trad->t('Modèles des termes de paiement'),
            'post'           => $post,
        ]);
    }

    /**
     * Summary of ligneModeleAction
     * @return string
     */
    public function ligneModeleAction(
        TpEnt $tpEnt,
        TpEvt $tpEvt,
        TpPevt $tpPevt,
        TyEvtStp $tyEvtStp,
    ) {
        $id = $this->request->getAttribute('idModele');

        $allTp = $tpEnt->findAll(['NUM_CDE' => $id, 'TYPEOBJ' => 'MODELE']);

        foreach ($allTp as &$tp) {
            $numtp    = $tp['NUM_TP'];
            $allTpEvt = $tpEvt->findAll(['NUM_CDE' => $id, 'TYPEOBJ' => 'MODELE', 'NUM_TP' => $numtp]);

            foreach ($allTpEvt as &$event) {
                $event['detailEvent'] = $tyEvtStp->find(['CODE_EVT' => $event['EVENEMENT']]);
                if (Sql::boolSql($event['detailEvent']['PRO_POSTE'] ?? false)) {
                    $event['seuil'] = FloatHelper::format($tpPevt->find(['NOCOMMAND' => $id, 'NOTP' => $numtp, 'NOLIGTP' => $event['NOL_TP'], 'TYPEOBJ' => 'MODELE'])['POURCBUT'] ?? '', 2);
                }
            }
            $tp['events'] = $allTpEvt;
        }
        unset($event);

        return $this->renderer->render('@TermeDePaiement/Modele/tableModeleDetail', [
            'tps'              => $allTp,
            'listeUnitesDelai' => $this->listeUnitesDelai,
            'id'               => $id,
        ]);
    }

    /**
     * Summary of ajoutDeclenchementsAction
     * @return string
     */
    public function ajoutDeclenchementsAction(): string
    {
        $module  = $this->request->getAttribute('MODULE');
        $id      = $this->request->getAttribute('id');
        $trad    = $this->getTranslationService();
        $critere = $this->request->getAttribute('critere');
        $numtp   = $this->request->getAttribute('numtp');

        $post = $this->request->getParsedBody();

        if (isset($post['selected_evt']) && is_string($post['selected_evt'])) {
            $listOfSelectedEvents = explode(',', $post['selected_evt']);
            unset($post['selected_evt']);
            foreach ($listOfSelectedEvents as $detailsEvent) {
                [$codeEvt, $libelleEvt, $isHAPLUS] = explode('|', $detailsEvent);
                $post['selected_evt'][]            = $codeEvt;
            }
        }

        if (isset($post['encoded'])) {
            $selectedEvt           = $post['selected_evt'];
            $post                 += json_decode($post['encoded'], true);
            $post['selected_evt']  = $selectedEvt;
        }

        Ariane::generate(4, $trad->t('Ajout de déclenchements'), $post);

        (new PaginatorGestion())->generate(10, 'CODE_EVT');
        $tyevtstp       = (new Listes($this->pdo))->listeTyevtstp($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        $menuContextuel = new EvenementTPContextuel($this->pdo, $this->router, $this->getTranslationService());
        foreach ($tyevtstp as &$tp) {
            $tp['menuContextuel'] = $menuContextuel->generate($tp, true, $id, true);
        }

        if (\intval($numtp) != 0) {
            $update = true;
        }

        if (\count($post) > 0) {
            $encoded     = json_encode($post);
            $selectedEvt = $post['selected_evt'];
            unset($post);
            $post['encoded']      = $encoded;
            $post['selected_evt'] = $selectedEvt;
        }

        return $this->renderer->render('@TermeDePaiement/TermeDePaiement/ajoutDeclenchements', [
            'MODULE'         => $module,
            'update'         => $update ?? false,
            'critere'        => $critere,
            'numtp'          => $numtp,
            'id'             => $id,
            'post'           => $post,
            'tyevtstp'       => $tyevtstp,
            'infoPagination' => $infoPagination,
            'modele'         => false,
        ]);
    }


    /**
     * Summary of ajoutDeclenchementsAction
     * @return string
     */
    public function ajoutDeclenchementsModeleAction(
        TyEvtStp $tyEvtStpRepo,
    ): string {
        $module  = $this->request->getAttribute('MODULE');
        $id      = $this->request->getAttribute('id');
        $critere = $this->request->getAttribute('critere');
        $numtp   = $this->request->getAttribute('numtp');

        $post = $this->request->getParsedBody();

        if (isset($post['selected_evt'])) {
            foreach ($post['selected_evt'] as $codeEvt) {
                $eventDetails                          = $tyEvtStpRepo->find(['CODE_EVT' => $codeEvt]);
                $post['selected_evt_detail'][$codeEvt] = $eventDetails;
            }
        }

        (new PaginatorGestion())->generate(10, 'CODE_EVT');
        $tyevtstp       = (new Listes($this->pdo))->listeTyevtstp($post);
        $infoPagination = PaginatorGestion::getInfoPagination();

        // $menuContextuel = new EvenementTPContextuel($this->pdo, $this->router, $this->getTranslationService());
        // foreach ($tyevtstp as &$tp) {
        //     $tp['menuContextuel'] = $menuContextuel->generate($tp, true, $id, true);
        // }

        if (\intval($id) != 0) {
            $update = true;
        }

        return $this->renderer->render('@TermeDePaiement/Modele/ajoutDeclenchementsModele', [
            'MODULE'         => $module,
            'update'         => $update ?? false,
            'critere'        => $critere,
            'numtp'          => $numtp,
            'id'             => $id,
            'tyevtstp'       => $tyevtstp,
            'infoPagination' => $infoPagination,
            'modele'         => true,
            'post'           => $post,
        ]);
    }

    public function ajaxLigneAction(
        TpEvt $tpEvt,
        TpPevt $tpPevt,
        TpPos $tpPos,
        TyEvtStp $tyEvtStp,
        TermeDePaiementService $termeDePaiementService,
    ): string {
        $module  = $this->request->getAttribute('MODULE');
        $module  = ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module);
        $id      = $this->request->getAttribute('id');
        $numtp   = $this->request->getAttribute('numtp');
        $critere = $this->request->getAttribute('critere') ?? '';

        $post = $this->request->getParsedBody();

        $critereRegroup = str_replace(Constante::oxaPipe, '|', $critere);

        $allTpEvt = $tpEvt->findAll(['NUM_CDE' => $id, 'NUM_TP' => $numtp, 'TYPEOBJ' => $module, 'CRITERE_REGROUP' => $critereRegroup]);
        $allTpPos = $tpPos->findAll(['NUM_CDE' => $id, 'NUM_TP' => $numtp, 'TYPEOBJ' => $module, 'CRITERE_REGROUP' => $critereRegroup]);

        $strategy = $termeDePaiementService->getStrategy($module, $critereRegroup);

        $lignesTpPos = $strategy->getDetailLigneTpPos($id, $allTpPos);

        foreach ($allTpEvt as &$event) {
            $event['detailEvent'] = $tyEvtStp->find(['CODE_EVT' => $event['EVENEMENT']]);
            $allLignesOnEvent     = $tpPevt->findAll(['NOCOMMAND' => (int) $id, 'NOTP' => (int) $numtp, 'NOLIGTP' => (int) $event['NOL_TP'], 'TYPEOBJ' => $module, 'CRITERE_REGROUP' => $critereRegroup]);
            $event['lignes']      = $strategy->getDetailLigneSeuil($id, $allLignesOnEvent);
        }
        unset($event);

        return $this->renderer->render('@TermeDePaiement/TermeDePaiement/ligneTermeDePaiement', [
            'MODULE'   => $module,
            'id'       => $id,
            'numtp'    => $numtp,
            'post'     => $post,
            'critere'  => $critere,
            'tps'      => $allTpEvt,
            'devise'   => $strategy->getDevise($id),
            'allTpPos' => $lignesTpPos ?? []
        ]);
    }

    /**
     * Summary of saveOrUpdateEntete
     * @param string $module
     * @param int|string $id
     * @param int|string $numTp
     * @param array<mixed> $post
     * @param string $critere
     * @return void
     */
    private function saveOrUpdateEntete(
        string $module,
        int|string $id,
        int|string $numTp,
        array $post,
        string $critere,
    ): void {
        $tpEnt    = $this->contenaire->get(TpEnt::class);
        $tpEvt    = $this->contenaire->get(TpEvt::class);
        $tpPos    = $this->contenaire->get(TpPos::class);
        $tpPevt   = $this->contenaire->get(TpPevt::class);
        $tyEvtStp = $this->contenaire->get(TyEvtStp::class);
        /** @var TermPaieRepo */
        $termPaieRep = $this->contenaire->get(TermPaieRepo::class);

        $mntBase = FloatHelper::stringToFloat($post['MNT_BASE'] ?? '');

        if ($numTp == 0) {
            $lastNumTp = $termPaieRep->getLastTp((string) $id);
            $newNumTp  = (int) $lastNumTp['NUM_TP'] + 1;

            $tpEnt->insert([
                'NUM_CDE'         => $id,
                'NUM_TP'          => $newNumTp,
                'LIBELLE'         => $post['LIBELLE_TP'],
                'DELAIFACT'       => $post['DELAIFACT_TP'] ?? '',
                'MNT_BASE'        => $mntBase,
                'POURC_TP'        => $post['POURC_TP'] ?? '',
                'CRITERE_REGROUP' => $critere,
                'BASE_LIVR'       => Sql::toBool($post['BASE_LIVR'] ?? ''),
                'TP_FACT'         => false,
                'FACTATERME'      => Sql::toBool($post['FACTATERME'] ?? ''),
                'TYPEDELAIFACT'   => $this->listeUnitesDelaiForDB[$post['TYPEDELAIFACT_TP'] ?? ''],
                'DESCRIPTIF'      => $post['DESCRIPTIF_TP'] ?? '',
                'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
            ]);

            if (!empty($post['selected_lignes_data'])) {
                foreach ($post['selected_lignes_data'] as $jsonLigne) {
                    $selectedData = json_decode($jsonLigne, true);
                    if (\is_array($selectedData)) {
                        $tpPos->insert([
                            'NUM_CDE'         => $id,
                            'CRITERE_REGROUP' => $critere,
                            'NUM_TP'          => $newNumTp,
                            'NUM_PO_CD'       => $selectedData['NO_PO'],
                            'MNT_DE_FA'       => 0,
                            'QTE_DE_FA'       => 0,
                            'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
                        ]);
                    }
                }
            }

            foreach ($post['selected_evt'] as $evt) {
                [$codeEvt, $libEvt, $isHAPLUS, $hasPostes] = explode('|', $evt, 4); // TODO : seul le codeEvt devrai etre envoyé par la vue
                $detailEvent                               = $tyEvtStp->find(['CODE_EVT' => $codeEvt]);
                $nolTp                                     = $termPaieRep->getLastNoLigneTpEvt($id, $newNumTp);
                $tpEvt->insert([
                    'NUM_CDE'         => (int) $id,
                    'NUM_TP'          => (int) $newNumTp,
                    'NOL_TP'          => (int) $nolTp['NEXT_NOL_TP'],
                    'EVENEMENT'       => $codeEvt,
                    'CRITERE_REGROUP' => $critere,
                    // Note : ce champs est obsolete et doit etre remplacé par this.EVENEMENT->TYEVTSTP.LIB_EVT
                    // 'LIB_EVT' => $detailEvent['LIB_EVT'],
                    'EVT_OK'          => Sql::boolSql2(false),
                    'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
                    'RES_TP'          => !Sql::toBool($detailEvent['HAPLUS']) ? $post['RESPONSABLE_TP-' . $codeEvt] : ''
                ]);

                if (Sql::toBool($detailEvent['PRO_POSTE'])) {
                    foreach ($post['seuils'][$codeEvt] as $key => $ligneSeuil) {
                        // if (floatval($ligneSeuil) != 0) {
                        $tpPevt->insert([
                            'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
                            'NOCOMMAND'       => $id,
                            'CRITERE_REGROUP' => $critere,
                            'NOTP'            => $newNumTp,
                            'NOLIGTP'         => $nolTp['NEXT_NOL_TP'],
                            'NOPOCDE'         => $key,
                            'POURCBUT'        => $ligneSeuil,
                            'LIGN_OK'         => false,
                        ]);
                        // }
                    }
                }
            }
        } else {
            $critereArray = ($module == 'PanierCDE') ? ['CRITERE_REGROUP' => $critere] : [];
            $tpEnt->delete(['NUM_CDE' => $id, 'NUM_TP' => $numTp, 'TYPEOBJ' => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module)] + $critereArray);
            $tpEvt->delete(['NUM_CDE' => $id, 'NUM_TP' => $numTp, 'TYPEOBJ' => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module)] + $critereArray);
            $tpPos->delete(['NUM_CDE' => $id, 'NUM_TP' => $numTp, 'TYPEOBJ' => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module)] + $critereArray);
            $tpPevt->delete(['NOCOMMAND' => $id, 'NOTP' => $numTp, 'TYPEOBJ' => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module)] + $critereArray);

            $tpEnt->insert([
                'NUM_CDE'         => $id,
                'NUM_TP'          => $numTp,
                'LIBELLE'         => $post['LIBELLE_TP'],
                'DELAIFACT'       => $post['DELAIFACT_TP'] ?? '',
                'MNT_BASE'        => $mntBase,
                'POURC_TP'        => $post['POURC_TP'] ?? '',
                'CRITERE_REGROUP' => $critere,
                'BASE_LIVR'       => Sql::toBool($post['BASE_LIVR'] ?? ''),
                'TP_FACT'         => false,
                'FACTATERME'      => Sql::toBool($post['FACTATERME'] ?? ''),
                'TYPEDELAIFACT'   => $this->listeUnitesDelaiForDB[$post['TYPEDELAIFACT_TP'] ?? ''],
                'DESCRIPTIF'      => $post['DESCRIPTIF_TP'] ?? '',
                'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
            ]);

            if (!empty($post['selected_lignes_data'])) {
                foreach ($post['selected_lignes_data'] as $jsonLigne) {
                    $selectedData = json_decode($jsonLigne, true);
                    if (\is_array($selectedData)) {
                        $tpPos->insert([
                            'NUM_CDE'         => $id,
                            'CRITERE_REGROUP' => $critere,
                            'NUM_TP'          => $numTp,
                            'NUM_PO_CD'       => $selectedData['NO_PO'],
                            'MNT_DE_FA'       => 0,
                            'QTE_DE_FA'       => 0,
                            'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
                        ]);
                    }
                }
            }

            foreach ($post['selected_evt'] as $evt) {
                [$codeEvt, $libEvt, $isHAPLUS, $hasPostes] = explode('|', $evt, 4);
                $detailEvent                               = $tyEvtStp->find(['CODE_EVT' => $codeEvt]);
                $nolTp                                     = $termPaieRep->getLastNoLigneTpEvt($id, $numTp);
                $tpEvt->insert([
                    'NUM_CDE'         => (int) $id,
                    'NUM_TP'          => (int) $numTp,
                    'NOL_TP'          => (int) $nolTp['NEXT_NOL_TP'],
                    'EVENEMENT'       => $codeEvt,
                    'CRITERE_REGROUP' => $critere,
                    // Note : ce champs est obsolete et doit etre remplacé par this.EVENEMENT->TYEVTSTP.LIB_EVT
                    // 'LIB_EVT' => $detailEvent['LIB_EVT'],
                    'EVT_OK'          => Sql::boolSql2(false),
                    'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
                    'RES_TP'          => !Sql::toBool($detailEvent['HAPLUS']) ? $post['RESPONSABLE_TP-' . $codeEvt] : ''
                ]);

                if (Sql::toBool($detailEvent['PRO_POSTE'])) {
                    foreach ($post['seuils'][$codeEvt] as $key => $ligneSeuil) {
                        // if (floatval($ligneSeuil) != 0) {
                        $tpPevt->insert([
                            'TYPEOBJ'         => ($module === 'DemandeAchat') ? 'DA_ENTET' : (($module === 'Commande') ? 'CA_ENTET' : $module),
                            'NOCOMMAND'       => $id,
                            'CRITERE_REGROUP' => $critere,
                            'NOTP'            => $numTp,
                            'NOLIGTP'         => $nolTp['NEXT_NOL_TP'],
                            'NOPOCDE'         => $key,
                            'POURCBUT'        => $ligneSeuil,
                            'LIGN_OK'         => false,
                        ]);
                        // }
                    }
                }
            }
        }
    }
}
