Merge branch 'dev_odex25_ensan' into you_dev_odex25_ensan
This commit is contained in:
commit
b5c697507d
|
|
@ -36,7 +36,7 @@ jobs:
|
|||
# Ensan Project
|
||||
ensan_master_server:
|
||||
name: Deploy to Ensan Master
|
||||
runs-on: ensan-client-project-runner
|
||||
runs-on: new-ensan-vpn-client-server-runner
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'Ensan-Project' && (github.ref == 'refs/heads/master_odex-event' || github.ref == 'refs/heads/master_odex25_helpdesk' || github.ref == 'refs/heads/master_odex25_accounting' || github.ref == 'refs/heads/master_odex25_base' || github.ref == 'refs/heads/master_odex25_dms' || github.ref == 'refs/heads/master_odex25_fleet' || github.ref == 'refs/heads/master_odex25_ENSAN' || github.ref == 'refs/heads/master_odex25_hr' || github.ref == 'refs/heads/master_odex25_inventory' || github.ref == 'refs/heads/master_odex25_maintenance' || github.ref == 'refs/heads/master_odex25_mobile' || github.ref == 'refs/heads/master_odex25_pos' || github.ref == 'refs/heads/master_odex25_project' || github.ref == 'refs/heads/master_odex25_purchase' || github.ref == 'refs/heads/master_odex25_realstate' || github.ref == 'refs/heads/master_odex25_sales' || github.ref == 'refs/heads/master_odex25_survey' || github.ref == 'refs/heads/master_odex25_transactions' || github.ref == 'refs/heads/master_odex25_website' || github.ref == 'refs/heads/master_openeducat_erp-14.0.1.0' || github.ref == 'refs/heads/master_odex25_ensan') &&
|
||||
(github.actor == 'moutazmuhammad' ||
|
||||
github.actor == 'expsa' ||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class ServicesSettings(models.Model):
|
|||
help='Link the service to an HR department'
|
||||
)
|
||||
hr_department_id = fields.Many2one(
|
||||
'hr.department', string='Linked Department', readonly=True
|
||||
'hr.department', string='Linked Department'
|
||||
)
|
||||
manager_id = fields.Many2one(
|
||||
'hr.employee', string='Manager',
|
||||
|
|
@ -29,59 +29,6 @@ class ServicesSettings(models.Model):
|
|||
])
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
service = super().create(vals)
|
||||
if service.linked_to_department:
|
||||
dept = self.env['hr.department'].search([('name', '=', service.service_name)], limit=1)
|
||||
if not dept:
|
||||
dept = self.env['hr.department'].create({
|
||||
'name': service.service_name,
|
||||
'department_type': 'unit',
|
||||
'manager_id': service.manager_id.id,
|
||||
|
||||
'service_link_id': service.id
|
||||
})
|
||||
service.hr_department_id = dept.id
|
||||
return service
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
for service in self:
|
||||
# If linked_to_department field updated
|
||||
if 'linked_to_department' in vals:
|
||||
if service.linked_to_department and not service.hr_department_id:
|
||||
# Create department if missing
|
||||
dept = self.env['hr.department'].search([('name', '=', service.service_name)], limit=1)
|
||||
if not dept:
|
||||
dept = self.env['hr.department'].create({
|
||||
'name': service.service_name,
|
||||
'department_type': 'unit',
|
||||
'manager_id': service.manager_id.id,
|
||||
'service_link_id': service.id
|
||||
})
|
||||
service.hr_department_id = dept.id
|
||||
elif not service.linked_to_department and service.hr_department_id:
|
||||
# Remove linked department if no dependencies (employees or requests)
|
||||
hr_dept = service.hr_department_id
|
||||
empowerment_request = self.env['empowerment.request'].search([('department_id', '=', hr_dept.id)], limit=1)
|
||||
if hr_dept.employee_ids or empowerment_request:
|
||||
raise ValidationError(_('لا يمكن فك الربط، قسم الموارد البشرية مرتبط بموظفين أو طلبات.'))
|
||||
hr_dept.unlink()
|
||||
service.hr_department_id = False
|
||||
return res
|
||||
|
||||
def unlink(self):
|
||||
for service in self:
|
||||
if service.linked_to_department and service.hr_department_id:
|
||||
hr_dept = service.hr_department_id
|
||||
empowerment_request = self.env['empowerment.request'].search([('department_id', '=', hr_dept.id)], limit=1)
|
||||
if hr_dept.employee_ids or empowerment_request:
|
||||
raise ValidationError(_('لا يمكن حذف الخدمة، القسم مرتبط بموظفين أو طلبات.'))
|
||||
hr_dept.unlink()
|
||||
return super().unlink()
|
||||
|
||||
|
||||
class HrDepartment(models.Model):
|
||||
_inherit = 'hr.department'
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<group>
|
||||
|
||||
<field name="linked_to_department" />
|
||||
<field name="hr_department_id" readonly="1" />
|
||||
<field name="hr_department_id"/>
|
||||
<field name="manager_id" />
|
||||
</group>
|
||||
|
||||
|
|
|
|||
|
|
@ -124,8 +124,11 @@ class CreatePortalAccount(http.Controller):
|
|||
|
||||
# Create the grant.benefit record and let its create flow run
|
||||
grant_benefit = request.env['grant.benefit'].sudo().with_context(force_website=True, is_benefit=True).create(benefit_data)
|
||||
else:
|
||||
grant_benefit = None
|
||||
elif account_type == 'donor':
|
||||
request.env['takaful.sponsor'].sudo().create({
|
||||
'partner_id': partner.id,
|
||||
'user_id': user.id,
|
||||
})
|
||||
|
||||
# Return success response
|
||||
data = {
|
||||
|
|
|
|||
|
|
@ -9854,6 +9854,7 @@ msgstr "احتساب قيمة الإيجار"
|
|||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_grant_benefit__rent_attachment
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__member_rent_attachment
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_attachment
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__rent_attachment
|
||||
msgid "Rent Attachment"
|
||||
msgstr "مرفق عقد الإيجار"
|
||||
|
|
@ -9865,6 +9866,7 @@ msgstr "معلومات عقد الإيجار"
|
|||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__member_rent_contract_number
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_contract_number
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__rent_contract_number
|
||||
msgid "Rent Contract Number"
|
||||
msgstr "رقم العقد"
|
||||
|
|
@ -9872,6 +9874,7 @@ msgstr "رقم العقد"
|
|||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_grant_benefit__rent_end_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__member_rent_end_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_end_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__rent_end_date
|
||||
msgid "Rent End Date"
|
||||
msgstr "تاريخ نهاية العقد"
|
||||
|
|
@ -9905,6 +9908,7 @@ msgstr "سكن مشترك إيجار"
|
|||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_grant_benefit__rent_start_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__member_rent_start_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_start_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__rent_start_date
|
||||
msgid "Rent Start Date"
|
||||
msgstr "تاريخ بداية العقد"
|
||||
|
|
@ -10072,6 +10076,7 @@ msgstr ""
|
|||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_grant_benefit__required_attach
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_services_settings__required_attach
|
||||
msgid "Required Attach"
|
||||
msgstr "ملفات مطلوبة"
|
||||
|
||||
|
|
@ -10114,7 +10119,7 @@ msgstr "الاخصائي الاجتماعي"
|
|||
#. module: odex_benefit
|
||||
#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_form
|
||||
msgid "Reset"
|
||||
msgstr ""
|
||||
msgstr "إرجاع"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: code:addons/odex_benefit/models/benefit.py:0
|
||||
|
|
@ -10257,7 +10262,7 @@ msgstr ""
|
|||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_grant_benefit__sa_iban
|
||||
msgid "SA"
|
||||
msgstr ""
|
||||
msgstr "الايبان"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_benefits_representative__is_seo_optimized
|
||||
|
|
@ -15943,6 +15948,30 @@ msgstr "سنوات"
|
|||
msgid "Max Amount"
|
||||
msgstr "الحد الأقصى للمبلغ"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields.selection,name:odex_benefit.selection__confirm_benefit_expense__state__assistant_general_manager
|
||||
msgid "Waiting For The Assistant General Manager"
|
||||
msgstr "بإنتظار مساعد المدير العام"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_confirm_benefit_expense__start_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_start
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__start
|
||||
msgid "Start Date"
|
||||
msgstr "تاريخ البداية"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_confirm_benefit_expense__end_date
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__end
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_end
|
||||
msgid "End Date"
|
||||
msgstr "تاريخ النهاية"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_grant_benefit__last_disbursement_date
|
||||
msgid "Last disbursement date"
|
||||
msgstr "تاريخ أخر صرف"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model_terms:ir.ui.view,arch_db:odex_benefit.services_settings_form
|
||||
msgid "Amounts by Categories"
|
||||
|
|
@ -16366,4 +16395,40 @@ msgstr "موافقة الإدارة القانونية"
|
|||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_services_settings__needs_project_management_approval
|
||||
msgid "Needs Project Management Approval"
|
||||
msgstr "موافقة إدارة المشاريع"
|
||||
msgstr "موافقة إدارة المشاريع"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model_terms:ir.ui.view,arch_db:odex_benefit.services_settings_form
|
||||
msgid "Services Attachments"
|
||||
msgstr "المستندات المطلوبة"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_payment_date_exception
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__rent_payment_date_exception
|
||||
msgid "Rent Payment Date Exception?"
|
||||
msgstr "استثناء في تاريخ دفع الإيجار؟"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__rent_amount_payment
|
||||
msgid "Rent Amount Payment"
|
||||
msgstr "مبلغ دفع الإيجار"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_contract
|
||||
msgid "New Rent Contract?"
|
||||
msgstr "عقد إيجار جديد؟"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__estimated_rent_amount_payment
|
||||
msgid "Estimated Rent Amount Payment"
|
||||
msgstr "المبلغ التقديري لدفع الإيجار"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_form
|
||||
msgid "New Rent Contract Information"
|
||||
msgstr "معلومات عقد الإيجار الجديد"
|
||||
|
||||
#. module: odex_benefit
|
||||
#: model:ir.model.fields,field_description:odex_benefit.field_service_request__new_rent_amount_payment
|
||||
msgid "New Rent Amount Payment"
|
||||
msgstr "مبلغ دفع الإيجار الجديد"
|
||||
|
|
|
|||
|
|
@ -609,6 +609,7 @@ class GrantBenefitProfile(models.Model):
|
|||
related='company_id.currency_id')
|
||||
family_edit = fields.Boolean(string='Family Edit', default=False)
|
||||
family_return_reason = fields.Text(string="Family Return Reason")
|
||||
last_disbursement_date = fields.Date(string="Last disbursement date", readonly=True)
|
||||
|
||||
_sql_constraints = [
|
||||
('unique_code', "unique (code) WHERE state NOT IN ('draft', 'new')", 'This code already exists')
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import date_utils
|
||||
|
||||
|
||||
class ConfirmBenefitExpense(models.Model):
|
||||
|
|
@ -10,9 +10,24 @@ class ConfirmBenefitExpense(models.Model):
|
|||
_description = 'Confirm Benefit Expense'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
|
||||
# region [Default Methods]
|
||||
|
||||
def _default_start_date(self):
|
||||
today = fields.Date.today()
|
||||
start_date = date_utils.start_of(today, 'month')
|
||||
return start_date
|
||||
|
||||
def _default_end_date(self):
|
||||
today = fields.Date.today()
|
||||
end_date = date_utils.end_of(today, 'month')
|
||||
return end_date
|
||||
|
||||
# endregion [Default Methods]
|
||||
|
||||
family_expense_seq = fields.Char(string="Family Expense Sequence", copy=False, readonly=True, default=lambda x: _('New'))
|
||||
state = fields.Selection(selection=[
|
||||
('draft', 'Draft'),
|
||||
('assistant_general_manager', 'Waiting For The Assistant General Manager'), # Translate
|
||||
('depart_manager', 'Department Manager'),
|
||||
('account_manager', 'Account Manager'),
|
||||
('cancel', 'Cancelled'),
|
||||
|
|
@ -25,8 +40,10 @@ class ConfirmBenefitExpense(models.Model):
|
|||
journal_id = fields.Many2one(comodel_name='account.journal', string="Journal", required=True,copy=False)
|
||||
|
||||
name = fields.Char(string="Name", states={'confirm': [('readonly', True)]}, copy=False)
|
||||
date = fields.Date(string="Date", default=fields.Date.context_today, required=True,
|
||||
date = fields.Date(string="Date", default=fields.Date.context_today, required=False,
|
||||
states={'confirm': [('readonly', True)]})
|
||||
start_date = fields.Date(string="Start Date", default=_default_start_date, required=True)
|
||||
end_date = fields.Date(string="End Date", required=True, default=_default_end_date)
|
||||
|
||||
family_ids = fields.Many2many(comodel_name='grant.benefit', relation='benefit_expense_grant_rel',
|
||||
column1='expense_id',
|
||||
|
|
@ -82,7 +99,7 @@ class ConfirmBenefitExpense(models.Model):
|
|||
# else:
|
||||
# record.family_ids = [(5,)] # Clear the records if source_field is empty
|
||||
|
||||
@api.depends('expense_type', 'date', 'branch_custom_id')
|
||||
@api.depends('expense_type', 'date', 'branch_custom_id', 'start_date', 'end_date')
|
||||
def _compute_domain_ids(self):
|
||||
for rec in self:
|
||||
journal_domain = []
|
||||
|
|
@ -105,14 +122,15 @@ class ConfirmBenefitExpense(models.Model):
|
|||
if rec.expense_type == 'family_invoice':
|
||||
base_domain.append(('meal_card', '=', True))
|
||||
|
||||
if rec.date:
|
||||
# if rec.date:
|
||||
if rec.start_date and rec.end_date:
|
||||
# Calculate the start date for the past month range
|
||||
month_ago = rec.date - relativedelta(months=1)
|
||||
# month_ago = rec.date - relativedelta(months=1)
|
||||
|
||||
# Search for conflicting records of the same expense type within the past month
|
||||
conflicting_records = self.search([
|
||||
('date', '>=', month_ago),
|
||||
('date', '<=', rec.date),
|
||||
('date', '>=', rec.start_date),
|
||||
('date', '<=', rec.end_date),
|
||||
('expense_type', '=', rec.expense_type),
|
||||
])
|
||||
|
||||
|
|
@ -152,6 +170,28 @@ class ConfirmBenefitExpense(models.Model):
|
|||
else:
|
||||
self.journal_id = False
|
||||
|
||||
def action_assistant_manager(self):
|
||||
if self.expense_type != 'family_expense':
|
||||
self.state = 'assistant_general_manager'
|
||||
return
|
||||
|
||||
disbursement_date = False
|
||||
# if not disbursement_date:
|
||||
last_expense = self.search(
|
||||
[("state", "=", "confirm"), ("end_date", "!=", False)],
|
||||
order="id desc",
|
||||
limit=1
|
||||
)
|
||||
if last_expense:
|
||||
disbursement_date = last_expense.end_date
|
||||
|
||||
# Apply the disbursement date to all families
|
||||
if disbursement_date:
|
||||
for family in self.family_ids:
|
||||
family.last_disbursement_date = disbursement_date
|
||||
|
||||
self.state = 'assistant_general_manager'
|
||||
|
||||
def action_depart_manager(self):
|
||||
self.state = 'depart_manager'
|
||||
|
||||
|
|
@ -246,7 +286,7 @@ class ConfirmBenefitExpense(models.Model):
|
|||
# for pay in self:
|
||||
# pay.available_payment_method_line_ids = pay.journal_id._get_available_payment_method_lines('outbound')
|
||||
|
||||
@api.onchange('expense_type', 'date', 'branch_custom_id')
|
||||
@api.onchange('expense_type', 'date', 'branch_custom_id', 'start_date', 'end_date')
|
||||
def _onchange_expense_type(self):
|
||||
"""Restrict families to a single expense type per month."""
|
||||
journal_domain = []
|
||||
|
|
@ -270,14 +310,15 @@ class ConfirmBenefitExpense(models.Model):
|
|||
if self.expense_type == 'family_invoice':
|
||||
base_domain.append(('meal_card', '=', True))
|
||||
|
||||
if self.date:
|
||||
# if self.date:
|
||||
if self.start_date and self.end_date:
|
||||
# Calculate the start date for the past month range
|
||||
month_ago = self.date - relativedelta(months=1)
|
||||
|
||||
# Search for conflicting records of the same expense type within the past month
|
||||
conflicting_records = self.search([
|
||||
('date', '>=', month_ago),
|
||||
('date', '<=', self.date),
|
||||
('date', '>=', self.start_date),
|
||||
('date', '<=', self.end_date),
|
||||
('expense_type', '=', self.expense_type),
|
||||
])
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ class ServiceRequest(models.Model):
|
|||
member_id = fields.Many2one('family.member',domain="[('benefit_id','=',family_id)]",string='Member')
|
||||
description = fields.Char(string='Description')
|
||||
need_status = fields.Selection(string='Need Status',selection=[('urgent', 'urgent'),('not_urgent', 'Not urgent')])
|
||||
main_service_category = fields.Many2one('services.settings',domain="[('is_main_service','=',True)]",string="Main Service Category")
|
||||
sub_service_category = fields.Many2one('services.settings',domain="[('is_main_service','=',False),('service_type','=',False),('parent_service','=',main_service_category)]",string='Sub Service Category')
|
||||
main_service_category = fields.Many2one('services.settings',domain="[('service_type','=','main_service')]",string="Main Service Category")
|
||||
sub_service_category = fields.Many2one('services.settings',domain="[('service_type','=','main_service'),('service_type','=',False),('parent_service','=',main_service_category)]",string='Sub Service Category')
|
||||
service_cat = fields.Many2one('services.settings',string='Service Cat.')
|
||||
available_service_cats = fields.Many2many('services.settings', compute='_compute_available_service_cats', store=True)
|
||||
service_attach = fields.Many2many('ir.attachment', 'rel_service_attachment_service_request', 'service_request_id','attachment_id', string='Service Attachment')
|
||||
|
|
@ -170,6 +170,28 @@ class ServiceRequest(models.Model):
|
|||
service_max_amount = fields.Float(string="Maximum Amount", copy=False)
|
||||
rent_period = fields.Integer('Rent Period')
|
||||
is_orphan = fields.Boolean(string='Orphaned (Both Parents Deceased)',compute='_compute_is_orphan',store=True)
|
||||
has_money_for_payment_is_appearance = fields.Boolean(string='Has money Field is appearance?',compute='_get_money_for_payment_is_appearance')
|
||||
has_money_for_payment = fields.Selection([('yes', 'Yes'), ('no', 'No')], string='Has money for payment?')
|
||||
has_money_to_pay_first_payment = fields.Selection([('yes', 'Yes'), ('no', 'No')],
|
||||
string='Has money to pay first payment?')
|
||||
has_money_field_is_appearance = fields.Boolean(string='Has money Field is appearance?',
|
||||
compute='_get_money_field_is_appearance')
|
||||
|
||||
@api.depends('requested_service_amount', 'service_max_amount')
|
||||
def _get_money_for_payment_is_appearance(self):
|
||||
for rec in self:
|
||||
if rec.requested_service_amount and rec.service_max_amount and rec.requested_service_amount > rec.service_max_amount:
|
||||
rec.has_money_for_payment_is_appearance = True
|
||||
else:
|
||||
rec.has_money_for_payment_is_appearance = False
|
||||
|
||||
@api.depends('requested_service_amount', 'service_max_amount')
|
||||
def _get_money_field_is_appearance(self):
|
||||
for rec in self:
|
||||
if rec.requested_service_amount and rec.service_max_amount and rec.requested_service_amount > rec.service_max_amount:
|
||||
rec.has_money_field_is_appearance = True
|
||||
else:
|
||||
rec.has_money_field_is_appearance = False
|
||||
|
||||
@api.depends('family_id.mother_marital_conf','family_id.replacement_mother_marital_conf')
|
||||
def _compute_is_orphan(self):
|
||||
|
|
@ -492,16 +514,21 @@ class ServiceRequest(models.Model):
|
|||
@api.onchange('member_id','family_id','eid_gift_benefit_count','service_cat')
|
||||
def _onchange_member(self):
|
||||
for rec in self:
|
||||
if rec.benefit_type == 'family' and rec.service_type == 'eid_gift':
|
||||
rec.requested_service_amount = rec.eid_gift_benefit_count * rec.service_cat.eid_gift_member_amount
|
||||
if rec.benefit_type == 'member' and rec.service_type == 'eid_gift':
|
||||
rec.requested_service_amount = rec.service_cat.eid_gift_member_amount
|
||||
if rec.benefit_type == 'family' and rec.service_type == 'winter_clothing':
|
||||
rec.requested_service_amount = rec.benefit_member_count * rec.service_cat.winter_clothing_member_amount
|
||||
if rec.benefit_type == 'member' and rec.service_type == 'winter_clothing':
|
||||
rec.requested_service_amount = rec.service_cat.winter_clothing_member_amount
|
||||
if rec.benefit_type == 'family' and rec.service_type == 'ramadan_basket':
|
||||
rec.requested_service_amount = rec.service_cat.ramadan_basket_member_amount
|
||||
if rec.family_id:
|
||||
if rec.benefit_type == 'family' and rec.service_type == 'eid_gift':
|
||||
rec.requested_service_amount = rec.eid_gift_benefit_count * rec.service_cat.eid_gift_member_amount
|
||||
if rec.benefit_type == 'member' and rec.service_type == 'eid_gift':
|
||||
rec.requested_service_amount = rec.service_cat.eid_gift_member_amount
|
||||
if rec.benefit_type == 'family' and rec.service_type == 'winter_clothing':
|
||||
rec.requested_service_amount = rec.benefit_member_count * rec.service_cat.winter_clothing_member_amount
|
||||
if rec.benefit_type == 'member' and rec.service_type == 'winter_clothing':
|
||||
rec.requested_service_amount = rec.service_cat.winter_clothing_member_amount
|
||||
if rec.benefit_type == 'family' and rec.service_type == 'ramadan_basket':
|
||||
rec.requested_service_amount = rec.service_cat.ramadan_basket_member_amount
|
||||
else:
|
||||
rec.member_id = False
|
||||
rec.service_cat = False
|
||||
rec.available_service_cats = False
|
||||
|
||||
|
||||
@api.onchange('service_cat','family_id')
|
||||
|
|
@ -538,7 +565,7 @@ class ServiceRequest(models.Model):
|
|||
interval = rec.service_cat.recurrence_interval or 1
|
||||
period = rec.service_cat.recurrence_period or 'months'
|
||||
max_limit_type = rec.service_cat.max_limit_type
|
||||
special_services = ['home_furnishing', 'electrical_devices']
|
||||
special_services = ['home_furnishing', 'electrical_devices','rent','alternative_housing']
|
||||
if rec.service_cat.service_type == 'buy_car':
|
||||
if rec.family_id.has_car:
|
||||
raise ValidationError(_("You cannot request this service because you have a car."))
|
||||
|
|
@ -841,7 +868,7 @@ class ServiceRequest(models.Model):
|
|||
ids.append(rec.id)
|
||||
default_service_ids = ids
|
||||
service_requests = self.env['service.request'].browse(ids)
|
||||
if any(request.state not in 'accounting_approve' for request in service_requests):
|
||||
if any(request.state not in 'send_request_to_supplier' for request in service_requests):
|
||||
raise UserError(_("All selected requests should be in Accounting Approve state"))
|
||||
if any(request.payment_order_id for request in service_requests):
|
||||
raise UserError(_("All selected requests should be not has payment order"))
|
||||
|
|
@ -861,7 +888,7 @@ class ServiceRequest(models.Model):
|
|||
ids.append(rec.id)
|
||||
service_requests = self.env['service.request'].browse(ids)
|
||||
service_producer_id = self.env['service.request'].search([('id','=',ids[0])],limit=1)
|
||||
if any(request.state not in 'family_received_device' for request in service_requests):
|
||||
if any(request.state not in 'approval_of_beneficiary_services' for request in service_requests):
|
||||
raise UserError(_("All selected requests should be in Family Received Device state"))
|
||||
if any(request.vendor_bill for request in service_requests):
|
||||
raise UserError(_("All selected requests should be not has Vendor Bill"))
|
||||
|
|
|
|||
|
|
@ -1431,6 +1431,7 @@
|
|||
<field name="family_monthly_meals"/>
|
||||
<field name="family_monthly_clotting"/>
|
||||
<field name="total_family_expenses"/>
|
||||
<field name="last_disbursement_date"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Family Cars">
|
||||
|
|
|
|||
|
|
@ -23,130 +23,135 @@
|
|||
<form string="Confirm Benefit Expense">
|
||||
<header>
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,depart_manager,account_manager,confirm"/>
|
||||
<button string="Cancel" type="object" name="action_cancel" class="oe_highlight"
|
||||
states="depart_manager,account_manager"/>
|
||||
<button string="Reset" type="object" name="action_reset_to_draft" class="oe_highlight"
|
||||
states="cancel"/>
|
||||
statusbar_visible="draft,assistant_general_manager,depart_manager,account_manager,confirm"/>
|
||||
<!-- <button string="Cancel" type="object" name="action_cancel" class="btn btn-danger"-->
|
||||
<!-- states="assistant_general_manager,depart_manager,account_manager"-->
|
||||
<!-- groups="odex_benefit.group_benefit_manager"/>-->
|
||||
<button string="Confirm" type="object" name="action_assistant_manager" class="oe_highlight"
|
||||
states="draft"/>
|
||||
<button string="Confirm" type="object" name="action_depart_manager" class="oe_highlight"
|
||||
states="draft" groups="odex25_account_payment_fix.group_depart_manager"/>
|
||||
states="assistant_general_manager" groups="odex25_account_payment_fix.group_depart_manager"/>
|
||||
<button string="Reset" type="object" name="action_reset_to_draft" class="btn btn-danger"
|
||||
states="assistant_general_manager" groups="odex25_account_payment_fix.group_depart_manager"/>
|
||||
<button string="Confirm" type="object" name="action_accounting_manager" class="oe_highlight"
|
||||
states="depart_manager" groups="odex25_account_payment_fix.group_accounting_manager"/>
|
||||
<button string="Reset" type="object" name="action_reset_to_draft" class="btn btn-danger"
|
||||
states="depart_manager" groups="odex25_account_payment_fix.group_accounting_manager"/>
|
||||
<button string="Confirm" type="object" name="action_confirm_selected" class="oe_highlight"
|
||||
states="account_manager" groups="odex25_account_payment_fix.group_general_manager"/>
|
||||
<button string="Reset" type="object" name="action_reset_to_draft" class="btn btn-danger"
|
||||
states="account_manager" groups="odex25_account_payment_fix.group_general_manager"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group invisible="1">
|
||||
<field name="family_domain_ids" widget="many2many_tags" />
|
||||
<field name="journal_domain_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button icon="fa-usd" name="action_open_related_move_records" type="object"
|
||||
attrs="{'invisible':[('expense_type','!=','family_expense')]}">
|
||||
<field name="total_moves" string="Moves" widget="statinfo"/>
|
||||
</button>
|
||||
<button icon="fa-usd" name="action_open_related_move_line_records" type="object"
|
||||
attrs="{'invisible':[('expense_type','!=','family_expense')]}">
|
||||
<field name="total_move_lines" string="Move Lines" widget="statinfo"/>
|
||||
</button>
|
||||
<button icon="fa-usd" name="action_open_related_invoice_records" type="object"
|
||||
attrs="{'invisible':[('expense_type','!=','family_invoice')]}">
|
||||
<field name="total_invoices" string="Invoices" widget="statinfo"/>
|
||||
</button>
|
||||
<field name="family_domain_ids" widget="many2many_tags" invisible="1"/>
|
||||
<field name="journal_domain_ids" widget="many2many_tags" invisible="1"/>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="family_expense_seq" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="family_expense_seq" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="expense_type" required="1"/>
|
||||
<field name="journal_id" required="1" domain="[('id', 'in', journal_domain_ids)]" attrs="{'invisible': [('expense_type', '!=', 'family_invoice')],'readonly':[('state', '=', 'confirm')]}" forec_save="1"/>
|
||||
<!-- <field name="payment_method_id" attrs="{'invisible': [('expense_type', '=', 'family_invoice')],'required': [('expense_type', '=', 'family_expense')]}"/>-->
|
||||
</group>
|
||||
<group>
|
||||
<field name="name" required="1" string="Process Details"/>
|
||||
<field name="date" required="1"/>
|
||||
<field name="branch_custom_id" required="1"/>
|
||||
<group>
|
||||
<field name="name" required="1" string="Process Details"
|
||||
attrs="{'readonly':[('state', '!=', 'draft')]}"/>
|
||||
<label for="start_date"/>
|
||||
<div>
|
||||
<field name="start_date"
|
||||
attrs="{'readonly':[('state', '!=', 'draft')]}"/>
|
||||
<strong><label for="end_date"/></strong>
|
||||
<field name="end_date"
|
||||
attrs="{'readonly':[('state', '!=', 'draft')]}"/>
|
||||
</div>
|
||||
<field name="branch_custom_id" required="1"
|
||||
attrs="{'readonly':[('state', '!=', 'draft')]}"/>
|
||||
<!-- <field name="payment_method_id" attrs="{'invisible': [('expense_type', '=', 'family_invoice')],'required': [('expense_type', '=', 'family_expense')]}"/>-->
|
||||
</group>
|
||||
<group>
|
||||
<field name="expense_type" required="1"/>
|
||||
<field name="journal_id" required="1" domain="[('id', 'in', journal_domain_ids)]"
|
||||
attrs="{'invisible': [('expense_type', '!=', 'family_invoice')]}" forec_save="1"/>
|
||||
<field name="date" required="1" attrs="{'readonly':[('state', '!=', 'draft')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Conditional fields based on expense_type -->
|
||||
<group>
|
||||
<group>
|
||||
<field name="available_payment_method_line_ids" invisible="1"/>
|
||||
<field name="cash_expense"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_invoice')]}"/>
|
||||
<field name="meal_expense"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_invoice')]}"/>
|
||||
<field name="cloth_expense"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_invoice')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="family_monthly_income"
|
||||
attrs="{'invisible': ['|',('expense_type', '=', 'family_invoice'),('cash_expense', '=', False)]}"/>
|
||||
<field name="family_monthly_meals" attrs="{'invisible': [('expense_type', '=', 'family_expense'),('meal_expense', '=', False)]}"/>
|
||||
<field name="family_monthly_clotting" attrs="{'invisible': ['|',('expense_type', '=', 'family_invoice'),('cloth_expense', '=', False)]}"/>
|
||||
</group>
|
||||
<field name="available_payment_method_line_ids" invisible="1"/>
|
||||
<field name="cash_expense"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_invoice')], 'readonly':[('state', '!=', 'draft')]}"/>
|
||||
<field name="meal_expense"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_invoice')], 'readonly':[('state', '!=', 'draft')]}"/>
|
||||
<field name="cloth_expense"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_invoice')], 'readonly':[('state', '!=', 'draft')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="family_monthly_income"
|
||||
attrs="{'invisible': ['|',('expense_type', '=', 'family_invoice'),('cash_expense', '=', False)]}"/>
|
||||
<field name="family_monthly_meals"
|
||||
attrs="{'invisible': [('expense_type', '=', 'family_expense'),('meal_expense', '=', False)]}"/>
|
||||
<field name="family_monthly_clotting"
|
||||
attrs="{'invisible': ['|',('expense_type', '=', 'family_invoice'),('cloth_expense', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<!-- Notebook with Families page -->
|
||||
<notebook>
|
||||
<page string="Families">
|
||||
<field name="family_ids" domain="[('id', 'in', family_domain_ids)]">
|
||||
<tree string="Family">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="sms_phone" optional="hide"/>
|
||||
<field name="researcher_id" optional="hide"/>
|
||||
<field name="sa_iban" />
|
||||
<!-- <field name="father_id_number" />-->
|
||||
<field name="meal_card"/>
|
||||
<field name="family_monthly_income"/>
|
||||
<field name="family_monthly_meals"/>
|
||||
<field name="family_monthly_clotting"/>
|
||||
<field name="total_family_expenses"/>
|
||||
<field name="father_id_number"/>
|
||||
<field name="sms_phone"/>
|
||||
<field name="benefit_member_count"/>
|
||||
<field name="non_member_count"/>
|
||||
<field name="researcher_id"/>
|
||||
<field name="last_visit_date"/>
|
||||
<field name="state"/>
|
||||
<field name="non_member_count" optional="hide"/>
|
||||
<field name="family_monthly_income" attrs="{'column_invisible': [('parent.expense_type', '!=', 'family_expense')]}"/>
|
||||
<field name="family_monthly_meals"/>
|
||||
<field name="family_monthly_clotting" attrs="{'column_invisible': [('parent.expense_type', '!=', 'family_expense')]}"/>
|
||||
<field name="total_family_expenses" attrs="{'column_invisible': [('parent.expense_type', '!=', 'family_expense')]}"/>
|
||||
<field name="last_disbursement_date" optional="hide"/>
|
||||
<!-- <field name="last_visit_date" optional="hide"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
|
||||
<field name="activity_ids" />
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
|
||||
<field name="activity_ids"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_confirm_benefit_expense_search">
|
||||
<field name="name">confirm.benefit.expense</field>
|
||||
<field name="model">confirm.benefit.expense</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<group string="Group By">
|
||||
<field name="name">confirm.benefit.expense</field>
|
||||
<field name="model">confirm.benefit.expense</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<group string="Group By">
|
||||
<filter string="Branch" name="branch_custom_id" context="{'group_by': 'branch_custom_id'}"/>
|
||||
</group>
|
||||
<separator/>
|
||||
<filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Depart Manager" name="depart_manager" domain="[('state', '=', 'depart_manager')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Account Manager" name="account_manager" domain="[('state', '=', 'account_manager')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Cancel" name="cancel" domain="[('state', '=', 'cancel')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Confirm" name="confirm" domain="[('state', '=', 'confirm')]"/>
|
||||
<separator/>
|
||||
</search>
|
||||
</field>
|
||||
</group>
|
||||
<separator/>
|
||||
<filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Depart Manager" name="depart_manager" domain="[('state', '=', 'depart_manager')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Account Manager" name="account_manager" domain="[('state', '=', 'account_manager')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Cancel" name="cancel" domain="[('state', '=', 'cancel')]"/>
|
||||
<separator/>
|
||||
<separator/>
|
||||
<filter string="Confirm" name="confirm" domain="[('state', '=', 'confirm')]"/>
|
||||
<separator/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action -->
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@
|
|||
<field name="education_status"/>
|
||||
<field name="benefit_id" attrs="{'readonly': [('state','!=','draft')]}" force_save="1"
|
||||
required="1"/>
|
||||
<field name="partner_id" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="is_work"
|
||||
|
|
|
|||
|
|
@ -18,18 +18,19 @@
|
|||
<field name="benefit_type" required="1"/>
|
||||
<field name="allow_non_beneficiary" widget="boolean_toggle"/>
|
||||
<field name="service_producer_id"
|
||||
attrs="{'invisible':['|',('is_main_service','=',True),('is_service_producer','=',False)]}"/>
|
||||
attrs="{'invisible':['|',('service_type','=','main_service'),('is_service_producer','=',False)]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="service_category"/>
|
||||
<field name="parent_service" attrs="{'invisible':[('is_main_service','=',True)]}"/>
|
||||
<field name="parent_service"
|
||||
attrs="{'invisible':[('service_type','=','main_service')]}"/>
|
||||
<field name="benefit_category_ids" widget="many2many_tags" required="1"/>
|
||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Settings">
|
||||
<page string="Settings" attrs="{'invisible':[('service_type','=','main_service')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="max_limit_type"/>
|
||||
|
|
@ -72,21 +73,24 @@
|
|||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="is_main_service" widget="boolean_toggle"/>
|
||||
<field name="is_main_service" invisible="1" widget="boolean_toggle"/>
|
||||
<field name="is_service_producer" widget="boolean_toggle"
|
||||
attrs="{'invisible':[('is_main_service','=',True)]}"/>
|
||||
<field name="is_this_service_for_student" widget="boolean_toggle"
|
||||
attrs="{'invisible':[('is_main_service','=',True)]}"/>
|
||||
attrs="{'invisible':[('service_type','=','main_service')]}"/>
|
||||
<field name="is_this_service_for_student" invisible="1"
|
||||
widget="boolean_toggle"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="required_attach" widget="boolean_toggle"
|
||||
attrs="{'invisible':[('is_main_service','=',True)]}"/>
|
||||
attrs="{'invisible':[('service_type','=','main_service')]}"/>
|
||||
<field name="is_seasonal_service" widget="boolean_toggle"/>
|
||||
<field name="show_in_portal" widget="boolean_toggle"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Accounts" attrs="{'invisible':[('is_main_service','=',True)]}">
|
||||
<page string="Accounts" attrs="{'invisible':[('service_type','=','main_service')]}">
|
||||
<group>
|
||||
<group>
|
||||
<field name="account_id"
|
||||
|
|
@ -97,7 +101,7 @@
|
|||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Eligibility Criteria">
|
||||
<page string="Eligibility Criteria" attrs="{'invisible':[('service_type','=','main_service')]}">
|
||||
<group>
|
||||
<field name="service_conditions"/>
|
||||
</group>
|
||||
|
|
@ -252,8 +256,9 @@
|
|||
<field name="name">services.settings.tree</field>
|
||||
<field name="model">services.settings</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Services Settings">
|
||||
<tree string="Services Settings" decoration-info="service_type=='main_service'">
|
||||
<field name="service_number"/>
|
||||
<field name="service_type" invisible="1"/>
|
||||
<field name="service_name"/>
|
||||
<field name="service_category"/>
|
||||
<field name="parent_service"/>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<field name="model">services.settings</field>
|
||||
<field name="inherit_id" ref="odex_benefit.services_settings_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='is_this_service_for_student']" position="after">
|
||||
<xpath expr="//field[@name='is_service_producer']" position="after">
|
||||
<field name="project_create" attrs="{'invisible':[('service_type','=','main_service')]}" widget="boolean_toggle"/>
|
||||
<field name="category_id" attrs="{'invisible': ['|',('service_type','=','main_service'),('project_create', '=', False)]}"/>
|
||||
</xpath>
|
||||
|
|
|
|||
|
|
@ -57,9 +57,11 @@
|
|||
'wizards/refund_payment_wizard.xml',
|
||||
'wizards/add_details_wizard.xml',
|
||||
'views/donations_details_lines.xml',
|
||||
'views/sponsorship_scheduling_line.xml',
|
||||
'views/takaful_menus_actions.xml',
|
||||
'views/preferred_communication.xml',
|
||||
'views/takaful_payment_method.xml',
|
||||
'views/product_views.xml',
|
||||
'data/message_template_data.xml',
|
||||
|
||||
'wizards/transfer_deduction_wizard_views.xml',
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -23,4 +23,5 @@ from . import res_partner
|
|||
from . import preferred_communication
|
||||
from . import takaful_payment_method
|
||||
from . import res_config_settings
|
||||
from . import product
|
||||
from . import product
|
||||
from . import donation_details_lines
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
from odoo import models, fields,api,_
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
|
|
@ -9,8 +8,23 @@ class AccountMove(models.Model):
|
|||
is_refund_sponsorship = fields.Boolean(string='Is Refund Sponsorship',default=False)
|
||||
sponsorship_scheduling_line = fields.Many2one('sponsorship.scheduling.line')
|
||||
payment_details_line = fields.Many2one('payment.details.lines')
|
||||
sponsorship_id = fields.Many2one('takaful.sponsorship',string='Sponsorship', readonly=True,)
|
||||
payment_id = fields.Many2one('account.payment',string='Payment', copy=False)
|
||||
|
||||
|
||||
def action_move_line_create(self):
|
||||
'''
|
||||
Confirm the vouchers given in ids and create the journal entries for each of them
|
||||
'''
|
||||
res = super(AccountMove, self).action_move_line_create()
|
||||
if res :
|
||||
self.write({'payment_id':self.move_id.line_ids.mapped('payment_id').id})
|
||||
|
||||
@api.onchange('payment_journal_id')
|
||||
def on_change_payment_journal_id(self):
|
||||
for rec in self:
|
||||
rec.account_id = rec.payment_journal_id.default_debit_account_id
|
||||
|
||||
def action_register_payment(self):
|
||||
''' Override the payment registration behavior. '''
|
||||
# Perform any custom logic before calling the original method
|
||||
|
|
@ -104,6 +118,145 @@ class AccountRegisterPayment(models.TransientModel):
|
|||
takaful_sponsorship_id = fields.Many2one('takaful.sponsorship')
|
||||
is_refund_sponsorship = fields.Boolean(string='Is Refund Sponsorship')
|
||||
|
||||
def _check_already_sponsored_beneficiaries(self, sponsorship_id):
|
||||
"""
|
||||
Check if any beneficiaries in the sponsorship lines are already sponsored
|
||||
Returns: recordset of conflicting donation lines
|
||||
"""
|
||||
sponsorship_id.ensure_one()
|
||||
|
||||
# Get all donation lines from the sponsorship
|
||||
all_lines = sponsorship_id.donations_details_lines_mechanism_ids
|
||||
|
||||
conflicting_lines = self.env['donations.details.lines']
|
||||
|
||||
for line in all_lines:
|
||||
# Skip lines without beneficiaries or non-sponsorship lines
|
||||
if line.donation_type != 'sponsorship':
|
||||
continue
|
||||
|
||||
# Check for individual beneficiary (person sponsorship)
|
||||
if line.benefit_id:
|
||||
if self._is_beneficiary_already_sponsored(line.benefit_id, line):
|
||||
conflicting_lines |= line
|
||||
continue
|
||||
|
||||
# Check for group beneficiaries
|
||||
if line.benefit_ids:
|
||||
for benefit in line.benefit_ids:
|
||||
if self._is_beneficiary_already_sponsored(benefit, line):
|
||||
conflicting_lines |= line
|
||||
break # No need to check other beneficiaries in this line
|
||||
|
||||
return conflicting_lines
|
||||
|
||||
|
||||
def _is_beneficiary_already_sponsored(self, beneficiary, current_line):
|
||||
"""
|
||||
Check if a specific beneficiary is already sponsored in active state
|
||||
Args:
|
||||
beneficiary: family.member record
|
||||
current_line: donations.details.lines record (to exclude from search)
|
||||
Returns: True if already sponsored, False otherwise
|
||||
"""
|
||||
if not beneficiary:
|
||||
return False
|
||||
|
||||
# Search for other active sponsorships with this beneficiary
|
||||
other_lines = self.env['donations.details.lines'].sudo().search([
|
||||
'|', ('sponsorship_id', '!=', False), ('sponsorship_mechanism_id', '!=', False),
|
||||
'|', ('benefit_id', '=', beneficiary.id), ('benefit_ids', 'in', [beneficiary.id]),
|
||||
('donation_type', '=', 'sponsorship'),
|
||||
('state', '=', 'active'), # Only check active sponsorships
|
||||
('id', '!=', current_line.id) # Exclude current line
|
||||
])
|
||||
|
||||
# Check if any of these lines belong to paid sponsorships
|
||||
for line in other_lines:
|
||||
sponsorship = line.sponsorship_id or line.sponsorship_mechanism_id
|
||||
if sponsorship and sponsorship.state == 'paid':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _create_payments(self):
|
||||
sponsorship_line_ids = self.env.context.get('sponsorship_line_ids')
|
||||
sponsorship_lines = []
|
||||
if sponsorship_line_ids:
|
||||
sponsorship_lines = self.env['donations.details.lines'].browse(sponsorship_line_ids)
|
||||
for line in sponsorship_lines:
|
||||
if line.record_type == 'sponsorship':
|
||||
for benefit in (line.benefit_id + line.benefit_ids):
|
||||
if self._is_beneficiary_already_sponsored(benefit, line):
|
||||
raise UserError(_("Cannot proceed with payment!\n\n"
|
||||
"The following sponsorship lines contain beneficiaries that are already sponsored by other sponsors:\n"
|
||||
"Lines: %s\n\n"
|
||||
"Please choose different beneficiaries for these lines before proceeding with the payment."
|
||||
) % line.sequence_no)
|
||||
|
||||
payments = super(AccountRegisterPayment, self)._create_payments()
|
||||
|
||||
if sponsorship_lines:
|
||||
sponsorship = sponsorship_lines.sponsorship_id or sponsorship_lines.sponsorship_mechanism_id
|
||||
all_lines = sponsorship.donations_details_lines_mechanism_ids + sponsorship.donations_details_lines
|
||||
|
||||
if not self.env.context.get('schedule_line_payment'):
|
||||
sponsorship_lines.write({'is_paid': True})
|
||||
|
||||
sponsorship_lines.filtered(lambda l: l.record_type == 'sponsorship' and (l.benefit_id + l.benefit_ids)).write({'state': 'active'})
|
||||
sponsorship_lines.filtered(lambda l: l.record_type == 'sponsorship' and not (l.benefit_id + l.benefit_ids)).write({'state': 'waiting'})
|
||||
sponsorship_lines.filtered(lambda l: l.record_type == 'donation').write({'state': 'paid'})
|
||||
|
||||
for line in sponsorship_lines:
|
||||
if line.record_type != 'sponsorship':
|
||||
continue
|
||||
if line.sponsorship_type == 'group':
|
||||
line.benefit_ids.write({'sponsor_related_id': line.sponsorship_mechanism_id.sponsor_id.id, 'sponsorship_id': line.sponsorship_mechanism_id.id})
|
||||
if line.sponsorship_type == 'person':
|
||||
line.benefit_id.write({'sponsor_related_id': line.sponsorship_mechanism_id.sponsor_id.id, 'sponsorship_id': line.sponsorship_mechanism_id.id})
|
||||
line.sponsorship_mechanism_id.sponsor_id.sudo().is_sponsor_portal = True
|
||||
|
||||
if 'draft' in all_lines.mapped('state'):
|
||||
sponsorship.state = 'wait_pay'
|
||||
else:
|
||||
sponsorship.state = 'paid'
|
||||
|
||||
payments.write({'takaful_sponsorship_id': sponsorship.id})
|
||||
vendor_bill_vals = []
|
||||
benefit_journal_id = self.env.company.kafala_benefit_journal_id.id
|
||||
for line in sponsorship_lines:
|
||||
for benefit in (line.benefit_id + line.benefit_ids):
|
||||
bill_values = {
|
||||
'takaful_sponsorship_id': line.sponsorship_id.id if line.sponsorship_id else line.sponsorship_mechanism_id.id,
|
||||
'name': self.env['ir.sequence'].next_by_code('account.move.accrsp'),
|
||||
'move_type': 'in_invoice',
|
||||
'journal_id': benefit_journal_id,
|
||||
'date': fields.Date.today(),
|
||||
'partner_id': benefit.partner_id.id,
|
||||
'invoice_line_ids': [(0, 0, {
|
||||
'product_id': line.product_id.id,
|
||||
'price_unit': line.donation_amount,
|
||||
'quantity': 1,
|
||||
'name': _("Benefit Number %s") % line.sequence_no,
|
||||
'analytic_account_id': line.sponsorship_id.branch_custom_id.branch.analytic_account_id.id,
|
||||
})]
|
||||
}
|
||||
vendor_bill_vals.append(bill_values)
|
||||
bill_id = self.env['account.move'].sudo().create(vendor_bill_vals)
|
||||
for line in bill_id.invoice_line_ids:
|
||||
line.account_id = line._get_computed_account()
|
||||
taxes = line._get_computed_taxes()
|
||||
if taxes and line.move_id.fiscal_position_id:
|
||||
taxes = line.move_id.fiscal_position_id.map_tax(taxes, partner=line.partner_id)
|
||||
line.tax_ids = taxes
|
||||
line.product_uom_id = line._get_computed_uom()
|
||||
|
||||
if self.env.context.get('schedule_line_id'):
|
||||
schedule_line = self.env['sponsorship.scheduling.line'].browse(self.env.context.get('schedule_line_id'))
|
||||
schedule_line.sudo().write({'status': 'paid'})
|
||||
|
||||
|
||||
return payments
|
||||
|
||||
def action_create_payments(self):
|
||||
# Call the original method to create payments
|
||||
|
|
@ -116,10 +269,14 @@ class AccountRegisterPayment(models.TransientModel):
|
|||
payment.move_id.takaful_sponsorship_id = self.takaful_sponsorship_id.id
|
||||
ctx = self.env.context.copy()
|
||||
|
||||
# You can update it as needed
|
||||
if self._context.get('dont_redirect_to_payments'):
|
||||
return True
|
||||
|
||||
|
||||
# You can update it as needed
|
||||
ctx.update({
|
||||
'create': False,
|
||||
})
|
||||
'create': False,
|
||||
})
|
||||
|
||||
# Prepare the action for redirection
|
||||
action = {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,656 @@
|
|||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError,UserError
|
||||
import re
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
class DonationsDetailsLines(models.Model):
|
||||
_name = "donations.details.lines"
|
||||
_inherit = ['mail.thread']
|
||||
|
||||
name = fields.Text(string="Note")
|
||||
display_type = fields.Selection([
|
||||
('line_section', "Section"),
|
||||
('line_note', "Note")], default=False, help="Technical field for UX purpose.")
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
sequence_no = fields.Char(default='/', readonly=True, copy=False)
|
||||
donation_type = fields.Selection([('donation', 'Donation'), ('waqf', 'Waqf'), ('sponsorship', 'Sponsorship'), ],string='Donation Type')
|
||||
donation_types = fields.Selection([('donation', 'Donation'), ('waqf', 'Waqf')],string='Donation Type')
|
||||
product_template_id = fields.Many2one('product.template', string="Donation Name", required=True)
|
||||
product_id = fields.Many2one('product.product', compute='_compute_product_id')
|
||||
sponsorship_id = fields.Many2one('takaful.sponsorship', string="Sponsorship")
|
||||
sponsorship_mechanism_id = fields.Many2one('takaful.sponsorship', string="Sponsorship")
|
||||
sponsorship_creation_date = fields.Datetime()
|
||||
donation_amount = fields.Float(string='Donation Amount', compute="_compute_donation_amount", store=True)
|
||||
donation_mechanism = fields.Selection([('with_conditions', _('With Conditions')),('without_conditions', _('Without Conditions'))],string='Donation Mechanism', readonly=True)
|
||||
benefit_type = fields.Selection([('orphan', 'Orphans'),('widow', 'Widows'),('both', 'Both')],string='Sponsorship Beneficiary Type',tracking=True)
|
||||
sponsorship_type = fields.Selection([('person', 'Individual'),('group', 'Group')],string='Sponsorship Type',tracking=True)
|
||||
gender = fields.Selection(selection=[('male', 'Male'), ('female', 'Female')], string="Gender")
|
||||
age_category_id = fields.Many2one('age.category', string='Age Category')
|
||||
education_status = fields.Selection(string='Education Status',selection=[('educated', 'educated'), ('illiterate', 'illiterate'),('under_study_age', 'Under Study Age')])
|
||||
education_level = fields.Many2one("education.level", string='Education Levels')
|
||||
members_domain_ids = fields.Many2many(comodel_name='family.member', compute='_compute_domain_ids')
|
||||
benefit_id = fields.Many2one('family.member',string='Beneficiary Name',ondelete='set null',domain = "[('id', 'in',members_domain_ids)]", tracking=True)
|
||||
family_id = fields.Many2one('grant.benefit',string='Family',ondelete='set null',related="benefit_id.benefit_id")
|
||||
benefit_ids = fields.Many2many('family.member',string='Beneficiaries Names', tracking=True)
|
||||
sponsorship_duration = fields.Selection([('temporary', 'Temporary'),('permanent', 'Permanent')],string='Sponsorship Type')
|
||||
start_date = fields.Date(string="Sponsorship Start Date", copy=False)
|
||||
end_date = fields.Date(string="Sponsorship End Date",compute='_compute_end_date', store=True)
|
||||
payment_option = fields.Selection([('month', 'Monthly'), ('once', 'For Once')], string='Payment Option')
|
||||
payment_month_count = fields.Integer(string='Payment Month Count', default=1)
|
||||
fixed_value = fields.Boolean(string='Is Fixed Value?',related='product_template_id.fixed_value')
|
||||
benefits_count = fields.Integer(string='Benefits Count',compute='_get_benefits_count')
|
||||
total_donation_amount = fields.Float(string='Total Donation Amount',compute='_get_total_donation_amount')
|
||||
sponsorships_computed = fields.Boolean(copy=False, readonly=True)
|
||||
payment_method_id = fields.Many2one('takaful.payment.method', string="Payment Method", domain="[('id', 'in', allowed_payment_method_ids)]")
|
||||
allowed_payment_method_ids = fields.Many2many('takaful.payment.method', compute='_compute_allowed_payment_method_ids')
|
||||
payment_method = fields.Selection(related="payment_method_id.payment_method")
|
||||
benefit_id_number = fields.Char("Benefit ID Number")
|
||||
benefit_family_code = fields.Char("Benefit Family Code")
|
||||
editable = fields.Boolean(string="Editable", default=True) # To differentiate
|
||||
sponsor_id = fields.Many2one('takaful.sponsor', related='sponsorship_id.sponsor_id')
|
||||
sponsor_phone = fields.Char(related='sponsorship_id.sponsor_id.mobile')
|
||||
branch_custom_id = fields.Many2one('branch.settings', related='sponsorship_id.branch_custom_id')
|
||||
record_type = fields.Selection([('sponsorship', 'Sponsorship'),('donation', 'Donation')], compute='_compute_record_type', store=True, readonly=True)
|
||||
state = fields.Selection([('draft', 'To Pay'),('waiting', 'Waiting'), ('active', 'Active'),('closed', 'Closed'),('extended', 'Extended'), ('paid', 'Paid')], string='State', default='draft')
|
||||
sponsorship_scheduling_line_ids = fields.One2many('sponsorship.scheduling.line', 'donation_detail_linked_id')
|
||||
is_paid = fields.Boolean(string="Is Paid", default=False)
|
||||
parent_state = fields.Char(compute='_compute_parent_state')
|
||||
|
||||
|
||||
@api.depends('sponsorship_id','sponsorship_mechanism_id')
|
||||
def _compute_parent_state(self):
|
||||
for rec in self:
|
||||
rec.parent_state = rec.sponsorship_id.state if rec.sponsorship_id else rec.sponsorship_mechanism_id.state
|
||||
|
||||
|
||||
@api.depends('sponsorship_id','sponsorship_mechanism_id', 'sponsorship_id.record_type', 'sponsorship_mechanism_id.record_type')
|
||||
def _compute_record_type(self):
|
||||
for rec in self:
|
||||
rec.record_type = rec.sponsorship_id.record_type if rec.sponsorship_id else rec.sponsorship_mechanism_id.record_type
|
||||
|
||||
@api.depends('sponsorship_duration')
|
||||
def _compute_allowed_payment_method_ids(self):
|
||||
for rec in self:
|
||||
domain = []
|
||||
if rec.sponsorship_duration == 'permanent':
|
||||
domain.append(('payment_method', '!=', 'direct_debit'))
|
||||
if rec.payment_method_id.payment_method == 'direct_debit':
|
||||
rec.payment_method_id = False
|
||||
rec.allowed_payment_method_ids = self.env['takaful.payment.method'].search(domain)
|
||||
|
||||
def _compute_product_id(self):
|
||||
for rec in self:
|
||||
if rec.product_template_id:
|
||||
rec.product_id = rec.product_template_id._get_first_possible_variant_id()
|
||||
else:
|
||||
rec.product_id = False
|
||||
|
||||
def onset_benefit_id(self):
|
||||
for rec in self:
|
||||
if rec.state == 'waiting' and (rec.benefit_id or rec.benefit_ids):
|
||||
rec.state = 'active'
|
||||
|
||||
@api.model
|
||||
def run_check_all_end_dates(self):
|
||||
lines = self.search([('end_date', '!=', False)])
|
||||
lines.check_end_date()
|
||||
|
||||
@api.depends('payment_month_count', 'product_template_id')
|
||||
def _compute_donation_amount(self):
|
||||
for rec in self.with_context(recursive_onchanges=False):
|
||||
if rec.payment_method == 'direct_debit':
|
||||
rec.donation_amount = rec.product_template_id.list_price * rec.payment_month_count
|
||||
elif not rec.donation_amount:
|
||||
rec.donation_amount = rec.product_template_id.list_price
|
||||
else:
|
||||
rec.donation_amount = rec.donation_amount
|
||||
|
||||
def check_end_date(self):
|
||||
for record in self:
|
||||
if record.end_date:
|
||||
today = fields.Date.today()
|
||||
end_date = record.end_date
|
||||
days_difference = (today - record.end_date).days
|
||||
if days_difference == 30:
|
||||
record.action_send_whatsapp(30,end_date)
|
||||
elif days_difference == 16:
|
||||
record.action_send_whatsapp(16,end_date)
|
||||
elif days_difference == 4:
|
||||
record.action_send_whatsapp(4,end_date)
|
||||
return False
|
||||
|
||||
|
||||
def action_send_whatsapp(self,duration,end_date):
|
||||
|
||||
if duration == 30:
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'before_finish'), ('message_type_ids.tool_type', '=', 'app'),('duration', '=', 30)],
|
||||
limit=1
|
||||
)
|
||||
expiry_date_str = end_date.strftime('%d-%m-%Y') if end_date else 'N/A'
|
||||
message = notification.message or _("No message found in 'Before Kafala End Date' notification.")
|
||||
message = message.replace('[ExpiryDate]', expiry_date_str)
|
||||
|
||||
elif duration == 16:
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'before_finish'), ('message_type_ids.tool_type', '=', 'app'),('duration', '=', 16)],
|
||||
limit=1
|
||||
)
|
||||
message = notification.message or _("No message found in 'Before Kafala End Date' notification.")
|
||||
|
||||
|
||||
|
||||
|
||||
elif duration == 4:
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'before_finish'), ('message_type_ids.tool_type', '=', 'app'),('duration', '=', 4)],
|
||||
limit=1
|
||||
)
|
||||
expiry_date_str = end_date.strftime('%d-%m-%Y') if end_date else 'N/A'
|
||||
message = notification.message or _("No message found in 'Before Kafala End Date' notification.")
|
||||
message = message.replace('[ExpiryDate]', expiry_date_str)
|
||||
|
||||
if not notification:
|
||||
raise ValidationError(_("No notification of type Before Kafala End Date found."))
|
||||
|
||||
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}'
|
||||
# Search for the notification message for 'create_kafala'
|
||||
|
||||
|
||||
# Use the message from the notification
|
||||
amount = self.donation_amount if hasattr(self, 'donation_amount') else 0.0
|
||||
|
||||
for partner in self:
|
||||
sponsorship_id = partner.sponsorship_mechanism_id or partner.sponsorship_id
|
||||
mobile = sponsorship_id.sponsor_id.mobile if sponsorship_id.sponsor_id else 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)
|
||||
|
||||
def sol_by_cart(self, operation, product_id, sponsorship_id):
|
||||
"""
|
||||
Create Sale Order Line By
|
||||
Cart Functionality
|
||||
"""
|
||||
|
||||
sol_object = self.env["donations.details.lines"]
|
||||
|
||||
if product_id.payment_method_id:
|
||||
payment_method = product_id.payment_method_id.id
|
||||
else:
|
||||
payment_method = self.env["takaful.payment.method"].search([('payment_method', '=', 'cash')], limit=1).id
|
||||
|
||||
sol_data = dict()
|
||||
sol_data["product_template_id"] = product_id.id
|
||||
sol_data["sponsorship_id"] = sponsorship_id.id
|
||||
sol_data["donation_amount"] = product_id.fixed_donation_amount
|
||||
sol_data["payment_method_id"] = payment_method
|
||||
sol_data["donation_types"] = 'donation'
|
||||
sol_data["name"] = product_id.name
|
||||
|
||||
if operation == "add":
|
||||
sol_object.create(sol_data)
|
||||
return
|
||||
|
||||
sol_ = sol_object.search(
|
||||
[('sponsorship_id', '=', sponsorship_id.id), ('product_template_id', '=', product_id.id), ]) # ("cart_flag", "=", True)
|
||||
|
||||
if operation == "remove":
|
||||
sol_.unlink()
|
||||
return
|
||||
|
||||
|
||||
def user_input_qty_sol(self, _qty, product_id, sponsorship_id):
|
||||
sol_object = self.env["donations.details.lines"]
|
||||
product_object = self.env["product.template"]
|
||||
cart_product_details = sol_object.search(
|
||||
[('sponsorship_id', "=", sponsorship_id), ("product_template_id", "=", product_id)
|
||||
]) # ("cart_flag", "=", True)
|
||||
if product_id.payment_method_id:
|
||||
payment_method = product_id.payment_method_id.id
|
||||
else:
|
||||
payment_method = self.env["takaful.payment.method"].search([('payment_method', '=', 'cash')], limit=1).id
|
||||
|
||||
|
||||
donation_id = product_object.search([('id', '=', product_id)])
|
||||
sol_data = dict()
|
||||
sol_data["product_template_id"] = donation_id.id
|
||||
sol_data["sponsorship_id"] = sponsorship_id
|
||||
sol_data["donation_amount"] = donation_id.list_price
|
||||
sol_data["payment_method_id"] = payment_method
|
||||
sol_data["donation_types"] = 'donation'
|
||||
sol_data["name"] = donation_id.name
|
||||
so = sol_object.create(sol_data)
|
||||
return
|
||||
|
||||
|
||||
@api.onchange('benefit_id_number', 'sponsorship_type', 'benefit_type')
|
||||
def _onchange_benefit_id_number(self):
|
||||
for rec in self:
|
||||
if rec.benefit_id_number and rec.sponsorship_type == 'person' and rec.benefit_type in ['orphan', 'widow']:
|
||||
member = self.env['family.member'].search([('member_id_number', '=', rec.benefit_id_number)], limit=1)
|
||||
if member:
|
||||
rec.benefit_id = member
|
||||
else:
|
||||
rec.benefit_id = False
|
||||
|
||||
|
||||
@api.constrains('payment_month_count')
|
||||
def _check_payment_month_count(self):
|
||||
for rec in self:
|
||||
if rec.donation_type == 'sponsorship' and rec.sponsorship_duration == 'temporary' and rec.payment_option == 'month' and rec.payment_month_count <= 0:
|
||||
raise ValidationError(
|
||||
_("Payment Month Count should be greather than zero!")
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(DonationsDetailsLines, self).default_get(fields)
|
||||
parent_id = self.env.context.get('default_active_id')
|
||||
parent_record = self.env['takaful.sponsorship'].browse(parent_id)
|
||||
|
||||
res['start_date'] = parent_record.sponsorship_creation_date
|
||||
res['sponsorship_creation_date'] = parent_record.sponsorship_creation_date
|
||||
# res['donation_mechanism'] = parent_record.donation_mechanism
|
||||
|
||||
self._onchange_sponsorship_type()
|
||||
return res
|
||||
|
||||
@api.onchange('donation_types', 'donation_type')
|
||||
def _onchange_sponsorship_type(self):
|
||||
for rec in self:
|
||||
if rec.sponsorship_mechanism_id:
|
||||
if rec.sponsorship_mechanism_id.record_type == 'sponsorship':
|
||||
rec.donation_type = 'sponsorship'
|
||||
|
||||
if rec.donation_types:
|
||||
if rec.donation_types == 'donation':
|
||||
rec.donation_type = 'donation'
|
||||
elif rec.donation_types == 'waqf':
|
||||
rec.donation_type = 'waqf'
|
||||
|
||||
@api.onchange('payment_method_id')
|
||||
def _onchange_payment_method(self):
|
||||
for rec in self:
|
||||
if rec.payment_method_id.payment_method == 'direct_debit':
|
||||
rec.payment_option = 'month'
|
||||
else:
|
||||
rec.payment_option = 'once'
|
||||
|
||||
@api.depends('start_date', 'payment_month_count')
|
||||
def _compute_end_date(self):
|
||||
for record in self:
|
||||
if record.start_date and record.payment_month_count:
|
||||
record.end_date = record.start_date + relativedelta(months=record.payment_month_count)
|
||||
else:
|
||||
record.end_date = False
|
||||
|
||||
@api.depends('benefit_ids')
|
||||
def _get_benefits_count(self):
|
||||
for rec in self:
|
||||
rec.benefits_count = len(rec.benefit_ids)
|
||||
|
||||
@api.depends('benefits_count','donation_amount')
|
||||
def _get_total_donation_amount(self):
|
||||
for rec in self:
|
||||
if rec.sponsorship_type == 'group':
|
||||
rec.total_donation_amount = rec.benefits_count * rec.donation_amount
|
||||
else :
|
||||
rec.total_donation_amount = rec.donation_amount
|
||||
|
||||
def _get_already_sponsored_beneficiaries(self, rec):
|
||||
"""
|
||||
Get list of beneficiary IDs that are already sponsored (active or in draft/waiting state)
|
||||
to exclude them from available selection
|
||||
"""
|
||||
# Search for all donation lines with active sponsorships
|
||||
all_lines = self.env['donations.details.lines'].sudo().search([('sponsorship_mechanism_id', '!=', False)])
|
||||
|
||||
# Filter for active/waiting/draft sponsorships
|
||||
active_lines = all_lines.filtered(
|
||||
lambda line: ((line.sponsorship_mechanism_id and line.sponsorship_mechanism_id.state == 'paid')
|
||||
) and line.state == 'active'
|
||||
)
|
||||
|
||||
# Exclude current record if editing existing line
|
||||
if rec.id:
|
||||
active_lines = active_lines.filtered(lambda line: line.id != rec.id)
|
||||
|
||||
# Get all benefit_ids from these active lines (both single and group)
|
||||
sponsored_ids = active_lines.mapped('benefit_id') + active_lines.mapped('benefit_ids')
|
||||
|
||||
return sponsored_ids # Remove duplicates
|
||||
|
||||
@api.depends('gender', 'education_status', 'education_level', 'sponsorship_type', 'benefit_type', 'age_category_id', 'benefit_family_code')
|
||||
def _compute_domain_ids(self):
|
||||
for rec in self:
|
||||
# Create a domain
|
||||
rec.members_domain_ids = [(6, 0, [])]
|
||||
|
||||
# Get all sponsored beneficiaries (exclude them from domain)
|
||||
sponsored_benefit_ids = self._get_already_sponsored_beneficiaries(rec)
|
||||
|
||||
if rec.benefit_family_code and rec.sponsorship_type:
|
||||
benefit_ids = self.env['family.member'].search([('benefit_id.code', '=', rec.benefit_family_code)])
|
||||
# Exclude already sponsored
|
||||
if sponsored_benefit_ids:
|
||||
benefit_ids = benefit_ids.filtered(lambda b: b not in sponsored_benefit_ids)
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search([('id', 'in', benefit_ids.ids)])
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
|
||||
if rec.benefit_type == 'orphan' and rec.sponsorship_type:
|
||||
base_domain = \
|
||||
[
|
||||
'|', ('state', '=', 'second_approve'), '&',('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended'),
|
||||
('member_status', '=', 'benefit'),
|
||||
'|',
|
||||
('relationn.relation_type', '=', 'daughter'),
|
||||
('relationn.relation_type', '=', 'son')
|
||||
]
|
||||
if rec.gender:
|
||||
if rec.gender == 'female':
|
||||
base_domain = [
|
||||
'|', ('state', '=', 'second_approve'), '&',
|
||||
('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended'),
|
||||
('member_status', '=', 'benefit'), ('relationn.relation_type', '=', 'daughter')]
|
||||
if rec.gender == 'male':
|
||||
base_domain = [
|
||||
'|', ('state', '=', 'second_approve'), '&',('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended'),
|
||||
('member_status', '=', 'benefit'), ('relationn.relation_type', '=', 'son')]
|
||||
if rec.education_status:
|
||||
base_domain.append(('education_status', '=', rec.education_status))
|
||||
if rec.education_level:
|
||||
base_domain.append(('education_levels', '=', rec.education_level.id))
|
||||
if rec.age_category_id:
|
||||
base_domain.append(('age', '<=', rec.age_category_id.max_age))
|
||||
base_domain.append(('age', '>=', rec.age_category_id.min_age))
|
||||
|
||||
# Exclude already sponsored beneficiaries
|
||||
if sponsored_benefit_ids:
|
||||
base_domain.append(('id', 'not in', sponsored_benefit_ids.ids))
|
||||
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search(base_domain)
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
if rec.benefit_type == 'widow' and rec.sponsorship_type:
|
||||
base_domain = ['|',('state','=','second_approve'),'&',('state','in',('waiting_approve','first_approve')),('action_type','=','suspended'),
|
||||
('member_status', '=', 'benefit'), '|', ('relationn.relation_type', '=', 'mother'),
|
||||
('relationn.relation_type', '=', 'replacement_mother')]
|
||||
if rec.education_status:
|
||||
base_domain.append(('education_status', '=', rec.education_status))
|
||||
if rec.education_level:
|
||||
base_domain.append(('education_levels', '=', rec.education_level.id))
|
||||
if rec.age_category_id:
|
||||
base_domain.append(('age', '<=', rec.age_category_id.max_age))
|
||||
base_domain.append(('age', '>=', rec.age_category_id.min_age))
|
||||
|
||||
# Exclude already sponsored beneficiaries
|
||||
if sponsored_benefit_ids:
|
||||
base_domain.append(('id', 'not in', sponsored_benefit_ids.ids))
|
||||
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search(base_domain)
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
if rec.benefit_type == 'both' and rec.sponsorship_type:
|
||||
base_domain = ['|',('state','=','second_approve'),'&',('state','in',('waiting_approve','first_approve')),('action_type','=','suspended'),
|
||||
('member_status', '=', 'benefit')]
|
||||
if rec.education_status:
|
||||
base_domain.append(('education_status', '=', rec.education_status))
|
||||
if rec.education_level:
|
||||
base_domain.append(('education_levels', '=', rec.education_level.id))
|
||||
if rec.age_category_id:
|
||||
base_domain.append(('age', '<=', rec.age_category_id.max_age))
|
||||
base_domain.append(('age', '>=', rec.age_category_id.min_age))
|
||||
|
||||
# Exclude already sponsored beneficiaries
|
||||
if sponsored_benefit_ids:
|
||||
base_domain.append(('id', 'not in', sponsored_benefit_ids.ids))
|
||||
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search(base_domain)
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
|
||||
@api.onchange('product_template_id','donation_types','donation_type')
|
||||
def onchange_product_template_id(self):
|
||||
for rec in self:
|
||||
# Process both donation details and mechanism details
|
||||
if rec.product_template_id.fixed_value:
|
||||
rec.donation_amount = rec.product_template_id.list_price
|
||||
selected_donations = []
|
||||
if rec.sponsorship_id or rec.sponsorship_mechanism_id:
|
||||
all_donation_lines = (
|
||||
(rec.sponsorship_id.donations_details_lines if rec.sponsorship_id else self.env['donations.details.lines']) |
|
||||
(rec.sponsorship_mechanism_id.donations_details_lines_mechanism_ids if rec.sponsorship_mechanism_id else self.env['donations.details.lines'])
|
||||
)
|
||||
selected_donations = all_donation_lines.mapped('product_template_id.id')
|
||||
domain = [('id', 'not in', selected_donations),('sale_ok', '=', True)]
|
||||
# Apply condition based on record type
|
||||
record_type = rec.sponsorship_id.record_type if rec.sponsorship_id else rec.sponsorship_mechanism_id.record_type
|
||||
|
||||
if record_type == 'donation':
|
||||
domain.append(('donation_category', '=', 'donation'))
|
||||
|
||||
elif record_type == 'sponsorship':
|
||||
domain.append(('donation_category', '=', 'sponsorship'))
|
||||
|
||||
return {
|
||||
'domain': {
|
||||
'product_template_id': domain}
|
||||
}
|
||||
|
||||
@api.onchange('donation_type')
|
||||
def onchange_donation_type(self):
|
||||
for rec in self:
|
||||
if rec.donation_type == 'sponsorship':
|
||||
rec.donation_mechanism = 'with_conditions'
|
||||
|
||||
def compute_sponsorships_lines(self):
|
||||
|
||||
for rec in self:
|
||||
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.payment_option == 'month' and rec.payment_method_id.payment_method == 'direct_debit':
|
||||
# Divide the total donation amount by the number of months
|
||||
if rec.payment_month_count > 0:
|
||||
base_amount, remainder = divmod(rec.total_donation_amount, rec.payment_month_count)
|
||||
else:
|
||||
raise ValidationError(
|
||||
_("Payment Month Count Must be Bigger than zero!")
|
||||
)
|
||||
|
||||
# Convert base_amount to a float with two decimal points
|
||||
base_amount = float(base_amount)
|
||||
|
||||
for index in range(rec.payment_month_count):
|
||||
# Add 1 to the base amount for the first 'remainder' months to handle the rounding issue
|
||||
amount = base_amount + 1 if index < remainder else base_amount
|
||||
# Format the amount to 2 decimal places for better representation
|
||||
amount = round(amount, 2)
|
||||
# Calculate the month and year
|
||||
month_year = (rec.start_date + relativedelta(months=index)).strftime("%m/%Y")
|
||||
# Create the Sponsorship Scheduling Link
|
||||
SponsorshipSchedulingLink.create({
|
||||
'sponsorship_id': sponsorship_id.id,
|
||||
'donation_detail_linked_id': rec.id,
|
||||
'beneficiary_id': rec.benefit_id.id,
|
||||
'month_year': month_year,
|
||||
'amount': amount
|
||||
})
|
||||
# else:
|
||||
# month_year = (sponsorship_id.sponsorship_creation_date + relativedelta(months=1)).strftime("%m/%Y")
|
||||
# # Create the Sponsorship Scheduling Link
|
||||
# SponsorshipSchedulingLink.create({
|
||||
# 'sponsorship_id': sponsorship_id.id,
|
||||
# 'donation_detail_linked_id': rec.id,
|
||||
# 'beneficiary_id': rec.benefit_id.id,
|
||||
# 'month_year': month_year,
|
||||
# 'amount': rec.donation_amount
|
||||
# })
|
||||
rec.sponsorships_computed = True
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# Check if sequence_no is not already set
|
||||
if vals.get('sequence_no', '/') == '/':
|
||||
# Assign the next sequence number
|
||||
vals['sequence_no'] = self.env['ir.sequence'].next_by_code('donations.details.lines.sequence') or '/'
|
||||
if vals.get('display_type'):
|
||||
vals.update({
|
||||
'product_template_id': False,
|
||||
'donation_type': False,
|
||||
'payment_method_id': False
|
||||
})
|
||||
|
||||
record = super(DonationsDetailsLines, self).create(vals)
|
||||
|
||||
if 'benefit_id' in vals and record.sponsorship_id:
|
||||
benefit_name = record.benefit_id.name or 'None'
|
||||
record.sponsorship_id.message_post(
|
||||
body=f"Benefit set to <b>{benefit_name}</b> in a donation item."
|
||||
)
|
||||
return record
|
||||
|
||||
|
||||
def write(self, vals):
|
||||
res = False
|
||||
for rec in self:
|
||||
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)
|
||||
|
||||
if 'display_type' in vals and self.filtered(lambda line: line.display_type != vals.get('display_type')):
|
||||
raise UserError(
|
||||
_("You cannot change the type of a sale quote line. Instead you should delete the current line and create a new line of the proper type."))
|
||||
if 'benefit_id' in vals:
|
||||
new_benefit = rec.benefit_id.name or 'None'
|
||||
sponsorship = self.env['takaful.sponsorship'].browse(
|
||||
self.env.context.get('active_id'))
|
||||
if sponsorship and len(sponsorship) == 1:
|
||||
message = _("Benefit changed from <b>%s</b> to <b>%s</b> in a donation item.") % (
|
||||
old_benefit or 'None', new_benefit)
|
||||
sponsorship.message_post(body=message)
|
||||
|
||||
# Auto-trigger state change when benefit is assigned to waiting line
|
||||
|
||||
if 'benefit_ids' in vals:
|
||||
new_benefits = rec.benefit_ids.mapped('name')
|
||||
new_benefits_set = set(new_benefits)
|
||||
|
||||
added = new_benefits_set - old_benefits_set
|
||||
removed = old_benefits_set - new_benefits_set
|
||||
|
||||
changes = []
|
||||
if added:
|
||||
changes.append(_("Added: <b>%s</b>") % ', '.join(added))
|
||||
if removed:
|
||||
changes.append(_("Removed: <b>%s</b>") % ', '.join(removed))
|
||||
|
||||
if changes:
|
||||
# Find sponsorship
|
||||
sponsorship = rec.sponsorship_id or self.env['takaful.sponsorship'].browse(
|
||||
self.env.context.get('active_id'))
|
||||
|
||||
if sponsorship and len(sponsorship) == 1:
|
||||
message = _("Benefit IDs changed in a donation item:<br/>%s") % "<br/>".join(changes)
|
||||
sponsorship.message_post(body=message)
|
||||
self.onset_benefit_id()
|
||||
return res
|
||||
|
||||
def action_view_replacement_wizard(self):
|
||||
self.ensure_one()
|
||||
|
||||
wizard = self.env['replacement.wiz'].create({
|
||||
'replacement_line_ids':[(0, 0, {
|
||||
'sponsorship_type': self.sponsorship_type,
|
||||
'from_benefit_id': self.benefit_id.id if self.sponsorship_type == 'person' else False,
|
||||
'from_benefit_ids': [(6, 0, self.benefit_ids.ids)] if self.sponsorship_type == 'group' else False
|
||||
})]
|
||||
})
|
||||
|
||||
return {
|
||||
'name': 'Replacement Wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'replacement.wiz',
|
||||
'view_mode': 'form',
|
||||
'res_id': wizard.id,
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def action_view_scheduling_lines(self):
|
||||
self.ensure_one()
|
||||
|
||||
return {
|
||||
'name': 'Sponsorship Scheduling Lines',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'sponsorship.scheduling.line',
|
||||
'view_mode': 'tree',
|
||||
'domain': [('donation_detail_linked_id', '=', self.id)],
|
||||
'context': {'default_donation_detail_linked_id': self.id, 'create': False, 'delete': False},
|
||||
}
|
||||
|
||||
def action_register_payment(self):
|
||||
self.ensure_one()
|
||||
sponsorship_id = self.sponsorship_mechanism_id.id if self.sponsorship_mechanism_id else self.sponsorship_id.id
|
||||
invoice_id = self.env['account.move'].sudo().search([('takaful_sponsorship_id', 'in', [sponsorship_id])], limit=1)
|
||||
if not invoice_id:
|
||||
raise ValidationError(_("No invoice found for this sponsorship."))
|
||||
# payment_method_line = self.env['account.payment.method.line'].search([
|
||||
# ('journal_id', '=', self.payment_method_id.journal_id.id),
|
||||
# ('payment_type', '=', 'inbound')
|
||||
# ], limit=1)
|
||||
return {
|
||||
'name': _('Register Payment'),
|
||||
'res_model': 'account.payment.register',
|
||||
'view_mode': 'form',
|
||||
'context': {
|
||||
'active_model': 'account.move',
|
||||
'active_ids': invoice_id.ids,
|
||||
'dont_redirect_to_payments': True,
|
||||
'sponsorship_line_ids': self.ids,
|
||||
'default_journal_id': self.payment_method_id.journal_id.id,
|
||||
'default_amount': self.total_donation_amount,
|
||||
# 'default_payment_method_line_id': payment_method_line.id,
|
||||
},
|
||||
'target': 'new',
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
|
|
@ -8,4 +8,24 @@ class ProductTemplate(models.Model):
|
|||
|
||||
def _compute_fixed_value(self):
|
||||
for rec in self:
|
||||
rec.fixed_value = False
|
||||
rec.fixed_value = False
|
||||
|
||||
def link_to_sponsorship(self):
|
||||
sponsorship_id = self.env.context.get('sponsorship_id')
|
||||
if not sponsorship_id:
|
||||
return
|
||||
|
||||
sponsorship = self.env['takaful.sponsorship'].browse(sponsorship_id)
|
||||
vals = []
|
||||
for rec in self:
|
||||
vals.append((0, 0, {
|
||||
'product_template_id': rec.id,
|
||||
'sponsorship_id': sponsorship_id,
|
||||
'donation_types': 'donation',
|
||||
'donation_mechanism': 'without_conditions',
|
||||
}))
|
||||
|
||||
# Append to existing lines instead of replacing them
|
||||
sponsorship.write({
|
||||
'donations_details_lines': vals
|
||||
})
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from dateutil.parser import parse
|
|||
from math import floor
|
||||
import re
|
||||
import requests
|
||||
from odoo.osv import expression
|
||||
|
||||
|
||||
|
||||
|
|
@ -45,8 +46,10 @@ class TakafulSponsorship(models.Model):
|
|||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_description = "Sponsorship"
|
||||
_rec_name = 'code'
|
||||
_order = 'id desc'
|
||||
|
||||
sponsor_id = fields.Many2one('takaful.sponsor',string='Sponsor Name',domain="[('branch_custom_id', '=', branch_custom_id),('branch_custom_id','!=',False)]")
|
||||
sponsor_id = fields.Many2one('takaful.sponsor',string='Sponsor Name',domain="[('id', 'in', allowed_sponsor_ids)]")
|
||||
allowed_sponsor_ids = fields.Many2many('takaful.sponsor', compute='_compute_allowed_sponsor_ids')
|
||||
member_id = fields.Many2one('res.partner',string='Member Name',domain="[('is_member', '=', True)]")
|
||||
is_gift = fields.Selection([('no', 'No'),('yes', 'Yes')],string='Is Gift To Person')
|
||||
gifter_id = fields.Many2one(
|
||||
|
|
@ -70,7 +73,7 @@ class TakafulSponsorship(models.Model):
|
|||
sponsor_title = fields.Many2one('res.partner.title',string='Sponsor Title')
|
||||
donate_for_another_person = fields.Boolean(string='Donate For Another Person')
|
||||
another_sponsors = fields.One2many('donate.for.another.person','sponsorship_id')
|
||||
registered_type = fields.Selection(string='Registered Type',selection=[('sponsor', 'Sponsor'),('member', 'Member')])
|
||||
registered_type = fields.Selection(string='Registered Type',selection=[('sponsor', 'Sponsor'),('member', 'Member'), ('donor', 'Donor')])
|
||||
members_domain_ids = fields.Many2many(comodel_name='family.member', compute='_compute_domain_ids')
|
||||
# This is if for one person, and not a group.
|
||||
benefit_id = fields.Many2one('family.member',string='Beneficiary Name',ondelete='set null',domain = "[('id', 'in',members_domain_ids)]")
|
||||
|
|
@ -109,7 +112,8 @@ class TakafulSponsorship(models.Model):
|
|||
|
||||
journal_entry_ids = fields.One2many('account.move', 'takaful_sponsorship_id')
|
||||
journal_entry_count = fields.Integer(compute="_compute_journal_entry_count")
|
||||
refund_payment_ids = fields.One2many('account.payment', 'takaful_sponsorship_id')
|
||||
journal_entry_count_vendor = fields.Integer(compute="_compute_journal_entry_count_vendor")
|
||||
payment_ids = fields.One2many('account.payment', 'takaful_sponsorship_id')
|
||||
refund_payment_count = fields.Integer(compute="_compute_refund_payment_count")
|
||||
related_move_records_count = fields.Integer(compute="_compute_related_move_records")
|
||||
related_move_lines_records_count = fields.Integer(compute="_compute_related_move_lines_records")
|
||||
|
|
@ -122,7 +126,22 @@ class TakafulSponsorship(models.Model):
|
|||
replaced = fields.Boolean('Replaced')
|
||||
replacement_id = fields.Many2one('replacement.process', string="Replacement")
|
||||
create_uid = fields.Many2one('res.users', default=lambda self: self.env.user)
|
||||
marketer_id = fields.Many2one('hr.employee')
|
||||
|
||||
@api.onchange('branch_custom_id', 'registered_type')
|
||||
def _compute_allowed_sponsor_ids(self):
|
||||
for rec in self:
|
||||
if rec.branch_custom_id and rec.registered_type:
|
||||
domain = []
|
||||
if rec.registered_type == 'sponsor':
|
||||
expression.AND([domain, [('is_sponsor_portal', '=', True)]])
|
||||
elif rec.registered_type == 'member':
|
||||
expression.AND([domain, [('is_member', '=', True)]])
|
||||
elif rec.registered_type == 'donor':
|
||||
expression.AND([domain, ['|', '|', ('is_member', '=', True), ('is_donor', '=', True),('is_sponsor_portal', '=', True)]])
|
||||
rec.allowed_sponsor_ids = self.env['takaful.sponsor'].search(domain)
|
||||
else:
|
||||
rec.allowed_sponsor_ids = self.env['takaful.sponsor']
|
||||
|
||||
def compute_days_after_payment(self):
|
||||
"""Check if the number of hours passed after payment is within the configured limit"""
|
||||
|
|
@ -296,37 +315,21 @@ class TakafulSponsorship(models.Model):
|
|||
return invoice
|
||||
|
||||
|
||||
def donation_catelog(self):
|
||||
cart_object = self.env["donations.details.lines"]
|
||||
donation_object = self.env["donations.items"]
|
||||
cart_products_details = cart_object.search(
|
||||
[('sponsorship_id', "=", self.id)]) # , ("cart_flag", "=", True)
|
||||
product_object_data = donation_object.search(
|
||||
[("_quantity", "!=", 0)])
|
||||
assign_quantity = 0
|
||||
for rec in product_object_data:
|
||||
rec._quantity = 0
|
||||
if len(cart_products_details) > 0:
|
||||
for rec in cart_products_details:
|
||||
if assign_quantity == 0:
|
||||
assign_quantity += 1
|
||||
|
||||
kanban_view = self.env.ref(
|
||||
'odex_takaful.product_product_view_kanban')
|
||||
def action_open_donation_catalog(self):
|
||||
all_donation_lines = self.donations_details_lines | self.donations_details_lines_mechanism_ids
|
||||
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Choose Donation Items'),
|
||||
'res_model': 'product.template',
|
||||
'views': [(kanban_view.id, 'kanban')],
|
||||
'domain': [('id', 'not in', all_donation_lines.mapped('product_template_id').ids),('donation_category','=','donation'),],
|
||||
'views': [(False, 'kanban')],
|
||||
'domain': [('id', 'not in', all_donation_lines.mapped('product_template_id').ids),('donation_category','=','donation')],
|
||||
'target': 'new',
|
||||
'context': {
|
||||
# '_quantity_change': True,
|
||||
'sponsorship_id': self.id,
|
||||
'create': False
|
||||
},
|
||||
|
||||
'help': _("""<p class="o_view_nocontent_smiling_face">
|
||||
Create a new product
|
||||
</p>""")
|
||||
|
|
@ -402,7 +405,12 @@ class TakafulSponsorship(models.Model):
|
|||
@api.depends('journal_entry_ids')
|
||||
def _compute_journal_entry_count(self):
|
||||
for rec in self:
|
||||
rec.journal_entry_count = len(rec.journal_entry_ids)
|
||||
rec.journal_entry_count = len(rec.journal_entry_ids.filtered(lambda r: r.move_type == 'out_invoice'))
|
||||
|
||||
@api.depends('journal_entry_ids')
|
||||
def _compute_journal_entry_count_vendor(self):
|
||||
for rec in self:
|
||||
rec.journal_entry_count_vendor = len(rec.journal_entry_ids.filtered(lambda r: r.move_type == 'in_invoice'))
|
||||
|
||||
@api.depends('donations_details_lines')
|
||||
def _compute_donation_count(self):
|
||||
|
|
@ -412,22 +420,32 @@ class TakafulSponsorship(models.Model):
|
|||
def action_view_journal_entries(self):
|
||||
self.ensure_one() # Ensure the method is called on a single record
|
||||
action = self.env.ref('account.action_move_out_invoice_type').read()[0]
|
||||
action['domain'] = [('id', 'in', self.journal_entry_ids.ids)]
|
||||
action['domain'] = [('move_type', '=', 'out_invoice'), ('id', 'in', self.journal_entry_ids.ids)]
|
||||
action['context'] = {
|
||||
'default_takaful_sponsorship_id': self.id,
|
||||
'create': False
|
||||
}
|
||||
return action
|
||||
|
||||
def action_view_journal_entries_vendor(self):
|
||||
self.ensure_one() # Ensure the method is called on a single record
|
||||
action = self.env.ref('account.action_move_out_invoice_type').read()[0]
|
||||
action['domain'] = [('move_type', '=', 'in_invoice'), ('id', 'in', self.journal_entry_ids.ids)]
|
||||
action['context'] = {
|
||||
'default_takaful_sponsorship_id': self.id,
|
||||
'create': False
|
||||
}
|
||||
return action
|
||||
|
||||
@api.depends('refund_payment_ids')
|
||||
@api.depends('payment_ids')
|
||||
def _compute_refund_payment_count(self):
|
||||
for rec in self:
|
||||
rec.refund_payment_count = len(rec.refund_payment_ids)
|
||||
rec.refund_payment_count = len(rec.payment_ids)
|
||||
|
||||
def action_view_refund_payments(self):
|
||||
self.ensure_one() # Ensure the method is called on a single record
|
||||
action = self.env.ref('account.action_account_payments').read()[0]
|
||||
action['domain'] = [('id', 'in', self.refund_payment_ids.ids)]
|
||||
action['domain'] = [('id', 'in', self.payment_ids.ids)]
|
||||
action['context'] = {
|
||||
'default_takaful_sponsorship_id': self.id,
|
||||
'create': False
|
||||
|
|
@ -454,6 +472,22 @@ class TakafulSponsorship(models.Model):
|
|||
'domain': [('id', 'in', moves)],
|
||||
}
|
||||
|
||||
def action_open_donation_catalog(self):
|
||||
""" Opens product catalog to link products to sponsorship """
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _('Donation Catalog'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'product.template',
|
||||
'view_mode': 'tree',
|
||||
'view_id': self.env.ref('odex_takaful.view_product_template_tree_sponsorship').id,
|
||||
'context': {
|
||||
'sponsorship_id': self.id, 'create': False, 'edit': False, 'delete': False,
|
||||
},
|
||||
'domain': [('donation_category', '=', 'donation'), ('id', 'not in', self.donations_details_lines.mapped('product_template_id').ids)],
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def _compute_related_move_lines_records(self):
|
||||
for record in self:
|
||||
record.related_move_lines_records_count = len(self.env['account.move'].search([
|
||||
|
|
@ -1224,18 +1258,19 @@ class TakafulSponsorship(models.Model):
|
|||
_("Please add at least one line in donation details!")
|
||||
)
|
||||
|
||||
if not len(self.donations_details_lines_mechanism_ids.payment_method_id) and not len(self.donations_details_lines.payment_method_id):
|
||||
raise ValidationError(
|
||||
_("Please define the payment method for each line!")
|
||||
)
|
||||
|
||||
# Process both donation details and mechanism details
|
||||
all_donation_lines = self.donations_details_lines | self.donations_details_lines_mechanism_ids
|
||||
all_donation_lines = all_donation_lines.filtered(lambda r: r.display_type == False)
|
||||
|
||||
# Calculate sponsorships lines automatically for no sponsorship donation type
|
||||
all_donation_lines.filtered(lambda r: r.donation_type != 'sponsorship').compute_sponsorships_lines()
|
||||
|
||||
if not all(all_donation_lines.mapped("sponsorships_computed")):
|
||||
raise ValidationError(
|
||||
_("Please schedule donations items for confirmation and continuity!")
|
||||
)
|
||||
|
||||
(self.donations_details_lines + self.donations_details_lines_mechanism_ids).compute_sponsorships_lines()
|
||||
|
||||
if self.state == 'draft':
|
||||
# Send SMS Notification
|
||||
|
|
@ -1257,14 +1292,6 @@ class TakafulSponsorship(models.Model):
|
|||
})
|
||||
|
||||
push.sudo().send_sms_notification()
|
||||
for donation in all_donation_lines:
|
||||
if donation.sponsorship_type == 'group':
|
||||
for benefit in donation.benefit_ids:
|
||||
benefit.sponsor_related_id = self.sponsor_id.id
|
||||
benefit.sponsorship_id = self.id
|
||||
if donation.sponsorship_type == 'person':
|
||||
donation.benefit_id.sponsor_related_id = self.sponsor_id.id
|
||||
donation.benefit_id.sponsorship_id = self.id
|
||||
|
||||
self.state = "confirmed"
|
||||
if self.sponsor_or_donor_type != 'registered':
|
||||
|
|
@ -1284,14 +1311,22 @@ class TakafulSponsorship(models.Model):
|
|||
'partner_id': self.sponsor_id.sponsor_partner_id.id,
|
||||
'invoice_line_ids': [(0, 0, {
|
||||
'product_id': line.product_id.id,
|
||||
'quantity': 1,
|
||||
'price_unit': line.total_donation_amount,
|
||||
'quantity': 1,
|
||||
'name': _("Sponsorship Entitlement Number %s") % line.sequence_no,
|
||||
'analytic_account_id': line.sponsorship_id.branch_custom_id.branch.analytic_account_id.id,
|
||||
}) for line in all_donation_lines],
|
||||
# 'branch_id': TODO there is no res.branch in takaful.sponsorship model
|
||||
}
|
||||
invoice_id = Invoice.create(invoice_values)
|
||||
for line in invoice_id.invoice_line_ids:
|
||||
line.account_id = line._get_computed_account()
|
||||
taxes = line._get_computed_taxes()
|
||||
if taxes and line.move_id.fiscal_position_id:
|
||||
taxes = line.move_id.fiscal_position_id.map_tax(taxes, partner=line.partner_id)
|
||||
line.tax_ids = taxes
|
||||
line.product_uom_id = line._get_computed_uom()
|
||||
|
||||
invoice_id.action_post()
|
||||
|
||||
# Search for the notification message for 'create_kafala'
|
||||
|
|
@ -1659,28 +1694,32 @@ class TakafulSponsorship(models.Model):
|
|||
|
||||
}, }
|
||||
|
||||
def action_register_payment(self):
|
||||
invoice_id = self.env['account.move'].sudo().search([('takaful_sponsorship_id', '=', self.id)], limit=1)
|
||||
if not invoice_id:
|
||||
raise ValidationError(_("No invoice found for this sponsorship."))
|
||||
sponsorship_line_ids = (self.donations_details_lines + self.donations_details_lines_mechanism_ids).filtered(lambda l: l.state == 'draft')
|
||||
amount = sum(sponsorship_line_ids.mapped('total_donation_amount'))
|
||||
return {
|
||||
'name': _('Register Payment'),
|
||||
'res_model': 'account.payment.register',
|
||||
'view_mode': 'form',
|
||||
'context': {
|
||||
'active_model': 'account.move',
|
||||
'active_ids': invoice_id.ids,
|
||||
'default_amount': amount,
|
||||
'default_journal_id': sponsorship_line_ids.payment_method_id[-1].journal_id.id,
|
||||
'dont_redirect_to_payments': True,
|
||||
'sponsorship_line_ids': sponsorship_line_ids.ids,
|
||||
},
|
||||
'target': 'new',
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
show_register_payment = fields.Boolean(string='Show Register Payment', compute='_compute_show_register_payment')
|
||||
|
||||
|
||||
class AccountVoucher(models.Model):
|
||||
_inherit = "account.move"
|
||||
|
||||
sponsorship_id = fields.Many2one('takaful.sponsorship',string='Sponsorship', readonly=True,)
|
||||
payment_id = fields.Many2one('account.payment',string='Payment', copy=False)
|
||||
|
||||
|
||||
# @api.multi
|
||||
def action_move_line_create(self):
|
||||
'''
|
||||
Confirm the vouchers given in ids and create the journal entries for each of them
|
||||
'''
|
||||
res = super(AccountVoucher, self).action_move_line_create()
|
||||
if res :
|
||||
self.write({'payment_id':self.move_id.line_ids.mapped('payment_id').id})
|
||||
|
||||
@api.onchange('payment_journal_id')
|
||||
def on_change_payment_journal_id(self):
|
||||
def _compute_show_register_payment(self):
|
||||
for rec in self:
|
||||
rec.account_id = rec.payment_journal_id.default_debit_account_id
|
||||
rec.show_register_payment = len(((rec.donations_details_lines + rec.donations_details_lines_mechanism_ids).filtered(lambda l: l.state == 'draft')).payment_method_id) <= 1
|
||||
|
||||
class AnotherSponsors(models.Model):
|
||||
_name = "donate.for.another.person"
|
||||
|
|
@ -1692,589 +1731,6 @@ class AnotherSponsors(models.Model):
|
|||
receive_messages = fields.Boolean(string='Receive messages?')
|
||||
note = fields.Char(string='Note')
|
||||
|
||||
class DonationsDetailsLines(models.Model):
|
||||
_name = "donations.details.lines"
|
||||
_inherit = ['mail.thread']
|
||||
|
||||
name = fields.Text(string="Note")
|
||||
display_type = fields.Selection([
|
||||
('line_section', "Section"),
|
||||
('line_note', "Note")], default=False, help="Technical field for UX purpose.")
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
sequence_no = fields.Char(default='/', readonly=True, copy=False)
|
||||
donation_type = fields.Selection([('donation', 'Donation'), ('waqf', 'Waqf'), ('sponsorship', 'Sponsorship'), ],string='Donation Type')
|
||||
donation_types = fields.Selection([('donation', 'Donation'), ('waqf', 'Waqf')],string='Donation Type')
|
||||
product_template_id = fields.Many2one('product.template', string="Donation Name", required=True)
|
||||
product_id = fields.Many2one('product.product', compute='_compute_product_id')
|
||||
sponsorship_id = fields.Many2one('takaful.sponsorship', string="Sponsorship")
|
||||
sponsorship_mechanism_id = fields.Many2one('takaful.sponsorship', string="Sponsorship")
|
||||
sponsorship_creation_date = fields.Datetime()
|
||||
donation_amount = fields.Float(string='Donation Amount', compute="_compute_donation_amount", store=True)
|
||||
donation_mechanism = fields.Selection([('with_conditions', _('With Conditions')),('without_conditions', _('Without Conditions'))],string='Donation Mechanism', readonly=True)
|
||||
benefit_type = fields.Selection([('orphan', 'Orphans'),('widow', 'Widows'),('both', 'Both')],string='Sponsorship Beneficiary Type',tracking=True)
|
||||
sponsorship_type = fields.Selection([('person', 'Individual'),('group', 'Group')],string='Sponsorship Type',tracking=True)
|
||||
gender = fields.Selection(selection=[('male', 'Male'), ('female', 'Female')], string="Gender")
|
||||
age_category_id = fields.Many2one('age.category', string='Age Category')
|
||||
education_status = fields.Selection(string='Education Status',selection=[('educated', 'educated'), ('illiterate', 'illiterate'),('under_study_age', 'Under Study Age')])
|
||||
education_level = fields.Many2one("education.level", string='Education Levels')
|
||||
members_domain_ids = fields.Many2many(comodel_name='family.member', compute='_compute_domain_ids')
|
||||
benefit_id = fields.Many2one('family.member',string='Beneficiary Name',ondelete='set null',domain = "[('id', 'in',members_domain_ids)]", tracking=True)
|
||||
family_id = fields.Many2one('grant.benefit',string='Family',ondelete='set null',related="benefit_id.benefit_id")
|
||||
benefit_ids = fields.Many2many('family.member',string='Beneficiaries Names', tracking=True)
|
||||
sponsorship_duration = fields.Selection([('temporary', 'Temporary'),('permanent', 'Permanent')],string='Sponsorship Type')
|
||||
start_date = fields.Date(string="Sponsorship Start Date", copy=False)
|
||||
end_date = fields.Date(string="Sponsorship End Date",compute='_compute_end_date', store=True)
|
||||
payment_option = fields.Selection([('month', 'Monthly'), ('once', 'For Once')], string='Payment Option')
|
||||
payment_month_count = fields.Integer(string='Payment Month Count', default=1)
|
||||
fixed_value = fields.Boolean(string='Is Fixed Value?',related='product_template_id.fixed_value')
|
||||
benefits_count = fields.Integer(string='Benefits Count',compute='_get_benefits_count')
|
||||
total_donation_amount = fields.Float(string='Total Donation Amount',compute='_get_total_donation_amount')
|
||||
sponsorships_computed = fields.Boolean(copy=False, readonly=True)
|
||||
payment_method_id = fields.Many2one('takaful.payment.method', string="Payment Method", domain="[('id', 'in', allowed_payment_method_ids)]")
|
||||
allowed_payment_method_ids = fields.Many2many('takaful.payment.method', compute='_compute_allowed_payment_method_ids')
|
||||
payment_method = fields.Selection(related="payment_method_id.payment_method")
|
||||
benefit_id_number = fields.Char("Benefit ID Number")
|
||||
benefit_family_code = fields.Char("Benefit Family Code")
|
||||
editable = fields.Boolean(string="Editable", default=True) # To differentiate
|
||||
sponsor_id = fields.Many2one('takaful.sponsor', related='sponsorship_id.sponsor_id')
|
||||
sponsor_phone = fields.Char(related='sponsorship_id.sponsor_id.mobile')
|
||||
branch_custom_id = fields.Many2one('branch.settings', related='sponsorship_id.branch_custom_id')
|
||||
record_type = fields.Selection(related='sponsorship_id.record_type', store=True, readonly=True)
|
||||
state = fields.Selection([('draft', 'To Pay'),('waiting', 'Waiting'), ('active', 'Active'),('closed', 'Closed'),('extended', 'Extended')], string='State', default='draft')
|
||||
sponsorship_scheduling_line_ids = fields.One2many('sponsorship.scheduling.line', 'donation_detail_linked_id')
|
||||
|
||||
|
||||
@api.onchange('sponsorship_duration')
|
||||
def _compute_allowed_payment_method_ids(self):
|
||||
for rec in self:
|
||||
domain = []
|
||||
if rec.sponsorship_duration == 'permanent':
|
||||
domain.append(('payment_method', '!=', 'direct_debit'))
|
||||
rec.allowed_payment_method_ids = self.env['takaful.payment.method'].search(domain)
|
||||
|
||||
def _compute_product_id(self):
|
||||
for rec in self:
|
||||
if rec.product_template_id:
|
||||
rec.product_id = rec.product_template_id._get_first_possible_variant_id()
|
||||
else:
|
||||
rec.product_id = False
|
||||
|
||||
def onset_benefit_id(self):
|
||||
for rec in self:
|
||||
if rec.state == 'waiting' and rec.benefit_id:
|
||||
rec.state = 'active'
|
||||
|
||||
|
||||
@api.model
|
||||
def run_check_all_end_dates(self):
|
||||
lines = self.search([('end_date', '!=', False)])
|
||||
lines.check_end_date()
|
||||
|
||||
@api.depends('payment_month_count')
|
||||
def _compute_donation_amount(self):
|
||||
for rec in self:
|
||||
rec.donation_amount = rec.product_template_id.list_price * rec.payment_month_count
|
||||
|
||||
def check_end_date(self):
|
||||
for record in self:
|
||||
if record.end_date:
|
||||
today = fields.Date.today()
|
||||
end_date = record.end_date
|
||||
days_difference = (today - record.end_date).days
|
||||
if days_difference == 30:
|
||||
record.action_send_whatsapp(30,end_date)
|
||||
elif days_difference == 16:
|
||||
record.action_send_whatsapp(16,end_date)
|
||||
elif days_difference == 4:
|
||||
record.action_send_whatsapp(4,end_date)
|
||||
return False
|
||||
|
||||
|
||||
def action_send_whatsapp(self,duration,end_date):
|
||||
|
||||
if duration == 30:
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'before_finish'), ('message_type_ids.tool_type', '=', 'app'),('duration', '=', 30)],
|
||||
limit=1
|
||||
)
|
||||
expiry_date_str = end_date.strftime('%d-%m-%Y') if end_date else 'N/A'
|
||||
message = notification.message or _("No message found in 'Before Kafala End Date' notification.")
|
||||
message = message.replace('[ExpiryDate]', expiry_date_str)
|
||||
|
||||
elif duration == 16:
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'before_finish'), ('message_type_ids.tool_type', '=', 'app'),('duration', '=', 16)],
|
||||
limit=1
|
||||
)
|
||||
message = notification.message or _("No message found in 'Before Kafala End Date' notification.")
|
||||
|
||||
|
||||
|
||||
|
||||
elif duration == 4:
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'before_finish'), ('message_type_ids.tool_type', '=', 'app'),('duration', '=', 4)],
|
||||
limit=1
|
||||
)
|
||||
expiry_date_str = end_date.strftime('%d-%m-%Y') if end_date else 'N/A'
|
||||
message = notification.message or _("No message found in 'Before Kafala End Date' notification.")
|
||||
message = message.replace('[ExpiryDate]', expiry_date_str)
|
||||
|
||||
if not notification:
|
||||
raise ValidationError(_("No notification of type Before Kafala End Date found."))
|
||||
|
||||
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}'
|
||||
# Search for the notification message for 'create_kafala'
|
||||
|
||||
|
||||
# Use the message from the notification
|
||||
amount = self.donation_amount if hasattr(self, 'donation_amount') else 0.0
|
||||
|
||||
for partner in self:
|
||||
sponsorship_id = partner.sponsorship_mechanism_id or partner.sponsorship_id
|
||||
mobile = sponsorship_id.sponsor_id.mobile if sponsorship_id.sponsor_id else 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)
|
||||
|
||||
|
||||
|
||||
def donation_catelog(self):
|
||||
cart_object = self.env["donations.details.lines"]
|
||||
donation_object = self.env["product.template"]
|
||||
sponsorship_id = self.env['takaful.sponsorship'].browse(self.env.context.get('default_active_id'))
|
||||
cart_products_details = cart_object.search(
|
||||
[('sponsorship_id', "=", sponsorship_id.id)]) # , ("cart_flag", "=", True)
|
||||
product_object_data = donation_object.search(
|
||||
[("_quantity", "!=", 0)])
|
||||
assign_quantity = 0
|
||||
for rec in product_object_data:
|
||||
rec._quantity = 0
|
||||
if len(cart_products_details) > 0:
|
||||
for rec in cart_products_details:
|
||||
if assign_quantity == 0:
|
||||
assign_quantity += 1
|
||||
|
||||
kanban_view = self.env.ref(
|
||||
'odex_takaful.product_product_view_kanban')
|
||||
all_donation_lines = self.sponsorship_id.donations_details_lines
|
||||
|
||||
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Choose Donation Items'),
|
||||
'res_model': 'donations.items',
|
||||
'views': [(kanban_view.id, 'kanban')],
|
||||
'domain': [('id', 'not in', all_donation_lines.mapped('product_template_id').ids), ('show_donation_item','=',True), ('donation_type','=',self.donation_types)],
|
||||
'context': {
|
||||
# '_quantity_change': True,
|
||||
'sponsorship_id': sponsorship_id.id,
|
||||
'create': False
|
||||
},
|
||||
'help': _("""<p class="o_view_nocontent_smiling_face">
|
||||
Create a new product
|
||||
</p>""")
|
||||
}
|
||||
|
||||
def sol_by_cart(self, operation, product_id, sponsorship_id):
|
||||
"""
|
||||
Create Sale Order Line By
|
||||
Cart Functionality
|
||||
"""
|
||||
|
||||
sol_object = self.env["donations.details.lines"]
|
||||
|
||||
if product_id.payment_method_id:
|
||||
payment_method = product_id.payment_method_id.id
|
||||
else:
|
||||
payment_method = self.env["takaful.payment.method"].search([('payment_method', '=', 'cash')], limit=1).id
|
||||
|
||||
sol_data = dict()
|
||||
sol_data["product_template_id"] = product_id.id
|
||||
sol_data["sponsorship_id"] = sponsorship_id.id
|
||||
sol_data["donation_amount"] = product_id.fixed_donation_amount
|
||||
sol_data["payment_method_id"] = payment_method
|
||||
sol_data["donation_types"] = 'donation'
|
||||
sol_data["name"] = product_id.name
|
||||
|
||||
if operation == "add":
|
||||
sol_object.create(sol_data)
|
||||
return
|
||||
|
||||
sol_ = sol_object.search(
|
||||
[('sponsorship_id', '=', sponsorship_id.id), ('product_template_id', '=', product_id.id), ]) # ("cart_flag", "=", True)
|
||||
|
||||
if operation == "remove":
|
||||
sol_.unlink()
|
||||
return
|
||||
|
||||
|
||||
def user_input_qty_sol(self, _qty, product_id, sponsorship_id):
|
||||
sol_object = self.env["donations.details.lines"]
|
||||
product_object = self.env["product.template"]
|
||||
cart_product_details = sol_object.search(
|
||||
[('sponsorship_id', "=", sponsorship_id), ("product_template_id", "=", product_id)
|
||||
]) # ("cart_flag", "=", True)
|
||||
if product_id.payment_method_id:
|
||||
payment_method = product_id.payment_method_id.id
|
||||
else:
|
||||
payment_method = self.env["takaful.payment.method"].search([('payment_method', '=', 'cash')], limit=1).id
|
||||
|
||||
|
||||
donation_id = product_object.search([('id', '=', product_id)])
|
||||
sol_data = dict()
|
||||
sol_data["product_template_id"] = donation_id.id
|
||||
sol_data["sponsorship_id"] = sponsorship_id
|
||||
sol_data["donation_amount"] = donation_id.list_price
|
||||
sol_data["payment_method_id"] = payment_method
|
||||
sol_data["donation_types"] = 'donation'
|
||||
sol_data["name"] = donation_id.name
|
||||
so = sol_object.create(sol_data)
|
||||
return
|
||||
|
||||
|
||||
@api.onchange('benefit_id_number', 'sponsorship_type', 'benefit_type')
|
||||
def _onchange_benefit_id_number(self):
|
||||
for rec in self:
|
||||
if rec.benefit_id_number and rec.sponsorship_type == 'person' and rec.benefit_type in ['orphan', 'widow']:
|
||||
member = self.env['family.member'].search([('member_id_number', '=', rec.benefit_id_number)], limit=1)
|
||||
if member:
|
||||
rec.benefit_id = member
|
||||
else:
|
||||
rec.benefit_id = False
|
||||
|
||||
|
||||
@api.constrains('payment_month_count')
|
||||
def _check_payment_month_count(self):
|
||||
for rec in self:
|
||||
if rec.donation_type == 'sponsorship' and rec.sponsorship_duration == 'temporary' and rec.payment_option == 'month' and rec.payment_month_count <= 0:
|
||||
raise ValidationError(
|
||||
_("Payment Month Count should be greather than zero!")
|
||||
)
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(DonationsDetailsLines, self).default_get(fields)
|
||||
parent_id = self.env.context.get('default_active_id')
|
||||
parent_record = self.env['takaful.sponsorship'].browse(parent_id)
|
||||
|
||||
res['start_date'] = parent_record.sponsorship_creation_date
|
||||
res['sponsorship_creation_date'] = parent_record.sponsorship_creation_date
|
||||
# res['donation_mechanism'] = parent_record.donation_mechanism
|
||||
|
||||
self._onchange_sponsorship_type()
|
||||
return res
|
||||
|
||||
@api.onchange('donation_types', 'donation_type')
|
||||
def _onchange_sponsorship_type(self):
|
||||
for rec in self:
|
||||
if rec.sponsorship_mechanism_id:
|
||||
if rec.sponsorship_mechanism_id.record_type == 'sponsorship':
|
||||
rec.donation_type = 'sponsorship'
|
||||
|
||||
if rec.donation_types:
|
||||
if rec.donation_types == 'donation':
|
||||
rec.donation_type = 'donation'
|
||||
elif rec.donation_types == 'waqf':
|
||||
rec.donation_type = 'waqf'
|
||||
|
||||
@api.onchange('payment_method_id')
|
||||
def _onchange_payment_method(self):
|
||||
for rec in self:
|
||||
if rec.payment_method_id.payment_method == 'direct_debit':
|
||||
rec.payment_option = 'month'
|
||||
else:
|
||||
rec.payment_option = 'once'
|
||||
|
||||
@api.depends('start_date', 'payment_month_count')
|
||||
def _compute_end_date(self):
|
||||
for record in self:
|
||||
if record.start_date and record.payment_month_count:
|
||||
record.end_date = record.start_date + relativedelta(months=record.payment_month_count)
|
||||
else:
|
||||
record.end_date = False
|
||||
|
||||
@api.depends('benefit_ids')
|
||||
def _get_benefits_count(self):
|
||||
for rec in self:
|
||||
rec.benefits_count = len(rec.benefit_ids)
|
||||
|
||||
@api.depends('benefits_count','donation_amount')
|
||||
def _get_total_donation_amount(self):
|
||||
for rec in self:
|
||||
if rec.sponsorship_type == 'group':
|
||||
rec.total_donation_amount = rec.benefits_count * rec.donation_amount
|
||||
else :
|
||||
rec.total_donation_amount = rec.donation_amount
|
||||
|
||||
@api.depends('gender', 'education_status', 'education_level', 'sponsorship_type', 'benefit_type', 'age_category_id', 'benefit_family_code')
|
||||
def _compute_domain_ids(self):
|
||||
for rec in self:
|
||||
# Create a domain
|
||||
rec.members_domain_ids = [(6, 0, [])]
|
||||
|
||||
if rec.benefit_family_code and rec.sponsorship_type:
|
||||
benefit_ids = self.env['family.member'].search([('benefit_id.code', '=', rec.benefit_family_code)])
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search([('id', 'in', benefit_ids.ids)])
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
|
||||
if rec.benefit_type == 'orphan' and rec.sponsorship_type:
|
||||
base_domain = \
|
||||
[
|
||||
'|', ('state', '=', 'second_approve'), '&',('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended'),
|
||||
('member_status', '=', 'benefit'),
|
||||
'|',
|
||||
('relationn.relation_type', '=', 'daughter'),
|
||||
('relationn.relation_type', '=', 'son')
|
||||
]
|
||||
if rec.gender:
|
||||
if rec.gender == 'female':
|
||||
base_domain = [
|
||||
'|', ('state', '=', 'second_approve'), '&',
|
||||
('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended'),
|
||||
('member_status', '=', 'benefit'), ('relationn.relation_type', '=', 'daughter')]
|
||||
if rec.gender == 'male':
|
||||
base_domain = [
|
||||
'|', ('state', '=', 'second_approve'), '&',('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended'),
|
||||
('member_status', '=', 'benefit'), ('relationn.relation_type', '=', 'son')]
|
||||
if rec.education_status:
|
||||
base_domain.append(('education_status', '=', rec.education_status))
|
||||
if rec.education_level:
|
||||
base_domain.append(('education_levels', '=', rec.education_level.id))
|
||||
if rec.age_category_id:
|
||||
base_domain.append(('age', '<=', rec.age_category_id.max_age))
|
||||
base_domain.append(('age', '>=', rec.age_category_id.min_age))
|
||||
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search(base_domain)
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
if rec.benefit_type == 'widow' and rec.sponsorship_type:
|
||||
base_domain = ['|',('state','=','second_approve'),'&',('state','in',('waiting_approve','first_approve')),('action_type','=','suspended'),
|
||||
('member_status', '=', 'benefit'), '|', ('relationn.relation_type', '=', 'mother'),
|
||||
('relationn.relation_type', '=', 'replacement_mother')]
|
||||
if rec.education_status:
|
||||
base_domain.append(('education_status', '=', rec.education_status))
|
||||
if rec.education_level:
|
||||
base_domain.append(('education_levels', '=', rec.education_level.id))
|
||||
if rec.age_category_id:
|
||||
base_domain.append(('age', '<=', rec.age_category_id.max_age))
|
||||
base_domain.append(('age', '>=', rec.age_category_id.min_age))
|
||||
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search(base_domain)
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
if rec.benefit_type == 'both' and rec.sponsorship_type:
|
||||
base_domain = ['|',('state','=','second_approve'),'&',('state','in',('waiting_approve','first_approve')),('action_type','=','suspended'),
|
||||
('member_status', '=', 'benefit')]
|
||||
if rec.education_status:
|
||||
base_domain.append(('education_status', '=', rec.education_status))
|
||||
if rec.education_level:
|
||||
base_domain.append(('education_levels', '=', rec.education_level.id))
|
||||
if rec.age_category_id:
|
||||
base_domain.append(('age', '<=', rec.age_category_id.max_age))
|
||||
base_domain.append(('age', '>=', rec.age_category_id.min_age))
|
||||
rec.members_domain_ids = self.env['family.member'].sudo().search(base_domain)
|
||||
domain = {'benefit_id': [('id', 'in', rec.members_domain_ids.ids)]}
|
||||
return {'domain': domain}
|
||||
|
||||
@api.onchange('product_template_id','donation_types','donation_type')
|
||||
def onchange_product_template_id(self):
|
||||
for rec in self:
|
||||
# Process both donation details and mechanism details
|
||||
if rec.product_template_id.fixed_value:
|
||||
rec.donation_amount = rec.product_template_id.list_price
|
||||
selected_donations = []
|
||||
if rec.sponsorship_id or rec.sponsorship_mechanism_id:
|
||||
all_donation_lines = (
|
||||
(rec.sponsorship_id.donations_details_lines if rec.sponsorship_id else self.env['donations.details.lines']) |
|
||||
(rec.sponsorship_mechanism_id.donations_details_lines_mechanism_ids if rec.sponsorship_mechanism_id else self.env['donations.details.lines'])
|
||||
)
|
||||
selected_donations = all_donation_lines.mapped('product_template_id.id')
|
||||
domain = [('id', 'not in', selected_donations),('sale_ok', '=', True)]
|
||||
# Apply condition based on record type
|
||||
record_type = rec.sponsorship_id.record_type if rec.sponsorship_id else rec.sponsorship_mechanism_id.record_type
|
||||
|
||||
if record_type == 'donation':
|
||||
domain.append(('donation_category', '=', 'donation'))
|
||||
|
||||
elif record_type == 'sponsorship':
|
||||
domain.append(('donation_category', '=', 'sponsorship'))
|
||||
|
||||
return {
|
||||
'domain': {
|
||||
'product_template_id': domain}
|
||||
}
|
||||
|
||||
@api.onchange('donation_type')
|
||||
def onchange_donation_type(self):
|
||||
for rec in self:
|
||||
if rec.donation_type == 'sponsorship':
|
||||
rec.donation_mechanism = 'with_conditions'
|
||||
|
||||
def compute_sponsorships_lines(self):
|
||||
|
||||
for rec in self:
|
||||
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.payment_option == 'month':
|
||||
# Divide the total donation amount by the number of months
|
||||
if rec.payment_month_count > 0:
|
||||
base_amount, remainder = divmod(rec.donation_amount, rec.payment_month_count)
|
||||
else:
|
||||
raise ValidationError(
|
||||
_("Payment Month Count Must be Bigger than zero!")
|
||||
)
|
||||
|
||||
# Convert base_amount to a float with two decimal points
|
||||
base_amount = float(base_amount)
|
||||
|
||||
for index in range(rec.payment_month_count):
|
||||
# Add 1 to the base amount for the first 'remainder' months to handle the rounding issue
|
||||
amount = base_amount + 1 if index < remainder else base_amount
|
||||
# Format the amount to 2 decimal places for better representation
|
||||
amount = round(amount, 2)
|
||||
# Calculate the month and year
|
||||
month_year = (rec.start_date + relativedelta(months=index)).strftime("%m/%Y")
|
||||
# Create the Sponsorship Scheduling Link
|
||||
SponsorshipSchedulingLink.create({
|
||||
'sponsorship_id': sponsorship_id.id,
|
||||
'donation_detail_linked_id': rec.id,
|
||||
'beneficiary_id': rec.benefit_id.id,
|
||||
'month_year': month_year,
|
||||
'amount': amount
|
||||
})
|
||||
else:
|
||||
month_year = (sponsorship_id.sponsorship_creation_date + relativedelta(months=1)).strftime("%m/%Y")
|
||||
# Create the Sponsorship Scheduling Link
|
||||
SponsorshipSchedulingLink.create({
|
||||
'sponsorship_id': sponsorship_id.id,
|
||||
'donation_detail_linked_id': rec.id,
|
||||
'beneficiary_id': rec.benefit_id.id,
|
||||
'month_year': month_year,
|
||||
'amount': rec.donation_amount
|
||||
})
|
||||
rec.sponsorships_computed = True
|
||||
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# Check if sequence_no is not already set
|
||||
if vals.get('sequence_no', '/') == '/':
|
||||
# Assign the next sequence number
|
||||
vals['sequence_no'] = self.env['ir.sequence'].next_by_code('donations.details.lines.sequence') or '/'
|
||||
if vals.get('display_type'):
|
||||
vals.update({
|
||||
'product_template_id': False,
|
||||
'donation_type': False,
|
||||
'payment_method_id': False
|
||||
})
|
||||
|
||||
record = super(DonationsDetailsLines, self).create(vals)
|
||||
|
||||
if 'benefit_id' in vals and record.sponsorship_id:
|
||||
benefit_name = record.benefit_id.name or 'None'
|
||||
record.sponsorship_id.message_post(
|
||||
body=f"Benefit set to <b>{benefit_name}</b> in a donation item."
|
||||
)
|
||||
return record
|
||||
|
||||
|
||||
def write(self, vals):
|
||||
for rec in self:
|
||||
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)
|
||||
|
||||
if 'display_type' in vals and self.filtered(lambda line: line.display_type != vals.get('display_type')):
|
||||
raise UserError(
|
||||
_("You cannot change the type of a sale quote line. Instead you should delete the current line and create a new line of the proper type."))
|
||||
if 'benefit_id' in vals:
|
||||
new_benefit = rec.benefit_id.name or 'None'
|
||||
sponsorship = self.env['takaful.sponsorship'].browse(
|
||||
self.env.context.get('active_id'))
|
||||
if sponsorship and len(sponsorship) == 1:
|
||||
message = _("Benefit changed from <b>%s</b> to <b>%s</b> in a donation item.") % (
|
||||
old_benefit or 'None', new_benefit)
|
||||
sponsorship.message_post(body=message)
|
||||
|
||||
if 'benefit_ids' in vals:
|
||||
new_benefits = rec.benefit_ids.mapped('name')
|
||||
new_benefits_set = set(new_benefits)
|
||||
|
||||
added = new_benefits_set - old_benefits_set
|
||||
removed = old_benefits_set - new_benefits_set
|
||||
|
||||
changes = []
|
||||
if added:
|
||||
changes.append(_("Added: <b>%s</b>") % ', '.join(added))
|
||||
if removed:
|
||||
changes.append(_("Removed: <b>%s</b>") % ', '.join(removed))
|
||||
|
||||
if changes:
|
||||
# Find sponsorship
|
||||
sponsorship = rec.sponsorship_id or self.env['takaful.sponsorship'].browse(
|
||||
self.env.context.get('active_id'))
|
||||
|
||||
if sponsorship and len(sponsorship) == 1:
|
||||
message = _("Benefit IDs changed in a donation item:<br/>%s") % "<br/>".join(changes)
|
||||
sponsorship.message_post(body=message)
|
||||
return res
|
||||
|
||||
def action_view_replacement_wizard(self):
|
||||
self.ensure_one()
|
||||
|
||||
wizard = self.env['replacement.wiz'].create({
|
||||
'replacement_line_ids':[(0, 0, {
|
||||
'sponsorship_type': self.sponsorship_type,
|
||||
'from_benefit_id': self.benefit_id.id if self.sponsorship_type == 'person' else False,
|
||||
'from_benefit_ids': [(6, 0, self.benefit_ids.ids)] if self.sponsorship_type == 'group' else False
|
||||
})]
|
||||
})
|
||||
|
||||
return {
|
||||
'name': 'Replacement Wizard',
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'replacement.wiz',
|
||||
'view_mode': 'form',
|
||||
'res_id': wizard.id,
|
||||
'target': 'new',
|
||||
}
|
||||
class SponsorshipSchedulingLine(models.Model):
|
||||
_name = 'sponsorship.scheduling.line'
|
||||
|
||||
|
|
@ -2320,9 +1776,33 @@ class SponsorshipSchedulingLine(models.Model):
|
|||
record.cancel_refund = hours_passed >= max_hours
|
||||
else:
|
||||
record.cancel_refund = False
|
||||
|
||||
|
||||
|
||||
|
||||
def action_register_payment(self):
|
||||
invoice_id = self.env['account.move'].sudo().search([('takaful_sponsorship_id', 'in', [self.sponsorship_id.id])], limit=1)
|
||||
if not invoice_id:
|
||||
raise ValidationError(_("No invoice found for this sponsorship."))
|
||||
# payment_method_line = self.env['account.payment.method.line'].search([
|
||||
# ('journal_id', '=', self.payment_method_id.journal_id.id),
|
||||
# ('payment_type', '=', 'inbound')
|
||||
# ], limit=1)
|
||||
return {
|
||||
'name': _('Register Payment'),
|
||||
'res_model': 'account.payment.register',
|
||||
'view_mode': 'form',
|
||||
'context': {
|
||||
'active_model': 'account.move',
|
||||
'active_ids': invoice_id.ids,
|
||||
'dont_redirect_to_payments': True,
|
||||
'sponsorship_line_ids': self.donation_detail_linked_id.ids,
|
||||
'default_amount': self.amount,
|
||||
'default_journal_id': self.donation_detail_linked_id.payment_method_id.journal_id.id,
|
||||
'schedule_line_payment': True,
|
||||
'schedule_line_id': self.id,
|
||||
},
|
||||
'target': 'new',
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
def pay_sponsorship_scheduling(self):
|
||||
"""
|
||||
|
|
@ -2493,9 +1973,6 @@ class RefundDetailsLines(models.TransientModel):
|
|||
|
||||
invoiced = fields.Boolean(copy=False, readonly=True)
|
||||
|
||||
|
||||
|
||||
|
||||
class PaymentDetailsLines(models.Model):
|
||||
_name = "payment.details.lines"
|
||||
|
||||
|
|
@ -2540,8 +2017,6 @@ class PaymentDetailsLines(models.Model):
|
|||
payment_method_id = fields.Many2one('takaful.payment.method', string="Payment Method")
|
||||
payment_method = fields.Selection(selection=[("cash", "Cash"),("card", "Card"),("check", "Check"),("credit_card", "Credit Card"),("bank_transfer", "Bank Transfer"),("direct_debit", "Direct Debit")], related="payment_method_id.payment_method")
|
||||
|
||||
|
||||
|
||||
def action_send_whatsapp(self):
|
||||
notification = self.env['takaful.notification'].sudo().search(
|
||||
[('notification_type', '=', 'partial_payment'), ('message_type_ids.tool_type', '=', 'app')],
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class TakafulSponsor(models.Model):
|
|||
('verified', 'Verified')
|
||||
], string='State',default='draft', tracking=True)
|
||||
|
||||
preferred_communication = fields.Many2one('preferred.communication', string="Preferred Communication", required=True)
|
||||
preferred_communication = fields.Many2one('preferred.communication', string="Preferred Communication")
|
||||
serial_code = fields.Char(string="Serial Code", readonly=True, copy=False)
|
||||
|
||||
responsible_user_ids = fields.Many2many(
|
||||
|
|
@ -206,15 +206,14 @@ class TakafulSponsor(models.Model):
|
|||
|
||||
# @api.multi
|
||||
def unlink(self):
|
||||
sponsorships = self.env['takaful.sponsorship'].search([('sponsor_id', 'in', self.ids)]).sponsor_id
|
||||
for record in self:
|
||||
if record.active:
|
||||
if record.user_id:
|
||||
record.user_id.sudo().write({
|
||||
"active": False
|
||||
})
|
||||
record.active = False
|
||||
else:
|
||||
raise UserError(_('Sponsor is already inactive'))
|
||||
if record in sponsorships:
|
||||
raise UserError(_('Sponsor %s is associated with sponsorships') % record.name)
|
||||
self.user_id.sudo().write({
|
||||
"active": False
|
||||
})
|
||||
return super(TakafulSponsor, self).unlink()
|
||||
|
||||
# @api.multi
|
||||
def on_activate_sponsor_multi(self):
|
||||
|
|
@ -277,7 +276,7 @@ class TakafulSponsor(models.Model):
|
|||
user = self.env['res.users'].sudo().with_context(no_reset_password=False).create({
|
||||
'name': res.name,
|
||||
# 'user_type': 'company',
|
||||
'login': res.id_number if not res.email else res.email,
|
||||
'login': res.mobile,
|
||||
'phone': res.mobile,
|
||||
'mobile': res.mobile,
|
||||
'partner_id': res.partner_id.id,
|
||||
|
|
@ -294,7 +293,7 @@ class TakafulSponsor(models.Model):
|
|||
'middle_name': res.middle_name,
|
||||
'family_name': res.family_name,
|
||||
# 'user_type': 'person',
|
||||
'login': res.id_number if not res.email else res.email,
|
||||
'login': res.mobile,
|
||||
'phone': res.mobile,
|
||||
'mobile': res.mobile,
|
||||
'partner_id': res.partner_id.id,
|
||||
|
|
@ -309,10 +308,10 @@ class TakafulSponsor(models.Model):
|
|||
# in odoo relation field accept a list of commands
|
||||
# command 4 means add the id in the second position must be an integer
|
||||
# ref return an object so we return the id
|
||||
( 4, self.env.ref('odex_takaful.takaful_group_user_sponsor').id),
|
||||
]
|
||||
(4, self.env.ref('odex_takaful.takaful_group_user_sponsor').id),
|
||||
(3, self.env.ref('base.group_user', False).id),
|
||||
(4, self.env.ref('base.group_portal', False).id)]
|
||||
})
|
||||
|
||||
res.user_id = user.id
|
||||
return res
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ class SponsorshipPayment(models.Model):
|
|||
rec.amount = rec.month_amount * rec.payment_month_number
|
||||
|
||||
def action_pay(self):
|
||||
# Check for already sponsored beneficiaries only for sponsorship records
|
||||
|
||||
count = 0
|
||||
invoices = []
|
||||
if self.sponsorship_id.state in ['confirmed','wait_pay','progress' , 'to_cancel']:
|
||||
|
|
@ -185,6 +187,7 @@ class SponsorshipPayment(models.Model):
|
|||
).create(payment_register_vals)
|
||||
|
||||
payment_register.action_create_payments()
|
||||
|
||||
|
||||
# @api.multi
|
||||
def open_account_invoice_action(self):
|
||||
|
|
|
|||
|
|
@ -220,6 +220,42 @@
|
|||
<field name="perm_unlink" eval="1"/>
|
||||
</record>
|
||||
|
||||
<!-- Groups for Department-based Access Control -->
|
||||
<record id="group_grant_benefit_department_access" model="res.groups">
|
||||
<field name="name">Grant Benefit - Department Access</field>
|
||||
<field name="category_id" ref="module_category_kufula"/>
|
||||
<field name="comment">Limits grant.benefit records to user's department</field>
|
||||
</record>
|
||||
|
||||
<record id="group_family_member_department_access" model="res.groups">
|
||||
<field name="name">Family Member - Department Access</field>
|
||||
<field name="category_id" ref="module_category_kufula"/>
|
||||
<field name="comment">Limits family.member records to user's department</field>
|
||||
</record>
|
||||
|
||||
<!-- Record Rules for Department-based Access Control -->
|
||||
<record id="grant_benefit_department_rule" model="ir.rule">
|
||||
<field name="name">Grant Benefit - Department Based Access</field>
|
||||
<field name="model_id" ref="odex_benefit.model_grant_benefit"/>
|
||||
<field name="groups" eval="[(4, ref('group_grant_benefit_department_access'))]"/>
|
||||
<field name="domain_force">[('branch_custom_id.branch', 'child_of', user.employee_id.department_id.id)]</field>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="1"/>
|
||||
</record>
|
||||
|
||||
<record id="family_member_department_rule" model="ir.rule">
|
||||
<field name="name">Family Member - Department Based Access</field>
|
||||
<field name="model_id" ref="odex_benefit.model_family_member"/>
|
||||
<field name="groups" eval="[(4, ref('group_family_member_department_access'))]"/>
|
||||
<field name="domain_force">[('benefit_id.branch_custom_id.branch', 'child_of', user.employee_id.department_id.id)]</field>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_unlink" eval="1"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<field name="is_refund_sponsorship" invisible ="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='amount']" position="attributes">
|
||||
<attribute name="attrs">{'readonly':[('is_refund_sponsorship','=',True)]}</attribute>
|
||||
<attribute name="readonly">context.get('sponsorship_line_ids')</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='journal_id']" position="attributes">
|
||||
<attribute name="attrs">{'readonly':[('is_refund_sponsorship','=',True)]}</attribute>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="donations_details_lines_view_search" model="ir.ui.view">
|
||||
<field name="name">donations.details.lines.view.search</field>
|
||||
<field name="model">donations.details.lines</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Donation Details Lines">
|
||||
<field name="sequence_no"/>
|
||||
<field name="sponsor_id"/>
|
||||
<field name="benefit_id"/>
|
||||
<field name="product_template_id"/>
|
||||
<field name="branch_custom_id"/>
|
||||
<separator/>
|
||||
<!-- State Filters -->
|
||||
<filter string="To Pay" name="filter_draft" domain="[('state', '=', 'draft')]"/>
|
||||
<filter string="Waiting" name="filter_waiting" domain="[('state', '=', 'waiting')]"/>
|
||||
<filter string="Active" name="filter_active" domain="[('state', '=', 'active')]"/>
|
||||
<filter string="Closed" name="filter_closed" domain="[('state', '=', 'closed')]"/>
|
||||
<filter string="Extended" name="filter_extended" domain="[('state', '=', 'extended')]"/>
|
||||
<separator/>
|
||||
<!-- Record Type Filters -->
|
||||
<filter string="Sponsorship" name="filter_sponsorship" domain="[('donation_type', '=', 'sponsorship')]"/>
|
||||
<filter string="Donation" name="filter_donation" domain="[('donation_type', '=', 'donation')]"/>
|
||||
<filter string="Waqf" name="filter_waqf" domain="[('donation_type', '=', 'waqf')]"/>
|
||||
<separator/>
|
||||
<!-- Sponsorship Duration Filters -->
|
||||
<filter string="Permanent" name="filter_permanent" domain="[('sponsorship_duration', '=', 'permanent')]"/>
|
||||
<filter string="Temporary" name="filter_temporary" domain="[('sponsorship_duration', '=', 'temporary')]"/>
|
||||
<separator/>
|
||||
<!-- Donation Mechanism Filters -->
|
||||
<filter string="With Conditions" name="filter_with_conditions" domain="[('donation_mechanism', '=', 'with_conditions')]"/>
|
||||
<filter string="Without Conditions" name="filter_without_conditions" domain="[('donation_mechanism', '=', 'without_conditions')]"/>
|
||||
<separator/>
|
||||
<filter string="Without Beneficiary" name="filter_no_benefit" domain="[('benefit_id', '=', False), ('donation_type', '=', 'sponsorship')]"/>
|
||||
<filter string="With Beneficiary" name="filter_with_benefit" domain="[('benefit_id', '!=', False), ('donation_type', '=', 'sponsorship')]"/>
|
||||
<separator/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="State" name="group_state" context="{'group_by': 'state'}"/>
|
||||
<filter string="Donation Type" name="group_donation_type" context="{'group_by': 'donation_type'}"/>
|
||||
<filter string="Sponsorship Duration" name="group_duration" context="{'group_by': 'sponsorship_duration'}"/>
|
||||
<filter string="Donation Mechanism" name="group_mechanism" context="{'group_by': 'donation_mechanism'}"/>
|
||||
<filter string="Sponsor" name="group_sponsor" context="{'group_by': 'sponsor_id'}"/>
|
||||
<filter string="Branch" name="group_branch" context="{'group_by': 'branch_custom_id'}"/>
|
||||
<filter string="Product" name="group_product" context="{'group_by': 'product_template_id'}"/>
|
||||
<filter string="Creation Date" name="group_creation_date" context="{'group_by': 'create_date'}"/>
|
||||
</group>
|
||||
<separator/>
|
||||
<searchpanel>
|
||||
<field name="state" enable_counters="1"/>
|
||||
<field name="record_type" enable_counters="1"/>
|
||||
<field name="sponsorship_duration" enable_counters="1"/>
|
||||
<field name="donation_mechanism" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="donations_details_lines_view_tree" model="ir.ui.view">
|
||||
<field name="name">donations.details.lines.view.tree</field>
|
||||
<field name="model">donations.details.lines</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<tree default_order="create_date asc">
|
||||
<field name="sponsorship_scheduling_line_ids" invisible="1" />
|
||||
<field name="payment_method" invisible="1" />
|
||||
<field name="sequence_no" />
|
||||
<field name="sponsor_id" />
|
||||
<field name="sponsor_phone" />
|
||||
<field name="donation_type" optional="show"/>
|
||||
<field name="sponsorship_duration" optional="hide"/>
|
||||
<field name="donation_mechanism" optional="hide"/>
|
||||
<field name="payment_method_id" />
|
||||
<field name="product_template_id" />
|
||||
<field name="start_date" />
|
||||
|
|
@ -19,11 +79,20 @@
|
|||
<field name="benefit_family_code" optional="hide" />
|
||||
<field name="benefit_id" optional="hide" />
|
||||
<field name="sponsorship_creation_date" />
|
||||
<field name="create_date" optional="hide"/>
|
||||
<field name="state" widget="badge"
|
||||
decoration-muted="state == 'draft'"
|
||||
decoration-warning="state == 'waiting'"
|
||||
decoration-success="state == 'active'"
|
||||
decoration-info="state in ['closed', 'extended']" />
|
||||
decoration-success="state in ['active', 'paid']"
|
||||
decoration-danger="state == 'closed'"
|
||||
decoration-info="state == 'extended'" />
|
||||
|
||||
<button name="action_view_scheduling_lines"
|
||||
string="View Scheduling Lines"
|
||||
type="object"
|
||||
attrs="{'invisible': ['|', ('payment_method', '!=', 'direct_debit'), ('sponsorship_scheduling_line_ids', '=', [])]}"
|
||||
class="btn-secondary"
|
||||
icon="fa-calendar" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
@ -34,15 +103,21 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Donation Details">
|
||||
<header>
|
||||
<button name="action_register_payment"
|
||||
string="Register Payment"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible': ['|', '|', ('payment_method', '=', 'direct_debit'), ('is_paid', '=', True), ('parent_state', '!=', 'confirmed')]}" />
|
||||
<button string="Compute Sponsorships"
|
||||
name="compute_sponsorships_lines"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': ['|', ('sponsorships_computed', '=', True), ('payment_option', '!=', 'month')]}" />
|
||||
attrs="{'invisible': ['|', ('sponsorships_computed', '=', True), ('payment_method', '!=', 'direct_debit')]}" />
|
||||
<button string="Orphan Replacement"
|
||||
name="action_view_replacement_wizard"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible': ['|', '&',('state', 'not in', ['active', 'paid']), ('record_type', '=', 'donation'), ('donation_mechanism', '=', 'without_conditions')]}"
|
||||
groups="odex_takaful.group_orphan_replacement" />
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,waiting,active,closed,extended" />
|
||||
|
|
@ -73,6 +148,8 @@
|
|||
<field name="sponsor_phone" />
|
||||
<field name="branch_custom_id" />
|
||||
<field name="sponsorship_creation_date" />
|
||||
<field name="parent_state" invisible="1" />
|
||||
<field name="is_paid" invisible="1" />
|
||||
</group>
|
||||
</group>
|
||||
|
||||
|
|
@ -135,7 +212,7 @@
|
|||
<field name="benefit_type"
|
||||
attrs="{'invisible': [('donation_mechanism','!=','with_conditions')], 'required': [('donation_mechanism','=','with_conditions')]}" />
|
||||
<field name="benefit_id"
|
||||
attrs="{'invisible': ['|', ('sponsorship_type','!=','person'), ('donation_mechanism','!=','with_conditions')], 'required': [('members_domain_ids', '!=', []), ('sponsorship_type','=','person'), ('donation_mechanism','=','with_conditions')]}"
|
||||
attrs="{'invisible': ['|', ('sponsorship_type','!=','person'), ('donation_mechanism','!=','with_conditions')], 'required': [('members_domain_ids', '!=', []), ('sponsorship_type','=','person'), ('donation_mechanism','=','with_conditions'), ('state', 'in', ['active', 'closed', 'extended'])]}"
|
||||
options="{'no_create': True, 'no_create_edit':True, 'no_open': True}" />
|
||||
<field name="family_id"
|
||||
attrs="{'invisible': ['&', ('sponsorship_type','=','group'), ('record_type','=','sponsorship')],
|
||||
|
|
@ -178,7 +255,7 @@
|
|||
</page>
|
||||
|
||||
<page string="Sponsorship Scheduling"
|
||||
attrs="{'invisible': [('sponsorship_scheduling_line_ids', '=', False)]}">
|
||||
attrs="{'invisible': ['|', ('sponsorship_scheduling_line_ids', '=', False), ('payment_method', '!=', 'direct_debit')]}">
|
||||
<field name="sponsorship_scheduling_line_ids" mode="tree">
|
||||
<tree create="false" delete="false" edit="false">
|
||||
<field name="sequence_no" />
|
||||
|
|
@ -197,7 +274,7 @@
|
|||
<!-- To pay sponsorship scheduling line -->
|
||||
<button string="Pay" name="pay_sponsorship_scheduling"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': ['|', ('status', '!=', 'unpaid'), ('sponsorship_state', 'not in', ['confirmed', 'wait_pay','partial_refund'])]}" />
|
||||
attrs="{'invisible': ['|', '|', ('payment_method', '=', 'direct_debit'), ('status', '!=', 'unpaid'), ('sponsorship_state', 'not in', ['confirmed', 'wait_pay','partial_refund'])]}" />
|
||||
|
||||
<!-- To approve refund for donation lines -->
|
||||
<button string="Approve Refund" name="approve_refund"
|
||||
|
|
@ -233,6 +310,8 @@
|
|||
<field name="name">Donations Details Lines</field>
|
||||
<field name="res_model">donations.details.lines</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="donations_details_lines_view_search"/>
|
||||
<field name="context">{'create': False, 'delete': False, 'search_default_filter_waiting': 1}</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Tree view for product.template with sponsorship button -->
|
||||
<record id="view_product_template_tree_sponsorship" model="ir.ui.view">
|
||||
<field name="name">product.template.tree.sponsorship</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Products">
|
||||
<header>
|
||||
<button name="link_to_sponsorship"
|
||||
type="object"
|
||||
string="Link to Sponsorship"
|
||||
class="btn-primary"
|
||||
icon="fa-link"/>
|
||||
</header>
|
||||
<field name="name"/>
|
||||
<field name="donation_category"/>
|
||||
<field name="list_price" string="Price"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Tree View for Sponsorship Scheduling Line -->
|
||||
<record id="view_sponsorship_scheduling_line_tree" model="ir.ui.view">
|
||||
<field name="name">sponsorship.scheduling.line.tree</field>
|
||||
<field name="model">sponsorship.scheduling.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Sponsorship Scheduling Lines" decoration-success="status == 'paid'"
|
||||
decoration-info="status == 'unpaid'" decoration-danger="status == 'fully_refund'"
|
||||
decoration-warning="status in ('approve_refund', 'under_refund', 'partial_refund')">
|
||||
<field name="sequence_no"/>
|
||||
<field name="sponsorship_id"/>
|
||||
<field name="sponsorship_state"/>
|
||||
<field name="donation_detail_linked_id"/>
|
||||
<field name="beneficiary_id"/>
|
||||
<field name="month_year"/>
|
||||
<field name="amount" sum="Total Amount"/>
|
||||
<field name="refunded_amount" sum="Total Refunded"/>
|
||||
<field name="payment_method"/>
|
||||
<field name="status"/>
|
||||
<button name="action_register_payment"
|
||||
string="Register Payment"
|
||||
type="object"
|
||||
class="btn-primary"
|
||||
attrs="{'invisible': [('status', '!=', 'unpaid')]}" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Search View for Sponsorship Scheduling Line -->
|
||||
<record id="view_sponsorship_scheduling_line_search" model="ir.ui.view">
|
||||
<field name="name">sponsorship.scheduling.line.search</field>
|
||||
<field name="model">sponsorship.scheduling.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Sponsorship Scheduling Lines">
|
||||
<field name="sequence_no"/>
|
||||
<field name="sponsorship_id"/>
|
||||
<field name="beneficiary_id"/>
|
||||
<field name="month_year"/>
|
||||
<field name="donation_detail_linked_id"/>
|
||||
<separator/>
|
||||
<filter string="Unpaid" name="unpaid" domain="[('status', '=', 'unpaid')]"/>
|
||||
<filter string="Paid" name="paid" domain="[('status', '=', 'paid')]"/>
|
||||
<filter string="Approve Refund" name="approve_refund" domain="[('status', '=', 'approve_refund')]"/>
|
||||
<filter string="Under Refund" name="under_refund" domain="[('status', '=', 'under_refund')]"/>
|
||||
<filter string="Partial Refund" name="partial_refund" domain="[('status', '=', 'partial_refund')]"/>
|
||||
<filter string="Fully Refund" name="fully_refund" domain="[('status', '=', 'fully_refund')]"/>
|
||||
<separator/>
|
||||
<filter string="Cash" name="cash" domain="[('payment_method', '=', 'cash')]"/>
|
||||
<filter string="Card" name="card" domain="[('payment_method', '=', 'card')]"/>
|
||||
<filter string="Bank Transfer" name="bank_transfer" domain="[('payment_method', '=', 'bank_transfer')]"/>
|
||||
<filter string="Direct Debit" name="direct_debit" domain="[('payment_method', '=', 'direct_debit')]"/>
|
||||
<separator/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="Sponsorship" name="group_sponsorship" context="{'group_by': 'sponsorship_id'}"/>
|
||||
<filter string="Beneficiary" name="group_beneficiary" context="{'group_by': 'beneficiary_id'}"/>
|
||||
<filter string="Status" name="group_status" context="{'group_by': 'status'}"/>
|
||||
<filter string="Payment Method" name="group_payment_method" context="{'group_by': 'payment_method'}"/>
|
||||
<filter string="Month/Year" name="group_month_year" context="{'group_by': 'month_year'}"/>
|
||||
<filter string="Sponsorship State" name="group_sponsorship_state" context="{'group_by': 'sponsorship_state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Action for Sponsorship Scheduling Line -->
|
||||
<record id="action_sponsorship_scheduling_line" model="ir.actions.act_window">
|
||||
<field name="name">Sponsorship Scheduling Lines</field>
|
||||
<field name="res_model">sponsorship.scheduling.line</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="search_view_id" ref="view_sponsorship_scheduling_line_search"/>
|
||||
<field name="context">{'create': False}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new Sponsorship Scheduling Line
|
||||
</p>
|
||||
<p>
|
||||
Track and manage sponsorship payment schedules for beneficiaries.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -123,7 +123,7 @@
|
|||
<field name="city_id"/>
|
||||
<field name="branch_custom_id"/>
|
||||
<field name="district_id" invisible="1"/>
|
||||
<field name="preferred_communication"/>
|
||||
<field name="preferred_communication" required="1"/>
|
||||
<field name="responsible_user_ids" widget="many2many_tags" groups="odex_takaful.sponsorship_system_manager_group"/>
|
||||
<!-- <field name="journal_id"/> -->
|
||||
<!-- <label for="account_number" string="Bank Account"/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue