Merge pull request #6 from jaredkipe/WIP/11/hr_expense_change

HR Expense Change (with Analytic)
This commit is contained in:
Jared Kipe
2018-11-22 13:33:51 -07:00
committed by GitHub
14 changed files with 304 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import wizard

View File

@@ -0,0 +1,30 @@
{
'name': 'HR Expense Change',
'author': 'Hibou Corp. <hello@hibou.io>',
'version': '11.0.1.0.0',
'category': 'Employees',
'sequence': 95,
'summary': 'Technical foundation for changing expenses.',
'description': """
Technical foundation for changing expenses.
Creates wizard and permissions for making expense changes that can be
handled by other individual modules.
This module implements, as examples, how to change the Date fields.
Abstractly, individual 'changes' should come from specific 'fields' or capability
modules that handle the consequences of changing that field in whatever state the
the invoice is currently in.
""",
'website': 'https://hibou.io/',
'depends': [
'hr_expense',
],
'data': [
'wizard/expense_change_views.xml',
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1 @@
from . import test_expense_change

View File

@@ -0,0 +1,20 @@
from odoo.addons.hr_expense.tests.test_expenses import TestCheckJournalEntry
class TestExpenseChange(TestCheckJournalEntry):
def test_expense_change_basic(self):
# posts expense and gets move ready at self.expense.account_move_id.id
self.test_journal_entry()
self.assertEqual(self.expense.expense_line_ids.date, self.expense.account_move_id.date)
ctx = {'active_model': 'hr.expense', 'active_ids': self.expense.expense_line_ids.ids}
change = self.env['hr.expense.change'].with_context(ctx).create({})
self.assertEqual(change.date, self.expense.expense_line_ids.date)
change_date = '2018-01-01'
change.write({'date': change_date})
change.affect_change()
self.assertEqual(change_date, self.expense.expense_line_ids.date)
self.assertEqual(change_date, self.expense.account_move_id.date)

View File

@@ -0,0 +1 @@
from . import expense_change

View File

@@ -0,0 +1,55 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class ExpenseChangeWizard(models.TransientModel):
_name = 'hr.expense.change'
_description = 'Expense Change'
expense_id = fields.Many2one('hr.expense', string='Expense', readonly=True, required=True)
expense_company_id = fields.Many2one('res.company', related='expense_id.company_id')
date = fields.Date(string='Expense Date')
@api.model
def default_get(self, fields):
rec = super(ExpenseChangeWizard, self).default_get(fields)
context = dict(self._context or {})
active_model = context.get('active_model')
active_ids = context.get('active_ids')
# Checks on context parameters
if not active_model or not active_ids:
raise UserError(
_("Programmation error: wizard action executed without active_model or active_ids in context."))
if active_model != 'hr.expense':
raise UserError(_(
"Programmation error: the expected model for this action is 'hr.expense'. The provided one is '%d'.") % active_model)
# Checks on received expense records
expense = self.env[active_model].browse(active_ids)
if len(expense) != 1:
raise UserError(_("Expense Change expects only one expense."))
rec.update({
'expense_id': expense.id,
'date': expense.date,
})
return rec
def _new_expense_vals(self):
vals = {}
if self.expense_id.date != self.date:
vals['date'] = self.date
return vals
@api.multi
def affect_change(self):
self.ensure_one()
vals = self._new_expense_vals()
old_date = self.expense_id.date
if vals:
self.expense_id.write(vals)
if 'date' in vals and self.expense_id.sheet_id.account_move_id:
self.expense_id.sheet_id.account_move_id.write({'date': vals['date']})
self.expense_id.sheet_id.account_move_id.line_ids\
.filtered(lambda l: l.date_maturity == old_date).write({'date_maturity': vals['date']})
return True

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="hr_expense_change_form" model="ir.ui.view">
<field name="name">Expense Change</field>
<field name="model">hr.expense.change</field>
<field name="arch" type="xml">
<form string="Expense Change">
<group>
<group name="group_left">
<field name="expense_id" invisible="1"/>
<field name="expense_company_id" invisible="1"/>
<field name="date"/>
</group>
<group name="group_right"/>
</group>
<footer>
<button name="affect_change" string="Change" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_view_hr_expense_change" model="ir.actions.act_window">
<field name="name">Expense Change Wizard</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">hr.expense.change</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Add Button to Existing Forms -->
<record id="hr_expense_form_view_inherit" model="ir.ui.view">
<field name="name">hr.expense.form.inherit</field>
<field name="model">hr.expense</field>
<field name="inherit_id" ref="hr_expense.hr_expense_form_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="before">
<button name="%(action_view_hr_expense_change)d" string="Change"
type="action" class="btn-secondary"
attrs="{'invisible': [('state', 'in', ('draft', 'refused'))]}"
context="{'default_expense_id': active_id}"
groups="account.group_account_manager" />
</xpath>
</field>
</record>
<record id="view_hr_expense_sheet_form_inherit" model="ir.ui.view">
<field name="name">hr.expense.sheet.form.inherit</field>
<field name="model">hr.expense.sheet</field>
<field name="inherit_id" ref="hr_expense.view_hr_expense_sheet_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='expense_line_ids']/tree" position="inside">
<field name="id" invisible="1"/>
<button name="%(action_view_hr_expense_change)d" string="Change" icon="fa-exchange"
type="action"
attrs="{'invisible': [('state', 'in', ('draft', 'refused'))]}"
context="{'default_expense_id': id}"
groups="account.group_account_manager" />
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
from . import wizard

View File

@@ -0,0 +1,23 @@
{
'name': 'HR Expense Change - Analytic',
'author': 'Hibou Corp. <hello@hibou.io>',
'version': '11.0.1.0.0',
'category': 'Employees',
'sequence': 96,
'summary': 'Change Analytic Account on Expense.',
'description': """
Adds fields and functionality to change the analytic account on expense
and subsequent documents.
""",
'website': 'https://hibou.io/',
'depends': [
'hr_expense_change',
'analytic',
],
'data': [
'wizard/expense_change_views.xml',
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1 @@
from . import test_expense_change

View File

@@ -0,0 +1,33 @@
from odoo.addons.hr_expense_change.tests.test_expense_change import TestExpenseChange
class TestWizard(TestExpenseChange):
def test_expense_change_basic(self):
self.analytic_account = self.env['account.analytic.account'].create({
'name': 'test account',
})
self.analytic_account2 = self.env['account.analytic.account'].create({
'name': 'test account2',
})
self.expense.expense_line_ids.write({'analytic_account_id': False})
super(TestWizard, self).test_expense_change_basic()
# Tests Adding an Analytic Account
self.assertFalse(self.expense.expense_line_ids.analytic_account_id)
ctx = {'active_model': 'hr.expense', 'active_ids': self.expense.expense_line_ids.ids}
change = self.env['hr.expense.change'].with_context(ctx).create({})
change.analytic_account_id = self.analytic_account
change.affect_change()
self.assertEqual(self.expense.expense_line_ids.analytic_account_id, self.analytic_account)
# Tests Changing
change.analytic_account_id = self.analytic_account2
change.affect_change()
self.assertEqual(self.expense.expense_line_ids.analytic_account_id, self.analytic_account2)
# Tests Removing
change.analytic_account_id = False
change.affect_change()
self.assertFalse(self.expense.expense_line_ids.analytic_account_id)

View File

@@ -0,0 +1 @@
from . import expense_change

View File

@@ -0,0 +1,57 @@
from odoo import api, fields, models, _
class ExpenseChangeWizard(models.TransientModel):
_inherit = 'hr.expense.change'
analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account')
analytic_account_warning = fields.Char(string='Analytic Account Warning', compute='_compute_analytic_warning')
@api.model
def default_get(self, fields):
rec = super(ExpenseChangeWizard, self).default_get(fields)
expense = self.env['hr.expense'].browse(rec['expense_id'])
rec.update({
'analytic_account_id': expense.analytic_account_id.id,
})
return rec
@api.onchange('expense_id', 'analytic_account_id')
@api.multi
def _compute_analytic_warning(self):
self.ensure_one()
expenses = self._find_expenses_to_write_analytic(self.expense_id.analytic_account_id.id)
if len(expenses) <= 1:
self.analytic_account_warning = ''
else:
other_expenses = expenses - self.expense_id
self.analytic_account_warning = '%d other expenses will be changed. (%s)' % \
(len(other_expenses), ', '.join(other_expenses.mapped('name')))
@api.multi
def affect_change(self):
old_analytic_id = self.expense_id.analytic_account_id.id
res = super(ExpenseChangeWizard, self).affect_change()
self._affect_analytic_change(old_analytic_id)
return res
def _find_expenses_to_write_analytic(self, old_analytic_id):
if self.analytic_account_id.id == old_analytic_id:
return []
# Essentially, if you have a move, you must write all related expenses and lines.
if not self.expense_id.sheet_id.account_move_id:
return self.expense_id
return self.expense_id.sheet_id.expense_line_ids\
.filtered(lambda l: l.analytic_account_id.id == old_analytic_id)
def _affect_analytic_change(self, old_analytic_id):
expenses_to_affect = self._find_expenses_to_write_analytic(old_analytic_id)
if expenses_to_affect:
expenses_to_affect.write({'analytic_account_id': self.analytic_account_id.id})
lines_to_affect = self.expense_id.sheet_id.account_move_id \
.line_ids.filtered(lambda l: l.analytic_account_id.id == old_analytic_id and l.debit)
lines_to_affect.write({'analytic_account_id': self.analytic_account_id.id})
lines_to_affect.create_analytic_lines()

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="hr_expense_change_form_inherit" model="ir.ui.view">
<field name="name">hr.expense.change.form.inherit</field>
<field name="model">hr.expense.change</field>
<field name="inherit_id" ref="hr_expense_change.hr_expense_change_form"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='group_right']" position="inside">
<field name="analytic_account_id" domain="[('company_id', '=', expense_company_id)]"/>
<field name="analytic_account_warning" attrs="{'invisible': [('analytic_account_warning', '=', '')]}"/>
</xpath>
</field>
</record>
</odoo>