# -*- coding: utf-8 -*- # Copyright 2024-2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) import base64 import json import logging import xml.etree.ElementTree as ET from odoo import api, fields, models _logger = logging.getLogger(__name__) class FusionAdpApplicationData(models.Model): _name = 'fusion.adp.application.data' _description = 'ADP Application Data (Parsed XML)' _order = 'application_date desc, id desc' _rec_name = 'display_name' # ------------------------------------------------------------------ # LINKAGE # ------------------------------------------------------------------ profile_id = fields.Many2one( 'fusion.client.profile', string='Client Profile', ondelete='cascade', index=True, ) sale_order_id = fields.Many2one( 'sale.order', string='Sale Order', ondelete='set null', index=True, ) display_name = fields.Char( string='Name', compute='_compute_display_name', store=True, ) # ------------------------------------------------------------------ # COMPLETE XML DATA (for round-trip export fidelity) # ------------------------------------------------------------------ xml_data_json = fields.Text( string='Complete XML Data (JSON)', help='Complete 1:1 JSON representation of all ~300 XML fields for export', ) raw_xml = fields.Text(string='Raw XML Data') # ------------------------------------------------------------------ # APPLICATION METADATA # ------------------------------------------------------------------ device_category = fields.Selection([ ('AA', 'Ambulation Aids (Section 2a)'), ('MD', 'Mobility Devices (Section 2b/2c)'), ('PS', 'Positioning/Seating (Section 2d)'), ('MX', 'Mixed/Multiple Sections'), ], string='Device Category') version_number = fields.Char(string='Form Version') application_date = fields.Date(string='Application Date') # ------------------------------------------------------------------ # SECTION 1 - APPLICANT BIOGRAPHICAL INFORMATION # ------------------------------------------------------------------ applicant_last_name = fields.Char(string='Last Name') applicant_first_name = fields.Char(string='First Name') applicant_middle_initial = fields.Char(string='Middle Initial') health_card_number = fields.Char(string='Health Card Number', index=True) health_card_version = fields.Char(string='Health Card Version') date_of_birth = fields.Date(string='Date of Birth') ltch_name = fields.Char(string='Long-Term Care Home') # Address (individual fields, not combined) unit_number = fields.Char(string='Unit Number') street_number = fields.Char(string='Street Number') street_name = fields.Char(string='Street Name') rural_route = fields.Char(string='Lot/Concession/Rural Route') city = fields.Char(string='City', index=True) province = fields.Char(string='Province') postal_code = fields.Char(string='Postal Code') # Contact home_phone = fields.Char(string='Home Phone') business_phone = fields.Char(string='Business Phone') phone_extension = fields.Char(string='Phone Extension') # ------------------------------------------------------------------ # SECTION 1 - CONFIRMATION OF BENEFITS # ------------------------------------------------------------------ receives_social_assistance = fields.Boolean(string='Receives Social Assistance') benefit_type = fields.Char(string='Benefit Program') benefit_owp = fields.Boolean(string='Ontario Works Program (OWP)') benefit_odsp = fields.Boolean(string='Ontario Disability Support Program (ODSP)') benefit_acsd = fields.Boolean(string='Assistance to Children with Severe Disabilities (ACSD)') wsib_eligible = fields.Boolean(string='WSIB Eligible') vac_eligible = fields.Boolean(string='Veterans Affairs Canada (VAC) Eligible') # ------------------------------------------------------------------ # SECTION 2 - DEVICES AND ELIGIBILITY # ------------------------------------------------------------------ medical_condition = fields.Text(string='Medical Condition / Diagnosis') mobility_status = fields.Text(string='Functional Mobility Status') # Previously funded equipment prev_funded_none = fields.Boolean(string='None Previously Funded') prev_funded_forearm = fields.Boolean(string='Forearm Crutches (Previously)') prev_funded_wheeled = fields.Boolean(string='Wheeled Walker (Previously)') prev_funded_manual = fields.Boolean(string='Manual Wheelchair (Previously)') prev_funded_power = fields.Boolean(string='Power Wheelchair (Previously)') prev_funded_addon = fields.Boolean(string='Power Add-On Device (Previously)') prev_funded_scooter = fields.Boolean(string='Power Scooter (Previously)') prev_funded_seating = fields.Boolean(string='Positioning Devices (Previously)') prev_funded_tilt = fields.Boolean(string='Power Tilt System (Previously)') prev_funded_recline = fields.Boolean(string='Power Recline System (Previously)') prev_funded_legrests = fields.Boolean(string='Power Elevating Leg Rests (Previously)') prev_funded_frame = fields.Boolean(string='Paediatric Standing Frame (Previously)') prev_funded_stroller = fields.Boolean(string='Paediatric Specialty Stroller (Previously)') # Devices currently required device_forearm_crutches = fields.Boolean(string='Forearm Crutches') device_wheeled_walker = fields.Boolean(string='Wheeled Walker') device_manual_wheelchair = fields.Boolean(string='Manual Wheelchair') device_ambulation_manual = fields.Boolean(string='Ambulation Aid + Manual Wheelchair') device_dependent_wheelchair = fields.Boolean(string='Manual Wheelchair (Dependent)') device_dynamic_tilt = fields.Boolean(string='Manual Dynamic Tilt Wheelchair') device_manual_dynamic = fields.Boolean(string='Manual Dynamic Tilt (Dependent)') device_manual_power_addon = fields.Boolean(string='Manual Wheelchair with Power Add-On') device_power_base = fields.Boolean(string='Power Base Only') device_power_scooter = fields.Boolean(string='Power Scooter Only') device_ambulation_power = fields.Boolean(string='Ambulation Aid + Power Base/Scooter') device_positioning = fields.Boolean(string='Positioning Devices (Seating)') device_high_tech = fields.Boolean(string='High Technology Power Base') device_standing_frame = fields.Boolean(string='Paediatric Standing Frame') device_adp_funded_mods = fields.Boolean(string='Modifications to ADP Funded Device(s)') device_non_adp_funded_mods = fields.Boolean(string='Modifications to Non ADP Funded Device(s)') # ------------------------------------------------------------------ # SECTION 2A - AMBULATION AIDS (Walkers) # ------------------------------------------------------------------ s2a_base_device = fields.Char(string='Walker Type') s2a_paediatric_frame = fields.Char(string='Paediatric Frame') s2a_forearm_crutches = fields.Char(string='Forearm Crutches Type') s2a_none = fields.Char(string='None Selected') s2a_reason = fields.Char(string='Reason for Application') s2a_replacement_status = fields.Char(string='Replacement - Mobility Status Change') s2a_replacement_size = fields.Char(string='Replacement - Body Size Change') s2a_replacement_adp = fields.Char(string='Replacement - Equipment Worn Out') s2a_replacement_special = fields.Char(string='Replacement - Special Circumstances') s2a_confirm1 = fields.Char(string='Confirmation 1') s2a_confirm2 = fields.Char(string='Confirmation 2') s2a_confirm3 = fields.Char(string='Confirmation 3') s2a_confirm4 = fields.Char(string='Confirmation 4') s2a_confirm5 = fields.Char(string='Confirmation 5') s2a_confirm6 = fields.Char(string='Confirmation 6') # Prescription s2a_seat_height = fields.Char(string='Seat Height') s2a_seat_height_unit = fields.Char(string='Seat Height Unit') s2a_handle_height = fields.Char(string='Push Handle Height') s2a_handle_height_unit = fields.Char(string='Handle Height Unit') s2a_hand_grips = fields.Char(string='Hand Grips') s2a_forearm_attachments = fields.Char(string='Forearm Attachments') s2a_width_handles = fields.Char(string='Width Between Push Handles') s2a_width_handles_unit = fields.Char(string='Width Handles Unit') s2a_client_weight = fields.Char(string='Client Weight') s2a_client_weight_unit = fields.Char(string='Client Weight Unit') s2a_brakes = fields.Char(string='Brakes') s2a_brake_type = fields.Char(string='Brake Type') s2a_num_wheels = fields.Char(string='Number of Wheels') s2a_wheel_size = fields.Char(string='Wheel Size') s2a_back_support = fields.Char(string='Back Support') # ADP options s2a_adp_walker = fields.Char(string='ADP Adolescent Walker') s2a_adp_frame = fields.Char(string='ADP Adolescent Frame') s2a_adp_standing = fields.Char(string='ADP Adolescent Standing') # Custom modifications s2a_custom = fields.Char(string='Custom Modifications Required') s2a_cost_labour = fields.Char(string='Cost of Labour') # ------------------------------------------------------------------ # SECTION 2B - MANUAL WHEELCHAIRS # ------------------------------------------------------------------ s2b_base_device = fields.Char(string='Manual Wheelchair Type') s2b_power_addon = fields.Char(string='Power Add-On Device') s2b_reason = fields.Char(string='Reason for Application') s2b_replacement_status = fields.Char(string='Replacement - Mobility Status') s2b_replacement_size = fields.Char(string='Replacement - Body Size') s2b_replacement_adp = fields.Char(string='Replacement - Equipment Worn') s2b_replacement_special = fields.Char(string='Replacement - Special') s2b_confirm1 = fields.Char(string='Confirmation 1') s2b_confirm2 = fields.Char(string='Confirmation 2') s2b_confirm3 = fields.Char(string='Confirmation 3') s2b_confirm4 = fields.Char(string='Confirmation 4') s2b_confirm5 = fields.Char(string='Confirmation 5') s2b_confirm6 = fields.Char(string='Confirmation 6') s2b_confirm7 = fields.Char(string='Confirmation 7') s2b_confirm8 = fields.Char(string='Confirmation 8') s2b_confirm9 = fields.Char(string='Confirmation 9') s2b_confirm10 = fields.Char(string='Confirmation 10') s2b_confirm11 = fields.Char(string='Confirmation 11') s2b_confirm12 = fields.Char(string='Confirmation 12') s2b_confirm13 = fields.Char(string='Confirmation 13') # Prescription s2b_seat_width = fields.Char(string='Seat Width') s2b_seat_width_unit = fields.Char(string='Seat Width Unit') s2b_seat_depth = fields.Char(string='Seat Depth') s2b_seat_depth_unit = fields.Char(string='Seat Depth Unit') s2b_floor_height = fields.Char(string='Finished Seat to Floor Height') s2b_floor_height_unit = fields.Char(string='Floor Height Unit') s2b_cane_height = fields.Char(string='Back Cane Height') s2b_cane_height_unit = fields.Char(string='Cane Height Unit') s2b_back_height = fields.Char(string='Finished Back Height') s2b_back_height_unit = fields.Char(string='Back Height Unit') s2b_rest_length = fields.Char(string='Finished Leg Rest Length') s2b_rest_length_unit = fields.Char(string='Rest Length Unit') s2b_client_weight = fields.Char(string='Client Weight') s2b_client_weight_unit = fields.Char(string='Client Weight Unit') # Add-on options s2b_adjustable_tension = fields.Boolean(string='Adjustable Tension Back Upholstery') s2b_heavy_duty = fields.Boolean(string='Heavy Duty Cross Braces & Upholstery') s2b_recliner = fields.Boolean(string='Recliner Option') s2b_footplates = fields.Boolean(string='Angle Adjustable Footplates') s2b_legrests = fields.Boolean(string='Elevating Legrests') s2b_spoke = fields.Boolean(string='Spoke Protectors') s2b_projected = fields.Boolean(string='Projected Handrims') s2b_standard_manual = fields.Boolean(string='Standard Manual with Dynamic Tilt') s2b_grade_aids = fields.Boolean(string='Grade Aids') s2b_caster_pin = fields.Boolean(string='Caster Pin Locks') s2b_amputee_axle = fields.Boolean(string='Amputee Axle Plates') s2b_quick_release = fields.Boolean(string='Quick Release Axles') s2b_stroller = fields.Boolean(string='Stroller Handles/Paediatric') s2b_oxygen = fields.Boolean(string='Oxygen Tank Holder') s2b_ventilator = fields.Boolean(string='Ventilator Tray') s2b_titanium = fields.Boolean(string='Titanium Frame') s2b_clothing_guards = fields.Boolean(string='Clothing Guards') s2b_one_arm = fields.Boolean(string='One Arm/Lever Drive') s2b_uni_lateral = fields.Boolean(string='Uni-Lateral Wheel Lock') s2b_plastic = fields.Boolean(string='Plastic Coated Handrims') s2b_rationale = fields.Text(string='Clinical Rationale') s2b_custom = fields.Char(string='Custom Modifications Required') s2b_cost_labour = fields.Char(string='Cost of Labour') # ------------------------------------------------------------------ # SECTION 2C - POWER BASES AND POWER SCOOTERS # ------------------------------------------------------------------ s2c_base_device = fields.Char(string='Power Base/Scooter Type') s2c_reason = fields.Char(string='Reason for Application') s2c_replacement_status = fields.Char(string='Replacement - Mobility Status') s2c_replacement_size = fields.Char(string='Replacement - Body Size') s2c_replacement_adp = fields.Char(string='Replacement - Equipment Worn') s2c_replacement_special = fields.Char(string='Replacement - Special') s2c_confirm1 = fields.Char(string='Power Base Confirmation 1') s2c_confirm2 = fields.Char(string='Power Base Confirmation 2') s2c_confirm3 = fields.Char(string='Scooter Confirmation 1') s2c_confirm4 = fields.Char(string='Scooter Confirmation 2') s2c_confirm5 = fields.Char(string='Scooter Confirmation 3') # Prescription s2c_seat_width = fields.Char(string='Seat Width') s2c_seat_width_unit = fields.Char(string='Seat Width Unit') s2c_back_height = fields.Char(string='Finished Back Height') s2c_back_height_unit = fields.Char(string='Back Height Unit') s2c_floor_height = fields.Char(string='Finished Seat to Floor Height') s2c_floor_height_unit = fields.Char(string='Floor Height Unit') s2c_rest_length = fields.Char(string='Leg Rest Length') s2c_rest_length_unit = fields.Char(string='Rest Length Unit') s2c_seat_depth = fields.Char(string='Seat Depth') s2c_seat_depth_unit = fields.Char(string='Seat Depth Unit') s2c_client_weight = fields.Char(string='Client Weight') s2c_client_weight_unit = fields.Char(string='Client Weight Unit') # Add-on options s2c_adjustable_tension = fields.Boolean(string='Adjustable Tension Back Upholstery') s2c_midline = fields.Boolean(string='Midline Control') s2c_manual_recline = fields.Boolean(string='Manual Recline Option') s2c_footplates = fields.Boolean(string='Angle Adjustable Footplates') s2c_legrests = fields.Boolean(string='Manual Elevating Legrests') s2c_swingaway = fields.Boolean(string='Swingaway Mounting Bracket') s2c_one_piece = fields.Boolean(string='One Piece 90/90 Front Riggings') s2c_seat_package_1 = fields.Boolean(string='Seat Package 1 for Power Bases') s2c_seat_package_2 = fields.Boolean(string='Seat Package 2 for Power Bases') s2c_oxygen = fields.Boolean(string='Oxygen Tank Holder') s2c_ventilator = fields.Boolean(string='Ventilator Tray') # Specialty controls s2c_sp_controls_1 = fields.Boolean(string='Specialty Controls 1 - Non Standard Joystick') s2c_sp_controls_2 = fields.Boolean(string='Specialty Controls 2 - Chin/Rim Control') s2c_sp_controls_3 = fields.Boolean(string='Specialty Controls 3 - Simple Touch') s2c_sp_controls_4 = fields.Boolean(string='Specialty Controls 4 - Proximity Control') s2c_sp_controls_5 = fields.Boolean(string='Specialty Controls 5 - Breath Control') s2c_sp_controls_6 = fields.Boolean(string='Specialty Controls 6 - Scanners') s2c_auto_correction = fields.Boolean(string='Auto Correction System') s2c_rationale = fields.Text(string='Clinical Rationale') # Power positioning s2c_power_tilt = fields.Boolean(string='Power Tilt Only') s2c_power_recline = fields.Boolean(string='Power Recline Only') s2c_tilt_and_recline = fields.Boolean(string='Power Tilt and Recline') s2c_power_elevating = fields.Boolean(string='Power Elevating Footrests') s2c_control_box = fields.Boolean(string='Multi-Function Control Box') s2c_custom = fields.Char(string='Custom Modifications Required') s2c_cost_labour = fields.Char(string='Cost of Labour') # ------------------------------------------------------------------ # SECTION 2D - POSITIONING DEVICES (SEATING) FOR MOBILITY # ------------------------------------------------------------------ # Seat Cushion s2d_seat_modular = fields.Boolean(string='Seat Cushion - Modular') s2d_seat_custom = fields.Boolean(string='Seat Cushion - Custom Fabricated') s2d_seat_cover_modular = fields.Boolean(string='Seat Cover - Modular') s2d_seat_cover_custom = fields.Boolean(string='Seat Cover - Custom Fabricated') s2d_seat_option_modular = fields.Boolean(string='Seat Options - Modular') s2d_seat_option_custom = fields.Boolean(string='Seat Options - Custom Fabricated') s2d_seat_hardware_modular = fields.Boolean(string='Seat Hardware - Modular') s2d_seat_hardware_custom = fields.Boolean(string='Seat Hardware - Custom Fabricated') s2d_adductor_modular = fields.Boolean(string='Pommel/Adductors - Modular') s2d_adductor_custom = fields.Boolean(string='Pommel/Adductors - Custom Fabricated') s2d_pommel_custom = fields.Boolean(string='Pommel Hardware - Custom Fabricated') # Back Support s2d_back_modular = fields.Boolean(string='Back Support - Modular') s2d_back_custom = fields.Boolean(string='Back Support - Custom Fabricated') s2d_back_option_modular = fields.Boolean(string='Back Options - Modular') s2d_back_option_custom = fields.Boolean(string='Back Options - Custom Fabricated') s2d_back_cover_custom = fields.Boolean(string='Back Cover - Custom Fabricated') s2d_back_hardware_modular = fields.Boolean(string='Back Hardware - Modular') s2d_back_hardware_custom = fields.Boolean(string='Back Hardware - Custom Fabricated') # Complete Assembly s2d_complete_modular = fields.Boolean(string='Complete Assembly - Modular') s2d_complete_custom = fields.Boolean(string='Complete Assembly - Custom Fabricated') # Headrest/Neckrest s2d_headrest_modular = fields.Boolean(string='Headrest/Neckrest - Modular') s2d_headrest_custom = fields.Boolean(string='Headrest/Neckrest - Custom Fabricated') s2d_head_option_custom = fields.Boolean(string='Headrest Options - Custom Fabricated') s2d_head_hardware_modular = fields.Boolean(string='Headrest Hardware - Modular') s2d_head_hardware_custom = fields.Boolean(string='Headrest Hardware - Custom Fabricated') # Positioning Belts s2d_belt_modular = fields.Boolean(string='Positioning Belt - Modular') s2d_belt_custom = fields.Boolean(string='Positioning Belt - Custom Fabricated') s2d_belt_option_custom = fields.Boolean(string='Belt Options - Custom Fabricated') # Arm Supports s2d_arm_modular = fields.Boolean(string='Arm Support - Modular') s2d_arm_custom = fields.Boolean(string='Arm Support - Custom Fabricated') s2d_arm_option_modular = fields.Boolean(string='Arm Options - Modular') s2d_arm_option_custom = fields.Boolean(string='Arm Options - Custom Fabricated') s2d_arm_hardware_modular = fields.Boolean(string='Arm Hardware - Modular') s2d_arm_hardware_custom = fields.Boolean(string='Arm Hardware - Custom Fabricated') # Tray s2d_tray_modular = fields.Boolean(string='Tray - Modular') s2d_tray_custom = fields.Boolean(string='Tray - Custom Fabricated') s2d_tray_option_modular = fields.Boolean(string='Tray Options - Modular') s2d_tray_option_custom = fields.Boolean(string='Tray Options - Custom Fabricated') # Lateral Supports s2d_lateral_modular = fields.Boolean(string='Lateral Support - Modular') s2d_lateral_custom = fields.Boolean(string='Lateral Support - Custom Fabricated') s2d_lateral_option_custom = fields.Boolean(string='Lateral Options - Custom Fabricated') s2d_lateral_hardware_custom = fields.Boolean(string='Lateral Hardware - Custom Fabricated') # Foot/Leg Supports s2d_foot_modular = fields.Boolean(string='Foot/Leg Support - Modular') s2d_foot_custom = fields.Boolean(string='Foot/Leg Support - Custom Fabricated') s2d_foot_option_modular = fields.Boolean(string='Foot Options - Modular') s2d_foot_option_custom = fields.Boolean(string='Foot Options - Custom Fabricated') s2d_foot_hardware_modular = fields.Boolean(string='Foot Hardware - Modular') s2d_foot_hardware_custom = fields.Boolean(string='Foot Hardware - Custom Fabricated') # Seating reason and confirmations s2d_reason = fields.Char(string='Reason for Application') s2d_replacement_status = fields.Char(string='Replacement - Mobility Status') s2d_replacement_size = fields.Char(string='Replacement - Body Size') s2d_replacement_adp = fields.Char(string='Replacement - Equipment Worn') s2d_replacement_special = fields.Char(string='Replacement - Special') s2d_confirm1 = fields.Char(string='Seating Confirmation 1') s2d_confirm2 = fields.Char(string='Seating Confirmation 2') s2d_custom = fields.Char(string='Custom Modifications Required') s2d_cost_labour = fields.Char(string='Cost of Labour') # ------------------------------------------------------------------ # SECTION 3 - APPLICANT CONSENT AND SIGNATURE # ------------------------------------------------------------------ consent_date = fields.Date(string='Consent Date') consent_signed_by = fields.Selection([ ('applicant', 'Applicant'), ('agent', 'Agent'), ], string='Signed By') # Agent/Contact info (if signed by agent) agent_relationship = fields.Char(string='Agent Relationship') agent_last_name = fields.Char(string='Agent Last Name') agent_first_name = fields.Char(string='Agent First Name') agent_middle_initial = fields.Char(string='Agent Middle Initial') agent_unit = fields.Char(string='Agent Unit') agent_street_no = fields.Char(string='Agent Street Number') agent_street_name = fields.Char(string='Agent Street Name') agent_rural_route = fields.Char(string='Agent Rural Route') agent_city = fields.Char(string='Agent City') agent_province = fields.Char(string='Agent Province') agent_postal_code = fields.Char(string='Agent Postal Code') agent_home_phone = fields.Char(string='Agent Home Phone') agent_bus_phone = fields.Char(string='Agent Business Phone') agent_phone_ext = fields.Char(string='Agent Phone Ext') # ------------------------------------------------------------------ # SECTION 4 - AUTHORIZER # ------------------------------------------------------------------ authorizer_last_name = fields.Char(string='Authorizer Last Name') authorizer_first_name = fields.Char(string='Authorizer First Name') authorizer_phone = fields.Char(string='Authorizer Phone') authorizer_phone_ext = fields.Char(string='Authorizer Phone Ext') authorizer_adp_number = fields.Char(string='Authorizer ADP Registration Number') assessment_date = fields.Date(string='Assessment Date') # ------------------------------------------------------------------ # SECTION 4 - VENDOR 1 # ------------------------------------------------------------------ vendor_business_name = fields.Char(string='Vendor Business Name') vendor_adp_number = fields.Char(string='Vendor ADP Registration Number') vendor_representative = fields.Char(string='Vendor Representative (Last, First)') vendor_position = fields.Char(string='Vendor Position Title') vendor_location = fields.Char(string='Vendor Location') vendor_phone = fields.Char(string='Vendor Phone') vendor_phone_ext = fields.Char(string='Vendor Phone Ext') vendor_sign_date = fields.Date(string='Vendor Sign Date') # ------------------------------------------------------------------ # SECTION 4 - VENDOR 2 # ------------------------------------------------------------------ vendor2_business_name = fields.Char(string='Vendor 2 Business Name') vendor2_adp_number = fields.Char(string='Vendor 2 ADP Registration') vendor2_representative = fields.Char(string='Vendor 2 Representative') vendor2_position = fields.Char(string='Vendor 2 Position') vendor2_location = fields.Char(string='Vendor 2 Location') vendor2_phone = fields.Char(string='Vendor 2 Phone') vendor2_phone_ext = fields.Char(string='Vendor 2 Phone Ext') vendor2_sign_date = fields.Date(string='Vendor 2 Sign Date') # ------------------------------------------------------------------ # SECTION 4 - EQUIPMENT SPEC & PROOF OF DELIVERY # ------------------------------------------------------------------ equip_vendor_invoice_no = fields.Char(string='Vendor Invoice Number') equip_vendor_adp_reg = fields.Char(string='Vendor ADP Reg (Page 12)') equip_cell1 = fields.Char(string='ADP Device Code') equip_cell2 = fields.Char(string='Description of Item') equip_cell3 = fields.Char(string='Base Device') equip_cell4 = fields.Char(string='ADP Portion') equip_cell5 = fields.Char(string='Client Portion') pod_received_by = fields.Char(string='Proof of Delivery - Received By') pod_date = fields.Date(string='Proof of Delivery Date') # ------------------------------------------------------------------ # SECTION 4 - NOTE TO ADP (sections submitted checklist) # ------------------------------------------------------------------ note_section1 = fields.Boolean(string='Section 1 Submitted') note_section2a = fields.Boolean(string='Section 2a Submitted') note_section2b = fields.Boolean(string='Section 2b Submitted') note_section2c = fields.Boolean(string='Section 2c Submitted') note_section2d = fields.Boolean(string='Section 2d Submitted') note_section3and4 = fields.Boolean(string='Section 3 & 4 Submitted') note_vendor_replacement = fields.Char(string='Vendor Quote - Replacement') note_vendor_custom = fields.Char(string='Vendor Quote - Custom Modifications') note_funding_chart = fields.Char(string='Justification for Funding Chart') note_letter = fields.Char(string='Letter of Rationale') # Computed summary sections_submitted = fields.Char( string='Sections Submitted', compute='_compute_sections_submitted', store=True, ) # Legacy compat fields base_device = fields.Char( string='Base Device Selected', compute='_compute_base_device', store=True, ) reason_for_application = fields.Char( string='Reason for Application', compute='_compute_reason', store=True, ) # ------------------------------------------------------------------ # COMPUTED # ------------------------------------------------------------------ @api.depends('applicant_last_name', 'applicant_first_name', 'application_date') def _compute_display_name(self): for rec in self: name_parts = [rec.applicant_last_name or '', rec.applicant_first_name or ''] name = ', '.join(p for p in name_parts if p) or 'Unknown' date_str = rec.application_date.strftime('%Y-%m-%d') if rec.application_date else 'No Date' rec.display_name = f'{name} ({date_str})' @api.depends('note_section1', 'note_section2a', 'note_section2b', 'note_section2c', 'note_section2d', 'note_section3and4') def _compute_sections_submitted(self): for rec in self: parts = [] if rec.note_section1: parts.append('1') if rec.note_section2a: parts.append('2a') if rec.note_section2b: parts.append('2b') if rec.note_section2c: parts.append('2c') if rec.note_section2d: parts.append('2d') if rec.note_section3and4: parts.append('3+4') rec.sections_submitted = ', '.join(parts) if parts else '' @api.depends('s2a_base_device', 's2b_base_device', 's2c_base_device') def _compute_base_device(self): for rec in self: rec.base_device = rec.s2a_base_device or rec.s2b_base_device or rec.s2c_base_device or '' @api.depends('s2a_reason', 's2b_reason', 's2c_reason', 's2d_reason') def _compute_reason(self): for rec in self: rec.reason_for_application = rec.s2a_reason or rec.s2b_reason or rec.s2c_reason or rec.s2d_reason or '' # ------------------------------------------------------------------ # XML EXPORT # ------------------------------------------------------------------ def action_export_xml(self): """Reconstruct ADP XML from stored JSON data.""" self.ensure_one() if not self.xml_data_json: # Fall back to raw_xml if available if self.raw_xml: xml_content = self.raw_xml.encode('utf-8') attachment = self.env['ir.attachment'].create({ 'name': f'{self.applicant_last_name}_{self.applicant_first_name}_data.xml', 'type': 'binary', 'datas': base64.b64encode(xml_content), 'mimetype': 'application/xml', }) return { 'type': 'ir.actions.act_url', 'url': f'/web/content/{attachment.id}?download=true', 'target': 'new', } return False try: data = json.loads(self.xml_data_json) xml_str = self._json_to_xml(data) attachment = self.env['ir.attachment'].create({ 'name': f'{self.applicant_last_name or "export"}_{self.applicant_first_name or "data"}_data.xml', 'type': 'binary', 'datas': base64.b64encode(xml_str.encode('utf-8')), 'mimetype': 'application/xml', }) return { 'type': 'ir.actions.act_url', 'url': f'/web/content/{attachment.id}?download=true', 'target': 'new', } except Exception as e: _logger.exception('XML export error: %s', e) return False def _json_to_xml(self, data): """Reconstruct the ADP XML from flat JSON dictionary.""" # Build the XML tree following the exact ADP structure root = ET.Element('form1') form = ET.SubElement(root, 'Form') # Simple top-level fields self._set_el(form, 'deviceCategory', data.get('deviceCategory', '')) self._set_el(form, 'VersionNumber', data.get('VersionNumber', '')) # Section 1 s1 = ET.SubElement(form, 'section1') s1_fields = [ 'applicantLastname', 'applicantFirstname', 'applicantMiddleinitial', 'healthNo', 'versionNo', 'DateOfBirth', 'nameLTCH', 'unitNo', 'streetNo', 'streetName', 'rrRoute', 'city', 'province', 'postalCode', 'homePhone', 'busPhone', 'phoneExtension', ] for f in s1_fields: self._set_el(s1, f, data.get(f'section1.{f}', '')) # Confirmation of benefit cob = ET.SubElement(s1, 'confirmationOfBenefit') for f in ['q1Yn', 'q1Ifyes', 'q2Yn', 'q3Yn']: self._set_el(cob, f, data.get(f'section1.confirmationOfBenefit.{f}', '')) # Section 2 s2 = ET.SubElement(form, 'section2') # Devices and Eligibility de = ET.SubElement(s2, 'devicesandEligibility') de_fields = [ 'condition', 'status', 'none', 'forearm', 'wheeled', 'manual', 'power', 'addOn', 'scooter', 'seating', 'tiltSystem', 'reclineSystem', 'legRests', 'frame', 'stroller', 'deviceForearm', 'deviceWheeled', 'deviceManual', 'deviceAmbulation', 'deviceDependent', 'deviceDynamic', 'manualDyanmic', 'manualWheelchair', 'powerBase', 'powerScooter', 'ambulation', 'positioning', 'highTech', 'standingFrame', 'adpFunded', 'nonADPFunded', ] for f in de_fields: self._set_el(de, f, data.get(f'section2.devicesandEligibility.{f}', '')) # Sections 2a, 2b, 2c, 2d for section_key in ['section2a', 'section2b', 'section2c', 'section2d']: section_data = {k.split(f'section2.{section_key}.')[1]: v for k, v in data.items() if k.startswith(f'section2.{section_key}.')} sec = ET.SubElement(s2, section_key) # Preserve field order from the data keys ordered_keys = [k.split(f'section2.{section_key}.')[1] for k in sorted(data.keys()) if k.startswith(f'section2.{section_key}.')] for f in ordered_keys: self._set_el(sec, f, section_data.get(f, '')) # Section 3 s3 = ET.SubElement(form, 'section3') sig = ET.SubElement(s3, 'sig') for f in ['signature', 'person', 'Date']: self._set_el(sig, f, data.get(f'section3.sig.{f}', '')) contact = ET.SubElement(s3, 'contact') contact_fields = [ 'relationship', 'applicantLastname', 'applicantFirstname', 'applicantMiddleinitial', 'unitNo', 'streetNo', 'streetName', 'rrRoute', 'city', 'province', 'postalCode', 'homePhone', 'busPhone', 'phoneExtension', ] for f in contact_fields: self._set_el(contact, f, data.get(f'section3.contact.{f}', '')) # Section 4 s4 = ET.SubElement(form, 'section4') # Authorizer auth = ET.SubElement(s4, 'authorizer') for f in ['authorizerLastname', 'authorizerFirstname', 'busPhone', 'phoneExtension', 'adpNo', 'signature', 'Date']: self._set_el(auth, f, data.get(f'section4.authorizer.{f}', '')) # Vendor vendor = ET.SubElement(s4, 'vendor') for f in ['vendorBusName', 'adpVendorRegNo', 'vendorLastfirstname', 'positionTitle', 'vendorLocation', 'busPhone', 'phoneExtension', 'signature', 'Date']: self._set_el(vendor, f, data.get(f'section4.vendor.{f}', '')) # Vendor 2 v2 = ET.SubElement(s4, 'vendor2') for f in ['vendorBusName', 'adpVendorRegNo', 'vendorLastfirstname', 'positionTitle', 'vendorLocation', 'busPhone', 'phoneExtension', 'signature', 'Date']: self._set_el(v2, f, data.get(f'section4.vendor2.{f}', '')) # Equipment Spec eq = ET.SubElement(s4, 'equipmentSpec') self._set_el(eq, 'vendorInvoiceNo', data.get('section4.equipmentSpec.vendorInvoiceNo', '')) self._set_el(eq, 'vendorADPRegNo', data.get('section4.equipmentSpec.vendorADPRegNo', '')) t2 = ET.SubElement(eq, 'Table2') r1 = ET.SubElement(t2, 'Row1') for c in ['Cell1', 'Cell2', 'Cell3', 'Cell4', 'Cell5']: self._set_el(r1, c, data.get(f'section4.equipmentSpec.Table2.Row1.{c}', '')) # Proof of delivery pod = ET.SubElement(s4, 'proofOfDelivery') for f in ['signature', 'receivedBy', 'Date']: self._set_el(pod, f, data.get(f'section4.proofOfDelivery.{f}', '')) # Note to ADP note = ET.SubElement(s4, 'noteToADP') for f in ['section1', 'section2a', 'section2b', 'section2c', 'section2d', 'section3and4', 'vendorReplacement', 'vendorCustom', 'fundingChart', 'letter']: self._set_el(note, f, data.get(f'section4.noteToADP.{f}', '')) # Convert to string tree = ET.ElementTree(root) ET.indent(tree, space='') import io buf = io.BytesIO() tree.write(buf, encoding='unicode', xml_declaration=True) return buf.getvalue() @staticmethod def _set_el(parent, tag, value): """Create a child element, self-closing if empty.""" el = ET.SubElement(parent, tag) if value: el.text = str(value)