336 lines
15 KiB
Python
336 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
from odoo import fields
|
|
from odoo.tests import TransactionCase
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class TestBatchPaymentIntegration(TransactionCase):
|
|
"""Test cases for batch payment integration with deduction functionality"""
|
|
|
|
def setUp(self):
|
|
super(TestBatchPaymentIntegration, self).setUp()
|
|
|
|
# Create test partners (suppliers)
|
|
self.partner1 = self.env['res.partner'].create({
|
|
'name': 'Test Vendor 1',
|
|
'supplier_rank': 1,
|
|
})
|
|
|
|
self.partner2 = self.env['res.partner'].create({
|
|
'name': 'Test Vendor 2',
|
|
'supplier_rank': 1,
|
|
})
|
|
|
|
# Get or create bank journal
|
|
self.journal = self.env['account.journal'].search([
|
|
('type', '=', 'bank'),
|
|
('company_id', '=', self.env.company.id)
|
|
], limit=1)
|
|
|
|
if not self.journal:
|
|
self.journal = self.env['account.journal'].create({
|
|
'name': 'Test Bank',
|
|
'type': 'bank',
|
|
'code': 'TBNK',
|
|
'company_id': self.env.company.id,
|
|
})
|
|
|
|
# Create substract account (expense account)
|
|
self.substract_account = self.env['account.account'].create({
|
|
'name': 'Withholding Tax Account',
|
|
'code': 'WHT001',
|
|
'account_type': 'expense',
|
|
'company_id': self.env.company.id,
|
|
})
|
|
|
|
# Create expense account for batch payment lines
|
|
self.expense_account = self.env['account.account'].create({
|
|
'name': 'General Expense Account',
|
|
'code': 'EXP001',
|
|
'account_type': 'expense',
|
|
'company_id': self.env.company.id,
|
|
})
|
|
|
|
def test_property_batch_payment_line_field_transfer(self):
|
|
"""
|
|
**Feature: vendor-payment-diff-amount, Property 13: Batch payment line field transfer**
|
|
**Validates: Requirements 7.4, 7.5**
|
|
|
|
Property: For any batch payment line with amount_substract and substract_account_id
|
|
values, when payments are generated, the created payment should have the same
|
|
amount_substract and substract_account_id values.
|
|
"""
|
|
# Create batch payment
|
|
batch_payment = self.env['account.batch.payment'].create({
|
|
'journal_id': self.journal.id,
|
|
'batch_type': 'outbound',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Create direct payment lines with deduction fields
|
|
line1 = self.env['account.batch.payment.line'].create({
|
|
'batch_payment_id': batch_payment.id,
|
|
'partner_id': self.partner1.id,
|
|
'amount': 1000.0,
|
|
'amount_substract': 100.0,
|
|
'substract_account_id': self.substract_account.id,
|
|
'expense_account_id': self.expense_account.id,
|
|
'memo': 'Payment 1 with deduction',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
line2 = self.env['account.batch.payment.line'].create({
|
|
'batch_payment_id': batch_payment.id,
|
|
'partner_id': self.partner2.id,
|
|
'amount': 2000.0,
|
|
'amount_substract': 200.0,
|
|
'substract_account_id': self.substract_account.id,
|
|
'expense_account_id': self.expense_account.id,
|
|
'memo': 'Payment 2 with deduction',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Verify lines were created with correct values
|
|
self.assertEqual(line1.amount_substract, 100.0,
|
|
"Line 1 should have amount_substract of 100")
|
|
self.assertEqual(line1.substract_account_id, self.substract_account,
|
|
"Line 1 should have correct substract_account_id")
|
|
self.assertEqual(line2.amount_substract, 200.0,
|
|
"Line 2 should have amount_substract of 200")
|
|
self.assertEqual(line2.substract_account_id, self.substract_account,
|
|
"Line 2 should have correct substract_account_id")
|
|
|
|
# Generate payments from lines
|
|
batch_payment.generate_payments_from_lines()
|
|
|
|
# Verify payments were generated
|
|
self.assertTrue(line1.payment_id, "Payment should be generated for line 1")
|
|
self.assertTrue(line2.payment_id, "Payment should be generated for line 2")
|
|
|
|
# Get the generated payments
|
|
payment1 = line1.payment_id
|
|
payment2 = line2.payment_id
|
|
|
|
# Verify payment 1 has correct deduction fields transferred
|
|
self.assertEqual(payment1.amount, 1000.0,
|
|
"Payment 1 should have amount of 1000")
|
|
self.assertEqual(payment1.amount_substract, 100.0,
|
|
"Payment 1 should have amount_substract of 100 (transferred from line)")
|
|
self.assertEqual(payment1.substract_account_id, self.substract_account,
|
|
"Payment 1 should have correct substract_account_id (transferred from line)")
|
|
self.assertEqual(payment1.final_payment_amount, 900.0,
|
|
"Payment 1 final_payment_amount should be 900 (1000 - 100)")
|
|
|
|
# Verify payment 2 has correct deduction fields transferred
|
|
self.assertEqual(payment2.amount, 2000.0,
|
|
"Payment 2 should have amount of 2000")
|
|
self.assertEqual(payment2.amount_substract, 200.0,
|
|
"Payment 2 should have amount_substract of 200 (transferred from line)")
|
|
self.assertEqual(payment2.substract_account_id, self.substract_account,
|
|
"Payment 2 should have correct substract_account_id (transferred from line)")
|
|
self.assertEqual(payment2.final_payment_amount, 1800.0,
|
|
"Payment 2 final_payment_amount should be 1800 (2000 - 200)")
|
|
|
|
# Verify payments are posted
|
|
self.assertEqual(payment1.state, 'posted', "Payment 1 should be posted")
|
|
self.assertEqual(payment2.state, 'posted', "Payment 2 should be posted")
|
|
|
|
# Verify journal entries have correct structure with deduction lines
|
|
move1 = payment1.move_id
|
|
move2 = payment2.move_id
|
|
|
|
self.assertTrue(move1, "Payment 1 should have journal entry")
|
|
self.assertTrue(move2, "Payment 2 should have journal entry")
|
|
|
|
# Verify payment 1 journal entry has substract line
|
|
substract_lines1 = move1.line_ids.filtered(
|
|
lambda l: l.account_id == self.substract_account
|
|
)
|
|
self.assertGreater(len(substract_lines1), 0,
|
|
"Payment 1 journal entry should have substract account line")
|
|
|
|
# Verify payment 2 journal entry has substract line
|
|
substract_lines2 = move2.line_ids.filtered(
|
|
lambda l: l.account_id == self.substract_account
|
|
)
|
|
self.assertGreater(len(substract_lines2), 0,
|
|
"Payment 2 journal entry should have substract account line")
|
|
|
|
# Verify bank lines have correct amounts (original amount)
|
|
bank_account = payment1.outstanding_account_id
|
|
bank_line1 = move1.line_ids.filtered(lambda l: l.account_id == bank_account)
|
|
bank_line2 = move2.line_ids.filtered(lambda l: l.account_id == bank_account)
|
|
|
|
self.assertAlmostEqual(sum(bank_line1.mapped('credit')), 1000.0, places=2,
|
|
msg="Payment 1 bank credit should be 1000 (original amount)")
|
|
self.assertAlmostEqual(sum(bank_line2.mapped('credit')), 2000.0, places=2,
|
|
msg="Payment 2 bank credit should be 2000 (original amount)")
|
|
|
|
def test_unit_batch_payment_line_fields_exist(self):
|
|
"""
|
|
Unit test: Verify batch payment line model has deduction fields.
|
|
Tests Requirements 7.1, 7.2, 7.3
|
|
"""
|
|
# Create batch payment
|
|
batch_payment = self.env['account.batch.payment'].create({
|
|
'journal_id': self.journal.id,
|
|
'batch_type': 'outbound',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Create batch payment line
|
|
line = self.env['account.batch.payment.line'].create({
|
|
'batch_payment_id': batch_payment.id,
|
|
'partner_id': self.partner1.id,
|
|
'amount': 1000.0,
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Verify fields exist
|
|
self.assertTrue(hasattr(line, 'amount_substract'),
|
|
"Batch payment line should have amount_substract field")
|
|
self.assertTrue(hasattr(line, 'substract_account_id'),
|
|
"Batch payment line should have substract_account_id field")
|
|
|
|
# Verify fields can be set
|
|
line.write({
|
|
'amount_substract': 100.0,
|
|
'substract_account_id': self.substract_account.id,
|
|
})
|
|
|
|
self.assertEqual(line.amount_substract, 100.0,
|
|
"amount_substract should be settable")
|
|
self.assertEqual(line.substract_account_id, self.substract_account,
|
|
"substract_account_id should be settable")
|
|
|
|
def test_unit_batch_payment_without_deduction(self):
|
|
"""
|
|
Unit test: Verify batch payment works without deduction fields.
|
|
Tests that the integration doesn't break existing functionality.
|
|
"""
|
|
# Create batch payment
|
|
batch_payment = self.env['account.batch.payment'].create({
|
|
'journal_id': self.journal.id,
|
|
'batch_type': 'outbound',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Create direct payment line WITHOUT deduction fields
|
|
line = self.env['account.batch.payment.line'].create({
|
|
'batch_payment_id': batch_payment.id,
|
|
'partner_id': self.partner1.id,
|
|
'amount': 1000.0,
|
|
'expense_account_id': self.expense_account.id,
|
|
'memo': 'Payment without deduction',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Verify line was created without deduction fields
|
|
self.assertEqual(line.amount_substract, 0.0,
|
|
"amount_substract should default to 0")
|
|
self.assertFalse(line.substract_account_id,
|
|
"substract_account_id should be False by default")
|
|
|
|
# Generate payments from lines
|
|
batch_payment.generate_payments_from_lines()
|
|
|
|
# Verify payment was generated
|
|
self.assertTrue(line.payment_id, "Payment should be generated")
|
|
|
|
# Get the generated payment
|
|
payment = line.payment_id
|
|
|
|
# Verify payment has no deduction
|
|
self.assertEqual(payment.amount, 1000.0,
|
|
"Payment should have amount of 1000")
|
|
self.assertEqual(payment.amount_substract, 0.0,
|
|
"Payment should have amount_substract of 0")
|
|
self.assertFalse(payment.substract_account_id,
|
|
"Payment should not have substract_account_id")
|
|
self.assertEqual(payment.final_payment_amount, 1000.0,
|
|
"Payment final_payment_amount should equal amount")
|
|
|
|
# Verify payment is posted
|
|
self.assertEqual(payment.state, 'posted', "Payment should be posted")
|
|
|
|
# Verify journal entry has standard structure (no substract line)
|
|
move = payment.move_id
|
|
self.assertTrue(move, "Payment should have journal entry")
|
|
|
|
# Verify no substract line
|
|
substract_lines = move.line_ids.filtered(
|
|
lambda l: l.account_id == self.substract_account
|
|
)
|
|
self.assertEqual(len(substract_lines), 0,
|
|
"Journal entry should not have substract account line")
|
|
|
|
def test_unit_batch_payment_mixed_lines(self):
|
|
"""
|
|
Unit test: Verify batch payment with mixed lines (some with deduction, some without).
|
|
Tests Requirements 7.4, 7.5
|
|
"""
|
|
# Create batch payment
|
|
batch_payment = self.env['account.batch.payment'].create({
|
|
'journal_id': self.journal.id,
|
|
'batch_type': 'outbound',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Create line WITH deduction
|
|
line_with_deduction = self.env['account.batch.payment.line'].create({
|
|
'batch_payment_id': batch_payment.id,
|
|
'partner_id': self.partner1.id,
|
|
'amount': 1000.0,
|
|
'amount_substract': 100.0,
|
|
'substract_account_id': self.substract_account.id,
|
|
'expense_account_id': self.expense_account.id,
|
|
'memo': 'With deduction',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Create line WITHOUT deduction
|
|
line_without_deduction = self.env['account.batch.payment.line'].create({
|
|
'batch_payment_id': batch_payment.id,
|
|
'partner_id': self.partner2.id,
|
|
'amount': 2000.0,
|
|
'expense_account_id': self.expense_account.id,
|
|
'memo': 'Without deduction',
|
|
'date': fields.Date.today(),
|
|
})
|
|
|
|
# Generate payments from lines
|
|
batch_payment.generate_payments_from_lines()
|
|
|
|
# Verify both payments were generated
|
|
self.assertTrue(line_with_deduction.payment_id,
|
|
"Payment should be generated for line with deduction")
|
|
self.assertTrue(line_without_deduction.payment_id,
|
|
"Payment should be generated for line without deduction")
|
|
|
|
# Get the generated payments
|
|
payment_with = line_with_deduction.payment_id
|
|
payment_without = line_without_deduction.payment_id
|
|
|
|
# Verify payment with deduction
|
|
self.assertEqual(payment_with.amount_substract, 100.0,
|
|
"Payment with deduction should have amount_substract")
|
|
self.assertEqual(payment_with.substract_account_id, self.substract_account,
|
|
"Payment with deduction should have substract_account_id")
|
|
self.assertEqual(payment_with.final_payment_amount, 900.0,
|
|
"Payment with deduction final amount should be 900")
|
|
|
|
# Verify payment without deduction
|
|
self.assertEqual(payment_without.amount_substract, 0.0,
|
|
"Payment without deduction should have amount_substract of 0")
|
|
self.assertFalse(payment_without.substract_account_id,
|
|
"Payment without deduction should not have substract_account_id")
|
|
self.assertEqual(payment_without.final_payment_amount, 2000.0,
|
|
"Payment without deduction final amount should equal amount")
|
|
|
|
# Verify both payments are posted
|
|
self.assertEqual(payment_with.state, 'posted',
|
|
"Payment with deduction should be posted")
|
|
self.assertEqual(payment_without.state, 'posted',
|
|
"Payment without deduction should be posted")
|