- 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.
667 lines
20 KiB
Python
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)
|