186 lines
6.8 KiB
Python
186 lines
6.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2024-2025 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
# Part of the Fusion Claim Assistant product family.
|
|
|
|
from odoo import models
|
|
|
|
|
|
class ProductProduct(models.Model):
|
|
_inherit = 'product.product'
|
|
|
|
def get_adp_device_code(self):
|
|
"""
|
|
Get ADP device code from the field mapped in fusion settings.
|
|
|
|
The field name is configured in Settings → Sales → Fusion Central →
|
|
Field Mappings → Product ADP Code Field.
|
|
|
|
Checks the mapped field on the product variant first, then on template.
|
|
Returns the value from the mapped field, or empty string if not found.
|
|
"""
|
|
self.ensure_one()
|
|
|
|
# Get the mapped field name from fusion settings
|
|
ICP = self.env['ir.config_parameter'].sudo()
|
|
field_name = ICP.get_param('fusion_claims.field_product_code', 'x_fc_adp_device_code')
|
|
|
|
if not field_name:
|
|
return ''
|
|
|
|
# Check if the mapped field exists on the product variant (product.product)
|
|
if field_name in self._fields:
|
|
value = getattr(self, field_name, '') or ''
|
|
if value:
|
|
return value
|
|
|
|
# Check if the mapped field exists on the product template
|
|
if self.product_tmpl_id and field_name in self.product_tmpl_id._fields:
|
|
value = getattr(self.product_tmpl_id, field_name, '') or ''
|
|
if value:
|
|
return value
|
|
|
|
return ''
|
|
|
|
def get_adp_price(self):
|
|
"""
|
|
Get ADP price from the field mapped in fusion settings.
|
|
|
|
The field name is configured in Settings → Sales → Fusion Central →
|
|
Field Mappings → Product ADP Price Field.
|
|
|
|
Checks the mapped field on the product variant first, then on template.
|
|
Returns the value from the mapped field, or 0.0 if not found.
|
|
"""
|
|
self.ensure_one()
|
|
|
|
# Get the mapped field name from fusion settings
|
|
ICP = self.env['ir.config_parameter'].sudo()
|
|
field_name = ICP.get_param('fusion_claims.field_product_adp_price', 'x_fc_adp_price')
|
|
|
|
if not field_name:
|
|
return 0.0
|
|
|
|
# Check if the mapped field exists on the product variant (product.product)
|
|
if field_name in self._fields:
|
|
value = getattr(self, field_name, 0.0) or 0.0
|
|
if value:
|
|
return value
|
|
|
|
# Check if the mapped field exists on the product template
|
|
if self.product_tmpl_id and field_name in self.product_tmpl_id._fields:
|
|
value = getattr(self.product_tmpl_id, field_name, 0.0) or 0.0
|
|
if value:
|
|
return value
|
|
|
|
return 0.0
|
|
|
|
def is_non_adp_funded(self):
|
|
"""
|
|
Check if this product has a NON-ADP, NON-FUNDED, or UNFUNDED device code.
|
|
|
|
Products with these device codes are not covered by ADP and should have:
|
|
- ADP portion = 0
|
|
- Client portion = full amount
|
|
- NOT included in ADP invoices (only in client invoices)
|
|
|
|
Returns True if the product is NOT funded by ADP.
|
|
"""
|
|
self.ensure_one()
|
|
|
|
# Get the ADP device code
|
|
adp_code = self.get_adp_device_code()
|
|
if not adp_code:
|
|
return False
|
|
|
|
# Check for non-funded codes (case-insensitive)
|
|
# These product codes indicate items NOT covered by ADP funding:
|
|
# - NON-ADP, NON-FUNDED, UNFUNDED: Explicitly not ADP funded
|
|
# - ACS: Accessibility items (client pays 100%)
|
|
# - ODS: ODSP items (client pays 100%)
|
|
# - OWP: Ontario Works items (client pays 100%)
|
|
non_funded_codes = [
|
|
'NON-ADP', 'NON ADP', 'NONADP',
|
|
'NON-FUNDED', 'NON FUNDED', 'NONFUNDED',
|
|
'UNFUNDED', 'NOT-FUNDED', 'NOT FUNDED', 'NOTFUNDED',
|
|
'ACS', 'ODS', 'OWP'
|
|
]
|
|
adp_code_upper = adp_code.upper().strip()
|
|
|
|
for non_funded in non_funded_codes:
|
|
if adp_code_upper == non_funded or adp_code_upper.startswith(non_funded):
|
|
return True
|
|
|
|
return False
|
|
|
|
def action_sync_adp_price_from_database(self):
|
|
"""
|
|
Update product's ADP price from the device codes database.
|
|
|
|
Looks up the product's ADP device code in the fusion.adp.device.code table
|
|
and updates the product's x_fc_adp_price field with the database value.
|
|
|
|
Returns a notification with the result.
|
|
"""
|
|
ADPDevice = self.env['fusion.adp.device.code'].sudo()
|
|
updated = []
|
|
not_found = []
|
|
no_code = []
|
|
|
|
for product in self:
|
|
device_code = product.get_adp_device_code()
|
|
if not device_code:
|
|
no_code.append(product.name)
|
|
continue
|
|
|
|
adp_device = ADPDevice.search([
|
|
('device_code', '=', device_code),
|
|
('active', '=', True)
|
|
], limit=1)
|
|
|
|
if adp_device and adp_device.adp_price:
|
|
# Update product template
|
|
product_tmpl = product.product_tmpl_id
|
|
old_price = 0
|
|
|
|
if hasattr(product_tmpl, 'x_fc_adp_price'):
|
|
old_price = getattr(product_tmpl, 'x_fc_adp_price', 0) or 0
|
|
product_tmpl.sudo().write({'x_fc_adp_price': adp_device.adp_price})
|
|
updated.append({
|
|
'name': product.name,
|
|
'code': device_code,
|
|
'old_price': old_price,
|
|
'new_price': adp_device.adp_price,
|
|
})
|
|
else:
|
|
not_found.append(f"{product.name} ({device_code})")
|
|
|
|
# Build result message
|
|
message_parts = []
|
|
if updated:
|
|
msg = f"<strong>Updated {len(updated)} product(s):</strong><ul>"
|
|
for u in updated:
|
|
msg += f"<li>{u['name']}: ${u['old_price']:.2f} → ${u['new_price']:.2f}</li>"
|
|
msg += "</ul>"
|
|
message_parts.append(msg)
|
|
|
|
if not_found:
|
|
message_parts.append(f"<strong>Not found in database:</strong> {', '.join(not_found)}")
|
|
|
|
if no_code:
|
|
message_parts.append(f"<strong>No ADP code:</strong> {', '.join(no_code)}")
|
|
|
|
if not message_parts:
|
|
message_parts.append("No products to process.")
|
|
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'title': 'ADP Price Sync',
|
|
'message': '<br/>'.join(message_parts),
|
|
'type': 'success' if updated else 'warning',
|
|
'sticky': True,
|
|
}
|
|
}
|