Initial commit

This commit is contained in:
gsinghpal
2026-02-22 01:22:18 -05:00
commit 5200d5baf0
2394 changed files with 386834 additions and 0 deletions

View 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}"