112 lines
4.6 KiB
Python
112 lines
4.6 KiB
Python
|
||
from datetime import date
|
||
|
||
from odoo import api, fields, models
|
||
|
||
|
||
class SaleOrder(models.Model):
|
||
_inherit = 'sale.order'
|
||
|
||
price_alarm = fields.Boolean(
|
||
string='Цены требуют проверки',
|
||
compute='_compute_price_alarm', store=True,
|
||
)
|
||
type_validation = fields.Selection(
|
||
[
|
||
('balance', 'По балансу'),
|
||
('overdraft', 'По балансу + овердрафт'),
|
||
('normal', 'По подтверждению'),
|
||
],
|
||
string='Тип контроля отгрузки', default='normal',
|
||
)
|
||
state = fields.Selection(
|
||
selection_add=[('wait', 'Ожидание оплаты')],
|
||
ondelete={'wait': 'set default'},
|
||
)
|
||
|
||
@api.depends('partner_id', 'order_line', 'order_line.price_unit', 'state')
|
||
def _compute_price_alarm(self):
|
||
SaleLine = self.env['sale.order.line']
|
||
for order in self:
|
||
if order.state != 'draft':
|
||
order.price_alarm = False
|
||
continue
|
||
alarm = False
|
||
partner = order.partner_id.parent_id or order.partner_id
|
||
for line in order.order_line:
|
||
if not line.product_id:
|
||
continue
|
||
previous_prices = SaleLine.search([
|
||
('order_id.partner_id', '=', partner.id),
|
||
('order_id.state', '=', 'sale'),
|
||
('product_id', '=', line.product_id.id),
|
||
]).sorted(
|
||
key=lambda ln: ln.order_id.date_order or fields.Datetime.now(),
|
||
reverse=True,
|
||
).mapped('price_unit')
|
||
# Сравниваем только с последней отгрузкой этому клиенту.
|
||
if previous_prices and line.price_unit < previous_prices[0]:
|
||
alarm = True
|
||
order.price_alarm = alarm
|
||
|
||
def _get_shipment_credit(self):
|
||
"""Долг и лимит кредита партнёра (с учётом головного контрагента)."""
|
||
self.ensure_one()
|
||
partner = self.partner_id.parent_id or self.partner_id
|
||
return partner.credit, partner.credit_limit
|
||
|
||
def _is_shipment_allowed(self):
|
||
"""Проверка финансовых условий отгрузки по выбранному типу контроля."""
|
||
self.ensure_one()
|
||
# Расчёт долга ведём в контексте компании заказа (без мутации env).
|
||
order = self.with_company(self.company_id)
|
||
credit, credit_limit = order._get_shipment_credit()
|
||
if self.type_validation == 'normal':
|
||
return True
|
||
if self.type_validation == 'balance':
|
||
return credit * (-1) >= self.amount_total
|
||
if self.type_validation == 'overdraft':
|
||
return credit * (-1) + credit_limit >= self.amount_total
|
||
return False
|
||
|
||
def action_confirm(self):
|
||
confirmable = self.env['sale.order']
|
||
for order in self:
|
||
if order._is_shipment_allowed():
|
||
order._log_shipment_activity()
|
||
# Заказ в ожидании оплаты вернём в черновик, чтобы штатный
|
||
# action_confirm принял его к подтверждению.
|
||
if order.state == 'wait':
|
||
order.state = 'draft'
|
||
confirmable |= order
|
||
elif order.state != 'wait':
|
||
order.message_post(
|
||
body='Проверка фин. условий оставила заказ в ожидании оплаты.'
|
||
)
|
||
order.state = 'wait'
|
||
if confirmable:
|
||
return super(SaleOrder, confirmable).action_confirm()
|
||
return True
|
||
|
||
def _log_shipment_activity(self):
|
||
self.ensure_one()
|
||
activity_type = self.env.ref(
|
||
'ruodoo_sale_control.mail_activity_shipment_allowed',
|
||
raise_if_not_found=False,
|
||
)
|
||
if not activity_type:
|
||
return
|
||
self.env['mail.activity'].create({
|
||
'res_model_id': self.env.ref('sale.model_sale_order').id,
|
||
'res_id': self.id,
|
||
'user_id': self.user_id.id,
|
||
'activity_type_id': activity_type.id,
|
||
'date_deadline': date.today(),
|
||
})
|
||
|
||
@api.model
|
||
def validate_all(self):
|
||
"""Повторно проверить все заказы в ожидании оплаты (cron/действие)."""
|
||
for order in self.search([('state', '=', 'wait')]):
|
||
order.action_confirm()
|