Valider 0e902520 rédigé par tcharlss's avatar tcharlss
Parcourir les fichiers

fix: faire fonctionner l'autocomplétion des billets à posteriori dans tous les cas

Ça fonctionnait quand on utilisait l'API editer_objet, mais pas avec le formulaire d'édition.
Dans ce cas la création se passe en 2 temps : l'objet est d'abord créé à vide, puis il est ensuite modifié avec les valeurs postées.

Il faut donc tenir compte de ce cas de figure : on combine post_insertion et pre_edition
Au final on auto-complète tant que le billet est au panier.

On ajoute un pipeline `billet_completer_champs` permettant aux autres plugins d'ajouter des trucs à l'autocomplétion : billetteries par profil par exemple.

Refs #21
parent f6130b06
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+164 −100
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -544,30 +544,174 @@ function billetteries_generer_commande($id_auteur) {
}

/**
 * Faire des choses après l'édition
 * Agir avant l'insertion en base lors de la création des objets
 *
 * - Valider les billets quand la commande est payée + maj les infos du type de billet
 * - Forcer le id_billets_type sur les billets
 *
 * @note
 * La création d'un billet se fait parfois en 2 étapes, notamment avec les forms d'édition :
 * l'objet est d'abord créé à vide avec objet_inserer,
 * puis les valeurs sont ajoutées avec objet_modifier.
 * On force à enregistrer le id_billets_type dès la 1ère étape,
 * sinon ça peut poser des problèmes, pour récupérer le prix dans pre_edition notamment.
 *
 * @pipeline pre_insertion
 * @param array $flux
 *   Flux du pipeline contenant le contexte et les couples champ/valeurs à insérer
 * @return array
 *   Retourne le flux possiblement modifié
 **/
function billetteries_pre_insertion($flux) {

	$table = (isset($flux['args']['table']) ? $flux['args']['table'] : null);

	// Si on crée un billet et qu'on a un type de billet
	if (
		$table === 'spip_billets'
		and $id_billets_type = _request('id_billets_type')
	) {
		$flux['data']['id_billets_type'] = $id_billets_type;
	}

	return $flux;
}

/**
 * Agir après l'insertion en base lors de la création des objets
 *
 * - Auto-compléter certains champs des billets
 *   Nb : ne peut se faire dans pre_insertion car on a besoin du n° du billet
 *
 * @note
 * La création d'un objet se fait parfois en 2 étapes, notamment avec les forms d'édition :
 * l'objet est d'abord créé à vide avec objet_inserer,
 * puis les valeurs sont ajoutées avec objet_modifier.
 * Dans ce cas il ne faut rien faire ici car les modifs seront écrasées,
 * on agira dans pre_edition plutôt.
 *
 * @uses billetteries_billet_completer_champs()
 *
 * @pipeline post_insertion
 * @param array $flux
 *   Flux du pipeline contenant le contexte et les couples champ/valeurs à insérer
 * @return array
 *   Retourne le flux possiblement modifié
 **/
function billetteries_post_insertion($flux) {

	$table = (isset($flux['args']['table']) ? $flux['args']['table'] : null);
	$id_objet = (isset($flux['args']['id_objet']) ? intval($flux['args']['id_objet']) : 0);

	// Si on crée un billet, auto-compléter certains champs.
	// Ici peu importe le statut contrairement à post_edition.
	if (
		$table === 'spip_billets'
		and $id_billet = $id_objet
		// Si le $set est vide ou qu'il ne contient que le statut et la date,
		// ça veut dire que la création se fait en 2 temps (ex. : formulaire d'édition).
		// Ne rien faire ici car les modifs seront écrasées, on agira dans pre_edition.
		and (
			count($flux['data']) > 0
			and !(
				count($flux['data']) === 2
				and array_keys($flux['data']) === array('statut', 'date')
			)
		)
		and $billet = sql_fetsel('*', 'spip_billets', 'id_billet = ' . $id_billet)
	) {
		include_spip('inc/billetteries');
		$champs = $flux['data'];
		$champs_modifs = billetteries_billet_completer_champs($id_billet, $champs, $billet);
		// On met à jour s'il y a des modifs
		if ($set = array_diff($champs_modifs, $champs)) {
			include_spip('action/editer_objet');
			$log_set = json_encode($set);
			spip_log("[post_insertion] compléments automatiques du nouveau billet $id_billet : $log_set", 'billetteries' . _LOG_DEBUG);
			objet_modifier('billet', $id_billet, $set);
		}
		// Et retourner les champs modifiés
		$flux['data'] = $champs_modifs;
	}

	return $flux;
}

