Browse Source

Un plugin qui gère des options sur les produits.

Première version, déjà en prod, mais des choses à améliorer et des évolutions possibles.
svn/root/tags/v1.3.3
nicolas.dorigny@gmail.com 5 years ago
commit
8d4f8ef5ff
  1. 65
      .gitattributes
  2. 56
      README.md
  3. 210
      action/commandes_paniers.php
  4. 41
      action/produit_panier.php
  5. 133
      action/remplir_panier.php
  6. 38
      action/supprimer_option.php
  7. 38
      action/supprimer_option_objet.php
  8. 140
      base/optionsproduits.php
  9. 16
      formulaires/configurer_options.html
  10. 30
      formulaires/editer_option.html
  11. 207
      formulaires/editer_option.php
  12. 20
      formulaires/editer_optionsgroupe.html
  13. 157
      formulaires/editer_optionsgroupe.php
  14. 100
      formulaires/options_liees_objet.html
  15. 71
      formulaires/options_liees_objet.php
  16. 76
      formulaires/panier.html
  17. 99
      formulaires/panier.php
  18. 45
      formulaires/panier_produit_options.html
  19. 55
      formulaires/panier_produit_options.php
  20. 105
      inc/prix_option.php
  21. 23
      javascript/optionsproduits.js
  22. 60
      lang/option_fr.php
  23. 21
      lang/options_fr.php
  24. 47
      lang/optionsgroupe_fr.php
  25. 14
      lang/paquet-options_fr.php
  26. 66
      optionsproduits_administrations.php
  27. 208
      optionsproduits_autorisations.php
  28. 64
      optionsproduits_fonctions.php
  29. 142
      optionsproduits_pipelines.php
  30. 36
      paquet.xml
  31. 18
      prive/objets/contenu/option.html
  32. 7
      prive/objets/contenu/optionsgroupe.html
  33. 16
      prive/objets/infos/option.html
  34. 16
      prive/objets/infos/optionsgroupe.html
  35. 46
      prive/objets/liste/objets_lies_option.html
  36. 47
      prive/objets/liste/options.html
  37. 3
      prive/objets/liste/options_liees_objet.html
  38. 39
      prive/objets/liste/optionsgroupes.html
  39. 7
      prive/squelettes/contenu/configurer_options.html
  40. 49
      prive/squelettes/contenu/option.html
  41. 36
      prive/squelettes/contenu/option_edit.html
  42. 7
      prive/squelettes/contenu/options.html
  43. 47
      prive/squelettes/contenu/optionsgroupe.html
  44. 7
      prive/squelettes/contenu/optionsgroupes.html
  45. 10
      prive/squelettes/hierarchie/option.html
  46. 1
      prive/squelettes/hierarchie/option_edit.html
  47. 63
      prive/squelettes/navigation/options.html
  48. 1
      prive/squelettes/navigation/optionsgroupes.html
  49. 22
      prive/style_prive_plugin_options.html
  50. BIN
      prive/themes/spip/images/option-12.png
  51. BIN
      prive/themes/spip/images/option-16.png
  52. BIN
      prive/themes/spip/images/option-24.png
  53. BIN
      prive/themes/spip/images/option-32.png
  54. BIN
      prive/themes/spip/images/option-new-16.png
  55. BIN
      prive/themes/spip/images/options-128.png
  56. BIN
      prive/themes/spip/images/options-32.png
  57. BIN
      prive/themes/spip/images/options-64.png
  58. BIN
      prive/themes/spip/images/optionsgroupe-12.png
  59. BIN
      prive/themes/spip/images/optionsgroupe-16.png
  60. BIN
      prive/themes/spip/images/optionsgroupe-24.png
  61. BIN
      prive/themes/spip/images/optionsgroupe-32.png
  62. BIN
      prive/themes/spip/images/optionsgroupe-new-16.png
  63. 50
      prix_option/produit.php
  64. 20
      saisies-vues/optionsgroupes.html
  65. 13
      saisies/optionsgroupes.html

65
.gitattributes vendored

@ -0,0 +1,65 @@
* text=auto !eol
/README.md -text
action/commandes_paniers.php -text
action/produit_panier.php -text
action/remplir_panier.php -text
action/supprimer_option.php -text
action/supprimer_option_objet.php -text
base/optionsproduits.php -text
formulaires/configurer_options.html -text
formulaires/editer_option.html -text
formulaires/editer_option.php -text
formulaires/editer_optionsgroupe.html -text
formulaires/editer_optionsgroupe.php -text
formulaires/options_liees_objet.html -text
formulaires/options_liees_objet.php -text
formulaires/panier.html -text
formulaires/panier.php -text
formulaires/panier_produit_options.html -text
formulaires/panier_produit_options.php -text
inc/prix_option.php -text
javascript/optionsproduits.js -text
lang/option_fr.php -text
lang/options_fr.php -text
lang/optionsgroupe_fr.php -text
lang/paquet-options_fr.php -text
/optionsproduits_administrations.php -text
/optionsproduits_autorisations.php -text
/optionsproduits_fonctions.php -text
/optionsproduits_pipelines.php -text
/paquet.xml -text
prive/objets/contenu/option.html -text
prive/objets/contenu/optionsgroupe.html -text
prive/objets/infos/option.html -text
prive/objets/infos/optionsgroupe.html -text
prive/objets/liste/objets_lies_option.html -text
prive/objets/liste/options.html -text
prive/objets/liste/options_liees_objet.html -text
prive/objets/liste/optionsgroupes.html -text
prive/squelettes/contenu/configurer_options.html -text
prive/squelettes/contenu/option.html -text
prive/squelettes/contenu/option_edit.html -text
prive/squelettes/contenu/options.html -text
prive/squelettes/contenu/optionsgroupe.html -text
prive/squelettes/contenu/optionsgroupes.html -text
prive/squelettes/hierarchie/option.html -text
prive/squelettes/hierarchie/option_edit.html -text
prive/squelettes/navigation/options.html -text
prive/squelettes/navigation/optionsgroupes.html -text
prive/style_prive_plugin_options.html -text
prive/themes/spip/images/option-12.png -text
prive/themes/spip/images/option-16.png -text
prive/themes/spip/images/option-24.png -text
prive/themes/spip/images/option-32.png -text
prive/themes/spip/images/option-new-16.png -text
prive/themes/spip/images/options-128.png -text
prive/themes/spip/images/options-32.png -text
prive/themes/spip/images/options-64.png -text
prive/themes/spip/images/optionsgroupe-12.png -text
prive/themes/spip/images/optionsgroupe-16.png -text
prive/themes/spip/images/optionsgroupe-24.png -text
prive/themes/spip/images/optionsgroupe-32.png -text
prive/themes/spip/images/optionsgroupe-new-16.png -text
prix_option/produit.php -text
saisies-vues/optionsgroupes.html -text
saisies/optionsgroupes.html -text

56
README.md

