openSOURCE

openSOURCE

Did You Know?

Simple, efficient, yet affordable!

QWeb (XML templating) — UI & report template

Panduan Lengkap QWeb <t t-esc>

Estimated reading: 8 minutes 39 views

Dokumen ini menjadi panduan praktis agar kita paham tuntas tentang <t t-esc="..."/> di QWeb Odoo 18: definisi, prinsip keamanan, pola pakai, sampai contoh lengkap untuk report, portal/website, dan komponen UI.


1) Apa itu t-esc?

t-esc adalah atribut QWeb untuk mencetak nilai dengan HTML‑escaping (diproses agar karakter khusus tidak dieksekusi sebagai HTML/JS). Ini adalah default yang aman saat kita ingin menampilkan teks/angka ke pengguna.

  • Aman: semua karakter berbahaya di-escape.
  • Serbaguna: bisa dipakai di hampir semua tag HTML (mis. span, div) maupun tag QWeb <t/>.
  • Bandingkan:
    • t-esc → aman (escaped).
    • t-raw → tidak di-escape (hanya gunakan untuk konten yang benar‑benar tepercaya).

2) Di mana kita pakai t-esc?

  • QWeb Report: faktur, SO/PO, delivery slip.
  • Portal & Website: halaman portal customer, website pages, snippets.
  • Backend QWeb: template kecil untuk widget/komponen tertentu.

Intinya, setiap kali kita menampilkan data dari database atau input pengguna, default‑nya gunakan t-esc.


3) Bentuk dasar & variasi sintaks

Kita bisa menaruh t-esc pada elemen apa pun atau langsung pada tag <t/>.

A. Pada elemen HTML

<span t-esc="o.partner_id.name"/>

B. Pada tag QWeb <t/>

<t t-esc="o.amount_total"/>

C. Dengan konten lain di dalam elemen (kombinasi static + dinamis)

<p>
  Total: <span t-esc="o.amount_total"/>
  <small>(incl. tax)</small>
</p>

D. Dengan ekspresi Python sederhana (fallback aman)

<span t-esc="o.partner_id.email or '-'"/>

Catatan: ekspresi dievaluasi sebagai Python (tanpa side‑effect). Untuk logika bercabang/pengulangan, gunakan t-if, t-elif, t-else, t-foreach.


4) Format & widget dengan t-options

Pada report (dan beberapa konteks QWeb lain), kita bisa memformat nilai dengan widget melalui t-options.

4.1. Uang (monetary)

<span
  t-esc="o.amount_total"
  t-options='{"widget": "monetary", "display_currency": o.currency_id}'/>

4.2. Angka (float/integer)

<span t-esc="o.x_percentage" t-options='{"widget": "float", "precision": 2}'/>

4.3. Jam/menit (float_time)

<span t-esc="o.x_duration_hours" t-options='{"widget": "float_time"}'/>

4.4. Tanggal & waktu

<span t-esc="o.date_order" t-options='{"widget": "date"}'/>
<span t-esc="o.create_date" t-options='{"widget": "datetime"}'/>

Tips: gunakan widget untuk lokalisasi (format angka/tanggal/uang mengikuti bahasa & locale pengguna/report).


5) Perbandingan t-esc vs t-raw

Gunakan t-esc sebagai default. t-raw hanya saat kita benar‑benar yakin konten aman (mis. HTML yang kita hasilkan sendiri, sudah disanitasi, bukan input user, dan dipahami dampaknya pada layout).

<!-- Aman: escaped -->
<span t-esc="o.note"/>

<!-- Tidak di-escape: tampilkan HTML apa adanya -->
<span t-raw="o.note_html"/>

Checklist cepat:

  • Konten dari user/database → t-esc.
  • Konten HTML tepercaya/terkontrol → pertimbangkan t-raw (dengan kehati‑hatian).

6) Contoh Lengkap — QWeb Report (Sales Order)

Contoh potongan template report untuk Sales Order yang memadukan t-esc, t-if, t-foreach, dan t-options.

<template id="report_saleorder_document">
  <t t-call="web.external_layout">
    <div class="page">
      <!-- Header -->
      <h2>
        <span>Quotation </span>
        <span t-esc="o.name"/>
      </h2>

      <!-- Partner info -->
      <div>
        <div><strong t-esc="o.partner_id.name"/></div>
        <div t-if="o.partner_id.vat">VAT: <span t-esc="o.partner_id.vat"/></div>
        <div t-esc="o.partner_id.contact_address"/>
      </div>

      <!-- Order meta -->
      <ul>
        <li>Date: <span t-esc="o.date_order" t-options='{"widget":"datetime"}'/></li>
        <li>Salesperson: <span t-esc="o.user_id.name or '-'"/></li>
        <li>Payment Terms: <span t-esc="o.payment_term_id.name or '-'"/></li>
      </ul>

      <!-- Lines -->
      <table class="table table-sm">
        <thead>
          <tr>
            <th>Description</th>
            <th class="text-end">Qty</th>
            <th class="text-end">Unit Price</th>
            <th class="text-end">Taxes</th>
            <th class="text-end">Subtotal</th>
          </tr>
        </thead>
        <tbody>
          <t t-foreach="o.order_line" t-as="l">
            <tr>
              <td>
                <span t-esc="l.name"/>
                <t t-if="l.product_id.default_code">
                  <small>(<span t-esc="l.product_id.default_code"/>)</small>
                </t>
              </td>
              <td class="text-end"><span t-esc="l.product_uom_qty" t-options='{"widget":"float","precision":2}'/></td>
              <td class="text-end"><span t-esc="l.price_unit" t-options='{"widget":"monetary", "display_currency": o.currency_id}'/></td>
              <td class="text-end"><span t-esc="', '.join(t.name for t in l.tax_id) or '-'"/></td>
              <td class="text-end"><span t-esc="l.price_subtotal" t-options='{"widget":"monetary", "display_currency": o.currency_id}'/></td>
            </tr>
          </t>
        </tbody>
      </table>

      <!-- Totals -->
      <div class="row mt-3">
        <div class="col-8"></div>
        <div class="col-4">
          <table class="table table-borderless">
            <tr>
              <th class="text-end">Untaxed Amount</th>
              <td class="text-end"><span t-esc="o.amount_untaxed" t-options='{"widget":"monetary", "display_currency": o.currency_id}'/></td>
            </tr>
            <tr>
              <th class="text-end">Taxes</th>
              <td class="text-end"><span t-esc="o.amount_tax" t-options='{"widget":"monetary", "display_currency": o.currency_id}'/></td>
            </tr>
            <tr>
              <th class="text-end">Total</th>
              <td class="text-end"><strong t-esc="o.amount_total" t-options='{"widget":"monetary", "display_currency": o.currency_id}'/></td>
            </tr>
          </table>
        </div>
      </div>

      <!-- Notes -->
      <t t-if="o.note">
        <div class="mt-2"><em t-esc="o.note"/></div>
      </t>
    </div>
  </t>
</template>

Poin penting di atas:

  • Semua nilai numerik/uang diformat dengan t-options.
  • Daftar pajak pada tiap line dibuat aman via ekspresi Python sederhana.
  • Note ditampilkan escaped (aman). Jika o.note berisi HTML yang harus dirender, gunakan t-raw dengan pertimbangan keamanan yang matang.

7) Contoh Lengkap — Portal/Website

Di portal/website, kita biasanya mengakses user & environment via request.

