Restructure: move packages from packages/ subdirectory to root

Flattened directory structure by moving payment packages from redundant
packages/ subdirectory to the root level of oca-payment repository.

Changes:
- Moved odoo-bringout-oca-payment-* from packages/ to root
- Updated CLAUDE.md to reflect new flat structure
- Removed redundant packages/ directory

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ernad Husremovic 2025-11-16 09:10:09 +01:00
parent 99c650f4f5
commit 7f7e88ab3d
202 changed files with 1 additions and 1 deletions

View file

@ -0,0 +1,6 @@
from . import test_payment_mode
from . import test_bank
from . import test_payment_order_inbound
from . import test_payment_order_outbound
from . import test_account_payment
from . import test_payment_order_transfer_journal

View file

@ -0,0 +1,156 @@
# Copyright 2019 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from unittest.mock import patch
from odoo.tests import tagged
from odoo.addons.account.models.account_payment_method import AccountPaymentMethod
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
@tagged("-at_install", "post_install")
class TestAccountPayment(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
Method_get_payment_method_information = (
AccountPaymentMethod._get_payment_method_information
)
def _get_payment_method_information(self):
res = Method_get_payment_method_information(self)
res["IN"] = {"mode": "multi", "domain": [("type", "=", "bank")]}
res["IN2"] = {"mode": "multi", "domain": [("type", "=", "bank")]}
res["OUT"] = {"mode": "multi", "domain": [("type", "=", "bank")]}
return res
cls.company = cls.company_data["company"]
cls.env.user.company_ids += cls.company
# MODELS
cls.account_payment_model = cls.env["account.payment"]
cls.account_journal_model = cls.env["account.journal"]
cls.payment_method_model = cls.env["account.payment.method"]
# INSTANCES
# Payment methods
with patch.object(
AccountPaymentMethod,
"_get_payment_method_information",
_get_payment_method_information,
):
cls.inbound_payment_method_01 = cls.payment_method_model.create(
{
"name": "inbound",
"code": "IN",
"payment_type": "inbound",
}
)
cls.inbound_payment_method_02 = cls.inbound_payment_method_01.copy(
{
"name": "inbound 2",
"code": "IN2",
"payment_type": "inbound",
}
)
cls.outbound_payment_method_01 = cls.payment_method_model.create(
{
"name": "outbound",
"code": "OUT",
"payment_type": "outbound",
}
)
# Journals
cls.manual_in = cls.env.ref("account.account_payment_method_manual_in")
cls.manual_out = cls.env.ref("account.account_payment_method_manual_out")
cls.bank_journal = cls.company_data["default_journal_bank"]
def test_account_payment_01(self):
self.assertFalse(self.inbound_payment_method_01.payment_order_only)
self.assertFalse(self.inbound_payment_method_02.payment_order_only)
self.assertFalse(self.bank_journal.inbound_payment_order_only)
self.inbound_payment_method_01.payment_order_only = True
self.assertTrue(self.inbound_payment_method_01.payment_order_only)
self.assertFalse(self.inbound_payment_method_02.payment_order_only)
self.assertFalse(self.bank_journal.inbound_payment_order_only)
for p in self.bank_journal.inbound_payment_method_line_ids.payment_method_id:
p.payment_order_only = True
self.assertTrue(self.bank_journal.inbound_payment_order_only)
def test_account_payment_02(self):
self.assertFalse(self.outbound_payment_method_01.payment_order_only)
self.assertFalse(self.bank_journal.outbound_payment_order_only)
self.outbound_payment_method_01.payment_order_only = True
self.assertTrue(self.outbound_payment_method_01.payment_order_only)
payment_method_id = (
self.bank_journal.outbound_payment_method_line_ids.payment_method_id
)
payment_method_id.payment_order_only = True
self.assertTrue(self.bank_journal.outbound_payment_order_only)
def test_account_payment_03(self):
self.assertFalse(self.inbound_payment_method_01.payment_order_only)
self.assertFalse(self.inbound_payment_method_02.payment_order_only)
self.assertFalse(self.bank_journal.inbound_payment_order_only)
new_account_payment = self.account_payment_model.with_context(
default_company_id=self.company.id
).new(
{
"journal_id": self.bank_journal.id,
"payment_type": "inbound",
"amount": 1,
"company_id": self.company.id,
}
)
# check payment methods
payment_methods = (
new_account_payment.available_payment_method_line_ids.filtered(
lambda x: x.payment_type == "inbound"
)
.mapped("payment_method_id")
.ids
)
self.assertIn(self.inbound_payment_method_01.id, payment_methods)
self.assertIn(self.inbound_payment_method_02.id, payment_methods)
# Set one payment method of the bank journal 'payment order only'
self.inbound_payment_method_01.payment_order_only = True
# check payment methods
new_account_payment2 = self.account_payment_model.with_context(
default_company_id=self.company.id
).new(
{
"journal_id": self.bank_journal.id,
"payment_type": "inbound",
"amount": 1,
"company_id": self.company.id,
}
)
payment_methods = new_account_payment2.available_payment_method_line_ids.mapped(
"payment_method_id"
).ids
self.assertNotIn(self.inbound_payment_method_01.id, payment_methods)
self.assertIn(self.inbound_payment_method_02.id, payment_methods)
# Set all payment methods of the bank journal 'payment order only'
for p in self.bank_journal.inbound_payment_method_line_ids.payment_method_id:
p.payment_order_only = True
self.assertTrue(self.bank_journal.inbound_payment_order_only)
# check payment methods
new_account_payment3 = self.account_payment_model.with_context(
default_company_id=self.company.id
).new(
{
"journal_id": self.bank_journal.id,
"payment_type": "inbound",
"amount": 1,
"company_id": self.company.id,
}
)
payment_methods = new_account_payment3.available_payment_method_line_ids.mapped(
"payment_method_id"
).ids
self.assertNotIn(self.inbound_payment_method_01.id, payment_methods)
self.assertNotIn(self.inbound_payment_method_02.id, payment_methods)

View file

@ -0,0 +1,35 @@
# © 2017 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
class TestBank(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
def test_bank(self):
bank = self.env["res.bank"].search([], limit=1)
if not bank:
# This should only happen if we don't have demo data
bank = (
self.env["res.bank"]
.env["res.bank"]
.create(
{
"name": "Fiducial Banque",
"bic": "FIDCFR21XXX",
"street": "38 rue Sergent Michel Berthet",
"zip": "69009",
"city": "Lyon",
"country": self.env.ref("base.fr").id,
}
)
)
with self.assertRaises(ValidationError):
bank.bic = "TEST"

View file

@ -0,0 +1,93 @@
# © 2017 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from unittest.mock import patch
from odoo.tests.common import TransactionCase
from odoo.addons.account.models.account_payment_method import AccountPaymentMethod
from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
class TestPaymentMode(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
Method_get_payment_method_information = (
AccountPaymentMethod._get_payment_method_information
)
def _get_payment_method_information(cls):
res = Method_get_payment_method_information(cls)
res["IN"] = {"mode": "multi", "domain": [("type", "=", "bank")]}
res["IN2"] = {"mode": "multi", "domain": [("type", "=", "bank")]}
res["electronic_out"] = {"mode": "multi", "domain": [("type", "=", "bank")]}
return res
# Company
cls.company = cls.env.ref("base.main_company")
cls.journal_c1 = cls.env["account.journal"].create(
{
"name": "Journal 1",
"code": "J1",
"type": "bank",
"company_id": cls.company.id,
}
)
cls.account = cls.env["account.account"].search(
[("reconcile", "=", True), ("company_id", "=", cls.company.id)], limit=1
)
cls.manual_out = cls.env.ref("account.account_payment_method_manual_out")
cls.manual_in = cls.env.ref("account.account_payment_method_manual_in")
with patch.object(
AccountPaymentMethod,
"_get_payment_method_information",
_get_payment_method_information,
):
cls.electronic_out = cls.env["account.payment.method"].create(
{
"name": "Electronic Out",
"code": "electronic_out",
"payment_type": "outbound",
}
)
cls.payment_mode_c1 = cls.env["account.payment.mode"].create(
{
"name": "Direct Debit of suppliers from Bank 1",
"bank_account_link": "variable",
"payment_method_id": cls.manual_out.id,
"company_id": cls.company.id,
"fixed_journal_id": cls.journal_c1.id,
"variable_journal_ids": [(6, 0, [cls.journal_c1.id])],
}
)
def test_onchange_payment_type(self):
self.payment_mode_c1.payment_method_id = self.manual_in
self.payment_mode_c1.payment_method_id_change()
self.assertTrue(
all(
[
journal.type in ["sale_refund", "sale"]
for journal in self.payment_mode_c1.default_journal_ids
]
)
)
self.payment_mode_c1.payment_method_id = self.manual_out
self.payment_mode_c1.payment_method_id_change()
self.assertTrue(
all(
[
journal.type in ["purchase_refund", "purchase"]
for journal in self.payment_mode_c1.default_journal_ids
]
)
)

View file

@ -0,0 +1,216 @@
# Copyright 2017 Camptocamp SA
# Copyright 2017 Creu Blanca
# Copyright 2019-2022 Tecnativa - Pedro M. Baeza
# Copyright 2024 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from datetime import date, timedelta
from freezegun import freeze_time
from odoo.exceptions import UserError, ValidationError
from odoo.tests import tagged
from odoo.tests.common import Form
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
@tagged("-at_install", "post_install")
class TestPaymentOrderInboundBase(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
cls.company = cls.company_data["company"]
cls.env.user.company_id = cls.company.id
cls.product = cls.env["product.product"].create(
{
"name": "Test product",
"type": "service",
}
)
cls.partner = cls.env["res.partner"].create(
{
"name": "Test Partner",
}
)
cls.inbound_mode = cls.env["account.payment.mode"].create(
{
"name": "Test Direct Debit of customers",
"bank_account_link": "variable",
"payment_method_id": cls.env.ref(
"account.account_payment_method_manual_in"
).id,
"company_id": cls.company.id,
}
)
cls.invoice_line_account = cls.company_data["default_account_revenue"]
cls.journal = cls.company_data["default_journal_bank"]
cls.inbound_mode.variable_journal_ids = cls.journal
# Make sure no others orders are present
cls.domain = [
("state", "=", "draft"),
("payment_type", "=", "inbound"),
("company_id", "=", cls.env.user.company_id.id),
]
cls.payment_order_obj = cls.env["account.payment.order"]
cls.payment_order_obj.search(cls.domain).unlink()
# Create payment order
cls.inbound_order = cls.env["account.payment.order"].create(
{
"payment_type": "inbound",
"payment_mode_id": cls.inbound_mode.id,
"journal_id": cls.journal.id,
}
)
# Open invoice
cls.invoice = cls._create_customer_invoice(cls)
cls.invoice.action_post()
# Add to payment order using the wizard
cls.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=cls.invoice.ids
).create({}).run()
def _create_customer_invoice(self):
with Form(
self.env["account.move"].with_context(default_move_type="out_invoice")
) as invoice_form:
invoice_form.partner_id = self.partner
with invoice_form.invoice_line_ids.new() as invoice_line_form:
invoice_line_form.product_id = self.product
invoice_line_form.name = "product that cost 100"
invoice_line_form.quantity = 1
invoice_line_form.price_unit = 100.0
invoice_line_form.account_id = self.invoice_line_account
invoice_line_form.tax_ids.clear()
invoice_form.reference_type = "structured"
invoice = invoice_form.save()
invoice_form = Form(invoice)
invoice_form.payment_mode_id = self.inbound_mode
return invoice_form.save()
@tagged("-at_install", "post_install")
class TestPaymentOrderInbound(TestPaymentOrderInboundBase):
def _line_creation(self, inbound_order):
vals = {
"order_id": inbound_order.id,
"partner_id": self.partner.id,
"currency_id": inbound_order.payment_mode_id.company_id.currency_id.id,
"amount_currency": 200.38,
"move_line_id": self.invoice.invoice_line_ids[0].id,
}
return self.env["account.payment.line"].create(vals)
def test_constrains_type(self):
with self.assertRaises(ValidationError):
order = self.env["account.payment.order"].create(
{"payment_mode_id": self.inbound_mode.id, "journal_id": self.journal.id}
)
order.payment_type = "outbound"
def test_constrains_date(self):
with self.assertRaises(ValidationError):
self.inbound_order.date_scheduled = date.today() - timedelta(days=1)
def test_invoice_communication_01(self):
self.assertEqual(
self.invoice.name, self.invoice._get_payment_order_communication_direct()
)
self.invoice.ref = "R1234"
self.assertEqual(
self.invoice.name, self.invoice._get_payment_order_communication_direct()
)
def test_invoice_communication_02(self):
self.invoice.payment_reference = "R1234"
self.assertEqual(
"R1234", self.invoice._get_payment_order_communication_direct()
)
def test_creation(self):
payment_order = self.inbound_order
self.assertEqual(len(payment_order.ids), 1)
payment_order.write({"journal_id": self.journal.id})
self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertFalse(payment_order.payment_ids)
# Open payment order
payment_order.draft2open()
self.assertEqual(payment_order.payment_count, 1)
# Generate and upload
payment_order.open2generated()
payment_order.generated2uploaded()
self.assertEqual(payment_order.state, "uploaded")
self.assertEqual(self.invoice.payment_state, "in_payment")
with self.assertRaises(UserError):
payment_order.unlink()
# Cancel order
payment_order.action_uploaded_cancel()
self.assertEqual(payment_order.state, "cancel")
payment_order.cancel2draft()
payment_order.unlink()
self.assertEqual(len(self.payment_order_obj.search(self.domain)), 0)
def test_constrains_payment_line(self):
inbound_order = self.env["account.payment.order"].create(
{"payment_mode_id": self.inbound_mode.id, "journal_id": self.journal.id}
)
# Create two payment lines with the same
# move line id and try to assign them to inbound order
payment_line_1 = self._line_creation(inbound_order)
inbound_order.payment_line_ids |= payment_line_1
with self.assertRaises(ValidationError):
payment_line_2 = self._line_creation(inbound_order)
inbound_order.payment_line_ids |= payment_line_2
@freeze_time("2024-04-01")
def test_creation_transfer_move_date_01(self):
self.inbound_order.date_prefered = "fixed"
self.inbound_order.date_scheduled = "2024-06-01"
self.inbound_order.draft2open()
payment = self.inbound_order.payment_ids
self.assertEqual(payment.payment_line_date, date(2024, 6, 1))
payment_move = payment.move_id
self.assertEqual(payment_move.date, date(2024, 4, 1)) # now
self.assertEqual(
payment_move.line_ids.mapped("date_maturity"),
[date(2024, 6, 1), date(2024, 6, 1)],
)
self.assertEqual(self.inbound_order.payment_count, 1)
self.inbound_order.open2generated()
self.inbound_order.generated2uploaded()
self.assertEqual(self.inbound_order.state, "uploaded")
payment = self.inbound_order.payment_ids
self.assertEqual(payment.payment_line_date, date(2024, 6, 1))
payment_move = payment.move_id
self.assertEqual(payment_move.date, date(2024, 4, 1)) # now
self.assertEqual(
payment_move.line_ids.mapped("date_maturity"),
[date(2024, 6, 1), date(2024, 6, 1)],
)
@freeze_time("2024-04-01")
def test_creation_transfer_move_date_02(self):
# Simulate that the invoice had a different due date
self.inbound_order.payment_line_ids.ml_maturity_date = "2024-06-01"
self.inbound_order.draft2open()
payment = self.inbound_order.payment_ids
self.assertEqual(payment.payment_line_date, date(2024, 6, 1))
payment_move = payment.move_id
self.assertEqual(payment_move.date, date(2024, 4, 1)) # now
self.assertEqual(
payment_move.line_ids.mapped("date_maturity"),
[date(2024, 6, 1), date(2024, 6, 1)],
)
self.assertEqual(self.inbound_order.payment_count, 1)
self.inbound_order.open2generated()
self.inbound_order.generated2uploaded()
self.assertEqual(self.inbound_order.state, "uploaded")
payment = self.inbound_order.payment_ids
self.assertEqual(payment.payment_line_date, date(2024, 6, 1))
payment_move = payment.move_id
self.assertEqual(payment_move.date, date(2024, 4, 1)) # now
self.assertEqual(
payment_move.line_ids.mapped("date_maturity"),
[date(2024, 6, 1), date(2024, 6, 1)],
)

View file

@ -0,0 +1,575 @@
# © 2017 Camptocamp SA
# © 2017 Creu Blanca
# Copyright 2022 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from datetime import date, datetime, timedelta
from odoo import fields
from odoo.exceptions import UserError, ValidationError
from odoo.fields import Command
from odoo.tests import Form, tagged
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
@tagged("-at_install", "post_install")
class TestPaymentOrderOutboundBase(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
cls.company = cls.company_data["company"]
cls.env.user.company_id = cls.company.id
cls.partner = cls.env["res.partner"].create(
{
"name": "Test Partner",
"bank_ids": [
(
0,
0,
{
"acc_number": "TEST-NUMBER",
},
)
],
}
)
cls.invoice_line_account = cls.env["account.account"].create(
{
"name": "Test account",
"code": "TEST1",
"account_type": "expense",
}
)
cls.mode = cls.env["account.payment.mode"].create(
{
"name": "Test Credit Transfer to Suppliers",
"company_id": cls.company.id,
"bank_account_link": "variable",
"payment_method_id": cls.env.ref(
"account.account_payment_method_manual_out"
).id,
}
)
cls.creation_mode = cls.env["account.payment.mode"].create(
{
"name": "Test Direct Debit of suppliers from Société Générale",
"company_id": cls.company.id,
"bank_account_link": "variable",
"payment_method_id": cls.env.ref(
"account.account_payment_method_manual_out"
).id,
}
)
cls.product = cls.env["product.product"].create(
{
"name": "Test product",
"type": "service",
}
)
cls.invoice = cls._create_supplier_invoice(cls, "F1242")
cls.invoice_02 = cls._create_supplier_invoice(cls, "F1243")
cls.bank_journal = cls.company_data["default_journal_bank"]
# Make sure no other payment orders are in the DB
cls.domain = [
("state", "=", "draft"),
("payment_type", "=", "outbound"),
("company_id", "=", cls.env.user.company_id.id),
]
cls.env["account.payment.order"].search(cls.domain).unlink()
def _create_supplier_invoice(self, ref):
invoice = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "in_invoice",
"ref": ref,
"payment_mode_id": self.mode.id,
"invoice_date": fields.Date.today(),
"invoice_line_ids": [
(
0,
None,
{
"product_id": self.product.id,
"quantity": 1.0,
"price_unit": 100.0,
"name": "product that cost 100",
"account_id": self.invoice_line_account.id,
},
)
],
}
)
return invoice
def _create_supplier_refund(self, move, manual=False):
if manual:
# Do the supplier refund manually
vals = {
"partner_id": self.partner.id,
"move_type": "in_refund",
"ref": move.ref,
"payment_mode_id": self.mode.id,
"invoice_date": fields.Date.today(),
"invoice_line_ids": [
(
0,
None,
{
"product_id": self.product.id,
"quantity": 1.0,
"price_unit": 90.0,
"name": "refund of 90.0",
"account_id": self.invoice_line_account.id,
},
)
],
}
move = self.env["account.move"].create(vals)
return move
wizard = (
self.env["account.move.reversal"]
.with_context(active_model="account.move", active_ids=move.ids)
.create(
{
"date_mode": "entry",
"refund_method": "refund",
"journal_id": move.journal_id.id,
}
)
)
wizard.reverse_moves()
return wizard.new_move_ids
@tagged("-at_install", "post_install")
class TestPaymentOrderOutbound(TestPaymentOrderOutboundBase):
def test_creation_due_date(self):
self.mode.variable_journal_ids = self.bank_journal
self.mode.group_lines = False
self.order_creation("due")
def test_creation_no_date(self):
self.mode.group_lines = True
self.creation_mode.write(
{
"group_lines": False,
"bank_account_link": "fixed",
"default_date_prefered": "due",
"fixed_journal_id": self.bank_journal.id,
}
)
self.mode.variable_journal_ids = self.bank_journal
self.order_creation(False)
def test_creation_fixed_date(self):
self.mode.write(
{
"bank_account_link": "fixed",
"default_date_prefered": "fixed",
"fixed_journal_id": self.bank_journal.id,
}
)
self.invoice_02.action_post()
self.order_creation("fixed")
def order_creation(self, date_prefered):
# Open invoice
self.invoice.action_post()
order_vals = {
"payment_type": "outbound",
"payment_mode_id": self.creation_mode.id,
}
if date_prefered:
order_vals["date_prefered"] = date_prefered
order = self.env["account.payment.order"].create(order_vals)
with self.assertRaises(UserError):
order.draft2open()
order.payment_mode_id = self.mode.id
order.payment_mode_id_change()
self.assertEqual(order.journal_id.id, self.bank_journal.id)
self.assertEqual(len(order.payment_line_ids), 0)
if date_prefered:
self.assertEqual(order.date_prefered, date_prefered)
with self.assertRaises(UserError):
order.draft2open()
line_create = (
self.env["account.payment.line.create"]
.with_context(active_model="account.payment.order", active_id=order.id)
.create(
{"date_type": "move", "move_date": datetime.now() + timedelta(days=1)}
)
)
line_create.payment_mode = "any"
line_create.move_line_filters_change()
line_create.populate()
line_create.create_payment_lines()
line_created_due = (
self.env["account.payment.line.create"]
.with_context(active_model="account.payment.order", active_id=order.id)
.create(
{"date_type": "due", "due_date": datetime.now() + timedelta(days=1)}
)
)
line_created_due.populate()
line_created_due.create_payment_lines()
self.assertGreater(len(order.payment_line_ids), 0)
self.assertFalse(order.partner_banks_archive_msg)
order.payment_line_ids.partner_bank_id.action_archive()
self.assertTrue(order.partner_banks_archive_msg)
order.payment_line_ids.partner_bank_id.action_unarchive()
self.assertFalse(order.partner_banks_archive_msg)
order.draft2open()
self.assertEqual(order.payment_ids[0].partner_bank_id, self.partner.bank_ids)
order.open2generated()
order.generated2uploaded()
self.assertEqual(order.move_ids[0].date, order.payment_ids[0].date)
self.assertEqual(order.state, "uploaded")
def _line_creation(self, outbound_order):
vals = {
"order_id": outbound_order.id,
"partner_id": self.partner.id,
"currency_id": outbound_order.payment_mode_id.company_id.currency_id.id,
"amount_currency": 200.38,
"move_line_id": self.invoice.invoice_line_ids[0].id,
}
return self.env["account.payment.line"].create(vals)
def test_account_payment_line_creation_without_payment_mode(self):
self.invoice.payment_mode_id = False
self.invoice.action_post()
with self.assertRaises(UserError):
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=self.invoice.ids
).create({}).run()
def test_cancel_payment_order(self):
# Open invoice
self.invoice.action_post()
# Add to payment order using the wizard
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=self.invoice.ids
).create({}).run()
payment_order = self.env["account.payment.order"].search(self.domain)
self.assertEqual(len(payment_order), 1)
payment_order.write({"journal_id": self.bank_journal.id})
self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertFalse(payment_order.payment_ids)
# Open payment order
payment_order.draft2open()
self.assertEqual(payment_order.payment_count, 1)
# Generate and upload
payment_order.open2generated()
payment_order.generated2uploaded()
self.assertEqual(payment_order.state, "uploaded")
with self.assertRaises(UserError):
payment_order.unlink()
payment_order.action_uploaded_cancel()
self.assertEqual(payment_order.state, "cancel")
payment_order.cancel2draft()
payment_order.unlink()
self.assertEqual(len(self.env["account.payment.order"].search(self.domain)), 0)
def test_constrains(self):
outbound_order = self.env["account.payment.order"].create(
{
"payment_type": "outbound",
"payment_mode_id": self.mode.id,
"journal_id": self.bank_journal.id,
}
)
with self.assertRaises(ValidationError):
outbound_order.date_scheduled = date.today() - timedelta(days=2)
# Create two payment lines with the same
# move line id and try to assign them to outbound order
payment_line_1 = self._line_creation(outbound_order)
outbound_order.payment_line_ids |= payment_line_1
with self.assertRaises(ValidationError):
payment_line_2 = self._line_creation(outbound_order)
outbound_order.payment_line_ids |= payment_line_2
def test_invoice_communication_01(self):
self.assertEqual(
"F1242", self.invoice._get_payment_order_communication_direct()
)
self.invoice.ref = "F1243"
self.assertEqual(
"F1243", self.invoice._get_payment_order_communication_direct()
)
def test_invoice_communication_02(self):
self.assertEqual(
"F1242", self.invoice._get_payment_order_communication_direct()
)
self.invoice.payment_reference = "R1234"
self.assertEqual(
"R1234", self.invoice._get_payment_order_communication_direct()
)
def test_invoice_communication_03(self):
self.invoice.ref = False
self.invoice.action_post()
self.assertEqual("", self.invoice._get_payment_order_communication_direct())
reverse_wizard = Form(
self.env["account.move.reversal"].with_context(
active_ids=self.invoice.ids, active_model=self.invoice._name
)
)
reverse = reverse_wizard.save()
reverse_res = reverse.reverse_moves()
reverse_move = self.env[reverse_res["res_model"]].browse(reverse_res["res_id"])
self.assertEqual(
" %s" % reverse_move.ref,
self.invoice._get_payment_order_communication_full(),
)
self.invoice.ref = "ref"
self.assertEqual(
"ref %s" % reverse_move.ref,
self.invoice._get_payment_order_communication_full(),
)
def test_supplier_invoice_payment_reference(self):
self.invoice.payment_reference = "+++F1234+++"
self.invoice.action_post()
self.assertEqual(
"+++F1234+++", self.invoice._get_payment_order_communication_full()
)
def test_manual_line_and_manual_date(self):
# Create payment order
outbound_order = self.env["account.payment.order"].create(
{
"date_prefered": "due",
"payment_type": "outbound",
"payment_mode_id": self.mode.id,
"journal_id": self.bank_journal.id,
"description": "order with manual line",
}
)
self.assertEqual(len(outbound_order.payment_line_ids), 0)
# Create a manual payment order line with custom date
vals = {
"order_id": outbound_order.id,
"partner_id": self.partner.id,
"communication": "manual line and manual date",
"currency_id": outbound_order.payment_mode_id.company_id.currency_id.id,
"amount_currency": 192.38,
"date": date.today() + timedelta(days=8),
}
self.env["account.payment.line"].create(vals)
self.assertEqual(len(outbound_order.payment_line_ids), 1)
self.assertEqual(
outbound_order.payment_line_ids[0].date, date.today() + timedelta(days=8)
)
# Create a manual payment order line with normal date
vals = {
"order_id": outbound_order.id,
"partner_id": self.partner.id,
"communication": "manual line",
"currency_id": outbound_order.payment_mode_id.company_id.currency_id.id,
"amount_currency": 200.38,
}
self.env["account.payment.line"].create(vals)
self.assertEqual(len(outbound_order.payment_line_ids), 2)
self.assertEqual(outbound_order.payment_line_ids[1].date, False)
# Open payment order
self.assertFalse(outbound_order.payment_ids)
outbound_order.draft2open()
self.assertEqual(outbound_order.payment_count, 2)
self.assertEqual(
outbound_order.payment_line_ids[0].payment_ids.date, fields.Date.today()
)
self.assertEqual(outbound_order.payment_line_ids[1].date, date.today())
self.assertEqual(
outbound_order.payment_line_ids[1].date,
fields.Date.context_today(outbound_order),
)
self.assertEqual(
outbound_order.payment_line_ids[1].payment_ids.date,
fields.Date.context_today(outbound_order),
)
def test_supplier_refund(self):
"""
Confirm the supplier invoice
Create a credit note based on that one with an inferior amount
Confirm the credit note
Create the payment order
The communication should be a combination of the invoice reference
and the credit note one
"""
self.invoice.action_post()
self.assertEqual(
"F1242", self.invoice._get_payment_order_communication_direct()
)
self.refund = self._create_supplier_refund(self.invoice)
with Form(self.refund) as refund_form:
refund_form.ref = "R1234"
with refund_form.invoice_line_ids.edit(0) as line_form:
line_form.price_unit = 75.0
self.refund.action_post()
self.assertEqual("R1234", self.refund._get_payment_order_communication_direct())
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=self.invoice.ids
).create({}).run()
payment_order = self.env["account.payment.order"].search(self.domain)
self.assertEqual(len(payment_order), 1)
payment_order.write({"journal_id": self.bank_journal.id})
self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertEqual("F1242 R1234", payment_order.payment_line_ids.communication)
def test_supplier_refund_reference(self):
"""
Confirm the supplier invoice
Set a payment referece
Create a credit note based on that one with an inferior amount
Confirm the credit note
Create the payment order
The communication should be a combination of the invoice payment reference
and the credit note one
"""
self.invoice.payment_reference = "F/1234"
self.invoice.action_post()
self.assertEqual(
"F/1234", self.invoice._get_payment_order_communication_direct()
)
self.refund = self._create_supplier_refund(self.invoice)
with Form(self.refund) as refund_form:
refund_form.ref = "R1234"
refund_form.payment_reference = "FR/1234"
with refund_form.invoice_line_ids.edit(0) as line_form:
line_form.price_unit = 75.0
self.refund.action_post()
self.assertEqual(
"FR/1234", self.refund._get_payment_order_communication_direct()
)
# The user add the outstanding payment to the invoice
invoice_line = self.invoice.line_ids.filtered(
lambda line: line.account_type == "liability_payable"
)
refund_line = self.refund.line_ids.filtered(
lambda line: line.account_type == "liability_payable"
)
(invoice_line | refund_line).reconcile()
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=self.invoice.ids
).create({}).run()
payment_order = self.env["account.payment.order"].search(self.domain)
self.assertEqual(len(payment_order), 1)
payment_order.write({"journal_id": self.bank_journal.id})
self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertEqual("F/1234 FR/1234", payment_order.payment_line_ids.communication)
def test_multiple_lines_without_move_line(self):
"""Test that a payment order with multiple lines without related
journal items can be created"""
self.env["account.payment.order"].create(
{
"date_prefered": "due",
"payment_type": "outbound",
"payment_mode_id": self.mode.id,
"journal_id": self.bank_journal.id,
"description": "order with manual line",
"payment_line_ids": [
Command.create(
{
"partner_id": self.partner.id,
"amount_currency": 101.00,
}
),
Command.create(
{
"partner_id": self.partner.id,
"amount_currency": 101.00,
}
),
],
}
)
def test_supplier_manual_refund(self):
"""
Confirm the supplier invoice with reference
Create a credit note manually
Confirm the credit note
Reconcile move lines together
Create the payment order
The communication should be a combination of the invoice payment reference
and the credit note one
"""
self.invoice.action_post()
self.assertEqual(
"F1242", self.invoice._get_payment_order_communication_direct()
)
self.refund = self._create_supplier_refund(self.invoice, manual=True)
with Form(self.refund) as refund_form:
refund_form.ref = "R1234"
self.refund.action_post()
self.assertEqual("R1234", self.refund._get_payment_order_communication_direct())
(self.invoice.line_ids + self.refund.line_ids).filtered(
lambda line: line.account_type == "liability_payable"
).reconcile()
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=self.invoice.ids
).create({}).run()
payment_order = self.env["account.payment.order"].search(self.domain)
self.assertEqual(len(payment_order), 1)
payment_order.write({"journal_id": self.bank_journal.id})
self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertEqual("F1242 R1234", payment_order.payment_line_ids.communication)
def test_action_open_business_document(self):
# Open invoice
self.invoice.action_post()
# Add to payment order using the wizard
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move", active_ids=self.invoice.ids
).create({}).run()
order = self.env["account.payment.order"].search(self.domain)
# Create payment line without move line
vals = {
"order_id": order.id,
"partner_id": self.partner.id,
"currency_id": order.payment_mode_id.company_id.currency_id.id,
"amount_currency": 200.38,
}
self.env["account.payment.line"].create(vals)
invoice_action = order.payment_line_ids[0].action_open_business_doc()
self.assertEqual(invoice_action["res_model"], "account.move")
self.assertEqual(invoice_action["res_id"], self.invoice.id)
manual_line_action = order.payment_line_ids[1].action_open_business_doc()
self.assertFalse(manual_line_action)

