refactor(fusion_tasks): strip all sync references from task model

Remove cross-instance sync fields (x_fc_sync_source, x_fc_sync_remote_id,
x_fc_sync_uuid, x_fc_is_shadow, x_fc_sync_client_name, x_fc_sync_client_phone,
x_fc_source_label), sync push calls in create/write/action methods, shadow
task logic in constraints and email guards, and x_fc_tech_sync_id from
res.users. Also remove task_sync import from models/__init__.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-12 20:26:23 -04:00
parent bc72486808
commit e10bf9d8fd
3 changed files with 13 additions and 117 deletions

View File

@@ -8,6 +8,5 @@ from . import res_company
from . import res_users
from . import res_config_settings
from . import technician_task
from . import task_sync
from . import technician_location
from . import push_subscription

View File

@@ -18,9 +18,3 @@ class ResUsers(models.Model):
readonly=False,
string='Start Location',
)
x_fc_tech_sync_id = fields.Char(
string='Tech Sync ID',
help='Shared identifier for this technician across Odoo instances. '
'Must be the same value on all instances for the same person.',
copy=False,
)

View File

@@ -14,7 +14,6 @@ from odoo.osv import expression
from markupsafe import Markup
import logging
import json
import uuid
import requests
from datetime import datetime as dt_datetime, timedelta
import urllib.parse
@@ -33,7 +32,7 @@ class FusionTechnicianTask(models.Model):
"""Richer display name: Client - Type | 9:00 AM - 10:00 AM [+2 techs]."""
type_labels = dict(self._fields['task_type'].selection)
for task in self:
client = task.x_fc_sync_client_name if task.x_fc_sync_source else (task.partner_id.name or '')
client = task.partner_id.name or ''
ttype = type_labels.get(task.task_type, task.task_type or '')
start = self._float_to_time_str(task.time_start)
end = self._float_to_time_str(task.time_end)
@@ -74,32 +73,6 @@ class FusionTechnicianTask(models.Model):
)
active = fields.Boolean(default=True)
# Cross-instance sync fields
x_fc_sync_source = fields.Char(
'Source Instance', readonly=True, index=True,
help='Origin instance ID if this is a synced shadow task (e.g. westin, mobility)',
)
x_fc_sync_remote_id = fields.Integer(
'Remote Task ID', readonly=True,
help='ID of the task on the remote instance',
)
x_fc_sync_uuid = fields.Char(
'Sync UUID', readonly=True, index=True, copy=False,
help='Unique ID for cross-instance deduplication',
)
x_fc_is_shadow = fields.Boolean(
'Shadow Task', compute='_compute_is_shadow', store=True,
help='True if this task was synced from another instance',
)
x_fc_sync_client_name = fields.Char(
'Synced Client Name', readonly=True,
help='Client name from the remote instance (shadow tasks only)',
)
x_fc_sync_client_phone = fields.Char(
'Synced Client Phone', readonly=True,
help='Client phone from the remote instance (shadow tasks only)',
)
client_display_name = fields.Char(
compute='_compute_client_display', string='Client Name (Display)',
)
@@ -107,28 +80,11 @@ class FusionTechnicianTask(models.Model):
compute='_compute_client_display', string='Client Phone (Display)',
)
x_fc_source_label = fields.Char(
'Source', compute='_compute_is_shadow', store=True,
)
@api.depends('x_fc_sync_source')
def _compute_is_shadow(self):
local_id = self.env['ir.config_parameter'].sudo().get_param(
'fusion_claims.sync_instance_id', '')
for task in self:
task.x_fc_is_shadow = bool(task.x_fc_sync_source)
task.x_fc_source_label = task.x_fc_sync_source or local_id
@api.depends('x_fc_sync_source', 'x_fc_sync_client_name',
'x_fc_sync_client_phone', 'partner_id')
@api.depends('partner_id')
def _compute_client_display(self):
for task in self:
if task.x_fc_sync_source:
task.client_display_name = task.x_fc_sync_client_name or task.name or ''
task.client_display_phone = task.x_fc_sync_client_phone or ''
else:
task.client_display_name = task.partner_id.name if task.partner_id else ''
task.client_display_phone = task.partner_id.phone if task.partner_id else ''
task.client_display_name = task.partner_id.name if task.partner_id else ''
task.client_display_phone = task.partner_id.phone if task.partner_id else ''
technician_id = fields.Many2one(
'res.users',
@@ -1101,8 +1057,6 @@ class FusionTechnicianTask(models.Model):
def _check_address_required(self):
"""Non-in-store tasks must have a geocoded address."""
for task in self:
if task.x_fc_sync_source:
continue
if task.is_in_store:
continue
if not task.address_street:
@@ -1121,8 +1075,6 @@ class FusionTechnicianTask(models.Model):
for task in self:
if task.status == 'cancelled':
continue
if task.x_fc_sync_source:
continue
# Validate time range
if task.time_start >= task.time_end:
raise ValidationError(_("Start time must be before end time."))
@@ -1134,8 +1086,8 @@ class FusionTechnicianTask(models.Model):
raise ValidationError(_(
"Tasks must be scheduled within store hours (%s - %s)."
) % (open_str, close_str))
# Validate not in the past (only for new/scheduled local tasks)
if task.status == 'scheduled' and task.scheduled_date and not task.x_fc_sync_source:
# Validate not in the past (only for new/scheduled tasks)
if task.status == 'scheduled' and task.scheduled_date:
local_now = self._local_now()
today = local_now.date()
if task.scheduled_date < today:
@@ -1408,8 +1360,6 @@ class FusionTechnicianTask(models.Model):
for vals in vals_list:
if vals.get('name', _('New')) == _('New'):
vals['name'] = self.env['ir.sequence'].next_by_code('fusion.technician.task') or _('New')
if not vals.get('x_fc_sync_uuid') and not vals.get('x_fc_sync_source'):
vals['x_fc_sync_uuid'] = str(uuid.uuid4())
# In-store tasks: auto-fill company address
if vals.get('is_in_store') and not vals.get('address_street'):
company_partner = self.env.company.partner_id
@@ -1417,7 +1367,7 @@ class FusionTechnicianTask(models.Model):
self._fill_address_vals(vals, company_partner)
else:
vals['address_street'] = self.env.company.name or 'In Store'
# Hook: fill address from linked records (overridden by fusion_claims)
# Hook: fill address from linked records
self._create_vals_fill(vals)
records = super().create(vals_list)
# Hook: post-create actions for linked records
@@ -1428,10 +1378,6 @@ class FusionTechnicianTask(models.Model):
# Send "Appointment Scheduled" email
for rec in records:
rec._send_task_scheduled_email()
# Push new local tasks to remote instances
local_records = records.filtered(lambda r: not r.x_fc_sync_source)
if local_records and not self.env.context.get('skip_task_sync'):
self.env['fusion.task.sync.config']._push_tasks(local_records, 'create')
# Sync to calendar for external calendar integrations
records._sync_calendar_event()
return records
@@ -1457,16 +1403,7 @@ class FusionTechnicianTask(models.Model):
def write(self, vals):
if self.env.context.get('skip_travel_recalc'):
res = super().write(vals)
if ('status' in vals and vals['status'] in ('completed', 'cancelled')
and not self.env.context.get('skip_task_sync')):
shadow_records = self.filtered(lambda r: r.x_fc_sync_source)
if shadow_records:
self.env['fusion.task.sync.config']._push_shadow_status(shadow_records)
local_records = self.filtered(lambda r: not r.x_fc_sync_source)
if local_records:
self.env['fusion.task.sync.config']._push_tasks(local_records, 'write')
return res
return super().write(vals)
# Safety: ensure time_end is consistent when start/duration change
# but time_end wasn't sent (readonly field in view may not save)
@@ -1526,20 +1463,6 @@ class FusionTechnicianTask(models.Model):
old_start=old['time_start'],
old_end=old['time_end'],
)
# Push updates to remote instances for local tasks
sync_fields = {'technician_id', 'additional_technician_ids',
'scheduled_date', 'time_start', 'time_end',
'duration_hours', 'status', 'task_type', 'address_street',
'address_city', 'address_zip', 'address_lat', 'address_lng',
'partner_id'}
if sync_fields & set(vals.keys()) and not self.env.context.get('skip_task_sync'):
local_records = self.filtered(lambda r: not r.x_fc_sync_source)
if local_records:
self.env['fusion.task.sync.config']._push_tasks(local_records, 'write')
if 'status' in vals and vals['status'] in ('completed', 'cancelled'):
shadow_records = self.filtered(lambda r: r.x_fc_sync_source)
if shadow_records:
self.env['fusion.task.sync.config']._push_shadow_status(shadow_records)
# Re-sync calendar event when schedule fields change
cal_fields = {'scheduled_date', 'time_start', 'time_end',
'duration_hours', 'technician_id', 'task_type',
@@ -1928,12 +1851,6 @@ class FusionTechnicianTask(models.Model):
task._send_task_en_route_email()
# Recalculate travel from tech's current location to THIS task
task._recalculate_travel_from_current_location()
if task.x_fc_sync_source:
try:
self.env['fusion.task.sync.config']._push_shadow_status(task)
except Exception:
_logger.exception(
"Failed to push en_route for shadow %s", task.name)
try:
remaining = self.sudo().search_count([
('technician_id', '=', task.technician_id.id),
@@ -2012,14 +1929,7 @@ class FusionTechnicianTask(models.Model):
task.status = 'cancelled'
task._write_action_location()
task._post_status_message('cancelled')
if task.x_fc_sync_source:
try:
self.env['fusion.task.sync.config']._push_shadow_status(task)
except Exception:
_logger.exception(
"Failed to push cancel for shadow %s", task.name)
else:
task._on_cancel_extra()
task._on_cancel_extra()
def _on_cancel_extra(self):
"""Hook: additional side-effects after task cancellation.
@@ -2079,14 +1989,8 @@ class FusionTechnicianTask(models.Model):
pass
def _notify_scheduler_on_completion(self):
"""Send an Odoo notification to the person who scheduled the task.
Shadow tasks skip this -- the push-back to the source instance
triggers the notification there where the real scheduler exists.
"""
"""Send an Odoo notification to the person who scheduled the task."""
self.ensure_one()
if self.x_fc_sync_source:
return
recipient = None
order = self._get_linked_order()
@@ -2224,7 +2128,7 @@ class FusionTechnicianTask(models.Model):
def _send_task_en_route_email(self):
"""Email the client that the technician is on the way."""
self.ensure_one()
if self.x_fc_sync_source or not self.x_fc_send_client_updates:
if not self.x_fc_send_client_updates:
return False
if not self.partner_id or not self.partner_id.email:
return False
@@ -2312,7 +2216,7 @@ class FusionTechnicianTask(models.Model):
- Standard thank-you without review request
"""
self.ensure_one()
if self.x_fc_sync_source or not self.x_fc_send_client_updates:
if not self.x_fc_send_client_updates:
return False
if not self.partner_id or not self.partner_id.email:
return False
@@ -2457,7 +2361,7 @@ class FusionTechnicianTask(models.Model):
'address_lat', 'address_lng', 'address_display',
'time_start', 'time_end', 'time_start_display', 'time_end_display',
'status', 'scheduled_date', 'travel_time_minutes',
'x_fc_sync_client_name', 'x_fc_is_shadow', 'x_fc_sync_source'],
],
order='scheduled_date asc NULLS LAST, time_start asc',
limit=500,
)
@@ -2802,7 +2706,6 @@ class FusionTechnicianTask(models.Model):
('status', '=', 'scheduled'),
('time_start', '<', current_hour),
('x_fc_late_notified', '=', False),
('x_fc_sync_source', '=', False),
('technician_id', '!=', False),
])