diff --git a/fusion-plating/fusion_tasks/__init__.py b/fusion-plating/fusion_tasks/__init__.py index 86043519..01f9ce74 100644 --- a/fusion-plating/fusion_tasks/__init__.py +++ b/fusion-plating/fusion_tasks/__init__.py @@ -14,13 +14,12 @@ def _fusion_tasks_post_init(env): """ ICP = env['ir.config_parameter'].sudo() defaults = { - 'fusion_claims.google_maps_api_key': '', - 'fusion_claims.store_open_hour': '9.0', - 'fusion_claims.store_close_hour': '18.0', - 'fusion_claims.push_enabled': 'False', - 'fusion_claims.push_advance_minutes': '30', - 'fusion_claims.sync_instance_id': '', - 'fusion_claims.technician_start_address': '', + 'fusion_tasks.google_maps_api_key': '', + 'fusion_tasks.store_open_hour': '9.0', + 'fusion_tasks.store_close_hour': '18.0', + 'fusion_tasks.push_enabled': 'False', + 'fusion_tasks.push_advance_minutes': '30', + 'fusion_tasks.technician_start_address': '', } for key, default_value in defaults.items(): if not ICP.get_param(key): diff --git a/fusion-plating/fusion_tasks/__manifest__.py b/fusion-plating/fusion_tasks/__manifest__.py index 717e31ce..8812e166 100644 --- a/fusion-plating/fusion_tasks/__manifest__.py +++ b/fusion-plating/fusion_tasks/__manifest__.py @@ -3,25 +3,27 @@ # License OPL-1 (Odoo Proprietary License v1.0) { - 'name': 'Fusion Tasks', + 'name': 'Fusion Plating — Delivery Tasks', 'version': '19.0.1.0.0', '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.', 'website': 'https://www.nexasystems.ca', - 'license': 'OPL-1', + 'license': 'LGPL-3', 'depends': [ 'base', 'mail', - 'calendar', - 'sales_team', + 'hr', + 'fusion_plating_logistics', ], 'data': [ 'security/security.xml', 'security/ir.model.access.csv', 'data/ir_cron_data.xml', 'views/technician_task_views.xml', - 'views/task_sync_views.xml', 'views/technician_location_views.xml', 'views/res_config_settings_views.xml', ], diff --git a/fusion-plating/fusion_tasks/data/ir_config_parameter_data.xml b/fusion-plating/fusion_tasks/data/ir_config_parameter_data.xml index 6ca041be..4f72dfe1 100644 --- a/fusion-plating/fusion_tasks/data/ir_config_parameter_data.xml +++ b/fusion-plating/fusion_tasks/data/ir_config_parameter_data.xml @@ -4,45 +4,38 @@ Default configuration parameters for Fusion Tasks. noupdate="1" ensures these are ONLY set on first install. forcecreate="false" prevents errors if keys already exist. - Keys use fusion_claims.* prefix to preserve existing data. --> - fusion_claims.google_maps_api_key + fusion_tasks.google_maps_api_key - fusion_claims.store_open_hour + fusion_tasks.store_open_hour 9.0 - fusion_claims.store_close_hour + fusion_tasks.store_close_hour 18.0 - fusion_claims.push_enabled + fusion_tasks.push_enabled False - fusion_claims.push_advance_minutes + fusion_tasks.push_advance_minutes 30 - - - fusion_claims.sync_instance_id - - - - fusion_claims.technician_start_address + fusion_tasks.technician_start_address diff --git a/fusion-plating/fusion_tasks/data/ir_cron_data.xml b/fusion-plating/fusion_tasks/data/ir_cron_data.xml index abdd009b..bcc49902 100644 --- a/fusion-plating/fusion_tasks/data/ir_cron_data.xml +++ b/fusion-plating/fusion_tasks/data/ir_cron_data.xml @@ -1,7 +1,7 @@ @@ -28,29 +28,6 @@ True - - - Fusion Tasks: Sync Remote Tasks (Pull) - - code - model._cron_pull_remote_tasks() - 2 - minutes - True - - - - - Fusion Tasks: Cleanup Old Shadow Tasks - - code - model._cron_cleanup_old_shadows() - 1 - days - True - - - Fusion Tasks: Check Late Technician Arrivals diff --git a/fusion-plating/fusion_tasks/models/email_builder_mixin.py b/fusion-plating/fusion_tasks/models/email_builder_mixin.py index a762dafe..ae3dc304 100644 --- a/fusion-plating/fusion_tasks/models/email_builder_mixin.py +++ b/fusion-plating/fusion_tasks/models/email_builder_mixin.py @@ -237,5 +237,5 @@ class FusionEmailBuilderMixin(models.AbstractModel): def _email_is_enabled(self): """Check if email notifications are enabled in settings.""" 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') diff --git a/fusion-plating/fusion_tasks/models/res_config_settings.py b/fusion-plating/fusion_tasks/models/res_config_settings.py index ec177b13..b5641f32 100644 --- a/fusion-plating/fusion_tasks/models/res_config_settings.py +++ b/fusion-plating/fusion_tasks/models/res_config_settings.py @@ -11,7 +11,7 @@ class ResConfigSettings(models.TransientModel): # Google Maps API Settings fc_google_maps_api_key = fields.Char( 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', ) fc_google_review_url = fields.Char( @@ -23,27 +23,27 @@ class ResConfigSettings(models.TransientModel): # Technician Management fc_store_open_hour = fields.Float( 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)', ) fc_store_close_hour = fields.Float( 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)', ) fc_google_distance_matrix_enabled = fields.Boolean( 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', ) fc_technician_start_address = fields.Char( 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)', ) fc_location_retention_days = fields.Char( 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. ' 'Leave empty = 30 days (1 month). ' '0 = delete at end of each day. ' @@ -53,21 +53,21 @@ class ResConfigSettings(models.TransientModel): # Web Push Notifications fc_push_enabled = fields.Boolean( string='Enable Push Notifications', - config_parameter='fusion_claims.push_enabled', + config_parameter='fusion_tasks.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', + config_parameter='fusion_tasks.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', + config_parameter='fusion_tasks.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', + config_parameter='fusion_tasks.push_advance_minutes', help='Send push notifications this many minutes before a scheduled task', ) diff --git a/fusion-plating/fusion_tasks/models/res_partner.py b/fusion-plating/fusion_tasks/models/res_partner.py index 72f8e978..d8942127 100644 --- a/fusion-plating/fusion_tasks/models/res_partner.py +++ b/fusion-plating/fusion_tasks/models/res_partner.py @@ -29,7 +29,7 @@ class ResPartner(models.Model): if not address or not address.strip(): return 0.0, 0.0 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: return 0.0, 0.0 try: diff --git a/fusion-plating/fusion_tasks/models/technician_location.py b/fusion-plating/fusion_tasks/models/technician_location.py index f2c79b2b..838ce75a 100644 --- a/fusion-plating/fusion_tasks/models/technician_location.py +++ b/fusion-plating/fusion_tasks/models/technician_location.py @@ -84,7 +84,7 @@ class FusionTechnicianLocation(models.Model): """) rows = self.env.cr.dictfetchall() local_id = self.env['ir.config_parameter'].sudo().get_param( - 'fusion_claims.sync_instance_id', '') + 'fusion_tasks.sync_instance_id', '') result = [] for row in rows: user = self.env['res.users'].sudo().browse(row['user_id']) @@ -104,13 +104,13 @@ class FusionTechnicianLocation(models.Model): def _cron_cleanup_old_locations(self): """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) - "0" => delete at end of day (keep today only) - "1" .. "N" => keep for N days """ 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 == '': retention_days = 30 # default: 1 month diff --git a/fusion-plating/fusion_tasks/models/technician_task.py b/fusion-plating/fusion_tasks/models/technician_task.py index 71e16132..356a74fc 100644 --- a/fusion-plating/fusion_tasks/models/technician_task.py +++ b/fusion-plating/fusion_tasks/models/technician_task.py @@ -52,11 +52,11 @@ class FusionTechnicianTask(models.Model): """Return (open_hour, close_hour) from settings. Defaults 9.0 / 18.0.""" ICP = self.env['ir.config_parameter'].sudo() 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): open_h = 9.0 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): close_h = 18.0 return (open_h, close_h) @@ -938,7 +938,7 @@ class FusionTechnicianTask(models.Model): Returns travel time in minutes, or 0 if unavailable.""" try: 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: return 0 @@ -1385,7 +1385,7 @@ class FusionTechnicianTask(models.Model): def _create_vals_fill(self, vals): """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. """ 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): """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. """ pass @@ -1556,12 +1556,12 @@ class FusionTechnicianTask(models.Model): def _post_task_created_to_linked_order(self): """Hook: post task creation notice to linked order chatter. - Override in fusion_claims.""" + Override in fusion_tasks.""" pass def _mark_sale_order_ready_for_delivery(self): """Hook: mark linked sale orders as ready for delivery. - Override in fusion_claims.""" + Override in fusion_tasks.""" pass def _recalculate_day_travel_chains(self): @@ -1584,7 +1584,7 @@ class FusionTechnicianTask(models.Model): Priority: 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 ''. """ 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() # Fallback to company default 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): """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. """ 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: return api_key = self._get_google_maps_api_key() @@ -1731,7 +1731,7 @@ class FusionTechnicianTask(models.Model): """ self.ensure_one() 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 tech_id = self.technician_id.id if not tech_id: @@ -1752,7 +1752,7 @@ class FusionTechnicianTask(models.Model): """ self.ensure_one() 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 tech_id = self.technician_id.id @@ -1913,12 +1913,12 @@ class FusionTechnicianTask(models.Model): def _check_completion_requirements(self): """Hook: check additional requirements before task completion. - Override in fusion_claims for rental inspection checks.""" + Override in subclass for rental inspection checks.""" pass def _on_complete_extra(self): """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 def action_cancel_task(self): @@ -1933,7 +1933,7 @@ class FusionTechnicianTask(models.Model): def _on_cancel_extra(self): """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() def action_reschedule(self): @@ -1985,7 +1985,7 @@ class FusionTechnicianTask(models.Model): def _post_completion_to_linked_order(self): """Hook: post completion notes to linked order chatter. - Override in fusion_claims.""" + Override in fusion_tasks.""" pass def _notify_scheduler_on_completion(self): @@ -2086,15 +2086,15 @@ class FusionTechnicianTask(models.Model): return {'to': to_emails, 'cc': list(set(cc_emails))} 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 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 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 # ------------------------------------------------------------------ @@ -2105,14 +2105,14 @@ class FusionTechnicianTask(models.Model): """Return a record that has the _email_build 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 def _is_email_notifications_enabled(self): """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. """ return True @@ -2120,7 +2120,7 @@ class FusionTechnicianTask(models.Model): def _get_linked_order(self): """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. """ return False @@ -2336,7 +2336,7 @@ class FusionTechnicianTask(models.Model): def _get_google_maps_api_key(self): """Get the Google Maps API key from config.""" return self.env['ir.config_parameter'].sudo().get_param( - 'fusion_claims.google_maps_api_key', '' + 'fusion_tasks.google_maps_api_key', '' ) @api.model @@ -2347,9 +2347,9 @@ class FusionTechnicianTask(models.Model): domain: optional extra domain from the search bar filters. """ 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( - 'fusion_claims.sync_instance_id', '') + 'fusion_tasks.sync_instance_id', '') base_domain = [ ('status', 'not in', ['cancelled']), ] @@ -2399,7 +2399,7 @@ class FusionTechnicianTask(models.Model): hq_address = ( self.env['ir.config_parameter'].sudo() - .get_param('fusion_claims.technician_start_address', '') or '' + .get_param('fusion_tasks.technician_start_address', '') or '' ).strip() 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). """ 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'): return @@ -2801,8 +2801,8 @@ class FusionTechnicianTask(models.Model): return ICP = self.env['ir.config_parameter'].sudo() - vapid_private = ICP.get_param('fusion_claims.vapid_private_key', '') - vapid_public = ICP.get_param('fusion_claims.vapid_public_key', '') + vapid_private = ICP.get_param('fusion_tasks.vapid_private_key', '') + vapid_public = ICP.get_param('fusion_tasks.vapid_public_key', '') if not vapid_private or not vapid_public: _logger.warning("VAPID keys not configured, cannot send push notification") return @@ -2850,10 +2850,10 @@ class FusionTechnicianTask(models.Model): def _cron_send_push_notifications(self): """Cron: Send push notifications for upcoming tasks.""" 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 - 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() tasks = self.search([ diff --git a/fusion-plating/fusion_tasks/security/ir.model.access.csv b/fusion-plating/fusion_tasks/security/ir.model.access.csv index dad063b7..45ef3ae3 100644 --- a/fusion-plating/fusion_tasks/security/ir.model.access.csv +++ b/fusion-plating/fusion_tasks/security/ir.model.access.csv @@ -1,12 +1,10 @@ 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_manager,fusion.technician.task.manager,model_fusion_technician_task,sales_team.group_sale_manager,1,1,1,1 +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,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_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_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_user,fusion.technician.location.user,model_fusion_technician_location,sales_team.group_sale_salesman,1,0,0,0 +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,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_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 diff --git a/fusion-plating/fusion_tasks/security/security.xml b/fusion-plating/fusion_tasks/security/security.xml index 7edf97aa..2505eafc 100644 --- a/fusion-plating/fusion_tasks/security/security.xml +++ b/fusion-plating/fusion_tasks/security/security.xml @@ -37,7 +37,7 @@ Technician Task: Manager Full Access [(1, '=', 1)] - + @@ -49,7 +49,7 @@ Technician Task: Sales User Access [(1, '=', 1)] - +