Public release from ruodoo-project: 19.0 - 2026-05-31 21:19:12 UTC
This commit is contained in:
228
l10n_ru_contract_account/tests/test_contract_account.py
Normal file
228
l10n_ru_contract_account/tests/test_contract_account.py
Normal file
@ -0,0 +1,228 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Tests for l10n_ru_contract_account — invoice field validation against contract.
|
||||
|
||||
Validates: Requirements 15.1, 15.2, 15.3, 15.4
|
||||
"""
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _get_or_create_partner(env, parent=None):
|
||||
"""Return or create a company partner, optionally with a parent."""
|
||||
partner = env['res.partner'].create({
|
||||
'name': 'Test Partner CA',
|
||||
'is_company': True,
|
||||
'parent_id': parent.id if parent else False,
|
||||
})
|
||||
return partner
|
||||
|
||||
|
||||
def _get_or_create_accounts(env):
|
||||
"""Return a receivable and payable account for the current company."""
|
||||
receivable = env['account.account'].search([
|
||||
('account_type', '=', 'asset_receivable'),
|
||||
('company_ids', 'in', env.company.id),
|
||||
], limit=1)
|
||||
payable = env['account.account'].search([
|
||||
('account_type', '=', 'liability_payable'),
|
||||
('company_ids', 'in', env.company.id),
|
||||
], limit=1)
|
||||
return receivable, payable
|
||||
|
||||
|
||||
def _get_or_create_journal(env, name='Test Sales Journal CA'):
|
||||
"""Return or create a sales journal."""
|
||||
journal = env['account.journal'].search([
|
||||
('type', '=', 'sale'),
|
||||
('company_id', '=', env.company.id),
|
||||
], limit=1)
|
||||
if not journal:
|
||||
journal = env['account.journal'].create({
|
||||
'name': name,
|
||||
'type': 'sale',
|
||||
'code': 'TSCA',
|
||||
'company_id': env.company.id,
|
||||
})
|
||||
return journal
|
||||
|
||||
|
||||
def _get_or_create_payment_term(env):
|
||||
"""Return or create a payment term."""
|
||||
term = env['account.payment.term'].search([], limit=1)
|
||||
if not term:
|
||||
term = env['account.payment.term'].create({'name': 'Immediate CA'})
|
||||
return term
|
||||
|
||||
|
||||
def _make_profile(env, journal, payment_term, receivable, payable):
|
||||
"""Create a contract.profile with all required account fields."""
|
||||
return env['contract.profile'].create({
|
||||
'name': 'Test Profile CA',
|
||||
'journal_id': journal.id,
|
||||
'payment_term_id': payment_term.id,
|
||||
'receivable_account_id': receivable.id,
|
||||
'payable_account_id': payable.id,
|
||||
'max_receivable_id': 100000.0,
|
||||
})
|
||||
|
||||
|
||||
def _make_contract(env, partner, profile):
|
||||
"""Create a minimal partner.contract.customer."""
|
||||
return env['partner.contract.customer'].create({
|
||||
'date_start': '2024-01-01',
|
||||
'date_end': '2024-12-31',
|
||||
'type': 'customer',
|
||||
'profile_id': profile.id,
|
||||
'partner_id': partner.id,
|
||||
'partner_type': 'company',
|
||||
'company_id': env.company.id,
|
||||
})
|
||||
|
||||
|
||||
def _make_invoice(env, partner, journal, payment_term, contract, receivable_account):
|
||||
"""Create a draft out_invoice linked to a contract."""
|
||||
product = env['product.product'].search([], limit=1)
|
||||
income_account = env['account.account'].search([
|
||||
('account_type', '=', 'income'),
|
||||
('company_ids', 'in', env.company.id),
|
||||
], limit=1)
|
||||
if not income_account:
|
||||
income_account = receivable_account # fallback
|
||||
|
||||
move = env['account.move'].create({
|
||||
'move_type': 'out_invoice',
|
||||
'partner_id': partner.id,
|
||||
'journal_id': journal.id,
|
||||
'invoice_payment_term_id': payment_term.id,
|
||||
'mt_contract_id': contract.id,
|
||||
'invoice_line_ids': [(0, 0, {
|
||||
'name': 'Test line',
|
||||
'quantity': 1.0,
|
||||
'price_unit': 100.0,
|
||||
'account_id': income_account.id,
|
||||
})],
|
||||
})
|
||||
return move
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TestContractAccountMove
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestContractAccountMove(TransactionCase):
|
||||
"""
|
||||
Tests for invoice field validation against contract profile.
|
||||
|
||||
Validates: Requirements 15.1, 15.2, 15.3, 15.4
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.receivable, self.payable = _get_or_create_accounts(self.env)
|
||||
self.journal = _get_or_create_journal(self.env)
|
||||
self.payment_term = _get_or_create_payment_term(self.env)
|
||||
self.partner = _get_or_create_partner(self.env)
|
||||
self.profile = _make_profile(
|
||||
self.env, self.journal, self.payment_term,
|
||||
self.receivable, self.payable,
|
||||
)
|
||||
self.contract = _make_contract(self.env, self.partner, self.profile)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 15.1 — journal mismatch raises ValidationError on post
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_invoice_posted_journal_mismatch_raises(self):
|
||||
"""
|
||||
Req 15.1 — posting an invoice whose journal differs from the contract's
|
||||
profile journal raises ValidationError.
|
||||
"""
|
||||
other_journal = self.env['account.journal'].create({
|
||||
'name': 'Other Journal CA',
|
||||
'type': 'sale',
|
||||
'code': 'OJCA',
|
||||
'company_id': self.env.company.id,
|
||||
})
|
||||
invoice = _make_invoice(
|
||||
self.env, self.partner, other_journal,
|
||||
self.payment_term, self.contract, self.receivable,
|
||||
)
|
||||
with self.assertRaises(ValidationError):
|
||||
invoice.action_post()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 15.2 — payment term mismatch raises ValidationError on post
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_invoice_posted_payment_term_mismatch_raises(self):
|
||||
"""
|
||||
Req 15.2 — posting an invoice whose payment term differs from the
|
||||
contract's profile payment term raises ValidationError.
|
||||
"""
|
||||
other_term = self.env['account.payment.term'].create({
|
||||
'name': 'Other Term CA',
|
||||
})
|
||||
invoice = _make_invoice(
|
||||
self.env, self.partner, self.journal,
|
||||
other_term, self.contract, self.receivable,
|
||||
)
|
||||
with self.assertRaises(ValidationError):
|
||||
invoice.action_post()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 15.3 — matching fields post without errors
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_invoice_posted_matching_contract_ok(self):
|
||||
"""
|
||||
Req 15.3 — posting an invoice whose journal and payment term match
|
||||
the contract profile succeeds without errors.
|
||||
"""
|
||||
invoice = _make_invoice(
|
||||
self.env, self.partner, self.journal,
|
||||
self.payment_term, self.contract, self.receivable,
|
||||
)
|
||||
# Should not raise
|
||||
invoice.action_post()
|
||||
self.assertEqual(invoice.state, 'posted',
|
||||
"Invoice should be in posted state after action_post")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Requirement 15.4 — sec_partner_id computed field
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_compute_sec_partner_id_with_parent(self):
|
||||
"""
|
||||
Req 15.4 — sec_partner_id equals partner_id.parent_id when parent exists.
|
||||
"""
|
||||
parent = _get_or_create_partner(self.env)
|
||||
child = _get_or_create_partner(self.env, parent=parent)
|
||||
|
||||
invoice = self.env['account.move'].create({
|
||||
'move_type': 'out_invoice',
|
||||
'partner_id': child.id,
|
||||
'journal_id': self.journal.id,
|
||||
})
|
||||
self.assertEqual(
|
||||
invoice.sec_partner_id, parent,
|
||||
"sec_partner_id should be partner_id.parent_id when parent exists",
|
||||
)
|
||||
|
||||
def test_compute_sec_partner_id_without_parent(self):
|
||||
"""
|
||||
Req 15.4 — sec_partner_id equals partner_id when partner has no parent.
|
||||
"""
|
||||
invoice = self.env['account.move'].create({
|
||||
'move_type': 'out_invoice',
|
||||
'partner_id': self.partner.id,
|
||||
'journal_id': self.journal.id,
|
||||
})
|
||||
self.assertEqual(
|
||||
invoice.sec_partner_id, self.partner,
|
||||
"sec_partner_id should equal partner_id when no parent exists",
|
||||
)
|
||||
Reference in New Issue
Block a user