source: spip-zone/_plugins_/commandes/trunk/commandes_pipelines.php

Last change on this file was 104971, checked in by cedric@…, 22 months ago

Grosse erreur de conception dans le traitement des paiements reccurents : la TVA est totalement ignoree
On corrige en permettant d'ajouter un montant_ht dans le descriptif des echeances, en veillant a ne rien casser pour les sites en prod.
Les fonctions commandes_lister_montants_echeances et commandes_trouver_prochaine_echeance sont conservees sans changement de signature pour continuite fonctionnelle, mais sont depreciees
et remplacees dans le plugin par les fonctions commandes_lister_paiements_echeances() et commandes_trouver_prochaine_echeance_desc() qui renvoient un descriptif de chaque paiement incluant montant ET montant_ht
Dans le pipeline commandes_bank_abos_preparer_echeance() le montant_ht est pris en compte lors de la creation de la transaction

Avec ces modifications, les echeances continuent de fonctionner a l'identique sur les commandes en base, ou avec des abonnements qui ne fournissent qu'un montant pour les echeances,
mais si les abonnements fournissent montant et montant_ht pour les echeances, on retrouve des transactions avec le bon montant_ht et donc une TVA correcte sur la facture

Le plugin ne fait aucun upgrade en base, car il ne sait a priori pas comment sont calculees les echeances, et ce serait dangereux de modifier les commandes existantes.
A chaque utilisateur/plugin de voir si il suit l'evolution et comment

