[IMP] account: new way of auto-completion of vendor bills/credit notes

This adds the possibilty to select another account.invoice object in a vendor bill or credit note, to automatically copy its lines.

When the purchase app is installed, the same field can be used for auto-completion and users can choose between vendor bills or purchase orders (preferably PO)

Co-authored-by: dat@openerp.com
This commit is contained in:
Fabien Pinckaers
2018-04-25 17:12:15 +02:00
committed by qdp-odoo
co-authored by
parent 04c44c479d
commit 051dfea35e
8 changed files with 169 additions and 12 deletions
+33
View File
@@ -286,6 +286,8 @@ class AccountInvoice(models.Model):
partner_id = fields.Many2one('res.partner', string='Partner', change_default=True,
required=True, readonly=True, states={'draft': [('readonly', False)]},
track_visibility='always')
vendor_bill_id = fields.Many2one('account.invoice', string='Vendor Bill',
help="Auto-complete from a past bill.")
payment_term_id = fields.Many2one('account.payment.term', string='Payment Terms', oldname='payment_term',
readonly=True, states={'draft': [('readonly', False)]},
help="If you use payment terms, the due date will be computed automatically at the generation "
@@ -372,6 +374,20 @@ class AccountInvoice(models.Model):
('number_uniq', 'unique(number, company_id, journal_id, type)', 'Invoice Number must be unique per Company!'),
]
# Load all Vendor Bill lines
@api.onchange('vendor_bill_id')
def _onchange_vendor_bill(self):
if not self.vendor_bill_id:
return {}
self.currency_id = self.vendor_bill_id.currency_id
new_lines = self.env['account.invoice.line']
for line in self.vendor_bill_id.invoice_line_ids:
new_lines += new_lines.new(line._prepare_invoice_line())
self.invoice_line_ids += new_lines
self.payment_term_id = self.vendor_bill_id.payment_term_id
self.vendor_bill_id = False
return {}
def _get_seq_number_next_stuff(self):
self.ensure_one()
journal_sequence = self.journal_id.sequence_id
@@ -1655,6 +1671,23 @@ class AccountInvoiceLine(models.Model):
raise UserError(_('You can only delete an invoice line if the invoice is in draft state.'))
return super(AccountInvoiceLine, self).unlink()
def _prepare_invoice_line(self):
data = {
'name': self.name,
'origin': self.origin,
'uom_id': self.uom_id.id,
'product_id': self.product_id.id,
'account_id': self.account_id.id,
'price_unit': self.price_unit,
'quantity': self.quantity,
'discount': self.discount,
'account_analytic_id': self.account_analytic_id.id,
'analytic_tag_ids': self.analytic_tag_ids.ids,
'invoice_line_tax_ids': self.invoice_line_tax_ids.ids
}
return data
class AccountInvoiceTax(models.Model):
_name = "account.invoice.tax"
_description = "Invoice Tax"
@@ -238,7 +238,7 @@
<label string="Bill " attrs="{'invisible': ['|',('state', '=', 'draft'), ('type','!=','in_invoice')]}"/>
<label string="Credit Note " attrs="{'invisible': ['|',('state', '=', 'draft'), ('type','!=','in_refund')]}"/>
<h1 class="mt0">
<field name="number" class="oe_inline" attrs="{'invisible': [('state', '=', 'draft')]}"/>
<field name="number" class="oe_inline" attrs="{'invisible': [('state', '=', 'draft')]}"/>
<div attrs="{'invisible': [('sequence_number_next_prefix','=',False)]}">
<field name="sequence_number_next_prefix" class="oe_inline"/>
<field name="sequence_number_next" class="oe_inline"/>
@@ -252,6 +252,10 @@
context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1, 'default_company_type': 'company'}"
domain="[('supplier', '=', True)]"/>
<field name="reference" string="Vendor Reference"/>
<field name="vendor_bill_id" attrs="{'invisible': [('state','not in',['draft'])]}"
domain="[('partner_id','child_of', [partner_id]), ('state','in',('open','paid')), ('type','=','in_invoice')]"
string="Auto-Complete" placeholder="Select an old vendor bill"
options="{'no_create': True}" context="{'show_total_amount': True}"/>
</group>
<group>
<field name="origin" attrs="{'invisible': [('origin', '=', False)]}"/>
+1
View File
@@ -3,6 +3,7 @@
from . import account_invoice
from . import purchase
from . import purchase_bill
from . import res_company
from . import res_config_settings
from . import res_partner
+5 -7
View File
@@ -4,16 +4,14 @@
from odoo import api, fields, models, _
from odoo.tools.float_utils import float_compare
from odoo.exceptions import UserError
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
purchase_id = fields.Many2one(
comodel_name='purchase.order',
string='Add Purchase Order',
readonly=True, states={'draft': [('readonly', False)]},
help='Encoding help. When selected, the associated purchase order lines are added to the vendor bill. Several PO can be selected.'
help='Load the vendor bill based on selected purchase order. Several PO can be selected.'
)
@api.onchange('state', 'partner_id', 'invoice_line_ids')
@@ -29,7 +27,7 @@ class AccountInvoice(models.Model):
purchase_ids = self.invoice_line_ids.mapped('purchase_id').filtered(lambda r: r.order_line <= purchase_line_ids)
result['domain'] = {'purchase_id': [
('invoice_status', '=', 'to invoice'),
('invoice_status', 'in', ['to invoice', 'no']),
('partner_id', 'child_of', self.partner_id.id),
('id', 'not in', purchase_ids.ids),
]}
@@ -48,7 +46,7 @@ class AccountInvoice(models.Model):
date = self.date_invoice
data = {
'purchase_line_id': line.id,
'name': line.order_id.name+': '+line.name,
'name': line.order_id.name + ': ' + line.name,
'origin': line.order_id.origin,
'uom_id': line.product_uom.id,
'product_id': line.product_id.id,
@@ -243,7 +241,7 @@ class AccountInvoice(models.Model):
invoice = super(AccountInvoice, self).create(vals)
purchase = invoice.invoice_line_ids.mapped('purchase_line_id.order_id')
if purchase and not invoice.refund_invoice_id:
message = _("This vendor bill has been created from: %s") % (",".join(["<a href=# data-oe-model=purchase.order data-oe-id="+str(order.id)+">"+order.name+"</a>" for order in purchase]))
message = _("This vendor bill has been created from: %s") % (",".join(["<a href=# data-oe-model=purchase.order data-oe-id=" + str(order.id) + ">" + order.name + "</a>" for order in purchase]))
invoice.message_post(body=message)
return invoice
@@ -257,7 +255,7 @@ class AccountInvoice(models.Model):
#To get all po reference when updating invoice line or adding purchase order reference from vendor bill.
purchase = (purchase_old | purchase_new) - (purchase_old & purchase_new)
if purchase:
message = _("This vendor bill has been modified from: %s") % (",".join(["<a href=# data-oe-model=purchase.order data-oe-id="+str(order.id)+">"+order.name+"</a>" for order in purchase]))
message = _("This vendor bill has been modified from: %s") % (",".join(["<a href=# data-oe-model=purchase.order data-oe-id=" + str(order.id) + ">" + order.name + "</a>" for order in purchase]))
invoice.message_post(body=message)
return result
+73
View File
@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, tools
from odoo.tools import formatLang
class PurchaseBillUnion(models.Model):
_name = 'purchase.bill.union'
_auto = False
_description = 'Bills & Purchases'
_order = "purchase_order_id desc, vendor_bill_id desc"
name = fields.Char(string='Reference', readonly=True)
reference = fields.Char(string='Source', readonly=True)
partner_id = fields.Many2one('res.partner', string='Vendor', readonly=True)
date = fields.Date(string='Date', readonly=True)
amount = fields.Float(string='Amount', readonly=True)
currency_id = fields.Many2one('res.currency', string='Currency', readonly=True)
company_id = fields.Many2one('res.company', 'Company', readonly=True)
vendor_bill_id = fields.Many2one('account.invoice', string='Vendor Bill', readonly=True)
purchase_order_id = fields.Many2one('purchase.order', string='Purchase Order', readonly=True)
@api.model_cr
def init(self):
tools.drop_view_if_exists(self.env.cr, 'purchase_bill_union')
self.env.cr.execute("""
CREATE OR REPLACE VIEW purchase_bill_union AS (
SELECT
id, number as name, reference, partner_id, date, amount_untaxed as amount, currency_id, company_id,
id as vendor_bill_id, NULL as purchase_order_id
FROM account_invoice
WHERE
type='in_invoice' and state in ('open','paid','cancel')
UNION
SELECT
-id, name, partner_ref, partner_id, date_order as date, amount_untaxed as amount, currency_id, company_id,
NULL as vendor_bill_id, id as purchase_order_id
FROM purchase_order
WHERE
state = 'purchase' AND
invoice_status in ('to invoice', 'no')
)""")
def name_get(self):
result = []
for doc in self:
name = doc.name or ''
if doc.reference:
name += ' - ' + doc.reference
amount = doc.amount
if doc.purchase_order_id and doc.purchase_order_id.invoice_status == 'no':
amount = 0.0
name += ': ' + formatLang(self.env, amount, monetary=True, currency_obj=doc.currency_id)
result.append((doc.id, name))
return result
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
vendor_bill_purchase_id = fields.Many2one(
comodel_name='purchase.bill.union',
string='Auto-Complete'
)
@api.onchange('vendor_bill_purchase_id')
def _onchange_bill_purchase_order(self):
if not self.vendor_bill_purchase_id:
return {}
self.purchase_id = self.vendor_bill_purchase_id.purchase_order_id
self.vendor_bill_id = self.vendor_bill_purchase_id.vendor_bill_id
self.vendor_bill_purchase_id = False
return {}
+2 -1
View File
@@ -51,4 +51,5 @@ access_stock_location_purchase_manager,stock.location purchase manager,stock.mod
access_stock_warehouse_orderpoint_manager,stock.warehouse.orderpoint,stock.model_stock_warehouse_orderpoint,purchase.group_purchase_manager,1,0,0,0
access_stock_warehouse_orderpoint_user,stock.warehouse.orderpoint,stock.model_stock_warehouse_orderpoint,group_purchase_user,1,0,0,0
access_product_price_history_purchase_user,prices.history purchase user,product.model_product_price_history,purchase.group_purchase_user,1,0,0,0
access_product_price_history_purchase_manager,prices.history purchase manager,product.model_product_price_history,purchase.group_purchase_manager,1,1,1,1
access_product_price_history_purchase_manager,prices.history purchase manager,product.model_product_price_history,purchase.group_purchase_manager,1,1,1,1
access_purchase_bill_union,access_purchase_bill_union,model_purchase_bill_union,purchase.group_purchase_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
51 access_stock_warehouse_orderpoint_manager stock.warehouse.orderpoint stock.model_stock_warehouse_orderpoint purchase.group_purchase_manager 1 0 0 0
52 access_stock_warehouse_orderpoint_user stock.warehouse.orderpoint stock.model_stock_warehouse_orderpoint group_purchase_user 1 0 0 0
53 access_product_price_history_purchase_user prices.history purchase user product.model_product_price_history purchase.group_purchase_user 1 0 0 0
54 access_product_price_history_purchase_manager prices.history purchase manager product.model_product_price_history purchase.group_purchase_manager 1 1 1 1
55 access_purchase_bill_union access_purchase_bill_union model_purchase_bill_union purchase.group_purchase_user 1 0 0 0
@@ -69,5 +69,11 @@
<field name="domain_force">['|',('order_id.message_partner_ids','child_of',[user.commercial_partner_id.id]),('order_id.partner_id','child_of',[user.commercial_partner_id.id])]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record>
<record model="ir.rule" id="purchase_bill_union_comp_rule">
<field name="name">Purchases &amp; Bills Union multi-company</field>
<field name="model_id" ref="model_purchase_bill_union"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
</data>
</odoo>
@@ -56,10 +56,18 @@
<field name="name">account.invoice.supplier.purchase</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="groups_id" eval="[(4,ref('purchase.group_purchase_user'))]"/>
<field name="arch" type="xml">
<field name="reference" position="after" >
<field name="purchase_id" attrs="{'readonly': [('state','not in',['draft'])], 'invisible': ['|', ('state', '=', 'purchase'), ('type', '=', 'in_refund')]}" class="oe_edit_only"
options="{'no_create': True}" context="{'show_total_amount': True}"/>
<field name="vendor_bill_id" position="after">
<field name="vendor_bill_purchase_id" attrs="{'invisible': ['|', '|', ('state','not in',['draft']), ('state', '=', 'purchase'), ('type', '=', 'in_refund')]}"
class="oe_edit_only" domain="[('partner_id','child_of',[partner_id])]"
placeholder="Select a purchase order or an old bill"
options="{'no_create': True, 'no_open': True}"/>
<field name="purchase_id" class="oe_edit_only"
invisible="1" context="{'show_total_amount': True}"/>
</field>
<field name="vendor_bill_id" position="attributes">
<attribute name="attrs">{'invisible': ['|', ('type', '=', 'in_invoice'), ('state', 'not in', ['draft'])]}</attribute>
</field>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='company_id']" position="after">
<field name="purchase_line_id" invisible="1" readonly="0"/>
@@ -78,4 +86,37 @@
</field>
</field>
</record>
<record id="view_purchase_bill_union_filter" model="ir.ui.view">
<field name="name">purchase.bill.union.select</field>
<field name="model">purchase.bill.union</field>
<field name="arch" type="xml">
<search string="Search Reference Document">
<field name="name" string="Reference" filter_domain="['|', ('name','ilike',self), ('reference','=like',str(self)+'%')]"/>
<field name="amount"/>
<separator/>
<field name="partner_id" operator="child_of"/>
<separator/>
<filter name="purchase_orders" string="Purchase Orders" domain="[('purchase_order_id', '!=', False)]"/>
<filter name="vendor_bills" string="Vendor Bills" domain="[('vendor_bill_id', '!=', False)]"/>
</search>
</field>
</record>
<record id="view_purchase_bill_union_tree" model="ir.ui.view">
<field name="name">purchase.bill.union.tree</field>
<field name="model">purchase.bill.union</field>
<field name="arch" type="xml">
<tree string="Reference Document">
<field name="name"/>
<field name="reference"/>
<field name="partner_id"/>
<field name="date"/>
<field name="amount"/>
<field name="currency_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</tree>
</field>
</record>
</odoo>