addons-cm/website_sale_aplicoop/tests/test_draft_persistence.py
snt cf9ea887c1 [REF] Code quality improvements and structure fixes
- Add mypy.ini configuration to exclude migration scripts
- Rename migration files to proper snake_case (post-migration.py → post_migration.py)
- Add __init__.py to migration directories for proper Python package structure
- Add new portal access tests for website_sale_aplicoop
- Code formatting improvements (black, isort)
- Update copilot instructions and project configuration

Related to previous code quality refactoring work.
2026-02-21 13:51:25 +01:00

667 lines
20 KiB
Python

# 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)