Merge lp:~therp-nl/openobject-addons/7.0-lp1080840-wrong_amounts_on_refund_vouchers into lp:openobject-addons

Proposed by Stefan Rijnhart (Opener)
Status: Needs review
Proposed branch: lp:~therp-nl/openobject-addons/7.0-lp1080840-wrong_amounts_on_refund_vouchers
Merge into: lp:openobject-addons
Diff against target: 243 lines (+60/-36)
2 files modified
account_voucher/account_voucher.py (+59/-36)
account_voucher/test/account_voucher.yml (+1/-0)
To merge this branch: bzr merge lp:~therp-nl/openobject-addons/7.0-lp1080840-wrong_amounts_on_refund_vouchers
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+135774@code.launchpad.net

Description of the change

Sorry for this stop-gap patch. It is the result of several weaknesses in the design of the voucher model:

- using the same functions for purchase/sale vouchers as for payment/receipt vouchers
- in doing so, using 'amount' (and in some cases its sign logic) as a given for payment/receipt vouchers and as a resulting sum in the case of purchase/sale vouchers
- allowing for both negative amounts on voucher lines as well as a debit/credit selection (without taking them into account consistently)
- insisting on showing the total voucher amount [1] with a positive sign and [2] before saving the voucher (i.e. using only on_change methods)

The voucher module is in dire need of a refactoring, in which API changes may be unavoidable. Hopefully that can be realized in 7.1.

This branch validates all the YAML tests included in the addon. I actually developed tests for this particular bug, but in order to run them I had to add a number of invisible fields to account_voucher.view_voucher_form because these are returned by the various on_change methods causing a YAML exception. I guess that shows how broken this addon actually is. You can find a version of this branch containing the tests here: https://code.launchpad.net/~therp-nl/openobject-addons/7.0-lp1080840-wrong_amounts_on_refund_vouchers_with_tests

To post a comment you must log in.

Unmerged revisions

8078. By Stefan Rijnhart (Opener)

