refactor(fusion_tasks): update deps, config, crons for delivery context
- Change depends to [base, mail, hr, fusion_plating_logistics] - Rename module to 'Fusion Plating -- Delivery Tasks' - Replace all fusion_claims.* config params with fusion_tasks.* - Remove sync crons (pull_remote_tasks, cleanup_old_shadows) - Remove sync config ACL lines from ir.model.access.csv - Replace sales_team group refs with hr/base equivalents - Update license from OPL-1 to LGPL-3 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,13 +14,12 @@ def _fusion_tasks_post_init(env):
|
|||||||
"""
|
"""
|
||||||
ICP = env['ir.config_parameter'].sudo()
|
ICP = env['ir.config_parameter'].sudo()
|
||||||
defaults = {
|
defaults = {
|
||||||
'fusion_claims.google_maps_api_key': '',
|
'fusion_tasks.google_maps_api_key': '',
|
||||||
'fusion_claims.store_open_hour': '9.0',
|
'fusion_tasks.store_open_hour': '9.0',
|
||||||
'fusion_claims.store_close_hour': '18.0',
|
'fusion_tasks.store_close_hour': '18.0',
|
||||||
'fusion_claims.push_enabled': 'False',
|
'fusion_tasks.push_enabled': 'False',
|
||||||
'fusion_claims.push_advance_minutes': '30',
|
'fusion_tasks.push_advance_minutes': '30',
|
||||||
'fusion_claims.sync_instance_id': '',
|
'fusion_tasks.technician_start_address': '',
|
||||||
'fusion_claims.technician_start_address': '',
|
|
||||||
}
|
}
|
||||||
for key, default_value in defaults.items():
|
for key, default_value in defaults.items():
|
||||||
if not ICP.get_param(key):
|
if not ICP.get_param(key):
|
||||||
|
|||||||
@@ -3,25 +3,27 @@
|
|||||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Fusion Tasks',
|
'name': 'Fusion Plating — Delivery Tasks',
|
||||||
'version': '19.0.1.0.0',
|
'version': '19.0.1.0.0',
|
||||||
'category': 'Services/Field Service',
|
'category': 'Services/Field Service',
|
||||||
'summary': 'Technician scheduling, route planning, GPS tracking, and cross-instance sync.',
|
'summary': 'Local delivery dispatch with GPS tracking and route planning.',
|
||||||
|
'description': 'Delivery task management for fusion plating logistics. '
|
||||||
|
'Handles driver scheduling, GPS tracking, travel time calculation, '
|
||||||
|
'and push notifications for delivery, pickup, and rush runs.',
|
||||||
'author': 'Nexa Systems Inc.',
|
'author': 'Nexa Systems Inc.',
|
||||||
'website': 'https://www.nexasystems.ca',
|
'website': 'https://www.nexasystems.ca',
|
||||||
'license': 'OPL-1',
|
'license': 'LGPL-3',
|
||||||
'depends': [
|
'depends': [
|
||||||
'base',
|
'base',
|
||||||
'mail',
|
'mail',
|
||||||
'calendar',
|
'hr',
|
||||||
'sales_team',
|
'fusion_plating_logistics',
|
||||||
],
|
],
|
||||||
'data': [
|
'data': [
|
||||||
'security/security.xml',
|
'security/security.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
'data/ir_cron_data.xml',
|
'data/ir_cron_data.xml',
|
||||||
'views/technician_task_views.xml',
|
'views/technician_task_views.xml',
|
||||||
'views/task_sync_views.xml',
|
|
||||||
'views/technician_location_views.xml',
|
'views/technician_location_views.xml',
|
||||||
'views/res_config_settings_views.xml',
|
'views/res_config_settings_views.xml',
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -4,45 +4,38 @@
|
|||||||
Default configuration parameters for Fusion Tasks.
|
Default configuration parameters for Fusion Tasks.
|
||||||
noupdate="1" ensures these are ONLY set on first install.
|
noupdate="1" ensures these are ONLY set on first install.
|
||||||
forcecreate="false" prevents errors if keys already exist.
|
forcecreate="false" prevents errors if keys already exist.
|
||||||
Keys use fusion_claims.* prefix to preserve existing data.
|
|
||||||
-->
|
-->
|
||||||
<data noupdate="1">
|
<data noupdate="1">
|
||||||
|
|
||||||
<!-- Google Maps API Key -->
|
<!-- Google Maps API Key -->
|
||||||
<record id="config_google_maps_api_key" model="ir.config_parameter" forcecreate="false">
|
<record id="config_google_maps_api_key" model="ir.config_parameter" forcecreate="false">
|
||||||
<field name="key">fusion_claims.google_maps_api_key</field>
|
<field name="key">fusion_tasks.google_maps_api_key</field>
|
||||||
<field name="value"></field>
|
<field name="value"></field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Store Hours -->
|
<!-- Store Hours -->
|
||||||
<record id="config_store_open_hour" model="ir.config_parameter" forcecreate="false">
|
<record id="config_store_open_hour" model="ir.config_parameter" forcecreate="false">
|
||||||
<field name="key">fusion_claims.store_open_hour</field>
|
<field name="key">fusion_tasks.store_open_hour</field>
|
||||||
<field name="value">9.0</field>
|
<field name="value">9.0</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="config_store_close_hour" model="ir.config_parameter" forcecreate="false">
|
<record id="config_store_close_hour" model="ir.config_parameter" forcecreate="false">
|
||||||
<field name="key">fusion_claims.store_close_hour</field>
|
<field name="key">fusion_tasks.store_close_hour</field>
|
||||||
<field name="value">18.0</field>
|
<field name="value">18.0</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Push Notifications -->
|
<!-- Push Notifications -->
|
||||||
<record id="config_push_enabled" model="ir.config_parameter" forcecreate="false">
|
<record id="config_push_enabled" model="ir.config_parameter" forcecreate="false">
|
||||||
<field name="key">fusion_claims.push_enabled</field>
|
<field name="key">fusion_tasks.push_enabled</field>
|
||||||
<field name="value">False</field>
|
<field name="value">False</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="config_push_advance_minutes" model="ir.config_parameter" forcecreate="false">
|
<record id="config_push_advance_minutes" model="ir.config_parameter" forcecreate="false">
|
||||||
<field name="key">fusion_claims.push_advance_minutes</field>
|
<field name="key">fusion_tasks.push_advance_minutes</field>
|
||||||
<field name="value">30</field>
|
<field name="value">30</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Cross-instance task sync -->
|
|
||||||
<record id="config_sync_instance_id" model="ir.config_parameter" forcecreate="false">
|
|
||||||
<field name="key">fusion_claims.sync_instance_id</field>
|
|
||||||
<field name="value"></field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Technician start address (HQ default) -->
|
<!-- Technician start address (HQ default) -->
|
||||||
<record id="config_technician_start_address" model="ir.config_parameter" forcecreate="false">
|
<record id="config_technician_start_address" model="ir.config_parameter" forcecreate="false">
|
||||||
<field name="key">fusion_claims.technician_start_address</field>
|
<field name="key">fusion_tasks.technician_start_address</field>
|
||||||
<field name="value"></field>
|
<field name="value"></field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
Copyright 2024-2026 Nexa Systems Inc.
|
Copyright 2024-2026 Nexa Systems Inc.
|
||||||
License OPL-1 (Odoo Proprietary License v1.0)
|
License LGPL-3
|
||||||
-->
|
-->
|
||||||
<odoo>
|
<odoo>
|
||||||
<data>
|
<data>
|
||||||
@@ -28,29 +28,6 @@
|
|||||||
<field name="active">True</field>
|
<field name="active">True</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Cron Job: Pull Remote Technician Tasks (cross-instance sync) -->
|
|
||||||
<record id="ir_cron_task_sync_pull" model="ir.cron">
|
|
||||||
<field name="name">Fusion Tasks: Sync Remote Tasks (Pull)</field>
|
|
||||||
<field name="model_id" ref="model_fusion_task_sync_config"/>
|
|
||||||
<field name="state">code</field>
|
|
||||||
<field name="code">model._cron_pull_remote_tasks()</field>
|
|
||||||
<field name="interval_number">2</field>
|
|
||||||
<field name="interval_type">minutes</field>
|
|
||||||
<field name="active">True</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Cron Job: Cleanup Old Shadow Tasks (30+ days) -->
|
|
||||||
<record id="ir_cron_task_sync_cleanup" model="ir.cron">
|
|
||||||
<field name="name">Fusion Tasks: Cleanup Old Shadow Tasks</field>
|
|
||||||
<field name="model_id" ref="model_fusion_task_sync_config"/>
|
|
||||||
<field name="state">code</field>
|
|
||||||
<field name="code">model._cron_cleanup_old_shadows()</field>
|
|
||||||
<field name="interval_number">1</field>
|
|
||||||
<field name="interval_type">days</field>
|
|
||||||
<field name="active">True</field>
|
|
||||||
<field name="nextcall" eval="DateTime.now().replace(hour=3, minute=0, second=0)"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Cron Job: Check for Late Technician Arrivals -->
|
<!-- Cron Job: Check for Late Technician Arrivals -->
|
||||||
<record id="ir_cron_check_late_arrivals" model="ir.cron">
|
<record id="ir_cron_check_late_arrivals" model="ir.cron">
|
||||||
<field name="name">Fusion Tasks: Check Late Technician Arrivals</field>
|
<field name="name">Fusion Tasks: Check Late Technician Arrivals</field>
|
||||||
|
|||||||
@@ -237,5 +237,5 @@ class FusionEmailBuilderMixin(models.AbstractModel):
|
|||||||
def _email_is_enabled(self):
|
def _email_is_enabled(self):
|
||||||
"""Check if email notifications are enabled in settings."""
|
"""Check if email notifications are enabled in settings."""
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
val = ICP.get_param('fusion_claims.enable_email_notifications', 'True')
|
val = ICP.get_param('fusion_tasks.enable_email_notifications', 'True')
|
||||||
return val.lower() in ('true', '1', 'yes')
|
return val.lower() in ('true', '1', 'yes')
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
# Google Maps API Settings
|
# Google Maps API Settings
|
||||||
fc_google_maps_api_key = fields.Char(
|
fc_google_maps_api_key = fields.Char(
|
||||||
string='Google Maps API Key',
|
string='Google Maps API Key',
|
||||||
config_parameter='fusion_claims.google_maps_api_key',
|
config_parameter='fusion_tasks.google_maps_api_key',
|
||||||
help='API key for Google Maps Places autocomplete in address fields',
|
help='API key for Google Maps Places autocomplete in address fields',
|
||||||
)
|
)
|
||||||
fc_google_review_url = fields.Char(
|
fc_google_review_url = fields.Char(
|
||||||
@@ -23,27 +23,27 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
# Technician Management
|
# Technician Management
|
||||||
fc_store_open_hour = fields.Float(
|
fc_store_open_hour = fields.Float(
|
||||||
string='Store Open Time',
|
string='Store Open Time',
|
||||||
config_parameter='fusion_claims.store_open_hour',
|
config_parameter='fusion_tasks.store_open_hour',
|
||||||
help='Store opening time for technician scheduling (e.g. 9.0 = 9:00 AM)',
|
help='Store opening time for technician scheduling (e.g. 9.0 = 9:00 AM)',
|
||||||
)
|
)
|
||||||
fc_store_close_hour = fields.Float(
|
fc_store_close_hour = fields.Float(
|
||||||
string='Store Close Time',
|
string='Store Close Time',
|
||||||
config_parameter='fusion_claims.store_close_hour',
|
config_parameter='fusion_tasks.store_close_hour',
|
||||||
help='Store closing time for technician scheduling (e.g. 18.0 = 6:00 PM)',
|
help='Store closing time for technician scheduling (e.g. 18.0 = 6:00 PM)',
|
||||||
)
|
)
|
||||||
fc_google_distance_matrix_enabled = fields.Boolean(
|
fc_google_distance_matrix_enabled = fields.Boolean(
|
||||||
string='Enable Distance Matrix',
|
string='Enable Distance Matrix',
|
||||||
config_parameter='fusion_claims.google_distance_matrix_enabled',
|
config_parameter='fusion_tasks.google_distance_matrix_enabled',
|
||||||
help='Enable Google Distance Matrix API for travel time calculations between technician tasks',
|
help='Enable Google Distance Matrix API for travel time calculations between technician tasks',
|
||||||
)
|
)
|
||||||
fc_technician_start_address = fields.Char(
|
fc_technician_start_address = fields.Char(
|
||||||
string='Technician Start Address',
|
string='Technician Start Address',
|
||||||
config_parameter='fusion_claims.technician_start_address',
|
config_parameter='fusion_tasks.technician_start_address',
|
||||||
help='Default start location for technician travel calculations (e.g. warehouse/office address)',
|
help='Default start location for technician travel calculations (e.g. warehouse/office address)',
|
||||||
)
|
)
|
||||||
fc_location_retention_days = fields.Char(
|
fc_location_retention_days = fields.Char(
|
||||||
string='Location History Retention (Days)',
|
string='Location History Retention (Days)',
|
||||||
config_parameter='fusion_claims.location_retention_days',
|
config_parameter='fusion_tasks.location_retention_days',
|
||||||
help='How many days to keep technician location history. '
|
help='How many days to keep technician location history. '
|
||||||
'Leave empty = 30 days (1 month). '
|
'Leave empty = 30 days (1 month). '
|
||||||
'0 = delete at end of each day. '
|
'0 = delete at end of each day. '
|
||||||
@@ -53,21 +53,21 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
# Web Push Notifications
|
# Web Push Notifications
|
||||||
fc_push_enabled = fields.Boolean(
|
fc_push_enabled = fields.Boolean(
|
||||||
string='Enable Push Notifications',
|
string='Enable Push Notifications',
|
||||||
config_parameter='fusion_claims.push_enabled',
|
config_parameter='fusion_tasks.push_enabled',
|
||||||
help='Enable web push notifications for technician tasks',
|
help='Enable web push notifications for technician tasks',
|
||||||
)
|
)
|
||||||
fc_vapid_public_key = fields.Char(
|
fc_vapid_public_key = fields.Char(
|
||||||
string='VAPID Public Key',
|
string='VAPID Public Key',
|
||||||
config_parameter='fusion_claims.vapid_public_key',
|
config_parameter='fusion_tasks.vapid_public_key',
|
||||||
help='Public key for Web Push VAPID authentication (auto-generated)',
|
help='Public key for Web Push VAPID authentication (auto-generated)',
|
||||||
)
|
)
|
||||||
fc_vapid_private_key = fields.Char(
|
fc_vapid_private_key = fields.Char(
|
||||||
string='VAPID Private Key',
|
string='VAPID Private Key',
|
||||||
config_parameter='fusion_claims.vapid_private_key',
|
config_parameter='fusion_tasks.vapid_private_key',
|
||||||
help='Private key for Web Push VAPID authentication (auto-generated)',
|
help='Private key for Web Push VAPID authentication (auto-generated)',
|
||||||
)
|
)
|
||||||
fc_push_advance_minutes = fields.Integer(
|
fc_push_advance_minutes = fields.Integer(
|
||||||
string='Notification Advance (min)',
|
string='Notification Advance (min)',
|
||||||
config_parameter='fusion_claims.push_advance_minutes',
|
config_parameter='fusion_tasks.push_advance_minutes',
|
||||||
help='Send push notifications this many minutes before a scheduled task',
|
help='Send push notifications this many minutes before a scheduled task',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ResPartner(models.Model):
|
|||||||
if not address or not address.strip():
|
if not address or not address.strip():
|
||||||
return 0.0, 0.0
|
return 0.0, 0.0
|
||||||
api_key = self.env['ir.config_parameter'].sudo().get_param(
|
api_key = self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'fusion_claims.google_maps_api_key', '')
|
'fusion_tasks.google_maps_api_key', '')
|
||||||
if not api_key:
|
if not api_key:
|
||||||
return 0.0, 0.0
|
return 0.0, 0.0
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class FusionTechnicianLocation(models.Model):
|
|||||||
""")
|
""")
|
||||||
rows = self.env.cr.dictfetchall()
|
rows = self.env.cr.dictfetchall()
|
||||||
local_id = self.env['ir.config_parameter'].sudo().get_param(
|
local_id = self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'fusion_claims.sync_instance_id', '')
|
'fusion_tasks.sync_instance_id', '')
|
||||||
result = []
|
result = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
user = self.env['res.users'].sudo().browse(row['user_id'])
|
user = self.env['res.users'].sudo().browse(row['user_id'])
|
||||||
@@ -104,13 +104,13 @@ class FusionTechnicianLocation(models.Model):
|
|||||||
def _cron_cleanup_old_locations(self):
|
def _cron_cleanup_old_locations(self):
|
||||||
"""Remove location logs based on configurable retention setting.
|
"""Remove location logs based on configurable retention setting.
|
||||||
|
|
||||||
Setting (fusion_claims.location_retention_days):
|
Setting (fusion_tasks.location_retention_days):
|
||||||
- Empty / not set => keep 30 days (default)
|
- Empty / not set => keep 30 days (default)
|
||||||
- "0" => delete at end of day (keep today only)
|
- "0" => delete at end of day (keep today only)
|
||||||
- "1" .. "N" => keep for N days
|
- "1" .. "N" => keep for N days
|
||||||
"""
|
"""
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
raw = (ICP.get_param('fusion_claims.location_retention_days') or '').strip()
|
raw = (ICP.get_param('fusion_tasks.location_retention_days') or '').strip()
|
||||||
|
|
||||||
if raw == '':
|
if raw == '':
|
||||||
retention_days = 30 # default: 1 month
|
retention_days = 30 # default: 1 month
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ class FusionTechnicianTask(models.Model):
|
|||||||
"""Return (open_hour, close_hour) from settings. Defaults 9.0 / 18.0."""
|
"""Return (open_hour, close_hour) from settings. Defaults 9.0 / 18.0."""
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
try:
|
try:
|
||||||
open_h = float(ICP.get_param('fusion_claims.store_open_hour', '9.0') or '9.0')
|
open_h = float(ICP.get_param('fusion_tasks.store_open_hour', '9.0') or '9.0')
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
open_h = 9.0
|
open_h = 9.0
|
||||||
try:
|
try:
|
||||||
close_h = float(ICP.get_param('fusion_claims.store_close_hour', '18.0') or '18.0')
|
close_h = float(ICP.get_param('fusion_tasks.store_close_hour', '18.0') or '18.0')
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
close_h = 18.0
|
close_h = 18.0
|
||||||
return (open_h, close_h)
|
return (open_h, close_h)
|
||||||
@@ -938,7 +938,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
Returns travel time in minutes, or 0 if unavailable."""
|
Returns travel time in minutes, or 0 if unavailable."""
|
||||||
try:
|
try:
|
||||||
api_key = self.env['ir.config_parameter'].sudo().get_param(
|
api_key = self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'fusion_claims.google_maps_api_key', '')
|
'fusion_tasks.google_maps_api_key', '')
|
||||||
if not api_key:
|
if not api_key:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -1385,7 +1385,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
def _create_vals_fill(self, vals):
|
def _create_vals_fill(self, vals):
|
||||||
"""Hook: fill address from linked records during create.
|
"""Hook: fill address from linked records during create.
|
||||||
|
|
||||||
Base implementation fills from partner_id. Override in fusion_claims
|
Base implementation fills from partner_id. Override in subclass
|
||||||
to also fill from sale_order_id or purchase_order_id.
|
to also fill from sale_order_id or purchase_order_id.
|
||||||
"""
|
"""
|
||||||
if vals.get('partner_id') and not vals.get('address_street'):
|
if vals.get('partner_id') and not vals.get('address_street'):
|
||||||
@@ -1396,7 +1396,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
def _on_create_post_actions(self):
|
def _on_create_post_actions(self):
|
||||||
"""Hook: post-create side-effects for linked records.
|
"""Hook: post-create side-effects for linked records.
|
||||||
|
|
||||||
Override in fusion_claims to post chatter messages to linked orders,
|
Override in subclass to post chatter messages to linked orders,
|
||||||
mark sale orders as ready for delivery, etc.
|
mark sale orders as ready for delivery, etc.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
@@ -1556,12 +1556,12 @@ class FusionTechnicianTask(models.Model):
|
|||||||
|
|
||||||
def _post_task_created_to_linked_order(self):
|
def _post_task_created_to_linked_order(self):
|
||||||
"""Hook: post task creation notice to linked order chatter.
|
"""Hook: post task creation notice to linked order chatter.
|
||||||
Override in fusion_claims."""
|
Override in fusion_tasks."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _mark_sale_order_ready_for_delivery(self):
|
def _mark_sale_order_ready_for_delivery(self):
|
||||||
"""Hook: mark linked sale orders as ready for delivery.
|
"""Hook: mark linked sale orders as ready for delivery.
|
||||||
Override in fusion_claims."""
|
Override in fusion_tasks."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _recalculate_day_travel_chains(self):
|
def _recalculate_day_travel_chains(self):
|
||||||
@@ -1584,7 +1584,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
|
|
||||||
Priority:
|
Priority:
|
||||||
1. Technician's personal x_fc_start_address (if set)
|
1. Technician's personal x_fc_start_address (if set)
|
||||||
2. Company default HQ address (fusion_claims.technician_start_address)
|
2. Company default HQ address (fusion_tasks.technician_start_address)
|
||||||
Returns the address string or ''.
|
Returns the address string or ''.
|
||||||
"""
|
"""
|
||||||
tech_user = self.env['res.users'].sudo().browse(tech_id)
|
tech_user = self.env['res.users'].sudo().browse(tech_id)
|
||||||
@@ -1592,7 +1592,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
return tech_user.x_fc_start_address.strip()
|
return tech_user.x_fc_start_address.strip()
|
||||||
# Fallback to company default
|
# Fallback to company default
|
||||||
return (self.env['ir.config_parameter'].sudo()
|
return (self.env['ir.config_parameter'].sudo()
|
||||||
.get_param('fusion_claims.technician_start_address', '') or '').strip()
|
.get_param('fusion_tasks.technician_start_address', '') or '').strip()
|
||||||
|
|
||||||
def _geocode_address_string(self, address, api_key):
|
def _geocode_address_string(self, address, api_key):
|
||||||
"""Geocode an address string and return (lat, lng) or (0.0, 0.0)."""
|
"""Geocode an address string and return (lat, lng) or (0.0, 0.0)."""
|
||||||
@@ -1621,7 +1621,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
For future dates, only 3 and 4 apply.
|
For future dates, only 3 and 4 apply.
|
||||||
"""
|
"""
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
enabled = ICP.get_param('fusion_claims.google_distance_matrix_enabled', False)
|
enabled = ICP.get_param('fusion_tasks.google_distance_matrix_enabled', False)
|
||||||
if not enabled:
|
if not enabled:
|
||||||
return
|
return
|
||||||
api_key = self._get_google_maps_api_key()
|
api_key = self._get_google_maps_api_key()
|
||||||
@@ -1731,7 +1731,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
"""
|
"""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
if not ICP.get_param('fusion_claims.google_distance_matrix_enabled', False):
|
if not ICP.get_param('fusion_tasks.google_distance_matrix_enabled', False):
|
||||||
return
|
return
|
||||||
tech_id = self.technician_id.id
|
tech_id = self.technician_id.id
|
||||||
if not tech_id:
|
if not tech_id:
|
||||||
@@ -1752,7 +1752,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
"""
|
"""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
if not ICP.get_param('fusion_claims.google_distance_matrix_enabled', False):
|
if not ICP.get_param('fusion_tasks.google_distance_matrix_enabled', False):
|
||||||
return
|
return
|
||||||
|
|
||||||
tech_id = self.technician_id.id
|
tech_id = self.technician_id.id
|
||||||
@@ -1913,12 +1913,12 @@ class FusionTechnicianTask(models.Model):
|
|||||||
|
|
||||||
def _check_completion_requirements(self):
|
def _check_completion_requirements(self):
|
||||||
"""Hook: check additional requirements before task completion.
|
"""Hook: check additional requirements before task completion.
|
||||||
Override in fusion_claims for rental inspection checks."""
|
Override in subclass for rental inspection checks."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _on_complete_extra(self):
|
def _on_complete_extra(self):
|
||||||
"""Hook: additional side-effects after task completion.
|
"""Hook: additional side-effects after task completion.
|
||||||
Override in fusion_claims for ODSP advancement and rental inspection."""
|
Override in subclass for ODSP advancement and rental inspection."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def action_cancel_task(self):
|
def action_cancel_task(self):
|
||||||
@@ -1933,7 +1933,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
|
|
||||||
def _on_cancel_extra(self):
|
def _on_cancel_extra(self):
|
||||||
"""Hook: additional side-effects after task cancellation.
|
"""Hook: additional side-effects after task cancellation.
|
||||||
Override in fusion_claims for sale order revert and email."""
|
Override in subclass for sale order revert and email."""
|
||||||
self._send_task_cancelled_email()
|
self._send_task_cancelled_email()
|
||||||
|
|
||||||
def action_reschedule(self):
|
def action_reschedule(self):
|
||||||
@@ -1985,7 +1985,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
|
|
||||||
def _post_completion_to_linked_order(self):
|
def _post_completion_to_linked_order(self):
|
||||||
"""Hook: post completion notes to linked order chatter.
|
"""Hook: post completion notes to linked order chatter.
|
||||||
Override in fusion_claims."""
|
Override in fusion_tasks."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _notify_scheduler_on_completion(self):
|
def _notify_scheduler_on_completion(self):
|
||||||
@@ -2086,15 +2086,15 @@ class FusionTechnicianTask(models.Model):
|
|||||||
return {'to': to_emails, 'cc': list(set(cc_emails))}
|
return {'to': to_emails, 'cc': list(set(cc_emails))}
|
||||||
|
|
||||||
def _send_task_cancelled_email(self):
|
def _send_task_cancelled_email(self):
|
||||||
"""Send cancellation email. Base: no-op. Override in fusion_claims."""
|
"""Send cancellation email. Base: no-op. Override in fusion_tasks."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _send_task_scheduled_email(self):
|
def _send_task_scheduled_email(self):
|
||||||
"""Send scheduled email. Base: no-op. Override in fusion_claims."""
|
"""Send scheduled email. Base: no-op. Override in fusion_tasks."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _send_task_rescheduled_email(self, old_date=None, old_start=None, old_end=None):
|
def _send_task_rescheduled_email(self, old_date=None, old_start=None, old_end=None):
|
||||||
"""Send rescheduled email. Base: no-op. Override in fusion_claims."""
|
"""Send rescheduled email. Base: no-op. Override in fusion_tasks."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -2105,14 +2105,14 @@ class FusionTechnicianTask(models.Model):
|
|||||||
"""Return a record that has the _email_build mixin.
|
"""Return a record that has the _email_build mixin.
|
||||||
|
|
||||||
Base: returns self (task model inherits mixin).
|
Base: returns self (task model inherits mixin).
|
||||||
Override in fusion_claims to prefer linked sale order.
|
Override in subclass to prefer linked sale order.
|
||||||
"""
|
"""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _is_email_notifications_enabled(self):
|
def _is_email_notifications_enabled(self):
|
||||||
"""Check if email notifications are enabled.
|
"""Check if email notifications are enabled.
|
||||||
|
|
||||||
Base: always True. Override in fusion_claims to check
|
Base: always True. Override in subclass to check
|
||||||
linked sale order's notification settings.
|
linked sale order's notification settings.
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
@@ -2120,7 +2120,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
def _get_linked_order(self):
|
def _get_linked_order(self):
|
||||||
"""Return the linked order record (SO or PO), or False.
|
"""Return the linked order record (SO or PO), or False.
|
||||||
|
|
||||||
Base: always False. Override in fusion_claims to return
|
Base: always False. Override in subclass to return
|
||||||
sale_order_id or purchase_order_id.
|
sale_order_id or purchase_order_id.
|
||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
@@ -2336,7 +2336,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
def _get_google_maps_api_key(self):
|
def _get_google_maps_api_key(self):
|
||||||
"""Get the Google Maps API key from config."""
|
"""Get the Google Maps API key from config."""
|
||||||
return self.env['ir.config_parameter'].sudo().get_param(
|
return self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'fusion_claims.google_maps_api_key', ''
|
'fusion_tasks.google_maps_api_key', ''
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
@@ -2347,9 +2347,9 @@ class FusionTechnicianTask(models.Model):
|
|||||||
domain: optional extra domain from the search bar filters.
|
domain: optional extra domain from the search bar filters.
|
||||||
"""
|
"""
|
||||||
api_key = self.env['ir.config_parameter'].sudo().get_param(
|
api_key = self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'fusion_claims.google_maps_api_key', '')
|
'fusion_tasks.google_maps_api_key', '')
|
||||||
local_instance = self.env['ir.config_parameter'].sudo().get_param(
|
local_instance = self.env['ir.config_parameter'].sudo().get_param(
|
||||||
'fusion_claims.sync_instance_id', '')
|
'fusion_tasks.sync_instance_id', '')
|
||||||
base_domain = [
|
base_domain = [
|
||||||
('status', 'not in', ['cancelled']),
|
('status', 'not in', ['cancelled']),
|
||||||
]
|
]
|
||||||
@@ -2399,7 +2399,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
|
|
||||||
hq_address = (
|
hq_address = (
|
||||||
self.env['ir.config_parameter'].sudo()
|
self.env['ir.config_parameter'].sudo()
|
||||||
.get_param('fusion_claims.technician_start_address', '') or ''
|
.get_param('fusion_tasks.technician_start_address', '') or ''
|
||||||
).strip()
|
).strip()
|
||||||
hq_lat, hq_lng = 0.0, 0.0
|
hq_lat, hq_lng = 0.0, 0.0
|
||||||
|
|
||||||
@@ -2693,7 +2693,7 @@ class FusionTechnicianTask(models.Model):
|
|||||||
tech and an in-app notification to the office (once per task).
|
tech and an in-app notification to the office (once per task).
|
||||||
"""
|
"""
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
push_enabled = ICP.get_param('fusion_claims.push_enabled', 'False')
|
push_enabled = ICP.get_param('fusion_tasks.push_enabled', 'False')
|
||||||
if push_enabled.lower() not in ('true', '1', 'yes'):
|
if push_enabled.lower() not in ('true', '1', 'yes'):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -2801,8 +2801,8 @@ class FusionTechnicianTask(models.Model):
|
|||||||
return
|
return
|
||||||
|
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
vapid_private = ICP.get_param('fusion_claims.vapid_private_key', '')
|
vapid_private = ICP.get_param('fusion_tasks.vapid_private_key', '')
|
||||||
vapid_public = ICP.get_param('fusion_claims.vapid_public_key', '')
|
vapid_public = ICP.get_param('fusion_tasks.vapid_public_key', '')
|
||||||
if not vapid_private or not vapid_public:
|
if not vapid_private or not vapid_public:
|
||||||
_logger.warning("VAPID keys not configured, cannot send push notification")
|
_logger.warning("VAPID keys not configured, cannot send push notification")
|
||||||
return
|
return
|
||||||
@@ -2850,10 +2850,10 @@ class FusionTechnicianTask(models.Model):
|
|||||||
def _cron_send_push_notifications(self):
|
def _cron_send_push_notifications(self):
|
||||||
"""Cron: Send push notifications for upcoming tasks."""
|
"""Cron: Send push notifications for upcoming tasks."""
|
||||||
ICP = self.env['ir.config_parameter'].sudo()
|
ICP = self.env['ir.config_parameter'].sudo()
|
||||||
if not ICP.get_param('fusion_claims.push_enabled', False):
|
if not ICP.get_param('fusion_tasks.push_enabled', False):
|
||||||
return
|
return
|
||||||
|
|
||||||
advance_minutes = int(ICP.get_param('fusion_claims.push_advance_minutes', '30'))
|
advance_minutes = int(ICP.get_param('fusion_tasks.push_advance_minutes', '30'))
|
||||||
local_now = self._local_now()
|
local_now = self._local_now()
|
||||||
|
|
||||||
tasks = self.search([
|
tasks = self.search([
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
access_fusion_technician_task_user,fusion.technician.task.user,model_fusion_technician_task,sales_team.group_sale_salesman,1,1,1,0
|
access_fusion_technician_task_user,fusion.technician.task.user,model_fusion_technician_task,base.group_user,1,1,1,0
|
||||||
access_fusion_technician_task_manager,fusion.technician.task.manager,model_fusion_technician_task,sales_team.group_sale_manager,1,1,1,1
|
access_fusion_technician_task_manager,fusion.technician.task.manager,model_fusion_technician_task,hr.group_hr_manager,1,1,1,1
|
||||||
access_fusion_technician_task_technician,fusion.technician.task.technician,model_fusion_technician_task,fusion_tasks.group_field_technician,1,1,0,0
|
access_fusion_technician_task_technician,fusion.technician.task.technician,model_fusion_technician_task,fusion_tasks.group_field_technician,1,1,0,0
|
||||||
access_fusion_technician_task_portal,fusion.technician.task.portal,model_fusion_technician_task,base.group_portal,1,0,0,0
|
access_fusion_technician_task_portal,fusion.technician.task.portal,model_fusion_technician_task,base.group_portal,1,0,0,0
|
||||||
access_fusion_push_subscription_user,fusion.push.subscription.user,model_fusion_push_subscription,base.group_user,1,1,1,0
|
access_fusion_push_subscription_user,fusion.push.subscription.user,model_fusion_push_subscription,base.group_user,1,1,1,0
|
||||||
access_fusion_push_subscription_portal,fusion.push.subscription.portal,model_fusion_push_subscription,base.group_portal,1,1,1,0
|
access_fusion_push_subscription_portal,fusion.push.subscription.portal,model_fusion_push_subscription,base.group_portal,1,1,1,0
|
||||||
access_fusion_technician_location_manager,fusion.technician.location.manager,model_fusion_technician_location,sales_team.group_sale_manager,1,1,1,1
|
access_fusion_technician_location_manager,fusion.technician.location.manager,model_fusion_technician_location,hr.group_hr_manager,1,1,1,1
|
||||||
access_fusion_technician_location_user,fusion.technician.location.user,model_fusion_technician_location,sales_team.group_sale_salesman,1,0,0,0
|
access_fusion_technician_location_user,fusion.technician.location.user,model_fusion_technician_location,base.group_user,1,0,0,0
|
||||||
access_fusion_technician_location_portal,fusion.technician.location.portal,model_fusion_technician_location,base.group_portal,0,0,1,0
|
access_fusion_technician_location_portal,fusion.technician.location.portal,model_fusion_technician_location,base.group_portal,0,0,1,0
|
||||||
access_fusion_task_sync_config_manager,fusion.task.sync.config.manager,model_fusion_task_sync_config,sales_team.group_sale_manager,1,1,1,1
|
|
||||||
access_fusion_task_sync_config_user,fusion.task.sync.config.user,model_fusion_task_sync_config,sales_team.group_sale_salesman,1,0,0,0
|
|
||||||
|
|||||||
|
@@ -37,7 +37,7 @@
|
|||||||
<field name="name">Technician Task: Manager Full Access</field>
|
<field name="name">Technician Task: Manager Full Access</field>
|
||||||
<field name="model_id" ref="model_fusion_technician_task"/>
|
<field name="model_id" ref="model_fusion_technician_task"/>
|
||||||
<field name="domain_force">[(1, '=', 1)]</field>
|
<field name="domain_force">[(1, '=', 1)]</field>
|
||||||
<field name="groups" eval="[(4, ref('sales_team.group_sale_manager'))]"/>
|
<field name="groups" eval="[(4, ref('hr.group_hr_manager'))]"/>
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True"/>
|
||||||
<field name="perm_write" eval="True"/>
|
<field name="perm_write" eval="True"/>
|
||||||
<field name="perm_create" eval="True"/>
|
<field name="perm_create" eval="True"/>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<field name="name">Technician Task: Sales User Access</field>
|
<field name="name">Technician Task: Sales User Access</field>
|
||||||
<field name="model_id" ref="model_fusion_technician_task"/>
|
<field name="model_id" ref="model_fusion_technician_task"/>
|
||||||
<field name="domain_force">[(1, '=', 1)]</field>
|
<field name="domain_force">[(1, '=', 1)]</field>
|
||||||
<field name="groups" eval="[(4, ref('sales_team.group_sale_salesman'))]"/>
|
<field name="groups" eval="[(4, ref('base.group_user'))]"/>
|
||||||
<field name="perm_read" eval="True"/>
|
<field name="perm_read" eval="True"/>
|
||||||
<field name="perm_write" eval="True"/>
|
<field name="perm_write" eval="True"/>
|
||||||
<field name="perm_create" eval="True"/>
|
<field name="perm_create" eval="True"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user