odex25_standard/odex25_ensan/odex25_program_activity/models/program.py

469 lines
17 KiB
Python

from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class PaProgramLevel(models.Model):
_name = 'pa.program.level'
_description = 'Program Levels Screen'
_rec_name = 'name'
_order = 'code'
code = fields.Char(
string='Level Code',
required=True,
copy=False,
readonly=True,
index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.level') or _('New'),
)
name = fields.Char(
string='Level Name',
required=True,
default=lambda self: _('Technical Tracks'),
help='Enter the level name such as: cultural, cognitive, religious, developmental, preventive, therapeutic',
)
type = fields.Selection([
('route', 'Tracks'),
('activity', 'Activities'),
('medad', 'Medad'),
], string='Level Type', required=True, help='Select the type of level')
description = fields.Text(string='Level Description')
active = fields.Boolean(string='Level Status', default=True)
track_ids = fields.One2many(
'pa.program.track',
'level_id',
string='Associated Tracks',
help='Tracks that belong to this level',
)
# Optional: enforce unique code at Python level
@api.model
def create(self, vals):
if 'code' in vals:
existing = self.search([('code', '=', vals['code'])])
if existing:
raise ValidationError(_('كود المستوى يجب أن يكون فريدًا'))
return super(PaProgramLevel, self).create(vals)
class PaProgramTrack(models.Model):
_name = 'pa.program.track'
_description = 'Program Track Screen'
_rec_name = 'name'
_order = 'code'
code = fields.Char(
string='Track Code',
required=True,
copy=False,
readonly=True,
index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.track') or _('New'),
)
name = fields.Char(string='Track Name', required=True)
description = fields.Text(string='Track Description')
# branch = fields.Many2one('age.category',string='Branch')
branch = fields.Many2one("branch.settings", string='Branch', domain="[('branch_type','=','branches')]")
gender = fields.Selection(
[('male', 'Male'), ('female', 'Female')],
string='Gender',
)
age_category = fields.Many2one(
'age.category',
string='Age Category',
help='Filter track based on age category',
)
study_category = fields.Many2one('education.level',string='Study Category')
hobby = fields.Char(string='Hobby')
study_status = fields.Char(string='Study Status')
health_status = fields.Char(string='Health Status')
education_status = fields.Char(string='Educational Status')
partner_id = fields.Many2one(
'res.partner',
string='Associated Partner',
help='The partner linked to the track'
)
active = fields.Boolean(string='Track Status', default=True)
level_id = fields.Many2one(
'pa.program.level',
string='Associated Level',
required=True,
ondelete='cascade'
)
class PaProgram(models.Model):
_name = 'pa.program'
_description = 'Programs Screen'
_rec_name = 'name'
_order = 'code'
code = fields.Char(
string='Program Code',
required=True,
copy=False,
readonly=True,
index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program') or _('New'),
)
name = fields.Char(string='Program Name', required=True)
program_type_id = fields.Many2one(
'pa.program.type',
string='Program Type',
)
payment_type = fields.Selection([
('paid', 'Paid'),
('unpaid', 'Unpaid')
], string='Payment Type', required=True)
sponsor_id = fields.Many2one('takaful.sponsorship', string='Linked Sponsor',
help='Sponsor is shown only if the payment type is Paid'
)
sponsor_support_amount = fields.Float(
string='Allocated Support Amount',
related='sponsor_id.total_sponsorship_amount',
readonly=True,
help='Support amount as per sponsor details'
)
budget = fields.Float(
string='Program Budget',
help='Used when payment type = Unpaid'
)
location = fields.Selection([
('inside', 'Internal'),
('outside', 'External')
], string='Program Location', required=True)
description = fields.Text(string='Program Description')
track_id = fields.Many2one(
'pa.program.track',
string='Associated Track',
help='Each program is linked to one track that contains several activities'
)
analytic_account_id = fields.Many2one(
'account.analytic.account',
string='Linked Analytic Account',
readonly=True,
help='Automatically created analytic account with the same name as the program and cannot be deleted'
)
estimated_budget = fields.Float(
string='Associated Estimated Budget',
help='Estimated budget related to the analytic account'
)
active = fields.Boolean(string='Program Status', default=True)
@api.constrains('payment_type', 'sponsor_id')
def _check_sponsor_if_paid(self):
for record in self:
if record.payment_type == 'paid' and not record.sponsor_id:
raise ValidationError(_('يجب اختيار الكافل في حالة نوع الدفع مدفوع'))
if record.payment_type == 'unpaid' and record.sponsor_id:
raise ValidationError(_('لا يجب اختيار كافل في حالة نوع الدفع غير مدفوع'))
@api.model
def create(self, vals):
res = super().create(vals) # ✅ fix
if not res.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': res.name,
'active': True,
})
res.analytic_account_id = account.id
return res
def write(self, vals):
res = super().write(vals) # ✅ same correction here
for record in self:
if not record.analytic_account_id:
account = self.env['account.analytic.account'].create({
'name': record.name,
'active': True,
})
record.analytic_account_id = account.id
return res
class PaProgramActivity(models.Model):
_name = 'pa.program.activity'
_description = 'Program Activity'
_rec_name = 'name'
code = fields.Char("Activity Code", required=True, copy=False, default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.activity'))
name = fields.Char("Activity Name", required=True)
description = fields.Text("Activity Description")
program_id = fields.Many2one('pa.program', string="Related Program")
location = fields.Selection([('inside', 'Internal'), ('outside', 'External')], required=True, string="Activity Location")
date_start = fields.Datetime("Activity Start Date")
date_end = fields.Datetime("Activity End Date")
analytic_account_id = fields.Many2one('account.analytic.account', string="Analytic Account")
estimated_budget = fields.Float("Estimated Budget")
active = fields.Boolean("Active", default=True)
class PaProgramMedad(models.Model):
_name = 'pa.program.medad'
_description = 'Medad'
_rec_name = 'name'
code = fields.Char("Medad Code", required=True, copy=False, default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.medad'))
name = fields.Char("Medad Name", required=True)
description = fields.Text("Medad Description")
medad_type = fields.Selection([
('skills', 'Skills'),
('training', 'Training'),
('innovation', 'Innovation Support')
], string="Medad Type", required=True)
activity_id = fields.Many2one('pa.program.activity', string="Associated Activity")
analytic_account_id = fields.Many2one('account.analytic.account', string="Associated Analytic Account")
estimated_budget = fields.Float("Estimated Budget")
active = fields.Boolean("Active", default=True)
# Example family/beneficiary for demo: you should replace with your actual model
class PaProgramActivityRegistration(models.Model):
_name = 'pa.program.activity.registration'
_description = 'Activity Registration'
_inherit = ['mail.thread']
name = fields.Char(string='Request Number', readonly=True, index=True,
default=lambda self: self.env['ir.sequence'].next_by_code('pa.program.activity.registration') or 'New')
request_date = fields.Datetime(string='Request Date', default=fields.Datetime.now, readonly=True)
creator_id = fields.Many2one('res.users', string='Creator', default=lambda self: self.env.user, readonly=True)
date_from = fields.Datetime(string='Date From')
date_to = fields.Datetime(string='Date To')
familye_id = fields.Many2one('grant.benefit', string='Family')
beneficiary_ids = fields.Many2many(
'family.member',
string='Beneficiary Name',
domain="[('benefit_id', '=', familye_id)]"
)
benefit_category_id = fields.Many2one(related='familye_id.benefit_category_id', string='Family Category', readonly=True)
# beneficiary_ids = fields.Many2many('family.member', string='Beneficiary Name')
sms_phone = fields.Char(related='familye_id.sms_phone', string='Mobile Number', readonly=True)
member_ids = fields.One2many(
'family.member',
'benefit_ids',
string='Family Members'
)
branch_custom_id = fields.Many2one(string='Branch', related='familye_id.branch_custom_id', readonly=True)
gender = fields.Selection(related='familye_id.gender', readonly=True)
nationality_id = fields.Many2one(string='Nationality', related='familye_id.nationality_id', readonly=True)
graduation_status = fields.Selection(string='Graduation Status', related='familye_id.graduation_status', readonly=True)
health_status = fields.Selection(string='Health Status', related='familye_id.health_status', readonly=True)
education_status = fields.Selection(string='Educational Status', related='familye_id.education_status', readonly=True)
mother_is_life = fields.Boolean(string='Is Mother Alive?', related='familye_id.mother_is_life', readonly=True)
mother_location_conf = fields.Many2one(string='Mother Location', related='familye_id.mother_location_conf', readonly=True)
is_mother_work = fields.Boolean(string='Is Mother Working?', related='familye_id.is_mother_work', readonly=True)
housing_type = fields.Selection(string='Housing Type', related='familye_id.housing_type', readonly=True)
beneficiary_relation = fields.Selection([
('mother', 'Mother'),
('son', 'Son'),
('daughter', 'Daughter')
], string='Beneficiary Relation')
sons = fields.Integer(
string="Number of Sons",
compute='_compute_sons_daughters',
store=False
)
daughters = fields.Integer(
string="Number of Daughters",
compute='_compute_sons_daughters',
store=False
)
return_reason = fields.Text(string='Return Reason')
@api.depends('familye_id', 'familye_id.member_ids', 'familye_id.member_ids.relationn',
'familye_id.member_ids.relationn.relation_type')
def _compute_sons_daughters(self):
for rec in self:
sons = 0
daughters = 0
members = rec.familye_id.member_ids.filtered(lambda m: m.relationn)
for member in members:
if member.relationn.relation_type == 'son':
sons += 1
elif member.relationn.relation_type == 'daughter':
daughters += 1
rec.sons = sons
rec.daughters = daughters
level_id = fields.Many2one('pa.program.level', string='مستويات البرامج', required=True)
track_id = fields.Many2one('pa.program.track', string='مسارات البرامج')
program_id = fields.Many2one('pa.program', string='البرامج')
activity_id = fields.Many2one('pa.program.activity', string='الانشطة')
medad_id = fields.Many2one('pa.program.medad', string='مداد')
want_transport = fields.Selection([('yes', 'نعم'), ('no', 'لا')], string='هل يرغب المستفيد في مواصلات')
state = fields.Selection([
('draft', 'مسودة'),
('social_specialist', 'اخصائي اجتماعي'),
('operation_manager', 'رئيس العمليات'),
('branch_manager', 'مدير الفرع'),
('activity_head', 'رئيس الأنشطة'),
('finance_manager', 'إدارة المالية'),
('approved', 'معتمد'),
('refused', 'مرفوض')
], default='draft', tracking=True)
rejection_reason = fields.Text('سبب الارجاع') # To hold the last rejection note
@api.onchange('familye_id')
def _onchange_familye_id(self):
if self.familye_id:
# Set member_ids to the current members of the selected familye_id
# This links existing family.member records (no create)
self.member_ids = [(6, 0, self.familye_id.member_ids.ids)]
else:
self.member_ids = [(5, 0, 0)] # Clear if no familye_id
# Validation of required fields based on level type
@api.constrains('level_id', 'track_id', 'program_id', 'activity_id', 'medad_id')
def _check_required_fields_based_on_level(self):
for rec in self:
if not rec.level_id:
continue
lvl_type = rec.level_id.type
if lvl_type == 'route': # مسارات
if not rec.track_id or not rec.program_id:
raise ValidationError(_('لحالة المستوى "مسارات"، الحقول "المسار" و "البرنامج" مطلوبان'))
elif lvl_type == 'activity': # أنشطة
if not rec.track_id or not rec.program_id or not rec.activity_id:
raise ValidationError(_('لحالة المستوى "أنشطة"، الحقول "المسار" و "البرنامج" و "النشاط" مطلوبة'))
elif lvl_type == 'medad': # مداد
if not rec.track_id or not rec.program_id or not rec.activity_id or not rec.medad_id:
raise ValidationError(_('لحالة المستوى "مداد"، جميع الحقول "المسار"، "البرنامج"، "النشاط"، "المداد" مطلوبة'))
def action_to_social_specialist(self):
self.ensure_one()
self.state = 'social_specialist'
def action_approve(self):
self.ensure_one()
transition_map = {
'social_specialist': 'operation_manager',
'operation_manager': 'branch_manager',
'branch_manager': 'activity_head',
'activity_head': 'finance_manager',
'finance_manager': 'approved',
}
next_state = transition_map.get(self.state)
if next_state:
self.state = next_state
def action_refuse(self):
self.ensure_one()
self.state = 'refused'
def action_reset_to_draft(self):
self.ensure_one()
self.state = 'draft'
def action_return_to_specialist(self):
self.ensure_one()
self.state = 'social_specialist'
def action_return_to_draft(self):
# Open wizard to collect return reason - opens form view on 'empowerment.return.reason.wizard'
return {
'type': 'ir.actions.act_window',
'name': _('سبب الإرجاع'),
'view_mode': 'form',
'res_model': 'pa.return.reason.wizard',
'target': 'new',
'context': {'default_registration_id': self.id}
}
class PaReturnReasonWizard(models.TransientModel):
_name = 'pa.return.reason.wizard'
_description = 'Return Reason Wizard'
reason = fields.Text(string='Return Reason', required=True)
registration_id = fields.Many2one('pa.program.activity.registration', string='Registration Request')
def action_confirm_return(self):
if self.registration_id:
self.registration_id.rejection_reason = self.reason
# move back to draft or social_specialist depending on the context/state
if self.registration_id.state == 'operation_manager':
self.registration_id.state = 'social_specialist'
self.registration_id.return_reason = self.reason
else:
self.registration_id.state = 'draft'
self.registration_id.return_reason = self.reason
return {'type': 'ir.actions.act_window_close'}
class PaProgram(models.Model):
_name = 'pa.family'
class PaProgramType(models.Model):
_name = 'pa.program.type'
pg_type =fields.Char(string='Name')
class FamilyMember(models.Model):
_inherit = 'family.member'
benefit_ids = fields.Many2one(
'pa.program.activity.registration',
string='Benefit Registration',
ondelete='cascade',
index=True,
)
need_trans = fields.Boolean(string='Need Transportation')
need_medicin = fields.Boolean(string='Need Medicien')
need_mental_dis = fields.Boolean(string='Have Mental Disorders')