From 1af3b5fc9bb230de149d94db8f604deef4897142 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20B?= <stephane.bouvry@unicaen.fr>
Date: Mon, 2 Oct 2023 18:46:33 +0200
Subject: [PATCH] =?UTF-8?q?Backup=20:=20D=C3=A9penses=20/=20Recettes=20v2?=
 =?UTF-8?q?=20(vue=20d=C3=A9taill=C3=A9es)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Oscar/Controller/DepenseController.php    |  20 +-
 .../Controller/ProjectGrantController.php     |  15 +-
 .../Oscar/src/Oscar/Service/SpentService.php  | 333 +++----
 .../view/oscar/project-grant/spent-list.phtml |   3 -
 .../js/oscar/src/ActivitySpentSynthesis.vue   |  13 +-
 .../assets/activityspentsynthesis-6325e583.js |   1 -
 .../assets/activityspentsynthesis-641b1fe6.js |   1 +
 public/js/oscar/vite/dist/manifest.json       |   2 +-
 ui/src/ActivitySpentDetails.js                |   4 +-
 ui/src/views/ActivitySpentSynthesis.vue       | 102 +-
 ui/src/views/SpentLinePFI.vue                 | 941 +++++++++---------
 11 files changed, 713 insertions(+), 722 deletions(-)
 delete mode 100644 public/js/oscar/vite/dist/assets/activityspentsynthesis-6325e583.js
 create mode 100644 public/js/oscar/vite/dist/assets/activityspentsynthesis-641b1fe6.js

diff --git a/module/Oscar/src/Oscar/Controller/DepenseController.php b/module/Oscar/src/Oscar/Controller/DepenseController.php
index 5bcef65a8..d99449b01 100644
--- a/module/Oscar/src/Oscar/Controller/DepenseController.php
+++ b/module/Oscar/src/Oscar/Controller/DepenseController.php
@@ -214,12 +214,13 @@ class DepenseController extends AbstractOscarController implements UseServiceCon
             // Récupération des affectations
             $postedAffectations = $this->params()->fromPost('affectation');
 
