# -*- coding: utf-8 -*- # Copyright 2024-2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) from odoo import models, fields, api, _ from odoo.exceptions import UserError import logging _logger = logging.getLogger(__name__) class LoanerCheckoutWizard(models.TransientModel): """Wizard to checkout loaner equipment.""" _name = 'fusion.loaner.checkout.wizard' _description = 'Loaner Checkout Wizard' # ========================================================================= # CONTEXT FIELDS # ========================================================================= sale_order_id = fields.Many2one( 'sale.order', string='Sale Order', readonly=True, ) partner_id = fields.Many2one( 'res.partner', string='Client', required=True, ) authorizer_id = fields.Many2one( 'res.partner', string='Authorizer', ) # ========================================================================= # PRODUCT SELECTION # ========================================================================= product_id = fields.Many2one( 'product.product', string='Product', domain="[('x_fc_can_be_loaned', '=', True)]", required=True, ) lot_id = fields.Many2one( 'stock.lot', string='Serial Number', domain="[('product_id', '=', product_id)]", ) available_lot_ids = fields.Many2many( 'stock.lot', compute='_compute_available_lots', string='Available Serial Numbers', ) # ========================================================================= # DATES # ========================================================================= checkout_date = fields.Date( string='Checkout Date', required=True, default=fields.Date.context_today, ) loaner_period_days = fields.Integer( string='Loaner Period (Days)', default=7, ) expected_return_date = fields.Date( string='Expected Return Date', compute='_compute_expected_return', ) # ========================================================================= # CONDITION # ========================================================================= checkout_condition = fields.Selection([ ('excellent', 'Excellent'), ('good', 'Good'), ('fair', 'Fair'), ('needs_repair', 'Needs Repair'), ], string='Condition', default='excellent', required=True) checkout_notes = fields.Text( string='Notes', ) # ========================================================================= # PHOTOS # ========================================================================= checkout_photo_ids = fields.Many2many( 'ir.attachment', 'loaner_checkout_wizard_photo_rel', 'wizard_id', 'attachment_id', string='Photos', ) # ========================================================================= # DELIVERY # ========================================================================= delivery_address = fields.Text( string='Delivery Address', ) # ========================================================================= # COMPUTED # ========================================================================= @api.depends('product_id') def _compute_available_lots(self): """Get available serial numbers for the selected product.""" for wizard in self: if wizard.product_id: # Get loaner location loaner_location = self.env.ref('fusion_claims.stock_location_loaner', raise_if_not_found=False) if loaner_location: # Find lots with stock in loaner location quants = self.env['stock.quant'].search([ ('product_id', '=', wizard.product_id.id), ('location_id', '=', loaner_location.id), ('quantity', '>', 0), ]) wizard.available_lot_ids = quants.mapped('lot_id') else: # Fallback: all lots for product wizard.available_lot_ids = self.env['stock.lot'].search([ ('product_id', '=', wizard.product_id.id), ]) else: wizard.available_lot_ids = False @api.depends('checkout_date', 'loaner_period_days') def _compute_expected_return(self): from datetime import timedelta for wizard in self: if wizard.checkout_date and wizard.loaner_period_days: wizard.expected_return_date = wizard.checkout_date + timedelta(days=wizard.loaner_period_days) else: wizard.expected_return_date = False # ========================================================================= # ONCHANGE # ========================================================================= @api.onchange('product_id') def _onchange_product_id(self): if self.product_id: self.loaner_period_days = self.product_id.x_fc_loaner_period_days or 7 self.lot_id = False # ========================================================================= # DEFAULT GET # ========================================================================= @api.model def default_get(self, fields_list): res = super().default_get(fields_list) # Get context active_model = self._context.get('active_model') active_id = self._context.get('active_id') if active_model == 'sale.order' and active_id: order = self.env['sale.order'].browse(active_id) res['sale_order_id'] = order.id res['partner_id'] = order.partner_id.id res['authorizer_id'] = order.x_fc_authorizer_id.id if order.x_fc_authorizer_id else False if order.partner_shipping_id: res['delivery_address'] = order.partner_shipping_id.contact_address # Get default loaner period from settings ICP = self.env['ir.config_parameter'].sudo() default_period = int(ICP.get_param('fusion_claims.default_loaner_period_days', '7')) res['loaner_period_days'] = default_period return res # ========================================================================= # ACTION # ========================================================================= def action_checkout(self): """Create and confirm loaner checkout.""" self.ensure_one() if not self.product_id: raise UserError(_("Please select a product.")) # Create persistent attachments for photos photo_ids = [] for photo in self.checkout_photo_ids: new_attachment = self.env['ir.attachment'].create({ 'name': photo.name, 'datas': photo.datas, 'res_model': 'fusion.loaner.checkout', 'res_id': 0, # Will update after checkout creation }) photo_ids.append(new_attachment.id) # Create checkout record checkout_vals = { 'sale_order_id': self.sale_order_id.id if self.sale_order_id else False, 'partner_id': self.partner_id.id, 'authorizer_id': self.authorizer_id.id if self.authorizer_id else False, 'sales_rep_id': self.env.user.id, 'product_id': self.product_id.id, 'lot_id': self.lot_id.id if self.lot_id else False, 'checkout_date': self.checkout_date, 'loaner_period_days': self.loaner_period_days, 'checkout_condition': self.checkout_condition, 'checkout_notes': self.checkout_notes, 'delivery_address': self.delivery_address, } checkout = self.env['fusion.loaner.checkout'].create(checkout_vals) # Update photo attachments if photo_ids: self.env['ir.attachment'].browse(photo_ids).write({'res_id': checkout.id}) checkout.checkout_photo_ids = [(6, 0, photo_ids)] # Confirm checkout checkout.action_checkout() # Return to checkout record return { 'type': 'ir.actions.act_window', 'name': _('Loaner Checkout'), 'res_model': 'fusion.loaner.checkout', 'res_id': checkout.id, 'view_mode': 'form', 'target': 'current', }