Skip to content

Commit

Permalink
[IMP] allow changing allocated account
Browse files Browse the repository at this point in the history
  • Loading branch information
robinkeunen committed Jan 4, 2019
1 parent 79d89f4 commit 1e00ad2
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 0 deletions.
1 change: 1 addition & 0 deletions invoice_correction/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import models
20 changes: 20 additions & 0 deletions invoice_correction/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

{
"name": "Account - Invoice Correction",
"summary": "Correction of taxes and account on invoice",
'description': "This module allow the account manager to correct invoice already validated",
"version": "9.0.1.0.0",
"license": "AGPL-3",
"author": "Coopiteasy",
"website": "http://www.coopiteasy.be",
'category': 'Accounting',
"depends": [
"account",
],
"data": [
'views/invoice.xml'
],
"installable": True,
}
1 change: 1 addition & 0 deletions invoice_correction/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import account
121 changes: 121 additions & 0 deletions invoice_correction/models/account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
from openerp import models, api, fields, _
from openerp.exceptions import UserError, ValidationError
from openerp.tools import float_compare

class AccountInvoice(models.Model):
_inherit = 'account.invoice'

correction = fields.Boolean("Correction Mode", copy=False)
invoice_line_ids = fields.One2many(readonly=False)
tax_line_ids = fields.One2many(readonly=False)
account_id = fields.Many2one(readonly=False)
origin_account_id = fields.Many2one('account.account', readonly=True)

def init(self, cr):
cr.execute("UPDATE account_invoice SET origin_account_id = account_id WHERE state in ('open', 'paid') AND origin_account_id IS NULL;")


@api.multi
def write(self, vals):
price_per_id = {rec.id : rec.amount_total for rec in self}

res = super(AccountInvoice, self).write(vals)
for rec in self:
if rec.state in ['open', 'paid'] and float_compare(
rec.amount_total,
price_per_id[rec.id],
precision_rounding=rec.currency_id.rounding) != 0:
raise ValidationError(_('You cannot change the amount of a validated invoice'))
return res

@api.multi
def invoice_validate(self):
""" Overwrite to keep track of the account_id set at validation """
for rec in self:
rec.origin_account_id = rec.account_id
return super(AccountInvoice, self).invoice_validate()

@api.multi
def start_correction(self):
self.ensure_one()
if not self.env.user.has_group('account.group_account_manager'):
raise UserError(_("Only Account/ Adviser user can start the correction of an invoice"))
self.correction = True

@api.multi
def validate_correction(self):
self.ensure_one()
if not self.env.user.has_group('account.group_account_manager'):
raise UserError(_("Only Account/ Adviser user can validate the correction of an invoice"))

main_move = self.env['account.move.line']
to_delete_move = self.env['account.move.line']
for move_line in self.move_id.line_ids:
if move_line.account_id == self.origin_account_id:
main_move |= move_line
else:
to_delete_move |= move_line

#1 Move in draft and reconcile entry inactive
reconcile = (self.move_id.line_ids.mapped('matched_debit_ids') | self.move_id.line_ids.mapped('matched_credit_ids'))
reconcile.write({'active': False})
self.invalidate_cache()
self.move_id.write({'state': 'draft'})
#2 Main move change account_id
main_move.write({'account_id': self.account_id.id})
#3 prepare line to delete
m2m_command = [(2, rec.id, 0) for rec in to_delete_move]
#4 prepate line to create
iml = self.invoice_line_move_line_get() + self.tax_line_move_line_get()
_, _, iml = self.compute_invoice_totals(self.company_id.currency_id, iml)
part = self.env['res.partner']._find_accounting_partner(self.partner_id)
line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml]
line = self.group_lines(iml, line)
line = self.finalize_invoice_move_lines(line)
m2m_command += line
self.move_id.with_context(check_move_validity=False, dont_create_taxes=True).write({'line_ids': m2m_command})
#5 Back to posted
reconcile.write({'active': True})
self.invalidate_cache()
self.move_id.write({'state': 'posted'})
#6 Clean correction
self.write({
'origin_account_id' : self.account_id.id,
'correction': False,
})

class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'

correction = fields.Boolean(related='invoice_id.correction', readonly=True)
state = fields.Selection(related='invoice_id.state', default='draft')
#Make all these fields readonly when the invoice is not in draft
price_unit = fields.Float(readonly=True, states={'draft': [('readonly', False)]})
product_id = fields.Many2one(readonly=True, states={'draft': [('readonly', False)]})
name = fields.Char(readonly=True, states={'draft': [('readonly', False)]})
quantity = fields.Float(readonly=True, states={'draft': [('readonly', False)]})

