Commit aecf45f1 authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Bugs

Prise en compte des tests dans les return et les IFs
parent f96288bc
Loading
Loading
Loading
Loading
+65 −24
Changes for code/Créateur de formule.php: 65 added lines, 24 removed lines.
Original line number Diff line number Diff line
@@ -65,42 +65,83 @@ switch ($action) {
            try {
                $bdd->exec($def);
                $bdd->exec($body);

                echo '<div class="alert alert-success">Package de formule correctement implanté dans la BDD</div>';
                affCreateData($fc);
            } catch
            (\Exception $e) {
                ?>
                <div class="alert alert-success">Package de formule correctement implanté dans la BDD</div>
                <div class="alert alert-danger">
                    <?php
                    $msg = $e->getMessage();
                    if (str_starts_with($msg, 'ORA-24344')) {
                        $msg = 'ERREUR : Le package ne compile pas';
                    }
                    echo $msg ?>
                </div>
                <?php
            }

            echo '<h2>Code généré</h2>';
        }

                $packageName = 'FORMULE_' . $name . '2';
        Util::highlight($def, 'plsql', true, ['show-line-numbers' => true]);
        Util::highlight($body, 'plsql', true, ['show-line-numbers' => true]);
    break;
}


function affCreateData(\Application\Model\FormuleCalcul $fc)
{
    $bdd         = oseAdmin()->getBdd();
    $packageName = 'FORMULE_' . $fc->getName();
    $pe          = $bdd->select('SELECT id FROM formule WHERE package_name = :pn', ['pn' => $packageName]);
    if (empty($pe)) {
        $newFormuleId = $bdd->select('SELECT max(id) + 1 nid FROM formule')[0]['NID'];

                    ?>
                    <div class="alert alert-info">
                        Cette formule n'est pas encore déclarée en BDD.
                        Vous devez l'ajouter dans le fichier /data/formules.php
                        <pre>
    <?= $newFormuleId ?> => [
        $array  = [
            'LIBELLE'      => '...',
        'PACKAGE_NAME' => '<?= $packageName ?>',
    ],</pre>

                        Puis lancer
                        <pre>./bin/ose update-bdd-formules</pre>
            'PACKAGE_NAME' => $packageName,
        ];
        $params = $fc->getParams();
        $plibs  = [
            'I_PARAM_1_LIBELLE'  => 'i.param_1',
            'I_PARAM_2_LIBELLE'  => 'i.param_2',
            'I_PARAM_3_LIBELLE'  => 'i.param_3',
            'I_PARAM_4_LIBELLE'  => 'i.param_4',
            'I_PARAM_5_LIBELLE'  => 'i.param_5',
            'VH_PARAM_1_LIBELLE' => 'vh.param_1',
            'VH_PARAM_2_LIBELLE' => 'vh.param_2',
            'VH_PARAM_3_LIBELLE' => 'vh.param_3',
            'VH_PARAM_4_LIBELLE' => 'vh.param_4',
            'VH_PARAM_5_LIBELLE' => 'vh.param_5',
        ];
        foreach ($plibs as $col => $param) {
            if (isset($params[$param])) {
                $array[$col] = $params[$param];
            }
        }

                    </div>
                    <?php
        $kl = 0;
        foreach ($array as $k => $v) {
            if (strlen($k) > $kl) $kl = strlen($k);
        }
            } catch (\Exception $e) {
                ?>
                <div class="alert alert-danger"><?= $e->getMessage() ?>></div>
                <?php

        echo '<div class="alert alert-info">';
        echo 'Cette formule n\'est pas encore déclarée en BDD. Vous devez l\'ajouter dans le fichier /data/formules.php';
        echo '<pre>';
        echo "$newFormuleId => [\n";
        foreach ($array as $k => $v) {
            $pad = str_pad('', $kl - strlen($k), ' ');
            echo "\t'$k'$pad => '$v',\n";
        }
        echo "];";
        echo '</pre>';

            echo '<h2>Code généré</h2>';
        if (!empty($params)) {
            echo '<div class="alert alert-warning">Attention : cette formule a besoin de paramètres. Vous devrez adapter le package et écrire les requêtes correspondantes</div>';
        }

        Util::highlight($def, 'plsql', true, ['show-line-numbers' => true]);
        Util::highlight($body, 'plsql', true, ['show-line-numbers' => true]);
    break;
        echo 'Puis lancer<pre>./bin/ose update-bdd-formules</pre>';
        echo '</div>';
    }
}
 No newline at end of file
