273 lines
13 KiB
Python
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"))
|