odex25_standard/odex25_takaful/odex_takaful/models/replacement_process.py

231 lines
11 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _, exceptions
from odoo.exceptions import ValidationError, UserError, Warning
import requests
import re
class ReplacementProcess(models.Model):
_name = 'replacement.process'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = "Replacement Process"
_rec_name = 'code'
code = fields.Char(string="Replacement Reference",copy=False,readonly=True)
user_id = fields.Many2one('res.users', string="Create User")
sponsorship_id = fields.Many2one('takaful.sponsorship',string='Sponsorship')
branch_id = fields.Many2one('branch.settings', string="Branch")
branch_ids = fields.Many2many('branch.settings', string="Branch")
sponsor_donor_type = fields.Selection(string='Sponsor / Donor Type',selection=[('registered', 'Registered'), ('new_sponsor', 'New Sponsor')])
record_type = fields.Selection([('sponsorship', 'Sponsorship'),('donation', 'Donation')], string="Record Type")
sponsor_id = fields.Many2one('res.partner',string='Sponsor Name')
replacement_reason_id = fields.Many2one('replacement.reasons', string="Replacement Reason")
benefit_ids = fields.Many2many('family.member',string='Benefits')
replaced = fields.Boolean('Replaced')
family_ids = fields.Many2many('grant.benefit',string='Family')
registered_type = fields.Selection(string='Registered Type',selection=[('sponsor', 'Sponsor'),('member', 'Member')])
replacement_line_ids = fields.One2many('replacement.process.line', 'process_id', string="Replacement Lines", tracking=True)
state = fields.Selection([('draft', 'Draft'),('replaced', 'Replaced')],string='State', default='draft', tracking=True)
# Model Operations
@api.model
def create(self, vals):
if vals.get('code', 'New') == 'New':
vals['code'] = self.env['ir.sequence'].sudo().next_by_code('replacement.process.sequence')
res = super(ReplacementProcess, self).create(vals)
return res
def unlink(self):
raise UserError(_('You cannot delete this record'))
return super(ReplacementProcess, self).unlink()
def confirm_replacement(self):
for rec in self:
rec.benefit_ids.sudo().write({'replaced': True})
rec.sponsorship_id.sudo().write({'state': 'replacement_done'})
rec.sponsorship_id.sudo().write({'branch_custom_id': self.branch_id.id})
if rec.replacement_line_ids:
for benefit in rec.replacement_line_ids:
all_donation_lines = (
(rec.sponsorship_id.donations_details_lines if rec.sponsorship_id.donations_details_lines else self.env[
'donations.details.lines']) |
(
rec.sponsorship_id.donations_details_lines_mechanism_ids if rec.sponsorship_id.donations_details_lines_mechanism_ids else
self.env['donations.details.lines'])
)
for donation_line in all_donation_lines:
if donation_line.sponsorship_type in ['person',benefit.sponsorship_type] and donation_line.benefit_id and benefit.to_benefit_id and donation_line.benefit_id == benefit.from_benefit_id:
donation_line.benefit_id.sudo().write({'replaced': True})
rec.family_ids = [(6, 0, [donation_line.benefit_id.benefit_id.id])]
donation_line.sudo().write({'benefit_id': benefit.to_benefit_id.id})
elif donation_line.sponsorship_type in ['group',benefit.sponsorship_type] and donation_line.benefit_ids and benefit.to_benefit_ids and donation_line.benefit_ids == benefit.from_benefit_ids:
rec.family_ids = [(6, 0, [donation_line.benefit_ids.mapped('benefit_id.id')[0]])]
donation_line.sudo().write({'benefit_ids': benefit.to_benefit_ids.ids})
donation_line.sudo().write({'benefit_id': benefit.to_benefit_ids.ids[0]})
donation_line.benefit_ids.sudo().write({'replaced': True})
rec.state = 'replaced'
rec.replaced = True
rec.action_send_whatsapp()
def action_send_whatsapp(self):
config = self.env['ir.config_parameter'].sudo()
account_sid = config.get_param('odex_takaful.twilio_account_sid')
auth_token = config.get_param('odex_takaful.twilio_auth_token')
from_whatsapp = config.get_param('odex_takaful.twilio_from_whatsapp')
if not account_sid or not auth_token or not from_whatsapp:
raise ValidationError(_("Twilio configuration is missing. Please configure Twilio SID, Auth Token, and WhatsApp number in General Configurations."))
from_cleaned_mobile = re.sub(r'[^\d+]', '', from_whatsapp)
from_whatsapp_number = f'whatsapp:{from_cleaned_mobile}'
message = "نشعركم بإستبدال أبنائكم المكفول/ة بآخر مستحق وذلك لإستبعاده من الجمعية نظامياً، للحصول على تقرير اليتيم الجديد يسعدنا تواصلكم مع الفرع، بلغكم الله مرافقة النبى صلى الله عليه وسلم فى الجنة"
for partner in self:
mobile = partner.sponsor_id.mobile if partner.sponsor_id else partner.sponsorship_id.member_id.mobile
if mobile:
# Clean the number (keep + and digits only)
cleaned_mobile = re.sub(r'[^\d+]', '', mobile)
to_whatsapp_number = f'whatsapp:{cleaned_mobile}'
url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json"
payload = {
'From': from_whatsapp_number,
'To': to_whatsapp_number,
'Body': message,
}
response = requests.post(
url,
data=payload,
auth=(account_sid, auth_token)
)
if response.status_code != 201:
raise ValidationError(_("Failed to send WhatsApp message: %s") % response.text)
class FamilyMember(models.Model):
_inherit = 'family.member'
replaced = fields.Boolean('Replaced')
def write(self, vals):
res = super(FamilyMember, self).write(vals)
sponsorship_states = ['confirmed', 'wait_pay', 'under_refund', 'under_replacement', 'replacement_done']
for record in self:
if any(key in vals for key in ['is_work', 'is_married', 'member_location_conf']):
if vals.get('is_work') or vals.get('is_married') or vals.get('member_location_conf') is False:
# Search in donations.details.lines where this member is either benefit_id or in benefit_ids
lines = self.env['donations.details.lines'].sudo().search([
'|',
('benefit_id', '=', record.id),
('benefit_ids', 'in', [record.id])
])
for line in lines:
# Get related sponsorship
sponsorship = line.sponsorship_mechanism_id or line.sponsorship_id
if sponsorship and sponsorship.state in sponsorship_states:
sponsor = sponsorship.sponsor_id or sponsorship.member_id
mobile = sponsor.mobile if sponsor else None
if mobile:
self.send_whatsapp_message(mobile, record.name)
break
return res
def send_whatsapp_message(self, mobile, member_name):
config = self.env['ir.config_parameter'].sudo()
account_sid = config.get_param('odex_takaful.twilio_account_sid')
auth_token = config.get_param('odex_takaful.twilio_auth_token')
from_whatsapp = config.get_param('odex_takaful.twilio_from_whatsapp')
if not account_sid or not auth_token or not from_whatsapp:
raise ValidationError(_("Twilio configuration is missing. Please configure Twilio SID, Auth Token, and WhatsApp number in General Configurations."))
from_cleaned_mobile = re.sub(r'[^\d+]', '', from_whatsapp)
from_whatsapp_number = f'whatsapp:{from_cleaned_mobile}'
message = "تنبيه: اليتيم الحالي [NAME] أصبح غير مستحق لأسباب محددة ويجب الاستبدال بيتيم اخر."
message = message.replace("[NAME]", member_name) # Clean the number (keep + and digits only)
cleaned_mobile = re.sub(r'[^\d+]', '', mobile)
to_whatsapp_number = f'whatsapp:{cleaned_mobile}'
url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Messages.json"
payload = {
'From': from_whatsapp_number,
'To': to_whatsapp_number,
'Body': message,
}
response = requests.post(url, data=payload, auth=(account_sid, auth_token))
if response.status_code != 201:
raise ValidationError(_("Failed to send WhatsApp message: %s") % response.text)
class ReplacementProcessLine(models.Model):
_name = 'replacement.process.line'
_description = 'Replacement ProcessLine'
members_domain_ids = fields.Many2many(comodel_name='family.member')
from_benefit_id = fields.Many2one('family.member', string="From Benefit")
to_benefit_id = fields.Many2one('family.member', string="To Benefit", domain = "[('id', 'in',members_domain_ids)]")
from_benefit_ids = fields.Many2many('family.member', 'replacement_process_from_benefit_wiz_rel', 'line_id', 'benefit_id', string="From Benefits (Group)")
to_benefit_ids = fields.Many2many('family.member', 'replacement_process_to_benefitwiz__rel', 'line_id', 'benefit_id', string="To Benefits (Group)", domain = "[('id', 'in',members_domain_ids)]")
sponsorship_type = fields.Selection([('person', 'Individual'),('group', 'Group')],string='Sponsorship Type')
process_id = fields.Many2one('replacement.process', string="Wizard")
@api.constrains('from_benefit_ids', 'to_benefit_ids')
def onchange_from_to_constrain(self):
for rec in self:
if len(self.from_benefit_ids) != len(self.to_benefit_ids):
raise ValidationError(
_("You must select the same number of beneficiaries in the from benefits group (%s) to the to benefits group (%s)" % (
", ".join(self.from_benefit_ids.mapped('name')),
", ".join(self.to_benefit_ids.mapped('name')))))
class GrantBenefit(models.Model):
_inherit = 'grant.benefit'
replaced = fields.Boolean('Replaced')
def action_open_replacements(self):
self.ensure_one()
return {
'type': 'ir.actions.act_window',
'name': 'Replacement Process',
'view_mode': 'tree,form',
'res_model': 'replacement.process',
'domain': [('family_ids', 'in', [self.id])],
}