+
             if( !$postedAffectations ){
                 return $this->getResponseBadRequest("Erreur de transmission : " . print_r($_POST, true));
             }
 
             try {
-                $this->getSpentService()->updateAffectation($postedAffectations);
+                $this->getSpentService()->updateAffectation(json_decode($postedAffectations, true));
 
             } catch (\Exception $e) {
                 return $this->getResponseInternalError($e->getMessage());
@@ -246,15 +247,28 @@ class DepenseController extends AbstractOscarController implements UseServiceCon
 
         $this->getOscarUserContextService()->check(Privileges::DEPENSE_DETAILS, $activity);
 
+        $format = $this->params()->fromQuery('format', 'json');
+
         try {
             if( !$activity->getCodeEOTP() ){
                 throw new OscarException(sprintf(_("Cette activité n'a pas de Numéro financier")));
             }
             //$spents = $this->getSpentService()->getGroupedSpentsDatas($activity->getCodeEOTP());
-            $spents = $this->getSpentService()->getSpentsDatas($activity->getCodeEOTP(), SpentService::SPENT_BOTH);
+            $spents = $this->getSpentService()->getSpentsDatas($activity->getCodeEOTP(),SpentService::SPENT_BOTH);
             $spents['informations'] = $activity->toArray();
+            if( $this->getOscarUserContextService()->hasPrivileges(Privileges::ACTIVITY_SHOW, $activity) ){
+                $spents['url_activity'] = $this->url()->fromRoute('contract/show', ['id' => $activity->getId()]);
+            }
+            if( $this->getOscarUserContextService()->hasPrivileges(Privileges::DEPENSE_SYNC, $activity) ){
+                $spents['url_sync'] = $this->url()->fromRoute('contract/list-spent', ['id' => $activity->getId()]);
+            }
+            if( $this->getOscarUserContextService()->hasPrivileges(Privileges::DEPENSE_DOWNLOAD, $activity) ){
+                $spents['url_download'] = $this->url()->fromRoute('spent/activity-api', ['id' => $activity->getId()]) . '?format=excel&mode=details';
+            }
+            if( $this->getOscarUserContextService()->hasPrivileges(Privileges::MAINTENANCE_SPENDTYPEGROUP_MANAGE) ){
+                $spents['url_spentaffectation'] = $this->url()->fromRoute('spent/compte-affectation');
+            }
 
-            $format = $this->params()->fromQuery('format', 'json');
             switch($format){
                 case 'json' :
                     $datas = $this->baseJsonResponse();
diff --git a/module/Oscar/src/Oscar/Controller/ProjectGrantController.php b/module/Oscar/src/Oscar/Controller/ProjectGrantController.php
index db81fc020..e17973b1e 100644
--- a/module/Oscar/src/Oscar/Controller/ProjectGrantController.php
+++ b/module/Oscar/src/Oscar/Controller/ProjectGrantController.php
@@ -2003,18 +2003,6 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif
             $out['error'] = null; // Affiche les erreurs survenue lors de la récupération/synchronisation des données
             $out['warning'] = null; // Affiche les avertissements
 
-//            if ($this->getOscarConfigurationService()->getAutoUpdateSpent()) {
-//                if (!$this->getOscarUserContextService()->hasPrivileges(Privileges::DEPENSE_SYNC, $entity)) {
-//                    $out['warning'] = "Vous n'êtes pas autorisé à mettre à jour les dépenses, les données peuvent ne pas être à jour";
-//                } else {
-//                    try {
-//                        $this->spentService->syncSpentsByEOTP($pfi);
-//                    } catch (\Exception $e) {
-//                        $out['error'] = $e->getMessage();
-//                    }
-//                }
-//            }
-
             // Construction des données de dépense
             $out['masses'] = $masses;
             $out['dateUpdated'] = $entity->getDateTotalSpent();
@@ -2022,7 +2010,8 @@ class ProjectGrantController extends AbstractOscarController implements UseNotif
                 $pfis,
                 $this->getOscarUserContextService()->hasPrivileges(
                     Privileges::MAINTENANCE_SPENDTYPEGROUP_MANAGE
-                )
+                ),
+                'basic'
             );
         } catch (\Exception $e) {
             return $this->getResponseInternalError("Impossible de charger les dépenses pour la/les activité(s)");
diff --git a/module/Oscar/src/Oscar/Service/SpentService.php b/module/Oscar/src/Oscar/Service/SpentService.php
index b0c88a19e..7fee2c212 100644
--- a/module/Oscar/src/Oscar/Service/SpentService.php
+++ b/module/Oscar/src/Oscar/Service/SpentService.php
@@ -847,204 +847,90 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
      * @param false $curationNB
      * @return array
      */
-    public function getSynthesisDatasPFI($pfi, $curationNB = false) :array
+    public function getSynthesisDatasPFI($pfis, $curationNB = false, string $mode = 'advanced' ) :array
     {
-        $clauseEffective = $this->getOscarConfigurationService()->getSpentEffectiveClauseValue();
-        $clausePredicted = $this->getOscarConfigurationService()->getSpentPredictedClauseValue();
-
-        // Récupération des dépenses
-        $effectives = $spents = $this->getSpentsByPFIs($pfi, self::SPENT_EFFECTIVE);
-        $predicted = $this->getSpentsByPFIs($pfi, self::SPENT_PREVISIONNAL);
+        $spents = [];
+        foreach ($pfis as $pfi) {
+            $spents = array_merge($spents, $this->getSpentsByPFI($pfi, self::SPENT_BOTH));
+        }
 
         // Récupération des Masses comptable configurées dans config
         $masses = $this->getOscarConfigurationService()->getMasses();
 
-        // Structuration du tableau de retour
-        $out = [];
-
-        $out['N.B'] = 0.0;
-        $out['entries'] = count($spents);
-        $out['total'] = 0.0;
-
-        $predicted_aggregator = [];
-
-
-        // Dépenses "prévues"
-        $out['predicted'] = [
-            'N.B' => []
-        ];
-        $out['predicted_count'] = count($predicted);
-        $out['predicted_total'] = 0.0;
-        $out['details'] = [];
-        $out['predicted_totals'] = [
-            'N.B' => 0.0
-        ];
-
-        // Dépenses "effectives"
-        $out['effective'] = [
-            'N.B' => []
-        ];
-        $out['effective_count'] = count($effectives);
-        $out['effective_total'] = 0.0;
-        $out['effective_totals'] = [
-            'N.B' => 0.0
-        ];
-
-        $out['details'] = [
-            'N.B' => []
-        ];
-        $out['totals'] = [
-            'N.B' => 0.0
-        ];
-        $out['recettes'] = [
-            'total'     => 0.0,
-            'details'   => []
+        return [
+            'pfi' => $pfi,
+            'masses' => $masses,
+            'synthesis' => $this->getSpentDatasSynthesisBySpents($spents)
         ];
 
-        if( $curationNB ){
-            $out['curations'] = [];
-        }
-
-        foreach ($masses as $key => $label) {
-            $out[$key] = 0.0;
-            $out['totals'][$key] = 0.0;
-            $out['details'][$key] = [];
-
-            $out['predicted'][$key] = [];
-            $out['predicted_totals'][$key] = 0.0;
-
-            $out['effective'][$key] = [];
-            $out['effective_totals'][$key] = 0.0;
-        }
-
-        // On commence par traiter les données effectives
-        $idsEffectiveDone = [];
-        // Aggrégation des données
-        /** @var SpentLine $spent */
-        foreach ($effectives as $spent) {
-
-            $compte = $spent->getCompteGeneral();
-            $compteInfos = $this->getCompte($compte);
-            $annexe = $compteInfos['annexe'];
-            $montant = floatval($spent->getMontant());
-            $out['details'][] = $spent->toArray();
-            $idSifac = $spent->getNumSifac();
-            $idsEffectiveDone[] = $idSifac;
-
-            if( $annexe == '' || $annexe == null ){
-                $annexe = $compteInfos['masse_inherit'];
-            }
-
-            if( $annexe == '0' ){
-                continue;
-            }
-
-            if( $annexe == '1' ){
-                $out['recettes']['total'] += $montant;
-                $out['recettes']['details'][] = $spent->toArray();
-                continue;
-            }
-
-            if ($annexe == '') {
-                if( $curationNB ){
-                    $exist = $compte == $compteInfos['code'];
-                    if( !array_key_exists($compte, $out['curations']) ){
-                        $out['curations'][$compte] = [
-                            'compte' => $compte,
-                            'compteInfos' => $compteInfos,
-                            'label' => $compteInfos['label'],
-                            'montant' => 0.0,
-                            'totalEntries' => 0,
-                            'exist' => $exist ? 'true' : 'false'
-                        ];
-                    }
-                    $out['curations'][$compte]['montant'] += $montant;
-                    $out['curations'][$compte]['totalEntries']++;
-                }
-                $annexe = 'N.B';
-                if (!in_array($compte, $out['details'][$annexe]))
-                    $out['details'][$annexe][] = $compte . ' (' . $compteInfos['label'] . ')';
-            }
-
-
-
-            $out[$annexe] += $montant;
-            $out['total'] += $montant;
-            $out['totals'][$annexe] += $montant;
-
-            $out['effective_total'] += $montant;
-            $out['effective_totals'][$annexe] += $montant;
-        }
-
-        // Puis les données prévues en évacuant les lignes déjà présentes dans les données effectives
-        //        /** @var SpentLine $spent */
-        foreach ($predicted as $spent) {
-
-            $idSifac = $spent->getNumSifac();
-            if( in_array($idSifac, $idsEffectiveDone) ){
-                continue;
-            }
-            $compte = $spent->getCompteGeneral();
-            $compteInfos = $this->getCompte($compte);
-            $annexe = $compteInfos['annexe'];
-            $montant = floatval($spent->getMontant());
-            $out['details'][] = $spent->toArray();
-
-            if( $annexe == '' || $annexe == null ){
-                $annexe = $compteInfos['masse_inherit'];
-            }
-
-            if( $annexe == '0' ){
-                continue;
-            }
-
-            if( $annexe == '1' ){
-                $out['recettes']['total'] += $montant;
-                $out['recettes']['details'][] = $spent->toArray();
-                continue;
-            }
-
-            if ($annexe == '') {
-                if( $curationNB ){
-                    $exist = $compte == $compteInfos['code'];
-                    if( !array_key_exists($compte, $out['curations']) ){
-                        $out['curations'][$compte] = [
-                            'compte' => $compte,
-                            'compteInfos' => $compteInfos,
-                            'label' => $compteInfos['label'],
-                            'montant' => 0.0,
-                            'totalEntries' => 0,
-                            'exist' => $exist ? 'true' : 'false'
-                        ];
-                    }
-                    $out['curations'][$compte]['montant'] += $montant;
-                    $out['curations'][$compte]['totalEntries']++;
-                }
-                $annexe = 'N.B';
-                if (!in_array($compte, $out['details'][$annexe]))
-                    $out['details'][$annexe][] = $compte . ' (' . $compteInfos['label'] . ')';
-            }
-
-
-
-            $out[$annexe] += $montant;
-            $out['total'] += $montant;
-            $out['totals'][$annexe] += $montant;
-
-            $out['predicted_total'] += $montant;
-            $out['predicted_totals'][$annexe] += $montant;
-        }
-
 
+//
+//
+//        // Structuration du tableau de retour
+//        $out = [];
+//
+//        $out['N.B'] = 0.0;
+//        $out['entries'] = count($spents);
+//        $out['total'] = 0.0;
+//
+//        $predicted_aggregator = [];
+//
+//
+//        // Dépenses "prévues"
+//        $out['predicted'] = [
+//            'N.B' => []
+//        ];
+//        $out['predicted_count'] = count($predicted);
+//        $out['predicted_total'] = 0.0;
+//        $out['predicted_totals'] = [
+//            'N.B' => 0.0
+//        ];
+//
+//        // Dépenses "effectives"
+//        $out['effective'] = [
+//            'N.B' => []
+//        ];
+//        $out['effective_count'] = count($effectives);
+//        $out['effective_total'] = 0.0;
+//        $out['effective_totals'] = [
+//            'N.B' => 0.0
+//        ];
+//
+//        $out['totals'] = [
+//            'N.B' => 0.0
+//        ];
+//        $out['recettes'] = [
+//            'total'     => 0.0,
+//        ];
+//
+//        if( $curationNB ){
+//            $out['curations'] = [];
+//        }
+//
+//        foreach ($masses as $key => $label) {
+//            $out[$key] = 0.0;
+//            $out['totals'][$key] = 0.0;
+//
+//            $out['predicted'][$key] = [];
+//            $out['predicted_totals'][$key] = 0.0;
+//
+//            $out['effective'][$key] = [];
+//            $out['effective_totals'][$key] = 0.0;
+//        }
+//
+//        // On commence par traiter les données effectives
+//        $idsEffectiveDone = [];
 //        // Aggrégation des données
 //        /** @var SpentLine $spent */
-//        foreach (array_merge($effectives, $predicted) as $spent) {
+//        foreach ($effectives as $spent) {
 //
 //            $compte = $spent->getCompteGeneral();
 //            $compteInfos = $this->getCompte($compte);
 //            $annexe = $compteInfos['annexe'];
 //            $montant = floatval($spent->getMontant());
-//            $out['details'][] = $spent->toArray();
+//            //$out['details'][] = $spent->toArray();
+//            $idSifac = $spent->getNumSifac();
+//            $idsEffectiveDone[] = $idSifac;
 //
 //            if( $annexe == '' || $annexe == null ){
 //                $annexe = $compteInfos['masse_inherit'];
@@ -1056,7 +942,7 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
 //
 //            if( $annexe == '1' ){
 //                $out['recettes']['total'] += $montant;
-//                $out['recettes']['details'][] = $spent->toArray();
+//                //$out['recettes']['details'][] = $spent->toArray();
 //                continue;
 //            }
 //
@@ -1077,8 +963,8 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
 //                    $out['curations'][$compte]['totalEntries']++;
 //                }
 //                $annexe = 'N.B';
-//                if (!in_array($compte, $out['details'][$annexe]))
-//                    $out['details'][$annexe][] = $compte . ' (' . $compteInfos['label'] . ')';
+////                if (!in_array($compte, $out['details'][$annexe]))
+////                    $out['details'][$annexe][] = $compte . ' (' . $compteInfos['label'] . ')';
 //            }
 //
 //
@@ -1087,18 +973,69 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
 //            $out['total'] += $montant;
 //            $out['totals'][$annexe] += $montant;
 //
-//            if( $spent->getRldnr() == $clauseEffective ){
-//                $out['effective_total'] += $montant;
-//                $out['effective_totals'][$annexe] += $montant;
+//            $out['effective_total'] += $montant;
+//            $out['effective_totals'][$annexe] += $montant;
+//        }
+//
+//        // Puis les données prévues en évacuant les lignes déjà présentes dans les données effectives
+//        //        /** @var SpentLine $spent */
+//        foreach ($predicted as $spent) {
+//
+//            $idSifac = $spent->getNumSifac();
+//            if( in_array($idSifac, $idsEffectiveDone) ){
+//                continue;
+//            }
+//            $compte = $spent->getCompteGeneral();
+//            $compteInfos = $this->getCompte($compte);
+//            $annexe = $compteInfos['annexe'];
+//            $montant = floatval($spent->getMontant());
+//            //$out['details'][] = $spent->toArray();
+//
+//            if( $annexe == '' || $annexe == null ){
+//                $annexe = $compteInfos['masse_inherit'];
+//            }
+//
+//            if( $annexe == '0' ){
+//                continue;
 //            }
-//            elseif ($spent->getRldnr() == $clausePredicted) {
-//                $out['predicted_total'] += $montant;
-//                $out['predicted_totals'][$annexe] += $montant;
+//
+//            if( $annexe == '1' ){
+//                $out['recettes']['total'] += $montant;
+//                //$out['recettes']['details'][] = $spent->toArray();
+//                continue;
 //            }
-//            else {
-//                $this->getLoggerService()->error("Une valeur de dépenses pour $spent est incohérente pour le champ RLDNR");
+//
+//            if ($annexe == '') {
+//                if( $curationNB ){
+//                    $exist = $compte == $compteInfos['code'];
+//                    if( !array_key_exists($compte, $out['curations']) ){
+//                        $out['curations'][$compte] = [
+//                            'compte' => $compte,
+//                            'compteInfos' => $compteInfos,
+//                            'label' => $compteInfos['label'],
+//                            'montant' => 0.0,
+//                            'totalEntries' => 0,
+//                            'exist' => $exist ? 'true' : 'false'
+//                        ];
+//                    }
+//                    $out['curations'][$compte]['montant'] += $montant;
+//                    $out['curations'][$compte]['totalEntries']++;
+//                }
+//                $annexe = 'N.B';
+//                if (!in_array($compte, $out['details'][$annexe]))
+//                    $out['details'][$annexe][] = $compte . ' (' . $compteInfos['label'] . ')';
 //            }
+//
+//
+//
+//            $out[$annexe] += $montant;
+//            $out['total'] += $montant;
+//            $out['totals'][$annexe] += $montant;
+//
+//            $out['predicted_total'] += $montant;
+//            $out['predicted_totals'][$annexe] += $montant;
 //        }
+
         return $out;
     }
 
@@ -1269,7 +1206,9 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
      * @return array[]
      */
     public function getSpentDatasSynthesisBySpents($spents){
+        $pfis = [];
         $synthesis = [
+            'lines' => count($spents),
             '1' => [
                 'label' => "Recettes",
                 'total' => 0.0,
@@ -1321,6 +1260,9 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
         $numSifacDone = [];
         /** @var SpentLine $spent */
         foreach ($spents as $spent) {
+            if( !in_array($spent->getPfi(), $pfis) ){
+                $pfis[] = $spent->getPfi();
+            }
             if($spent->getBtart() == SpentLine::BTART_EFFECTUE && !in_array($spent->getNumSifac(), $numSifacDone)){
                 $numSifacDone[] = $spent->getNumSifac();
             }
@@ -1352,7 +1294,7 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
             $synthesis[$masse]['total'] += $spent->getMontant();
             $synthesis[$masse]['total_effectue'] += $totalEffectue;
             $synthesis[$masse]['total_engage'] += $totalEngage;
-            
+
             if( in_array($masse, $massesKeys) ){
                 $synthesis['totaux']['effectue'] += $totalEffectue;
                 $synthesis['totaux']['engage'] += $totalEngage;
@@ -1360,6 +1302,7 @@ class SpentService implements UseLoggerService, UseOscarConfigurationService, Us
             $synthesis[$masse]['nbr']++;
 
         }
+        $synthesis['pfis'] = $pfis;
 
 
         return $synthesis;
diff --git a/module/Oscar/view/oscar/project-grant/spent-list.phtml b/module/Oscar/view/oscar/project-grant/spent-list.phtml
index d09c824c5..01e4f7749 100644
--- a/module/Oscar/view/oscar/project-grant/spent-list.phtml
+++ b/module/Oscar/view/oscar/project-grant/spent-list.phtml
@@ -16,11 +16,8 @@
 
 </style>
 <section class="container-fluid">
-    <h1>TEST</h1>
     <div id="depensesdetails"
-         data-informations="<?= json_encode($activity->toArray()) ?>"
          data-url="<?= $this->url('spent/activity-api', ['id' => $activity->getId()]) ?>"
-
     >
     </div>
     <?= $this->Vite()->addJs('src/ActivitySpentDetails.js'); ?>
diff --git a/public/js/oscar/src/ActivitySpentSynthesis.vue b/public/js/oscar/src/ActivitySpentSynthesis.vue
index 33c1459c1..8a72586c7 100644
--- a/public/js/oscar/src/ActivitySpentSynthesis.vue
+++ b/public/js/oscar/src/ActivitySpentSynthesis.vue
@@ -52,6 +52,8 @@
             </div>
         </transition>
 
+      {{ synthesis }}
+
         <table class="table table-condensed" v-if="!pendingMsg">
             <tr v-for="m,k in masses">
                 <th>{{ m }}</th>
@@ -91,9 +93,6 @@
     </section>
 </template>
 <script>
-    // nodejs node_modules/.bin/poi watch --format umd --moduleName  ActivitySpentSynthesis --filename.js ActivitySpentSynthesis.js --dist public/js/oscar/dist public/js/oscar/src/ActivitySpentSynthesis.vue
-
-
     export default {
         props: ['url', 'manageDepense'],
 
@@ -106,7 +105,13 @@
                 masses: {},
                 dateUpdated: null,
                 showCuration: false,
-                affectations: {}
+                affectations: {},
+
+              // URL
+              url_activity: null,
+              url_sync: null,
+              url_download: null,
+              url_spentaffectation: null,
             }
         },
 
diff --git a/public/js/oscar/vite/dist/assets/activityspentsynthesis-6325e583.js b/public/js/oscar/vite/dist/assets/activityspentsynthesis-6325e583.js
deleted file mode 100644
index 5efd9d572..000000000
--- a/public/js/oscar/vite/dist/assets/activityspentsynthesis-6325e583.js
+++ /dev/null
@@ -1 +0,0 @@
-import{a as C,c as n,b as h,w as p,T as m,F as _,f,d as e,g as r,t as i,e as u,o,h as k,v as M,l as D}from"../vendor.js";import{_ as N}from"../vendor3.js";const T={props:{url:{required:!0}},computed:{synthesis(){return this.infos}},data(){return{infos:null,pendingMsg:null,showCuration:!1,masses:[]}},methods:{fetch(){this.pendingMsg="Chargement des données financières",C.get(this.url).then(s=>{console.log("OK",s),this.infos=s.data.synthesis,this.masses=s.data.masses},s=>{console.log(s)}).then(s=>{this.pendingMsg=!1})}},mounted(){this.fetch()}},V={key:0,class:"overlay"},A={class:"overlay-content"},B=e("p",null,"Les comptes suivants ne sont pas qualifiés, vous pouvez utiliser cet écran pour les attribuer à une masse budgétaire :",-1),F={class:"card row"},L={class:"col-md-4"},q={class:"col-md-8"},U=["onUpdate:modelValue","onChange"],j=e("option",{value:"0"},"Ignorer",-1),E=e("option",{value:"1"},"Traiter comme une recette",-1),I=["value"],S=e("hr",null,null,-1),z=e("i",{class:"icon-cancel-circled"},null,-1),O=e("i",{class:"icon-floppy"},null,-1),Q={key:0,class:"alert alert-danger"},R=e("i",{class:"icon-attention-1"},null,-1),H={key:0,class:"alert-warning alert"},K=e("i",{class:"icon-warning-empty"},null,-1),P={key:0,class:"pending"},X={class:""},G=e("i",{class:"icon-spinner animate-spin"},null,-1),J={key:0,class:"table table-condensed"},W=e("tr",null,[e("th",null,"masse"),e("th",{style:{"text-align":"right"}},"Réalisées"),e("th",{style:{"text-align":"right"}},"Engagées")],-1),Y={style:{"text-align":"right","white-space":"nowrap"}},Z={style:{"text-align":"right","white-space":"nowrap"}},x={key:0,style:{"border-top":"solid #000 thin"}},$=e("br",null,null,-1),ee={style:{"font-weight":"300"},class:"error-block"},se=e("i",{class:"icon-attention"},null,-1),te={key:0},ne=e("i",{class:"icon-cog"},null,-1),oe={key:1},le={style:{"text-align":"right","white-space":"nowrap"}},ie={style:{"border-top":"solid #000 thin","font-size":"1.6em"}},ae=e("th",null,"TOTAL : ",-1),re={style:{"text-align":"right","white-space":"nowrap"}},de={style:{"text-align":"right","white-space":"nowrap"}},ue={key:1,class:"table table-condensed"},ce=e("th",null,[e("i",{class:"icon-euro"}),r("Recettes")],-1),he={style:{"text-align":"right","white-space":"nowrap"}},pe={key:0};function me(s,d,g,y,a,l){return o(),n("section",null,[h(m,{name:"fade"},{default:p(()=>[a.showCuration?(o(),n("div",V,[e("div",A,[e("h3",null,[r(" Qualification des comptes "),e("span",{class:"overlay-closer",onClick:d[0]||(d[0]=t=>a.showCuration=!1)},"X")]),B,(o(!0),n(_,null,f(l.synthesis.curations,t=>(o(),n("div",F,[e("div",L,[e("strong",null,i(t.compte),1),r(" - "),e("em",null,i(t.compteInfos.label),1)]),e("div",q,[k(e("select",{name:"",id:"",class:"form-control","onUpdate:modelValue":c=>s.affectations[t.compte]=c,onChange:c=>s.updateAffectations(t.compte,c)},[j,E,(o(!0),n(_,null,f(a.masses,(c,w)=>(o(),n("option",{value:w},i(c),9,I))),256))],40,U),[[M,s.affectations[t.compte]]])])]))),256)),S,e("button",{onClick:d[1]||(d[1]=(...t)=>s.handlerCurationCancel&&s.handlerCurationCancel(...t)),class:"btn btn-danger"},[z,r("Annuler")]),e("button",{onClick:d[2]||(d[2]=(...t)=>s.handlerCurationConfirm&&s.handlerCurationConfirm(...t)),class:"btn btn-success"},[O,r("Enregistrer")])])])):u("",!0)]),_:1}),h(m,{name:"fade"},{default:p(()=>[s.error?(o(),n("div",Q,[R,r(" Il y'a eut un problème lors de la récupération des données financières : "+i(s.error),1)])):u("",!0)]),_:1}),h(m,{name:"fade"},{default:p(()=>[s.warning?(o(),n("div",H,[K,r(" Les données affichées peuvent ne pas être à jour : "+i(s.warning),1)])):u("",!0)]),_:1}),h(m,{name:"fade"},{default:p(()=>[a.pendingMsg?(o(),n("div",P,[e("div",X,[G,r(" "+i(a.pendingMsg),1)])])):u("",!0)]),_:1}),!a.pendingMsg&&l.synthesis!=null?(o(),n("table",J,[W,(o(!0),n(_,null,f(a.masses,(t,c)=>(o(),n("tr",null,[e("th",null,i(t),1),e("td",Y,i(s.$filters.money(l.synthesis.effective_totals[c]))+" €",1),e("td",Z,i(s.$filters.money(l.synthesis.predicted_totals[c]))+" €",1)]))),256)),l.synthesis["N.B"]?(o(),n("tr",x,[e("th",null,[r(" Hors masse"),$,e("small",ee,[se,r(" Les annexes de certains comptes ne sont pas renseignés : "),e("ul",null,[(o(!0),n(_,null,f(s.getNoMasse,t=>(o(),n("li",null,[e("strong",null,i(t),1),l.synthesis.curations?(o(),n("div",te)):u("",!0)]))),256))]),s.manageDepense?(o(),n("a",{key:0,onClick:d[3]||(d[3]=(...t)=>s.handlerCuration&&s.handlerCuration(...t)),class:"btn btn-xs btn-default"},[ne,r("Qualifer les comptes")])):(o(),n("span",oe,"Merci de contacter un administrateur pour que les annexes des comptes soient configurés."))])]),e("td",le,"$filters.money("+i(l.synthesis["N.B"])+") €",1)])):u("",!0),e("tr",ie,[ae,e("td",re,i(s.$filters.money(l.synthesis.effective_total))+" €",1),e("td",de,i(s.$filters.money(l.synthesis.predicted_total))+" €",1)])])):u("",!0),l.synthesis&&l.synthesis.recettes?(o(),n("table",ue,[e("tr",null,[ce,e("td",he,i(s.$filters.money(l.synthesis.recettes.total))+" €",1)])])):u("",!0),e("small",null,[r("Données mise à jour : "),s.dateUpdated?(o(),n("strong",pe,i(s.dateUpdated.date|s.dateFull),1)):u("",!0)])])}const _e=N(T,[["render",me]]),fe={money(s){for(var d=s.toFixed(2),a="",g=!1,y=0,a=[],l=d.length-1;l>=0;l--){var t=d[l];t=="."?(a.push(","),g=!0):(a.push(t),g==!0&&t!="-"&&l>0&&(y++,y%3==0&&a.push(" ")))}return a.reverse().join("")}};let v=document.querySelector("#depenses2");const b=D(_e,{url:v.dataset.url,syncurl:v.dataset.syncurl});b.config.globalProperties.$filters={money:function(s){return fe.money(s)}};b.mount("#depenses2");
diff --git a/public/js/oscar/vite/dist/assets/activityspentsynthesis-641b1fe6.js b/public/js/oscar/vite/dist/assets/activityspentsynthesis-641b1fe6.js
new file mode 100644
index 000000000..631e6f93f
--- /dev/null
+++ b/public/js/oscar/vite/dist/assets/activityspentsynthesis-641b1fe6.js
@@ -0,0 +1 @@
+import{a as k,c as o,b as c,w as y,T as f,d as s,F as g,f as m,t as n,e as h,g as r,k as w,o as l,h as M,v as I,l as N}from"../vendor.js";import{_ as B}from"../vendor3.js";const D={props:{url:{required:!0}},computed:{synthesis(){return this.infos}},data(){return{infos:null,pendingMsg:null,showCuration:!1,masses:[],synthesis:null}},methods:{fetch(){this.pendingMsg="Chargement des données financières",k.get(this.url).then(e=>{this.synthesis=e.data.synthesis,this.masses=e.data.masses},e=>{console.log(e)}).then(e=>{this.pendingMsg=!1})}},mounted(){this.fetch()}},T={key:0,class:"overlay"},V={class:"overlay-content"},F=s("p",null,"Les comptes suivants ne sont pas qualifiés, vous pouvez utiliser cet écran pour les attribuer à une masse budgétaire :",-1),A={class:"card row"},R={class:"col-md-4"},U={class:"col-md-8"},j=["onUpdate:modelValue","onChange"],q=s("option",{value:"0"},"Ignorer",-1),E=s("option",{value:"1"},"Traiter comme une recette",-1),L=["value"],S=s("hr",null,null,-1),z=s("i",{class:"icon-cancel-circled"},null,-1),H=s("i",{class:"icon-floppy"},null,-1),P={key:0,class:"alert alert-danger"},Q=s("i",{class:"icon-attention-1"},null,-1),X={key:0,class:"alert-warning alert"},G=s("i",{class:"icon-warning-empty"},null,-1),J={key:0,class:"pending"},K={class:""},O=s("i",{class:"icon-spinner animate-spin"},null,-1),W={key:0,class:"table table-condensed card synthesis"},Y=s("thead",null,[s("tr",null,[s("th",null,"Masse"),s("th",{style:{"text-align":"right"}},"Engagé"),s("th",{style:{"text-align":"right"}},"Réalisé")])],-1),Z=["href"],$={style:{"text-align":"right"}},x={style:{"text-align":"right"}},ss={class:"total"},es=s("th",null,"Total",-1),ts={style:{"text-align":"right"}},ns={style:{"text-align":"right"}},os={key:0},ls=s("small",null,[s("i",{class:"icon-attention"}),r(" Hors-masse")],-1),is={href:"#repport-nb",class:"label label-info"},rs={style:{"text-align":"right"}},as={style:{"text-align":"right"}},ds={key:1},hs=s("h3",null,[s("i",{class:"icon-calculator"}),r("Recettes")],-1),us={key:0,class:"table table-condensed card synthesis"},cs={class:"label label-info xs",href:"#repport-1"},ys={style:{"text-align":"right"}},fs={key:2},_s={key:0},ps=s("i",{class:"icon-eye-off"},null,-1),gs={key:1},ms=s("i",{class:"icon-eye"},null,-1),bs={key:0,class:"table table-condensed card synthesis"},vs={class:"label label-info",href:"#repport-0"},Cs={style:{"text-align":"right"}},ks={key:0};function ws(e,a,_,p,t,u){return l(),o("section",null,[c(f,{name:"fade"},{default:y(()=>[t.showCuration?(l(),o("div",T,[s("div",V,[s("h3",null,[r(" Qualification des comptes "),s("span",{class:"overlay-closer",onClick:a[0]||(a[0]=i=>t.showCuration=!1)},"X")]),F,(l(!0),o(g,null,m(t.synthesis.curations,i=>(l(),o("div",A,[s("div",R,[s("strong",null,n(i.compte),1),r(" - "),s("em",null,n(i.compteInfos.label),1)]),s("div",U,[M(s("select",{name:"",id:"",class:"form-control","onUpdate:modelValue":d=>e.affectations[i.compte]=d,onChange:d=>e.updateAffectations(i.compte,d)},[q,E,(l(!0),o(g,null,m(t.masses,(d,C)=>(l(),o("option",{value:C},n(d),9,L))),256))],40,j),[[I,e.affectations[i.compte]]])])]))),256)),S,s("button",{onClick:a[1]||(a[1]=(...i)=>e.handlerCurationCancel&&e.handlerCurationCancel(...i)),class:"btn btn-danger"},[z,r("Annuler")]),s("button",{onClick:a[2]||(a[2]=(...i)=>e.handlerCurationConfirm&&e.handlerCurationConfirm(...i)),class:"btn btn-success"},[H,r("Enregistrer")])])])):h("",!0)]),_:1}),c(f,{name:"fade"},{default:y(()=>[e.error?(l(),o("div",P,[Q,r(" Il y'a eut un problème lors de la récupération des données financières : "+n(e.error),1)])):h("",!0)]),_:1}),c(f,{name:"fade"},{default:y(()=>[e.warning?(l(),o("div",X,[G,r(" Les données affichées peuvent ne pas être à jour : "+n(e.warning),1)])):h("",!0)]),_:1}),c(f,{name:"fade"},{default:y(()=>[t.pendingMsg?(l(),o("div",J,[s("div",K,[O,r(" "+n(t.pendingMsg),1)])])):h("",!0)]),_:1}),t.synthesis?(l(),o("table",W,[Y,s("tbody",null,[(l(!0),o(g,null,m(t.synthesis.masses,(i,d)=>(l(),o("tr",null,[s("th",null,[s("small",null,n(i),1),s("a",{class:"label label-info xs",href:"#repport-"+d},n(t.synthesis.synthesis[d].nbr_effectue)+" / "+n(t.synthesis.synthesis[d].nbr_engage),9,Z)]),s("td",$,n(e.$filters.money(t.synthesis.synthesis[d].total_engage)),1),s("td",x,n(e.$filters.money(t.synthesis.synthesis[d].total_effectue)),1)]))),256))]),s("tbody",null,[s("tr",ss,[es,s("td",ts,n(e.$filters.money(t.synthesis.synthesis.totaux.engage)),1),s("td",ns,n(e.$filters.money(t.synthesis.synthesis.totaux.effectue)),1)])]),s("tbody",null,[t.synthesis.synthesis["N.B"].total!=0?(l(),o("tr",os,[s("th",null,[ls,s("a",is,n(t.synthesis.synthesis["N.B"].nbr),1)]),s("td",rs,n(e.$filters.money(t.synthesis.synthesis["N.B"].total_engage)),1),s("td",as,n(e.$filters.money(t.synthesis.synthesis["N.B"].total_effectue)),1)])):h("",!0)])])):h("",!0),e.manageRecettes?(l(),o("div",ds,[hs,e.spentlines?(l(),o("table",us,[s("tbody",null,[s("tr",null,[s("th",null,[r("Recette "),s("a",cs,n(t.synthesis.synthesis[1].nbr),1)]),s("td",ys,n(e.$filters.money(t.synthesis.synthesis[1].total)),1)])])])):h("",!0)])):h("",!0),e.manageIgnored&&t.synthesis.synthesis[0].total!=0?(l(),o("div",fs,[s("a",{href:"#",onClick:a[3]||(a[3]=w(i=>e.displayIgnored=!e.displayIgnored,["prevent"]))},[e.displayIgnored?(l(),o("span",_s,[ps,r(" Cacher")])):(l(),o("span",gs,[ms,r(" Montrer")])),r(" les données ignorées ")]),e.spentlines&&e.displayIgnored?(l(),o("table",bs,[s("tbody",null,[s("tr",null,[s("th",null,[r(" Ignorées "),s("a",vs,n(t.synthesis.synthesis[0].nbr),1)]),s("td",Cs,n(e.$filters.money(t.synthesis.synthesis[0].total)),1)])])])):h("",!0)])):h("",!0),s("small",null,[r("Données mise à jour : "),e.dateUpdated?(l(),o("strong",ks,n(e.dateUpdated.date|e.dateFull),1)):h("",!0)])])}const Ms=B(D,[["render",ws]]),Is={money(e){for(var a=e.toFixed(2),t="",_=!1,p=0,t=[],u=a.length-1;u>=0;u--){var i=a[u];i=="."?(t.push(","),_=!0):(t.push(i),_==!0&&i!="-"&&u>0&&(p++,p%3==0&&t.push(" ")))}return t.reverse().join("")}};let b=document.querySelector("#depenses2");const v=N(Ms,{url:b.dataset.url,syncurl:b.dataset.syncurl});v.config.globalProperties.$filters={money:function(e){return Is.money(e)}};v.mount("#depenses2");
diff --git a/public/js/oscar/vite/dist/manifest.json b/public/js/oscar/vite/dist/manifest.json
index ff98dcc35..37ae29faa 100644
--- a/public/js/oscar/vite/dist/manifest.json
+++ b/public/js/oscar/vite/dist/manifest.json
@@ -13,7 +13,7 @@
     "file": "vendor3.js"
   },
   "src/ActivitySpentSynthesis.js": {
-    "file": "assets/activityspentsynthesis-6325e583.js",
+    "file": "assets/activityspentsynthesis-641b1fe6.js",
     "imports": [
       "_vendor.js",
       "_vendor3.js"
diff --git a/ui/src/ActivitySpentDetails.js b/ui/src/ActivitySpentDetails.js
index c2ea63aec..6f6df57cd 100644
--- a/ui/src/ActivitySpentDetails.js
+++ b/ui/src/ActivitySpentDetails.js
@@ -5,9 +5,7 @@ import MoneyFilter from "./utils/MoneyFilter";
 
 let elemDatas = document.querySelector('#depensesdetails');
 const app = createApp(SpentLinePFI, {
-    "url": elemDatas.dataset.url,
-    "syncurl": elemDatas.dataset.syncurl,
-    "informations": elemDatas.dataset.informations
+    "url": elemDatas.dataset.url
 });
 app.config.globalProperties.$filters = {
    money: function (value){
diff --git a/ui/src/views/ActivitySpentSynthesis.vue b/ui/src/views/ActivitySpentSynthesis.vue
index 35cb6c689..9121231d0 100644
--- a/ui/src/views/ActivitySpentSynthesis.vue
+++ b/ui/src/views/ActivitySpentSynthesis.vue
@@ -52,48 +52,76 @@
       </div>
     </transition>
 
-    <table class="table table-condensed" v-if="!pendingMsg && synthesis != null">
+    <table class="table table-condensed card synthesis" v-if="synthesis">
+      <thead>
       <tr>
-        <th>masse</th>
-        <th style="text-align: right;">Réalisées</th>
-        <th style="text-align: right;">Engagées</th>
+        <th>Masse</th>
+        <th style="text-align: right">Engagé</th>
+        <th style="text-align: right">Réalisé</th>
       </tr>
-      <tr v-for="m,k in masses">
-        <th>{{ m }}</th>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis['effective_totals'][k]) }} €</td>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis['predicted_totals'][k]) }}&nbsp;€</td>
-      </tr>
-      <tr style="border-top: solid #000 thin" v-if="synthesis['N.B']">
-        <th>
-          Hors masse<br>
-          <small style="font-weight: 300" class="error-block"><i class="icon-attention"></i> Les annexes de certains comptes ne sont pas renseignés :
-            <ul>
-              <li v-for="c in getNoMasse"><strong>{{c}}</strong>
-                <div v-if="synthesis.curations">
+      </thead>
 
-                </div>
-              </li>
-            </ul>
-            <a @click="handlerCuration" v-if="manageDepense" class="btn btn-xs btn-default"> <i class="icon-cog"></i>Qualifer les comptes</a>
-            <span v-else>Merci de contacter un administrateur pour que les annexes des comptes soient configurés.</span>
-          </small>
+      <tbody>
+      <tr v-for="dt,key in synthesis.masses">
+        <th>
+          <small>{{ dt }}</small>
+          <a class="label label-info xs" :href="'#repport-' + key">{{ synthesis.synthesis[key].nbr_effectue }} /
+            {{ synthesis.synthesis[key].nbr_engage }}</a>
         </th>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis['effective_totals']['N.B']) }}&nbsp;€</td>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis['predicted_totals']['N.B']) }}&nbsp;€</td>
