From e10bf9d8fd17f7c53227b12ecada754c25986e78 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sun, 12 Apr 2026 20:26:23 -0400 Subject: [PATCH] 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) --- .../fusion_tasks/models/__init__.py | 1 - .../fusion_tasks/models/res_users.py | 6 - .../fusion_tasks/models/technician_task.py | 123 ++---------------- 3 files changed, 13 insertions(+), 117 deletions(-) diff --git a/fusion-plating/fusion_tasks/models/__init__.py b/fusion-plating/fusion_tasks/models/__init__.py index ecfb3fa6..e8e94d6a 100644 --- a/fusion-plating/fusion_tasks/models/__init__.py +++ b/fusion-plating/fusion_tasks/models/__init__.py @@ -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 diff --git a/fusion-plating/fusion_tasks/models/res_users.py b/fusion-plating/fusion_tasks/models/res_users.py index 7d82b551..714e8eba 100644 --- a/fusion-plating/fusion_tasks/models/res_users.py +++ b/fusion-plating/fusion_tasks/models/res_users.py @@ -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, - ) diff --git a/fusion-plating/fusion_tasks/models/technician_task.py b/fusion-plating/fusion_tasks/models/technician_task.py index 768d9ca4..71e16132 100644 --- a/fusion-plating/fusion_tasks/models/technician_task.py +++ b/fusion-plating/fusion_tasks/models/technician_task.py @@ -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), ])