diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index 2c0da345e3f..cd8a907c796 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -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"
diff --git a/addons/account/views/account_invoice_view.xml b/addons/account/views/account_invoice_view.xml
index 1eaf678e93e..33a5c8579a7 100644
--- a/addons/account/views/account_invoice_view.xml
+++ b/addons/account/views/account_invoice_view.xml
@@ -238,7 +238,7 @@
-
+
@@ -252,6 +252,10 @@
context="{'default_customer': 0, 'search_default_supplier': 1, 'default_supplier': 1, 'default_company_type': 'company'}"
domain="[('supplier', '=', True)]"/>
+
diff --git a/addons/purchase/models/__init__.py b/addons/purchase/models/__init__.py
index 668d20cc290..d0ec983e287 100644
--- a/addons/purchase/models/__init__.py
+++ b/addons/purchase/models/__init__.py
@@ -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
diff --git a/addons/purchase/models/account_invoice.py b/addons/purchase/models/account_invoice.py
index 33ef682f3d9..025baa47282 100644
--- a/addons/purchase/models/account_invoice.py
+++ b/addons/purchase/models/account_invoice.py
@@ -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([""+order.name+"" for order in purchase]))
+ message = _("This vendor bill has been created from: %s") % (",".join(["" + order.name + "" 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([""+order.name+"" for order in purchase]))
+ message = _("This vendor bill has been modified from: %s") % (",".join(["" + order.name + "" for order in purchase]))
invoice.message_post(body=message)
return result
diff --git a/addons/purchase/models/purchase_bill.py b/addons/purchase/models/purchase_bill.py
new file mode 100644
index 00000000000..02b8051c932
--- /dev/null
+++ b/addons/purchase/models/purchase_bill.py
@@ -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 {}
diff --git a/addons/purchase/security/ir.model.access.csv b/addons/purchase/security/ir.model.access.csv
index 1740c592902..3646eeccffe 100644
--- a/addons/purchase/security/ir.model.access.csv
+++ b/addons/purchase/security/ir.model.access.csv
@@ -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
\ No newline at end of file
+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
diff --git a/addons/purchase/security/purchase_security.xml b/addons/purchase/security/purchase_security.xml
index 73dcd6c1487..75fbca272f6 100644
--- a/addons/purchase/security/purchase_security.xml
+++ b/addons/purchase/security/purchase_security.xml
@@ -69,5 +69,11 @@
['|',('order_id.message_partner_ids','child_of',[user.commercial_partner_id.id]),('order_id.partner_id','child_of',[user.commercial_partner_id.id])]
+
+ Purchases & Bills Union multi-company
+
+
+ ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]
+
diff --git a/addons/purchase/views/account_invoice_views.xml b/addons/purchase/views/account_invoice_views.xml
index f3eabb91534..794311a7263 100644
--- a/addons/purchase/views/account_invoice_views.xml
+++ b/addons/purchase/views/account_invoice_views.xml
@@ -56,10 +56,18 @@
account.invoice.supplier.purchase
account.invoice
+
-
-
+
+
+
+
+
+ {'invisible': ['|', ('type', '=', 'in_invoice'), ('state', 'not in', ['draft'])]}
@@ -78,4 +86,37 @@
+
+
+ purchase.bill.union.select
+ purchase.bill.union
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ purchase.bill.union.tree
+ purchase.bill.union
+
+
+
+
+
+
+
+
+
+
+
+
+