# -*- 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 class FusionLTCRepairStage(models.Model): _name = 'fusion.ltc.repair.stage' _description = 'LTC Repair Stage' _order = 'sequence, id' name = fields.Char(string='Stage Name', required=True, translate=True) sequence = fields.Integer(string='Sequence', default=10) fold = fields.Boolean( string='Folded in Kanban', help='Folded stages are hidden by default in the kanban view', ) color = fields.Char( string='Stage Color', help='CSS color class for stage badge (e.g. info, success, warning, danger)', default='secondary', ) description = fields.Text(string='Description') class FusionLTCRepair(models.Model): _name = 'fusion.ltc.repair' _description = 'LTC Repair Request' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'issue_reported_date desc, id desc' name = fields.Char( string='Reference', required=True, copy=False, readonly=True, default=lambda self: _('New'), ) facility_id = fields.Many2one( 'fusion.ltc.facility', string='LTC Facility', required=True, tracking=True, index=True, ) client_id = fields.Many2one( 'res.partner', string='Client/Resident', tracking=True, help='Link to the resident contact record', ) client_name = fields.Char( string='Client Name', help='Quick entry name when no contact record exists', ) display_client_name = fields.Char( compute='_compute_display_client_name', string='Client', store=True, ) room_number = fields.Char(string='Room Number') stage_id = fields.Many2one( 'fusion.ltc.repair.stage', string='Stage', tracking=True, group_expand='_read_group_stage_ids', default=lambda self: self._default_stage_id(), index=True, ) kanban_state = fields.Selection([ ('normal', 'In Progress'), ('done', 'Ready'), ('blocked', 'Blocked'), ], string='Kanban State', default='normal', tracking=True) color = fields.Integer(string='Color Index') is_emergency = fields.Boolean( string='Emergency Repair', tracking=True, help='Emergency visits may be chargeable at an extra rate', ) priority = fields.Selection([ ('0', 'Normal'), ('1', 'High'), ], string='Priority', default='0') product_serial = fields.Char(string='Product Serial #') product_id = fields.Many2one( 'product.product', string='Product', help='Link to product record if applicable', ) issue_description = fields.Text( string='Issue Description', required=True, ) issue_reported_date = fields.Date( string='Issue Reported Date', required=True, default=fields.Date.context_today, tracking=True, ) issue_fixed_date = fields.Date( string='Issue Fixed Date', tracking=True, ) resolution_description = fields.Text(string='Resolution Description') assigned_technician_id = fields.Many2one( 'res.users', string='Assigned Technician', tracking=True, ) task_id = fields.Many2one( 'fusion.technician.task', string='Field Service Task', tracking=True, ) sale_order_id = fields.Many2one( 'sale.order', string='Sale Order', tracking=True, help='Sale order created for this repair if applicable', ) sale_order_name = fields.Char( related='sale_order_id.name', string='SO Reference', ) poa_name = fields.Char(string='Family/POA Name') poa_phone = fields.Char(string='Family/POA Phone') company_id = fields.Many2one( 'res.company', string='Company', default=lambda self: self.env.company, ) currency_id = fields.Many2one( 'res.currency', related='company_id.currency_id', ) repair_value = fields.Monetary( string='Repair Value', currency_field='currency_id', ) photo_ids = fields.Many2many( 'ir.attachment', 'ltc_repair_photo_rel', 'repair_id', 'attachment_id', string='Photos (Legacy)', ) before_photo_ids = fields.Many2many( 'ir.attachment', 'ltc_repair_before_photo_rel', 'repair_id', 'attachment_id', string='Before Photos', ) after_photo_ids = fields.Many2many( 'ir.attachment', 'ltc_repair_after_photo_rel', 'repair_id', 'attachment_id', string='After Photos', ) notes = fields.Text(string='Internal Notes') source = fields.Selection([ ('portal_form', 'Portal Form'), ('manual', 'Manual Entry'), ('phone', 'Phone Call'), ('migrated', 'Migrated'), ], string='Source', default='manual', tracking=True) stage_color = fields.Char( related='stage_id.color', string='Stage Color', store=True, ) @api.model_create_multi def create(self, vals_list): for vals in vals_list: if vals.get('name', _('New')) == _('New'): vals['name'] = self.env['ir.sequence'].next_by_code('fusion.ltc.repair') or _('New') records = super().create(vals_list) for record in records: record._post_creation_message() return records def _post_creation_message(self): body = _( "Repair request submitted for %(client)s in Room %(room)s" " at %(facility)s.
" "Issue: %(issue)s", client=self.display_client_name or 'N/A', room=self.room_number or 'N/A', facility=self.facility_id.name, issue=self.issue_description or '', ) self.message_post(body=body, message_type='comment') def _default_stage_id(self): return self.env['fusion.ltc.repair.stage'].search([], order='sequence', limit=1).id @api.model def _read_group_stage_ids(self, stages, domain): return self.env['fusion.ltc.repair.stage'].search([], order='sequence') @api.depends('client_id', 'client_name') def _compute_display_client_name(self): for repair in self: if repair.client_id: repair.display_client_name = repair.client_id.name else: repair.display_client_name = repair.client_name or '' @api.onchange('client_id') def _onchange_client_id(self): if self.client_id: self.client_name = self.client_id.name if hasattr(self.client_id, 'x_fc_ltc_room_number') and self.client_id.x_fc_ltc_room_number: self.room_number = self.client_id.x_fc_ltc_room_number if hasattr(self.client_id, 'x_fc_ltc_facility_id') and self.client_id.x_fc_ltc_facility_id: self.facility_id = self.client_id.x_fc_ltc_facility_id def action_view_sale_order(self): self.ensure_one() if not self.sale_order_id: return return { 'name': self.sale_order_id.name, 'type': 'ir.actions.act_window', 'res_model': 'sale.order', 'view_mode': 'form', 'res_id': self.sale_order_id.id, } def action_view_task(self): self.ensure_one() if not self.task_id: return return { 'name': self.task_id.name, 'type': 'ir.actions.act_window', 'res_model': 'fusion.technician.task', 'view_mode': 'form', 'res_id': self.task_id.id, } def action_create_sale_order(self): self.ensure_one() if self.sale_order_id: raise UserError(_('A sale order already exists for this repair.')) if not self.client_id and self.client_name: return { 'name': _('Link Contact'), 'type': 'ir.actions.act_window', 'res_model': 'fusion.ltc.repair.create.so.wizard', 'view_mode': 'form', 'target': 'new', 'context': { 'default_repair_id': self.id, 'default_client_name': self.client_name, }, } if not self.client_id: raise UserError(_('Please set a client before creating a sale order.')) return self._create_linked_sale_order() def _create_linked_sale_order(self): self.ensure_one() SaleOrder = self.env['sale.order'] OrderLine = self.env['sale.order.line'] so_vals = { 'partner_id': self.client_id.id, 'x_fc_ltc_repair_id': self.id, } sale_order = SaleOrder.create(so_vals) seq = 10 OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_section', 'name': 'PRODUCTS & REPAIRS', 'sequence': seq, }) seq += 10 repair_tmpl = self.env.ref( 'fusion_claims.product_ltc_repair_service', raise_if_not_found=False ) repair_product = ( repair_tmpl.product_variant_id if repair_tmpl else False ) line_vals = { 'order_id': sale_order.id, 'sequence': seq, 'name': 'Repairs at LTC Home - %s' % (self.facility_id.name or ''), } if repair_product: line_vals['product_id'] = repair_product.id else: line_vals['display_type'] = 'line_note' OrderLine.create(line_vals) seq += 10 OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_section', 'name': 'REPORTED ISSUES', 'sequence': seq, }) seq += 10 if self.issue_description: OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_note', 'name': self.issue_description, 'sequence': seq, }) seq += 10 if self.issue_reported_date: OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_note', 'name': 'Reported Date: %s' % self.issue_reported_date, 'sequence': seq, }) seq += 10 OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_section', 'name': 'PROPOSED RESOLUTION', 'sequence': seq, }) seq += 10 if self.resolution_description: OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_note', 'name': self.resolution_description, 'sequence': seq, }) seq += 10 if self.product_serial: OrderLine.create({ 'order_id': sale_order.id, 'display_type': 'line_note', 'name': 'Serial Number: %s' % self.product_serial, 'sequence': seq, }) self.sale_order_id = sale_order.id return { 'name': sale_order.name, 'type': 'ir.actions.act_window', 'res_model': 'sale.order', 'view_mode': 'form', 'res_id': sale_order.id, }