Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View File

@@ -0,0 +1,602 @@
# -*- 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.
import logging
from odoo import models, fields, api
_logger = logging.getLogger(__name__)
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
# =========================================================================
# COMPANY SETTINGS (Related to res.company)
# =========================================================================
fc_store_address_1 = fields.Char(
related='company_id.x_fc_store_address_1',
readonly=False,
string='Store Address Line 1',
)
fc_store_address_2 = fields.Char(
related='company_id.x_fc_store_address_2',
readonly=False,
string='Store Address Line 2',
)
fc_company_tagline = fields.Char(
related='company_id.x_fc_company_tagline',
readonly=False,
string='Company Tagline',
)
fc_etransfer_email = fields.Char(
related='company_id.x_fc_etransfer_email',
readonly=False,
string='E-Transfer Email',
)
fc_cheque_payable_to = fields.Char(
related='company_id.x_fc_cheque_payable_to',
readonly=False,
string='Cheque Payable To',
)
fc_payment_terms_html = fields.Html(
related='company_id.x_fc_payment_terms_html',
readonly=False,
string='Payment Terms',
)
fc_include_refund_page = fields.Boolean(
related='company_id.x_fc_include_refund_page',
readonly=False,
string='Include Refund Policy Page',
)
fc_refund_policy_html = fields.Html(
related='company_id.x_fc_refund_policy_html',
readonly=False,
string='Refund Policy',
)
# =========================================================================
# ADP BILLING SETTINGS
# =========================================================================
fc_vendor_code = fields.Char(
string='ADP Vendor Code',
config_parameter='fusion_claims.vendor_code',
help='Your ADP vendor/location code for claim submissions',
)
# =========================================================================
# FIELD MAPPINGS
# =========================================================================
fc_field_sale_type = fields.Char(
string='Sale Type Field',
config_parameter='fusion_claims.field_sale_type',
help='Field name for sale type on sale.order',
)
fc_field_so_client_type = fields.Char(
string='SO Client Type Field',
config_parameter='fusion_claims.field_so_client_type',
help='Field name for client type on sale.order',
)
fc_field_so_authorizer = fields.Char(
string='SO Authorizer Field',
config_parameter='fusion_claims.field_so_authorizer',
help='Field name for authorizer on sale.order',
)
fc_field_invoice_type = fields.Char(
string='Invoice Type Field',
config_parameter='fusion_claims.field_invoice_type',
help='Field name for invoice type on account.move',
)
fc_field_inv_client_type = fields.Char(
string='Invoice Client Type Field',
config_parameter='fusion_claims.field_inv_client_type',
help='Field name for client type on account.move',
)
fc_field_inv_authorizer = fields.Char(
string='Invoice Authorizer Field',
config_parameter='fusion_claims.field_inv_authorizer',
help='Field name for authorizer on account.move',
)
fc_field_product_code = fields.Char(
string='Product ADP Code Field',
config_parameter='fusion_claims.field_product_code',
help='Field name for ADP device code on product.template',
)
fc_field_sol_serial = fields.Char(
string='SO Line Serial Field',
config_parameter='fusion_claims.field_sol_serial',
help='Field name for serial number on sale.order.line',
)
fc_field_aml_serial = fields.Char(
string='Invoice Line Serial Field',
config_parameter='fusion_claims.field_aml_serial',
help='Field name for serial number on account.move.line',
)
# =========================================================================
# ADDITIONAL SALE ORDER FIELD MAPPINGS
# =========================================================================
fc_field_so_claim_number = fields.Char(
string='SO Claim Number Field',
config_parameter='fusion_claims.field_so_claim_number',
help='Field name for claim number on sale.order',
)
fc_field_so_client_ref_1 = fields.Char(
string='SO Client Ref 1 Field',
config_parameter='fusion_claims.field_so_client_ref_1',
help='Field name for client reference 1 on sale.order',
)
fc_field_so_client_ref_2 = fields.Char(
string='SO Client Ref 2 Field',
config_parameter='fusion_claims.field_so_client_ref_2',
help='Field name for client reference 2 on sale.order',
)
fc_field_so_delivery_date = fields.Char(
string='SO Delivery Date Field',
config_parameter='fusion_claims.field_so_delivery_date',
help='Field name for ADP delivery date on sale.order',
)
fc_field_so_adp_status = fields.Char(
string='SO ADP Status Field',
config_parameter='fusion_claims.field_so_adp_status',
help='Field name for ADP status on sale.order',
)
fc_field_so_service_start = fields.Char(
string='SO Service Start Date Field',
config_parameter='fusion_claims.field_so_service_start',
help='Field name for service start date on sale.order',
)
fc_field_so_service_end = fields.Char(
string='SO Service End Date Field',
config_parameter='fusion_claims.field_so_service_end',
help='Field name for service end date on sale.order',
)
# =========================================================================
# ADDITIONAL INVOICE FIELD MAPPINGS
# =========================================================================
fc_field_inv_claim_number = fields.Char(
string='Invoice Claim Number Field',
config_parameter='fusion_claims.field_inv_claim_number',
help='Field name for claim number on account.move',
)
fc_field_inv_client_ref_1 = fields.Char(
string='Invoice Client Ref 1 Field',
config_parameter='fusion_claims.field_inv_client_ref_1',
help='Field name for client reference 1 on account.move',
)
fc_field_inv_client_ref_2 = fields.Char(
string='Invoice Client Ref 2 Field',
config_parameter='fusion_claims.field_inv_client_ref_2',
help='Field name for client reference 2 on account.move',
)
fc_field_inv_delivery_date = fields.Char(
string='Invoice Delivery Date Field',
config_parameter='fusion_claims.field_inv_delivery_date',
help='Field name for ADP delivery date on account.move',
)
fc_field_inv_service_start = fields.Char(
string='Invoice Service Start Date Field',
config_parameter='fusion_claims.field_inv_service_start',
help='Field name for service start date on account.move',
)
fc_field_inv_service_end = fields.Char(
string='Invoice Service End Date Field',
config_parameter='fusion_claims.field_inv_service_end',
help='Field name for service end date on account.move',
)
# =========================================================================
# SALE ORDER LINE FIELD MAPPINGS
# =========================================================================
fc_field_sol_placement = fields.Char(
string='SO Line Placement Field',
config_parameter='fusion_claims.field_sol_placement',
help='Field name for device placement on sale.order.line',
)
# =========================================================================
# INVOICE LINE FIELD MAPPINGS
# =========================================================================
fc_field_aml_placement = fields.Char(
string='Invoice Line Placement Field',
config_parameter='fusion_claims.field_aml_placement',
help='Field name for device placement on account.move.line',
)
# =========================================================================
# PRODUCT FIELD MAPPINGS
# =========================================================================
fc_field_product_adp_price = fields.Char(
string='Product ADP Price Field',
config_parameter='fusion_claims.field_product_adp_price',
help='Field name for ADP price on product.template',
)
# =========================================================================
# HEADER-LEVEL SERIAL NUMBER MAPPINGS
# =========================================================================
fc_field_so_primary_serial = fields.Char(
string='SO Primary Serial Field',
config_parameter='fusion_claims.field_so_primary_serial',
help='Field name for primary serial number on sale.order (header level)',
)
fc_field_inv_primary_serial = fields.Char(
string='Invoice Primary Serial Field',
config_parameter='fusion_claims.field_inv_primary_serial',
help='Field name for primary serial number on account.move (header level)',
)
# =========================================================================
# ADP POSTING SCHEDULE SETTINGS
# =========================================================================
fc_adp_posting_base_date = fields.Char(
string='ADP Posting Base Date',
config_parameter='fusion_claims.adp_posting_base_date',
help='Reference date for calculating bi-weekly posting schedule (a known posting day). Format: YYYY-MM-DD',
)
fc_adp_posting_frequency_days = fields.Integer(
string='Posting Frequency (Days)',
config_parameter='fusion_claims.adp_posting_frequency_days',
help='Number of days between ADP posting cycles (typically 14 days)',
)
fc_adp_billing_reminder_user_id = fields.Many2one(
'res.users',
string='Billing Deadline Reminder Person',
# NOTE: stored manually via get_values/set_values (not config_parameter)
# because Many2one + config_parameter causes double-write conflicts
help='Person to remind on Monday to complete ADP billing by Wednesday 6 PM',
)
fc_adp_correction_reminder_user_ids = fields.Many2many(
'res.users',
'fc_config_correction_reminder_users_rel',
'config_id',
'user_id',
string='Correction Alert Recipients',
help='People to notify when an ADP invoice needs correction/resubmission',
)
# =========================================================================
# EMAIL NOTIFICATION SETTINGS
# =========================================================================
fc_enable_email_notifications = fields.Boolean(
string='Enable Automated Email Notifications',
config_parameter='fusion_claims.enable_email_notifications',
help='Enable/disable automated email notifications for ADP workflow events',
)
fc_office_notification_ids = fields.Many2many(
related='company_id.x_fc_office_notification_ids',
readonly=False,
string='Office Notification Recipients',
)
fc_application_reminder_days = fields.Integer(
string='First Reminder Days',
config_parameter='fusion_claims.application_reminder_days',
help='Number of days after assessment completion to send first application reminder to therapist',
)
fc_application_reminder_2_days = fields.Integer(
string='Second Reminder Days (After First)',
config_parameter='fusion_claims.application_reminder_2_days',
help='Number of days after first reminder to send second application reminder to therapist',
)
# =========================================================================
# WORKFLOW LOCK SETTINGS
# =========================================================================
fc_allow_sale_type_override = fields.Boolean(
string='Allow Sale Type Override',
config_parameter='fusion_claims.allow_sale_type_override',
help='If enabled, allows changing Sale Type even after application is submitted (for cases where additional benefits are discovered)',
)
fc_allow_document_lock_override = fields.Boolean(
string='Allow Document Lock Override',
config_parameter='fusion_claims.allow_document_lock_override',
help='When enabled, users in the "Document Lock Override" group can edit locked documents on old cases. '
'Disable this once all legacy cases have been processed to enforce strict workflow.',
)
fc_designated_vendor_signer = fields.Many2one(
'res.users',
string='Designated Vendor Signer',
help='The user who signs Page 12 on behalf of the company',
)
# =========================================================================
# GOOGLE MAPS API SETTINGS
# =========================================================================
fc_google_maps_api_key = fields.Char(
string='Google Maps API Key',
config_parameter='fusion_claims.google_maps_api_key',
help='API key for Google Maps Places autocomplete in address fields',
)
# ------------------------------------------------------------------
# AI CLIENT INTELLIGENCE
# ------------------------------------------------------------------
fc_ai_api_key = fields.Char(
string='AI API Key',
config_parameter='fusion_claims.ai_api_key',
help='OpenAI API key for Client Intelligence chat',
)
fc_ai_model = fields.Selection([
('gpt-4o-mini', 'GPT-4o Mini (Fast, Lower Cost)'),
('gpt-4o', 'GPT-4o (Best Quality)'),
('gpt-4.1-mini', 'GPT-4.1 Mini'),
('gpt-4.1', 'GPT-4.1'),
], string='AI Model',
config_parameter='fusion_claims.ai_model',
)
fc_auto_parse_xml = fields.Boolean(
string='Auto-Parse XML Files',
config_parameter='fusion_claims.auto_parse_xml',
help='Automatically parse ADP XML files when uploaded and create/update client profiles',
)
# ------------------------------------------------------------------
# TECHNICIAN MANAGEMENT
# ------------------------------------------------------------------
fc_store_open_hour = fields.Float(
string='Store Open Time',
config_parameter='fusion_claims.store_open_hour',
help='Store opening time for technician scheduling (e.g. 9.0 = 9:00 AM)',
)
fc_store_close_hour = fields.Float(
string='Store Close Time',
config_parameter='fusion_claims.store_close_hour',
help='Store closing time for technician scheduling (e.g. 18.0 = 6:00 PM)',
)
fc_google_distance_matrix_enabled = fields.Boolean(
string='Enable Distance Matrix',
config_parameter='fusion_claims.google_distance_matrix_enabled',
help='Enable Google Distance Matrix API for travel time calculations between technician tasks',
)
fc_technician_start_address = fields.Char(
string='Technician Start Address',
config_parameter='fusion_claims.technician_start_address',
help='Default start location for technician travel calculations (e.g. warehouse/office address)',
)
fc_location_retention_days = fields.Char(
string='Location History Retention (Days)',
config_parameter='fusion_claims.location_retention_days',
help='How many days to keep technician location history. '
'Leave empty = 30 days (1 month). '
'0 = delete at end of each day. '
'1+ = keep for that many days.',
)
# ------------------------------------------------------------------
# WEB PUSH NOTIFICATIONS
# ------------------------------------------------------------------
fc_push_enabled = fields.Boolean(
string='Enable Push Notifications',
config_parameter='fusion_claims.push_enabled',
help='Enable web push notifications for technician tasks',
)
fc_vapid_public_key = fields.Char(
string='VAPID Public Key',
config_parameter='fusion_claims.vapid_public_key',
help='Public key for Web Push VAPID authentication (auto-generated)',
)
fc_vapid_private_key = fields.Char(
string='VAPID Private Key',
config_parameter='fusion_claims.vapid_private_key',
help='Private key for Web Push VAPID authentication (auto-generated)',
)
fc_push_advance_minutes = fields.Integer(
string='Notification Advance (min)',
config_parameter='fusion_claims.push_advance_minutes',
help='Send push notifications this many minutes before a scheduled task',
)
# ------------------------------------------------------------------
# TWILIO SMS SETTINGS
# ------------------------------------------------------------------
fc_twilio_enabled = fields.Boolean(
string='Enable Twilio SMS',
config_parameter='fusion_claims.twilio_enabled',
help='Enable SMS notifications via Twilio for assessment bookings and key status updates',
)
fc_twilio_account_sid = fields.Char(
string='Twilio Account SID',
config_parameter='fusion_claims.twilio_account_sid',
groups='fusion_claims.group_fusion_claims_manager',
)
fc_twilio_auth_token = fields.Char(
string='Twilio Auth Token',
config_parameter='fusion_claims.twilio_auth_token',
groups='fusion_claims.group_fusion_claims_manager',
)
fc_twilio_phone_number = fields.Char(
string='Twilio Phone Number',
config_parameter='fusion_claims.twilio_phone_number',
help='Your Twilio phone number for sending SMS (e.g. +1234567890)',
)
# ------------------------------------------------------------------
# MARCH OF DIMES SETTINGS
# ------------------------------------------------------------------
fc_mod_default_email = fields.Char(
string='MOD Default Email',
config_parameter='fusion_claims.mod_default_email',
help='Default email for sending quotations and documents to March of Dimes (e.g. hvmp@marchofdimes.ca)',
)
fc_mod_vendor_code = fields.Char(
string='March of Dimes Vendor Code',
config_parameter='fusion_claims.mod_vendor_code',
help='Your vendor code assigned by March of Dimes (e.g. TRD0001234)',
)
# ------------------------------------------------------------------
# MOD FOLLOW-UP SETTINGS
# ------------------------------------------------------------------
fc_mod_followup_interval_days = fields.Integer(
string='Follow-up Interval (Days)',
config_parameter='fusion_claims.mod_followup_interval_days',
help='Number of days between follow-up reminders for MOD cases awaiting funding (default: 14)',
)
fc_mod_followup_escalation_days = fields.Integer(
string='Escalation Delay (Days)',
config_parameter='fusion_claims.mod_followup_escalation_days',
help='Days after a follow-up activity is due before auto-sending email to client (default: 3)',
)
# ------------------------------------------------------------------
# ODSP CONFIGURATION
# ------------------------------------------------------------------
fc_sa_mobility_email = fields.Char(
string='SA Mobility Email',
config_parameter='fusion_claims.sa_mobility_email',
help='Email address for SA Mobility submissions (default: samobility@ontario.ca)',
)
fc_sa_mobility_phone = fields.Char(
string='SA Mobility Phone',
config_parameter='fusion_claims.sa_mobility_phone',
help='SA Mobility phone number (default: 1-888-222-5099)',
)
fc_odsp_default_office_id = fields.Many2one(
'res.partner',
string='Default ODSP Office',
domain="[('x_fc_contact_type', '=', 'odsp_office')]",
help='Default ODSP office contact for new ODSP cases',
)
@api.model
def get_values(self):
res = super().get_values()
ICP = self.env['ir.config_parameter'].sudo()
# Get billing reminder user
billing_user_id = ICP.get_param('fusion_claims.adp_billing_reminder_user_id', False)
if billing_user_id:
try:
res['fc_adp_billing_reminder_user_id'] = int(billing_user_id)
except (ValueError, TypeError):
res['fc_adp_billing_reminder_user_id'] = False
# Get correction reminder users (stored as comma-separated IDs)
correction_user_ids = ICP.get_param('fusion_claims.adp_correction_reminder_user_ids', '')
if correction_user_ids:
try:
user_ids = [int(x.strip()) for x in correction_user_ids.split(',') if x.strip()]
res['fc_adp_correction_reminder_user_ids'] = [(6, 0, user_ids)]
except (ValueError, TypeError):
res['fc_adp_correction_reminder_user_ids'] = [(6, 0, [])]
# Get designated vendor signer
vendor_signer_id = ICP.get_param('fusion_claims.designated_vendor_signer', False)
if vendor_signer_id:
try:
res['fc_designated_vendor_signer'] = int(vendor_signer_id)
except (ValueError, TypeError):
res['fc_designated_vendor_signer'] = False
# Get default ODSP office
odsp_office_id = ICP.get_param('fusion_claims.odsp_default_office_id', False)
if odsp_office_id:
try:
res['fc_odsp_default_office_id'] = int(odsp_office_id)
except (ValueError, TypeError):
res['fc_odsp_default_office_id'] = False
return res
def set_values(self):
ICP = self.env['ir.config_parameter'].sudo()
# --- Protect sensitive config_parameter fields from accidental blanking ---
# These are keys where a blank/default value should NOT overwrite
# an existing non-empty value (e.g. API keys, user-customized settings).
_protected_keys = [
'fusion_claims.ai_api_key',
'fusion_claims.google_maps_api_key',
'fusion_claims.vendor_code',
'fusion_claims.ai_model',
'fusion_claims.adp_posting_base_date',
'fusion_claims.application_reminder_days',
'fusion_claims.application_reminder_2_days',
'fusion_claims.store_open_hour',
'fusion_claims.store_close_hour',
'fusion_claims.technician_start_address',
]
# Snapshot existing values BEFORE super().set_values() runs
_existing = {}
for key in _protected_keys:
val = ICP.get_param(key, '')
if val:
_existing[key] = val
super().set_values()
# Restore any protected values that were blanked by the save
for key, old_val in _existing.items():
new_val = ICP.get_param(key, '')
if not new_val and old_val:
ICP.set_param(key, old_val)
_logger.warning(
"Settings protection: restored %s (was blanked during save)", key
)
# Store billing reminder user (Many2one - manual handling)
if self.fc_adp_billing_reminder_user_id:
ICP.set_param('fusion_claims.adp_billing_reminder_user_id',
str(self.fc_adp_billing_reminder_user_id.id))
# Only clear if explicitly set to empty AND there was no existing value
elif not ICP.get_param('fusion_claims.adp_billing_reminder_user_id', ''):
ICP.set_param('fusion_claims.adp_billing_reminder_user_id', '')
# Store correction reminder users as comma-separated IDs
if self.fc_adp_correction_reminder_user_ids:
user_ids = ','.join(str(u.id) for u in self.fc_adp_correction_reminder_user_ids)
ICP.set_param('fusion_claims.adp_correction_reminder_user_ids', user_ids)
# Only clear if explicitly empty AND no existing value
elif not ICP.get_param('fusion_claims.adp_correction_reminder_user_ids', ''):
ICP.set_param('fusion_claims.adp_correction_reminder_user_ids', '')
# Office notification recipients are stored via related field on res.company
# No need to store in ir.config_parameter
# Store designated vendor signer (Many2one - manual handling)
if self.fc_designated_vendor_signer:
ICP.set_param('fusion_claims.designated_vendor_signer',
str(self.fc_designated_vendor_signer.id))
elif not ICP.get_param('fusion_claims.designated_vendor_signer', ''):
ICP.set_param('fusion_claims.designated_vendor_signer', '')
# Store default ODSP office (Many2one - manual handling)
if self.fc_odsp_default_office_id:
ICP.set_param('fusion_claims.odsp_default_office_id',
str(self.fc_odsp_default_office_id.id))
elif not ICP.get_param('fusion_claims.odsp_default_office_id', ''):
ICP.set_param('fusion_claims.odsp_default_office_id', '')
# =========================================================================
# ACTION METHODS
# =========================================================================
def action_open_field_mapping_wizard(self):
"""Open the field mapping configuration wizard."""
return {
'type': 'ir.actions.act_window',
'name': 'Field Mapping Configuration',
'res_model': 'fusion_claims.field_mapping_config',
'view_mode': 'form',
'target': 'new',
'context': {},
}