add spreadsheet_dashboard_pos_cooperative & pos_dashboard_cooperative
This commit is contained in:
parent
86101218e9
commit
5247938b86
34 changed files with 7974 additions and 0 deletions
29
pos_dashboard_cooperative/README.md
Normal file
29
pos_dashboard_cooperative/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# POS Dashboard Cooperative
|
||||||
|
|
||||||
|
Real-time BI dashboards for cooperative supermarkets, built on top of
|
||||||
|
Point of Sale data.
|
||||||
|
|
||||||
|
This module extends `report.pos.order` with three new dimensions:
|
||||||
|
|
||||||
|
| Field | Description |
|
||||||
|
|---|---|
|
||||||
|
| `is_member_at_date` | True if the customer held a `share.line` whose `effective_date` was on or before the order date. |
|
||||||
|
| `categ_root_id` | Product family (root of `product.category` parent_path). |
|
||||||
|
| `categ_parent_id` | Product subfamily (parent of the leaf category). |
|
||||||
|
| `date_day` | Order date truncated to day. |
|
||||||
|
| `hour_of_day` | Hour of the order (`EXTRACT(HOUR FROM date_order)`). |
|
||||||
|
| `day_of_week` | Day of week, 1 = Monday … 7 = Sunday (ISO). |
|
||||||
|
|
||||||
|
Pre-configured menus under *Point of Sale → Reporting → Cooperative
|
||||||
|
Dashboards* cover overview, members vs. non-members, categories, top
|
||||||
|
products, and time distributions. Four tiles surface the headline KPIs
|
||||||
|
on the `web_dashboard_tile` board.
|
||||||
|
|
||||||
|
For spreadsheet dashboards published in Odoo's *Dashboards* menu, install
|
||||||
|
the companion module `spreadsheet_dashboard_pos_cooperative`.
|
||||||
|
|
||||||
|
See `readme/` for the OCA-style structured documentation.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
AGPL-3.0 or later.
|
||||||
1
pos_dashboard_cooperative/__init__.py
Normal file
1
pos_dashboard_cooperative/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from . import report
|
||||||
27
pos_dashboard_cooperative/__manifest__.py
Normal file
27
pos_dashboard_cooperative/__manifest__.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Copyright 2026 Criptomart
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
{
|
||||||
|
"name": "POS Dashboard Cooperative",
|
||||||
|
"version": "16.0.1.0.0",
|
||||||
|
"summary": "Real-time BI dashboards for cooperative supermarkets (POS)",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"author": "Criptomart, Odoo Community Association (OCA)",
|
||||||
|
"website": "https://github.com/OCA/pos",
|
||||||
|
"category": "Point of Sale",
|
||||||
|
"depends": [
|
||||||
|
"point_of_sale",
|
||||||
|
"cooperator",
|
||||||
|
"pos_margin",
|
||||||
|
"web_dashboard_tile",
|
||||||
|
"web_pivot_computed_measure",
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
"report/pos_order_report_views.xml",
|
||||||
|
"views/pos_order_report_member_views.xml",
|
||||||
|
"views/pos_order_report_category_views.xml",
|
||||||
|
"views/pos_order_report_time_views.xml",
|
||||||
|
"views/dashboard_tiles.xml",
|
||||||
|
"views/menus.xml",
|
||||||
|
],
|
||||||
|
"installable": True,
|
||||||
|
}
|
||||||
151
pos_dashboard_cooperative/i18n/es.po
Normal file
151
pos_dashboard_cooperative/i18n/es.po
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * pos_dashboard_cooperative
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: 2026-06-05 12:00+0000\n"
|
||||||
|
"Last-Translator: Criptomart\n"
|
||||||
|
"Language-Team: Spanish\n"
|
||||||
|
"Language: es\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_by_day_of_week
|
||||||
|
msgid "Sales by Day of Week"
|
||||||
|
msgstr "Ventas por día de la semana"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_by_hour
|
||||||
|
msgid "Sales by Hour of Day"
|
||||||
|
msgstr "Ventas por hora del día"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_categories
|
||||||
|
msgid "Sales by Category"
|
||||||
|
msgstr "Ventas por categoría"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_members
|
||||||
|
msgid "Members vs Non-members"
|
||||||
|
msgstr "Socios vs no socios"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_overview
|
||||||
|
msgid "Cooperative POS Overview"
|
||||||
|
msgstr "Vista general TPV cooperativa"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_top_members
|
||||||
|
msgid "Top Member Buyers"
|
||||||
|
msgstr "Top socias compradoras"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_top_products
|
||||||
|
msgid "Top Products"
|
||||||
|
msgstr "Top productos"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model,name:pos_dashboard_cooperative.model_report_pos_order
|
||||||
|
msgid "Point of Sale Orders Report"
|
||||||
|
msgstr "Informe de pedidos del TPV"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__categ_parent_id
|
||||||
|
msgid "Product Subfamily (parent)"
|
||||||
|
msgstr "Subfamilia de producto (padre)"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__categ_root_id
|
||||||
|
msgid "Product Family (root)"
|
||||||
|
msgstr "Familia de producto (raíz)"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__date_day
|
||||||
|
msgid "Order Day"
|
||||||
|
msgstr "Día del pedido"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__day_of_week
|
||||||
|
msgid "Day of Week (1=Mon, 7=Sun)"
|
||||||
|
msgstr "Día de la semana (1=lun, 7=dom)"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__hour_of_day
|
||||||
|
msgid "Hour of Day"
|
||||||
|
msgstr "Hora del día"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__is_member_at_date
|
||||||
|
msgid "Member at Order Date"
|
||||||
|
msgstr "Socio en la fecha del pedido"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_by_day
|
||||||
|
msgid "By Day of Week"
|
||||||
|
msgstr "Por día de la semana"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_by_hour
|
||||||
|
msgid "By Hour of Day"
|
||||||
|
msgstr "Por hora del día"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_categories
|
||||||
|
msgid "By Category"
|
||||||
|
msgstr "Por categoría"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_cooperative
|
||||||
|
msgid "Cooperative Dashboards"
|
||||||
|
msgstr "Tableros de la cooperativa"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_members
|
||||||
|
msgid "Members vs Non-members"
|
||||||
|
msgstr "Socios vs no socios"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_overview
|
||||||
|
msgid "Overview"
|
||||||
|
msgstr "Vista general"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_top_members
|
||||||
|
msgid "Top Members"
|
||||||
|
msgstr "Top socias"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_top_products
|
||||||
|
msgid "Top Products"
|
||||||
|
msgstr "Top productos"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.category,name:pos_dashboard_cooperative.tile_category_cooperative
|
||||||
|
msgid "Cooperative POS"
|
||||||
|
msgstr "TPV cooperativa"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_margin_last_30_days
|
||||||
|
msgid "Margin last 30 days (€)"
|
||||||
|
msgstr "Margen últimos 30 días (€)"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_sales_last_30_days
|
||||||
|
msgid "Sales last 30 days (€)"
|
||||||
|
msgstr "Ventas últimos 30 días (€)"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_sales_members_last_30_days
|
||||||
|
msgid "Members sales last 30 days (€)"
|
||||||
|
msgstr "Ventas a socias últimos 30 días (€)"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_sales_non_members_last_30_days
|
||||||
|
msgid "Non-members sales last 30 days (€)"
|
||||||
|
msgstr "Ventas a no socias últimos 30 días (€)"
|
||||||
149
pos_dashboard_cooperative/i18n/pos_dashboard_cooperative.pot
Normal file
149
pos_dashboard_cooperative/i18n/pos_dashboard_cooperative.pot
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * pos_dashboard_cooperative
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_by_day_of_week
|
||||||
|
msgid "Sales by Day of Week"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_by_hour
|
||||||
|
msgid "Sales by Hour of Day"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_categories
|
||||||
|
msgid "Sales by Category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_members
|
||||||
|
msgid "Members vs Non-members"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_overview
|
||||||
|
msgid "Cooperative POS Overview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_top_members
|
||||||
|
msgid "Top Member Buyers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.actions.act_window,name:pos_dashboard_cooperative.action_pos_dashboard_top_products
|
||||||
|
msgid "Top Products"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model,name:pos_dashboard_cooperative.model_report_pos_order
|
||||||
|
msgid "Point of Sale Orders Report"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__categ_parent_id
|
||||||
|
msgid "Product Subfamily (parent)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__categ_root_id
|
||||||
|
msgid "Product Family (root)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__date_day
|
||||||
|
msgid "Order Day"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__day_of_week
|
||||||
|
msgid "Day of Week (1=Mon, 7=Sun)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__hour_of_day
|
||||||
|
msgid "Hour of Day"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.model.fields,field_description:pos_dashboard_cooperative.field_report_pos_order__is_member_at_date
|
||||||
|
msgid "Member at Order Date"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_by_day
|
||||||
|
msgid "By Day of Week"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_by_hour
|
||||||
|
msgid "By Hour of Day"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_categories
|
||||||
|
msgid "By Category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_cooperative
|
||||||
|
msgid "Cooperative Dashboards"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_members
|
||||||
|
msgid "Members vs Non-members"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_overview
|
||||||
|
msgid "Overview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_top_members
|
||||||
|
msgid "Top Members"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:ir.ui.menu,name:pos_dashboard_cooperative.menu_pos_dashboard_top_products
|
||||||
|
msgid "Top Products"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.category,name:pos_dashboard_cooperative.tile_category_cooperative
|
||||||
|
msgid "Cooperative POS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_margin_last_30_days
|
||||||
|
msgid "Margin last 30 days (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_sales_last_30_days
|
||||||
|
msgid "Sales last 30 days (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_sales_members_last_30_days
|
||||||
|
msgid "Members sales last 30 days (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: pos_dashboard_cooperative
|
||||||
|
#: model:tile.tile,name:pos_dashboard_cooperative.tile_pos_sales_non_members_last_30_days
|
||||||
|
msgid "Non-members sales last 30 days (€)"
|
||||||
|
msgstr ""
|
||||||
7
pos_dashboard_cooperative/readme/CONFIGURE.rst
Normal file
7
pos_dashboard_cooperative/readme/CONFIGURE.rst
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
No specific configuration is required after installation. The module
|
||||||
|
auto-installs ``pos_margin``, ``web_dashboard_tile`` and
|
||||||
|
``web_pivot_computed_measure`` if they are not already present.
|
||||||
|
|
||||||
|
To control who sees the new dashboards, adjust the standard POS
|
||||||
|
security groups (``point_of_sale.group_pos_manager``) — the new analyses
|
||||||
|
inherit the access rules already in place for ``report.pos.order``.
|
||||||
1
pos_dashboard_cooperative/readme/CONTRIBUTORS.rst
Normal file
1
pos_dashboard_cooperative/readme/CONTRIBUTORS.rst
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
* Criptomart <https://criptomart.net>
|
||||||
24
pos_dashboard_cooperative/readme/DESCRIPTION.rst
Normal file
24
pos_dashboard_cooperative/readme/DESCRIPTION.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
Real-time Business Intelligence dashboards for cooperative supermarkets
|
||||||
|
built on top of Point of Sale data. Extends the standard
|
||||||
|
``report.pos.order`` view to expose new dimensions that the standard POS
|
||||||
|
analysis lacks:
|
||||||
|
|
||||||
|
* **Cooperative member dimension** — ``is_member_at_date`` flags each
|
||||||
|
ticket line according to the customer's share status *at the order
|
||||||
|
date*, so historic comparisons (members vs. non-members) reflect the
|
||||||
|
reality of the moment.
|
||||||
|
* **Category hierarchy** — ``categ_root_id`` (family) and
|
||||||
|
``categ_parent_id`` (subfamily) derived from
|
||||||
|
``product.category.parent_path``, ready to drive drilldowns.
|
||||||
|
* **Time dimensions** — ``date_day``, ``hour_of_day``, ``day_of_week``
|
||||||
|
for daily/weekly/hourly distributions.
|
||||||
|
|
||||||
|
Pre-configured menu entries under *Point of Sale → Reporting →
|
||||||
|
Cooperative Dashboards* cover overview, members vs. non-members,
|
||||||
|
categories, top products, day-of-week and hour-of-day analyses. Four
|
||||||
|
dashboard tiles surface the most important KPIs on the
|
||||||
|
``web_dashboard_tile`` board.
|
||||||
|
|
||||||
|
The companion module ``spreadsheet_dashboard_pos_cooperative`` publishes
|
||||||
|
spreadsheet dashboards in Odoo's *Dashboards* menu that consume the
|
||||||
|
same data.
|
||||||
12
pos_dashboard_cooperative/readme/ROADMAP.rst
Normal file
12
pos_dashboard_cooperative/readme/ROADMAP.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
* Materialize the SQL view into a regular table populated by a nightly
|
||||||
|
cron, in case real-time aggregation becomes too slow on very large
|
||||||
|
POS datasets.
|
||||||
|
* Refine the ``is_member_at_date`` calculation by consuming
|
||||||
|
``subscription.register`` to subtract sell-back and transfer
|
||||||
|
operations from the share balance. The current implementation simply
|
||||||
|
checks for the existence of a ``share.line`` dated on or before the
|
||||||
|
order date, which over-reports memberships when shares are returned.
|
||||||
|
* Add multi-company test coverage once a clean multi-company test
|
||||||
|
fixture is available.
|
||||||
|
* Add Galician, Catalan, French, Dutch and Croatian translations
|
||||||
|
(currently shipped with Spanish only).
|
||||||
39
pos_dashboard_cooperative/readme/USAGE.rst
Normal file
39
pos_dashboard_cooperative/readme/USAGE.rst
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
Open *Point of Sale → Reporting → Cooperative Dashboards* and pick one
|
||||||
|
of the predefined analyses:
|
||||||
|
|
||||||
|
* **Overview** — sales, margin and order count grouped by month.
|
||||||
|
* **Members vs Non-members** — same axes split by cooperative
|
||||||
|
membership at the order date.
|
||||||
|
* **Top Members** — sales aggregated per cooperative member, sort by
|
||||||
|
total to obtain the top buyers.
|
||||||
|
* **By Category** — sales by product family (root category); drill down
|
||||||
|
to subfamily and product from the *Group By* menu.
|
||||||
|
* **Top Products** — sales per product.
|
||||||
|
* **By Day of Week / By Hour of Day** — temporal distributions.
|
||||||
|
|
||||||
|
In every view, additional dimensions are available from the *Filters*
|
||||||
|
and *Group By* menus: ``Members``, ``Non members``, ``Member``,
|
||||||
|
``Product Family``, ``Product Subfamily``, ``Day of Week``,
|
||||||
|
``Hour of Day``.
|
||||||
|
|
||||||
|
Time dimensions
|
||||||
|
===============
|
||||||
|
|
||||||
|
* ``day_of_week`` is the ISO day number (``EXTRACT(ISODOW FROM
|
||||||
|
date_order)``): **1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 =
|
||||||
|
Thursday, 5 = Friday, 6 = Saturday, 7 = Sunday**.
|
||||||
|
* ``hour_of_day`` is the integer hour in the order's timezone
|
||||||
|
(``EXTRACT(HOUR FROM date_order)``), 0..23.
|
||||||
|
|
||||||
|
These are deliberately exposed as integers rather than translated
|
||||||
|
labels so they aggregate cleanly in pivots, charts and spreadsheet
|
||||||
|
formulas. Map the numbers to weekday names in the consumer (for
|
||||||
|
example, in the o-spreadsheet dashboards) if a localized label is
|
||||||
|
needed.
|
||||||
|
|
||||||
|
Pivot views support the ratios defined by ``web_pivot_computed_measure``
|
||||||
|
(e.g. average ticket = total sales / order count). Click *Insert
|
||||||
|
Computed Measure* in the pivot's *Measures* menu.
|
||||||
|
|
||||||
|
For curated dashboards rendered in Odoo's *Dashboards* menu, install
|
||||||
|
the companion module ``spreadsheet_dashboard_pos_cooperative``.
|
||||||
1
pos_dashboard_cooperative/report/__init__.py
Normal file
1
pos_dashboard_cooperative/report/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from . import pos_order_report
|
||||||
130
pos_dashboard_cooperative/report/pos_order_report.py
Normal file
130
pos_dashboard_cooperative/report/pos_order_report.py
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
# Copyright 2026 Criptomart
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import fields, models
|
||||||
|
|
||||||
|
|
||||||
|
class PosOrderReport(models.Model):
|
||||||
|
_inherit = "report.pos.order"
|
||||||
|
|
||||||
|
# --- Time dimensions ----------------------------------------------------
|
||||||
|
date_day = fields.Date(
|
||||||
|
string="Order Day",
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
hour_of_day = fields.Integer(
|
||||||
|
string="Hour of Day",
|
||||||
|
readonly=True,
|
||||||
|
group_operator=None,
|
||||||
|
)
|
||||||
|
day_of_week = fields.Integer(
|
||||||
|
string="Day of Week (1=Mon, 7=Sun)",
|
||||||
|
readonly=True,
|
||||||
|
group_operator=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Category hierarchy -------------------------------------------------
|
||||||
|
# Family = root category, subfamily = direct parent of categ_id.
|
||||||
|
# Computed from product.category.parent_path (materialized path
|
||||||
|
# "1/3/7/"), which is maintained automatically by Odoo (_parent_store).
|
||||||
|
categ_root_id = fields.Many2one(
|
||||||
|
"product.category",
|
||||||
|
string="Product Family (root)",
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
categ_root_id_int = fields.Integer(
|
||||||
|
string="Product Family ID (root)",
|
||||||
|
readonly=True,
|
||||||
|
group_operator=None,
|
||||||
|
)
|
||||||
|
categ_parent_id = fields.Many2one(
|
||||||
|
"product.category",
|
||||||
|
string="Product Subfamily (parent)",
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
categ_parent_id_int = fields.Integer(
|
||||||
|
string="Product Subfamily ID (parent)",
|
||||||
|
readonly=True,
|
||||||
|
group_operator=None,
|
||||||
|
)
|
||||||
|
product_categ_id_int = fields.Integer(
|
||||||
|
string="Product Category ID (leaf)",
|
||||||
|
readonly=True,
|
||||||
|
group_operator=None,
|
||||||
|
)
|
||||||
|
product_id_int = fields.Integer(
|
||||||
|
string="Product ID",
|
||||||
|
readonly=True,
|
||||||
|
group_operator=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Cooperative member dimension --------------------------------------
|
||||||
|
# True when the customer of the ticket held at least one share line whose
|
||||||
|
# effective_date was on or before the order date, in the same company.
|
||||||
|
#
|
||||||
|
# NOTE: this is an approximation. cooperator does not store an end date
|
||||||
|
# on share.line; share buy-backs and transfers are recorded only in
|
||||||
|
# subscription.register. A future version may refine the calculation by
|
||||||
|
# consuming subscription.register to substract sell_back/transfer
|
||||||
|
# operations, at the cost of a more expensive subquery.
|
||||||
|
is_member_at_date = fields.Boolean(
|
||||||
|
string="Member at Order Date",
|
||||||
|
readonly=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _select(self):
|
||||||
|
return (
|
||||||
|
super()._select()
|
||||||
|
+ """,
|
||||||
|
s.date_order::date AS date_day,
|
||||||
|
EXTRACT(HOUR FROM (s.date_order AT TIME ZONE 'UTC') AT TIME ZONE 'Europe/Madrid')::int AS hour_of_day,
|
||||||
|
EXTRACT(ISODOW FROM s.date_order)::int AS day_of_week,
|
||||||
|
cat_root.id AS categ_root_id,
|
||||||
|
cat_root.id AS categ_root_id_int,
|
||||||
|
pt_categ.parent_id AS categ_parent_id,
|
||||||
|
pt_categ.parent_id AS categ_parent_id_int,
|
||||||
|
pt.categ_id AS product_categ_id_int,
|
||||||
|
pt.id AS product_id_int,
|
||||||
|
CASE WHEN EXISTS (
|
||||||
|
SELECT 1 FROM share_line sl
|
||||||
|
WHERE sl.partner_id = s.partner_id
|
||||||
|
AND sl.company_id = s.company_id
|
||||||
|
AND sl.effective_date IS NOT NULL
|
||||||
|
AND sl.effective_date <= s.date_order::date
|
||||||
|
) THEN TRUE ELSE FALSE END AS is_member_at_date
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def _from(self):
|
||||||
|
# Extra joins to resolve:
|
||||||
|
# - pt_categ: direct category of the product (used for parent_id and
|
||||||
|
# parent_path lookup).
|
||||||
|
# - cat_root: root category, found by taking the first id in
|
||||||
|
# parent_path. parent_path looks like "1/3/7/".
|
||||||
|
return (
|
||||||
|
super()._from()
|
||||||
|
+ """
|
||||||
|
LEFT JOIN product_category pt_categ ON pt_categ.id = pt.categ_id
|
||||||
|
LEFT JOIN product_category cat_root
|
||||||
|
ON cat_root.id = NULLIF(
|
||||||
|
split_part(pt_categ.parent_path, '/', 1), ''
|
||||||
|
)::int
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
def _group_by(self):
|
||||||
|
# Append non-aggregated expressions added in _select() that are not
|
||||||
|
# already in the parent GROUP BY. s.date_order is already there
|
||||||
|
# (point_of_sale.report.pos_order_report._group_by), so the time
|
||||||
|
# dimensions derived from it (date_day, hour_of_day, day_of_week)
|
||||||
|
# are functionally dependent and don't need to be listed.
|
||||||
|
# is_member_at_date is a scalar subquery; not needed either.
|
||||||
|
return (
|
||||||
|
super()._group_by()
|
||||||
|
+ """,
|
||||||
|
cat_root.id,
|
||||||
|
pt_categ.parent_id,
|
||||||
|
pt.categ_id,
|
||||||
|
pt.id
|
||||||
|
"""
|
||||||
|
)
|
||||||
125
pos_dashboard_cooperative/report/pos_order_report_views.xml
Normal file
125
pos_dashboard_cooperative/report/pos_order_report_views.xml
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Extend the core search view to expose:
|
||||||
|
- Member dimension filters (members / non-members)
|
||||||
|
- Category hierarchy group-bys (family, subfamily)
|
||||||
|
- Time dimension group-bys (day of week, hour of day)
|
||||||
|
- Filters by company (since this module is multi-company aware)
|
||||||
|
-->
|
||||||
|
<record id="report_pos_order_view_search" model="ir.ui.view">
|
||||||
|
<field name="name">report.pos.order.search.cooperative</field>
|
||||||
|
<field name="model">report.pos.order</field>
|
||||||
|
<field name="inherit_id" ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//filter[@name='not_invoiced']" position="after">
|
||||||
|
<separator/>
|
||||||
|
<filter
|
||||||
|
string="Members"
|
||||||
|
name="members"
|
||||||
|
domain="[('is_member_at_date', '=', True)]"
|
||||||
|
/>
|
||||||
|
<filter
|
||||||
|
string="Non members"
|
||||||
|
name="non_members"
|
||||||
|
domain="[('is_member_at_date', '=', False)]"
|
||||||
|
/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//group" position="inside">
|
||||||
|
<separator/>
|
||||||
|
<filter
|
||||||
|
string="Member"
|
||||||
|
name="group_member"
|
||||||
|
context="{'group_by': 'is_member_at_date'}"
|
||||||
|
/>
|
||||||
|
<filter
|
||||||
|
string="Product Family"
|
||||||
|
name="group_categ_root"
|
||||||
|
context="{'group_by': 'categ_root_id'}"
|
||||||
|
/>
|
||||||
|
<filter
|
||||||
|
string="Product Subfamily"
|
||||||
|
name="group_categ_parent"
|
||||||
|
context="{'group_by': 'categ_parent_id'}"
|
||||||
|
/>
|
||||||
|
<separator/>
|
||||||
|
<filter
|
||||||
|
string="Day of Week"
|
||||||
|
name="group_day_of_week"
|
||||||
|
context="{'group_by': 'day_of_week'}"
|
||||||
|
/>
|
||||||
|
<filter
|
||||||
|
string="Hour of Day"
|
||||||
|
name="group_hour_of_day"
|
||||||
|
context="{'group_by': 'hour_of_day'}"
|
||||||
|
/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Extend the core pivot view to include the most useful measures for
|
||||||
|
a cooperative supermarket dashboard: price total (sales), margin,
|
||||||
|
margin rate and order count. Members vs non-members can then be
|
||||||
|
compared by adding the "Member" group-by from the search bar.
|
||||||
|
-->
|
||||||
|
<record id="report_pos_order_view_pivot" model="ir.ui.view">
|
||||||
|
<field name="name">report.pos.order.pivot.cooperative</field>
|
||||||
|
<field name="model">report.pos.order</field>
|
||||||
|
<field name="inherit_id" ref="point_of_sale.view_report_pos_order_pivot"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='price_total']" position="after">
|
||||||
|
<field name="margin" type="measure"/>
|
||||||
|
<field name="margin_rate" type="measure"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Extend the core tree view to expose the new dimensions as optional
|
||||||
|
columns so users can toggle them without changing the default UI.
|
||||||
|
-->
|
||||||
|
<record id="report_pos_order_view_tree" model="ir.ui.view">
|
||||||
|
<field name="name">report.pos.order.tree.cooperative</field>
|
||||||
|
<field name="model">report.pos.order</field>
|
||||||
|
<field name="inherit_id" ref="point_of_sale.report_pos_order_view_tree"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//field[@name='product_categ_id']" position="after">
|
||||||
|
<field name="categ_root_id" optional="hide"/>
|
||||||
|
<field name="categ_parent_id" optional="hide"/>
|
||||||
|
<field name="is_member_at_date" optional="show"/>
|
||||||
|
<field name="hour_of_day" optional="hide"/>
|
||||||
|
<field name="day_of_week" optional="hide"/>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Cooperative-flavoured action over report.pos.order. Defaults to a
|
||||||
|
graph view grouped by month, with the most relevant measures
|
||||||
|
pre-selected. Pivot + tree are also available.
|
||||||
|
-->
|
||||||
|
<record id="action_pos_dashboard_overview" model="ir.actions.act_window">
|
||||||
|
<field name="name">Cooperative POS Overview</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">graph,pivot,tree</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="context">{
|
||||||
|
'search_default_order_month': 1,
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
'group_by': [],
|
||||||
|
}</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
No data yet!
|
||||||
|
</p><p>
|
||||||
|
Sell some products at the Point of Sale to populate this
|
||||||
|
cooperative dashboard.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
1
pos_dashboard_cooperative/tests/__init__.py
Normal file
1
pos_dashboard_cooperative/tests/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
from . import test_pos_dashboard
|
||||||
215
pos_dashboard_cooperative/tests/test_pos_dashboard.py
Normal file
215
pos_dashboard_cooperative/tests/test_pos_dashboard.py
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
# Copyright 2026 Criptomart
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
import odoo
|
||||||
|
from odoo.tests.common import TransactionCase
|
||||||
|
|
||||||
|
|
||||||
|
@odoo.tests.tagged("post_install", "-at_install")
|
||||||
|
class TestPosDashboardCooperative(TransactionCase):
|
||||||
|
"""Validate the extra dimensions added by pos_dashboard_cooperative on
|
||||||
|
top of point_of_sale.report.pos.order:
|
||||||
|
|
||||||
|
- time dimensions (date_day, hour_of_day, day_of_week)
|
||||||
|
- product category hierarchy (categ_root_id, categ_parent_id)
|
||||||
|
- cooperative member historic flag (is_member_at_date)
|
||||||
|
|
||||||
|
These tests use a minimal hand-built pos.session to stay independent
|
||||||
|
from any existing data in the database and from the heavy
|
||||||
|
TestPoSCommon setup machinery, which requires a clean accounting
|
||||||
|
setup.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
cls.company = cls.env.ref("base.main_company")
|
||||||
|
|
||||||
|
# Two-level category hierarchy: family -> subfamily -> leaf
|
||||||
|
cls.family_root = cls.env["product.category"].create(
|
||||||
|
{"name": "DASHBOARD-FAMILY-ROOT"}
|
||||||
|
)
|
||||||
|
cls.subfamily = cls.env["product.category"].create(
|
||||||
|
{"name": "DASHBOARD-SUBFAMILY", "parent_id": cls.family_root.id}
|
||||||
|
)
|
||||||
|
cls.categ_leaf = cls.env["product.category"].create(
|
||||||
|
{"name": "DASHBOARD-LEAF", "parent_id": cls.subfamily.id}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Product sold at the POS in every test.
|
||||||
|
cls.product = cls.env["product.product"].create(
|
||||||
|
{
|
||||||
|
"name": "DASHBOARD-PRODUCT",
|
||||||
|
"type": "consu",
|
||||||
|
"available_in_pos": True,
|
||||||
|
"list_price": 10.0,
|
||||||
|
"standard_price": 6.0,
|
||||||
|
"categ_id": cls.categ_leaf.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Share product needed by cooperator.share.line.
|
||||||
|
cls.share_product = cls.env["product.product"].create(
|
||||||
|
{
|
||||||
|
"name": "DASHBOARD-SHARE",
|
||||||
|
"is_share": True,
|
||||||
|
"type": "service",
|
||||||
|
"list_price": 25.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Two partners: one cooperative member (share dated in the past)
|
||||||
|
# and one non-member.
|
||||||
|
cls.member_partner = cls.env["res.partner"].create(
|
||||||
|
{"name": "DASHBOARD-MEMBER"}
|
||||||
|
)
|
||||||
|
cls.non_member_partner = cls.env["res.partner"].create(
|
||||||
|
{"name": "DASHBOARD-NON-MEMBER"}
|
||||||
|
)
|
||||||
|
cls.env["share.line"].create(
|
||||||
|
{
|
||||||
|
"partner_id": cls.member_partner.id,
|
||||||
|
"share_product_id": cls.share_product.id,
|
||||||
|
"share_number": 1,
|
||||||
|
"share_unit_price": 25.0,
|
||||||
|
"effective_date": date.today() - timedelta(days=365),
|
||||||
|
"company_id": cls.company.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reuse an existing POS config to avoid bootstrapping payment
|
||||||
|
# methods and journals from scratch. Any installed config is
|
||||||
|
# acceptable since we never go through the POS UI.
|
||||||
|
cls.pos_config = cls.env["pos.config"].search(
|
||||||
|
[("company_id", "=", cls.company.id)], limit=1
|
||||||
|
)
|
||||||
|
assert cls.pos_config, "A pos.config in the main company is required."
|
||||||
|
if not cls.pos_config.current_session_id:
|
||||||
|
cls.pos_config.open_ui()
|
||||||
|
cls.pos_session = cls.pos_config.current_session_id
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Helpers
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
def _create_pos_order(self, partner):
|
||||||
|
return self.env["pos.order"].create(
|
||||||
|
{
|
||||||
|
"session_id": self.pos_session.id,
|
||||||
|
"partner_id": partner.id,
|
||||||
|
"company_id": self.company.id,
|
||||||
|
"lines": [
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
"name": "DASHBOARD-OL",
|
||||||
|
"product_id": self.product.id,
|
||||||
|
"price_unit": 10.0,
|
||||||
|
"discount": 0,
|
||||||
|
"qty": 1.0,
|
||||||
|
"price_subtotal": 10.0,
|
||||||
|
"price_subtotal_incl": 10.0,
|
||||||
|
"total_cost": 6.0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
"amount_total": 10.0,
|
||||||
|
"amount_tax": 0.0,
|
||||||
|
"amount_paid": 0.0,
|
||||||
|
"amount_return": 0.0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _reports_for(self, partner):
|
||||||
|
return (
|
||||||
|
self.env["report.pos.order"]
|
||||||
|
.sudo()
|
||||||
|
.search(
|
||||||
|
[
|
||||||
|
("product_id", "=", self.product.id),
|
||||||
|
("partner_id", "=", partner.id),
|
||||||
|
],
|
||||||
|
order="id",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# Tests
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
def test_member_flag_for_member_partner(self):
|
||||||
|
"""Partner with a share line predating the order is flagged as
|
||||||
|
member."""
|
||||||
|
self._create_pos_order(self.member_partner)
|
||||||
|
reports = self._reports_for(self.member_partner)
|
||||||
|
self.assertTrue(reports)
|
||||||
|
self.assertTrue(reports[0].is_member_at_date)
|
||||||
|
|
||||||
|
def test_member_flag_for_non_member_partner(self):
|
||||||
|
"""Partner without any share line is not flagged as member."""
|
||||||
|
self._create_pos_order(self.non_member_partner)
|
||||||
|
reports = self._reports_for(self.non_member_partner)
|
||||||
|
self.assertTrue(reports)
|
||||||
|
self.assertFalse(reports[0].is_member_at_date)
|
||||||
|
|
||||||
|
def test_member_flag_is_historic(self):
|
||||||
|
"""Share line dated AFTER the order date does not mark the partner
|
||||||
|
as member for that order."""
|
||||||
|
future_member = self.env["res.partner"].create(
|
||||||
|
{"name": "DASHBOARD-FUTURE-MEMBER"}
|
||||||
|
)
|
||||||
|
self._create_pos_order(future_member)
|
||||||
|
self.env["share.line"].create(
|
||||||
|
{
|
||||||
|
"partner_id": future_member.id,
|
||||||
|
"share_product_id": self.share_product.id,
|
||||||
|
"share_number": 1,
|
||||||
|
"share_unit_price": 25.0,
|
||||||
|
"effective_date": date.today() + timedelta(days=30),
|
||||||
|
"company_id": self.company.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
reports = self._reports_for(future_member)
|
||||||
|
self.assertTrue(reports)
|
||||||
|
self.assertFalse(
|
||||||
|
reports[0].is_member_at_date,
|
||||||
|
"Member flag must reflect the situation at order date.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_category_hierarchy_is_resolved(self):
|
||||||
|
"""categ_root_id and categ_parent_id reflect the product category
|
||||||
|
ancestors derived from parent_path."""
|
||||||
|
self._create_pos_order(self.member_partner)
|
||||||
|
reports = self._reports_for(self.member_partner)
|
||||||
|
self.assertTrue(reports)
|
||||||
|
report = reports[0]
|
||||||
|
self.assertEqual(report.categ_root_id, self.family_root)
|
||||||
|
self.assertEqual(report.categ_parent_id, self.subfamily)
|
||||||
|
|
||||||
|
def test_time_dimensions_are_populated(self):
|
||||||
|
"""date_day matches order date; hour_of_day / day_of_week are in
|
||||||
|
valid ranges."""
|
||||||
|
self._create_pos_order(self.member_partner)
|
||||||
|
reports = self._reports_for(self.member_partner)
|
||||||
|
self.assertTrue(reports)
|
||||||
|
report = reports[0]
|
||||||
|
self.assertIsNotNone(report.date_day)
|
||||||
|
self.assertGreaterEqual(report.hour_of_day, 0)
|
||||||
|
self.assertLess(report.hour_of_day, 24)
|
||||||
|
self.assertGreaterEqual(report.day_of_week, 1)
|
||||||
|
self.assertLessEqual(report.day_of_week, 7)
|
||||||
|
|
||||||
|
def test_read_group_by_member_flag(self):
|
||||||
|
"""Aggregations grouped by the member flag return one row per
|
||||||
|
member status when both kinds of partners have purchased."""
|
||||||
|
self._create_pos_order(self.member_partner)
|
||||||
|
self._create_pos_order(self.non_member_partner)
|
||||||
|
results = self.env["report.pos.order"].read_group(
|
||||||
|
[("product_id", "=", self.product.id)],
|
||||||
|
["price_total", "is_member_at_date"],
|
||||||
|
["is_member_at_date"],
|
||||||
|
)
|
||||||
|
statuses = {r["is_member_at_date"] for r in results}
|
||||||
|
self.assertIn(True, statuses)
|
||||||
|
self.assertIn(False, statuses)
|
||||||
104
pos_dashboard_cooperative/views/dashboard_tiles.xml
Normal file
104
pos_dashboard_cooperative/views/dashboard_tiles.xml
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo noupdate="1">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Tile categories shown in the dashboard.
|
||||||
|
Two categories: a "members" one (members only) and a generic one
|
||||||
|
for global sales KPIs.
|
||||||
|
-->
|
||||||
|
<record id="tile_category_cooperative" model="tile.category">
|
||||||
|
<field name="name">Cooperative POS</field>
|
||||||
|
<field name="sequence">100</field>
|
||||||
|
<field name="active" eval="True"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Tile: Total sales (excluding refunds).
|
||||||
|
Sums price_total over the last 30 days. Uses paid/done/invoiced
|
||||||
|
states to exclude drafts and cancellations.
|
||||||
|
|
||||||
|
NOTE on accuracy: tile.tile counts/aggregates records of the
|
||||||
|
target model. report.pos.order is at line granularity, so:
|
||||||
|
- SUM(price_total) is correctly the total amount sold.
|
||||||
|
- COUNT() would count *lines*, not tickets. To count tickets we
|
||||||
|
would need DISTINCT order_id which tile.tile does not support.
|
||||||
|
Use the pivot views for ticket-accurate metrics; tiles are
|
||||||
|
intentionally limited to monetary KPIs that aggregate by simple
|
||||||
|
SUM over lines.
|
||||||
|
-->
|
||||||
|
<record id="tile_pos_sales_last_30_days" model="tile.tile">
|
||||||
|
<field name="name">Sales last 30 days (€)</field>
|
||||||
|
<field name="sequence">10</field>
|
||||||
|
<field name="category_id" ref="tile_category_cooperative"/>
|
||||||
|
<field name="model_id" ref="point_of_sale.model_report_pos_order"/>
|
||||||
|
<field name="action_id" ref="action_pos_dashboard_overview"/>
|
||||||
|
<field name="primary_function">sum</field>
|
||||||
|
<field name="primary_field_id"
|
||||||
|
ref="point_of_sale.field_report_pos_order__price_total"/>
|
||||||
|
<field name="primary_format">{:,.2f} €</field>
|
||||||
|
<field
|
||||||
|
name="domain"
|
||||||
|
>[('state', 'in', ['paid', 'done', 'invoiced']),
|
||||||
|
('date', '>=', (context_today - relativedelta(days=30)).strftime('%Y-%m-%d'))]</field>
|
||||||
|
<field name="background_color">#2E7D32</field>
|
||||||
|
<field name="font_color">#FFFFFF</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="tile_pos_margin_last_30_days" model="tile.tile">
|
||||||
|
<field name="name">Margin last 30 days (€)</field>
|
||||||
|
<field name="sequence">20</field>
|
||||||
|
<field name="category_id" ref="tile_category_cooperative"/>
|
||||||
|
<field name="model_id" ref="point_of_sale.model_report_pos_order"/>
|
||||||
|
<field name="action_id" ref="action_pos_dashboard_overview"/>
|
||||||
|
<field name="primary_function">sum</field>
|
||||||
|
<field name="primary_field_id"
|
||||||
|
ref="point_of_sale.field_report_pos_order__margin"/>
|
||||||
|
<field name="primary_format">{:,.2f} €</field>
|
||||||
|
<field
|
||||||
|
name="domain"
|
||||||
|
>[('state', 'in', ['paid', 'done', 'invoiced']),
|
||||||
|
('date', '>=', (context_today - relativedelta(days=30)).strftime('%Y-%m-%d'))]</field>
|
||||||
|
<field name="background_color">#1565C0</field>
|
||||||
|
<field name="font_color">#FFFFFF</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="tile_pos_sales_members_last_30_days" model="tile.tile">
|
||||||
|
<field name="name">Members sales last 30 days (€)</field>
|
||||||
|
<field name="sequence">30</field>
|
||||||
|
<field name="category_id" ref="tile_category_cooperative"/>
|
||||||
|
<field name="model_id" ref="point_of_sale.model_report_pos_order"/>
|
||||||
|
<field name="action_id" ref="action_pos_dashboard_members"/>
|
||||||
|
<field name="primary_function">sum</field>
|
||||||
|
<field name="primary_field_id"
|
||||||
|
ref="point_of_sale.field_report_pos_order__price_total"/>
|
||||||
|
<field name="primary_format">{:,.2f} €</field>
|
||||||
|
<field
|
||||||
|
name="domain"
|
||||||
|
>[('state', 'in', ['paid', 'done', 'invoiced']),
|
||||||
|
('is_member_at_date', '=', True),
|
||||||
|
('date', '>=', (context_today - relativedelta(days=30)).strftime('%Y-%m-%d'))]</field>
|
||||||
|
<field name="background_color">#EF6C00</field>
|
||||||
|
<field name="font_color">#FFFFFF</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="tile_pos_sales_non_members_last_30_days" model="tile.tile">
|
||||||
|
<field name="name">Non-members sales last 30 days (€)</field>
|
||||||
|
<field name="sequence">40</field>
|
||||||
|
<field name="category_id" ref="tile_category_cooperative"/>
|
||||||
|
<field name="model_id" ref="point_of_sale.model_report_pos_order"/>
|
||||||
|
<field name="action_id" ref="action_pos_dashboard_members"/>
|
||||||
|
<field name="primary_function">sum</field>
|
||||||
|
<field name="primary_field_id"
|
||||||
|
ref="point_of_sale.field_report_pos_order__price_total"/>
|
||||||
|
<field name="primary_format">{:,.2f} €</field>
|
||||||
|
<field
|
||||||
|
name="domain"
|
||||||
|
>[('state', 'in', ['paid', 'done', 'invoiced']),
|
||||||
|
('is_member_at_date', '=', False),
|
||||||
|
('date', '>=', (context_today - relativedelta(days=30)).strftime('%Y-%m-%d'))]</field>
|
||||||
|
<field name="background_color">#6A1B9A</field>
|
||||||
|
<field name="font_color">#FFFFFF</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
68
pos_dashboard_cooperative/views/menus.xml
Normal file
68
pos_dashboard_cooperative/views/menus.xml
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_cooperative"
|
||||||
|
name="Cooperative Dashboards"
|
||||||
|
parent="point_of_sale.menu_point_rep"
|
||||||
|
sequence="50"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_overview"
|
||||||
|
name="Overview"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_overview"
|
||||||
|
sequence="10"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_members"
|
||||||
|
name="Members vs Non-members"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_members"
|
||||||
|
sequence="20"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_top_members"
|
||||||
|
name="Top Members"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_top_members"
|
||||||
|
sequence="30"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_categories"
|
||||||
|
name="By Category"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_categories"
|
||||||
|
sequence="40"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_top_products"
|
||||||
|
name="Top Products"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_top_products"
|
||||||
|
sequence="50"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_by_day"
|
||||||
|
name="By Day of Week"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_by_day_of_week"
|
||||||
|
sequence="60"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
id="menu_pos_dashboard_by_hour"
|
||||||
|
name="By Hour of Day"
|
||||||
|
parent="menu_pos_dashboard_cooperative"
|
||||||
|
action="action_pos_dashboard_by_hour"
|
||||||
|
sequence="70"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Category analysis: sales broken down by family (root), subfamily
|
||||||
|
(parent of leaf), and leaf category. Designed to answer the
|
||||||
|
"category traction" and "top families" questions from the BI brief.
|
||||||
|
-->
|
||||||
|
<record id="action_pos_dashboard_categories" model="ir.actions.act_window">
|
||||||
|
<field name="name">Sales by Category</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">pivot,graph,tree</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="context">{
|
||||||
|
'search_default_group_categ_root': 1,
|
||||||
|
'search_default_order_month': 1,
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
}</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
No data yet!
|
||||||
|
</p><p>
|
||||||
|
Add Subfamily or Product group-bys to drill down. Useful
|
||||||
|
to detect tractor categories.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_pos_dashboard_top_products" model="ir.actions.act_window">
|
||||||
|
<field name="name">Top Products</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">pivot,tree,graph</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="context">{
|
||||||
|
'group_by': ['product_id'],
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Members vs non-members comparison.
|
||||||
|
Opens the analysis pre-grouped by member flag and by month, with
|
||||||
|
sales / orders / margin as primary measures.
|
||||||
|
-->
|
||||||
|
<record id="action_pos_dashboard_members" model="ir.actions.act_window">
|
||||||
|
<field name="name">Members vs Non-members</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">pivot,graph,tree</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="context">{
|
||||||
|
'search_default_group_member': 1,
|
||||||
|
'search_default_order_month': 1,
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
}</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
No data yet!
|
||||||
|
</p><p>
|
||||||
|
This view contrasts cooperative members and non-members on
|
||||||
|
the same axes (sales, ticket count, margin).
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Detail per member: top buyers, per-partner KPIs.
|
||||||
|
Filters to members only and groups by partner.
|
||||||
|
-->
|
||||||
|
<record id="action_pos_dashboard_top_members" model="ir.actions.act_window">
|
||||||
|
<field name="name">Top Member Buyers</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">pivot,tree,graph</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="domain">[('is_member_at_date', '=', True)]</field>
|
||||||
|
<field name="context">{
|
||||||
|
'search_default_members': 1,
|
||||||
|
'group_by': ['partner_id'],
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
}</field>
|
||||||
|
<field name="help" type="html">
|
||||||
|
<p class="o_view_nocontent_smiling_face">
|
||||||
|
No data yet!
|
||||||
|
</p><p>
|
||||||
|
Sales aggregated per cooperative member. Sort by total
|
||||||
|
price to obtain the top buyers.
|
||||||
|
</p>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Time-based analyses: distribution of sales across days of the week
|
||||||
|
and hours of the day, to size shifts and detect peaks.
|
||||||
|
-->
|
||||||
|
<record id="action_pos_dashboard_by_day_of_week" model="ir.actions.act_window">
|
||||||
|
<field name="name">Sales by Day of Week</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">graph,pivot,tree</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="context">{
|
||||||
|
'search_default_group_day_of_week': 1,
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_pos_dashboard_by_hour" model="ir.actions.act_window">
|
||||||
|
<field name="name">Sales by Hour of Day</field>
|
||||||
|
<field name="res_model">report.pos.order</field>
|
||||||
|
<field name="view_mode">graph,pivot,tree</field>
|
||||||
|
<field name="search_view_id"
|
||||||
|
ref="point_of_sale.view_report_pos_order_search"/>
|
||||||
|
<field name="context">{
|
||||||
|
'search_default_group_hour_of_day': 1,
|
||||||
|
'group_by_no_leaf': 1,
|
||||||
|
}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
31
spreadsheet_dashboard_pos_cooperative/README.md
Normal file
31
spreadsheet_dashboard_pos_cooperative/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Spreadsheet Dashboard POS Cooperative
|
||||||
|
|
||||||
|
Publishes spreadsheet-based dashboards in Odoo's *Dashboards* menu, in
|
||||||
|
a dedicated *Cooperative* group. Built on top of o-spreadsheet, the
|
||||||
|
same technology used by Odoo's official `spreadsheet_dashboard_*`
|
||||||
|
modules (`spreadsheet_dashboard_sale`, `spreadsheet_dashboard_purchase`,
|
||||||
|
etc.).
|
||||||
|
|
||||||
|
Depends on `pos_dashboard_cooperative` for the underlying data model
|
||||||
|
(`report.pos.order` extended with member / category / time
|
||||||
|
dimensions).
|
||||||
|
|
||||||
|
Four dashboards are bundled:
|
||||||
|
|
||||||
|
| Dashboard | Contents |
|
||||||
|
|---|---|
|
||||||
|
| POS Overview | Sales, Orders, Avg ticket, Margin + monthly chart |
|
||||||
|
| POS Members | Members vs non-members KPIs + monthly chart + TOP 50 buyers |
|
||||||
|
| POS Categories | Members contribution + TOP 10 families / subfamilies / products |
|
||||||
|
| POS Sales by Time | Sales by day of week + sales by hour of day |
|
||||||
|
|
||||||
|
The JSON files under `data/files/` are hand-authored and intentionally
|
||||||
|
diff-friendly. To redesign one of them visually, install
|
||||||
|
`spreadsheet_oca`, edit in the o-spreadsheet UI, export to JSON and
|
||||||
|
replace the matching file.
|
||||||
|
|
||||||
|
See `readme/USAGE.rst` for the full procedure and metric definitions.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
AGPL-3.0 or later.
|
||||||
1
spreadsheet_dashboard_pos_cooperative/__init__.py
Normal file
1
spreadsheet_dashboard_pos_cooperative/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# Part of the spreadsheet_dashboard ecosystem. Nothing to import.
|
||||||
20
spreadsheet_dashboard_pos_cooperative/__manifest__.py
Normal file
20
spreadsheet_dashboard_pos_cooperative/__manifest__.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Copyright 2026 Criptomart
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
{
|
||||||
|
"name": "Spreadsheet dashboard for POS cooperative",
|
||||||
|
"version": "16.0.1.0.0",
|
||||||
|
"category": "Hidden",
|
||||||
|
"summary": "Spreadsheet dashboards for cooperative supermarkets POS",
|
||||||
|
"license": "AGPL-3",
|
||||||
|
"author": "Criptomart, Odoo Community Association (OCA)",
|
||||||
|
"website": "https://github.com/OCA/pos",
|
||||||
|
"depends": [
|
||||||
|
"spreadsheet_dashboard",
|
||||||
|
"pos_dashboard_cooperative",
|
||||||
|
],
|
||||||
|
"data": [
|
||||||
|
"data/dashboards.xml",
|
||||||
|
],
|
||||||
|
"auto_install": ["pos_dashboard_cooperative"],
|
||||||
|
"installable": True,
|
||||||
|
}
|
||||||
82
spreadsheet_dashboard_pos_cooperative/data/dashboards.xml
Normal file
82
spreadsheet_dashboard_pos_cooperative/data/dashboards.xml
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright 2026 Criptomart - License AGPL-3 -->
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
New dashboard group "Cooperative" sitting alongside the standard
|
||||||
|
Odoo groups (Sales, Finance, HR, ...). Sequence 150 places it
|
||||||
|
right after Sales (100) and before Finance (300).
|
||||||
|
-->
|
||||||
|
<record id="spreadsheet_dashboard_group_cooperative"
|
||||||
|
model="spreadsheet.dashboard.group">
|
||||||
|
<field name="name">PDV Supermercado</field>
|
||||||
|
<field name="sequence">150</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Section 1: high-level KPIs and monthly evolution for the whole
|
||||||
|
store. The "headline" dashboard, intentionally compact so it
|
||||||
|
loads first.
|
||||||
|
-->
|
||||||
|
<record id="spreadsheet_dashboard_pos_overview"
|
||||||
|
model="spreadsheet.dashboard">
|
||||||
|
<field name="name">Ventas</field>
|
||||||
|
<field name="data" type="base64"
|
||||||
|
file="spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json"/>
|
||||||
|
<field name="dashboard_group_id"
|
||||||
|
ref="spreadsheet_dashboard_group_cooperative"/>
|
||||||
|
<field name="group_ids"
|
||||||
|
eval="[Command.link(ref('point_of_sale.group_pos_manager'))]"/>
|
||||||
|
<field name="sequence">100</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Section 4 of the BI brief: sales distribution across days of the
|
||||||
|
week and hours of the day. Two line charts.
|
||||||
|
-->
|
||||||
|
<record id="spreadsheet_dashboard_pos_time"
|
||||||
|
model="spreadsheet.dashboard">
|
||||||
|
<field name="name">Ventas horas y días</field>
|
||||||
|
<field name="data" type="base64"
|
||||||
|
file="spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json"/>
|
||||||
|
<field name="dashboard_group_id"
|
||||||
|
ref="spreadsheet_dashboard_group_cooperative"/>
|
||||||
|
<field name="group_ids"
|
||||||
|
eval="[Command.link(ref('point_of_sale.group_pos_manager'))]"/>
|
||||||
|
<field name="sequence">400</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Section 3 of the BI brief: TOP families / subfamilies / products,
|
||||||
|
plus members contribution KPIs (purchase share, penetration).
|
||||||
|
-->
|
||||||
|
<record id="spreadsheet_dashboard_pos_categories"
|
||||||
|
model="spreadsheet.dashboard">
|
||||||
|
<field name="name">Categorías</field>
|
||||||
|
<field name="data" type="base64"
|
||||||
|
file="spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json"/>
|
||||||
|
<field name="dashboard_group_id"
|
||||||
|
ref="spreadsheet_dashboard_group_cooperative"/>
|
||||||
|
<field name="group_ids"
|
||||||
|
eval="[Command.link(ref('point_of_sale.group_pos_manager'))]"/>
|
||||||
|
<field name="sequence">300</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Section 2 of the BI brief: detailed comparison between members
|
||||||
|
and non-members. KPIs per group, monthly evolution chart and a
|
||||||
|
TOP 50 of the best buying members.
|
||||||
|
-->
|
||||||
|
<record id="spreadsheet_dashboard_pos_members"
|
||||||
|
model="spreadsheet.dashboard">
|
||||||
|
<field name="name">Socias</field>
|
||||||
|
<field name="data" type="base64"
|
||||||
|
file="spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json"/>
|
||||||
|
<field name="dashboard_group_id"
|
||||||
|
ref="spreadsheet_dashboard_group_cooperative"/>
|
||||||
|
<field name="group_ids"
|
||||||
|
eval="[Command.link(ref('point_of_sale.group_pos_manager'))]"/>
|
||||||
|
<field name="sequence">200</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,367 @@
|
||||||
|
{
|
||||||
|
"version": 12,
|
||||||
|
"sheets": [
|
||||||
|
{
|
||||||
|
"id": "dashboard",
|
||||||
|
"name": "Overview",
|
||||||
|
"colNumber": 26,
|
||||||
|
"rowNumber": 50,
|
||||||
|
"rows": {
|
||||||
|
"0": {
|
||||||
|
"size": 40
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cols": {},
|
||||||
|
"merges": [],
|
||||||
|
"cells": {
|
||||||
|
"A1": {
|
||||||
|
"style": 1,
|
||||||
|
"content": "=_t(\"Cooperative POS — Overview\")"
|
||||||
|
},
|
||||||
|
"A3": {
|
||||||
|
"style": 2,
|
||||||
|
"content": "=_t(\"Monthly evolution\")"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conditionalFormats": [],
|
||||||
|
"figures": [
|
||||||
|
{
|
||||||
|
"id": "kpi-sales",
|
||||||
|
"x": 0,
|
||||||
|
"y": 60,
|
||||||
|
"width": 200,
|
||||||
|
"height": 120,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"type": "scorecard",
|
||||||
|
"title": "Sales (€)",
|
||||||
|
"keyValue": "Data!D1",
|
||||||
|
"baseline": "Data!E1",
|
||||||
|
"baselineDescr": "since last period",
|
||||||
|
"baselineMode": "percentage",
|
||||||
|
"baselineColorUp": "#00A04A",
|
||||||
|
"baselineColorDown": "#DC6965"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kpi-orders",
|
||||||
|
"x": 220,
|
||||||
|
"y": 60,
|
||||||
|
"width": 200,
|
||||||
|
"height": 120,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"type": "scorecard",
|
||||||
|
"title": "Orders",
|
||||||
|
"keyValue": "Data!D2",
|
||||||
|
"baseline": "Data!E2",
|
||||||
|
"baselineDescr": "since last period",
|
||||||
|
"baselineMode": "percentage",
|
||||||
|
"baselineColorUp": "#00A04A",
|
||||||
|
"baselineColorDown": "#DC6965"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kpi-ticket",
|
||||||
|
"x": 440,
|
||||||
|
"y": 60,
|
||||||
|
"width": 200,
|
||||||
|
"height": 120,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"type": "scorecard",
|
||||||
|
"title": "Average ticket (€)",
|
||||||
|
"keyValue": "Data!D3",
|
||||||
|
"baseline": "Data!E3",
|
||||||
|
"baselineDescr": "since last period",
|
||||||
|
"baselineMode": "percentage",
|
||||||
|
"baselineColorUp": "#00A04A",
|
||||||
|
"baselineColorDown": "#DC6965"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "kpi-margin",
|
||||||
|
"x": 660,
|
||||||
|
"y": 60,
|
||||||
|
"width": 200,
|
||||||
|
"height": 120,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"type": "scorecard",
|
||||||
|
"title": "Gross margin (€)",
|
||||||
|
"keyValue": "Data!D4",
|
||||||
|
"baseline": "Data!E4",
|
||||||
|
"baselineDescr": "since last period",
|
||||||
|
"baselineMode": "percentage",
|
||||||
|
"baselineColorUp": "#00A04A",
|
||||||
|
"baselineColorDown": "#DC6965"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "chart-monthly-sales",
|
||||||
|
"x": 0,
|
||||||
|
"y": 220,
|
||||||
|
"width": 1000,
|
||||||
|
"height": 300,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"title": "Monthly sales (€)",
|
||||||
|
"background": "#FFFFFF",
|
||||||
|
"legendPosition": "none",
|
||||||
|
"metaData": {
|
||||||
|
"groupBy": [
|
||||||
|
"date:month"
|
||||||
|
],
|
||||||
|
"measure": "price_total",
|
||||||
|
"order": null,
|
||||||
|
"resModel": "report.pos.order"
|
||||||
|
},
|
||||||
|
"searchParams": {
|
||||||
|
"comparison": null,
|
||||||
|
"context": {
|
||||||
|
"group_by": [
|
||||||
|
"date:month"
|
||||||
|
],
|
||||||
|
"group_by_no_leaf": 1
|
||||||
|
},
|
||||||
|
"domain": [
|
||||||
|
[
|
||||||
|
"state",
|
||||||
|
"in",
|
||||||
|
[
|
||||||
|
"paid",
|
||||||
|
"done",
|
||||||
|
"invoiced"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"groupBy": [
|
||||||
|
"date:month"
|
||||||
|
],
|
||||||
|
"orderBy": []
|
||||||
|
},
|
||||||
|
"type": "odoo_line",
|
||||||
|
"verticalAxisPosition": "left"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"areGridLinesVisible": false,
|
||||||
|
"isVisible": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "data",
|
||||||
|
"name": "Data",
|
||||||
|
"colNumber": 5,
|
||||||
|
"rowNumber": 10,
|
||||||
|
"rows": {},
|
||||||
|
"cols": {
|
||||||
|
"0": {
|
||||||
|
"size": 200
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"size": 140
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"size": 140
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"size": 140
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"size": 140
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"merges": [],
|
||||||
|
"cells": {
|
||||||
|
"A1": {
|
||||||
|
"content": "=_t(\"KPI - Sales\")"
|
||||||
|
},
|
||||||
|
"A2": {
|
||||||
|
"content": "=_t(\"KPI - Orders\")"
|
||||||
|
},
|
||||||
|
"A3": {
|
||||||
|
"content": "=_t(\"KPI - Average ticket\")"
|
||||||
|
},
|
||||||
|
"A4": {
|
||||||
|
"content": "=_t(\"KPI - Margin\")"
|
||||||
|
},
|
||||||
|
"B1": {
|
||||||
|
"content": "=ODOO.PIVOT(1,\"price_total\")"
|
||||||
|
},
|
||||||
|
"B2": {
|
||||||
|
"content": "=ODOO.PIVOT(1,\"order_id\")"
|
||||||
|
},
|
||||||
|
"B3": {
|
||||||
|
"content": "=IFERROR(B1/B2,0)"
|
||||||
|
},
|
||||||
|
"B4": {
|
||||||
|
"content": "=ODOO.PIVOT(1,\"margin\")"
|
||||||
|
},
|
||||||
|
"C1": {
|
||||||
|
"content": "=ODOO.PIVOT(2,\"price_total\")"
|
||||||
|
},
|
||||||
|
"C2": {
|
||||||
|
"content": "=ODOO.PIVOT(2,\"order_id\")"
|
||||||
|
},
|
||||||
|
"C3": {
|
||||||
|
"content": "=IFERROR(C1/C2,0)"
|
||||||
|
},
|
||||||
|
"C4": {
|
||||||
|
"content": "=ODOO.PIVOT(2,\"margin\")"
|
||||||
|
},
|
||||||
|
"D1": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(B1)"
|
||||||
|
},
|
||||||
|
"D2": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(B2)"
|
||||||
|
},
|
||||||
|
"D3": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(B3)"
|
||||||
|
},
|
||||||
|
"D4": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(B4)"
|
||||||
|
},
|
||||||
|
"E1": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(C1)"
|
||||||
|
},
|
||||||
|
"E2": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(C2)"
|
||||||
|
},
|
||||||
|
"E3": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(C3)"
|
||||||
|
},
|
||||||
|
"E4": {
|
||||||
|
"content": "=FORMAT.LARGE.NUMBER(C4)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conditionalFormats": [],
|
||||||
|
"figures": [],
|
||||||
|
"areGridLinesVisible": true,
|
||||||
|
"isVisible": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entities": {},
|
||||||
|
"styles": {
|
||||||
|
"1": {
|
||||||
|
"bold": true,
|
||||||
|
"fontSize": 22,
|
||||||
|
"textColor": "#2E7D32"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"bold": true,
|
||||||
|
"fontSize": 14,
|
||||||
|
"textColor": "#333333"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"formats": {
|
||||||
|
"1": "#,##0.00 [$€]",
|
||||||
|
"2": "#,##0"
|
||||||
|
},
|
||||||
|
"borders": {},
|
||||||
|
"revisionId": "START_REVISION",
|
||||||
|
"chartOdooMenusReferences": {},
|
||||||
|
"odooVersion": 1,
|
||||||
|
"lists": {},
|
||||||
|
"listNextId": 1,
|
||||||
|
"pivots": {
|
||||||
|
"1": {
|
||||||
|
"colGroupBys": [],
|
||||||
|
"context": {
|
||||||
|
"group_by_no_leaf": 1,
|
||||||
|
"group_by": []
|
||||||
|
},
|
||||||
|
"domain": [
|
||||||
|
[
|
||||||
|
"state",
|
||||||
|
"in",
|
||||||
|
[
|
||||||
|
"paid",
|
||||||
|
"done",
|
||||||
|
"invoiced"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"id": "1",
|
||||||
|
"measures": [
|
||||||
|
{
|
||||||
|
"field": "price_total"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "margin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "order_id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"model": "report.pos.order",
|
||||||
|
"rowGroupBys": [],
|
||||||
|
"name": "POS KPIs - current",
|
||||||
|
"sortedColumn": null
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"colGroupBys": [],
|
||||||
|
"context": {
|
||||||
|
"group_by_no_leaf": 1,
|
||||||
|
"group_by": []
|
||||||
|
},
|
||||||
|
"domain": [
|
||||||
|
[
|
||||||
|
"state",
|
||||||
|
"in",
|
||||||
|
[
|
||||||
|
"paid",
|
||||||
|
"done",
|
||||||
|
"invoiced"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"id": "2",
|
||||||
|
"measures": [
|
||||||
|
{
|
||||||
|
"field": "price_total"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "margin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "order_id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"model": "report.pos.order",
|
||||||
|
"rowGroupBys": [],
|
||||||
|
"name": "POS KPIs - previous",
|
||||||
|
"sortedColumn": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pivotNextId": 3,
|
||||||
|
"globalFilters": [
|
||||||
|
{
|
||||||
|
"id": "11111111-1111-1111-1111-111111111111",
|
||||||
|
"type": "date",
|
||||||
|
"label": "Period",
|
||||||
|
"defaultValue": {},
|
||||||
|
"rangeType": "month",
|
||||||
|
"defaultsToCurrentPeriod": true,
|
||||||
|
"pivotFields": {
|
||||||
|
"1": {
|
||||||
|
"field": "date",
|
||||||
|
"type": "datetime",
|
||||||
|
"offset": 0
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"field": "date",
|
||||||
|
"type": "datetime",
|
||||||
|
"offset": -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"listFields": {},
|
||||||
|
"graphFields": {
|
||||||
|
"chart-monthly-sales": {
|
||||||
|
"field": "date",
|
||||||
|
"type": "datetime",
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
{
|
||||||
|
"version": 12,
|
||||||
|
"sheets": [
|
||||||
|
{
|
||||||
|
"id": "dashboard",
|
||||||
|
"name": "Sales by time",
|
||||||
|
"colNumber": 26,
|
||||||
|
"rowNumber": 50,
|
||||||
|
"rows": {
|
||||||
|
"0": {
|
||||||
|
"size": 40
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cols": {},
|
||||||
|
"merges": [],
|
||||||
|
"cells": {
|
||||||
|
"A1": {
|
||||||
|
"style": 1,
|
||||||
|
"content": "=_t(\"Cooperative POS — Sales by hours and days\")"
|
||||||
|
},
|
||||||
|
"A3": {
|
||||||
|
"style": 2,
|
||||||
|
"content": "=_t(\"Sales by day of the week\")"
|
||||||
|
},
|
||||||
|
"A20": {
|
||||||
|
"style": 2,
|
||||||
|
"content": "=_t(\"Sales by hour of the day\")"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conditionalFormats": [],
|
||||||
|
"figures": [
|
||||||
|
{
|
||||||
|
"id": "chart-by-day",
|
||||||
|
"x": 0,
|
||||||
|
"y": 60,
|
||||||
|
"width": 1000,
|
||||||
|
"height": 280,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"title": "Sales by day of week",
|
||||||
|
"background": "#FFFFFF",
|
||||||
|
"legendPosition": "none",
|
||||||
|
"metaData": {
|
||||||
|
"groupBy": [
|
||||||
|
"day_of_week"
|
||||||
|
],
|
||||||
|
"measure": "price_total",
|
||||||
|
"order": null,
|
||||||
|
"resModel": "report.pos.order"
|
||||||
|
},
|
||||||
|
"searchParams": {
|
||||||
|
"comparison": null,
|
||||||
|
"context": {
|
||||||
|
"group_by": [
|
||||||
|
"day_of_week"
|
||||||
|
],
|
||||||
|
"group_by_no_leaf": 1
|
||||||
|
},
|
||||||
|
"domain": [
|
||||||
|
[
|
||||||
|
"state",
|
||||||
|
"in",
|
||||||
|
[
|
||||||
|
"paid",
|
||||||
|
"done",
|
||||||
|
"invoiced"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"groupBy": [
|
||||||
|
"day_of_week"
|
||||||
|
],
|
||||||
|
"orderBy": []
|
||||||
|
},
|
||||||
|
"type": "odoo_line",
|
||||||
|
"verticalAxisPosition": "left"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "chart-by-hour",
|
||||||
|
"x": 0,
|
||||||
|
"y": 380,
|
||||||
|
"width": 1000,
|
||||||
|
"height": 280,
|
||||||
|
"tag": "chart",
|
||||||
|
"data": {
|
||||||
|
"title": "Sales by hour of day",
|
||||||
|
"background": "#FFFFFF",
|
||||||
|
"legendPosition": "none",
|
||||||
|
"metaData": {
|
||||||
|
"groupBy": [
|
||||||
|
"hour_of_day"
|
||||||
|
],
|
||||||
|
"measure": "price_total",
|
||||||
|
"order": null,
|
||||||
|
"resModel": "report.pos.order"
|
||||||
|
},
|
||||||
|
"searchParams": {
|
||||||
|
"comparison": null,
|
||||||
|
"context": {
|
||||||
|
"group_by": [
|
||||||
|
"hour_of_day"
|
||||||
|
],
|
||||||
|
"group_by_no_leaf": 1
|
||||||
|
},
|
||||||
|
"domain": [
|
||||||
|
[
|
||||||
|
"state",
|
||||||
|
"in",
|
||||||
|
[
|
||||||
|
"paid",
|
||||||
|
"done",
|
||||||
|
"invoiced"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"groupBy": [
|
||||||
|
"hour_of_day"
|
||||||
|
],
|
||||||
|
"orderBy": []
|
||||||
|
},
|
||||||
|
"type": "odoo_line",
|
||||||
|
"verticalAxisPosition": "left"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"areGridLinesVisible": false,
|
||||||
|
"isVisible": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"entities": {},
|
||||||
|
"styles": {
|
||||||
|
"1": {
|
||||||
|
"bold": true,
|
||||||
|
"fontSize": 22,
|
||||||
|
"textColor": "#2E7D32"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"bold": true,
|
||||||
|
"fontSize": 14,
|
||||||
|
"textColor": "#333333"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"formats": {},
|
||||||
|
"borders": {},
|
||||||
|
"revisionId": "START_REVISION",
|
||||||
|
"chartOdooMenusReferences": {},
|
||||||
|
"odooVersion": 1,
|
||||||
|
"lists": {},
|
||||||
|
"listNextId": 1,
|
||||||
|
"pivots": {},
|
||||||
|
"pivotNextId": 1,
|
||||||
|
"globalFilters": [
|
||||||
|
{
|
||||||
|
"id": "11111111-1111-1111-1111-111111111111",
|
||||||
|
"type": "date",
|
||||||
|
"label": "Period",
|
||||||
|
"defaultValue": {},
|
||||||
|
"rangeType": "month",
|
||||||
|
"defaultsToCurrentPeriod": true,
|
||||||
|
"pivotFields": {},
|
||||||
|
"listFields": {},
|
||||||
|
"graphFields": {
|
||||||
|
"chart-by-day": {
|
||||||
|
"field": "date",
|
||||||
|
"type": "datetime",
|
||||||
|
"offset": 0
|
||||||
|
},
|
||||||
|
"chart-by-hour": {
|
||||||
|
"field": "date",
|
||||||
|
"type": "datetime",
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "22222222-2222-2222-2222-222222222222",
|
||||||
|
"type": "relation",
|
||||||
|
"label": "Product Category",
|
||||||
|
"modelName": "product.category",
|
||||||
|
"defaultValue": [],
|
||||||
|
"defaultValueDisplayNames": [],
|
||||||
|
"rangeType": "year",
|
||||||
|
"defaultsToCurrentPeriod": false,
|
||||||
|
"pivotFields": {},
|
||||||
|
"listFields": {},
|
||||||
|
"graphFields": {
|
||||||
|
"chart-by-day": {
|
||||||
|
"field": "product_categ_id",
|
||||||
|
"type": "many2one"
|
||||||
|
},
|
||||||
|
"chart-by-hour": {
|
||||||
|
"field": "product_categ_id",
|
||||||
|
"type": "many2one"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "33333333-3333-3333-3333-333333333333",
|
||||||
|
"type": "relation",
|
||||||
|
"label": "Product",
|
||||||
|
"modelName": "product.product",
|
||||||
|
"defaultValue": [],
|
||||||
|
"defaultValueDisplayNames": [],
|
||||||
|
"rangeType": "year",
|
||||||
|
"defaultsToCurrentPeriod": false,
|
||||||
|
"pivotFields": {},
|
||||||
|
"listFields": {},
|
||||||
|
"graphFields": {
|
||||||
|
"chart-by-day": {
|
||||||
|
"field": "product_id",
|
||||||
|
"type": "many2one"
|
||||||
|
},
|
||||||
|
"chart-by-hour": {
|
||||||
|
"field": "product_id",
|
||||||
|
"type": "many2one"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
634
spreadsheet_dashboard_pos_cooperative/i18n/es.po
Normal file
634
spreadsheet_dashboard_pos_cooperative/i18n/es.po
Normal file
|
|
@ -0,0 +1,634 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * spreadsheet_dashboard_pos_cooperative
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-06-05 15:43+0000\n"
|
||||||
|
"PO-Revision-Date: 2026-06-05 15:43+0000\n"
|
||||||
|
"Last-Translator: Criptomart\n"
|
||||||
|
"Language-Team: Spanish\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Language: es\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Average ticket (€)"
|
||||||
|
msgstr "Ticket medio (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Categoría"
|
||||||
|
msgstr "Categoría"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Compradoras distintas (no socias)"
|
||||||
|
msgstr "Compradoras distintas (no socias)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Compradoras distintas (socias)"
|
||||||
|
msgstr "Compradoras distintas (socias)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Contribución de las socias"
|
||||||
|
msgstr "Contribución de las socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Categories"
|
||||||
|
msgstr "TPV Cooperativa — Categorías"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Members vs Non-members"
|
||||||
|
msgstr "TPV Cooperativa — Socias vs no socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Overview"
|
||||||
|
msgstr "TPV Cooperativa — Vista general"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Sales by hours and days"
|
||||||
|
msgstr "TPV Cooperativa — Ventas por horas y días"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cuota %"
|
||||||
|
msgstr "Cuota %"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cuota de compra"
|
||||||
|
msgstr "Cuota de compra"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cuota de compra %"
|
||||||
|
msgstr "Cuota de compra %"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Evolución mensual por condición de socia"
|
||||||
|
msgstr "Evolución mensual por condición de socia"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Evolución mensual — Socias vs no socias"
|
||||||
|
msgstr "Evolución mensual — Socias vs no socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Evolución mensual — Socias vs no socias (€)"
|
||||||
|
msgstr "Evolución mensual — Socias vs no socias (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Familia"
|
||||||
|
msgstr "Familia"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Frecuencia socias"
|
||||||
|
msgstr "Frecuencia socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Gross margin (€)"
|
||||||
|
msgstr "Margen bruto (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Average ticket"
|
||||||
|
msgstr "KPI - Ticket medio"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Margin"
|
||||||
|
msgstr "KPI - Margen"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Orders"
|
||||||
|
msgstr "KPI - Tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Sales"
|
||||||
|
msgstr "KPI - Ventas"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPIs de no socias"
|
||||||
|
msgstr "KPIs de no socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPIs de socias"
|
||||||
|
msgstr "KPIs de socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Mejores compradoras (socias)"
|
||||||
|
msgstr "Mejores compradoras (socias)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Monthly evolution"
|
||||||
|
msgstr "Evolución mensual"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Monthly sales (€)"
|
||||||
|
msgstr "Ventas mensuales (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Orders"
|
||||||
|
msgstr "Tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "POS KPIs"
|
||||||
|
msgstr "POS KPIs"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Penetración socias"
|
||||||
|
msgstr "Penetración socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Penetración socias %"
|
||||||
|
msgstr "Penetración socias %"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Period"
|
||||||
|
msgstr "Período"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Product"
|
||||||
|
msgstr "Producto"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Product Category"
|
||||||
|
msgstr "Categoría de producto"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Producto"
|
||||||
|
msgstr "Producto"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales (€)"
|
||||||
|
msgstr "Ventas (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by day of the week"
|
||||||
|
msgstr "Ventas por día de la semana"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by day of week"
|
||||||
|
msgstr "Ventas por día de la semana"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by hour of day"
|
||||||
|
msgstr "Ventas por hora del día"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by hour of the day"
|
||||||
|
msgstr "Ventas por hora del día"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socia"
|
||||||
|
msgstr "Socia"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Compradoras distintas"
|
||||||
|
msgstr "Socias - Compradoras distintas"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Frecuencia"
|
||||||
|
msgstr "Socias - Frecuencia"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Ticket medio"
|
||||||
|
msgstr "Socias - Ticket medio"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Tickets"
|
||||||
|
msgstr "Socias - Tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - UPT"
|
||||||
|
msgstr "Socias - UPT"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Ventas"
|
||||||
|
msgstr "Socias - Ventas"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Subfamilia"
|
||||||
|
msgstr "Subfamilia"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "TOP 50 socias compradoras"
|
||||||
|
msgstr "TOP 50 socias compradoras"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "TPV por condición de socia"
|
||||||
|
msgstr "TPV por condición de socia"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ticket medio (€)"
|
||||||
|
msgstr "Ticket medio (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ticket medio no socias (€)"
|
||||||
|
msgstr "Ticket medio no socias (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ticket medio socias (€)"
|
||||||
|
msgstr "Ticket medio socias (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Tickets"
|
||||||
|
msgstr "Tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Tickets no socias"
|
||||||
|
msgstr "Tickets no socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Tickets socias"
|
||||||
|
msgstr "Tickets socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 categorías"
|
||||||
|
msgstr "Top 10 categorías"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 familias"
|
||||||
|
msgstr "Top 10 familias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 productos"
|
||||||
|
msgstr "Top 10 productos"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 subfamilias"
|
||||||
|
msgstr "Top 10 subfamilias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top categorías"
|
||||||
|
msgstr "Top categorías"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top familias"
|
||||||
|
msgstr "Top familias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top productos"
|
||||||
|
msgstr "Top productos"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top subfamilias"
|
||||||
|
msgstr "Top subfamilias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Total compradoras distintas"
|
||||||
|
msgstr "Total compradoras distintas"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Total ventas"
|
||||||
|
msgstr "Total ventas"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "UPT"
|
||||||
|
msgstr "UPT"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "UPT no socias"
|
||||||
|
msgstr "UPT no socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "UPT socias"
|
||||||
|
msgstr "UPT socias"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Unidades"
|
||||||
|
msgstr "Unidades"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ventas (€)"
|
||||||
|
msgstr "Ventas (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ventas no socias (€)"
|
||||||
|
msgstr "Ventas no socias (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ventas socias (€)"
|
||||||
|
msgstr "Ventas socias (€)"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "en el período"
|
||||||
|
msgstr "en el período"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "in selected period"
|
||||||
|
msgstr "en el período seleccionado"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "sales / orders"
|
||||||
|
msgstr "ventas / tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "socias compradoras / total"
|
||||||
|
msgstr "socias compradoras / total"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "socias únicas"
|
||||||
|
msgstr "socias únicas"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "tickets"
|
||||||
|
msgstr "tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "tickets / compradora"
|
||||||
|
msgstr "tickets / compradora"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "uds / ticket"
|
||||||
|
msgstr "uds / ticket"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "ventas / tickets"
|
||||||
|
msgstr "ventas / tickets"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "ventas socias / total"
|
||||||
|
msgstr "ventas socias / total"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "únicas"
|
||||||
|
msgstr "únicas"
|
||||||
|
|
@ -0,0 +1,633 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * spreadsheet_dashboard_pos_cooperative
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-06-05 15:43+0000\n"
|
||||||
|
"PO-Revision-Date: 2026-06-05 15:43+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: \n"
|
||||||
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Average ticket (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Categoría"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Compradoras distintas (no socias)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Compradoras distintas (socias)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Contribución de las socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Categories"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Members vs Non-members"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Overview"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cooperative POS — Sales by hours and days"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cuota %"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cuota de compra"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Cuota de compra %"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Evolución mensual por condición de socia"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Evolución mensual — Socias vs no socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Evolución mensual — Socias vs no socias (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Familia"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Frecuencia socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Gross margin (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Average ticket"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Margin"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Orders"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPI - Sales"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPIs de no socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "KPIs de socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Mejores compradoras (socias)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Monthly evolution"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Monthly sales (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Orders"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "POS KPIs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Penetración socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Penetración socias %"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Period"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Product"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Product Category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Producto"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by day of the week"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by day of week"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by hour of day"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/time_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Sales by hour of the day"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socia"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Compradoras distintas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Frecuencia"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Ticket medio"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Tickets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - UPT"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Socias - Ventas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Subfamilia"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "TOP 50 socias compradoras"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "TPV por condición de socia"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ticket medio (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ticket medio no socias (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ticket medio socias (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Tickets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Tickets no socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Tickets socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 categorías"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 familias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 productos"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top 10 subfamilias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top categorías"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top familias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top productos"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Top subfamilias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Total compradoras distintas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Total ventas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "UPT"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "UPT no socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "UPT socias"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Unidades"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/categories_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ventas (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ventas no socias (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "Ventas socias (€)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "en el período"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "in selected period"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "sales / orders"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "socias compradoras / total"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "socias únicas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/overview_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "tickets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "tickets / compradora"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "uds / ticket"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "ventas / tickets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "ventas socias / total"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: spreadsheet_dashboard_pos_cooperative
|
||||||
|
#. odoo-javascript
|
||||||
|
#: code:addons/spreadsheet_dashboard_pos_cooperative/data/files/members_dashboard.json:0
|
||||||
|
#, python-format
|
||||||
|
msgid "únicas"
|
||||||
|
msgstr ""
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
* Criptomart <https://criptomart.net>
|
||||||
23
spreadsheet_dashboard_pos_cooperative/readme/DESCRIPTION.rst
Normal file
23
spreadsheet_dashboard_pos_cooperative/readme/DESCRIPTION.rst
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
Publishes spreadsheet-based dashboards for cooperative supermarkets
|
||||||
|
in Odoo's *Dashboards* menu, under a dedicated *Cooperative* group.
|
||||||
|
|
||||||
|
The dashboards consume the data prepared by ``pos_dashboard_cooperative``
|
||||||
|
(extended ``report.pos.order`` with member-at-date flag, category
|
||||||
|
hierarchy and time dimensions). They use Odoo's o-spreadsheet engine,
|
||||||
|
the same as Odoo Enterprise's official ``spreadsheet_dashboard_*``
|
||||||
|
modules.
|
||||||
|
|
||||||
|
Four dashboards ship out of the box:
|
||||||
|
|
||||||
|
* **POS Overview** — headline KPIs (Sales, Orders, Average ticket,
|
||||||
|
Margin) and monthly evolution.
|
||||||
|
* **POS Members** — members vs non-members comparison, monthly
|
||||||
|
evolution chart, TOP 50 buying members.
|
||||||
|
* **POS Categories** — members contribution KPIs and TOP 10 families,
|
||||||
|
subfamilies and products.
|
||||||
|
* **POS Sales by Time** — sales by day of the week and hour of the
|
||||||
|
day.
|
||||||
|
|
||||||
|
Each dashboard is a small hand-authored JSON file. They can be
|
||||||
|
redesigned visually inside o-spreadsheet (with ``spreadsheet_oca``
|
||||||
|
installed) and re-exported; see USAGE for the workflow.
|
||||||
38
spreadsheet_dashboard_pos_cooperative/readme/ROADMAP.rst
Normal file
38
spreadsheet_dashboard_pos_cooperative/readme/ROADMAP.rst
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
* Period-over-period comparisons on the scorecards (the BI brief shows
|
||||||
|
"X% desde el último periodo" arrows on every KPI). In o-spreadsheet
|
||||||
|
this is wired through ``baseline`` references plus a comparison
|
||||||
|
range on the date global filter. Postponed until the four dashboards
|
||||||
|
are validated by the customer in production.
|
||||||
|
|
||||||
|
* Quarter-level selection (*Q1..Q4*) on the ``Period`` filter. The
|
||||||
|
o-spreadsheet date filter in Odoo 16 only accepts a single
|
||||||
|
``rangeType`` per filter; we picked ``month`` because it is the
|
||||||
|
finest granularity. A second date filter with ``rangeType:
|
||||||
|
"quarter"`` would coexist visually but duplicate the year picker,
|
||||||
|
which the customer rejected. Revisit in Odoo 17 where the filter
|
||||||
|
UI allows choosing the granularity dynamically.
|
||||||
|
|
||||||
|
* Rolling-window date filter (*Last 30 / 90 / 180 days*) as an
|
||||||
|
alternative to the month picker. Same limitation as above (one
|
||||||
|
``rangeType`` per filter).
|
||||||
|
|
||||||
|
* "Sales concentration" KPI on the Categories dashboard: share of
|
||||||
|
sales captured by the top 20% of buying members. The Top buyers
|
||||||
|
pivot already exists in the Members dashboard; only an aggregation
|
||||||
|
formula plus a scorecard would be needed.
|
||||||
|
|
||||||
|
* Stricter definition of **Members penetration** as ``distinct member
|
||||||
|
buyers / total members in the cooperative`` (instead of the current
|
||||||
|
``/ total buyers in the period``). Requires sourcing the total from
|
||||||
|
``share.line`` rather than from ``report.pos.order``.
|
||||||
|
|
||||||
|
* Translate ``spreadsheet.dashboard.name`` / ``spreadsheet.dashboard.group.name``
|
||||||
|
so the entries in the *Dashboards* menu render in the user's
|
||||||
|
language (currently always English: *POS Overview*, *POS Members*,
|
||||||
|
etc.). Blocked upstream: the core ``name`` fields are not declared
|
||||||
|
``translate=True``. Either patch the core fields downstream or rename
|
||||||
|
the records to the customer's primary language in the XML.
|
||||||
|
|
||||||
|
* Add Galician, Catalan, French, Dutch and Croatian translations.
|
||||||
|
Spanish (``es.po``) ships out of the box. The other locales can be
|
||||||
|
produced from the same ``.pot`` by translating each ``msgstr``.
|
||||||
149
spreadsheet_dashboard_pos_cooperative/readme/USAGE.rst
Normal file
149
spreadsheet_dashboard_pos_cooperative/readme/USAGE.rst
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
Open *Dashboards → Cooperative* in the Odoo backend. Four dashboards
|
||||||
|
are published:
|
||||||
|
|
||||||
|
The workbook content (titles, KPI labels, table headers, scorecard
|
||||||
|
descriptions) is available in **English (source) and Spanish** out of
|
||||||
|
the box. Users with ``lang = es_ES`` will see all in-cell texts in
|
||||||
|
Spanish; the rest of the locales can be added by translating the
|
||||||
|
``i18n/spreadsheet_dashboard_pos_cooperative.pot`` template.
|
||||||
|
|
||||||
|
Note: the dashboard names shown in the *Dashboards* menu sidebar
|
||||||
|
(*POS Overview*, *POS Members*, *POS Categories*, *POS Sales by
|
||||||
|
Time*) are not translatable because ``spreadsheet.dashboard.name`` is
|
||||||
|
not declared as a translatable field in Odoo core.
|
||||||
|
|
||||||
|
POS Overview
|
||||||
|
============
|
||||||
|
|
||||||
|
Headline KPIs and monthly evolution for the whole store.
|
||||||
|
|
||||||
|
* **Sales (€)** — sum of ``price_total`` over orders in the period.
|
||||||
|
* **Orders** — count of distinct ``order_id``.
|
||||||
|
* **Average ticket (€)** — ``Sales / Orders``.
|
||||||
|
* **Gross margin (€)** — sum of ``margin``.
|
||||||
|
* A line chart with monthly sales evolution.
|
||||||
|
|
||||||
|
POS Members
|
||||||
|
===========
|
||||||
|
|
||||||
|
Detailed comparison between cooperative members and non-members. For
|
||||||
|
each group the dashboard shows:
|
||||||
|
|
||||||
|
* Sales (€), Orders, Average ticket (€), UPT, Distinct buyers, and
|
||||||
|
(members only) Frequency.
|
||||||
|
* Monthly evolution chart with one line per group.
|
||||||
|
* TOP 50 buying members (ranked by sales), with sales, orders, units,
|
||||||
|
average ticket and UPT.
|
||||||
|
|
||||||
|
POS Categories
|
||||||
|
==============
|
||||||
|
|
||||||
|
Members contribution KPIs and the top product breakdowns.
|
||||||
|
|
||||||
|
* **Members sales (€)** — sales from orders where the customer was a
|
||||||
|
cooperative member at the order date.
|
||||||
|
* **Purchase share** — ``members sales / total sales``.
|
||||||
|
* **Members penetration** — ``distinct members buyers / distinct total
|
||||||
|
buyers`` (see "Metric definitions" below for the caveat).
|
||||||
|
* TOP 10 product families (root categories) with sales, orders, share %.
|
||||||
|
* TOP 10 product subfamilies (parent categories) with the same columns.
|
||||||
|
* TOP 10 products with sales, units, share %.
|
||||||
|
|
||||||
|
POS Sales by Time
|
||||||
|
=================
|
||||||
|
|
||||||
|
* Line chart of sales by ISO day of the week (1 = Monday, 7 = Sunday).
|
||||||
|
* Line chart of sales by hour of the day (0..23).
|
||||||
|
|
||||||
|
Global filters
|
||||||
|
==============
|
||||||
|
|
||||||
|
Every dashboard ships a ``Period`` date filter. Members, Categories
|
||||||
|
and Sales by Time also ship ``Product Category``, ``Product`` and
|
||||||
|
(Members only) ``Member`` relation filters. Each filter is wired to
|
||||||
|
every pivot and chart on the dashboard, so changing one selection
|
||||||
|
updates the whole view.
|
||||||
|
|
||||||
|
* **Period** — year picker plus a month dropdown
|
||||||
|
(January..December). Pick a year only to look at the full year
|
||||||
|
(e.g. *2026*, *2025*), or add a month to narrow the range (e.g.
|
||||||
|
*March 2026*). Defaults to the current month.
|
||||||
|
* **Product Category** — relation picker over ``product.category``.
|
||||||
|
Choose one or more categories to restrict every metric to products
|
||||||
|
of those categories. Empty = no restriction.
|
||||||
|
* **Product** — relation picker over ``product.product``. Useful to
|
||||||
|
audit a specific reference.
|
||||||
|
* **Member** — relation picker over ``res.partner``. Available only
|
||||||
|
on the Members dashboard; restricts the comparison and the TOP 50
|
||||||
|
to the selected partners.
|
||||||
|
|
||||||
|
Note: the o-spreadsheet date filter in Odoo 16 only accepts a single
|
||||||
|
``rangeType`` per filter (year, quarter or month). We chose ``month``
|
||||||
|
because it is the finest granularity the customer requested; for
|
||||||
|
year-only views, just pick a year and leave the month dropdown
|
||||||
|
unset. Rolling ranges (*Last 30 / 90 / 180 days*) and quarter
|
||||||
|
selection (*Q1..Q4*) are not available on the spreadsheet filters;
|
||||||
|
both are handled in ``pos_dashboard_cooperative`` through the
|
||||||
|
standard search view on *Point of Sale → Reporting → Cooperative
|
||||||
|
Dashboards*, which exposes the usual Odoo date filters.
|
||||||
|
|
||||||
|
Metric definitions
|
||||||
|
==================
|
||||||
|
|
||||||
|
The BI brief from the customer left several KPIs without a precise
|
||||||
|
formulation. The dashboards use the following standard retail
|
||||||
|
definitions; revise them in the JSON if your cooperative prefers a
|
||||||
|
different convention.
|
||||||
|
|
||||||
|
* **UPT** (Units per Ticket) = ``total units sold / number of
|
||||||
|
orders``. ``product_qty`` summed and divided by distinct
|
||||||
|
``order_id``.
|
||||||
|
* **Frequency** = ``number of orders / number of distinct buyers``.
|
||||||
|
Measures how many tickets the average member buyer made in the
|
||||||
|
period.
|
||||||
|
* **Average ticket (€)** = ``total sales / number of orders``. POS has
|
||||||
|
no separate "average ticket value", so this metric matches the
|
||||||
|
"Ticket medio" and "Valor medio del ticket" rows in the BI brief.
|
||||||
|
* **Purchase share %** = ``members sales / total sales``. Share of
|
||||||
|
total revenue contributed by member-driven orders.
|
||||||
|
* **Members penetration %** = ``distinct member buyers / distinct
|
||||||
|
total buyers`` *in the selected period*. Note: a stricter definition
|
||||||
|
would be ``distinct member buyers / total members in the
|
||||||
|
cooperative`` (regardless of whether they bought). That denominator
|
||||||
|
is not exposed by ``report.pos.order``; a future iteration may add a
|
||||||
|
separate KPI sourced from ``share.line``.
|
||||||
|
* **Sales concentration** (not yet rendered) would be the share of
|
||||||
|
sales captured by the top X% of buying members, typically X = 20.
|
||||||
|
Easy to add later from the same ``Top buyers`` pivot.
|
||||||
|
|
||||||
|
Iterating on the layouts
|
||||||
|
========================
|
||||||
|
|
||||||
|
Each dashboard is a ``data/files/*.json`` file shipped as a base64
|
||||||
|
binary on a ``spreadsheet.dashboard`` record. They are intentionally
|
||||||
|
small and hand-authored to be diff-friendly.
|
||||||
|
|
||||||
|
To redesign one of them visually:
|
||||||
|
|
||||||
|
1. Install ``spreadsheet_oca`` (from OCA's ``spreadsheet`` repository)
|
||||||
|
on top of this module. It provides full o-spreadsheet editing in
|
||||||
|
the backend, including saving back to ``spreadsheet.dashboard``.
|
||||||
|
2. Open the dashboard in *Dashboards → Cooperative*.
|
||||||
|
3. Edit pivots, charts, styles and global filters from the
|
||||||
|
o-spreadsheet UI. The data sources are pre-wired against
|
||||||
|
``report.pos.order`` and consume the dimensions exposed by
|
||||||
|
``pos_dashboard_cooperative``:
|
||||||
|
|
||||||
|
* ``is_member_at_date`` (boolean) — cooperative member flag at the
|
||||||
|
order date.
|
||||||
|
* ``categ_root_id`` / ``categ_parent_id`` — product family /
|
||||||
|
subfamily.
|
||||||
|
* ``hour_of_day`` / ``day_of_week`` — time distributions.
|
||||||
|
|
||||||
|
4. Export the workbook to JSON.
|
||||||
|
5. Replace the matching ``data/files/<name>.json`` and reinstall (or
|
||||||
|
upgrade) the module.
|
||||||
|
|
||||||
|
Reference: the same workflow is used by Odoo core's
|
||||||
|
``spreadsheet_dashboard_sale``, ``spreadsheet_dashboard_purchase`` and
|
||||||
|
similar modules.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue