# -*- coding: utf-8 -*-
import logging
from datetime import datetime, date

from dateutil.relativedelta import relativedelta as rd
from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
import qrcode
import base64
from io import BytesIO
import re
from odoo.osv import expression

SAUDI_MOBILE_PATTERN = "(^(05|5)(5|0|3|6|4|9|1|8|7)([0-9]{7})$)"
ALPHABETIC_PATTERN = "^[\u0600-\u065F\u066A-\u06EF\u06FA-\u06FFA-Za-z ]+$"

_logger = logging.getLogger(__name__)


class GrantBenefitProfile(models.Model):
    _name = 'grant.benefit'
    _description = "Benefits - Profiles"
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _inherits = {'res.partner': 'partner_id'}
    _order = 'create_date desc'
    def get_url(self):
        return "wwww"

    #def name_get(self):
    #    result = []
    #    for rec in self:
    #        if rec.name and rec.code:
    #            display_name = f"{rec.code} - {rec.name}"
    #            result.append((rec.id, display_name))
    #        else:
    #            result.append((rec.id, rec.name or rec.code or ""))
    #    return result

    @api.model
    def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
        args = args or []
        name = name.strip() if name else ""

        if operator == "ilike" and not name:
            domain = []
        else:
            domain = ["|", "|", "|",
                      ("name", operator, name),
                      ("code", operator, name),
                      ("sms_phone", operator, name),
                      ("father_id_number", operator, name),
                      ]
        return self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid)

    profile_step_count = fields.Integer()
    complete_registration_step = fields.Char(string="Complete Registration Step")
    complete_registration_done = fields.Boolean('Does Complete Registration Done ?')
    partner_id = fields.Many2one('res.partner', string='partner', required=True, ondelete="cascade")
    code = fields.Char(string="Code", copy=False, default=lambda x: _('New'))
    benefit_type = fields.Selection([('benefit', 'benefit'), ('orphan', 'orphan'), ('widow', 'widow')
                                     ], string='Benefit Type', tracking=True)
    mother_status = fields.Selection(string='Mother Status', related="mother_family_member_id.member_status")
    mother_salary_certificate = fields.Many2many('ir.attachment', 'mother_member_salary_cert_rel', 'mother_grant_benefit_id', 'attachment_id',
                                          string="Salary Certificate")
    phone2 = fields.Char(string="Phone2")
    relative_phone = fields.Char(string="Relative Phone")
    relative_relation = fields.Char(string="Relative Relation")
    sms_phone = fields.Char(string="Contact Phone",tracking=True)
    name_in_bank = fields.Char()
    family_bank = fields.Many2one('res.partner.bank')
    acc_number = fields.Char('Account Number',copy=False,tracking=True)
    acc_holder_name = fields.Char('Account Holder Name')
    acc_holder_id_number = fields.Char(string="Account Holder ID Number")
    bank_id = fields.Many2one("res.bank",string='Bank')
    account_relation = fields.Many2one('relation.settings',string="Account Owner Relation")
    orphan_status = fields.Selection(
        selection=[('father', 'Father-Orphan'), ('mother', 'Mother-Orphan'), ('parent', 'Parent-Orphan'), ],
        compute="_compute_orphan_Type", store=True)
    iban_attach = fields.Many2many('ir.attachment',
                                   relation="ir_iban_attach_rel",
                                   column1="iban",
                                   column2="name",
                                   string="Iban Attach")
    id_number_attach = fields.Many2many('ir.attachment',
                                        relation="ir_id_number_attach_rel",
                                        column1="id_number",
                                        column2="name",
                                        string="Id Number Attach")
    instrument_number = fields.Char()
    instrument_attach = fields.Many2many('ir.attachment',
                                         relation="ir_instrument_attach_rel",
                                         column1="instrument_number",
                                         column2="name",
                                         string="Instrument Attach")
    step = fields.Integer('Step')
    has_needs = fields.Boolean(compute='_onchange_is_has_needs',
                               store=True)  # This boolean filed for check if benefit has need in
    # Job
    job_position = fields.Char()
    job_department = fields.Char()
    job_company = fields.Char()
    # login info
    user_id = fields.Many2one('res.users', string="User")
    password = fields.Char('Password')
    # Category And Family
    benefit_category_id = fields.Many2one('benefit.category', string='Benefit Category', compute="get_benefit_category",store=True,tracking=True)
    benefit_category_old = fields.Many2one('benefit.category', string='Family category in the old system')
    family_id = fields.Many2one('benefit.family', string='Benefit Family')
    # address
    housing_id = fields.Many2one('benefit.housing', string='Benefit Housing')
    lat = fields.Float(string='Lat', digits=(16, 5))
    lon = fields.Float(string='Long', digits=(16, 5))
    block = fields.Char(string='block')
    street = fields.Char(string='street')
    house_number = fields.Char(string='house number')
    floor = fields.Char(string='floor')
    housing_number = fields.Char(string='housing number')
    rent_amount = fields.Float(string='Rent Amount',compute='_compute_rent_from_contract',store=True)
    estimated_rent_amount = fields.Float(string="Estimated Rent Amount", compute="_compute_estimated_rent_amount",store=True)
    housing_type = fields.Selection([
        ('apartment', 'apartment'),
        ('villa', 'villa'),
        ('popular_house', 'popular house'),
        ('tent', 'tent'),
        ('Appendix', 'Appendix'), ], default='apartment',tracking=True)
    property_instrument_number = fields.Char(string='Property Instrument number')
    property_instrument_attach = fields.Many2many('ir.attachment','rel_property_instrument_attach_attachment','benefit_id','attachment_id',string='Property Instrument Attach')
    electricity_attach = fields.Many2many('ir.attachment','rel_electricity_attach_attachment','benefit_id','attachment_id',string='Electricity Attach',compute='_compute_rent_from_contract',store=True,)
    property_instrument_date = fields.Date(string='Property Instrument Date')
    location_url = fields.Char(string='Location URL')
    location = fields.Char(string='location')
    rooms_number = fields.Integer('Rooms Number')
    water_bill_account_number = fields.Char(string='water Bill Account Number', )
    electricity_bill_account_number = fields.Char(string='Electricity Bill Account Number')
    domestic_labor_ids = fields.Many2many('domestic.labor')
    responsible = fields.Selection(string='responsible', selection=[('father', 'Father'),
                                                                    ('mother', 'mother'),
                                                                    ('other', 'other')], required=False, )
    responsible_id = fields.Many2one('grant.benefit', domain="[('is_responsible','=',True)]", string='', required=False)
    qr_code = fields.Binary( attachment=True, compute='_compute_qr_code')
    ## car data
    car_ids = fields.One2many('cars.line', 'benefit_id')
    car_count = fields.Integer(compute='_onchange_car_count')
    # compute = 'count_car'
    ####clothing data #
    cloth_ids = fields.One2many('benefit.cloth', 'benefit_id')
    expenses_request_ids = fields.One2many('benefit.expenses', 'benefit_id')
    expenses_ids = fields.One2many('expenses.line', 'benefit_id')
    mother_expenses_ids = fields.One2many('expenses.line','mother_benefit_id',string="Mother Commitments / Expenses")
    # Father's case and his data # Birth Date # Address # dead data
    # Father's case and his data
    # family_name = fields.Char(string="Family Name", tracking=True)
    benefit_partner_name = fields.Char(string="Name",related='partner_id.name',store=True)
    # father_name = fields.Char(string="Father First Name", tracking=True)
    # father_second_name = fields.Char(string="Father Second Name", tracking=True)
    # father_third_name = fields.Char(string="Father Third Name", tracking=True)
    # father_family_name = fields.Char(string="Father Family Name", tracking=True)
    father_id_number = fields.Char(string="Id Number", tracking=True)
    father_marital = fields.Selection(
        [('single', _('Single')), ('married', _('Married')), ('widower', _('Widower')), ('divorced', _('Divorced'))],
        _('Marital Status'), default='single', tracking=True)
    father_job_id = fields.Many2one('job.settings')
    father_job_id_not_defined = fields.Boolean(related="father_job_id.not_defined")
    father_job = fields.Char(string='Father Job')
    father_id_number_type = fields.Selection([('citizen', _('Citizen')),('resident', _('Resident')),('visitor', _('Visitor'))],string='Father ID number type')
    father_birth_date = fields.Date(string="Birth Date")
    father_age = fields.Integer(string="Age", compute='_compute_get_father_age')
    father_country_id = fields.Many2one('res.country', 'Father Nationality', tracking=True)
    father_city_id = fields.Many2one('res.country.city', string='City')
    father_dead_reason_id = fields.Many2one('death.reason.settings', string='Dead Reason', required=False)
    father_dead_reason_id_not_defined = fields.Boolean(related='father_dead_reason_id.not_defined')
    father_dead_reason = fields.Char(string='Dead Reason', required=False)
    father_dead_date = fields.Date(string="Father Dead Date")
    father_dead_country_id = fields.Many2one('res.country', string='Father Dead Country', tracking=True)
    father_dead_country_id_code = fields.Char(related='father_dead_country_id.code')
    father_dead_city_id = fields.Many2one('res.country.city', string='Father Dead City',domain="[('country_id', '=', father_dead_country_id)]")
    father_dead_res_city_id = fields.Many2one('res.country.city', string='Father Dead City',domain="['|', ('country_id', '=', father_dead_country_id), ('country_id', '=', False)]")
    father_dead_city = fields.Char(string='Father Dead City')
    father_dead_certificate = fields.Many2many('ir.attachment', 'rel_father_dead_attachment','benefit_id','attachment_id',string='Father Dead Certificate')
    # Mother's case and her data # Birth Date # Address # dead data
    mother_relation = fields.Selection(
        [('mother', _('Mother')), ('replacement_mother', _('Replacement Mother'))])
    mother_relationn = fields.Many2one('relation.settings',domain="['|',('relation_type','=','mother'),('relation_type','=','replacement_mother')]")
    replacement_mother_relation = fields.Many2one('relation.settings',domain="[('relation_type','=','replacement_mother')]")
    mother_id = fields.Many2one('grant.benefit', domain="[('benefit_type','!=','orphan'),('gender','=','female')]")
    mother_name = fields.Char(string="Mother Name", tracking=True)
    mother_second_name = fields.Char(string="Mother Second Name", tracking=True)
    mother_third_name = fields.Char(string="Mother Third Name", tracking=True)
    mother_family_name = fields.Char(string="MotherFamily Name", tracking=True)
    mother_country_id = fields.Many2one('res.country', 'Mother Nationality', tracking=True)
    mother_id_number = fields.Char(string="Id Number", tracking=True)
    mother_id_number_type = fields.Selection([('citizen', _('Citizen')),('resident', _('Resident')),('visitor', _('Visitor'))],string='Mother ID number type')
    mother_marital = fields.Selection(
        [('married', _('Married')), ('widower', _('Widower')), ('divorced', _('Divorced')),
         ('divorced_from_another_man', _('Divorced From Another Man'))
            , ('prisoner', _('Prisoner')), ('dead', _('Dead')), ('hanging', _('Hanging'))],
        _('Marital Status'))
    mother_marital_conf = fields.Many2one('marital.status',string='Mother Marital')
    mother_is_dead = fields.Boolean(string='Mother Is Dead?',related='mother_marital_conf.is_dead')
    mother_dead_country_id = fields.Many2one('res.country', string='Mother Dead Country', tracking=True)
    mother_dead_country_id_code = fields.Char(related='mother_dead_country_id.code')
    mother_dead_city_id = fields.Many2one('res.country.city', string='Mother Dead City',domain="[('country_id', '=', mother_dead_country_id)]")
    mother_dead_reason_id = fields.Many2one('death.reason.settings', string='Mother Dead Reason', required=False)
    mother_dead_reason_id_not_defined = fields.Boolean(related='mother_dead_reason_id.not_defined')
    mother_dead_reason = fields.Char(string='Mother Dead Reason', required=False)
    mother_dead_res_city_id = fields.Many2one('res.country.city', string='Mother Dead City',domain="[('country_id', '=', mother_dead_country_id)]")
    mother_dead_city = fields.Char(string='Mother Dead City')
    mother_location = fields.Selection(
        [('with_husband_and_children', _('With Husband And Children')), ('with_children', _('With Children')),
         ('not_live_with_children', _('Not live with children'))], string='Mother Location')
    mother_location_conf = fields.Many2one('location.settings',string='Mother Location',domain="[('location_type','=','mother_location')]")
    is_mother_work = fields.Boolean('Is Mother Work?')
    mother_has_disabilities = fields.Boolean('Has Disabilities?')
    mother_income = fields.Float("Mother Income", digits=(16, 0),compute='calculate_income', store=True,tracking=True)
    mother_net_income = fields.Float(string="Mother Net Income",compute='_compute_mother_net_income',
        store=True,help="Mother gross income minus her deducted expenses and monthly debt installments")
    mother_birth_date = fields.Date(string="Birth Date")
    mother_age = fields.Integer(string="Age", compute='_compute_get_mother_age')
    mother_city_id = fields.Many2one('res.country.city', string='City')
    mother_dead_reason = fields.Char(string='Dead Reason', required=False)
    mother_dead_date = fields.Date(string="Mother Dead Date")
    mother_dead_certificate = fields.Many2many('ir.attachment', 'rel_mother_dead_attachment','benefit_id','attachment_id',string='Mother Dead Certificate')
    mother_family_member_id = fields.Many2one('family.member', string='Mother Family Member', domain="[('id','in',member_ids)]")
    replacement_mother_family_member_id = fields.Many2one('family.member', string='Mother Family Member', domain="[('id','in',member_ids)]")
    member_ids = fields.One2many('family.member', 'benefit_id')
    # orphan
    orphan_ids = fields.Many2many('grant.benefit', 'orphan_list', 'id_number', 'mother_id',
                                  compute='_orphan_list_compute')
    orphan_count = fields.Integer(
        string='',
        required=False)
    # widows and divorcees
    widows_ids = fields.One2many('widow.family', 'benefit_id', string='Widows', required=False)
    divorcee_ids = fields.One2many('divorcee.family', 'benefit_id', string='divorcee', required=False)
    # Husband info
    husband_name = fields.Char('Husband')
    husband_id = fields.Char('Husband ID')
    date_death_husband = fields.Date()
    date_divorcee = fields.Date()
    # Education_data
    mother_education_status_ids = fields.One2many('education.status', 'mother_grant_benefit_id')
    mother_diseases_attachment_ids = fields.One2many('ir.attachment', 'mother_grant_benefit_id', string='Diseases Attachments',domain=[('diseases_id', '!=', False)])
    mother_disabilities_attachment_ids = fields.One2many('ir.attachment', 'mother_grant_benefit_id', string='Disabilities Attachments',domain=[('disabilities_id', '!=', False)])
    education_status = fields.Selection(
        string='Education Status',
        selection=[('educated', 'educated'), ('illiterate', 'illiterate')],
        defualt='illiterate'
    )
    case_study = fields.Selection(string='Case Study',
                                  selection=[('continuous', 'continuous'), ('intermittent', 'intermittent'),
                                             ('graduate', 'Graduate')])
    illiterate_reason = fields.Char(string='Illiterate Reason')
    intermittent_reason = fields.Many2one('education.illiterate.reason',string='Intermittent Reason')
    education_entity = fields.Selection(string='Education Entity', selection=[('governmental', 'Governmental'),
                                                                              ('special', 'Special')])
    education_start_date = fields.Date(string='Education Start Date')
    education_end_date = fields.Date(string='Education End Date')
    educational_certificate = fields.Many2many('ir.attachment','rel_educational_certificate_attachment','benefit_id','attachment_id',string='Educational Certificate')
    last_education_entity = fields.Selection(string='Last Education Entity',
                                             selection=[('governmental', 'Governmental'),
                                                        ('special', 'Special')])
    entities = fields.Many2one("res.partner", string='Entity')
    last_entities = fields.Many2one("res.partner", string='Last Entity')
    education_levels = fields.Many2one("education.level", string='Education Levels')
    last_education_levels = fields.Many2one("education.level", string='Last Education Levels')
    nearest_literacy_school = fields.Char(string='The Nearest Literacy School', required=False)
    literacy_school_note = fields.Text(string="Literacy School Note", required=False)
    classroom = fields.Many2one('education.classroom', string='Classroom')
    last_classroom = fields.Many2one('education.classroom', string='Last Classroom')
    degree = fields.Many2one('education.result', string='Degree')
    last_degree = fields.Many2one('education.result', string='Last Degree')
    percentage = fields.Float(string="Percentage%")
    last_percentage = fields.Float(string="Last Percentage%")
    last_education_start_date = fields.Date(string='Last Education Start Date')
    last_education_end_date = fields.Date(string='Last Education End Date')
    last_educational_certificate = fields.Many2many('ir.attachment','rel_last_educational_certificate_attachment','benefit_id','attachment_id',string='Last Educational Certificate')
    end_date = fields.Date('End Date')
    specialization_ids = fields.Many2one('specialization.specialization', string='specialization')
    last_specialization_ids = fields.Many2one('specialization.specialization', string='Last Specialization')
    weak_study = fields.Many2many('study.material',relation='grant_benefit_weak_study_rel',string='Weak Study')
    educational_institution_information = fields.Char('Educational institution information')
    graduation_status = fields.Selection(string='Education Status', selection=[('graduated', 'graduated'),
                                                                               ('ungraduated', 'ungraduated'),
                                                                               ('intermittent', 'intermittent')])
    graduation_date = fields.Date('Graduation Date')
    reasons_for_interruption = fields.Char('Reasons for interruption')
    interruption_date = fields.Date('Interruption Date')
    # attach
    study_document_attached = fields.Many2many('ir.attachment','rel_study_document_attachment','benefit_id','attachment_id',string="Study Document Attached")
    acadimec_regsteration_attached = fields.Binary(string="Acadimec Regsteration Attached",attachment=True )
    Transcript_attached = fields.Binary(string="Transcript Attached",attachment=True )
    # Quran memorize
    quran_memorize_name = fields.Char(string='')
    number_parts = fields.Integer(string='')
    # is craft skills
    craft_skill_ids = fields.One2many('craft.skills', 'benefit_id', string='Craft Skill')
    training_inclinations_ids = fields.One2many('training.inclinations', 'benefit_id', string='Training Inclinations')
    ### alhaju , amra and zakat fitr ####
    amra_date = fields.Date(string='')
    ######################
    food_surplus_type = fields.Many2many('food.surplus.type', string='')
    # Income and salary
    salary_ids = fields.One2many('salary.line', 'benefit_id', string='')
    mother_salary_ids = fields.One2many('salary.line', 'mother_benefit_id', string="Mother Income")
    # Commercial Record
    is_active = fields.Boolean(string='')
    commercial_record_code = fields.Char(string='Commercial Record Code')
    commercial_record_attach = fields.Binary(attachment=True)
    commercial_record_amount = fields.Float(string='')
    # other_associations
    associations_ids = fields.One2many('associations.line', 'benefit_id', string='')
    benefit_behavior_ids = fields.One2many('benefit.behaviors', 'benefit_id', string='')
    # Refuse Reason
    first_refusal_reason = fields.Text(string='First Refusal Reason', tracking=True)
    first_refuse_date = fields.Date(tracking=True)
    final_refusal_reason = fields.Text(string='Final Refusal Reason', tracking=True)
    final_refuse_date = fields.Date(tracking=True)
    black_list_reason = fields.Text(string='Black List Reason', tracking=True)
    black_list_message = fields.Text(string='Black List Message')
    # health information#
    # diseases
    hospital_id = fields.Many2one('hospital.hospital', string='')
    hospital_attach = fields.Binary(attach=True)
    diseases_type = fields.Selection(string='Diseases Type', selection=[('chronic', 'chronic'),
                                                                        ('psycho', 'psycho'),
                                                                        ('organic', 'organic')])
    treatment_used = fields.Char(string='')
    treatment_amount = fields.Float(string='')
    is_treatment_amount_country = fields.Boolean(string='')
    treatment_amount_country_Monthly = fields.Float(string='')
    treatment_amount_country_description = fields.Text(string="")
    treatment_amount_country_attach = fields.Binary(attachment=True)
    # Hospital information
    hospital_card = fields.Binary(attachment=True)
    # disability
    disability_type = fields.Char(string='')
    disability_accessories = fields.Char(string='')
    disability_attach = fields.Binary(attachment=True)
    disability_amount = fields.Float()
    # Medical Insurance
    insurance_type = fields.Many2one('insurance.type')
    insurance_company = fields.Many2one('insurance.company')
    insurance_amount = fields.Float()
    insurance_attach = fields.Binary(attachment=True)
    insured_party = fields.Many2one('res.company')
    # Weight rate
    weight = fields.Float('Weight')
    height = fields.Float('Height')
    p_weight = fields.Float('Overweight', store=True, compute="_compute_obesity_rate", )
    sport_ids = fields.One2many('sport.line', 'benefit_id')
    wife_number = fields.Integer(string="Wife")
    child_number = fields.Integer(string="Children")
    old_stage = fields.Char(string='old Stage', tracking=True)
    dead_certificate = fields.Binary(string="Certificate",attachment=True)
    dead_certificate_date = fields.Date(string="Certificate Date")
    approve_date = fields.Date(string="Approve Date")
    benefit_needs_value = fields.Float()
    benefit_needs_percent = fields.Float()
    followers_total = fields.Integer(string="followers Total")
    followers_out_total = fields.Integer(string="followers Total", )
    expenses_total = fields.Integer(string="Expenses", compute="get_total_expenses",store=True)
    #################################################################
    # Boolean Fields to use in filters#TODO
    #################################################################
    is_responsible = fields.Boolean(string='')  # Differentiate between a primary beneficiary and a dependent
    father_is_life = fields.Boolean(string="Life")
    mother_is_life = fields.Boolean(string="Life")
    is_widows = fields.Boolean(string='is widows', required=False)
    is_divorcee = fields.Boolean(string='is Divorcee', required=False)
    is_want_education = fields.Boolean(string='is Want Education', required=False)
    is_quran_memorize = fields.Boolean('memorize the quran ?')
    is_craft = fields.Boolean(string='')
    is_zakat_fitr = fields.Boolean(string='Zakat Al-Fitr')
    has_car= fields.Boolean('Has Car?',compute='_onchange_car_count',store=True)
    is_producer = fields.Boolean(string='Producer')
    is_food_surplus = fields.Boolean(string='food surplus')
    is_loans = fields.Boolean('loans')
    is_al_al_bayt = fields.Boolean(string='Al al-Bayt')
    is_commercial_record = fields.Boolean(string='Commercial Record')
    is_other_associations = fields.Boolean(string='other associations?')
    is_smoke = fields.Boolean('Smoke')
    # health_status
    is_diseases = fields.Boolean()
    is_disability = fields.Boolean(string='')
    is_insurance = fields.Boolean()
    is_sport = fields.Boolean()
    support_separation = fields.Boolean(string="Support Separation", tracking=True)
    is_life = fields.Boolean(string="Life", default=True)
    total_expenses = fields.Float('Total Expenses', compute="get_total_expenses",store=True,tracking=True)
    total_income = fields.Float('Total Income', compute="get_total_income", store=True,tracking=True)
    benefit_member_count = fields.Integer(string="Members count", compute="get_members_count",store=True)
    non_member_count = fields.Integer(string="Non Benefit Members count", compute="get_members_count")
    member_income = fields.Float(string="Member Income Average", compute="get_member_income",store=True,tracking=True)
    request_activity_id = fields.Many2one('mail.activity')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('new', 'Researcher Assignment'),
        ('complete_info', 'Waiting for Researcher'),
        ('waiting_approve', 'Waiting for Operation Manager'),
        ('first_approve', 'Waiting for Branch Manager'),
        ('family_services_manager', 'Waiting Family Services Manager'),
        ('first_refusal', 'First Refusal'),
        ('second_approve', 'Second Approved'),
        ('refused', 'Refused'),
        ('temporary_suspended', 'Temporary Suspended'),
        ('suspended_second_approve', 'Suspended Second Approved'),
        ('exception_second_approve', 'Waiting for General Manager'),
        ('black_list', 'Black List'),
    ], string='state', default="draft", tracking=True, group_expand='_expand_states')
    branch_custom_id = fields.Many2one('branch.settings', string="Branch",tracking=True)
    branch_family_id = fields.Many2one('branch.settings', string="Family Branch",tracking=True)
    branch_has_employees = fields.Boolean('Has Employees In branch',related="branch_custom_id.has_employees")
    district_id = fields.Many2one('res.districts', string="District", domain="[('branch_custom_id','=',branch_custom_id)]",tracking=True)
    meal_card = fields.Boolean(string="Meal Card",related="district_id.meal_card", store=True,related_sudo=True)
    attachment_ids = fields.One2many('ir.attachment', 'benefit_id')
    family_debits_ids = fields.One2many('family.debits', 'benefit_id')
    mother_debits_ids = fields.One2many('family.debits','mother_benefit_id',string="Mother Debts")
    researcher_id = fields.Many2one("committees.line", string="Researcher",tracking=True)
    assigned_researcher_id = fields.Many2one('committees.line',string='Assigned Researcher',tracking=True)
    auto_accept_for_member = fields.Boolean(string="Auto Accept For members", default=True)
    last_visit_date = fields.Datetime(string='Last Visit Date')
    # Benefit Housing Information
    # housing_name = fields.Char(compute='_compute_get_name')
    zip = fields.Char('Zip', change_default=True, readonly=False, store=True)
    short_number = fields.Char(
        readonly=False,
        required=False,
        states={
            'second_approve': [('readonly', True)],
            'complete_info': [('required', True)]
        }
    )
    extra_code = fields.Char(
        readonly=False,
        required=False,
        states={
            'second_approve': [('readonly', True)],
        }
    )
    zip = fields.Char('Zip', change_default=True, readonly=False, store=True)
    # res_city_id = fields.Many2one('res.city', domain="[('country_city_id', '=', city_id)]")
    # housing_city = fields.Char()
    url = fields.Char()
    url_html = fields.Html(
        sanitize=False,
        compute="get_html")
    image = fields.Binary(string="", )
    image_1 = fields.Binary(string="", )
    image_2 = fields.Binary(string="", )
    image_3 = fields.Binary(string="", )
    image_4 = fields.Binary(string="", )
    nearby_mosque = fields.Char(string='Nearby mosque')
    housing_note = fields.Char(string='housing note')
    note_neighborhood = fields.Char()
    contract_num = fields.Char(string="Contract Number",compute='_compute_rent_from_contract',store=True)
    rent_start_date = fields.Date(string='Rent Start Date',compute='_compute_rent_from_contract',store=True)
    rent_end_date = fields.Date(string='Rent End Date',compute='_compute_rent_from_contract',store=True)
    rent_attachment = fields.Many2many('ir.attachment','rel_rent_attachment_attachment','benefit_id','attachment_id',string='Rent Attachment',compute='_compute_rent_from_contract',store=True,)
    national_address_attachment = fields.Many2many('ir.attachment','rel_national_address_attachment','benefit_id','attachment_id',string='National Address Attachment')
    payment_type = fields.Selection(
        [
            ('1', 'Yearly'),
            ('2', 'Half-yearly'),
            ('4', 'Quarterly'),
            ('12', 'Monthly')
        ],
        string='Payment Type',
        compute='_compute_rent_from_contract',store=True,
    )
    housing_cat = fields.Selection([
        ('excellent', 'Excellent'),
        ('good', 'Good'),
        ('bad', 'Bad'),
        ('collapsible', 'Collapsible'),
        ('collapsed', 'Collapsed')])
    property_type = fields.Selection([
        ('ownership', 'ownership'),
        ('rent', 'rent'),
        ('charitable', 'charitable'),
        ('ownership_shared', 'Ownership Shared'),
        ('rent_shared', 'Rent Shared')])
    property_type_id = fields.Many2one('property.type.settings',string="Property Type",tracking=True)
    property_type_code = fields.Selection([
        ('ownership', 'Ownership'),
        ('rent', 'Rent')
    ], string="Property Type Code",related='property_type_id.type', store=True)
    room_ids = fields.One2many('benefit.housing.rooms', inverse_name='housing_id')
    request_producer_id = fields.Many2one('res.partner',string='Request Producer', compute='_compute_request_producer_id')
    request_producer = fields.Many2one('res.partner',string='Request Producer',default=lambda self: self.env.user.partner_id)
    request_producer_relation = fields.Many2one('relation.settings',string='Request Producer Relation',domain="[('relation_type','=','other relation')]")
    # Suspend
    is_excluded_suspension = fields.Boolean('Excluded from suspension?')
    suspend_reason = fields.Many2one('suspend.reason', string='Suspend Reason')
    reason = fields.Text(string='Reason')
    suspend_description = fields.Text(string='Suspend Description')
    suspend_attachment = fields.Many2many('ir.attachment','rel_suspend_attachment_attachment','benefit_id','attachment_id',string='Suspend Attachment')
    suspend_type = fields.Selection(
        selection=[('temporarily_suspend', 'Temporarily Suspended'), ('suspend', 'Suspend')], string="Suspend Type")
    suspend_method = fields.Selection(selection=[('manual', 'Manual'), ('auto', 'Auto')], string="Suspend Method")
    #Exception fields
    exception_reason = fields.Many2one('exception.reason', string='Exception Reason')
    exception_description = fields.Text(string='Exception Description')
    exception_type = fields.Selection(
        selection=[('temporarily_exception', 'Temporarily Exception'), ('permanent_exception', 'Permanent Exception')],
        string="Exception Type")
    exception_attachment = fields.Many2many('ir.attachment','rel_exception_attachment','benefit_id','attachment_id',string='Exception Attachment')
    exception_start_date = fields.Datetime(string='Exception Start Date')
    exception_end_date = fields.Datetime(string='Exception End Date')

    # sponsor_id = fields.Many2one('res.partner', string='Sponsor',domain="[('account_type','=','sponsor')]")
    sponsor_id = fields.Many2one('res.partner', string='Sponsor',domain="[('is_sponsor_portal', '=', True)]")

    family_monthly_income = fields.Float(string="Family Monthly Income", compute='_get_family_monthly_values')
    family_monthly_meals = fields.Float(string="Family Monthly Meals", compute='_get_family_monthly_values')
    family_monthly_clotting = fields.Float(string="Family Monthly Clotting", compute='_get_family_monthly_values')
    total_family_expenses = fields.Float(string="Total Family Expenses", compute='_get_family_monthly_values')
    total_move_lines = fields.Float(string="Total Move Lines", compute='_get_total_move_lines')
    visit_location_count = fields.Integer(string="Visit Location Count", compute='_compute_visit_location_count')
    total_service_requests = fields.Integer(compute='_get_total_service_requests')
    total_seasonal_service_requests = fields.Integer(compute='_get_total_seasonal_service_requests')
    invoices_count = fields.Integer(string="Invoices Count", compute='_get_invoices_count')
    required_attach = fields.Selection(selection=[('true', 'True'), ('false', 'False')],compute='get_required_attach',store=True)
    income_required_attach  = fields.Selection(selection=[('true', 'True'), ('false', 'False')],compute='get_income_required_attach',store=True)
    sa_iban = fields.Char('SA',default='SA',readonly=True)
    iban_document = fields.Many2many('ir.attachment', 'rel_iban_document', 'benefit_id', 'attachment_id')
    #Replacement Mother
    add_replacement_mother = fields.Boolean('Add Replacement Mother?')
    replacement_mother_name = fields.Char(string="Replacement Mother Name", tracking=True)
    replacement_mother_second_name = fields.Char(string="Replacement Mother Second Name", tracking=True)
    replacement_mother_third_name = fields.Char(string="Replacement Mother Third Name", tracking=True)
    replacement_mother_family_name = fields.Char(string="Replacement Mother Family Name", tracking=True)
    replacement_mother_country_id = fields.Many2one('res.country', 'Replacement Mother Nationality', tracking=True)
    replacement_mother_id_number = fields.Char(string="Replacement Mother Id Number", tracking=True)
    replacement_mother_id_number_type = fields.Selection([('citizen', _('Citizen')),('resident', _('Resident')),('visitor', _('Visitor'))],string='Replacement Mother ID number type')
    replacement_mother_marital_conf = fields.Many2one('marital.status', string='Replacement Mother Marital')
    replacement_mother_is_dead = fields.Boolean(string='Replacement Mother Is Dead?',related='replacement_mother_marital_conf.is_dead')
    replacement_mother_dead_country_id = fields.Many2one('res.country', string='Replacement Mother Dead Country', tracking=True)
    replacement_dead_country_id_code = fields.Char(related='replacement_mother_dead_country_id.code')
    replacement_mother_dead_city_id = fields.Many2one('res.country.city', string='Replacement Mother Dead City',domain="[('country_id', '=', replacement_mother_dead_country_id)]")
    replacement_dead_reason_id = fields.Many2one('death.reason.settings', string='Replacement Mother Dead Reason', required=False)
    replacement_dead_reason_id_not_defined = fields.Boolean(related='replacement_dead_reason_id.not_defined')
    replacement_dead_reason = fields.Char(string='Replacement Mother Dead Reason', required=False)
    replacement_dead_res_city_id = fields.Many2one('res.country.city', string='Replacement Mother Dead City',domain="[('country_id', '=', replacement_dead_country_id)]")
    replacement_dead_city = fields.Char(string='Replacement Mother Dead City')
    replacement_mother_location = fields.Selection(
        [('with_husband_and_children', _('With Husband And Children')), ('with_children', _('With Children')),
         ('not_live_with_children', _('Not live with children'))], string='Replacement Mother Location')
    replacement_mother_location_conf = fields.Many2one('location.settings',string='Replacement Mother Location',domain="[('location_type','=','mother_location')]")
    replacement_is_mother_work = fields.Boolean('Is Replacement Mother Work?')
    replacement_mother_has_disabilities = fields.Boolean('Has Disabilities?')
    replacement_mother_income = fields.Float("Replacement Mother Income")
    replacement_mother_birth_date = fields.Date(string="Replacement Mother Birth Date")
    replacement_mother_age = fields.Integer(string="Replacement Mother Age", compute='_compute_get_replacement_mother_age')
    replacement_mother_city_id = fields.Many2one('res.country.city', string='City')
    replacement_mother_dead_reason = fields.Char(string='Dead Reason', required=False)
    replacement_mother_dead_date = fields.Date(string="Replacement Mother Dead Date")
    replacement_mother_dead_certificate = fields.Many2many('ir.attachment', 'rel_replacement_mother_dead_attachment', 'benefit_id', 'attachment_id', string='Replacement Mother Dead Certificate')
    replacement_mother_status = fields.Selection(string='Replacement Mother Status', related="replacement_mother_family_member_id.member_status")
    replacement_mother_salary_certificate = fields.Many2many('ir.attachment', 'replacement_mother_member_salary_cert_rel',
                                                 'replacement_mother_grant_benefit_id', 'attachment_id',
                                                 string="Salary Certificate")
    # Education_data for replacement mother
    replacement_education_status_ids = fields.One2many('education.status', 'replacement_grant_benefit_id')
    replacement_education_status = fields.Selection(
        string='Education Status',
        selection=[('educated', 'educated'), ('illiterate', 'illiterate')],
        default='illiterate'
    )
    replacement_case_study = fields.Selection(string='Case Study',
                                  selection=[('continuous', 'continuous'), ('intermittent', 'intermittent'),
                                             ('graduate', 'Graduate')])
    replacement_illiterate_reason = fields.Char(string='Illiterate Reason')
    replacement_intermittent_reason = fields.Many2one('education.illiterate.reason', string='Intermittent Reason')
    replacement_education_entity = fields.Selection(string='Education Entity', selection=[('governmental', 'Governmental'),
                                                                              ('special', 'Special')])
    replacement_entities = fields.Many2one("res.partner", string='Entity')
    replacement_specialization_ids = fields.Many2one('specialization.specialization', string='specialization')
    replacement_classroom = fields.Many2one('education.classroom', string='Classroom')
    replacement_degree = fields.Many2one('education.result', string='Degree')
    replacement_percentage = fields.Float(string="Percentage%")
    replacement_education_start_date = fields.Date(string='Education Start Date')
    replacement_education_end_date = fields.Date(string='Education End Date')

    replacement_last_education_entity = fields.Selection(string='Last Education Entity',
                                             selection=[('governmental', 'Governmental'),
                                                        ('special', 'Special')])
    replacement_last_entities = fields.Many2one("res.partner", string='Last Entity')
    replacement_education_levels = fields.Many2one("education.level", string='Education Levels')
    replacement_last_education_levels = fields.Many2one("education.level", string='Last Education Levels')
    replacement_last_specialization_ids = fields.Many2one('specialization.specialization', string='Last Specialization')
    replacement_educational_certificate = fields.Many2many('ir.attachment','rel_replacement_educational_certificate_attachment','benefit_id','attachment_id',string='Educational Certificate')

    replacement_last_classroom = fields.Many2one('education.classroom', string='Last Classroom')
    replacement_last_degree = fields.Many2one('education.result', string='Last Degree')
    replacement_last_percentage = fields.Float(string="Last Percentage%")
    replacement_last_education_start_date = fields.Date(string='Last Education Start Date')
    replacement_last_education_end_date = fields.Date(string='Last Education End Date')
    replacement_last_educational_certificate = fields.Many2many('ir.attachment','rel_replacement_last_educational__certificate_attachment','benefit_id','attachment_id',string='Last Educational Certificate')
    replacement_weak_study = fields.Many2many('study.material',relation='grant_benefit_replacement_weak_study_rel',string='Weak Study')
    replacement_mother_diseases_attachment_ids = fields.One2many('ir.attachment', 'replacement_mother_grant_benefit_id', string='Diseases Attachments',domain=[('diseases_id', '!=', False)])
    replacement_mother_disabilities_attachment_ids = fields.One2many('ir.attachment', 'replacement_mother_grant_benefit_id',string='Disabilities Attachments',domain=[('disabilities_id', '!=', False)])
    sponsorship_id = fields.Many2one('takaful.sponsorship',string='Sponsorship')
    #check if Account Holder is Family memeber of not
    is_family_member = fields.Boolean(string='Is Family member?' , help="check if Account Holder is Family memeber",default=True)
    family_member_id = fields.Many2one('family.member', string='Account Holder Name', domain="[('id','in',member_ids)]")
    owner_identity_attachment_ids = fields.Many2many('ir.attachment', 'rel_identity_attachment','benefit_id','attachment_id',string='Account holder identity')
    family_approval_attachment_ids = fields.Many2many('ir.attachment', 'rel_approval_attachment','benefit_id','attachment_id',string='Family approval of transfer')
    seasonal_service_id = fields.Many2one('seasonal.service', string="Seasonal Service")
    is_from_portal = fields.Boolean(string='is Created from Portal?', default=False, readonly=True)
    applicant_name = fields.Char(readonly=True)
    doc_count = fields.Integer(compute='_compute_attached_docs_count', string="Number of documents attached")
    action_type = fields.Selection(selection=[
        ('new', 'New'),
        ('edit_info', 'Edit Information'),
        ('approved', 'Approved'),
        ('suspended', 'Suspended'),
        ('resume_from_temporary', 'Resume from Temporary Suspension'),
        ('resume_from_final', 'Resume from Final Suspension'),
        ('exception', 'Exception'),
    ], string='Action Type', default='new', tracking=True)
    contact_type = fields.Selection([
        ('email', 'Email'),
        ('sms', 'SMS'),
    ], string='Contact Type',default='sms')
    company_id = fields.Many2one('res.company', default=lambda self: self.env.company)
    currency_id = fields.Many2one(
        comodel_name='res.currency',
        string="Company Currency",
        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)
    total_father_families = fields.Integer(string="Father Families", compute='_compute_total_families')
    total_mother_families = fields.Integer(string="Mother Families", compute='_compute_total_families')
    total_replacement_mother_families = fields.Integer(string="Replacement Mother Families", compute='_compute_total_families')
    final_suspend_date = fields.Date(string="Final Suspend Date")
    resume_reason_id = fields.Many2one('suspend.reason', string='Return Reason')
    resume_date = fields.Date(string="Return Date")
    resume_notes = fields.Text(string="Return Notes")
    rent_contract_ids = fields.One2many('rent.contract', 'family_id',string='Rent Contracts')
    rent_contract_count = fields.Integer(
        string="Number of Rent Contracts",
        compute='_compute_rent_contract_count',
        store=True
    )
    current_rent_contract_id = fields.Many2one('rent.contract',string='Current Active Rent Contract',compute='_compute_current_rent_contract',store=True,)
    notes = fields.Html(string='Notes', tracking=True)
    color = fields.Integer(string="Color Index",related='benefit_category_id.color')
    decoration_color = fields.Selection([
        ('danger', 'Red'),
        ('success', 'Green'),
        ('warning', 'Orange'),
        ('info', 'Blue'),
        ('primary', 'Primary'),
        ('muted', 'Muted'),
    ],related='benefit_category_id.decoration_color')

    _sql_constraints = [
        ('unique_code', "unique (code) WHERE state NOT IN ('draft', 'new')", 'This code already exists')
    ]

    @api.depends('rent_contract_ids')
    def _compute_rent_contract_count(self):
        for record in self:
            record.rent_contract_count = len(record.rent_contract_ids)

    def action_view_all_rent_contracts(self):
        self.ensure_one()
        ctx = self.env.context.copy()
        ctx.update({
            'default_family_id': self.id,
            'default_landlord_type': 'family'
        })
        return {
            'name': _('Rent Contracts - Full Details'),
            'type': 'ir.actions.act_window',
            'res_model': 'rent.contract',
            'view_mode': 'tree,form',
            'domain': [('family_id', '=', self.id)],
            'context': ctx,
            'target': 'current',
        }

    @api.depends('rent_contract_ids', 'rent_contract_ids.state', 'rent_contract_ids.start_date')
    def _compute_current_rent_contract(self):
        for family in self:
            if not family.rent_contract_ids:
                family.current_rent_contract_id = False
                continue
            active_contracts = family.rent_contract_ids.filtered(
                lambda c: c.state == 'active' and c.landlord_type == 'family'
            ).sorted('start_date', reverse=True)

            family.current_rent_contract_id = active_contracts[:1] or False

    @api.depends('member_ids', 'member_ids.member_status', 'add_replacement_mother',
                 'replacement_mother_family_member_id', 'replacement_mother_status', 'mother_family_member_id',
                 'mother_status','mother_marital_conf','mother_location_conf','mother_income')
    def get_members_count(self):
        for ben in self:
            if ben.id:
                ben.non_member_count = len(ben.member_ids.filtered(lambda x: x.member_status == 'non_benefit'))
                ben.benefit_member_count = len(ben.member_ids.filtered(lambda x: x.member_status == 'benefit'))
                if ben.add_replacement_mother and not ben.replacement_mother_family_member_id and ben.replacement_mother_status == 'benefit':
                    ben.benefit_member_count += 1

                if not ben.mother_family_member_id and ben.mother_status == 'benefit':
                    ben.benefit_member_count += 1
            else:
                ben.benefit_member_count = 0.0
                ben.non_member_count = 0.0


    @api.depends('current_rent_contract_id')
    def _compute_rent_from_contract(self):
        for family in self:
            contract = family.current_rent_contract_id
            if contract:
                family.contract_num = contract.name
                family.rent_start_date = contract.start_date
                family.rent_end_date = contract.end_date
                family.rent_amount = contract.rent_amount
                family.payment_type = contract.payment_type
                family.rent_attachment = [(6, 0, contract.contract_attachment.ids)]
                #family.electricity_attach = [(6, 0, contract.electricity_bill_attachment.ids)]
            else:
                family.contract_num = False
                family.rent_start_date = False
                family.rent_end_date = False
                family.rent_amount = 0.0
                family.payment_type = False
                family.rent_attachment = [(5, 0, 0)]
                #family.electricity_attach = [(5, 0, 0)]

    def _sms_get_number_fields(self):
        return ['sms_phone']

    @api.onchange('family_member_id')
    def _onchange_family_member_id(self):
        for record in self:
            if record.is_family_member and record.family_member_id:
                record.acc_holder_name = record.family_member_id.name
                record.acc_holder_id_number = record.family_member_id.member_id_number
            else:
                record.acc_holder_name = False
                record.acc_holder_id_number = False


    @api.depends('is_mother_work','mother_salary_ids','mother_expenses_ids','mother_debits_ids')
    def _compute_mother_net_income(self):
        for rec in self:
            deductions = (
                    sum(rec.mother_expenses_ids.filtered('deduct_from_family_income').mapped('amount')) +
                    sum(rec.mother_debits_ids.filtered('deduct_from_family_income').mapped('monthly_installment'))
            )

            mother_income = sum(rec.mother_salary_ids.filtered(lambda e: e.approved and e.is_mother_salary).mapped('salary_amount'))

            rec.mother_net_income = max(mother_income - deductions, 0.0)

    def _compute_total_families(self):
        for record in self:
            record.total_father_families = self.search_count([('father_id_number','=',record.father_id_number),('id','!=',record.id)])
            record.total_mother_families = self.search_count([('mother_id_number','=',record.mother_id_number),('id','!=',record.id)])
            record.total_replacement_mother_families = self.search_count([('replacement_mother_id_number','=',record.replacement_mother_id_number),('id','!=',record.id)])

    def action_open_related_father_families(self):
        self.ensure_one()
        return {
            'name': _("Father Families"),
            'type': 'ir.actions.act_window',
            'res_model': 'grant.benefit',
            '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')],
            'domain': [('father_id_number','=',self.father_id_number),('id','!=',self.id)],
            'context': {'create': False},
        }

    def action_open_related_mother_families(self):
        self.ensure_one()
        return {
            'name': _("Mother Families"),
            'type': 'ir.actions.act_window',
            'res_model': 'grant.benefit',
            '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')],
            'domain': [('mother_id_number','=',self.mother_id_number),('id','!=',self.id)],
            'context': {'create': False},
        }

    def action_open_related_replacement_mother_families(self):
        self.ensure_one()
        return {
            'name': _("Replacement Mother Families"),
            'type': 'ir.actions.act_window',
            'res_model': 'grant.benefit',
            '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')],
            'domain': [('replacement_mother_id_number','=',self.replacement_mother_id_number),('id','!=',self.id)],
            'context': {'create': False},
        }

    def _expand_states(self, states, domain, order):
        return [key for key, val in type(self).state.selection]

    @api.constrains('short_number')
    def _check_short_number(self):
        pattern = re.compile(r'^[A-Za-z]{4}[0-9]{4}$')
        for record in self:
            if record.short_number and not pattern.match(record.short_number):
                raise ValidationError(_("Short Number must be 4 letters followed by 4 digits (e.g., ABCD1234)."))


    @api.constrains('father_name', 'father_second_name', 'father_third_name', 'father_family_name',
                    'mother_name', 'mother_second_name', 'mother_third_name', 'mother_family_name',
                    'replacement_mother_name','replacement_mother_second_name','replacement_mother_third_name','replacement_mother_family_name')
    def _check_names_alphabetic(self):
        char_fields = {
            'father_name': _('Father First Name'),
            'father_second_name': _('Father Second Name'),
            'father_third_name': _('Father Third Name'),
            'father_family_name': _('Father Family Name'),
            'mother_name': _('Mother Name'),
            'mother_second_name': _('Mother Second Name'),
            'mother_third_name':_('Mother Third Name'),
            'mother_family_name': _('MotherFamily Name'),
            'replacement_mother_name': _('Replacement Mother Name'),
            'replacement_mother_second_name': _('Replacement Mother Second Name'),
            'replacement_mother_third_name': _('Replacement Mother Third Name'),
            'replacement_mother_family_name': _('Replacement Mother Family Name')
        }

        for record in self:
            for field_name, field_label in char_fields.items():
                field_value = getattr(record, field_name)
                if field_value and not re.match(ALPHABETIC_PATTERN, field_value.strip()):
                    raise ValidationError(
                        _("%s must contain only alphabetic characters and spaces. "
                          "Numbers and special characters are not allowed.") % field_label
                    )

    @api.constrains('active', 'state')
    def _prevent_archive_unless_allowed(self):
        for rec in self:
            if not rec.active and rec.state not in ['refused', 'suspended_second_approve', 'black_list']:
                raise ValidationError(_(
                    "You can only archive the family if its status is: Refused, Final Suspension, or Blacklisted."
                ))

    @api.depends('rent_amount','property_type_id','benefit_member_count', 'branch_custom_id.branch_type')
    def _compute_estimated_rent_amount(self):
        for rec in self:
            estimated_rent_amount = 0.0
            rent_line = False
            if rec.property_type_id and rec.property_type_code == 'rent':
                if rec.branch_custom_id.branch_type == 'branches':
                     rent_line = self.env['rent.lines'].search(
                        [('benefit_count', '=', rec.benefit_member_count)], order="estimated_rent_branches desc",limit=1)
                     if rent_line:
                        estimated_rent_amount = rent_line.estimated_rent_branches
                else:
                    rent_line = self.env['rent.lines'].search(
                        [('benefit_count', '=', rec.benefit_member_count)], order="estimated_rent_governorate desc",limit=1)
                    if rent_line:
                        estimated_rent_amount = rent_line.estimated_rent_governorate

                if rec.property_type_id.is_shared and rent_line and rent_line.discount_rate_shared_housing:
                    discount = rent_line.discount_rate_shared_housing / 100.0
                    estimated_rent_amount *= discount
            rec.estimated_rent_amount = estimated_rent_amount / 12.0

    def assign_sequence_to_all(self):
        sequence = self.env['ir.sequence'].search([('code', '=', 'benefit.sequence')], limit=1)
        if not sequence:
            raise UserError(_("Sequence with code 'benefit.sequence' not found"))
        sequence.sudo().write({'number_next': 1})

        records = self.search([], order='create_date')

        for rec in records:
            code = self.env['ir.sequence'].sudo().next_by_code('benefit.sequence')
            rec.with_context(force_website=True).write({'code':code})


    def action_set_waiting_if_needed(self):
        records = self.env['grant.benefit'].browse(self._context.get('active_ids', []))
        print("hh")

        for rec in records:
            if rec.salary_ids:
                for recored in rec.salary_ids:
                    if recored.state not in ['accepted', 'refused']:
                        recored.state = 'waiting'
            if rec.expenses_ids:
                for recorede in rec.expenses_ids:
                    if recorede.state not in ['accepted', 'refused']:
                        recorede.state = 'waiting'

    @api.depends('request_producer')
    def _compute_request_producer_id(self):
        for rec in self:
            rec.request_producer_id = rec.user_id.partner_id if rec.request_producer.id == rec.env.ref('base.public_partner').id else rec.request_producer

    def validate_attachments(self):
        for rec in self:
            if not rec.owner_identity_attachment_ids and rec.is_family_member == False and rec.state == 'first_approve':
                raise ValidationError(_("Account Holder Identity Attachment is required."))
            if not rec.family_approval_attachment_ids and rec.is_family_member == False and rec.state == 'first_approve':
                raise ValidationError(_("Family approval of transfer Attachment is required."))

    def _validate_required_attachments(self):
        """Validate required Many2many attachments"""
        for rec in self:
            if not rec.father_dead_certificate:
                raise ValidationError(_("Father Dead Certificate is required."))

            if rec.state not in ['draft', 'new', 'complete_info'] and not rec._context.get('bypass_attachments_requirement', False) and not rec.national_address_attachment:
                raise ValidationError(_("National Address Attachment is required."))

    @api.constrains('father_birth_date', 'father_dead_date', 'mother_birth_date', 'replacement_mother_birth_date')
    def _check_dates(self):
        today = date.today()

        for rec in self:
            # Check that dates are not in the future
            if rec.father_birth_date and rec.father_birth_date > today:
                raise ValidationError("Father's Birth Date cannot be in the future.")

            if rec.father_dead_date and rec.father_dead_date > today:
                raise ValidationError("Father's Death Date cannot be in the future.")

            if rec.mother_birth_date and rec.mother_birth_date > today:
                raise ValidationError("Mother's Birth Date cannot be in the future.")

            if rec.replacement_mother_birth_date and rec.replacement_mother_birth_date > today:
                raise ValidationError("Replacement Mother's Birth Date cannot be in the future.")

            # Check that father_dead_date is after father_birth_date
            if (
                rec.father_birth_date
                and rec.father_dead_date
                and rec.father_dead_date < rec.father_birth_date
            ):
                raise ValidationError("Father's Death Date must be after the Birth Date.")

    # @api.depends('attachment_ids')
    # def get_required_attach(self):
    #     for rec in self.attachment_ids:
    #         if rec.is_required and not rec.datas:
    #             self.required_attach = None
    #             break
    #         elif rec.is_required and rec.datas:
    #             self.required_attach = 'true'
    #         elif rec.is_default and not rec.is_required and (rec.datas or not rec.datas):
    #             self.required_attach = 'true'
    #         else:
    #             self.required_attach = 'true'
    @api.depends('attachment_ids.datas', 'attachment_ids.is_required', 'attachment_ids.is_default')
    def get_required_attach(self):
        bypass_verify_backend_require_attachs = self._context.get('bypass_verify_backend_require_attachs', False)
        for record in self:
            required_missing = False
            for att in record.attachment_ids:
                if (not bypass_verify_backend_require_attachs or att.show_in_portal) and att.is_required and not att.datas:
                    required_missing = True
                    break
            if required_missing:
                record.required_attach = 'false'
            else:
                record.required_attach = 'true'

    def get_attached_domain(self):
        self.ensure_one()
        visit_location = self.env['visit.location'].search([('benefit_id', '=', self.id)]).ids
        service_requests = self.env['service.request'].search([('family_id', '=', self.id)]).ids
        family_complaints = self.env['family.complaints'].search([('family_id', '=', self.id)]).ids
        hobby_ids = self.member_ids.mapped('hobbies_ids').ids
        member_education_status_ids = self.member_ids.mapped('member_education_status_ids').ids
        diseases_ids = self.member_ids.mapped('diseases_ids').ids
        disabilities_ids = self.member_ids.mapped('disabilities_ids').ids
        return ['|', '|', '|','|','|','|','|','|','|','|','|','|','|',
                '&', ('res_model', '=', 'grant.benefit'),
                ('res_id', 'in', self.ids),
                ('benefit_id', 'in', self.ids),
                '&', ('res_model', '=', 'visit.location'),
                ('res_id', 'in', visit_location),
                '&', ('res_model', '=', 'service.request'),
                ('res_id', 'in', service_requests),
                '&', ('res_model', '=', 'family.complaints'),
                ('res_id', 'in', family_complaints),
                '&', ('res_model', '=', 'education.status'),
                ('res_id', 'in', self.mother_education_status_ids.ids),
                '&', ('res_model', '=', 'family.debits'),
                ('res_id', 'in', (self.family_debits_ids + self.mother_debits_ids).ids),
                '&', ('res_model', '=', 'salary.line'),
                ('res_id', 'in', self.salary_ids.ids),
                '&', ('res_model', '=', 'family.member'),
                ('res_id', 'in', self.member_ids.ids),
                ('member_id', 'in', self.member_ids.ids),
                '&', ('res_model', '=', 'member.hobbies'),
                ('res_id', 'in', hobby_ids),
                '&', ('res_model', '=', 'education.status'),
                ('res_id', 'in', member_education_status_ids),
                '&', ('res_model', '=', 'member.diseases'),
                ('res_id', 'in', diseases_ids),
                '&', ('res_model', '=', 'member.disabilities'),
                ('res_id', 'in', disabilities_ids),
                ]
    def _compute_attached_docs_count(self):
        Attachment = self.env['ir.attachment']
        for benefit in self:
            benefit.doc_count = Attachment.search_count(benefit.get_attached_domain())

    def view_attachments(self):
        action = self.env['ir.actions.act_window']._for_xml_id('base.action_attachment')
        action['domain'] = str(self.get_attached_domain())
        action['context'] = {'create': False}
        return action

    @api.depends('salary_ids')
    def get_income_required_attach(self):
        for rec in self.salary_ids:
            if rec.is_required and not rec.salary_attach:
                self.income_required_attach = None
                break
            elif rec.is_required and rec.salary_attach:
                self.income_required_attach = 'true'
            elif rec.is_default and not rec.is_required and (rec.salary_attach or not rec.salary_attach):
                self.income_required_attach = 'true'
            else:
                self.income_required_attach = 'true'

    def _get_invoices_count(self):
        for rec in self:
            rec.invoices_count = self.env['account.move'].search_count([
                ('benefit_family_ids', 'in', [rec.id]),('move_type','=','in_invoice')
            ])


    def _get_total_move_lines(self):
        for rec in self:
            move_lines = self.env['account.move.line'].search([('benefit_family_id', '=', rec.id),('family_confirm_id','!=', False)])
            rec.total_move_lines = sum(move_lines.mapped('debit')) - sum(move_lines.mapped('credit'))

    def _compute_visit_location_count(self):
        for rec in self:
            rec.with_context(bypass_attachments_requirement=True).write({
                'visit_location_count': self.env['visit.location'].search_count([('benefit_id', '=', rec.id)]),
            })

    def action_view_benefit_members(self):
        self.ensure_one()
        return {
            'type': 'ir.actions.act_window',
            'name': _('Benefit Members'),
            'res_model': 'family.member',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', self.member_ids.filtered(lambda m: m.member_status == 'benefit').ids)],
            'target': 'current',
        }

    def action_view_non_benefit_members(self):
        self.ensure_one()
        action =  {
            'type': 'ir.actions.act_window',
            'name': _('Non Benefit Members'),
            'res_model': 'family.member',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', self.member_ids.filtered(lambda m: m.member_status == 'non_benefit').ids)],
            'target': 'current',
        }
        return action

    def action_open_related_move_line_records(self):
        """ Opens a tree view with related records filtered by a dynamic domain """
        move_lines = self.env['account.move.line'].search([
            ('benefit_family_id', '=', self.id),('family_confirm_id','!=', False)
        ]).ids

        action = {
            'type': 'ir.actions.act_window',
            'name': 'Move Lines',
            'res_model': 'account.move.line',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', move_lines)],
            'target': 'current',
        }
        return action

    def action_open_visit_location(self):
        """ Opens a tree view with related records filtered by a dynamic domain """
        visit_location = self.env['visit.location'].search([('benefit_id', '=', self.id)]).ids
        action = {
            'type': 'ir.actions.act_window',
            'name': _('Visit Location'),
            'res_model': 'visit.location',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', visit_location)],
            'target': 'current',
        }
        return action

    def _get_total_service_requests(self):
        for rec in self:
            rec.total_service_requests = self.env['service.request'].search_count([('family_id', '=', rec.id),('is_seasonal','=',False)])

    def action_open_related_service_requests(self):
        """ Opens a tree view with related records filtered by a dynamic domain """
        service_requests = self.env['service.request'].search([('family_id', '=', self.id),('is_seasonal','=',False)]).ids

        action = {
            'type': 'ir.actions.act_window',
            'name': _('Service Requests'),
            'res_model': 'service.request',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', service_requests)],
            'target': 'current',
        }
        return action

    def _get_total_seasonal_service_requests(self):
        for rec in self:
            rec.total_seasonal_service_requests = len(self.env['service.request'].search([('family_id', '=', self.id), ('is_seasonal', '=', True)]))

    def action_open_related_seasonal_service_requests(self):
        """ Opens a tree view with related records filtered by a dynamic domain """
        seasonal_service_requests = self.env['service.request'].search([('family_id', '=', self.id), ('is_seasonal', '=', True)]).ids

        action = {
            'type': 'ir.actions.act_window',
            'name': _('Seasonal Service Requests'),
            'res_model': 'service.request',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', seasonal_service_requests)],
            'target': 'current',
        }
        return action

    def action_open_related_invoice_records(self):
        """ Opens a tree view with related records filtered by a dynamic domain """
        invoices = self.env['account.move'].search([
            ('benefit_family_ids', 'in', [self.id]),('move_type','=','in_invoice')
        ]).ids
        action = {
            'type': 'ir.actions.act_window',
            'name': 'Invoices',
            'res_model': 'account.move',
            'view_mode': 'tree,form',
            'domain': [('id', 'in', invoices)],
            'target': 'current',
        }
        return action

    def _get_family_monthly_values(self):
        validation_setting = self.env["family.validation.setting"].search([], limit=1)
        for rec in self:
            if rec.benefit_category_id.id in validation_setting.benefit_category_ids.ids:
                total_family_members = rec.benefit_member_count
                rec.family_monthly_income = total_family_members * validation_setting.cash_expense
                rec.family_monthly_meals = total_family_members * validation_setting.meal_expense
                rec.family_monthly_clotting = total_family_members * validation_setting.clothing_expense
                rec.total_family_expenses = rec.family_monthly_income + rec.family_monthly_meals + rec.family_monthly_clotting
            else:
                rec.family_monthly_income = 0
                rec.family_monthly_meals = 0
                rec.family_monthly_clotting = 0
                rec.total_family_expenses = 0

    def get_html(self):
        for rec in self:
            print(f'<iframe id="custom_src" height="500" width="500" src="{rec.url}"></iframe>')
            rec.url_html = f'<iframe id="custom_src" height="500" width="500" src="{rec.url}"/>'

    # @api.multi
    def open_map(self):
        for Location in self:
            url = "http://maps.google.com/maps?oi=map&q="
            if Location.street:
                url += Location.street.replace(' ', ',')
            if Location.city_id:
                url += '+' + Location.district_id.name.replace(' ', ',')
                # url += '+' + Location.city_id.name.replace(' ', ',')
                url += '+' + Location.city_id.state_id.name.replace(' ', '')
                url += '+' + Location.zip.replace(' ', ',')
                url += '+' + Location.city_id.country_id.name.replace(' ', ',')
            if Location.nearby_mosque:
                url += Location.nearby_mosque.replace(' ', ',')
            return {
                'type': 'ir.actions.act_url',
                'target': 'new',
                'url': url
            }

    @api.onchange('url')
    def onchange_image_url(self):
        if self.image_url:
            self.img_attach = '<img id="img" src="%s"/>' % self.url

    def get_researchers_email(self):
        email_ids = ''
        for rec in self.researcher_id.employee_id:
            if email_ids:
                email_ids = email_ids + ',' + str(rec.work_email)
            else:
                email_ids = str(rec.work_email)
        return email_ids

    @api.depends('room_ids')
    def get_rooms_total(self):
        for rec in self:
            if rec.id:
                rooms = rec.env['benefit.housing.rooms'].sudo().search([('housing_id', '=', rec.id)])
                rec.rooms_number = len(rooms)

    @api.onchange('room_ids')
    def onchange_room_ids(self):
        res = {}
        items_ids = []
        for record in self:
            items_ids.append(record.id)
        res['domain'] = {'items': [('room_id', 'in', items_ids)]}
        return res

    @api.onchange('branch_family_id')
    def _onchange_branch_family_id(self):
        if self.branch_family_id:
            branch = self.branch_family_id
            if branch.has_employees:
                chosen_branch = branch
            else:
                chosen_branch = branch.replacement_branch_id

            self.branch_custom_id = chosen_branch
        else:
            self.branch_custom_id = False

    @api.onchange("father_country_id", 'mother_country_id')
    def onchange_father_mother_country_id(self):
        res = {}
        for rec in self:
            if rec.father_country_id and rec.mother_country_id:
                if rec.mother_country_id.code != 'SA' and rec.father_country_id.code != 'SA' and not rec.mother_country_id.is_excluded and not rec.father_country_id.is_excluded :
                    rec.mother_country_id = False
                    res['warning'] = {'title': _('ValidationError'),
                                      'message': _('Non-Saudi mothers and fathers cannot register')}
                    return res

    @api.constrains('acc_holder_id_number')
    def _check_acc_holder_id_number(self):
        for record in self:
            id_number = record.acc_holder_id_number
            if id_number:
                if not re.match(r'^\d{10}$', id_number):
                    raise ValidationError(_("Account Holder ID Number must contain exactly 10 digits."))

    @api.constrains('father_id_number', 'mother_id_number', 'replacement_mother_id_number')
    def _onchange_id_numbers(self):
        id_numbers = {
            'رقم هوية الأب': self.father_id_number,
            'رقم هوية الأم': self.mother_id_number,
            'رقم هوية الأم البديلة': self.replacement_mother_id_number,
        }

        # Check each ID number for 10-digit format and uniqueness within the parent model
        unique_ids = set()
        for label, id_number in id_numbers.items():
            if id_number == 'NULL' and label == 'رقم هوية الأم':
                continue
            if id_number:
                if not re.match(r'^\d{10}$', id_number):
                    raise ValidationError(_("%s must contain exactly 10 digits.")%label)
                if id_number in unique_ids:
                    raise ValidationError(_("%s must be unique within the same record.") % label)
                if id_number.startswith('1') and label == 'رقم هوية الأب':
                    self.father_country_id =  self.env["res.country"].search([('code','=','SA')],limit=1).id
                    self.father_id_number_type = 'citizen'
                if id_number.startswith('1') and label == 'رقم هوية الأم':
                    self.mother_country_id =  self.env["res.country"].search([('code','=','SA')],limit=1).id
                    self.mother_id_number_type = 'citizen'
                if id_number.startswith('1') and label == 'رقم هوية الأم البديلة':
                    self.replacement_mother_country_id =  self.env["res.country"].search([('code','=','SA')],limit=1).id
                    self.replacement_mother_id_number_type = 'citizen'
                unique_ids.add(id_number)

        # Check for uniqueness against `member_id_number` in child records and across database records
        for member in self.member_ids:
            if member.member_id_number == 'NULL':
                continue
            if member.member_id_number and member.member_id_number in unique_ids and member.id not in [self.mother_family_member_id.id,self.replacement_mother_family_member_id.id]:
                raise ValidationError(_("The ID number %s in the Family Members list must be unique across the record.")%member.member_id_number)
        for id_number in unique_ids:
            if id_number == 'NULL':
                continue
            if id_number == self.father_id_number:
                conflict = self.env['grant.benefit'].search([
                    ('id', '!=', self._origin.id),
                    '|',
                    ('mother_id_number', '=', id_number),
                    ('replacement_mother_id_number', '=', id_number),
                ], limit=1)
                if conflict:
                    raise ValidationError(
                        _("Father ID %s is already used in another family (as non-father) with code %s.") %
                        (id_number, conflict.code))
            elif id_number == self.mother_id_number:
                conflict = self.env['grant.benefit'].search([
                    ('id', '!=', self._origin.id),
                    '|',
                    ('father_id_number', '=', id_number),
                    ('replacement_mother_id_number', '=', id_number),
                ], limit=1)
                if conflict:
                    raise ValidationError(
                        _("Mother ID %s is already used in another family with code %s.") %
                        (id_number, conflict.code))
                continue
            elif id_number == self.replacement_mother_id_number:
                conflict = self.env['grant.benefit'].search([
                    ('id', '!=', self.id),
                    '|',
                    ('father_id_number', '=', id_number),
                    ('mother_id_number', '=', id_number),
                ], limit=1)
                if conflict:
                    raise ValidationError(
                        _("Replacement Mother ID %s is already used in another family (as non-replacement) with code %s.") %
                        (id_number, conflict.code)
                    )
            duplicate_record_members = self.env['family.member'].search([('member_id_number', '=', id_number)])
            for member in duplicate_record_members:
                if member.relationn and member.relationn.relation_type in ['mother', 'replacement_mother']:
                    continue
                if member.benefit_id.id != self.id:
                    raise ValidationError(
                        _("The ID number %s already exists in family with code %s. Please enter a unique ID number.") %
                        (id_number, member.benefit_id.code)
                    )

    @api.onchange("family_bank")
    def onchange_family_bank(self):
        for rec in self:
            if rec.family_bank:
                exist = self.search([('family_bank', '=', rec.family_bank.id)])
                if exist:
                    raise ValidationError(
                        _('The Family Bank Already Exist!'))

    @api.model
    def _geo_localize(self, street='', zip='', city='', state='', country=''):
        geo_obj = self.env['base.geocoder']
        search = geo_obj.geo_query_address(
            street=street, zip=zip, city=city, state=state, country=country
        )
        result = geo_obj.geo_find(search, force_country=country)
        if result is None:
            search = geo_obj.geo_query_address(
                city=city, state=state, country=country
            )
            result = geo_obj.geo_find(search, force_country=country)
        return result, search

    def geo_localize(self):
        for location in self.with_context(lang='en_US'):
            result = self._geo_localize(
                street=location.street,
                zip=location.zip,
                city=location.city_id.name,
                state=location.state_id.name,
                country=location.country_id.name,
            )
            if result:
                location.write(
                    {
                        'lat': result[0][0],
                        'lon': result[0][1],
                    }
                )
            return True

    def get_location_on_map(self):
        for location in self.with_context(lang='en_US'):
            url = "http://maps.google.com/maps/search/?api=1&query=%s,%s" % (location.lat, location.lon),
            return {
                'type': 'ir.actions.act_url',
                'target': 'new',
                'url': url
            }

    def check_mother_status(self):
        validation_setting = self.env["family.validation.setting"].search([], limit=1)
        mini_income_for_mother = validation_setting.mini_income_for_mother
        max_income_for_mother = validation_setting.max_income_for_mother
        for rec in self:
            reasons = []
            status = 'benefit'
            if rec.mother_location_conf and rec.mother_marital_conf:
                if not rec.mother_location_conf.is_benefit or not rec.mother_marital_conf.is_benefit or rec.state in ['suspended_second_approve','refused']:
                    reasons.append(_("The mother's marital or location conditions are not eligible."))
                    status = 'non_benefit'
                elif rec.mother_marital_conf.is_benefit :
                    if rec.mother_country_id.code != 'SA' and rec.father_country_id.code != 'SA' and not rec.mother_country_id.is_excluded and not rec.father_country_id.is_excluded:
                        reasons.append(_("Non-Saudi mothers and fathers cannot register."))
                        status = 'non_benefit'
                    else:
                        if mini_income_for_mother < rec.mother_net_income <= max_income_for_mother:
                            reasons.append(_("The mother's income is between minimum and maximum thresholds."))
                            status = 'non_benefit'
                        elif rec.mother_net_income <= mini_income_for_mother:
                            status = 'benefit'
                        elif rec.mother_net_income > max_income_for_mother:
                            status = 'benefit'
            return status, reasons

    def check_replacement_mother_status(self):
        for rec in self:
            reasons = []
            status = 'benefit'
            if not rec.add_replacement_mother:
                continue
            if rec.state in ['suspended_second_approve', 'refused']:
                status = 'non_benefit'
                reasons.append(_("Family is suspended or refused."))
                return status, reasons

            if not rec.replacement_mother_marital_conf or not rec.replacement_mother_location_conf:
                status = 'non_benefit'
                reasons.append(_("Replacement mother marital or location information is missing."))
                return status, reasons

            if not rec.replacement_mother_marital_conf.replacement_mother_is_benefit:
                status = 'non_benefit'
                reasons.append(_("The replacement mother's marital status is not eligible for benefits."))

            if not rec.replacement_mother_location_conf.replacement_mother_is_benefit:
                status = 'non_benefit'
                reasons.append(_("The replacement mother's location is not eligible for benefits."))
            return status, reasons

    def delete_from_db(self):
        find_id = self.env['benefit.housing'].search([])
        for r in find_id:
            r.unlink()

    @api.model
    def default_get(self, fields):
        res = super(GrantBenefitProfile, self).default_get(fields)

        # Get default attachments
        default_attachment = self.env["attachments.settings"].search([('is_default', '=', True)])

        # Prepare the list of default attachments for the one2many field
        default_attachments_data = []
        income_attachments_data = []
        for attach in default_attachment:
            if attach.attach_type == 'family_attach':
                default_attachments_data.append((0, 0, {
                    'name': attach.name,
                    'is_required': attach.is_required,
                    'is_default': attach.is_default,
                    'show_in_portal': attach.show_in_portal
                }))
            if attach.attach_type == 'income_attach':
                income_attachments_data.append((0, 0, {
                    'income_type': attach.id,
                    'is_required': attach.is_required,
                    'is_default': attach.is_default,
                    # 'show_in_portal': attach.show_in_portal
                }))

        # Add the default attachments to the res dictionary for attachment_ids
        if 'attachment_ids' in fields:
            res['attachment_ids'] = default_attachments_data
        if 'salary_ids' in fields:
            res['salary_ids'] = income_attachments_data
        return res

    def write(self, vals):
        res = super(GrantBenefitProfile, self).write(vals)
        if "name" in vals and self.user_id:
            self.user_id.sudo().write({"name": vals.get("name")})
        if any(field in vals for field in ["name", "first_name", "second_name", "middle_name", "family_name",
                                           "father_name", "father_second_name", "father_third_name",
                                           "father_family_name"]):
            for record in self:
                for member in record.member_ids:
                    member.get_partner_name()
                # record.partner_id.get_partner_name()  # Force recomputation of name
                if record.user_id:
                    record.sudo().user_id.write({"name": record.partner_id.name})
        if 'active' in vals:
            for rec in self:
                rec.member_ids.write({'active': vals['active']})
        #if not self.env.context.get('force_website', False) and not self.env.context.get('bypass_attachments_requirement', False):
        #    self._validate_required_attachments()

        # Handle mother update/create
        mother_fields = [
            'mother_name', 'mother_second_name', 'mother_third_name', 'mother_family_name', 'mother_id_number',
            'mother_birth_date', 'mother_marital_conf', 'mother_location_conf', 'is_mother_work',
            'mother_net_income', 'mother_age','education_status','mother_diseases_attachment_ids',
            'mother_education_status_ids','mother_disabilities_attachment_ids'
        ]
        if any(field in vals for field in mother_fields):
            for rec in self:
                #rec.calculate_income(rec.mother_net_income, rec.mother_status, rec.salary_ids)
                rec.add_or_replace_mother_as_member()

        # Handle replacement mother update/create
        replacement_fields = [
            'replacement_mother_name', 'replacement_mother_second_name', 'replacement_mother_third_name',
            'replacement_mother_family_name','replacement_mother_id_number',
            'replacement_mother_birth_date', 'replacement_mother_marital_conf',
            'replacement_mother_location_conf','replacement_mother_relation',
            'replacement_is_mother_work', 'replacement_mother_income', 'replacement_education_status',
            'replacement_mother_age','replacement_mother_disabilities_attachment_ids',
            'replacement_education_status_ids', 'replacement_mother_diseases_attachment_ids'
        ]
        if any(field in vals for field in replacement_fields):
            for rec in self:
                if rec.add_replacement_mother:
                    #rec.calculate_income(rec.replacement_mother_income, rec.replacement_mother_status, rec.salary_ids)
                    rec.add_or_replace_replacement_mother_as_member()
        return res

    @api.model
    def create(self, vals):
        res = super(GrantBenefitProfile, self).create(vals)
        if "applicant_name" not in vals:
            res.applicant_name = self.env.user.display_name
        if "name" in vals and res.user_id:
            res.user_id.sudo().write({"name": vals.get("name")})
        if res.user_id:
            res.sudo().user_id.write({"name": res.name})
        #if not self.env.context.get('force_website', False):
            ##res._validate_required_attachments()
        if not res.code or res.code == _('New'):
            res.code = self.env['ir.sequence'].sudo().next_by_code('benefit.sequence') or _('New')
        # Add mother
        if res.mother_id_number:
            #res.calculate_income(res.mother_net_income, res.mother_status, res.salary_ids)
            res.add_or_replace_mother_as_member()
        # Add replacement mother
        if res.add_replacement_mother and res.replacement_mother_id_number:
            #res.calculate_income(res.replacement_mother_income, res.replacement_mother_status, res.salary_ids)
            res.add_or_replace_replacement_mother_as_member()
        return res

    def unlink(self):
        users_to_delete = self.env['res.users']
        skip_user = self.env.context.get('skip_user_unlink')
        force_unlink = self.env.context.get('force_unlink', False)

        for record in self:
            if not force_unlink and record.state not in ['draft']:
                raise UserError(_('You cannot delete this record'))

            self.env['ir.attachment'].search([('benefit_id', '=', record.id)]).unlink()
            if record.member_ids:
                record.member_ids.unlink()

            if not skip_user and record.user_id:
                other_benefits = self.env['grant.benefit'].search([
                    ('user_id', '=', record.user_id.id),
                    ('id', '!=', record.id)
                ])
                if other_benefits:
                    raise UserError(
                        _("Cannot delete user '%s': still linked to other benefit profiles.")
                        % record.user_id.name
                    )
                users_to_delete |= record.user_id

        res = super().unlink()

        if not skip_user:
            users_to_delete.unlink()

        return res

    def copy(self, default=None):
        """Override the copy method to prevent duplicating the record."""
        raise UserError(_('You cannot Duplicate this record'))

    def complete_data(self):
        message = self.create_message('complete_info')
        self.partner_id.send_sms_notification(message, self.phone)
        ctx = dict(self.env.context or {})
        ctx['create_visit'] = True
        return {
            'name': _('Rerearcher Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'researcher.family.wizard',
            'view_id': self.env.ref('odex_benefit.view_resarcher_family_wizard_form').id,
            'target': 'new',
            'context': ctx,
        }

    def action_assign_specialist_mass(self):
        ctx = dict(self.env.context or {})
        return {
            'name': _('Rerearcher Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'researcher.family.wizard',
            'view_id': self.env.ref('odex_benefit.view_assigned_researcher_family_wizard_form').id,
            'target': 'new',
            'context': ctx,
        }

    def finish_complete_data(self):
        message = self.create_message('waiting_approve')
        self.partner_id.send_sms_notification(message, self.phone)
        for rec in self:
            visits = self.env['visit.location'].search([('benefit_id', '=', rec.id),('state', 'not in', ['close', 'done'])])
            if not rec.benefit_category_id.is_benefit:
                raise ValidationError(_("The procedure cannot be continued; the family is not a beneficiary."))
            if rec.action_type == 'new' and visits:
                raise ValidationError(_("Please complete your pending visits before proceeding."))
            rec.validate_attachments()
            self.state = 'waiting_approve'

    def action_first_accepted(self):
        """Accept  registration"""
        for rec in self:
            rec.state = "first_approve"

    def action_second_accepted(self):
        """Accept  registration"""
        for rec in self:
            messages = []
            if rec.total_family_expenses:
                if not rec.acc_number:
                    messages.append(_("Account Number is required."))
                if not rec.bank_id:
                    messages.append(_("Bank is required."))
                if rec.is_family_member and not rec.family_member_id:
                    messages.append(_("Family Member must be selected."))
                if not rec.is_family_member and not rec.owner_identity_attachment_ids:
                   messages.append(_("Owner Identity Attachment is required."))
                if not rec.is_family_member and not rec.family_approval_attachment_ids:
                    messages.append(_("Family Approval Attachment is required."))
                if not rec.acc_holder_name:
                    messages.append(_("Account Holder Name is required."))
                if not rec.acc_holder_id_number:
                    messages.append(_("Account Holder ID Number is required."))

                if messages:
                    raise UserError("\n".join(messages))

            #if not rec.user_id:
            #    self.sudo().create_user()

            if rec.user_id:
                rec.user_id.sudo().write({
                    'groups_id': [(3, self.env.ref('base.group_user', False).id)],
                })
                # rec.user_id.sudo().write({
                #     'groups_id': [(4, self.env.ref('odex_benefit.group_benefit_user', False).id)],
                # })
                rec.user_id.sudo().write({
                    'groups_id': [(4, self.env.ref('base.group_portal', False).id)],
                })
            if rec.action_type == 'new':
                rec.approve_date = datetime.now()
            self.sudo().send_approval_benefit_email()
            partner_ids = []
            for id in self.message_follower_ids.ids:
                partner_ids.append(self.env['mail.followers'].search([('id', '=', id)]).partner_id)
            self.state = "second_approve"
            self.action_type = "approved"
            #self.sudo()._send_notification(partner_ids, rec.state)
        # for member in self.member_ids:
        #     member.create_member_partner()

    # @api.multi
    def action_first_refusal(self):
        """First refusal to entity registration"""
        domain = []
        context = {}
        context = dict(self.env.context or {})
        context['state'] = "first_refusal"
        self.partner_id.send_sms_notification("First Refusal", self.phone)
        context['active_id'] = self.id
        return {
            'name': _('Refuse Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'entity.refused.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_entity_refused_reason_wizard_form').id,
            'target': 'new',
            'domain': domain,
            'context': context,
        }

    def action_set_to_draft(self):
        context = dict(self.env.context or {})
        context['target_state'] = "draft"
        context['active_id'] = self.id
        return {
            'name': _('Return Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'entity.return.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_entity_return_reason_wizard_form').id,
            'target': 'new',
            'context': context,
        }

    def action_set_to_new(self):
        context = dict(self.env.context or {})
        context['target_state'] = "complete_info"
        context['active_id'] = self.id
        return {
            'name': _('Return Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'entity.return.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_entity_return_reason_wizard_form').id,
            'target': 'new',
            'context': context,
        }

    def action_set_waiting_approve(self):
        context = dict(self.env.context or {})
        context['target_state'] = "waiting_approve"
        context['active_id'] = self.id
        return {
            'name': _('Return Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'entity.return.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_entity_return_reason_wizard_form').id,
            'target': 'new',
            'context': context,
        }


    # @api.multi
    def action_refuse(self):
        """Refuse entity registration"""
        domain = []
        context = dict(self.env.context or {})
        context['state'] = "refused"
        context['active_id'] = self.id
        return {
            'name': _('Refuse Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'entity.refused.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_entity_final_refused_reason_wizard_form').id,
            'target': 'new',
            'domain': domain,
            'context': context,
        }

    # @api.multi
    def action_black_list(self):
        """Move benefit to black list"""
        domain = []
        context = dict(self.env.context or {})
        context['state'] = "black_list"
        context['active_id'] = self.id
        return {
            'name': _('Black List Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'entity.black.list.wizard',
            'view_id': self.env.ref('odex_benefit.view_entity_black_list_wizard_form').id,
            'target': 'new',
            'domain': domain,
            'context': context,
        }

    # @api.multi
    def action_edit_info(self):
        #user = self.user_id
        #if not user:
        #    user = self.env['res.users'].sudo().search(
        #        [('partner_id', '=', self.partner_id.id), ('active', '=', False)])
        #    if user:
        #        user.write({'active': True})
        #    else:
        #        user = self.create_user()
        #group_e = self.env.ref('odex_benefit.group_benefit_edit', False)
        try:
            #group_e.sudo().write({'users': [(4, user.id)]})
            self.old_stage = self.state
            template = self.env.ref('odex_benefit.edit_benefit_email', False)
        except:
            pass
        self.state = 'complete_info'
        self.action_type = 'edit_info'

    def action_suspend(self):
        return {
            'name': _('Suspend Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'suspend.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_suspend_reason_wizard_form').id,
            'target': 'new',
        }

    def action_resume_family(self):
        ctx = dict(self.env.context or {})
        ctx['resume_family'] = True
        return {
            'name': _('Resume Reason Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'suspend.reason.wizard',
            'view_id': self.env.ref('odex_benefit.view_resume_reason_wizard_form').id,
            'target': 'new',
            'context': ctx,
        }

    def action_suspend_first_accept(self):
        for rec in self:
            rec.state = 'first_approve'

    def action_resume_first_accept(self):
        for rec in self:
            rec.state = 'first_approve'

    def action_suspend_second_accept(self):
        for rec in self:
            rec.action_type = 'suspended'
            if rec.suspend_reason.need_service_manager_approval:
                rec.state = 'family_services_manager'
            elif rec.suspend_reason.suspend_type == 'temporarily_suspend':
                rec.state = 'temporary_suspended'
            else:
                rec.state = 'suspended_second_approve'

    def action_resume_second_accept(self):
        for rec in self:
            if rec.suspend_reason.need_service_manager_approval:
                rec.state = 'family_services_manager'
            else:
                rec.state = 'second_approve'
                rec.action_type = 'approved'

    def action_suspend_third_accept(self):
        for rec in self:
            if rec.suspend_reason.suspend_type == 'temporarily_suspend':
                rec.state = 'temporary_suspended'
            else:
                rec.state = 'suspended_second_approve'

    def action_resume_third_accept(self):
        for rec in self:
            rec.state = 'second_approve'
            rec.action_type = 'approved'

    def action_final_suspend(self):
        today = fields.Date.today()
        for rec in self:
            if rec.final_suspend_date and today >= rec.final_suspend_date:
                rec.write({
                    'state': 'suspended_second_approve',
                    'suspend_type': 'suspend',
                })
            else:
                raise UserError(_("Final suspension cannot be executed until after the specified final suspension date."))

    def action_auto_suspend(self):
        # Fetch grants in second approval state that are not excluded from suspension
        #case_one :
        grants = self.env["grant.benefit"].search(
            [('state', '=', 'second_approve'), ('is_excluded_suspension', '=', False)]
        )

        for grant in grants:
            # Check if there are no benefit members
            if grant.benefit_member_count == 0:
                grant.state = 'complete_info'
                grant.suspend_method = 'auto'
                grant.action_type = 'suspended'

        #case two :
        members = self.env["family.member"].search(
            [('state', '=', 'second_approve'), ('is_excluded_suspension', '=', False), ('member_status', '=', 'non_benefit')]
        )
        for member in members:
            member.state_a = 'complete_info'
            member.suspend_method = 'auto'
            member.action_type = 'suspended'
            member.is_member_workflow = True

    def check_actt(self):
        # case_one :
        grants = self.env["grant.benefit"].search(
            [('state', '=', 'second_approve'), ('is_excluded_suspension', '=', False)]
        )
        for grant in grants:
            # Check if any attachment of the grant is expired
            for attachment in grant.attachment_ids:
                if attachment.attach_status == 'expired':
                    # Change state to temporarily suspended if there are benefit members
                    if grant.benefit_member_count != 0:
                        grant.state = 'complete_info'
                        grant.action_type = 'suspended'
                        grant.suspend_method = 'auto'
                    break  # Exit attachment loop after processing

            # Check each member's attachments
            for member in grant.member_ids:
                for member_attachment in member.attachment_ids:
                    if member_attachment.attach_status == 'expired':
                        # Change state to temporarily suspended if there are benefit members
                        if grant.benefit_member_count != 0:
                            grant.state = 'complete_info'
                            grant.action_type = 'suspended'
                            grant.suspend_method = 'auto'
                        break  # Exit member attachment loop after processing

    def action_suspend_refuse(self):
        for rec in self:
            rec.state = 'second_approve'
            rec.action_type = 'approved'
            rec.get_member_income()

    def action_reject_resume(self):
        for rec in self:
            if rec.action_type == 'resume_from_temporary':
                rec.state = 'temporary_suspended'
            elif rec.action_type == 'resume_from_final':
                rec.state = 'suspended_second_approve'
            rec.action_type = 'suspended'

    #Excption Work flow
    def action_exception(self):
        return {
            'name': _('Exception Wizard'),
            'view_mode': 'form',
            'view_type': 'form',
            'type': 'ir.actions.act_window',
            'res_model': 'exception.wizard',
            'view_id': self.env.ref('odex_benefit.view_exception_wizard_form').id,
            'target': 'new',
        }

    def action_exception_first_accept(self):
        for rec in self:
            rec.state = 'first_approve'

    def action_exception_second_accept(self):
        for rec in self:
            rec.state = 'exception_second_approve'
    def action_exception_final_accept(self):
        for rec in self:
            rec.is_excluded_suspension = True
            rec.state = 'second_approve'
            for member in self.member_ids:
                member.is_excluded_suspension = True
            rec.get_member_income()

    def action_auto_exception(self):
        obj = self.env["grant.benefit"].search(
            [('state', '=', 'second_approve'), ('is_excluded_suspension', '=',  True)])
        for rec in obj:
            if rec.exception_end_date and rec.exception_end_date <= fields.Datetime.now():
                rec.is_excluded_suspension = False
                rec.state = 'suspended_second_approve'
                rec.action_type = 'suspended'
                for member in rec.member_ids:
                    member.is_excluded_suspension = False

    def run_auto_final_suspend(self):
        today = date.today()
        records = self.search([
            ('state', '=', 'temporary_suspended'),
            ('final_suspend_date', '<=', today),
        ])

        for rec in records:
            rec.state = 'suspended_second_approve'

    def action_exception_refuse(self):
        for rec in self:
            rec.state = 'suspended_second_approve'
            rec.action_type = 'suspended'

    # @api.multi
    def action_remove_from_black_list(self):
        """Remove entity from black list"""
        partner_ids = []
        for entity in self:
            if self.old_stage == 'draft':
                entity.state = 'draft'
            else:
                entity.state = 'second_approve'
            entity.black_list_message = False
            user = self.env['res.users'].search([('partner_id', '=', entity.partner_id.id)], limit=1)
            user.toggle_active()
            # activate user
            subject = _('Beneficiaries')
            state_label = dict(entity.fields_get(allfields=['state'])['state']['selection'])[entity.state]
            body = ' '.join(
                (_(u'The Beneficial '), entity.name, _(u' State changed to '), state_label, u'.')).encode(
                'utf-8')
            partner_ids += [(6, 0, entity.message_follower_ids.ids)]
            message_vals = {
                'subject': subject,
                'body': body,
                'partner_ids': partner_ids,
            }
            # entity.message_post(body=body, subject=subject, message_type='email')
            # entity.send_remove_from_black_list_email()

    @api.depends('car_ids')
    def _onchange_car_count(self):
        for rec in self:
            rec.car_count = len(rec.car_ids)
            rec.has_car = any(line.member_id for line in rec.car_ids)

    @api.onchange('is_diseases')
    def onchange_is_diseases(self):
        for rec in self:
            rec.is_diseases = 'sick' if rec.is_diseases else 'healthy'

    def _onchange_is_has_needs(self):
          for rec in self:
            benefits_needs = rec.env['benefits.needs'].sudo().search(['|',
                                                                      ('benefit_id', '=', rec.id),
                                                                      ('benefit_ids', 'in', rec.id)])
            needs = []
            for need in benefits_needs:
                if need.state == 'published' and need.remaining_amount > 0.0:
                    needs.append(need.id)
            if len(needs) > 0:
                rec.sudo().has_needs = True
            elif len(needs) == 0:
                rec.sudo().has_needs = False

    def _orphan_list_compute(self):
        for rec in self:
            benefits = rec.env['grant.benefit'].sudo().search([('mother_id', '=', rec.id)])
            rec.orphan_ids = [(6, 0, benefits.ids)]
            rec.orphan_count = len(rec.orphan_ids)

    def _compute_orphan_Type(self):
        for rec in self:
            if rec.benefit_type == "orphan":
                if not rec.father_is_life and not rec.mother_is_life:
                    rec.orphan_status = 'parent'
                elif not rec.father_is_life:
                    rec.orphan_status = 'father'
                elif not rec.mother_is_life:
                    rec.orphan_status = 'mother'
            # TODO FIXME: i commented these lines because this field doen't exist in model grant.benefit
            #     else:
            #         rec.orphan_type = ''
            # else:
            #     rec.orphan_type = ''

    @api.onchange('birth_date')
    def onchange_category(self):
        for rec in self:
            rec.expenses_ids = False
            for expenses in rec.benefit_category_id:
                if expenses.state == 'second_pprove':
                    for i in expenses.expenses_ids:
                        expenses = {}
                        expenses['expenses_type'] = i.expenses_type
                        expenses['amount'] = i.amount
                        rec.expenses_ids = [(0, 0, expenses)]
            expenses = self.env['benefit.expenses'].sudo().search(
                [('benefit_id', '=', self._origin.id), ('state', '=', 'accreditation')])
            for expenses_extra in expenses:
                expenses = {}
                expenses['expenses_type'] = expenses_extra.expenses_type
                expenses['amount'] = expenses_extra.amount
                expenses['note'] = expenses_extra.name
                rec.expenses_ids = [(0, 0, expenses)]
                # Todo

    def create_message(self, case):
        sms_template = self.env['benefit.sms.configuration'].sudo().search([('state', '=', case)])
        if sms_template:
            message = sms_template.case_text
            if '$اسم_المستفيد' in message:
                if self.name:
                    message = message.replace("$اسم_المستفيد", self.name)
                else:
                    raise ValidationError(_("عفواءً القالب المخصص يتوجب وجود اسم المستفيد"))
            if '$رقم_الهوية' in message:
                if self.id_number:
                    message = message.replace("$رقم_الهوية", self.id_number)
                else:
                    raise ValidationError(_("عفواءً القالب المخصص يتوجب وجود رقم الهوية"))
            if '$اسم_العائلة' in message:
                if self.institution_id:
                    message = message.replace("$اسم_العائلة", self.institution_id.name)
                else:
                    raise ValidationError(_("عفواءً القالب المخصص يتوجب وجود اسم العائلة"))
            return message

    def get_error_response(self, result):
        if result == "105":
            raise ValidationError(_("Sorry, there is not enough credit!"))
        if result == "102":
            raise ValidationError(_("Sorry, wrong username!"))
        if result == "103":
            raise ValidationError(_("Sorry, wrong password!"))
        if result == "106":
            raise ValidationError(_("Sorry, sender name is not available!"))
        if result == "1013":
            raise ValidationError(_("Sorry, no message has been posted!"))
        if result == "1011":
            raise ValidationError(_("Sorry, no message has been posted!"))

    @api.depends('name')
    def _compute_qr_code(self):
        for rec in self:
            qr = qrcode.QRCode(
                version=1,
                error_correction=qrcode.constants.ERROR_CORRECT_L,
                box_size=15,
                border=4,
            )
            name = rec.name
            qr.add_data(name)
            qr.make(fit=True)
            img = qr.make_image()
            temp = BytesIO()
            img.save(temp, format="PNG")
            qr_image = base64.b64encode(temp.getvalue())
            rec.qr_code = qr_image

    @api.onchange('bank_id')
    def _compute_prefix_iban(self):
        if self.bank_id:
            self.iban = self.bank_id.iban

    @api.onchange('weight', 'height')
    def _compute_obesity_rate(self):
        for rec in self:
            if rec.weight and rec.height:
                height = (rec.height / 100)
                rec.p_weight = (rec.weight / (height * height))

    @api.depends(
        'expenses_ids',
        'estimated_rent_amount',
        'expenses_ids.deduct_from_family_income',
        'expenses_ids.amount',
        'family_debits_ids',
        'family_debits_ids.deduct_from_family_income',
        'family_debits_ids.monthly_installment',
    )
    def get_total_expenses(self):
        for ben in self:
            followers = ben.env['benefit.followers'].sudo().search([('benefit_id', '=', ben.id)])
            expenses = ben.env['expenses.line'].sudo().search([('benefit_id', '=', ben.id)])
            total_expenses = 0.0
            if ben.expenses_ids and ben.family_debits_ids:
                total_expenses = sum(ben.expenses_ids.filtered(lambda e: e.deduct_from_family_income).mapped('amount')) + sum(ben.family_debits_ids.filtered(lambda e: e.deduct_from_family_income).mapped('monthly_installment'))
            elif ben.expenses_ids and not ben.family_debits_ids:
                total_expenses = sum(ben.expenses_ids.filtered(lambda e: e.deduct_from_family_income).mapped('amount'))
            elif ben.family_debits_ids and not ben.expenses_ids:
                total_expenses = sum(ben.family_debits_ids.filtered(lambda e: e.deduct_from_family_income).mapped('monthly_installment'))
            if followers:
                ben.followers_total = len(followers)
            if expenses:
                ben.expenses_total = len(expenses)
            ben.total_expenses = total_expenses + ben.estimated_rent_amount

    @api.depends('mother_net_income', 'mother_status')
    def calculate_income(self):
        validation_setting = self.env["family.validation.setting"].search([], limit=1)
        max_income_for_mother = validation_setting.max_income_for_mother
        for rec in self:
            add_mother_net_income = (rec.mother_location_conf.is_benefit and rec.mother_marital_conf.is_benefit and rec.mother_net_income > max_income_for_mother)
            if add_mother_net_income:
                rec.mother_income = rec.mother_net_income
            else:
                rec.mother_income = 0.0

    @api.depends(
        'salary_ids',
        'salary_ids.salary_amount',
        'salary_ids.approved',
        'mother_income',
    )
    def get_total_income(self):
        for rec in self:
            total = 0.0
            rec.total_income = 0.0
            if rec.mother_status == 'non_benefit':
                total = sum(rec.salary_ids.filtered(lambda e: e.approved).mapped('salary_amount'))
            elif rec.mother_status == 'benefit':
                total = sum(rec.salary_ids.filtered(lambda e: e.approved).mapped('salary_amount')) + rec.mother_income
            rec.total_income = total

    def get_mother_name(self):
        for rec in self:
            name = ''
            if all([rec.mother_name, rec.mother_second_name, rec.mother_third_name, rec.mother_family_name]):
                name = rec.mother_name + " " + rec.mother_second_name + " " + rec.mother_third_name + " " + rec.mother_family_name
            else:
                name = name
        return name

    def get_replacement_mother_name(self):
        for rec in self:
            name = ''
            if all([rec.replacement_mother_name, rec.replacement_mother_second_name, rec.replacement_mother_third_name,
                    rec.replacement_mother_family_name]):
                name = rec.replacement_mother_name + " " + rec.replacement_mother_second_name + " " + rec.replacement_mother_third_name + " " + rec.replacement_mother_family_name
            else:
                name = name
        return name

    def add_or_replace_mother_as_member(self):
        FamilyMember = self.env['family.member']
        Relation = self.env['relation.settings'].search([('relation_type', '=', 'mother')], limit=1)

        for rec in self:
            mother_name = rec.get_mother_name()
            val = {
                'name': mother_name,
                'mother_first_name': rec.mother_name,
                'mother_second_name': rec.mother_second_name,
                'mother_third_name': rec.mother_third_name,
                'mother_family_name': rec.mother_family_name,
                'member_id_number': rec.mother_id_number,
                'is_mother': True,
                'birth_date': rec.mother_birth_date,
                'gender': 'female',
                'relationn': Relation.id,
                'mother_marital_conf': rec.mother_marital_conf.id,
                'member_location_conf': rec.mother_location_conf.id,
                'age': rec.mother_age,
                'is_work': rec.is_mother_work,
                'member_income': rec.mother_net_income,
                'education_status': rec.education_status,
                #'member_status': rec.mother_status,
                'member_education_status_ids': [(5, 0)] + [(4, edu.id) for edu in rec.mother_education_status_ids],
                'salary_certificate': [(6, 0, rec.mother_salary_certificate.ids)],
            }

            mother_family_member = rec.mother_family_member_id
            if mother_family_member:
                mother_family_member.write(val)
            else:
                val['benefit_id'] = rec.id
                mother_family_member = FamilyMember.create(val)
                rec.write({'mother_family_member_id': mother_family_member.id})
            rec.mother_diseases_attachment_ids.write({'member_id': mother_family_member.id})
            rec.mother_disabilities_attachment_ids.write({'member_id': mother_family_member.id})

    def add_or_replace_replacement_mother_as_member(self):
        FamilyMember = self.env['family.member']

        for rec in self:
            mother_name = rec.get_replacement_mother_name()
            val = {
                'name': mother_name,
                'mother_first_name': rec.replacement_mother_name,
                'mother_second_name': rec.replacement_mother_second_name,
                'mother_third_name': rec.replacement_mother_third_name,
                'mother_family_name': rec.replacement_mother_family_name,
                'member_id_number': rec.replacement_mother_id_number,
                'is_mother': False,
                'birth_date': rec.replacement_mother_birth_date,
                'gender': 'female',
                'relationn': rec.replacement_mother_relation.id,
                'mother_marital_conf': rec.replacement_mother_marital_conf.id,
                'member_location_conf': rec.replacement_mother_location_conf.id,
                'age': rec.replacement_mother_age,
                'is_work': rec.replacement_is_mother_work,
                'member_income': rec.replacement_mother_income,
                'education_status': rec.replacement_education_status,
                #'member_status': rec.replacement_mother_status,
                'member_education_status_ids': [(5, 0)] + [(4, edu.id) for edu in rec.replacement_education_status_ids],
                'salary_certificate': [(6, 0, rec.replacement_mother_salary_certificate.ids)],
            }

            if rec.replacement_mother_family_member_id:
                rec.replacement_mother_family_member_id.write(val)
                replacement_member = rec.replacement_mother_family_member_id
            else:
                val['benefit_id'] = rec.id
                replacement_member = FamilyMember.create(val)
                rec.write({'replacement_mother_family_member_id': replacement_member.id})

            rec.replacement_mother_diseases_attachment_ids.write({'member_id': replacement_member.id})
            rec.replacement_mother_disabilities_attachment_ids.write({'member_id': replacement_member.id})


    @api.depends('benefit_member_count','total_income','total_expenses')
    def get_member_income(self):
        for ben in self:
            income = 0.0
            family_income = ben.total_income - ben.total_expenses
            if ben.benefit_member_count:
                if ben.benefit_member_count > 3:
                    income = family_income / ben.benefit_member_count
                elif ben.benefit_member_count <= 3:
                    income = family_income / 3
            else:
                income = family_income
            ben.member_income = round(income, 0)

    @api.depends("member_income", "benefit_member_count")
    def get_benefit_category(self):
        default_category = self.env['benefit.category'].sudo().search(
            [('is_benefit', '=', False)], limit=1
        )
        for record in self:
            if record.benefit_member_count <= 0:
                record.benefit_category_id = default_category.id if default_category else False
                continue
            category = self.env['benefit.category'].sudo().search(
                [
                    ('mini_income_amount', '<=', record.member_income),
                    ('max_income_amount', '>=', record.member_income)
                ],
                limit=1
            )
            record.benefit_category_id = category.id if category else default_category.id

    def open_followers(self):
        context = {}
        context['default_benefit_id'] = self.id
        return {
            'name': _('Benefit Followers'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'views': [(self.env.ref(
                'odex_benefit.benefit_followers_tree').id, 'tree'),
                      (self.env.ref('odex_benefit.benefit_followers_form').id, 'form')],
            'res_model': 'benefit.followers',
            'type': 'ir.actions.act_window',
            'context': context,
            'domain': "[('benefit_id','=',%s)]" % (self.id),
            'target': 'current',
        }

    def open_expenses(self):
        context = {}
        context['default_benefit_id'] = self.id
        return {
            'name': _('Benefit Expenses'),
            'view_type': 'form',
            'view_mode': 'tree,form',
            'views': [(self.env.ref(
                'odex_benefit.benefit_expenses_tree').id, 'tree'),
                      (self.env.ref('odex_benefit.expenses_line_form').id, 'form')],
            'res_model': 'benefit.expenses',
            'type': 'ir.actions.act_window',
            'context': context,
            'domain': "[('benefit_id','=',%s)]" % (self.id),
            'target': 'current',
        }

    @api.depends('father_birth_date')
    def _compute_get_father_age(self):
        for rec in self:
            if rec.father_birth_date:
                today = date.today()
                day = datetime.strptime(str(rec.father_birth_date), DEFAULT_SERVER_DATE_FORMAT)
                age = rd(today, day)
                rec.father_age = age.years
            else:
                rec.father_age = 0

    @api.depends('mother_birth_date')
    def _compute_get_mother_age(self):
        for rec in self:
            if rec.mother_birth_date:
                today = date.today()
                day = datetime.strptime(str(rec.mother_birth_date), DEFAULT_SERVER_DATE_FORMAT)
                age = rd(today, day)
                rec.mother_age = age.years
            else:
                rec.mother_age = 0

    @api.depends('replacement_mother_birth_date')
    def _compute_get_replacement_mother_age(self):
        for rec in self:
            if rec.replacement_mother_birth_date:
                today = date.today()
                day = datetime.strptime(str(rec.replacement_mother_birth_date), DEFAULT_SERVER_DATE_FORMAT)
                age = rd(today, day)
                rec.replacement_mother_age = age.years
            else:
                rec.replacement_mother_age = 0

    def action_finish_edit(self):
        for rec in self:
            #group_e = self.env.ref('odex_benefit.group_benefit_edit', False)
            #group_e.write({'users': [(3, self.user_id.id)]})
            rec.state = rec.old_stage

    # @api.multi
    def edit_password(self):
        if self.user_id:
            self.user_id.sudo().action_reset_password()

    def create_family_partner(self):
        bank_val = {
            'acc_number':self.acc_number,
            'acc_holder_name':self.acc_holder_name,
            'bank_id':self.bank_id.id,
        }
        partner = self.env['res.partner'].create({
            'name': self.name,
            'email': self.email,
            'phone': self.phone,
            # 'account_type':'family',
            'is_family': True,
            'code':self.code,
            'bank_ids': [(0,0,bank_val)]
        })
        self.partner_id = partner.id
    # def create_member_partner(self):
    #     # bank_val = {
    #     #     'acc_number':self.acc_number,
    #     #     'partner_id':self.account_holder,
    #     #     'bank_name':self.bank_name,
    #     # }
    #     partner = self.env['res.partner'].create({
    #         'name': self.name,
    #         'email': self.email,
    #         'phone': self.phone,
    #         'account_type':'member',
    #         'code':self.code,
    #         # 'bank_ids': [(0,0,bank_val)]
    #     })
    #     self.partner_id = partner.id

    def create_user(self):
        bank_val = {
            'acc_number':self.acc_number,
            'acc_holder_name':self.acc_holder_name,
            'bank_id':self.bank_id.id,
        }
        for follower in self['message_follower_ids']:
            follower.sudo().unlink()
        if not self.partner_id:
            partner = self.create_family_partner()
        self.partner_id.write({
            'name': self.name,
            'email': self.email,
            'phone': self.phone,
            # 'account_type': 'family',
            'is_family': True,
            'code': self.code,
        })
        if bank_val['acc_number'] and bank_val['acc_holder_name'] and bank_val['bank_id']:
            self.partner_id.write({
                'bank_ids': [(0,0,bank_val)]
            })
        user = self.env['res.users'].sudo().with_context(no_reset_password=True).create({
            'name': self.name,
            'login': self.sms_phone or self.email,
            'partner_id': self.partner_id.id,
            'active': True,
            'otp_mobile_phone': self.sms_phone,
        })
        self.user_id = user.id
        if self.password:
            user.sudo().write({'password': self.password, })

        user.sudo().write({
            'groups_id': [(3, self.env.ref('base.group_user', False).id)],
        })
        user.sudo().write({
            'groups_id': [(4, self.env.ref('base.group_portal', False).id)],
        })

    # @api.multi
    def send_approval_benefit_email(self):
        """Send approval email when benefit registration is accepted"""
        template = self.env.ref('odex_benefit.approval_benefit_email', False)
        if not template:
            return
        template.with_context(lang=self.env.user.lang).send_mail(self.id, force_send=True, raise_exception=False)

    # @api.multi
    def _send_notification(self, partner_ids, state):
        """Send notification when entity state changes"""
        subject = _('Beneficial')
        state_label = dict(self.fields_get(allfields=['state'])['state']['selection'])[state]
        body = ' '.join((_(u'The Beneficiaries '), self.name, _(u' State changed to '), state_label, u'.')).encode(
            'utf-8')
        partner_list_ids = []
        for id in partner_ids:
            partner_list_ids.append(id.id)
        message_vals = {
            'subject': subject,
            'body': body,
            'partner_ids': partner_list_ids,
            # 'model': self._name,
            # 'res_id': self.id,
        }
        test = self.sudo().message_post(message_type="notification", subtype_xmlid="mt_comment",
                                        **message_vals)

    def send_black_list_email(self):
        """Send black list email when entity black list"""
        template = self.env.ref('odex_benefit.black_list_entity_email', False)
        if not template:
            return
        template.with_context(lang=self.env.user.lang).send_mail(self.id, force_send=True, raise_exception=False)

    # @api.multi
    def send_remove_from_black_list_email(self):
        """Send black list email when entity black list"""
        template = self.env.ref('odex_benefit.black_list_remove_benefit_email', False)
        if not template:
            return
        template.with_context(lang=self.env.user.lang).send_mail(self.id, force_send=True, raise_exception=False)

    # # Validation Opertaion
    # @api.onchange('phone', 'phone2','sms_phone')
    # def _onchange_mobile_validation(self):
    #     if self.phone:
    #         if self.phone.startswith('+966'):
    #             phone = self.phone[4:]
    #             self.phone = phone
    #         if re.match(SAUDI_MOBILE_PATTERN, self.phone) == None:
    #             raise ValidationError(
    #                 _('Enter a valid Saudi mobile number'))
    #     if self.phone2:
    #         if self.phone2.startswith('+966'):
    #             phone2 = self.phone2[4:]
    #             self.phone2 = phone2
    #         if re.match(SAUDI_MOBILE_PATTERN, self.phone2) == None:
    #             raise ValidationError(
    #                 _('Enter a valid Saudi mobile number'))
    #     if self.sms_phone:
    #         if self.sms_phone.startswith('+966'):
    #             sms_phone = self.sms_phone[4:]
    #             self.sms_phone = sms_phone
    #         if re.match(SAUDI_MOBILE_PATTERN, self.sms_phone) == None:
    #             raise ValidationError(
    #                 _('Enter a valid Saudi mobile number'))

    @api.constrains('phone', 'phone2','sms_phone')
    def _onchange_phone_numbers(self):
        phone_numbers = {
            #'الهاتف': self.phone,
            'رقم الجوال الثاني': self.phone2,
            'رقم الجوال للتواصل': self.sms_phone,
        }

        # Check each ID number for 10-digit format and uniqueness within the parent model
        unique_ids = set()
        for label, phone_number in phone_numbers.items():
            if phone_number:
                if re.match(SAUDI_MOBILE_PATTERN,phone_number) == None:
                    raise ValidationError(
                        _('Enter a valid Saudi mobile number'))
                if phone_number in unique_ids:
                    raise ValidationError(_("%s must be unique within the same record.") % label)
                unique_ids.add(phone_number)

        # Check for uniqueness against `member_phone` in child records and across database records
        for member in self.member_ids:
            if member.member_phone and member.member_phone in unique_ids:
                raise ValidationError(
                    _("The Phone Number %s in the Family Members list must be unique across the record.") % member.member_phone)
        # Check for duplicate IDs across records in the database
        for phone_number in unique_ids:
            duplicate_record_family = self.env['grant.benefit'].search([
                '|', ('phone2', '=', phone_number),
                ('sms_phone', '=', phone_number), ('id', '!=', self._origin.id)
            ], limit=1)
            duplicate_record_member = self.env['family.member'].search([('member_phone', '=', phone_number)], limit=1)
            if duplicate_record_family:
                raise ValidationError(
                    _("The phone number {} already exists in family with code {}.").format(
                        phone_number, duplicate_record_family.code))
            if duplicate_record_member:
                raise ValidationError(
                    _("The phone {} already exists in family with code {}.").format(
                        phone_number, duplicate_record_member.benefit_id.code))

    @api.onchange('email')
    def onchange_email(self):
        if self.email:
            for rec in self:
                exist = self.search([('email', '=', rec.email)])
                if exist:
                    raise ValidationError(
                        _('The Email Already Exist!'))

    @api.onchange('sms_phone')
    def onchange_sms_phone(self):
        if self.sms_phone:
            for rec in self:
                exist = self.search([('sms_phone', '=', rec.sms_phone)])
                if exist:
                    raise ValidationError(
                        _('The SMS phone Already Exist!'))

    @api.onchange('acc_number')
    def onchange_acc_number(self):
        if self.acc_number:
            # Check if the value is numeric before anything else
            if not self.acc_number.isdigit():
                raise ValidationError(_("The account number should contain only digits."))

            # Check if the account number contains exactly 22 digits
            if len(self.acc_number) != 22:
                raise ValidationError(_("The IBAN number must contain exactly 22 digits."))

            # Check if the account number already exists in the partner bank or benefit
            #partner_exist = self.env['res.partner.bank'].search([('acc_number', '=', self.acc_number)], limit=1)
            #benefit_exist = self.search([('acc_number', '=', self.acc_number)], limit=1)

            #if partner_exist or benefit_exist:
            #    raise ValidationError(_("The account number already exists!"))

    @api.onchange('mother_marital_conf', 'mother_location_conf', 'mother_net_income')
    def _onchange_mother_info(self):
        res = {}
        if self.mother_status == 'non_benefit':
            res['warning'] = {'title': _('ValidationError'),
                              'message': _('Not Benefit')}
        return res

    @api.onchange('replacement_mother_marital_conf', 'replacement_mother_location_conf')
    def _onchange_replacement_mother_info(self):
        res = {}
        for rec in self:
            if rec.replacement_mother_status == 'non_benefit':
                res['warning'] = {'title': _('ValidationError'),
                                  'message': _('Not Benefit')}
                return res

    def create_scheduled_visit(self):
        records = self.env["grant.benefit"].search([('state', '=', 'second_approve')])
        recurrence_visit_id = self.env.ref('odex_benefit.recurrence_visit')
        period_unit = {
            recurrence_visit_id.recurrence_period: recurrence_visit_id.recurrence_interval
        }
        for rec in records.filtered(lambda r: r.last_visit_date and (r.last_visit_date + rd(**period_unit)).date() <= fields.Date.context_today(self)):
            self.env['visit.location'].create({
                'benefit_id': rec.id,
                'visit_date': date.today(),
                'visit_types': recurrence_visit_id.id,
                'selector': 'researcher',
                'researcher_id': rec.researcher_id.id,
                # 'researcher_team': rec.researcher_team.id,
                'state': 'draft'
            })

    def create_manual_visit(self):
        self.env['visit.location'].create({
            'benefit_id': self.id,
            'visit_date': date.today(),
            'visit_types': 2,
            # 'selector': 'researcher',
            'researcher_id': self.researcher_id.id,
            # 'researcher_team': rec.researcher_team.id,
            'state': 'draft'
        })
    def change_attachment_status(self):
        obj = self.env["grant.benefit"].search([])
        for attach in obj.attachment_ids:
            attach.get_status()

    # Notifications
    def send_expiry_date_notification(self):
        self.change_attachment_status()
        obj = self.env["grant.benefit"].search([])
        for rec in obj:
            for attach in rec.attachment_ids:
                if attach.attach_status == 'expired':
                    template = self.env.ref('odex_benefit.attachment_expiration_family_email_template', False)
                    if not template:
                        return
                    template.with_context(lang=self.env.user.lang).send_mail(rec.id, force_send=True,
                                                                             raise_exception=False)
    #Update data automatically daily
    def update_data_automatically(self):
        obj = self.env["grant.benefit"].search([])
        for member in obj.member_ids:
            member._compute_get_age_date()
            member.check_member_status()
        #self.action_auto_suspend()


class BenefitFollowers(models.Model):
    _name = 'benefit.followers'
    _inherit = ['mail.thread', 'mail.activity.mixin']

    benefit_id = fields.Many2one('grant.benefit', )
    name = fields.Many2one('grant.benefit', domain="[('is_responsible','=',False)]")
    follower_type = fields.Selection(
        [('benefit', 'benefit'), ('orphan', 'orphan'), ('widow', 'widow'), ('poor', 'poor'), ('other', 'other'),
         ], string='Benefit Type', tracking=True, related="name.benefit_type", )
    birth_date = fields.Date(related="name.birth_date", string="Birth Date")
    age = fields.Integer(string="Age", compute='_compute_get_age_date', store=True)
    gender = fields.Selection(selection=[('male', 'Male'), ('female', 'Female')], string="Gender",
                              related="name.gender", )
    is_live_with_family = fields.Boolean('Is Live With Family')

    @api.depends('birth_date')
    def _compute_get_age_date(self):
        for rec in self:
            if rec.birth_date:
                today = date.today()
                day = datetime.strptime(rec.birth_date, DEFAULT_SERVER_DATE_FORMAT)
                age = rd(today, day)
                rec.age = age.years


class WidowFamily(models.Model):
    _name = 'widow.family'

    benefit_id = fields.Many2one('grant.benefit')
    widow_name = fields.Many2one('grant.benefit', domain="[('benefit_type','=','widow')]", string='Widow Name')
    widows_husband = fields.Char('Widows Husband', related="widow_name.husband_name")
    widows_husband_id = fields.Char('Widows Husband ID', related="widow_name.husband_id")
    date_death_husband = fields.Date(related="widow_name.date_death_husband")


class divorceeFamily(models.Model):
    _name = 'divorcee.family'

    benefit_id = fields.Many2one('grant.benefit')
    divorcee_name = fields.Many2one('grant.benefit', 'divorcee Name')
    divorcee_husband = fields.Char('Widows Husband', related="divorcee_name.husband_name")
    divorcee_husband_id = fields.Char('Widows Husband ID', related="divorcee_name.husband_id")
    date_divorcee = fields.Date(related="divorcee_name.date_divorcee")


class ExternalBenefit(models.Model):
    _name = 'external.benefits'
    _inherits = {'res.partner': 'partner_id'}
    _inherit = ['mail.thread', 'mail.activity.mixin']

    location = fields.Char(string='location')
    benefit_nationality = fields.Many2one('res.country', 'Benefit Nationality')
    block = fields.Char('Benefit Block')
    work = fields.Char()
    partner_id = fields.Many2one('res.partner', string='partner', required=True, ondelete="cascade")

    @api.onchange('first_name', 'second_name', 'middle_name', 'family_name')
    def get_benefit_name(self):
        for rec in self:
            if rec.first_name and rec.second_name and rec.middle_name and rec.family_name:
                rec.name = rec.first_name + " " + rec.second_name + " " + rec.middle_name + " " + rec.family_name

    def create_partner(self):
        partner = self.env['res.partner'].create({
            'name': self.name,
            'email': self.email,
            'phone': self.phone,
            # 'city': self.city_id.name if self.city_id else False,
            # 'country_id': self.country_id.id,
        })
        self.partner_id = partner.id


# neighborhood representative
class Representative(models.Model):
    _name = 'benefits.representative'
    _inherits = {'res.partner': 'partner_id'}
    _inherit = ['mail.thread', 'mail.activity.mixin']

    location = fields.Char(string='location')
    block = fields.Char('Benefit Block')
    work = fields.Char()
    partner_id = fields.Many2one('res.partner', string='partner', required=True, ondelete="cascade")
