mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-27 03:52:02 +02:00
Initial commit: Sale packages
This commit is contained in:
commit
14e3d26998
6469 changed files with 2479670 additions and 0 deletions
156
odoo-bringout-oca-ocb-sale/sale/models/account_move.py
Normal file
156
odoo-bringout-oca-ocb-sale/sale/models/account_move.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# -*- 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
|
||||
from odoo.tools import groupby
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_name = 'account.move'
|
||||
_inherit = ['account.move', 'utm.mixin']
|
||||
|
||||
team_id = fields.Many2one(
|
||||
'crm.team', string='Sales 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):
|
||||
applicable_moves = self.filtered(
|
||||
lambda move:
|
||||
move.is_sale_document(include_receipts=True)
|
||||
)
|
||||
|
||||
for ((user_id, company_id), moves) in groupby(
|
||||
applicable_moves,
|
||||
key=lambda m: (m.invoice_user_id.id, m.company_id.id)
|
||||
):
|
||||
self.env['account.move'].concat(*moves).team_id = self.env['crm.team'].with_context(
|
||||
allowed_company_ids=[company_id]
|
||||
)._get_default_team_id(
|
||||
user_id=user_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 not line.sale_line_ids.display_type:
|
||||
line.sale_line_ids._compute_name()
|
||||
|
||||
downpayment_lines = self.line_ids.sale_line_ids.filtered(lambda l: l.is_downpayment and not l.display_type)
|
||||
other_so_lines = downpayment_lines.order_id.order_line - downpayment_lines
|
||||
real_invoices = set(other_so_lines.invoice_lines.move_id)
|
||||
for dpl in downpayment_lines:
|
||||
try:
|
||||
dpl.price_unit = dpl._get_downpayment_line_price_unit(real_invoices)
|
||||
dpl.tax_id = dpl.invoice_lines.tax_ids
|
||||
except UserError:
|
||||
# a UserError here means the SO was locked, which prevents changing the taxes
|
||||
# just ignore the error - this is a nice to have feature and should not be blocking
|
||||
pass
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue