https://dev.app.pol-crm.com/api/templates/f47ef469dac34bc29180feb40a25724c Return to referer URL

PlaceholderAction

Request

GET Parameters

No GET parameters

POST Parameters

No POST parameters

Uploaded Files

No files were uploaded

Request Attributes

Key Value
_api_item_operation_name
"put"
_api_normalization_context
[
  "groups" => [
    "template:read"
  ]
  "operation_type" => "item"
  "item_operation_name" => "put"
  "resource_class" => "App\Model\Template\Template"
  "input" => null
  "output" => null
  "request_uri" => "/api/templates/f47ef469dac34bc29180feb40a25724c"
  "uri" => "https://dev.app.pol-crm.com/api/templates/f47ef469dac34bc29180feb40a25724c"
  "resources" => ApiPlatform\Core\Serializer\ResourceList {#3321
    storage: []
    flag::STD_PROP_LIST: false
    flag::ARRAY_AS_PROPS: false
    iteratorClass: "ArrayIterator"
  }
  "exclude_from_cache_key" => [
    "resources"
    "resources_to_push"
  ]
  "resources_to_push" => ApiPlatform\Core\Serializer\ResourceList {#5921
    storage: []
    flag::STD_PROP_LIST: false
    flag::ARRAY_AS_PROPS: false
    iteratorClass: "ArrayIterator"
  }
]
_api_resource_class
"App\Model\Template\Template"
_api_write_item_iri
"/api/templates/f47ef469dac34bc29180feb40a25724c"
_controller
"api_platform.action.put_item"
_firewall_context
"security.firewall.map.context.api"
_format
null
_links
Fig\Link\GenericLinkProvider {#5905
  -links: [
    "000000001c197faf000000003adbb848" => Fig\Link\Link {#5873
      -href: "https://dev.app.pol-crm.com/api/docs.jsonld"
      -rel: [
        "http://www.w3.org/ns/hydra/core#apiDocumentation" => true
      ]
      -attributes: []
    }
  ]
}
_resources
[]
_route
"api_templates_put_item"
_route_params
[
  "_format" => null
  "_api_resource_class" => "App\Model\Template\Template"
  "_api_item_operation_name" => "put"
  "id" => "f47ef469dac34bc29180feb40a25724c"
]
_stopwatch_token
"e83ddf"
data
App\Model\Template\Template {#173
  -id: "f47ef469dac34bc29180feb40a25724c"
  -customerId: "customer_121"
  -name: "Test"
  -content: """
    <!doctype html>\n
    <html lang="fr">\n
    <meta charset="utf-8">\n
    <meta name="viewport" content="width=device-width, initial-scale=1">\n
    <title>Devis – YANIGAV – {{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}</title>\n
    <style>\n
      :root { --primary:#0f172a; --muted:#475569; --border:#e2e8f0; --bg:#f8fafc; }\n
      html, body { margin:0; padding:0; background:var(--bg); color:#0b1220; font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji"; }\n
      .page { max-width:900px; margin:2rem auto; background:#fff; border:1px solid var(--border); border-radius:12px; overflow:hidden; box-shadow:0 10px 30px rgba(0,0,0,.04); }\n
      header { padding:1.25rem 1.5rem; background:#fff; border-bottom:1px solid var(--border); display:flex; gap:1rem; align-items:center; }\n
      .brand { font-weight:700; letter-spacing:.2px; font-size:1rem; color:var(--primary); }\n
      .sub { color:var(--muted); font-size:.9rem; }\n
      .grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }\n
      .section { padding:1.25rem 1.5rem; }\n
      h1 { font-size:1.4rem; margin:.25rem 0 .5rem; letter-spacing:.2px; }\n
      h2 { font-size:1.1rem; margin:0 0 .75rem; color:var(--primary); }\n
      p { margin:.25rem 0; line-height:1.55; }\n
      .card { background:#fff; border:1px solid var(--border); border-radius:10px; padding:1rem; }\n
      .muted { color:var(--muted); }\n
      .kvs { display:grid; grid-template-columns:1fr 1fr; gap:.5rem 1rem; font-size:.95rem; }\n
      .kvs div { display:flex; align-items:center; gap:.5rem; }\n
      .pill { font-size:.8rem; padding:.15rem .5rem; border:1px solid var(--border); border-radius:999px; background:#f1f5f9; }\n
      table { width:100%; border-collapse:collapse; }\n
      th, td { border:1px solid var(--border); padding:.6rem .5rem; text-align:left; vertical-align:top; }\n
      thead th { background:#f1f5f9; }\n
      tfoot td { font-weight:600; }\n
      .note { font-size:.92rem; background:#f8fafc; border:1px dashed var(--border); padding:.75rem; border-radius:8px; }\n
      .cols-3 { columns:2; column-gap:1rem; }\n
      .signature { height:80px; border:1px dashed var(--border); border-radius:10px; display:flex; align-items:center; justify-content:center; color:var(--muted); }\n
      footer { padding:1rem 1.5rem; border-top:1px solid var(--border); color:var(--muted); font-size:.9rem; background:#fff; }\n
    </style>\n
    \n
    <body>\n
    <div class="page">\n
    \n
      {# ==== Raccourcis / sécurisation des accès ==== #}\n
      {% set c = (quote.prospect is defined and quote.prospect.contact is defined) ? quote.prospect.contact : null %}\n
      {% set a = (c and c.mainAddress is defined) ? c.mainAddress : null %}\n
      {% set comp = (quote.prospect is defined and quote.prospect.company is defined) ? quote.prospect.company : null %}\n
      {% set lines = quote.quoteLines|default([]) %}\n
    \n
      {# Portable du commercial : on cherche dans un ordre sûr #}\n
      {% set tel_portable = '' %}\n
      {% if managedBy is defined %}\n
        {% if managedBy.phoneNumber is defined and managedBy.phoneNumber %}{% set tel_portable = managedBy.phoneNumber %}\n
        {% elseif managedBy.mobilePhone is defined and managedBy.mobilePhone %}{% set tel_portable = managedBy.mobilePhone %}\n
        {% elseif managedBy.phone is defined and managedBy.phone %}{% set tel_portable = managedBy.phone %}\n
        {% endif %}\n
      {% endif %}\n
    \n
      {# ==== Totaux/remise/TVA - robustes ==== #}\n
      {% set total_ht_before_discount = 0 %}\n
      {% for l in lines %}\n
        {% set q = l.quantity|default(1) %}\n
        {% set pu = l.unitPriceExclVat|default(0) %}\n
        {% set total_ht_before_discount = total_ht_before_discount + (q * pu) %}\n
      {% endfor %}\n
      {% if total_ht_before_discount == 0 %}\n
        {% set total_ht_before_discount = quote.totalExcludingVat|default(0) %}\n
      {% endif %}\n
      {% set total_ht = quote.totalExcludingVat|default(total_ht_before_discount) %}\n
      {% set discount_value = total_ht_before_discount - total_ht %}\n
      {% set discount_percent = total_ht_before_discount > 0 ? (discount_value / total_ht_before_discount * 100) : 0 %}\n
      {% set vat_total = 0 %}\n
      {% for l in lines %}\n
        {% set vat_total = vat_total + (l.vatAmount|default(0)) %}\n
      {% endfor %}\n
    \n
      {# ==== Sélection ligne principale / formation / options (sans filtres avancés) ==== #}\n
      {% set first = (lines[0] is defined) ? lines[0] : null %}\n
      {% set mainLine = null %}\n
      {% set formationLine = null %}\n
      {% set options = [] %}\n
      {% for l in lines %}\n
        {% set ref = l.reference|default('')|lower %}\n
        {% set isOpt = l.isOptional is defined and l.isOptional %}\n
        {% if mainLine is null and not isOpt and ('formation' not in ref) %}\n
          {% set mainLine = l %}\n
        {% endif %}\n
        {% if formationLine is null and ('formation' in ref) %}\n
          {% set formationLine = l %}\n
        {% endif %}\n
        {% if isOpt %}\n
          {% set options = options|merge([l]) %}\n
        {% endif %}\n
      {% endfor %}\n
      {% if mainLine is null %}{% set mainLine = first %}{% endif %}\n
    \n
      <!-- HEADER -->\n
      <header>\n
        <div style="flex:1">\n
          <div class="brand">YANIGAV – Enfonce-pieux • Affûte-piquet • Fendeuse de bûche</div>\n
          <div class="sub">RCS ROANNE B 403 872 724 • SIRET 403 872 724 00014 • APE 4661Z • TVA FR114038727224</div>\n
        </div>\n
        <div class="pill">{{ (quote.createdAt|default('now'))|date('d F Y') }}</div>\n
      </header>\n
    \n
      <!-- COORDONNÉES -->\n
      <div class="section grid-2">\n
        <div class="card">\n
          <h2>Expéditeur</h2>\n
          <p><strong>YANIGAV</strong></p>\n
          <p>De la part de <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}</strong> ({{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }})</p>\n
          <div class="kvs">\n
            <div><span class="pill">Tél</span> {{ managedBy is defined and managedBy.phone is defined and managedBy.phone ? managedBy.phone : '—' }}</div>\n
            {% if tel_portable %}\n
              <div><span class="pill">Port</span> {{ tel_portable }}</div>\n
            {% endif %}\n
            <div><span class="pill">Email</span>\n
              {% if managedBy is defined and managedBy.email is defined and managedBy.email %}\n
                <a href="mailto:{{ managedBy.email }}">{{ managedBy.email }}</a>\n
              {% else %}—{% endif %}\n
            </div>\n
          </div>\n
        </div>\n
        <div class="card">\n
          <h2>Destinataire</h2>\n
          <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}</strong></p>\n
          {% if comp and comp.name is defined and comp.name %}<p><strong>{{ comp.name }}</strong></p>{% endif %}\n
          {% if a and (a.postalCode is defined or a.city is defined) %}<p class="muted">{{ a.postalCode|default('') }} {{ a.city|default('') }}</p>{% endif %}\n
        </div>\n
      </div>\n
    \n
      <!-- INTRO -->\n
      <div class="section">\n
        <div class="card">\n
          <h1>Proposition commerciale</h1>\n
          <p>{% if c and c.civility is defined and c.civility %}{{ c.civility }},{% else %}Madame, Monsieur,{% endif %}</p>\n
          <p>Nous vous remercions de l’intérêt que vous portez à la marque YANIGAV et à ses produits. Suite à votre récent appel téléphonique, voici notre proposition pour un <strong>{{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}</strong> correspondant à votre demande.</p>\n
          {% if quote.priceListRef is defined and quote.priceListRef %}\n
            <p class="muted">{{ quote.priceListRef }}</p>\n
          {% else %}\n
            <p class="muted">Tarif — {{ (quote.createdAt|default('now'))|date('Y') }}</p>\n
          {% endif %}\n
        </div>\n
      </div>\n
    \n
      <!-- OFFRE PRINCIPALE -->\n
      <div class="section">\n
        <div class="card">\n
          <h2>Offre principale</h2>\n
          <table>\n
            <thead>\n
              <tr>\n
                <th>Désignation</th>\n
                <th>Référence</th>\n
                <th>Prix unitaire HT</th>\n
              </tr>\n
            </thead>\n
            <tbody>\n
              {% set pu = (mainLine and mainLine.unitPriceExclVat is defined) ? mainLine.unitPriceExclVat : (total_ht_before_discount > 0 ? total_ht_before_discount : 0) %}\n
              <tr>\n
                <td>{{ (mainLine and mainLine.name is defined and mainLine.name) ? mainLine.name : quote.name }}</td>\n
                <td>{{ (mainLine and mainLine.reference is defined and mainLine.reference) ? mainLine.reference : '—' }}</td>\n
                <td>{{ pu|number_format(0, ',', ' ') }} €</td>\n
              </tr>\n
            </tbody>\n
          </table>\n
          {% set note = 'Cinématique unique sur le marché — un véritable atout dans les terrains compliqués.' %}\n
          <p class="note" style="margin-top:.75rem">{{ note }}</p>\n
        </div>\n
      </div>\n
    \n
      {# ==== DESCRIPTION / ÉQUIPEMENT / FORMATION / OPTIONS ==== #}\n
      {% set description = (mainLine and mainLine.description is defined and mainLine.description) ? mainLine.description : '' %}\n
      {% set description = description|replace({'•':'\n',';':'\n'}) %}\n
      {% set descList = description|split('\n') %}\n
    \n
      <div class="section grid-2">\n
        <div class="card">\n
          <h2>Points forts</h2>\n
          {% set hasPoint = false %}\n
          <ul class="cols-3">\n
            {% for item in descList %}\n
              {% set t = item|trim %}\n
              {% if t != '' %}\n
                {% set hasPoint = true %}\n
                <li>{{ t }}</li>\n
              {% endif %}\n
            {% endfor %}\n
          </ul>\n
          {% if not hasPoint %}\n
            <p class="muted">Aucun détail technique renseigné pour cet article.</p>\n
          {% endif %}\n
        </div>\n
    \n
        <div class="card">\n
          <h2>Équipement de série</h2>\n
          {% set printedEquip = false %}\n
          {# 1) Liste explicite mainLine.features si fournie #}\n
          {% if mainLine and mainLine.features is defined and mainLine.features %}\n
            <ul>\n
              {% for f in mainLine.features %}\n
                <li>{{ f }}</li>\n
                {% set printedEquip = true %}\n
              {% endfor %}\n
            </ul>\n
          {% endif %}\n
    \n
          {# 2) Sinon, tentative d’extraction depuis descList avec mots-clés #}\n
          {% if not printedEquip %}\n
            {% set equipList = [] %}\n
            {% for item in descList %}\n
              {% set t = item|trim %}\n
              {% if t matches '/(équipement|equipement|de série|serie)/i' %}\n
                {% set equipList = equipList|merge([t]) %}\n
              {% endif %}\n
            {% endfor %}\n
            {% if equipList %}\n
              <ul>\n
                {% for f in equipList %}<li>{{ f }}</li>{% endfor %}\n
              </ul>\n
              {% set printedEquip = true %}\n
            {% endif %}\n
          {% endif %}\n
    \n
          {% if not printedEquip %}\n
            <p class="muted">Aucun équipement de série spécifié.</p>\n
          {% endif %}\n
    \n
          {% if formationLine %}\n
            <h2 style="margin-top:1rem">Formation / Mise en route</h2>\n
            <p><strong>{{ formationLine.name|default('Formation / Mise en route') }}</strong> – Prix net :\n
              {{ (formationLine.totalExclVat|default(formationLine.unitPriceExclVat|default(0)))|number_format(0, ',', ' ') }} € HT</p>\n
            {% if formationLine.description is defined and formationLine.description %}<p class="muted">{{ formationLine.description }}</p>{% endif %}\n
          {% endif %}\n
    \n
          {% if options %}\n
            <h2 style="margin-top:1rem">Équipements recommandés</h2>\n
            <ul>\n
              {% for opt in options %}\n
                {% set q = opt.quantity|default(1) %}\n
                {% set puo = opt.unitPriceExclVat|default(0) %}\n
                {% set rem = opt.discountPercent|default(0) %}\n
                {% set opt_total = opt.totalExclVat|default(q * puo * (1 - (rem / 100))) %}\n
                <li>{{ opt.name }} — {{ opt_total|number_format(0, ',', ' ') }} € HT</li>\n
              {% endfor %}\n
            </ul>\n
          {% endif %}\n
        </div>\n
      </div>\n
    \n
      <!-- CONDITIONS COMMERCIALES -->\n
      <div class="section">\n
        <div class="card">\n
          <h2>Conditions commerciales</h2>\n
          <ul>\n
            {% if quote.expiredAt is defined and quote.expiredAt %}<li>Validité de l’offre : 1 mois (jusqu’au {{ quote.expiredAt|date('d/m/Y') }})</li>{% else %}<li>Validité de l’offre : 1 mois</li>{% endif %}\n
            {% if discount_value > 0 %}<li>Remise de service : {{ discount_percent|round(0, 'floor') }} %</li>{% endif %}\n
            {% if quote.orderContext is defined and quote.orderContext %}<li>{{ quote.orderContext }}</li>{% endif %}\n
            <li>Règlement {{ quote.paymentMode|default('30 jours nets par LCR') }}</li>\n
            <li>Délai : {{ quote.leadTime|default('2 à 3 mois après commande') }}</li>\n
            {% if quote.shippingFeesHt is defined %}\n
              {% if quote.shippingFeesHt == 0 %}<li>Port franco</li>\n
              {% elseif quote.shippingFeesHt > 0 %}<li>Frais de port : {{ quote.shippingFeesHt|number_format(2, ',', ' ') }} € HT</li>\n
              {% else %}<li>Port : {{ quote.shippingMode|default('selon conditions') }}</li>\n
              {% endif %}\n
            {% else %}\n
              <li>Port : {{ quote.shippingMode|default('selon conditions') }}</li>\n
            {% endif %}\n
            {% if quote.customerRef is defined and quote.customerRef %}<li>Réf. client : {{ quote.customerRef }}</li>{% endif %}\n
          </ul>\n
        </div>\n
      </div>\n
    \n
      <!-- SIGNATURES -->\n
      <div class="section grid-2">\n
        <div class="card">\n
          <h2>Signataires</h2>\n
          <p>\n
            <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}</strong>\n
            – {{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }}\n
            {% if tel_portable %} – {{ tel_portable }}{% endif %}\n
          </p>\n
          <div class="signature">Signature expéditeur</div>\n
        </div>\n
        <div class="card">\n
          <h2>Bon pour accord</h2>\n
          <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}</strong>{% if comp and comp.name is defined and comp.name %} – {{ comp.name }}{% endif %}</p>\n
          <div class="signature">Cachet et signature</div>\n
        </div>\n
      </div>\n
    \n
      <!-- PIED -->\n
      <footer>\n
        YANIGAV – Enfonce-pieux • Affûte-piquet • Fendeuse de bûche — RCS ROANNE B 403 872 724 — SIRET 403 872 724 00014 — APE 4661Z — TVA FR114038727224\n
      </footer>\n
    </div>\n
    \n
    {# PAGE 2 : CGV (optionnelle) #}\n
    {% if cgv is defined or quote.cgvText is defined %}\n
      <div style="page-break-before:always;"></div>\n
      <div class="page">\n
        <div class="section">\n
          <div class="card">\n
            <h2>Conditions Générales de Vente</h2>\n
            <div class="note" style="white-space:pre-wrap">\n
              {{ cgv|default(quote.cgvText)|raw }}\n
            </div>\n
          </div>\n
        </div>\n
        <footer>\n
          Document généré automatiquement — valable sous réserve des conditions précisées ci-dessus.\n
        </footer>\n
      </div>\n
    {% endif %}\n
    </body>\n
    </html>
    """
  -createdBy: null
  -updatedBy: null
  -createdAt: null
  -updatedAt: null
  #shouldNormalizeAsIRI: false
}
id
"f47ef469dac34bc29180feb40a25724c"
previous_data
App\Model\Template\Template {#438
  -id: "f47ef469dac34bc29180feb40a25724c"
  -customerId: "customer_121"
  -name: "Test"
  -content: """
    <!doctype html>\n
    <html lang="fr">\n
    <meta charset="utf-8">\n
    <meta name="viewport" content="width=device-width, initial-scale=1">\n
    <title>Devis – YANIGAV – {{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}</title>\n
    <style>\n
      :root { --primary:#0f172a; --muted:#475569; --border:#e2e8f0; --bg:#f8fafc; }\n
      html, body { margin:0; padding:0; background:var(--bg); color:#0b1220; font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji"; }\n
      .page { max-width:900px; margin:2rem auto; background:#fff; border:1px solid var(--border); border-radius:12px; overflow:hidden; box-shadow:0 10px 30px rgba(0,0,0,.04); }\n
      header { padding:1.25rem 1.5rem; background:#fff; border-bottom:1px solid var(--border); display:flex; gap:1rem; align-items:center; }\n
      .brand { font-weight:700; letter-spacing:.2px; font-size:1rem; color:var(--primary); }\n
      .sub { color:var(--muted); font-size:.9rem; }\n
      .grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }\n
      .section { padding:1.25rem 1.5rem; }\n
      h1 { font-size:1.4rem; margin:.25rem 0 .5rem; letter-spacing:.2px; }\n
      h2 { font-size:1.1rem; margin:0 0 .75rem; color:var(--primary); }\n
      p { margin:.25rem 0; line-height:1.55; }\n
      .card { background:#fff; border:1px solid var(--border); border-radius:10px; padding:1rem; }\n
      .muted { color:var(--muted); }\n
      .kvs { display:grid; grid-template-columns:1fr 1fr; gap:.5rem 1rem; font-size:.95rem; }\n
      .kvs div { display:flex; align-items:center; gap:.5rem; }\n
      .pill { font-size:.8rem; padding:.15rem .5rem; border:1px solid var(--border); border-radius:999px; background:#f1f5f9; }\n
      table { width:100%; border-collapse:collapse; }\n
      th, td { border:1px solid var(--border); padding:.6rem .5rem; text-align:left; vertical-align:top; }\n
      thead th { background:#f1f5f9; }\n
      tfoot td { font-weight:600; }\n
      .note { font-size:.92rem; background:#f8fafc; border:1px dashed var(--border); padding:.75rem; border-radius:8px; }\n
      .cols-3 { columns:2; column-gap:1rem; }\n
      .signature { height:80px; border:1px dashed var(--border); border-radius:10px; display:flex; align-items:center; justify-content:center; color:var(--muted); }\n
      footer { padding:1rem 1.5rem; border-top:1px solid var(--border); color:var(--muted); font-size:.9rem; background:#fff; }\n
    </style>\n
    \n
    <body>\n
    <div class="page">\n
    \n
      {# ==== Raccourcis / sécurisation des accès ==== #}\n
      {% set c = (quote.prospect is defined and quote.prospect.contact is defined) ? quote.prospect.contact : null %}\n
      {% set a = (c and c.mainAddress is defined) ? c.mainAddress : null %}\n
      {% set comp = (quote.prospect is defined and quote.prospect.company is defined) ? quote.prospect.company : null %}\n
      {% set lines = quote.quoteLines|default([]) %}\n
    \n
      {# Portable du commercial : on cherche dans un ordre sûr #}\n
      {% set tel_portable = '' %}\n
      {% if managedBy is defined %}\n
        {% if managedBy.phoneNumber is defined and managedBy.phoneNumber %}{% set tel_portable = managedBy.phoneNumber %}\n
        {% elseif managedBy.mobilePhone is defined and managedBy.mobilePhone %}{% set tel_portable = managedBy.mobilePhone %}\n
        {% elseif managedBy.phone is defined and managedBy.phone %}{% set tel_portable = managedBy.phone %}\n
        {% endif %}\n
      {% endif %}\n
    \n
      {# ==== Totaux/remise/TVA - robustes ==== #}\n
      {% set total_ht_before_discount = 0 %}\n
      {% for l in lines %}\n
        {% set q = l.quantity|default(1) %}\n
        {% set pu = l.unitPriceExclVat|default(0) %}\n
        {% set total_ht_before_discount = total_ht_before_discount + (q * pu) %}\n
      {% endfor %}\n
      {% if total_ht_before_discount == 0 %}\n
        {% set total_ht_before_discount = quote.totalExcludingVat|default(0) %}\n
      {% endif %}\n
      {% set total_ht = quote.totalExcludingVat|default(total_ht_before_discount) %}\n
      {% set discount_value = total_ht_before_discount - total_ht %}\n
      {% set discount_percent = total_ht_before_discount > 0 ? (discount_value / total_ht_before_discount * 100) : 0 %}\n
      {% set vat_total = 0 %}\n
      {% for l in lines %}\n
        {% set vat_total = vat_total + (l.vatAmount|default(0)) %}\n
      {% endfor %}\n
    \n
      {# ==== Sélection ligne principale / formation / options (sans filtres avancés) ==== #}\n
      {% set first = (lines[0] is defined) ? lines[0] : null %}\n
      {% set mainLine = null %}\n
      {% set formationLine = null %}\n
      {% set options = [] %}\n
      {% for l in lines %}\n
        {% set ref = l.reference|default('')|lower %}\n
        {% set isOpt = l.isOptional is defined and l.isOptional %}\n
        {% if mainLine is null and not isOpt and ('formation' not in ref) %}\n
          {% set mainLine = l %}\n
        {% endif %}\n
        {% if formationLine is null and ('formation' in ref) %}\n
          {% set formationLine = l %}\n
        {% endif %}\n
        {% if isOpt %}\n
          {% set options = options|merge([l]) %}\n
        {% endif %}\n
      {% endfor %}\n
      {% if mainLine is null %}{% set mainLine = first %}{% endif %}\n
    \n
      <!-- HEADER -->\n
      <header>\n
        <div style="flex:1">\n
          <div class="brand">YANIGAV – Enfonce-pieux • Affûte-piquet • Fendeuse de bûche</div>\n
          <div class="sub">RCS ROANNE B 403 872 724 • SIRET 403 872 724 00014 • APE 4661Z • TVA FR114038727224</div>\n
        </div>\n
        <div class="pill">{{ (quote.createdAt|default('now'))|date('d F Y') }}</div>\n
      </header>\n
    \n
      <!-- COORDONNÉES -->\n
      <div class="section grid-2">\n
        <div class="card">\n
          <h2>Expéditeur</h2>\n
          <p><strong>YANIGAV</strong></p>\n
          <p>De la part de <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}</strong> ({{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }})</p>\n
          <div class="kvs">\n
            <div><span class="pill">Tél</span> {{ managedBy is defined and managedBy.phone is defined and managedBy.phone ? managedBy.phone : '—' }}</div>\n
            {% if tel_portable %}\n
              <div><span class="pill">Port</span> {{ tel_portable }}</div>\n
            {% endif %}\n
            <div><span class="pill">Email</span>\n
              {% if managedBy is defined and managedBy.email is defined and managedBy.email %}\n
                <a href="mailto:{{ managedBy.email }}">{{ managedBy.email }}</a>\n
              {% else %}—{% endif %}\n
            </div>\n
          </div>\n
        </div>\n
        <div class="card">\n
          <h2>Destinataire</h2>\n
          <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}</strong></p>\n
          {% if comp and comp.name is defined and comp.name %}<p><strong>{{ comp.name }}</strong></p>{% endif %}\n
          {% if a and (a.postalCode is defined or a.city is defined) %}<p class="muted">{{ a.postalCode|default('') }} {{ a.city|default('') }}</p>{% endif %}\n
        </div>\n
      </div>\n
    \n
      <!-- INTRO -->\n
      <div class="section">\n
        <div class="card">\n
          <h1>Proposition commerciale</h1>\n
          <p>{% if c and c.civility is defined and c.civility %}{{ c.civility }},{% else %}Madame, Monsieur,{% endif %}</p>\n
          <p>Nous vous remercions de l’intérêt que vous portez à la marque YANIGAV et à ses produits. Suite à votre récent appel téléphonique, voici notre proposition pour un <strong>{{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}</strong> correspondant à votre demande.</p>\n
          {% if quote.priceListRef is defined and quote.priceListRef %}\n
            <p class="muted">{{ quote.priceListRef }}</p>\n
          {% else %}\n
            <p class="muted">Tarif — {{ (quote.createdAt|default('now'))|date('Y') }}</p>\n
          {% endif %}\n
        </div>\n
      </div>\n
    \n
      <!-- OFFRE PRINCIPALE -->\n
      <div class="section">\n
        <div class="card">\n
          <h2>Offre principale</h2>\n
          <table>\n
            <thead>\n
              <tr>\n
                <th>Désignation</th>\n
                <th>Référence</th>\n
                <th>Prix unitaire HT</th>\n
              </tr>\n
            </thead>\n
            <tbody>\n
              {% set pu = (mainLine and mainLine.unitPriceExclVat is defined) ? mainLine.unitPriceExclVat : (total_ht_before_discount > 0 ? total_ht_before_discount : 0) %}\n
              <tr>\n
                <td>{{ (mainLine and mainLine.name is defined and mainLine.name) ? mainLine.name : quote.name }}</td>\n
                <td>{{ (mainLine and mainLine.reference is defined and mainLine.reference) ? mainLine.reference : '—' }}</td>\n
                <td>{{ pu|number_format(0, ',', ' ') }} €</td>\n
              </tr>\n
            </tbody>\n
          </table>\n
          {% set note = (mainLine and mainLine.description is defined and mainLine.description) ? mainLine.description : 'Cinématique unique sur le marché — un véritable atout dans les terrains compliqués.' %}\n
          <p class="note" style="margin-top:.75rem">{{ note }}</p>\n
        </div>\n
      </div>\n
    \n
      {# ==== DESCRIPTION / ÉQUIPEMENT / FORMATION / OPTIONS ==== #}\n
      {% set description = (mainLine and mainLine.description is defined and mainLine.description) ? mainLine.description : '' %}\n
      {% set description = description|replace({'•':'\n',';':'\n'}) %}\n
      {% set descList = description|split('\n') %}\n
    \n
      <div class="section grid-2">\n
        <div class="card">\n
          <h2>Points forts</h2>\n
          {% set hasPoint = false %}\n
          <ul class="cols-3">\n
            {% for item in descList %}\n
              {% set t = item|trim %}\n
              {% if t != '' %}\n
                {% set hasPoint = true %}\n
                <li>{{ t }}</li>\n
              {% endif %}\n
            {% endfor %}\n
          </ul>\n
          {% if not hasPoint %}\n
            <p class="muted">Aucun détail technique renseigné pour cet article.</p>\n
          {% endif %}\n
        </div>\n
    \n
        <div class="card">\n
          <h2>Équipement de série</h2>\n
          {% set printedEquip = false %}\n
          {# 1) Liste explicite mainLine.features si fournie #}\n
          {% if mainLine and mainLine.features is defined and mainLine.features %}\n
            <ul>\n
              {% for f in mainLine.features %}\n
                <li>{{ f }}</li>\n
                {% set printedEquip = true %}\n
              {% endfor %}\n
            </ul>\n
          {% endif %}\n
    \n
          {# 2) Sinon, tentative d’extraction depuis descList avec mots-clés #}\n
          {% if not printedEquip %}\n
            {% set equipList = [] %}\n
            {% for item in descList %}\n
              {% set t = item|trim %}\n
              {% if t matches '/(équipement|equipement|de série|serie)/i' %}\n
                {% set equipList = equipList|merge([t]) %}\n
              {% endif %}\n
            {% endfor %}\n
            {% if equipList %}\n
              <ul>\n
                {% for f in equipList %}<li>{{ f }}</li>{% endfor %}\n
              </ul>\n
              {% set printedEquip = true %}\n
            {% endif %}\n
          {% endif %}\n
    \n
          {% if not printedEquip %}\n
            <p class="muted">Aucun équipement de série spécifié.</p>\n
          {% endif %}\n
    \n
          {% if formationLine %}\n
            <h2 style="margin-top:1rem">Formation / Mise en route</h2>\n
            <p><strong>{{ formationLine.name|default('Formation / Mise en route') }}</strong> – Prix net :\n
              {{ (formationLine.totalExclVat|default(formationLine.unitPriceExclVat|default(0)))|number_format(0, ',', ' ') }} € HT</p>\n
            {% if formationLine.description is defined and formationLine.description %}<p class="muted">{{ formationLine.description }}</p>{% endif %}\n
          {% endif %}\n
    \n
          {% if options %}\n
            <h2 style="margin-top:1rem">Équipements recommandés</h2>\n
            <ul>\n
              {% for opt in options %}\n
                {% set q = opt.quantity|default(1) %}\n
                {% set puo = opt.unitPriceExclVat|default(0) %}\n
                {% set rem = opt.discountPercent|default(0) %}\n
                {% set opt_total = opt.totalExclVat|default(q * puo * (1 - (rem / 100))) %}\n
                <li>{{ opt.name }} — {{ opt_total|number_format(0, ',', ' ') }} € HT</li>\n
              {% endfor %}\n
            </ul>\n
          {% endif %}\n
        </div>\n
      </div>\n
    \n
      <!-- CONDITIONS COMMERCIALES -->\n
      <div class="section">\n
        <div class="card">\n
          <h2>Conditions commerciales</h2>\n
          <ul>\n
            {% if quote.expiredAt is defined and quote.expiredAt %}<li>Validité de l’offre : 1 mois (jusqu’au {{ quote.expiredAt|date('d/m/Y') }})</li>{% else %}<li>Validité de l’offre : 1 mois</li>{% endif %}\n
            {% if discount_value > 0 %}<li>Remise de service : {{ discount_percent|round(0, 'floor') }} %</li>{% endif %}\n
            {% if quote.orderContext is defined and quote.orderContext %}<li>{{ quote.orderContext }}</li>{% endif %}\n
            <li>Règlement {{ quote.paymentMode|default('30 jours nets par LCR') }}</li>\n
            <li>Délai : {{ quote.leadTime|default('2 à 3 mois après commande') }}</li>\n
            {% if quote.shippingFeesHt is defined %}\n
              {% if quote.shippingFeesHt == 0 %}<li>Port franco</li>\n
              {% elseif quote.shippingFeesHt > 0 %}<li>Frais de port : {{ quote.shippingFeesHt|number_format(2, ',', ' ') }} € HT</li>\n
              {% else %}<li>Port : {{ quote.shippingMode|default('selon conditions') }}</li>\n
              {% endif %}\n
            {% else %}\n
              <li>Port : {{ quote.shippingMode|default('selon conditions') }}</li>\n
            {% endif %}\n
            {% if quote.customerRef is defined and quote.customerRef %}<li>Réf. client : {{ quote.customerRef }}</li>{% endif %}\n
          </ul>\n
        </div>\n
      </div>\n
    \n
      <!-- SIGNATURES -->\n
      <div class="section grid-2">\n
        <div class="card">\n
          <h2>Signataires</h2>\n
          <p>\n
            <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}</strong>\n
            – {{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }}\n
            {% if tel_portable %} – {{ tel_portable }}{% endif %}\n
          </p>\n
          <div class="signature">Signature expéditeur</div>\n
        </div>\n
        <div class="card">\n
          <h2>Bon pour accord</h2>\n
          <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}</strong>{% if comp and comp.name is defined and comp.name %} – {{ comp.name }}{% endif %}</p>\n
          <div class="signature">Cachet et signature</div>\n
        </div>\n
      </div>\n
    \n
      <!-- PIED -->\n
      <footer>\n
        YANIGAV – Enfonce-pieux • Affûte-piquet • Fendeuse de bûche — RCS ROANNE B 403 872 724 — SIRET 403 872 724 00014 — APE 4661Z — TVA FR114038727224\n
      </footer>\n
    </div>\n
    \n
    {# PAGE 2 : CGV (optionnelle) #}\n
    {% if cgv is defined or quote.cgvText is defined %}\n
      <div style="page-break-before:always;"></div>\n
      <div class="page">\n
        <div class="section">\n
          <div class="card">\n
            <h2>Conditions Générales de Vente</h2>\n
            <div class="note" style="white-space:pre-wrap">\n
              {{ cgv|default(quote.cgvText)|raw }}\n
            </div>\n
          </div>\n
        </div>\n
        <footer>\n
          Document généré automatiquement — valable sous réserve des conditions précisées ci-dessus.\n
        </footer>\n
      </div>\n
    {% endif %}\n
    </body>\n
    </html>
    """
  -createdBy: null
  -updatedBy: null
  -createdAt: null
  -updatedAt: null
  #shouldNormalizeAsIRI: false
}

