Public release from ruodoo-project: 19.0 - 2026-11-01 22:52:25 UTC
This commit is contained in:
132
rsbu_fns_reporting/models/rsbu_upd_generation.py
Normal file
132
rsbu_fns_reporting/models/rsbu_upd_generation.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""Ручное формирование документа реализации (и УПД) из инвойса Odoo.
|
||||
|
||||
Пользователь оформляет и проводит инвойс (account.move, out_invoice) —
|
||||
РСБУ-слой формирует проводку реализации с зачётом авансов (резолвер
|
||||
shipment_upd). Документ реализации (rsbu.realization), из которого затем
|
||||
выгружается/печатается УПД, создаётся НЕ автоматически, а по кнопке
|
||||
«Создать документ реализации» на форме инвойса.
|
||||
|
||||
Документ реализации создаётся для ЛЮБОЙ отгрузки — облагаемой НДС и
|
||||
«Без НДС». При наличии НДС хотя бы в одной строке он порождает подчинённый
|
||||
отгрузочный счёт-фактуру (rsbu.invoice, тип «shipment»).
|
||||
|
||||
Жизненный цикл закрывающего документа отражает поле closing_document на
|
||||
инвойсе:
|
||||
not_done — закрывающий документ не сформирован;
|
||||
issued — документ реализации оформлен, ждём подпись клиента;
|
||||
signed — клиент подписал (проставляется вручную).
|
||||
|
||||
При создании документа реализации статус переходит в «issued». При
|
||||
удалении/отмене реализации — возвращается в «not_done» (хук на
|
||||
rsbu.realization). В «signed» статус переводит только человек. Исходная
|
||||
РСБУ-проводка инвойса при формировании УПД не меняется: реализация и СФ —
|
||||
документы-надстройки, собственных проводок отгрузки не создают (их уже
|
||||
сформировал резолвер при проведении).
|
||||
"""
|
||||
from odoo import _, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
closing_document = fields.Selection(
|
||||
selection=[
|
||||
('not_done', 'Не сделан'),
|
||||
('issued', 'Оформлен'),
|
||||
('signed', 'Подписан'),
|
||||
],
|
||||
string='Закрывающий документ', default='not_done', copy=False,
|
||||
tracking=True,
|
||||
help='Состояние закрывающего документа (УПД) по реализации: '
|
||||
'«Не сделан» — документ реализации не сформирован; '
|
||||
'«Оформлен» — создан, ждём подпись клиента; «Подписан» — '
|
||||
'клиент подписал (ставится вручную).')
|
||||
|
||||
# Связанный документ реализации РСБУ (источник УПД).
|
||||
rsbu_realization_id = fields.Many2one(
|
||||
'rsbu.realization', string='Документ реализации (УПД)', copy=False,
|
||||
compute='_compute_rsbu_realization_id', store=False,
|
||||
help='Документ реализации РСБУ-слоя, сформированный по этому инвойсу '
|
||||
'для выгрузки/печати УПД.')
|
||||
|
||||
def _compute_rsbu_realization_id(self):
|
||||
Realization = self.env['rsbu.realization'].sudo()
|
||||
for move in self:
|
||||
move.rsbu_realization_id = Realization.search([
|
||||
('source_model', '=', 'account.move'),
|
||||
('source_res_id', '=', move.id),
|
||||
('state', '!=', 'cancelled'),
|
||||
('company_id', '=', move.company_id.id),
|
||||
], limit=1)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
def _upd_can_create(self):
|
||||
"""Можно ли сформировать документ реализации по этому инвойсу.
|
||||
|
||||
Документ реализации формируется по любой проведённой реализации
|
||||
(out_invoice, с НДС и без), если он ещё не создан.
|
||||
"""
|
||||
self.ensure_one()
|
||||
return bool(
|
||||
self.move_type == 'out_invoice'
|
||||
and self.state == 'posted'
|
||||
and not self.rsbu_realization_id
|
||||
)
|
||||
|
||||
def action_create_realization(self):
|
||||
"""Сформировать документ реализации (и УПД) по инвойсу.
|
||||
|
||||
Всегда создаётся rsbu.realization; при наличии НДS хотя бы в одной
|
||||
строке — дополнительно порождается подчинённый отгрузочный СФ.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.move_type != 'out_invoice':
|
||||
raise UserError(_(
|
||||
'Документ реализации формируется только по счёту покупателю '
|
||||
'(реализация).'))
|
||||
if self.state != 'posted':
|
||||
raise UserError(_(
|
||||
'Проведите инвойс перед формированием документа реализации.'))
|
||||
if self.rsbu_realization_id:
|
||||
raise UserError(_(
|
||||
'По этому инвойсу уже сформирован документ реализации: %s.')
|
||||
% self.rsbu_realization_id.name)
|
||||
|
||||
Realization = self.env['rsbu.realization'].sudo()
|
||||
realization = Realization.create({
|
||||
'partner_id': self.partner_id.id,
|
||||
'company_id': self.company_id.id,
|
||||
'date': self.invoice_date or self.date or fields.Date.today(),
|
||||
'source_model': 'account.move',
|
||||
'source_res_id': self.id,
|
||||
'amount_untaxed': abs(self.amount_untaxed),
|
||||
'amount_tax': abs(self.amount_tax),
|
||||
'state': 'confirmed',
|
||||
})
|
||||
if realization._has_vat(self):
|
||||
realization._create_shipment_invoice()
|
||||
self.closing_document = 'issued'
|
||||
# Связь rsbu_realization_id — non-stored computed; сбрасываем кэш,
|
||||
# чтобы кнопки/статус сразу отразили созданную реализацию.
|
||||
self.invalidate_recordset(['rsbu_realization_id'])
|
||||
return self._upd_open_realization(realization)
|
||||
|
||||
def action_open_realization(self):
|
||||
"""Открыть сформированный документ реализации (УПД)."""
|
||||
self.ensure_one()
|
||||
realization = self.rsbu_realization_id
|
||||
if not realization:
|
||||
raise UserError(_(
|
||||
'По этому инвойсу документ реализации ещё не сформирован.'))
|
||||
return self._upd_open_realization(realization)
|
||||
|
||||
def _upd_open_realization(self, realization):
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': _('Документ реализации (УПД)'),
|
||||
'res_model': 'rsbu.realization',
|
||||
'view_mode': 'form',
|
||||
'res_id': realization.id,
|
||||
'target': 'current',
|
||||
}
|
||||
Reference in New Issue
Block a user