Merge lp:~camptocamp/account-invoicing/7.0-account_invoice_zero into lp:~account-core-editors/account-invoicing/7.0

Proposed by Guewen Baconnier @ Camptocamp
Status: Merged
Approved by: Yannick Vaucher @ Camptocamp
Approved revision: 42
Merged at revision: 42
Proposed branch: lp:~camptocamp/account-invoicing/7.0-account_invoice_zero
Merge into: lp:~account-core-editors/account-invoicing/7.0
Diff against target: 215 lines (+189/-0)
5 files modified
account_invoice_zero/__init__.py (+3/-0)
account_invoice_zero/__openerp__.py (+52/-0)
account_invoice_zero/account_invoice.py (+50/-0)
account_invoice_zero/test/account_invoice_no_zero_open.yml (+40/-0)
account_invoice_zero/test/account_invoice_zero_paid.yml (+44/-0)
To merge this branch: bzr merge lp:~camptocamp/account-invoicing/7.0-account_invoice_zero
Reviewer Review Type Date Requested Status
Pedro Manuel Baeza code review Approve
Vincent Renaville@camptocamp (community) Approve
Yannick Vaucher @ Camptocamp code review Approve
Review via email: mp+210215@code.launchpad.net

Commit message

add account_invoice_zero: automatically set invoices with a zero amount to 'paid'

Description of the change

Invoices with a amount of 0 are automatically set as paid.

When an invoice has an amount of 0, OpenERP still generates a
receivable/payable move line with a 0 balance. The invoice stays as
open even if there is nothing to pay. The user has 2 ways to set the
invoice as paid: create a payment of 0 and reconcile the line with the
payment or reconcile the receivable/payable move line with itself.
This module takes the latter approach and will directly set the invoice
as paid once it is opened.

To post a comment you must log in.
Revision history for this message
Vincent Renaville@camptocamp (vrenaville-c2c) wrote :

Hello,

Juste question at line 109

I don't know if it's better to use float_compare method with precision

prec = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
not float_compare(debit, credit, precision_digits=prec)

Vincent

review: Needs Information
42. By Guewen Baconnier @ Camptocamp

use float comparisons

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> Hello,
>
> Juste question at line 109
>
> I don't know if it's better to use float_compare method with precision
>
> prec = self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')
> not float_compare(debit, credit, precision_digits=prec)
>
> Vincent

Thanks for the review. I made the change, but used float_is_zero.

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Guewen, I'm curious about the use case for having 0 amount invoices.

review: Needs Information
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

Pedro,

This can be the case when a customer order a product and has a reduction that makes it at 0.

The Sale Order will generate an invoice even if the price is 0.

Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

LGTM

review: Approve (code review)
Revision history for this message
Vincent Renaville@camptocamp (vrenaville-c2c) wrote :

LGTM

review: Approve
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Guewen, thanks for the clarification. Here in Spain that operation is forbidden by law (because you need at least declare taxes for the amount).

Regards.

review: Approve (code review)
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

> Hi, Guewen, thanks for the clarification. Here in Spain that operation is
> forbidden by law (because you need at least declare taxes for the amount).
>
> Regards.

Interesting.

For my curiosity, if you have a sale line with 100€ taxes included and you add a second line with a rebate of -100€ taxes include too what happens? Can't happen so?

Here, the total amount is 0, the invoice still have move lines for the taxes but they are balanced by the rebate.

Example: ("TVA" are the taxes, "Bons de rabais" are discounts)
http://postimg.org/image/95bb6lgl1/
http://postimg.org/image/95bb6lgl1/

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Twice the same image, here is the second one with the move details.
http://postimg.org/image/k9bx94w17/

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Guewen, the case you told it's also forbidden. Let me explain: the only official mechanism for compensating invoices is via refunds. You don't need to make cash flows, but you need to have both documents. That is theoretically. In practice, if you have an amount to compensate (a potential refund) that is lower than the amount of the invoice, it's a common and tolerated practise to discount it from the invoice, but never if the amount is equal.