View file

@ -0,0 +1,52 @@
# Copyright 2023 Noviat
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import odoo.tests
from odoo import fields
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
@odoo.tests.tagged("post_install", "-at_install")
class TestPaymentOrderTranserJournal(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
today = fields.Date.today()
cls.in_invoice = cls.init_invoice(
"in_invoice", invoice_date=today, products=cls.product_a
)
cls.bank_journal = cls.company_data["default_journal_bank"]
cls.misc_journal = cls.company_data["default_journal_misc"]
cls.payment_mode = cls.env["account.payment.mode"].create(
{
"name": "Test Credit Transfer to Suppliers",
"company_id": cls.env.company.id,
"payment_method_id": cls.env.ref(
"account.account_payment_method_manual_out"
).id,
"fixed_journal_id": cls.bank_journal.id,
"bank_account_link": "fixed",
}
)
def test_payment_order_transfer_journal(self):
self.in_invoice._post()
self.payment_mode.transfer_journal_id = self.misc_journal
ap_aml = self.in_invoice.line_ids.filtered(
lambda r: r.account_type == "liability_payable"
)
payline_vals = {
"move_line_id": ap_aml.id,
"partner_id": self.in_invoice.partner_id.id,
"communication": "F0123",
"amount_currency": -ap_aml.amount_currency,
}
order_vals = {
"payment_type": "outbound",
"payment_mode_id": self.payment_mode.id,
"payment_line_ids": [(0, 0, payline_vals)],
}
order = self.env["account.payment.order"].create(order_vals)
order.draft2open()
self.assertEqual(order.mapped("move_ids.journal_id"), self.misc_journal)