When creating a Vendor Bill, the default Sales Team & Person of the company is assigned to the Vendor Bill. The field isn't even displayed, it's hidden, you can only display it with Studio and can't even change it. The fact is : purchases and sales are two completely different roles and business in companies. This has the indirect consequence that any user that follows the default Sales Team will get notified of any new Vendor Bill created in Accounting, which he very likely does not need/want to see. This PR correct that by adding a condition on the filling of these fields. These fields will be filled when the move is a sale document. closes odoo/odoo#120628 Task-id: 3279233 Related: odoo/enterprise#44034 Signed-off-by: Florian Gilbert (flg) <flg@odoo.com>
168 lines
7.0 KiB
Python
168 lines
7.0 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.exceptions import UserError
|
|
|
|
|
|
class AccountMove(models.Model):
|
|
_name = 'account.move'
|
|
_inherit = ['account.move', 'utm.mixin']
|
|
|
|
@api.model
|
|
def _get_invoice_default_sale_team(self):
|
|
return self.env['crm.team']._get_default_team_id()
|
|
|
|
team_id = fields.Many2one(
|
|
'crm.team', string='Sales Team', default=_get_invoice_default_sale_team,
|
|
compute='_compute_team_id', store=True, readonly=False,
|
|
ondelete="set null", tracking=True,
|
|
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
|
|
|
|
# UTMs - enforcing the fact that we want to 'set null' when relation is unlinked
|
|
campaign_id = fields.Many2one(ondelete='set null')
|
|
medium_id = fields.Many2one(ondelete='set null')
|
|
source_id = fields.Many2one(ondelete='set null')
|
|
sale_order_count = fields.Integer(compute="_compute_origin_so_count", string='Sale Order Count')
|
|
|
|
def unlink(self):
|
|
downpayment_lines = self.mapped('line_ids.sale_line_ids').filtered(lambda line: line.is_downpayment and line.invoice_lines <= self.mapped('line_ids'))
|
|
res = super(AccountMove, self).unlink()
|
|
if downpayment_lines:
|
|
downpayment_lines.unlink()
|
|
return res
|
|
|
|
@api.depends('invoice_user_id')
|
|
def _compute_team_id(self):
|
|
for move in self:
|
|
if not move.invoice_user_id.sale_team_id or not move.is_sale_document(include_receipts=True):
|
|
continue
|
|
move.team_id = self.env['crm.team']._get_default_team_id(
|
|
user_id=move.invoice_user_id.id,
|
|
domain=[('company_id', '=', move.company_id.id)])
|
|
|
|
@api.depends('line_ids.sale_line_ids')
|
|
def _compute_origin_so_count(self):
|
|
for move in self:
|
|
move.sale_order_count = len(move.line_ids.sale_line_ids.order_id)
|
|
|
|
def _reverse_moves(self, default_values_list=None, cancel=False):
|
|
# OVERRIDE
|
|
if not default_values_list:
|
|
default_values_list = [{} for move in self]
|
|
for move, default_values in zip(self, default_values_list):
|
|
default_values.update({
|
|
'campaign_id': move.campaign_id.id,
|
|
'medium_id': move.medium_id.id,
|
|
'source_id': move.source_id.id,
|
|
})
|
|
return super()._reverse_moves(default_values_list=default_values_list, cancel=cancel)
|
|
|
|
def action_post(self):
|
|
#inherit of the function from account.move to validate a new tax and the priceunit of a downpayment
|
|
res = super(AccountMove, self).action_post()
|
|
down_payment_lines = self.line_ids.filtered('is_downpayment')
|
|
for line in down_payment_lines:
|
|
if any(order.locked for order in line.sale_line_ids.order_id):
|
|
# We cannot change lines content on locked SO, changes on invoices are not
|
|
# forwarded to the SO if the SO is locked.
|
|
continue
|
|
|
|
if not line.sale_line_ids.display_type:
|
|
line.sale_line_ids._compute_name()
|
|
|
|
line.sale_line_ids.tax_id = line.tax_ids
|
|
line.sale_line_ids.price_unit = line.price_unit
|
|
return res
|
|
|
|
def button_draft(self):
|
|
res = super().button_draft()
|
|
|
|
self.line_ids.filtered('is_downpayment').sale_line_ids.filtered(
|
|
lambda sol: not sol.display_type)._compute_name()
|
|
|
|
return res
|
|
|
|
def button_cancel(self):
|
|
res = super().button_cancel()
|
|
|
|
self.line_ids.filtered('is_downpayment').sale_line_ids.filtered(
|
|
lambda sol: not sol.display_type)._compute_name()
|
|
|
|
return res
|
|
|
|
def _post(self, soft=True):
|
|
# OVERRIDE
|
|
# Auto-reconcile the invoice with payments coming from transactions.
|
|
# It's useful when you have a "paid" sale order (using a payment transaction) and you invoice it later.
|
|
posted = super()._post(soft)
|
|
|
|
for invoice in posted.filtered(lambda move: move.is_invoice()):
|
|
payments = invoice.mapped('transaction_ids.payment_id').filtered(lambda x: x.state == 'posted')
|
|
move_lines = payments.line_ids.filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable') and not line.reconciled)
|
|
for line in move_lines:
|
|
invoice.js_assign_outstanding_line(line.id)
|
|
return posted
|
|
|
|
def _invoice_paid_hook(self):
|
|
# OVERRIDE
|
|
res = super(AccountMove, self)._invoice_paid_hook()
|
|
todo = set()
|
|
for invoice in self.filtered(lambda move: move.is_invoice()):
|
|
for line in invoice.invoice_line_ids:
|
|
for sale_line in line.sale_line_ids:
|
|
todo.add((sale_line.order_id, invoice.name))
|
|
for (order, name) in todo:
|
|
order.message_post(body=_("Invoice %s paid", name))
|
|
return res
|
|
|
|
def _action_invoice_ready_to_be_sent(self):
|
|
# OVERRIDE
|
|
# Make sure the send invoice CRON is called when an invoice becomes ready to be sent by mail.
|
|
res = super()._action_invoice_ready_to_be_sent()
|
|
|
|
send_invoice_cron = self.env.ref('sale.send_invoice_cron', raise_if_not_found=False)
|
|
if send_invoice_cron:
|
|
send_invoice_cron._trigger()
|
|
|
|
return res
|
|
|
|
def action_view_source_sale_orders(self):
|
|
self.ensure_one()
|
|
source_orders = self.line_ids.sale_line_ids.order_id
|
|
result = self.env['ir.actions.act_window']._for_xml_id('sale.action_orders')
|
|
if len(source_orders) > 1:
|
|
result['domain'] = [('id', 'in', source_orders.ids)]
|
|
elif len(source_orders) == 1:
|
|
result['views'] = [(self.env.ref('sale.view_order_form', False).id, 'form')]
|
|
result['res_id'] = source_orders.id
|
|
else:
|
|
result = {'type': 'ir.actions.act_window_close'}
|
|
return result
|
|
|
|
def _is_downpayment(self):
|
|
# OVERRIDE
|
|
self.ensure_one()
|
|
return self.line_ids.sale_line_ids and all(sale_line.is_downpayment for sale_line in self.line_ids.sale_line_ids) or False
|
|
|
|
@api.depends('line_ids.sale_line_ids.order_id', 'currency_id', 'tax_totals', 'date')
|
|
def _compute_partner_credit(self):
|
|
super()._compute_partner_credit()
|
|
for move in self.filtered(lambda m: m.is_invoice(include_receipts=True)):
|
|
sale_orders = move.line_ids.sale_line_ids.order_id
|
|
amount_total_currency = move.currency_id._convert(
|
|
move.tax_totals['amount_total'],
|
|
move.company_currency_id,
|
|
move.company_id,
|
|
move.date
|
|
)
|
|
amount_to_invoice_currency = sum(
|
|
sale_order.currency_id._convert(
|
|
sale_order.amount_to_invoice,
|
|
move.company_currency_id,
|
|
move.company_id,
|
|
move.date
|
|
) for sale_order in sale_orders
|
|
)
|
|
move.partner_credit += max(amount_total_currency - amount_to_invoice_currency, 0.0)
|