Merge pull request #5749 from expsa/rr

[IMP] odex_benefit: IMP benefit
This commit is contained in:
kchyounes19 2025-12-17 15:55:36 +01:00 committed by GitHub
commit 48be32ad9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 154 additions and 72 deletions

View File

@ -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`: يحتاج موافقة مدير المستفيدين؟

View File

@ -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"

View File

@ -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')

View File

@ -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

View File

@ -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')
services_settings_id = fields.Many2one('services.settings', string='Services Settings')

View File

@ -1677,7 +1677,7 @@
<field name="family_member_id"
attrs="{'invisible':[('is_family_member','=',False)],'readonly':[('state','not in',['complete_info','waiting_approve','first_approve'])]}"
options="{'no_create': True, 'no_create_edit': True}"
groups="!odex_benefit.group_benefit_manager"/>
/>
<field name="owner_identity_attachment_ids"
attrs="{'invisible':[('is_family_member','=',True)],'readonly':[('state','not in',['complete_info','waiting_approve','first_approve'])]}"
widget="many2many_attachment_preview"/>

View File

@ -18,6 +18,7 @@
<field name="family_monthly_clotting"/>
<field name="family_monthly_othaime"/>
<field name="total_family_expenses"/>
<field name="researcher_id"/>
<field name="is_return" optional="hide"/>
<field name="return_reason_id" optional="hide"/>
<field name="payment_order_id" invisible="1"/>

View File

@ -50,6 +50,11 @@
attrs="{'invisible':[('service_type','!=','marriage')]}"/>
<field name="orphan_member_amount"
attrs="{'invisible':[('service_type','!=','marriage')]}"/>
<field name="max_limit_period"/>
<field name="allowed_period"
attrs="{'invisible': [('max_limit_period', 'not in', ['year_from_request', 'calendar_year'])]}"/>
<field name="max_months_limit"
attrs="{'invisible': [('max_limit_period', '!=', 'month')]}"/>
<field name="currency_id" invisible="1"/>
</group>
<group>
@ -67,9 +72,6 @@
<field name="recurrence_interval" class="oe_inline" nolabel="1"/>
<field name="recurrence_period" class="oe_inline" nolabel="1"/>
</div>
<field name="max_limit_period"/>
<field name="max_months_limit"
attrs="{'invisible': [('max_limit_period', '!=', 'month')]}"/>
</group>
<group>
<field name="requires_visit" widget="boolean_toggle"/>

View File

@ -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')

View File

@ -61,10 +61,10 @@
<field name="branch_custom_id" invisible="1"
attrs="{'invisible':[('branch_has_employees','=',True)]}"/>
<field name="branch_has_employees" invisible="1"/>
<field name="assignment_type" required="1"/>
<field name="researcher_team" required="1"
domain="[('branch_custom_id', '=',branch_custom_id)]"
options="{'no_create': True, 'no_create_edit': True,'no_quick_create': True, 'no_open': True}"/>
<field name="assignment_type" required="1"/>
</group>
<footer>
<button name="submit_family" type="object" string="Submit" class="oe_highlight"

View File

@ -11,15 +11,26 @@ class ServiceRequestInherit(models.Model):
project_expected_delivery_date = fields.Date(string='Expected Delivery Date', related='project_id.date', )
rent_period = fields.Integer('Rent Period')
project_create = fields.Boolean(string='Project Create?', related='service_cat.project_create')
project_state = fields.Selection(string='Project Status',
selection=[('new', 'New'), ('open', 'Running'), ('hold', 'Hold'),
('close', 'Closed')],
compute='_compute_project_state', store=True, )
def action_accounting_approve(self):
super(ServiceRequestInherit, self).action_accounting_approve()
@api.depends('project_id.status')
def _compute_project_state(self):
for rec in self:
if rec.service_cat.project_create and not rec.project_id:
rec.project_state = rec.project_id.status
if rec.project_id.status == 'close':
rec.state = 'send_request_to_supplier'
def action_create_project(self):
super(ServiceRequestInherit, self).action_create_project()
for rec in self:
if rec.project_create and not rec.project_id:
project = self.env['project.project'].sudo().create(
{
'name': (
_('%s') % rec.service_cat.service_type) + "/" + rec.family_id.name + "/" + rec.family_id.code,
_('%s') % rec.service_cat.service_name) + "/" + rec.family_id.name + "/" + rec.family_id.code,
'partner_id': rec.service_producer_id.id,
'beneficiary_id': rec.family_id.partner_id.id,
'category_id': rec.service_cat.category_id.id,
@ -36,4 +47,4 @@ class ServiceRequestInherit(models.Model):
'country_id': rec.family_id.city_id.country_id.id,
}
)
rec.project_id = project
rec.project_id = project

View File

@ -15,6 +15,33 @@
<field name="project_expected_delivery_date" readonly="1"
attrs="{'invisible': ['|',('project_create', '=',False),('project_expected_delivery_date', '=',False)]}"/>
</xpath>
<xpath expr="//header/button[@name='action_projects_department_approve']" position="attributes">
<attribute name="states"/>
<attribute name="attrs">{'invisible': ['|',('state', '!=', 'projects_department'),('project_create',
'=', True)]}
</attribute>
</xpath>
<xpath expr="//header/button[@name='action_first_refuse'][5]" position="attributes">
<attribute name="states"/>
<attribute name="attrs">{'invisible': ['|',('state', '!=', 'projects_department'),('project_create',
'=', True)]}
</attribute>
</xpath>
<xpath expr="//header/button[@name='action_refuse'][6]" position="attributes">
<attribute name="states"/>
<attribute name="attrs">{'invisible': ['|',('state', '!=', 'projects_department'),('project_create',
'=', True)]}
</attribute>
</xpath>
<xpath expr="//sheet/div[hasclass('oe_button_box')]" position="after">
<div attrs="{'invisible': [('project_id','=',False)]}">
<header>
<field name="project_state"
widget="statusbar" readonly="1" nolabel="1"/>
</header>
</div>
</xpath>
</field>
</record>
</data>