+16 −3
Changes for code/test1.php: 16 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -10,15 +10,28 @@

use UnicaenCode\Util;

$fc = new \Application\Model\FormuleCalcul(getcwd() . '/cache/guyane.xlsx', 'GUYANE');
$file = getcwd() . '/cache/OSE-calculHC-Rennes2-20211101.xlsx';

$fc = new \Application\Model\FormuleCalcul($file, 'TEST');


$f = 'IF(ISERROR([.J20]);1;[.J20])*IF(AND([.$A20]="ES3";i_structure_code<>"ES3";[.$AE$15]>=12);4/3;1)';

$f = 'SUM([.AD$1:.AD$1048576])';

return $fc->testFormule($f);
$f = 'IF([.AJ$15]>0;[.AI20]/[.AJ$15];0)';

//$f = 'IF(AND([.$D20]="Oui";[.$N20]<>"Oui";[.$A20]=i_structure_code;[.$O20]="Oui");IF([.$AG$16];[.$M20]*[.$AD20];0);0)';


//xmlDump($fc->getSheet()->getNode());

$fc->testFormule($f);

//echo $fc->getSheet(1)->html();

Util::highlight($fc->makePackageBody(), 'plsql', true, ['show-line-numbers' => true]);
//Util::highlight($fc->makePackageBody(), 'plsql', true, ['show-line-numbers' => true]);


//xmlDump($fc->getSheet()->getNode());
+2 −83
Changes for code/test2.php: 2 added lines, 83 removed lines.
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@
 */


$file  = getcwd() . '/cache/GUYANE.ods';
$file  = getcwd() . '/cache/Téléchargement/OSE-calculHC-Rennes2-20211101.xlsx';
$sheet = 1;
//$file  = getcwd() . '/cache/test.ods';
//$sheet = 0;
@@ -25,89 +25,8 @@ $rc = array_keys($s->getRefCells($c));
var_dump($rc);
//echo $s->html();
  */