/**
 * Faire des choses avant l'édition d'un objet
 *
 * - Auto-compléter certains champs des billets tant qu'ils sont panier
 *
 * @note
 * On passe parfois dans ce pipeline même en cas de création d'objet.
 * Voir la @note de post_insertion.
 *
 * @uses billetteries_billet_completer_champs()
 *
 * @pipeline pre_edition
 * @param array $flux
 *   Flux du pipeline contenant le contexte et les couples champ/valeurs à modifier
 * @return array
 *   Retourne le flux possiblement modifié
 */
function billetteries_pre_edition($flux) {

	$table = (isset($flux['args']['table']) ? $flux['args']['table'] : null);
	$id_objet = (isset($flux['args']['id_objet']) ? intval($flux['args']['id_objet']) : 0);
	$action = (isset($flux['args']['action']) ? $flux['args']['action'] : null);

	// Si c'est un billet au panier, auto-compléter certains champs
	if (
		$table === 'spip_billets'
		and $id_billet = $id_objet
		and $action === 'modifier'
		and $billet = sql_fetsel('*', 'spip_billets', "id_billet = $id_billet")
		and $statut = (isset($flux['data']['statut']) ? $flux['data']['statut'] : $billet['statut'])
		and $statut === 'panier'
	) {
		include_spip('inc/billetteries');
		$champs = $flux['data'];
		$champs_modifs = billetteries_billet_completer_champs($id_billet, $champs, $billet);
		// On log s'il y a des modifs
		if ($set = array_diff($champs_modifs, $champs)) {
			$log_set = json_encode($set);
			spip_log("[pre_edition] compléments automatiques du billet $id_billet au panier : $log_set", 'billetteries' . _LOG_DEBUG);
		}
		// Et retourner les champs modifiés
		$flux['data'] = $champs_modifs;
	}

	return $flux;
}

/**
 * Faire des choses après l'édition d'un objet
 *
 * - Valider les billets quand une commande est payée
 * - Appeler les notifs quand un billet est annulé (WIP)
 *
 * @pipeline post_edition
 * @param array $flux
 * 		Flux du pipeline contenant toutes les saisies des formulaires
 *   Flux du pipeline contenant le contexte et les couples champ/valeurs modifiées
 * @return array
 *   Retourne le flux possiblement modifié
 */
