# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) # Part of the Fusion Plating product family. from odoo import api, fields, models class FpPickupRequest(models.Model): """Customer-initiated request for pickup of parts to be processed. Lifecycle: new → scheduled → en_route → picked_up → received → (cancelled) A pickup request is created when a customer phones or emails asking for parts to be collected. Dispatch schedules a driver + vehicle, the driver updates status on the road, and the receiving facility confirms arrival of the parts. Chain of custody events are written automatically as the state transitions. """ _name = 'fusion.plating.pickup.request' _description = 'Fusion Plating — Pickup Request' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'requested_date desc, id desc' name = fields.Char( string='Reference', required=True, copy=False, default=lambda self: self._default_name(), tracking=True, ) partner_id = fields.Many2one( 'res.partner', string='Customer', required=True, tracking=True, ) pickup_address_id = fields.Many2one( 'res.partner', string='Pickup Address', help='Leave blank to use the customer default address.', ) contact_name = fields.Char( string='Contact Name', ) contact_phone = fields.Char( string='Contact Phone', ) requested_date = fields.Datetime( string='Requested Date', default=fields.Datetime.now, tracking=True, ) scheduled_date = fields.Datetime( string='Scheduled Date', tracking=True, ) assigned_driver_id = fields.Many2one( 'hr.employee', string='Assigned Driver', tracking=True, domain=[('x_fc_is_driver', '=', True)], ) vehicle_id = fields.Many2one( 'fusion.plating.vehicle', string='Vehicle', tracking=True, ) destination_facility_id = fields.Many2one( 'fusion.plating.facility', string='Destination Facility', tracking=True, ) company_id = fields.Many2one( 'res.company', related='destination_facility_id.company_id', store=True, readonly=True, ) item_description = fields.Html( string='Items to Pick Up', ) estimated_weight_kg = fields.Float( string='Est. Weight (kg)', ) tdg_required = fields.Boolean( string='TDG Required', tracking=True, help='Check if the load qualifies as Transportation of Dangerous ' 'Goods. Only TDG-certified drivers and vehicles may be ' 'assigned.', ) state = fields.Selection( [ ('new', 'New'), ('scheduled', 'Scheduled'), ('en_route', 'En Route'), ('picked_up', 'Picked Up'), ('received', 'Received at Facility'), ('cancelled', 'Cancelled'), ], string='Status', default='new', required=True, tracking=True, ) picked_up_at = fields.Datetime( string='Picked Up At', readonly=True, ) received_at = fields.Datetime( string='Received At', readonly=True, ) notes = fields.Html( string='Notes', ) custody_event_ids = fields.One2many( 'fusion.plating.chain.of.custody', 'pickup_request_id', string='Custody Events', ) custody_event_count = fields.Integer( compute='_compute_custody_count', ) @api.model def _default_name(self): seq = self.env['ir.sequence'].next_by_code('fusion.plating.pickup.request') return seq or '/' def _compute_custody_count(self): for rec in self: rec.custody_event_count = len(rec.custody_event_ids) def _log_custody_event(self, event_type, from_party=None, to_party=None): self.ensure_one() self.env['fusion.plating.chain.of.custody'].create({ 'event_datetime': fields.Datetime.now(), 'event_type': event_type, 'from_party': from_party or '', 'to_party': to_party or '', 'pickup_request_id': self.id, 'facility_id': self.destination_facility_id.id, 'recorded_by_id': self.env.user.id, }) # ========================================================================== # Actions # ========================================================================== def action_schedule(self): self.write({'state': 'scheduled'}) def action_start_route(self): self.write({'state': 'en_route'}) def action_mark_picked_up(self): for rec in self: rec.write({ 'state': 'picked_up', 'picked_up_at': fields.Datetime.now(), }) rec._log_custody_event( 'received_from_customer', from_party=rec.partner_id.display_name, to_party=(rec.assigned_driver_id.display_name or rec.vehicle_id.display_name or 'Driver'), ) def action_mark_received(self): for rec in self: rec.write({ 'state': 'received', 'received_at': fields.Datetime.now(), }) rec._log_custody_event( 'entered_facility', from_party=(rec.assigned_driver_id.display_name or rec.vehicle_id.display_name or 'Driver'), to_party=(rec.destination_facility_id.display_name or 'Facility'), ) def action_cancel(self): self.write({'state': 'cancelled'}) def action_reset_to_new(self): self.write({'state': 'new'})