<template id="portal_greeting" name="Portal Greeting">
  <section class="container my-3">
    <h3>
      Halo, <span t-esc="request.env.user.name or 'Guest'"/>!
    </h3>
    <p>
      Anda login sebagai: <code t-esc="request.env.user.login"/>
    </p>

    <t t-if="request.env.user.partner_id">
      <p>Perusahaan: <span t-esc="request.env.user.partner_id.commercial_company_name or '-'"/></p>
    </t>

    <t t-if="request.params.get('msg')">
      <div class="alert alert-info" role="alert">
        <span t-esc="request.params.get('msg')"/>
      </div>
    </t>
  </section>
</template>

Poin penting:

  • Parameter query (request.params) harus di‑escape dengan t-esc karena berasal dari user.
  • Nama user/login juga di‑escape sebagai kebiasaan aman.

8) Pola Praktik Terbaik (Best Practices)

  1. Default ke t-esc untuk semua output; beralih ke t-raw hanya jika wajib.
  2. Gunakan t-options untuk format angka/tanggal/uang → konsisten & sesuai locale.
  3. Fallback aman: t-esc="value or '-'" agar UI tidak kosong saat data null.
  4. Pisahkan logika: gunakan t-if/t-elif/t-else dan t-foreach alih‑alih ekspresi kompleks.
  5. Uji dengan data nyata: cetak report pada beberapa dokumen dengan variasi (tanpa pajak, multi‑currency, nilai 0, dsb.).
  6. Jangan gunakan t-raw untuk input user (komentar, deskripsi bebas) kecuali sudah disanitasi.

9) Debugging Cepat

  • Aktifkan Developer Mode.
  • Untuk report: cetak dokumen → buka HTML hasil cetak (print preview) untuk inspeksi struktur.
  • Untuk website/portal: gunakan menu Website → EditEdit Template untuk melihat dan menguji perubahan.
  • Jika output tidak muncul, cek:
    • Apakah ekspresi benar dan objek tersedia di context (o, doc, docs, request, dll.)?
    • Apakah ada error di log server saat render report?
    • Apakah ada modul lain yang meng‑inherit template yang sama (override di urutan load)?

10) Quick Reference (Ringkasan Praktis)

  • Cetak aman: <span t-esc="expr"/>
  • Cetak raw (hati‑hati): <span t-raw="expr"/>
  • Format uang: t-options='{"widget":"monetary", "display_currency": currency}'
  • Format tanggal: t-options='{"widget":"date"}' atau "datetime"
  • Array → teks: t-esc="', '.join(x.name for x in recs) or '-'"
  • Fallback null: t-esc="expr or '-'"

11) FAQ Singkat

Apakah t-esc bisa dipakai di semua tag?
Bisa. Pasang pada <t/> atau elemen HTML biasa (span/div/td/...).

Apa bedanya t-esc dengan t-out?
Pada QWeb modern, kita gunakan t-esc sebagai cara baku untuk menampilkan teks ter‑escape. (Jika menemui t-out di template lama, perlakukan sebagai pola lama untuk output teks.)

Bagaimana cara translate teks statis di template?
Gunakan mekanisme translasi QWeb (mis. t-translation pada elemen statis) atau string di file PO. Untuk nilai dinamis, fokus pada format (mis. t-options).


12) Checklist sebelum deploy

  • Semua output teks/angka pakai t-esc (atau widget via t-options).
  • Tidak ada t-raw terhadap input user/field bebas.
  • Report diuji pada beberapa dokumen (tanpa pajak, multi‑currency, diskon, dsb.).
  • Portal/website diuji pada user tanpa company dan tanpa data opsional (fallback tampil rapi).
  • Tidak ada override template yang saling menimpa tanpa sengaja.

13) Layanan Bantuan

Kirimkan potongan template & tujuan output yang kita inginkan (format angka/tanggal/uang, daftar, dsb.). Tim OdooCamp siap bantu review ekspresi dan menyarankan t-options/widget yang tepat agar hasilnya konsisten dan aman.

Leave a Comment

Share this Doc

Panduan Lengkap QWeb <t t-esc>

Or copy link

CONTENTS