Tower: upload laundry_management 19.0.19.0.4 (via marketplace)

This commit is contained in:
2026-05-01 15:16:17 +00:00
parent e8760f7d0d
commit 422687b588

View File

@@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ════════════════════════════════════════════════════════════════
Laundry Reporting — extends standard Odoo dashboards.
────────────────────────────────────────────────────────────────
Strategy:
• Pure standard view types (graph + pivot) — no OWL, no
client action, no SCSS. Identical to the way
sale.order/account.move ship their analysis views.
• New menu items hang off the EXISTING reporting menus that
core already exposes:
sale.menu_sale_report (Sales → Reporting)
account.menu_finance_reports (Accounting → Reporting)
Plus a convenience entry under the Laundry app root.
• No view inheritance against core dashboards — adding our
own graph/pivot under their reporting menus is the safe,
standard pattern; overriding `account.dashboard.kanban`
would be invasive and version-fragile.
════════════════════════════════════════════════════════════════ -->
<!-- ── laundry.order — Operations & Financial graph/pivot ──────── -->
<record id="view_laundry_order_graph" model="ir.ui.view">
<field name="name">laundry.order.graph</field>
<field name="model">laundry.order</field>
<field name="arch" type="xml">
<graph string="Laundry Orders Analysis" type="bar"
stacked="0" sample="1">
<field name="create_date" interval="day" type="row"/>
<field name="state" type="col"/>
<field name="amount_total" type="measure"/>
<field name="amount_due" type="measure"/>
</graph>
</field>
</record>
<record id="view_laundry_order_pivot" model="ir.ui.view">
<field name="name">laundry.order.pivot</field>
<field name="model">laundry.order</field>
<field name="arch" type="xml">
<pivot string="Laundry Orders Analysis" sample="1">
<field name="create_date" interval="month" type="row"/>
<field name="state" type="col"/>
<field name="amount_total" type="measure"/>
<field name="amount_paid_cash" type="measure"/>
<field name="amount_due" type="measure"/>
<field name="item_count" type="measure"/>
</pivot>
</field>
</record>
<!-- Action: Sales-side analysis (orders + revenue + AOV via measures) -->
<record id="action_laundry_orders_reporting" model="ir.actions.act_window">
<field name="name">Laundry Orders</field>
<field name="res_model">laundry.order</field>
<field name="view_mode">graph,pivot,list,form</field>
<field name="view_ids" eval="[
(5, 0, 0),
(0, 0, {'view_mode': 'graph', 'view_id': ref('view_laundry_order_graph')}),
(0, 0, {'view_mode': 'pivot', 'view_id': ref('view_laundry_order_pivot')}),
(0, 0, {'view_mode': 'list', 'view_id': ref('view_laundry_order_list')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('view_laundry_order_form')}),
]"/>
<field name="search_view_id" ref="view_laundry_order_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No laundry orders for this period.
</p>
<p>
Switch to the Pivot view for a customer / month / state
breakdown, or use the date filters to narrow the range.
</p>
</field>
</record>
<!-- ── laundry.order — Operations-only KPI (Processing/Ready/Delayed) -->
<!-- Same model, different default filter — surfaces the operational
in-flight pipeline so the cashier / operator can spot bottlenecks. -->
<record id="action_laundry_operations_kpi" model="ir.actions.act_window">
<field name="name">Laundry Operations (Live)</field>
<field name="res_model">laundry.order</field>
<field name="view_mode">graph,pivot,list</field>
<field name="domain">[('state', 'in', ['intake', 'processing', 'ready'])]</field>
<field name="context">{'search_default_groupby_state': 1}</field>
<field name="view_ids" eval="[
(5, 0, 0),
(0, 0, {'view_mode': 'graph', 'view_id': ref('view_laundry_order_graph')}),
(0, 0, {'view_mode': 'pivot', 'view_id': ref('view_laundry_order_pivot')}),
(0, 0, {'view_mode': 'list', 'view_id': ref('view_laundry_order_list')}),
]"/>
<field name="search_view_id" ref="view_laundry_order_search"/>
</record>
<!-- ── account.move — Laundry-flagged invoices analysis ────────── -->
<!-- Uses the existing `is_laundry_invoice` computed flag on
account.move (from models/account_move.py). No new accounting
logic — pure read filter. -->
<record id="view_laundry_invoice_graph" model="ir.ui.view">
<field name="name">account.move.graph.laundry</field>
<field name="model">account.move</field>
<field name="arch" type="xml">
<graph string="Laundry Invoices" type="bar" stacked="0" sample="1">
<field name="invoice_date" interval="month" type="row"/>
<field name="state" type="col"/>
<field name="amount_total_signed" type="measure"/>
<field name="amount_residual_signed" type="measure"/>
</graph>
</field>
</record>
<record id="view_laundry_invoice_pivot" model="ir.ui.view">
<field name="name">account.move.pivot.laundry</field>
<field name="model">account.move</field>
<field name="arch" type="xml">
<pivot string="Laundry Invoices" sample="1">
<field name="partner_id" type="row"/>
<field name="invoice_date" interval="month" type="col"/>
<field name="amount_total_signed" type="measure"/>
<field name="amount_residual_signed" type="measure"/>
</pivot>
</field>
</record>
<record id="action_laundry_invoices_reporting" model="ir.actions.act_window">
<field name="name">Laundry Invoices</field>
<field name="res_model">account.move</field>
<field name="view_mode">graph,pivot,list,form</field>
<field name="domain">[
('is_laundry_invoice', '=', True),
('move_type', 'in', ('out_invoice', 'out_refund')),
]</field>
<field name="view_ids" eval="[
(5, 0, 0),
(0, 0, {'view_mode': 'graph', 'view_id': ref('view_laundry_invoice_graph')}),
(0, 0, {'view_mode': 'pivot', 'view_id': ref('view_laundry_invoice_pivot')}),
]"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No laundry invoices for this period.
</p>
<p>
Switch to the Pivot view for a customer / month
breakdown of revenue, settled, and outstanding.
</p>
</field>
</record>
<!-- ════════════════════════════════════════════════════════════════
MENU INTEGRATION — extend existing core reporting menus.
No menu override; pure additive child entries.
════════════════════════════════════════════════════════════════ -->
<!-- Sales → Reporting → Laundry Orders -->
<menuitem id="menu_sale_report_laundry_orders"
name="Laundry Orders"
parent="sale.menu_sale_report"
action="action_laundry_orders_reporting"
sequence="100"
groups="laundry_management.group_laundry_operator"/>
<!-- Accounting → Reporting → Laundry Invoices -->
<menuitem id="menu_finance_report_laundry_invoices"
name="Laundry Invoices"
parent="account.menu_finance_reports"
action="action_laundry_invoices_reporting"
sequence="100"
groups="laundry_management.group_laundry_manager"/>
<!-- Convenience entry under the Laundry app: same actions surfaced
here so operators don't have to hop into Sales/Accounting. -->
<menuitem id="menu_laundry_reports_root"
name="Reports"
parent="menu_laundry_root"
sequence="80"
groups="laundry_management.group_laundry_operator"/>
<menuitem id="menu_laundry_reports_orders"
name="Orders Analysis"
parent="menu_laundry_reports_root"
action="action_laundry_orders_reporting"
sequence="10"
groups="laundry_management.group_laundry_operator"/>
<menuitem id="menu_laundry_reports_operations"
name="Operations (Live)"
parent="menu_laundry_reports_root"
action="action_laundry_operations_kpi"
sequence="20"
groups="laundry_management.group_laundry_operator"/>
<menuitem id="menu_laundry_reports_invoices"
name="Invoices Analysis"
parent="menu_laundry_reports_root"
action="action_laundry_invoices_reporting"
sequence="30"
groups="laundry_management.group_laundry_manager"/>
</odoo>