Initial commit
This commit is contained in:
237
fusion_claims/models/submission_history.py
Normal file
237
fusion_claims/models/submission_history.py
Normal file
@@ -0,0 +1,237 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2024-2026 Nexa Systems Inc.
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
# Part of the Fusion Claim Assistant product family.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from markupsafe import Markup
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FusionSubmissionHistory(models.Model):
|
||||
"""Track submission history for ADP applications.
|
||||
|
||||
Each record represents one submission or resubmission to ADP,
|
||||
including the documents submitted, the result, and any rejection reasons.
|
||||
"""
|
||||
_name = 'fusion.submission.history'
|
||||
_description = 'ADP Submission History'
|
||||
_order = 'submission_date desc, id desc'
|
||||
_rec_name = 'display_name'
|
||||
|
||||
# ==========================================================================
|
||||
# RELATIONSHIPS
|
||||
# ==========================================================================
|
||||
sale_order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# SUBMISSION DETAILS
|
||||
# ==========================================================================
|
||||
display_name = fields.Char(
|
||||
string='Display Name',
|
||||
compute='_compute_display_name',
|
||||
store=True,
|
||||
)
|
||||
|
||||
submission_number = fields.Integer(
|
||||
string='Submission #',
|
||||
default=1,
|
||||
help='Sequence number for this submission (1 = first submission, 2+ = resubmissions)',
|
||||
)
|
||||
|
||||
submission_type = fields.Selection(
|
||||
selection=[
|
||||
('initial', 'Initial Submission'),
|
||||
('resubmission', 'Resubmission'),
|
||||
('correction', 'Correction'),
|
||||
],
|
||||
string='Type',
|
||||
default='initial',
|
||||
)
|
||||
|
||||
submission_date = fields.Date(
|
||||
string='Submission Date',
|
||||
default=fields.Date.today,
|
||||
required=True,
|
||||
)
|
||||
|
||||
submitted_by_id = fields.Many2one(
|
||||
'res.users',
|
||||
string='Submitted By',
|
||||
default=lambda self: self.env.user,
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# DOCUMENTS SUBMITTED (copies at time of submission)
|
||||
# ==========================================================================
|
||||
final_application = fields.Binary(
|
||||
string='Final Application (PDF)',
|
||||
attachment=True,
|
||||
help='Copy of the final application PDF at time of submission',
|
||||
)
|
||||
final_application_filename = fields.Char(
|
||||
string='Final Application Filename',
|
||||
)
|
||||
|
||||
xml_file = fields.Binary(
|
||||
string='XML File',
|
||||
attachment=True,
|
||||
help='Copy of the XML file at time of submission',
|
||||
)
|
||||
xml_filename = fields.Char(
|
||||
string='XML Filename',
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# RESULT TRACKING
|
||||
# ==========================================================================
|
||||
result = fields.Selection(
|
||||
selection=[
|
||||
('pending', 'Pending'),
|
||||
('accepted', 'Accepted'),
|
||||
('rejected', 'Rejected'),
|
||||
('approved', 'Approved'),
|
||||
('denied', 'Denied'),
|
||||
],
|
||||
string='Result',
|
||||
default='pending',
|
||||
)
|
||||
|
||||
result_date = fields.Date(
|
||||
string='Result Date',
|
||||
help='Date when the result was received from ADP',
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# REJECTION DETAILS (if rejected)
|
||||
# ==========================================================================
|
||||
rejection_reason = fields.Selection(
|
||||
selection=[
|
||||
('name_correction', 'Name Correction Needed'),
|
||||
('healthcard_correction', 'Health Card Correction Needed'),
|
||||
('duplicate_claim', 'Duplicate Claim Exists'),
|
||||
('xml_format_error', 'XML Format/Validation Error'),
|
||||
('missing_info', 'Missing Required Information'),
|
||||
('other', 'Other'),
|
||||
],
|
||||
string='Rejection Reason',
|
||||
)
|
||||
|
||||
rejection_details = fields.Text(
|
||||
string='Rejection Details',
|
||||
help='Additional details about the rejection',
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# CORRECTION NOTES (for resubmissions)
|
||||
# ==========================================================================
|
||||
correction_notes = fields.Text(
|
||||
string='Correction Notes',
|
||||
help='Notes about what was corrected for this resubmission',
|
||||
)
|
||||
|
||||
# ==========================================================================
|
||||
# COMPUTED FIELDS
|
||||
# ==========================================================================
|
||||
@api.depends('sale_order_id', 'submission_number', 'submission_type')
|
||||
def _compute_display_name(self):
|
||||
for record in self:
|
||||
order_name = record.sale_order_id.name or 'New'
|
||||
type_label = dict(record._fields['submission_type'].selection).get(
|
||||
record.submission_type, record.submission_type
|
||||
)
|
||||
record.display_name = f"{order_name} - Submission #{record.submission_number} ({type_label})"
|
||||
|
||||
# ==========================================================================
|
||||
# HELPER METHODS
|
||||
# ==========================================================================
|
||||
@api.model
|
||||
def create_from_submission(self, sale_order, submission_type='initial', correction_notes=None):
|
||||
"""Create a submission history record from a sale order submission.
|
||||
|
||||
Args:
|
||||
sale_order: The sale.order record being submitted
|
||||
submission_type: 'initial', 'resubmission', or 'correction'
|
||||
correction_notes: Optional notes about corrections made
|
||||
|
||||
Returns:
|
||||
The created fusion.submission.history record
|
||||
"""
|
||||
# Get next submission number
|
||||
existing_count = self.search_count([('sale_order_id', '=', sale_order.id)])
|
||||
submission_number = existing_count + 1
|
||||
|
||||
# If submission_number > 1, it's a resubmission
|
||||
if submission_number > 1 and submission_type == 'initial':
|
||||
submission_type = 'resubmission'
|
||||
|
||||
vals = {
|
||||
'sale_order_id': sale_order.id,
|
||||
'submission_number': submission_number,
|
||||
'submission_type': submission_type,
|
||||
'submission_date': fields.Date.today(),
|
||||
'submitted_by_id': self.env.user.id,
|
||||
'correction_notes': correction_notes,
|
||||
}
|
||||
|
||||
# Copy current documents
|
||||
if sale_order.x_fc_final_submitted_application:
|
||||
vals['final_application'] = sale_order.x_fc_final_submitted_application
|
||||
vals['final_application_filename'] = sale_order.x_fc_final_application_filename
|
||||
|
||||
if sale_order.x_fc_xml_file:
|
||||
vals['xml_file'] = sale_order.x_fc_xml_file
|
||||
vals['xml_filename'] = sale_order.x_fc_xml_filename
|
||||
|
||||
record = self.create(vals)
|
||||
|
||||
# Post to chatter
|
||||
sale_order.message_post(
|
||||
body=Markup(
|
||||
'<div style="border-left: 3px solid #3498db; padding-left: 12px; margin: 8px 0;">'
|
||||
'<p style="margin: 0 0 8px 0; font-weight: 600; color: #2980b9;">'
|
||||
f'<i class="fa fa-paper-plane"></i> Submission #{submission_number} Recorded</p>'
|
||||
'<table style="font-size: 13px; color: #555;">'
|
||||
f'<tr><td style="padding: 2px 8px 2px 0; font-weight: 500;">Type:</td><td>{dict(self._fields["submission_type"].selection).get(submission_type)}</td></tr>'
|
||||
f'<tr><td style="padding: 2px 8px 2px 0; font-weight: 500;">Date:</td><td>{fields.Date.today().strftime("%B %d, %Y")}</td></tr>'
|
||||
f'<tr><td style="padding: 2px 8px 2px 0; font-weight: 500;">By:</td><td>{self.env.user.name}</td></tr>'
|
||||
'</table>'
|
||||
+ (f'<p style="margin: 8px 0 0 0; font-size: 12px;"><strong>Corrections:</strong> {correction_notes}</p>' if correction_notes else '') +
|
||||
'</div>'
|
||||
),
|
||||
message_type='notification',
|
||||
subtype_xmlid='mail.mt_note',
|
||||
)
|
||||
|
||||
return record
|
||||
|
||||
def update_result(self, result, rejection_reason=None, rejection_details=None):
|
||||
"""Update the result of a submission.
|
||||
|
||||
Args:
|
||||
result: 'accepted', 'rejected', 'approved', or 'denied'
|
||||
rejection_reason: Selection value for rejection reason
|
||||
rejection_details: Text details for rejection
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
vals = {
|
||||
'result': result,
|
||||
'result_date': fields.Date.today(),
|
||||
}
|
||||
|
||||
if result == 'rejected':
|
||||
vals['rejection_reason'] = rejection_reason
|
||||
vals['rejection_details'] = rejection_details
|
||||
|
||||
self.write(vals)
|
||||
|
||||
return self
|
||||
Reference in New Issue
Block a user