1+ # Copyright 2024 ForgeFlow, S.L.
2+ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)
3+
14from odoo import fields
25from odoo .exceptions import AccessError
3- from odoo .models import Command
6+ from odoo .fields import Command
7+ from odoo .tests import tagged
48
59from odoo .addons .operating_unit .tests .common import OperatingUnitCommon
610
711
12+ @tagged ("post_install" , "-at_install" )
813class TestPOSOperatingUnit (OperatingUnitCommon ):
14+ """Test Point of Sale Operating Unit access controls and functionality."""
15+
916 @classmethod
1017 def setUpClass (cls ):
1118 super ().setUpClass ()
19+
20+ # Setup models
1221 cls .PosOrder = cls .env ["pos.order" ]
13- cls .pos_product = cls .env .ref ("point_of_sale.whiteboard_pen" )
14- cls .pricelist = cls .env ["product.pricelist" ].search ([], limit = 1 )
22+ cls .PosConfig = cls .env ["pos.config" ]
23+ cls .PosSession = cls .env ["pos.session" ]
24+
25+ # Setup product for testing
26+ cls .pos_product = cls .env ["product.product" ].create (
27+ {
28+ "name" : "Test POS Product" ,
29+ "available_in_pos" : True ,
30+ "list_price" : 1000.0 ,
31+ }
32+ )
1533
16- # Create a new pos config and open it
17- cls .pos_config = cls .env .ref ("point_of_sale.pos_config_main" ).copy ()
34+ # Setup pricelist
35+ cls .pricelist = cls .env ["product.pricelist" ].create (
36+ {
37+ "name" : "Test POS Pricelist" ,
38+ "currency_id" : cls .env .company .currency_id .id ,
39+ }
40+ )
41+
42+ # Setup groups
1843 cls .group_pos_manager = cls .env .ref ("point_of_sale.group_pos_manager" )
1944 cls .group_account_invoice = cls .env .ref ("account.group_account_invoice" )
2045
21- cls .pos_config .operating_unit_ids = [Command .set ([cls .ou1 .id ])]
46+ # Create POS config with operating unit
47+ cls .pos_config = cls .env ["pos.config" ].create (
48+ {
49+ "name" : "Test POS Config" ,
50+ "operating_unit_ids" : [Command .set ([cls .ou1 .id ])],
51+ "available_pricelist_ids" : [Command .set ([cls .pricelist .id ])],
52+ "pricelist_id" : cls .pricelist .id ,
53+ }
54+ )
55+
56+ # Open session
2257 cls .pos_config .open_ui ()
2358
59+ # Configure users with proper groups and operating units
2460 cls .user1 .write (
2561 {
2662 "groups_id" : [
2763 Command .link (cls .group_pos_manager .id ),
2864 Command .link (cls .group_account_invoice .id ),
2965 ],
30- "operating_unit_ids" : [Command .link (cls .b2b .id )],
66+ "operating_unit_ids" : [Command .link (cls .ou1 .id )],
3167 }
3268 )
3369 cls .user2 .write (
@@ -41,80 +77,101 @@ def setUpClass(cls):
4177 )
4278
4379 def test_operating_unit_access_config (self ):
44- config1_ids = self .env ["pos.config" ].with_user (self .user1 ).search ([])
80+ """Test that users can only access POS configs for their operating units."""
81+ # User1 has access to ou1 (same as pos_config)
82+ config1_ids = self .PosConfig .with_user (self .user1 ).search ([])
4583 self .assertIn (self .pos_config , config1_ids )
46- config2_ids = self .env ["pos.config" ].with_user (self .user2 ).search ([])
84+
85+ # User2 has access to b2b (different from pos_config)
86+ config2_ids = self .PosConfig .with_user (self .user2 ).search ([])
4787 self .assertNotIn (self .pos_config , config2_ids )
4888
4989 def test_operating_unit_access_session (self ):
90+ """Test that users can only access sessions for their operating units."""
91+ # User1 should be able to read the session
5092 self .pos_config .current_session_id .with_user (self .user1 ).read ()
93+
94+ # User2 should not have access
5195 with self .assertRaises (AccessError ):
5296 self .pos_config .current_session_id .with_user (self .user2 ).read ()
5397
5498 def test_operating_unit_access_order_and_line_and_payment (self ):
99+ """Test that users can only access orders for their operating units."""
55100 order = self ._create_order ()
101+
102+ # User1 should have access to order and related records
56103 order .with_user (self .user1 ).read ()
57104 order .lines .with_user (self .user1 ).read ()
105+ order .payment_ids .with_user (self .user1 ).read ()
106+
107+ # User2 should not have access
58108 with self .assertRaises (AccessError ):
59109 order .with_user (self .user2 ).read ()
60110 with self .assertRaises (AccessError ):
61111 order .lines .with_user (self .user2 ).read ()
62- order .payment_ids .with_user (self .user1 ).read ()
63112 with self .assertRaises (AccessError ):
64113 order .payment_ids .with_user (self .user2 ).read ()
65114
66115 def _create_order (self ):
67- # Create order
68- account_id = self . env . user . partner_id . property_account_receivable_id . id
116+ """ Create a test POS order using the modern Odoo 18 approach."""
117+ # Create order using sync_from_ui method
69118 order_data = {
70119 "id" : "0006-001-0010" ,
71120 "to_invoice" : False ,
72- "data" : {
73- "date_order" : fields .Datetime .to_string (fields .Datetime .now ()),
74- "pricelist_id" : self .pricelist .id ,
75- "user_id" : 1 ,
76- "name" : "Order 0006-001-0010" ,
77- "partner_id" : False ,
78- "amount_paid" : 1000 ,
79- "pos_session_id" : self .pos_config .current_session_id .id ,
80- "lines" : [
81- [
82- 0 ,
83- 0 ,
84- {
85- "product_id" : self .pos_product .id ,
86- "qty" : 1 ,
87- "price_unit" : 1000 ,
88- "price_subtotal" : 1000 ,
89- "price_subtotal_incl" : 1000 ,
90- },
91- ]
92- ],
93- "statement_ids" : [
94- [
95- 0 ,
96- 0 ,
97- {
98- "payment_method_id" : self .pos_config .payment_method_ids [
99- 0
100- ].id ,
101- "amount" : 1000 ,
102- "name" : fields .Datetime .now (),
103- "account_id" : account_id ,
104- "session_id" : self .pos_config .current_session_id .id ,
105- },
106- ]
107- ],
108- "creation_date" : "2022-11-27 15:51:03" ,
109- "amount_tax" : 0 ,
110- "fiscal_position_id" : False ,
111- "uid" : "00001-001-0001" ,
112- "amount_return" : 0 ,
113- "sequence_number" : 1 ,
114- "amount_total" : 1000.0 ,
115- "session_id" : self .pos_config .current_session_id .id ,
116- },
121+ "session_id" : self .pos_config .current_session_id .id ,
122+ "date_order" : fields .Datetime .to_string (fields .Datetime .now ()),
123+ "pricelist_id" : self .pricelist .id ,
124+ "user_id" : self .env .user .id ,
125+ "name" : "Order 0006-001-0010" ,
126+ "partner_id" : False ,
127+ "amount_paid" : 1000.0 ,
128+ "amount_total" : 1000.0 ,
129+ "amount_tax" : 0.0 ,
130+ "amount_return" : 0.0 ,
131+ "fiscal_position_id" : False ,
132+ "sequence_number" : 1 ,
133+ "uuid" : "00001-001-0001" ,
134+ "lines" : [
135+ [
136+ 0 ,
137+ 0 ,
138+ {
139+ "product_id" : self .pos_product .id ,
140+ "qty" : 1.0 ,
141+ "price_unit" : 1000.0 ,
142+ "price_subtotal" : 1000.0 ,
143+ "price_subtotal_incl" : 1000.0 ,
144+ "discount" : 0.0 ,
145+ },
146+ ]
147+ ],
148+ "payment_ids" : [
149+ [
150+ 0 ,
151+ 0 ,
152+ {
153+ "payment_method_id" : self .pos_config .payment_method_ids [0 ].id ,
154+ "amount" : 1000.0 ,
155+ },
156+ ]
157+ ],
117158 }
118- result = self .PosOrder .create_from_ui ([order_data ])
119- order = self .PosOrder .browse (result [0 ].get ("id" ))
120- return order
159+
160+ # Create the order
161+ result = self .PosOrder .sync_from_ui ([order_data ])
162+ if not result or "pos.order" not in result :
163+ raise ValueError ("Failed to create POS order" )
164+
165+ # Get order data from result
166+ pos_orders = result ["pos.order" ]
167+ if not pos_orders :
168+ raise ValueError ("No order data in result" )
169+
170+ # Extract order ID from the first order data
171+ order_data_dict = pos_orders [0 ] if pos_orders else {}
172+ order_id = order_data_dict .get ("id" )
173+
174+ if not order_id :
175+ raise ValueError ("Failed to get order ID from result" )
176+
177+ return self .PosOrder .browse (order_id )
0 commit comments