@api.multi
def write(self, vals):
price_per_id = {rec.id : rec.price_subtotal for rec in self}
res = super(AccountInvoiceLine, self).write(vals)
for rec in self:
if rec.state in ['open', 'paid'] and float_compare(
rec.price_subtotal,
price_per_id[rec.id],
precision_rounding=rec.currency_id.rounding) != 0:
raise ValidationError(_('You cannot change the amount of a validated invoice'))
return res

@api.multi
def unlink(self):
if any([s in ['open', 'paid'] for s in self.mapped('state')]):
raise ValidationError(_('You cannot delete a invoice line from a confirmed invoice'))
return super(AccountInvoiceLine, self)


class AccountPartialReconcile(models.Model):
_inherit = "account.partial.reconcile"

active = fields.Boolean(default=True)
92 changes: 92 additions & 0 deletions invoice_correction/views/invoice.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="invoice_correction_form" model="ir.ui.view">
<field name="name">Invoice Correction Form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form" />
<field name="arch" type="xml">
<xpath expr="//button[@name='action_cancel_draft']" position="after">
<button name="start_correction" string="Start Correction"
type="object" groups="account.group_account_manager"
attrs="{'invisible': ['|', ('state', 'not in', ['open', 'paid']), ('correction', '=', True)]}" />
<button name="validate_correction" string="Validate Correction"
type="object" groups="account.group_account_manager"
attrs="{'invisible': ['|', ('state', 'not in', ['open', 'paid']), ('correction', '=', False)]}" />
</xpath>
<xpath expr="//field[@name='date_invoice']" position="after">
<field name="correction" invisible="1" />
<field name="origin_account_id" invisible="1" />
</xpath>
<xpath expr="//field[@name='invoice_line_ids']" position="attributes">
<attribute name="attrs">{'readonly': [('correction', '=', False), ('state', 'in', ['open', 'paid'])]}</attribute>
</xpath>
<xpath expr="//field[@name='move_id']/../field[@name='account_id']" position="attributes">
<attribute name="attrs">{'readonly': [('correction', '=', False), ('state', 'in', ['open', 'paid'])]}</attribute>
</xpath>
<xpath expr="//field[@name='tax_line_ids']" position="attributes">
<attribute name="attrs">{'readonly': [('correction', '=', False), ('state', 'in', ['open', 'paid'])]}</attribute>
</xpath>
<xpath expr="//form//tree" position="inside">
<field name="correction" invisible="1" />
<field name="state" invisible="1" />
</xpath>
</field>
</record>

<record id="invoice_line_correction_form" model="ir.ui.view">
<field name="name">Invoice Line Correction Form</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_form" />
<field name="arch" type="xml">
<xpath expr="//form" position="inside">
<field name="state" invisible="1" />
</xpath>
</field>
</record>

<record id="invoice_line_correction_tree" model="ir.ui.view">
<field name="name">Invoice Line Correction Tree</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_tree" />
<field name="arch" type="xml">
<xpath expr="//tree" position="inside">
<field name="state" invisible="1" />
</xpath>
</field>
</record>

<record id="invoice_correction_form_supplier" model="ir.ui.view">
<field name="name">Invoice Correction Form Supplier</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form" />
<field name="arch" type="xml">
<xpath expr="//button[@name='action_cancel_draft']" position="after">
<button name="start_correction" string="Start Correction"
type="object" groups="account.group_account_manager"
attrs="{'invisible': ['|', ('state', 'not in', ['open', 'paid']), ('correction', '=', True)]}" />
<button name="validate_correction" string="Validate Correction"
type="object" groups="account.group_account_manager"
attrs="{'invisible': ['|', ('state', 'not in', ['open', 'paid']), ('correction', '=', False)]}" />
</xpath>
<xpath expr="//field[@name='date_invoice']" position="after">
<field name="correction" invisible="1" />
<field name="origin_account_id" invisible="1" />
</xpath>
<xpath expr="//field[@name='invoice_line_ids']" position="attributes">
<attribute name="attrs">{'readonly': [('correction', '=', False), ('state', 'in', ['open', 'paid'])]}</attribute>
</xpath>
<xpath expr="//field[@name='journal_id']/../field[@name='account_id']" position="attributes">
<attribute name="attrs">{'readonly': [('correction', '=', False), ('state', 'in', ['open', 'paid'])]}</attribute>
</xpath>
<xpath expr="//field[@name='tax_line_ids']" position="attributes">
<attribute name="attrs">{'readonly': [('correction', '=', False), ('state', 'in', ['open', 'paid'])]}</attribute>
</xpath>
<xpath expr="//form//tree" position="inside">
<field name="correction" invisible="1" />
<field name="state" invisible="1" />
</xpath>
</field>
</record>


</odoo>

0 comments on commit 1e00ad2

Please sign in to comment.