From e583014cc2726711bfb2f1c7c91f91751d4f775f Mon Sep 17 00:00:00 2001 From: younes Date: Thu, 13 Nov 2025 19:49:55 +0100 Subject: [PATCH] [IMP] odex_benefit: IMP benefit --- odex25_ensan/odex_benefit/i18n/ar_001.po | 20 -- .../odex_benefit/models/family_expense.py | 267 +++++++++--------- .../models/family_expense_line.py | 1 + .../views/family_expense_line_view.xml | 2 + .../views/family_expense_view.xml | 116 +++++--- .../odex_benefit/views/family_members.xml | 4 +- 6 files changed, 224 insertions(+), 186 deletions(-) diff --git a/odex25_ensan/odex_benefit/i18n/ar_001.po b/odex25_ensan/odex_benefit/i18n/ar_001.po index ee33246d1..23897a125 100644 --- a/odex25_ensan/odex_benefit/i18n/ar_001.po +++ b/odex25_ensan/odex_benefit/i18n/ar_001.po @@ -2690,7 +2690,6 @@ msgstr "المرتد" #: model:ir.model.fields,field_description:odex_benefit.field_service_request__branch_custom_id #: model_terms:ir.ui.view,arch_db:odex_benefit.grant_benefit_search #: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_search -#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_search msgid "Branch" msgstr "الفرع" @@ -5017,11 +5016,6 @@ msgstr "خدمات استثنائية" msgid "Excluded from suspension?" msgstr "مستثنى من إيقاف الخدمة" -#. module: odex_benefit -#: model:ir.model.fields,field_description:odex_benefit.field_confirm_benefit_expense__expense_type -msgid "Expense Type" -msgstr "نوع الاجراء" - #. module: odex_benefit #: model:ir.model.fields,field_description:odex_benefit.field_benefit_category__expenses_ids #: model:ir.model.fields,field_description:odex_benefit.field_benefit_need__expenses_ids @@ -5203,11 +5197,6 @@ msgstr "ديون الأسرة" msgid "Family Domain" msgstr "" -#. module: odex_benefit -#: model:ir.model.fields.selection,name:odex_benefit.selection__confirm_benefit_expense__expense_type__family_expense -msgid "Family Expense" -msgstr "مصروف التغذية الشهرية" - #. module: odex_benefit #: code:addons/odex_benefit/models/family_expense.py:0 #: code:addons/odex_benefit/wizards/family_expense_move_wiz.py:0 @@ -5792,7 +5781,6 @@ msgstr "تاريخ التخرج" #. module: odex_benefit #: model_terms:ir.ui.view,arch_db:odex_benefit.grant_benefit_search #: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_search -#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_search msgid "Group By" msgstr "" @@ -7863,11 +7851,6 @@ msgstr "" msgid "Meal Card" msgstr "بطاقة الغذاء" -#. module: odex_benefit -#: model:ir.model.fields.selection,name:odex_benefit.selection__confirm_benefit_expense__expense_type__family_invoice -msgid "Meal Card Invoice" -msgstr "فاتورة كرت الغذاء" - #. module: odex_benefit #: model:ir.model.fields,field_description:odex_benefit.field_family_validation_setting__meal_expense msgid "Meal Expense" @@ -14445,7 +14428,6 @@ msgstr "أمر الصرف تم" #. module: odex_benefit #: model_terms:ir.ui.view,arch_db:odex_benefit.seasonal_service_form_view #: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_form -#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_form msgid "Payment Done" msgstr "تم الدفع" @@ -16775,7 +16757,6 @@ msgstr "الحصول على دورة تأهيلية" #. module: odex_benefit #: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_form -#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_form msgid "Total Moves" msgstr "القيد المحاسبي" @@ -16946,7 +16927,6 @@ msgstr "موافقة المسؤول" #. module: odex_benefit #: model_terms:ir.ui.view,arch_db:odex_benefit.seasonal_service_form_view #: model_terms:ir.ui.view,arch_db:odex_benefit.service_request_form -#: model_terms:ir.ui.view,arch_db:odex_benefit.view_confirm_benefit_expense_form msgid "Payment Waiting" msgstr "في انتظار الدفع" diff --git a/odex25_ensan/odex_benefit/models/family_expense.py b/odex25_ensan/odex_benefit/models/family_expense.py index 8ee5af3ee..3e36d2052 100644 --- a/odex25_ensan/odex_benefit/models/family_expense.py +++ b/odex25_ensan/odex_benefit/models/family_expense.py @@ -35,10 +35,6 @@ class ConfirmBenefitExpense(models.Model): ('cancel', 'Cancelled'), ('confirm', 'Confirmed'), ], string='Status', default='draft', required=True, copy=False, tracking=True) - expense_type = fields.Selection(selection=[ - ('family_expense', 'Family Expense'), - ('family_invoice', 'Meal Card Invoice'), - ], string='Expense Type', default='family_expense', required=True) name = fields.Char(string="Name", states={'confirm': [('readonly', True)]}, copy=False) date = fields.Date(string="Date", default=fields.Date.context_today, required=False, states={'confirm': [('readonly', True)]}) @@ -57,13 +53,15 @@ class ConfirmBenefitExpense(models.Model): payment_order_id = fields.Many2one('payment.orders', string='Payment Order', ondelete="set null", copy=False) move_id = fields.Many2one('account.move', ondelete='cascade') available_payment_method_line_ids = fields.Many2many(comodel_name='account.payment.method.line') - total_moves = fields.Integer(string="Total Move", compute='_get_total_move_lines') - total_move_lines = fields.Integer(string="Total Move Lines", compute='_get_total_move_lines') - family_monthly_income = fields.Float(string="Total Monthly Income", compute='_get_family_monthly_values') - family_monthly_meals = fields.Float(string="Total Monthly Meals", compute='_get_family_monthly_values') - family_monthly_clotting = fields.Float(string="Total Monthly Clotting", compute='_get_family_monthly_values') - family_monthly_total = fields.Float(string="Total", compute='_get_family_monthly_values') - branch_custom_id = fields.Many2one(comodel_name='branch.settings', string="Branch") + family_monthly_income = fields.Float(string="Total Monthly Income", compute='_get_family_monthly_values', + store=True) + family_monthly_meals = fields.Float(string="Total Monthly Meals", compute='_get_family_monthly_values', store=True) + family_monthly_clotting = fields.Float(string="Total Monthly Clotting", compute='_get_family_monthly_values', + store=True) + family_monthly_othaime = fields.Float(string="Total Othaim", compute='_get_family_monthly_values', store=True) + family_monthly_total = fields.Float(string="Total", compute='_get_family_monthly_values', store=True) + branch_custom_ids = fields.Many2many(comodel_name='branch.settings', relation='confirm_benefit_expense_branch_rel', + column1='expense_id', column2='branch_id', string="Branches") family_domain_ids = fields.Many2many(comodel_name='grant.benefit', compute='_compute_domain_ids') company_id = fields.Many2one('res.company', default=lambda self: self.env.company) currency_id = fields.Many2one(comodel_name='res.currency', string="Company Currency", @@ -71,25 +69,41 @@ class ConfirmBenefitExpense(models.Model): payment_state = fields.Selection(string='Payment State', selection=[ ('none', 'None'), ('waiting', 'Waiting Payment'), - ('done', 'Done Payment'), ], copy=False, compute="_compute_payment_state", store=True) + ('done', 'Done Payment'), ], copy=False, compute="_compute_payment_move_state", store=True) + move_state = fields.Selection(string='Move State', selection=[ + ('none', 'None'), + ('waiting', 'Waiting Payment'), + ('done', 'Done Payment'), ], copy=False, compute="_compute_payment_move_state", store=True) + family_count_expense = fields.Integer(string="Family Count (Monthly Expense)", + compute='_get_family_monthly_values', store=True) + + family_count_othaim = fields.Integer(string="Family Count (Othaim)", compute='_get_family_monthly_values', + store=True) + member_count_expense = fields.Integer(string="Member Count (Monthly Expense)", compute='_get_family_monthly_values', + store=True, ) + + member_count_othaim = fields.Integer(string="Member Count (Othaim)", compute='_get_family_monthly_values', + store=True, ) @api.depends('payment_order_id', 'payment_order_id.state', 'move_id', 'move_id.state') - def _compute_payment_state(self): + def _compute_payment_move_state(self): for rec in self: payment_state = 'none' + move_state = 'none' if rec.payment_order_id: if rec.payment_order_id.state == "done": payment_state = "done" - rec.state = "confirm" else: payment_state = "waiting" - elif rec.move_id: + if rec.move_id: if rec.move_id.state == "posted": - payment_state = "done" - rec.state = "confirm" + move_state = "done" else: - payment_state = "waiting" + move_state = "waiting" + rec.move_state = move_state rec.payment_state = payment_state + if rec.move_state == 'done' and rec.payment_state == 'done': + rec.state = 'confirm' @api.model def create(self, vals): @@ -107,9 +121,14 @@ class ConfirmBenefitExpense(models.Model): income, meals, clotting = 0, 0, 0 if not family: continue - monthly_meals = family.family_monthly_meals - if self.expense_type == 'family_expense' and family.meal_card: - monthly_meals = 0.0 + monthly_meals = 0.0 if family.meal_card else family.family_monthly_meals + othaime = family.family_monthly_meals if family.meal_card else 0.0 + if self.cash_expense: + income = family.family_monthly_income + if self.meal_expense: + meals = monthly_meals + if self.cloth_expense: + clotting = family.family_monthly_clotting vals = { 'branch_id': family.branch_custom_id.id, 'family_category_id': family.benefit_category_id.id, @@ -117,25 +136,11 @@ class ConfirmBenefitExpense(models.Model): 'benefit_member_count': family.benefit_member_count, 'start_date': self.start_date, 'end_date': self.end_date, + 'family_monthly_income': income, + 'family_monthly_meals': meals, + 'family_monthly_clotting': clotting, + 'family_monthly_othaime': othaime, } - if self.expense_type == 'family_expense': - if self.cash_expense: - income = family.family_monthly_income - if self.meal_expense: - meals = monthly_meals - if self.cloth_expense: - clotting = family.family_monthly_clotting - vals.update({ - 'family_monthly_income': income, - 'family_monthly_meals': meals, - 'family_monthly_clotting': clotting, - }) - else: - vals.update({ - 'family_monthly_income': 0.0, - 'family_monthly_meals': monthly_meals, - 'family_monthly_clotting': 0.0, - }) line.write(vals) def action_calculate(self): @@ -147,9 +152,9 @@ class ConfirmBenefitExpense(models.Model): if not families: raise UserError(_("Please select at least one family to calculate.")) - if rec.expense_type == 'family_expense': - if not rec.cash_expense and not rec.meal_expense and not rec.cloth_expense: - raise UserError(_("At least one expense type should be selected.")) + # Todo ask awatif + if not rec.cash_expense and not rec.meal_expense and not rec.cloth_expense: + raise UserError(_("At least one expense type should be selected.")) rec.benefit_expense_line_ids.unlink() lines = [] @@ -172,45 +177,41 @@ class ConfirmBenefitExpense(models.Model): raise UserError(_("You can only recalculate when status is 'Calculated'.")) rec._update_benefit_expense_lines() - @api.depends('expense_type', 'date', 'branch_custom_id', 'start_date', 'end_date') + @api.depends('branch_custom_ids', 'start_date', 'end_date') def _compute_domain_ids(self): for rec in self: # Define base domain for family selection validation_setting = self.env["family.validation.setting"].search([], limit=1) base_domain = ['|', ('state', '=', 'second_approve'), '&', ('state', 'in', ('waiting_approve', 'first_approve')), ('action_type', '=', 'suspended')] - if rec.branch_custom_id: - base_domain.append(('branch_custom_id', '=', rec.branch_custom_id.id)) + if rec.branch_custom_ids: + base_domain.append(('branch_custom_id', 'in', rec.branch_custom_ids.ids)) min_income = validation_setting.benefit_category_ids.mapped('mini_income_amount') max_income = validation_setting.benefit_category_ids.mapped('max_income_amount') base_domain.extend([('member_income', '>=', min(min_income)), ('member_income', '<=', max(max_income))]) base_domain.extend([('benefit_category_id', '!=', False)]) - if rec.expense_type == 'family_invoice': - base_domain.append(('meal_card', '=', True)) - - # if rec.date: if rec.start_date and rec.end_date: - # Calculate the start date for the past month range - # month_ago = rec.date - relativedelta(months=1) - - # Search for conflicting records of the same expense type within the past month conflicting_records = self.search([ ('id', '!=', rec._origin.id), ('start_date', '<=', rec.end_date), ('end_date', '>=', rec.start_date), - ('expense_type', '=', rec.expense_type), ]) if conflicting_records: - # Gather the family IDs that are already associated with the same expense type conflicting_family_ids = conflicting_records.mapped('family_ids').ids base_domain.append(('id', 'not in', conflicting_family_ids)) rec.family_domain_ids = self.env['grant.benefit'].search(base_domain) - @api.onchange('branch_custom_id') - def _onchange_branch_custom_id(self): - if self.branch_custom_id: + @api.onchange('branch_custom_ids') + def _onchange_branch_custom_ids(self): + if self.branch_custom_ids: + allowed_families = self.env['grant.benefit'].search([ + ('id', 'in', self.family_ids.ids), + ('branch_custom_id', 'in', self.branch_custom_ids.ids), + ]) + self.family_ids = [(6, 0, allowed_families.ids)] + else: self.family_ids = [(5, 0, 0)] def unlink(self): @@ -222,15 +223,26 @@ class ConfirmBenefitExpense(models.Model): @api.depends('benefit_expense_line_ids') def _get_family_monthly_values(self): for rec in self: - rec.family_monthly_income = sum(rec.benefit_expense_line_ids.mapped('family_monthly_income')) - rec.family_monthly_meals = sum(rec.benefit_expense_line_ids.mapped('family_monthly_meals')) - rec.family_monthly_clotting = sum(rec.benefit_expense_line_ids.mapped('family_monthly_clotting')) + lines = rec.benefit_expense_line_ids + rec.family_monthly_income = sum(lines.mapped('family_monthly_income')) + rec.family_monthly_meals = sum(lines.mapped('family_monthly_meals')) + rec.family_monthly_clotting = sum(lines.mapped('family_monthly_clotting')) + rec.family_monthly_othaime = sum(lines.mapped('family_monthly_othaime')) rec.family_monthly_total = rec.family_monthly_income + rec.family_monthly_meals + rec.family_monthly_clotting + expense_lines = lines.filtered(lambda l: not l.meal_card) + othaim_lines = lines.filtered('meal_card') + rec.family_count_expense = len(expense_lines.mapped('family_id')) + rec.member_count_expense = sum(expense_lines.mapped('benefit_member_count')) + + rec.family_count_othaim = len(othaim_lines.mapped('family_id')) + rec.member_count_othaim = sum(othaim_lines.mapped('benefit_member_count')) + def action_assistant_manager(self): - if self.expense_type != 'family_expense': - self.state = 'assistant_general_manager' - return + # Todo ask awatif + # if self.expense_type != 'family_expense': + # self.state = 'assistant_general_manager' + # return disbursement_date = False # if not disbursement_date: @@ -256,28 +268,13 @@ class ConfirmBenefitExpense(models.Model): self.state = 'cancel' def action_reset_to_draft(self): - self.benefit_expense_line_ids.unlink() self.payment_order_id.unlink() self.move_id.unlink() + self.benefit_expense_line_ids.unlink() self.state = 'draft' - def _get_total_move_lines(self): - for rec in self: - if self.expense_type == 'family_expense': - moves = self.payment_order_id.move_id - else: - moves = self.move_id - - rec.total_moves = len(moves) - rec.total_move_lines = len(moves.mapped('line_ids')) - def action_open_related_move_records(self): - """ Opens a tree view with related records filtered by a dynamic domain """ - if self.expense_type == 'family_expense': - moves = self.payment_order_id.move_id.ids - else: - moves = self.move_id.ids - + moves = self.move_id.ids return { 'name': _('Vendor Bills'), 'type': 'ir.actions.act_window', @@ -286,63 +283,77 @@ class ConfirmBenefitExpense(models.Model): 'domain': [('id', 'in', moves)], } + def action_open_related_payment_orders(self): + payment_orders = self.payment_order_id.ids + return { + 'name': _('Payment Orders'), + 'type': 'ir.actions.act_window', + 'res_model': 'payment.orders', + 'view_mode': 'tree,form', + 'domain': [('id', 'in', payment_orders)], + } + def action_accounting_transfer(self): for rec in self: validation_setting = self.env["family.validation.setting"].search([], limit=1) lines = rec.benefit_expense_line_ids if not lines: raise UserError(_("Please make sure you have benefit expense lines.")) - if rec.expense_type == 'family_expense': - families = lines.mapped('family_id') - invalid_families = families.filtered( - lambda f: f.state != 'second_approve' - or (f.state in ('waiting_approve', 'first_approve') and f.action_type == 'suspended') - ) - if invalid_families: - raise UserError(_( - "Some selected benefits are not in valid state or are suspended:\n%s" - ) % ", ".join(invalid_families.mapped('name'))) - if not validation_setting.cash_expense_account_id or not validation_setting.meal_expense_account_id or not validation_setting.clothing_expense_account_id: - raise UserError(_("Please configure the expense accounts in the validation settings.")) + families = lines.mapped('family_id') + invalid_families = families.filtered( + lambda f: f.state != 'second_approve' + or (f.state in ('waiting_approve', 'first_approve') and f.action_type == 'suspended') + ) + if invalid_families: + raise UserError(_( + "Some selected benefits are not in valid state or are suspended:\n%s" + ) % ", ".join(invalid_families.mapped('name'))) - credit_account_id = validation_setting.account_id.id + if not validation_setting.cash_expense_account_id or not validation_setting.meal_expense_account_id or not validation_setting.clothing_expense_account_id: + raise UserError(_("Please configure the expense accounts in the validation settings.")) - if not credit_account_id: - raise UserError(_("Please select credit account.")) + credit_account_id = validation_setting.account_id.id - payment_order = self.env['payment.orders'].create({ - 'state': 'draft', - 'accountant_id': validation_setting.accountant_id.id, - 'benefit_expense_line_ids': [(6, 0, rec.benefit_expense_line_ids.ids)], - 'type': 'benefit_expense', - }) - rec.payment_order_id = payment_order - else: - account_id = validation_setting.meal_expense_account_id - invoice_lines = [] - for line in lines: - family = line.family_id - invoice_lines.append((0, 0, { - 'name': f'{family.name}/{family.code}', - 'account_id': account_id.id, - 'quantity': 1, - 'benefit_family_id': family.id, - 'price_unit': line.family_monthly_meals, - 'analytic_account_id': family.branch_family_id.branch.analytic_account_id.id - })) - invoice_vals = { - 'move_type': 'in_invoice', - 'partner_id': validation_setting.meal_partner_id.id, - 'invoice_date': rec.date, - 'family_confirm_id': rec.id, - 'benefit_family_ids': [(6, 0, rec.benefit_expense_line_ids.mapped('family_id').ids)], - 'journal_id': validation_setting.journal_id.id, - 'invoice_line_ids': invoice_lines, - 'ref': rec.name, - } + if not credit_account_id: + raise UserError(_("Please select credit account.")) - invoice = self.env['account.move'].create(invoice_vals) - rec.move_id = invoice + # todo if have paymnet or move dont create again + + # Create Payment Order for Benefit Expense + payment_order = self.env['payment.orders'].create({ + 'state': 'draft', + 'accountant_id': validation_setting.accountant_id.id, + 'benefit_expense_line_ids': [(6, 0, rec.benefit_expense_line_ids.ids)], + 'type': 'benefit_expense', + }) + rec.payment_order_id = payment_order + + # Create Vendor Bill for Meal Card Invoice(othaime) + account_id = validation_setting.meal_expense_account_id + invoice_lines = [] + for line in lines.filtered(lambda l: l.meal_card): + family = line.family_id + invoice_lines.append((0, 0, { + 'name': f'{family.name}/{family.code}', + 'account_id': account_id.id, + 'quantity': 1, + 'benefit_family_id': family.id, + 'price_unit': line.family_monthly_othaime, + 'analytic_account_id': family.branch_family_id.branch.analytic_account_id.id + })) + invoice_vals = { + 'move_type': 'in_invoice', + 'partner_id': validation_setting.meal_partner_id.id, + 'invoice_date': rec.date, + 'family_confirm_id': rec.id, + 'benefit_family_ids': [(6, 0, rec.benefit_expense_line_ids.mapped('family_id').ids)], + 'journal_id': validation_setting.journal_id.id, + 'invoice_line_ids': invoice_lines, + 'ref': rec.name, + } + + invoice = self.env['account.move'].create(invoice_vals) + rec.move_id = invoice return True diff --git a/odex25_ensan/odex_benefit/models/family_expense_line.py b/odex25_ensan/odex_benefit/models/family_expense_line.py index cbd2e63ce..fb0d28df1 100644 --- a/odex25_ensan/odex_benefit/models/family_expense_line.py +++ b/odex25_ensan/odex_benefit/models/family_expense_line.py @@ -20,6 +20,7 @@ class BenefitExpenseLine(models.Model): family_monthly_income = fields.Float(string="Family Monthly Income") family_monthly_meals = fields.Float(string="Family Monthly Meals") family_monthly_clotting = fields.Float(string="Family Monthly Clotting") + family_monthly_othaime = fields.Float(string="Othaim Total Monthly") total_family_expenses = fields.Float(string="Total Family Expenses", compute='_compute_total_family_expenses') start_date = fields.Date(string='Start Date', ) end_date = fields.Date(string='End Date', ) diff --git a/odex25_ensan/odex_benefit/views/family_expense_line_view.xml b/odex25_ensan/odex_benefit/views/family_expense_line_view.xml index 72789dc73..1e2a0051e 100644 --- a/odex25_ensan/odex_benefit/views/family_expense_line_view.xml +++ b/odex25_ensan/odex_benefit/views/family_expense_line_view.xml @@ -16,6 +16,7 @@ + @@ -43,6 +44,7 @@ + diff --git a/odex25_ensan/odex_benefit/views/family_expense_view.xml b/odex25_ensan/odex_benefit/views/family_expense_view.xml index 49494cffe..351678a70 100644 --- a/odex25_ensan/odex_benefit/views/family_expense_view.xml +++ b/odex25_ensan/odex_benefit/views/family_expense_view.xml @@ -9,8 +9,7 @@ - - + @@ -59,25 +58,44 @@ - - -

@@ -97,52 +115,55 @@

- - +
- - + + + + + + - - - - - - - - + attrs="{'invisible': [('cash_expense', '=', False)]}"/> + attrs="{'invisible': [('meal_expense', '=', False)]}"/> + attrs="{'invisible': [('cloth_expense', '=', False)]}"/> - + + + + + + + - + @@ -157,13 +178,39 @@ + + domain="[('id', 'in', family_domain_ids)]"> + + + + + + + + + + + + + + + + + + + + @@ -182,9 +229,6 @@ confirm.benefit.expense - - - diff --git a/odex25_ensan/odex_benefit/views/family_members.xml b/odex25_ensan/odex_benefit/views/family_members.xml index 2b401b16e..48b08d235 100644 --- a/odex25_ensan/odex_benefit/views/family_members.xml +++ b/odex25_ensan/odex_benefit/views/family_members.xml @@ -584,7 +584,7 @@ font-size:14px; "> + style="color:#198754; font-size:14px;"/>
@@ -618,7 +618,7 @@ + style="color:#9aa5a0; font-size:12px;"/>