+        <td style="text-align: right">{{ $filters.money(synthesis.synthesis[key].total_engage) }}</td>
+        <td style="text-align: right">{{ $filters.money(synthesis.synthesis[key].total_effectue) }}</td>
       </tr>
-      <tr style="border-top: solid #000 thin; font-size: 1.6em">
-        <th>TOTAL : </th>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis['effective_total']) }}&nbsp;€</td>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis['predicted_total']) }}&nbsp;€</td>
+      </tbody>
+      <tbody>
+      <tr class="total">
+        <th>Total</th>
+        <td style="text-align: right">{{ $filters.money(synthesis.synthesis.totaux.engage) }}</td>
+        <td style="text-align: right">{{ $filters.money(synthesis.synthesis.totaux.effectue) }}</td>
       </tr>
-    </table>
-
-    <table class="table table-condensed" v-if="synthesis && synthesis.recettes">
-      <tr>
-        <th><i class="icon-euro"></i>Recettes</th>
-        <td style="text-align: right; white-space: nowrap">{{ $filters.money(synthesis.recettes.total) }}&nbsp;€</td>
+      </tbody>
+      <tbody>
+      <tr v-if="synthesis.synthesis['N.B'].total != 0">
+        <th>
+          <small><i class="icon-attention"></i> Hors-masse</small>
+          <a href="#repport-nb" class="label label-info">{{ synthesis.synthesis['N.B'].nbr}}</a>
+        </th>
+        <td style="text-align: right">{{ $filters.money(synthesis.synthesis['N.B'].total_engage) }}</td>
+        <td style="text-align: right">{{ $filters.money(synthesis.synthesis['N.B'].total_effectue) }}</td>
       </tr>