$formules = [
    'T20'  => 'of:=IF([.$I20]="Référentiel";0;IF([.$F20]+[.$G20]=0;0;([.$AJ20]+[.$AP20])/([.$F20]+[.$G20]))*[.F20]+[.$BZ20])',
    'U20'  => 'of:=IF([.$I20]="Référentiel";0;IF([.$F20]+[.$G20]=0;0;([.$AJ20]+[.$AP20])/([.$F20]+[.$G20]))*[.G20])',
    'V20'  => 'of:=IF([.$I20]="Référentiel";0;[.$AV20]+[.$BB20])',
    'W20'  => 'of:=IF([.$I20]="Référentiel";[.$BH20]+[.$BN20]+[.$BT20];0)',
    'X20'  => 'of:=IF([.$I20]="Référentiel";0;IF([.$F20]+[.$G20]=0;0;([.$AL20]+[.$AR20])/([.$F20]+[.$G20]))*[.F20]+[.$CB20])',
    'Y20'  => 'of:=IF([.$I20]="Référentiel";0;IF([.$F20]+[.$G20]=0;0;([.$AL20]+[.$AR20])/([.$F20]+[.$G20]))*[.G20])',
    'Z20'  => 'of:=IF([.$I20]="Référentiel";0;[.$AX20]+[.$BD20])',
    'AA20' => 'of:=0',
    'AB20' => 'of:=IF([.$I20]="Référentiel";[.$BJ20]+[.$BP20]+[.$BV20];0)',
    'AD20' => 'of:=IF(ISERROR([.J20]);1;[.J20])*IF([.$A20]="ES3";[.N20];0)',
    'AE15' => 'of:=SUM([.AD$1:.AD$1048576])',
    'AE20' => 'of:=IF(ISERROR([.J20]);1;[.J20])*IF(AND([.$A20]="ES3";i_structure_code<>"ES3";[.$AE$15]>=12);4/3;1)',
    'AF20' => 'of:=IF(ISERROR([.K20]);1;[.K20])*IF(AND([.$A20]="ES3";i_structure_code<>"ES3";[.$AE$15]>=12);4/3;1)',
    'AH20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]<>"Référentiel";[.$A20]=i_structure_code);[.$N20]*([.$F20]+[.$G20])*[.$AE20];0)',
    'AI15' => 'of:=SUM([.AH$1:.AH$1048576])',
    'AI16' => 'of:=MIN([.AI15];i_service_du)',
    'AI17' => 'of:=i_service_du-[.AI16]',
    'AI20' => 'of:=IF([.AI$15]>0;[.AH20]/[.AI$15];0)',
    'AJ20' => 'of:=[.AI$16]*[.AI20]',
    'AK20' => 'of:=IF([.AI$17]=0;([.AH20]-[.AJ20])/[.$AE20];0)',
    'AL20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.AK20]*[.$AF20];0)',
    'AN20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]<>"Réfé""re""ntiel";[.$A20]<>i_structure_code);[.$N20]*([.$F20]+[.$G20])*[.$AE20];0)',
    'AO15' => 'of:=SUM([.AN$1:.AN$1048576])',
    'AO16' => 'of:=MIN([.AO15];[.AI17])',
    'AO17' => 'of:=[.AI17]-[.AO16]',
    'AO20' => 'of:=IF([.AO$15]>0;[.AN20]/[.AO$15];0)',
    'AP20' => 'of:=[.AO$16]*[.AO20]',
    'AQ20' => 'of:=IF([.AO$17]=0;([.AN20]-[.AP20])/[.$AE20];0)',
    'AR20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.AQ20]*[.$AF20];0)',
    'AT20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]<>"Référentiel";[.$A20]=i_structure_code);[.$N20]*[.$H20]*[.$AE20];0)',
    'AU15' => 'of:=SUM([.AT$1:.AT$1048576])',
    'AU16' => 'of:=MIN([.AU15];[.AO17])',
    'AU17' => 'of:=[.AO17]-[.AU16]',
    'AU20' => 'of:=IF([.AU$15]>0;[.AT20]/[.AU$15];0)',
    'AV20' => 'of:=[.AU$16]*[.AU20]',
    'AW20' => 'of:=IF([.AU$17]=0;([.AT20]-[.AV20])/[.$AE20];0)',
    'AX20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.AW20]*[.$AF20];0)',
    'AZ20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]<>"Référentiel";[.$A20]<>i_structure_code);[.$N20]*[.$H20]*[.$AE20];0)',
    'BA15' => 'of:=SUM([.AZ$1:.AZ$1048576])',
    'BA16' => 'of:=MIN([.BA15];[.AU17])',
    'BA17' => 'of:=[.AU17]-[.BA16]',
    'BA20' => 'of:=IF([.BA$15]>0;[.AZ20]/[.BA$15];0)',
    'BB20' => 'of:=[.BA$16]*[.BA20]',
    'BC20' => 'of:=IF([.BA$17]=0;([.AZ20]-[.BB20])/[.$AE20];0)',
    'BD20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.BC20]*[.$AF20];0)',
    'BF20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]="Référentiel";[.$A20]=i_structure_code);[.$N20]*[.$AE20];0)',
    'BG15' => 'of:=SUM([.BF$1:.BF$1048576])',
    'BG16' => 'of:=MIN([.BG15];[.BA17])',
    'BG17' => 'of:=[.BA17]-[.BG16]',
    'BG20' => 'of:=IF([.BG$15]>0;[.BF20]/[.BG$15];0)',
    'BH20' => 'of:=[.BG$16]*[.BG20]',
    'BI20' => 'of:=IF([.BG$17]=0;([.BF20]-[.BH20])/[.$AE20];0)',
    'BJ20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.BI20]*[.$AF20];0)',
    'BL20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]="Référentiel";[.$A20]<>i_structure_code;[.$A20]<>[.$K$10]);[.$N20]*[.$AE20];0)',
    'BM15' => 'of:=SUM([.BL$1:.BL$1048576])',
    'BM16' => 'of:=MIN([.BM15];[.BG17])',
    'BM17' => 'of:=[.BG17]-[.BM16]',
    'BM20' => 'of:=IF([.BM$15]>0;[.BL20]/[.BM$15];0)',
    'BN20' => 'of:=[.BM$16]*[.BM20]',
    'BO20' => 'of:=IF([.BM$17]=0;([.BL20]-[.BN20])/[.$AE20];0)',
    'BP20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.BO20]*[.$AF20];0)',
    'BR20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]<>"Oui";[.$I20]="Référentiel";[.$A20]=[.$K$10]);[.$N20]*[.$AE20];0)',
    'BS15' => 'of:=SUM([.BR$1:.BR$1048576])',
    'BS16' => 'of:=MIN([.BS15];[.BM17])',
    'BS17' => 'of:=[.BM17]-[.BS16]',
    'BS20' => 'of:=IF([.BS$15]>0;[.BR20]/[.BS$15];0)',
    'BT20' => 'of:=[.BS$16]*[.BS20]',
    'BU20' => 'of:=IF([.BS$17]=0;([.BR20]-[.BT20])/[.$AE20];0)',
    'BV20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.BU20]*[.$AF20];0)',
    'BX20' => 'of:=IF(AND([.$E20]="Oui";[.$D20]="Oui");[.$N20]*[.$AE20];0)',
    'BY15' => 'of:=SUM([.BX$1:.BX$1048576])',
    'BY16' => 'of:=MIN([.BY15];[.BS17])',
    'BY17' => 'of:=[.BS17]-[.BY16]',
    'BY20' => 'of:=IF([.BY$15]>0;[.BX20]/[.BY$15];0)',
    'BZ20' => 'of:=[.BY$16]*[.BY20]',
    'CA20' => 'of:=IF([.BY$17]=0;([.BX20]-[.BZ20])/[.$AE20];0)',
    'CB20' => 'of:=IF(i_depassement_service_du_sans_hc="Non";[.CA20]*[.$AF20];0)',
];

