diff --git a/addons/hr_expense/__manifest__.py b/addons/hr_expense/__manifest__.py index 4573b5b3967..6033895df55 100644 --- a/addons/hr_expense/__manifest__.py +++ b/addons/hr_expense/__manifest__.py @@ -36,6 +36,7 @@ This module also uses analytic accounting and is compatible with the invoice on 'data/hr_expense_sequence.xml', 'data/hr_expense_data.xml', 'wizard/hr_expense_refuse_reason_views.xml', + 'wizard/hr_expense_approve_duplicate_views.xml', 'views/hr_expense_views.xml', 'views/mail_activity_views.xml', 'security/ir_rule.xml', diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index dd2662b9e52..6ec4833ae34 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -98,6 +98,8 @@ class HrExpense(models.Model): ('refused', 'Refused') ], compute='_compute_state', string='Status', copy=False, index=True, readonly=True, store=True, default='draft', help="Status of the expense.") sheet_id = fields.Many2one('hr.expense.sheet', string="Expense Report", domain="[('employee_id', '=', employee_id), ('company_id', '=', company_id)]", readonly=True, copy=False) + approved_by = fields.Many2one('res.users', string='Approved By', related='sheet_id.user_id') + approved_on = fields.Datetime(string='Approved On', related='sheet_id.approval_date') reference = fields.Char("Bill Reference") is_refused = fields.Boolean("Explicitly Refused by manager or accountant", readonly=True, copy=False) @@ -105,6 +107,8 @@ class HrExpense(models.Model): is_ref_editable = fields.Boolean("Reference Is Editable By Current User", compute='_compute_is_ref_editable') product_has_cost = fields.Boolean("Is product with non zero cost selected", compute='_compute_product_has_cost') same_currency = fields.Boolean("Is currency_id different from the company_currency_id", compute='_compute_same_currency') + duplicate_expense_ids = fields.Many2many('hr.expense', compute='_compute_duplicate_expense_ids') + sample = fields.Boolean() label_total_amount_company = fields.Char(compute='_compute_label_total_amount_company') label_convert_rate = fields.Char(compute='_compute_label_convert_rate') @@ -234,6 +238,35 @@ class HrExpense(models.Model): for expense in self: expense.employee_id = self.env.user.with_company(expense.company_id).employee_id + @api.depends('employee_id', 'product_id', 'total_amount') + def _compute_duplicate_expense_ids(self): + self.duplicate_expense_ids = [(5, 0, 0)] + + expenses = self.filtered(lambda e: e.employee_id and e.product_id and e.total_amount) + if expenses.ids: + duplicates_query = """ + SELECT ARRAY_AGG(DISTINCT he.id) + FROM hr_expense AS he + JOIN hr_expense AS ex ON he.employee_id = ex.employee_id + AND he.product_id = ex.product_id + AND he.date = ex.date + AND he.total_amount = ex.total_amount + AND he.company_id = ex.company_id + AND he.currency_id = ex.currency_id + WHERE ex.id in %(expense_ids)s + GROUP BY he.employee_id, he.product_id, he.date, he.total_amount, he.company_id, he.currency_id + HAVING COUNT(he.id) > 1 + """ + self.env.cr.execute(duplicates_query, { + 'expense_ids': tuple(expenses.ids), + }) + duplicates = [x[0] for x in self.env.cr.fetchall()] + + for ids in duplicates: + exp = expenses.filtered(lambda e: e.id in ids) + exp.duplicate_expense_ids = [(6, 0, ids)] + expenses = expenses - exp + @api.onchange('product_id', 'date', 'account_id') def _onchange_product_id_date_account_id(self): rec = self.env['account.analytic.default'].sudo().account_get( @@ -364,7 +397,7 @@ Or send your receipts at { + return this._rpc({ + model: 'hr.expense', + method: 'action_approve_duplicates', + args: [recordID], + }); + }); + } else { + this._super.apply(this, arguments); + } + } else { + this._super.apply(this, arguments); + } + }, + + _showConfirmDialog: function(confirm_callback) { + return new Promise(function (resolve, reject) { + Dialog.confirm(this, _t("An expense of same category, amount and date already exists."), { + buttons: [ + { + text: _t("Save Anyways"), + classes: 'btn-primary', + close: true, + click: function() { + confirm_callback(); + resolve(); + } + }, { + text: _t("Cancel"), + close: true, + click: reject, + } + ], + }); + }); + } + }); + + var ExpenseFormView = FormView.extend({ + config: _.extend({}, FormView.prototype.config, { + Controller: ExpenseFormController, + }), + }); + + viewRegistry.add('hr_expense_form_view', ExpenseFormView); +}); diff --git a/addons/hr_expense/views/assets.xml b/addons/hr_expense/views/assets.xml index 2fc4116b41e..e9f2ff60178 100644 --- a/addons/hr_expense/views/assets.xml +++ b/addons/hr_expense/views/assets.xml @@ -4,6 +4,7 @@