+      </tbody>
     </table>
+
+    <div v-if="manageRecettes">
+      <h3><i class="icon-calculator"></i>Recettes</h3>
+      <table class="table table-condensed card synthesis" v-if="spentlines">
+        <tbody>
+        <tr>
+          <th>Recette <a class="label label-info xs" href="#repport-1">{{ synthesis.synthesis['1'].nbr}}</a></th>
+          <td style="text-align: right">{{ $filters.money(synthesis.synthesis['1'].total)}}</td>
+        </tr>
+        </tbody>
+      </table>
+    </div>
+
+    <div v-if="manageIgnored && synthesis.synthesis['0'].total != 0">
+      <a href="#" @click.prevent="displayIgnored = !displayIgnored">
+        <span v-if="displayIgnored"><i class="icon-eye-off"></i> Cacher</span>
+        <span v-else><i class="icon-eye"></i> Montrer</span>
+        les données ignorées
+      </a>
+      <table class="table table-condensed card synthesis" v-if="spentlines && displayIgnored">
+        <tbody>
+        <tr>
+          <th>
+            Ignorées
+            <a class="label label-info" href="#repport-0">{{ synthesis.synthesis['0'].nbr}}</a>
+          </th>
+          <td style="text-align: right">{{ $filters.money(synthesis.synthesis['0'].total)}}</td>
+        </tr>
+        </tbody>
+      </table>
+    </div>
+
     <small>Données mise à jour : <strong v-if="dateUpdated">{{ dateUpdated.date | dateFull }}</strong></small>
   </section>
 </template>
