from odoo import models, fields, api, _ import logging _logger = logging.getLogger(__name__) class SaleOrder(models.Model): _inherit = 'sale.order' def action_confirm(self): """ Override to create a POS Order for KDS when a Website Order is confirmed. """ res = super(SaleOrder, self).action_confirm() for order in self: # Check if it's a website order (usually has website_id) if order.website_id: try: self._create_pos_order_for_kds(order) except Exception as e: _logger.error(f"Failed to create POS order for Website Order {order.name}: {str(e)}") return res def _create_pos_order_for_kds(self, sale_order): """Create a POS Order based on the Sale Order details""" # Use a savepoint so that if KDS creation fails, the main Sale Order confirmation succeeds with self.env.cr.savepoint(): PosOrder = self.env['pos.order'] PosSession = self.env['pos.session'] PosConfig = self.env['pos.config'] # 1. Find a suitable POS Config (e.g., 'Website' or first available restaurant) config = PosConfig.search([('module_pos_restaurant', '=', True), ('active', '=', True)], limit=1) if not config: _logger.warning("No active POS Restaurant configuration found. Skipping KDS creation.") return # 2. Find or Open a Session session = PosSession.search([ ('config_id', '=', config.id), ('state', '=', 'opened') ], limit=1) if not session: _logger.warning(f"No open POS session found for config {config.name}. Cannot send to KDS.") return # 3. Create POS Order Lines lines_data = [] for line in sale_order.order_line: if not line.product_id: continue qty = line.product_uom_qty if qty <= 0: continue # Skip non-kitchen items (delivery charges, shipping, etc.) if not line.product_id.is_kitchen_item or line.product_id.type == 'service': continue lines_data.append((0, 0, { 'product_id': line.product_id.id, 'qty': qty, 'price_unit': line.price_unit, 'price_subtotal': line.price_subtotal, 'price_subtotal_incl': line.price_total, 'full_product_name': line.name, 'tax_ids': [(6, 0, line.tax_id.ids)], # Online orders: hold for cashier confirmation before sending to KDS 'preparation_status': False, 'customer_note': 'Web Order', })) if not lines_data: return # Generate proper POS reference matching Odoo's regex pattern '([0-9-]){14,}' # Odoo's _export_for_ui expects this to exist otherwise it crashes import datetime uid = f"{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}-{session.id}-{sale_order.id}" pos_reference = f"Order {uid}" # 4. Create POS Order (in Draft/New state to avoid double accounting) # Use skip_kds_notify context to prevent immediate KDS notification # Online orders will be sent to KDS only after cashier confirmation pos_order = PosOrder.with_context(skip_kds_notify=True).create({ 'session_id': session.id, 'company_id': sale_order.company_id.id, 'partner_id': sale_order.partner_id.id, 'pricelist_id': sale_order.pricelist_id.id or session.config_id.pricelist_id.id, 'pos_reference': pos_reference, 'lines': lines_data, 'amount_total': sale_order.amount_total, 'amount_tax': sale_order.amount_tax, 'amount_paid': 0.0, # Not processing payment in POS to avoid duplication 'amount_return': 0.0, 'note': f"From Website Order {sale_order.name}", # 'state': 'draft', # Default is draft }) # Notification to KDS is deferred until cashier confirms via dine360_online_orders _logger.info(f"Created POS Order {pos_order.name} from Website Order {sale_order.name} (pending cashier confirmation).")