← Back to team overview

openerp-dev-web team mailing list archive

[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','&lt;&gt;','view'),('type','&lt;&gt;','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