@@ -118,7 +146,8 @@ export default {
       infos: null,
       pendingMsg: null,
       showCuration: false,
-      masses: []
+      masses: [],
+      synthesis: null
     }
   },
 
@@ -127,8 +156,7 @@ export default {
       this.pendingMsg = "Chargement des données financières";
       axios.get(this.url).then(
           ok => {
-            console.log("OK",ok);
-            this.infos = ok.data.synthesis;
+            this.synthesis = ok.data.synthesis;
             this.masses = ok.data.masses;
           },
           ko => {
diff --git a/ui/src/views/SpentLinePFI.vue b/ui/src/views/SpentLinePFI.vue
index 59fa31bbb..abfb59802 100644
--- a/ui/src/views/SpentLinePFI.vue
+++ b/ui/src/views/SpentLinePFI.vue
@@ -1,477 +1,494 @@
 <template>
-    <section class="spentlines">
-
-        <transition name="fade">
-            <div class="error overlay" v-if="error">
-                <div class="overlay-content">
-                    <i class="icon-warning-empty"></i>
-                    {{ error }}
-                    <br>
-                    <a href="#" @click="error = null" class="btn btn-sm btn-default btn-xs">
-                        <i class="icon-cancel-circled"></i>
-                        Fermer</a>
-                </div>
-            </div>
-        </transition>
-
-        <transition name="fade">
-            <div class="pending overlay" v-if="pendingMsg">
-                <div class="overlay-content">
-                    <i class="icon-spinner animate-spin"></i>
-                    {{ pendingMsg }}
-                </div>
-            </div>
-        </transition>
-
-        <div class="overlay" v-if="editCompte">
-            <div class="overlay-content">
-                <h3><i class="icon-zoom-in-outline"></i>Modification de la masse : {{ editCompte.code }} - {{ editCompte.label }}</h3>
-                <hr>
-                <select name="" v-model="editCompte.annexe">
-                    <option value="0">Ignoré</option>
-                    <option value="1">Recette</option>
-                    <option :value="m" v-for="masse,m in spentlines.masses">{{ masse }}</option>
-                </select>
-
-                <button class="btn btn-danger" @click="editCompte = null"><i class="icon-cancel-circled-outline"></i>Annuler</button>
-                <button class="btn btn-success" @click="handlerAffectationCompte(editCompte)"><i class="icon-valid"></i>Valider</button>
-            </div>
+  <section class="spentlines">
+
+    <transition name="fade">
+      <div class="error overlay" v-if="error">
+        <div class="overlay-content">
+          <i class="icon-warning-empty"></i>
+          {{ error }}
+          <br>
+          <a href="#" @click="error = null" class="btn btn-sm btn-default btn-xs">
+            <i class="icon-cancel-circled"></i>
+            Fermer</a>
         </div>
+      </div>
+    </transition>
+
+    <transition name="fade">
+      <div class="pending overlay" v-if="pendingMsg">
+        <div class="overlay-content">
+          <i class="icon-spinner animate-spin"></i>
+          {{ pendingMsg }}
+        </div>
+      </div>
+    </transition>
+
+    <div class="overlay" v-if="editCompte">
+      <div class="overlay-content">
+        <h3><i class="icon-zoom-in-outline"></i>Modification de la masse : {{ editCompte.code }} - {{ editCompte.label
+          }}</h3>
+        <hr>
+        <select name="" v-model="editCompte.annexe">
+          <option value="0">Ignoré</option>
+          <option value="1">Recette</option>
+          <option :value="m" v-for="masse,m in spentlines.masses">{{ masse }}</option>
+        </select>
+
+        <button class="btn btn-danger" @click="editCompte = null"><i class="icon-cancel-circled-outline"></i>Annuler
+        </button>
+        <button class="btn btn-success" @click="handlerAffectationCompte(editCompte)"><i class="icon-valid"></i>Valider
+        </button>
+      </div>
+    </div>
+
+    <div class="overlay" v-if="details">
+      <div class="overlay-content">
+        <h3><i class="icon-zoom-in-outline"></i>Détails des entrées comptables</h3>
+        <button class="btn btn-default" @click="details = null">Fermer</button>
+
+        <table class="list table table-condensed table-bordered table-condensed card">
+          <thead>
+          <tr>
+            <th>ID</th>
+            <th>N°SIFAC</th>
+            <th>Btart</th>
+            <th>Description</th>
+            <th>Montant engagé</th>
+            <th>Montant effectué</th>
+            <th>Compte Budgetaire</th>
+            <th>Centre de profit</th>
+            <th>Compte général</th>
+            <th>Masse</th>
+            <th>Date comptable</th>
+            <th>Date paiement</th>
+            <th>Année</th>
+          </tr>
+          </thead>
+          <tbody>
+          <tr class="text-small" v-for="d in details.details">
+            <td>{{ d.syncid }}</td>
+            <td>{{ d.numSifac }}</td>
+            <td>{{ d.btart }}</td>
+            <td>{{ d.texteFacture|d.designation }}</td>
+            <td style="text-align: right">{{ $filters.money(d.montant_engage) }}</td>
+            <td style="text-align: right">{{ $filters.money(d.montant_effectue) }}</td>
+            <td>{{ d.compteBudgetaire }}</td>
+            <td>{{ d.centreFinancier }}</td>
+            <td><strong>{{ d.compteGeneral }}</strong> : {{ d.type }}</td>
+            <td><strong>{{ d.masse }}</strong></td>
+            <td>{{ d.dateComptable }}</td>
+            <td>{{ d.datePaiement }}</td>
+            <td>{{ d.dateAnneeExercice }}</td>
+          </tr>
+          </tbody>
+        </table>
+      </div>
+    </div>
+
+    <div class="container-fluid">
+
+      <div class="row">
+        <div class="col-md-3">
+          <h3>
+            <i class="icon-help-circled"></i>
+            Informations
+          </h3>
+          <div class="card" v-if="informations">
+            <table class="table table-condensed card synthesis" v-if="spentlines">
+              <tbody>
+              <tr>
+                <th><small>PFI</small></th>
+                <td style="text-align: right">
+                  {{ informations.PFI }}
+                </td>
+              </tr>
+              <tr>
+                <th><small>N°OSCAR</small></th>
+                <td style="text-align: right">
+                  {{ informations.numOscar }}
+                </td>
+              </tr>
+              <tr>
+                <th><small>Montant</small></th>
+                <td style="text-align: right">
+                  {{ $filters.money(informations.amount) }}
+                </td>
+              </tr>
+              <tr>
+                <th><small>Projet</small></th>
+                <td style="text-align: right">
+                  <strong>{{ informations.projectacronym }}</strong><br>
+                  <small>{{ informations.project }}</small>
+                </td>
+              </tr>
+              <tr>
+                <th><small>Activité</small></th>
+                <td style="text-align: right">
+                  <small>{{ informations.label }}</small>
+                </td>
+              </tr>
+              </tbody>
+            </table>
+
+            <a :href="url_activity" v-if="url_activity" class="btn btn-default btn-xs"><i class="icon-cube"></i> Revenir à
+              l'activité</a>
+
+            <form :action="url_sync" method="post" class="form-inline" v-if="url_sync">
+              <input type="hidden" name="action" value="update"/>
+              <button type="submit" class="btn btn-primary btn-xs">
+                <i class="icon-signal"></i>
+                Mettre à jour les données depuis SIFAC
+              </button>
+            </form>
+            <a :href="urlDownload" class="btn btn-default btn-xs" v-if="urlDownload">
+              <i class="icon-download"></i>
+              Télécharger les données (Excel)</a>
+          </div>
+
+
+          <h3><i class="icon-calculator"></i>Dépenses</h3>
+          <table class="table table-condensed card synthesis" v-if="spentlines">
+            <thead>
+            <tr>
+              <th>Masse</th>
+              <th style="text-align: right">Engagé</th>
+              <th style="text-align: right">Effectué</th>
+            </tr>
+            </thead>
+
+            <tbody>
+            <tr v-for="dt,key in spentlines.masses">
+              <th>
+                <small>{{ dt }}</small>
+                <a class="label label-info xs" :href="'#repport-' + key">{{ spentlines.synthesis[key].nbr_effectue }} /
+                  {{ spentlines.synthesis[key].nbr_engage }}</a>
+              </th>
+              <td style="text-align: right">{{ $filters.money(spentlines.synthesis[key].total_engage) }}</td>
+              <td style="text-align: right">{{ $filters.money(spentlines.synthesis[key].total_effectue) }}</td>
+            </tr>
+            </tbody>
+            <tbody>
+            <tr class="total">
+              <th>Total</th>
+              <td style="text-align: right">{{ $filters.money(spentlines.synthesis.totaux.engage) }}</td>
+              <td style="text-align: right">{{ $filters.money(spentlines.synthesis.totaux.effectue) }}</td>
+            </tr>
+            </tbody>
+            <tbody>
+            <tr v-if="spentlines.synthesis['N.B'].total != 0">
+              <th>
+                <small><i class="icon-attention"></i> Hors-masse</small>
+                <a href="#repport-nb" class="label label-info">{{ spentlines.synthesis['N.B'].nbr}}</a>
+              </th>
+              <td style="text-align: right">{{ $filters.money(spentlines.synthesis['N.B'].total_engage) }}</td>
+              <td style="text-align: right">{{ $filters.money(spentlines.synthesis['N.B'].total_effectue) }}</td>
+            </tr>
+            </tbody>
+          </table>
+
+          <div v-if="manageRecettes">
+            <h3><i class="icon-calculator"></i>Recettes</h3>
+            <table class="table table-condensed card synthesis" v-if="spentlines">
+              <tbody>
+              <tr>
+                <th>Recette <a class="label label-info xs" href="#repport-1">{{ spentlines.synthesis['1'].nbr}}</a></th>
+                <td style="text-align: right">{{ $filters.money(spentlines.synthesis['1'].total)}}</td>
+              </tr>
+              </tbody>
+            </table>
+          </div>
+
+          <div v-if="manageIgnored && spentlines.synthesis['0'].total != 0">
+            <a href="#" @click.prevent="displayIgnored = !displayIgnored">
+              <span v-if="displayIgnored"><i class="icon-eye-off"></i> Cacher</span>
+              <span v-else><i class="icon-eye"></i> Montrer</span>
+              les données ignorées
+            </a>
+            <table class="table table-condensed card synthesis" v-if="spentlines && displayIgnored">
+              <tbody>
+              <tr>
+                <th>
+                  Ignorées
+                  <a class="label label-info" href="#repport-0">{{ spentlines.synthesis['0'].nbr}}</a>
+                </th>
+                <td style="text-align: right">{{ $filters.money(spentlines.synthesis['0'].total)}}</td>
+              </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+        <div class="col-md-9" style="height: 80vh; overflow-y: scroll">
+
+          <div v-if="spentlines != null">
+            <div v-for="m, k in masses">
+              <h3 :id="'repport-' + k">{{ m }}</h3>
+              <spent-line-p-f-i-grouped
+                  :lines="byMasse.datas[k]" :total="spentlines.synthesis[k].total"
+                  @editcompte="handlerEditCompte"
+                  @detailsline="handlerDetailsLine"
+              />
+            </div>
 
-        <div class="overlay" v-if="details">
-            <div class="overlay-content">
-                <h3><i class="icon-zoom-in-outline"></i>Détails des entrées comptables</h3>
-                <button class="btn btn-default" @click="details = null">Fermer</button>
-
-                <table class="list table table-condensed table-bordered table-condensed card">
-                    <thead>
-                    <tr>
-                        <th>ID</th>
-                        <th>N°SIFAC</th>
-                        <th>Btart</th>
-                        <th>Description</th>
-                        <th>Montant engagé</th>
-                        <th>Montant effectué</th>
-                        <th>Compte Budgetaire</th>
-                        <th>Centre de profit</th>
-                        <th>Compte général</th>
-                        <th>Masse</th>
-                        <th>Date comptable</th>
-                        <th>Date paiement</th>
-                        <th>Année</th>
-                    </tr>
-                    </thead>
-                    <tbody>
-                    <tr class="text-small" v-for="d in details.details">
-                        <td>{{ d.syncid }}</td>
-                        <td>{{ d.numSifac }}</td>
-                        <td>{{ d.btart }}</td>
-                        <td>{{ d.texteFacture|d.designation }}</td>
-                        <td style="text-align: right">{{ $filters.money(d.montant_engage) }}</td>
-                        <td style="text-align: right">{{ $filters.money(d.montant_effectue) }}</td>
-                        <td>{{ d.compteBudgetaire }}</td>
-                        <td>{{ d.centreFinancier }}</td>
-                        <td><strong>{{ d.compteGeneral }}</strong> : {{ d.type }}</td>
-                        <td><strong>{{ d.masse }}</strong></td>
-                        <td>{{ d.dateComptable }}</td>
-                        <td>{{ d.datePaiement }}</td>
-                        <td>{{ d.dateAnneeExercice }}</td>
-                    </tr>
-                    </tbody>
-                </table>
+            <div v-if="Object.keys(byMasse.datas['N.B']).length > 0">
+              <h3 :id="'repport-nb'">Hors-masse</h3>
+              <div class="alert alert-warning">
+                <i class="icon-attention"></i> Les comptes des entrées suivantes ne sont pas qualifié.
+              </div>
+              <spent-line-p-f-i-grouped
+                  :lines="byMasse.datas['N.B']" :total="spentlines.synthesis['N.B'].total"
+                  @editcompte="handlerEditCompte"
+                  @detailsline="handlerDetailsLine"
+              />
             </div>
-        </div>
 
-        <div class="container-fluid">
-
-            <div class="row">
-                <div class="col-md-3">
-                    <h3>
-                        <i class="icon-help-circled"></i>
-                        Informations
-                    </h3>
-                    <div class="card" v-if="informations">
-                        <table class="table table-condensed card synthesis" v-if="spentlines">
-                            <tbody>
-                                <tr>
-                                    <th><small>PFI</small></th>
-                                    <td style="text-align: right">
-                                        {{ informations.PFI }}
-                                    </td>
-                                </tr>
-                                <tr>
-                                    <th><small>N°OSCAR</small></th>
-                                    <td style="text-align: right">
-                                        {{ informations.numOscar }}
-                                    </td>
-                                </tr>
-                                <tr>
-                                    <th><small>Montant</small></th>
-                                    <td style="text-align: right">
-                                        {{ $filters.money(informations.amount) }}
-                                    </td>
-                                </tr>
-                                <tr>
-                                    <th><small>Projet</small></th>
-                                    <td style="text-align: right">
-                                        <strong>{{ informations.projectacronym }}</strong><br>
-                                        <small>{{ informations.project }}</small>
-                                    </td>
-                                </tr>
-                                <tr>
-                                    <th><small>Activité</small></th>
-                                    <td style="text-align: right">
-                                        <small>{{ informations.label }}</small>
-                                    </td>
-                                </tr>
-                            </tbody>
-                        </table>
-                        <a :href="urlActivity" v-if="urlActivity" class="btn btn-default btn-xs"><i class="icon-cube"></i> Revenir à l'activité</a>
-                        <form :action="urlSync" method="post" class="form-inline" v-if="urlSync">
-                            <input type="hidden" name="action" value="update" />
-                            <button type="submit" class="btn btn-primary btn-xs">
-                                <i class="icon-signal"></i>
-                                Mettre à jour les données depuis SIFAC
-                            </button>
-                        </form>
-                        <a :href="urlDownload" class="btn btn-default btn-xs" v-if="urlDownload">
-                            <i class="icon-download"></i>
-                            Télécharger les données (Excel)</a>
-                    </div>
-
-
-                    <h3><i class="icon-calculator"></i>Dépenses</h3>
-                    <table class="table table-condensed card synthesis" v-if="spentlines">
-                        <thead>
-                        <tr>
-                          <th>Masse</th>
-                          <th style="text-align: right">Engagé</th>
-                          <th style="text-align: right">Effectué</th>
-                        </tr>
-                        </thead>
-
-                        <tbody>
-                        <tr v-for="dt,key in spentlines.masses">
-                            <th>
-                                <small>{{ dt }}</small>
-                                <a class="label label-info xs" :href="'#repport-' + key">{{ spentlines.synthesis[key].nbr_effectue }} / {{ spentlines.synthesis[key].nbr_engage }}</a>
-                            </th>
-                            <td style="text-align: right">{{ $filters.money(spentlines.synthesis[key].total_engage) }}</td>
-                            <td style="text-align: right">{{ $filters.money(spentlines.synthesis[key].total_effectue) }}</td>
-                        </tr>
-                        </tbody>
-                        <tbody>
-                        <tr class="total">
-                            <th>Total</th>
-                            <td style="text-align: right">{{ $filters.money(spentlines.synthesis.totaux.engage) }}</td>
-                            <td style="text-align: right">{{ $filters.money(spentlines.synthesis.totaux.effectue) }}</td>
-                        </tr>
-                        </tbody>
-                        <tbody>
-                        <tr v-if="spentlines.synthesis['N.B'].total != 0">
-                          <th>
-                            <small><i class="icon-attention"></i> Hors-masse</small>
-                            <a href="#repport-nb" class="label label-info">{{ spentlines.synthesis['N.B'].nbr}}</a>
-                          </th>
-                          <td style="text-align: right">{{ $filters.money(spentlines.synthesis['N.B'].total_engage) }}</td>
-                          <td style="text-align: right">{{ $filters.money(spentlines.synthesis['N.B'].total_effectue) }}</td>
-                        </tr>
-                        </tbody>
-                    </table>
-
-                    <div v-if="manageRecettes">
-                        <h3><i class="icon-calculator"></i>Recettes</h3>
-                        <table class="table table-condensed card synthesis" v-if="spentlines">
-                            <tbody>
-                            <tr>
-                                <th>Recette <a class="label label-info xs" href="#repport-1">{{ spentlines.synthesis['1'].nbr}}</a></th>
-                                <td style="text-align: right">{{ $filters.money(spentlines.synthesis['1'].total)}}</td>
-                            </tr>
-                            </tbody>
-                        </table>
-                    </div>
-
-                    <div v-if="manageIgnored && spentlines.synthesis['0'].total != 0">
-                        <a href="#" @click.prevent="displayIgnored = !displayIgnored">
-                            <span v-if="displayIgnored"><i class="icon-eye-off"></i> Cacher</span>
-                            <span v-else><i class="icon-eye"></i> Montrer</span>
-                            les données ignorées
-                        </a>
-                        <table class="table table-condensed card synthesis" v-if="spentlines && displayIgnored">
-                            <tbody>
-                            <tr>
-                                <th>
-                                    Ignorées
-                                    <a class="label label-info"  href="#repport-0">{{ spentlines.synthesis['0'].nbr}}</a>
-                                </th>
-                                <td style="text-align: right">{{ $filters.money(spentlines.synthesis['0'].total)}}</td>
-                            </tr>
-                            </tbody>
-                        </table>
-                    </div>
-                </div>
-                <div class="col-md-9" style="height: 80vh; overflow-y: scroll">
-
-                    <div v-if="spentlines != null">
-                        <div v-for="m, k in masses">
-                            <h3 :id="'repport-' + k">{{ m }}</h3>
-                            <spent-line-p-f-i-grouped
-                                :lines="byMasse.datas[k]" :total="spentlines.synthesis[k].total"
-                                @editcompte="handlerEditCompte"
-                                @detailsline="handlerDetailsLine"
-                            />
-                        </div>
-
-                        <div v-if="Object.keys(byMasse.datas['N.B']).length > 0">
-                            <h3 :id="'repport-nb'">Hors-masse</h3>
-                            <div class="alert alert-warning">
-                                <i class="icon-attention"></i> Les comptes des entrées suivantes ne sont pas qualifié.
-                            </div>
-                            <spent-line-p-f-i-grouped
-                                    :lines="byMasse.datas['N.B']" :total="spentlines.synthesis['N.B'].total"
-                                    @editcompte="handlerEditCompte"
-                                    @detailsline="handlerDetailsLine"
-                            />
-                        </div>
-
-                        <div v-if="manageRecettes && Object.keys(byMasse.datas['recettes']).length > 0">
-                            <h3 :id="'repport-1'">Recettes</h3>
-                            <spent-line-p-f-i-grouped
-                                    :lines="byMasse.datas['recettes']" :total="spentlines.synthesis['1'].total"
-                                    @editcompte="handlerEditCompte"
-                                    @detailsline="handlerDetailsLine"
-                            />
-                        </div>
-                        <div v-if="manageIgnored && Object.keys(byMasse.datas['ignorés']).length > 0">
-                            <h3 :id="'repport-0'">Ignorés</h3>
-                            <spent-line-p-f-i-grouped
-                                    :lines="byMasse.datas['ignorés']" :total="spentlines.synthesis['0'].total"
-                                    @editcompte="handlerEditCompte"
-                                    @detailsline="handlerDetailsLine"
-                            />
-                        </div>
-                    </div>
-                </div>
+            <div v-if="manageRecettes && Object.keys(byMasse.datas['recettes']).length > 0">
+              <h3 :id="'repport-1'">Recettes</h3>
+              <spent-line-p-f-i-grouped
+                  :lines="byMasse.datas['recettes']" :total="spentlines.synthesis['1'].total"
+                  @editcompte="handlerEditCompte"
+                  @detailsline="handlerDetailsLine"
+              />
+            </div>
+            <div v-if="manageIgnored && Object.keys(byMasse.datas['ignorés']).length > 0">
+              <h3 :id="'repport-0'">Ignorés</h3>
+              <spent-line-p-f-i-grouped
+                  :lines="byMasse.datas['ignorés']" :total="spentlines.synthesis['0'].total"
+                  @editcompte="handlerEditCompte"
+                  @detailsline="handlerDetailsLine"
+              />
             </div>
+          </div>
         </div>
-    </section>
+      </div>
+    </div>
+  </section>
 
 </template>
 <script>
-    // nodejs node_modules/.bin/poi watch --format umd --moduleName  SpentLinePFI --filename.js SpentLinePFI.js --dist public/js/oscar/dist public/js/oscar/src/SpentLinePFI.vue
-
-    import SpentLinePFIGrouped from "./SpentLinePFIGrouped.vue";
-    import axios from "axios";
-
-    export default {
-        props: [
-            'url',
-            'urlSpentAffectation',
-            'urlActivity',
-            'urlSync',
-            'urlDownload',
-            'manageRecettes',
-            'manageIgnored'
-        ],
-
-        components: {
-            SpentLinePFIGrouped
+// nodejs node_modules/.bin/poi watch --format umd --moduleName  SpentLinePFI --filename.js SpentLinePFI.js --dist public/js/oscar/dist public/js/oscar/src/SpentLinePFI.vue
+
+import SpentLinePFIGrouped from "./SpentLinePFIGrouped.vue";
+import axios from "axios";
+
+export default {
+  props: [
+    'url'
+  ],
+
+  components: {
+    SpentLinePFIGrouped
+  },
+
+  data() {
+    return {
+      state: "masse",
+      error: null,
+      pendingMsg: "",
+      spentlines: null,
+      masses: {},
+      details: null,
+      displayIgnored: true,
+      editCompte: null,
+      informations: null,
+
+      //
+      manageRecettes: true,
+
+      // URL
+      url_activity: null,
+      url_sync: null,
+      url_download: null,
+      url_spentaffectation: null,
+    }
+  },
+
+  computed: {
+    totalDepenses() {
+      let total = 0.0;
+      for (let i in this.spentlines.synthesis) {
+        if (i != '0' && i != '1') {
+          total += this.spentlines.synthesis[i].total;
+        }
+      }
+      return total;
+    },
+
+    byMasse() {
+      let out = {
+        datas: {
+          'N.B': {},
+          'recettes': {},
+          'ignorés': {}
         },
+        totaux: {
+          'N.B': 0.0,
+          'recettes': 0.0,
+          'ignorés': 0.0
+        }
+      };
+
+      for (let k in this.masses) {
+        out.datas[k] = {};
+        out.totaux[k] = 0.0;
+      }
+
+      if (this.spentlines) {
+        for (let s in this.spentlines.spents) {
+
+          let line = this.spentlines.spents[s];
+          let masse = line.masse;
+          let btart = line.btart;
+
+          if (masse == '1') masse = 'recettes';
+          if (masse == '0') masse = 'ignorés';
+          let numPiece = line.numPiece;
+
+          if (!out.datas.hasOwnProperty(masse)) {
+            masse = 'N.B';
+          }
+
+          if (!out.datas[masse].hasOwnProperty(numPiece)) {
+            out.datas[masse][numPiece] = {
+              'ids': [],
+              'numpiece': numPiece,
+              'numSifac': [],
+              'text': [],
+              'types': [],
+              'montant': 0.0,
+              'montant_engage': 0.0,
+              'montant_effectue': 0.0,
+              'btart': btart,
+              'compteBudgetaires': [],
+              'comptes': [],
+              'masse': [],
+              'dateComptable': line.dateComptable,
+              'datePaiement': line.datePaiement,
+              'annee': line.dateAnneeExercice,
+              'refPiece': line.refPiece,
+              details: []
+            };
+          }
+          out.datas[masse][numPiece].details.push(line);
+
+          let text = line.texteFacture;
+          let designation = line.designation;
+          let type = line.type;
+          let compte = line.compteGeneral;
+          let compteBudgetaire = line.compteBudgetaire;
+
+          if (out.datas[masse][numPiece].numSifac.indexOf(line.numSifac) == -1) {
+            out.datas[masse][numPiece].numSifac.push(line.numSifac);
+          }
+
+          out.datas[masse][numPiece].montant += line.montant;
+          out.datas[masse][numPiece].montant_effectue += line.montant_effectue;
+          out.datas[masse][numPiece].montant_engage += line.montant_engage;
+
+
+          if (text && out.datas[masse][numPiece].text.indexOf(text) < 0) {
+            out.datas[masse][numPiece].text.push(text);
+          }
+
+          if (designation && out.datas[masse][numPiece].text.indexOf(designation) < 0) {
+            out.datas[masse][numPiece].text.push(designation);
+          }
+
+          if (type && out.datas[masse][numPiece].types.indexOf(type) < 0) {
+            out.datas[masse][numPiece].types.push(type);
+          }
+
+          if (compte && out.datas[masse][numPiece].comptes.indexOf(compte) < 0) {
+            out.datas[masse][numPiece].comptes.push(compte);
+          }
+
+          if (compteBudgetaire && out.datas[masse][numPiece].compteBudgetaires.indexOf(compteBudgetaire) < 0) {
+            out.datas[masse][numPiece].compteBudgetaires.push(compteBudgetaire);
+          }
+        }
+      }
 
-        data() {
-            return {
-                state: "masse",
-                error: null,
-                pendingMsg: "",
-                spentlines: null,
-                masses: {},
-                details: null,
-                displayIgnored: false,
-                editCompte: null,
-                informations: null,
+      return out;
+    }
+  },
+
+  methods: {
+    ////////////////////////////////////////////////////////////////
+    //
+    // HANDLERS
+    //
+    ////////////////////////////////////////////////////////////////
+    handlerEditCompte(compte) {
+      this.editCompte = JSON.parse(JSON.stringify(this.spentlines.comptes[compte]));
+    },
+
+    handlerDetailsLine(line) {
+      this.details = line;
+    },
+
+    handlerAffectationCompte(compte) {
+      //$codeCompteFull => $compteAffectation
+      let affectations = {};
+      affectations[compte.codeFull] = compte.annexe;
+      this.editCompte = null;
+      this.pendingMsg = "Modification de la masse pour " + compte.codeFull;
+
+      let posted = new FormData();
+      posted.append('affectation', JSON.stringify(affectations));
+
+      axios.post(this.url_spentaffectation, posted).then(
+          success => {
+            this.editCompte = null;
+            this.fetch();
+          },
+          error => {
+            if (error.status == 403) {
+              this.error = "Vous n'avez pas l'autorisation d'accès à ces informations.";
+            } else {
+              this.error = error.data
             }
-        },
-
-        computed: {
-            totalDepenses() {
-                let total = 0.0;
-                for (let i in this.spentlines.synthesis) {
-                    if (i != '0' && i != '1') {
-                        total += this.spentlines.synthesis[i].total;
-                    }
-                }
-                return total;
-            },
-
-            byMasse() {
-                let out = {
-                    datas: {
-                        'N.B': {},
-                        'recettes': {},
-                        'ignorés': {}
-                    },
-                    totaux: {
-                        'N.B': 0.0,
-                        'recettes': 0.0,
-                        'ignorés': 0.0
-                    }
-                };
-
-                for (let k in this.masses) {
-                    out.datas[k] = {};
-                    out.totaux[k] = 0.0;
-                }
-
-                if( this.spentlines ) {
-                    for (let s in this.spentlines.spents) {
-
-                        let line = this.spentlines.spents[s];
-                        let masse = line.masse;
-                        let btart = line.btart;
-
-                        if( masse == '1' ) masse = 'recettes';
-                        if( masse == '0' ) masse = 'ignorés';
-                        let numPiece = line.numPiece;
-
-                        if( !out.datas.hasOwnProperty(masse) ){
-                            masse = 'N.B';
-                        }
-
-                        if( !out.datas[masse].hasOwnProperty(numPiece) ){
-                            out.datas[masse][numPiece] = {
-                                'ids': [],
-                                'numpiece': numPiece,
-                                'numSifac': [],
-                                'text': [],
-                                'types': [],
-                                'montant': 0.0,
-                                'montant_engage': 0.0,
-                                'montant_effectue': 0.0,
-                                'btart': btart,
-                                'compteBudgetaires': [],
-                                'comptes': [],
-                                'masse': [],
-                                'dateComptable': line.dateComptable,
-                                'datePaiement': line.datePaiement,
-                                'annee': line.dateAnneeExercice,
-                                'refPiece': line.refPiece,
-                                details: []
-                            };
-                        }
-                        out.datas[masse][numPiece].details.push(line);
-
-                        let text = line.texteFacture;
-                        let designation = line.designation;
-                        let type = line.type;
-                        let compte = line.compteGeneral;
-                        let compteBudgetaire = line.compteBudgetaire;
-
-                        if( out.datas[masse][numPiece].numSifac.indexOf(line.numSifac) == -1 ){
-                          out.datas[masse][numPiece].numSifac.push(line.numSifac);
-                        }
-
-                        out.datas[masse][numPiece].montant += line.montant;
-                        out.datas[masse][numPiece].montant_effectue += line.montant_effectue;
-                        out.datas[masse][numPiece].montant_engage += line.montant_engage;
-
-
-                        if( text && out.datas[masse][numPiece].text.indexOf(text) < 0 ){
-                            out.datas[masse][numPiece].text.push(text);
-                        }
-
-                        if( designation && out.datas[masse][numPiece].text.indexOf(designation) < 0 ){
-                            out.datas[masse][numPiece].text.push(designation);
-                        }
-
-                        if( type && out.datas[masse][numPiece].types.indexOf(type) < 0 ){
-                            out.datas[masse][numPiece].types.push(type);
-                        }
-
-                        if( compte && out.datas[masse][numPiece].comptes.indexOf(compte) < 0 ){
-                            out.datas[masse][numPiece].comptes.push(compte);
-                        }
-
-                        if( compteBudgetaire && out.datas[masse][numPiece].compteBudgetaires.indexOf(compteBudgetaire) < 0 ){
-                            out.datas[masse][numPiece].compteBudgetaires.push(compteBudgetaire);
-                        }
-                    }
-                }
-
-                return out;
+            this.pendingMsg = "";
+          }
+      );
+    },
+
+    ////////////////////////////////////////////////////////////////
+    //
+    // OPERATIONS REST
+    //
+    ////////////////////////////////////////////////////////////////
+
+    /**
+     * Chargement des jalons depuis l'API
+     */
+    fetch() {
+      this.pendingMsg = "Chargement des dépense";
+
+      axios.get(this.url).then(
+          success => {
+            this.masses = success.data.spents.masses;
+            this.spentlines = success.data.spents;
+            this.informations = success.data.spents.informations;
+
+            this.url_sync = success.data.spents.url_sync;
+            this.url_activity = success.data.spents.url_activity;
+            this.url_spentaffectation = success.data.spents.url_spentaffectation;
+            this.url_download = success.data.spents.url_download;
+          },
+          error => {
+            if (error.status == 403) {
+              this.error = "Vous n'avez pas l'autorisation d'accès à ces informations.";
+            } else {
+              this.error = "Impossible de charger les dépenses pour ce PFI : " + error.data
             }
-        },
-
-        methods: {
-            ////////////////////////////////////////////////////////////////
-            //
-            // HANDLERS
-            //
-            ////////////////////////////////////////////////////////////////
-            handlerEditCompte(compte){
-                this.editCompte = JSON.parse(JSON.stringify(this.spentlines.comptes[compte]));
-            },
-
-            handlerDetailsLine(line){
-                this.details = line;
-            },
-
-            handlerAffectationCompte(compte){
-                //$codeCompteFull => $compteAffectation
-                let affectations = {};
-                affectations[compte.codeFull] = compte.annexe;
-                this.editCompte = null;
-                this.pendingMsg = "Modification de la masse pour " + compte.codeFull;
-                console.log(this.pendingMsg);
-
-                axios.post(this.urlSpentAffectation, {'affectation': affectations }).then(
-                    success => {
-                        this.editCompte = null;
-                        this.fetch();
-                    },
-                    error => {
-                        if( error.status == 403 ){
-                            this.error = "Vous n'avez pas l'autorisation d'accès à ces informations.";
-                        } else {
-                            this.error = error.data
-                        }
-                        this.pendingMsg = "";
-                    }
-                );
-            },
-
-            ////////////////////////////////////////////////////////////////
-            //
-            // OPERATIONS REST
-            //
-            ////////////////////////////////////////////////////////////////
-
-            /**
-             * Chargement des jalons depuis l'API
-             */
-            fetch() {
-                this.pendingMsg = "Chargement des dépense";
-
-                axios.get(this.url).then(
-                    success => {
-                        this.masses = success.data.spents.masses;
-                        this.spentlines = success.data.spents;
-                        this.informations = success.data.spents.informations;
-                    },
-                    error => {
-                        if (error.status == 403) {
-                            this.error = "Vous n'avez pas l'autorisation d'accès à ces informations.";
-                        } else {
-                            this.error = "Impossible de charger les dépenses pour ce PFI : " + error.data
-                        }
-                    }
-                ).then(n => {
-                    this.pendingMsg = "";
-                });
-            },
-        },
-
-        mounted() {
-            this.fetch()
-        }
-    }
+          }
+      ).then(n => {
+        this.pendingMsg = "";
+      });
+    },
+  },
+
+  mounted() {
+    this.fetch()
+  }
+}
 </script>
\ No newline at end of file
-- 
GitLab