From 239bf3156c8920b4d45c9587ef768f36ff138194 Mon Sep 17 00:00:00 2001 From: younes Date: Wed, 17 Dec 2025 15:54:36 +0100 Subject: [PATCH] [IMP] odex_benefit: IMP benefit --- odex25_benefit/odex_benefit/MODULE_REVIEW.md | 2 +- odex25_benefit/odex_benefit/i18n/ar_001.po | 10 --- .../models/family_expense_line.py | 2 +- .../odex_benefit/models/service_request.py | 58 ++++++++---- .../odex_benefit/models/services_settings.py | 90 ++++++++++++------- .../odex_benefit/views/benefit_view.xml | 2 +- .../views/family_expense_line_view.xml | 1 + .../odex_benefit/views/services_settings.xml | 8 +- .../odex_benefit/wizards/researcher_wizard.py | 3 + .../wizards/researcher_wizard.xml | 2 +- .../models/service_request.py | 21 +++-- .../views/service_request_inherit.xml | 27 ++++++ 12 files changed, 154 insertions(+), 72 deletions(-) diff --git a/odex25_benefit/odex_benefit/MODULE_REVIEW.md b/odex25_benefit/odex_benefit/MODULE_REVIEW.md index 45686a709..5227af4b3 100644 --- a/odex25_benefit/odex_benefit/MODULE_REVIEW.md +++ b/odex25_benefit/odex_benefit/MODULE_REVIEW.md @@ -305,7 +305,7 @@ - `recurrence_period`: فترة التكرار (months/years) - `recurrence_interval`: فترة التكرار - `max_limit_type`: نوع الحد الأقصى (none/fixed/category/amount_person/etc.) - - `max_limit_period`: فترة الحد الأقصى (request/individual/month/year/recurrence_period) + - `max_limit_period`: فترة الحد الأقصى (request/individual/month/year) - **الموافقات:** - `needs_beneficiary_manager_approval`: يحتاج موافقة مدير المستفيدين؟ diff --git a/odex25_benefit/odex_benefit/i18n/ar_001.po b/odex25_benefit/odex_benefit/i18n/ar_001.po index 5e62a85f8..6affb6760 100644 --- a/odex25_benefit/odex_benefit/i18n/ar_001.po +++ b/odex25_benefit/odex_benefit/i18n/ar_001.po @@ -16531,16 +16531,6 @@ msgstr "للفرد" msgid "Per Month" msgstr "للشهر" -#. module: odex_benefit -#: model:ir.model.fields.selection,name:odex_benefit.selection__services_settings__max_limit_period__year -msgid "Per Year" -msgstr "للسنة" - -#. module: odex_benefit -#: model:ir.model.fields.selection,name:odex_benefit.selection__services_settings__max_limit_period__recurrence_period -msgid "For Allowed Recurrence Period" -msgstr "لفترة التكرار المسموح" - #. module: odex_benefit #: model:ir.model.fields,field_description:odex_benefit.field_services_settings__max_months_limit msgid "Maximum Number of Months" diff --git a/odex25_benefit/odex_benefit/models/family_expense_line.py b/odex25_benefit/odex_benefit/models/family_expense_line.py index e7254e2de..cb996bdb0 100644 --- a/odex25_benefit/odex_benefit/models/family_expense_line.py +++ b/odex25_benefit/odex_benefit/models/family_expense_line.py @@ -13,7 +13,7 @@ class BenefitExpenseLine(models.Model): confirm_expense_id = fields.Many2one(comodel_name='confirm.benefit.expense', string='Confirm Benefit Expense', ondelete='cascade') - return_confirm_id = fields.Many2one('confirm.benefit.expense', string="Return Confirm", ondelete="set null", ) + return_confirm_id = fields.Many2one('confirm.benefit.expense', string="Return Confirm", ondelete='cascade', ) family_id = fields.Many2one(comodel_name='grant.benefit', string='Family', required=True) branch_id = fields.Many2one(comodel_name='branch.settings', string='Branch') family_category_id = fields.Many2one(comodel_name='benefit.category', string='Family Category') diff --git a/odex25_benefit/odex_benefit/models/service_request.py b/odex25_benefit/odex_benefit/models/service_request.py index 1d21218b8..e9484c39e 100644 --- a/odex25_benefit/odex_benefit/models/service_request.py +++ b/odex25_benefit/odex_benefit/models/service_request.py @@ -1,8 +1,8 @@ from odoo import fields, models, api, _ from odoo.exceptions import UserError, ValidationError -from datetime import datetime, timedelta +from datetime import date,datetime, timedelta from dateutil.relativedelta import relativedelta -from odoo.tools import html_escape +from odoo.tools import html_escape,html2plaintext class ServiceRequest(models.Model): @@ -39,7 +39,7 @@ class ServiceRequest(models.Model): store=True) service_attach = fields.Many2many('ir.attachment', 'rel_service_attachment_service_request', 'service_request_id', 'attachment_id', string='Service Attachment') - requested_service_amount = fields.Float(string="Requested Service Amount") + requested_service_amount = fields.Float(string="Requested Service Amount",copy=False) # yearly Estimated Rent Amount estimated_rent_amount = fields.Float(string="Estimated Rent Amount", compute="_get_estimated_rent_amount") # The value of payment by payment method(yearly-half-quartarly) @@ -209,6 +209,9 @@ class ServiceRequest(models.Model): compute='_compute_related_information_html', store=True, ) researcher_opinion = fields.Html(string='Specialist Opinion',tracking=True) + def action_create_project(self): + pass + @api.depends('service_cat', 'family_id', 'member_id', 'benefit_type') def _compute_related_information_html(self): for rec in self: @@ -550,7 +553,7 @@ class ServiceRequest(models.Model): def action_researcher_send_request(self): for rec in self: - if not rec.researcher_opinion or not rec.researcher_opinion.strip(): + if not html2plaintext(rec.researcher_opinion or '').strip(): raise ValidationError( _('Please write the specialist opinion before completing the action.') ) @@ -582,6 +585,7 @@ class ServiceRequest(models.Model): if rec.service_cat.needs_legal_approval: rec.state = 'legal_department' elif rec.service_cat.needs_project_management_approval: + rec.action_create_project() rec.state = 'projects_department' elif rec.service_cat.needs_beneficiary_manager_approval or rec.exception: rec.state = 'gm_assistant' @@ -591,6 +595,7 @@ class ServiceRequest(models.Model): def action_legal_department_approve(self): for rec in self: if rec.service_cat.needs_project_management_approval: + rec.action_create_project() rec.state = 'projects_department' elif rec.service_cat.needs_beneficiary_manager_approval or rec.exception: rec.state = 'gm_assistant' @@ -762,7 +767,7 @@ class ServiceRequest(models.Model): interval = rec.service_cat.recurrence_interval or 1 period = rec.service_cat.recurrence_period or 'months' max_limit_type = rec.service_cat.max_limit_type - special_services = ['home_furnishing', 'electrical_devices', 'alternative_housing'] + special_services = ['electrical_devices', 'alternative_housing'] base_domain = [('family_id', '=', family_id), ('service_cat', '=', rec.service_cat.id), ('id', '!=', rec._origin.id), ('state', '!=', 'refused')] if rec.benefit_type == "member": @@ -968,20 +973,41 @@ class ServiceRequest(models.Model): _("You cannot request this service for more than %s months.") % rec.service_cat.max_months_limit ) rec.service_max_amount *= num_months - elif rec.max_limit_period == "year": - before_year_domain = base_domain + [('date', '>', date_before_year)] - existing_requests_within_year = Service.search(before_year_domain) - total_spent = sum(existing_requests_within_year.mapped('requested_service_amount')) + elif rec.max_limit_period == "calendar_year": + current_date = rec.date.date() if isinstance(rec.date, datetime) else rec.date + allowed_years = rec.service_cat.allowed_period or 1 + start_year = current_date.year - (allowed_years - 1) + end_year = current_date.year + + year_start = date(start_year, 1, 1) + year_end = date(end_year, 12, 31) + + calendar_year_domain = base_domain + [ + ('date', '>=', datetime.combine(year_start, datetime.min.time())), + ('date', '<=', datetime.combine(year_end, datetime.max.time())), + ] + + existing_requests = Service.search(calendar_year_domain) + total_spent = sum(existing_requests.mapped('requested_service_amount')) + remaining_amount = rec.service_cat.max_amount - total_spent + + rec.service_max_amount = max(remaining_amount, 0.0) + elif rec.max_limit_period == "year_from_request": + current_date = rec.date.date() if isinstance(rec.date, datetime) else rec.date + allowed_years = rec.service_cat.allowed_period or 1 + period_start_date = current_date - relativedelta(years=allowed_years) + period_end_date = current_date + + year_from_request_domain = base_domain + [ + ('date', '>=', datetime.combine(period_start_date, datetime.min.time())), + ('date', '<=', datetime.combine(period_end_date, datetime.max.time())), + ] + + existing_requests = Service.search(year_from_request_domain) + total_spent = sum(existing_requests.mapped('requested_service_amount')) rec.service_max_amount = rec.service_cat.max_amount - total_spent elif rec.max_limit_period == "individual": rec.service_max_amount *= rec.service_benefit_count - elif rec.max_limit_period == "recurrence_period": - prev_requests = Service.search(base_domain) - total_spent = sum(prev_requests.mapped('requested_service_amount')) - remaining = rec.service_cat.max_amount - total_spent - if remaining < 0: - remaining = 0 - rec.service_max_amount = remaining if rec.service_cat.service_type == 'marriage': if rec.marriage_contract_date and rec.date: request_date = rec.date.date() if isinstance(rec.date, datetime) else rec.date diff --git a/odex25_benefit/odex_benefit/models/services_settings.py b/odex25_benefit/odex_benefit/models/services_settings.py index e067e4b98..be5f40710 100644 --- a/odex25_benefit/odex_benefit/models/services_settings.py +++ b/odex25_benefit/odex_benefit/models/services_settings.py @@ -8,60 +8,69 @@ class ServicesSettings(models.Model): service_name = fields.Char(string='Service Name') benefit_type = fields.Selection(string='Benefit Type', selection=[('family', 'Family'), ('member', 'Member')]) - parent_service = fields.Many2one('services.settings',string='Parent Service') + parent_service = fields.Many2one('services.settings', string='Parent Service') is_main_service = fields.Boolean(string='Is Main Service?') is_service_producer = fields.Boolean(string='Is Service Producer?') - service_producer_id = fields.Many2one('res.partner',string='Service Producer') + service_producer_id = fields.Many2one('res.partner', string='Service Producer') is_this_service_for_student = fields.Boolean(string='Is Service For Student?') - service_type = fields.Selection([('rent', 'Rent'),('home_restoration', 'Home Restoration'),('alternative_housing', 'Alternative Housing'),('home_maintenance','Home Maintenance') - ,('complete_building_house','Complete Building House'),('electrical_devices','Electrical Devices'),('home_furnishing','Home furnishing') - ,('electricity_bill','Electricity bill'),('water_bill','Water bill'),('buy_car','Buy Car'),('recruiting_driver','Recruiting Driver') - ,('transportation_insurance','Transportation Insurance'),('debits','Debits'),('health_care','Health Care'), - ('providing_medicines_medical_devices_and_needs_the_disabled','Providing Medicines Medical Devices And Needs The Disabled'), - ('recruiting_domestic_worker_or_nurse','Recruiting a domestic worker or nurse') ,('marriage','Marriage'),('eid_gift','Eid gift'), - ('winter_clothing','Winter clothing'),('ramadan_basket','Ramadan basket'),('natural_disasters','Natural disasters'), - ('legal_arguments','Legal arguments'),('buy_home','Buy Home'),('main_service','Main Service'),('normal_service', 'Normal Service')] - ,string='Service Type') + service_type = fields.Selection( + [('rent', 'Rent'), ('home_restoration', 'Home Restoration'), ('alternative_housing', 'Alternative Housing'), + ('home_maintenance', 'Home Maintenance') + , ('complete_building_house', 'Complete Building House'), ('electrical_devices', 'Electrical Devices'), + ('home_furnishing', 'Home furnishing') + , ('electricity_bill', 'Electricity bill'), ('water_bill', 'Water bill'), ('buy_car', 'Buy Car'), + ('recruiting_driver', 'Recruiting Driver') + , ('transportation_insurance', 'Transportation Insurance'), ('debits', 'Debits'), + ('health_care', 'Health Care'), + ('providing_medicines_medical_devices_and_needs_the_disabled', + 'Providing Medicines Medical Devices And Needs The Disabled'), + ('recruiting_domestic_worker_or_nurse', 'Recruiting a domestic worker or nurse'), ('marriage', 'Marriage'), + ('eid_gift', 'Eid gift'), + ('winter_clothing', 'Winter clothing'), ('ramadan_basket', 'Ramadan basket'), + ('natural_disasters', 'Natural disasters'), + ('legal_arguments', 'Legal arguments'), ('buy_home', 'Buy Home'), ('main_service', 'Main Service'), + ('normal_service', 'Normal Service')] + , string='Service Type') raise_amount_for_orphan = fields.Float(string='Raise Amount For Orphan') - rent_lines = fields.One2many('rent.lines','services_settings_id') - attachment_lines = fields.One2many('service.attachments.settings','service_id') - #Fields for home restoration - category_amount_lines = fields.One2many('category.amount.line','services_settings_id') + rent_lines = fields.One2many('rent.lines', 'services_settings_id') + attachment_lines = fields.One2many('service.attachments.settings', 'service_id') + # Fields for home restoration + category_amount_lines = fields.One2many('category.amount.line', 'services_settings_id') rent_amount_for_alternative_housing = fields.Float(string='Rent Amount For Alternative Housing') rent_period = fields.Integer('Rent Period') - home_maintenance_lines = fields.One2many('home.maintenance.lines','services_settings_id') + home_maintenance_lines = fields.One2many('home.maintenance.lines', 'services_settings_id') benefit_category_ids = fields.Many2many('benefit.category', string='Allowed Categories') - account_id = fields.Many2one('account.account',string='Expenses Account',domain="[('user_type_id.id','=',15)]") - accountant_id = fields.Many2one('res.users',string='Accountant') - #For Electrical Devices - electrical_devices_lines = fields.One2many('electrical.devices','services_settings_id') - #Home Furnishing - home_furnishing_lines = fields.One2many('home.furnishing.lines','services_settings_id') + account_id = fields.Many2one('account.account', string='Expenses Account', domain="[('user_type_id.id','=',15)]") + accountant_id = fields.Many2one('res.users', string='Accountant') + # For Electrical Devices + electrical_devices_lines = fields.One2many('electrical.devices', 'services_settings_id') + # Home Furnishing + home_furnishing_lines = fields.One2many('home.furnishing.lines', 'services_settings_id') max_furnishing_amount_if_exception = fields.Float(string='Max Furnishing Amount (Exception)') bill_lines = fields.One2many('bill.lines', 'services_settings_id') min_count_member = fields.Integer(string='Mini Count Member') member_max_payroll = fields.Float(string='Member Max Payroll') fatherless_member_amount = fields.Float(string='Fatherless Member Amount') orphan_member_amount = fields.Float(string='Orphan Member Amount') - #Buy Home + # Buy Home limit_person_line_ids = fields.One2many('service.limit.person.line', 'services_settings_id') buy_home_max_total_amount = fields.Float(string='Buy Home Max Total Amount') home_age = fields.Integer(string='Home Age') required_attach = fields.Boolean(string='Required Attach') is_seasonal_service = fields.Boolean(string='Is Seasonal Service?') active = fields.Boolean('Active', default=True) - show_in_portal = fields.Boolean(string="Show in Portal",copy=False) - service_number = fields.Char(string="Service Number",copy=False) + show_in_portal = fields.Boolean(string="Show in Portal", copy=False) + service_number = fields.Char(string="Service Number", copy=False) service_category = fields.Selection([ ('emergency', 'Emergency'), ('permanent', 'Permanent'), ('exceptional', 'Exceptional'), ('seasonal', 'Seasonal'), - ], string="Service Category",copy=False) + ], string="Service Category", copy=False) company_id = fields.Many2one('res.company', string="Company", default=lambda self: self.env.user.company_id) currency_id = fields.Many2one('res.currency', string="Currency", related='company_id.currency_id') - max_amount = fields.Monetary(string="Maximum Amount", currency_field='currency_id',copy=False) - max_age = fields.Integer(string="Maximum Age",copy=False) + max_amount = fields.Monetary(string="Maximum Amount", currency_field='currency_id', copy=False) + max_age = fields.Integer(string="Maximum Age", copy=False) service_description = fields.Text(string="Service Description") service_conditions = fields.Html(string="Service Conditions") allowed_recurrence = fields.Selection([ @@ -71,7 +80,7 @@ class ServicesSettings(models.Model): ], string="Allowed Recurrence", default='once') recurrence_period = fields.Selection([ ('months', 'Months'), - ('years', 'Years'),], + ('years', 'Years'), ], string="Recurrence Period", default='months' ) recurrence_interval = fields.Integer( @@ -100,9 +109,13 @@ class ServicesSettings(models.Model): ('request', 'Per Request'), ('individual', 'Per Individual'), ('month', 'Per Month'), - ('year', 'Per Year'), - ('recurrence_period', 'For Allowed Recurrence Period'), + ('year_from_request', 'Year from date of request'), + ('calendar_year', 'Calendar year'), ], string='Maximum Limit Period') + allowed_period = fields.Integer( + string='Maximum Allowed Period', default=1, + help='Specify the maximum allowed number of months or years based on the selected period type.' + ) max_months_limit = fields.Integer( string='Maximum Number of Months', help='Specify the maximum allowed number of months when the period type is monthly.' @@ -112,7 +125,7 @@ class ServicesSettings(models.Model): ('none', 'None'), ('payment_order', 'Payment Order'), ('invoice', 'Invoice'), - ], string='Payment Method',default="payment_order") + ], string='Payment Method', default="payment_order") family_related_fields = fields.Many2many( comodel_name='ir.model.fields', relation='services_settings_family_field_rel', @@ -138,6 +151,10 @@ class ServicesSettings(models.Model): if self.benefit_type != 'member': self.member_related_fields = [(5, 0, 0)] + @api.onchange('max_limit_period') + def _onchange_max_limit_period(self): + if self.max_limit_period not in ['year_from_request', 'calendar_year']: + self.allowed_period = 0 class RentLines(models.Model): @@ -166,6 +183,7 @@ class CategoryAmountLine(models.Model): services_settings_id = fields.Many2one('services.settings', string='Services Settings') max_amount = fields.Float(string='Max Amount') + class HomeMaintenanceLines(models.Model): _name = 'home.maintenance.lines' _rec_name = 'maintenance_name' @@ -173,6 +191,7 @@ class HomeMaintenanceLines(models.Model): services_settings_id = fields.Many2one('services.settings', string='Services Settings') maintenance_name = fields.Char(string='Maintenance Name') + class ElectricalDevices(models.Model): _name = 'electrical.devices' _rec_name = 'device_name' @@ -181,10 +200,11 @@ class ElectricalDevices(models.Model): max_count_member = fields.Integer(string='To') device_name = fields.Char(string="Device Name") allowed_quantity = fields.Integer(string='Allowed Quantity') - account_id = fields.Many2one('account.account',string='Expenses Account',domain="[('user_type_id.id','=',15)]") + account_id = fields.Many2one('account.account', string='Expenses Account', domain="[('user_type_id.id','=',15)]") services_settings_id = fields.Many2one('services.settings') price_unit = fields.Float() + class HomeFurnishingLines(models.Model): _name = 'home.furnishing.lines' @@ -192,6 +212,7 @@ class HomeFurnishingLines(models.Model): name = fields.Char(string="Furnishing Name") max_furnishing_amount = fields.Float(string='Furnishing Amount') + class BillLines(models.Model): _name = 'bill.lines' @@ -201,10 +222,11 @@ class BillLines(models.Model): max_amount_for_bill = fields.Float(string='Max Amount For Bill') services_settings_id = fields.Many2one('services.settings', string='Services Settings') + class ServiceLimitByPersonLine(models.Model): _name = 'service.limit.person.line' min_count_member = fields.Integer(string='Minimum Number of Persons') max_count_member = fields.Integer(string='Maximum Number of Persons') amount = fields.Float(string='Amount') - services_settings_id = fields.Many2one('services.settings', string='Services Settings') \ No newline at end of file + services_settings_id = fields.Many2one('services.settings', string='Services Settings') diff --git a/odex25_benefit/odex_benefit/views/benefit_view.xml b/odex25_benefit/odex_benefit/views/benefit_view.xml index bee23f155..eb9281025 100644 --- a/odex25_benefit/odex_benefit/views/benefit_view.xml +++ b/odex25_benefit/odex_benefit/views/benefit_view.xml @@ -1677,7 +1677,7 @@ + /> diff --git a/odex25_benefit/odex_benefit/views/family_expense_line_view.xml b/odex25_benefit/odex_benefit/views/family_expense_line_view.xml index 4ea4307ca..a61c4b26b 100644 --- a/odex25_benefit/odex_benefit/views/family_expense_line_view.xml +++ b/odex25_benefit/odex_benefit/views/family_expense_line_view.xml @@ -18,6 +18,7 @@ + diff --git a/odex25_benefit/odex_benefit/views/services_settings.xml b/odex25_benefit/odex_benefit/views/services_settings.xml index ac95db2da..fef62ccf7 100644 --- a/odex25_benefit/odex_benefit/views/services_settings.xml +++ b/odex25_benefit/odex_benefit/views/services_settings.xml @@ -50,6 +50,11 @@ attrs="{'invisible':[('service_type','!=','marriage')]}"/> + + + @@ -67,9 +72,6 @@ - - diff --git a/odex25_benefit/odex_benefit/wizards/researcher_wizard.py b/odex25_benefit/odex_benefit/wizards/researcher_wizard.py index 28d56a31d..f53958a45 100644 --- a/odex25_benefit/odex_benefit/wizards/researcher_wizard.py +++ b/odex25_benefit/odex_benefit/wizards/researcher_wizard.py @@ -62,6 +62,7 @@ class ReasearcherFamilyWizard(models.TransientModel): assignment_type = fields.Selection([ ('researcher', 'Assign Researcher'), ('assigned_researcher', 'Assign Assigned Researcher'), + ('end_assignment', 'End Assignment'), ], string='Assignment Type', default='researcher') @api.depends('benefit_ids') @@ -108,6 +109,8 @@ class ReasearcherFamilyWizard(models.TransientModel): update_vals['researcher_id'] = self.researcher_team.id elif self.assignment_type == 'assigned_researcher': update_vals['assigned_researcher_id'] = self.researcher_team.id + elif self.assignment_type == 'end_assignment': + update_vals['assigned_researcher_id'] = False benefit.with_context(bypass_attachments_requirement=True).write(update_vals) specialist_name = self.researcher_team.name or _('Not Specified') diff --git a/odex25_benefit/odex_benefit/wizards/researcher_wizard.xml b/odex25_benefit/odex_benefit/wizards/researcher_wizard.xml index 40585e276..53494287c 100644 --- a/odex25_benefit/odex_benefit/wizards/researcher_wizard.xml +++ b/odex25_benefit/odex_benefit/wizards/researcher_wizard.xml @@ -61,10 +61,10 @@ + -