[FIX] account_voucher: wrong amounts with refunds using debet/credit field

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account_voucher/account_voucher.py'
--- account_voucher/account_voucher.py 2012-11-15 12:38:51 +0000
+++ account_voucher/account_voucher.py 2012-11-22 20:47:25 +0000
@@ -299,6 +299,7 @@
299 \n* The \'Posted\' status is used when user create voucher,a voucher number is generated and voucher entries are created in account \299 \n* The \'Posted\' status is used when user create voucher,a voucher number is generated and voucher entries are created in account \
300 \n* The \'Cancelled\' status is used when user cancel voucher.'),300 \n* The \'Cancelled\' status is used when user cancel voucher.'),
301 'amount': fields.float('Total', digits_compute=dp.get_precision('Account'), required=True, readonly=True, states={'draft':[('readonly',False)]}),301 'amount': fields.float('Total', digits_compute=dp.get_precision('Account'), required=True, readonly=True, states={'draft':[('readonly',False)]}),
302 'amount_signed': fields.float('Total (signed)', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}),
302 'tax_amount':fields.float('Tax Amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}),303 'tax_amount':fields.float('Tax Amount', digits_compute=dp.get_precision('Account'), readonly=True, states={'draft':[('readonly',False)]}),
303 'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."),304 'reference': fields.char('Ref #', size=64, readonly=True, states={'draft':[('readonly',False)]}, help="Transaction reference number."),
304 'number': fields.char('Number', size=32, readonly=True,),305 'number': fields.char('Number', size=32, readonly=True,),
@@ -365,13 +366,16 @@
365366
366 for voucher in voucher_pool.browse(cr, uid, ids, context=context):367 for voucher in voucher_pool.browse(cr, uid, ids, context=context):
367 voucher_amount = 0.0368 voucher_amount = 0.0
369 if voucher.type in ('payment', 'receipt'):
370 continue
371
368 for line in voucher.line_ids:372 for line in voucher.line_ids:
369 voucher_amount += line.untax_amount or line.amount373 voucher_amount += (line.type == 'dr' and 1 or -1) * (line.untax_amount or line.amount)
370 line.amount = line.untax_amount or line.amount374 line.amount = line.untax_amount or line.amount
371 voucher_line_pool.write(cr, uid, [line.id], {'amount':line.amount, 'untax_amount':line.untax_amount})375 voucher_line_pool.write(cr, uid, [line.id], {'amount':line.amount, 'untax_amount':line.untax_amount})
372376
373 if not voucher.tax_id:377 if not voucher.tax_id:
374 self.write(cr, uid, [voucher.id], {'amount':voucher_amount, 'tax_amount':0.0})378 self.write(cr, uid, [voucher.id], {'amount': abs(voucher_amount), 'amount_signed': voucher_amount, 'tax_amount':0.0})
375 continue379 continue
376380
377 tax = [tax_pool.browse(cr, uid, voucher.tax_id.id, context=context)]381 tax = [tax_pool.browse(cr, uid, voucher.tax_id.id, context=context)]
@@ -385,7 +389,7 @@
385 if not tax[0].price_include:389 if not tax[0].price_include:
386 for line in voucher.line_ids:390 for line in voucher.line_ids:
387 for tax_line in tax_pool.compute_all(cr, uid, tax, line.amount, 1).get('taxes', []):391 for tax_line in tax_pool.compute_all(cr, uid, tax, line.amount, 1).get('taxes', []):
388 total_tax += tax_line.get('amount', 0.0)392 total_tax += (line.type == 'dr' and 1 or -1) * tax_line.get('amount', 0.0)
389 total += total_tax393 total += total_tax
390 else:394 else:
391 for line in voucher.line_ids:395 for line in voucher.line_ids:
@@ -393,13 +397,13 @@
393 line_tax = 0.0397 line_tax = 0.0
394398
395 for tax_line in tax_pool.compute_all(cr, uid, tax, line.untax_amount or line.amount, 1).get('taxes', []):399 for tax_line in tax_pool.compute_all(cr, uid, tax, line.untax_amount or line.amount, 1).get('taxes', []):
396 line_tax += tax_line.get('amount', 0.0)400 line_tax += (line.type == 'dr' and 1 or -1) * tax_line.get('amount', 0.0)
397 line_total += tax_line.get('price_unit')401 line_total += tax_line.get('price_unit')
398 total_tax += line_tax402 total_tax += line_tax
399 untax_amount = line.untax_amount or line.amount403 untax_amount = line.untax_amount or line.amount
400 voucher_line_pool.write(cr, uid, [line.id], {'amount':line_total, 'untax_amount':untax_amount})404 voucher_line_pool.write(cr, uid, [line.id], {'amount':line_total, 'untax_amount':untax_amount})
401405
402 self.write(cr, uid, [voucher.id], {'amount':total, 'tax_amount':total_tax})406 self.write(cr, uid, [voucher.id], {'amount': abs(total), 'amount_signed': total, 'tax_amount':total_tax})
403 return True407 return True
404408
405 def onchange_price(self, cr, uid, ids, line_ids, tax_id, partner_id=False, context=None):409 def onchange_price(self, cr, uid, ids, line_ids, tax_id, partner_id=False, context=None):
@@ -414,12 +418,12 @@
414 }418 }
415 voucher_total = 0.0419 voucher_total = 0.0
416420
417 line_ids = resolve_o2m_operations(cr, uid, line_pool, line_ids, ["amount"], context)421 line_ids = resolve_o2m_operations(cr, uid, line_pool, line_ids, ["amount", "type"], context)
418422
419 total_tax = 0.0423 total_tax = 0.0
420 for line in line_ids:424 for line in line_ids:
421 line_amount = 0.0425 line_amount = 0.0
422 line_amount = line.get('amount',0.0)426 line_amount = (line['type'] == 'dr' and 1 or -1) * line.get('amount',0.0)
423427
424 if tax_id:428 if tax_id:
425 tax = [tax_pool.browse(cr, uid, tax_id, context=context)]429 tax = [tax_pool.browse(cr, uid, tax_id, context=context)]
@@ -436,7 +440,7 @@
436 total = voucher_total + total_tax440 total = voucher_total + total_tax
437441
438 res.update({442 res.update({
439 'amount': total or voucher_total,443 'amount': abs(total or voucher_total),
440 'tax_amount': total_tax444 'tax_amount': total_tax
441 })445 })
442 return {446 return {
@@ -919,13 +923,20 @@
919 # ANSWER: We can have payment and receipt "In Advance".923 # ANSWER: We can have payment and receipt "In Advance".
920 # TODO: Make this logic available.924 # TODO: Make this logic available.
921 # -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt925 # -for sale, purchase we have but for the payment and receipt we do not have as based on the bank/cash journal we can not know its payment or receipt
922 if voucher_brw.type in ('purchase', 'payment'):926 if voucher_brw.type == 'payment':
923 credit = voucher_brw.paid_amount_in_company_currency927 credit = voucher_brw.paid_amount_in_company_currency
924 elif voucher_brw.type in ('sale', 'receipt'):928 amount_currency = -1 * voucher_brw.amount
929 elif voucher_brw.type == 'receipt':
925 debit = voucher_brw.paid_amount_in_company_currency930 debit = voucher_brw.paid_amount_in_company_currency
926 if debit < 0: credit = -debit; debit = 0.0931 amount_currency = voucher_brw.amount
927 if credit < 0: debit = -credit; credit = 0.0932 else:
928 sign = debit - credit < 0 and -1 or 1933 amount_currency = -1 * voucher_brw.amount_signed
934 if voucher_brw.amount_signed > 0:
935 credit = voucher_brw.paid_amount_in_company_currency
936 debit = 0.0
937 else:
938 debit = voucher_brw.paid_amount_in_company_currency
939 credit = 0.0
929 #set the first line of the voucher940 #set the first line of the voucher
930 move_line = {941 move_line = {
931 'name': voucher_brw.name or '/',942 'name': voucher_brw.name or '/',
@@ -937,7 +948,7 @@
937 'period_id': voucher_brw.period_id.id,948 'period_id': voucher_brw.period_id.id,
938 'partner_id': voucher_brw.partner_id.id,949 'partner_id': voucher_brw.partner_id.id,
939 'currency_id': company_currency <> current_currency and current_currency or False,950 'currency_id': company_currency <> current_currency and current_currency or False,
940 'amount_currency': company_currency <> current_currency and sign * voucher_brw.amount or 0.0,951 'amount_currency': company_currency <> current_currency and amount_currency or 0.0,
941 'date': voucher_brw.date,952 'date': voucher_brw.date,
942 'date_maturity': voucher_brw.date_due953 'date_maturity': voucher_brw.date_due
943 }954 }
@@ -1073,6 +1084,7 @@
1073 context = {}1084 context = {}
1074 move_line_obj = self.pool.get('account.move.line')1085 move_line_obj = self.pool.get('account.move.line')
1075 currency_obj = self.pool.get('res.currency')1086 currency_obj = self.pool.get('res.currency')
1087 voucher_line_obj = self.pool.get('account.voucher.line')
1076 tax_obj = self.pool.get('account.tax')1088 tax_obj = self.pool.get('account.tax')
1077 tot_line = line_total1089 tot_line = line_total
1078 rec_lst_ids = []1090 rec_lst_ids = []
@@ -1084,15 +1096,37 @@
1084 #create one move line per voucher line where amount is not 0.01096 #create one move line per voucher line where amount is not 0.0
1085 if not line.amount:1097 if not line.amount:
1086 continue1098 continue
1099
1100 if line.amount < 0:
1101 line_type = line.type
1102 if line.type == 'dr':
1103 line_type = 'cr'
1104 else:
1105 line_type = 'dr'
1106 voucher_line_obj.write(
1107 cr, uid, line.id,
1108 {'type': line_type,
1109 'amount': -1 * line.amount,
1110 'untax_amount': line.untax_amount and -1 * line.untax_amount
1111 }, context=context)
1112 line.refresh()
1113
1114 if voucher_brw.type == 'payment':
1115 sign = 1
1116 elif voucher_brw.type == 'receipt':
1117 sign = -1
1118 else:
1119 sign = line.type == 'dr' and 1 or -1
1120
1087 # convert the amount set on the voucher line into the currency of the voucher's company1121 # convert the amount set on the voucher line into the currency of the voucher's company
1088 amount = self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher_brw.id, context=ctx)1122 amount = sign * self._convert_amount(cr, uid, line.untax_amount or line.amount, voucher_brw.id, context=ctx)
1123
1089 # if the amount encoded in voucher is equal to the amount unreconciled, we need to compute the1124 # if the amount encoded in voucher is equal to the amount unreconciled, we need to compute the
1090 # currency rate difference1125 # currency rate difference
1091 if line.amount == line.amount_unreconciled:1126 if line.amount == line.amount_unreconciled:
1092 if not line.move_line_id.amount_residual:1127 if not line.move_line_id.amount_residual:
1093 raise osv.except_osv(_('Wrong bank statement line'),_("You have to delete the bank statement line which the payment was reconciled to manually. Please check the payment of the partner %s by the amount of %s.")%(line.voucher_id.partner_id.name, line.voucher_id.amount))1128 raise osv.except_osv(_('Wrong bank statement line'),_("You have to delete the bank statement line which the payment was reconciled to manually. Please check the payment of the partner %s by the amount of %s.")%(line.voucher_id.partner_id.name, line.voucher_id.amount))
1094 sign = voucher_brw.type in ('payment', 'purchase') and -1 or 11129 currency_rate_difference = -1 * (sign * line.move_line_id.amount_residual - amount)
1095 currency_rate_difference = sign * (line.move_line_id.amount_residual - amount)
1096 else:1130 else:
1097 currency_rate_difference = 0.01131 currency_rate_difference = 0.0
1098 move_line = {1132 move_line = {
@@ -1109,19 +1143,12 @@
1109 'debit': 0.0,1143 'debit': 0.0,
1110 'date': voucher_brw.date1144 'date': voucher_brw.date
1111 }1145 }
1112 if amount < 0:
1113 amount = -amount
1114 if line.type == 'dr':
1115 line.type = 'cr'
1116 else:
1117 line.type = 'dr'
11181146
1119 if (line.type=='dr'):1147 if amount > 0:
1120 tot_line += amount
1121 move_line['debit'] = amount1148 move_line['debit'] = amount
1122 else:1149 else:
1123 tot_line -= amount1150 move_line['credit'] = -1 * amount
1124 move_line['credit'] = amount1151 tot_line += amount
11251152
1126 if voucher_brw.tax_id and voucher_brw.type in ('sale', 'purchase'):1153 if voucher_brw.tax_id and voucher_brw.type in ('sale', 'purchase'):
1127 move_line.update({1154 move_line.update({
@@ -1143,7 +1170,6 @@
1143 # we compute the amount in that foreign currency.1170 # we compute the amount in that foreign currency.
1144 if line.move_line_id.currency_id.id == current_currency:1171 if line.move_line_id.currency_id.id == current_currency:
1145 # if the voucher and the voucher line share the same currency, there is no computation to do1172 # if the voucher and the voucher line share the same currency, there is no computation to do
1146 sign = (move_line['debit'] - move_line['credit']) < 0 and -1 or 1
1147 amount_currency = sign * (line.amount)1173 amount_currency = sign * (line.amount)
1148 elif line.move_line_id.currency_id.id == voucher_brw.payment_rate_currency_id.id:1174 elif line.move_line_id.currency_id.id == voucher_brw.payment_rate_currency_id.id:
1149 # if the rate is specified on the voucher, we must use it1175 # if the rate is specified on the voucher, we must use it
@@ -1152,9 +1178,8 @@
1152 else:1178 else:
1153 # otherwise we use the rates of the system (giving the voucher date in the context)1179 # otherwise we use the rates of the system (giving the voucher date in the context)
1154 amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)1180 amount_currency = currency_obj.compute(cr, uid, company_currency, line.move_line_id.currency_id.id, move_line['debit']-move_line['credit'], context=ctx)
1155 if line.amount == line.amount_unreconciled and line.move_line_id.currency_id.id == voucher_currency:1181 if amount == line.amount_unreconciled and line.move_line_id.currency_id.id == voucher_currency:
1156 sign = voucher_brw.type in ('payment', 'purchase') and -1 or 11182 foreign_currency_diff = line.move_line_id.amount_residual_currency + amount_currency
1157 foreign_currency_diff = sign * line.move_line_id.amount_residual_currency + amount_currency
11581183
1159 move_line['amount_currency'] = amount_currency1184 move_line['amount_currency'] = amount_currency
1160 voucher_line = move_line_obj.create(cr, uid, move_line)1185 voucher_line = move_line_obj.create(cr, uid, move_line)
@@ -1266,6 +1291,7 @@
1266 context = {}1291 context = {}
1267 move_pool = self.pool.get('account.move')1292 move_pool = self.pool.get('account.move')
1268 move_line_pool = self.pool.get('account.move.line')1293 move_line_pool = self.pool.get('account.move.line')
1294 self.compute_tax(cr, uid, ids, context=context)
1269 for voucher in self.browse(cr, uid, ids, context=context):1295 for voucher in self.browse(cr, uid, ids, context=context):
1270 if voucher.move_id:1296 if voucher.move_id:
1271 continue1297 continue
@@ -1285,14 +1311,11 @@
1285 move_line_brw = move_line_pool.browse(cr, uid, move_line_id, context=context)1311 move_line_brw = move_line_pool.browse(cr, uid, move_line_id, context=context)
1286 line_total = move_line_brw.debit - move_line_brw.credit1312 line_total = move_line_brw.debit - move_line_brw.credit
1287 rec_list_ids = []1313 rec_list_ids = []
1288 if voucher.type == 'sale':1314 line_total = line_total - self._convert_amount(cr, uid, voucher.tax_amount, voucher.id, context=ctx)
1289 line_total = line_total - self._convert_amount(cr, uid, voucher.tax_amount, voucher.id, context=ctx)
1290 elif voucher.type == 'purchase':
1291 line_total = line_total + self._convert_amount(cr, uid, voucher.tax_amount, voucher.id, context=ctx)
1292 # Create one move line per voucher line where amount is not 0.01315 # Create one move line per voucher line where amount is not 0.0
1293 line_total, rec_list_ids = self.voucher_move_line_create(cr, uid, voucher.id, line_total, move_id, company_currency, current_currency, context)1316 line_total, rec_list_ids = self.voucher_move_line_create(cr, uid, voucher.id, line_total, move_id, company_currency, current_currency, context)
12941317
1295 # Create the writeoff line if needed1318 # Create the writeoff line if needed
1296 ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, context)1319 ml_writeoff = self.writeoff_move_line_get(cr, uid, voucher.id, line_total, move_id, name, company_currency, current_currency, context)
1297 if ml_writeoff:1320 if ml_writeoff:
1298 move_line_pool.create(cr, uid, ml_writeoff, context)1321 move_line_pool.create(cr, uid, ml_writeoff, context)
12991322
=== modified file 'account_voucher/test/account_voucher.yml'
--- account_voucher/test/account_voucher.yml 2012-10-19 11:07:20 +0000
+++ account_voucher/test/account_voucher.yml 2012-11-22 20:47:25 +0000
@@ -13,6 +13,7 @@
13 - account_id: account.a_recv13 - account_id: account.a_recv
14 amount: 1000.014 amount: 1000.0
15 name: Voucher for Axelor15 name: Voucher for Axelor
16 type: cr
16 partner_id: base.res_partner_1217 partner_id: base.res_partner_12
17 period_id: account.period_618 period_id: account.period_6
18 reference: none19 reference: none

Subscribers

People subscribed via source and target branches

to all changes: