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
-
-
-
-
-
-
-
-