Odoo Help

5 Answers
Carlos Castillo
2/21/14, 6:55 AM


I had the same issue and in my case I needed to remove the field "move_id" from account.voucher and adding the field "move_line_id" to account.voucher.line, have you tried that?

move_line_id should match the ID of the account.move.line whose "move_id" field matches the "move_id" field of the invoice you created

I also set 'type'='cr' for account.voucher.line

After that, executing workflow('account.voucher', 'proforma_voucher', voucher_id) worked ok,

Hope this helps!

1 Comment
Vlad Janicek
2/26/14, 4:29 PM

Had few days without checking this and yes!! i found out how to do it and is exactly what you said!!

Alkivi SAS
5/2/14, 12:29 PM

Hi guys,

I've been facing the same issue here, and here is the code that is currently working for us. Any feedback are appreciated :) Transaction object is a custom one, but contains the journal_id related to the bank account and an amount.

    invoice = self.browse(cr, uid, ids[0], context=context)
    move = invoice.move_id

    # First part, create voucher
    account = transaction.journal_id.default_credit_account_id or transaction.journal_id.default_debit_account_id
    period_id = self.pool.get('account.voucher')._get_period(cr, uid)
    partner_id = self.pool.get('res.partner')._find_accounting_partner(invoice.partner_id).id,

    voucher_data = {
        'partner_id': partner_id,
        'amount': abs(transaction.amount),
        'journal_id': transaction.journal_id.id,
        'period_id': period_id,
        'account_id': account.id,
        'type': invoice.type in ('out_invoice','out_refund') and 'receipt' or 'payment',
        'reference' : invoice.name,


    voucher_id = self.pool.get('account.voucher').create(cr, uid, voucher_data, context=context)

    # Equivalent to workflow proform
    self.pool.get('account.voucher').write(cr, uid, [voucher_id], {'state':'draft'}, context=context)

    # Need to create basic account.voucher.line according to the type of invoice need to check stuff ...
    double_check = 0
    for move_line in invoice.move_id.line_id:
        # According to invoice type
        if invoice.type in ('out_invoice','out_refund'):
            if move_line.debit > 0.0:
                line_data = {
                    'name': invoice.number,
                    'voucher_id' : voucher_id,
                    'move_line_id' : move_line.id,
                    'account_id' : invoice.account_id.id,
                    'partner_id' : partner_id,
                    'amount_unreconciled': abs(move_line.debit),
                    'amount_original': abs(move_line.debit),
                    'amount': abs(move_line.debit),
                    'type': 'cr',

                line_id = self.pool.get('account.voucher.line').create(cr, uid, line_data, context=context)
                double_check += 1
            if move_line.credit > 0.0:
                line_data = {
                    'name': invoice.number,
                    'voucher_id' : voucher_id,
                    'move_line_id' : move_line.id,
                    'account_id' : invoice.account_id.id,
                    'partner_id' : partner_id,
                    'amount_unreconciled': abs(move_line.credit),
                    'amount_original': abs(move_line.credit),
                    'amount': abs(move_line.credit),
                    'type': 'dr',

                line_id = self.pool.get('account.voucher.line').create(cr, uid, line_data, context=context)
                double_check += 1

    # Cautious check to see if we did ok
    if double_check == 0:
        raise osv.except_osv(_("Warning"), _("I did not create any voucher line"))
    elif double_check > 1:
        raise osv.except_osv(_("Warning"), _("I created multiple voucher line ??"))

    # Where the magic happen
    self.pool.get('account.voucher').button_proforma_voucher(cr, uid, [voucher_id], context=context)
1 Comment
OpusVL, Peter Alabaster
9/8/15, 12:50 PM

Thanks for this - helped me to write test cases for registering payment on invoices. For some reason i was getting the 'double_check > 1' case, and it turned out it was a stock account getting into the mix with a debit above 0. I'm not sure if this is a config issue or just that the above code doesn't take into account the stock accounts (V8). Either way, cheers !

Ashif Abdulrahman
2/14/14, 1:16 AM

no need to inherit account.voucher. after creating the account.voucher record, you just add this in your XMLRPC script.

self.sock.execute(self.dbname, self.uid, self.pwd, 'account.voucher', 
                             'button_proforma_voucher', voucher_id, {})

voucher_id should be the ID of the created voucher.

Vlad Janicek
2/14/14, 11:50 AM

I did, as I mentioned in my post, but it didnt chante its status. Am i missing something with the voucher or its line? Should I add another record? or should I add more lines per voucher?

Jack Richard
2/14/14, 5:51 PM

@Vlad Janicek what is the issue with it? have you got any errors?

Vlad Janicek
2/15/14, 7:41 PM

I may be inserting wrong records in voucher lines... I get no errors when I execute the workflow. Ashif suggested execute but execute is for browsing. I used exec_workflow. I only get False and no changes are made

Vlad Janicek
2/16/14, 8:19 PM

any ideas? im about to give up

Vlad Janicek
2/18/14, 1:37 AM

I tried that too. I get this returned: {'type': 'ir.actions.act_window_close'}

That is the button that is pressed in the register payment wizard view. Wont this avoid all the functions in that view?

I tried that when I realized that I have to execute all the onmove functions in order to have all the account_voucher_lines records.

Thanks a lot, I really appreciate your help dude! I'll keep trying to figure it out

Vlad Janicek
2/18/14, 1:40 AM

I even found out that 'confirm_paid' would make an invoice as 'paid' but wont tie it to a voucher. wf_service.trg_validate(uid, 'account.invoice', invoice_id, 'confirm_paid', cr). The invoice will be paid but it wont register it's payment. Doesn't work for us either

Vlad Janicek
2/14/14, 3:31 PM

Thank you very much for for answer and help.

I tried that already and it didn't work. It may be that I'm missing to add the exact move_line_id or any other record to account_voucher_line or that I'm missing something else.

Just in case, I followed everything you said with no payment being registered.

This is how I inherited account_voucher:

class account_voucher(osv.osv):
    _inherit = 'account.voucher'

    def action_proforma_voucher(self, cr, uid, voucher_id, context=None):
        wf_service = netsvc.LocalService("workflow")
        wf_service.trg_validate(uid, 'account.voucher', voucher_id,
                                'proforma_voucher', cr)
        wf_service.trg_write(uid, 'account.voucher', voucher_id, cr)
        return True

BTW I printed both outputs

wf_service.trg_validate(uid, ...
wf_service.trg_write(uid, 'acc...

and they print False and None respectively

This is what I used to execute the XMLRPC call

def set_payment(voucher_id):
    db_conn = xmlrpclib.ServerProxy(dc.url + '/xmlrpc/object')
    return db_conn.execute('mydb', myuid, 'mypass', 'account.voucher',
                           'action_proforma_voucher', voucher_id, {})

I still don't understand this process. What is exactly needed by the 'proforma_voucher' WF process? I have checked all the onchange functions in the register payment view and they create many account_voucher_lines whereas I'm just creating one.

Thanks a lot for your help pal

Ashif Abdulrahman
2/17/14, 9:44 AM

There is an another way, i have updated my previous answer. check it out....

Vlad Janicek
2/17/14, 11:42 AM

@Ashif: thanks! I updated my last comment. It didnt work either.

Vlad Janicek
2/17/14, 11:10 PM

Still trying... doing each onchange by hand and it doesn't work

Ashif Abdulrahman
2/18/14, 1:26 AM

hi, please check this too...

Vlad Janicek
2/18/14, 9:33 PM

Updated, still not working

Vlad Janicek
2/19/14, 1:52 PM

Any ideas?

Ferdinand Gassauer
8/18/14, 1:04 AM

I suggest to create a python function (module) which is called via XMLRPC  - XMLRPC is much to slow

  1. create and open invoice
  2. create and post payment move
  3. reconcile

        for inv in invoice_ids: 
            invoice_id = inv.id
            wf_service.trg_validate(uid, 'account.invoice', invoice_id, 'invoice_open', cr)
            for inv_open in invoice_obj.browse(cr, uid, [invoice_id] , context):
                # payment
                journal_id = journal_obj.search(cr, uid, [('code','=', order_vals['pay_method'])])[0]
                journal = journal_obj.browse(cr, uid, [journal_id], context)[0]
                move_val = {
                    'partner_id' : inv_open.partner_id.id,
                    'date'       : inv_open.date_invoice,
                    'period_id'  : inv_open.period_id.id,
                    'journal_id' : journal_id,
                    'ref' : order_vals['pay_ref']
                move_id =  move_obj.create(cr, uid, move_val, context)
                line_val = {
                    'account_id' : inv_open.account_id.id,
                    'credit'     : inv_open.residual,
                    'move_id'    : move_id,
                    'name'       : order_vals['pay_ref']
                line_id = move_line_obj.create(cr, uid, line_val, context)
                reconcile_lines = [line_id]
                line_val = {
                    'account_id' : journal.default_debit_account_id.id,
                    'debit'      : inv_open.residual,
                    'move_id'    : move_id,
                    'name'       : order_vals['pay_ref']
                line_id = move_line_obj.create(cr, uid, line_val, context)
                move_obj.button_validate(cr, uid, [move_id], context=context)

                inv_move_line_id = move_line_obj.search(cr, uid, [('move_id','=',inv_open.move_id.id), ('account_id','=', inv_open.account_id.id) ])[0]
                move_line_obj.reconcile(cr, uid, reconcile_lines)

                invoice_obj.invoice_print(cr, uid, [inv_open.id], 'account.invoice', context)

Ask a Question
About This Community

This platform is for beginners and experts willing to share their Odoo knowledge. It's not a forum to discuss ideas, but a knowledge base of questions and their answers.

Odoo Training Center

Access to our E-learning platform and experience all Odoo Apps through learning videos, exercises and Quizz.

Test it now