feat: separate fusion field service and LTC into standalone modules, update core modules

- fusion_claims: separated field service logic, updated controllers/views
- fusion_tasks: updated task views and map integration
- fusion_authorizer_portal: added page 11 signing, schedule booking, migrations
- fusion_shipping: new standalone shipping module (Canada Post, FedEx, DHL, Purolator)
- fusion_ltc_management: new standalone LTC management module
This commit is contained in:
2026-03-11 16:19:52 +00:00
parent 1f79cdcaaf
commit 431052920e
274 changed files with 52782 additions and 7302 deletions

View File

@@ -29,10 +29,11 @@ class SaleOrderLine(models.Model):
@api.depends('product_id', 'product_id.default_code')
def _compute_adp_device_type(self):
"""Compute ADP device type from the product's device code."""
"""Compute ADP device type and build type from the product's device code."""
ADPDevice = self.env['fusion.adp.device.code'].sudo()
for line in self:
device_type = ''
build_type = False
if line.product_id:
# Get the device code from product (default_code or custom field)
device_code = line._get_adp_device_code()
@@ -44,7 +45,9 @@ class SaleOrderLine(models.Model):
], limit=1)
if adp_device:
device_type = adp_device.device_type or ''
build_type = adp_device.build_type or False
line.x_fc_adp_device_type = device_type
line.x_fc_adp_build_type = build_type
# ==========================================================================
# SERIAL NUMBER AND DEVICE PLACEMENT
@@ -110,6 +113,16 @@ class SaleOrderLine(models.Model):
store=True,
help='Device type from ADP mobility manual (for approval matching)',
)
x_fc_adp_build_type = fields.Selection(
selection=[
('modular', 'Modular'),
('custom_fabricated', 'Custom Fabricated'),
],
string='Build Type',
compute='_compute_adp_device_type',
store=True,
help='Build type from ADP mobility manual (Modular or Custom Fabricated)',
)
# ==========================================================================
# COMPUTED ADP PORTIONS
@@ -306,6 +319,49 @@ class SaleOrderLine(models.Model):
# 5. Final fallback - return default_code even if not in ADP database
return self.product_id.default_code or ''
def _get_adp_code_for_report(self):
"""Return the ADP device code for display on reports.
Uses the product's x_fc_adp_device_code field (not default_code).
Returns 'NON-FUNDED' for non-ADP products.
"""
self.ensure_one()
if not self.product_id:
return 'NON-FUNDED'
if self.product_id.is_non_adp_funded():
return 'NON-FUNDED'
product_tmpl = self.product_id.product_tmpl_id
code = ''
if hasattr(product_tmpl, 'x_fc_adp_device_code'):
code = getattr(product_tmpl, 'x_fc_adp_device_code', '') or ''
if not code and hasattr(product_tmpl, 'x_adp_code'):
code = getattr(product_tmpl, 'x_adp_code', '') or ''
if not code:
return 'NON-FUNDED'
ADPDevice = self.env['fusion.adp.device.code'].sudo()
if ADPDevice.search_count([('device_code', '=', code), ('active', '=', True)]) > 0:
return code
return 'NON-FUNDED'
def _get_adp_device_type(self):
"""Live lookup of device type from the ADP device code table.
Returns 'No Funding Available' for non-ADP products.
"""
self.ensure_one()
if not self.product_id or self.product_id.is_non_adp_funded():
return 'No Funding Available'
code = self._get_adp_code_for_report()
if code == 'NON-FUNDED':
return 'No Funding Available'
if self.x_fc_adp_device_type:
return self.x_fc_adp_device_type
adp_device = self.env['fusion.adp.device.code'].sudo().search([
('device_code', '=', code),
('active', '=', True),
], limit=1)
return adp_device.device_type if adp_device else 'No Funding Available'
def _get_serial_number(self):
"""Get serial number from mapped field or native field."""
self.ensure_one()