[IMP] odex_benefit: IMP benefit
This commit is contained in:
parent
3a742a0496
commit
c7afd786f1
|
|
@ -628,9 +628,9 @@ class GrantBenefitProfile(models.Model):
|
|||
|
||||
def _compute_total_families(self):
|
||||
for record in self:
|
||||
record.total_father_families = self.search_count([('father_id_number','=',self.father_id_number),('id','!=',self.id)])
|
||||
record.total_mother_families = self.search_count([('mother_id_number','=',self.mother_id_number),('id','!=',self.id)])
|
||||
record.total_replacement_mother_families = self.search_count([('replacement_mother_id_number','=',self.replacement_mother_id_number),('id','!=',self.id)])
|
||||
record.total_father_families = self.search_count([('father_id_number','=',record.father_id_number),('id','!=',record.id)])
|
||||
record.total_mother_families = self.search_count([('mother_id_number','=',record.mother_id_number),('id','!=',record.id)])
|
||||
record.total_replacement_mother_families = self.search_count([('replacement_mother_id_number','=',record.replacement_mother_id_number),('id','!=',record.id)])
|
||||
|
||||
def action_open_related_father_families(self):
|
||||
self.ensure_one()
|
||||
|
|
@ -827,6 +827,7 @@ class GrantBenefitProfile(models.Model):
|
|||
record.required_attach = 'true'
|
||||
|
||||
def get_attached_domain(self):
|
||||
self.ensure_one()
|
||||
visit_location = self.env['visit.location'].search([('benefit_id', '=', self.id)]).ids
|
||||
service_requests = self.env['service.request'].search([('family_id', '=', self.id)]).ids
|
||||
family_complaints = self.env['family.complaints'].search([('family_id', '=', self.id)]).ids
|
||||
|
|
@ -865,7 +866,7 @@ class GrantBenefitProfile(models.Model):
|
|||
def _compute_attached_docs_count(self):
|
||||
Attachment = self.env['ir.attachment']
|
||||
for benefit in self:
|
||||
benefit.doc_count = Attachment.search_count(self.get_attached_domain())
|
||||
benefit.doc_count = Attachment.search_count(benefit.get_attached_domain())
|
||||
|
||||
def view_attachments(self):
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('base.action_attachment')
|
||||
|
|
@ -1881,20 +1882,21 @@ class GrantBenefitProfile(models.Model):
|
|||
|
||||
@api.depends('name')
|
||||
def _compute_qr_code(self):
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
||||
box_size=15,
|
||||
border=4,
|
||||
)
|
||||
name = self.name
|
||||
qr.add_data(name)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image()
|
||||
temp = BytesIO()
|
||||
img.save(temp, format="PNG")
|
||||
qr_image = base64.b64encode(temp.getvalue())
|
||||
self.qr_code = qr_image
|
||||
for rec in self:
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
||||
box_size=15,
|
||||
border=4,
|
||||
)
|
||||
name = rec.name
|
||||
qr.add_data(name)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image()
|
||||
temp = BytesIO()
|
||||
img.save(temp, format="PNG")
|
||||
qr_image = base64.b64encode(temp.getvalue())
|
||||
rec.qr_code = qr_image
|
||||
|
||||
@api.onchange('bank_id')
|
||||
def _compute_prefix_iban(self):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from odoo import fields, models, api, _
|
|||
from odoo.exceptions import UserError, ValidationError
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.tools import html_escape
|
||||
|
||||
class ServiceRequest(models.Model):
|
||||
_name = 'service.request'
|
||||
|
|
@ -204,6 +204,125 @@ class ServiceRequest(models.Model):
|
|||
total_moves = fields.Integer(string="Total Move", compute='_get_total_move_lines')
|
||||
return_reason_id = fields.Many2one("return.reason", string="Return Reason")
|
||||
agree_terms = fields.Boolean(string="I agree to the Terms and Conditions", default=False, )
|
||||
related_information_html = fields.Html(string="Related Information",
|
||||
compute='_compute_related_information_html',store=True,)
|
||||
|
||||
@api.depends('service_cat', 'family_id', 'member_id', 'benefit_type')
|
||||
def _compute_related_information_html(self):
|
||||
for rec in self:
|
||||
if not rec.service_cat:
|
||||
rec.related_information_html = f"""
|
||||
<div class="o_form_sheet_not_found">
|
||||
<div class="o_form_sheet_not_found_icon">📋</div>
|
||||
<h4>{_("No service selected")}</h4>
|
||||
<p>{_("Please select a service category to view related information.")}</p>
|
||||
</div>
|
||||
"""
|
||||
continue
|
||||
|
||||
family_rows = []
|
||||
member_rows = []
|
||||
|
||||
for ir_field in rec.service_cat.family_related_fields:
|
||||
row = rec._get_field_display_value(rec.family_id, ir_field)
|
||||
if row:
|
||||
family_rows.append(row)
|
||||
if rec.benefit_type == 'member' and rec.member_id:
|
||||
for ir_field in rec.service_cat.member_related_fields:
|
||||
row = rec._get_field_display_value(rec.member_id, ir_field)
|
||||
if row:
|
||||
member_rows.append(row)
|
||||
family_table = rec._build_info_table(_("Family Information"), family_rows)
|
||||
member_table = rec._build_info_table(_("Member Information"), member_rows) if member_rows else ""
|
||||
|
||||
rec.related_information_html = f"""
|
||||
<div class="info-container">
|
||||
{family_table}
|
||||
{member_table}
|
||||
</div>
|
||||
"""
|
||||
|
||||
def _build_info_table(self, title, rows):
|
||||
if not rows:
|
||||
return f"""
|
||||
<div class="info-section">
|
||||
<h3>{title}</h3>
|
||||
<div class="info-empty">{_("No information available for this section.")}</div>
|
||||
</div>
|
||||
"""
|
||||
return f"""
|
||||
<div class="info-section">
|
||||
<h3>{title}</h3>
|
||||
<table class="table info-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{_("Field Name")}</th>
|
||||
<th>{_("Value")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{''.join(rows)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
"""
|
||||
|
||||
def _get_field_display_value(self, record, ir_field):
|
||||
if not record or not ir_field:
|
||||
return ""
|
||||
|
||||
field_name = ir_field.name
|
||||
field = record._fields.get(field_name)
|
||||
if not field:
|
||||
return ""
|
||||
|
||||
value = record[field_name]
|
||||
label = html_escape(ir_field.field_description or field_name)
|
||||
|
||||
if value in (False, None, '') or (hasattr(value, '__len__') and len(value) == 0):
|
||||
display = '<span class="info-empty">—</span>'
|
||||
elif field.type == 'boolean':
|
||||
display = f"<span class='badge badge-success'>✓ {_('Yes')}</span>" if value else f"<span class='badge badge-danger'>✗ {_('No')}</span>"
|
||||
elif field.type == 'selection':
|
||||
sel_dict = dict(field._description_selection(record.env))
|
||||
display_val = sel_dict.get(value, value)
|
||||
display = f'<span class="badge">{html_escape(str(display_val or "—"))}</span>'
|
||||
elif field.type == 'many2one':
|
||||
display = f'<strong>{html_escape(value.name or "—")}</strong>'
|
||||
elif field.type == 'many2many':
|
||||
if field.comodel_name == 'ir.attachment':
|
||||
if not value:
|
||||
display = '<span class="info-empty">—</span>'
|
||||
else:
|
||||
links = []
|
||||
for attach in value:
|
||||
filename = attach.name or _("Unnamed file")
|
||||
url = f"/web/content/{attach.id}?download=true"
|
||||
links.append(f'<a class="file-link" href="{url}" target="_blank">📎 {html_escape(filename)}</a>')
|
||||
display = '<br/>'.join(links)
|
||||
else:
|
||||
badges = [f'<span class="badge badge-secondary">{html_escape(r.name or "-")}</span>' for r in value]
|
||||
display = ' '.join(badges) or '<span class="info-empty">—</span>'
|
||||
elif field.type == 'one2many':
|
||||
items = [f'<div style="margin:8px 0; padding:6px 0; border-bottom:1px dotted #ddd;">• {html_escape(r.display_name or r.name or "-")}</div>' for r in value[:20]]
|
||||
more = f'<div style="color:#875A92; font-weight:600; margin-top:10px;">... {_("and")} {len(value)-20} {_("more records")}</div>' if len(value) > 20 else ""
|
||||
display = ''.join(items) + more or '<span class="info-empty">—</span>'
|
||||
elif field.type == 'binary':
|
||||
if value:
|
||||
filename = getattr(record, f"{field_name}_fname", None) or _("Download file")
|
||||
url = f"/web/content/{record._name}/{record.id}/{field_name}?download=true"
|
||||
display = f'<a class="file-link" href="{url}" target="_blank">📎 {html_escape(filename)}</a>'
|
||||
else:
|
||||
display = '<span class="info-empty">—</span>'
|
||||
else:
|
||||
display = html_escape(str(value))
|
||||
|
||||
return f"""
|
||||
<tr>
|
||||
<td class="info-label">{label}</td>
|
||||
<td class="info-value">{display}</td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
@api.depends('payment_order_ids')
|
||||
def _compute_payment_order(self):
|
||||
|
|
|
|||
|
|
@ -113,6 +113,30 @@ class ServicesSettings(models.Model):
|
|||
('payment_order', 'Payment Order'),
|
||||
('invoice', 'Invoice'),
|
||||
], string='Payment Method',default="payment_order")
|
||||
family_related_fields = fields.Many2many(
|
||||
comodel_name='ir.model.fields',
|
||||
relation='services_settings_family_field_rel',
|
||||
column1='services_settings_id',
|
||||
column2='field_id',
|
||||
string='Related Family Fields',
|
||||
domain="[('model_id.model', '=', 'grant.benefit')]",
|
||||
help="Select fields from the Family profile (grant.benefit) to display in the service request."
|
||||
)
|
||||
|
||||
member_related_fields = fields.Many2many(
|
||||
comodel_name='ir.model.fields',
|
||||
relation='services_settings_member_field_rel',
|
||||
column1='services_settings_id',
|
||||
column2='field_id',
|
||||
string='Related Member Fields',
|
||||
domain="[('model_id.model', '=', 'family.member')]",
|
||||
help="Select fields from the Member profile to display only when the service is for a member."
|
||||
)
|
||||
|
||||
@api.onchange('benefit_type')
|
||||
def _onchange_benefit_type(self):
|
||||
if self.benefit_type != 'member':
|
||||
self.member_related_fields = [(5, 0, 0)]
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
.info-container {
|
||||
font-family: inherit;
|
||||
}
|
||||
.info-container .info-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
.info-container .info-section h3 {
|
||||
color: #000000;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 16px 0;
|
||||
padding-bottom: 8px;
|
||||
display: inline-block;
|
||||
}
|
||||
.info-container .info-table {
|
||||
width: 70%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.info-container .info-table th {
|
||||
background-color: #EEE;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
.info-container .info-table td {
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
.info-container .info-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
.info-container .info-table tr:hover td {
|
||||
background-color: #f8f5f9;
|
||||
}
|
||||
.info-container .info-value {
|
||||
color: #212529;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.info-container .badge {
|
||||
padding: 5px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: inline-block;
|
||||
margin: 3px 6px 3px 0;
|
||||
}
|
||||
.info-container .badge-success { background:#d4edda; color:#155724; }
|
||||
.info-container .badge-danger { background:#f8d7da; color:#721c24; }
|
||||
.info-container .badge-info { background:#d1ecf1; color:#0c5460; }
|
||||
.info-container .badge-secondary{ background:#e2e3e5; color:#383d41; }
|
||||
.info-container .file-link {
|
||||
color: #875A92;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
.info-container .file-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.info-container .info-empty {
|
||||
color: #adb5bd;
|
||||
font-style: italic;
|
||||
text-align: center;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.o_form_sheet_not_found {
|
||||
text-align:center;
|
||||
padding:50px;
|
||||
background:#f8f9fa;
|
||||
border:2px dashed #dee2e6;
|
||||
border-radius:12px;
|
||||
color:#6c757d;
|
||||
}
|
||||
|
||||
.o_form_sheet_not_found .o_form_sheet_not_found_icon {
|
||||
font-size:48px;
|
||||
opacity:0.3;
|
||||
margin-bottom:16px;
|
||||
}
|
||||
|
|
@ -444,6 +444,11 @@
|
|||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Related Information">
|
||||
<group>
|
||||
<field name="related_information_html" nolabel="1" readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
|
|
|
|||
|
|
@ -217,6 +217,17 @@
|
|||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Related Information">
|
||||
<group>
|
||||
<group>
|
||||
<field name="family_related_fields" widget="many2many_tags"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="member_related_fields" widget="many2many_tags"
|
||||
attrs="{'invisible': [('benefit_type', '!=', 'member')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<template id="custom_assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" type="text/scss" href="/odex_benefit/static/src/scss/custom_style.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/odex_benefit/static/src/css/backend_style.css"/>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
Loading…
Reference in New Issue