I hope I explain it well.

Regards.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

On 03/14/2014 11:06 AM, Pedro Manuel Baeza wrote:
> Hi, Guewen, the case you told it's also forbidden. Let me explain: the only official mechanism for compensating invoices is via refunds. You don't need to make cash flows, but you need to have both documents. That is theoretically. In practice, if you have an amount to compensate (a potential refund) that is lower than the amount of the invoice, it's a common and tolerated practise to discount it from the invoice, but never if the amount is equal.
>
> I hope I explain it well.
>
> Regards.
>

Good to know!
Thanks for the explanation.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'account_invoice_zero'
=== added file 'account_invoice_zero/__init__.py'
--- account_invoice_zero/__init__.py 1970-01-01 00:00:00 +0000
+++ account_invoice_zero/__init__.py 2014-03-10 14:45:38 +0000
@@ -0,0 +1,3 @@
1# -*- coding: utf-8 -*-
2
3from . import account_invoice
04
=== added file 'account_invoice_zero/__openerp__.py'
--- account_invoice_zero/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_invoice_zero/__openerp__.py 2014-03-10 14:45:38 +0000
@@ -0,0 +1,52 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2014 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22{'name': 'Account Invoice Zero',
23 'version': '1.0',
24 'author': 'Camptocamp',
25 'maintainer': 'Camptocamp',
26 'license': 'AGPL-3',
27 'category': 'Accounting & Finance',
28 'depends': ['account',
29 ],
30 'description': """
31Account Invoice Zero
32====================
33
34Invoices with a amount of 0 are automatically set as paid.
35
36When an invoice has an amount of 0, OpenERP still generates a
37receivable/payable move line with a 0 balance. The invoice stays as
38open even if there is nothing to pay. The user has 2 ways to set the
39invoice as paid: create a payment of 0 and reconcile the line with the
40payment or reconcile the receivable/payable move line with itself.
41This module takes the latter approach and will directly set the invoice
42as paid once it is opened.
43
44 """,
45 'website': 'http://www.camptocamp.com',
46 'data': [],
47 'test': ['test/account_invoice_zero_paid.yml',
48 'test/account_invoice_no_zero_open.yml',
49 ],
50 'installable': True,
51 'auto_install': False,
52}
053
=== added file 'account_invoice_zero/account_invoice.py'
--- account_invoice_zero/account_invoice.py 1970-01-01 00:00:00 +0000
+++ account_invoice_zero/account_invoice.py 2014-03-10 14:45:38 +0000
@@ -0,0 +1,50 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Author: Guewen Baconnier
5# Copyright 2014 Camptocamp SA
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22from functools import partial
23
24from openerp.osv import orm
25from openerp.tools.float_utils import float_is_zero
26
27
28class account_invoice(orm.Model):
29 _inherit = 'account.invoice'
30
31 def invoice_validate(self, cr, uid, ids, context=None):
32 result = super(account_invoice, self).invoice_validate(
33 cr, uid, ids, context=context)
34 dp_obj = self.pool['decimal.precision']
35 precision = dp_obj.precision_get(cr, uid, 'Account')
36 is_zero = partial(float_is_zero, precision_digits=precision)
37 for invoice in self.browse(cr, uid, ids, context=context):
38 if is_zero(invoice.amount_total):
39 account = invoice.account_id.id
40 # search the payable / receivable lines
41 lines = [line for line in invoice.move_id.line_id
42 if line.account_id.id == account]
43 # reconcile the lines with a zero balance
44 if is_zero(sum(line.debit - line.credit for line in lines)):
45 move_line_obj = self.pool['account.move.line']
46 move_line_obj.reconcile(cr, uid,
47 [line.id for line in lines],
48 context=context)
49 return result
50
051
=== added directory 'account_invoice_zero/test'
=== added file 'account_invoice_zero/test/account_invoice_no_zero_open.yml'
--- account_invoice_zero/test/account_invoice_no_zero_open.yml 1970-01-01 00:00:00 +0000
+++ account_invoice_zero/test/account_invoice_no_zero_open.yml 2014-03-10 14:45:38 +0000
@@ -0,0 +1,40 @@
1-
2 In order to test that the invoices with an amount still behave normally, I create on invoice
3-
4 !record {model: account.invoice, id: account_invoice_state}:
5 account_id: account.a_recv
6 company_id: base.main_company
7 currency_id: base.EUR
8 invoice_line:
9 - account_id: account.a_sale
10 name: '[PCSC234] PC Assemble SC234'
11 price_unit: 450.0
12 quantity: 1.0
13 product_id: product.product_product_3
14 uos_id: product.product_uom_unit
15 journal_id: account.bank_journal
16 partner_id: base.res_partner_12
17 reference_type: none
18-
19 I check that Initially customer invoice state is "Draft"
20-
21 !assert {model: account.invoice, id: account_invoice_state}:
22 - state == 'draft'
23-
24 I called the "Confirm Draft Invoices" wizard
25-
26 !record {model: account.invoice.confirm, id: account_invoice_confirm_0}:
27 {}
28-
29 I clicked on Confirm Invoices Button
30-
31 !python {model: account.invoice.confirm}: |
32 self.invoice_confirm(cr, uid, [ref("account_invoice_confirm_0")], {"lang": 'en_US',
33 "tz": False, "active_model": "account.invoice", "active_ids": [ref("account_invoice_state")],
34 "type": "out_invoice", "active_id": ref("account_invoice_state"), })
35-
36 I check that customer invoice state is "Open"
37-
38 !assert {model: account.invoice, id: account_invoice_state}:
39 - state == 'open'
40
041
=== added file 'account_invoice_zero/test/account_invoice_zero_paid.yml'
--- account_invoice_zero/test/account_invoice_zero_paid.yml 1970-01-01 00:00:00 +0000
+++ account_invoice_zero/test/account_invoice_zero_paid.yml 2014-03-10 14:45:38 +0000
@@ -0,0 +1,44 @@
1-
2 In order to test that an invoice with a zero amount is directly paid, I create an invoice
3-
4 !record {model: account.invoice, id: account_invoice_zero_paid}:
5 account_id: account.a_recv
6 company_id: base.main_company
7 currency_id: base.EUR
8 invoice_line:
9 - account_id: account.a_sale
10 name: '[PCSC234] PC Assemble SC234'
11 price_unit: 120.0
12 quantity: 1.0
13 product_id: product.product_product_3
14 uos_id: product.product_uom_unit
15 - account_id: account.a_sale
16 name: discount
17 price_unit: -120.0
18 quantity: 1.0
19 uos_id: product.product_uom_unit
20 journal_id: account.bank_journal
21 partner_id: base.res_partner_12
22 reference_type: none
23-
24 I check that Initially customer invoice state is "Draft"
25-
26 !assert {model: account.invoice, id: account_invoice_zero_paid}:
27 - state == 'draft'
28-
29 I called the "Confirm Draft Invoices" wizard
30-
31 !record {model: account.invoice.confirm, id: account_invoice_confirm_0}:
32 {}
33-
34 I clicked on Confirm Invoices Button
35-
36 !python {model: account.invoice.confirm}: |
37 self.invoice_confirm(cr, uid, [ref("account_invoice_confirm_0")], {"lang": 'en_US',
38 "tz": False, "active_model": "account.invoice", "active_ids": [ref("account_invoice_zero_paid")],
39 "type": "out_invoice", "active_id": ref("account_invoice_zero_paid"), })
40-
41 I check that customer invoice state is "Paid"
42-
43 !assert {model: account.invoice, id: account_invoice_zero_paid}:
44 - state == 'paid'

Subscribers

People subscribed via source and target branches