Request Headers

Header Value
accept
"application/ld+json"
accept-encoding
"gzip, deflate, br, zstd"
accept-language
"fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7"
connection
"close"
content-length
"15077"
content-type
"application/json"
host
"dev.app.pol-crm.com"
origin
"https://dev.pol-crm.com"
priority
"u=1, i"
referer
"https://dev.pol-crm.com/"
sec-ch-ua
""Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140""
sec-ch-ua-mobile
"?0"
sec-ch-ua-platform
""Windows""
sec-fetch-dest
"empty"
sec-fetch-mode
"cors"
sec-fetch-site
"same-site"
user-agent
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"
x-accel-internal
"/internal-nginx-static-location"
x-php-ob-level
"1"
x-pol-auth
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NjA5MTI0NDEsImV4cCI6MTc2MDkxNjA0MSwicm9sZXMiOlsiUk9MRV9VU0VSIiwiUk9MRV9TVVBFUkFETUlOIiwiUk9MRV9BRE1JTiIsIlJPTEVfTU9EVUxFX1BST0RVQ1QiLCJST0xFX01PRFVMRV9QUk9EVUNUX0NVU1RPTUlaRSIsIlJPTEVfTU9EVUxFX1FVT1RFX0xJTkUiLCJQUk9TUEVDVF9TSE9XIiwiUFJPU1BFQ1RfQ1VEIiwiQ09OVEFDVF9DVUQiLCJDT05UQUNUX1NIT1ciLCJUQVNLX1NIT1ciLCJUQVNLX0NVRCIsIlFVT1RFX1NIT1ciLCJRVU9URV9DVUQiLCJRVU9URV9SRUdFTkVSQVRFX1BSSUNFUyJdLCJsb2dpbiI6ImRlbW95YW5pZ2F2IiwidXNlcl9pZCI6InVzZXJfMTAxMSIsInVzZXJfZXh0ZXJuYWxfaWQiOiIxMDExIiwiZW1haWwiOiJnLXNhdXRyb25Ac2ZpLmZyIiwiY3VzdG9tZXJfaWQiOiJjdXN0b21lcl8xMjEiLCJjdXN0b21lcl9uYW1lIjoiWUFOSUdBViIsImN1c3RvbWVyX2V4dGVybmFsX2lkIjoiMTIxIiwiY3VzdG9tZXJfbWFpbGluZ19pZCI6IjE0NyIsImZpcnN0bmFtZSI6Ikd1aWxsYXVtZSIsImxhc3RuYW1lIjoiU0FVVFJPTiIsImxpdmVvTG9naW4iOm51bGwsImxpdmVvUGFzc3dvcmQiOm51bGwsImhhc0ludHJhbmV0IjpmYWxzZSwibGFuZ3VhZ2UiOiJGUiIsInNlY3Rpb25zX2xlYWRlZCI6W10sInNlY3Rpb25zX21lbWJlcnMiOlsidXNlcl8xMDExIl0sImlzX3NlY3Rpb25zX2FjdGl2YXRlZCI6ZmFsc2UsInJlZnJlc2hfdG9rZW4iOiIifQ.smruhTDO6MF4efpXGiPp4DyZoLSpsUh3ykwBDmscLGtkvlySQlnSFvS1bxozG8T5Y0oGdkijvDiliogWK_zhqLF6FXho-oEscgCbKhvTjdosGLc4QHX0QAtM1LeVpT3BGVz9isHY1J7X0RDnoWA2GdCwCZ-ELXlS7fP08w_Mc5j8GqGhN5XwD70MLfR5ltD75o5BEhCWKMsWsatkGs3bbd7AfjhqoSz7qexpiHj1BRszq-H5QekWiJWgwOLDUJc85rZYaNVbYu75qseEbKfW-kWAxOZhAZCmVfFDQ-qBxSJ1i7KwVasIGTJDTnJn7l8fDqFWF0jGtC4LJzQEOZDjoOrQVaP2szLusNdOeKICnE3GOpY7E2sHIJpbTf8KlRUSm0uKc4t4hgoSRxnCdQGLx4hcTGSGHyITgso7tVs6068piCfp8JttEo5SoXERPiVNl2oeKa7VQAgtUWMzPI-SYX6QfGCjnrYE3JcTufx8xFtvlS4pmeIaLNJs7Y8l21f-A8MB7y-3zOAzriYExuKUOtT9oZ0GRtCWG5oTUyQ2LI4IjzaqBW_ikRfcccdSOZqZxV_FVw1fO9vPg9Lgi9XKAfKtjCLtI9nMboiZsSk9mx5_CAREqtb476hnnUVOfvHCBazVRQo-FWsSSWNLCIe8MtR9pUny0D8hn5qCQ712Axk"
x-real-ip
"176.174.157.21"
x-transaction-id
"front:zv9jvbn66i"

Request Content

Pretty

{
    "id": "f47ef469dac34bc29180feb40a25724c",
    "customerId": "customer_121",
    "name": "Test",
    "content": "<!doctype html>\n<html lang=\"fr\">\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Devis \u2013 YANIGAV \u2013 {{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}<\/title>\n<style>\n  :root { --primary:#0f172a; --muted:#475569; --border:#e2e8f0; --bg:#f8fafc; }\n  html, body { margin:0; padding:0; background:var(--bg); color:#0b1220; font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,\"Apple Color Emoji\",\"Segoe UI Emoji\"; }\n  .page { max-width:900px; margin:2rem auto; background:#fff; border:1px solid var(--border); border-radius:12px; overflow:hidden; box-shadow:0 10px 30px rgba(0,0,0,.04); }\n  header { padding:1.25rem 1.5rem; background:#fff; border-bottom:1px solid var(--border); display:flex; gap:1rem; align-items:center; }\n  .brand { font-weight:700; letter-spacing:.2px; font-size:1rem; color:var(--primary); }\n  .sub { color:var(--muted); font-size:.9rem; }\n  .grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }\n  .section { padding:1.25rem 1.5rem; }\n  h1 { font-size:1.4rem; margin:.25rem 0 .5rem; letter-spacing:.2px; }\n  h2 { font-size:1.1rem; margin:0 0 .75rem; color:var(--primary); }\n  p { margin:.25rem 0; line-height:1.55; }\n  .card { background:#fff; border:1px solid var(--border); border-radius:10px; padding:1rem; }\n  .muted { color:var(--muted); }\n  .kvs { display:grid; grid-template-columns:1fr 1fr; gap:.5rem 1rem; font-size:.95rem; }\n  .kvs div { display:flex; align-items:center; gap:.5rem; }\n  .pill { font-size:.8rem; padding:.15rem .5rem; border:1px solid var(--border); border-radius:999px; background:#f1f5f9; }\n  table { width:100%; border-collapse:collapse; }\n  th, td { border:1px solid var(--border); padding:.6rem .5rem; text-align:left; vertical-align:top; }\n  thead th { background:#f1f5f9; }\n  tfoot td { font-weight:600; }\n  .note { font-size:.92rem; background:#f8fafc; border:1px dashed var(--border); padding:.75rem; border-radius:8px; }\n  .cols-3 { columns:2; column-gap:1rem; }\n  .signature { height:80px; border:1px dashed var(--border); border-radius:10px; display:flex; align-items:center; justify-content:center; color:var(--muted); }\n  footer { padding:1rem 1.5rem; border-top:1px solid var(--border); color:var(--muted); font-size:.9rem; background:#fff; }\n<\/style>\n\n<body>\n<div class=\"page\">\n\n  {# ==== Raccourcis \/ s\u00e9curisation des acc\u00e8s ==== #}\n  {% set c = (quote.prospect is defined and quote.prospect.contact is defined) ? quote.prospect.contact : null %}\n  {% set a = (c and c.mainAddress is defined) ? c.mainAddress : null %}\n  {% set comp = (quote.prospect is defined and quote.prospect.company is defined) ? quote.prospect.company : null %}\n  {% set lines = quote.quoteLines|default([]) %}\n\n  {# Portable du commercial : on cherche dans un ordre s\u00fbr #}\n  {% set tel_portable = '' %}\n  {% if managedBy is defined %}\n    {% if managedBy.phoneNumber is defined and managedBy.phoneNumber %}{% set tel_portable = managedBy.phoneNumber %}\n    {% elseif managedBy.mobilePhone is defined and managedBy.mobilePhone %}{% set tel_portable = managedBy.mobilePhone %}\n    {% elseif managedBy.phone is defined and managedBy.phone %}{% set tel_portable = managedBy.phone %}\n    {% endif %}\n  {% endif %}\n\n  {# ==== Totaux\/remise\/TVA - robustes ==== #}\n  {% set total_ht_before_discount = 0 %}\n  {% for l in lines %}\n    {% set q = l.quantity|default(1) %}\n    {% set pu = l.unitPriceExclVat|default(0) %}\n    {% set total_ht_before_discount = total_ht_before_discount + (q * pu) %}\n  {% endfor %}\n  {% if total_ht_before_discount == 0 %}\n    {% set total_ht_before_discount = quote.totalExcludingVat|default(0) %}\n  {% endif %}\n  {% set total_ht = quote.totalExcludingVat|default(total_ht_before_discount) %}\n  {% set discount_value = total_ht_before_discount - total_ht %}\n  {% set discount_percent = total_ht_before_discount > 0 ? (discount_value \/ total_ht_before_discount * 100) : 0 %}\n  {% set vat_total = 0 %}\n  {% for l in lines %}\n    {% set vat_total = vat_total + (l.vatAmount|default(0)) %}\n  {% endfor %}\n\n  {# ==== S\u00e9lection ligne principale \/ formation \/ options (sans filtres avanc\u00e9s) ==== #}\n  {% set first = (lines[0] is defined) ? lines[0] : null %}\n  {% set mainLine = null %}\n  {% set formationLine = null %}\n  {% set options = [] %}\n  {% for l in lines %}\n    {% set ref = l.reference|default('')|lower %}\n    {% set isOpt = l.isOptional is defined and l.isOptional %}\n    {% if mainLine is null and not isOpt and ('formation' not in ref) %}\n      {% set mainLine = l %}\n    {% endif %}\n    {% if formationLine is null and ('formation' in ref) %}\n      {% set formationLine = l %}\n    {% endif %}\n    {% if isOpt %}\n      {% set options = options|merge([l]) %}\n    {% endif %}\n  {% endfor %}\n  {% if mainLine is null %}{% set mainLine = first %}{% endif %}\n\n  <!-- HEADER -->\n  <header>\n    <div style=\"flex:1\">\n      <div class=\"brand\">YANIGAV \u2013 Enfonce-pieux \u2022 Aff\u00fbte-piquet \u2022 Fendeuse de b\u00fbche<\/div>\n      <div class=\"sub\">RCS ROANNE B 403 872 724 \u2022 SIRET 403 872 724 00014 \u2022 APE 4661Z \u2022 TVA FR114038727224<\/div>\n    <\/div>\n    <div class=\"pill\">{{ (quote.createdAt|default('now'))|date('d F Y') }}<\/div>\n  <\/header>\n\n  <!-- COORDONN\u00c9ES -->\n  <div class=\"section grid-2\">\n    <div class=\"card\">\n      <h2>Exp\u00e9diteur<\/h2>\n      <p><strong>YANIGAV<\/strong><\/p>\n      <p>De la part de <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}<\/strong> ({{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }})<\/p>\n      <div class=\"kvs\">\n        <div><span class=\"pill\">T\u00e9l<\/span> {{ managedBy is defined and managedBy.phone is defined and managedBy.phone ? managedBy.phone : '\u2014' }}<\/div>\n        {% if tel_portable %}\n          <div><span class=\"pill\">Port<\/span> {{ tel_portable }}<\/div>\n        {% endif %}\n        <div><span class=\"pill\">Email<\/span>\n          {% if managedBy is defined and managedBy.email is defined and managedBy.email %}\n            <a href=\"mailto:{{ managedBy.email }}\">{{ managedBy.email }}<\/a>\n          {% else %}\u2014{% endif %}\n        <\/div>\n      <\/div>\n    <\/div>\n    <div class=\"card\">\n      <h2>Destinataire<\/h2>\n      <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}<\/strong><\/p>\n      {% if comp and comp.name is defined and comp.name %}<p><strong>{{ comp.name }}<\/strong><\/p>{% endif %}\n      {% if a and (a.postalCode is defined or a.city is defined) %}<p class=\"muted\">{{ a.postalCode|default('') }} {{ a.city|default('') }}<\/p>{% endif %}\n    <\/div>\n  <\/div>\n\n  <!-- INTRO -->\n  <div class=\"section\">\n    <div class=\"card\">\n      <h1>Proposition commerciale<\/h1>\n      <p>{% if c and c.civility is defined and c.civility %}{{ c.civility }},{% else %}Madame, Monsieur,{% endif %}<\/p>\n      <p>Nous vous remercions de l\u2019int\u00e9r\u00eat que vous portez \u00e0 la marque YANIGAV et \u00e0 ses produits. Suite \u00e0 votre r\u00e9cent appel t\u00e9l\u00e9phonique, voici notre proposition pour un <strong>{{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}<\/strong> correspondant \u00e0 votre demande.<\/p>\n      {% if quote.priceListRef is defined and quote.priceListRef %}\n        <p class=\"muted\">{{ quote.priceListRef }}<\/p>\n      {% else %}\n        <p class=\"muted\">Tarif \u2014 {{ (quote.createdAt|default('now'))|date('Y') }}<\/p>\n      {% endif %}\n    <\/div>\n  <\/div>\n\n  <!-- OFFRE PRINCIPALE -->\n  <div class=\"section\">\n    <div class=\"card\">\n      <h2>Offre principale<\/h2>\n      <table>\n        <thead>\n          <tr>\n            <th>D\u00e9signation<\/th>\n            <th>R\u00e9f\u00e9rence<\/th>\n            <th>Prix unitaire HT<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody>\n          {% set pu = (mainLine and mainLine.unitPriceExclVat is defined) ? mainLine.unitPriceExclVat : (total_ht_before_discount > 0 ? total_ht_before_discount : 0) %}\n          <tr>\n            <td>{{ (mainLine and mainLine.name is defined and mainLine.name) ? mainLine.name : quote.name }}<\/td>\n            <td>{{ (mainLine and mainLine.reference is defined and mainLine.reference) ? mainLine.reference : '\u2014' }}<\/td>\n            <td>{{ pu|number_format(0, ',', ' ') }} \u20ac<\/td>\n          <\/tr>\n        <\/tbody>\n      <\/table>\n      {% set note = 'Cin\u00e9matique unique sur le march\u00e9 \u2014 un v\u00e9ritable atout dans les terrains compliqu\u00e9s.' %}\n      <p class=\"note\" style=\"margin-top:.75rem\">{{ note }}<\/p>\n    <\/div>\n  <\/div>\n\n  {# ==== DESCRIPTION \/ \u00c9QUIPEMENT \/ FORMATION \/ OPTIONS ==== #}\n  {% set description = (mainLine and mainLine.description is defined and mainLine.description) ? mainLine.description : '' %}\n  {% set description = description|replace({'\u2022':'\\n',';':'\\n'}) %}\n  {% set descList = description|split('\\n') %}\n\n  <div class=\"section grid-2\">\n    <div class=\"card\">\n      <h2>Points forts<\/h2>\n      {% set hasPoint = false %}\n      <ul class=\"cols-3\">\n        {% for item in descList %}\n          {% set t = item|trim %}\n          {% if t != '' %}\n            {% set hasPoint = true %}\n            <li>{{ t }}<\/li>\n          {% endif %}\n        {% endfor %}\n      <\/ul>\n      {% if not hasPoint %}\n        <p class=\"muted\">Aucun d\u00e9tail technique renseign\u00e9 pour cet article.<\/p>\n      {% endif %}\n    <\/div>\n\n    <div class=\"card\">\n      <h2>\u00c9quipement de s\u00e9rie<\/h2>\n      {% set printedEquip = false %}\n      {# 1) Liste explicite mainLine.features si fournie #}\n      {% if mainLine and mainLine.features is defined and mainLine.features %}\n        <ul>\n          {% for f in mainLine.features %}\n            <li>{{ f }}<\/li>\n            {% set printedEquip = true %}\n          {% endfor %}\n        <\/ul>\n      {% endif %}\n\n      {# 2) Sinon, tentative d\u2019extraction depuis descList avec mots-cl\u00e9s #}\n      {% if not printedEquip %}\n        {% set equipList = [] %}\n        {% for item in descList %}\n          {% set t = item|trim %}\n          {% if t matches '\/(\u00e9quipement|equipement|de s\u00e9rie|serie)\/i' %}\n            {% set equipList = equipList|merge([t]) %}\n          {% endif %}\n        {% endfor %}\n        {% if equipList %}\n          <ul>\n            {% for f in equipList %}<li>{{ f }}<\/li>{% endfor %}\n          <\/ul>\n          {% set printedEquip = true %}\n        {% endif %}\n      {% endif %}\n\n      {% if not printedEquip %}\n        <p class=\"muted\">Aucun \u00e9quipement de s\u00e9rie sp\u00e9cifi\u00e9.<\/p>\n      {% endif %}\n\n      {% if formationLine %}\n        <h2 style=\"margin-top:1rem\">Formation \/ Mise en route<\/h2>\n        <p><strong>{{ formationLine.name|default('Formation \/ Mise en route') }}<\/strong> \u2013 Prix net :\n          {{ (formationLine.totalExclVat|default(formationLine.unitPriceExclVat|default(0)))|number_format(0, ',', ' ') }} \u20ac HT<\/p>\n        {% if formationLine.description is defined and formationLine.description %}<p class=\"muted\">{{ formationLine.description }}<\/p>{% endif %}\n      {% endif %}\n\n      {% if options %}\n        <h2 style=\"margin-top:1rem\">\u00c9quipements recommand\u00e9s<\/h2>\n        <ul>\n          {% for opt in options %}\n            {% set q = opt.quantity|default(1) %}\n            {% set puo = opt.unitPriceExclVat|default(0) %}\n            {% set rem = opt.discountPercent|default(0) %}\n            {% set opt_total = opt.totalExclVat|default(q * puo * (1 - (rem \/ 100))) %}\n            <li>{{ opt.name }} \u2014 {{ opt_total|number_format(0, ',', ' ') }} \u20ac HT<\/li>\n          {% endfor %}\n        <\/ul>\n      {% endif %}\n    <\/div>\n  <\/div>\n\n  <!-- CONDITIONS COMMERCIALES -->\n  <div class=\"section\">\n    <div class=\"card\">\n      <h2>Conditions commerciales<\/h2>\n      <ul>\n        {% if quote.expiredAt is defined and quote.expiredAt %}<li>Validit\u00e9 de l\u2019offre : 1 mois (jusqu\u2019au {{ quote.expiredAt|date('d\/m\/Y') }})<\/li>{% else %}<li>Validit\u00e9 de l\u2019offre : 1 mois<\/li>{% endif %}\n        {% if discount_value > 0 %}<li>Remise de service : {{ discount_percent|round(0, 'floor') }} %<\/li>{% endif %}\n        {% if quote.orderContext is defined and quote.orderContext %}<li>{{ quote.orderContext }}<\/li>{% endif %}\n        <li>R\u00e8glement {{ quote.paymentMode|default('30 jours nets par LCR') }}<\/li>\n        <li>D\u00e9lai : {{ quote.leadTime|default('2 \u00e0 3 mois apr\u00e8s commande') }}<\/li>\n        {% if quote.shippingFeesHt is defined %}\n          {% if quote.shippingFeesHt == 0 %}<li>Port franco<\/li>\n          {% elseif quote.shippingFeesHt > 0 %}<li>Frais de port : {{ quote.shippingFeesHt|number_format(2, ',', ' ') }} \u20ac HT<\/li>\n          {% else %}<li>Port : {{ quote.shippingMode|default('selon conditions') }}<\/li>\n          {% endif %}\n        {% else %}\n          <li>Port : {{ quote.shippingMode|default('selon conditions') }}<\/li>\n        {% endif %}\n        {% if quote.customerRef is defined and quote.customerRef %}<li>R\u00e9f. client : {{ quote.customerRef }}<\/li>{% endif %}\n      <\/ul>\n    <\/div>\n  <\/div>\n\n  <!-- SIGNATURES -->\n  <div class=\"section grid-2\">\n    <div class=\"card\">\n      <h2>Signataires<\/h2>\n      <p>\n        <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}<\/strong>\n        \u2013 {{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }}\n        {% if tel_portable %} \u2013 {{ tel_portable }}{% endif %}\n      <\/p>\n      <div class=\"signature\">Signature exp\u00e9diteur<\/div>\n    <\/div>\n    <div class=\"card\">\n      <h2>Bon pour accord<\/h2>\n      <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}<\/strong>{% if comp and comp.name is defined and comp.name %} \u2013 {{ comp.name }}{% endif %}<\/p>\n      <div class=\"signature\">Cachet et signature<\/div>\n    <\/div>\n  <\/div>\n\n  <!-- PIED -->\n  <footer>\n    YANIGAV \u2013 Enfonce-pieux \u2022 Aff\u00fbte-piquet \u2022 Fendeuse de b\u00fbche \u2014 RCS ROANNE B 403 872 724 \u2014 SIRET 403 872 724 00014 \u2014 APE 4661Z \u2014 TVA FR114038727224\n  <\/footer>\n<\/div>\n\n{# PAGE 2 : CGV (optionnelle) #}\n{% if cgv is defined or quote.cgvText is defined %}\n  <div style=\"page-break-before:always;\"><\/div>\n  <div class=\"page\">\n    <div class=\"section\">\n      <div class=\"card\">\n        <h2>Conditions G\u00e9n\u00e9rales de Vente<\/h2>\n        <div class=\"note\" style=\"white-space:pre-wrap\">\n          {{ cgv|default(quote.cgvText)|raw }}\n        <\/div>\n      <\/div>\n    <\/div>\n    <footer>\n      Document g\u00e9n\u00e9r\u00e9 automatiquement \u2014 valable sous r\u00e9serve des conditions pr\u00e9cis\u00e9es ci-dessus.\n    <\/footer>\n  <\/div>\n{% endif %}\n<\/body>\n<\/html>\n"
}

Raw

{"id":"f47ef469dac34bc29180feb40a25724c","customerId":"customer_121","name":"Test","content":"<!doctype html>\n<html lang=\"fr\">\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Devis – YANIGAV – {{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}</title>\n<style>\n  :root { --primary:#0f172a; --muted:#475569; --border:#e2e8f0; --bg:#f8fafc; }\n  html, body { margin:0; padding:0; background:var(--bg); color:#0b1220; font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,\"Apple Color Emoji\",\"Segoe UI Emoji\"; }\n  .page { max-width:900px; margin:2rem auto; background:#fff; border:1px solid var(--border); border-radius:12px; overflow:hidden; box-shadow:0 10px 30px rgba(0,0,0,.04); }\n  header { padding:1.25rem 1.5rem; background:#fff; border-bottom:1px solid var(--border); display:flex; gap:1rem; align-items:center; }\n  .brand { font-weight:700; letter-spacing:.2px; font-size:1rem; color:var(--primary); }\n  .sub { color:var(--muted); font-size:.9rem; }\n  .grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:1rem; }\n  .section { padding:1.25rem 1.5rem; }\n  h1 { font-size:1.4rem; margin:.25rem 0 .5rem; letter-spacing:.2px; }\n  h2 { font-size:1.1rem; margin:0 0 .75rem; color:var(--primary); }\n  p { margin:.25rem 0; line-height:1.55; }\n  .card { background:#fff; border:1px solid var(--border); border-radius:10px; padding:1rem; }\n  .muted { color:var(--muted); }\n  .kvs { display:grid; grid-template-columns:1fr 1fr; gap:.5rem 1rem; font-size:.95rem; }\n  .kvs div { display:flex; align-items:center; gap:.5rem; }\n  .pill { font-size:.8rem; padding:.15rem .5rem; border:1px solid var(--border); border-radius:999px; background:#f1f5f9; }\n  table { width:100%; border-collapse:collapse; }\n  th, td { border:1px solid var(--border); padding:.6rem .5rem; text-align:left; vertical-align:top; }\n  thead th { background:#f1f5f9; }\n  tfoot td { font-weight:600; }\n  .note { font-size:.92rem; background:#f8fafc; border:1px dashed var(--border); padding:.75rem; border-radius:8px; }\n  .cols-3 { columns:2; column-gap:1rem; }\n  .signature { height:80px; border:1px dashed var(--border); border-radius:10px; display:flex; align-items:center; justify-content:center; color:var(--muted); }\n  footer { padding:1rem 1.5rem; border-top:1px solid var(--border); color:var(--muted); font-size:.9rem; background:#fff; }\n</style>\n\n<body>\n<div class=\"page\">\n\n  {# ==== Raccourcis / sécurisation des accès ==== #}\n  {% set c = (quote.prospect is defined and quote.prospect.contact is defined) ? quote.prospect.contact : null %}\n  {% set a = (c and c.mainAddress is defined) ? c.mainAddress : null %}\n  {% set comp = (quote.prospect is defined and quote.prospect.company is defined) ? quote.prospect.company : null %}\n  {% set lines = quote.quoteLines|default([]) %}\n\n  {# Portable du commercial : on cherche dans un ordre sûr #}\n  {% set tel_portable = '' %}\n  {% if managedBy is defined %}\n    {% if managedBy.phoneNumber is defined and managedBy.phoneNumber %}{% set tel_portable = managedBy.phoneNumber %}\n    {% elseif managedBy.mobilePhone is defined and managedBy.mobilePhone %}{% set tel_portable = managedBy.mobilePhone %}\n    {% elseif managedBy.phone is defined and managedBy.phone %}{% set tel_portable = managedBy.phone %}\n    {% endif %}\n  {% endif %}\n\n  {# ==== Totaux/remise/TVA - robustes ==== #}\n  {% set total_ht_before_discount = 0 %}\n  {% for l in lines %}\n    {% set q = l.quantity|default(1) %}\n    {% set pu = l.unitPriceExclVat|default(0) %}\n    {% set total_ht_before_discount = total_ht_before_discount + (q * pu) %}\n  {% endfor %}\n  {% if total_ht_before_discount == 0 %}\n    {% set total_ht_before_discount = quote.totalExcludingVat|default(0) %}\n  {% endif %}\n  {% set total_ht = quote.totalExcludingVat|default(total_ht_before_discount) %}\n  {% set discount_value = total_ht_before_discount - total_ht %}\n  {% set discount_percent = total_ht_before_discount > 0 ? (discount_value / total_ht_before_discount * 100) : 0 %}\n  {% set vat_total = 0 %}\n  {% for l in lines %}\n    {% set vat_total = vat_total + (l.vatAmount|default(0)) %}\n  {% endfor %}\n\n  {# ==== Sélection ligne principale / formation / options (sans filtres avancés) ==== #}\n  {% set first = (lines[0] is defined) ? lines[0] : null %}\n  {% set mainLine = null %}\n  {% set formationLine = null %}\n  {% set options = [] %}\n  {% for l in lines %}\n    {% set ref = l.reference|default('')|lower %}\n    {% set isOpt = l.isOptional is defined and l.isOptional %}\n    {% if mainLine is null and not isOpt and ('formation' not in ref) %}\n      {% set mainLine = l %}\n    {% endif %}\n    {% if formationLine is null and ('formation' in ref) %}\n      {% set formationLine = l %}\n    {% endif %}\n    {% if isOpt %}\n      {% set options = options|merge([l]) %}\n    {% endif %}\n  {% endfor %}\n  {% if mainLine is null %}{% set mainLine = first %}{% endif %}\n\n  <!-- HEADER -->\n  <header>\n    <div style=\"flex:1\">\n      <div class=\"brand\">YANIGAV – Enfonce-pieux • Affûte-piquet • Fendeuse de bûche</div>\n      <div class=\"sub\">RCS ROANNE B 403 872 724 • SIRET 403 872 724 00014 • APE 4661Z • TVA FR114038727224</div>\n    </div>\n    <div class=\"pill\">{{ (quote.createdAt|default('now'))|date('d F Y') }}</div>\n  </header>\n\n  <!-- COORDONNÉES -->\n  <div class=\"section grid-2\">\n    <div class=\"card\">\n      <h2>Expéditeur</h2>\n      <p><strong>YANIGAV</strong></p>\n      <p>De la part de <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}</strong> ({{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }})</p>\n      <div class=\"kvs\">\n        <div><span class=\"pill\">Tél</span> {{ managedBy is defined and managedBy.phone is defined and managedBy.phone ? managedBy.phone : '—' }}</div>\n        {% if tel_portable %}\n          <div><span class=\"pill\">Port</span> {{ tel_portable }}</div>\n        {% endif %}\n        <div><span class=\"pill\">Email</span>\n          {% if managedBy is defined and managedBy.email is defined and managedBy.email %}\n            <a href=\"mailto:{{ managedBy.email }}\">{{ managedBy.email }}</a>\n          {% else %}—{% endif %}\n        </div>\n      </div>\n    </div>\n    <div class=\"card\">\n      <h2>Destinataire</h2>\n      <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}</strong></p>\n      {% if comp and comp.name is defined and comp.name %}<p><strong>{{ comp.name }}</strong></p>{% endif %}\n      {% if a and (a.postalCode is defined or a.city is defined) %}<p class=\"muted\">{{ a.postalCode|default('') }} {{ a.city|default('') }}</p>{% endif %}\n    </div>\n  </div>\n\n  <!-- INTRO -->\n  <div class=\"section\">\n    <div class=\"card\">\n      <h1>Proposition commerciale</h1>\n      <p>{% if c and c.civility is defined and c.civility %}{{ c.civility }},{% else %}Madame, Monsieur,{% endif %}</p>\n      <p>Nous vous remercions de l’intérêt que vous portez à la marque YANIGAV et à ses produits. Suite à votre récent appel téléphonique, voici notre proposition pour un <strong>{{ quote.name|default('Enfonce-pieux HYDROCHOC HPG 790') }}</strong> correspondant à votre demande.</p>\n      {% if quote.priceListRef is defined and quote.priceListRef %}\n        <p class=\"muted\">{{ quote.priceListRef }}</p>\n      {% else %}\n        <p class=\"muted\">Tarif — {{ (quote.createdAt|default('now'))|date('Y') }}</p>\n      {% endif %}\n    </div>\n  </div>\n\n  <!-- OFFRE PRINCIPALE -->\n  <div class=\"section\">\n    <div class=\"card\">\n      <h2>Offre principale</h2>\n      <table>\n        <thead>\n          <tr>\n            <th>Désignation</th>\n            <th>Référence</th>\n            <th>Prix unitaire HT</th>\n          </tr>\n        </thead>\n        <tbody>\n          {% set pu = (mainLine and mainLine.unitPriceExclVat is defined) ? mainLine.unitPriceExclVat : (total_ht_before_discount > 0 ? total_ht_before_discount : 0) %}\n          <tr>\n            <td>{{ (mainLine and mainLine.name is defined and mainLine.name) ? mainLine.name : quote.name }}</td>\n            <td>{{ (mainLine and mainLine.reference is defined and mainLine.reference) ? mainLine.reference : '—' }}</td>\n            <td>{{ pu|number_format(0, ',', ' ') }} €</td>\n          </tr>\n        </tbody>\n      </table>\n      {% set note = 'Cinématique unique sur le marché — un véritable atout dans les terrains compliqués.' %}\n      <p class=\"note\" style=\"margin-top:.75rem\">{{ note }}</p>\n    </div>\n  </div>\n\n  {# ==== DESCRIPTION / ÉQUIPEMENT / FORMATION / OPTIONS ==== #}\n  {% set description = (mainLine and mainLine.description is defined and mainLine.description) ? mainLine.description : '' %}\n  {% set description = description|replace({'•':'\\n',';':'\\n'}) %}\n  {% set descList = description|split('\\n') %}\n\n  <div class=\"section grid-2\">\n    <div class=\"card\">\n      <h2>Points forts</h2>\n      {% set hasPoint = false %}\n      <ul class=\"cols-3\">\n        {% for item in descList %}\n          {% set t = item|trim %}\n          {% if t != '' %}\n            {% set hasPoint = true %}\n            <li>{{ t }}</li>\n          {% endif %}\n        {% endfor %}\n      </ul>\n      {% if not hasPoint %}\n        <p class=\"muted\">Aucun détail technique renseigné pour cet article.</p>\n      {% endif %}\n    </div>\n\n    <div class=\"card\">\n      <h2>Équipement de série</h2>\n      {% set printedEquip = false %}\n      {# 1) Liste explicite mainLine.features si fournie #}\n      {% if mainLine and mainLine.features is defined and mainLine.features %}\n        <ul>\n          {% for f in mainLine.features %}\n            <li>{{ f }}</li>\n            {% set printedEquip = true %}\n          {% endfor %}\n        </ul>\n      {% endif %}\n\n      {# 2) Sinon, tentative d’extraction depuis descList avec mots-clés #}\n      {% if not printedEquip %}\n        {% set equipList = [] %}\n        {% for item in descList %}\n          {% set t = item|trim %}\n          {% if t matches '/(équipement|equipement|de série|serie)/i' %}\n            {% set equipList = equipList|merge([t]) %}\n          {% endif %}\n        {% endfor %}\n        {% if equipList %}\n          <ul>\n            {% for f in equipList %}<li>{{ f }}</li>{% endfor %}\n          </ul>\n          {% set printedEquip = true %}\n        {% endif %}\n      {% endif %}\n\n      {% if not printedEquip %}\n        <p class=\"muted\">Aucun équipement de série spécifié.</p>\n      {% endif %}\n\n      {% if formationLine %}\n        <h2 style=\"margin-top:1rem\">Formation / Mise en route</h2>\n        <p><strong>{{ formationLine.name|default('Formation / Mise en route') }}</strong> – Prix net :\n          {{ (formationLine.totalExclVat|default(formationLine.unitPriceExclVat|default(0)))|number_format(0, ',', ' ') }} € HT</p>\n        {% if formationLine.description is defined and formationLine.description %}<p class=\"muted\">{{ formationLine.description }}</p>{% endif %}\n      {% endif %}\n\n      {% if options %}\n        <h2 style=\"margin-top:1rem\">Équipements recommandés</h2>\n        <ul>\n          {% for opt in options %}\n            {% set q = opt.quantity|default(1) %}\n            {% set puo = opt.unitPriceExclVat|default(0) %}\n            {% set rem = opt.discountPercent|default(0) %}\n            {% set opt_total = opt.totalExclVat|default(q * puo * (1 - (rem / 100))) %}\n            <li>{{ opt.name }} — {{ opt_total|number_format(0, ',', ' ') }} € HT</li>\n          {% endfor %}\n        </ul>\n      {% endif %}\n    </div>\n  </div>\n\n  <!-- CONDITIONS COMMERCIALES -->\n  <div class=\"section\">\n    <div class=\"card\">\n      <h2>Conditions commerciales</h2>\n      <ul>\n        {% if quote.expiredAt is defined and quote.expiredAt %}<li>Validité de l’offre : 1 mois (jusqu’au {{ quote.expiredAt|date('d/m/Y') }})</li>{% else %}<li>Validité de l’offre : 1 mois</li>{% endif %}\n        {% if discount_value > 0 %}<li>Remise de service : {{ discount_percent|round(0, 'floor') }} %</li>{% endif %}\n        {% if quote.orderContext is defined and quote.orderContext %}<li>{{ quote.orderContext }}</li>{% endif %}\n        <li>Règlement {{ quote.paymentMode|default('30 jours nets par LCR') }}</li>\n        <li>Délai : {{ quote.leadTime|default('2 à 3 mois après commande') }}</li>\n        {% if quote.shippingFeesHt is defined %}\n          {% if quote.shippingFeesHt == 0 %}<li>Port franco</li>\n          {% elseif quote.shippingFeesHt > 0 %}<li>Frais de port : {{ quote.shippingFeesHt|number_format(2, ',', ' ') }} € HT</li>\n          {% else %}<li>Port : {{ quote.shippingMode|default('selon conditions') }}</li>\n          {% endif %}\n        {% else %}\n          <li>Port : {{ quote.shippingMode|default('selon conditions') }}</li>\n        {% endif %}\n        {% if quote.customerRef is defined and quote.customerRef %}<li>Réf. client : {{ quote.customerRef }}</li>{% endif %}\n      </ul>\n    </div>\n  </div>\n\n  <!-- SIGNATURES -->\n  <div class=\"section grid-2\">\n    <div class=\"card\">\n      <h2>Signataires</h2>\n      <p>\n        <strong>{{ managedBy is defined and managedBy.fullname is defined ? managedBy.fullname : (quote.managedByRealName|default('')) }}</strong>\n        – {{ managedBy is defined and managedBy.role is defined and managedBy.role ? managedBy.role : 'Resp. Commercial' }}\n        {% if tel_portable %} – {{ tel_portable }}{% endif %}\n      </p>\n      <div class=\"signature\">Signature expéditeur</div>\n    </div>\n    <div class=\"card\">\n      <h2>Bon pour accord</h2>\n      <p><strong>{{ quote.contactIdRealName|default(c and (c.fullname is defined and c.fullname ? c.fullname : (c.name|default('')))) }}</strong>{% if comp and comp.name is defined and comp.name %} – {{ comp.name }}{% endif %}</p>\n      <div class=\"signature\">Cachet et signature</div>\n    </div>\n  </div>\n\n  <!-- PIED -->\n  <footer>\n    YANIGAV – Enfonce-pieux • Affûte-piquet • Fendeuse de bûche — RCS ROANNE B 403 872 724 — SIRET 403 872 724 00014 — APE 4661Z — TVA FR114038727224\n  </footer>\n</div>\n\n{# PAGE 2 : CGV (optionnelle) #}\n{% if cgv is defined or quote.cgvText is defined %}\n  <div style=\"page-break-before:always;\"></div>\n  <div class=\"page\">\n    <div class=\"section\">\n      <div class=\"card\">\n        <h2>Conditions Générales de Vente</h2>\n        <div class=\"note\" style=\"white-space:pre-wrap\">\n          {{ cgv|default(quote.cgvText)|raw }}\n        </div>\n      </div>\n    </div>\n    <footer>\n      Document généré automatiquement — valable sous réserve des conditions précisées ci-dessus.\n    </footer>\n  </div>\n{% endif %}\n</body>\n</html>\n"}

Response

Response Headers

Header Value
access-control-allow-origin
"https://dev.pol-crm.com"
access-control-expose-headers
"x-debug-token, sentry-trace, baggage, retry-after"
cache-control
"private, must-revalidate"
content-location
"/api/templates/f47ef469dac34bc29180feb40a25724c"
content-type
"application/ld+json; charset=utf-8"
date
"Sun, 19 Oct 2025 22:39:10 GMT"
expires
-1
link
"<https://dev.app.pol-crm.com/api/docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation""
pragma
"no-cache"
vary
"Accept"
x-content-type-options
"nosniff"
x-debug-token
"a91501"
x-frame-options
"deny"

Cookies

Request Cookies

No request cookies

Response Cookies

No response cookies

Session

Session Metadata

No session metadata

Session Attributes

No session attributes

Flashes

Flashes

No flash messages were created.

Server Parameters

Server Parameters

Defined in .env

Key Value
API_BUSINESS_HOST
"http://dev.pol-api-business.pol-crm.com"
API_CRM_HOST
"http://dev.pol-api-crm.pol-crm.com"
API_GED_HOST
"http://dev.pol-api-ged.pol-crm.com"
API_LIVEO
"https://webservice.centrex.liveo.fr/ws/"
API_MIDDLEWARE_HOST
"https://pol-middleware"
API_NOTIFY_HOST
"http://dev.pol-api-notify.pol-crm.com"
API_PARAM_HOST
"http://dev.pol-api-param.pol-crm.com"
API_POL_MAILING
"http://mailing.sfi.fr/webservices"
API_POL_MAILING_V2
"https://dev.mailing.pol-crm.com/webservices"
API_SEARCH_HOST
"http://dev.pol-api-search.pol-crm.com"
API_SERVICE_PLENETUDE_HOST
"http://dev.plenetude.pol-crm.com"
API_USER_HOST
"http://dev.pol-api-user.pol-crm.com"
APP_ENV
"dev"
APP_SECRET
"61ff627c8e96e9ac55fc1926e4878f2e"
BDD_API_BUSINESS
"dev_pol_core"
BDD_API_CRM
"dev_pol_core"
BDD_API_GED
"dev_pol_core"
BDD_API_NOTIFY
"dev_pol_core"
BDD_API_PARAM
"dev_pol_core"
BDD_API_SEARCH
"dev_pol_core"
BDD_API_USER
"dev_pol_core"
BDD_MIDDLEWARE
"dev_pol_core"
BDD_SERVICE_PLENETUDE
"dev_pol_core"
BEGIN_DATE
"2024-01-01"
CORS_ALLOW_ORIGIN
"^https?://pol-(crm|prospect).localhost(:[0-9]+)?$"
DATABASE_URL
"mysql://dev_pol_core:VTgooWkhcjebxLPy8E2ycoTjytrULgNQ@127.0.0.1:3306/dev_pol_core"
END_DATE
"2025-01-31"
FRONT_URL
"https://pol-crm.localhost"
FTP_INTRANET_SFI_HOST
"preprod.intranet.sfimultimedia.com"
FTP_INTRANET_SFI_PASSWORD
"iAw453e?iAw453e?"
FTP_INTRANET_SFI_USER
"intranetpreprod"
GED_ABSOLUTE_DIRECTORY_PATH
"/var/www/pol-api-ged/application/data/ged"
GEONAME_API_TOKEN
"ceciestuntestpourSfi/0000"
IMPORT_ONDUPACK_PATH_FILE
"/httpdocs/app-pol-crm/dev/current/application/data/import_ondupack"
INSEE_API_SIRENE_KEY
"09afd2bf-050b-465e-afd2-bf050b865e20"
IS_MAINTENANCE
"false"
JWT_PASSPHRASE
"7de1072d7a8fcab69679c1892deb39a7"
JWT_PUBLIC_KEY
"%kernel.project_dir%/config/jwt/public.pem"
JWT_SECRET_KEY
"%kernel.project_dir%/config/jwt/private.pem"
JWT_WHITELIST_PATH
"%kernel.project_dir%/var/tokens"
MAILER_URL
"smtp://127.0.0.1:1025"
MAILING_ENV_USER
"depot_mailing_dev-xv42"
MESSENGER_TRANSPORT_DSN_MIDDLEWARE
"amqp://sfiweb:sfiwweb0000@127.0.0.1:5672/%2f/dev_middleware_messages"
MESSENGER_TRANSPORT_DSN_NOTIFY
"amqp://sfiweb:sfiwweb0000@127.0.0.1:5672/%2f/dev_notify_messages"
MESSENGER_TRANSPORT_DSN_SEARCH
"amqp://sfiweb:sfiwweb0000@127.0.0.1:5672/%2f/dev_messages"
MICROSOFT_GRAPH_API_CLIENT_ID
"3b7f02c4-aa14-4e54-a2b9-2ee1d5d17f8a"
MICROSOFT_GRAPH_API_CLIENT_SECRET
"FID8Q~zfFRP~Gw-85LpaCj0VqrrRr__HMGpI-drP"
MICROSOFT_GRAPH_API_NOTIFICATION_URL
"https://dev.app.pol-crm.com/api/microsoft-graph/outlook-subscription-configuration"
MICROSOFT_GRAPH_API_REDIRECT_URI
"https://dev.pol-crm.com/microsoft-graph"
MICROSOFT_GRAPH_API_SUBSCRIPTION_EXPIRED_AT
"+2 days"
MICROSOFT_GRAPH_API_TOKEN_LIFETIME
"+2 days"
MODULE_MICROSOFT_GRAPH_SECRET
"jqsFP7MjEx1FBe1138D3"
MONOLOG_APPLICATION_ENVIRONMENT
"dev"
MONOLOG_APPLICATION_NAME
"pol-middleware"
MONOLOG_SUBJECT
"[DEV][%level_name%] POL-MIDDLEWARE - %message%"
MONOLOG_TO_EMAIL
"polv3.log@sfi.fr"
MYSQL_DATABASE
"dev_pol_core"
MYSQL_HOST
"127.0.0.1"
MYSQL_PASSWORD
"VTgooWkhcjebxLPy8E2ycoTjytrULgNQ"
MYSQL_PORT
"3306"
MYSQL_USER
"dev_pol_core"
PREFIX_CUSTOMER_NAME_MAILING
"[DEV]"
REDIS_ENABLE_V4
"true"
REDIS_PREFIX
"dev"
REDIS_URL
"redis://127.0.0.1:6379"
SECURITY_ENABLE_TOKEN_WHITELIST
"0"
SENTRY_DSN
"https://99729cc06c8241e3b07e3f6ae9b6feec@sentry.sfimultimedia.com/9"
SENTRY_ENVIRONMENT
"dev"
SENTRY_PERFORMANCE_SAMPLE_RATE
"1.0"
SFI_MAILING_URL
"https://mailing.sfi.fr/webservices/recupererContactPol.php"
SFI_SSO_FORCE_CREDENTIALS
"87;707"
SFI_SSO_MAILING_HOST
"https://mailing.sfi.fr/webservices/sso.php"
SYSTEMUSER_0662705af65c48908b017d8fb0724bac_PASSWORD
"7G4k4WhQZDkkB5IGLRPcdfik5s58gf58f2g5s6W6T6BXfbYj2H_customer_newco"
SYSTEMUSER_0662705af65c48908b017d8fb0724bac_USERNAME
"system_0662705af65c48908b017d8fb0724bac"
SYSTEMUSER_customer_124_PASSWORD
"A6uraa5HQ87hY*unfx3$mr158!d7i*TX_customer_124"
SYSTEMUSER_customer_124_USERNAME
"system_customer_124"
SYSTEMUSER_customer_65_PASSWORD
"uBRJV4pUKP1wRk4iULwMnty93MPr4qr3Sod8jFlfJwZdURZB_customer_65"
SYSTEMUSER_customer_65_USERNAME
"system_customer_65"
SYSTEMUSER_customer_66_PASSWORD
"7G4k4WhQZDkkB5IGLRPcdfik3tOZfL4PVfs6W6T6BXfbYj2H_customer_66"
SYSTEMUSER_customer_66_USERNAME
"system_customer_66"
SYSTEMUSER_customer_98_PASSWORD
"wWZJwEgYjqLdPx77B1o9GR7r6r4Fvug82fmALJLvQCBjWD4G_customer_98"
SYSTEMUSER_customer_98_USERNAME
"system_customer_98"
SYSTEMUSER_e8919dbc01f34f79ab22b9c434f114eb_PASSWORD
"TPB5ccJCl4ZL5jurkpedelfwdEiYRt4g30xYM82"
SYSTEMUSER_e8919dbc01f34f79ab22b9c434f114eb_USERNAME
"system_e8919dbc01f34f79ab22b9c434f114eb"

Defined as regular env variables

Key Value
APP_DEBUG
"1"
CONTENT_LENGTH
"15077"
CONTENT_TYPE
"application/json"
CONTEXT_DOCUMENT_ROOT
"/var/www/vhosts/app.pol-crm.com/httpdocs/app-pol-crm/dev/current/application/public"
CONTEXT_PREFIX
""
DOCUMENT_ROOT
"/var/www/vhosts/app.pol-crm.com/httpdocs/app-pol-crm/dev/current/application/public"
FCGI_ROLE
"RESPONDER"
GATEWAY_INTERFACE
"CGI/1.1"
HOME
"/var/www/vhosts/app.pol-crm.com"
HTTPS
"on"
HTTP_ACCEPT
"application/ld+json"
HTTP_ACCEPT_ENCODING
"gzip, deflate, br, zstd"
HTTP_ACCEPT_LANGUAGE
"fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7"
HTTP_CONNECTION
"close"
HTTP_HOST
"dev.app.pol-crm.com"
HTTP_ORIGIN
"https://dev.pol-crm.com"
HTTP_PRIORITY
"u=1, i"
HTTP_REFERER
"https://dev.pol-crm.com/"
HTTP_SEC_CH_UA
""Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140""
HTTP_SEC_CH_UA_MOBILE
"?0"
HTTP_SEC_CH_UA_PLATFORM
""Windows""
HTTP_SEC_FETCH_DEST
"empty"
HTTP_SEC_FETCH_MODE
"cors"
HTTP_SEC_FETCH_SITE
"same-site"
HTTP_USER_AGENT
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36"
HTTP_X_ACCEL_INTERNAL
"/internal-nginx-static-location"
HTTP_X_POL_AUTH
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NjA5MTI0NDEsImV4cCI6MTc2MDkxNjA0MSwicm9sZXMiOlsiUk9MRV9VU0VSIiwiUk9MRV9TVVBFUkFETUlOIiwiUk9MRV9BRE1JTiIsIlJPTEVfTU9EVUxFX1BST0RVQ1QiLCJST0xFX01PRFVMRV9QUk9EVUNUX0NVU1RPTUlaRSIsIlJPTEVfTU9EVUxFX1FVT1RFX0xJTkUiLCJQUk9TUEVDVF9TSE9XIiwiUFJPU1BFQ1RfQ1VEIiwiQ09OVEFDVF9DVUQiLCJDT05UQUNUX1NIT1ciLCJUQVNLX1NIT1ciLCJUQVNLX0NVRCIsIlFVT1RFX1NIT1ciLCJRVU9URV9DVUQiLCJRVU9URV9SRUdFTkVSQVRFX1BSSUNFUyJdLCJsb2dpbiI6ImRlbW95YW5pZ2F2IiwidXNlcl9pZCI6InVzZXJfMTAxMSIsInVzZXJfZXh0ZXJuYWxfaWQiOiIxMDExIiwiZW1haWwiOiJnLXNhdXRyb25Ac2ZpLmZyIiwiY3VzdG9tZXJfaWQiOiJjdXN0b21lcl8xMjEiLCJjdXN0b21lcl9uYW1lIjoiWUFOSUdBViIsImN1c3RvbWVyX2V4dGVybmFsX2lkIjoiMTIxIiwiY3VzdG9tZXJfbWFpbGluZ19pZCI6IjE0NyIsImZpcnN0bmFtZSI6Ikd1aWxsYXVtZSIsImxhc3RuYW1lIjoiU0FVVFJPTiIsImxpdmVvTG9naW4iOm51bGwsImxpdmVvUGFzc3dvcmQiOm51bGwsImhhc0ludHJhbmV0IjpmYWxzZSwibGFuZ3VhZ2UiOiJGUiIsInNlY3Rpb25zX2xlYWRlZCI6W10sInNlY3Rpb25zX21lbWJlcnMiOlsidXNlcl8xMDExIl0sImlzX3NlY3Rpb25zX2FjdGl2YXRlZCI6ZmFsc2UsInJlZnJlc2hfdG9rZW4iOiIifQ.smruhTDO6MF4efpXGiPp4DyZoLSpsUh3ykwBDmscLGtkvlySQlnSFvS1bxozG8T5Y0oGdkijvDiliogWK_zhqLF6FXho-oEscgCbKhvTjdosGLc4QHX0QAtM1LeVpT3BGVz9isHY1J7X0RDnoWA2GdCwCZ-ELXlS7fP08w_Mc5j8GqGhN5XwD70MLfR5ltD75o5BEhCWKMsWsatkGs3bbd7AfjhqoSz7qexpiHj1BRszq-H5QekWiJWgwOLDUJc85rZYaNVbYu75qseEbKfW-kWAxOZhAZCmVfFDQ-qBxSJ1i7KwVasIGTJDTnJn7l8fDqFWF0jGtC4LJzQEOZDjoOrQVaP2szLusNdOeKICnE3GOpY7E2sHIJpbTf8KlRUSm0uKc4t4hgoSRxnCdQGLx4hcTGSGHyITgso7tVs6068piCfp8JttEo5SoXERPiVNl2oeKa7VQAgtUWMzPI-SYX6QfGCjnrYE3JcTufx8xFtvlS4pmeIaLNJs7Y8l21f-A8MB7y-3zOAzriYExuKUOtT9oZ0GRtCWG5oTUyQ2LI4IjzaqBW_ikRfcccdSOZqZxV_FVw1fO9vPg9Lgi9XKAfKtjCLtI9nMboiZsSk9mx5_CAREqtb476hnnUVOfvHCBazVRQo-FWsSSWNLCIe8MtR9pUny0D8hn5qCQ712Axk"
HTTP_X_REAL_IP
"176.174.157.21"
HTTP_X_TRANSACTION_ID
"front:zv9jvbn66i"
PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY
"0"
PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY
"0"
PATH
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
PHP_SELF
"/index.php"
QUERY_STRING
""
REDIRECT_HTTPS
"on"
REDIRECT_PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY
"0"
REDIRECT_PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY
"0"
REDIRECT_SSL_TLS_SNI
"dev.app.pol-crm.com"
REDIRECT_STATUS
"200"
REDIRECT_URL
"/api/templates/f47ef469dac34bc29180feb40a25724c"
REMOTE_ADDR
"176.174.157.21"
REMOTE_PORT
"51304"
REQUEST_METHOD
"PUT"
REQUEST_SCHEME
"https"
REQUEST_TIME
1760913548
REQUEST_TIME_FLOAT
1760913548.9908
REQUEST_URI
"/api/templates/f47ef469dac34bc29180feb40a25724c"
SCRIPT_FILENAME
"/var/www/vhosts/app.pol-crm.com/httpdocs/app-pol-crm/dev/current/application/public/index.php"
SCRIPT_NAME
"/index.php"
SERVER_ADDR
"185.18.171.8"
SERVER_ADMIN
"[no address given]"
SERVER_NAME
"dev.app.pol-crm.com"
SERVER_PORT
"443"
SERVER_PROTOCOL
"HTTP/1.0"
SERVER_SIGNATURE
"<address>Apache Server at dev.app.pol-crm.com Port 443</address>\n"
SERVER_SOFTWARE
"Apache"
SSL_TLS_SNI
"dev.app.pol-crm.com"
SYMFONY_DOTENV_VARS
"APP_ENV,APP_SECRET,BDD_API_BUSINESS,BDD_API_CRM,BDD_API_GED,BDD_API_NOTIFY,BDD_API_PARAM,BDD_API_SEARCH,BDD_API_USER,BDD_MIDDLEWARE,BDD_SERVICE_PLENETUDE,MYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWORD,MYSQL_DATABASE,DATABASE_URL,MAILER_URL,CORS_ALLOW_ORIGIN,JWT_SECRET_KEY,JWT_PUBLIC_KEY,JWT_PASSPHRASE,JWT_WHITELIST_PATH,MONOLOG_SUBJECT,MONOLOG_TO_EMAIL,MONOLOG_APPLICATION_NAME,MONOLOG_APPLICATION_ENVIRONMENT,MESSENGER_TRANSPORT_DSN_SEARCH,MESSENGER_TRANSPORT_DSN_NOTIFY,MESSENGER_TRANSPORT_DSN_MIDDLEWARE,SENTRY_DSN,SENTRY_ENVIRONMENT,SENTRY_PERFORMANCE_SAMPLE_RATE,IS_MAINTENANCE,SECURITY_ENABLE_TOKEN_WHITELIST,REDIS_ENABLE_V4,REDIS_URL,API_BUSINESS_HOST,API_CRM_HOST,API_GED_HOST,API_NOTIFY_HOST,API_PARAM_HOST,API_SEARCH_HOST,API_USER_HOST,API_MIDDLEWARE_HOST,API_SERVICE_PLENETUDE_HOST,API_POL_MAILING,API_POL_MAILING_V2,API_LIVEO,MAILING_ENV_USER,FTP_INTRANET_SFI_HOST,FTP_INTRANET_SFI_USER,FTP_INTRANET_SFI_PASSWORD,SFI_SSO_FORCE_CREDENTIALS,MICROSOFT_GRAPH_API_REDIRECT_URI,MICROSOFT_GRAPH_API_CLIENT_ID,MICROSOFT_GRAPH_API_NOTIFICATION_URL,MICROSOFT_GRAPH_API_CLIENT_SECRET,MICROSOFT_GRAPH_API_SUBSCRIPTION_EXPIRED_AT,MODULE_MICROSOFT_GRAPH_SECRET,INSEE_API_SIRENE_KEY,GEONAME_API_TOKEN,GED_ABSOLUTE_DIRECTORY_PATH,IMPORT_ONDUPACK_PATH_FILE,FRONT_URL,REDIS_PREFIX,SFI_SSO_MAILING_HOST,SFI_MAILING_URL,PREFIX_CUSTOMER_NAME_MAILING,MICROSOFT_GRAPH_API_TOKEN_LIFETIME,SYSTEMUSER_e8919dbc01f34f79ab22b9c434f114eb_USERNAME,SYSTEMUSER_e8919dbc01f34f79ab22b9c434f114eb_PASSWORD,SYSTEMUSER_customer_65_USERNAME,SYSTEMUSER_customer_65_PASSWORD,SYSTEMUSER_customer_66_USERNAME,SYSTEMUSER_customer_66_PASSWORD,SYSTEMUSER_customer_124_USERNAME,SYSTEMUSER_customer_124_PASSWORD,SYSTEMUSER_0662705af65c48908b017d8fb0724bac_USERNAME,SYSTEMUSER_0662705af65c48908b017d8fb0724bac_PASSWORD,SYSTEMUSER_customer_98_USERNAME,SYSTEMUSER_customer_98_PASSWORD,BEGIN_DATE,END_DATE"
USER
"app-pol-crm"
proxy-nokeepalive
"1"