$t = 'T20';
//$t = 'BA15';
//$formules = [$t => $formules[$t]];
$formule = '[.AG15]>=[.AF16]';

foreach ($formules as $f) {
    $formule = new \Unicaen\OpenDocument\Calc\Formule($f);
+4 −0
Changes for data/formules.php: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -103,4 +103,8 @@ return [
        'LIBELLE'      => 'Université de Versailles Saint-Quentin-en-Yvelines',
        'PACKAGE_NAME' => 'FORMULE_UVSQ',
    ],
    24 => [
        'LIBELLE'      => 'Université Paris-Saclay',
        'PACKAGE_NAME' => 'FORMULE_SACLAY',
    ],
];
 No newline at end of file
+148 −10
Changes for module/Application/src/Model/FormuleCalcul.php: 148 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -92,11 +92,6 @@ class FormuleCalcul
            'ponderation_service_du'    => 'vh.ponderation_service_du',
            'ponderation_service_compl' => 'vh.ponderation_service_compl',
            'heures'                    => 'vh.heures',
            'p1'                        => 'vh.param_1',
            'p2'                        => 'vh.param_2',
            'p3'                        => 'vh.param_3',
            'p4'                        => 'vh.param_4',
            'p5'                        => 'vh.param_5',
            'service_fi'                => 'vh.service_fi',
            'service_fa'                => 'vh.service_fa',
            'service_fc'                => 'vh.service_fc',
@@ -118,6 +113,20 @@ class FormuleCalcul
            }
        }

        for ($colNum = 1; $colNum <= $maxCol; $colNum++) {
            $cell   = $this->getSheet()->getCellByCoords($colNum, $this->mainLine - 2);
            $colLib = Util::reduce($cell?->getContent() ?? '');
            if (str_contains($colLib, Util::reduce('spécifique'))) {
                for ($pnum = 1; $pnum <= 5; $pnum++) {
                    $cell = $this->getSheet()->getCellByCoords($colNum - 1 + $pnum, $this->mainLine);
                    if (($cell?->getContent() ?? '') != '') {
                        $this->cellsPos['vh.param_' . $pnum] = Calc::numberToLetter($colNum - 1 + $pnum);
                    }
                }
                break;
            }
        }

        $iColsRefs = [
            'type_intervenant_code'          => 'i.type_intervenant_code',
            'structure_code'                 => 'i.structure_code',
@@ -125,11 +134,6 @@ class FormuleCalcul
            'heures_service_statutaire'      => 'i.heures_service_statutaire',
            'heures_service_modifie'         => 'i.heures_service_modifie',
            'depassement_service_du_sans_hc' => 'i.depassement_service_du_sans_hc',
            'param_1'                        => 'i.param_1',
            'param_2'                        => 'i.param_2',
            'param_3'                        => 'i.param_3',
            'param_4'                        => 'i.param_4',
            'param_5'                        => 'i.param_5',
        ];
        $col       = 3; // C

