Slink/sos_brm/report/sos_brm_report_result.xml

418 lines
17 KiB
XML
Executable File

<odoo>
<record id="paperformat_brm_landscape" model="report.paperformat">
<field name="name">BRM Landscape Format</field>
<field name="default" eval="False"/>
<field name="format">A4</field>
<field name="orientation">Landscape</field>
<field name="margin_top">10</field>
<field name="margin_bottom">10</field>
<field name="margin_left">10</field>
<field name="margin_right">10</field>
</record>
<!-- Updated report with paperformat reference -->
<record id="action_brm_summary_report" model="ir.actions.report">
<field name="name">To-Do Reports</field>
<field name="model">sos_brm_action</field>
<field name="report_type">qweb-html</field> <!-- Changed to qweb-pdf for printing -->
<field name="report_name">sos_brm.report_brm_action_plan_summary</field>
<field name="print_report_name">BRM_Plan_Summary</field>
<field name="paperformat_id" ref="paperformat_brm_landscape"/>
</record>
<template id="report_brm_action_plan_summary">
<t t-call="web.basic_layout">
<t t-call="web.html_container">
<!-- Optional: keep your global CSS -->
<link rel="stylesheet" href="/sos_inventory/static/src/css/style.css?v=7"/>
<!-- Polishing CSS just for this report -->
<style>
.subrow td { background:#fff; padding:0; }
.subtable { width:100%; border-collapse:collapse; font-size:12px; margin:4px 0 10px; }
.subtable thead th { background:#f2f3f7; border-bottom:1px solid #e2e4ea; padding:6px; text-align:left; }
.subtable td { padding:6px; border-bottom:1px solid #eee; }
.subtable tr, .subtable { page-break-inside: avoid; }
.status-pill { border-radius:999px; padding:2px 8px; font-size:12px; border:1px solid #ddd; display:inline-block; background-color: #e1375e;
color: #fff;
font-weight: bold; }
.page{
margin-top: 10px;
}
:root {
--ink: #1d1b23;
--muted: #6f6a7d;
--edge: #ece8ff;
--chip: #f4f1ff;
--badge-open: #fbd5ad;
--badge-open-text: #7a4b00;
--badge-close: #e9f7ec;
--badge-close-text: #1e6f3b;
--badge-hold: #f2f2f2;
--badge-hold-text: #606060;
--overdue: #b00020;
--soon: #9a6700;
--ok: #2e7d32;
--head: #eae6ff;
--hover: #f8f7ff;
}
.hdr { display:flex; justify-content:space-between; align-items:flex-start; margin:2px 0 10px; }
.title { margin:0; font-size:18px; color:var(--ink); }
.chips { display:flex; flex-wrap:wrap; gap:8px; margin-top:6px; }
.chip { background:var(--chip); border:1px solid var(--edge); border-radius:999px; padding:4px 10px; font-size:12px; }
.summary-row{width:100%;border-collapse:separate;border-spacing:10px 0;margin:8px 0 12px;}
.summary-row td{box-shadow: rgba(0, 0, 0, 0.12) 0px 2px 6px;width:33.33%;vertical-align:top;padding:10px 12px;border:1px solid var(--edge);background:#fff;border-radius:10px;}
.summary-row .lab{color:var(--muted);font-size:11px;}
.summary-row .val{font-weight:600;font-size:16px;}
@media print {.summary-row{border-spacing:8px 0;}}
.table_custom { width:100%; border-collapse:collapse; font-size:13px; }
.table_custom thead th { background:var(--head); border-bottom:1px solid #cfc8ff; padding:8px; text-align:left; }
.table_custom td { padding:8px; overflow-wrap: anywhere; }
.table_custom tbody tr:hover { background:var(--hover); }
.nowrap { white-space:nowrap; }
.badge { border-radius:999px; padding:2px 8px; font-size:12px; border:1px solid transparent; display:inline-block; }
.b-open { background:var(--badge-open); color:var(--badge-open-text); border-color:#ffe6a8; }
.b-close { background:var(--badge-close); color:var(--badge-close-text); border-color:#bfe8c8; }
.b-hold { background:var(--badge-hold); color:var(--badge-hold-text); border-color:#dedede; }
.date-ok { color:var(--ok); font-weight:600; }
.date-soon { color:var(--soon); font-weight:600; }
.date-overdue { color:var(--overdue); font-weight:700; }
.btn-link { border:1px solid #6a5acd; color:#4b3dbb; padding:4px 10px; border-radius:999px; text-decoration:none; font-size:12px; }
.btn-link:hover { background:#efeaff; }
/* keep rows together on PDF */
.table_custom tr { page-break-inside: avoid; }
h4 { margin:14px 0 6px; }
.section-head { display:flex; align-items:center; gap:10px; }
.pill { background: #202022;
border: 1px solid var(--edge);
border-radius: 999px;
padding: 2px 8px;
font-size: 12px;
color: #ffffff;}
</style>
<div class="page">
<!-- Today helper (remove if you pass 'today' from Python) -->
<t t-set="today" t-value="datetime.date.today()"/>
<!-- Header -->
<div class="hdr">
<h3 class="title">To-Do Summary</h3>
</div>
<div style="font-size:12px; margin-top:4px;">
<strong>Responsible:</strong>
<t t-esc="done_by.name or '—'"/>
&#160;|&#160;
<strong>Status:</strong> <t t-esc="status"/>
<t t-if="department">
&#160;|&#160;
<strong>Department:</strong> <t t-esc="department"/>
</t>
</div>
<!-- KPIs -->
<table class="summary-row">
<tr>
<t t-if="cross_dept_action != 'cross_dept'">
<td>
<div class="lab">Intra-Dept Actions</div>
<div class="val"><t t-esc="count_local"/></div>
</td>
</t>
<t t-if="cross_dept_action != 'inter_dept'">
<td>
<div class="lab">Cross-Dept Actions</div>
<div class="val"><t t-esc="count_cross"/></div>
</td>
</t>
<t t-if="cross_dept_action == 'all'">
<td>
<div class="lab">Total</div>
<div class="val"><t t-esc="count_local + count_cross"/></div>
</td>
</t>
</tr>
</table>
<!-- INTRA-DEPT -->
<t t-if="cross_dept_action != 'cross_dept'">
<div class="section-head">
<h4>Intra-Department Actions</h4>
<span class="pill">Total: <t t-esc="count_local"/></span>
</div>
<table class="table_custom">
<thead>
<tr>
<th>Action Point</th>
<th>Department</th>
<th>Assigned By</th>
<th>Assigned To</th>
<th class="nowrap" style="text-align:center;">Start Date</th>
<th class="nowrap" style="text-align:center;">Target Date</th>
<th class="nowrap" style="text-align:center;">Actual End Date</th>
<!-- <th class="nowrap" style="text-align:center;">Revised Target Date</th> -->
<!-- <th>Remarks</th> -->
<!-- NEW child columns -->
<th>Action Plan</th>
<th>Revised Target Date</th>
<th>Result</th>
<th style="text-align:center;">Status</th>
</tr>
</thead>
<tbody>
<t t-if="local and len(local)">
<t t-foreach="local" t-as="rec">
<t t-set="is_closed" t-value="rec.status == 'close'"/>
<t t-set="is_overdue" t-value="rec.target_date and not is_closed and rec.target_date &lt; today"/>
<t t-set="is_soon" t-value="rec.target_date and not is_closed and not is_overdue and (rec.target_date - today).days &lt;= 7"/>
<!-- fetch child lines and rows to span -->
<t t-set="lines" t-value="lines_map.get(rec.id, [])"/>
<t t-set="rows" t-value="max(1, len(lines))"/>
<!-- first row carries all parent cells (rowspanned) + first child (or dashes) -->
<tr>
<td t-att-rowspan="rows">
<a t-att-href="'/web#id=%d&amp;model=sos_brm_action&amp;view_type=form' % rec.id" target="_blank">
<t t-esc="rec.name or '—'"/>
</a>
</td>
<td t-att-rowspan="rows"><t t-esc="rec.department.name or '—'"/></td>
<td t-att-rowspan="rows">
<div style="display:flex; align-items:center;">
<!-- User Image -->
<img t-att-src="'/web/image/%s/%s/image_1920' % (rec.assigned_by._name, rec.assigned_by.id)"
style="width:24px; height:24px; border-radius:50%; margin-right:5px;"/>
<!-- User Name -->
<t t-esc="rec.assigned_by.name or '—'"/>
</div></td>
<td t-att-rowspan="rows">
<div style="display:flex; align-items:center;">
<!-- User Image -->
<img t-att-src="'/web/image/%s/%s/image_1920' % (rec.responsible_person._name, rec.responsible_person.id)"
style="width:24px; height:24px; border-radius:50%; margin-right:5px;"/>
<!-- User Name -->
<t t-esc="rec.responsible_person.name or '—'"/>
</div>
</td>
<td class="nowrap" style="text-align:center;" t-att-rowspan="rows">
<t t-esc="rec.start_date and rec.start_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<td class="nowrap" style="text-align:center;" t-att-rowspan="rows"
t-attf-class="#{is_overdue and 'date-overdue' or (is_soon and 'date-soon' or 'date-ok')}">
<t t-esc="rec.target_date and rec.target_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<td class="nowrap" style="text-align:center;" t-att-rowspan="rows">
<t t-esc="rec.end_date and rec.end_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<!-- <td class="nowrap" style="text-align:center;" t-att-rowspan="rows">
<t t-esc="rec.latest_target_date and rec.latest_target_date.strftime('%d-%m-%Y') or '—'"/>
</td> -->
<!-- <td style="text-align:center;" t-att-rowspan="rows">
<t t-set="cls" t-value="rec.status == 'open' and 'b-open' or (rec.status == 'close' and 'b-close' or 'b-hold')"/>
<span class="badge" t-attf-class="badge #{cls}">
<t t-esc="dict(rec._fields['status'].selection).get(rec.status, rec.status)"/>
</span>
</td> -->
<!-- <td t-att-rowspan="rows"><t t-esc="rec.result or ''"/></td> -->
<!-- child plan + status (first child or dashes) -->
<td>
<t t-esc="(len(lines) and (lines[0].name or '—')) or '—'"/>
</td>
<td class="nowrap" style="text-align:center;">
<t t-esc="(len(lines) and (lines[0].target_date and lines[0].target_date.strftime('%d-%m-%Y') or '—')) or '—'"/>
</td>
<td>
<t t-esc="(len(lines) and (lines[0].result or '—')) or '—'"/>
</td>
<td style="text-align:center;">
<t t-if="len(lines)">
<span class="status-pill"
t-att-style="'background-color:#2e7d32; border-color:#bfe8c8;' if lines[0].status == 'close' else ''">
<t t-esc="dict(lines[0]._fields['status'].selection).get(lines[0].status, lines[0].status)"/>
</span>
</t>
<t t-else=""></t>
</td>
</tr>
<!-- any remaining child lines as extra rows (only the FOUR child cols) -->
<t t-if="len(lines) &gt; 1">
<t t-foreach="lines[1:]" t-as="ln">
<tr>
<td><t t-esc="ln.name or '—'"/></td>
<td class="nowrap" style="text-align:center;">
<t t-esc="ln.target_date and ln.target_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<td><t t-esc="ln.result or '—'"/></td>
<td style="text-align:center;">
<span class="status-pill"
t-att-style="'background-color:#2e7d32; border-color:#bfe8c8;' if ln.status == 'close' else 'background-color:#e1375e;'">
<t t-esc="dict(ln._fields['status'].selection).get(ln.status, ln.status)"/>
</span>
</td>
</tr>
</t>
</t>
</t>
</t>
<t t-if="not local or len(local) == 0">
<!-- total columns = 8 -->
<tr><td colspan="11" style="text-align:center; color:#666; padding:12px;">No within-department actions.</td></tr>
</t>
</tbody>
</table>
</t>
<div style="height:16px;"></div>
<t t-if="cross_dept_action != 'inter_dept'">
<!-- CROSS-DEPT -->
<div class="section-head">
<h4>Cross-Department Actions</h4>
<span class="pill">Total: <t t-esc="count_cross"/></span>
</div>
<table class="table_custom">
<thead>
<tr>
<th>Action Point</th>
<th>Assigned By Dept</th>
<th>Assigned To Dept</th>
<th>Assigned By</th>
<th>Assigned To</th>
<th class="nowrap" style="text-align:center;">Start Date</th>
<th class="nowrap" style="text-align:center;">Target Date</th>
<th class="nowrap" style="text-align:center;">Actual End Date</th>
<!-- NEW child columns -->
<th>Action Plan</th>
<th>Revised Target Date</th>
<th>Result</th>
<th style="text-align:center;">Status</th>
</tr>
</thead>
<tbody>
<t t-if="cross and len(cross)">
<t t-foreach="cross" t-as="rec">
<t t-set="is_closed" t-value="rec.status == 'close'"/>
<t t-set="is_overdue" t-value="rec.target_date and not is_closed and rec.target_date &lt; today"/>
<t t-set="is_soon" t-value="rec.target_date and not is_closed and not is_overdue and (rec.target_date - today).days &lt;= 7"/>
<t t-set="lines" t-value="lines_map.get(rec.id, [])"/>
<t t-set="rows" t-value="max(1, len(lines))"/>
<tr>
<td t-att-rowspan="rows">
<a t-att-href="'/web#id=%d&amp;model=sos_brm_action&amp;view_type=form' % rec.id" target="_blank">
<t t-esc="rec.name or '—'"/>
</a>
</td>
<td t-att-rowspan="rows"><t t-esc="rec.assigned_from_dept.name or '—'"/></td>
<td t-att-rowspan="rows"><t t-esc="rec.assigned_to_dept.name or '—'"/></td>
<td t-att-rowspan="rows"><div style="display:flex; align-items:center;">
<!-- User Image -->
<img t-att-src="'/web/image/%s/%s/image_1920' % (rec.assigned_by._name, rec.assigned_by.id)"
style="width:24px; height:24px; border-radius:50%; margin-right:5px;"/>
<!-- User Name -->
<t t-esc="rec.assigned_by.name or '—'"/>
</div></td>
<td t-att-rowspan="rows">
<div style="display:flex; align-items:center;">
<!-- User Image -->
<img t-att-src="'/web/image/%s/%s/image_1920' % (rec.responsible_person._name, rec.responsible_person.id)"
style="width:24px; height:24px; border-radius:50%; margin-right:5px;"/>
<!-- User Name -->
<t t-esc="rec.responsible_person.name or '—'"/>
</div>
</td>
<td class="nowrap" style="text-align:center;" t-att-rowspan="rows">
<t t-esc="rec.start_date and rec.start_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<td class="nowrap" style="text-align:center;" t-att-rowspan="rows"
t-attf-class="#{is_overdue and 'date-overdue' or (is_soon and 'date-soon' or 'date-ok')}">
<t t-esc="rec.target_date and rec.target_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<td class="nowrap" style="text-align:center;" t-att-rowspan="rows">
<t t-esc="rec.end_date and rec.end_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<!-- child plan + status (first child or dashes) -->
<td>
<t t-esc="(len(lines) and (lines[0].name or '—')) or '—'"/>
</td>
<td class="nowrap" style="text-align:center;">
<t t-esc="(len(lines) and (lines[0].target_date and lines[0].target_date.strftime('%d-%m-%Y') or '—')) or '—'"/>
</td>
<td>
<t t-esc="(len(lines) and (lines[0].result or '—')) or '—'"/>
</td>
<td style="text-align:center;">
<t t-if="len(lines)">
<span class="status-pill"
t-att-style="'background-color:#2e7d32; border-color:#bfe8c8;' if lines[0].status == 'close' else ''">
<t t-esc="dict(lines[0]._fields['status'].selection).get(lines[0].status, lines[0].status)"/>
</span>
</t>
<t t-else=""></t>
</td>
</tr>
<!-- extra child rows: ONLY the four child columns -->
<t t-if="len(lines) &gt; 1">
<t t-foreach="lines[1:]" t-as="ln">
<tr>
<td><t t-esc="ln.name or '—'"/></td>
<td class="nowrap" style="text-align:center;">
<t t-esc="ln.target_date and ln.target_date.strftime('%d-%m-%Y') or '—'"/>
</td>
<td><t t-esc="ln.result or '—'"/></td>
<td style="text-align:center;">
<span class="status-pill"
t-att-style="'background-color:#2e7d32; border-color:#bfe8c8;' if ln.status == 'close' else 'background-color:#e1375e;'">
<t t-esc="dict(ln._fields['status'].selection).get(ln.status, ln.status)"/>
</span>
</td>
</tr>
</t>
</t>
</t>
</t>
<t t-if="not cross or len(cross) == 0">
<!-- total columns = 12 -->
<tr><td colspan="9" style="text-align:center; color:#666; padding:12px;">No cross-department actions.</td></tr>
</t>
</tbody>
</table>
</t>
</div>
</t>
</t>
</template>
</odoo>