File size: 18.3 KB
Line 
1<?php
2/**
3 * Pieplines utilisées par le plugin Commandes
4 *
5 * @plugin     Commandes
6 * @copyright  2014
7 * @author     Ateliers CYM, Matthieu Marcillaud, Les Développements Durables
8 * @licence    GPL 3
9 * @package    SPIP\Commandes\Pipelines
10 */
11
12// Sécurité
13if (!defined('_ECRIRE_INC_VERSION')) return;
14
15
16/**
17 * Insertion de la feuille de style CSS sur les pages publiques
18 *
19 * @pipeline insert_head_css
20 * @param  string $flux Données du pipeline
21 * @return string       Données du pipeline
22 */
23function commandes_insert_head_css($flux){
24        $css = find_in_path('css/commandes.css');
25        $flux .= "<link rel='stylesheet' type='text/css' media='all' href='$css' />\n";
26        return $flux;
27}
28
29
30/**
31 * Optimiser la base de donnée en supprimant toutes les commandes en cours qui sont trop vieilles
32 *
33 * Le délai de "péremption" est défini dans les options de configuration du plugin
34 *
35 * @pipeline optimiser_base_disparus
36 * @param  array $flux Données du pipeline
37 * @return array       Données du pipeline
38 */
39function commandes_optimiser_base_disparus($flux){
40        include_spip('inc/config');
41        // On cherche la date depuis quand on a le droit d'avoir fait la commande (par défaut 1h)
42        $depuis = date('Y-m-d H:i:s', time() - 3600*intval(lire_config('commandes/duree_vie', 1)));
43        // On récupère les commandes trop vieilles
44        $commandes = sql_allfetsel(
45                'id_commande',
46                'spip_commandes',
47                'statut = '.sql_quote('encours').' and date<'.sql_quote($depuis)
48        );
49
50        // S'il y a bien des commandes à supprimer
51        if ($commandes) {
52                $commandes = array_map('reset', $commandes);
53                include_spip('inc/commandes');
54                commandes_supprimer($commandes);
55                $flux['data'] += count($commandes);
56        }
57
58        return $flux;
59}
60
61
62/**
63 * Ajout de contenu sur certaines pages
64 *
65 * - Formulaires pour modifier les dates sur la fiche d'une commande
66 *
67 * @pipeline affiche_milieu
68 * @param  array $flux Données du pipeline
69 * @return array       Données du pipeline
70 */
71function commandes_affiche_milieu($flux) {
72
73        if (
74                $exec = trouver_objet_exec($flux['args']['exec'])
75                and $exec['edition'] == false 
76                and $exec['type'] == 'commande'
77                and $id_table_objet = $exec['id_table_objet']
78                and (isset($flux['args'][$id_table_objet]) and $id_commande = intval($flux['args'][$id_table_objet]))
79        ) {
80                $texte = recuperer_fond('prive/squelettes/contenu/commande_affiche_milieu',array('id_commande'=>$id_commande));
81        }
82
83        if (isset($texte)) {
84                if ($p=strpos($flux['data'],"<!--affiche_milieu-->"))
85                        $flux['data'] = substr_replace($flux['data'],$texte,$p,0);
86                else
87                        $flux['data'] .= $texte;
88        }
89
90        return $flux;
91}
92
93
94/**
95 * Ajout de contenu dans la liste des éléments en attente de validation
96 *
97 * - Liste des commandes aux statuts définis comme "actifs" dans les options de configuration
98 *
99 * @pipeline accueil_encours
100 * @param  array $flux Données du pipeline
101 * @return array       Données du pipeline
102 */
103function commandes_accueil_encours($flux) {
104
105        include_spip('inc/config');
106        $activer = lire_config('commandes/accueil_encours');
107        $statuts = lire_config('commandes/statuts_actifs');
108        if ($activer and is_array($statuts)) {
109                foreach($statuts as $statut){
110                        if ($nb_{$statut} = sql_countsel(table_objet_sql('commande'), "statut=".sql_quote($statut))) {
111                                $titre_{$statut} = singulier_ou_pluriel($nb_{$statut}, 'commandes:info_1_commande_statut_'.$statut, 'commandes:info_nb_commandes_statut_'.$statut);
112                                $flux .= recuperer_fond('prive/objets/liste/commandes', array(
113                                        'titre' => $titre_{$statut},
114                                        'statut' => $statut,
115                                        'cacher_tri' => true,
116                                        'nb' => 5),
117                                        array('ajax' => true)
118                                );
119                        }
120                }
121        }
122
123        return $flux;
124}
125
126
127/**
128 * Ajout de liste sur la vue d'un auteur
129 *
130 * - Liste des commandes de l'auteur
131 *
132 * @pipeline affiche_auteurs_interventions
133 * @param  array $flux Données du pipeline
134 * @return array       Données du pipeline
135**/
136function commandes_affiche_auteurs_interventions($flux) {
137
138        if ($id_auteur = intval($flux['args']['id_auteur'])) {
139
140                $ins = recuperer_fond('prive/objets/liste/commandes', array(
141                        'id_auteur' => $id_auteur,
142                        'titre' => _T('commandes:titre_commandes_auteur'),
143                        'cacher_tri' => true
144                        ),
145                        array('ajax' => true)
146                );
147                $mark = '<!--bank-->';
148                if (($p = strpos($flux['data'], $mark)) !== false) {
149                        $flux['data'] = substr_replace($flux['data'], $ins, $p + strlen($mark), 0);
150                }
151                else {
152                        $flux['data'] .= $ins;
153                }
154        }
155
156        return $flux;
157}
158
159
160/**
161 * Compléter la liste des types d'adresses du plugin Coordonnées
162 *
163 * Ajout de 2 types d'adresses : facturation et livraison
164 *
165 * @pipeline types_coordonnees
166 * @param  array $liste Données du pipeline
167 * @return array        Données du pipeline
168**/
169function commandes_types_coordonnees($liste) {
170
171        $types_adresses = $liste['adresse'];
172        if (!$types_adresses or !is_array($types_adresses)) $types_adresses = array();
173
174        // on définit les couples types + chaînes de langue à ajouter
175        $types_adresses_commandes = array(
176                'livraison' => _T('commandes:type_adresse_livraison'),
177                'facturation' => _T('commandes:type_adresse_facturation')
178        );
179        // on les rajoute à la liste des types des adresses
180        $liste['adresse'] = array_merge($types_adresses, $types_adresses_commandes);
181
182        return $liste;
183}
184
185
186/**
187 * Enregistrer le bon reglement d'une commande liee a une transaction du plugin bank
188 *
189 * @pipeline bank_traiter_reglement
190 * @param array $flux
191 * @return array mixed
192 */
193function commandes_bank_traiter_reglement($flux){
194        // Si on est dans le bon cas d'un paiement de commande et qu'il y a un id_commande et que la commande existe toujours
195        if (
196                $id_transaction = $flux['args']['id_transaction']
197                and $transaction = sql_fetsel("*","spip_transactions","id_transaction=".intval($id_transaction))
198                and $id_commande = $transaction['id_commande']
199                and $commande = sql_fetsel('id_commande, statut, id_auteur, echeances, reference', 'spip_commandes', 'id_commande='.intval($id_commande))
200        ){
201                $statut_commande = $commande['statut'];
202                $montant_regle = $transaction['montant_regle'];
203                $transaction_mode = $transaction['mode'];
204                $statut_nouveau = 'paye';
205
206
207                // Si la commande n'a pas d'échéance, le montant attendu est celui du prix de la commande
208                include_spip('inc/commandes_echeances');
209                if (!$commande['echeances']
210                        or !$echeances = unserialize($commande['echeances'])
211                  or !$desc = commandes_trouver_prochaine_echeance_desc($id_commande, $echeances, true)
212                  or !isset($desc['montant'])) {
213                        $fonction_prix = charger_fonction('prix', 'inc/');
214                        $montant_attendu = $fonction_prix('commande', $id_commande);
215                }
216                // Sinon le montant attendu est celui de la prochaine échéance (en ignorant la dernière transaction OK que justement on cherche à tester)
217                else {
218                        $montant_attendu = $desc['montant'];
219                }
220                spip_log("commande #$id_commande attendu:$montant_attendu regle:$montant_regle", 'commandes');
221
222                // Si le plugin n'était pas déjà en payé et qu'on a pas assez payé
223                // (si le plugin était déjà en payé, ce sont possiblement des renouvellements)
224                if (
225                        $statut_commande != 'paye'
226                        and (floatval($montant_attendu) - floatval($montant_regle)) >= 0.01
227                ){
228                        $statut_nouveau = 'partiel';
229                }
230               
231                // S'il y a bien un statut à changer
232                if ($statut_nouveau !== $statut_commande){
233                        spip_log("commandes_bank_traiter_reglement marquer la commande #$id_commande statut: $statut_commande -> $statut_nouveau mode=$transaction_mode",'commandes');
234                        // On met a jour la commande
235                        include_spip("action/editer_commande");
236                        commande_modifier($id_commande, array('statut'=>$statut_nouveau, 'mode'=>$transaction_mode));
237                }
238
239                // un message gentil pour l'utilisateur qui vient de payer, on lui rappelle son numero de commande
240                $flux['data'] .= "<br />"._T('commandes:merci_de_votre_commande_paiement',array('reference'=>$commande['reference']));
241        }
242
243        return $flux;
244}
245
246/**
247 * Enregistrer le reglement en attente d'une commande liee a une transaction du plugin bank
248 * (cas du reglement par cheque par exemple)
249 *
250 * @pipeline trig_bank_reglement_en_attente
251 * @param array $flux
252 * @return array mixed
253 */
254function commandes_trig_bank_reglement_en_attente($flux){
255        // Si on est dans le bon cas d'un paiement de commande et qu'il y a un id_commande et que la commande existe toujours
256        if ($id_transaction = $flux['args']['id_transaction']
257          AND $transaction = sql_fetsel("*","spip_transactions","id_transaction=".intval($id_transaction))
258                AND $id_commande = $transaction['id_commande']
259                AND $commande = sql_fetsel('id_commande, statut, id_auteur, mode', 'spip_commandes', 'id_commande='.intval($id_commande))){
260
261                $statut_commande = $commande['statut'];
262                $transaction_mode = $transaction['mode'];
263                $commande_mode = $commande['mode'];
264                $statut_nouveau = 'attente';
265                if ($statut_nouveau !== $statut_commande OR $transaction_mode !==$commande_mode){
266                        spip_log("commandes_trig_bank_reglement_en_attente marquer la commande #$id_commande statut=$statut_nouveau mode=$transaction_mode",'commandes');
267                        //on met a jour la commande
268                        include_spip("action/editer_commande");
269                        commande_modifier($id_commande,array('statut'=>$statut_nouveau,'mode'=>$transaction_mode));
270                }
271        }
272
273        return $flux;
274}
275
276
277/**
278 * Enregistrer le reglement en echec d'une commande liee a une transaction du plugin bank
279 * (cas du reglement annule ou du refus de carte etc)
280 *
281 * @pipeline trig_bank_reglement_en_echec
282 * @param array $flux
283 * @return array mixed
284 */
285function commandes_trig_bank_reglement_en_echec($flux){
286        // Si on est dans le bon cas d'un paiement de commande et qu'il y a un id_commande et que la commande existe toujours
287        if ($id_transaction = $flux['args']['id_transaction']
288          AND $transaction = sql_fetsel("*","spip_transactions","id_transaction=".intval($id_transaction))
289                AND $id_commande = $transaction['id_commande']
290                AND $commande = sql_fetsel('id_commande, statut, id_auteur', 'spip_commandes', 'id_commande='.intval($id_commande))){
291
292                $statut_commande = $commande['statut'];
293                $transaction_mode = $transaction['mode'];
294                $statut_nouveau = $statut_commande;
295
296                // on ne passe la commande en erreur que si le reglement a effectivement echoue,
297                // pas si c'est une simple annulation (retour en arriere depuis la page de paiement bancaire)
298                if (strncmp($transaction['statut'],"echec",5)==0){
299                        $statut_nouveau = 'erreur';
300                }
301                if ($statut_nouveau !== $statut_commande){
302                        spip_log("commandes_trig_bank_reglement_en_attente marquer la commande #$id_commande statut=$statut_nouveau",'commandes');
303                        //on met a jour la commande
304                        include_spip("action/editer_commande");
305                        commande_modifier($id_commande,array('statut'=>$statut_nouveau,'mode'=>$transaction_mode));
306                }
307        }
308
309        return $flux;
310}
311
312/**
313 * Déclarer les échéances à la banque
314 *
315 * @pipeline bank_abos_decrire_echeance
316 **/
317function commandes_bank_abos_decrire_echeance($flux) {
318        if (
319                // si on doit bien faire du prélèvement auto
320                $flux['args']['force_auto'] == true
321                // et qu'on a une transaction sous la main
322                and $id_transaction = intval($flux['args']['id_transaction'])
323                // et que cette transaction a un id_commande
324                and $id_commande = intval(sql_getfetsel('id_commande', 'spip_transactions', 'id_transaction = '.$id_transaction))
325                // et que la commande a des informations d'échéances
326                and $commande = sql_fetsel('echeances_type, echeances_date_debut, echeances', 'spip_commandes', 'id_commande = '.$id_commande)
327                and $echeances = unserialize($commande['echeances'])
328                and $echeances_type = $commande['echeances_type']
329                and in_array($echeances_type, array('mois', 'annee'))
330        ) {
331                // On définit la périodicité
332                switch($echeances_type) {
333                        case 'mois':
334                                $flux['data']['freq'] = 'monthly';
335                                break;
336                        case 'annee':
337                                $flux['data']['freq'] = 'yearly';
338                                break;
339                }
340
341                if ($commande['echeances_date_debut']
342                        and strtotime($commande['echeances_date_debut'])>$_SERVER['REQUEST_TIME']) {
343                        $flux['data']['date_start'] = $commande['echeances_date_debut'];
344                }
345               
346                // Si c'est une seule valeur toute simple
347                if (!is_array($echeances)) {
348                        $echeances = floatval($echeances);
349                        $flux['data']['montant'] = $echeances;
350                }
351                // ou un array d'une seule echeance
352                elseif (count($echeances) == 1) {
353                        $echeance = reset($echeances);
354                        $flux['data']['montant'] = floatval($echeance['montant']);
355                        if (isset($echeance['nb'])) {
356                                $flux['data']['count'] = $echeance['nb'];
357                        }
358                }
359                // Sinon c'est un peu plus compliqué, et pour l'instant on ne gère que DEUX montants possibles
360                elseif (count($echeances) >= 2) {
361                        // Premier montant d'échéances
362                        $flux['data']['montant_init'] = $echeances[0]['montant'];
363                        $flux['data']['count_init'] = $echeances[0]['nb'];
364                        // Deuxième montant d'échéances
365                        $flux['data']['montant'] = $echeances[1]['montant'];
366                        if (isset($echeances[1]['nb'])) {
367                                $flux['data']['count'] = $echeances[1]['nb'];
368                        }
369                }
370        }
371
372        return $flux;
373}
374
375/**
376 * Lier une commande à un identifiant bancaire lorsqu'un prélèvement bancaire est bien validé
377 *
378 * @pipeline bank_abos_activer_abonnement
379 **/
380function commandes_bank_abos_activer_abonnement($flux){
381        // Si on a une transaction
382        if ($id_transaction = intval($flux['args']['id_transaction'])) {
383                $where = 'id_transaction = '.$id_transaction;
384        }
385        // Sinon on cherche par l'identifiant d'abonnement bancaire
386        elseif ($abo_uid = $flux['args']['abo_uid']) {
387                $where = 'abo_uid = '.sql_quote($abo_uid);
388        }
389       
390        // On gère d'abord les erreurs possibles si on ne trouve pas la bonne transaction
391        if (!$where or !$transaction = sql_fetsel('*', 'spip_transactions', $where)) {
392                spip_log("Impossible de trouver la transaction ($id_transaction / $abo_uid).", 'commandes.'._LOG_ERREUR);
393                $flux['data'] = false;
394        }
395        elseif ($transaction['statut'] == 'commande') {
396                spip_log("La transaction ${transaction['id_transaction']} n’a pas été réglée.", 'commandes.'._LOG_ERREUR);
397                $flux['data'] = false;
398        }
399        elseif (strncmp($transaction['statut'], 'echec',5) == 0) {
400                spip_log("La transaction ${transaction['id_transaction']} a echoué.",'commandes.'._LOG_ERREUR);
401                $flux['data'] = false;
402        }
403        // Si on a trouvé ce qu'il faut, on va lier la commande à l'identifiant bancaire
404        elseif ($id_commande = intval($transaction['id_commande'])) {
405                include_spip('action/editer_objet');
406               
407                objet_modifier('commande', $id_commande, array('bank_uid' => $flux['args']['abo_uid']));
408        }
409       
410        return $flux;
411}
412
413/**
414 * Créer la transaction correspondant à la prochaine échéance d'une commande
415 *
416 * @pipeline bank_abos_preparer_echeance
417 **/
418function commandes_bank_abos_preparer_echeance($flux){
419        // On commence par chercher la commande dont il s'agit
420        // et vérifier qu'elle a des échéances
421        if (
422                isset($flux['args']['id'])
423                and $id = $flux['args']['id']
424                and strncmp($id,"uid:",4) == 0
425                and $bank_uid = substr($id, 4)) {
426
427                // robustesse pour retrouver la comande correspondant a un numero d'abonnement
428                if ($id_commande = sql_getfetsel('id_commande','spip_commandes','bank_uid='.sql_quote($bank_uid))
429                  or $id_commande = sql_getfetsel('id_commande','spip_transactions','abo_uid='.sql_quote($bank_uid))) {
430
431                        if ($commande = sql_fetsel('*', 'spip_commandes', 'id_commande='.intval($id_commande))
432                          and $echeances = unserialize($commande['echeances'])
433                          and $echeances_type = $commande['echeances_type'] ) {
434
435                                include_spip('inc/commandes_echeances');
436
437                                // Si on a bien trouvé une prochaine échéance
438                                if ($desc = commandes_trouver_prochaine_echeance_desc($id_commande, $echeances)
439                                  and isset($desc['montant'])) {
440                                        include_spip('action/editer_objet');
441
442                                        $set = array('statut' => 'attente');
443                                        // robustesse/reparation si echec d'update a la premiere echeance payee
444                                        if (!$commande['bank_uid']) {
445                                                $set['bank_uid'] = $bank_uid;
446                                        }
447
448                                        // On remet la commande en attente de paiement puisqu'on… attend un paiement !
449                                        objet_modifier('commande', $id_commande, $set);
450
451                                        // On crée la transaction qui testera le vrai paiement
452                                        $montant = $desc['montant'];
453                                        $inserer_transaction = charger_fonction('inserer_transaction', 'bank');
454                                        $options_transaction = array(
455                                                'id_auteur' => intval($commande['id_auteur']),
456                                                'champs' => array(
457                                                        'id_commande' => $id_commande,
458                                                ),
459                                        );
460                                        if (isset($desc['montant_ht'])) {
461                                                $options_transaction['montant_ht'] = $desc['montant_ht'];
462                                        }
463                                        $id_transaction = intval($inserer_transaction($montant, $options_transaction));
464
465                                        $flux['data'] = $id_transaction;
466                                }
467
468                        }
469                }
470
471        }
472
473        return $flux;
474}
475
476/**
477 * Mettre en erreur une commande dont le prélèvement automatique aurait échoué
478 * on repere ce cas via le flag erreur=true envoyer lors de la resiliation
479 *
480 * @pipeline bank_abos_resilier
481 **/
482function commandes_bank_abos_resilier($flux){
483        // On commence par chercher la commande dont il s'agit
484        // et vérifier qu'elle a des échéances
485        if (
486                isset($flux['args']['erreur']) and $flux['args']['erreur']
487                and isset($flux['args']['id']) and $id = $flux['args']['id']
488                and strncmp($id,"uid:",4) == 0
489                and $bank_uid = substr($id, 4)
490                and $commande = sql_fetsel('*', 'spip_commandes', 'bank_uid = '.sql_quote($bank_uid))
491                and $id_commande = intval($commande['id_commande'])
492        ) {
493                include_spip('action/editer_objet');
494               
495                // Le prélèvement a échoué explicitement, donc la commande d'origine est en erreur
496                objet_modifier('commande', $id_commande, array('statut' => 'erreur'));
497        }
498       
499        return $flux;
500}
501
502/**
503 * Si le plugin Bank est activé, un changement de statut vers Payée redirige vers la page de paiement de la transaction
504 *
505 * @pipeline pre_edition
506 **/
507
508function commandes_pre_edition($flux){
509        if (test_plugin_actif('bank')
510                AND $flux['args']['table'] == 'spip_commandes'
511                AND $flux['args']['action'] == 'instituer'
512                AND $flux['data']['statut'] == 'paye') {
513
514                /*
515                $id_commande = $flux['args']['id_objet'];
516
517                $transaction = sql_fetsel('id_transaction, transaction_hash, statut', 'spip_transactions', 'id_commande='.intval($id_commande));
518
519                if (!is_null($transaction) AND $transaction['statut'] != 'ok') {
520                        $arguments = "id_transaction=".$transaction['id_transaction']."&transaction_hash=".$transaction['transaction_hash'];
521
522                        include_spip('inc/headers');
523                        redirige_url_ecrire('payer' , $arguments);
524                }
525                */
526        }
527        return $flux;
528}
Note: See TracBrowser for help on using the repository browser.