This commit is contained in:
gsinghpal
2026-03-13 12:38:28 -04:00
parent db4b9aa278
commit fc3c966484
2975 changed files with 1614 additions and 498 deletions

View File

@@ -20,18 +20,7 @@ class FusionADPDeviceCode(models.Model):
_order = 'device_type, device_code'
def _register_hook(self):
"""
Called when the model is loaded.
Re-loads device codes from packaged JSON on module upgrade.
"""
super()._register_hook()
# Use with_context to check if this is a module upgrade
# The data will be loaded via post_init_hook on install,
# and via this hook on upgrade (when module is reloaded)
try:
self.sudo()._load_packaged_device_codes()
except Exception as e:
_logger.warning("Could not auto-load device codes: %s", str(e))
# ==========================================================================
# MAIN FIELDS

View File

@@ -69,7 +69,60 @@ class ResPartner(models.Model):
store=True,
)
# ==========================================================================
# AUTHORIZER FIELDS
# ==========================================================================
x_fc_authorizer_number = fields.Char(
string='ADP Authorizer Number',
tracking=True,
index=True,
help='ADP Registration Number for this authorizer (e.g. OT). '
'Used to auto-link authorizers when processing ADP XML files.',
)
x_fc_adp_application_count = fields.Integer(
string='ADP Applications',
compute='_compute_adp_application_count',
)
@api.depends('x_fc_contact_type')
def _compute_is_odsp_office(self):
for partner in self:
partner.x_fc_is_odsp_office = partner.x_fc_contact_type == 'odsp_office'
def _compute_adp_application_count(self):
AppData = self.env['fusion.adp.application.data']
for partner in self:
domain = self._get_authorizer_application_domain(partner)
partner.x_fc_adp_application_count = AppData.search_count(domain) if domain else 0
def _get_authorizer_application_domain(self, partner):
"""Build domain to find applications linked to this authorizer."""
conditions = []
if partner.x_fc_authorizer_number:
conditions.append(('authorizer_adp_number', '=', partner.x_fc_authorizer_number))
name = (partner.name or '').strip()
if name:
parts = name.replace(',', ' ').split()
if len(parts) >= 2:
conditions.append(
'&',
)
conditions.append(('authorizer_last_name', 'ilike', parts[0]))
conditions.append(('authorizer_first_name', 'ilike', parts[-1]))
if not conditions:
return []
if len(conditions) > 3:
return ['|'] + conditions
return conditions
def action_view_adp_applications(self):
self.ensure_one()
domain = self._get_authorizer_application_domain(self)
return {
'name': 'ADP Applications',
'type': 'ir.actions.act_window',
'res_model': 'fusion.adp.application.data',
'view_mode': 'list,form',
'domain': domain,
'context': {'default_authorizer_adp_number': self.x_fc_authorizer_number or ''},
}

View File

@@ -66,6 +66,10 @@ class FusionXmlParser(models.AbstractModel):
# Step 3: Create/update profile
profile = self._find_or_create_profile(model_vals, sale_order)
# Step 3b: Auto-link authorizer on sale order by ADP number
if sale_order:
self._link_authorizer_by_adp_number(model_vals, sale_order)
# Step 4: Create application data record
model_vals['profile_id'] = profile.id
model_vals['sale_order_id'] = sale_order.id if sale_order else False
@@ -637,6 +641,39 @@ class FusionXmlParser(models.AbstractModel):
# ------------------------------------------------------------------
# PROFILE MANAGEMENT
# ------------------------------------------------------------------
def _link_authorizer_by_adp_number(self, vals, sale_order):
"""Auto-link the authorizer contact on the sale order using the ADP number from XML."""
adp_number = (vals.get('authorizer_adp_number') or '').strip()
if not adp_number or adp_number.upper() in ('NA', 'N/A', ''):
return
if sale_order.x_fc_authorizer_id:
return
Partner = self.env['res.partner']
authorizer = Partner.search([
('x_fc_authorizer_number', '=', adp_number),
], limit=1)
if not authorizer:
first = (vals.get('authorizer_first_name') or '').strip()
last = (vals.get('authorizer_last_name') or '').strip()
if first and last:
authorizer = Partner.search([
'|',
('name', 'ilike', f'{first} {last}'),
('name', 'ilike', f'{last}, {first}'),
], limit=1)
if authorizer and not authorizer.x_fc_authorizer_number:
authorizer.write({'x_fc_authorizer_number': adp_number})
if authorizer:
sale_order.write({'x_fc_authorizer_id': authorizer.id})
_logger.info(
'Auto-linked authorizer %s (ADP# %s) to SO %s',
authorizer.name, adp_number, sale_order.name,
)
def _find_or_create_profile(self, vals, sale_order=None):
"""Find or create a client profile from parsed application data."""
Profile = self.env['fusion.client.profile']

View File

@@ -16,6 +16,22 @@
<field name="x_fc_contact_type" placeholder="Select contact type..."/>
</xpath>
<!-- ADP Applications smart button for authorizers -->
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_view_adp_applications" type="object"
class="oe_stat_button" icon="fa-file-text"
invisible="x_fc_adp_application_count == 0">
<field name="x_fc_adp_application_count" widget="statinfo" string="Applications"/>
</button>
</xpath>
<!-- Authorizer number for OTs/PTs/authorizer contacts -->
<xpath expr="//field[@name='x_fc_contact_type']" position="after">
<field name="x_fc_authorizer_number" string="ADP Reg. Number"
invisible="x_fc_contact_type not in ('occupational_therapist', 'physiotherapist', 'adp_agent')"
placeholder="e.g. 3000001234"/>
</xpath>
<!-- ODSP section in notebook -->
<xpath expr="//notebook" position="inside">
<page string="ODSP" name="odsp_info"