@ -0,0 +1,56 @@
# Gérer des options sur des produits
Le plugin gère des groupes d'options, dans lesquels on crée des options.
Chaque option a un prix HT par défaut (positif ou négatif), qui s'ajoute au prix de base du produit.
Sur chaque produit, on choisit quelles options on lui affecte.
On peut aussi modifier le prix de l'option sur le produit, pour avoir un prix différent du prix par défaut de l'option.
Côté public, les options sont proposées sous forme de boutons radio, classées par groupes.
Le prix HT des options est ajouté au prix HT du produit, et la TVA s'applique donc sur le total.
Un script JS mets à jour visuellement le prix TTC du produit en fonction des options choisies.
Les options sont transmises aux paniers puis aux commandes.
La surcharge de formulaires/panier permet d'afficher le nom du produit avec toutes les options choisies.
## Pour tester
Pour afficher le formulaire de choix des options et d'ajout au panier, utiliser #FORMULAIRE_PANIER_PRODUIT_OPTIONS{#ID_PRODUIT} dans le contexte d'un produit.
## Notes techniques
A l'installation, ajout d'un champ 'options varchar(100)' dans les tables spip_paniers_liens et spip_commandes_details
La clé primaire composée de spip_paniers_liens est supprimée et recréée avec ces champs : (id_panier, id_objet, objet, options)
Surcharges du plugin panier pour tenir compte des options :
- action/commandes_paniers.php
- action/remplir_panier.php
- formulaires/panier.html
- formulaires/panier.php
## TODO
**1 - Choix des options**
Actuellement, côté public, on ne peut choisir qu'une option par groupe.
Proposer une configuration pour chaque groupe, qui permettrait d'en choisir soit une seule soit plusieurs (radio/checkbox).
**2 - Problème à l'installation**
Si la table spip_paniers_liens contient déjà des données, la création de la nouvelle primary key composée génère une erreur sur un serveur Mysql (Duplicate entry ...).
Deux solutions :
1/ vider la table spip_paniers_liens
2/ passer par une clé autoincrement temporaire :
ALTER TABLE `spip_paniers_liens` ADD `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
ALTER TABLE `spip_paniers_liens` ADD UNIQUE KEY (`id_panier`, `id_objet`, `objet`, `options`);
ALTER TABLE `spip_paniers_liens` DROP `id`;
mais ça ne marche pas sur tous les serveurs Mysql

210
action/commandes_paniers.php

@ -0,0 +1,210 @@
<?php
/**
* Fonction du plugin Commandes de paniers
*
* @plugin Commandes de Paniers
* @copyright 2014
* @author Les Développements Durables
* @licence GNU/GPL
* @package SPIP\Panier2commande\Action
*/
// Sécurité
if (!defined("_ECRIRE_INC_VERSION"))
return;
include_spip('inc/base');
/**
* Créer une commande et remplir ses détails d'après le panier en cours du visiteur (ou d'après un panier donné).
*
* Pour créer une commande d'après le panier présent dans la session:
* #URL_ACTION{commandes_paniers,'',#SELF}
* Pour créer une commande d'après un panier précis :
* #URL_ACTION{commandes_paniers,#ID_PANIER,#SELF}
* Sans redirection explicite, la fonction redirige vers la page de la commande
*
* @param string $arg
* id_panier pour creer la commande et le detruire
* id_panier-1 pour creer la commande et le conserver
* @return void
* */
function action_commandes_paniers_dist($arg = null) {
// Si $arg n'est pas donné directement, le récupérer via _POST ou _GET
if (is_null($arg)) {
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
}
$arg = explode("-", $arg);
$id_panier = 0;
if (count($arg))
$id_panier = intval(array_shift($arg));
$keep = false;
if (count($arg))
$keep = intval(array_shift($arg));
// Sans paramètre, récupérer $id_panier dans la session du visiteur actuel
if (!$id_panier) {
include_spip('inc/paniers');
$id_panier = paniers_id_panier_encours();
}
// Si aucun panier ne pas agir
if (!$id_panier)
return;
$id_auteur = sql_getfetsel("id_auteur", "spip_paniers", "id_panier=" . intval($id_panier));
include_spip('inc/commandes');
include_spip('inc/config');
// si une commande recente est encours (statut et dans la session de l'utilisateur), on la reutilise
// plutot que de recreer N commandes pour un meme panier
// (cas de l'utilisateur qui revient en arriere puis retourne a la commande)
include_spip('inc/session');
$id_commande = sql_getfetsel("id_commande", "spip_commandes", $w = "statut=" . sql_quote('encours') . " AND date>" . sql_quote(date('Y-m-d H:i:s', strtotime('-' . lire_config('paniers/limite_ephemere', 24) . ' hour'))) . " AND source=" . sql_quote("panier#$id_panier") . " AND id_commande=" . session_get('id_commande'));
// sinon on cree une commande "en cours"
if (!$id_commande) {
$id_commande = creer_commande_encours();
}
// et la remplir les details de la commande d'après le panier en session
if ($id_commande) {
panier2commande_remplir_commande($id_commande, $id_panier, false);
}
// Supprimer le panier ?
if (!$keep) {
$supprimer_panier = charger_fonction('supprimer_panier_encours', 'action/');
$supprimer_panier();
}
// Sans redirection donnée, proposer une redirection par defaut vers la page de la commande créée
if (is_null(_request('redirect'))) {
$GLOBALS['redirect'] = generer_url_public('commande', 'id_commande=' . $id_commande, true);
}
}
/**
* Remplir une commande d'apres un panier
*
* @param int $id_commande
* @param int $id_panier
* @param bool $append
* true pour ajouter brutalement le panier a la commande, false pour verifier que commande==panier en ajoutant/supprimant uniquement les details necessaires
*/
function panier2commande_remplir_commande($id_commande, $id_panier, $append = true) {
include_spip('action/editer_objet');
include_spip('inc/filtres');
include_spip('inc/paniers');
// noter le panier source dans le champ source de la commande
objet_modifier('commande', $id_commande, array('source' => "panier#$id_panier"));
// recopier le contenu du panier dans la commande
// On récupère le contenu du panier
$panier = sql_allfetsel(
'*', 'spip_paniers_liens', 'id_panier = ' . intval($id_panier)
);
// Pour chaque élément du panier, on va remplir la commande
// (ou verifier que la ligne est deja dans la commande)
if ($panier and is_array($panier)) {
$details = array();
include_spip('spip_bonux_fonctions');
$fonction_prix = charger_fonction('prix_option', 'inc/');
$fonction_prix_ht = charger_fonction('ht', 'inc/prix_option');
foreach ($panier as $emplette) {
$prix_ht = $fonction_prix_ht($emplette['objet'], $emplette['id_objet'], $emplette['options'], 6);
$prix = $fonction_prix($emplette['objet'], $emplette['id_objet'], $emplette['options'], 6);
// On déclenche un pipeline pour pouvoir éditer le prix avant la création de la commande
// Utile par exemple pour appliquer une réduction automatique lorsque la commande est crée
$prix_pipeline = pipeline(
'panier2commande_prix',
array(
'args' => $emplette,
'data' => array(
'prix' => $prix,
'prix_ht' => $prix_ht
)
)
);
// On ne récupère que le prix_ht dans le pipeline
$prix_ht = $prix_pipeline['prix_ht'];
$prix = $prix_pipeline['prix'];
if ($prix_ht > 0)
$taxe = round(($prix - $prix_ht) / $prix_ht, 6);
else
$taxe = 0;
$libelle_option = '';
if ($emplette['options']) {
$options = explode('|', trim($emplette['options'],'|'));
foreach ($options as $option) {
$titre_option = sql_fetsel(
'titre, titre_groupe',
'spip_options left join spip_optionsgroupes using(id_optionsgroupe)',
'id_option = ' . intval($option)
);
if ($titre_option) {
$libelle_option .= "\n\r".'<br><small>'.supprimer_numero($titre_option['titre_groupe']).' : '.$titre_option['titre'].'</small>';
}
}
}
$set = array(
'id_commande' => $id_commande,
'objet' => $emplette['objet'],
'id_objet' => $emplette['id_objet'],
'options' => $emplette['options'],
'descriptif' => generer_info_entite($emplette['id_objet'], $emplette['objet'], 'titre', '*') . $libelle_option,
'quantite' => $emplette['quantite'],
'reduction' => $emplette['reduction'],
'prix_unitaire_ht' => $prix_ht,
'taxe' => $taxe,
'statut' => 'attente',
);
$where = array();
foreach ($set as $k => $w) {
if (in_array($k, array('id_commande', 'objet', 'id_objet', 'options'))) {
$where[] = "$k=" . sql_quote($w);
}
}
// est-ce que cette ligne est deja la ?
if ($append OR ! $id_commandes_detail = sql_getfetsel("id_commandes_detail", "spip_commandes_details", $where)) {
// sinon création et renseignement du détail de la commande
$id_commandes_detail = objet_inserer('commandes_detail');
}
if ($id_commandes_detail) {
objet_modifier('commandes_detail', $id_commandes_detail, $set);
$details[] = $id_commandes_detail;
}
}
if (!$append) {
// supprimer les details qui n'ont rien a voir avec ce panier
sql_delete("spip_commandes_details", "id_commande=" . intval($id_commande) . " AND " . sql_in('id_commandes_detail', $details, "NOT"));
}
// Envoyer aux plugins après édition pour verification eventuelle du contenu de la commande
pipeline(
'post_edition',
array(
'args' => array(
'table' => 'spip_commandes',
'id_objet' => $id_commande,
'action' => 'remplir_commande',
),
'data' => array()
)
);
}
}

41
action/produit_panier.php

@ -0,0 +1,41 @@
<?php
// Sécurité
if (!defined('_ECRIRE_INC_VERSION')) return;
include_spip('xavier_fonctions');
/**
* Remplir un panier avec un objet quelconque
*/
function action_produit_panier_dist() {
// On récupère les infos
$quantite= intval(_request('quantite'));
$negatif= intval(_request('negatif'));
// On reçoit des options en POST sous la forme id_option
// ou id_optionX où X est l'id du groupe d'options.
$options = array(_request('id_option'));
$groupes = sql_allfetsel('id_optionsgroupe', 'spip_optionsgroupes');
foreach ($groupes as $groupe) {
if ($id_option = _request('id_option' . $groupe['id_optionsgroupe'])) {
$options[] = $id_option;
}
}
// On concatène pour passer les options à l'action remplir_panier.
$options = join('|',$options);
if($id_objet = _request('id_produit')) {
$id_objet= intval(_request('id_produit'));
$objet = 'produit';
} else {
$objet = _request('objet');
$id_objet= intval(_request('id_objet'));
}
d($objet.'-'.$id_objet.'-'.$quantite.'-'.$negatif.'-'.$options);
// On appelle l'action remplir_panier
$remplir_panier=charger_fonction('remplir_panier','action');
return $remplir_panier($objet.'-'.$id_objet.'-'.$quantite.'-'.$negatif.'-'.$options);
}

133
action/remplir_panier.php

@ -0,0 +1,133 @@
<?php
// Sécurité
if (!defined('_ECRIRE_INC_VERSION')) return;
/**
* Remplir un panier avec un objet quelconque
* @param string $arg
*/
function action_remplir_panier_dist($arg=null) {
if (is_null($arg)){
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
}
// On récupère les infos de l'argument
@list($objet, $id_objet, $quantite, $negatif, $options) = explode('-', $arg);
$paniers_arrondir_quantite = charger_fonction('paniers_arrondir_quantite', 'inc');
if (!isset($quantite) or is_null($quantite) or !strlen($quantite)) {
$quantite = 1;
}
$quantite = $paniers_arrondir_quantite($quantite, $objet, $id_objet);
// si la quantite est nulle, on ne fait rien
if ($quantite<=0) {
return;
}
// retirer un objet du panier
if(isset($negatif) && $negatif) {
$quantite = $paniers_arrondir_quantite(-1 * $quantite, $objet, $id_objet);
}
// Il faut cherche le panier du visiteur en cours
include_spip('inc/paniers');
$id_panier_base = 0;
if ($id_panier = paniers_id_panier_encours()){
//est-ce que le panier est bien en base
$id_panier_base = intval(sql_getfetsel(
'id_panier',
'spip_paniers',
array(
'id_panier = '.intval($id_panier),
'statut = '.sql_quote('encours')
)
));
}
// S'il n'y a pas de panier, on le crée
if (!$id_panier OR !$id_panier_base){
$id_panier = paniers_creer_panier();
}
// On ne fait que s'il y a bien un panier existant et un objet valable
if ($id_panier > 0 and $objet and $id_objet) {
// Il faut maintenant chercher si cet objet précis est *déjà* dans le panier
$quantite_deja = sql_getfetsel(
'quantite',
'spip_paniers_liens',
array(
'id_panier = ' . intval($id_panier),
'objet = ' . sql_quote($objet),
'id_objet = ' . intval($id_objet),
'options = ' . sql_quote($options),
)
);
$quantite_deja = $paniers_arrondir_quantite($quantite_deja, $objet, $id_objet);
// Si on a déjà une quantité, on fait une mise à jour
if ($quantite_deja > 0){
$cumul_quantite = $paniers_arrondir_quantite($quantite_deja + $quantite, $objet, $id_objet);
//Si le cumul_quantite est 0, on efface
if ($cumul_quantite <= 0) {
sql_delete(
'spip_paniers_liens',
'id_panier = ' . intval($id_panier) . ' and objet = ' . sql_quote($objet) . ' and id_objet = ' . intval($id_objet) . ' and options = ' . sql_quote($options)
);
} //Sinon on met à jour
else {
sql_updateq(
'spip_paniers_liens',
array('quantite' => $cumul_quantite),
'id_panier = ' . intval($id_panier) . ' and objet = ' . sql_quote($objet) . ' and id_objet = ' . intval($id_objet) . ' and options = ' . sql_quote($options)
);
}
} // Sinon on crée le lien
else {
$id_panier_lien = sql_insertq(
'spip_paniers_liens',
array(
'id_panier' => $id_panier,
'objet' => $objet,
'id_objet' => $id_objet,
'quantite' => $quantite,
'options' => $options,
)
);
}
// Mais dans tous les cas on met la date du panier à jour
sql_updateq(
'spip_paniers',
array('date'=>date('Y-m-d H:i:s')),
'id_panier = '.intval($id_panier)
);
}
// appel du pipeline remplir_panier pour ajouter des traitements, vérifications
$args_pipeline = array(
'id_panier' => $id_panier,
'objet' => $objet,
'id_objet' => $id_objet,
'quantite' => $quantite,
'negatif' => $negatif,
'options' => $options,
);
if(isset($id_panier_lien)){
$args_pipeline['id_panier_lien'] = $id_panier_lien;
}
pipeline(
'remplir_panier',
array(
'args' => $args_pipeline
)
);
// On vide le cache de l'objet sur lequel on vient de travailler.
include_spip('inc/invalideur');
suivre_invalideur("id='$objet/$id_objet'");
}

38
action/supprimer_option.php

@ -0,0 +1,38 @@
<?php
/**
* Utilisation de l'action supprimer pour l'objet option
*
* @plugin Optionsproduits
* @copyright 2017
* @author nicod_
* @licence GNU/GPL
* @package SPIP\Optionsproduits\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Action pour supprimer un·e option
*
* Vérifier l'autorisation avant d'appeler l'action.
*
* @param null|int $arg
* Identifiant à supprimer.
* En absence de id utilise l'argument de l'action sécurisée.
**/
function action_supprimer_option_dist($arg = null) {
if (is_null($arg)) {
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
}
$arg = intval($arg);
// cas suppression
if ($arg) {
sql_delete('spip_options', 'id_option=' . sql_quote($arg));
} else {
spip_log("action_supprimer_option_dist $arg pas compris");
}
}

38
action/supprimer_option_objet.php

@ -0,0 +1,38 @@
<?php
/**
* Utilisation de l'action supprimer pour l'objet option
*
* @plugin Optionsproduits
* @copyright 2017
* @author nicod_
* @licence GNU/GPL
* @package SPIP\Optionsproduits\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Action pour supprimer un·e option
*
* Vérifier l'autorisation avant d'appeler l'action.
*
* @param null|int $arg
* Identifiant à supprimer.
* En absence de id utilise l'argument de l'action sécurisée.
**/
function action_supprimer_option_objet_dist($arg = null) {
if (is_null($arg)) {
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
}
// On récupère les infos de l'argument
@list($objet, $id_objet, $id_option) = explode('-', $arg);
include_spip('action/editer_liens');
objet_dissocier(
array('option' => $id_option),
array($objet => $id_objet)
);
}

140
base/optionsproduits.php

@ -0,0 +1,140 @@
<?php
/**
* Déclarations relatives à la base de données
*
* @plugin Optionsproduits produits
* @copyright 2018
* @author nicod_
* @licence GNU/GPL
* @package SPIP\Optionsproduits\Pipelines
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Déclaration des alias de tables et filtres automatiques de champs
*
* @pipeline declarer_tables_interfaces
*
* @param array $interfaces
* Déclarations d'interface pour le compilateur
*
* @return array
* Déclarations d'interface pour le compilateur
*/
function optionsproduits_declarer_tables_interfaces($interfaces) {
$interfaces['table_des_tables']['options'] = 'options';
$interfaces['table_des_tables']['optionsgroupes'] = 'optionsgroupes';
$interfaces['table_des_traitements']['PRIX_OPTION'][] = 'prix_formater(%s)';
$interfaces['table_des_traitements']['PRIX_OPTION_HT'][] = 'prix_formater(%s)';
$interfaces['table_des_traitements']['PRIX_DEFAUT']['spip_options'] = 'prix_formater(%s)';
$interfaces['table_des_traitements']['TITRE_GROUPE']['spip_optionsgroupes'] = 'supprimer_numero(%s)';
$interfaces['table_des_traitements']['DESCRIPTIF']['spip_commandes_details'] = _TRAITEMENT_RACCOURCIS;
// $interfaces['tables_jointures']['spip_optionsgroupes'][] = 'options';
// $interfaces['tables_jointures']['spip_options'][] = 'optionsgroupes';
return $interfaces;
}
/**
* Déclaration des objets éditoriaux
*
* @pipeline declarer_tables_objets_sql
*
* @param array $tables
* Description des tables
*
* @return array
* Description complétée des tables
*/
function optionsproduits_declarer_tables_objets_sql($tables) {
$tables['spip_options'] = array(
'type' => 'option',
'principale' => 'oui',
'field' => array(
'id_option' => 'bigint(21) NOT NULL',
'id_optionsgroupe' => 'bigint(21) NOT NULL DEFAULT 0',
'titre' => 'text',
'description' => 'text',
'prix_defaut' => 'decimal(20,6)',
'date' => 'datetime NOT NULL DEFAULT "0000-00-00 00:00:00"',
'maj' => 'TIMESTAMP',
),
'key' => array(
'PRIMARY KEY' => 'id_option',
'KEY id_optionsgroupe' => 'id_optionsgroupe',
),
'titre' => 'titre AS titre, "" AS lang',
'date' => 'date',
'champs_editables' => array('titre', 'description', 'prix_defaut', 'id_optionsgroupe'),
'champs_versionnes' => array('titre', 'description', 'prix_defaut', 'id_optionsgroupe'),
'rechercher_champs' => array("titre" => 10, 'description' => 5),
'tables_jointures' => array('spip_options_liens'),
'join' => array(
'id_option' => 'id_option',
'id_optionsgroupe' => 'id_optionsgroupe',
),
);
$tables['spip_optionsgroupes'] = array(
'type' => 'optionsgroupe',
'principale' => 'oui',
'field' => array(
'id_optionsgroupe' => 'bigint(21) NOT NULL',
'titre_groupe' => 'text',
'date' => 'datetime NOT NULL DEFAULT "0000-00-00 00:00:00"',
'maj' => 'TIMESTAMP',
),
'key' => array(
'PRIMARY KEY' => 'id_optionsgroupe',
),
'titre' => 'titre_groupe AS titre, "" AS lang',
'date' => 'date',
'champs_editables' => array('titre_groupe'),
'champs_versionnes' => array('titre_groupe'),
'rechercher_champs' => array("titre_groupe" => 10),
'tables_jointures' => array('spip_options'),
'join' => array(
'id_optionsgroupe' => 'id_optionsgroupe',
),
);
return $tables;
}
/**
* Déclaration des tables secondaires (liaisons)
*
* @pipeline declarer_tables_auxiliaires
*
* @param array $tables
* Description des tables
*
* @return array
* Description complétée des tables
*/
function optionsproduits_declarer_tables_auxiliaires($tables) {
$tables['spip_options_liens'] = array(
'field' => array(
'id_option' => 'bigint(21) DEFAULT "0" NOT NULL',
'id_objet' => 'bigint(21) DEFAULT "0" NOT NULL',
'objet' => 'varchar(25) DEFAULT "" NOT NULL',
'prix_option_objet' => 'decimal(20,6)',
),
'key' => array(
'PRIMARY KEY' => 'id_option,id_objet,objet',
'KEY id_option' => 'id_option',
),
);
return $tables;
}

16
formulaires/configurer_options.html

@ -0,0 +1,16 @@
<div class="formulaire_spip formulaire_configurer formulaire_#FORM">
<h3 class="titrem"><:options:cfg_titre_parametrages:></h3>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
<form method="post" action="#ENV{action}">
<div>
#ACTION_FORMULAIRE{#ENV{action}}
<input type="hidden" name="_meta_casier" value="options" />
<p class="boutons"><span class="image_loading">&nbsp;</span><input type="submit" class="submit" value="<:bouton_enregistrer:>" /></p>
</div>
</form>
</div>

30
formulaires/editer_option.html

@ -0,0 +1,30 @@
<div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_option,nouveau}'>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#ENV{editable})
<form method="post" action="#ENV{action}"><div>
#ACTION_FORMULAIRE{#ENV{action}}
<input type="hidden" name="id_option" value="#ENV{id_option}" />
<div class="editer-groupe">
[(#SAISIE{input, titre, obligatoire=oui,
label=<:option:champ_titre_label:>})]
[(#SAISIE{optionsgroupes, id_optionsgroupe, obligatoire=oui,
label=<:option:champ_id_optionsgroupe_label:>})]
[(#SAISIE{textarea, description,
label=<:option:champ_description_label:>, rows=2})]
[(#SAISIE{input, prix_defaut,
label=<:option:champ_prix_defaut_label:>,
explication=<:option:champ_prix_defaut_explication:> })]
</div>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer:>" /></p>
</div></form>
]
</div>

207
formulaires/editer_option.php

@ -0,0 +1,207 @@
<?php
/**
* Gestion du formulaire de d'édition de option
*
* @plugin Optionsproduits
* @copyright 2018
* @author nicod_
* @licence GNU/GPL
* @package SPIP\Optionsproduits\Formulaires
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/actions');
include_spip('inc/editer');
/**
* Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
*
* @param int|string $id_option
* Identifiant du option. 'new' pour un nouveau option.
* @param int $id_optionsgroupe
* Identifiant de l'objet parent (si connu)
* @param string $retour
* URL de redirection après le traitement
* @param string $associer_objet
* Éventuel `objet|x` indiquant de lier le option créé à cet objet,
* tel que `article|3`
* @param int $lier_trad
* Identifiant éventuel d'un option source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du option, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return string
* Hash du formulaire
*/
function formulaires_editer_option_identifier_dist(
$id_option = 'new',
$id_optionsgroupe = 0,
$retour = '',
$associer_objet = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
return serialize(array(intval($id_option), $associer_objet));
}
/**
* Chargement du formulaire d'édition de option
*
* Déclarer les champs postés et y intégrer les valeurs par défaut
*
* @uses formulaires_editer_objet_charger()
*
* @param int|string $id_option
* Identifiant du option. 'new' pour un nouveau option.
* @param int $id_optionsgroupe
* Identifiant de l'objet parent (si connu)
* @param string $retour
* URL de redirection après le traitement
* @param string $associer_objet
* Éventuel `objet|x` indiquant de lier le option créé à cet objet,
* tel que `article|3`
* @param int $lier_trad
* Identifiant éventuel d'un option source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du option, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return array
* Environnement du formulaire
*/
function formulaires_editer_option_charger_dist(
$id_option = 'new',
$id_optionsgroupe = 0,
$retour = '',
$associer_objet = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
$valeurs = formulaires_editer_objet_charger('option', $id_option, $id_optionsgroupe, $lier_trad, $retour, $config_fonc, $row, $hidden);
if (!$valeurs['id_optionsgroupe']) {
$valeurs['id_optionsgroupe'] = $id_optionsgroupe;
}
return $valeurs;
}
/**
* Vérifications du formulaire d'édition de option
*
* Vérifier les champs postés et signaler d'éventuelles erreurs
*
* @uses formulaires_editer_objet_verifier()
*
* @param int|string $id_option
* Identifiant du option. 'new' pour un nouveau option.
* @param int $id_optionsgroupe
* Identifiant de l'objet parent (si connu)
* @param string $retour
* URL de redirection après le traitement
* @param string $associer_objet
* Éventuel `objet|x` indiquant de lier le option créé à cet objet,
* tel que `article|3`
* @param int $lier_trad
* Identifiant éventuel d'un option source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du option, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return array
* Tableau des erreurs
*/
function formulaires_editer_option_verifier_dist(
$id_option = 'new',
$id_optionsgroupe = 0,
$retour = '',
$associer_objet = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
$erreurs = array();
$erreurs = formulaires_editer_objet_verifier('option', $id_option, array('id_optionsgroupe', 'titre', 'id_optionsgroupe'));
if(_request('prix_defaut') && !is_numeric(_request('prix_defaut'))){
$erreurs['prix_defaut'] = 'Saisissez un nombre décimal avec un point';
}
return $erreurs;
}
/**
* Traitement du formulaire d'édition de option
*
* Traiter les champs postés
*
* @uses formulaires_editer_objet_traiter()
*
* @param int|string $id_option
* Identifiant du option. 'new' pour un nouveau option.
* @param int $id_optionsgroupe
* Identifiant de l'objet parent (si connu)
* @param string $retour
* URL de redirection après le traitement
* @param string $associer_objet
* Éventuel `objet|x` indiquant de lier le option créé à cet objet,
* tel que `article|3`
* @param int $lier_trad
* Identifiant éventuel d'un option source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du option, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return array
* Retours des traitements
*/
function formulaires_editer_option_traiter_dist(
$id_option = 'new',
$id_optionsgroupe = 0,
$retour = '',
$associer_objet = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
$retours = formulaires_editer_objet_traiter('option', $id_option, $id_optionsgroupe, $lier_trad, $retour, $config_fonc, $row, $hidden);
// Un lien a prendre en compte ?
if ($associer_objet and $id_option = $retours['id_option']) {
list($objet, $id_objet) = explode('|', $associer_objet);
if ($objet and $id_objet and autoriser('modifier', $objet, $id_objet)) {
include_spip('action/editer_liens');
objet_associer(array('option' => $id_option), array($objet => $id_objet));
if (isset($retours['redirect'])) {
$retours['redirect'] = parametre_url($retours['redirect'], 'id_lien_ajoute', $id_option, '&');
}
}
}
return $retours;
}

20
formulaires/editer_optionsgroupe.html

@ -0,0 +1,20 @@
<div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_optionsgroupe,nouveau}'>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#ENV{editable})
<form method="post" action="#ENV{action}"><div>
#ACTION_FORMULAIRE{#ENV{action}}
<input type="hidden" name="id_optionsgroupe" value="#ENV{id_optionsgroupe}" />
<div class="editer-groupe">
[(#SAISIE{input, titre_groupe, obligatoire=oui,
label=<:optionsgroupe:champ_titre_label:>})]
</div>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer:>" /></p>
</div></form>
]
</div>

157
formulaires/editer_optionsgroupe.php

@ -0,0 +1,157 @@
<?php
/**
* Gestion du formulaire de d'édition de optionsgroupe
*
* @plugin Optionsproduits
* @copyright 2018
* @author nicod_
* @licence GNU/GPL
* @package SPIP\Optionsproduits\Formulaires
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/actions');
include_spip('inc/editer');
/**
* Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
*
* @param int|string $id_optionsgroupe
* Identifiant du optionsgroupe. 'new' pour un nouveau optionsgroupe.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un optionsgroupe source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du optionsgroupe, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return string
* Hash du formulaire
*/
function formulaires_editer_optionsgroupe_identifier_dist(
$id_optionsgroupe = 'new',
$retour = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
return serialize(array(intval($id_optionsgroupe)));
}
/**
* Chargement du formulaire d'édition de optionsgroupe
*
* Déclarer les champs postés et y intégrer les valeurs par défaut
*
* @uses formulaires_editer_objet_charger()
*
* @param int|string $id_optionsgroupe
* Identifiant du optionsgroupe. 'new' pour un nouveau optionsgroupe.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un optionsgroupe source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du optionsgroupe, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return array
* Environnement du formulaire
*/
function formulaires_editer_optionsgroupe_charger_dist(
$id_optionsgroupe = 'new',
$retour = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
$valeurs = formulaires_editer_objet_charger('optionsgroupe', $id_optionsgroupe, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $valeurs;
}
/**
* Vérifications du formulaire d'édition de optionsgroupe
*
* Vérifier les champs postés et signaler d'éventuelles erreurs
*
* @uses formulaires_editer_objet_verifier()
*
* @param int|string $id_optionsgroupe
* Identifiant du optionsgroupe. 'new' pour un nouveau optionsgroupe.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un optionsgroupe source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du optionsgroupe, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return array
* Tableau des erreurs
*/
function formulaires_editer_optionsgroupe_verifier_dist(
$id_optionsgroupe = 'new',
$retour = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
$erreurs = array();
$erreurs = formulaires_editer_objet_verifier('optionsgroupe', $id_optionsgroupe, array('titre_groupe'));
return $erreurs;
}
/**
* Traitement du formulaire d'édition de optionsgroupe
*
* Traiter les champs postés
*
* @uses formulaires_editer_objet_traiter()
*
* @param int|string $id_optionsgroupe
* Identifiant du optionsgroupe. 'new' pour un nouveau optionsgroupe.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un optionsgroupe source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du optionsgroupe, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
*
* @return array
* Retours des traitements
*/
function formulaires_editer_optionsgroupe_traiter_dist(
$id_optionsgroupe = 'new',
$retour = '',
$lier_trad = 0,
$config_fonc = '',
$row = array(),
$hidden = ''
) {
$retours = formulaires_editer_objet_traiter('optionsgroupe', $id_optionsgroupe, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $retours;
}

100
formulaires/options_liees_objet.html

@ -0,0 +1,100 @@
#SET{prix_objet, #PRIX*{#ENV{objet},#ENV{id_objet}}}
#SET{options_liees, #ARRAY}
<div class="formulaire_spip formulaire_configurer formulaire_#FORM">
<B_options_liees>
<h3 class="titrem">Options liées</h3>
<div class="liste-objets [(#VAL{option}|objet_info{table_objet})]">
<table class='spip liste'>
[<caption><strong class="caption"><a href="[(#ID_OPTIONSGROUPE|generer_url_entite{optionsgroupe})]">(#TITRE_GROUPE)</a></strong></caption>]
<thead>
<tr class='first_row'>
<th class='titre principale' scope='col'><:option:champ_titre_label:></th>
<th class='principale' scope='col'>Prix option HT</th>
<th class='principale' scope='col'>Prix option TTC</th>
<th class='principale' scope='col'>Prix final TTC</th>
<th class='id' scope='col'></th>
<th class='id' scope='col'></th>
</tr>
</thead>
<tbody>
<BOUCLE_options_liees(OPTIONS spip_options_liens spip_optionsgroupes)
{par num titre_groupe, options_liens.prix_option_objet, num titre}
{options_liens.objet=#ENV{objet}}{options_liens.id_objet=#ENV{id_objet}}{si #ENV{modifier_option}|non}>
[(#REM) |unique sur l'id, pas sur le titre, au cas où deux groupes aient le même nom ]
[<tr class="row-inverse (#ID_OPTIONSGROUPE|unique)"><td colspan="6"><strong>[(#TITRE_GROUPE|supprimer_numero)]</strong></td></tr>]
#SET{prix_final, #PRIX_OPTION*{#ENV{objet},#ENV{id_objet},#ID_OPTION}}
#SET{prix_option, #GET{prix_final}|moins{#GET{prix_objet}}}
#SET{options_liees, #GET{options_liees}|push{#ID_OPTION} }
<tr class="row_even">
<td class='titre principale'>#TITRE</td>
<td>[(#PRIX_OPTION_OBJET|prix_formater)]</td>
<td>[(#GET{prix_option}|prix_formater)]</td>
<td>[(#GET{prix_final}|prix_formater)]</td>
<td>[(#BOUTON_ACTION{<:option:modifier:>,#SELF|parametre_url{id_option,#ID_OPTION}|parametre_url{modifier_option,1},ajax})]</td>
<td>[(#BOUTON_ACTION{<:option:retirer:>,#URL_ACTION_AUTEUR{supprimer_option_objet,#ENV{objet}-#ENV{id_objet}-#ID_OPTION,#SELF},ajax,<:option:retirer_lien_option:> ?})]</td>
</tr>
</BOUCLE_options_liees>
</tbody>
</table>
</div>
</B_options_liees>
</div>
<div class="formulaire_spip formulaire_configurer formulaire_#FORM">
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#REM) mode édition du prix d'une option ]
<BOUCLE_modifier_option(CONDITION){si #ENV{modifier_option}}>
<h3 class="titrem">Modifier le prix d'une option</h3>
<form method="post" action="#ENV{action}">
#ACTION_FORMULAIRE{#ENV{action}}
<div class="editer-groupe">
<BOUCLE_modifoption(OPTIONS){par num titre}{id_option}{options_liens.objet}{options_liens.id_objet}>
<div class="editer">
<h3>[(#TITRE)]</h3>
</div>
<input type="hidden" name="id_option" value="#ENV{id_option}" />
<input type="hidden" name="modifier_option" value="1" />
[(#SAISIE{input, prix, label=<:option:champ_prix_option_label:>, explication=Laisser vide pour utiliser le prix par défaut,valeur=#ENV{prix,#PRIX_OPTION_OBJET}})]
</BOUCLE_modifoption>
</div>
<p class="boutons">
<a href="[(#SELF|parametre_url{modifier_option,''})]" class="ajax bouton">Annuler</a>
<input type="submit" class="submit" value="<:bouton_enregistrer:>" />
</p>
</form>
</BOUCLE_modifier_option>
[(#REM) mode ajout d'options ]
<form method="post" action="#ENV{action}">
<h3 class="titrem">Ajouter une option</h3>
#ACTION_FORMULAIRE{#ENV{action}}
<div class="editer-groupe">
<BOUCLE_groupes(OPTIONSGROUPES){par num titre_groupe}>
<B_options>
<div class="editer">
<label for="ajout_option_groupe_#ID_OPTIONSGROUPE">#TITRE_GROUPE</label>
<select id="ajout_option_groupe_#ID_OPTIONSGROUPE" name="id_option_groupe_#ID_OPTIONSGROUPE">
<option value=""></option>
<BOUCLE_options(OPTIONS){par prix_defaut, num titre}{id_optionsgroupe}{id_option !IN #GET{options_liees}}>
<option value="#ID_OPTION">#TITRE : [(#PRIX_DEFAUT|prix_formater)]</option>
</BOUCLE_options>
</select>
</div>
</B_options>
</BOUCLE_groupes>
</div>
<p class="boutons"><span class="image_loading">&nbsp;</span><input type="submit" class="submit" value="Ajouter" /></p>
</form>
<//B_modifier_option>
</form>
</div>

71
formulaires/options_liees_objet.php

@ -0,0 +1,71 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('action/editer_liens');
function formulaires_options_liees_objet_charger_dist($objet, $id_objet) {
$valeurs = array(
'objet' => $objet,
'id_objet' => $id_objet,
'id_option' => _request('id_option'),
'modifier_option' => _request('modifier_option'),
'prix' => _request('prix'),
);
return $valeurs;
}
function formulaires_options_liees_objet_verifier_dist($objet, $id_objet) {
$erreurs = array();
if (_request('prix') && !is_numeric(_request('prix'))) {
$erreurs['prix'] = 'Saisissez un nombre décimal avec un point';
}
return $erreurs;
}
function formulaires_options_liees_objet_traiter_dist($objet, $id_objet) {
$retours = array();
// modification du prix
if(_request('modifier_option')) {
if ($id_option = _request('id_option')) {
$prix = _request('prix');
if ($prix == '') {
$prix = sql_getfetsel('prix_defaut', 'spip_options', 'id_option = ' . $id_option);
}
if (objet_associer(
array('option' => $id_option),
array($objet => $id_objet),
array('prix_option_objet' => $prix)
)) {
$retours['message_ok'] = _T('option:option_ajoutee');
}
}
set_request('modifier_option', '');
} else {
// association d'options
$groupes = sql_allfetsel('id_optionsgroupe', 'spip_optionsgroupes');
foreach ($groupes as $groupe) {
if ($id_option = _request('id_option_groupe_' . $groupe['id_optionsgroupe'])) {
$prix = sql_getfetsel('prix_defaut', 'spip_options', 'id_option = ' . $id_option);
if (objet_associer(
array('option' => $id_option),
array($objet => $id_objet),
array('prix_option_objet' => $prix)
)) {
$retours['message_ok'] = _T('option:option_ajoutee');
}
}
}
}
return $retours;
}

76
formulaires/panier.html

@ -0,0 +1,76 @@
#CACHE{0}
<div class="formulaire_spip formulaire_#ENV{form}[ formulaire_#ENV{form}-(#ENV{id,nouveau})]">
<B_contenu_panier>
<form method="post" action="#ENV{action}" enctype="multipart/form-data">
<div>
[(#REM) declarer les hidden qui declencheront le service du formulaire
parametre : url d'action ]
#ACTION_FORMULAIRE{#ENV{action}}
<table cellspacing="0">
<thead>
<tr>
<th class="description"><:paniers:panier_description:></th>
<th class="prix_unitaire"><:paniers:panier_prix_unitaire:></th>
<th class="quantite"><:paniers:panier_quantite:></th>
<th class="montant"><:paniers:panier_montant:></th>
</tr>
</thead>
<tbody>
<BOUCLE_contenu_panier(PANIERS_LIENS){id_panier=#ENV{_id_panier}}>
#SET{prix_unitaire, #PRIX_OPTION*{#OBJET,#ID_OBJET,#OPTIONS}
[(#SET{taxe_objet,[(#GET{prix_unitaire}|moins{#PRIX_HT*{#OBJET,#ID_OBJET}}|mult{#QUANTITE})]})]
[(#SET{cumul_taxes,[(#GET{cumul_taxes}|plus{[(#GET{taxe_objet})]})]})]
<tr class="emplette[ (#ENV{erreurs}|table_valeur{quantites}|table_valeur{#OBJET}|table_valeur{#ID_OBJET}|?{erreur})]">
<td class="description">
[(#INFO_TITRE{#OBJET,#ID_OBJET})]
<BOUCLE_options(DATA){source tableau, #OPTIONS|explode{|}}>
<BOUCLE_option(OPTIONS){id_option=#VALEUR}>
<br><small>[(#INFO_TITRE_GROUPE{optionsgroupe,#ID_OPTIONSGROUPE}|supprimer_numero) : ]#TITRE</small>
</BOUCLE_option>
</BOUCLE_options>
</td>
<td class="prix_unitaire">[(#GET{prix_unitaire}|prix_formater)]</td>
<td class="quantite">
<input type="text" class="text quantite" size="3" name="quantites[#OBJET][#ID_OBJET]" value="[(#ENV{quantites}|table_valeur{#OBJET}|table_valeur{#ID_OBJET}|sinon{#QUANTITE})]" />
</td>
<td class="montant">[(#GET{prix_unitaire}|mult{#QUANTITE}|prix_formater)]</td>
</tr>
</BOUCLE_contenu_panier>
<tr class="total_ttc[(#ENV*{message_ok}|oui)reponse_formulaire reponse_formulaire_ok]">
<td class="description">[(#ENV*{message_ok})]</td>
<td class="total"><:paniers:panier_total_ttc:></td>
<td class="quantite"></td>
<td class="montant">#PRIX{panier,#ENV{_id_panier}}</td>
</tr>
[(#GET{cumul_taxes}|>{0}|oui)
<tr class="taxes">
<td class="total" colspan="2"><:paniers:dont_total_taxe:></td>
<td class="quantite"></td>
<td class="montant">[(#GET{cumul_taxes}|prix_formater)]</td>
</tr>]
</tbody>
</table>
[<p class="reponse_formulaire reponse_formulaire_erreur">
(#ENV*{message_erreur})
</p>]
<p class="boutons">
<span class="image_loading">&nbsp;</span>
<button class="submit over offscreen" type="submit" name="recalcul" value="1"><:paniers:panier_recalculer:></button>
<button class="submit vider btn-link left" type="submit" name="vider" value="1"><:paniers:vider_le_panier:></button>
<button class="submit recalcul" type="submit" name="recalcul" value="1"><:paniers:panier_recalculer:></button>
</p>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
</div>
</form>
</B_contenu_panier>
<:paniers:panier_vide:>
<//B_contenu_panier>
</div>
<script type="application/javascript">
jQuery(function(){
jQuery('.formulaire_panier .submit.recalcul').css('visibility','hidden');
jQuery('.formulaire_panier').on('keypress change focus','input.quantite',function(){jQuery(this).closest('.formulaire_panier').find('.submit.recalcul').css('visibility','visible')});
});
</script>

99
formulaires/panier.php

@ -0,0 +1,99 @@
<?php
// Sécurité
if (!defined('_ECRIRE_INC_VERSION')) return;
function formulaires_panier_charger($id_panier=0){
// On commence par chercher le panier du visiteur actuel s'il n'est pas fourni a l'appel du formulaire
include_spip('inc/paniers');
if (!$id_panier) $id_panier = paniers_id_panier_encours();
$contexte = array(
'_id_panier' => $id_panier,
'quantites' => array()
);
return $contexte;
}
function formulaires_panier_verifier($id_panier=0){
$erreurs = array();
if (!_request('vider')){
$quantites = _request('quantites');
$paniers_arrondir_quantite = charger_fonction('paniers_arrondir_quantite', 'inc');
if (is_array($quantites)){
foreach ($quantites as $objet => $objets_de_ce_type){
foreach ($objets_de_ce_type as $id_objet => $quantite){
if (!is_numeric($quantite) or
$quantite!=$paniers_arrondir_quantite($quantite, $objet, $id_objet)
or (is_numeric($quantite) and $quantite<0)){
$erreurs['message_erreur'] = _T('paniers:panier_erreur_quantites');
$erreurs['quantites'][$objet][$id_objet] = 'erreur';
}
}
}
}
}
return $erreurs;
}
function formulaires_panier_traiter($id_panier=0){
$retours = array();
// On commence par chercher le panier du visiteur actuel s'il n'est pas fourni a l'appel du formulaire
include_spip('inc/paniers');
if (!$id_panier) $id_panier = paniers_id_panier_encours();
if (_request('vider')){
$supprimer_panier = charger_fonction("supprimer_panier","action");
$supprimer_panier($id_panier);
}
else {
$quantites = _request('quantites');
$ok = 0;
if (is_array($quantites))
$paniers_arrondir_quantite = charger_fonction('paniers_arrondir_quantite', 'inc');
foreach($quantites as $objet => $objets_de_ce_type)
foreach($objets_de_ce_type as $id_objet => $quantite){
$quantite = $paniers_arrondir_quantite($quantite, $objet, $id_objet);
// Si la quantite est 0, on supprime du panier
if ($quantite<=0)
$ok += sql_delete(
'spip_paniers_liens',
'id_panier = '.intval($id_panier).' and objet = '.sql_quote($objet).' and id_objet = '.intval($id_objet)
);
// Sinon on met à jour
else{
if ($quantite!=sql_getfetsel("quantite","spip_paniers_liens",'id_panier = '.intval($id_panier).' and objet = '.sql_quote($objet).' and id_objet = '.intval($id_objet))){
$ok += sql_updateq(
'spip_paniers_liens',
array('quantite' => $quantite),
'id_panier = '.intval($id_panier).' and objet = '.sql_quote($objet).' and id_objet = '.intval($id_objet)
);
}
}
}
// Mais dans tous les cas on met la date du panier à jour
sql_updateq(
'spip_paniers',
array('date'=>date('Y-m-d H:i:s')),
'id_panier = '.intval($id_panier)
);
if ($ok){
$retours['message_ok'] = _T('paniers:panier_quantite_ok');
}
}
return $retours;
}
?>

45
formulaires/panier_produit_options.html

@ -0,0 +1,45 @@
<BOUCLE_produit(spip_produits){id_produit}>
#SET{prix,#PRIX*}
<div class="formulaire_spip overflow-visible">
<form action="#ENV{action}" method="post" class="js-achat-form achat">
#ACTION_FORMULAIRE{#ENV{action}}
<input type="hidden" name="prix_produit" value="#GET{prix}">
[(#REM) les options listées par groupe ]
#SET{options, #ENV{options}|explode{|}}
<BOUCLE_optionsgroupes(OPTIONSGROUPES){par titre_groupe}>
<B_radio>
<div class="editer editer_radio editer_options_produit">
<label>#TITRE_GROUPE</label>
<BOUCLE_radio(OPTIONS){id_optionsgroupe}{options_liens.objet=produit}{options_liens.id_objet=#ID_PRODUIT}{par prix_option_objet}{doublons}>
[(#SET{prix_option, #PRIX_OPTION*{produit,#ID_PRODUIT,#ID_OPTION}})]
[(#SET{prix_option_seule, #GET{prix_option}|moins{#GET{prix}}})]
<div class="choix">
[(#LOGO_OPTION|image_reduire{240,200})]
<input data-prixoption="#GET{prix_option_seule}" type="radio" name="id_option#ID_OPTIONSGROUPE" class="radio"
id="champ_id_option_[(#ID_OPTIONSGROUPE)]_[(#COMPTEUR_BOUCLE)]"
[(#COMPTEUR_BOUCLE|=={1}|et{#ENV{#VAL{id_option}|concat{#ID_OPTIONSGROUPE}}|non})checked="checked"]
[(#ID_OPTION|in_array{#GET{options}}|oui)checked="checked"] value="#ID_OPTION" />
<label for="champ_id_option_[(#ID_OPTIONSGROUPE)]_[(#COMPTEUR_BOUCLE)]">
#TITRE [(#PRIX_OPTION_OBJET|=={0}|non) [(#GET{prix_option}|>{#GET{prix}}|oui)+][(#GET{prix_option}|<{#GET{prix}}|oui)-][(#GET{prix_option}|moins{#GET{prix}}|prix_formater)] ]
[<span class="description_option">(#DESCRIPTION|propre|PtoBR)</span>]
</label>
</div>
</BOUCLE_radio>
</div>
</B_radio>
</BOUCLE_optionsgroupes>
<