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()