如何在Odoo 8中用Invoice ID替换发票编号序列?
Got it, let's break this down into actionable steps since you're right—Odoo doesn't have a built-in way to swap the invoice number sequence with the database's auto-incrementing invoice_id (the primary key id field). Building a custom module is the way to go, and here's exactly how to do it:
Odoo uses the name field on the account.move model (which represents invoices) to store the human-readable invoice number. By default, this is populated by a predefined sequence. We need to override this logic so that name instead uses the auto-generated database id of the invoice record.
Start by creating a simple custom module with these core files:
__manifest__.py: Defines the module metadata (name, version, dependencies, etc.)models/account_move.py: Where we'll override the invoice model logic- (Optional)
data/sequence_disable.xml: To disable the default invoice sequence (if needed) - (Optional)
views/account_move_views.xml: To add a button for updating existing invoices
In models/account_move.py, inherit the account.move model and override the create method to skip the sequence and use the database id:
from odoo import models, api class AccountMove(models.Model): _inherit = 'account.move' @api.model def create(self, vals): # Target only invoice/refund types (adjust if you need to include/exclude specific types) invoice_types = ['out_invoice', 'in_invoice', 'out_refund', 'in_refund'] if vals.get('move_type') in invoice_types: # Create the invoice first without setting the 'name' field # This lets Odoo generate the auto-incrementing 'id' invoice = super().create({k: v for k, v in vals.items() if k != 'name'}) # Update the invoice's 'name' to match its database ID invoice.write({'name': str(invoice.id)}) return invoice # For non-invoice moves (like journal entries), keep the default behavior return super().create(vals)
Key Notes:
- This ensures every new invoice gets its
nameset to the databaseidright after creation. - We skip passing the
namein the initial create call so Odoo doesn't trigger the default sequence.
If you need to retroactively update existing invoices to use their id as the number, add this method to the same AccountMove class:
def action_update_existing_invoices(self): # Fetch all invoices/refunds invoices = self.search([('move_type', 'in', ['out_invoice', 'in_invoice', 'out_refund', 'in_refund'])]) for invoice in invoices: if invoice.name != str(invoice.id): invoice.write({'name': str(invoice.id)})
Then add a button to the invoice form view (in views/account_move_views.xml) to trigger this action:
<odoo> <record id="account_move_form_inherit" model="ir.ui.view"> <field name="name">account.move.form.inherit</field> <field name="model">account.move</field> <field name="inherit_id" ref="account.view_move_form"/> <field name="arch" type="xml"> <xpath expr="//button[@name='action_post']" position="after"> <button name="action_update_existing_invoices" string="Update to ID-Based Numbers" type="object" class="btn-primary"/> </xpath> </field> </record> </odoo>
To prevent accidental use of the old sequence, you can disable the default invoice sequence in data/sequence_disable.xml:
<odoo> <record id="account.sequence_move" model="ir.sequence"> <field name="active" eval="False"/> </record> </odoo>
⚠️ Warning: This disables the sequence for all account.move records (including journal entries). If you still need sequences for non-invoice moves, skip this step—our code already ensures only invoices use the id instead.
- Create new customer/supplier invoices and refunds to verify the
namematches the databaseid. - Run the existing invoice update button (if added) and check that old invoices are updated correctly.
- Test posting invoices, generating PDF reports, and other core invoice workflows to ensure no conflicts.
内容的提问来源于stack exchange,提问作者MoncefB

