openerp-dev-web team mailing list archive
-
openerp-dev-web team
-
Mailing list archive
-
Message #00442
[Merge] lp:~openerp-commiter/openobject-addons/trunk-dev-addons3-psi into lp:~openerp-dev/openobject-addons/trunk-dev-addons3
psi (OpenERP) has proposed merging lp:~openerp-commiter/openobject-addons/trunk-dev-addons3-psi into lp:~openerp-dev/openobject-addons/trunk-dev-addons3.
Requested reviews:
OpenERP R&D Team (openerp-dev)
Related bugs:
#662538 account - account_move_lines for payables and receivables must have partner_id - missing check
https://bugs.launchpad.net/bugs/662538
#665326 Multi_company : Journal entry missing for company OpenERP IN.
https://bugs.launchpad.net/bugs/665326
#667619 Export po file from OpenERP, Accounting reports does not translated.
https://bugs.launchpad.net/bugs/667619
accunt_voucher: Writeoff implementation
I was about to implement these features
- one selection box: "Do not reconcile balance" or "Close the balance"
- If you select "Close the balance", OpenERP asks for a write-off account to put the unbalanced amount
It's working fine for "Do not reconcile balance" option
Facing problem in "close the balance" option
Task is partially done
--
https://code.launchpad.net/~openerp-commiter/openobject-addons/trunk-dev-addons3-psi/+merge/40719
Your team OpenERP R&D Team is requested to review the proposed merge of lp:~openerp-commiter/openobject-addons/trunk-dev-addons3-psi into lp:~openerp-dev/openobject-addons/trunk-dev-addons3.
=== modified file 'account_voucher/__openerp__.py'
--- account_voucher/__openerp__.py 2010-10-20 13:36:16 +0000
+++ account_voucher/__openerp__.py 2010-11-12 13:24:09 +0000
@@ -43,6 +43,7 @@
"account_voucher_report.xml",
"wizard/account_voucher_unreconcile_view.xml",
"wizard/account_statement_from_invoice_view.xml",
+ "wizard/account_voucher_payment_option.xml",
"account_voucher_view.xml",
"voucher_payment_receipt_view.xml",
"voucher_sales_purchase_view.xml",
=== modified file 'account_voucher/account_voucher.py'
--- account_voucher/account_voucher.py 2010-11-12 04:23:07 +0000
+++ account_voucher/account_voucher.py 2010-11-12 13:24:09 +0000
@@ -539,6 +539,38 @@
self.write(cr, uid, ids, res)
return True
+ def do_check(self, cr, uid, ids, context=None):
+ cur_obj = self.pool.get('res.currency')
+ mod_obj = self.pool.get('ir.model.data')
+ if context is None:
+ context = {}
+ voucher = self.browse(cr, uid, [ids[0]], context=context)[0]
+ debit= credit = 0.0
+ if voucher.line_dr_ids:
+ for line in voucher.line_dr_ids:
+ debit += line.amount_original
+ if voucher.line_cr_ids:
+ for line in voucher.line_cr_ids:
+ credit += line.amount_original
+ if (voucher.amount + debit) != credit:
+ model_data_ids = mod_obj.search(cr, uid,[('model', '=', 'ir.ui.view'), ('name', '=', 'view_account_voucher_pay_writeoff')], context=context)
+ resource_id = mod_obj.read(cr, uid, model_data_ids, fields=['res_id'], context=context)[0]['res_id']
+ context.update({'voucher_id': ids[0]})
+ return {
+ 'name': _('Information addendum'),
+ 'context': context,
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'account.voucher.pay.writeoff',
+ 'views': [(resource_id, 'form')],
+ 'type': 'ir.actions.act_window',
+ 'target': 'new',
+ 'nodestroy': True
+ }
+ else:
+ self.action_move_line_create(cr, uid, ids, context=context)
+ return True
+
def unlink(self, cr, uid, ids, context=None):
for t in self.read(cr, uid, ids, ['state'], context=context):
if t['state'] not in ('draft', 'cancel'):
@@ -566,7 +598,6 @@
return {'value':res}
def action_move_line_create(self, cr, uid, ids, context=None):
-
def _get_payment_term_lines(term_id, amount):
term_pool = self.pool.get('account.payment.term')
if term_id and amount:
@@ -646,7 +677,6 @@
line_total = line_total - currency_pool.compute(cr, uid, inv.currency_id.id, company_currency, inv.tax_amount)
elif inv.type == 'purchase':
line_total = line_total + currency_pool.compute(cr, uid, inv.currency_id.id, company_currency, inv.tax_amount)
-
for line in inv.line_ids:
if not line.amount:
continue
@@ -714,7 +744,6 @@
else:
account_id = inv.partner_id.property_account_payable.id
move_line['account_id'] = account_id
-
move_line_pool.create(cr, uid, move_line)
self.write(cr, uid, [inv.id], {
@@ -728,6 +757,110 @@
move_line_pool.reconcile_partial(cr, uid, rec_ids)
return True
+ def pay_and_reconcile(self, cr, uid, ids, pay_amount, pay_account_id, period_id, pay_journal_id, writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context=None, name=''):
+ if context is None:
+ context = {}
+ seq_obj = self.pool.get('ir.sequence')
+ #TODO check if we can use different period for payment and the writeoff line
+ assert len(ids)==1, "Can only pay one voucher at a time"
+ voucher = self.browse(cr, uid, ids[0])
+ if voucher.number:
+ name = voucher.number
+ elif voucher.journal_id.sequence_id:
+ name = seq_obj.get_id(cr, uid, voucher.journal_id.sequence_id.id)
+ else:
+ raise osv.except_osv(_('Error !'), _('Please define a sequence on the journal !'))
+ if not voucher.reference:
+ ref = name.replace('/','')
+ else:
+ ref = voucher.reference
+
+ src_account_id = voucher.account_id.id
+ # Take the seq as name for move
+ types = {'sale': -1, 'purchase': 1, 'payment': 1, 'receipt': -1}
+ direction = types[voucher.type]
+ #take the choosen date
+ if 'date_p' in context and context['date_p']:
+ date = context['date_p']
+ else:
+ date = time.strftime('%Y-%m-%d')
+ # Take the amount in currency and the currency of the payment
+ if 'amount_currency' in context and context['amount_currency'] and 'currency_id' in context and context['currency_id']:
+ amount_currency = context['amount_currency']
+ currency_id = context['currency_id']
+ else:
+ amount_currency = False
+ currency_id = False
+ pay_journal = self.pool.get('account.journal').read(cr, uid, pay_journal_id, ['type'], context=context)
+ if voucher.type in ('sale', 'receipt'):
+ if pay_journal['type'] == 'bank':
+ entry_type = 'bank_pay_voucher' # Bank payment
+ else:
+ entry_type = 'pay_voucher' # Cash payment
+ else:
+ entry_type = 'cont_voucher'
+
+ # Pay attention to the sign for both debit/credit AND amount_currency
+ l1 = {
+ 'debit': direction * pay_amount>0 and direction * pay_amount,
+ 'credit': direction * pay_amount<0 and - direction * pay_amount,
+ 'account_id': src_account_id,
+ 'partner_id': voucher.partner_id.id,
+ 'ref':ref,
+ 'date': date,
+ 'currency_id':currency_id,
+ 'amount_currency':amount_currency and direction * amount_currency or 0.0,
+ 'company_id': voucher.company_id.id,
+ }
+ l2 = {
+ 'debit': direction * pay_amount<0 and - direction * pay_amount,
+ 'credit': direction * pay_amount>0 and direction * pay_amount,
+ 'account_id': pay_account_id,
+ 'partner_id': voucher.partner_id.id,
+ 'ref':ref,
+ 'date': date,
+ 'currency_id':currency_id,
+ 'amount_currency':amount_currency and - direction * amount_currency or 0.0,
+ 'company_id': voucher.company_id.id,
+ }
+
+ if not name:
+ name = voucher.line_ids and voucher.line_ids[0].name or voucher.number
+ l1['name'] = name
+ l2['name'] = name
+ lines = [(0, 0, l1), (0, 0, l2)]
+ move = {'ref': ref, 'line_id': lines, 'journal_id': pay_journal_id, 'period_id': period_id, 'name': name, 'date': date}
+ move_id = self.pool.get('account.move').create(cr, uid, move, context=context)
+
+ line_ids = []
+ total = 0.0
+ line = self.pool.get('account.move.line')
+ move_ids = [move_id,]
+ if voucher.move_id:
+ move_ids.append(voucher.move_id.id)
+ cr.execute('SELECT id FROM account_move_line '\
+ 'WHERE move_id IN %s',
+ ((move_id,),))
+ lines = line.browse(cr, uid, map(lambda x: x[0], cr.fetchall()) )
+ for l in lines:
+ if l.account_id.id == src_account_id:
+ line_ids.append(l.id)
+ total += (l.debit or 0.0) - (l.credit or 0.0)
+
+ voc_id, name = self.name_get(cr, uid, [voucher.id], context=context)[0]
+ if (not round(total,self.pool.get('decimal.precision').precision_get(cr, uid, 'Account'))) or writeoff_acc_id:
+ self.pool.get('account.move.line').reconcile(cr, uid, line_ids, 'manual', writeoff_acc_id, writeoff_period_id, writeoff_journal_id, context)
+ else:
+ code = voucher.currency_id.code
+ # TODO: use currency's formatting function
+ msg = _("Invoice '%s' is paid partially: %s%s of %s%s (%s%s remaining)") % \
+ (name, pay_amount, code, voucher.amount_total, code, total, code)
+ self.log(cr, uid, voc_id, msg)
+ self.pool.get('account.move.line').reconcile_partial(cr, uid, line_ids, 'manual', context)
+ # Update the stored value (fields.function), so we write to trigger recompute
+ self.write(cr, uid, ids, {'state':'posted'}, context=context)
+ return True
+
def copy(self, cr, uid, id, default={}, context=None):
default.update({
'state': 'draft',
=== modified file 'account_voucher/voucher_payment_receipt_view.xml'
--- account_voucher/voucher_payment_receipt_view.xml 2010-10-27 11:08:06 +0000
+++ account_voucher/voucher_payment_receipt_view.xml 2010-11-12 13:24:09 +0000
@@ -217,7 +217,7 @@
<button name="cancel_voucher" string="Cancel" states="draft,proforma" icon="gtk-cancel"/>
<button name="cancel_voucher" string="Unreconcile" type="object" states="posted" icon="terp-stock_effects-object-colorize" confirm="Are you sure to unreconcile this record ?"/>
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft" icon="terp-stock_effects-object-colorize"/>
- <button name="proforma_voucher" string="Validate" states="draft" icon="gtk-go-forward"/>
+ <button name="do_check" type="object" string="Validate" states="draft" icon="gtk-go-forward"/>
</group>
</form>
</field>
@@ -325,7 +325,7 @@
<button name="cancel_voucher" string="Cancel" states="draft,proforma" icon="gtk-cancel"/>
<button name="cancel_voucher" string="Unreconcile" type="object" states="posted" icon="terp-stock_effects-object-colorize" confirm="Are you sure to unreconcile this record ?"/>
<button name="action_cancel_draft" type="object" states="cancel" string="Set to Draft" icon="terp-stock_effects-object-colorize"/>
- <button name="proforma_voucher" string="Validate" states="draft" icon="gtk-go-forward"/>
+ <button name="do_check" type="object" string="Validate" states="draft" icon="gtk-go-forward"/>
</group>
</form>
</field>
=== modified file 'account_voucher/wizard/__init__.py'
--- account_voucher/wizard/__init__.py 2010-09-22 06:23:08 +0000
+++ account_voucher/wizard/__init__.py 2010-11-12 13:24:09 +0000
@@ -21,5 +21,6 @@
import account_voucher_unreconcile
import account_statement_from_invoice
+import account_voucher_payment_option
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
=== added file 'account_voucher/wizard/account_voucher_payment_option.py'
--- account_voucher/wizard/account_voucher_payment_option.py 1970-01-01 00:00:00 +0000
+++ account_voucher/wizard/account_voucher_payment_option.py 2010-11-12 13:24:09 +0000
@@ -0,0 +1,116 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from osv import fields, osv
+from tools.translate import _
+
+class account_voucher_pay_writeoff(osv.osv_memory):
+ """
+ Opens the write off amount pay form.
+ """
+ _name = "account.voucher.pay.writeoff"
+ _description = "Pay Voucher"
+ _columns = {
+ 'payment_option':fields.selection([
+ ('not_reconcile', 'Do not reconcile balance'),
+ ('close_balance', 'close the balance'),
+ ], 'Payment Option', required=True),
+ 'writeoff_acc_id': fields.many2one('account.account', 'Write-Off account'),
+ 'writeoff_journal_id': fields.many2one('account.journal', 'Write-Off journal'),
+ 'comment': fields.char('Comment', size=64, required=True),
+ 'analytic_id': fields.many2one('account.analytic.account','Analytic Account'),
+ }
+ _defaults = {
+ 'payment_option': 'not_reconcile',
+ 'comment': 'Write-Off',
+ }
+
+ def pay_and_reconcile_writeoff(self, cr, uid, ids, context=None):
+ voucher_obj = self.pool.get('account.voucher')
+ data = self.read(cr, uid, ids,context=context)[0]
+ voucher_id = context.get('voucher_id', False)
+ if data['payment_option'] == 'not_reconcile':
+ voucher_obj.action_move_line_create(cr, uid, [voucher_id], context=context)
+ return {}
+ context.update({'write_off':data})
+ self.pool.get('account.voucher.pay').pay_and_reconcile(cr, uid, [voucher_id], context=context)
+ return {}
+
+account_voucher_pay_writeoff()
+
+class account_voucher_pay(osv.osv_memory):
+ """
+ Generate pay invoice wizard, user can make partial or full payment for invoice.
+ """
+ _name = "account.voucher.pay"
+ _description = "Pay Voucher"
+
+ def pay_and_reconcile(self, cr, uid, ids, context=None):
+ cur_obj = self.pool.get('res.currency')
+ voucher_obj = self.pool.get('account.voucher')
+ if context is None:
+ context = {}
+ voucher = voucher_obj.browse(cr, uid, [ids[0]], context=context)[0]
+ writeoff_account_id = False
+ writeoff_journal_id = False
+ comment = False
+
+ if 'write_off' in context and context['write_off'] :
+ writeoff_account_id = context['write_off']['writeoff_acc_id']
+ writeoff_journal_id = context['write_off']['writeoff_journal_id']
+ comment = context['write_off']['comment']
+
+ amount = voucher.amount
+ journal = voucher.journal_id
+ # Compute the amount in company's currency, with the journal currency (which is equal to payment currency)
+ # when it is needed : If payment currency (according to selected journal.currency) is <> from company currency
+ if journal.currency and voucher.company_id.currency_id.id<>journal.currency.id:
+ ctx = {'date': voucher.date}
+ amount = cur_obj.compute(cr, uid, journal.currency.id, voucher.company_id.currency_id.id, amount, context=ctx)
+ currency_id = journal.currency.id
+ # Put the paid amount in currency, and the currency, in the context if currency is different from company's currency
+ context.update({'amount_currency': voucher.amount, 'currency_id': currency_id})
+
+ if voucher.company_id.currency_id.id<>voucher.currency_id.id:
+ ctx = {'date':voucher.date}
+ amount = cur_obj.compute(cr, uid, voucher.currency_id.id, voucher.company_id.currency_id.id, amount, context=ctx)
+ currency_id = voucher.currency_id.id
+ # Put the paid amount in currency, and the currency, in the context if currency is different from company's currency
+ context.update({'amount_currency':voucher.amount,'currency_id':currency_id})
+
+ # Take the choosen date
+ if comment:
+ context.update({'date_p':voucher.date, 'comment':comment})
+ else:
+ context.update({'date_p':voucher.date, 'comment':False})
+
+ acc_id = journal.default_credit_account_id and journal.default_credit_account_id.id
+ if not acc_id:
+ raise osv.except_osv(_('Error !'), _('Your journal must have a default credit and debit account.'))
+
+ voucher_obj.pay_and_reconcile(cr, uid, ids,
+ amount, acc_id, voucher.period_id.id, journal.id, writeoff_account_id,
+ voucher.period_id, writeoff_journal_id, context, voucher.name)
+ return {}
+
+account_voucher_pay()
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
=== added file 'account_voucher/wizard/account_voucher_payment_option.xml'
--- account_voucher/wizard/account_voucher_payment_option.xml 1970-01-01 00:00:00 +0000
+++ account_voucher/wizard/account_voucher_payment_option.xml 2010-11-12 13:24:09 +0000
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+ <data>
+
+ <record id="view_account_voucher_pay_writeoff" model="ir.ui.view">
+ <field name="name">account.voucher.pay.writeoff.form</field>
+ <field name="model">account.voucher.pay.writeoff</field>
+ <field name="type">form</field>
+ <field name="arch" type="xml">
+ <form string="Information addendum">
+ <group height="280" width="590">
+ <field name="payment_option"/>
+ <group colspan="4" attrs="{'invisible':[('payment_option','!=','close_balance')]}">
+ <separator string="Write-Off Move" colspan="4"/>
+ <field name="writeoff_journal_id" attrs="{'required':[('payment_option','=','close_balance')]}"/>
+ <field name="writeoff_acc_id" domain="[('type','<>','view'),('type','<>','consolidation')]" attrs="{'required':[('payment_option','=','close_balance')]}"/>
+ <field name="comment"/>
+ <group colspan="4" groups="analytic.group_analytic_accounting">
+ <separator string="Analytic" colspan="4"/>
+ <field name="analytic_id"/>
+ </group>
+ </group>
+ <separator colspan="4"/>
+ <group colspan="4" col="6">
+ <button icon="gtk-close" special="cancel" string="Close"/>
+ <button icon="gtk-execute" string="Pay and reconcile" name="pay_and_reconcile_writeoff" type="object"/>
+ </group>
+ </group>
+ </form>
+ </field>
+ </record>
+
+ <record id="action_account_voucher_pay_writeoff" model="ir.actions.act_window">
+ <field name="name">Payment Writeoff</field>
+ <field name="type">ir.actions.act_window</field>
+ <field name="res_model">account.voucher.pay.writeoff</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">form</field>
+ <field name="view_id" ref="view_account_voucher_pay_writeoff"/>
+ <field name="context">{'record_id' : active_id}</field>
+ <field name="target">new</field>
+ </record>
+
+
+ </data>
+</openerp>
Follow ups