src/CompanyGroupBundle/Resources/views/pages/quotes/quote_print.html.twig line 1

Open in your IDE?
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width,initial-scale=1">
  6. <title>Subscription Quote {{ quote.quoteToken|slice(0,8)|upper }} — HoneyBee ERP</title>
  7. <style>
  8. *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
  9. /* ── Design tokens (Scandinavian — matches home.html.twig) ── */
  10. :root {
  11.     --cream:      #F7F5F0;
  12.     --cream-2:    #F0EDE5;
  13.     --cream-3:    #E8E3D9;
  14.     --white:      #FFFFFF;
  15.     --dark:       #1A1D2E;
  16.     --navy:       #1E3A6E;
  17.     --amber:      #C07D2A;
  18.     --amber-lt:   #D4954A;
  19.     --amber-dim:  rgba(192,125,42,.10);
  20.     --sage:       #3D6B52;
  21.     --muted:      #6B6E7F;
  22.     --muted-2:    #9395A5;
  23.     --border:     rgba(26,29,46,.07);
  24.     --border-md:  rgba(26,29,46,.12);
  25.     --border-str: rgba(26,29,46,.18);
  26. }
  27. body {
  28.     font-family: 'Segoe UI', -apple-system, Arial, sans-serif;
  29.     font-size: 13px;
  30.     color: var(--dark);
  31.     background: #fff;
  32.     print-color-adjust: exact;
  33.     -webkit-print-color-adjust: exact;
  34.     line-height: 1.55;
  35. }
  36. .page { width: 210mm; min-height: 297mm; margin: 0 auto; padding: 14mm 16mm 10mm; background: #fff; }
  37. /* ── Header ── */
  38. .doc-header {
  39.     display: flex; justify-content: space-between; align-items: flex-start;
  40.     padding-bottom: 18px;
  41.     border-bottom: 1.5px solid var(--cream-3);
  42.     margin-bottom: 22px;
  43. }
  44. .brand { display: flex; align-items: center; gap: 13px; }
  45. .brand-logo { width: 42px; height: 42px; object-fit: contain; border-radius: 8px; }
  46. .brand-name { font-size: 1.2rem; font-weight: 800; color: var(--navy); letter-spacing: -.02em; line-height: 1.1; }
  47. .brand-sub  { font-size: 0.67rem; color: var(--muted-2); margin-top: 2px; text-transform: uppercase; letter-spacing: .08em; }
  48. .brand-contact { font-size: 0.67rem; color: var(--muted-2); margin-top: 3px; }
  49. .doc-meta { text-align: right; }
  50. .doc-type   { font-size: 0.78rem; font-weight: 800; color: var(--amber); text-transform: uppercase; letter-spacing: .12em; }
  51. .doc-ref    { font-size: 0.76rem; color: var(--muted); margin-top: 3px; }
  52. .doc-ref strong { color: var(--dark); }
  53. .doc-expires { font-size: 0.73rem; color: #a0522d; font-weight: 600; margin-top: 8px; }
  54. /* ── Status row ── */
  55. .status-row { display: flex; align-items: center; gap: 9px; margin-bottom: 22px; flex-wrap: wrap; }
  56. .status-badge {
  57.     display: inline-flex; align-items: center; gap: 5px;
  58.     border-radius: 4px; padding: 3px 12px;
  59.     font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .09em;
  60.     border: 1px solid transparent;
  61. }
  62. .status-badge.sent      { background: rgba(30,58,110,.07);  color: var(--navy);  border-color: rgba(30,58,110,.15); }
  63. .status-badge.accepted  { background: rgba(61,107,82,.08);  color: var(--sage);  border-color: rgba(61,107,82,.2); }
  64. .status-badge.draft     { background: rgba(26,29,46,.05);   color: var(--muted); border-color: var(--border-md); }
  65. .status-badge.modified  { background: var(--amber-dim);     color: var(--amber); border-color: rgba(192,125,42,.2); }
  66. .status-badge.rejected  { background: rgba(160,82,45,.07);  color: #a0522d;      border-color: rgba(160,82,45,.2); }
  67. .status-badge.requested { background: rgba(30,58,110,.07);  color: var(--navy);  border-color: rgba(30,58,110,.15); }
  68. .renew-badge {
  69.     display: inline-flex; align-items: center; gap: 5px;
  70.     background: var(--amber-dim); color: var(--amber);
  71.     border: 1px solid rgba(192,125,42,.2); border-radius: 4px;
  72.     padding: 3px 12px; font-size: 0.68rem; font-weight: 600;
  73. }
  74. /* ── Parties ── */
  75. .doc-parties { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 22px; }
  76. .party-label { font-size: 0.6rem; text-transform: uppercase; letter-spacing: .14em; color: var(--muted-2); font-weight: 700; margin-bottom: 6px; }
  77. .party-name  { font-weight: 700; font-size: 0.92rem; color: var(--dark); margin-bottom: 3px; }
  78. .party-line  { font-size: 0.8rem; color: var(--muted); margin-bottom: 1px; }
  79. /* ── Section title ── */
  80. .section-title {
  81.     font-size: 0.63rem; font-weight: 800; text-transform: uppercase; letter-spacing: .14em;
  82.     color: var(--muted-2); margin-bottom: 10px; margin-top: 22px;
  83.     display: flex; align-items: center; gap: 8px;
  84. }
  85. .section-title::after { content: ''; flex: 1; height: 1px; background: var(--cream-3); }
  86. /* ── Plan card ── */
  87. .plan-card {
  88.     background: var(--cream);
  89.     border: 1px solid var(--border-md);
  90.     border-radius: 8px; padding: 16px 20px;
  91.     display: grid; grid-template-columns: repeat(3,1fr); gap: 16px;
  92. }
  93. .plan-item__label { font-size: 0.59rem; text-transform: uppercase; letter-spacing: .12em; color: var(--muted-2); font-weight: 700; margin-bottom: 3px; }
  94. .plan-item__val   { font-size: 0.9rem; font-weight: 700; color: var(--dark); }
  95. .plan-item__note  { font-size: 0.7rem; color: var(--muted); margin-top: 2px; }
  96. /* ── What's Included ── */
  97. .features-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 4px 16px; }
  98. .feature-item { display: flex; align-items: center; gap: 7px; font-size: 0.79rem; color: var(--muted); padding: 4px 0; }
  99. .feat-check {
  100.     width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0;
  101.     display: inline-flex; align-items: center; justify-content: center;
  102.     font-size: 0.55rem; font-weight: 900;
  103.     background: var(--amber-dim); color: var(--amber); border: 1px solid rgba(192,125,42,.25);
  104. }
  105. .feat-check.sage { background: rgba(61,107,82,.08); color: var(--sage); border-color: rgba(61,107,82,.25); }
  106. /* ── Pricing table ── */
  107. .doc-table { width: 100%; border-collapse: collapse; }
  108. .doc-table thead tr { background: var(--cream-2); }
  109. .doc-table th {
  110.     padding: 9px 14px; text-align: left;
  111.     font-size: 0.67rem; font-weight: 700; letter-spacing: .07em; color: var(--muted);
  112.     text-transform: uppercase; border-bottom: 1.5px solid var(--cream-3);
  113. }
  114. .doc-table th.c { text-align: center; }
  115. .doc-table th.r { text-align: right; }
  116. .doc-table td { padding: 10px 14px; border-bottom: 1px solid var(--cream-3); font-size: 0.83rem; vertical-align: middle; color: var(--dark); }
  117. .doc-table td.c { text-align: center; color: var(--muted); }
  118. .doc-table td.r { text-align: right; font-weight: 700; }
  119. .doc-table tbody tr:last-child td { border-bottom: none; }
  120. .row-name { font-weight: 600; color: var(--dark); }
  121. .row-sub  { font-size: 0.73rem; color: var(--muted-2); margin-top: 2px; }
  122. .user-tag {
  123.     display: inline-block; padding: 1px 7px; border-radius: 3px; margin-left: 5px;
  124.     font-size: 0.63rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  125. }
  126. .user-tag.std   { background: rgba(30,58,110,.07);  color: var(--navy); }
  127. .user-tag.admin { background: var(--amber-dim);      color: var(--amber); }
  128. .user-tag.ml    { background: rgba(61,107,82,.08);   color: var(--sage); }
  129. .yearly-note { font-size: 0.7rem; color: var(--muted-2); margin-top: 8px; font-style: italic; }
  130. /* ── Totals ── */
  131. .totals-wrap { display: flex; justify-content: flex-end; margin-top: 16px; }
  132. .totals-box { width: 310px; border: 1px solid var(--border-md); border-radius: 8px; overflow: hidden; }
  133. .totals-row { display: flex; justify-content: space-between; align-items: center; padding: 9px 18px; font-size: 0.85rem; border-bottom: 1px solid var(--cream-3); color: var(--dark); }
  134. .totals-row.discount { color: var(--sage); }
  135. .totals-row.promo    { color: var(--amber); }
  136. .totals-row.total-final {
  137.     border: none;
  138.     /*background: var(--navy);*/
  139.     background: var(--amber);
  140.     color: #fff;
  141.     font-weight: 800; font-size: 0.97rem; padding: 13px 18px;
  142. }
  143. .total-sub { font-size: 0.67rem; color: rgba(255,255,255,.55); margin-top: 2px; }
  144. /* ── Payment grid ── */
  145. .payment-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  146. .pay-item { background: var(--cream); border: 1px solid var(--border); border-radius: 7px; padding: 12px 15px; }
  147. .pay-item__title { font-size: 0.64rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--muted-2); margin-bottom: 5px; }
  148. .pay-item__body  { font-size: 0.8rem; color: var(--muted); line-height: 1.55; }
  149. /* ── SLA ── */
  150. .sla-row { display: grid; grid-template-columns: repeat(3,1fr); gap: 8px; }
  151. .sla-item { background: var(--cream); border: 1px solid var(--border); border-radius: 7px; padding: 11px 14px; }
  152. .sla-item__title { font-size: 0.72rem; font-weight: 700; color: var(--dark); margin-bottom: 3px; }
  153. .sla-item__body  { font-size: 0.74rem; color: var(--muted); line-height: 1.45; }
  154. /* ── Notes ── */
  155. .notes-box {
  156.     padding: 11px 16px;
  157.     background: rgba(192,125,42,.06);
  158.     border-left: 3px solid var(--amber);
  159.     border-radius: 5px;
  160.     font-size: 0.8rem; color: #7a5820;
  161. }
  162. /* ── Key terms callout ── */
  163. .terms-callout {
  164.     background: var(--cream);
  165.     border: 1px solid var(--border-md);
  166.     border-left: 3px solid var(--navy);
  167.     border-radius: 7px; padding: 14px 18px;
  168. }
  169. .terms-callout__title { font-size: 0.64rem; font-weight: 800; text-transform: uppercase; letter-spacing: .12em; color: var(--navy); margin-bottom: 6px; }
  170. .terms-callout__body  { font-size: 0.8rem; color: var(--muted); line-height: 1.65; }
  171. .terms-callout__body a { color: var(--navy); text-decoration: none; border-bottom: 1px solid rgba(30,58,110,.25); }
  172. /* ── Footer ── */
  173. .doc-footer {
  174.     margin-top: 26px; padding-top: 14px;
  175.     border-top: 1px solid var(--cream-3);
  176.     display: flex; justify-content: space-between; align-items: flex-end;
  177.     font-size: 0.68rem; color: var(--muted-2);
  178. }
  179. .footer-links { display: flex; gap: 12px; margin-top: 3px; }
  180. .footer-links a { color: var(--muted-2); text-decoration: none; font-size: 0.65rem; border-bottom: 1px solid var(--cream-3); }
  181. /* ── Print ── */
  182. @media print {
  183.     body { background: #fff; }
  184.     .no-print { display: none !important; }
  185.     .page { padding: 8mm 12mm; }
  186. }
  187. @media screen {
  188.     body { background: var(--cream-2); padding: 20px 0 40px; }
  189.     .print-btn { display: block; max-width: 210mm; margin: 0 auto 16px; text-align: right; }
  190.     .print-btn button {
  191.         background: var(--navy); color: #fff; border: none;
  192.         padding: 9px 22px; border-radius: 7px; font-size: 0.88rem; font-weight: 700; cursor: pointer;
  193.     }
  194.     .print-btn button:hover { background: var(--dark); }
  195. }
  196. </style>
  197. </head>
  198. <body>
  199. <div class="print-btn no-print">
  200.     <button onclick="window.print()">Print / Save as PDF</button>
  201. </div>
  202. <div class="page">
  203.     {# ── HEADER ── #}
  204.     <div class="doc-header">
  205.         <div class="brand">
  206. {#            <a class="hb-brand" href="{{ url('dashboard') }}">#}
  207. {#                <img src="{{ absolute_url(path('dashboard')) }}honeybee_web_assets/icons/honeybeeicon.svg?v={{ constant('ApplicationBundle\\Constants\\GeneralConstant::ENTITY_APP_VERSION') }}" alt="HoneyBee">#}
  208. {#                <span class="hb-brand-name">Honey<b>Bee</b></span>#}
  209. {#            </a>#}
  210.             <img class="brand-logo" src="{{ url('dashboard') }}honeybee_web_assets/icons/honeybeeicon.svg" alt="HoneyBee ERP">
  211.             <div>
  212.                 <div class="hb-brand-name" style="font-size: 15.5px;
  213.     font-weight: 800;
  214.     color: var(--hb-ink);
  215.     letter-spacing: -.01em;
  216.     line-height: 1;"><span>Honey<b style="color: var(--hb-amber);">Bee</b></span></div>
  217.                 <div class="brand-sub">Ecosystem</div>
  218.                 <div class="brand-contact">contact@ourhoneybee.eu · ourhoneybee.eu</div>
  219.             </div>
  220.         </div>
  221.         <div class="doc-meta">
  222.             <div class="doc-type">Subscription Quote</div>
  223.             <div class="doc-ref">Ref: <strong>{{ quote.quoteToken|slice(0,12)|upper }}</strong></div>
  224.             <div class="doc-ref">Issued: <strong>{{ quote.createdAt ? quote.createdAt|date('d M Y') : '—' }}</strong></div>
  225.             <div class="doc-expires">Valid Until: {{ quote.expiresAt ? quote.expiresAt|date('d M Y') : '30 days from issue' }}</div>
  226.         </div>
  227.     </div>
  228.     {# ── STATUS ── #}
  229.     <div class="status-row">
  230.         <span class="status-badge {{ quote.status }}">
  231.             {% if quote.status == 'accepted' %}✓ {% elseif quote.status == 'rejected' %}✕ {% endif %}{{ quote.status|upper }}
  232.         </span>
  233.         <span class="renew-badge">↻ Auto-renewing · {{ quote.billingCycle|title }} Subscription</span>
  234.     </div>
  235.     {# ── PARTIES ── #}
  236.     <div class="doc-parties">
  237.         <div>
  238.             <div class="party-label">From</div>
  239.             <div class="party-name">HoneyBee IoT (Pte.) Ltd.</div>
  240.             <div class="party-line">2 Venture Drive, #19-21
  241.                 Vision Exchange,</div>
  242.             <div class="party-line"> Singapore 608526</div>
  243.             <div class="party-line">UEN: 202507612D</div>
  244.             <div class="party-line">contact@ourhoneybee.eu</div>
  245.             <div class="party-line">ourhoneybee.eu</div>
  246.         </div>
  247.         <div>
  248.             <div class="party-label" style="">Prepared For</div>
  249.             <div class="party-name">{{ quote.companyName ?: (quote.customerName ?: 'Valued Customer') }}</div>
  250.             {% if quote.customerName and quote.companyName %}<div class="party-line">Attn: {{ quote.customerName }}</div>{% endif %}
  251.             {% if quote.customerDesignation %}<div class="party-line"> {{ quote.customerDesignation }}</div>{% endif %}
  252.             {% if quote.customerEmail %}<div class="party-line">{{ quote.customerEmail }}</div>{% endif %}
  253.             {% if quote.customerPhone %}<div class="party-line">{{ quote.customerPhone }}</div>{% endif %}
  254.             {% if quote.companyAddress %}<div class="party-line">{{ quote.companyAddress }}</div>{% endif %}
  255.             {% if quote.country %}<div class="party-line">{{ quote.country }}</div>{% endif %}
  256.             {% if quote.companyVatNo %}<div class="party-line">VAT NO. {{ quote.companyVatNo }}</div>{% endif %}
  257.      
  258.         </div>
  259.     </div>
  260.     {# ── SUBSCRIPTION DETAILS ── #}
  261.     <div class="section-title">Subscription Details</div>
  262.     <div class="plan-card">
  263.         <div>
  264.             <div class="plan-item__label">Plan</div>
  265.             <div class="plan-item__val">HoneyBee {{ quote.planType|title }}</div>
  266.             <div class="plan-item__note">Cloud SaaS · Per-seat licensing</div>
  267.         </div>
  268.         <div>
  269.             <div class="plan-item__label">Billing Cycle</div>
  270.             <div class="plan-item__val">{{ quote.billingCycle|title }}</div>
  271.             <div class="plan-item__note">
  272.                 {%- if quote.billingCycle == 'yearly' -%}Billed annually · 20% saving{%- else -%}Billed each calendar month{%- endif -%}
  273.             </div>
  274.         </div>
  275.         <div>
  276.             {% set totalSeats = (quote.normalUserCount ?: 0) + (quote.adminUserCount ?: 0) + (quote.mlUserCount ?: 0) %}
  277.             {% set totalSeatsWithoutMl = (quote.normalUserCount ?: 0) + (quote.adminUserCount ?: 0)  %}
  278.             <div class="plan-item__label">Total Seats / AI ML Enhanced Seats</div>
  279.             <div class="plan-item__val">{{ totalSeatsWithoutMl }} Seat{{ totalSeats != 1 ? 's' : '' }} / {{ (quote.mlUserCount ?: 0) }} Seat{{ (quote.mlUserCount ?: 0) != 1 ? 's' : '' }} </div>
  280. {#            <div class="plan-item__val">{{ totalSeats }} User{{ totalSeats != 1 ? 's' : '' }}</div>#}
  281.             <div class="plan-item__note">Scalable · Add users anytime</div>
  282.         </div>
  283.     </div>
  284.     {# ── WHAT'S INCLUDED ── #}
  285.     <div class="section-title">What's Included</div>
  286.     <div class="features-grid">
  287.         <div class="feature-item"><span class="feat-check">✓</span> CRM &amp; Sales Management</div>
  288.         <div class="feature-item"><span class="feat-check">✓</span> Inventory &amp; Warehouse</div>
  289.         <div class="feature-item"><span class="feat-check">✓</span> Finance &amp; Accounting</div>
  290.         <div class="feature-item"><span class="feat-check">✓</span> HR &amp; Payroll</div>
  291.         <div class="feature-item"><span class="feat-check">✓</span> Purchase Management</div>
  292.         <div class="feature-item"><span class="feat-check">✓</span> Reports &amp; Analytics</div>
  293.         <div class="feature-item"><span class="feat-check">✓</span> Production Module</div>
  294.         <div class="feature-item"><span class="feat-check">✓</span> Document Management</div>
  295.         {% if quote.mlUserCount > 0 %}
  296.         <div class="feature-item"><span class="feat-check sage">✓</span> AI / ML Intelligence Suite</div>
  297.         {% else %}
  298.         <div class="feature-item"><span class="feat-check">✓</span> Multi-currency &amp; Tax Support</div>
  299.         {% endif %}
  300.     </div>
  301.     {# ── PRICING TABLE ── #}
  302.     <div class="section-title">Pricing Breakdown</div>
  303.     {% set sub_total_unchanged=0 %}
  304.     {% if breakdown %}
  305.     <table class="doc-table">
  306.         <thead>
  307.             <tr>
  308.                 <th>Description</th>
  309.                 <th class="c">Seats</th>
  310.                 <th class="c">Unit / Month</th>
  311.                 <th class="r">Monthly Subtotal</th>
  312.             </tr>
  313.         </thead>
  314.         <tbody>
  315.             {% if breakdown.normal_users > 0 %}
  316.                 {%  set sub_total_unchanged=sub_total_unchanged+12*breakdown.subtotal_normal %}
  317.             <tr>
  318.                 <td>
  319.                     <div class="row-name">Standard User License <span class="user-tag std">Standard</span></div>
  320.                     <div class="row-sub">Full ERP access · All standard modules included</div>
  321.                 </td>
  322.                 <td class="c">{{ breakdown.normal_users }}</td>
  323.                 <td class="c">€{{ breakdown.price_normal_monthly|number_format(2) }}</td>
  324.                 <td class="r">€{{ breakdown.subtotal_normal|number_format(2) }}</td>
  325.             </tr>
  326.             {% endif %}
  327.             {% if breakdown.admin_users > 0 %}
  328.                 {%  set sub_total_unchanged=sub_total_unchanged+12*breakdown.subtotal_admin %}
  329.             <tr>
  330.                 <td>
  331.                     <div class="row-name">Administrator License <span class="user-tag admin">Admin</span></div>
  332.                     <div class="row-sub">Full access + user management + system configuration</div>
  333.                 </td>
  334.                 <td class="c">{{ breakdown.admin_users }}</td>
  335.                 <td class="c">€{{ breakdown.price_admin_monthly|number_format(2) }}</td>
  336.                 <td class="r">€{{ breakdown.subtotal_admin|number_format(2) }}</td>
  337.             </tr>
  338.             {% endif %}
  339.             {% if breakdown.ml_users > 0 %}
  340.                 {%  set sub_total_unchanged=sub_total_unchanged+12*breakdown.subtotal_ml %}
  341.             <tr>
  342.                 <td>
  343.                     <div class="row-name">AI-Enhancement per Seat <span class="user-tag ml">AI / ML</span></div>
  344.                     <div class="row-sub">Full access + AI assistant + ML analytics &amp; predictions</div>
  345.                 </td>
  346.                 <td class="c">{{ breakdown.ml_users }}</td>
  347.                 <td class="c">€{{ breakdown.price_ml_monthly|number_format(2) }}</td>
  348.                 <td class="r">€{{ breakdown.subtotal_ml|number_format(2) }}</td>
  349.             </tr>
  350.             {% endif %}
  351.         </tbody>
  352.     </table>
  353.     {% if quote.billingCycle == 'yearly' %}
  354.     <div class="yearly-note">* Monthly unit prices shown above. Annual total reflects 20% yearly discount — see billing summary below.</div>
  355.     {% endif %}
  356.     {% else %}
  357.     <table class="doc-table">
  358.         <thead>
  359.             <tr>
  360.                 <th>Description</th>
  361.                 <th>Plan Type</th>
  362.                 <th class="r">Amount</th>
  363.             </tr>
  364.         </thead>
  365.         <tbody>
  366.             <tr>
  367.                 <td>
  368.                     <div class="row-name">HoneyBee ERP — {{ quote.planType|title }} Plan</div>
  369.                     <div class="row-sub">Custom enterprise subscription · Pricing configured by your account team</div>
  370.                 </td>
  371.                 <td>{{ quote.billingCycle|title }}</td>
  372.                 <td class="r">{{ quote.baseAmount ? '€' ~ quote.baseAmount|number_format(2) : 'To be confirmed' }}</td>
  373.             </tr>
  374.         </tbody>
  375.     </table>
  376.     {% endif %}
  377.     {# ── BILLING SUMMARY ── #}
  378.     <div class="totals-wrap">
  379.         <div class="totals-box">
  380.             <div class="totals-row">
  381.                 <span>Subtotal</span>
  382.                 <span>€{{ sub_total_unchanged ? sub_total_unchanged|number_format(2) : '0.00' }}</span>
  383. {#                <span>€{{ quote.baseAmount ? quote.baseAmount|number_format(2) : '0.00' }}</span>#}
  384.             </div>
  385.             {% if quote.discountAmount > 0 or quote.discountPercent>0  %}
  386.             <div class="totals-row discount">
  387.                 <span>Discount{% if quote.discountPercent > 0 %} ({{ quote.discountPercent }}%){% endif %}</span>
  388.                 <span>−€{{ quote.discountAmount|number_format(2) }}</span>
  389.             </div>
  390.             {% endif %}
  391.             {% if quote.promoCodeDiscount > 0 %}
  392.             <div class="totals-row promo">
  393.                 <span>Promo Code</span>
  394.                 <span>−€{{ quote.promoCodeDiscount|number_format(2) }}</span>
  395.             </div>
  396.             {% endif %}
  397.             {% if breakdown is defined and breakdown and quote.billingCycle == 'yearly' %}
  398.             <div class="totals-row discount">
  399.                 <span>Annual Saving ({{ breakdown.yearly_discount_pct }}% off)</span>
  400.                 <span>−€{{ breakdown.yearly_savings|number_format(2) }}</span>
  401.             </div>
  402.             {% endif %}
  403.             <div class="totals-row total-final">
  404.                 <div>
  405.                     <div>Total Due ({{ quote.billingCycle|title }})</div>
  406.                     <div class="total-sub">{{ quote.currency ?: 'EUR' }} · Excl. applicable taxes</div>
  407.                 </div>
  408.                 <span>€{{ quote.finalAmount ? quote.finalAmount|number_format(2) : '0.00' }}</span>
  409.             </div>
  410.         </div>
  411.     </div>
  412.     {# ── PAYMENT & BILLING ── #}
  413.     <div class="section-title">Payment &amp; Billing</div>
  414.     <div class="payment-grid">
  415.         <div class="pay-item">
  416.             <div class="pay-item__title">Payment Due</div>
  417.             <div class="pay-item__body">
  418.                 {% if quote.paymentType == 'automatic' %}
  419.                     Processed automatically on the billing date via card or SEPA mandate.
  420.                 {% else %}
  421.                     Bank transfer within <strong>14 days</strong> of invoice date. Use reference <strong>{{ quote.quoteToken|slice(0,12)|upper }}</strong>.
  422.                 {% endif %}
  423.             </div>
  424.         </div>
  425.         <div class="pay-item">
  426.             <div class="pay-item__title">Accepted Methods</div>
  427.             <div class="pay-item__body">
  428.                 {% if quote.paymentType == 'automatic' %}
  429.                     Credit / Debit Card · Stripe · SEPA Direct Debit
  430.                 {% else %}
  431.                     Bank Transfer (IBAN) ·
  432.                     Oversea-Chinese Banking Corporation Limited (OCBC)
  433.                     Bank Address:
  434.                     65 Chulia Street
  435.                     OCBC Centre
  436.                     Singapore 049513
  437.                     Singapore
  438.                     SWIFT / BIC:
  439.                     OCBCSGSG
  440.                     Online payment link on request
  441.                 {% endif %}
  442.             </div>
  443.         </div>
  444.         <div class="pay-item">
  445.             <div class="pay-item__title">Auto-Renewal</div>
  446.             <div class="pay-item__body">
  447.                 Renews automatically each {{ quote.billingCycle }} cycle. You will be notified before renewal. Cancel anytime before the next billing date.
  448.             </div>
  449.         </div>
  450.         <div class="pay-item">
  451.             <div class="pay-item__title">Late Payments</div>
  452.             <div class="pay-item__body">
  453.                 A 7-day grace period applies to overdue invoices. Access may be suspended after the grace period pending settlement.
  454.             </div>
  455.         </div>
  456.     </div>
  457.     {# ── SUPPORT & SLA ── #}
  458.     <div class="section-title">Support &amp; Service Level</div>
  459.     <div class="sla-row">
  460.         <div class="sla-item">
  461.             <div class="sla-item__title">Email Support</div>
  462.             <div class="sla-item__body">Response within 1 business day · contact@ourhoneybee.eu</div>
  463.         </div>
  464.         <div class="sla-item">
  465.             <div class="sla-item__title">Uptime SLA</div>
  466.             <div class="sla-item__body">99.5% monthly uptime · Maintenance notified in advance</div>
  467.         </div>
  468.         <div class="sla-item">
  469.             <div class="sla-item__title">Platform Updates</div>
  470.             <div class="sla-item__body">All updates included · No additional upgrade fees</div>
  471.         </div>
  472.     </div>
  473.     {# ── NOTES ── #}
  474.     {% if quote.adminNotes %}
  475.     <div class="section-title" style="margin-top:18px;">Notes from Your Account Manager</div>
  476.     <div class="notes-box">{{ quote.adminNotes }}</div>
  477.     {% endif %}
  478.     {# ── KEY TERMS ── #}
  479.     <div class="section-title" style="margin-top:18px;">Summary of Key Terms</div>
  480.     <div class="terms-callout">
  481.         <div class="terms-callout__title">Before You Accept</div>
  482.         <div class="terms-callout__body">
  483.             This subscription renews automatically each <strong>{{ quote.billingCycle }}</strong> billing cycle until canceled.
  484.             By accepting this quote, you agree to the HoneyBee ERP
  485.             <a href="https://ourhoneybee.eu/terms">Terms of Service</a>,
  486.             <a href="https://ourhoneybee.eu/privacy">Privacy Policy</a>, and
  487.             <a href="https://ourhoneybee.eu/subscription">Subscription Agreement</a>.
  488.             You may cancel at any time before the next renewal date — see our
  489.             <a href="https://ourhoneybee.eu/subscription#cancellation">Cancellation Policy</a>.
  490.             Full legal terms at <strong>ourhoneybee.eu/legal</strong>.
  491.         </div>
  492.     </div>
  493.     {# ── FOOTER ── #}
  494.     <div class="doc-footer">
  495.         <div>
  496.             <div><strong>HoneyBee ERP</strong> · contact@ourhoneybee.eu · ourhoneybee.eu</div>
  497.             <div class="footer-links">
  498.                 <a href="https://ourhoneybee.eu/terms">Terms</a>
  499.                 <a href="https://ourhoneybee.eu/privacy">Privacy</a>
  500.                 <a href="https://ourhoneybee.eu/subscription">Subscription Agreement</a>
  501.                 <a href="https://ourhoneybee.eu/legal">Legal</a>
  502.             </div>
  503.         </div>
  504.         <div style="text-align:right;">
  505.             <div>Quote <strong>{{ quote.quoteToken|slice(0,12)|upper }}</strong></div>
  506.             <div>Generated {{ "now"|date('d M Y') }}</div>
  507.         </div>
  508.     </div>
  509. </div>
  510. </body>
  511. </html>