Files
odoo_source/addons/purchase/models/account_invoice.py
T

180 lines
8.4 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.tools.float_utils import float_compare
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='Load the vendor bill based on selected purchase order. Several PO can be selected.'
)
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 {}
@api.onchange('state', 'partner_id', 'invoice_line_ids')
def _onchange_allowed_purchase_ids(self):
'''
The purpose of the method is to define a domain for the available
purchase orders.
'''
result = {}
# A PO can be selected only if at least one PO line is not already in the invoice
purchase_line_ids = self.invoice_line_ids.mapped('purchase_line_id')
purchase_ids = self.invoice_line_ids.mapped('purchase_id').filtered(lambda r: r.order_line <= purchase_line_ids)
result['domain'] = {'purchase_id': [
('invoice_status', 'in', ['to invoice', 'no']),
('partner_id', 'child_of', self.partner_id.id),
('id', 'not in', purchase_ids.ids),
]}
return result
def _prepare_invoice_line_from_po_line(self, line):
if line.product_id.purchase_method == 'purchase':
qty = line.product_qty - line.qty_invoiced
else:
qty = line.qty_received - line.qty_invoiced
if float_compare(qty, 0.0, precision_rounding=line.product_uom.rounding) <= 0:
qty = 0.0
taxes = line.taxes_id
invoice_line_tax_ids = line.order_id.fiscal_position_id.map_tax(taxes, line.product_id, line.order_id.partner_id)
invoice_line = self.env['account.invoice.line']
date = self.date
data = {
'purchase_line_id': line.id,
'name': line.order_id.name + ': ' + line.name,
'origin': line.order_id.origin,
'uom_id': line.product_uom.id,
'product_id': line.product_id.id,
'account_id': invoice_line.with_context({'journal_id': self.journal_id.id, 'type': 'in_invoice'})._default_account(),
'price_unit': line.order_id.currency_id._convert(
line.price_unit, self.currency_id, line.company_id, date or fields.Date.today(), round=False),
'quantity': qty,
'discount': 0.0,
'account_analytic_id': line.account_analytic_id.id,
'analytic_tag_ids': line.analytic_tag_ids.ids,
'invoice_line_tax_ids': invoice_line_tax_ids.ids
}
account = invoice_line.get_invoice_line_account('in_invoice', line.product_id, line.order_id.fiscal_position_id, self.env.user.company_id)
if account:
data['account_id'] = account.id
return data
def _onchange_product_id(self):
domain = super(AccountInvoice, self)._onchange_product_id()
if self.purchase_id:
# Use the purchase uom by default
self.uom_id = self.product_id.uom_po_id
return domain
# Load all unsold PO lines
@api.onchange('purchase_id')
def purchase_order_change(self):
if not self.purchase_id:
return {}
if not self.partner_id:
self.partner_id = self.purchase_id.partner_id.id
if not self.invoice_line_ids:
#as there's no invoice line yet, we keep the currency of the PO
self.currency_id = self.purchase_id.currency_id
new_lines = self.env['account.invoice.line']
for line in self.purchase_id.order_line - self.invoice_line_ids.mapped('purchase_line_id'):
data = self._prepare_invoice_line_from_po_line(line)
new_line = new_lines.new(data)
new_line._set_additional_fields(self)
new_lines += new_line
self.invoice_line_ids += new_lines
self.payment_term_id = self.purchase_id.payment_term_id
self.env.context = dict(self.env.context, from_purchase_order_change=True)
self.purchase_id = False
return {}
@api.onchange('currency_id')
def _onchange_currency_id(self):
if self.currency_id:
for line in self.invoice_line_ids.filtered(lambda r: r.purchase_line_id):
date = self.date or fields.Date.today()
company = self.company_id
line.price_unit = line.purchase_id.currency_id._convert(
line.purchase_line_id.price_unit, self.currency_id, company, date, round=False)
@api.onchange('invoice_line_ids')
def _onchange_origin(self):
purchase_ids = self.invoice_line_ids.mapped('purchase_id')
if purchase_ids:
self.origin = ', '.join(purchase_ids.mapped('name'))
@api.onchange('partner_id', 'company_id')
def _onchange_partner_id(self):
payment_term_id = self.env.context.get('from_purchase_order_change') and self.payment_term_id or False
res = super(AccountInvoice, self)._onchange_partner_id()
if payment_term_id:
self.payment_term_id = payment_term_id
if not self.env.context.get('default_journal_id') and self.partner_id and self.currency_id and\
self.type in ['in_invoice', 'in_refund'] and\
self.currency_id != self.partner_id.property_purchase_currency_id and\
self.partner_id.property_purchase_currency_id.id:
journal_domain = [
('type', '=', 'purchase'),
('company_id', '=', self.company_id.id),
('currency_id', '=', self.partner_id.property_purchase_currency_id.id),
]
default_journal_id = self.env['account.journal'].search(journal_domain, limit=1)
if default_journal_id:
self.journal_id = default_journal_id
if self.env.context.get('default_currency_id'):
self.currency_id = self.env.context['default_currency_id']
return res
@api.model
def create(self, vals):
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]))
invoice.message_post(body=message)
return invoice
@api.multi
def write(self, vals):
result = True
for invoice in self:
purchase_old = invoice.invoice_line_ids.mapped('purchase_line_id.order_id')
result = result and super(AccountInvoice, invoice).write(vals)
purchase_new = invoice.invoice_line_ids.mapped('purchase_line_id.order_id')
#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]))
invoice.message_post(body=message)
return result
class AccountInvoiceLine(models.Model):
""" Override AccountInvoice_line to add the link to the purchase order line it is related to"""
_inherit = 'account.invoice.line'
purchase_line_id = fields.Many2one('purchase.order.line', 'Purchase Order Line', ondelete='set null', index=True, readonly=True)
purchase_id = fields.Many2one('purchase.order', related='purchase_line_id.order_id', string='Purchase Order', store=False, readonly=True, related_sudo=False,
help='Associated Purchase Order. Filled in automatically when a PO is chosen on the vendor bill.')