diff --git a/odex25_benefit/odex_benefit/i18n/ar_001.po b/odex25_benefit/odex_benefit/i18n/ar_001.po
index 6426b703d..820a6c08b 100644
--- a/odex25_benefit/odex_benefit/i18n/ar_001.po
+++ b/odex25_benefit/odex_benefit/i18n/ar_001.po
@@ -16876,14 +16876,6 @@ msgstr "موافقة المسؤول"
msgid "Payment Waiting"
msgstr "في انتظار الدفع"
-#. module: odex_benefit
-#: code:addons/odex_benefit/models/service_request.py:0
-#, python-format
-msgid ""
-"Some attachment records are missing files. Please make sure all required "
-"attachments are uploaded before submitting."
-msgstr "بعض سجلات المرفقات تفتقد إلى ملفات. يرجى التأكد من تحميل جميع المرفقات المطلوبة قبل الإرسال."
-
#. module: odex_benefit
#: model:ir.actions.server,name:odex_benefit.server_action_accounting_transfer
#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_form
diff --git a/odex25_benefit/odex_benefit/models/benefit.py b/odex25_benefit/odex_benefit/models/benefit.py
index 89e212ebb..d8172dc9d 100644
--- a/odex25_benefit/odex_benefit/models/benefit.py
+++ b/odex25_benefit/odex_benefit/models/benefit.py
@@ -116,7 +116,7 @@ class GrantBenefitProfile(models.Model):
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')
+ 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'),
@@ -126,7 +126,7 @@ class GrantBenefitProfile(models.Model):
('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')
+ 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')
@@ -452,10 +452,10 @@ class GrantBenefitProfile(models.Model):
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")
- rent_start_date = fields.Date(string='Rent Start Date')
- rent_end_date = fields.Date(string='Rent End Date')
- rent_attachment = fields.Many2many('ir.attachment','rel_rent_attachment_attachment','benefit_id','attachment_id',string='Rent Attachment')
+ 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(
[
@@ -464,7 +464,8 @@ class GrantBenefitProfile(models.Model):
('4', 'Quarterly'),
('5', 'Monthly')
],
- string='Payment Type'
+ string='Payment Type',
+ compute='_compute_rent_from_contract',store=True,
)
housing_cat = fields.Selection([
('excellent', 'Excellent'),
@@ -636,13 +637,74 @@ class GrantBenefitProfile(models.Model):
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,)
_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('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)]
+
+
@api.depends('mother_income', 'is_mother_work','mother_expenses_ids','mother_debits_ids')
def _compute_mother_net_income(self):
for rec in self:
diff --git a/odex25_benefit/odex_benefit/models/benefit_config.py b/odex25_benefit/odex_benefit/models/benefit_config.py
index fe1066ffc..6c3127092 100644
--- a/odex25_benefit/odex_benefit/models/benefit_config.py
+++ b/odex25_benefit/odex_benefit/models/benefit_config.py
@@ -927,6 +927,23 @@ class ServiceAttachmentsSettings(models.Model):
service_request_id = fields.Many2one('service.request',string='Service Request')
previous_service_attachment_settings_id = fields.Many2one('service.attachments.settings', readonly=True)
notes = fields.Text(string='Notes')
+ state = fields.Selection(selection=[
+ ('draft', 'Draft'),
+ ('waiting_family', 'Waiting Family'),
+ ('researcher', 'Researcher'),
+ ('waiting_approve', 'Waiting for Operation Manager'),
+ ('first_approve', 'Waiting for Branch Manager'),
+ ('family_services_manager', 'Waiting Family Services Manager'),
+ ('legal_department', 'Waiting Legal Department'),
+ ('projects_department', 'Waiting Projects Department'),
+ ('gm_assistant', 'Waiting Assistant General Manager'),
+ ('accounting_approve', 'Accounting Approve'),
+ ('return_to_bank', 'Return to Bank'),
+ ('approval_of_beneficiary_services', 'Approval of beneficiary services'),
+ ('send_request_to_supplier', 'Send Request To Supplier'),
+ ('family_received_device', 'Family Received Device'),
+ ('refused', 'Refused')
+ ], string='State', default='waiting_family')
class HomeMaintenanceItems(models.Model):
_name = 'home.maintenance.items'
@@ -962,3 +979,67 @@ class PropertyTypeSettings(models.Model):
string="Unavailable Services",
help="Services that are not available for families or members with this property type"
)
+
+class RentContract(models.Model):
+ _name = 'rent.contract'
+ _description = 'Rent Contract'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ _order = 'create_date desc, id desc'
+
+ name = fields.Char(string='Contract Number',required=True,copy=False,tracking=True)
+ family_id = fields.Many2one('grant.benefit',string='Family',required=True,ondelete='cascade')
+ member_id = fields.Many2one('family.member',string='Member (Tenant)',
+ domain="""[
+ ('benefit_id', '=', family_id),
+ ('education_status', '=', 'educated'),
+ ('member_education_status_ids', '!=', False),
+ ('member_education_status_ids.case_study', '=', 'continuous')
+ ]"""
+ )
+ contract_type = fields.Selection([
+ ('fixed', 'Fixed Term'),
+ ('unlimited', 'Indefinite'),
+ ], string='Contract Type', required=True, default='fixed', tracking=True)
+ start_date = fields.Date(string='Start Date', required=True)
+ end_date = fields.Date(string='End Date')
+ payment_type = fields.Selection([
+ ('1', 'Yearly'),
+ ('2', 'Half-yearly'),
+ ('4', 'Quarterly'),
+ ('5', 'Monthly'),
+ ], string='Payment Type', required=True)
+ rent_amount = fields.Float(string='Rent Amount', required=True)
+ contract_attachment = fields.Many2many(
+ 'ir.attachment', 'rent_contract_attachment_rel',
+ 'contract_id', 'attachment_id',
+ string='Contract Attachment'
+ )
+ electricity_bill_attachment = fields.Many2many(
+ 'ir.attachment', 'rent_electricity_bill_rel',
+ 'contract_id', 'attachment_id',
+ string='Electricity Bill Attachment'
+ )
+ state = fields.Selection([
+ ('active', 'Active'),
+ ('expired', 'Expired'),
+ ], string='Status', default='active', tracking=True)
+ landlord_type = fields.Selection([
+ ('family', 'Family'),
+ ('member', 'Member / Student'),
+ ], string='Landlord Type', default='family', required=True)
+
+ @api.onchange('end_date', 'start_date')
+ def _onchange_contract_dates(self):
+ if self.end_date and self.start_date and self.end_date < self.start_date:
+ raise ValidationError(_("End Date cannot be before Start Date."))
+
+ @api.onchange('landlord_type')
+ def _onchange_landlord_type(self):
+ for rec in self:
+ if rec.landlord_type == 'family':
+ rec.member_id = False
+
+ @api.onchange('contract_type')
+ def _onchange_contract_type(self):
+ if self.contract_type == 'unlimited':
+ self.end_date = False
\ No newline at end of file
diff --git a/odex25_benefit/odex_benefit/models/service_request.py b/odex25_benefit/odex_benefit/models/service_request.py
index ca4397828..c35ac3e56 100644
--- a/odex25_benefit/odex_benefit/models/service_request.py
+++ b/odex25_benefit/odex_benefit/models/service_request.py
@@ -51,7 +51,7 @@ class ServiceRequest(models.Model):
('none', 'None'),
('payment_order', 'Payment Order'),
('invoice', 'Invoice'),
- ], string='Payment Method', default="payment_order")
+ ], string='Payment Method', related='service_cat.payment_method', store=True, default="payment_order")
# is_alternative_housing = fields.Boolean(string='Is Alternative Housing?')
rent_contract_number = fields.Char(string="Rent Contract Number", compute='_compute_rent_details', store=True)
rent_start_date = fields.Date(string='Rent Start Date', compute='_compute_rent_details', store=True)
@@ -214,6 +214,19 @@ class ServiceRequest(models.Model):
def action_create_project(self):
pass
+ def _check_required_attachments(self):
+ self.ensure_one()
+ current_state = self.state
+ required_docs = self.attachment_lines.filtered(lambda l: l.state == current_state)
+ missing_docs = required_docs.filtered(lambda l: not l.service_attach)
+ if missing_docs:
+ missing_names = ", ".join(missing_docs.mapped('name'))
+ raise UserError(
+ _("Cannot proceed with approval. The following required documents for status '%(status)s' are missing: %(missing)s") % {
+ 'status': dict(self._fields['state'].selection).get(current_state, current_state),
+ 'missing': missing_names
+ })
+
@api.depends('service_cat', 'family_id', 'member_id', 'benefit_type')
def _compute_related_information_html(self):
for rec in self:
@@ -457,6 +470,7 @@ class ServiceRequest(models.Model):
'name': attachment_line.name,
'notes': attachment_line.notes,
'previous_service_attachment_settings_id': attachment_line.id,
+ 'state': attachment_line.state,
}))
rec.attachment_lines = commands
@@ -474,22 +488,33 @@ class ServiceRequest(models.Model):
raise UserError(_('You cannot delete this record'))
return super(ServiceRequest, self).unlink()
- @api.depends('family_id')
+ @api.depends('family_id','member_id','benefit_type')
def _compute_rent_details(self):
for rec in self:
- if rec.family_id:
- if not rec.rent_contract_number:
- rec.rent_contract_number = rec.family_id.contract_num
- if not rec.rent_start_date:
- rec.rent_start_date = rec.family_id.rent_start_date
- if not rec.rent_end_date:
- rec.rent_end_date = rec.family_id.rent_end_date
- if not rec.rent_amount:
- rec.rent_amount = rec.family_id.rent_amount
- if not rec.payment_type:
- rec.payment_type = rec.family_id.payment_type
- if not rec.rent_attachment:
- rec.rent_attachment = rec.family_id.rent_attachment
+ contract = False
+
+ if rec.benefit_type == 'family' and rec.family_id:
+ contract = rec.family_id.current_rent_contract_id
+ elif rec.benefit_type == 'member' and rec.member_id:
+ member_contracts = rec.family_id.rent_contract_ids.filtered(
+ lambda c: c.state == 'active' and c.member_id == rec.member_id and c.landlord_type == 'member'
+ ).sorted('start_date', reverse=True)
+ contract = member_contracts[:1] or False
+
+ if contract:
+ rec.rent_contract_number = contract.name
+ rec.rent_start_date = contract.start_date
+ rec.rent_end_date = contract.end_date
+ rec.rent_amount = contract.rent_amount
+ rec.payment_type = contract.payment_type
+ rec.rent_attachment = [(6, 0, contract.contract_attachment.ids)]
+ else:
+ rec.rent_contract_number = False
+ rec.rent_start_date = False
+ rec.rent_end_date = False
+ rec.rent_amount = 0.0
+ rec.payment_type = False
+ rec.rent_attachment = [(5, 0, 0)]
def _get_added_amount_if_mother_dead(self):
for rec in self:
@@ -555,6 +580,7 @@ class ServiceRequest(models.Model):
def action_send_to_researcher(self):
for rec in self:
+ rec._check_required_attachments()
if rec.service_cat and rec.service_cat.service_type == 'home_furnishing':
for item in rec.furnishing_items_ids:
max_amount = item.home_furnishing_items.max_furnishing_amount or 0.0
@@ -595,21 +621,17 @@ class ServiceRequest(models.Model):
if not rec.requested_service_amount or rec.requested_service_amount <= 0:
raise UserError(_("Please enter a valid service amount."))
- if rec.attachment_lines:
- for attach_line in rec.attachment_lines:
- if not attach_line.service_attach:
- raise UserError(_(
- "Some attachment records are missing files. Please make sure all required attachments are uploaded before submitting."
- ))
-
+ rec._check_required_attachments()
rec.state = 'waiting_approve'
def action_operations_chief_approve(self):
for rec in self:
+ rec._check_required_attachments()
rec.state = 'first_approve'
def action_branch_manager_approve(self):
for rec in self:
+ rec._check_required_attachments()
if rec.service_cat.needs_services_head_approval or rec.exception:
rec.state = 'family_services_manager'
else:
@@ -617,6 +639,7 @@ class ServiceRequest(models.Model):
def action_family_services_manager_approve(self):
for rec in self:
+ rec._check_required_attachments()
if rec.service_cat.needs_legal_approval:
rec.state = 'legal_department'
elif rec.service_cat.needs_project_management_approval:
@@ -629,6 +652,7 @@ class ServiceRequest(models.Model):
def action_legal_department_approve(self):
for rec in self:
+ rec._check_required_attachments()
if rec.service_cat.needs_project_management_approval:
rec.action_create_project()
rec.state = 'projects_department'
@@ -637,6 +661,7 @@ class ServiceRequest(models.Model):
def action_projects_department_approve(self):
for rec in self:
+ rec._check_required_attachments()
if rec.service_cat.needs_beneficiary_manager_approval or rec.exception:
rec.state = 'gm_assistant'
else:
@@ -644,10 +669,12 @@ class ServiceRequest(models.Model):
def action_beneficiary_manager_approve(self):
for rec in self:
+ rec._check_required_attachments()
rec.state = 'accounting_approve'
def action_accounting_approve(self):
for rec in self:
+ rec._check_required_attachments()
if rec.service_type == 'electrical_devices':
rec.state = 'approval_of_beneficiary_services'
else:
@@ -656,6 +683,7 @@ class ServiceRequest(models.Model):
def action_supplier_approve(self):
for rec in self:
+ rec._check_required_attachments()
rec.service_approval_date = fields.Datetime.now()
rec.state = 'send_request_to_supplier'
@@ -725,11 +753,11 @@ class ServiceRequest(models.Model):
if rec.service_cat:
rec.benefit_type = rec.service_cat.benefit_type
rec.service_producer_id = rec.service_cat.service_producer_id
- rec.payment_method = rec.service_cat.payment_method
+ # rec.payment_method = rec.service_cat.payment_method
else:
rec.benefit_type = False
rec.service_producer_id = False
- rec.payment_method = 'payment_order'
+ # rec.payment_method = 'payment_order'
if not rec.family_id:
rec.member_id = False
@@ -738,7 +766,7 @@ class ServiceRequest(models.Model):
@api.onchange('service_cat', 'family_id')
def _onchange_service_cat(self):
- if self.service_cat.service_type == 'rent' and self.family_id.property_type_code == 'rent' and self.benefit_type == 'family':
+ if self.service_cat.service_type == 'rent' and self.family_id.property_type_code != 'rent' and self.benefit_type == 'family':
raise UserError(_("You cannot benefit from this service (property type not rent)"))
@api.onchange('start', 'end', 'rent_start_date', 'rent_end_date', 'payment_type')
diff --git a/odex25_benefit/odex_benefit/security/ir.model.access.csv b/odex25_benefit/odex_benefit/security/ir.model.access.csv
index a7d252bec..8628c1164 100644
--- a/odex25_benefit/odex_benefit/security/ir.model.access.csv
+++ b/odex25_benefit/odex_benefit/security/ir.model.access.csv
@@ -172,4 +172,5 @@ access_expense_researcher,access_expense_researcher,model_benefit_expense_line,o
access_family_bank_report_wizard,access_family_bank_report_wizard,model_family_bank_report_wizard,base.group_user,1,1,1,1
access_return_reason,access_return_reason,model_return_reason,base.group_user,1,1,1,1
access_return_reason_wizard,access_return_reason_wizard,model_return_reason_wizard,base.group_user,1,1,1,1
-access_property_type_settings,access_property_type_settings,model_property_type_settings,base.group_user,1,1,1,1
\ No newline at end of file
+access_property_type_settings,access_property_type_settings,model_property_type_settings,base.group_user,1,1,1,1
+access_rent_contract,access_rent_contract,model_rent_contract,base.group_user,1,1,1,1
\ No newline at end of file
diff --git a/odex25_benefit/odex_benefit/views/benefit_config_view.xml b/odex25_benefit/odex_benefit/views/benefit_config_view.xml
index cf347879c..3826d5c3e 100644
--- a/odex25_benefit/odex_benefit/views/benefit_config_view.xml
+++ b/odex25_benefit/odex_benefit/views/benefit_config_view.xml
@@ -1500,5 +1500,55 @@
+
+ rent.contract.tree
+ rent.contract
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ rent.contract.form
+ rent.contract
+
+
+
+
diff --git a/odex25_benefit/odex_benefit/views/benefit_view.xml b/odex25_benefit/odex_benefit/views/benefit_view.xml
index e73d124f3..deb66528e 100644
--- a/odex25_benefit/odex_benefit/views/benefit_view.xml
+++ b/odex25_benefit/odex_benefit/views/benefit_view.xml
@@ -1421,20 +1421,21 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -1498,7 +1499,28 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+