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 -*-
"""
Ready for Delivery Wizard
Wizard to assign delivery technicians and mark order as Ready for Delivery.
"""
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from markupsafe import Markup
import logging
_logger = logging.getLogger(__name__)
class ReadyForDeliveryWizard(models.TransientModel):
_name = 'fusion.ready.for.delivery.wizard'
_description = 'Ready for Delivery Wizard'
sale_order_id = fields.Many2one(
'sale.order',
string='Sale Order',
required=True,
readonly=True,
)
partner_id = fields.Many2one(
'res.partner',
string='Client',
related='sale_order_id.partner_id',
readonly=True,
)
claim_number = fields.Char(
string='Claim Number',
related='sale_order_id.x_fc_claim_number',
readonly=True,
)
is_early_delivery = fields.Boolean(
string='Early Delivery',
related='sale_order_id.x_fc_early_delivery',
readonly=True,
help='This delivery is before ADP approval',
)
current_status = fields.Selection(
related='sale_order_id.x_fc_adp_application_status',
string='Current Status',
readonly=True,
)
# Technician Assignment
technician_ids = fields.Many2many(
'res.users',
'ready_delivery_wizard_technician_rel',
'wizard_id',
'user_id',
string='Delivery Technicians',
required=True,
help='Select one or more field technicians for this delivery',
)
# Scheduling
scheduled_datetime = fields.Datetime(
string='Scheduled Delivery Date/Time',
help='Optional: When is the delivery scheduled?',
)
# Delivery Address
delivery_address = fields.Text(
string='Delivery Address',
compute='_compute_delivery_address',
readonly=True,
)
# Notes
notes = fields.Text(
string='Delivery Notes',
help='Any special instructions for the delivery technicians',
)
@api.depends('sale_order_id')
def _compute_delivery_address(self):
"""Compute delivery address from partner shipping address."""
for wizard in self:
order = wizard.sale_order_id
if order and order.partner_shipping_id:
addr = order.partner_shipping_id
parts = [addr.street, addr.street2, addr.city, addr.state_id.name if addr.state_id else '', addr.zip]
wizard.delivery_address = ', '.join([p for p in parts if p])
elif order and order.partner_id:
addr = order.partner_id
parts = [addr.street, addr.street2, addr.city, addr.state_id.name if addr.state_id else '', addr.zip]
wizard.delivery_address = ', '.join([p for p in parts if p])
else:
wizard.delivery_address = ''
def action_confirm(self):
"""Confirm and mark as Ready for Delivery."""
self.ensure_one()
order = self.sale_order_id
if not self.technician_ids:
raise UserError(_("Please select at least one delivery technician."))
# Get technician names for chatter message
technician_names = ', '.join(self.technician_ids.mapped('name'))
user_name = self.env.user.name
# Update the sale order
order.with_context(skip_status_validation=True).write({
'x_fc_adp_application_status': 'ready_delivery',
'x_fc_delivery_technician_ids': [(6, 0, self.technician_ids.ids)],
'x_fc_ready_for_delivery_date': fields.Datetime.now(),
'x_fc_scheduled_delivery_datetime': self.scheduled_datetime,
})
# Build chatter message
scheduled_str = ''
if self.scheduled_datetime:
scheduled_str = f'<li><strong>Scheduled:</strong> {self.scheduled_datetime.strftime("%B %d, %Y at %I:%M %p")}</li>'
notes_str = ''
if self.notes:
notes_str = f'<hr><p class="mb-0"><strong>Delivery Notes:</strong> {self.notes}</p>'
early_badge = ''
if self.is_early_delivery:
early_badge = ' <span class="badge bg-warning text-dark">Early Delivery</span>'
chatter_body = Markup(f'''
<div class="alert alert-success" role="alert">
<h5 class="alert-heading"><i class="fa fa-truck"></i> Ready for Delivery{early_badge}</h5>
<ul>
<li><strong>Marked By:</strong> {user_name}</li>
<li><strong>Technician(s):</strong> {technician_names}</li>
{scheduled_str}
<li><strong>Delivery Address:</strong> {self.delivery_address or 'N/A'}</li>
</ul>
{notes_str}
</div>
''')
order.message_post(
body=chatter_body,
message_type='notification',
subtype_xmlid='mail.mt_note',
)
# Send email notifications
order._send_ready_for_delivery_email(
technicians=self.technician_ids,
scheduled_datetime=self.scheduled_datetime,
notes=self.notes,
)
# Auto-create technician tasks for each assigned technician
self._create_technician_tasks(order)
return {'type': 'ir.actions.act_window_close'}
def _create_technician_tasks(self, order):
"""Create a technician task for each assigned technician.
The task model's create() method auto-populates address fields
from the linked sale order's shipping address when address_street
is not explicitly provided, so we intentionally omit address here.
"""
Task = self.env['fusion.technician.task']
scheduled_date = False
time_start = 9.0 # default 9:00 AM
if self.scheduled_datetime:
scheduled_date = self.scheduled_datetime.date()
time_start = self.scheduled_datetime.hour + (self.scheduled_datetime.minute / 60.0)
else:
scheduled_date = fields.Date.context_today(self)
created_tasks = self.env['fusion.technician.task']
for tech in self.technician_ids:
vals = {
'technician_id': tech.id,
'sale_order_id': order.id,
'task_type': 'delivery',
'scheduled_date': scheduled_date,
'time_start': time_start,
'time_end': time_start + 1.0, # 1 hour default
'partner_id': order.partner_id.id,
'description': self.notes or '',
'pod_required': True,
}
task = Task.create(vals)
created_tasks |= task
_logger.info("Created delivery task %s for %s on order %s", task.name, tech.name, order.name)
# Post a summary of created tasks back to the sale order chatter
if created_tasks:
task_lines = ''
for t in created_tasks:
task_url = f'/web#id={t.id}&model=fusion.technician.task&view_type=form'
time_str = t.time_start_12h or ''
task_lines += (
f'<li><a href="{task_url}">{t.name}</a> - '
f'{t.technician_id.name} '
f'({t.scheduled_date.strftime("%b %d, %Y") if t.scheduled_date else "TBD"}'
f'{" at " + time_str if time_str else ""})</li>'
)
summary = Markup(
'<div class="alert alert-info" style="margin:0;">'
'<strong><i class="fa fa-wrench"></i> Delivery Tasks Created</strong>'
'<ul style="margin-bottom:0;">%s</ul>'
'</div>'
) % Markup(task_lines)
order.message_post(
body=summary,
message_type='notification',
subtype_xmlid='mail.mt_note',
)