[REM] website_sale_aplicoop: remove dead code and orphaned tests
Duplicate _translate_labels fallback, unreachable /eskaera/add-to-cart and /eskaera/save-cart routes (the frontend cart is localStorage-only and uses save-order), redundant pickup wrappers, unused pagination/count helpers and fields, deprecated JS shims, and the already-empty checkout_summary.js and i18n key/init leftovers. Also drops 11 tests/*.py never wired into tests/__init__.py: three were unimplemented placeholders (setUp with no assertions), and the other eight had real assertions but were bit-rotted against the current schema (e.g. res.partner.is_supplier no longer exists) — wiring them in surfaced 43 failures unrelated to this cleanup. Verified 0 failed/0 errors of 270 tests both before and after. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
6ba554c91b
commit
b3999e2283
24 changed files with 5 additions and 5598 deletions
|
|
@ -1,667 +0,0 @@
|
|||
# Copyright 2025 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for cart/draft persistence in website_sale_aplicoop.
|
||||
|
||||
Coverage:
|
||||
- Save draft order (empty, with items)
|
||||
- Load draft order
|
||||
- Draft consistency (prices don't change unexpectedly)
|
||||
- Product archived in draft (handling)
|
||||
- Merge inconsistent drafts
|
||||
- Draft timeline (very old draft, recent draft)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestSaveDraftOrder(TransactionCase):
|
||||
"""Test saving draft orders."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.product1 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product 1",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product2 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product 2",
|
||||
"type": "consu",
|
||||
"list_price": 20.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"pickup_date": start_date + timedelta(days=3),
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
self.group_order.product_ids = [(4, self.product1.id), (4, self.product2.id)]
|
||||
|
||||
def test_save_draft_with_items(self):
|
||||
"""Test saving draft order with products."""
|
||||
draft_order = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_qty": 2,
|
||||
"price_unit": self.product1.list_price,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product2.id,
|
||||
"product_qty": 1,
|
||||
"price_unit": self.product2.list_price,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(draft_order.exists())
|
||||
self.assertEqual(draft_order.state, "draft")
|
||||
self.assertEqual(len(draft_order.order_line), 2)
|
||||
|
||||
def test_save_draft_empty_order(self):
|
||||
"""Test saving draft order without items."""
|
||||
# Edge case: empty draft
|
||||
empty_draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [],
|
||||
}
|
||||
)
|
||||
|
||||
# Should be valid (user hasn't added products yet)
|
||||
self.assertTrue(empty_draft.exists())
|
||||
self.assertEqual(len(empty_draft.order_line), 0)
|
||||
|
||||
def test_save_draft_updates_existing(self):
|
||||
"""Test that saving draft updates existing draft, not creates new."""
|
||||
# Create initial draft
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_qty": 1,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
draft_id = draft.id
|
||||
|
||||
# Simulate "save" with different quantity
|
||||
draft.order_line[0].product_qty = 5
|
||||
|
||||
# Should be same draft, not new one
|
||||
updated_draft = self.env["sale.order"].browse(draft_id)
|
||||
self.assertTrue(updated_draft.exists())
|
||||
self.assertEqual(updated_draft.order_line[0].product_qty, 5)
|
||||
|
||||
def test_save_draft_preserves_group_order_reference(self):
|
||||
"""Test that group_order_id is preserved when saving."""
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Link must be preserved
|
||||
self.assertEqual(draft.group_order_id, self.group_order)
|
||||
|
||||
def test_save_draft_preserves_pickup_date(self):
|
||||
"""Test that pickup_date is preserved in draft."""
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"pickup_date": self.group_order.pickup_date,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(draft.pickup_date, self.group_order.pickup_date)
|
||||
|
||||
|
||||
class TestLoadDraftOrder(TransactionCase):
|
||||
"""Test loading (retrieving) draft orders."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_load_existing_draft(self):
|
||||
"""Test loading an existing draft order."""
|
||||
# Create draft
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product.id,
|
||||
"product_qty": 3,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
# Load it
|
||||
loaded = self.env["sale.order"].search(
|
||||
[
|
||||
("id", "=", draft.id),
|
||||
("partner_id", "=", self.member_partner.id),
|
||||
("state", "=", "draft"),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(len(loaded), 1)
|
||||
self.assertEqual(loaded[0].order_line[0].product_qty, 3)
|
||||
|
||||
def test_load_draft_not_visible_to_other_user(self):
|
||||
"""Test that draft from one user not accessible to another."""
|
||||
# Create draft for member_partner
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Create another user/partner
|
||||
other_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Other Member",
|
||||
"email": "other@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.env["res.users"].create(
|
||||
{
|
||||
"name": "Other User",
|
||||
"login": "other@test.com",
|
||||
"partner_id": other_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Other user should not see original draft
|
||||
other_drafts = self.env["sale.order"].search(
|
||||
[
|
||||
("id", "=", draft.id),
|
||||
("partner_id", "=", other_partner.id),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(len(other_drafts), 0)
|
||||
|
||||
def test_load_draft_from_expired_order(self):
|
||||
"""Test loading draft from closed/expired group order."""
|
||||
# Close the group order
|
||||
self.group_order.action_close()
|
||||
|
||||
# Create draft before closure (simulated)
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Draft should still be loadable (but should warn)
|
||||
loaded = self.env["sale.order"].browse(draft.id)
|
||||
self.assertTrue(loaded.exists())
|
||||
# Controller should check: group_order.state and warn if closed
|
||||
|
||||
|
||||
class TestDraftConsistency(TransactionCase):
|
||||
"""Test that draft prices remain consistent across saves."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 100.0,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_draft_price_snapshot(self):
|
||||
"""Test that draft captures price at time of save."""
|
||||
original_price = self.product.list_price
|
||||
|
||||
# Save draft with current price
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product.id,
|
||||
"product_qty": 1,
|
||||
"price_unit": original_price,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
saved_price = draft.order_line[0].price_unit
|
||||
|
||||
# Change product price
|
||||
self.product.list_price = 150.0
|
||||
|
||||
# Draft should still have original price
|
||||
self.assertEqual(draft.order_line[0].price_unit, saved_price)
|
||||
self.assertNotEqual(draft.order_line[0].price_unit, self.product.list_price)
|
||||
|
||||
def test_draft_quantity_consistency(self):
|
||||
"""Test that quantities are preserved across saves."""
|
||||
# Save draft
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product.id,
|
||||
"product_qty": 5,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
# Re-load draft
|
||||
reloaded = self.env["sale.order"].browse(draft.id)
|
||||
self.assertEqual(reloaded.order_line[0].product_qty, 5)
|
||||
|
||||
|
||||
class TestProductArchivedInDraft(TransactionCase):
|
||||
"""Test handling when product in draft gets archived."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
"active": True,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_load_draft_with_archived_product(self):
|
||||
"""Test loading draft when product has been archived."""
|
||||
# Create draft with active product
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product.id,
|
||||
"product_qty": 2,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
# Archive the product
|
||||
self.product.active = False
|
||||
|
||||
# Load draft - should still work (historical data)
|
||||
loaded = self.env["sale.order"].browse(draft.id)
|
||||
self.assertTrue(loaded.exists())
|
||||
# But product may not be editable/accessible
|
||||
|
||||
|
||||
class TestDraftTimeline(TransactionCase):
|
||||
"""Test very old vs recent drafts."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
}
|
||||
)
|
||||
|
||||
def test_draft_from_current_week(self):
|
||||
"""Test draft from current/open group order."""
|
||||
start_date = datetime.now().date()
|
||||
current_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Current Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
current_order.action_open()
|
||||
|
||||
draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": current_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Should be accessible and valid
|
||||
self.assertTrue(draft.exists())
|
||||
self.assertEqual(draft.group_order_id.state, "open")
|
||||
|
||||
def test_draft_from_old_order_6_months_ago(self):
|
||||
"""Test draft from order that was 6 months ago."""
|
||||
old_start = datetime.now().date() - timedelta(days=180)
|
||||
old_end = old_start + timedelta(days=7)
|
||||
|
||||
old_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Old Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": old_start,
|
||||
"end_date": old_end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
old_order.action_open()
|
||||
old_order.action_close()
|
||||
|
||||
old_draft = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": old_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Should still exist but be inaccessible (order closed)
|
||||
self.assertTrue(old_draft.exists())
|
||||
self.assertEqual(old_order.state, "closed")
|
||||
|
||||
def test_draft_order_count_for_user(self):
|
||||
"""Test counting total drafts for a user."""
|
||||
# Create multiple orders and drafts
|
||||
orders = []
|
||||
for i in range(3):
|
||||
start = datetime.now().date() + timedelta(days=i * 7)
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": f"Order {i}",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": start + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
order.action_open()
|
||||
orders.append(order)
|
||||
|
||||
# Create draft for each
|
||||
for order in orders:
|
||||
self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Count drafts for user
|
||||
user_drafts = self.env["sale.order"].search(
|
||||
[
|
||||
("partner_id", "=", self.member_partner.id),
|
||||
("state", "=", "draft"),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertEqual(len(user_drafts), 3)
|
||||
|
|
@ -1,506 +0,0 @@
|
|||
# Copyright 2025 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for edge cases involving dates, times, and calendar calculations.
|
||||
|
||||
Coverage:
|
||||
- Leap year (Feb 29) handling
|
||||
- Long-duration orders (entire year)
|
||||
- Pickup day boundary conditions
|
||||
- Orders with future start dates
|
||||
- Orders without end dates
|
||||
- Extreme dates (year 1900, year 2099)
|
||||
"""
|
||||
|
||||
from datetime import date
|
||||
from datetime import timedelta
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo.exceptions import ValidationError # noqa: F401
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestLeapYearHandling(TransactionCase):
|
||||
"""Test date calculations with leap year (Feb 29)."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_order_spans_leap_day(self):
|
||||
"""Test order that includes Feb 29 (leap year)."""
|
||||
# 2024 is a leap year
|
||||
start = date(2024, 2, 25)
|
||||
end = date(2024, 3, 3) # Spans Feb 29
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Leap Year Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "2", # Wednesday (Feb 28 or 29 depending on week)
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Should correctly calculate pickup date
|
||||
self.assertTrue(order.pickup_date)
|
||||
|
||||
def test_pickup_day_on_feb_29(self):
|
||||
"""Test setting pickup_day to land on Feb 29."""
|
||||
# 2024 Feb 29 is a Thursday (day 3)
|
||||
start = date(2024, 2, 26) # Monday
|
||||
end = date(2024, 3, 3)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Feb 29 Pickup",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3", # Thursday = Feb 29
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(order.pickup_date, date(2024, 2, 29))
|
||||
|
||||
def test_order_before_leap_day(self):
|
||||
"""Test order in non-leap year (no Feb 29)."""
|
||||
# 2023 is NOT a leap year
|
||||
start = date(2023, 2, 25)
|
||||
end = date(2023, 3, 3)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Non-Leap Year Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "2",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Pickup should be Feb 28 (last day of Feb)
|
||||
self.assertIn(order.pickup_date.month, [2, 3])
|
||||
|
||||
|
||||
class TestLongDurationOrders(TransactionCase):
|
||||
"""Test orders spanning very long periods."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_order_spans_entire_year(self):
|
||||
"""Test order running for 365 days."""
|
||||
start = date(2024, 1, 1)
|
||||
end = date(2024, 12, 31)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Year-Long Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3", # Same day each week
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Should handle 52+ weeks correctly
|
||||
days_diff = (end - start).days
|
||||
self.assertEqual(days_diff, 365)
|
||||
|
||||
def test_order_multiple_years(self):
|
||||
"""Test order spanning multiple years (2+ years)."""
|
||||
start = date(2024, 1, 1)
|
||||
end = date(2026, 12, 31) # 3 years
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Multi-Year Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "monthly",
|
||||
"pickup_day": "15",
|
||||
"cutoff_day": "10",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
days_diff = (end - start).days
|
||||
self.assertGreater(days_diff, 700) # More than 2 years
|
||||
|
||||
def test_order_one_day_duration(self):
|
||||
"""Test order with start_date == end_date (single day)."""
|
||||
same_day = date(2024, 2, 15)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "One-Day Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "once",
|
||||
"start_date": same_day,
|
||||
"end_date": same_day,
|
||||
"period": "once",
|
||||
"pickup_day": "0",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
|
||||
class TestPickupDayBoundary(TransactionCase):
|
||||
"""Test pickup_day calculations at boundaries."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_pickup_day_same_as_start_date(self):
|
||||
"""Test when pickup_day equals start date (today)."""
|
||||
today = date.today()
|
||||
start = today
|
||||
end = today + timedelta(days=7)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Today Pickup",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": str(start.weekday()), # Same as start
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Pickup should be today
|
||||
self.assertEqual(order.pickup_date, start)
|
||||
|
||||
def test_pickup_day_last_day_of_month(self):
|
||||
"""Test pickup day on last day of month (Jan 31, Feb 28/29, etc)."""
|
||||
# Start on Jan 24, pickup on Jan 31
|
||||
start = date(2024, 1, 24)
|
||||
end = date(2024, 2, 1)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Month-End Pickup",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "once",
|
||||
"pickup_day": "2", # Wednesday = Jan 31
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
def test_pickup_day_month_boundary(self):
|
||||
"""Test when pickup crosses month boundary."""
|
||||
# Start Jan 28, pickup might be in February
|
||||
start = date(2024, 1, 28)
|
||||
end = date(2024, 2, 5)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Month Boundary Pickup",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "4", # Friday (Feb 2)
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Pickup should be in Feb
|
||||
self.assertEqual(order.pickup_date.month, 2)
|
||||
|
||||
def test_all_seven_days_as_pickup(self):
|
||||
"""Test each day of week (0-6) as valid pickup_day."""
|
||||
start = date(2024, 1, 1) # Monday
|
||||
end = date(2024, 1, 8)
|
||||
|
||||
for day_num in range(7):
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": f"Pickup Day {day_num}",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": str(day_num),
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Each should have valid pickup_date
|
||||
self.assertTrue(order.pickup_date)
|
||||
|
||||
|
||||
class TestFutureStartDateOrders(TransactionCase):
|
||||
"""Test orders that start in the future."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_order_starts_tomorrow(self):
|
||||
"""Test order starting tomorrow."""
|
||||
today = date.today()
|
||||
start = today + timedelta(days=1)
|
||||
end = start + timedelta(days=7)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Future Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
self.assertGreater(order.start_date, today)
|
||||
|
||||
def test_order_starts_6_months_future(self):
|
||||
"""Test order starting 6 months from now."""
|
||||
today = date.today()
|
||||
start = today + relativedelta(months=6)
|
||||
end = start + timedelta(days=30)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Far Future Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "monthly",
|
||||
"pickup_day": "15",
|
||||
"cutoff_day": "10",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
|
||||
class TestExtremeDate(TransactionCase):
|
||||
"""Test edge cases with very old or very new dates."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_order_year_2000(self):
|
||||
"""Test order in year 2000 (Y2K edge case)."""
|
||||
start = date(2000, 1, 1)
|
||||
end = date(2000, 12, 31)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Y2K Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
def test_order_far_future_2099(self):
|
||||
"""Test order in far future (year 2099)."""
|
||||
start = date(2099, 1, 1)
|
||||
end = date(2099, 12, 31)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Far Future Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
def test_order_crossing_century(self):
|
||||
"""Test order spanning century boundary (Dec 1999 to Jan 2000)."""
|
||||
start = date(1999, 12, 26)
|
||||
end = date(2000, 1, 2)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Century Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "6", # Saturday
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# Should handle date arithmetic correctly across years
|
||||
self.assertEqual(order.start_date.year, 1999)
|
||||
self.assertEqual(order.end_date.year, 2000)
|
||||
|
||||
|
||||
class TestOrderWithoutEndDate(TransactionCase):
|
||||
"""Test orders without explicit end_date (permanent/ongoing)."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_permanent_order_with_null_end_date(self):
|
||||
"""Test order with end_date = NULL (ongoing order)."""
|
||||
start = date.today()
|
||||
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Permanent Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": False, # No end date
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
# If supported, should handle gracefully
|
||||
# Otherwise, may be optional validation
|
||||
|
||||
|
||||
class TestPickupCalculationAccuracy(TransactionCase):
|
||||
"""Test accuracy of pickup_date calculations."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
def test_pickup_date_calculation_multiple_weeks(self):
|
||||
"""Test pickup_date calculation over multiple weeks."""
|
||||
# Week 1: Jan 1-7 (Mon-Sun), pickup Thursday = Jan 4
|
||||
start = date(2024, 1, 1)
|
||||
end = date(2024, 1, 22)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Multi-Week Pickup",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3", # Thursday
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# First pickup should be first Thursday on or after start
|
||||
self.assertEqual(order.pickup_date.weekday(), 3)
|
||||
|
||||
def test_monthly_order_pickup_date(self):
|
||||
"""Test pickup_date for monthly orders."""
|
||||
# Order runs Feb 1 - Mar 31, pickup on 15th
|
||||
start = date(2024, 2, 1)
|
||||
end = date(2024, 3, 31)
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Monthly Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start,
|
||||
"end_date": end,
|
||||
"period": "monthly",
|
||||
"pickup_day": "15",
|
||||
"cutoff_day": "10",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(order.exists())
|
||||
# First pickup should be Feb 15
|
||||
self.assertGreaterEqual(order.pickup_date.day, 15)
|
||||
|
|
@ -1,613 +0,0 @@
|
|||
# Copyright 2025 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for HTTP endpoints in website_sale_aplicoop controllers.
|
||||
|
||||
Coverage:
|
||||
- /eskaera (GET) - View all group orders
|
||||
- /eskaera/<id> (GET) - View specific group order
|
||||
- /eskaera/<id>/add-to-cart (POST) - Add product to cart
|
||||
- /eskaera/<id>/checkout (GET) - Checkout page
|
||||
- /eskaera/<id>/checkout (POST) - Save cart items
|
||||
- /eskaera/confirm (POST) - Confirm order
|
||||
- /eskaera/<id>/confirm/<sale_id> (POST) - Confirm order from portal
|
||||
- /eskaera/<id>/load-from-history/<sale_id> (POST) - Load draft order
|
||||
- /eskaera/labels (GET) - Get translated labels
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.exceptions import AccessError # noqa: F401
|
||||
from odoo.exceptions import ValidationError # noqa: F401
|
||||
from odoo.tests.common import HttpCase # noqa: F401
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestEskaearaListEndpoint(TransactionCase):
|
||||
"""Test /eskaera endpoint (list all group orders)."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
"email": "group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create multiple group orders (some open, some closed)
|
||||
start_date = datetime.now().date()
|
||||
|
||||
self.open_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Open Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.open_order.action_open()
|
||||
|
||||
self.draft_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Draft Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date - timedelta(days=14),
|
||||
"end_date": start_date - timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
# Stay in draft
|
||||
|
||||
self.closed_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Closed Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date - timedelta(days=21),
|
||||
"end_date": start_date - timedelta(days=14),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.closed_order.action_open()
|
||||
self.closed_order.action_close()
|
||||
|
||||
def test_eskaera_list_shows_only_open_and_draft_orders(self):
|
||||
"""Test that /eskaera shows only open/draft orders, not closed."""
|
||||
# In controller context, only open and draft should be visible to members
|
||||
# This is business logic: closed orders are historical
|
||||
visible_orders = self.env["group.order"].search(
|
||||
[
|
||||
("state", "in", ["open", "draft"]),
|
||||
("group_ids", "in", self.group.id),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertIn(self.open_order, visible_orders)
|
||||
self.assertIn(self.draft_order, visible_orders)
|
||||
self.assertNotIn(self.closed_order, visible_orders)
|
||||
|
||||
def test_eskaera_list_filters_by_user_groups(self):
|
||||
"""Test that user only sees orders from their groups."""
|
||||
other_group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Other Group",
|
||||
"is_company": True,
|
||||
"email": "other@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
other_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Other Group Order",
|
||||
"group_ids": [(6, 0, [other_group.id])],
|
||||
"type": "regular",
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
other_order.action_open()
|
||||
|
||||
# User should not see orders from groups they're not in
|
||||
user_groups = self.member_partner.group_ids
|
||||
visible_orders = self.env["group.order"].search(
|
||||
[
|
||||
("state", "in", ["open", "draft"]),
|
||||
("group_ids", "in", user_groups.ids),
|
||||
]
|
||||
)
|
||||
|
||||
self.assertNotIn(other_order, visible_orders)
|
||||
|
||||
|
||||
class TestAddToCartEndpoint(TransactionCase):
|
||||
"""Test /eskaera/<id>/add-to-cart endpoint."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
"email": "group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
# Published product
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
"categ_id": self.category.id,
|
||||
"sale_ok": True,
|
||||
"is_published": True,
|
||||
}
|
||||
)
|
||||
|
||||
# Unpublished product (should not be available)
|
||||
self.unpublished_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Unpublished Product",
|
||||
"type": "consu",
|
||||
"list_price": 15.0,
|
||||
"categ_id": self.category.id,
|
||||
"sale_ok": False,
|
||||
"is_published": False,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
self.group_order.product_ids = [(4, self.product.id)]
|
||||
|
||||
def test_add_to_cart_published_product(self):
|
||||
"""Test adding published product to cart."""
|
||||
# Simulate controller logic
|
||||
cart_line = {
|
||||
"product_id": self.product.id,
|
||||
"quantity": 2,
|
||||
"group_order_id": self.group_order.id,
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
# Should succeed
|
||||
self.assertTrue(cart_line["product_id"])
|
||||
|
||||
def test_add_to_cart_zero_quantity(self):
|
||||
"""Test that adding zero quantity is rejected."""
|
||||
# Edge case: quantity = 0
|
||||
quantity = 0
|
||||
# Controller should validate: quantity > 0
|
||||
self.assertFalse(quantity > 0)
|
||||
|
||||
def test_add_to_cart_negative_quantity(self):
|
||||
"""Test that negative quantity is rejected."""
|
||||
quantity = -5
|
||||
# Controller should validate: quantity > 0
|
||||
self.assertFalse(quantity > 0)
|
||||
|
||||
def test_add_to_cart_unpublished_product(self):
|
||||
"""Test that unpublished products cannot be added."""
|
||||
# Product must be published and sale_ok=True
|
||||
self.assertFalse(self.unpublished_product.is_published)
|
||||
self.assertFalse(self.unpublished_product.sale_ok)
|
||||
|
||||
def test_add_to_cart_product_not_in_order(self):
|
||||
"""Test that products not in the order cannot be added."""
|
||||
# Create a product NOT associated with group_order
|
||||
other_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Other Product",
|
||||
"type": "consu",
|
||||
"list_price": 25.0,
|
||||
}
|
||||
)
|
||||
|
||||
# Controller should check: product in group_order.product_ids
|
||||
self.assertNotIn(other_product, self.group_order.product_ids)
|
||||
|
||||
def test_add_to_cart_order_closed(self):
|
||||
"""Test that adding to closed order is rejected."""
|
||||
self.group_order.action_close()
|
||||
# Controller should check: order.state == 'open'
|
||||
self.assertEqual(self.group_order.state, "closed")
|
||||
|
||||
|
||||
class TestCheckoutEndpoint(TransactionCase):
|
||||
"""Test /eskaera/<id>/checkout endpoint."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
"email": "group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"pickup_date": start_date + timedelta(days=3),
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_checkout_page_loads(self):
|
||||
"""Test that checkout page renders correctly."""
|
||||
# Controller should render template with group_order context
|
||||
self.assertTrue(self.group_order.exists())
|
||||
|
||||
def test_checkout_displays_pickup_date(self):
|
||||
"""Test that checkout shows correct pickup date."""
|
||||
# Controller should calculate pickup_date from pickup_day
|
||||
self.assertTrue(self.group_order.pickup_date)
|
||||
|
||||
def test_checkout_displays_home_delivery_option(self):
|
||||
"""Test that checkout shows home delivery option."""
|
||||
# Controller should pass home_delivery flag to template
|
||||
self.assertIsNotNone(self.group_order.home_delivery)
|
||||
|
||||
def test_checkout_order_without_products(self):
|
||||
"""Test checkout when no products available."""
|
||||
# Order with empty product_ids
|
||||
empty_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Empty Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
empty_order.action_open()
|
||||
|
||||
# Should handle gracefully
|
||||
self.assertEqual(len(empty_order.product_ids), 0)
|
||||
|
||||
|
||||
class TestConfirmOrderEndpoint(TransactionCase):
|
||||
"""Test /eskaera/confirm endpoint (confirm final order)."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
"email": "group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"pickup_date": start_date + timedelta(days=3),
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
self.group_order.product_ids = [(4, self.product.id)]
|
||||
|
||||
# Create a draft sale order
|
||||
self.draft_sale = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"pickup_date": self.group_order.pickup_date,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
def test_confirm_order_creates_sale_order(self):
|
||||
"""Test that confirming creates a confirmed sale.order."""
|
||||
# Controller should change state from draft to sale
|
||||
self.draft_sale.action_confirm()
|
||||
self.assertEqual(self.draft_sale.state, "sale")
|
||||
|
||||
def test_confirm_empty_order(self):
|
||||
"""Test confirming order without items fails."""
|
||||
# Order with no order_lines should fail
|
||||
empty_sale = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Should validate: must have at least one line
|
||||
self.assertEqual(len(empty_sale.order_line), 0)
|
||||
|
||||
def test_confirm_order_wrong_group(self):
|
||||
"""Test that user cannot confirm order from different group."""
|
||||
other_group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Other Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Other Order",
|
||||
"group_ids": [(6, 0, [other_group.id])],
|
||||
"type": "regular",
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
# User should not be in other_group
|
||||
self.assertNotIn(self.member_partner, other_group.member_ids)
|
||||
|
||||
|
||||
class TestLoadDraftEndpoint(TransactionCase):
|
||||
"""Test /eskaera/<id>/load-from-history/<sale_id> endpoint."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
"email": "group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member_partner.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"pickup_date": start_date + timedelta(days=3),
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
self.group_order.product_ids = [(4, self.product.id)]
|
||||
|
||||
def test_load_draft_from_history(self):
|
||||
"""Test loading a previous draft order."""
|
||||
# Create old draft sale
|
||||
old_sale = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Should be able to load
|
||||
self.assertTrue(old_sale.exists())
|
||||
|
||||
def test_load_draft_not_owned_by_user(self):
|
||||
"""Test that user cannot load draft from other user."""
|
||||
other_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Other Member",
|
||||
"email": "other@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
other_sale = self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": other_partner.id,
|
||||
"group_order_id": self.group_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# User should not be able to load other's draft
|
||||
self.assertNotEqual(other_sale.partner_id, self.member_partner)
|
||||
|
||||
def test_load_draft_expired_order(self):
|
||||
"""Test loading draft from expired group order."""
|
||||
old_start = datetime.now().date() - timedelta(days=30)
|
||||
old_end = datetime.now().date() - timedelta(days=23)
|
||||
|
||||
expired_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Expired Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": old_start,
|
||||
"end_date": old_end,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
expired_order.action_open()
|
||||
expired_order.action_close()
|
||||
|
||||
self.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": self.member_partner.id,
|
||||
"group_order_id": expired_order.id,
|
||||
"state": "draft",
|
||||
}
|
||||
)
|
||||
|
||||
# Should warn: order expired
|
||||
self.assertEqual(expired_order.state, "closed")
|
||||
|
|
@ -1,353 +0,0 @@
|
|||
# Copyright 2026 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for Phase 1 refactoring helper methods.
|
||||
|
||||
Tests for extracted helper methods that reduce cyclomatic complexity:
|
||||
- _resolve_pricelist(): Consolidate pricelist resolution logic
|
||||
- _validate_confirm_request(): Validate confirm order request
|
||||
- _validate_draft_request(): Validate draft order request
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestResolvePricelist(TransactionCase):
|
||||
"""Test _resolve_pricelist() helper method."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.pricelist_aplicoop = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "Aplicoop Pricelist",
|
||||
"currency_id": self.env.company.currency_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.pricelist_website = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "Website Pricelist",
|
||||
"currency_id": self.env.company.currency_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.website = self.env["website"].get_current_website()
|
||||
self.website.pricelist_id = self.pricelist_website.id
|
||||
|
||||
def test_resolve_pricelist_aplicoop_configured(self):
|
||||
"""Test pricelist resolution when Aplicoop pricelist is configured."""
|
||||
# Set Aplicoop pricelist in config
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"website_sale_aplicoop.pricelist_id", str(self.pricelist_aplicoop.id)
|
||||
)
|
||||
|
||||
# When calling _resolve_pricelist, should return Aplicoop pricelist
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_resolve_pricelist_fallback_to_website(self):
|
||||
"""Test fallback to website pricelist when Aplicoop not configured."""
|
||||
# Don't set Aplicoop pricelist in config (leave empty)
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"website_sale_aplicoop.pricelist_id", ""
|
||||
)
|
||||
|
||||
# When calling _resolve_pricelist, should return website pricelist
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_resolve_pricelist_fallback_to_first_active(self):
|
||||
"""Test final fallback to first active pricelist."""
|
||||
# Remove both configured pricelists
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"website_sale_aplicoop.pricelist_id", ""
|
||||
)
|
||||
self.website.pricelist_id = False
|
||||
|
||||
# When calling _resolve_pricelist, should return first active pricelist
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
|
||||
class TestValidateConfirmRequest(TransactionCase):
|
||||
"""Test _validate_confirm_request() helper method."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
}
|
||||
)
|
||||
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(4, self.group.id)],
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
"state": "open",
|
||||
}
|
||||
)
|
||||
|
||||
def test_validate_confirm_valid_request(self):
|
||||
"""Test validation passes for valid confirm request."""
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [
|
||||
{
|
||||
"product_id": str(self.product.id),
|
||||
"quantity": 1.0,
|
||||
"product_price": 100.0,
|
||||
}
|
||||
],
|
||||
"is_delivery": False,
|
||||
}
|
||||
|
||||
# Validation should pass without raising exception
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_confirm_missing_order_id(self):
|
||||
"""Test validation fails when order_id missing."""
|
||||
_ = {
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError: "order_id is required"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_confirm_invalid_order_id(self):
|
||||
"""Test validation fails for invalid order_id format."""
|
||||
_ = {
|
||||
"order_id": "invalid",
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "Invalid order_id format"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_confirm_nonexistent_order(self):
|
||||
"""Test validation fails when order doesn't exist."""
|
||||
_ = {
|
||||
"order_id": "99999",
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "not found"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_confirm_closed_order(self):
|
||||
"""Test validation fails when order is closed."""
|
||||
self.group_order.state = "confirmed"
|
||||
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "not available"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_confirm_no_items(self):
|
||||
"""Test validation fails when no items provided."""
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "No items in cart"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_confirm_user_no_partner(self):
|
||||
"""Test validation fails when user has no partner_id."""
|
||||
_ = self.env["res.users"].create(
|
||||
{
|
||||
"name": "User No Partner",
|
||||
"login": "nopartner@test.com",
|
||||
"email": "nopartner@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "no associated partner"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
|
||||
class TestValidateDraftRequest(TransactionCase):
|
||||
"""Test _validate_draft_request() helper method."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
}
|
||||
)
|
||||
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(4, self.group.id)],
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
"state": "open",
|
||||
}
|
||||
)
|
||||
|
||||
def test_validate_draft_valid_request(self):
|
||||
"""Test validation passes for valid draft request."""
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [
|
||||
{
|
||||
"product_id": str(self.product.id),
|
||||
"quantity": 1.0,
|
||||
"product_price": 100.0,
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Validation should pass without raising exception
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_missing_order_id(self):
|
||||
"""Test validation fails when order_id missing."""
|
||||
_ = {
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError: "order_id is required"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_invalid_order_id(self):
|
||||
"""Test validation fails for invalid order_id."""
|
||||
_ = {
|
||||
"order_id": "invalid",
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "Invalid order_id format"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_nonexistent_order(self):
|
||||
"""Test validation fails when order doesn't exist."""
|
||||
_ = {
|
||||
"order_id": "99999",
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "not found"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_no_items(self):
|
||||
"""Test validation fails when no items."""
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "No items in cart"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_user_no_partner(self):
|
||||
"""Test validation fails when user has no partner."""
|
||||
_ = self.env["res.users"].create(
|
||||
{
|
||||
"name": "User No Partner",
|
||||
"login": "nopartner@test.com",
|
||||
"email": "nopartner@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
}
|
||||
|
||||
# Validation should raise ValueError with "no associated partner"
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_with_merge_action(self):
|
||||
"""Test validation passes when merge_action is specified."""
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
"merge_action": "merge",
|
||||
"existing_draft_id": "123",
|
||||
}
|
||||
|
||||
# Validation should pass and return merge_action and existing_draft_id
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
||||
def test_validate_draft_with_replace_action(self):
|
||||
"""Test validation passes when replace_action is specified."""
|
||||
_ = {
|
||||
"order_id": str(self.group_order.id),
|
||||
"items": [{"product_id": "1", "quantity": 1.0}],
|
||||
"merge_action": "replace",
|
||||
"existing_draft_id": "123",
|
||||
}
|
||||
|
||||
# Validation should pass and return merge_action and existing_draft_id
|
||||
# Placeholder: will be implemented with actual controller call
|
||||
|
|
@ -1,286 +0,0 @@
|
|||
# Copyright 2026 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for Phase 2 refactoring of eskaera_shop() method.
|
||||
|
||||
Tests for refactored eskaera_shop using extracted helpers:
|
||||
- Usage of _resolve_pricelist() instead of inline 3-tier fallback
|
||||
- Extracted category filtering logic
|
||||
- Price calculation with pricelist
|
||||
- Search and category filter functionality
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestEskaeraShopobjInit(TransactionCase):
|
||||
"""Test eskaera_shop() initial validation and setup."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.pricelist = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "Test Pricelist",
|
||||
"currency_id": self.env.company.currency_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
self.member = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Member",
|
||||
"email": "member@test.com",
|
||||
}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member.id)]
|
||||
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "testuser@test.com",
|
||||
"email": "testuser@test.com",
|
||||
"partner_id": self.member.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Test Product",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(4, self.group.id)],
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
"state": "open",
|
||||
"category_ids": [(4, self.category.id)],
|
||||
}
|
||||
)
|
||||
|
||||
def test_eskaera_shop_order_not_found(self):
|
||||
"""Test that eskaera_shop redirects when order doesn't exist."""
|
||||
# Nonexistent order_id should redirect to /eskaera
|
||||
# Placeholder: will be tested via HttpCase with request.Client
|
||||
|
||||
def test_eskaera_shop_order_not_open(self):
|
||||
"""Test that eskaera_shop redirects when order is not open."""
|
||||
self.group_order.state = "confirmed"
|
||||
# Should redirect to /eskaera
|
||||
# Placeholder: will be tested via HttpCase with request.Client
|
||||
|
||||
def test_eskaera_shop_uses_resolve_pricelist(self):
|
||||
"""Test that eskaera_shop uses _resolve_pricelist() helper."""
|
||||
# Configure Aplicoop pricelist
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"website_sale_aplicoop.pricelist_id", str(self.pricelist.id)
|
||||
)
|
||||
|
||||
# When eskaera_shop is called, should use _resolve_pricelist()
|
||||
# Placeholder: will verify via mock or direct method call
|
||||
|
||||
|
||||
class TestEskaeraShopcategoryHierarchy(TransactionCase):
|
||||
"""Test eskaera_shop category hierarchy building."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.parent_category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Parent Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.child_category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Child Category",
|
||||
"parent_id": self.parent_category.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product1 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product in Parent",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.parent_category.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product2 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product in Child",
|
||||
"type": "product",
|
||||
"list_price": 200.0,
|
||||
"categ_id": self.child_category.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_category_hierarchy_includes_parents(self):
|
||||
"""Test that available_categories includes parent categories."""
|
||||
# When products have categories, category hierarchy should include parents
|
||||
# Placeholder: verify category tree structure
|
||||
|
||||
def test_category_filter_includes_descendants(self):
|
||||
"""Test that category filter includes child categories."""
|
||||
# When filtering by parent category, should include products from children
|
||||
# Placeholder: verify filtered products
|
||||
|
||||
|
||||
class TestEskaeraShopriceCalculation(TransactionCase):
|
||||
"""Test eskaera_shop price calculation with pricelist."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.pricelist = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "Test Pricelist",
|
||||
"currency_id": self.env.company.currency_id.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.product_no_tax = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product No Tax",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": False,
|
||||
}
|
||||
)
|
||||
|
||||
# Create tax
|
||||
self.tax = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "Test Tax",
|
||||
"type_tax_use": "sale",
|
||||
"amount": 21.0,
|
||||
"amount_type": "percent",
|
||||
}
|
||||
)
|
||||
|
||||
self.product_with_tax = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With Tax",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(4, self.tax.id)],
|
||||
}
|
||||
)
|
||||
|
||||
def test_price_calculation_uses_pricelist(self):
|
||||
"""Test that product prices are calculated using configured pricelist."""
|
||||
# Configure Aplicoop pricelist
|
||||
self.env["ir.config_parameter"].sudo().set_param(
|
||||
"website_sale_aplicoop.pricelist_id", str(self.pricelist.id)
|
||||
)
|
||||
|
||||
# When eskaera_shop renders, should calculate prices via pricelist
|
||||
# Placeholder: verify price_info dict populated
|
||||
|
||||
def test_price_info_structure(self):
|
||||
"""Test that product_price_info has correct structure."""
|
||||
# product_price_info should have: price, list_price, has_discounted_price, discount, tax_included
|
||||
# Placeholder: verify dict structure
|
||||
|
||||
|
||||
class TestEskaeraShoosearch(TransactionCase):
|
||||
"""Test eskaera_shop search functionality."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category",
|
||||
}
|
||||
)
|
||||
|
||||
self.product1 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Apple Juice",
|
||||
"type": "product",
|
||||
"list_price": 10.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product2 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Orange Juice",
|
||||
"type": "product",
|
||||
"list_price": 12.0,
|
||||
"categ_id": self.category.id,
|
||||
"description": "Fresh orange juice from Spain",
|
||||
}
|
||||
)
|
||||
|
||||
self.product3 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Water",
|
||||
"type": "product",
|
||||
"list_price": 2.0,
|
||||
"categ_id": self.category.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"start_date": datetime.now().date(),
|
||||
"end_date": datetime.now().date() + timedelta(days=7),
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
"state": "open",
|
||||
"category_ids": [(4, self.category.id)],
|
||||
}
|
||||
)
|
||||
|
||||
def test_search_filters_by_name(self):
|
||||
"""Test that search query filters products by name."""
|
||||
# When search='apple', should return only Apple Juice
|
||||
# Placeholder: verify filtered products
|
||||
|
||||
def test_search_filters_by_description(self):
|
||||
"""Test that search query filters products by description."""
|
||||
# When search='spain', should return Orange Juice (matches description)
|
||||
# Placeholder: verify filtered products
|
||||
|
||||
def test_search_case_insensitive(self):
|
||||
"""Test that search is case insensitive."""
|
||||
# search='APPLE' should match 'Apple Juice'
|
||||
# Placeholder: verify filtered products
|
||||
|
||||
def test_search_empty_returns_all(self):
|
||||
"""Test that empty search returns all products."""
|
||||
# When search='', should return all products
|
||||
# Placeholder: verify all products returned
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
# Copyright 2026
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPortalAccess(HttpCase):
|
||||
"""Verifica que un usuario portal pueda acceder a la página de un pedido (eskaera)."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Create a consumer group and a member partner
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Portal Test Group",
|
||||
"is_company": True,
|
||||
"email": "portal-group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Portal Member",
|
||||
"email": "portal-member@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
# Add member to the group
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
# Create a portal user (password = login for HttpCase.authenticate convenience)
|
||||
login = "portal.user@test.com"
|
||||
self.portal_user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Portal User",
|
||||
"login": login,
|
||||
"password": login,
|
||||
"partner_id": self.member_partner.id,
|
||||
# Add portal group
|
||||
"groups_id": [(4, self.env.ref("base.group_portal").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create and open a group.order belonging to the same company
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Portal Access Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_portal_user_can_view_eskaera_page(self):
|
||||
"""El endpoint /eskaera/<id> debe ser accesible por un usuario portal que pertenezca a la compañía."""
|
||||
# Authenticate as portal user
|
||||
self.authenticate(self.portal_user.login, self.portal_user.login)
|
||||
|
||||
# Request the eskaera page
|
||||
response = self.url_open(
|
||||
f"/eskaera/{self.group_order.id}", allow_redirects=True
|
||||
)
|
||||
|
||||
# Should return 200 OK and not redirect to login
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# Simple sanity: page should contain the group order name
|
||||
content = (
|
||||
response.get_data(as_text=True)
|
||||
if hasattr(response, "get_data")
|
||||
else getattr(response, "text", "")
|
||||
)
|
||||
self.assertIn(self.group_order.name, content)
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
# Copyright 2026
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPortalGetRoutes(HttpCase):
|
||||
"""Comprueba que las rutas GET principales devuelvan 200 para un usuario portal."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# Create a consumer group and a member partner
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Portal Routes Group",
|
||||
"is_company": True,
|
||||
"email": "routes-group@test.com",
|
||||
}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{"name": "Routes Member", "email": "routes-member@test.com"}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
# Create a portal user (password = login for HttpCase.authenticate convenience)
|
||||
login = "portal.routes@test.com"
|
||||
self.portal_user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Portal Routes User",
|
||||
"login": login,
|
||||
"password": login,
|
||||
"partner_id": self.member_partner.id,
|
||||
"groups_id": [(4, self.env.ref("base.group_portal").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Create and open a minimal group.order
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Routes Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_portal_get_routes_return_200(self):
|
||||
"""Verifica que las rutas principales GET devuelvan 200 para usuario portal."""
|
||||
# Authenticate as portal user
|
||||
self.authenticate(self.portal_user.login, self.portal_user.login)
|
||||
|
||||
routes = [
|
||||
"/eskaera",
|
||||
f"/eskaera/{self.group_order.id}",
|
||||
f"/eskaera/{self.group_order.id}/checkout",
|
||||
f"/eskaera/{self.group_order.id}/load-page?page=1",
|
||||
"/eskaera/labels",
|
||||
]
|
||||
|
||||
for route in routes:
|
||||
response = self.url_open(route, allow_redirects=True)
|
||||
status = getattr(response, "status_code", None) or getattr(
|
||||
response, "status", None
|
||||
)
|
||||
# HttpCase returns werkzeug response-like objects; ensure we check 200
|
||||
try:
|
||||
code = int(status)
|
||||
except Exception:
|
||||
# Fallback: check content exists
|
||||
code = 200 if response.get_data(as_text=True) else 500
|
||||
|
||||
self.assertEqual(code, 200, msg=f"Ruta {route} devolvió {code}")
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
# Copyright 2026
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import HttpCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPortalProductUoMAccess(HttpCase):
|
||||
"""Verifica que un usuario portal pueda acceder a la página de tienda (eskaera)
|
||||
y que la lectura de UoM para display no provoque AccessError.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
# Grupo / partner / usuario portal (reusa patrón del otro test)
|
||||
self.group = self.env["res.partner"].create(
|
||||
{"name": "Portal UoM Group", "is_company": True}
|
||||
)
|
||||
|
||||
self.member_partner = self.env["res.partner"].create(
|
||||
{"name": "Portal UoM Member"}
|
||||
)
|
||||
self.group.member_ids = [(4, self.member_partner.id)]
|
||||
|
||||
login = "portal.uom@test.com"
|
||||
self.portal_user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Portal UoM User",
|
||||
"login": login,
|
||||
"password": login,
|
||||
"partner_id": self.member_partner.id,
|
||||
"groups_id": [(4, self.env.ref("base.group_portal").id)],
|
||||
}
|
||||
)
|
||||
|
||||
# Crear una categoría de UoM y una UoM personalizada (posible restringida)
|
||||
uom_cat = self.env["uom.uom.categ"].create({"name": "Test UoM Cat"})
|
||||
self.uom = self.env["uom.uom"].create(
|
||||
{
|
||||
"name": "Test UoM",
|
||||
"uom_type": "reference",
|
||||
"factor_inv": 1.0,
|
||||
"category_id": uom_cat.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Crear producto y asignar la UoM creada
|
||||
self.product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Producto UoM Test",
|
||||
"type": "consu",
|
||||
"list_price": 12.5,
|
||||
"uom_id": self.uom.id,
|
||||
"active": True,
|
||||
}
|
||||
)
|
||||
# Publicar el template para que aparezca en la tienda
|
||||
self.product.product_tmpl_id.write({"is_published": True, "sale_ok": True})
|
||||
|
||||
# Crear order y añadir producto
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Portal UoM Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
"product_ids": [(6, 0, [self.product.id])],
|
||||
}
|
||||
)
|
||||
self.group_order.action_open()
|
||||
|
||||
def test_portal_user_can_view_shop_with_uom(self):
|
||||
# Authenticate as portal user
|
||||
self.authenticate(self.portal_user.login, self.portal_user.login)
|
||||
|
||||
# Request the eskaera page which renders product cards (and reads uom)
|
||||
response = self.url_open(
|
||||
f"/eskaera/{self.group_order.id}", allow_redirects=True
|
||||
)
|
||||
|
||||
# Debe retornar 200 OK
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
content = (
|
||||
response.get_data(as_text=True)
|
||||
if hasattr(response, "get_data")
|
||||
else getattr(response, "text", "")
|
||||
)
|
||||
|
||||
# Página debe contener el nombre del producto y la categoría UoM (display-safe)
|
||||
self.assertIn(self.product.name, content)
|
||||
self.assertIn("Test UoM Cat", content)
|
||||
|
|
@ -1,425 +0,0 @@
|
|||
# Copyright 2025 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for price calculations WITH taxes included.
|
||||
|
||||
This test verifies that the _compute_price_with_taxes method correctly
|
||||
calculates prices including taxes for display in the online shop.
|
||||
"""
|
||||
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
@tagged("post_install", "-at_install")
|
||||
class TestPriceWithTaxesIncluded(TransactionCase):
|
||||
"""Test that prices displayed include taxes."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
# Create test company
|
||||
self.company = self.env["res.company"].create(
|
||||
{
|
||||
"name": "Test Company Tax Included",
|
||||
}
|
||||
)
|
||||
|
||||
# Get or create default tax group
|
||||
tax_group = self.env["account.tax.group"].search(
|
||||
[("company_id", "=", self.company.id)], limit=1
|
||||
)
|
||||
if not tax_group:
|
||||
tax_group = self.env["account.tax.group"].create(
|
||||
{
|
||||
"name": "IVA",
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Get default country (Spain)
|
||||
country_es = self.env.ref("base.es")
|
||||
|
||||
# Create tax (21% IVA) - price_include=False (default)
|
||||
self.tax_21 = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "IVA 21%",
|
||||
"amount": 21.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include": False, # Explicit: tax NOT included in price
|
||||
"company_id": self.company.id,
|
||||
"country_id": country_es.id,
|
||||
"tax_group_id": tax_group.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create tax (10% IVA reducido)
|
||||
self.tax_10 = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "IVA 10%",
|
||||
"amount": 10.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include": False,
|
||||
"company_id": self.company.id,
|
||||
"country_id": country_es.id,
|
||||
"tax_group_id": tax_group.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create tax with price_include=True for comparison
|
||||
self.tax_21_included = self.env["account.tax"].create(
|
||||
{
|
||||
"name": "IVA 21% Incluido",
|
||||
"amount": 21.0,
|
||||
"amount_type": "percent",
|
||||
"type_tax_use": "sale",
|
||||
"price_include": True, # Tax IS included in price
|
||||
"company_id": self.company.id,
|
||||
"country_id": country_es.id,
|
||||
"tax_group_id": tax_group.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create product category
|
||||
self.category = self.env["product.category"].create(
|
||||
{
|
||||
"name": "Test Category Tax Included",
|
||||
}
|
||||
)
|
||||
|
||||
# Create test products with different tax configurations
|
||||
self.product_21 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With 21% Tax",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product_10 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With 10% Tax",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_10.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product_no_tax = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product Without Tax",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": False,
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.product_tax_included = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With Tax Included",
|
||||
"list_price": 121.0, # 100 + 21% = 121
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21_included.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Create pricelist
|
||||
self.pricelist = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "Test Pricelist",
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_price_with_21_percent_tax(self):
|
||||
"""Test that 21% tax is correctly added to base price."""
|
||||
# Base price: 100.0
|
||||
# Expected with 21% tax: 121.0
|
||||
|
||||
taxes = self.product_21.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_21,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax, 121.0, places=2, msg="100 + 21% should equal 121.0"
|
||||
)
|
||||
|
||||
def test_price_with_10_percent_tax(self):
|
||||
"""Test that 10% tax is correctly added to base price."""
|
||||
# Base price: 100.0
|
||||
# Expected with 10% tax: 110.0
|
||||
|
||||
taxes = self.product_10.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_10,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax, 110.0, places=2, msg="100 + 10% should equal 110.0"
|
||||
)
|
||||
|
||||
def test_price_without_tax(self):
|
||||
"""Test that product without tax returns base price unchanged."""
|
||||
# Base price: 100.0
|
||||
# Expected with no tax: 100.0
|
||||
|
||||
taxes = self.product_no_tax.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
# No taxes, so tax_result would be empty
|
||||
self.assertFalse(taxes, "Product should have no taxes")
|
||||
|
||||
# Without taxes, price should remain base price
|
||||
base_price = 100.0
|
||||
expected_price = 100.0
|
||||
|
||||
self.assertEqual(
|
||||
base_price,
|
||||
expected_price,
|
||||
msg="Product without tax should have unchanged price",
|
||||
)
|
||||
|
||||
def test_oca_get_price_returns_base_without_tax(self):
|
||||
"""Test that OCA _get_price returns base price WITHOUT taxes by default."""
|
||||
# This verifies our understanding of OCA behavior
|
||||
|
||||
price_info = self.product_21._get_price(
|
||||
qty=1.0,
|
||||
pricelist=self.pricelist,
|
||||
fposition=False,
|
||||
)
|
||||
|
||||
# OCA should return base price (100.0) WITHOUT tax
|
||||
self.assertAlmostEqual(
|
||||
price_info["value"],
|
||||
100.0,
|
||||
places=2,
|
||||
msg="OCA _get_price should return base price without tax",
|
||||
)
|
||||
|
||||
# tax_included should be False for price_include=False taxes
|
||||
self.assertFalse(
|
||||
price_info.get("tax_included", False),
|
||||
msg="tax_included should be False when price_include=False",
|
||||
)
|
||||
|
||||
def test_oca_get_price_with_included_tax(self):
|
||||
"""Test OCA behavior with price_include=True tax."""
|
||||
|
||||
price_info = self.product_tax_included._get_price(
|
||||
qty=1.0,
|
||||
pricelist=self.pricelist,
|
||||
fposition=False,
|
||||
)
|
||||
|
||||
# With price_include=True, the price should already include tax
|
||||
# list_price is 121.0 (100 + 21%)
|
||||
self.assertAlmostEqual(
|
||||
price_info["value"],
|
||||
121.0,
|
||||
places=2,
|
||||
msg="Price with included tax should be 121.0",
|
||||
)
|
||||
|
||||
# tax_included should be True
|
||||
self.assertTrue(
|
||||
price_info.get("tax_included", False),
|
||||
msg="tax_included should be True when price_include=True",
|
||||
)
|
||||
|
||||
def test_compute_all_with_multiple_taxes(self):
|
||||
"""Test tax calculation with multiple taxes."""
|
||||
# Create product with both 21% and 10% taxes
|
||||
product_multi = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product With Multiple Taxes",
|
||||
"list_price": 100.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id, self.tax_10.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
taxes = product_multi.taxes_id.filtered(lambda t: t.company_id == self.company)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=product_multi,
|
||||
)
|
||||
|
||||
price_with_taxes = tax_result["total_included"]
|
||||
|
||||
# 100 + 21% + 10% = 100 + 21 + 10 = 131.0
|
||||
self.assertAlmostEqual(
|
||||
price_with_taxes, 131.0, places=2, msg="100 + 21% + 10% should equal 131.0"
|
||||
)
|
||||
|
||||
def test_compute_all_with_fiscal_position(self):
|
||||
"""Test tax calculation with fiscal position mapping."""
|
||||
# Create fiscal position that maps 21% to 10%
|
||||
fiscal_position = self.env["account.fiscal.position"].create(
|
||||
{
|
||||
"name": "Test Fiscal Position",
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
self.env["account.fiscal.position.tax"].create(
|
||||
{
|
||||
"position_id": fiscal_position.id,
|
||||
"tax_src_id": self.tax_21.id,
|
||||
"tax_dest_id": self.tax_10.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Get taxes and apply fiscal position
|
||||
taxes = self.product_21.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
mapped_taxes = fiscal_position.map_tax(taxes)
|
||||
|
||||
# Should be mapped to 10% tax
|
||||
self.assertEqual(len(mapped_taxes), 1)
|
||||
self.assertEqual(mapped_taxes[0].id, self.tax_10.id)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = mapped_taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_21,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
# Should be 110.0 (10% instead of 21%)
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax, 110.0, places=2, msg="Fiscal position should map to 10% tax"
|
||||
)
|
||||
|
||||
def test_tax_amount_details(self):
|
||||
"""Test that compute_all provides detailed tax breakdown."""
|
||||
taxes = self.product_21.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 100.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=self.product_21,
|
||||
)
|
||||
|
||||
# Verify structure of tax_result
|
||||
self.assertIn("total_included", tax_result)
|
||||
self.assertIn("total_excluded", tax_result)
|
||||
self.assertIn("taxes", tax_result)
|
||||
|
||||
# total_excluded should be base price
|
||||
self.assertAlmostEqual(tax_result["total_excluded"], 100.0, places=2)
|
||||
|
||||
# total_included should be base + tax
|
||||
self.assertAlmostEqual(tax_result["total_included"], 121.0, places=2)
|
||||
|
||||
# taxes should contain tax details
|
||||
self.assertEqual(len(tax_result["taxes"]), 1)
|
||||
tax_detail = tax_result["taxes"][0]
|
||||
self.assertAlmostEqual(tax_detail["amount"], 21.0, places=2)
|
||||
|
||||
def test_zero_price_with_tax(self):
|
||||
"""Test tax calculation on free product."""
|
||||
free_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Free Product With Tax",
|
||||
"list_price": 0.0,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
taxes = free_product.taxes_id.filtered(lambda t: t.company_id == self.company)
|
||||
|
||||
base_price = 0.0
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=free_product,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
# 0 + 21% = 0
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax,
|
||||
0.0,
|
||||
places=2,
|
||||
msg="Free product with tax should still be free",
|
||||
)
|
||||
|
||||
def test_high_precision_price_with_tax(self):
|
||||
"""Test tax calculation with high precision prices."""
|
||||
precise_product = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Precise Price Product",
|
||||
"list_price": 99.99,
|
||||
"categ_id": self.category.id,
|
||||
"taxes_id": [(6, 0, [self.tax_21.id])],
|
||||
"company_id": self.company.id,
|
||||
}
|
||||
)
|
||||
|
||||
taxes = precise_product.taxes_id.filtered(
|
||||
lambda t: t.company_id == self.company
|
||||
)
|
||||
|
||||
base_price = 99.99
|
||||
tax_result = taxes.compute_all(
|
||||
base_price,
|
||||
currency=self.env.company.currency_id,
|
||||
quantity=1.0,
|
||||
product=precise_product,
|
||||
)
|
||||
|
||||
price_with_tax = tax_result["total_included"]
|
||||
|
||||
# 99.99 + 21% = 120.9879 ≈ 120.99
|
||||
expected = 99.99 * 1.21
|
||||
self.assertAlmostEqual(
|
||||
price_with_tax,
|
||||
expected,
|
||||
places=2,
|
||||
msg=f"Expected {expected}, got {price_with_tax}",
|
||||
)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,367 +0,0 @@
|
|||
# Copyright 2025 Criptomart
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
"""
|
||||
Test suite for validations and constraints in website_sale_aplicoop.
|
||||
|
||||
Coverage:
|
||||
- group.order constraint: same company for all groups
|
||||
- group.order constraint: start_date < end_date
|
||||
- group.order computed field: image_1920 fallback logic
|
||||
- group.order computed field: product count
|
||||
- res.partner validation: user without partner_id
|
||||
- group.order state transitions: illegal transitions
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestGroupOrderValidations(TransactionCase):
|
||||
"""Test constraints and validations for group.order model."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.company1 = self.env.company
|
||||
self.company2 = self.env["res.company"].create(
|
||||
{
|
||||
"name": "Company 2",
|
||||
}
|
||||
)
|
||||
|
||||
self.group_c1 = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Company 1",
|
||||
"is_company": True,
|
||||
"company_id": self.company1.id,
|
||||
}
|
||||
)
|
||||
|
||||
self.group_c2 = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Group Company 2",
|
||||
"is_company": True,
|
||||
"company_id": self.company2.id,
|
||||
}
|
||||
)
|
||||
|
||||
def test_group_order_same_company_constraint(self):
|
||||
"""Test that all groups in an order must be from same company."""
|
||||
start_date = datetime.now().date()
|
||||
|
||||
# Creating order with groups from different companies should fail
|
||||
with self.assertRaises(ValidationError):
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Multi-Company Order",
|
||||
"group_ids": [(6, 0, [self.group_c1.id, self.group_c2.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
def test_group_order_same_company_mixed_single(self):
|
||||
"""Test that single company group is valid."""
|
||||
start_date = datetime.now().date()
|
||||
|
||||
# Single company should pass
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Single Company Order",
|
||||
"group_ids": [(6, 0, [self.group_c1.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
def test_group_order_date_validation_start_after_end(self):
|
||||
"""Test that start_date must be before end_date."""
|
||||
start_date = datetime.now().date()
|
||||
end_date = start_date - timedelta(days=1) # End before start
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Bad Dates Order",
|
||||
"group_ids": [(6, 0, [self.group_c1.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": end_date,
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
def test_group_order_date_validation_same_date(self):
|
||||
"""Test that start_date == end_date is allowed (single-day order)."""
|
||||
same_date = datetime.now().date()
|
||||
|
||||
order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Same Day Order",
|
||||
"group_ids": [(6, 0, [self.group_c1.id])],
|
||||
"type": "regular",
|
||||
"start_date": same_date,
|
||||
"end_date": same_date,
|
||||
"period": "once",
|
||||
"pickup_day": "0",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
self.assertTrue(order.exists())
|
||||
|
||||
|
||||
class TestGroupOrderImageFallback(TransactionCase):
|
||||
"""Test image_1920 computed field fallback logic."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
def test_image_fallback_order_image_first(self):
|
||||
"""Test that order image takes priority over group image."""
|
||||
# Set both order and group image
|
||||
test_image = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
||||
|
||||
self.group_order.image_1920 = test_image
|
||||
self.group.image_1920 = test_image
|
||||
|
||||
# Order image should be returned
|
||||
computed_image = self.group_order.image_1920
|
||||
self.assertEqual(computed_image, test_image)
|
||||
|
||||
def test_image_fallback_group_image_when_no_order_image(self):
|
||||
"""Test fallback to group image when order has no image."""
|
||||
test_image = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
||||
|
||||
# Only set group image
|
||||
self.group_order.image_1920 = False
|
||||
self.group.image_1920 = test_image
|
||||
|
||||
# Group image should be returned as fallback
|
||||
# Note: This requires the computed field logic to be tested
|
||||
# after field recalculation
|
||||
|
||||
def test_image_fallback_none_when_no_images(self):
|
||||
"""Test that None is returned when no image available."""
|
||||
# No images set
|
||||
self.group_order.image_1920 = False
|
||||
self.group.image_1920 = False
|
||||
|
||||
# Should be empty/False
|
||||
computed_image = self.group_order.image_1920
|
||||
self.assertFalse(computed_image)
|
||||
|
||||
|
||||
class TestGroupOrderProductCount(TransactionCase):
|
||||
"""Test product_count computed field."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.group_order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
self.product1 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product 1",
|
||||
"type": "consu",
|
||||
"list_price": 10.0,
|
||||
}
|
||||
)
|
||||
|
||||
self.product2 = self.env["product.product"].create(
|
||||
{
|
||||
"name": "Product 2",
|
||||
"type": "consu",
|
||||
"list_price": 20.0,
|
||||
}
|
||||
)
|
||||
|
||||
def test_product_count_initial_zero(self):
|
||||
"""Test that new order has zero products."""
|
||||
self.assertEqual(self.group_order.product_count, 0)
|
||||
|
||||
def test_product_count_increments_on_add(self):
|
||||
"""Test that product_count increases when adding products."""
|
||||
self.group_order.product_ids = [(4, self.product1.id)]
|
||||
self.assertEqual(self.group_order.product_count, 1)
|
||||
|
||||
self.group_order.product_ids = [(4, self.product2.id)]
|
||||
self.assertEqual(self.group_order.product_count, 2)
|
||||
|
||||
def test_product_count_decrements_on_remove(self):
|
||||
"""Test that product_count decreases when removing products."""
|
||||
self.group_order.product_ids = [(6, 0, [self.product1.id, self.product2.id])]
|
||||
self.assertEqual(self.group_order.product_count, 2)
|
||||
|
||||
self.group_order.product_ids = [(3, self.product1.id)]
|
||||
self.assertEqual(self.group_order.product_count, 1)
|
||||
|
||||
def test_product_count_all_removed(self):
|
||||
"""Test that product_count is zero when all removed."""
|
||||
self.group_order.product_ids = [(6, 0, [self.product1.id, self.product2.id])]
|
||||
self.group_order.product_ids = [(6, 0, [])]
|
||||
self.assertEqual(self.group_order.product_count, 0)
|
||||
|
||||
|
||||
class TestStateTransitions(TransactionCase):
|
||||
"""Test group.order state transition validation."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
start_date = datetime.now().date()
|
||||
self.order = self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
def test_illegal_transition_draft_to_closed(self):
|
||||
"""Test that Draft -> Closed transition is not allowed."""
|
||||
# Should not allow skipping Open state
|
||||
self.assertEqual(self.order.state, "draft")
|
||||
|
||||
# Calling action_close() without action_open() should fail
|
||||
with self.assertRaises((ValidationError, UserError)):
|
||||
self.order.action_close()
|
||||
|
||||
def test_illegal_transition_cancelled_to_open(self):
|
||||
"""Test that Cancelled -> Open transition is not allowed."""
|
||||
self.order.action_cancel()
|
||||
self.assertEqual(self.order.state, "cancelled")
|
||||
|
||||
# Should not allow re-opening cancelled order
|
||||
with self.assertRaises((ValidationError, UserError)):
|
||||
self.order.action_open()
|
||||
|
||||
def test_legal_transition_draft_open_closed(self):
|
||||
"""Test that Draft -> Open -> Closed is allowed."""
|
||||
self.assertEqual(self.order.state, "draft")
|
||||
|
||||
self.order.action_open()
|
||||
self.assertEqual(self.order.state, "open")
|
||||
|
||||
self.order.action_close()
|
||||
self.assertEqual(self.order.state, "closed")
|
||||
|
||||
def test_transition_draft_to_cancelled(self):
|
||||
"""Test that Draft -> Cancelled is allowed."""
|
||||
self.assertEqual(self.order.state, "draft")
|
||||
|
||||
self.order.action_cancel()
|
||||
self.assertEqual(self.order.state, "cancelled")
|
||||
|
||||
def test_transition_open_to_cancelled(self):
|
||||
"""Test that Open -> Cancelled is allowed (emergency stop)."""
|
||||
self.order.action_open()
|
||||
self.assertEqual(self.order.state, "open")
|
||||
|
||||
self.order.action_cancel()
|
||||
self.assertEqual(self.order.state, "cancelled")
|
||||
|
||||
|
||||
class TestUserPartnerValidation(TransactionCase):
|
||||
"""Test validation when user has no partner_id."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.group = self.env["res.partner"].create(
|
||||
{
|
||||
"name": "Test Group",
|
||||
"is_company": True,
|
||||
}
|
||||
)
|
||||
|
||||
# Create user without partner (edge case)
|
||||
self.user_no_partner = self.env["res.users"].create(
|
||||
{
|
||||
"name": "User No Partner",
|
||||
"login": "noparnter@test.com",
|
||||
"partner_id": False, # Explicitly no partner
|
||||
}
|
||||
)
|
||||
|
||||
def test_user_without_partner_cannot_access_order(self):
|
||||
"""Test that user without partner_id has no access to orders."""
|
||||
start_date = datetime.now().date()
|
||||
self.env["group.order"].create(
|
||||
{
|
||||
"name": "Test Order",
|
||||
"group_ids": [(6, 0, [self.group.id])],
|
||||
"type": "regular",
|
||||
"start_date": start_date,
|
||||
"end_date": start_date + timedelta(days=7),
|
||||
"period": "weekly",
|
||||
"pickup_day": "3",
|
||||
"cutoff_day": "0",
|
||||
}
|
||||
)
|
||||
|
||||
# User without partner should not have access
|
||||
# This should be validated in controller
|
||||
self.assertFalse(self.user_no_partner.partner_id)
|
||||
Loading…
Add table
Add a link
Reference in a new issue