Merge pull request #5821 from expsa/esterdad_bugs

Esterdad bugs
This commit is contained in:
kchyounes19 2025-12-25 10:56:42 +01:00 committed by GitHub
commit e672707a6e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 151 additions and 37 deletions

View File

@ -43,6 +43,7 @@
'views/payment_details_lines_views.xml',
'wizards/account_payment_register.xml',
'views/res_partner_bank.xml',
'views/acount_move.xml',
'views/res_users_inherit.xml',
'views/takaful_push_notification_view.xml',

View File

@ -281,6 +281,7 @@ class DonationsDetailsLines(models.Model):
rec.end_date and
rec.end_date >= today and
rec.state == 'active'
and rec.sponsorship_id.state in ['canceled' , 'closed']
)
rec.show_extend_button = show_extend_button
@ -683,7 +684,10 @@ class DonationsDetailsLines(models.Model):
for rec in self:
if rec.record_type == 'donation':
if rec.sponsorship_id.donation_mechanism == 'without_conditions':
rec.total_donation_amount = rec.donation_amount * rec.donation_qty
if rec.direct_debit:
rec.total_donation_amount = rec.donation_amount * rec.donation_qty * rec.payment_month_count
else:
rec.total_donation_amount = rec.donation_amount * rec.donation_qty
else:
rec.total_donation_amount = rec.total_months_amount
else:
@ -874,14 +878,15 @@ class DonationsDetailsLines(models.Model):
def compute_sponsorships_lines(self):
for rec in self:
rec.write({'sponsorship_scheduling_line_ids': [(5, 0, 0)]})
sponsorship_id = rec.sponsorship_mechanism_id if rec.sponsorship_mechanism_id.donations_details_lines_mechanism_ids else rec.sponsorship_id
SponsorshipSchedulingLink = self.env['sponsorship.scheduling.line'].sudo()
SponsorshipSchedulingLink.search([('sponsorship_id', 'in', sponsorship_id.ids),
('donation_detail_linked_id.sponsorships_computed', '=', False)]).unlink()
if rec.sponsorships_computed:
return
# if rec.sponsorships_computed:
# return
if rec.payment_option == 'month' and rec.direct_debit:
# Divide the total donation amount by the number of months
if rec.payment_month_count > 0:
@ -982,18 +987,45 @@ class DonationsDetailsLines(models.Model):
record = super(DonationsDetailsLines, self).create(vals)
if record.benefit_ids == 1:
record.benefit_id = record.benefit_ids[0].id
print('Vals >>> ' , vals)
# Ensure the line is linked to the sponsor's donation_detail_ids M2M
if record.sponsor_id:
record.sponsor_id.write({
'donation_detail_ids': [(4, record.id)],
})
# Auto-trigger kafel_state recomputation for the sponsor
record.sponsor_id._compute_kafel_state()
return record
def write(self, vals):
res = False
# Track sponsors that need kafel_state recomputation
sponsors_to_recompute = set()
for rec in self:
# Track old sponsor before write
old_sponsor_id = rec.sponsor_id.id if rec.sponsor_id else False
old_benefit = rec.benefit_id.name
old_benefits = rec.benefit_ids.mapped('name') # assuming benefit has a 'name'
old_benefits_set = set(old_benefits)
res |= super(DonationsDetailsLines, rec).write(vals)
rec.invalidate_cache()
rec = self.browse(rec.id)
# Track sponsors for recomputation if relevant fields change
if any(field in vals for field in ['sponsor_id', 'sponsorship_duration', 'state']):
# Add old sponsor if it existed
if old_sponsor_id:
sponsors_to_recompute.add(old_sponsor_id)
# Add new sponsor if sponsor_id changed
if 'sponsor_id' in vals:
new_sponsor_id = vals.get('sponsor_id')
if new_sponsor_id:
sponsors_to_recompute.add(new_sponsor_id)
# Add current sponsor if other relevant fields changed
elif rec.sponsor_id:
sponsors_to_recompute.add(rec.sponsor_id.id)
if 'display_type' in vals and self.filtered(lambda line: line.display_type != vals.get('display_type')):
raise UserError(
@ -1046,6 +1078,18 @@ class DonationsDetailsLines(models.Model):
# vals['replace_date'] = False
self.onset_benefit_id()
# Ensure each line is linked to its sponsor's donation_detail_ids M2M
for rec in self:
if rec.sponsor_id:
rec.sponsor_id.write({
'donation_detail_ids': [(4, rec.id)],
})
# Auto-trigger kafel_state recomputation for affected sponsors
if sponsors_to_recompute:
sponsors = self.env['res.partner'].browse(list(sponsors_to_recompute))
sponsors._compute_kafel_state()
return res
def action_view_replacement_wizard(self):

View File

@ -53,6 +53,7 @@ class ResPartner(models.Model):
('verified', 'Verified')
], string='State',default='draft', tracking=True)
check_lines = fields.Boolean()
def _get_default_preferred_communication(self):
"""Get first preferred communication method as default"""
first_comm = self.env['preferred.communication'].search([], limit=1, order='id asc')
@ -96,17 +97,22 @@ class ResPartner(models.Model):
string="# of Gifts",
readonly=True
)
donation_line_ids = fields.Many2many( 'donations.details.lines',
string="Donation Lines",
)
kafel_state = fields.Selection([
('active', "Active"),
('not_active', "Not Active")] ,string='Status')
_sql_constraints = [
('id_number_uniq', 'unique (id_number)', 'The ID Number Already Exist!'),
]
def view_sponsorship_payment_action(self):
"""Enable The Sponsor To Pay Sponsorships Entries"""
sponsorship_id = self.env['takaful.sponsorship'].sudo().search([('sponsor_id', '=', self.id), ('has_delay', '=', True)], limit=1)
sponsorship_id = self.env['takaful.sponsorship'].sudo().search([('sponsor_id', '=', self.id), ('has_delay', '=', True)], limit=1)
context = dict(self.env.context or {})
context['default_sponsor_id'] = self.id or False
context['default_sponsorship_id'] = sponsorship_id.id or False
@ -124,27 +130,48 @@ class ResPartner(models.Model):
'context': context,
}
@api.constrains('is_family', 'is_benefit', 'is_donor', 'is_sponsor_portal')
def _check_family_beneficiary_exclusivity(self):
for rec in self:
is_family_or_beneficiary = rec.is_family or rec.is_benefit
is_donor_vendor_sponsor = rec.is_donor or rec.is_sponsor_portal or rec.is_vendor
if is_family_or_beneficiary and is_donor_vendor_sponsor:
raise ValidationError(_("A contact cannot be both Family/Beneficiary and Donor/Member/Sponsor at the same time!"))
def _normalize_phone_search_args(self, args):
"""Normalize phone/mobile values in domain by stripping a leading '0' if present."""
def _normalize(term):
# Term can be an operator ('&', '|', '!') or a domain triplet/list (possibly nested)
if isinstance(term, list):
# Domain leaf: ['phone', 'ilike', '0123'] or ['mobile', '=', '0123']
if len(term) == 3 and term[0] in ('phone', 'mobile') and isinstance(term[2], str):
val = term[2]
if val and val.startswith('0'):
term = [term[0], term[1], val[1:]]
else:
# Nested list: normalize inner items
term = [_normalize(t) for t in term]
return term
return [_normalize(t) for t in args] if args else args
@api.model
def search(self, args, offset=0, limit=None, order=None, count=False):
if not self.env.context.get('from_contact_search'):
return super().search(args, offset=offset, limit=limit, order=order, count=count)
# if not self.env.context.get('from_contact_search'):
# return super().search(args, offset=offset, limit=limit, order=order, count=count)
if self.env.context.get('mail_read') or self.env.context.get('mail_message_origin'):
return super().search(args, offset=offset, limit=limit, order=order, count=count)
base_results = super().search(args, offset=offset, limit=limit, order=order)
# Normalize phone/mobile search values (strip leading zero)
normalized_args = self._normalize_phone_search_args(args)
base_results = super().search(normalized_args, offset=offset, limit=limit, order=order)
if not base_results:
return base_results
@ -159,7 +186,21 @@ class ResPartner(models.Model):
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
if not args:
args = []
domain = ['|', '|', ('name', operator, name),('id_number', operator, name),('mobile', operator, name)]
# Build search domains for the raw name and (optionally) the name
# without leading zero, to "ignore" a starting 0 in the search term.
search_terms = [name] if name else []
if name and name.startswith('0'):
search_terms.append(name[1:])
domain = []
for term in search_terms:
term_domain = ['|', '|',
('name', operator, term),
('id_number', operator, term),
('mobile', operator, term)]
domain = term_domain if not domain else expression.OR([domain, term_domain])
domain = expression.AND([domain, args])
parent_record_ids = self.search(domain).ids
domain = expression.OR([domain, [('parent_id', 'in', parent_record_ids)]])
@ -227,7 +268,7 @@ class ResPartner(models.Model):
res = all(bank_info)
return res
def unlink(self):
related_contact = self.env['res.partner'].search([('parent_id', 'in', self.ids)])
sponsorships = self.env['takaful.sponsorship'].search([('sponsor_id', 'in', self.ids)])
@ -272,9 +313,9 @@ class ResPartner(models.Model):
values.update({'is_sponsor_portal': True})
if not values.get('serial_code'):
values['serial_code'] = self.env['ir.sequence'].next_by_code('takaful.sponsor.sequence') or 'S/0000'
res = super(ResPartner, self).create(values)
if context.get('sponsor_contact'):
if context.get('parent_model') == 'takaful.sponsorship' and context.get('parent_id'):
parent_record = self.env[context['parent_model']].browse(context['parent_id'])
@ -311,8 +352,8 @@ class ResPartner(models.Model):
if 'mobile' in vals and self.mobile != False:
kafeel = self.env['res.users'].with_user(2).create({
'name' : vals['name'],
'branch_custom_id':vals['branch_custom_id'],
'name' : self.name,
'branch_custom_id':self.branch_custom_id.id or vals['branch_custom_id'],
'sel_groups_1_9_10' : 9,
'partner_id' : self.id,
'login' : vals['mobile'],
@ -327,7 +368,7 @@ class ResPartner(models.Model):
def create_user(self):
for follower in self.message_follower_ids:
follower.sudo().unlink()
# If you add 'no_reset_password' to the context to True, it won't send an email.
# If you add 'no_reset_password' to the context to True, it won't send an email.
# You can then set the password manually (and find a way to let the user know it).
user = self.env['res.users'].sudo().with_context(no_reset_password=False).create({
'name': self.name,
@ -353,7 +394,7 @@ class ResPartner(models.Model):
self.user_id = user.id
return self
def action_open_sponsor_operation(self):
"""Open Operations History for a Sponsor"""
domain = [('sponsor_id', '=', self.id or False)]
@ -372,7 +413,7 @@ class ResPartner(models.Model):
'context': context,
}
def view_sponsorship_action(self):
"""List Sponsorships For The Sponsor"""
domain = [('sponsor_id', '=', self.id or False)]
@ -395,9 +436,9 @@ class ResPartner(models.Model):
@api.model
def get_active_sponsors_users(self):
sponsors_users = self.env['res.users'].sudo().search([
("active", "=", True),
("active", "=", True),
("groups_id", "=", self.env.ref("odex_takaful.takaful_group_user_sponsor").id)])#self.env['res.users'].sudo().search([])
count = len(sponsors_users) or 0
sponsors = self.env['res.partner'].sudo().search([])
for rec in sponsors:
@ -472,7 +513,7 @@ class ResPartner(models.Model):
rec.name = " ".join(names)
else:
rec.name = " "
class ResPartnerBank(models.Model):
_inherit = 'res.partner.bank'

View File

@ -1394,8 +1394,8 @@ class TakafulSponsorship(models.Model):
"Please choose different beneficiaries for these lines before proceeding with the payment." % line.sequence_no))
if not all(all_donation_lines.mapped("sponsorships_computed")):
(self.donations_details_lines + self.donations_details_lines_mechanism_ids).compute_sponsorships_lines()
(self.donations_details_lines + self.donations_details_lines_mechanism_ids).compute_sponsorships_lines()
if self.state == 'draft':
# Send SMS Notification

View File

@ -9,19 +9,27 @@
<attribute name="attrs">{'invisible': False}</attribute>
</xpath>
<xpath expr="//field[@name='invoice_origin']" position="after">
<field name="esterdad_id" invisible="1"/>
<xpath expr="//field[@name='partner_id']" position="after">
<field name="esterdad_id" invisible="0"/>
</xpath>
<xpath expr="//div[hasclass('oe_button_box')]" position="inside">
<button name="action_view_esterdad_id" type="object" class="oe_stat_button" icon="fa-money"
attrs="{'invisible': [('esterdad_id', '=', False)]}">
</button>
</xpath>
</field>
</record>
<record id="account_move_view1" model="ir.ui.view">
<field name="name">account.move.inherit.form.attachment</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_view_esterdad_id" type="object" class="oe_stat_button" icon="fa-money"
attrs="{'invisible': [('esterdad_id', '=', False)]}">
</button>
</xpath>
</field>
</record>
</odoo>

View File

@ -180,7 +180,7 @@
}"/>
<div class="o_row">
<field name="sponsor_id" nolabel="1"
context="{'form_view_ref': 'odex_takaful.view_takaful_sponsor_form'}"
context="{'form_view_ref': 'odex_takaful.view_takaful_sponsor_form' ,'tree_view_ref':'odex_takaful.takaful_sponsor_tree'}"
attrs="{
'invisible': ['|',
'&amp;', ('record_type','=','donation'), ('sponsor_or_donor_type','=','unknown'),
@ -532,8 +532,8 @@
</header>
<group>
<group>
<field name="ages" invisible="0"/>
<field name="members_domain_ids" invisible="0"/>
<field name="ages" invisible="1"/>
<field name="members_domain_ids" invisible="1"/>
<field name="waiting_date" invisible="1" widget="date"/>
<field name="family_id"

View File

@ -1,5 +1,24 @@
<?xml version="1.0"?>
<odoo>
<record id="res_partner_view_form" model="ir.ui.view">
<field name="name">res_partner_view_form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_res_partner_filter"/>
<field name="arch" type="xml">
<xpath expr="//search" position="inside">
<filter string="Status Active " name="filter_status_of_kafeel" domain="[('kafel_state', '=', 'active')]"/>
<filter string="Status Not Active" name="filter_status_of_kafeel_not" domain="[('kafel_state', '=', 'not_active')]"/>
<searchpanel>
<field name="kafel_state" enable_counters="1"/>
</searchpanel>
</xpath>
</field>
</record>
<record id="takaful_sponsor_sequence" model="ir.sequence">
<field name="name">Takaful Sponsor Sequence</field>
<field name="code">takaful.sponsor.sequence</field>
@ -106,6 +125,7 @@
<field name="district_id" invisible="1"/>
<field name="user_id" invisible="1" options="{'no_create': True, 'no_create_edit':True}"
readonly="1"/>
<field name="kafel_state" invisible="0"/>
</group>
</group>
<notebook>