From 0b1c5d0a3d40f8e3ef556124069de3072b238dd6 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 1 Jun 2024 00:17:39 +0200 Subject: [PATCH] Fix again achatVente MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - remplacement des données/JSON dans le html par des Flags sur le ChatMessage - extraction de la gestion des infos de ventes pour rassembler la génération du ChatMessage - on ne perd plus la quantité ou le vendeur - attention au mergeObject: il modifie le premier parametre, ce qui modifiait parfois l'acteur (!!!) et toujours la quantité de l'objet du vendeur lors de la création de l'objet de l'acheteur! --- changelog.md | 2 +- module/achat-vente/chat-vente.js | 70 +++++++++++++++++++ module/{ => achat-vente}/dialog-item-achat.js | 56 +++++---------- module/{ => achat-vente}/dialog-item-vente.js | 52 ++++++++------ module/actor/base-actor.js | 49 ++++++------- module/actor/commerce-sheet.js | 2 +- module/item.js | 24 ++----- module/rdd-utility.js | 2 +- templates/chat-vente-item.html | 13 ++-- templates/dialog-item-achat.html | 4 +- templates/dialog-item-vente.html | 4 +- 11 files changed, 157 insertions(+), 121 deletions(-) create mode 100644 module/achat-vente/chat-vente.js rename module/{ => achat-vente}/dialog-item-achat.js (65%) rename module/{ => achat-vente}/dialog-item-vente.js (61%) diff --git a/changelog.md b/changelog.md index d995288e..34eb5cf8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # 11.2 ## 11.2.22 - Le futur d'Akarlikarlikar - +- correction de la vente par le tchat: seul le premier acheteur pouvait acheter ### Support V12 - adaptation fenêtre de recherche diff --git a/module/achat-vente/chat-vente.js b/module/achat-vente/chat-vente.js new file mode 100644 index 00000000..76d69d9f --- /dev/null +++ b/module/achat-vente/chat-vente.js @@ -0,0 +1,70 @@ +import { SYSTEM_RDD } from "../constants.js"; +import { RdDUtility } from "../rdd-utility.js"; + +const DETAIL_VENTE = 'detailVente'; +const NB_LOTS = 'nbLotss'; + +export class ChatVente { + + static getDetailVente(chatMessageId) { + const chatMessage = game.messages.get(chatMessageId) + if (!chatMessage) { + return undefined; + } + const nbLots = chatMessage.getFlag(SYSTEM_RDD, NB_LOTS) + const detail = foundry.utils.duplicate(chatMessage.getFlag(SYSTEM_RDD, DETAIL_VENTE)) + if (!detail.item) { + ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes") + return undefined; + } + + const vendeur = detail.vendeurId ? game.actors.get(detail.vendeurId) : undefined; + return foundry.utils.mergeObject(detail, + { + alias: vendeur?.name ?? game.user.name, + vendeur, + nbLots: nbLots, + chatMessageIdVente: chatMessageId + }) + } + + static getDetailAchatVente(chatMessageId) { + const acheteur = RdDUtility.getSelectedActor() + const detail = ChatVente.getDetailVente(chatMessageId) + if (!acheteur && !detail.vendeur) { + ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement"); + return undefined; + } + return foundry.utils.mergeObject(detail, { acheteur }) + } + + + static async setDetailAchatVente(chatMessage, vente) { + await chatMessage?.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots) + await chatMessage?.setFlag(SYSTEM_RDD, DETAIL_VENTE, { + item: vente.item, + properties: vente.item.getProprietes(), + vendeurId: vente.vendeurId, + tailleLot: vente.tailleLot, + quantiteIllimite: vente.quantiteIllimite, + prixLot: vente.prixLot + }) + } + + static async diminuerQuantite(chatMessageId, quantite) { + const chatMessage = game.messages.get(chatMessageId) + const vente = ChatVente.getDetailVente(chatMessageId) + vente.nbLots = Math.max(0, vente.nbLots - quantite) + await chatMessage?.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots) + + const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente); + chatMessage.update({ content: html }); + chatMessage.render(true); + } + + static async displayAchatVente(venteData) { + const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData); + const chatMessage = await ChatMessage.create(RdDUtility.chatDataSetup(html)) + await ChatVente.setDetailAchatVente(chatMessage, venteData) + } +} \ No newline at end of file diff --git a/module/dialog-item-achat.js b/module/achat-vente/dialog-item-achat.js similarity index 65% rename from module/dialog-item-achat.js rename to module/achat-vente/dialog-item-achat.js index 25e591c0..3e1814ea 100644 --- a/module/dialog-item-achat.js +++ b/module/achat-vente/dialog-item-achat.js @@ -1,35 +1,13 @@ -import { Misc } from "./misc.js"; -import { RdDUtility } from "./rdd-utility.js"; +import { Misc } from "../misc.js"; +import { RdDUtility } from "../rdd-utility.js"; +import { ChatVente } from "./chat-vente.js"; export class DialogItemAchat extends Dialog { static preparerAchat(chatButton) { - const vendeurId = chatButton.attributes['data-vendeurId']?.value; - const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined; - const acheteur = RdDUtility.getSelectedActor(); - const json = chatButton.attributes['data-jsondata']?.value; - if (!acheteur && !vendeur) { - ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement"); - return undefined; - } - if (!json) { - ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes") - return undefined; - } - - return { - item: JSON.parse(json), - vendeur, - acheteur, - nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value), - tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1), - prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0), - quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true', - chatMessageIdVente: RdDUtility.findChatMessageId(chatButton), - }; + return ChatVente.getDetailAchatVente(RdDUtility.findChatMessageId(chatButton)) } - static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) { const venteData = { item, @@ -38,17 +16,21 @@ export class DialogItemAchat extends Dialog { acheteur, tailleLot, quantiteIllimite, - quantiteNbLots: nbLots, + nbLots, choix: { seForcer: false, supprimerSiZero: true }, prixLot, isVente: prixLot > 0, isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(), chatMessageIdVente - }; + } + if (venteData.vendeur?.id == venteData.acheteur?.id) { + ui.notifications.info("Inutile de se vendre à soi-même") + return + } - DialogItemAchat.changeNombreLots(venteData, 1); - const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData); - new DialogItemAchat(html, venteData).render(true); + DialogItemAchat.changeNombreLots(venteData, 1) + const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData) + new DialogItemAchat(html, venteData).render(true) } static changeNombreLots(venteData, nombreLots) { @@ -116,18 +98,18 @@ export class DialogItemAchat extends Dialog { this.venteData.choix.seForcer = event.currentTarget.checked; } - setNombreLots(nombreLots) { + setNombreLots(nbLots) { if (!this.venteData.quantiteIllimite) { - if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) { - ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`) + if (!this.venteData.quantiteIllimite && nbLots > this.venteData.nbLots) { + ui.notifications.warn(`Seulement ${this.venteData.nbLots} lots disponibles, vous ne pouvez pas en prendre ${nbLots}`) } - nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots); + nbLots = Math.min(nbLots, this.venteData.nbLots); } - DialogItemAchat.changeNombreLots(this.venteData, nombreLots); + DialogItemAchat.changeNombreLots(this.venteData, nbLots); - this.html.find(".nombreLots").val(nombreLots); + this.html.find(".nombreLots").val(nbLots); this.html.find(".prixTotal").text(this.venteData.prixTotal); this.html.find("span.total-sust").text(this.venteData.totalSust); this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere); diff --git a/module/dialog-item-vente.js b/module/achat-vente/dialog-item-vente.js similarity index 61% rename from module/dialog-item-vente.js rename to module/achat-vente/dialog-item-vente.js index d871f7c1..07b1bad2 100644 --- a/module/dialog-item-vente.js +++ b/module/achat-vente/dialog-item-vente.js @@ -1,29 +1,30 @@ -import { HtmlUtility } from "./html-utility.js"; +import { HtmlUtility } from "../html-utility.js"; +import { RdDUtility } from "../rdd-utility.js"; +import { ChatVente } from "./chat-vente.js"; export class DialogItemVente extends Dialog { - static async display({ item, callback, quantiteMax = undefined }) { + static async display({ item, quantiteMax = undefined }) { const quantite = quantiteMax ?? item.getQuantite() ?? 1; - const isOwned = item.parent; const venteData = { item: item, alias: item.actor?.name ?? game.user.name, - vendeurId: item.actor?.id, + vendeurId: item.actor.id, prixOrigine: item.calculerPrixCommercant(), prixUnitaire: item.calculerPrixCommercant(), prixLot: item.calculerPrixCommercant(), tailleLot: 1, - quantiteNbLots: quantite, - quantiteMaxLots: quantite, + nbLots: quantite, + maxLots: quantite, quantiteMax: quantite, - quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned, - isOwned: isOwned, - }; + quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !item.parent, + isOwned: item.parent, + } const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData); - return new DialogItemVente(venteData, html, callback).render(true); + return new DialogItemVente(venteData, html).render(true); } - constructor(venteData, html, callback) { + constructor(venteData, html) { let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 }; let conf = { @@ -34,7 +35,6 @@ export class DialogItemVente extends Dialog { }; super(conf, options); - this.callback = callback; this.venteData = venteData; } @@ -43,7 +43,7 @@ export class DialogItemVente extends Dialog { this.html = html; this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value))); - this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value))); + this.html.find(".nbLots").change(event => this.setNbLots(Number(event.currentTarget.value))); this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked)); this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value))); @@ -52,7 +52,15 @@ export class DialogItemVente extends Dialog { async onProposer(it) { this.updateVente(this.getChoixVente()); - this.callback(this.venteData); + + this.venteData["properties"] = this.venteData.item.getProprietes(); + if (this.venteData.isOwned) { + if (this.venteData.nbLots * this.venteData.tailleLot > this.venteData.quantiteMax) { + ui.notifications.warn(`Vous avez ${this.venteData.quantiteMax} ${this.venteData.item.name}, ce n'est pas suffisant pour vendre ${this.venteData.nbLots} de ${this.venteData.tailleLot}`) + return; + } + } + await ChatVente.displayAchatVente(this.venteData) } updateVente(update) { @@ -61,7 +69,7 @@ export class DialogItemVente extends Dialog { getChoixVente() { return { - quantiteNbLots: Number(this.html.find(".quantiteNbLots").val()), + nbLots: Number(this.html.find(".nbLots").val()), tailleLot: Number(this.html.find(".tailleLot").val()), quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'), prixLot: Number(this.html.find(".prixLot").val()) @@ -77,26 +85,26 @@ export class DialogItemVente extends Dialog { const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot); this.updateVente({ tailleLot, - quantiteNbLots: Math.min(maxLots, this.venteData.quantiteNbLots), - quantiteMaxLots: maxLots, + nbLots: Math.min(maxLots, this.venteData.nbLots), + maxLots: maxLots, prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2) }); this.html.find(".prixLot").val(this.venteData.prixLot); - this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots); - this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots) + this.html.find(".nbLots").val(this.venteData.nbLots); + this.html.find(".nbLots").attr("max", this.venteData.maxLots) } setNbLots(nbLots) { this.updateVente({ - quantiteNbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)) : nbLots + nbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.maxLots)) : nbLots }) - this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots); + this.html.find(".nbLots").val(this.venteData.nbLots); } setQuantiteIllimite(checked) { this.updateVente({ quantiteIllimite: checked }) this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles"); - HtmlUtility.showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite) + HtmlUtility.showControlWhen(this.html.find(".nbLots"), !this.venteData.quantiteIllimite) } } \ No newline at end of file diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index a9913159..224b253a 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -1,3 +1,4 @@ +import { ChatVente } from "../achat-vente/chat-vente.js"; import { ChatUtility } from "../chat-utility.js"; import { SYSTEM_SOCKET_ID } from "../constants.js"; import { Grammar } from "../grammar.js"; @@ -360,12 +361,9 @@ export class RdDBaseActor extends Actor { ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); return; } - await this.decrementerVente(vendeur, itemVendu, quantite, cout); - if (acheteur) { - await acheteur.depenserSols(cout); - const createdItemId = await acheteur.creerQuantiteItem(itemVendu, quantite); - await acheteur.consommerNourritureAchetee(achat, achat.vente, createdItemId); - } + await vendeur?.vendre(itemVendu, quantite, cout); + await acheteur?.acheter(itemVendu, quantite, cout, achat) + if (cout > 0) { RdDAudio.PlayContextAudio("argent"); } @@ -379,24 +377,26 @@ export class RdDBaseActor extends Actor { }); if (!achat.vente.quantiteIllimite) { - if (achat.vente.quantiteNbLots <= achat.choix.nombreLots) { + if (achat.vente.nbLots <= achat.choix.nombreLots) { ChatUtility.removeChatMessageId(achat.chatMessageIdVente); } else if (achat.chatMessageIdVente) { - achat.vente.properties = itemVendu.getProprietes(); - achat.vente.quantiteNbLots -= achat.choix.nombreLots; - achat.vente.jsondata = JSON.stringify(achat.vente.item); - const messageVente = game.messages.get(achat.chatMessageIdVente); - messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', achat.vente) }); - messageVente.render(true); + await ChatVente.diminuerQuantite(achat.chatMessageIdVente, achat.choix.nombreLots) } } } - async decrementerVente(vendeur, itemVendu, quantite, cout) { - if (vendeur) { - await vendeur.ajouterSols(cout); - await vendeur.decrementerQuantiteItem(itemVendu, quantite); + async vendre(item, quantite, cout) { + await this.ajouterSols(cout); + await this.decrementerQuantiteItem(item, quantite); + } + + async acheter(item, quantite, cout, achat) { + await this.depenserSols(cout) + const createdItemId = await this.creerQuantiteItem(item, quantite) + if (achat.choix.consommer && item.type == 'nourritureboisson' && createdItemId != undefined) { + achat.choix.doses = achat.choix.nombreLots; + await this.consommerNourritureboisson(createdItemId, achat.choix, achat.vente.actingUserId); } } @@ -409,31 +409,28 @@ export class RdDBaseActor extends Actor { return disponible == undefined || disponible >= quantiteDemande; } - async consommerNourritureAchetee(achat, vente, createdItemId) { - if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) { - achat.choix.doses = achat.choix.nombreLots; - await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId); - } - } - + async consommerNourritureboisson(itemId, choix, userId) { } async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) { if (item.isService()) { return; } + const itemId = item.id; let resteQuantite = (item.system.quantite ?? 1) - quantite; if (resteQuantite <= 0) { if (options.supprimerSiZero) { await this.deleteEmbeddedDocuments("Item", [item.id]); } else { - await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': 0 }]); + await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': 0 }]); } if (resteQuantite < 0) { ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`) } } else if (resteQuantite > 0) { + const realItem = this.getItem(item.id) + realItem.update({ 'system.quantite': resteQuantite }); await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]); } } @@ -445,7 +442,7 @@ export class RdDBaseActor extends Actor { type: item.type, img: item.img, name: item.name, - system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }) + system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false }) }; const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem); const items = await this.createEmbeddedDocuments("Item", newItems); diff --git a/module/actor/commerce-sheet.js b/module/actor/commerce-sheet.js index 1fb84fc3..5a7c4cd5 100644 --- a/module/actor/commerce-sheet.js +++ b/module/actor/commerce-sheet.js @@ -1,4 +1,4 @@ -import { DialogItemAchat } from "../dialog-item-achat.js"; +import { DialogItemAchat } from "../achat-vente/dialog-item-achat.js"; import { RdDItem } from "../item.js"; import { RdDUtility } from "../rdd-utility.js"; import { RdDBaseActorSheet } from "./base-actor-sheet.js"; diff --git a/module/item.js b/module/item.js index e52970e0..a97c050c 100644 --- a/module/item.js +++ b/module/item.js @@ -1,4 +1,4 @@ -import { DialogItemVente } from "./dialog-item-vente.js"; +import { DialogItemVente } from "./achat-vente/dialog-item-vente.js"; import { Grammar } from "./grammar.js"; import { Misc } from "./misc.js"; import { RdDHerbes } from "./rdd-herbes.js"; @@ -233,7 +233,7 @@ export class RdDItem extends Item { } isCompetenceArme() { - return this.isCompetence() && [ 'melee','tir', 'lancer'].includes(this.system.categorie) + return this.isCompetence() && ['melee', 'tir', 'lancer'].includes(this.system.categorie) } isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" } @@ -538,7 +538,7 @@ export class RdDItem extends Item { _id: this.id, 'system.quantite': this.system.quantite * sust, 'system.encombrement': Misc.keepDecimals(this.system.encombrement / sust, 2), - 'system.cout': Misc.keepDecimals(this.system.cout / sust, 2), + 'system.cout': Math.max(0, Misc.keepDecimals(this.system.cout / sust, 2)), 'system.sust': 1 }]) } @@ -621,23 +621,7 @@ export class RdDItem extends Item { ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`); return; } - await DialogItemVente.display({ - item: this, - quantiteMax, - callback: async (vente) => { - vente["properties"] = this.getProprietes(); - if (vente.isOwned) { - if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) { - ui.notifications.warn(`Vous avez ${vente.quantiteMax} ${vente.item.name}, ce n'est pas suffisant pour vendre ${vente.quantiteNbLots} de ${vente.tailleLot}`) - return; - } - } - vente.jsondata = JSON.stringify(vente.item); - - let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente); - ChatMessage.create(RdDUtility.chatDataSetup(html)); - } - }); + await DialogItemVente.display({ item: this, quantiteMax }) } /* -------------------------------------------- */ diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 35e50a5d..780e1382 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -4,7 +4,7 @@ import { RdDCombat } from "./rdd-combat.js"; import { Misc } from "./misc.js"; import { Grammar } from "./grammar.js"; import { TMRUtility } from "./tmr-utility.js"; -import { DialogItemAchat } from "./dialog-item-achat.js"; +import { DialogItemAchat } from "./achat-vente/dialog-item-achat.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { RdDDice } from "./rdd-dice.js"; import { RdDItem } from "./item.js"; diff --git a/templates/chat-vente-item.html b/templates/chat-vente-item.html index 90603356..a39562b1 100644 --- a/templates/chat-vente-item.html +++ b/templates/chat-vente-item.html @@ -1,3 +1,4 @@ +{{log 'chat-vente-item' this}}

