Initial commit
This commit is contained in:
214
fusion_claims/wizard/schedule_assessment_wizard.py
Normal file
214
fusion_claims/wizard/schedule_assessment_wizard.py
Normal file
@@ -0,0 +1,214 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024-2025 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import datetime, timedelta
|
||||
from markupsafe import Markup
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ScheduleAssessmentWizard(models.TransientModel):
|
||||
"""Wizard to schedule an assessment and create a calendar event."""
|
||||
_name = 'fusion_claims.schedule.assessment.wizard'
|
||||
_description = 'Schedule Assessment Wizard'
|
||||
|
||||
sale_order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
# Assessment Details
|
||||
assessment_date = fields.Date(
|
||||
string='Assessment Date',
|
||||
required=True,
|
||||
default=fields.Date.context_today,
|
||||
)
|
||||
assessment_time = fields.Float(
|
||||
string='Assessment Time',
|
||||
required=True,
|
||||
default=9.0, # 9:00 AM
|
||||
help='Time in 24-hour format (e.g., 14.5 = 2:30 PM)',
|
||||
)
|
||||
duration = fields.Float(
|
||||
string='Duration (hours)',
|
||||
required=True,
|
||||
default=2.0,
|
||||
)
|
||||
|
||||
# Location and Notes
|
||||
location = fields.Char(
|
||||
string='Location',
|
||||
help='Assessment location (client address, etc.)',
|
||||
)
|
||||
notes = fields.Text(
|
||||
string='Notes',
|
||||
help='Additional notes for the assessment',
|
||||
)
|
||||
|
||||
# Attendees
|
||||
assessor_id = fields.Many2one(
|
||||
'res.users',
|
||||
string='Assessor',
|
||||
default=lambda self: self.env.user,
|
||||
required=True,
|
||||
help='User who will conduct the assessment',
|
||||
)
|
||||
|
||||
# Calendar options
|
||||
create_calendar_event = fields.Boolean(
|
||||
string='Create Calendar Event',
|
||||
default=True,
|
||||
help='Create an event in Odoo calendar',
|
||||
)
|
||||
send_reminder = fields.Boolean(
|
||||
string='Send Reminder',
|
||||
default=True,
|
||||
help='Send email reminder before the assessment',
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
active_id = self._context.get('active_id')
|
||||
if active_id:
|
||||
order = self.env['sale.order'].browse(active_id)
|
||||
res['sale_order_id'] = order.id
|
||||
# Pre-fill location with client address if available
|
||||
if order.partner_id:
|
||||
partner = order.partner_id
|
||||
address_parts = [
|
||||
partner.street,
|
||||
partner.street2,
|
||||
partner.city,
|
||||
partner.state_id.name if partner.state_id else None,
|
||||
partner.zip,
|
||||
]
|
||||
res['location'] = ', '.join(filter(None, address_parts))
|
||||
return res
|
||||
|
||||
def action_schedule(self):
|
||||
"""Schedule the assessment and optionally create a calendar event."""
|
||||
self.ensure_one()
|
||||
|
||||
order = self.sale_order_id
|
||||
|
||||
# Validate status
|
||||
if order.x_fc_adp_application_status != 'quotation':
|
||||
raise UserError("Can only schedule assessment from 'Quotation' status.")
|
||||
|
||||
# Calculate datetime
|
||||
assessment_datetime = datetime.combine(
|
||||
self.assessment_date,
|
||||
datetime.min.time()
|
||||
) + timedelta(hours=self.assessment_time)
|
||||
|
||||
# Create calendar event if requested
|
||||
calendar_event = None
|
||||
if self.create_calendar_event:
|
||||
calendar_event = self._create_calendar_event(assessment_datetime)
|
||||
|
||||
# Update sale order
|
||||
order.with_context(skip_status_validation=True).write({
|
||||
'x_fc_adp_application_status': 'assessment_scheduled',
|
||||
'x_fc_assessment_start_date': self.assessment_date,
|
||||
})
|
||||
|
||||
# Post to chatter
|
||||
time_str = self._format_time(self.assessment_time)
|
||||
event_link = ''
|
||||
if calendar_event:
|
||||
event_link = f'<p style="margin: 4px 0 0 0;"><a href="/web#id={calendar_event.id}&model=calendar.event&view_type=form" target="_blank"><i class="fa fa-calendar"/> View Calendar Event</a></p>'
|
||||
|
||||
order.message_post(
|
||||
body=Markup(
|
||||
'<div style="background: #e8f4fd; border-left: 4px solid #17a2b8; padding: 12px; margin: 8px 0; border-radius: 4px;">'
|
||||
'<h4 style="color: #17a2b8; margin: 0 0 8px 0;"><i class="fa fa-calendar"/> Assessment Scheduled</h4>'
|
||||
f'<p style="margin: 0;"><strong>Date:</strong> {self.assessment_date.strftime("%B %d, %Y")}</p>'
|
||||
f'<p style="margin: 4px 0 0 0;"><strong>Time:</strong> {time_str}</p>'
|
||||
f'<p style="margin: 4px 0 0 0;"><strong>Duration:</strong> {self.duration} hour(s)</p>'
|
||||
f'<p style="margin: 4px 0 0 0;"><strong>Assessor:</strong> {self.assessor_id.name}</p>'
|
||||
f'{f"<p style=\'margin: 4px 0 0 0;\'><strong>Location:</strong> {self.location}</p>" if self.location else ""}'
|
||||
f'{f"<p style=\'margin: 4px 0 0 0;\'><strong>Notes:</strong> {self.notes}</p>" if self.notes else ""}'
|
||||
f'{event_link}'
|
||||
'</div>'
|
||||
),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def _create_calendar_event(self, start_datetime):
|
||||
"""Create a calendar event for the assessment."""
|
||||
order = self.sale_order_id
|
||||
|
||||
end_datetime = start_datetime + timedelta(hours=self.duration)
|
||||
|
||||
# Build attendee list
|
||||
partner_ids = [self.assessor_id.partner_id.id]
|
||||
if order.partner_id:
|
||||
partner_ids.append(order.partner_id.id)
|
||||
|
||||
event_vals = {
|
||||
'name': f'ADP Assessment - {order.partner_id.name} ({order.name})',
|
||||
'start': start_datetime,
|
||||
'stop': end_datetime,
|
||||
'allday': False,
|
||||
'location': self.location or '',
|
||||
'description': self._build_event_description(),
|
||||
'partner_ids': [(6, 0, partner_ids)],
|
||||
'user_id': self.assessor_id.id,
|
||||
}
|
||||
|
||||
# Add alarm if reminder requested
|
||||
if self.send_reminder:
|
||||
# Find or create a 1-day email reminder
|
||||
alarm = self.env['calendar.alarm'].search([
|
||||
('alarm_type', '=', 'email'),
|
||||
('duration', '=', 1),
|
||||
('interval', '=', 'days'),
|
||||
], limit=1)
|
||||
if not alarm:
|
||||
alarm = self.env['calendar.alarm'].create({
|
||||
'name': '1 Day Before',
|
||||
'alarm_type': 'email',
|
||||
'duration': 1,
|
||||
'interval': 'days',
|
||||
})
|
||||
event_vals['alarm_ids'] = [(6, 0, [alarm.id])]
|
||||
|
||||
return self.env['calendar.event'].create(event_vals)
|
||||
|
||||
def _build_event_description(self):
|
||||
"""Build the calendar event description."""
|
||||
order = self.sale_order_id
|
||||
lines = [
|
||||
f"ADP Assessment for {order.partner_id.name}",
|
||||
f"Sale Order: {order.name}",
|
||||
"",
|
||||
]
|
||||
if order.x_fc_reason_for_application:
|
||||
reason_label = dict(order._fields['x_fc_reason_for_application'].selection or []).get(
|
||||
order.x_fc_reason_for_application, 'N/A'
|
||||
)
|
||||
lines.append(f"Reason: {reason_label}")
|
||||
if self.notes:
|
||||
lines.append("")
|
||||
lines.append(f"Notes: {self.notes}")
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _format_time(self, time_float):
|
||||
"""Convert float time (e.g., 14.5) to readable format (2:30 PM)."""
|
||||
hours = int(time_float)
|
||||
minutes = int((time_float - hours) * 60)
|
||||
period = 'AM' if hours < 12 else 'PM'
|
||||
display_hours = hours if hours <= 12 else hours - 12
|
||||
if display_hours == 0:
|
||||
display_hours = 12
|
||||
return f"{display_hours}:{minutes:02d} {period}"
|
||||
Reference in New Issue
Block a user