@@ -141,6 +145,15 @@ class FormuleCalcul
            }
        }

        ['col' => $null, 'row' => $dsdshc] = Calc::cellNameToCoords($this->cellsPos['i.depassement_service_du_sans_hc']);

        for ($pnum = 1; $pnum <= 5; $pnum++) {
            $cell = $this->getSheet()->getCellByCoords($col + 1, $dsdshc + $pnum);
            if ($cell?->getContent()) {
                $this->cellsPos['i.param_' . $pnum] = Calc::coordsToCellName($col + 1, $dsdshc + $pnum);
            }
        }

        return $this->cellsPos;
    }

@@ -252,6 +265,31 @@ class FormuleCalcul



    public function getParams(): array
    {
        $params   = [];
        $cellsPos = $this->getCellsPos();

        for ($i = 1; $i <= 5; $i++) {
            if (isset($cellsPos['i.param_' . $i])) {
                $lcp = Calc::cellNameToCoords($cellsPos['i.param_' . $i]);
                $lcp['col']--;
                $cell                    = $this->getSheet()->getCellByCoords($lcp['col'], $lcp['row']);
                $params['i.param_' . $i] = $cell->getContent();
            }
            if (isset($cellsPos['vh.param_' . $i])) {
                $lcp                      = Calc::cellNameToCoords($cellsPos['vh.param_' . $i]);
                $lcp['row']               = $this->mainLine - 1;
                $cell                     = $this->getSheet()->getCellByCoords($lcp['col'], $lcp['row']);
                $params['vh.param_' . $i] = $cell->getContent();
            }
        }

        return $params;
    }



    public function makePackageDef(): string
    {
        $def = "CREATE OR REPLACE PACKAGE FORMULE_" . $this->getName() . " AS
@@ -292,6 +330,9 @@ END FORMULE_" . $this->getName() . ";";
        /** @var Calc\Cell[] $formules */
        foreach ($formules as $name => $cell) {
            $expr = $cell->getFormuleExpr();
            if ($this->exprIsTest($expr)) {
                $expr = $this->exprTestToIf($expr);
            }

            $mls = (string)$this->mainLine;
            if (str_ends_with($name, $mls)) {
@@ -324,6 +365,9 @@ END FORMULE_" . $this->getName() . ";";
        $formule = new Formule($tableur);

        $struct = $formule->analyse();
        if ($this->exprIsTest($struct)) {
            $struct = $this->exprTestToIf($struct);
        }

        $plsql = $this->exprToPlSql($struct);
        \UnicaenCode\Util::highlight($plsql, 'plsql', true, ['show-line-numbers' => true]);
@@ -334,6 +378,96 @@ END FORMULE_" . $this->getName() . ";";



    private function exprIsTest(array &$expr): bool
    {
        if (count($expr) === 1 && $expr[0]['type'] === 'function') {
            switch ($expr[0]['name']) {
                case 'AND':
                    return true;
                case 'OR':
                    return true;
                case 'NOT':
                    return true;
            }

            return false;
        }

        foreach ($expr as $term) {
            if ($term['type'] === 'op') {
                switch ($term['name']) {
                    case '=';
                        return true;
                    case '>=';
                        return true;
                    case '<=';
                        return true;
                    case '<>';
                        return true;
                    case '>';
                        return true;
                    case '<';
                        return true;
                }
            }
        }

        return false;
    }



    private function exprTestToIf(array $expr): array
    {
        return [
            [
                'type'  => 'function',
                'name'  => 'IF',
                'exprs' => [
                    $expr,
                    [
                        [
                            'type'  => 'number',
                            'value' => 1.0,
                        ],
                    ],
                    [
                        [
                            'type'  => 'number',
                            'value' => 0,
                        ],
                    ],
                ],
            ],
        ];
    }



    private function exprToTest(array $expr): array
    {
        $res = [];
        if (count($expr) === 1) {
            $res = $expr;
        } else {
            $res = [['type' => 'expr', 'expr' => $expr]];
        }


        $res[] = [
            'type' => 'op',
            'name' => '=',
        ];
        $res[] = [
            'type'  => 'number',
            'value' => 1.0,
        ];

        return $res;
    }



    private function exprToPlSql(array $expr): string
    {
        $this->preTraitementExpr($expr);
@@ -768,6 +902,10 @@ END FORMULE_" . $this->getName() . ";";
            $else = null;
        }

        if (!$this->exprIsTest($cond)) {
            $cond = $this->exprToTest($cond);
        }

        $plsql = 'IF ' . $this->traductionExpr($cond, false) . " THEN\n";
        $plsql .= $this->indent($this->returnPlsql($this->traductionExpr($then)));
        if ($else) {