odex25_standard/odex25_takaful/odex_takaful/wizards/esterdad.py

273 lines
13 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError, Warning
import logging
import random
import requests
from odoo import SUPERUSER_ID
from datetime import datetime, date, timedelta
_logger = logging.getLogger(__name__)
class EsterdadWizard(models.Model):
_name = "esterdad.wizard"
amount = fields.Monetary(currency_field='currency_id', compute='_get_total_sponsorship_amount')
currency_id = fields.Many2one(
'res.currency',
string="Currency",
required=True,
default=lambda self: self.env.company.currency_id
)
cancel_date = fields.Date()
pay_date = fields.Datetime(related='sponsor_id.pay_date')
cancel_reason = fields.Many2one('sponsorship.reason.stop')
another_reason = fields.Boolean()
reason = fields.Text()
sponsor_id = fields.Many2one('takaful.sponsorship')
journal_entry_ids = fields.Many2many('account.move', domain="[('id', 'in', allowed_journal_entry_ids)]")
allowed_journal_entry_ids = fields.Many2many('account.move', compute='_compute_allowed_journal_entry_ids')
sponsor_name = fields.Char()
mobile = fields.Char(required=True)
id_num = fields.Char()
payment_ids = fields.Many2many('account.payment', compute='_compute_payment_ids')
# allowed_payment_ids = fields.Many2many(
# 'account.payment',
# 'esterdad_wizard_allowed_payment_rel',
# 'wizard_id',
# 'payment_id',
# string="Allowed Payments",
# )
confirmed = fields.Boolean()
@api.depends('sponsor_id')
def _compute_allowed_journal_entry_ids(self):
for rec in self:
refund_hour_limit = self.env['ir.config_parameter'].sudo().get_param('odex_takaful.cancel_refund', default=0)
limit_refund_date_time = fields.Datetime.now() - timedelta(hours=int(refund_hour_limit))
# rec.allowed_journal_entry_ids = rec.sponsor_id.journal_entry_ids.ids
rec.allowed_journal_entry_ids = rec.sponsor_id.journal_entry_ids.filtered(lambda r:
r.move_type == 'out_invoice' and\
r.payment_state == 'paid' and\
r.create_date >= limit_refund_date_time).ids
@api.depends('journal_entry_ids')
def _compute_payment_ids(self):
for rec in self:
rec.payment_ids = [(6, 0, rec.journal_entry_ids._get_reconciled_payments().ids)]
# @api.onchange('sponsor_id')
# def _onchange_sponsor_id_set_payment_domain(self):
# """Limit available payments to same partner within restriction_period days."""
# for rec in self:
# domain = []
# partner = False
# invoice_names = []
# if rec.sponsor_id:
# # Assuming sponsor_id.sponsor_id is the related partner on the sponsorship
# partner = getattr(rec.sponsor_id, 'sponsor_id', False) or getattr(rec.sponsor_id, 'partner_id', False)
# # Get all invoices from journal_entry_ids where move_type is 'out_invoice'
# invoices = rec.sponsor_id.journal_entry_ids.filtered(lambda inv: inv.move_type == 'out_invoice')
# # Get all invoice names (numbers) in a list
# invoice_names = invoices.mapped('name')
# if partner:
# # Get restriction period (in days) from config parameters
# sudo_conf = self.env['ir.config_parameter'].sudo()
# restriction_period = sudo_conf.get_param('odex_takaful.restriction_period')
# try:
# restriction_period = int(restriction_period or 0)
# except (TypeError, ValueError):
# restriction_period = 0
# if restriction_period and restriction_period > 0:
# limit_date = date.today() - timedelta(days=restriction_period)
# domain = [
# ('partner_id', '=', partner.id),
# ('date', '>=', limit_date),
# ]
# else:
# # If no restriction configured, just filter by partner
# domain = [('partner_id', '=', partner.id)]
# # Add filter for ref field to match invoice names if we have any
# if invoice_names:
# domain.append(('ref', 'in', invoice_names))
# # If we have a domain, fetch the matching payments and store them
# # in the helper field, then use their IDs as the domain.
# if domain:
# payments = self.env['account.payment'].search(domain)
# rec.allowed_payment_ids = payments
# return {'domain': {'payment_ids': [('id', 'in', payments.ids)]}}
# else:
# rec.allowed_payment_ids = False
# return {'domain': {'payment_ids': []}}
def action_confirm_refund(self):
for rec in self:
sponsor_phone = rec.mobile
if sponsor_phone:
company_id = rec.env.company
# Generate OTP & send it
otp = 1111
if company_id.sms_mode == 'test':
_logger.info(f"--- SMS TEST MODE --- OTP for mobile {sponsor_phone} is {otp}. SMS not sent.")
else:
otp = str(random.randint(1000, 9999))
payload = {
"recipients": [sponsor_phone],
"body": f"Your OTP code is: {otp}",
"sender": company_id.sms_sender_name,
}
headers = {
"Authorization": f"Bearer {company_id.sms_api_token}",
"Content-Type": "application/json",
}
try:
response = requests.post(company_id.sms_api_url, json=payload, headers=headers, timeout=10)
response.raise_for_status() # Raise an error for non-2xx responses
_logger.info(f"OTP {otp} sent successfully to {sponsor_phone}")
except requests.exceptions.RequestException as e:
_logger.error(f"Failed to send OTP to {sponsor_phone}: {e}")
raise ValidationError("Failed to send OTP. Please check API configuration or try again later.")
##################
context = dict(self.env.context or {})
# context['default_user_id'] = user.id
context['default_otp'] = otp
context['default_esterdad_id'] = rec.id
context['default_invoice_ids'] = rec.journal_entry_ids.ids
context['default_cancel_reason'] = rec.cancel_reason.name if not rec.another_reason else rec.reason
rec.sponsor_id.write({
'cancel_record_id': rec.id
})
rec.sponsor_id.sponsor_id.write({
'first_name': rec.sponsor_name
})
if rec.sponsor_id.sponsor_or_donor_type == 'unknown' and not rec.sponsor_id.sponsor_phone:
rec.sponsor_id.sponsor_phone = rec.mobile
if rec.sponsor_id.sponsor_or_donor_type == 'registered' and rec.id_num:
rec.sponsor_id.sponsor_id.id_number == rec.id_num
# context['default_payment_ids'] = [(6, 0, rec.payment_ids.ids)]
view = self.env.ref('odex_takaful.view_otp_wizard_form')
return {
'name': _('OTP Confirmation'),
'view_mode': 'form',
'view_type': 'form',
'type': 'ir.actions.act_window',
'res_model': 'otp.confirmation.wizard',
'view_id': view.id,
'target': 'new',
'context': context,
}
else:
raise UserError(_("Mobile is required!"))
@api.depends('payment_ids')
def _get_total_sponsorship_amount(self):
for rec in self:
rec.amount = sum(rec.payment_ids.mapped('amount'))
class OTPWizard(models.TransientModel):
_name = "otp.confirmation.wizard"
otp = fields.Integer()
otp_code = fields.Integer()
esterdad_id = fields.Many2one('esterdad.wizard')
# user_id = fields.Many2one('res.users')
invoice_ids = fields.Many2many('account.move')
# payment_ids = fields.Many2many(
# 'account.payment',
# string="Payments"
# )
cancel_reason = fields.Text()
def action_confirm_otp(self):
for rec in self:
if rec.otp == rec.otp_code:
sponsor_ship = rec.esterdad_id.sponsor_id
rec.esterdad_id.cancel_date = date.today()
if sponsor_ship:
# # Get ref values from selected payments
# payment_refs = rec.payment_ids.mapped('ref')
# # Filter out empty/False refs
# payment_refs = [ref for ref in payment_refs if ref]
# if not payment_refs:
# raise UserError(_("No references found in selected payments"))
# # Search for invoices in account.move matching payment refs
# invoices = self.env['account.move'].search([
# ('name', 'in', payment_refs),
# ])
if not rec.invoice_ids:
raise UserError(_("No invoices matching the specified references"))
for invoice in rec.invoice_ids:
credit = self.env['account.move.reversal'].with_company(self.env.user.company_id.id).create({
'refund_method': 'refund',
'date': date.today(),
'date_mode': 'custom',
'move_ids': [invoice.id],
})
x = credit.reverse_moves()
sponsor_ship.state = 'canceled'
domain_ids = x.get('res_id')
if domain_ids:
last_id = domain_ids
sponsor_ship.write({
'journal_entry_ids': [(4, last_id)]
})
credit_note = self.env['account.move'].search([('id', '=', last_id)])
credit_note.action_post()
credit_note.write({
'esterdad_id': rec.esterdad_id.id,
'sponsorship_cancel_reason': rec.cancel_reason
})
rec.esterdad_id.confirmed = True
rec.esterdad_id.sponsor_id.is_canceled_refund = True
# Get all donation lines from donations_details_lines and donations_details_lines_mechanism_ids
all_donation_lines = sponsor_ship.donations_details_lines | sponsor_ship.donations_details_lines_mechanism_ids
# Set state to 'cancel' for all donation lines
if all_donation_lines:
all_donation_lines.write({'state': 'cancel'})
all_donation_lines.mapped('benefit_id').write({'kafala_status': 'have_not_kafala',
'sponsor_related_id': False,
'sponsorship_end_date': fields.Date.today(),
})
# Process extension history for each donation line
for donation_line in all_donation_lines:
# Get extension_history_ids for this donation line
extension_histories = donation_line.extension_history_ids
if extension_histories:
# Set state to 'cancel' for all extension histories
extension_histories.write({'state': 'cancel'})
total_extension_months = 0
current_payment_month_count = 0
new_payment_month_count = 0
# Sum all extension_months
total_extension_months = sum(extension_histories.mapped('extension_months'))
# Subtract the sum from payment_month_count
if total_extension_months > 0:
current_payment_month_count = donation_line.payment_month_count or 0
new_payment_month_count = current_payment_month_count - total_extension_months
# Ensure it doesn't go below 0
donation_line.write({
'payment_month_count': max(0, new_payment_month_count)
})
else:
raise UserError(_("The entered number is incorrect"))