534 lines
17 KiB
Python
534 lines
17 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, 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',
|
|
})
|
|
|
|
other_user = 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)
|