From 7aafe0c6fb3d1f398480b5c6cdf482d10bacb859 Mon Sep 17 00:00:00 2001 From: Alaguraj0361 Date: Tue, 17 Mar 2026 20:26:05 +0530 Subject: [PATCH] Introduce comprehensive order channel management, including online, self-order, and KDS integration, with detailed fulfilment and delivery options for POS orders and receipts. --- .agents/workflows/testing.md | 50 ++++ addons/dine360_kds/__manifest__.py | 2 +- .../dine360_kds/static/src/js/kds_backend.js | 5 +- .../views/pos_order_line_views.xml | 24 +- addons/dine360_online_orders/__manifest__.py | 2 +- .../dine360_online_orders/controllers/main.py | 4 +- .../dine360_online_orders/models/pos_order.py | 21 +- .../models/pos_order_line.py | 14 +- .../models/sale_order.py | 29 +- .../static/src/js/service_mode.js | 6 +- .../views/kds_override_views.xml | 27 -- .../views/pos_order_views.xml | 14 +- .../views/website_sale_templates.xml | 4 +- addons/dine360_order_channels/__init__.py | 2 + addons/dine360_order_channels/__manifest__.py | 34 +++ .../controllers/__init__.py | 1 + .../controllers/main.py | 44 +++ .../dine360_order_channels/models/__init__.py | 2 + .../models/pos_config.py | 30 ++ .../models/pos_order.py | 142 ++++++++++ .../security/ir.model.access.csv | 1 + .../static/src/css/channel_panel.css | 43 +++ .../static/src/js/channel_panel.js | 125 +++++++++ .../static/src/js/order_channel_model.js | 103 +++++++ .../static/src/js/product_screen_patch.js | 23 ++ .../static/src/xml/channel_panel.xml | 116 ++++++++ .../static/src/xml/receipt_extension.xml | 40 +++ .../views/pos_order_views.xml | 93 +++++++ addons/dine360_self_order/__init__.py | 2 + addons/dine360_self_order/__manifest__.py | 29 ++ .../controllers/__init__.py | 1 + addons/dine360_self_order/controllers/main.py | 114 ++++++++ addons/dine360_self_order/models/__init__.py | 1 + .../models/restaurant_table.py | 38 +++ .../static/src/css/self_order.css | 89 ++++++ .../static/src/js/self_order.js | 259 ++++++++++++++++++ .../views/restaurant_table_views.xml | 31 +++ .../views/self_order_templates.xml | 124 +++++++++ 38 files changed, 1599 insertions(+), 90 deletions(-) create mode 100644 .agents/workflows/testing.md create mode 100644 addons/dine360_order_channels/__init__.py create mode 100644 addons/dine360_order_channels/__manifest__.py create mode 100644 addons/dine360_order_channels/controllers/__init__.py create mode 100644 addons/dine360_order_channels/controllers/main.py create mode 100644 addons/dine360_order_channels/models/__init__.py create mode 100644 addons/dine360_order_channels/models/pos_config.py create mode 100644 addons/dine360_order_channels/models/pos_order.py create mode 100644 addons/dine360_order_channels/security/ir.model.access.csv create mode 100644 addons/dine360_order_channels/static/src/css/channel_panel.css create mode 100644 addons/dine360_order_channels/static/src/js/channel_panel.js create mode 100644 addons/dine360_order_channels/static/src/js/order_channel_model.js create mode 100644 addons/dine360_order_channels/static/src/js/product_screen_patch.js create mode 100644 addons/dine360_order_channels/static/src/xml/channel_panel.xml create mode 100644 addons/dine360_order_channels/static/src/xml/receipt_extension.xml create mode 100644 addons/dine360_order_channels/views/pos_order_views.xml create mode 100644 addons/dine360_self_order/__init__.py create mode 100644 addons/dine360_self_order/__manifest__.py create mode 100644 addons/dine360_self_order/controllers/__init__.py create mode 100644 addons/dine360_self_order/controllers/main.py create mode 100644 addons/dine360_self_order/models/__init__.py create mode 100644 addons/dine360_self_order/models/restaurant_table.py create mode 100644 addons/dine360_self_order/static/src/css/self_order.css create mode 100644 addons/dine360_self_order/static/src/js/self_order.js create mode 100644 addons/dine360_self_order/views/restaurant_table_views.xml create mode 100644 addons/dine360_self_order/views/self_order_templates.xml diff --git a/.agents/workflows/testing.md b/.agents/workflows/testing.md new file mode 100644 index 0000000..f5f12ab --- /dev/null +++ b/.agents/workflows/testing.md @@ -0,0 +1,50 @@ +--- +description: Dine360 End-to-End (E2E) Integration Testing Workflow +--- + +# 🚀 Dine360 E2E Testing Workflow + +This workflow ensures all modules (`Self-Order`, `Online Orders`, `KDS`, and `POS`) are communicating correctly. + +## 1. Environment Check +Before testing, verify the services are up: +// turbo +`docker ps` +Ensure `odoo_client2` and `db` are in a 'Healthy' or 'Up' state. + +## 2. Setup POS Session +1. Open your Odoo instance (usually `http://localhost:8069`). +2. Go to **Point of Sale**. +3. **Open** a new session for your main Shop/Restaurant. + +## 3. Test Flow: Self-Order (Table QR) +1. Go to **Point of Sale > Configuration > Floor Plans**. +2. Select a floor and a table (e.g., "Table 1"). +3. Click the **Open Front-end** button (this opens the Self-Order menu). +4. **Action**: Add 2-3 items to the cart and click **Send to Kitchen**. +5. **Verification**: + - [ ] Go to the **Kitchen (KDS)** module. + - [ ] Check that the items appear in the **Waiting** column. + - [ ] Confirm the source badge shows **QR Table Order / Table 1**. + +## 4. Test Flow: Online Orders (Website) +1. Navigate to the Website Shop (`/shop`). +2. **Action**: Add items to the cart, proceed to checkout, and complete the order. +3. **Internal POS Verification**: + - [ ] Open the POS UI. + - [ ] Click the **Online Orders** tab in the top navbar. + - [ ] Select your order and click **Confirm & Send to Kitchen**. +4. **KDS Verification**: + - [ ] Check the **Kitchen (KDS)** module. + - [ ] Source badge should show **Online / eCommerce**. + +## 5. Test Flow: KDS Management +1. In the **Kitchen (KDS)** dashboard: +2. **Action**: Click the **Preparing** button on one of the cards. +3. **Action**: Click the **Ready** button when finished. +4. **Verification**: + - [ ] Confirm the item moves to the correct column. + - [ ] If you are in the POS UI, check if any notifications appear regarding readiness (if implemented). + +## 6. Verification Summary +If all checks above pass, the integration between the Frontend (Customer), Middle-end (POS), and Backend (KDS) is working perfectly. diff --git a/addons/dine360_kds/__manifest__.py b/addons/dine360_kds/__manifest__.py index c3b170e..c7909d5 100644 --- a/addons/dine360_kds/__manifest__.py +++ b/addons/dine360_kds/__manifest__.py @@ -12,7 +12,7 @@ - Floor/Table based organization """, 'author': 'Dine360', - 'depends': ['point_of_sale', 'pos_restaurant', 'dine360_restaurant', 'sale_management', 'website_sale'], + 'depends': ['point_of_sale', 'pos_restaurant', 'dine360_restaurant', 'sale_management', 'website_sale', 'dine360_order_channels'], 'data': [ 'security/ir.model.access.csv', 'views/pos_order_line_views.xml', diff --git a/addons/dine360_kds/static/src/js/kds_backend.js b/addons/dine360_kds/static/src/js/kds_backend.js index 48f04e8..5088a89 100644 --- a/addons/dine360_kds/static/src/js/kds_backend.js +++ b/addons/dine360_kds/static/src/js/kds_backend.js @@ -4,13 +4,14 @@ import { registry } from "@web/core/registry"; import { KanbanController } from "@web/views/kanban/kanban_controller"; import { kanbanView } from "@web/views/kanban/kanban_view"; import { onWillUnmount } from "@odoo/owl"; +import { useService } from "@web/core/utils/hooks"; export class KdsKanbanController extends KanbanController { setup() { super.setup(); console.log("[KDS Controller] Setup"); - // Direct access to services to avoid useService potential conflicts + // Direct access to services to avoid 'methods is not iterable' error in Owl lifecycle this.busService = this.env.services.bus_service; this.notification = this.env.services.notification; @@ -28,8 +29,6 @@ export class KdsKanbanController extends KanbanController { this.busService.removeEventListener("notification", handler); } }); - } else { - console.error("[KDS Controller] Bus service not found!"); } } diff --git a/addons/dine360_kds/views/pos_order_line_views.xml b/addons/dine360_kds/views/pos_order_line_views.xml index 563ac13..bb8c86d 100644 --- a/addons/dine360_kds/views/pos_order_line_views.xml +++ b/addons/dine360_kds/views/pos_order_line_views.xml @@ -12,11 +12,13 @@ + + -
+
@@ -26,22 +28,30 @@
- +
-
- Note: +
+ Note:
-
- +
+
+
+ + + + + + +
@@ -81,6 +91,8 @@ + + diff --git a/addons/dine360_online_orders/__manifest__.py b/addons/dine360_online_orders/__manifest__.py index bc4ae0f..7cbdb35 100644 --- a/addons/dine360_online_orders/__manifest__.py +++ b/addons/dine360_online_orders/__manifest__.py @@ -11,7 +11,7 @@ - Real-time notifications via bus service """, 'author': 'Dine360', - 'depends': ['point_of_sale', 'pos_restaurant', 'dine360_kds', 'website_sale', 'sale_management'], + 'depends': ['point_of_sale', 'pos_restaurant', 'dine360_kds', 'website_sale', 'sale_management', 'dine360_order_channels'], 'data': [ 'security/ir.model.access.csv', 'views/pos_order_views.xml', diff --git a/addons/dine360_online_orders/controllers/main.py b/addons/dine360_online_orders/controllers/main.py index 4b6e196..279f82c 100644 --- a/addons/dine360_online_orders/controllers/main.py +++ b/addons/dine360_online_orders/controllers/main.py @@ -8,7 +8,7 @@ class Dine360OnlineOrders(http.Controller): order = request.website.sale_get_order() if order and service_mode in ['pickup', 'delivery', 'dine_in']: order.sudo().write({ - 'dine360_service_mode': service_mode, - 'dine360_order_source': 'web' + 'fulfilment_type': service_mode, + 'order_source': 'online' }) return True diff --git a/addons/dine360_online_orders/models/pos_order.py b/addons/dine360_online_orders/models/pos_order.py index 389eb84..9182683 100644 --- a/addons/dine360_online_orders/models/pos_order.py +++ b/addons/dine360_online_orders/models/pos_order.py @@ -31,17 +31,8 @@ class PosOrder(models.Model): default=fields.Datetime.now ) - dine360_order_source = fields.Selection([ - ('web', 'Customer Self (Web)'), - ('kiosk', 'Store Self (Kiosk)'), - ('pos', 'Standard POS') - ], string='Order Source', default='pos') - - dine360_service_mode = fields.Selection([ - ('pickup', 'Pickup'), - ('delivery', 'Delivery'), - ('dine_in', 'Dine-In') - ], string='Service Mode', default='dine_in') + # Note: order_source and fulfilment_type fields are defined in dine360_order_channels + # dine360_online_orders just uses these fields @api.depends('partner_id', 'partner_id.name') def _compute_online_customer_name(self): @@ -98,8 +89,8 @@ class PosOrder(models.Model): if 'session_id' in vals: session = self.env['pos.session'].browse(vals['session_id']) if session.config_id.is_kiosk: - vals['dine360_order_source'] = 'kiosk' - vals['dine360_service_mode'] = session.config_id.kiosk_service_mode + vals['order_source'] = 'kiosk' + vals['fulfilment_type'] = session.config_id.kiosk_service_mode or 'pickup' return super().create(vals_list) @api.model @@ -134,8 +125,8 @@ class PosOrder(models.Model): 'amount_total': order.amount_total, 'date_order': order.date_order.isoformat() if order.date_order else '', 'sale_order_name': order.sale_order_id.name if order.sale_order_id else '', - 'service_mode': order.dine360_service_mode, - 'order_source': order.dine360_order_source, + 'service_mode': order.fulfilment_type, + 'order_source': order.order_source, 'note': order.note or '', 'lines': lines, }) diff --git a/addons/dine360_online_orders/models/pos_order_line.py b/addons/dine360_online_orders/models/pos_order_line.py index cd3a7b3..561f558 100644 --- a/addons/dine360_online_orders/models/pos_order_line.py +++ b/addons/dine360_online_orders/models/pos_order_line.py @@ -1,15 +1,5 @@ -from odoo import models, fields, api +from odoo import models class PosOrderLine(models.Model): _inherit = 'pos.order.line' - - dine360_order_source = fields.Selection( - related='order_id.dine360_order_source', - string='Order Source', - store=True - ) - dine360_service_mode = fields.Selection( - related='order_id.dine360_service_mode', - string='Service Mode', - store=True - ) + # Related fields order_source and fulfilment_type are now provided by dine360_order_channels diff --git a/addons/dine360_online_orders/models/sale_order.py b/addons/dine360_online_orders/models/sale_order.py index bfdab3c..d4d1d33 100644 --- a/addons/dine360_online_orders/models/sale_order.py +++ b/addons/dine360_online_orders/models/sale_order.py @@ -12,17 +12,24 @@ class SaleOrderOnline(models.Model): help='The POS order created from this website sale order' ) - dine360_order_source = fields.Selection([ - ('web', 'Customer Self (Web)'), - ('kiosk', 'Store Self (Kiosk)'), - ('pos', 'Standard POS') - ], string='Order Source', default='web') + # order_source is now canonical field from dine360_order_channels (pos.order) + # We add it to sale.order for tracking which channel the web sale originated from + order_source = fields.Selection([ + ('walk_in', 'Walk-In'), + ('phone', 'Phone'), + ('online', 'Online / eCommerce'), + ('whatsapp', 'WhatsApp'), + ('social_media', 'Social Media'), + ('platform', 'Platform'), + ('kiosk', 'Kiosk'), + ('qr', 'QR Code'), + ], string='Order Source', default='online') - dine360_service_mode = fields.Selection([ - ('pickup', 'Pickup'), + fulfilment_type = fields.Selection([ + ('dine_in', 'Dine-In'), + ('pickup', 'Pickup'), ('delivery', 'Delivery'), - ('dine_in', 'Dine-In') - ], string='Service Mode', default='pickup') + ], string='Fulfilment Type', default='pickup') def _create_pos_order_for_kds(self, sale_order): """ @@ -47,8 +54,8 @@ class SaleOrderOnline(models.Model): 'online_order_status': 'pending', 'sale_order_id': sale_order.id, 'online_order_date': fields.Datetime.now(), - 'dine360_order_source': sale_order.dine360_order_source, - 'dine360_service_mode': sale_order.dine360_service_mode, + 'order_source': sale_order.order_source or 'online', + 'fulfilment_type': sale_order.fulfilment_type or 'pickup', }) # Link back to sale order diff --git a/addons/dine360_online_orders/static/src/js/service_mode.js b/addons/dine360_online_orders/static/src/js/service_mode.js index 3cde396..3c2a465 100644 --- a/addons/dine360_online_orders/static/src/js/service_mode.js +++ b/addons/dine360_online_orders/static/src/js/service_mode.js @@ -6,12 +6,12 @@ import { jsonrpc } from "@web/core/network/rpc_service"; publicWidget.registry.ServiceModeSelector = publicWidget.Widget.extend({ selector: '#service_mode_selector', events: { - 'change input[name="dine360_service_mode"]': '_onChangeServiceMode', + 'change input[name="fulfilment_type"]': '_onChangeServiceMode', }, start: function () { // Init visual selection - this.$('input[name="dine360_service_mode"]:checked').closest('.service-option').find('.service-card') + this.$('input[name="fulfilment_type"]:checked').closest('.service-option').find('.service-card') .css({ 'border-color': '#FECD4F', 'background-color': '#fffdf6', 'box-shadow': '0 4px 10px rgba(254, 205, 79, 0.2)' }); return this._super.apply(this, arguments); }, @@ -46,7 +46,7 @@ publicWidget.registry.CartCheckoutValidation = publicWidget.Widget.extend({ _onCheckoutClicked: function (ev) { // If there's a selector on the page if (this.$('#service_mode_selector').length > 0) { - var selectedMode = this.$('input[name="dine360_service_mode"]:checked').val(); + var selectedMode = this.$('input[name="fulfilment_type"]:checked').val(); if (!selectedMode) { ev.preventDefault(); this.$('#service_mode_error').removeClass('d-none'); diff --git a/addons/dine360_online_orders/views/kds_override_views.xml b/addons/dine360_online_orders/views/kds_override_views.xml index e31d236..b922ec8 100644 --- a/addons/dine360_online_orders/views/kds_override_views.xml +++ b/addons/dine360_online_orders/views/kds_override_views.xml @@ -10,31 +10,4 @@ '|', ('order_id.is_online_order', '=', False), ('order_id.online_order_status', '!=', 'pending') ] - - - - pos.order.line.kds.kanban.inherit - pos.order.line - - - - - - - -
- - - - - - - - - -
-
-
-
diff --git a/addons/dine360_online_orders/views/pos_order_views.xml b/addons/dine360_online_orders/views/pos_order_views.xml index d8f4858..98e23ae 100644 --- a/addons/dine360_online_orders/views/pos_order_views.xml +++ b/addons/dine360_online_orders/views/pos_order_views.xml @@ -15,11 +15,11 @@ decoration-success="online_order_status=='confirmed'" decoration-danger="online_order_status=='rejected'"/> - - + +
@@ -38,8 +38,8 @@ decoration-success="online_order_status=='confirmed'" decoration-danger="online_order_status=='rejected'"/> - - + + diff --git a/addons/dine360_online_orders/views/website_sale_templates.xml b/addons/dine360_online_orders/views/website_sale_templates.xml index da39bd5..f4d1018 100644 --- a/addons/dine360_online_orders/views/website_sale_templates.xml +++ b/addons/dine360_online_orders/views/website_sale_templates.xml @@ -6,7 +6,7 @@

How would you like your order?