231 lines
11 KiB
Python
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])],
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|