{{#if alias}}{{alias}} propose: {{else}}Acheter {{/if}}{{item.name}}

{{#if item.img}} @@ -12,7 +13,7 @@

{{#unless quantiteIllimite}} - Lots disponibles: {{quantiteNbLots}}
+ Lots disponibles: {{nbLots}}
{{/unless}} {{#if (gt tailleLot 1)}} Lots de: {{tailleLot}}
@@ -22,15 +23,9 @@ {{numberFormat prixLot decimals=2 sign=false}} Sols
{{/if}}

- {{#if (or (gt quantiteNbLots 0) quantiteIllimite)}} + {{#if (or (gt nbLots 0) quantiteIllimite)}} - + {{#if (eq prixLot 0)}}Prendre{{else}}Acheter{{/if}} {{/if}} diff --git a/templates/dialog-item-achat.html b/templates/dialog-item-achat.html index 31dbe440..eba79b40 100644 --- a/templates/dialog-item-achat.html +++ b/templates/dialog-item-achat.html @@ -31,7 +31,7 @@
@@ -41,7 +41,7 @@
diff --git a/templates/dialog-item-vente.html b/templates/dialog-item-vente.html index 4107cd28..6032aeb5 100644 --- a/templates/dialog-item-vente.html +++ b/templates/dialog-item-vente.html @@ -18,8 +18,8 @@ quantiteIllimite}}checked{{/if}} /> {{/unless}} - +