Rémi Janot
Co-fondateur & CTO chez Wheeliz
Certains sont fans de Ikea, montent le meuble et l'installent au milieu de leur salon. D'autres prennent un peu de temps pour détourner l'objet et en faire un meuble unique… ou un vélo à partir d'un tabouret.
L'idée ici est semblable.
Août 2014, je co-fonde une société, Wheeliz, tout en restant dans mon ancienne société. Je dois donc optimiser mon temps de travail. J'avais 6 mois pour créer entièrement une marketplace.
Après le succès de notre KissKissBankBank, je me retrouve avec des codes promo à générer. Je commence à lister rapidement les conditions possibles pour la validité du code promo :
Et je pense que j'en ai oublié.
Ces conditions peuvent être liées par de simples AND, ou un mix entre AND et OR.
Quand au montant:
Sachant que ce montant doit également pouvoir s'adapter. Exemple 5€ pour 1 journée, 10 € pour 2 journées, et 20€ pour 1 semaine, le tout avec le même code.
Bref, j'avais besoin d'une flexibilité extrême.
Après avoir regardé un peu Prestashop, Magento, … je me suis dit qu'il fallait que je fasse un arbre de conditions. Mais là, ça veut dire UX compliquée, flexibilité assez bonne, sans montant modulable. Allez, au bas mot 1 semaine de travail.
Toutes ces conditions peuvent très bien s'écrire en PHP.
Mais faire une release pour l'ajout d'un code promo, ce n'est clairement pas l'idéal.
Ajouter du php évalué dans ma base de données ? Euh comment dire...
Si seulement j'avais à disposition un meta-langage qui puisse être compris par les commerciaux (après une petite formation, hein) et qui serait exécutable en PHP…
Ah, ça y est, vous me voyez venir ? Oui j'ai utilisé Twig pour “coder” le code de réduction.
Je me retrouve donc avec 2 tables simples :
Après avoir repéré l'exemple de code promo qui les intéresse, les personnes en charge du marketing ou du service client ont juste à cliquer sur un petit bouton pour accéder à un formulaire. Là, ils rentrent le nom du code promo, et emballé c'est pesé. Et si besoin, ils peuvent l'adapter à la marge (date de validité, restriction sur un utilisateur, ...).
Temps de développement réel : 1 journée.
Temps de création des templates de code promo : 2h
Temps de formation : 2-3 midis
Verdict : opération très rentable pour la phase de prototype.
Aujourd'hui, Wheeliz n'est plus au stade de prototype mais ce fonctionnement est resté, et il offre une grande souplesse, surtout dans les coups de rush (le soir à 18h pour une opération qui n'a jamais été faite jusque là, et lancée le lendemain…).
Exemple avec un code promo valable 1 seule fois par personne, jusqu'à une certaine date, et uniquement sur la première location :
{% if discountAlreadyUsed(discount, loggedInUser, rental) or now>discount.usageLimitAt or ((rental.tenant.rentalsDoneCountAsTenant + rental.tenant.rentalsValidatedCountAsOwner)>=1) %}
0
{% else %}
1
{% endif %}
Et du coup, le code PHP qui analyse ça :
/**
* @param DiscountEntity $discount
* @param RentalEntity $rental
* @param array|RentalLine[] $rentalLines
*
* @return boolean
*/
public function isDiscountApplicableToRental(DiscountEntity $discount, RentalEntity $rental, array $rentalLines)
{
try {
$variables = $this->getTemplateVariables($discount, $rental, $rentalLines);
$toTest = $this->twigEnvironment->createTemplate($discount->getTestExpression())->render($variables);
$toTest = trim($toTest);
if ($toTest) {
return true;
}
return false;
} catch (\Exception $e) {
$this->logger->warn('Exception while calculating discount Code: '.$e->getMessage().$e->getTraceAsString());
return false;
}
}
Mais pour l'application des montants, ça va un chouilla plus loin, puisque je ne récupère pas juste un booléen, mais un objet json :
/**
* @param OrderLineEntity $orderLine
* @param array $variables
*
* @return bool
* @throws \Exception
* @throws \Throwable
*/
public function applyRubricOnLine(DiscountEntity $discount, array $variables)
{
$output = null;
try {
$output = $this->twigEnvironment->createTemplate($discount->getAmountsExpression())->render(array_merge($variables, array('discount' => $discount)));
$json = json_decode($output, true);
if ($json) {
if (isset($json['debug'])) {
$this->logger->info('DEBUG INFO for rubric '.$orderLine->getRubric()->getId(), $json);
unset($json['debug']);
}
return $json;
} else {
$this->logger->warn('can\'t decode json amounts for discount '.$discount->getId(), $json);
}
return false;
} catch (\Exception $e) {
$this->logger->critical('Exception while calculating discount amounts '.$discount->getId().' : '.$e->getMessage().' '.$e->getTraceAsString().' '.$output);
throw $e;
}
}
Tout d'abord, comme quoi je suis fan de ce procédé, je le réintroduis actuellement dans un système de gamification.
Mais je vois très bien ce genre d'utilisation dans des ERP de paie, ou même comptabilité en général. En fait, le principal cas d'utilisation est quand il faut que des technico-commerciaux soient autonomes sur des formules de calcul.
On pourrait même imaginer ça pour du CMS, si toutefois nous n'avions pas lu l'excellent article présentant les CMS Headless.
Mais il ne faut pas perdre de vue que les personnes qui vont utiliser ceci au quotidien doivent avoir des rudiments de programmation et être formées à twig. Ce qui n'est pas le cas de tout le monde, loin s'en faut.