# -*- coding: utf-8 -*- from odoo import models, fields, api, _ from odoo.exceptions import ValidationError from random import randint from datetime import date import logging import os import re SAUDI_MOBILE_PATTERN = "(^(05|5)(5|0|3|6|4|9|1|8|7)([0-9]{7})$)" _logger = logging.getLogger(__name__) class BenefitCategory(models.Model): _name = 'benefit.category' _description = "Benefits - category" name = fields.Char(string="Category Name") description = fields.Char(string="Description") gender = fields.Selection(selection=[('male', _('Male')), ('female', _('Female')) ,('both', _('Both'))], string="Gender") age_from = fields.Integer(string="From") age_to = fields.Integer(string="To") benefit_ids = fields.One2many('grant.benefit', 'benefit_category_id', string="Category Benefits") benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total") mini_income_amount = fields.Float(string="Min Income Amount") max_income_amount = fields.Float(string="Max Income Amount") expenses_ids = fields.One2many('expenses.line', 'category_id') is_benefit = fields.Boolean(string="Is Benefit",default=True) color = fields.Integer(string="Color Index", default=0) decoration_color = fields.Selection([ ('danger', 'Red'), ('success', 'Green'), ('warning', 'Orange'), ('info', 'Blue'), ('primary', 'Primary'), ('muted', 'Muted'), ]) def get_benefits_total(self): for rec in self: rec.benefits_total = len(rec.benefit_ids) def open_benefits(self): return { 'name': _("Benefits"), 'view_type': 'form', 'view_mode': 'tree,form', 'views': [(self.env.ref( 'odex_benefit.grant_benefit_tree').id, 'tree'), (self.env.ref('odex_benefit.grant_benefit_form').id, 'form')], 'res_model': 'grant.benefit', 'type': 'ir.actions.act_window', 'domain': [('id', 'in', self.benefit_ids.ids)], 'target': 'current', } class GrantFamily(models.Model): _name = 'benefit.family' _description = "Benefits - family" name = fields.Char( string='', required=False) responsible_benefit_id = fields.Many2one( 'grant.benefit', domain="[('is_responsible','=',True),('family_id','=',id)]") housing_id = fields.Many2one( 'benefit.housing') loan_ids = fields.Many2many('benefit.loans', 'family_id') total_expenses = fields.Float( compute='get_total_needs_percent', string='Total Expenses of Family', required=False) total_income = fields.Float( compute='get_total_needs_percent', string='Total Income of Family', required=False) benefit_needs_percent = fields.Float( compute='get_total_needs_percent', string='', store=True, required=False) is_producer = fields.Boolean(string='Producer') description = fields.Char(string="Description") benefits_total = fields.Integer(string="Benefit Total", compute="get_benefits_total", store=True) benefit_ids = fields.One2many('grant.benefit', 'family_id', string="Benefits") @api.depends("benefit_ids") def get_benefits_total(self): for rec in self: rec.benefits_total = len(rec.benefit_ids) def get_total_needs_percent(self): for rec in self: if rec.benefit_ids: percent = 0.0 for amount in rec.benefit_ids: rec.total_income += amount.total_income rec.total_expenses += amount.total_expenses percent += amount.benefit_needs_percent rec.benefit_needs_percent = percent / len(rec.benefit_ids) else: rec.benefit_needs_percent = 0.0 rec.total_income = 0.0 rec.total_expenses = 0.0 def open_benefits(self): return { 'name': "Benefits", 'view_type': 'form', 'view_mode': 'tree,form', 'views': [(self.env.ref( 'odex_benefit.grant_benefit_tree').id, 'tree'), (self.env.ref('odex_benefit.grant_benefit_form').id, 'form')], 'res_model': 'grant.benefit', 'type': 'ir.actions.act_window', 'domain': "[('family_id','=',%s)]" % (self.id), 'target': 'current', } class SportLine(models.Model): _name = 'sport.line' _description = "Benefits - sport" benefit_id = fields.Many2one( 'grant.benefit') sport_type = fields.Many2one( 'sport.type') sport_attendance = fields.Boolean( string='', required=False) Subtype = fields.Selection( string='Subtype', selection=[('daily', 'daily'), ('monthly', 'Monthly'), ('yearly', 'yearly'), ], ) sport_time = fields.Selection( string='Sport Time', selection=[('morning', 'Morning'), ('day', 'day'), ('evening', 'evening'), ], required=False, ) sport_club = fields.Char( string='', required=False) sport_amount = fields.Float( string='', required=False) sport_clothing = fields.Char( string='', required=False) sport_equipment = fields.Char( string='', required=False) class SportType(models.Model): _name = 'sport.type' _description = "Benefits - sport Type" name = fields.Char( string='', required=False) description = fields.Char( string='Description', required=False) class CraftSkills(models.Model): _name = 'craft.skills' _description = "Benefits - sport" name = fields.Char( string='', required=False) benefit_id = fields.Many2one( 'grant.benefit') is_invested = fields.Boolean( string='', required=False) skill_rating = fields.Float( string='', required=False) is_development = fields.Boolean( string='', required=False) is_capital = fields.Boolean( string='', required=False) is_work_place = fields.Boolean( string='', required=False) work_history = fields.Char( string='', required=False) achievements = fields.Char( string='', required=False) certificates = fields.Binary(string="") # Awards and certificates # TODO# class inclination(models.Model): _name = 'training.inclinations' _description = "Benefits - inclination" name = fields.Char( string='', required=False) benefit_id = fields.Many2one( 'grant.benefit') training_type_id = fields.Many2one('training.type', string='', required=False) is_invested = fields.Boolean( string='', required=False) training_rating = fields.Float( string='', required=False) is_development = fields.Boolean( string='', required=False) is_capital = fields.Boolean( string='', required=False) training_history = fields.Char( string='', required=False) book_history = fields.Char( string='What books has he read?', required=False) courses = fields.Char( string='What courses did he take?', required=False) steps = fields.Char( string='', required=False) training_future = fields.Char( string='', required=False) training_site = fields.Char( string='', required=False) training_records = fields.Char( string='', required=False) achievements = fields.Char() certificates = fields.Binary(string="") # Awards and certificates class BenefitBehaviors(models.Model): _name = 'benefit.behaviors' _description = "Benefits - behaviors" name = fields.Char( related='behavior_id.name') benefit_id = fields.Many2one( 'grant.benefit') behavior_id = fields.Many2one( 'benefit.behaviors.type') behavior_date = fields.Date( string='', required=False) need_help = fields.Boolean( string='', required=False) class BenefitBehaviorsType(models.Model): _name = 'benefit.behaviors.type' _description = "Benefits - behaviors type" name = fields.Char( string='', required=False) type = fields.Selection( string='', selection=[('negative', 'Negative'), ('positive', 'Positive'), ], required=False, ) class Salary(models.Model): _name = 'salary.line' _description = "Benefits - Salary line" benefit_id = fields.Many2one( 'grant.benefit') mother_benefit_id = fields.Many2one('grant.benefit', string="Mother Benefit", ondelete='cascade') currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id') salary_type = fields.Char() income_type = fields.Many2one('attachments.settings',string='Income Type',domain="[('attach_type','=','income_attach')]") salary_amount = fields.Float( string='Income Amount', required=False) salary_attach = fields.Many2many('ir.attachment',string="Attachment") attach_start_date = fields.Date(string='Attach Start Date') attach_end_date = fields.Date(string='Attach End Date') is_required = fields.Boolean(string='Is Required?') is_mother_salary = fields.Boolean(string="Is Mother Salary", default=False) approved = fields.Boolean(string="Is Approved", default=False) is_default = fields.Boolean(string='Is Default?') state = fields.Selection(string='Status',selection=[('waiting', 'Waiting'),('accepted', 'Accepted'),('refused', 'Refused')],default="waiting") note = fields.Char(string="Note") # total_salary = fields.Float(string="Total Salary", compute='_compute_total_salary',store=True) # @api.depends('salary_amount','state') # def _compute_total_salary(self): # total = 0 # for record in self: # # Apply your custom condition here # records = self.env['salary.line'].search([('state', '=', 'accepted')]) # for rec in records: # total += rec.salary_amount # record.total_salary = total @api.model def create(self, vals): if 'state' not in vals or vals.get('state') not in ['accepted', 'refused']: vals['state'] = 'waiting' return super(Salary, self).create(vals) def write(self, vals): if 'state' not in vals: for rec in self: if rec.state not in ['accepted', 'refused']: vals['state'] = 'waiting' break return super(Salary, self).write(vals) def action_accept(self): self.state = 'accepted' def action_refuse(self): self.state = 'refused' def get_salary_attachment_name(self): """Return salary attachment name without extension.""" if self.salary_attach: return os.path.splitext(self.salary_attach.name)[0] return '' def get_notification_emails(self): """Return a list of valid emails to notify, removing False values.""" emails = self.benefit_id.researcher_id.employee_id.mapped('work_email') or [] emails.extend([ self.benefit_id.branch_custom_id.branch.manager_id.work_email, self.benefit_id.branch_custom_id.branch.operation_manager_id.work_email ]) # Remove False or None values emails = list(filter(None, emails)) # Filters out None and False values return ','.join(emails) if emails else 'admin@example.com' def action_send_attachment_expiry_email(self): """Send email notifications for attachments expiring today and log the body in the chatter.""" today = date.today() salary_lines = self.search([('attach_end_date', '=', today)]) mail_template = self.env.ref('odex_benefit.email_salary_attachment_expiry') if not mail_template: raise ValidationError("Salary Attachment Expiry Mail template not found!") for salary_line in salary_lines: # Render the email body email_body = mail_template._render_field('body_html', [salary_line.id], compute_lang=True)[salary_line.id] # Send the email mail_template.send_mail(salary_line.id, force_send=True) # Post the email body in the chatter of benefit_id if salary_line.benefit_id: salary_line.benefit_id.message_post( body=email_body, subtype_xmlid="mail.mt_note" # Log as a note in the chatter ) class ibanBanks(models.Model): _inherit = 'res.bank' _description = "Add iban details in bank screen" iban = fields.Char("IBAN") code = fields.Char(string='Code') class benefitsExpensesLine(models.Model): _name = 'benefit.expenses' _description = "Benefits - expenses" name = fields.Char() benefit_id = fields.Many2one('grant.benefit') expenses_type = fields.Selection( string='', selection=[('governmental', 'Governmental Expenses'), ('medical', 'Medical Expenses'), ('transportation', 'Transportation Expenses'), ('debts', 'Debts Expenses'), ('pandemics', 'Pandemics Expenses'), ('living', 'Living Expenses'), ('educational', 'Educational Expenses'), ('clothing', 'Clothing Expenses'), ], required=False, ) expenses_fees_type = fields.Selection( string='Fees Type', selection=[('fixed', 'Fixed'), ('dynamic', 'dynamic')], required=False, ) medicine_type = fields.Selection( string='Medicine Type', selection=[('pills', 'pills'), ('drink', 'drink'), ('inhalation', 'inhalation')], required=False, ) diseases_type = fields.Selection( string='Diseases Type', selection=[('chronic', 'chronic'), ('psycho', 'psycho'), ('organic', 'organic')], required=False, ) trans_type = fields.Selection( string='trans Type', selection=[('general', 'General'), ('especially', 'Especially')], required=False, ) debt_reason = fields.Char(string='', required=False) attach = fields.Binary(string="",attachment=True ) debt_type = fields.Selection(selection=[('necessary', 'Necessary'), ('need', 'Need'), ('improve', 'to improve'), ('case', 'case or not'), ('Installed', 'Installed or not'), ]) pandemics_explain = fields.Char(string='pandemics explain', required=False) amount = fields.Float() state = fields.Selection([('draft', 'Draft'), ('accreditation', 'Accreditation'), ], string='state', default="draft", tracking=True) def action_accepted(self): for i in self: i.state = 'accreditation' class cloth(models.Model): _name = 'benefit.cloth' name = fields.Char() benefit_id = fields.Many2one('grant.benefit') cloth_type = fields.Many2one('cloth.type') cloth_size = fields.Many2one('cloth.size') cloth_note = fields.Char() class ClothType(models.Model): _name = 'cloth.type' name = fields.Char() class ClothSize(models.Model): _name = 'cloth.size' name = fields.Char() class ExpensesLine(models.Model): _name = 'expenses.line' category_id = fields.Many2one( 'benefit.category') benefit_id = fields.Many2one('grant.benefit') mother_benefit_id = fields.Many2one('grant.benefit',string="Mother Benefit",ondelete='cascade') currency_id = fields.Many2one('res.currency', related='benefit_id.currency_id') #expenses_type_custom = fields.Many2one('expenses.type') expenses_type_custom = fields.Many2one('attachments.settings', string='Expenses Type Custom', domain="[('attach_type','=','expense_attach')]") expenses_type = fields.Selection( string='', selection=[('governmental', 'Governmental Expenses'), ('medical', 'Medical Expenses'), ('transportation', 'Transportation Expenses'), ('debts', 'Debts Expenses'), ('pandemics', 'Pandemics Expenses'), ('living', 'Living Expenses'), ('educational', 'Educational Expenses'), ('clothing', 'Clothing Expenses'), ], required=False, ) amount = fields.Float() note = fields.Char() state = fields.Selection(string='Status', selection=[('waiting', 'Waiting'),('accepted', 'Accepted'), ('refused', 'Refused')],default="waiting") expense_attachments = fields.Many2many('ir.attachment','expenses_line_attachment_rel','expense_line_id','attachment_id',string="Attachment") deduct_from_family_income = fields.Boolean(string="Deduct from Family Income") def action_accept(self): # self.benefit_id.get_member_income() self.state = 'accepted' def action_refuse(self): self.state = 'refused' class EntityRefuseReason(models.Model): _name = 'entity.refuse_reason' name = fields.Text("Refuse Reason") user_id = fields.Many2one('res.users', 'Assigned to', default=lambda self: self.env.user, index=True) entity_id = fields.Many2one('grant.benefit', 'Benefit Id') date = fields.Datetime(string='Refuse Date', default=fields.Datetime.now) class specialization(models.Model): _name = 'specialization.specialization' name = fields.Char( string='', required=False) description = fields.Char( string='Description', required=False) is_scientific_specialty = fields.Boolean('Is Scientific Specialty?') is_medical_specialty = fields.Boolean('Is Medical Specialty?') class OtherAssociations(models.Model): _name = 'other.associations' name = fields.Char( string='', required=False) city_id = fields.Many2one( 'res.country.city') description = fields.Char( string='Description', required=False) class Associations(models.Model): _name = 'associations.line' benefit_id = fields.Many2one( 'grant.benefit') associations_ids = fields.Many2one( 'other.associations', string='Other Associations', required=False) support_type = fields.Selection( string='', selection=[('material', 'Material'), ('cash', 'cash'), ('both', 'Both'), ], required=False, ) support_amount = fields.Float( string='', required=False) associations_description = fields.Text( string="", required=False) class Hospital(models.Model): _name = 'hospital.hospital' name = fields.Char( string='', required=False) Location = fields.Char( string='', required=False) class InsuranceCompany(models.Model): _name = 'insurance.company' name = fields.Char( string='', required=False) description = fields.Char( string='Description', required=False) class InsuranceType(models.Model): _name = 'insurance.type' name = fields.Char( string='', required=False) description = fields.Char( string='Description', required=False) class Cars(models.Model): _name = 'cars.line' name = fields.Char() benefit_id = fields.Many2one('grant.benefit') is_driver_family_member = fields.Boolean(string="Is Driver Family Member?", default=True) driver_name = fields.Char(string="Driver Name") member_id = fields.Many2one('family.member',domain="[('benefit_id','=',benefit_id)]", string="Member") car_model = fields.Many2one('benefit.vehicle.model', ondelete='restrict') status = fields.Selection( string='', selection=[('good', 'Good'), ('bad', 'bad'), ], required=False,default='good' ) # TODO purchased_by_association = fields.Boolean( string="Purchased by the Association?", default=False, help="Indicates whether the car was purchased by the association" ) application_form = fields.Many2many('ir.attachment','cars_application_form_rel', 'cars_id','attachment_id',string="Application Form") driving_license = fields.Many2many('ir.attachment','cars_driving_license_rel','cars_id','attachment_id',string="Driving License") owner_identity = fields.Many2many('ir.attachment','cars_owner_identity_rel','cars_id', 'attachment_id',string="Owner Identity") @api.onchange('is_driver_family_member') def _onchange_is_driver_family_member(self): for rec in self: if rec.is_driver_family_member: rec.driver_name = False else: rec.member_id = False class TrainingType(models.Model): _name = 'training.type' name = fields.Char() class Committees(models.Model): _name = 'committees.line' _inherit = ['mail.thread', 'mail.activity.mixin'] name = fields.Char() employee_id = fields.Many2many('hr.employee',domain="[('branch_name','=',branch_id)]", string="Employee") type = fields.Selection( string='', selection=[('male', 'Men'), ('female', 'women'), ('both', 'combined'), ], required=False, ) branch_custom_id = fields.Many2one("branch.settings", string="Branch") branch_id = fields.Many2one('hr.department',string='Branch',related='branch_custom_id.branch',store=True) active = fields.Boolean('Active', default=True) benefit_count = fields.Integer(compute="get_benefit_count") mobile = fields.Char(string="Mobile Number") @api.constrains('mobile') def _check_mobile(self): for rec in self: if rec.mobile and not re.match(SAUDI_MOBILE_PATTERN, rec.mobile): raise ValidationError( _("Please enter a valid Saudi mobile number (example: 05xxxxxxxx).") ) def get_benefit_count(self): for record in self: benefit_ids = self.env['grant.benefit'].search([('researcher_id', 'in', record.ids)]) record.benefit_count = len(benefit_ids) def action_view_benefits(self): return { 'name': _('Benefits'), 'type': 'ir.actions.act_window', 'res_model': 'grant.benefit', 'view_mode': 'tree,form', 'domain': [('researcher_id', 'in', self.ids)], 'target': 'current', } class ResDistricts(models.Model): _name = 'res.districts' name = fields.Char(string="Name") meal_card = fields.Boolean(string='Meal Card') city_id = fields.Many2one('res.country.city') branch_custom_id = fields.Many2one("branch.settings", string="Branch") class VisitsSettings(models.Model): _name = 'visits.types' name = fields.Char(string="Name", required=True) creation_method = fields.Selection( [('manual', 'Manual'),('automatic', 'Automatic')], string="Creation Method", default='manual', required=True, help="Whether the visit is entered manually or created automatically" ) recurrence_interval = fields.Integer( string="Recurrence Interval", default=1, help="Determines how often visits are created automatically" ) recurrence_period = fields.Selection([ ('days', 'Days'), ('weeks', 'Weeks'), ('months', 'Months') ], string="Recurrence Period", default='days', help="Time unit for recurrence") otp_verification = fields.Boolean( string="OTP Verification", default=False, help="Whether this visit requires OTP confirmation from the family" ) otp_validity_minutes = fields.Integer( string="OTP Validity (Minutes)", default=5, help="OTP code validity duration in minutes" ) active = fields.Boolean( string="Active", default=True ) survey_id = fields.Many2one( 'survey.survey', string="Evaluation Survey" ) class SurveySetting(models.Model): _name = 'survey.setting' survey_url = fields.Char("Survey URL") class SuspendReason(models.Model): _name = 'suspend.reason' _description = "Suspend - Reason" name = fields.Char(string="Name", required=True) is_stop_reason = fields.Boolean(string="Stop Reason",default=False) is_reject_reason = fields.Boolean(string="Reject Reason",default=False) is_return_reason = fields.Boolean(string="Return Reason",default=False) is_resume_reason = fields.Boolean(string="Resume Reason", default=False) is_family_return_reason = fields.Boolean(string="Family Return Reason",default=False) is_incomplete_visit_reason = fields.Boolean(string="Incomplete Visit Reason",default=False) active = fields.Boolean(default=True) entity_type = fields.Selection([('family', 'Family'),('member', 'Member')],string='Entity Type') allow_service = fields.Boolean(string="Allow Service Use", default=False) days_before_final_suspend = fields.Integer(string="Days Before Final Suspension", default=0,help="Number of days before the suspension becomes final.") suspend_type = fields.Selection( selection=[('temporarily_suspend', 'Temporarily Suspended'), ('suspend', 'Suspend')], string="Suspend Type",) need_service_manager_approval = fields.Boolean( string="Needs Service Manager Approval" ) check_all_members_non_benefit = fields.Boolean(string="Check All Members Non-Benefit",default=False) class ReturnReason(models.Model): _name = "return.reason" _description = "Return Reasons" name = fields.Char(string="Name", required=True) active = fields.Boolean(string="Active", default=True) class BranchSettings(models.Model): _name = 'branch.settings' _description = "Branch Settings" name = fields.Char(related='branch.name') branch = fields.Many2one('hr.department',string='Branch',domain =[('is_branch', '=', True)]) manager_id = fields.Many2one('hr.employee', related='branch.manager_id') operation_manager_id = fields.Many2one('hr.employee', related='branch.operation_manager_id') branch_type = fields.Selection( selection=[ ('branches', 'Branches'), ('governorates', 'Governorates')], string='Branch Type') city_id = fields.Many2one('res.country.city') has_employees = fields.Boolean('Has Employees' ,defualt=True) replacement_branch_id = fields.Many2one( 'branch.settings', string="Replacement Branch" ) service_producer_id = fields.Many2one('res.partner', string='Service Producer') class RelationSettings(models.Model): _name = 'relation.settings' _description = "Relation Settings" name = fields.Char(string='name') relation_type = fields.Selection( [('son', _('Son')), ('daughter', _('Daughter')),('mother', _('Mother')),('replacement_mother', _('Replacement Mother')),('other relation', _('Other Relation'))]) age_difference = fields.Integer() grace_period_days = fields.Integer( string="Grace Period After Age Limit (Days)", default=0, help="Number of days the member remains eligible for benefits after reaching the configured age limit." ) class LocationSettings(models.Model): _name = 'location.settings' _description = "Location Settings" name = fields.Char(string='name') location_type = fields.Selection([('member', _('Member')), ('mother_location', _('Mother Location'))]) is_benefit = fields.Boolean(string='Is Benefit?') is_far_from_family = fields.Boolean(string='Is Far From Family?') replacement_mother_is_benefit = fields.Boolean(string="Replacement Mother Is Benefit?", default=True, ) class AttachmentsSettings(models.Model): _name = 'attachments.settings' _description = "Attachments Settings" _order = 'family_appearance_seq,member_appearance_seq,income_appearance_seq asc' name = fields.Char(string='name') hobby_id = fields.Many2one('hobbies.settings',string='Hobbies') diseases_id = fields.Many2one('diseases.settings',string='Diseases') disabilities_id = fields.Many2one('disabilities.settings',string='Disabilities') attach_type = fields.Selection( [('family_attach', _('Family Attach')), ('member_attach', _('Member Attach')), ('hobbies_attach', _('Hobbies Attach')), ('diseases_attach', _('Diseases Attach')), ('disabilities_attach', _('Disabilities Attach')), ('income_attach', _('Income Attach')), ('expense_attach', _('Expense Attach')), ('exams_attach', _('Exams Attach'))]) is_required = fields.Boolean(string='Is Required?') is_default = fields.Boolean(string='Is Default?') show_in_portal = fields.Boolean(default=True) family_appearance_seq = fields.Integer(string='Appearance Sequence') member_appearance_seq = fields.Integer(string='Appearance Sequence') income_appearance_seq = fields.Integer(string='Appearance Sequence') is_mother_salary = fields.Boolean(string="Is Mother Salary", default=False) parent_id = fields.Many2one('attachments.settings',string='Parent') child_ids = fields.One2many('attachments.settings','parent_id',string='Children') @api.constrains('parent_id') def _check_no_recursive_parent(self): for rec in self: parent = rec.parent_id while parent: if parent == rec: raise ValidationError( "Recursive hierarchy is not allowed." ) parent = parent.parent_id class EducationIlliterateReason(models.Model): _name = 'education.illiterate.reason' _description = "Education Illiterate Reason" name = fields.Char(string='name') class EducationDelayReason(models.Model): _name = 'education.delay.reason' _description = "Education Delay Reason" name = fields.Char(string='Name', required=True) class IncomeType(models.Model): _name = 'income.type' _description = "Income Type" name = fields.Char(string='name') class LoanGiver(models.Model): _name = 'loan.giver' _description = "LoanGiver" name = fields.Char(string='name') class LoanReason(models.Model): _name = 'loan.reason' _description = "Loan Reason" name = fields.Char(string='name') class HobbiesSettings(models.Model): _name = 'hobbies.settings' name = fields.Char(string="Name") class DiseasesSettings(models.Model): _name = 'diseases.settings' name = fields.Char(string="Name") class DisabilitiesSettings(models.Model): _name = 'disabilities.settings' name = fields.Char(string="Name") class ExceptionReason(models.Model): _name = 'exception.reason' name = fields.Char(string="Name") class MaritalStatus(models.Model): _name = 'marital.status' name = fields.Char(string="Name") is_benefit = fields.Boolean(string='Is Benefit?') is_dead = fields.Boolean(string='Is Dead?') replacement_mother_is_benefit = fields.Boolean(string="Replacement Mother Is Benefit?",default=True,) class AgeCategory(models.Model): _name = 'age.category' min_age = fields.Integer(string="From") max_age = fields.Integer(string="To") name = fields.Char(string="Name", compute="_compute_name", store=True) @api.depends('min_age', 'max_age') def _compute_name(self): for record in self: if record.min_age is not None and record.max_age is not None: record.name = f"[{record.min_age}:{record.max_age}]" else: record.name = "" class ComplaintsCategory(models.Model): _name = 'complaints.category' def _get_default_color(self): return randint(1, 11) name = fields.Char('Category Name', required=True, translate=True) color = fields.Integer('Color', default=_get_default_color) class ServiceAttachmentsSettings(models.Model): _name = 'service.attachments.settings' _description = "Service Attachments Settings" name = fields.Char(string='name') service_attach = fields.Many2many('ir.attachment','rel_service_attachments', 'service_id', 'attach_id',string="Attachment") service_type = fields.Selection( [('rent', 'Rent'), ('home_restoration', 'Home Restoration'), ('alternative_housing', 'Alternative Housing'), ('home_maintenance', 'Home Maintenance'), ('complete_building_house', 'Complete Building House'), ('electrical_devices', 'Electrical Devices'), ('home_furnishing', 'Home furnishing') , ('electricity_bill', 'Electricity bill'), ('water_bill', 'Water bill'), ('buy_car', 'Buy Car'), ('recruiting_driver', 'Recruiting Driver') , ('transportation_insurance', 'Transportation Insurance'), ('debits', 'Debits'), ('health_care', 'Health Care'), ('providing_medicines_medical_devices_and_needs_the_disabled', 'Providing Medicines Medical Devices And Needs The Disabled'), ('recruiting_domestic_worker_or_nurse', 'Recruiting a domestic worker or nurse'), ('marriage', 'Marriage'), ('eid_gift', 'Eid gift'), ('winter_clothing', 'Winter clothing'), ('ramadan_basket', 'Ramadan basket'), ('natural_disasters', 'Natural disasters'), ('legal_arguments', 'Legal arguments')],string='Service Type',related="service_id.service_type") service_id = fields.Many2one('services.settings',string='Service') service_request_id = fields.Many2one('service.request',string='Service Request') previous_service_attachment_settings_id = fields.Many2one('service.attachments.settings', readonly=True) notes = fields.Text(string='Notes') state = fields.Selection(selection=[ ('draft', 'Draft'), ('waiting_family', 'Waiting Family'), ('researcher', 'Researcher'), ('waiting_approve', 'Waiting for Operation Manager'), ('first_approve', 'Waiting for Branch Manager'), ('family_services_manager', 'Waiting Family Services Manager'), ('legal_department', 'Waiting Legal Department'), ('projects_department', 'Waiting Projects Department'), ('gm_assistant', 'Waiting Assistant General Manager'), ('accounting_approve', 'Accounting Approve'), ('return_to_bank', 'Return to Bank'), ('approval_of_beneficiary_services', 'Approval of beneficiary services'), ('send_request_to_supplier', 'Send Request To Supplier'), ('family_received_device', 'Family Received Device'), ('refused', 'Refused') ], string='State', default='waiting_family') class HomeMaintenanceItems(models.Model): _name = 'home.maintenance.items' maintenance_items_id = fields.Many2one('home.maintenance.lines', string="Maintenance Items") service_request_id = fields.Many2one('service.request',string='Service Request') class HomeFurnishingItems(models.Model): _name = 'home.furnishing.items' home_furnishing_items = fields.Many2one('home.furnishing.lines', string='Furnishing Items') furnishing_cost = fields.Float(string='Furnishing Cost') price_first = fields.Float(string='Price First') price_first_attach = fields.Many2many('ir.attachment','rel_first_price_attachments', 'furnishing_id', 'attach_id',string="First Price Attachment") price_second = fields.Float(string='Price Second') price_second_attach = fields.Many2many('ir.attachment','rel_second_price_attachments', 'furnishing_id', 'attach_id',string="Second Price Attachment") service_request_id = fields.Many2one('service.request',string='Service Request') class ElectricalDeviceLine(models.Model): _name = 'electrical.device.line' _description = 'Electrical Device Line' service_request_id = fields.Many2one('service.request',string='Service Request',ondelete='cascade',) device_id = fields.Many2one('electrical.devices',string='Device',compute='_compute_device_id',store=True) product_id = fields.Many2one('product.product',string='Product',required=True,) quantity = fields.Integer(string='Quantity',required=True,default=1) unit_price = fields.Float( string='Unit Price',compute='_compute_unit_price',store=True) subtotal = fields.Float(string='Subtotal',compute='_compute_subtotal',store=True) @api.depends('device_id') def _compute_unit_price(self): for line in self: if line.device_id: line.unit_price = line.product_id.standard_price else: line.unit_price = 0.0 @api.depends('quantity', 'unit_price') def _compute_subtotal(self): for line in self: line.subtotal = line.quantity * line.unit_price @api.depends('product_id', 'service_request_id.benefit_member_count', 'service_request_id.service_cat') def _compute_device_id(self): for line in self: if not line.product_id or not line.service_request_id or not line.service_request_id.service_cat: line.device_id = False continue member_count = line.service_request_id.benefit_member_count or 0 matching = line.service_request_id.service_cat.electrical_devices_lines.filtered( lambda d: line.product_id in d.product_ids and (d.min_count_member or 0) <= member_count <= (d.max_count_member or 999999) ) if matching: line.device_id = matching[0] else: line.device_id = False class PropertyTypeSettings(models.Model): _name = 'property.type.settings' _description = 'Property Type Settings' _order = 'name' name = fields.Char(string="Name", required=True) type = fields.Selection([ ('ownership', 'Ownership'), ('rent', 'Rent') ], string="Property Type", required=True) is_shared = fields.Boolean(string="Shared", default=False) active = fields.Boolean(string="Active", default=True) unavailable_service_ids = fields.Many2many( 'services.settings', string="Unavailable Services", help="Services that are not available for families or members with this property type" ) class RentContract(models.Model): _name = 'rent.contract' _description = 'Rent Contract' _inherit = ['mail.thread', 'mail.activity.mixin'] _order = 'create_date desc, id desc' name = fields.Char(string='Contract Number',required=True,copy=False,tracking=True) family_id = fields.Many2one('grant.benefit',string='Family',required=True,ondelete='cascade') member_id = fields.Many2one('family.member',string='Member (Tenant)', domain="""[ ('benefit_id', '=', family_id), ('education_status', '=', 'educated'), ('member_education_status_ids', '!=', False), ('member_education_status_ids.case_study', '=', 'continuous') ]""" ) contract_type = fields.Selection([ ('fixed', 'Fixed Term'), ('unlimited', 'Indefinite'), ], string='Contract Type', required=True, default='fixed', tracking=True) start_date = fields.Date(string='Start Date', required=True) end_date = fields.Date(string='End Date') payment_type = fields.Selection([ ('1', 'Yearly'), ('2', 'Half-yearly'), ('4', 'Quarterly'), ('12', 'Monthly'), ], string='Payment Type', required=True, default='2') rent_amount = fields.Float(string='Rent Amount', required=True) contract_attachment = fields.Many2many( 'ir.attachment', 'rent_contract_attachment_rel', 'contract_id', 'attachment_id', string='Contract Attachment' ) electricity_bill_attachment = fields.Many2many( 'ir.attachment', 'rent_electricity_bill_rel', 'contract_id', 'attachment_id', string='Electricity Bill Attachment' ) state = fields.Selection([ ('active', 'Active'), ('expired', 'Expired'), ], string='Status', default='active', tracking=True) landlord_type = fields.Selection([ ('family', 'Family'), ('member', 'Member / Student'), ], string='Landlord Type', default='family', required=True) @api.onchange('end_date', 'start_date') def _onchange_contract_dates(self): if self.end_date and self.start_date and self.end_date < self.start_date: raise ValidationError(_("End Date cannot be before Start Date.")) @api.onchange('landlord_type') def _onchange_landlord_type(self): for rec in self: if rec.landlord_type == 'family': rec.member_id = False