Initial commit
This commit is contained in:
185
fusion_claims/wizard/ready_to_bill_wizard.py
Normal file
185
fusion_claims/wizard/ready_to_bill_wizard.py
Normal file
@@ -0,0 +1,185 @@
|
||||
# -*- 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 date
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ReadyToBillWizard(models.TransientModel):
|
||||
"""Wizard to collect Proof of Delivery and delivery date before marking as Ready to Bill."""
|
||||
_name = 'fusion_claims.ready.to.bill.wizard'
|
||||
_description = 'Ready to Bill Wizard'
|
||||
|
||||
# ==========================================================================
|
||||
# FIELDS
|
||||
# ==========================================================================
|
||||
sale_order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
# Delivery Information
|
||||
delivery_date = fields.Date(
|
||||
string='Delivery Date',
|
||||
required=True,
|
||||
default=fields.Date.today,
|
||||
help='Date the product was delivered to the client',
|
||||
)
|
||||
|
||||
# Proof of Delivery
|
||||
proof_of_delivery = fields.Binary(
|
||||
string='Proof of Delivery',
|
||||
required=True,
|
||||
help='Upload the Proof of Delivery document (PDF)',
|
||||
)
|
||||
proof_of_delivery_filename = fields.Char(
|
||||
string='POD Filename',
|
||||
)
|
||||
|
||||
# Optional notes
|
||||
notes = fields.Text(
|
||||
string='Notes',
|
||||
help='Optional notes about the delivery',
|
||||
)
|
||||
|
||||
# Info fields
|
||||
has_existing_pod = fields.Boolean(
|
||||
string='Has Existing POD',
|
||||
compute='_compute_existing_data',
|
||||
)
|
||||
has_existing_date = fields.Boolean(
|
||||
string='Has Existing Date',
|
||||
compute='_compute_existing_data',
|
||||
)
|
||||
existing_pod_filename = fields.Char(
|
||||
string='Existing POD Filename',
|
||||
compute='_compute_existing_data',
|
||||
)
|
||||
existing_delivery_date = fields.Date(
|
||||
string='Existing Delivery Date',
|
||||
compute='_compute_existing_data',
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# COMPUTED METHODS
|
||||
# ==========================================================================
|
||||
@api.depends('sale_order_id')
|
||||
def _compute_existing_data(self):
|
||||
for wizard in self:
|
||||
order = wizard.sale_order_id
|
||||
wizard.has_existing_pod = bool(order.x_fc_proof_of_delivery)
|
||||
wizard.has_existing_date = bool(order.x_fc_adp_delivery_date)
|
||||
wizard.existing_pod_filename = order.x_fc_proof_of_delivery_filename or ''
|
||||
wizard.existing_delivery_date = order.x_fc_adp_delivery_date
|
||||
|
||||
# ==========================================================================
|
||||
# DEFAULT GET
|
||||
# ==========================================================================
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
|
||||
active_id = self._context.get('active_id')
|
||||
if not active_id:
|
||||
return res
|
||||
|
||||
order = self.env['sale.order'].browse(active_id)
|
||||
res['sale_order_id'] = order.id
|
||||
|
||||
# Pre-fill delivery date if already set
|
||||
if order.x_fc_adp_delivery_date:
|
||||
res['delivery_date'] = order.x_fc_adp_delivery_date
|
||||
|
||||
# Pre-fill POD if already uploaded
|
||||
if order.x_fc_proof_of_delivery:
|
||||
res['proof_of_delivery'] = order.x_fc_proof_of_delivery
|
||||
res['proof_of_delivery_filename'] = order.x_fc_proof_of_delivery_filename
|
||||
|
||||
return res
|
||||
|
||||
# ==========================================================================
|
||||
# ACTION METHODS
|
||||
# ==========================================================================
|
||||
def action_mark_ready_to_bill(self):
|
||||
"""Validate and mark the order as Ready to Bill."""
|
||||
self.ensure_one()
|
||||
|
||||
order = self.sale_order_id
|
||||
|
||||
# Validate status
|
||||
if order.x_fc_adp_application_status not in ('approved', 'approved_deduction'):
|
||||
raise UserError(
|
||||
"Order can only be marked as 'Ready to Bill' from 'Approved' status."
|
||||
)
|
||||
|
||||
# Validate POD file type
|
||||
if self.proof_of_delivery_filename:
|
||||
if not self.proof_of_delivery_filename.lower().endswith('.pdf'):
|
||||
raise UserError(
|
||||
f"Proof of Delivery must be a PDF file.\n"
|
||||
f"Uploaded: '{self.proof_of_delivery_filename}'"
|
||||
)
|
||||
|
||||
# Check device verification
|
||||
if not order.x_fc_device_verification_complete:
|
||||
raise UserError(
|
||||
"Device approval verification must be completed before marking as Ready to Bill.\n\n"
|
||||
"Please verify which devices were approved by ADP using the 'Mark as Approved' button first."
|
||||
)
|
||||
|
||||
# Update the order
|
||||
order.with_context(skip_status_validation=True).write({
|
||||
'x_fc_adp_application_status': 'ready_bill',
|
||||
'x_fc_adp_delivery_date': self.delivery_date,
|
||||
'x_fc_proof_of_delivery': self.proof_of_delivery,
|
||||
'x_fc_proof_of_delivery_filename': self.proof_of_delivery_filename,
|
||||
})
|
||||
|
||||
# Create attachment for POD to post in chatter
|
||||
pod_attachment = self.env['ir.attachment'].create({
|
||||
'name': self.proof_of_delivery_filename or 'Proof_of_Delivery.pdf',
|
||||
'datas': self.proof_of_delivery,
|
||||
'res_model': 'sale.order',
|
||||
'res_id': order.id,
|
||||
})
|
||||
|
||||
# Post to chatter
|
||||
from markupsafe import Markup
|
||||
|
||||
notes_html = ''
|
||||
if self.notes:
|
||||
notes_html = f'<p style="margin: 8px 0 0 0;"><strong>Notes:</strong> {self.notes}</p>'
|
||||
|
||||
order.message_post(
|
||||
body=Markup(
|
||||
'<div style="background: #d4edda; border-left: 4px solid #28a745; padding: 12px; margin: 8px 0; border-radius: 4px;">'
|
||||
'<h4 style="color: #28a745; margin: 0 0 8px 0;"><i class="fa fa-dollar"/> Ready to Bill</h4>'
|
||||
f'<p style="margin: 0;"><strong>Delivery Date:</strong> {self.delivery_date.strftime("%B %d, %Y")}</p>'
|
||||
f'<p style="margin: 4px 0 0 0;"><strong>Proof of Delivery:</strong> {self.proof_of_delivery_filename}</p>'
|
||||
f'{notes_html}'
|
||||
f'<p style="margin: 8px 0 0 0; color: #666; font-size: 0.9em;">Marked by {self.env.user.name}</p>'
|
||||
'</div>'
|
||||
),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
attachment_ids=[pod_attachment.id],
|
||||
)
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.client',
|
||||
'tag': 'display_notification',
|
||||
'params': {
|
||||
'title': _('Ready to Bill'),
|
||||
'message': _('Order marked as Ready to Bill. POD attached.'),
|
||||
'type': 'success',
|
||||
'sticky': False,
|
||||
'next': {'type': 'ir.actions.act_window_close'},
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user