from odoo import models, fields, api, _ from odoo.exceptions import UserError import datetime class PosOrder(models.Model): _inherit = 'pos.order' is_uber_order = fields.Boolean(string='Is Uber Order', default=False) uber_order_id = fields.Char(string='Uber Order ID') uber_delivery_id = fields.Char(string='Uber Delivery ID') uber_status = fields.Selection([ ('pending', 'Pending Uber Pickup'), ('pickup', 'Uber Driver Picked Up'), ('delivering', 'In Transit'), ('delivered', 'Delivered'), ('cancelled', 'Cancelled') ], string='Uber Delivery Status') delivery_type = fields.Selection([ ('none', 'None'), ('dine_in', 'Dine In'), ('takeaway', 'Takeaway'), ('uber', 'Uber Direct') ], string='Delivery Type', default='none') # Advanced Features Fields uber_tracking_url = fields.Char(string='Driver Tracking Link') uber_eta = fields.Datetime(string='Predicted Delivery Time') uber_delivery_fee = fields.Float(string='Uber Delivery Fee', readonly=True) uber_request_time = fields.Datetime(string='Uber Request Time') uber_alert_triggered = fields.Boolean(string='Driver Timeout Alert Sent', default=False) def _check_all_lines_ready(self): """Check if all kitchen items in the order are ready or served""" self.ensure_one() kitchen_lines = self.lines.filtered(lambda l: l.product_id.is_kitchen_item) if not kitchen_lines: return False return all(line.preparation_status in ['ready', 'served'] for line in kitchen_lines) def action_request_uber_delivery(self): """Trigger Uber Direct delivery request and estimate fee""" for order in self: if order.is_uber_order and order.uber_status and order.uber_status != 'cancelled': continue # SIMULATION: In a real flow, we would call Uber's 'Quotes' API first simulated_fee = 15.0 # Placeholder fee order.write({ 'uber_status': 'pending', 'is_uber_order': True, 'uber_delivery_id': 'UBER-' + str(order.id) + '-' + fields.Datetime.now().strftime('%Y%m%d%H%M%S'), 'uber_request_time': fields.Datetime.now(), 'uber_delivery_fee': simulated_fee, 'uber_tracking_url': 'https://ubr.to/sample-tracking-' + str(order.id), 'uber_eta': fields.Datetime.now() + datetime.timedelta(minutes=30) }) # AUTOMATICALLY ADD CHARGE TO BILL order._add_uber_delivery_fee(simulated_fee) # order.message_post(body="Uber Direct delivery requested. Estimated Fee: %.2f. ETA: %s" % (simulated_fee, order.uber_eta)) def _add_uber_delivery_fee(self, amount): """Add the delivery fee as a line item if not already added""" config = self.env['uber.config'].search([('active', '=', True)], limit=1) if config and config.delivery_product_id: # Check if fee line exists fee_line = self.lines.filtered(lambda l: l.product_id == config.delivery_product_id) if not fee_line: self.write({'lines': [(0, 0, { 'product_id': config.delivery_product_id.id, 'price_unit': amount, 'qty': 1, 'tax_ids': [(6, 0, config.delivery_product_id.taxes_id.ids)], })]}) def action_cancel_uber_delivery(self): for order in self: if not order.uber_delivery_id: continue order.write({ 'uber_status': 'cancelled', 'uber_delivery_id': False, 'is_uber_order': False, 'uber_tracking_url': False, 'uber_eta': False }) # order.message_post(body="Uber Direct delivery request cancelled.") @api.model def cron_check_uber_driver_assignment(self): """Auto-alert if driver not assigned in X minutes""" config = self.env['uber.config'].search([('active', '=', True)], limit=1) if not config or config.timeout_minutes <= 0: return timeout_threshold = fields.Datetime.now() - datetime.timedelta(minutes=config.timeout_minutes) pending_orders = self.search([ ('uber_status', '=', 'pending'), ('uber_request_time', '<=', timeout_threshold), ('uber_alert_triggered', '=', False) ]) for order in pending_orders: # Send notification to POS Users/Managers order.uber_alert_triggered = True # order.message_post(body="🚨 ALERT: No Uber driver assigned for over %s minutes! Please check Uber dashboard." % config.timeout_minutes) # Broadcaster for UI Alert self.env['bus.bus']._sendone('pos_alerts', 'uber_timeout', { 'order_name': order.name, 'minutes': config.timeout_minutes }) def action_view_uber_map(self): """Open Uber Live Tracking Link""" self.ensure_one() if not self.uber_tracking_url: raise UserError(_("No tracking link available yet.")) return { 'type': 'ir.actions.act_url', 'url': self.uber_tracking_url, 'target': 'new', }