function billetteries_post_edition($flux) {

	// Si on paye une commande il faut valider les billets dedans
	$table = (isset($flux['args']['table']) ? $flux['args']['table'] : null);
	$id_objet = (isset($flux['args']['id_objet']) ? intval($flux['args']['id_objet']) : 0);
	$action = (isset($flux['args']['action']) ? $flux['args']['action'] : null);

	// Commande : si on la paye il faut valider les billets dedans
	if (
		// Si on institue une commande
		isset($flux['args']['table'])
		and $flux['args']['table'] == 'spip_commandes'
		and $id_commande = intval($flux['args']['id_objet'])
		and $flux['args']['action'] == 'instituer'
		$table === 'spip_commandes'
		and $id_commande = $id_objet
		and $action === 'instituer'
		// Et qu'on passe en statut "paye" depuis autre chose
		and $flux['data']['statut'] == 'paye'
		and $flux['args']['statut_ancien'] != 'paye'
		and $flux['data']['statut'] === 'paye'
		and $flux['args']['statut_ancien'] !== 'paye'
		// Et que la commande existe bien
		and $commande = sql_fetsel('*', 'spip_commandes', 'id_commande = ' . $id_commande)
		and sql_countsel('spip_commandes', 'id_commande = ' . $id_commande)
		// Et qu'on a des billets liés à cette commande
		and include_spip('action/editer_liens')
		and $liens = objet_trouver_liens(array('commande'=>$id_commande), array('billet'=>'*'))
@@ -587,14 +731,15 @@ function billetteries_post_edition($flux) {
			}
		}
	}
	// Quand un billet est annulé, il faut envoyer certaines notifications
	// Si c'est un billet annulé, il faut envoyer certaines notifications
	// WIP : ces notifs n'existent pas encore + rendre configurable
	elseif (
		$flux['args']['table'] == 'spip_billets'
		and $id_billet = intval($flux['args']['id_objet'])
		and $flux['args']['action'] == 'instituer'
		and $flux['data']['statut'] == 'annule'
		and $flux['args']['statut_ancien'] != 'annule'
		and $billet = sql_fetsel('*', 'spip_billets', 'id_billet = '.$id_billet)
		$table === 'spip_billets'
		and $id_billet = $id_objet
		and sql_countsel('spip_billets', 'id_billet = ' . $id_billet)
		and $action === 'instituer'
		and $flux['data']['statut'] === 'annule'
		and $flux['data']['statut_ancien'] !== 'annule'
	) {
		// Notifications
		if ($notifications = charger_fonction('notifications', 'inc')) {
@@ -610,87 +755,6 @@ function billetteries_post_edition($flux) {
	return $flux;
}

/**
 * Actions à effectuer après la création d'un billet
 *
 * - Générer le code des nouveaux billets dès la création
 * - Remplir le champ `id_billetterie`
 * - Graver les infos du type de billet
 *
 * @pipeline post_insertion
 * @param array $flux
 * 		Flux du pipeline contenant toutes les saisies des formulaires
 * @return array
 * 		Retourne le flux possiblement modifié
 **/
function billetteries_post_insertion($flux) {
	if (
		// Si on institue un billet
		isset($flux['args']['table'])
		and $flux['args']['table'] == 'spip_billets'
		and $id_billet = intval($flux['args']['id_objet'])
	) {

		$set = array();
		include_spip('action/editer_objet');

		// Générer le code si le billet n'a pas déjà un code rempli
		if (empty($flux['data']['code'])) {
			// On génère le code unique
			$fonction_code = charger_fonction('billetteries_code', 'inc/');
			$code = $fonction_code($id_billet);

			$set['code' ] = $code;
			$flux['data']['code'] = $code;
		}

		// Remplir `id_billetterie` si besoin
		// [FIXME] via le formulaire, id_billets_type n'est pas présent dans $flux['data] ?
		if (
			empty($flux['data']['id_billetterie'])
			and $id_billets_type = (isset($flux['data']['id_billets_type']) ? $flux['data']['id_billets_type'] : _request('id_billets_type'))
		) {
			$id_billetterie = sql_getfetsel('id_billetterie', 'spip_billets_types', 'id_billets_type='.intval($id_billets_type));
			$set['id_billetterie'] = $id_billetterie;
			$flux['data']['id_billetterie'] = $id_billetterie;
		}

		// Garder des infos sur le type de billet au cas où il change ou disparaisse par la suite
		// [FIXME] via le formulaire, id_billets_type n'est pas présent dans $flux['data] ?
		if (
			$id_billets_type = (isset($flux['data']['id_billets_type']) ? $flux['data']['id_billets_type'] : _request('id_billets_type'))
			and $infos_billets_type = sql_fetsel('titre AS titre_billets_type', 'spip_billets_types', 'id_billets_type='.intval($id_billets_type))
		) {
				// Récupérer le prix_ht + montant taxes
				if (
					$fonction_prix_ht = charger_fonction('ht', 'inc/prix', true)
					and $fonction_taxes = charger_fonction('taxes', 'inc/', true)
				) {
					$infos_billets_type['prix_ht'] = $fonction_prix_ht('billet', $id_billet);
					$taxes = $fonction_taxes('billet', $id_billet);
					$taxes_montant = array_sum(array_column($taxes, 'montants'));
					$infos_billets_type['taxes'] = $taxes_montant;
				}
				$infos = (isset($flux['data']['infos']) ? unserialize($flux['data']['infos']) : array());
				$infos_plus = array_merge(
					$infos,
					$infos_billets_type
				);
				$infos_plus = serialize($infos_plus);
				$set['infos'] = $infos_plus;
				$flux['data']['infos'] = $infos_plus;
		}

		// S'il y a ds choses à modifier
		if ($set) {
			objet_modifier('billet', $id_billet, $set);
		}

	}

	return $flux;
}

/**
 * Protéger le formulaire de mise au panier de billets
 *

inc/billetteries.php

0 → 100644
+168 −0
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
<?php
/**
 * Fonctions du plugin Billetteries
 *
 * @plugin     Billetteries
 * @copyright  2019
 * @author     Mukt, Concurrences
 * @licence    GPL 3
 * @package    SPIP\Billetteries\Fonctions
 */

// Sécurité
if (!defined('_ECRIRE_INC_VERSION')) {
	return;
}

/**
 * Compléter automatiquement certains champs d'un billet
 *
 * Sous-entendu : au moment de son édition et tant qu'il n'est pas encore "finalisé",
 * c'est à dire à la création ou tant qu'il est encore au panier.
 *
 * La fonction ne fait que retourner les champs éventuellement modifiés.
 * Elle ne met pas à jour le billet, c'est à l'appelant de procéder.
 *
 * Important : il faut que le billet ait déjà un id_billets_type,
 * sinon le prix retourné sera toujours 0.
 *
 * Champs concernés :
 * - id_billetterie : s'il est vide
 * - code : s'il est vide
 * - email : s'il est vide et qu'on a un id_auteur
 * - source : s'il est vide et qu'on est dans le privé
 * - infos : ajout de prix_ht, taxes, et titre_billets_type
 *
 * @param int $id_billet
 *   Numéro du billet
 * @param array $champs
 *   Couples champ => valeur.
 *   Si des champs complétables ne sont pas présents dans la liste, ils seront ajoutés.
 *   Ce ne sont pas nécessairement les valeurs en base :
 *   par ex. des nouvelles valeurs si on est en train de modifier le billet.
 * @param array|null $billet
 *   Ligne SQL du billet si on l'a déjà sous la main
 * @return array
 *   Couples champs => valeurs, certaines étant éventuellement modifiées
 */
function billetteries_billet_completer_champs($id_billet, $champs = array(), $billet = array()) {

	include_spip('base/abstract_sql');

	// Récupérer les valeurs en base si nécessaire
	if (!$billet) {
		$billet = sql_fetsel('*', 'spip_billets', 'id_billet = ' . $id_billet);
	}

	// Garder une trace des modifs
	$champs_avant = $champs;

	// Les champs à compléter
	$champs_a_completer = array(
		'code',
		'email',
		'id_billetterie',
		'source',
		'infos',
	);
	$id_billets_type = intval(isset($champs['id_billets_type']) ? $champs['id_billets_type'] : $billet['id_billets_type']);
	$id_auteur = intval(isset($champs['id_auteur']) ? $champs['id_auteur'] : $billet['id_auteur']);
	foreach ($champs_a_completer as $champ) {
		// Si la valeur n'est pas donnée, récupérer celle en base
		$valeur = (isset($champs[$champ]) ? $champs[$champ] : $billet[$champ]);
		switch ($champ) {

			// Si le code est vide : le générer
			case 'code':
				if (empty($valeur)) {
					$fonction_code = charger_fonction('billetteries_code', 'inc/');
					$code = $fonction_code($id_billet);
					$champs['code'] = $code;
				}
				break;

			// Si l'email est vide : prendre celui de l'auteur associé
			case 'email':
				if (
					empty($valeur)
					and $id_auteur > 0
				) {
					$email = sql_getfetsel('email', 'spip_auteurs', "id_auteur = $id_auteur");
					$champs['email'] = $email;
				}
				break;

			// Si le numéro de billetterie est vide : prendre celui du type de billet
			case 'id_billetterie':
				if (
					empty($valeur)
					and $id_billets_type > 0
				) {
					$id_billetterie = intval(sql_getfetsel('id_billetterie', 'spip_billets_types', "id_billets_type = $id_billets_type"));
					$champs['id_billetterie'] = $id_billetterie;
				}
				break;

			// Si la source est vide et qu'on est dans le privé : indiquer l'admin
			case 'source':
				if (
					empty($valeur)
					and test_espace_prive()
				) {
					$id_admin = (isset($GLOBALS['visiteur_session']['id_auteur']) ? intval($GLOBALS['visiteur_session']['id_auteur']) : '?');
					$source = "admin#{$id_admin}";
					$champs['source'] = $source;
				}
				break;

			// Garder le prix actuel du billet au cas où il change par la suite
			case 'infos':
				// Récupérer les infos actuelles désérialisées
				$infos = array();
				if (!empty($valeur)) {
					try {
						$infos = unserialize($valeur);
					} catch (Exception $e) {
						$erreur = $e->getMessage();
						spip_log("[auto_completer_billet] échec unserialize infos du billet $id_billet : $erreur", 'billetteries' . _LOG_ERREUR);
					}
				}
				$infos = (is_array($infos) ? $infos : array());
				// Ajouter le titre du type de billet
				$titre_billets_type = sql_getfetsel('titre', 'spip_billets_types', "id_billets_type = $id_billets_type");
				$infos['billets_type'] = $titre_billets_type;
				// Ajouter le prix et les taxes
				// Pour les taxes on peut avoir plusieurs taux, on ne garde donc que le montant total pour simplifier
				if (
					$fonction_prix_ht = charger_fonction('ht', 'inc/prix', true)
					and $fonction_taxes = charger_fonction('taxes', 'inc/', true)
				) {
					$infos['prix_ht'] = $fonction_prix_ht('billet', $id_billet);
					$taxes = $fonction_taxes('billet', $id_billet);
					$taxes_montant = array_sum(array_column($taxes, 'montant'));
					$infos['taxes'] = $taxes_montant;
				}
				// Resérialiser
				$infos = serialize($infos);
				$champs['infos'] = $infos;
				break;
		}
	}

	// Un coup pour les plugins (billetteries_profils…)
	$champs = pipeline('billet_completer_champs', array(
		'args' => array(
			'id_billet' => $id_billet,
			'billet' => $billet,
		),
		'data' => $champs
	));

	// Loguer s'il y a des choses modifiées
	// if ($set = array_diff($champs, $champs_avant)) {
	// 	$log_set = json_encode($set);
	// 	spip_log("[billet_completer_champs] compléments automatiques du billet $id_billet : $log_set", 'billetteries' . _LOG_DEBUG);
	// }

	return $champs;
}
+3 −0
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -37,7 +37,9 @@
	<pipeline nom="saisies_autonomes" inclure="billetteries_pipelines.php" />
	<pipeline nom="jquery_plugins" inclure="billetteries_pipelines.php" />
	<pipeline nom="formulaire_traiter" inclure="billetteries_pipelines.php" />
	<pipeline nom="pre_edition" inclure="billetteries_pipelines.php" />
	<pipeline nom="post_edition" inclure="billetteries_pipelines.php" />
	<pipeline nom="pre_insertion" inclure="billetteries_pipelines.php" />
	<pipeline nom="post_insertion" inclure="billetteries_pipelines.php" />
	<pipeline nom="nospam_lister_formulaires" inclure="billetteries_pipelines.php" />

@@ -45,6 +47,7 @@
	<pipeline nom="billetteries_exporter_billets_colonnes" action="" />
	<pipeline nom="billetteries_exporter_billets_ligne" action="" />
	<pipeline nom="billet_afficher_infos" action="" />
	<pipeline nom="billet_completer_champs" action="" />

	<menu nom="billetteries" titre="billetterie:titre_billetteries" parent="menu_edition" icone="images/billetterie-16.png" action="billetteries" />
	<menu nom="billets" titre="billet:titre_billets" parent="menu_activite" icone="images/billet-16.png" action="billets" />