diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index c30dcba9512..23909de6dea 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -82,7 +82,7 @@ class HrExpense(models.Model): @api.depends('sheet_id', 'sheet_id.account_move_id', 'sheet_id.state') def _compute_state(self): for expense in self: - if not expense.sheet_id: + if not expense.sheet_id or expense.sheet_id.state == 'draft': expense.state = "draft" elif expense.sheet_id.state == "cancel": expense.state = "refused" @@ -177,7 +177,7 @@ class HrExpense(models.Model): @api.multi def action_submit_expenses(self): - if any(expense.state != 'draft' for expense in self): + if any(expense.state != 'draft' or expense.sheet_id for expense in self): raise UserError(_("You cannot report twice the same line!")) if len(self.mapped('employee_id')) != 1: raise UserError(_("You cannot report expenses for different employees in the same report.")) @@ -508,19 +508,20 @@ class HrExpenseSheet(models.Model): name = fields.Char('Expense Report Summary', required=True) expense_line_ids = fields.One2many('hr.expense', 'sheet_id', string='Expense Lines', states={'approve': [('readonly', True)], 'done': [('readonly', True)], 'post': [('readonly', True)]}, copy=False) state = fields.Selection([ + ('draft', 'Draft'), ('submit', 'Submitted'), ('approve', 'Approved'), ('post', 'Posted'), ('done', 'Paid'), ('cancel', 'Refused') - ], string='Status', index=True, readonly=True, track_visibility='onchange', copy=False, default='submit', required=True, help='Expense Report State') - employee_id = fields.Many2one('hr.employee', string="Employee", required=True, readonly=True, states={'submit': [('readonly', False)]}, default=lambda self: self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)) + ], string='Status', index=True, readonly=True, track_visibility='onchange', copy=False, default='draft', required=True, help='Expense Report State') + employee_id = fields.Many2one('hr.employee', string="Employee", required=True, readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: self.env['hr.employee'].search([('user_id', '=', self.env.uid)], limit=1)) address_id = fields.Many2one('res.partner', string="Employee Home Address") payment_mode = fields.Selection([("own_account", "Employee (to reimburse)"), ("company_account", "Company")], related='expense_line_ids.payment_mode', default='own_account', readonly=True, string="Paid By") - user_id = fields.Many2one('res.users', 'Manager', readonly=True, copy=False, states={'submit': [('readonly', False)]}, track_visibility='onchange', oldname='responsible_id') + user_id = fields.Many2one('res.users', 'Manager', readonly=True, copy=False, states={'draft': [('readonly', False)]}, track_visibility='onchange', oldname='responsible_id') total_amount = fields.Monetary('Total Amount', currency_field='currency_id', compute='_compute_amount', store=True, digits=dp.get_precision('Account')) - company_id = fields.Many2one('res.company', string='Company', readonly=True, states={'submit': [('readonly', False)]}, default=lambda self: self.env.user.company_id) - currency_id = fields.Many2one('res.currency', string='Currency', readonly=True, states={'submit': [('readonly', False)]}, default=lambda self: self.env.user.company_id.currency_id) + company_id = fields.Many2one('res.company', string='Company', readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: self.env.user.company_id) + currency_id = fields.Many2one('res.currency', string='Currency', readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: self.env.user.company_id.currency_id) attachment_number = fields.Integer(compute='_compute_attachment_number', string='Number of Attachments') journal_id = fields.Many2one('account.journal', string='Expense Journal', states={'done': [('readonly', True)], 'post': [('readonly', True)]}, default=_default_journal_id, help="The journal used when the expense is done.") bank_journal_id = fields.Many2one('account.journal', string='Bank Journal', states={'done': [('readonly', True)], 'post': [('readonly', True)]}, default=_default_bank_journal_id, help="The payment method used when the expense is paid by the company.") @@ -528,6 +529,7 @@ class HrExpenseSheet(models.Model): account_move_id = fields.Many2one('account.move', string='Journal Entry', ondelete='restrict', copy=False) department_id = fields.Many2one('hr.department', string='Department', states={'post': [('readonly', True)], 'done': [('readonly', True)]}) is_multiple_currency = fields.Boolean("Handle lines with different currencies", compute='_compute_is_multiple_currency') + can_reset = fields.Boolean('Can Reset', compute='_compute_can_reset') @api.depends('expense_line_ids.total_amount_company') def _compute_amount(self): @@ -544,6 +546,12 @@ class HrExpenseSheet(models.Model): for sheet in self: sheet.is_multiple_currency = len(sheet.expense_line_ids.mapped('currency_id')) > 1 + @api.multi + def _compute_can_reset(self): + is_expense_user = self.user_has_groups('hr_expense.group_hr_expense_user') + for sheet in self: + sheet.can_reset = is_expense_user if is_expense_user else sheet.employee_id.user_id == self.env.user + @api.onchange('employee_id') def _onchange_employee_id(self): self.address_id = self.employee_id.sudo().address_home_id @@ -647,6 +655,10 @@ class HrExpenseSheet(models.Model): def set_to_paid(self): self.write({'state': 'done'}) + @api.multi + def action_submit_sheet(self): + self.write({'state': 'submit'}) + @api.multi def approve_expense_sheets(self): if not self.user_has_groups('hr_expense.group_hr_expense_user'): @@ -688,8 +700,10 @@ class HrExpenseSheet(models.Model): @api.multi def reset_expense_sheets(self): + if not self.can_reset: + raise UserError(_("Only HR Officers or the concerned employee can reset to draft.")) self.mapped('expense_line_ids').write({'is_refused': False}) - self.write({'state': 'submit'}) + self.write({'state': 'draft'}) self.activity_update() return True diff --git a/addons/hr_expense/security/ir.model.access.csv b/addons/hr_expense/security/ir.model.access.csv index f995ebe78d7..f2d58d25114 100644 --- a/addons/hr_expense/security/ir.model.access.csv +++ b/addons/hr_expense/security/ir.model.access.csv @@ -1,9 +1,10 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_hr_expense_user,hr.expense.user,model_hr_expense,hr_expense.group_hr_expense_user,1,1,1,1 access_hr_expense_employee,hr.expense.employee,model_hr_expense,base.group_user,1,1,1,1 -access_hr_expense_sheet_manager,hr.expense.sheet.manager,model_hr_expense_sheet,hr_expense.group_hr_expense_manager,1,1,1,1 -access_hr_expense_sheet_user,hr.expense.sheet.user,model_hr_expense_sheet,hr_expense.group_hr_expense_user,1,1,1,1 access_hr_expense_sheet_employee,hr.expense.sheet.employee,model_hr_expense_sheet,base.group_user,1,1,1,1 +access_hr_expense_user,hr.expense.user,model_hr_expense,hr_expense.group_hr_expense_user,1,1,1,1 +access_hr_expense_sheet_user,hr.expense.sheet.user,model_hr_expense_sheet,hr_expense.group_hr_expense_user,1,1,1,1 +access_hr_expense_manager,hr.expense.manager,model_hr_expense,hr_expense.group_hr_expense_manager,1,1,1,1 +access_hr_expense_sheet_manager,hr.expense.sheet.manager,model_hr_expense_sheet,hr_expense.group_hr_expense_manager,1,1,1,1 access_product_product_hr_expense_user,product.product.hr.expense.user,product.model_product_product,hr_expense.group_hr_expense_user,1,1,1,1 access_product_template_hr_expense_user,product.template.hr.expense.user,product.model_product_template,hr_expense.group_hr_expense_user,1,1,1,1 access_uom_uom_hr_expense_user,uom.uom.hr.expense.user,uom.model_uom_uom,hr_expense.group_hr_expense_user,1,1,1,1 diff --git a/addons/hr_expense/static/src/js/tour.js b/addons/hr_expense/static/src/js/tour.js index 7f53ae364cc..b5c63c5186a 100644 --- a/addons/hr_expense/static/src/js/tour.js +++ b/addons/hr_expense/static/src/js/tour.js @@ -15,20 +15,19 @@ tour.register('hr_expense_tour' , trigger: '.o_app[data-menu-xmlid="hr_expense.menu_hr_expense_root"], .oe_menu_toggler[data-menu-xmlid="hr_expense.menu_hr_expense_root"]', content: _t("Want to manage your expenses? It starts here."), position: 'bottom', -}, { - trigger: '.o_list_button_add', - extra_trigger: ".o_expense_tree", - content: _t('
Let’s start by creating your first expense.
'), - position: 'bottom' }, { trigger: '.o_form_button_save', - extra_trigger: ".o_expense_sheet", - content: _t("Once your Expense report is ready, you can save it and wait for the approval from your manager.
"), + content: _t("Once your Expense is ready, you can save it.
"), position: 'bottom', }, { - trigger: '.o_expense_form .o_chatter_button_new_message', + trigger: '.o_attach_document', content: _t("Attach your receipt here."), - position: 'top', + position: 'bottom', +}, { + trigger: '.o_expense_submit', + extra_triggger: ".o_expense_form", + content: _t('Click on Create Report to create the report.
'), + position: 'right', }, { trigger: '.o_expense_tree .o_checkbox > input[type=checkbox]', content: _t('Select expenses to submit them to your manager
'), @@ -36,11 +35,15 @@ tour.register('hr_expense_tour' , }, { trigger: '.o_dropdown_toggler_btn', extra_trigger: ".o_expense_tree", - content: _t('Click on Action Submit To Manager to submit selected expenses to your manager
'), + content: _t('Click on Action Create Report to submit selected expenses to your manager
'), position: 'right', +}, { + trigger: '.o_expense_sheet_submit', + content: _t('Once your Expense report is ready, you can submit it to your manager and wait for the approval from your manager.'), + position: 'bottom', }, { trigger: '.o_expense_sheet_approve', - content: _t("Approve the sheet here.
Tip: if you refuse, don’t forget to give the reason thanks to the hereunder message tool
"), + content: _t("Approve the report here.
Tip: if you refuse, don’t forget to give the reason thanks to the hereunder message tool
"), position: 'bottom', }, { trigger: '.o_expense_sheet_post', diff --git a/addons/hr_expense/tests/test_expenses.py b/addons/hr_expense/tests/test_expenses.py index 8d526b02a36..485b5dac6e0 100644 --- a/addons/hr_expense/tests/test_expenses.py +++ b/addons/hr_expense/tests/test_expenses.py @@ -43,7 +43,10 @@ class TestAccountEntry(TestExpenseCommon): 'analytic_account_id': self.analytic_account.id, }) expense_line._onchange_product_id() + # State should default to draft + self.assertEquals(expense.state, 'draft', 'Expense should be created in Draft state') # Submitted to Manager + expense.action_submit_sheet() self.assertEquals(expense.state, 'submit', 'Expense is not in Reported state') # Approve expense.approve_expense_sheets() diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml index 6176b2057d5..4ba5028ca18 100644 --- a/addons/hr_expense/views/hr_expense_views.xml +++ b/addons/hr_expense/views/hr_expense_views.xml @@ -43,10 +43,10 @@