karrio-server-graph 2025.5.5__py3-none-any.whl → 2025.5.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- karrio/server/graph/schemas/base/__init__.py +82 -18
- karrio/server/graph/schemas/base/inputs.py +199 -70
- karrio/server/graph/schemas/base/mutations.py +313 -122
- karrio/server/graph/schemas/base/types.py +139 -22
- karrio/server/graph/serializers.py +115 -41
- karrio/server/graph/tests/test_rate_sheets.py +1950 -176
- {karrio_server_graph-2025.5.5.dist-info → karrio_server_graph-2025.5.7.dist-info}/METADATA +1 -1
- {karrio_server_graph-2025.5.5.dist-info → karrio_server_graph-2025.5.7.dist-info}/RECORD +10 -10
- {karrio_server_graph-2025.5.5.dist-info → karrio_server_graph-2025.5.7.dist-info}/WHEEL +0 -0
- {karrio_server_graph-2025.5.5.dist-info → karrio_server_graph-2025.5.7.dist-info}/top_level.txt +0 -0
|
@@ -5,194 +5,1899 @@ import karrio.server.providers.models as providers
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class TestRateSheets(GraphTestCase):
|
|
8
|
+
"""Tests for Rate Sheet CRUD operations."""
|
|
9
|
+
|
|
10
|
+
def setUp(self):
|
|
11
|
+
super().setUp()
|
|
12
|
+
|
|
13
|
+
# Create a test rate sheet with shared zones and surcharges
|
|
14
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
15
|
+
name="Test Rate Sheet",
|
|
16
|
+
carrier_name="ups",
|
|
17
|
+
slug="test_rate_sheet",
|
|
18
|
+
zones=[
|
|
19
|
+
{
|
|
20
|
+
"id": "zone_1",
|
|
21
|
+
"label": "Zone 1",
|
|
22
|
+
"cities": ["New York", "Los Angeles"],
|
|
23
|
+
"country_codes": ["US"],
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
surcharges=[
|
|
27
|
+
{
|
|
28
|
+
"id": "surch_fuel",
|
|
29
|
+
"name": "Fuel Surcharge",
|
|
30
|
+
"amount": 10.0,
|
|
31
|
+
"surcharge_type": "percentage",
|
|
32
|
+
"active": True,
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
service_rates=[
|
|
36
|
+
{
|
|
37
|
+
"service_id": None, # Will be set after service creation
|
|
38
|
+
"zone_id": "zone_1",
|
|
39
|
+
"rate": 10.00,
|
|
40
|
+
"cost": 8.00,
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
created_by=self.user,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Create a test service
|
|
47
|
+
self.service = providers.ServiceLevel.objects.create(
|
|
48
|
+
service_name="UPS Standard",
|
|
49
|
+
service_code="ups_standard",
|
|
50
|
+
carrier_service_code="11",
|
|
51
|
+
currency="USD",
|
|
52
|
+
active=True,
|
|
53
|
+
zone_ids=["zone_1"],
|
|
54
|
+
surcharge_ids=["surch_fuel"],
|
|
55
|
+
created_by=self.user,
|
|
56
|
+
)
|
|
57
|
+
self.rate_sheet.services.add(self.service)
|
|
58
|
+
|
|
59
|
+
# Update service_rates with actual service ID
|
|
60
|
+
self.rate_sheet.service_rates = [
|
|
61
|
+
{
|
|
62
|
+
"service_id": self.service.id,
|
|
63
|
+
"zone_id": "zone_1",
|
|
64
|
+
"rate": 10.00,
|
|
65
|
+
"cost": 8.00,
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
self.rate_sheet.save()
|
|
69
|
+
|
|
70
|
+
# =========================================================================
|
|
71
|
+
# RATE SHEET QUERY TESTS
|
|
72
|
+
# =========================================================================
|
|
73
|
+
|
|
74
|
+
def test_query_rate_sheets(self):
|
|
75
|
+
"""Test querying all rate sheets with zones, surcharges, and service_rates."""
|
|
76
|
+
response = self.query(
|
|
77
|
+
"""
|
|
78
|
+
query get_rate_sheets {
|
|
79
|
+
rate_sheets {
|
|
80
|
+
edges {
|
|
81
|
+
node {
|
|
82
|
+
id
|
|
83
|
+
name
|
|
84
|
+
carrier_name
|
|
85
|
+
slug
|
|
86
|
+
zones {
|
|
87
|
+
id
|
|
88
|
+
label
|
|
89
|
+
cities
|
|
90
|
+
country_codes
|
|
91
|
+
}
|
|
92
|
+
surcharges {
|
|
93
|
+
id
|
|
94
|
+
name
|
|
95
|
+
amount
|
|
96
|
+
surcharge_type
|
|
97
|
+
active
|
|
98
|
+
}
|
|
99
|
+
service_rates {
|
|
100
|
+
service_id
|
|
101
|
+
zone_id
|
|
102
|
+
rate
|
|
103
|
+
cost
|
|
104
|
+
}
|
|
105
|
+
services {
|
|
106
|
+
id
|
|
107
|
+
service_name
|
|
108
|
+
service_code
|
|
109
|
+
carrier_service_code
|
|
110
|
+
active
|
|
111
|
+
currency
|
|
112
|
+
zone_ids
|
|
113
|
+
surcharge_ids
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
""",
|
|
120
|
+
operation_name="get_rate_sheets",
|
|
121
|
+
)
|
|
122
|
+
response_data = response.data
|
|
123
|
+
|
|
124
|
+
self.assertResponseNoErrors(response)
|
|
125
|
+
self.assertDictEqual(
|
|
126
|
+
lib.to_dict(response_data),
|
|
127
|
+
RATE_SHEETS_RESPONSE,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def test_query_single_rate_sheet(self):
|
|
131
|
+
"""Test querying a single rate sheet by ID."""
|
|
132
|
+
response = self.query(
|
|
133
|
+
"""
|
|
134
|
+
query get_rate_sheet($id: String!) {
|
|
135
|
+
rate_sheet(id: $id) {
|
|
136
|
+
id
|
|
137
|
+
name
|
|
138
|
+
carrier_name
|
|
139
|
+
zones {
|
|
140
|
+
id
|
|
141
|
+
label
|
|
142
|
+
}
|
|
143
|
+
surcharges {
|
|
144
|
+
id
|
|
145
|
+
name
|
|
146
|
+
}
|
|
147
|
+
services {
|
|
148
|
+
id
|
|
149
|
+
service_name
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
""",
|
|
154
|
+
operation_name="get_rate_sheet",
|
|
155
|
+
variables={"id": self.rate_sheet.id},
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
self.assertResponseNoErrors(response)
|
|
159
|
+
self.assertEqual(response.data["data"]["rate_sheet"]["name"], "Test Rate Sheet")
|
|
160
|
+
self.assertEqual(response.data["data"]["rate_sheet"]["carrier_name"], "ups")
|
|
161
|
+
|
|
162
|
+
def test_query_rate_sheet_not_found(self):
|
|
163
|
+
"""Test querying a rate sheet that doesn't exist."""
|
|
164
|
+
response = self.query(
|
|
165
|
+
"""
|
|
166
|
+
query get_rate_sheet($id: String!) {
|
|
167
|
+
rate_sheet(id: $id) {
|
|
168
|
+
id
|
|
169
|
+
name
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
""",
|
|
173
|
+
operation_name="get_rate_sheet",
|
|
174
|
+
variables={"id": "rsht_nonexistent"},
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
self.assertResponseNoErrors(response)
|
|
178
|
+
self.assertIsNone(response.data["data"]["rate_sheet"])
|
|
179
|
+
|
|
180
|
+
# =========================================================================
|
|
181
|
+
# RATE SHEET CREATE TESTS
|
|
182
|
+
# =========================================================================
|
|
183
|
+
|
|
184
|
+
def test_create_rate_sheet(self):
|
|
185
|
+
"""Test creating a new rate sheet with services."""
|
|
186
|
+
response = self.query(
|
|
187
|
+
"""
|
|
188
|
+
mutation create_rate_sheet($data: CreateRateSheetMutationInput!) {
|
|
189
|
+
create_rate_sheet(input: $data) {
|
|
190
|
+
rate_sheet {
|
|
191
|
+
id
|
|
192
|
+
name
|
|
193
|
+
carrier_name
|
|
194
|
+
zones {
|
|
195
|
+
id
|
|
196
|
+
label
|
|
197
|
+
postal_codes
|
|
198
|
+
}
|
|
199
|
+
surcharges {
|
|
200
|
+
id
|
|
201
|
+
name
|
|
202
|
+
amount
|
|
203
|
+
surcharge_type
|
|
204
|
+
}
|
|
205
|
+
services {
|
|
206
|
+
id
|
|
207
|
+
service_name
|
|
208
|
+
service_code
|
|
209
|
+
currency
|
|
210
|
+
zone_ids
|
|
211
|
+
surcharge_ids
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
""",
|
|
217
|
+
operation_name="create_rate_sheet",
|
|
218
|
+
variables=CREATE_RATE_SHEET_DATA,
|
|
219
|
+
)
|
|
220
|
+
response_data = response.data
|
|
221
|
+
|
|
222
|
+
self.assertResponseNoErrors(response)
|
|
223
|
+
self.assertDictEqual(response_data, CREATE_RATE_SHEET_RESPONSE)
|
|
224
|
+
|
|
225
|
+
def test_create_rate_sheet_minimal(self):
|
|
226
|
+
"""Test creating a rate sheet with only required fields."""
|
|
227
|
+
response = self.query(
|
|
228
|
+
"""
|
|
229
|
+
mutation create_rate_sheet($data: CreateRateSheetMutationInput!) {
|
|
230
|
+
create_rate_sheet(input: $data) {
|
|
231
|
+
rate_sheet {
|
|
232
|
+
id
|
|
233
|
+
name
|
|
234
|
+
carrier_name
|
|
235
|
+
zones {
|
|
236
|
+
id
|
|
237
|
+
}
|
|
238
|
+
surcharges {
|
|
239
|
+
id
|
|
240
|
+
}
|
|
241
|
+
services {
|
|
242
|
+
id
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
errors {
|
|
246
|
+
field
|
|
247
|
+
messages
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
""",
|
|
252
|
+
operation_name="create_rate_sheet",
|
|
253
|
+
variables={
|
|
254
|
+
"data": {
|
|
255
|
+
"name": "Minimal Rate Sheet",
|
|
256
|
+
"carrier_name": "generic",
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
self.assertResponseNoErrors(response)
|
|
262
|
+
rate_sheet = response.data["data"]["create_rate_sheet"]["rate_sheet"]
|
|
263
|
+
self.assertEqual(rate_sheet["name"], "Minimal Rate Sheet")
|
|
264
|
+
self.assertEqual(rate_sheet["zones"], [])
|
|
265
|
+
self.assertEqual(rate_sheet["surcharges"], [])
|
|
266
|
+
self.assertEqual(rate_sheet["services"], [])
|
|
267
|
+
|
|
268
|
+
# =========================================================================
|
|
269
|
+
# RATE SHEET UPDATE TESTS
|
|
270
|
+
# =========================================================================
|
|
271
|
+
|
|
272
|
+
def test_update_rate_sheet(self):
|
|
273
|
+
"""Test updating a rate sheet's basic fields."""
|
|
274
|
+
response = self.query(
|
|
275
|
+
"""
|
|
276
|
+
mutation update_rate_sheet($data: UpdateRateSheetMutationInput!) {
|
|
277
|
+
update_rate_sheet(input: $data) {
|
|
278
|
+
rate_sheet {
|
|
279
|
+
id
|
|
280
|
+
name
|
|
281
|
+
services {
|
|
282
|
+
id
|
|
283
|
+
service_name
|
|
284
|
+
zone_ids
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
""",
|
|
290
|
+
operation_name="update_rate_sheet",
|
|
291
|
+
variables={
|
|
292
|
+
"data": {
|
|
293
|
+
"id": self.rate_sheet.id,
|
|
294
|
+
"name": "Updated Rate Sheet",
|
|
295
|
+
"services": [
|
|
296
|
+
{
|
|
297
|
+
"id": self.service.id,
|
|
298
|
+
"service_name": "Updated Service",
|
|
299
|
+
"zone_ids": ["zone_1"],
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
)
|
|
305
|
+
response_data = response.data
|
|
306
|
+
|
|
307
|
+
self.assertResponseNoErrors(response)
|
|
308
|
+
self.assertDictEqual(
|
|
309
|
+
lib.to_dict(response_data),
|
|
310
|
+
UPDATE_RATE_SHEET_RESPONSE,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def test_update_rate_sheet_name_only(self):
|
|
314
|
+
"""Test updating only the rate sheet name."""
|
|
315
|
+
response = self.query(
|
|
316
|
+
"""
|
|
317
|
+
mutation update_rate_sheet($data: UpdateRateSheetMutationInput!) {
|
|
318
|
+
update_rate_sheet(input: $data) {
|
|
319
|
+
rate_sheet {
|
|
320
|
+
id
|
|
321
|
+
name
|
|
322
|
+
}
|
|
323
|
+
errors {
|
|
324
|
+
field
|
|
325
|
+
messages
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
""",
|
|
330
|
+
operation_name="update_rate_sheet",
|
|
331
|
+
variables={
|
|
332
|
+
"data": {
|
|
333
|
+
"id": self.rate_sheet.id,
|
|
334
|
+
"name": "New Name Only",
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
self.assertResponseNoErrors(response)
|
|
340
|
+
self.assertEqual(
|
|
341
|
+
response.data["data"]["update_rate_sheet"]["rate_sheet"]["name"],
|
|
342
|
+
"New Name Only"
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# =========================================================================
|
|
346
|
+
# RATE SHEET DELETE TESTS
|
|
347
|
+
# =========================================================================
|
|
348
|
+
|
|
349
|
+
def test_delete_rate_sheet(self):
|
|
350
|
+
"""Test deleting a rate sheet."""
|
|
351
|
+
# First create a rate sheet to delete
|
|
352
|
+
new_sheet = providers.RateSheet.objects.create(
|
|
353
|
+
name="To Be Deleted",
|
|
354
|
+
carrier_name="ups",
|
|
355
|
+
slug="to_be_deleted",
|
|
356
|
+
created_by=self.user,
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
response = self.query(
|
|
360
|
+
"""
|
|
361
|
+
mutation delete_rate_sheet($data: DeleteMutationInput!) {
|
|
362
|
+
delete_rate_sheet(input: $data) {
|
|
363
|
+
id
|
|
364
|
+
errors {
|
|
365
|
+
field
|
|
366
|
+
messages
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
""",
|
|
371
|
+
operation_name="delete_rate_sheet",
|
|
372
|
+
variables={
|
|
373
|
+
"data": {
|
|
374
|
+
"id": new_sheet.id,
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
self.assertResponseNoErrors(response)
|
|
380
|
+
self.assertEqual(response.data["data"]["delete_rate_sheet"]["id"], new_sheet.id)
|
|
381
|
+
|
|
382
|
+
# Verify it's deleted
|
|
383
|
+
self.assertFalse(providers.RateSheet.objects.filter(id=new_sheet.id).exists())
|
|
384
|
+
|
|
385
|
+
def test_delete_rate_sheet_cascades_services(self):
|
|
386
|
+
"""Test that deleting a rate sheet also deletes its services."""
|
|
387
|
+
# Create a rate sheet with a service
|
|
388
|
+
sheet = providers.RateSheet.objects.create(
|
|
389
|
+
name="Sheet With Service",
|
|
390
|
+
carrier_name="ups",
|
|
391
|
+
slug="sheet_with_service",
|
|
392
|
+
created_by=self.user,
|
|
393
|
+
)
|
|
394
|
+
service = providers.ServiceLevel.objects.create(
|
|
395
|
+
service_name="Test Service",
|
|
396
|
+
service_code="test_service",
|
|
397
|
+
carrier_service_code="TEST",
|
|
398
|
+
currency="USD",
|
|
399
|
+
created_by=self.user,
|
|
400
|
+
)
|
|
401
|
+
sheet.services.add(service)
|
|
402
|
+
service_id = service.id
|
|
403
|
+
|
|
404
|
+
response = self.query(
|
|
405
|
+
"""
|
|
406
|
+
mutation delete_rate_sheet($data: DeleteMutationInput!) {
|
|
407
|
+
delete_rate_sheet(input: $data) {
|
|
408
|
+
id
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
""",
|
|
412
|
+
operation_name="delete_rate_sheet",
|
|
413
|
+
variables={"data": {"id": sheet.id}},
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
self.assertResponseNoErrors(response)
|
|
417
|
+
# Verify service is also deleted
|
|
418
|
+
self.assertFalse(providers.ServiceLevel.objects.filter(id=service_id).exists())
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
class TestRateSheetZones(GraphTestCase):
|
|
422
|
+
"""Tests for shared zone CRUD operations."""
|
|
423
|
+
|
|
424
|
+
def setUp(self):
|
|
425
|
+
super().setUp()
|
|
426
|
+
|
|
427
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
428
|
+
name="Zone Test Sheet",
|
|
429
|
+
carrier_name="ups",
|
|
430
|
+
slug="zone_test_sheet",
|
|
431
|
+
zones=[
|
|
432
|
+
{
|
|
433
|
+
"id": "zone_1",
|
|
434
|
+
"label": "Zone 1",
|
|
435
|
+
"cities": ["New York", "Los Angeles"],
|
|
436
|
+
"country_codes": ["US"],
|
|
437
|
+
"postal_codes": ["10001", "90001"],
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
created_by=self.user,
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
self.service = providers.ServiceLevel.objects.create(
|
|
444
|
+
service_name="Test Service",
|
|
445
|
+
service_code="test_service",
|
|
446
|
+
carrier_service_code="TEST",
|
|
447
|
+
currency="USD",
|
|
448
|
+
zone_ids=["zone_1"],
|
|
449
|
+
created_by=self.user,
|
|
450
|
+
)
|
|
451
|
+
self.rate_sheet.services.add(self.service)
|
|
452
|
+
|
|
453
|
+
# =========================================================================
|
|
454
|
+
# ADD ZONE TESTS
|
|
455
|
+
# =========================================================================
|
|
456
|
+
|
|
457
|
+
def test_add_shared_zone(self):
|
|
458
|
+
"""Test adding a new shared zone."""
|
|
459
|
+
response = self.query(
|
|
460
|
+
"""
|
|
461
|
+
mutation add_zone($data: AddSharedZoneMutationInput!) {
|
|
462
|
+
add_shared_zone(input: $data) {
|
|
463
|
+
rate_sheet {
|
|
464
|
+
id
|
|
465
|
+
zones {
|
|
466
|
+
id
|
|
467
|
+
label
|
|
468
|
+
country_codes
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
errors {
|
|
472
|
+
field
|
|
473
|
+
messages
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
""",
|
|
478
|
+
operation_name="add_zone",
|
|
479
|
+
variables={
|
|
480
|
+
"data": {
|
|
481
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
482
|
+
"zone": {
|
|
483
|
+
"label": "Zone 2",
|
|
484
|
+
"country_codes": ["CA", "MX"],
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
self.assertResponseNoErrors(response)
|
|
491
|
+
zones = response.data["data"]["add_shared_zone"]["rate_sheet"]["zones"]
|
|
492
|
+
self.assertEqual(len(zones), 2)
|
|
493
|
+
self.assertEqual(zones[1]["label"], "Zone 2")
|
|
494
|
+
self.assertEqual(zones[1]["country_codes"], ["CA", "MX"])
|
|
495
|
+
|
|
496
|
+
def test_add_shared_zone_with_all_fields(self):
|
|
497
|
+
"""Test adding a zone with all optional fields."""
|
|
498
|
+
response = self.query(
|
|
499
|
+
"""
|
|
500
|
+
mutation add_zone($data: AddSharedZoneMutationInput!) {
|
|
501
|
+
add_shared_zone(input: $data) {
|
|
502
|
+
rate_sheet {
|
|
503
|
+
id
|
|
504
|
+
zones {
|
|
505
|
+
id
|
|
506
|
+
label
|
|
507
|
+
country_codes
|
|
508
|
+
cities
|
|
509
|
+
postal_codes
|
|
510
|
+
transit_days
|
|
511
|
+
transit_time
|
|
512
|
+
radius
|
|
513
|
+
latitude
|
|
514
|
+
longitude
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
""",
|
|
520
|
+
operation_name="add_zone",
|
|
521
|
+
variables={
|
|
522
|
+
"data": {
|
|
523
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
524
|
+
"zone": {
|
|
525
|
+
"label": "Full Zone",
|
|
526
|
+
"country_codes": ["US"],
|
|
527
|
+
"cities": ["Seattle", "Portland"],
|
|
528
|
+
"postal_codes": ["98101", "97201"],
|
|
529
|
+
"transit_days": 3,
|
|
530
|
+
"transit_time": 72,
|
|
531
|
+
"radius": 100.0,
|
|
532
|
+
"latitude": 47.6062,
|
|
533
|
+
"longitude": -122.3321,
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
},
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
self.assertResponseNoErrors(response)
|
|
540
|
+
zones = response.data["data"]["add_shared_zone"]["rate_sheet"]["zones"]
|
|
541
|
+
new_zone = zones[-1]
|
|
542
|
+
self.assertEqual(new_zone["label"], "Full Zone")
|
|
543
|
+
self.assertEqual(new_zone["cities"], ["Seattle", "Portland"])
|
|
544
|
+
self.assertEqual(new_zone["transit_days"], 3)
|
|
545
|
+
self.assertEqual(new_zone["radius"], 100.0)
|
|
546
|
+
|
|
547
|
+
def test_add_multiple_zones_sequentially(self):
|
|
548
|
+
"""Test adding multiple zones one after another."""
|
|
549
|
+
for i in range(2, 5):
|
|
550
|
+
response = self.query(
|
|
551
|
+
"""
|
|
552
|
+
mutation add_zone($data: AddSharedZoneMutationInput!) {
|
|
553
|
+
add_shared_zone(input: $data) {
|
|
554
|
+
rate_sheet {
|
|
555
|
+
zones {
|
|
556
|
+
id
|
|
557
|
+
label
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
""",
|
|
563
|
+
operation_name="add_zone",
|
|
564
|
+
variables={
|
|
565
|
+
"data": {
|
|
566
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
567
|
+
"zone": {
|
|
568
|
+
"label": f"Zone {i}",
|
|
569
|
+
"country_codes": ["US"],
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
)
|
|
574
|
+
self.assertResponseNoErrors(response)
|
|
575
|
+
|
|
576
|
+
# Verify all zones exist
|
|
577
|
+
self.rate_sheet.refresh_from_db()
|
|
578
|
+
self.assertEqual(len(self.rate_sheet.zones), 4)
|
|
579
|
+
|
|
580
|
+
# =========================================================================
|
|
581
|
+
# UPDATE ZONE TESTS
|
|
582
|
+
# =========================================================================
|
|
583
|
+
|
|
584
|
+
def test_update_shared_zone(self):
|
|
585
|
+
"""Test updating an existing shared zone."""
|
|
586
|
+
response = self.query(
|
|
587
|
+
"""
|
|
588
|
+
mutation update_zone($data: UpdateSharedZoneMutationInput!) {
|
|
589
|
+
update_shared_zone(input: $data) {
|
|
590
|
+
rate_sheet {
|
|
591
|
+
id
|
|
592
|
+
zones {
|
|
593
|
+
id
|
|
594
|
+
label
|
|
595
|
+
country_codes
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
""",
|
|
601
|
+
operation_name="update_zone",
|
|
602
|
+
variables={
|
|
603
|
+
"data": {
|
|
604
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
605
|
+
"zone_id": "zone_1",
|
|
606
|
+
"zone": {
|
|
607
|
+
"label": "Updated Zone 1",
|
|
608
|
+
"country_codes": ["US", "CA"],
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
},
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
self.assertResponseNoErrors(response)
|
|
615
|
+
zones = response.data["data"]["update_shared_zone"]["rate_sheet"]["zones"]
|
|
616
|
+
self.assertEqual(zones[0]["label"], "Updated Zone 1")
|
|
617
|
+
self.assertEqual(zones[0]["country_codes"], ["US", "CA"])
|
|
618
|
+
|
|
619
|
+
def test_update_zone_partial_fields(self):
|
|
620
|
+
"""Test updating only specific fields of a zone."""
|
|
621
|
+
response = self.query(
|
|
622
|
+
"""
|
|
623
|
+
mutation update_zone($data: UpdateSharedZoneMutationInput!) {
|
|
624
|
+
update_shared_zone(input: $data) {
|
|
625
|
+
rate_sheet {
|
|
626
|
+
zones {
|
|
627
|
+
id
|
|
628
|
+
label
|
|
629
|
+
cities
|
|
630
|
+
country_codes
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
""",
|
|
636
|
+
operation_name="update_zone",
|
|
637
|
+
variables={
|
|
638
|
+
"data": {
|
|
639
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
640
|
+
"zone_id": "zone_1",
|
|
641
|
+
"zone": {
|
|
642
|
+
"label": "New Label Only",
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
self.assertResponseNoErrors(response)
|
|
649
|
+
zone = response.data["data"]["update_shared_zone"]["rate_sheet"]["zones"][0]
|
|
650
|
+
self.assertEqual(zone["label"], "New Label Only")
|
|
651
|
+
# Other fields might be reset based on implementation
|
|
652
|
+
|
|
653
|
+
def test_update_nonexistent_zone(self):
|
|
654
|
+
"""Test updating a zone that doesn't exist."""
|
|
655
|
+
response = self.query(
|
|
656
|
+
"""
|
|
657
|
+
mutation update_zone($data: UpdateSharedZoneMutationInput!) {
|
|
658
|
+
update_shared_zone(input: $data) {
|
|
659
|
+
rate_sheet {
|
|
660
|
+
id
|
|
661
|
+
}
|
|
662
|
+
errors {
|
|
663
|
+
field
|
|
664
|
+
messages
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
""",
|
|
669
|
+
operation_name="update_zone",
|
|
670
|
+
variables={
|
|
671
|
+
"data": {
|
|
672
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
673
|
+
"zone_id": "nonexistent_zone",
|
|
674
|
+
"zone": {
|
|
675
|
+
"label": "Will Fail",
|
|
676
|
+
},
|
|
677
|
+
},
|
|
678
|
+
},
|
|
679
|
+
)
|
|
680
|
+
|
|
681
|
+
# Should have an error
|
|
682
|
+
self.assertIsNotNone(response.data.get("errors") or response.data["data"]["update_shared_zone"].get("errors"))
|
|
683
|
+
|
|
684
|
+
# =========================================================================
|
|
685
|
+
# DELETE ZONE TESTS
|
|
686
|
+
# =========================================================================
|
|
687
|
+
|
|
688
|
+
def test_delete_shared_zone(self):
|
|
689
|
+
"""Test deleting a shared zone."""
|
|
690
|
+
# First add a second zone
|
|
691
|
+
self.rate_sheet.zones.append({
|
|
692
|
+
"id": "zone_2",
|
|
693
|
+
"label": "Zone 2",
|
|
694
|
+
"country_codes": ["CA"],
|
|
695
|
+
})
|
|
696
|
+
self.rate_sheet.save()
|
|
697
|
+
|
|
698
|
+
response = self.query(
|
|
699
|
+
"""
|
|
700
|
+
mutation delete_zone($data: DeleteSharedZoneMutationInput!) {
|
|
701
|
+
delete_shared_zone(input: $data) {
|
|
702
|
+
rate_sheet {
|
|
703
|
+
id
|
|
704
|
+
zones {
|
|
705
|
+
id
|
|
706
|
+
label
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
errors {
|
|
710
|
+
field
|
|
711
|
+
messages
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
""",
|
|
716
|
+
operation_name="delete_zone",
|
|
717
|
+
variables={
|
|
718
|
+
"data": {
|
|
719
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
720
|
+
"zone_id": "zone_2",
|
|
721
|
+
},
|
|
722
|
+
},
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
self.assertResponseNoErrors(response)
|
|
726
|
+
zones = response.data["data"]["delete_shared_zone"]["rate_sheet"]["zones"]
|
|
727
|
+
self.assertEqual(len(zones), 1)
|
|
728
|
+
self.assertEqual(zones[0]["id"], "zone_1")
|
|
729
|
+
|
|
730
|
+
def test_delete_zone_removes_from_service_zone_ids(self):
|
|
731
|
+
"""Test that deleting a zone removes it from services' zone_ids."""
|
|
732
|
+
# Add zone to service
|
|
733
|
+
self.service.zone_ids = ["zone_1"]
|
|
734
|
+
self.service.save()
|
|
735
|
+
|
|
736
|
+
response = self.query(
|
|
737
|
+
"""
|
|
738
|
+
mutation delete_zone($data: DeleteSharedZoneMutationInput!) {
|
|
739
|
+
delete_shared_zone(input: $data) {
|
|
740
|
+
rate_sheet {
|
|
741
|
+
zones {
|
|
742
|
+
id
|
|
743
|
+
}
|
|
744
|
+
services {
|
|
745
|
+
id
|
|
746
|
+
zone_ids
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
""",
|
|
752
|
+
operation_name="delete_zone",
|
|
753
|
+
variables={
|
|
754
|
+
"data": {
|
|
755
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
756
|
+
"zone_id": "zone_1",
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
self.assertResponseNoErrors(response)
|
|
762
|
+
services = response.data["data"]["delete_shared_zone"]["rate_sheet"]["services"]
|
|
763
|
+
self.assertEqual(services[0]["zone_ids"], [])
|
|
764
|
+
|
|
765
|
+
def test_delete_zone_removes_service_rates(self):
|
|
766
|
+
"""Test that deleting a zone removes associated service_rates."""
|
|
767
|
+
# Add service rate for the zone
|
|
768
|
+
self.rate_sheet.service_rates = [
|
|
769
|
+
{"service_id": self.service.id, "zone_id": "zone_1", "rate": 10.0}
|
|
770
|
+
]
|
|
771
|
+
self.rate_sheet.save()
|
|
772
|
+
|
|
773
|
+
response = self.query(
|
|
774
|
+
"""
|
|
775
|
+
mutation delete_zone($data: DeleteSharedZoneMutationInput!) {
|
|
776
|
+
delete_shared_zone(input: $data) {
|
|
777
|
+
rate_sheet {
|
|
778
|
+
zones {
|
|
779
|
+
id
|
|
780
|
+
}
|
|
781
|
+
service_rates {
|
|
782
|
+
zone_id
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
""",
|
|
788
|
+
operation_name="delete_zone",
|
|
789
|
+
variables={
|
|
790
|
+
"data": {
|
|
791
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
792
|
+
"zone_id": "zone_1",
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
)
|
|
796
|
+
|
|
797
|
+
self.assertResponseNoErrors(response)
|
|
798
|
+
service_rates = response.data["data"]["delete_shared_zone"]["rate_sheet"]["service_rates"]
|
|
799
|
+
self.assertEqual(service_rates, [])
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
class TestRateSheetSurcharges(GraphTestCase):
|
|
803
|
+
"""Tests for shared surcharge CRUD operations."""
|
|
804
|
+
|
|
805
|
+
def setUp(self):
|
|
806
|
+
super().setUp()
|
|
807
|
+
|
|
808
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
809
|
+
name="Surcharge Test Sheet",
|
|
810
|
+
carrier_name="ups",
|
|
811
|
+
slug="surcharge_test_sheet",
|
|
812
|
+
surcharges=[
|
|
813
|
+
{
|
|
814
|
+
"id": "surch_fuel",
|
|
815
|
+
"name": "Fuel Surcharge",
|
|
816
|
+
"amount": 10.0,
|
|
817
|
+
"surcharge_type": "percentage",
|
|
818
|
+
"active": True,
|
|
819
|
+
"cost": 8.0,
|
|
820
|
+
}
|
|
821
|
+
],
|
|
822
|
+
created_by=self.user,
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
self.service = providers.ServiceLevel.objects.create(
|
|
826
|
+
service_name="Test Service",
|
|
827
|
+
service_code="test_service",
|
|
828
|
+
carrier_service_code="TEST",
|
|
829
|
+
currency="USD",
|
|
830
|
+
surcharge_ids=["surch_fuel"],
|
|
831
|
+
created_by=self.user,
|
|
832
|
+
)
|
|
833
|
+
self.rate_sheet.services.add(self.service)
|
|
834
|
+
|
|
835
|
+
# =========================================================================
|
|
836
|
+
# ADD SURCHARGE TESTS
|
|
837
|
+
# =========================================================================
|
|
838
|
+
|
|
839
|
+
def test_add_shared_surcharge(self):
|
|
840
|
+
"""Test adding a new shared surcharge."""
|
|
841
|
+
response = self.query(
|
|
842
|
+
"""
|
|
843
|
+
mutation add_surcharge($data: AddSharedSurchargeMutationInput!) {
|
|
844
|
+
add_shared_surcharge(input: $data) {
|
|
845
|
+
rate_sheet {
|
|
846
|
+
id
|
|
847
|
+
surcharges {
|
|
848
|
+
id
|
|
849
|
+
name
|
|
850
|
+
amount
|
|
851
|
+
surcharge_type
|
|
852
|
+
active
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
""",
|
|
858
|
+
operation_name="add_surcharge",
|
|
859
|
+
variables={
|
|
860
|
+
"data": {
|
|
861
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
862
|
+
"surcharge": {
|
|
863
|
+
"name": "Energy Surcharge",
|
|
864
|
+
"amount": 2.50,
|
|
865
|
+
"surcharge_type": "fixed",
|
|
866
|
+
},
|
|
867
|
+
},
|
|
868
|
+
},
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
self.assertResponseNoErrors(response)
|
|
872
|
+
surcharges = response.data["data"]["add_shared_surcharge"]["rate_sheet"]["surcharges"]
|
|
873
|
+
self.assertEqual(len(surcharges), 2)
|
|
874
|
+
new_surcharge = surcharges[1]
|
|
875
|
+
self.assertEqual(new_surcharge["name"], "Energy Surcharge")
|
|
876
|
+
self.assertEqual(new_surcharge["amount"], 2.5)
|
|
877
|
+
self.assertEqual(new_surcharge["surcharge_type"], "fixed")
|
|
878
|
+
self.assertTrue(new_surcharge["active"])
|
|
879
|
+
|
|
880
|
+
def test_add_surcharge_percentage_type(self):
|
|
881
|
+
"""Test adding a percentage-based surcharge."""
|
|
882
|
+
response = self.query(
|
|
883
|
+
"""
|
|
884
|
+
mutation add_surcharge($data: AddSharedSurchargeMutationInput!) {
|
|
885
|
+
add_shared_surcharge(input: $data) {
|
|
886
|
+
rate_sheet {
|
|
887
|
+
surcharges {
|
|
888
|
+
id
|
|
889
|
+
name
|
|
890
|
+
amount
|
|
891
|
+
surcharge_type
|
|
892
|
+
cost
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
""",
|
|
898
|
+
operation_name="add_surcharge",
|
|
899
|
+
variables={
|
|
900
|
+
"data": {
|
|
901
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
902
|
+
"surcharge": {
|
|
903
|
+
"name": "Peak Season",
|
|
904
|
+
"amount": 15.0,
|
|
905
|
+
"surcharge_type": "percentage",
|
|
906
|
+
"cost": 12.0,
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
},
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
self.assertResponseNoErrors(response)
|
|
913
|
+
surcharges = response.data["data"]["add_shared_surcharge"]["rate_sheet"]["surcharges"]
|
|
914
|
+
new_surcharge = surcharges[-1]
|
|
915
|
+
self.assertEqual(new_surcharge["surcharge_type"], "percentage")
|
|
916
|
+
self.assertEqual(new_surcharge["cost"], 12.0)
|
|
917
|
+
|
|
918
|
+
def test_add_inactive_surcharge(self):
|
|
919
|
+
"""Test adding a surcharge that starts as inactive."""
|
|
920
|
+
response = self.query(
|
|
921
|
+
"""
|
|
922
|
+
mutation add_surcharge($data: AddSharedSurchargeMutationInput!) {
|
|
923
|
+
add_shared_surcharge(input: $data) {
|
|
924
|
+
rate_sheet {
|
|
925
|
+
surcharges {
|
|
926
|
+
id
|
|
927
|
+
name
|
|
928
|
+
active
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
""",
|
|
934
|
+
operation_name="add_surcharge",
|
|
935
|
+
variables={
|
|
936
|
+
"data": {
|
|
937
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
938
|
+
"surcharge": {
|
|
939
|
+
"name": "Future Surcharge",
|
|
940
|
+
"amount": 5.0,
|
|
941
|
+
"active": False,
|
|
942
|
+
},
|
|
943
|
+
},
|
|
944
|
+
},
|
|
945
|
+
)
|
|
946
|
+
|
|
947
|
+
self.assertResponseNoErrors(response)
|
|
948
|
+
surcharges = response.data["data"]["add_shared_surcharge"]["rate_sheet"]["surcharges"]
|
|
949
|
+
new_surcharge = surcharges[-1]
|
|
950
|
+
self.assertFalse(new_surcharge["active"])
|
|
951
|
+
|
|
952
|
+
# =========================================================================
|
|
953
|
+
# UPDATE SURCHARGE TESTS
|
|
954
|
+
# =========================================================================
|
|
955
|
+
|
|
956
|
+
def test_update_shared_surcharge(self):
|
|
957
|
+
"""Test updating an existing shared surcharge."""
|
|
958
|
+
response = self.query(
|
|
959
|
+
"""
|
|
960
|
+
mutation update_surcharge($data: UpdateSharedSurchargeMutationInput!) {
|
|
961
|
+
update_shared_surcharge(input: $data) {
|
|
962
|
+
rate_sheet {
|
|
963
|
+
id
|
|
964
|
+
surcharges {
|
|
965
|
+
id
|
|
966
|
+
name
|
|
967
|
+
amount
|
|
968
|
+
surcharge_type
|
|
969
|
+
active
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
""",
|
|
975
|
+
operation_name="update_surcharge",
|
|
976
|
+
variables={
|
|
977
|
+
"data": {
|
|
978
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
979
|
+
"surcharge_id": "surch_fuel",
|
|
980
|
+
"surcharge": {
|
|
981
|
+
"name": "Updated Fuel Surcharge",
|
|
982
|
+
"amount": 12.0,
|
|
983
|
+
"surcharge_type": "percentage",
|
|
984
|
+
"active": True,
|
|
985
|
+
},
|
|
986
|
+
},
|
|
987
|
+
},
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
self.assertResponseNoErrors(response)
|
|
991
|
+
surcharges = response.data["data"]["update_shared_surcharge"]["rate_sheet"]["surcharges"]
|
|
992
|
+
self.assertEqual(surcharges[0]["name"], "Updated Fuel Surcharge")
|
|
993
|
+
self.assertEqual(surcharges[0]["amount"], 12.0)
|
|
994
|
+
|
|
995
|
+
def test_update_surcharge_toggle_active(self):
|
|
996
|
+
"""Test toggling surcharge active status."""
|
|
997
|
+
response = self.query(
|
|
998
|
+
"""
|
|
999
|
+
mutation update_surcharge($data: UpdateSharedSurchargeMutationInput!) {
|
|
1000
|
+
update_shared_surcharge(input: $data) {
|
|
1001
|
+
rate_sheet {
|
|
1002
|
+
surcharges {
|
|
1003
|
+
id
|
|
1004
|
+
active
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
""",
|
|
1010
|
+
operation_name="update_surcharge",
|
|
1011
|
+
variables={
|
|
1012
|
+
"data": {
|
|
1013
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1014
|
+
"surcharge_id": "surch_fuel",
|
|
1015
|
+
"surcharge": {
|
|
1016
|
+
"name": "Fuel Surcharge",
|
|
1017
|
+
"amount": 10.0,
|
|
1018
|
+
"active": False,
|
|
1019
|
+
},
|
|
1020
|
+
},
|
|
1021
|
+
},
|
|
1022
|
+
)
|
|
1023
|
+
|
|
1024
|
+
self.assertResponseNoErrors(response)
|
|
1025
|
+
surcharges = response.data["data"]["update_shared_surcharge"]["rate_sheet"]["surcharges"]
|
|
1026
|
+
self.assertFalse(surcharges[0]["active"])
|
|
1027
|
+
|
|
1028
|
+
def test_update_nonexistent_surcharge(self):
|
|
1029
|
+
"""Test updating a surcharge that doesn't exist."""
|
|
1030
|
+
response = self.query(
|
|
1031
|
+
"""
|
|
1032
|
+
mutation update_surcharge($data: UpdateSharedSurchargeMutationInput!) {
|
|
1033
|
+
update_shared_surcharge(input: $data) {
|
|
1034
|
+
rate_sheet {
|
|
1035
|
+
id
|
|
1036
|
+
}
|
|
1037
|
+
errors {
|
|
1038
|
+
field
|
|
1039
|
+
messages
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
""",
|
|
1044
|
+
operation_name="update_surcharge",
|
|
1045
|
+
variables={
|
|
1046
|
+
"data": {
|
|
1047
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1048
|
+
"surcharge_id": "nonexistent_surcharge",
|
|
1049
|
+
"surcharge": {
|
|
1050
|
+
"name": "Will Fail",
|
|
1051
|
+
"amount": 0,
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
},
|
|
1055
|
+
)
|
|
1056
|
+
|
|
1057
|
+
# Should have an error
|
|
1058
|
+
self.assertIsNotNone(response.data.get("errors") or response.data["data"]["update_shared_surcharge"].get("errors"))
|
|
1059
|
+
|
|
1060
|
+
# =========================================================================
|
|
1061
|
+
# DELETE SURCHARGE TESTS
|
|
1062
|
+
# =========================================================================
|
|
1063
|
+
|
|
1064
|
+
def test_delete_shared_surcharge(self):
|
|
1065
|
+
"""Test deleting a shared surcharge."""
|
|
1066
|
+
# Add a second surcharge
|
|
1067
|
+
self.rate_sheet.surcharges.append({
|
|
1068
|
+
"id": "surch_energy",
|
|
1069
|
+
"name": "Energy",
|
|
1070
|
+
"amount": 5.0,
|
|
1071
|
+
"surcharge_type": "fixed",
|
|
1072
|
+
"active": True,
|
|
1073
|
+
})
|
|
1074
|
+
self.rate_sheet.save()
|
|
1075
|
+
|
|
1076
|
+
response = self.query(
|
|
1077
|
+
"""
|
|
1078
|
+
mutation delete_surcharge($data: DeleteSharedSurchargeMutationInput!) {
|
|
1079
|
+
delete_shared_surcharge(input: $data) {
|
|
1080
|
+
rate_sheet {
|
|
1081
|
+
id
|
|
1082
|
+
surcharges {
|
|
1083
|
+
id
|
|
1084
|
+
name
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
""",
|
|
1090
|
+
operation_name="delete_surcharge",
|
|
1091
|
+
variables={
|
|
1092
|
+
"data": {
|
|
1093
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1094
|
+
"surcharge_id": "surch_energy",
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
1097
|
+
)
|
|
1098
|
+
|
|
1099
|
+
self.assertResponseNoErrors(response)
|
|
1100
|
+
surcharges = response.data["data"]["delete_shared_surcharge"]["rate_sheet"]["surcharges"]
|
|
1101
|
+
self.assertEqual(len(surcharges), 1)
|
|
1102
|
+
self.assertEqual(surcharges[0]["id"], "surch_fuel")
|
|
1103
|
+
|
|
1104
|
+
def test_delete_surcharge_removes_from_service_surcharge_ids(self):
|
|
1105
|
+
"""Test that deleting a surcharge removes it from services' surcharge_ids."""
|
|
1106
|
+
self.service.surcharge_ids = ["surch_fuel"]
|
|
1107
|
+
self.service.save()
|
|
1108
|
+
|
|
1109
|
+
response = self.query(
|
|
1110
|
+
"""
|
|
1111
|
+
mutation delete_surcharge($data: DeleteSharedSurchargeMutationInput!) {
|
|
1112
|
+
delete_shared_surcharge(input: $data) {
|
|
1113
|
+
rate_sheet {
|
|
1114
|
+
surcharges {
|
|
1115
|
+
id
|
|
1116
|
+
}
|
|
1117
|
+
services {
|
|
1118
|
+
id
|
|
1119
|
+
surcharge_ids
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
""",
|
|
1125
|
+
operation_name="delete_surcharge",
|
|
1126
|
+
variables={
|
|
1127
|
+
"data": {
|
|
1128
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1129
|
+
"surcharge_id": "surch_fuel",
|
|
1130
|
+
},
|
|
1131
|
+
},
|
|
1132
|
+
)
|
|
1133
|
+
|
|
1134
|
+
self.assertResponseNoErrors(response)
|
|
1135
|
+
services = response.data["data"]["delete_shared_surcharge"]["rate_sheet"]["services"]
|
|
1136
|
+
self.assertEqual(services[0]["surcharge_ids"], [])
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
class TestServiceRates(GraphTestCase):
|
|
1140
|
+
"""Tests for service rate (service-zone rate mapping) operations."""
|
|
1141
|
+
|
|
1142
|
+
def setUp(self):
|
|
1143
|
+
super().setUp()
|
|
1144
|
+
|
|
1145
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
1146
|
+
name="Service Rate Test Sheet",
|
|
1147
|
+
carrier_name="ups",
|
|
1148
|
+
slug="service_rate_test_sheet",
|
|
1149
|
+
zones=[
|
|
1150
|
+
{"id": "zone_1", "label": "Zone 1", "country_codes": ["US"]},
|
|
1151
|
+
{"id": "zone_2", "label": "Zone 2", "country_codes": ["CA"]},
|
|
1152
|
+
{"id": "zone_3", "label": "Zone 3", "country_codes": ["MX"]},
|
|
1153
|
+
],
|
|
1154
|
+
created_by=self.user,
|
|
1155
|
+
)
|
|
1156
|
+
|
|
1157
|
+
self.service = providers.ServiceLevel.objects.create(
|
|
1158
|
+
service_name="Test Service",
|
|
1159
|
+
service_code="test_service",
|
|
1160
|
+
carrier_service_code="TEST",
|
|
1161
|
+
currency="USD",
|
|
1162
|
+
zone_ids=["zone_1", "zone_2"],
|
|
1163
|
+
created_by=self.user,
|
|
1164
|
+
)
|
|
1165
|
+
self.rate_sheet.services.add(self.service)
|
|
1166
|
+
|
|
1167
|
+
# Add initial service rates
|
|
1168
|
+
self.rate_sheet.service_rates = [
|
|
1169
|
+
{"service_id": self.service.id, "zone_id": "zone_1", "rate": 10.00, "cost": 8.00},
|
|
1170
|
+
{"service_id": self.service.id, "zone_id": "zone_2", "rate": 15.00, "cost": 12.00},
|
|
1171
|
+
]
|
|
1172
|
+
self.rate_sheet.save()
|
|
1173
|
+
|
|
1174
|
+
# =========================================================================
|
|
1175
|
+
# UPDATE SERVICE RATE TESTS
|
|
1176
|
+
# =========================================================================
|
|
1177
|
+
|
|
1178
|
+
def test_update_service_rate(self):
|
|
1179
|
+
"""Test updating an existing service rate."""
|
|
1180
|
+
response = self.query(
|
|
1181
|
+
"""
|
|
1182
|
+
mutation update_rate($data: UpdateServiceRateMutationInput!) {
|
|
1183
|
+
update_service_rate(input: $data) {
|
|
1184
|
+
rate_sheet {
|
|
1185
|
+
id
|
|
1186
|
+
service_rates {
|
|
1187
|
+
service_id
|
|
1188
|
+
zone_id
|
|
1189
|
+
rate
|
|
1190
|
+
cost
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
""",
|
|
1196
|
+
operation_name="update_rate",
|
|
1197
|
+
variables={
|
|
1198
|
+
"data": {
|
|
1199
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1200
|
+
"service_id": self.service.id,
|
|
1201
|
+
"zone_id": "zone_1",
|
|
1202
|
+
"rate": 15.00,
|
|
1203
|
+
"cost": 12.00,
|
|
1204
|
+
},
|
|
1205
|
+
},
|
|
1206
|
+
)
|
|
1207
|
+
|
|
1208
|
+
self.assertResponseNoErrors(response)
|
|
1209
|
+
service_rates = response.data["data"]["update_service_rate"]["rate_sheet"]["service_rates"]
|
|
1210
|
+
zone_1_rate = next(r for r in service_rates if r["zone_id"] == "zone_1")
|
|
1211
|
+
self.assertEqual(zone_1_rate["rate"], 15.0)
|
|
1212
|
+
self.assertEqual(zone_1_rate["cost"], 12.0)
|
|
1213
|
+
|
|
1214
|
+
def test_update_service_rate_creates_new(self):
|
|
1215
|
+
"""Test that updating a non-existent service rate creates it."""
|
|
1216
|
+
response = self.query(
|
|
1217
|
+
"""
|
|
1218
|
+
mutation update_rate($data: UpdateServiceRateMutationInput!) {
|
|
1219
|
+
update_service_rate(input: $data) {
|
|
1220
|
+
rate_sheet {
|
|
1221
|
+
service_rates {
|
|
1222
|
+
service_id
|
|
1223
|
+
zone_id
|
|
1224
|
+
rate
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
""",
|
|
1230
|
+
operation_name="update_rate",
|
|
1231
|
+
variables={
|
|
1232
|
+
"data": {
|
|
1233
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1234
|
+
"service_id": self.service.id,
|
|
1235
|
+
"zone_id": "zone_3", # New zone
|
|
1236
|
+
"rate": 20.00,
|
|
1237
|
+
},
|
|
1238
|
+
},
|
|
1239
|
+
)
|
|
1240
|
+
|
|
1241
|
+
self.assertResponseNoErrors(response)
|
|
1242
|
+
service_rates = response.data["data"]["update_service_rate"]["rate_sheet"]["service_rates"]
|
|
1243
|
+
self.assertEqual(len(service_rates), 3)
|
|
1244
|
+
zone_3_rate = next(r for r in service_rates if r["zone_id"] == "zone_3")
|
|
1245
|
+
self.assertEqual(zone_3_rate["rate"], 20.0)
|
|
1246
|
+
|
|
1247
|
+
def test_update_service_rate_with_weight_limits(self):
|
|
1248
|
+
"""Test updating service rate with weight limits."""
|
|
1249
|
+
response = self.query(
|
|
1250
|
+
"""
|
|
1251
|
+
mutation update_rate($data: UpdateServiceRateMutationInput!) {
|
|
1252
|
+
update_service_rate(input: $data) {
|
|
1253
|
+
rate_sheet {
|
|
1254
|
+
service_rates {
|
|
1255
|
+
service_id
|
|
1256
|
+
zone_id
|
|
1257
|
+
rate
|
|
1258
|
+
min_weight
|
|
1259
|
+
max_weight
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
""",
|
|
1265
|
+
operation_name="update_rate",
|
|
1266
|
+
variables={
|
|
1267
|
+
"data": {
|
|
1268
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1269
|
+
"service_id": self.service.id,
|
|
1270
|
+
"zone_id": "zone_1",
|
|
1271
|
+
"rate": 10.00,
|
|
1272
|
+
"min_weight": 0.0,
|
|
1273
|
+
"max_weight": 50.0,
|
|
1274
|
+
},
|
|
1275
|
+
},
|
|
1276
|
+
)
|
|
1277
|
+
|
|
1278
|
+
self.assertResponseNoErrors(response)
|
|
1279
|
+
service_rates = response.data["data"]["update_service_rate"]["rate_sheet"]["service_rates"]
|
|
1280
|
+
zone_1_rate = next(r for r in service_rates if r["zone_id"] == "zone_1")
|
|
1281
|
+
self.assertEqual(zone_1_rate["min_weight"], 0.0)
|
|
1282
|
+
self.assertEqual(zone_1_rate["max_weight"], 50.0)
|
|
1283
|
+
|
|
1284
|
+
# =========================================================================
|
|
1285
|
+
# BATCH UPDATE SERVICE RATES TESTS
|
|
1286
|
+
# =========================================================================
|
|
1287
|
+
|
|
1288
|
+
def test_batch_update_service_rates(self):
|
|
1289
|
+
"""Test batch updating multiple service rates."""
|
|
1290
|
+
response = self.query(
|
|
1291
|
+
"""
|
|
1292
|
+
mutation batch_update($data: BatchUpdateServiceRatesMutationInput!) {
|
|
1293
|
+
batch_update_service_rates(input: $data) {
|
|
1294
|
+
rate_sheet {
|
|
1295
|
+
service_rates {
|
|
1296
|
+
service_id
|
|
1297
|
+
zone_id
|
|
1298
|
+
rate
|
|
1299
|
+
cost
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
""",
|
|
1305
|
+
operation_name="batch_update",
|
|
1306
|
+
variables={
|
|
1307
|
+
"data": {
|
|
1308
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1309
|
+
"rates": [
|
|
1310
|
+
{
|
|
1311
|
+
"service_id": self.service.id,
|
|
1312
|
+
"zone_id": "zone_1",
|
|
1313
|
+
"rate": 11.00,
|
|
1314
|
+
"cost": 9.00,
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
"service_id": self.service.id,
|
|
1318
|
+
"zone_id": "zone_2",
|
|
1319
|
+
"rate": 16.00,
|
|
1320
|
+
"cost": 13.00,
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
"service_id": self.service.id,
|
|
1324
|
+
"zone_id": "zone_3",
|
|
1325
|
+
"rate": 21.00,
|
|
1326
|
+
"cost": 17.00,
|
|
1327
|
+
},
|
|
1328
|
+
],
|
|
1329
|
+
},
|
|
1330
|
+
},
|
|
1331
|
+
)
|
|
1332
|
+
|
|
1333
|
+
self.assertResponseNoErrors(response)
|
|
1334
|
+
service_rates = response.data["data"]["batch_update_service_rates"]["rate_sheet"]["service_rates"]
|
|
1335
|
+
self.assertEqual(len(service_rates), 3)
|
|
1336
|
+
|
|
1337
|
+
# Verify each rate
|
|
1338
|
+
rates_by_zone = {r["zone_id"]: r for r in service_rates}
|
|
1339
|
+
self.assertEqual(rates_by_zone["zone_1"]["rate"], 11.0)
|
|
1340
|
+
self.assertEqual(rates_by_zone["zone_2"]["rate"], 16.0)
|
|
1341
|
+
self.assertEqual(rates_by_zone["zone_3"]["rate"], 21.0)
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
class TestServiceAssignments(GraphTestCase):
|
|
1345
|
+
"""Tests for service zone_ids and surcharge_ids assignment operations."""
|
|
1346
|
+
|
|
1347
|
+
def setUp(self):
|
|
1348
|
+
super().setUp()
|
|
1349
|
+
|
|
1350
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
1351
|
+
name="Assignment Test Sheet",
|
|
1352
|
+
carrier_name="ups",
|
|
1353
|
+
slug="assignment_test_sheet",
|
|
1354
|
+
zones=[
|
|
1355
|
+
{"id": "zone_1", "label": "Zone 1", "country_codes": ["US"]},
|
|
1356
|
+
{"id": "zone_2", "label": "Zone 2", "country_codes": ["CA"]},
|
|
1357
|
+
],
|
|
1358
|
+
surcharges=[
|
|
1359
|
+
{"id": "surch_fuel", "name": "Fuel", "amount": 10.0, "surcharge_type": "percentage", "active": True},
|
|
1360
|
+
{"id": "surch_energy", "name": "Energy", "amount": 5.0, "surcharge_type": "fixed", "active": True},
|
|
1361
|
+
],
|
|
1362
|
+
created_by=self.user,
|
|
1363
|
+
)
|
|
1364
|
+
|
|
1365
|
+
self.service = providers.ServiceLevel.objects.create(
|
|
1366
|
+
service_name="Test Service",
|
|
1367
|
+
service_code="test_service",
|
|
1368
|
+
carrier_service_code="TEST",
|
|
1369
|
+
currency="USD",
|
|
1370
|
+
zone_ids=["zone_1"],
|
|
1371
|
+
surcharge_ids=["surch_fuel"],
|
|
1372
|
+
created_by=self.user,
|
|
1373
|
+
)
|
|
1374
|
+
self.rate_sheet.services.add(self.service)
|
|
1375
|
+
|
|
1376
|
+
# =========================================================================
|
|
1377
|
+
# UPDATE SERVICE ZONE IDS TESTS
|
|
1378
|
+
# =========================================================================
|
|
1379
|
+
|
|
1380
|
+
def test_update_service_zone_ids(self):
|
|
1381
|
+
"""Test updating service zone_ids."""
|
|
1382
|
+
response = self.query(
|
|
1383
|
+
"""
|
|
1384
|
+
mutation update_zone_ids($data: UpdateServiceZoneIdsMutationInput!) {
|
|
1385
|
+
update_service_zone_ids(input: $data) {
|
|
1386
|
+
rate_sheet {
|
|
1387
|
+
id
|
|
1388
|
+
services {
|
|
1389
|
+
id
|
|
1390
|
+
zone_ids
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
""",
|
|
1396
|
+
operation_name="update_zone_ids",
|
|
1397
|
+
variables={
|
|
1398
|
+
"data": {
|
|
1399
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1400
|
+
"service_id": self.service.id,
|
|
1401
|
+
"zone_ids": ["zone_1", "zone_2"],
|
|
1402
|
+
},
|
|
1403
|
+
},
|
|
1404
|
+
)
|
|
1405
|
+
|
|
1406
|
+
self.assertResponseNoErrors(response)
|
|
1407
|
+
services = response.data["data"]["update_service_zone_ids"]["rate_sheet"]["services"]
|
|
1408
|
+
self.assertEqual(services[0]["zone_ids"], ["zone_1", "zone_2"])
|
|
1409
|
+
|
|
1410
|
+
def test_update_service_zone_ids_empty(self):
|
|
1411
|
+
"""Test clearing service zone_ids."""
|
|
1412
|
+
response = self.query(
|
|
1413
|
+
"""
|
|
1414
|
+
mutation update_zone_ids($data: UpdateServiceZoneIdsMutationInput!) {
|
|
1415
|
+
update_service_zone_ids(input: $data) {
|
|
1416
|
+
rate_sheet {
|
|
1417
|
+
services {
|
|
1418
|
+
id
|
|
1419
|
+
zone_ids
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
""",
|
|
1425
|
+
operation_name="update_zone_ids",
|
|
1426
|
+
variables={
|
|
1427
|
+
"data": {
|
|
1428
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1429
|
+
"service_id": self.service.id,
|
|
1430
|
+
"zone_ids": [],
|
|
1431
|
+
},
|
|
1432
|
+
},
|
|
1433
|
+
)
|
|
1434
|
+
|
|
1435
|
+
self.assertResponseNoErrors(response)
|
|
1436
|
+
services = response.data["data"]["update_service_zone_ids"]["rate_sheet"]["services"]
|
|
1437
|
+
self.assertEqual(services[0]["zone_ids"], [])
|
|
1438
|
+
|
|
1439
|
+
# =========================================================================
|
|
1440
|
+
# UPDATE SERVICE SURCHARGE IDS TESTS
|
|
1441
|
+
# =========================================================================
|
|
1442
|
+
|
|
1443
|
+
def test_update_service_surcharge_ids(self):
|
|
1444
|
+
"""Test updating service surcharge_ids."""
|
|
1445
|
+
response = self.query(
|
|
1446
|
+
"""
|
|
1447
|
+
mutation update_surcharge_ids($data: UpdateServiceSurchargeIdsMutationInput!) {
|
|
1448
|
+
update_service_surcharge_ids(input: $data) {
|
|
1449
|
+
rate_sheet {
|
|
1450
|
+
id
|
|
1451
|
+
services {
|
|
1452
|
+
id
|
|
1453
|
+
surcharge_ids
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
""",
|
|
1459
|
+
operation_name="update_surcharge_ids",
|
|
1460
|
+
variables={
|
|
1461
|
+
"data": {
|
|
1462
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1463
|
+
"service_id": self.service.id,
|
|
1464
|
+
"surcharge_ids": ["surch_fuel", "surch_energy"],
|
|
1465
|
+
},
|
|
1466
|
+
},
|
|
1467
|
+
)
|
|
1468
|
+
|
|
1469
|
+
self.assertResponseNoErrors(response)
|
|
1470
|
+
services = response.data["data"]["update_service_surcharge_ids"]["rate_sheet"]["services"]
|
|
1471
|
+
self.assertEqual(services[0]["surcharge_ids"], ["surch_fuel", "surch_energy"])
|
|
1472
|
+
|
|
1473
|
+
def test_update_service_surcharge_ids_empty(self):
|
|
1474
|
+
"""Test clearing service surcharge_ids."""
|
|
1475
|
+
response = self.query(
|
|
1476
|
+
"""
|
|
1477
|
+
mutation update_surcharge_ids($data: UpdateServiceSurchargeIdsMutationInput!) {
|
|
1478
|
+
update_service_surcharge_ids(input: $data) {
|
|
1479
|
+
rate_sheet {
|
|
1480
|
+
services {
|
|
1481
|
+
id
|
|
1482
|
+
surcharge_ids
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
""",
|
|
1488
|
+
operation_name="update_surcharge_ids",
|
|
1489
|
+
variables={
|
|
1490
|
+
"data": {
|
|
1491
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1492
|
+
"service_id": self.service.id,
|
|
1493
|
+
"surcharge_ids": [],
|
|
1494
|
+
},
|
|
1495
|
+
},
|
|
1496
|
+
)
|
|
1497
|
+
|
|
1498
|
+
self.assertResponseNoErrors(response)
|
|
1499
|
+
services = response.data["data"]["update_service_surcharge_ids"]["rate_sheet"]["services"]
|
|
1500
|
+
self.assertEqual(services[0]["surcharge_ids"], [])
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
class TestRateSheetServices(GraphTestCase):
|
|
1504
|
+
"""Tests for rate sheet service operations."""
|
|
1505
|
+
|
|
1506
|
+
def setUp(self):
|
|
1507
|
+
super().setUp()
|
|
1508
|
+
|
|
1509
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
1510
|
+
name="Service Test Sheet",
|
|
1511
|
+
carrier_name="ups",
|
|
1512
|
+
slug="service_test_sheet",
|
|
1513
|
+
zones=[
|
|
1514
|
+
{"id": "zone_1", "label": "Zone 1", "country_codes": ["US"]},
|
|
1515
|
+
],
|
|
1516
|
+
created_by=self.user,
|
|
1517
|
+
)
|
|
1518
|
+
|
|
1519
|
+
self.service1 = providers.ServiceLevel.objects.create(
|
|
1520
|
+
service_name="Service 1",
|
|
1521
|
+
service_code="service_1",
|
|
1522
|
+
carrier_service_code="S1",
|
|
1523
|
+
currency="USD",
|
|
1524
|
+
zone_ids=["zone_1"],
|
|
1525
|
+
created_by=self.user,
|
|
1526
|
+
)
|
|
1527
|
+
self.service2 = providers.ServiceLevel.objects.create(
|
|
1528
|
+
service_name="Service 2",
|
|
1529
|
+
service_code="service_2",
|
|
1530
|
+
carrier_service_code="S2",
|
|
1531
|
+
currency="USD",
|
|
1532
|
+
zone_ids=["zone_1"],
|
|
1533
|
+
created_by=self.user,
|
|
1534
|
+
)
|
|
1535
|
+
self.rate_sheet.services.add(self.service1, self.service2)
|
|
1536
|
+
|
|
1537
|
+
def test_delete_rate_sheet_service(self):
|
|
1538
|
+
"""Test deleting a service from a rate sheet."""
|
|
1539
|
+
response = self.query(
|
|
1540
|
+
"""
|
|
1541
|
+
mutation delete_service($data: DeleteRateSheetServiceMutationInput!) {
|
|
1542
|
+
delete_rate_sheet_service(input: $data) {
|
|
1543
|
+
rate_sheet {
|
|
1544
|
+
id
|
|
1545
|
+
services {
|
|
1546
|
+
id
|
|
1547
|
+
service_name
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
errors {
|
|
1551
|
+
field
|
|
1552
|
+
messages
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
""",
|
|
1557
|
+
operation_name="delete_service",
|
|
1558
|
+
variables={
|
|
1559
|
+
"data": {
|
|
1560
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1561
|
+
"service_id": self.service2.id,
|
|
1562
|
+
},
|
|
1563
|
+
},
|
|
1564
|
+
)
|
|
1565
|
+
|
|
1566
|
+
self.assertResponseNoErrors(response)
|
|
1567
|
+
services = response.data["data"]["delete_rate_sheet_service"]["rate_sheet"]["services"]
|
|
1568
|
+
self.assertEqual(len(services), 1)
|
|
1569
|
+
self.assertEqual(services[0]["service_name"], "Service 1")
|
|
1570
|
+
|
|
1571
|
+
class TestRateSheetModelMethods(GraphTestCase):
|
|
1572
|
+
"""Tests for RateSheet model methods (rate calculation, etc.)."""
|
|
1573
|
+
|
|
8
1574
|
def setUp(self):
|
|
9
1575
|
super().setUp()
|
|
10
1576
|
|
|
11
|
-
# Create a test rate sheet
|
|
12
1577
|
self.rate_sheet = providers.RateSheet.objects.create(
|
|
13
|
-
name="Test
|
|
1578
|
+
name="Calculation Test Sheet",
|
|
14
1579
|
carrier_name="ups",
|
|
15
|
-
slug="
|
|
1580
|
+
slug="calculation_test_sheet",
|
|
1581
|
+
zones=[
|
|
1582
|
+
{"id": "zone_1", "label": "Zone 1", "country_codes": ["US"]},
|
|
1583
|
+
{"id": "zone_2", "label": "Zone 2", "country_codes": ["CA"], "transit_days": 5},
|
|
1584
|
+
],
|
|
1585
|
+
surcharges=[
|
|
1586
|
+
{"id": "surch_fuel", "name": "Fuel", "amount": 10.0, "surcharge_type": "percentage", "active": True, "cost": 8.0},
|
|
1587
|
+
{"id": "surch_handling", "name": "Handling", "amount": 5.0, "surcharge_type": "fixed", "active": True, "cost": 3.0},
|
|
1588
|
+
{"id": "surch_inactive", "name": "Inactive", "amount": 100.0, "surcharge_type": "fixed", "active": False},
|
|
1589
|
+
],
|
|
1590
|
+
service_rates=[],
|
|
16
1591
|
created_by=self.user,
|
|
17
1592
|
)
|
|
18
1593
|
|
|
19
|
-
# Create a test service
|
|
20
1594
|
self.service = providers.ServiceLevel.objects.create(
|
|
21
|
-
service_name="
|
|
22
|
-
service_code="
|
|
23
|
-
carrier_service_code="
|
|
1595
|
+
service_name="Test Service",
|
|
1596
|
+
service_code="test_service",
|
|
1597
|
+
carrier_service_code="TEST",
|
|
24
1598
|
currency="USD",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
"rate": 10.00,
|
|
29
|
-
"label": "Zone 1",
|
|
30
|
-
"cities": ["New York", "Los Angeles"],
|
|
31
|
-
}
|
|
32
|
-
],
|
|
1599
|
+
zone_ids=["zone_1", "zone_2"],
|
|
1600
|
+
surcharge_ids=["surch_fuel", "surch_handling", "surch_inactive"],
|
|
33
1601
|
created_by=self.user,
|
|
34
1602
|
)
|
|
35
1603
|
self.rate_sheet.services.add(self.service)
|
|
36
1604
|
|
|
37
|
-
|
|
1605
|
+
# Add service rates
|
|
1606
|
+
self.rate_sheet.service_rates = [
|
|
1607
|
+
{"service_id": self.service.id, "zone_id": "zone_1", "rate": 100.00, "cost": 80.00},
|
|
1608
|
+
{"service_id": self.service.id, "zone_id": "zone_2", "rate": 150.00, "cost": 120.00},
|
|
1609
|
+
]
|
|
1610
|
+
self.rate_sheet.save()
|
|
1611
|
+
|
|
1612
|
+
def test_get_zone(self):
|
|
1613
|
+
"""Test getting a zone by ID."""
|
|
1614
|
+
zone = self.rate_sheet.get_zone("zone_1")
|
|
1615
|
+
self.assertIsNotNone(zone)
|
|
1616
|
+
self.assertEqual(zone["label"], "Zone 1")
|
|
1617
|
+
|
|
1618
|
+
zone_none = self.rate_sheet.get_zone("nonexistent")
|
|
1619
|
+
self.assertIsNone(zone_none)
|
|
1620
|
+
|
|
1621
|
+
def test_get_surcharge(self):
|
|
1622
|
+
"""Test getting a surcharge by ID."""
|
|
1623
|
+
surcharge = self.rate_sheet.get_surcharge("surch_fuel")
|
|
1624
|
+
self.assertIsNotNone(surcharge)
|
|
1625
|
+
self.assertEqual(surcharge["name"], "Fuel")
|
|
1626
|
+
|
|
1627
|
+
surcharge_none = self.rate_sheet.get_surcharge("nonexistent")
|
|
1628
|
+
self.assertIsNone(surcharge_none)
|
|
1629
|
+
|
|
1630
|
+
def test_get_service_rate(self):
|
|
1631
|
+
"""Test getting a service rate by service_id and zone_id."""
|
|
1632
|
+
rate = self.rate_sheet.get_service_rate(self.service.id, "zone_1")
|
|
1633
|
+
self.assertIsNotNone(rate)
|
|
1634
|
+
self.assertEqual(rate["rate"], 100.00)
|
|
1635
|
+
|
|
1636
|
+
rate_none = self.rate_sheet.get_service_rate(self.service.id, "nonexistent")
|
|
1637
|
+
self.assertIsNone(rate_none)
|
|
1638
|
+
|
|
1639
|
+
def test_apply_surcharges_to_rate_percentage(self):
|
|
1640
|
+
"""Test applying percentage surcharges."""
|
|
1641
|
+
# 10% of 100 = 10
|
|
1642
|
+
total, breakdown = self.rate_sheet.apply_surcharges_to_rate(100.0, ["surch_fuel"])
|
|
1643
|
+
self.assertEqual(total, 110.0)
|
|
1644
|
+
self.assertEqual(len(breakdown), 1)
|
|
1645
|
+
self.assertEqual(breakdown[0]["amount"], 10.0)
|
|
1646
|
+
self.assertEqual(breakdown[0]["surcharge_type"], "percentage")
|
|
1647
|
+
|
|
1648
|
+
def test_apply_surcharges_to_rate_fixed(self):
|
|
1649
|
+
"""Test applying fixed surcharges."""
|
|
1650
|
+
total, breakdown = self.rate_sheet.apply_surcharges_to_rate(100.0, ["surch_handling"])
|
|
1651
|
+
self.assertEqual(total, 105.0)
|
|
1652
|
+
self.assertEqual(len(breakdown), 1)
|
|
1653
|
+
self.assertEqual(breakdown[0]["amount"], 5.0)
|
|
1654
|
+
self.assertEqual(breakdown[0]["surcharge_type"], "fixed")
|
|
1655
|
+
|
|
1656
|
+
def test_apply_surcharges_to_rate_combined(self):
|
|
1657
|
+
"""Test applying multiple surcharges."""
|
|
1658
|
+
# 100 + 10% (10) + 5 fixed = 115
|
|
1659
|
+
total, breakdown = self.rate_sheet.apply_surcharges_to_rate(100.0, ["surch_fuel", "surch_handling"])
|
|
1660
|
+
self.assertEqual(total, 115.0)
|
|
1661
|
+
self.assertEqual(len(breakdown), 2)
|
|
1662
|
+
|
|
1663
|
+
def test_apply_surcharges_skips_inactive(self):
|
|
1664
|
+
"""Test that inactive surcharges are skipped."""
|
|
1665
|
+
total, breakdown = self.rate_sheet.apply_surcharges_to_rate(100.0, ["surch_fuel", "surch_inactive"])
|
|
1666
|
+
self.assertEqual(total, 110.0) # Only fuel applied
|
|
1667
|
+
self.assertEqual(len(breakdown), 1) # Only one active surcharge
|
|
1668
|
+
|
|
1669
|
+
def test_calculate_rate(self):
|
|
1670
|
+
"""Test full rate calculation with surcharges."""
|
|
1671
|
+
total, breakdown = self.rate_sheet.calculate_rate(self.service.id, "zone_1")
|
|
1672
|
+
# Base: 100, Fuel (10%): 10, Handling (fixed): 5 = 115
|
|
1673
|
+
self.assertEqual(total, 115.0)
|
|
1674
|
+
self.assertEqual(breakdown["base_rate"], 100.0)
|
|
1675
|
+
self.assertEqual(breakdown["base_cost"], 80.0)
|
|
1676
|
+
self.assertEqual(len(breakdown["surcharges"]), 2) # Only active surcharges
|
|
1677
|
+
|
|
1678
|
+
def test_get_service_zones_for_rating(self):
|
|
1679
|
+
"""Test getting zones with rates for SDK rating."""
|
|
1680
|
+
zones = self.rate_sheet.get_service_zones_for_rating(self.service.id)
|
|
1681
|
+
self.assertEqual(len(zones), 2)
|
|
1682
|
+
|
|
1683
|
+
zone_1 = next(z for z in zones if z["id"] == "zone_1")
|
|
1684
|
+
self.assertEqual(zone_1["rate"], 100.0)
|
|
1685
|
+
self.assertEqual(zone_1["cost"], 80.0)
|
|
1686
|
+
|
|
1687
|
+
zone_2 = next(z for z in zones if z["id"] == "zone_2")
|
|
1688
|
+
self.assertEqual(zone_2["rate"], 150.0)
|
|
1689
|
+
self.assertEqual(zone_2["transit_days"], 5) # From zone definition
|
|
1690
|
+
|
|
1691
|
+
def test_get_surcharges_for_rating(self):
|
|
1692
|
+
"""Test getting surcharges for SDK rating."""
|
|
1693
|
+
surcharges = self.rate_sheet.get_surcharges_for_rating(["surch_fuel", "surch_handling", "surch_inactive"])
|
|
1694
|
+
# Should only return active surcharges
|
|
1695
|
+
self.assertEqual(len(surcharges), 2)
|
|
1696
|
+
|
|
1697
|
+
fuel = next(s for s in surcharges if s["id"] == "surch_fuel")
|
|
1698
|
+
self.assertEqual(fuel["amount"], 10.0)
|
|
1699
|
+
self.assertEqual(fuel["cost"], 8.0)
|
|
1700
|
+
|
|
1701
|
+
|
|
1702
|
+
class TestRateSheetEdgeCases(GraphTestCase):
|
|
1703
|
+
"""Tests for edge cases and error handling."""
|
|
1704
|
+
|
|
1705
|
+
def setUp(self):
|
|
1706
|
+
super().setUp()
|
|
1707
|
+
|
|
1708
|
+
self.rate_sheet = providers.RateSheet.objects.create(
|
|
1709
|
+
name="Edge Case Sheet",
|
|
1710
|
+
carrier_name="ups",
|
|
1711
|
+
slug="edge_case_sheet",
|
|
1712
|
+
zones=[],
|
|
1713
|
+
surcharges=[],
|
|
1714
|
+
service_rates=[],
|
|
1715
|
+
created_by=self.user,
|
|
1716
|
+
)
|
|
1717
|
+
|
|
1718
|
+
def test_operations_on_empty_rate_sheet(self):
|
|
1719
|
+
"""Test that operations work on an empty rate sheet."""
|
|
1720
|
+
# Add first zone
|
|
38
1721
|
response = self.query(
|
|
39
1722
|
"""
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
1723
|
+
mutation add_zone($data: AddSharedZoneMutationInput!) {
|
|
1724
|
+
add_shared_zone(input: $data) {
|
|
1725
|
+
rate_sheet {
|
|
1726
|
+
zones {
|
|
44
1727
|
id
|
|
45
|
-
|
|
46
|
-
carrier_name
|
|
47
|
-
slug
|
|
48
|
-
services {
|
|
49
|
-
id
|
|
50
|
-
service_name
|
|
51
|
-
service_code
|
|
52
|
-
carrier_service_code
|
|
53
|
-
active
|
|
54
|
-
currency
|
|
55
|
-
zones {
|
|
56
|
-
rate
|
|
57
|
-
label
|
|
58
|
-
cities
|
|
59
|
-
postal_codes
|
|
60
|
-
country_codes
|
|
61
|
-
}
|
|
62
|
-
}
|
|
1728
|
+
label
|
|
63
1729
|
}
|
|
64
1730
|
}
|
|
65
1731
|
}
|
|
66
1732
|
}
|
|
67
1733
|
""",
|
|
68
|
-
operation_name="
|
|
1734
|
+
operation_name="add_zone",
|
|
1735
|
+
variables={
|
|
1736
|
+
"data": {
|
|
1737
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1738
|
+
"zone": {
|
|
1739
|
+
"label": "First Zone",
|
|
1740
|
+
"country_codes": ["US"],
|
|
1741
|
+
},
|
|
1742
|
+
},
|
|
1743
|
+
},
|
|
69
1744
|
)
|
|
70
|
-
response_data = response.data
|
|
71
1745
|
|
|
72
1746
|
self.assertResponseNoErrors(response)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
RATE_SHEETS_RESPONSE,
|
|
76
|
-
)
|
|
1747
|
+
zones = response.data["data"]["add_shared_zone"]["rate_sheet"]["zones"]
|
|
1748
|
+
self.assertEqual(len(zones), 1)
|
|
77
1749
|
|
|
78
|
-
def
|
|
1750
|
+
def test_operations_on_nonexistent_rate_sheet(self):
|
|
1751
|
+
"""Test that operations fail gracefully on nonexistent rate sheet."""
|
|
79
1752
|
response = self.query(
|
|
80
1753
|
"""
|
|
81
|
-
mutation
|
|
82
|
-
|
|
1754
|
+
mutation add_zone($data: AddSharedZoneMutationInput!) {
|
|
1755
|
+
add_shared_zone(input: $data) {
|
|
83
1756
|
rate_sheet {
|
|
84
1757
|
id
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
1758
|
+
}
|
|
1759
|
+
errors {
|
|
1760
|
+
field
|
|
1761
|
+
messages
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
""",
|
|
1766
|
+
operation_name="add_zone",
|
|
1767
|
+
variables={
|
|
1768
|
+
"data": {
|
|
1769
|
+
"rate_sheet_id": "rsht_nonexistent",
|
|
1770
|
+
"zone": {
|
|
1771
|
+
"label": "Will Fail",
|
|
1772
|
+
},
|
|
1773
|
+
},
|
|
1774
|
+
},
|
|
1775
|
+
)
|
|
1776
|
+
|
|
1777
|
+
# Should have an error
|
|
1778
|
+
self.assertIsNotNone(response.data.get("errors") or response.data["data"]["add_shared_zone"].get("errors"))
|
|
1779
|
+
|
|
1780
|
+
def test_zone_with_empty_arrays(self):
|
|
1781
|
+
"""Test zone with empty country_codes, cities, postal_codes."""
|
|
1782
|
+
response = self.query(
|
|
1783
|
+
"""
|
|
1784
|
+
mutation add_zone($data: AddSharedZoneMutationInput!) {
|
|
1785
|
+
add_shared_zone(input: $data) {
|
|
1786
|
+
rate_sheet {
|
|
1787
|
+
zones {
|
|
88
1788
|
id
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
rate
|
|
94
|
-
label
|
|
95
|
-
postal_codes
|
|
96
|
-
}
|
|
1789
|
+
label
|
|
1790
|
+
country_codes
|
|
1791
|
+
cities
|
|
1792
|
+
postal_codes
|
|
97
1793
|
}
|
|
98
1794
|
}
|
|
99
1795
|
}
|
|
100
1796
|
}
|
|
101
1797
|
""",
|
|
102
|
-
operation_name="
|
|
103
|
-
variables=
|
|
1798
|
+
operation_name="add_zone",
|
|
1799
|
+
variables={
|
|
1800
|
+
"data": {
|
|
1801
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1802
|
+
"zone": {
|
|
1803
|
+
"label": "Empty Zone",
|
|
1804
|
+
"country_codes": [],
|
|
1805
|
+
"cities": [],
|
|
1806
|
+
"postal_codes": [],
|
|
1807
|
+
},
|
|
1808
|
+
},
|
|
1809
|
+
},
|
|
104
1810
|
)
|
|
105
|
-
response_data = response.data
|
|
106
1811
|
|
|
107
1812
|
self.assertResponseNoErrors(response)
|
|
108
|
-
|
|
1813
|
+
zone = response.data["data"]["add_shared_zone"]["rate_sheet"]["zones"][0]
|
|
1814
|
+
self.assertEqual(zone["country_codes"], [])
|
|
1815
|
+
self.assertEqual(zone["cities"], [])
|
|
1816
|
+
self.assertEqual(zone["postal_codes"], [])
|
|
109
1817
|
|
|
110
|
-
def
|
|
1818
|
+
def test_surcharge_with_zero_amount(self):
|
|
1819
|
+
"""Test adding a surcharge with zero amount."""
|
|
111
1820
|
response = self.query(
|
|
112
1821
|
"""
|
|
113
|
-
mutation
|
|
114
|
-
|
|
1822
|
+
mutation add_surcharge($data: AddSharedSurchargeMutationInput!) {
|
|
1823
|
+
add_shared_surcharge(input: $data) {
|
|
115
1824
|
rate_sheet {
|
|
116
|
-
|
|
117
|
-
name
|
|
118
|
-
services {
|
|
1825
|
+
surcharges {
|
|
119
1826
|
id
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
rate
|
|
123
|
-
label
|
|
124
|
-
country_codes
|
|
125
|
-
}
|
|
1827
|
+
name
|
|
1828
|
+
amount
|
|
126
1829
|
}
|
|
127
1830
|
}
|
|
128
1831
|
}
|
|
129
1832
|
}
|
|
130
1833
|
""",
|
|
131
|
-
operation_name="
|
|
1834
|
+
operation_name="add_surcharge",
|
|
132
1835
|
variables={
|
|
133
1836
|
"data": {
|
|
134
|
-
"
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
"service_name": "Updated Service",
|
|
140
|
-
"zones": [
|
|
141
|
-
{
|
|
142
|
-
"rate": 20.0,
|
|
143
|
-
"label": "Updated Zone",
|
|
144
|
-
"country_codes": ["US", "CA"],
|
|
145
|
-
}
|
|
146
|
-
],
|
|
147
|
-
}
|
|
148
|
-
],
|
|
1837
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1838
|
+
"surcharge": {
|
|
1839
|
+
"name": "Zero Surcharge",
|
|
1840
|
+
"amount": 0.0,
|
|
1841
|
+
},
|
|
149
1842
|
},
|
|
150
1843
|
},
|
|
151
1844
|
)
|
|
152
|
-
response_data = response.data
|
|
153
1845
|
|
|
154
1846
|
self.assertResponseNoErrors(response)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
1847
|
+
surcharge = response.data["data"]["add_shared_surcharge"]["rate_sheet"]["surcharges"][0]
|
|
1848
|
+
self.assertEqual(surcharge["amount"], 0.0)
|
|
1849
|
+
|
|
1850
|
+
def test_service_rate_with_null_cost(self):
|
|
1851
|
+
"""Test service rate with null cost."""
|
|
1852
|
+
# First add a zone and service
|
|
1853
|
+
self.rate_sheet.zones = [{"id": "zone_1", "label": "Zone 1", "country_codes": ["US"]}]
|
|
1854
|
+
self.rate_sheet.save()
|
|
1855
|
+
|
|
1856
|
+
service = providers.ServiceLevel.objects.create(
|
|
1857
|
+
service_name="Test Service",
|
|
1858
|
+
service_code="test_service",
|
|
1859
|
+
carrier_service_code="TEST",
|
|
1860
|
+
currency="USD",
|
|
1861
|
+
created_by=self.user,
|
|
158
1862
|
)
|
|
1863
|
+
self.rate_sheet.services.add(service)
|
|
159
1864
|
|
|
160
|
-
def test_update_service_zone(self):
|
|
161
1865
|
response = self.query(
|
|
162
1866
|
"""
|
|
163
|
-
mutation
|
|
164
|
-
|
|
1867
|
+
mutation update_rate($data: UpdateServiceRateMutationInput!) {
|
|
1868
|
+
update_service_rate(input: $data) {
|
|
165
1869
|
rate_sheet {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
label
|
|
172
|
-
country_codes
|
|
173
|
-
}
|
|
1870
|
+
service_rates {
|
|
1871
|
+
service_id
|
|
1872
|
+
zone_id
|
|
1873
|
+
rate
|
|
1874
|
+
cost
|
|
174
1875
|
}
|
|
175
1876
|
}
|
|
176
1877
|
}
|
|
177
1878
|
}
|
|
178
1879
|
""",
|
|
179
|
-
operation_name="
|
|
1880
|
+
operation_name="update_rate",
|
|
180
1881
|
variables={
|
|
181
1882
|
"data": {
|
|
182
|
-
"
|
|
183
|
-
"service_id":
|
|
184
|
-
|
|
1883
|
+
"rate_sheet_id": self.rate_sheet.id,
|
|
1884
|
+
"service_id": service.id,
|
|
1885
|
+
"zone_id": "zone_1",
|
|
1886
|
+
"rate": 10.00,
|
|
1887
|
+
# cost is not provided
|
|
185
1888
|
},
|
|
186
1889
|
},
|
|
187
1890
|
)
|
|
188
|
-
response_data = response.data
|
|
189
1891
|
|
|
190
1892
|
self.assertResponseNoErrors(response)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
1893
|
+
service_rate = response.data["data"]["update_service_rate"]["rate_sheet"]["service_rates"][0]
|
|
1894
|
+
self.assertEqual(service_rate["rate"], 10.0)
|
|
1895
|
+
# cost should be null or default
|
|
1896
|
+
|
|
195
1897
|
|
|
1898
|
+
# =========================================================================
|
|
1899
|
+
# EXPECTED RESPONSES
|
|
1900
|
+
# =========================================================================
|
|
196
1901
|
|
|
197
1902
|
RATE_SHEETS_RESPONSE = {
|
|
198
1903
|
"data": {
|
|
@@ -203,6 +1908,32 @@ RATE_SHEETS_RESPONSE = {
|
|
|
203
1908
|
"carrier_name": "ups",
|
|
204
1909
|
"id": ANY,
|
|
205
1910
|
"name": "Test Rate Sheet",
|
|
1911
|
+
"slug": "test_rate_sheet",
|
|
1912
|
+
"zones": [
|
|
1913
|
+
{
|
|
1914
|
+
"id": "zone_1",
|
|
1915
|
+
"label": "Zone 1",
|
|
1916
|
+
"cities": ["New York", "Los Angeles"],
|
|
1917
|
+
"country_codes": ["US"],
|
|
1918
|
+
}
|
|
1919
|
+
],
|
|
1920
|
+
"surcharges": [
|
|
1921
|
+
{
|
|
1922
|
+
"id": "surch_fuel",
|
|
1923
|
+
"name": "Fuel Surcharge",
|
|
1924
|
+
"amount": 10.0,
|
|
1925
|
+
"surcharge_type": "percentage",
|
|
1926
|
+
"active": True,
|
|
1927
|
+
}
|
|
1928
|
+
],
|
|
1929
|
+
"service_rates": [
|
|
1930
|
+
{
|
|
1931
|
+
"service_id": ANY,
|
|
1932
|
+
"zone_id": "zone_1",
|
|
1933
|
+
"rate": 10.0,
|
|
1934
|
+
"cost": 8.0,
|
|
1935
|
+
}
|
|
1936
|
+
],
|
|
206
1937
|
"services": [
|
|
207
1938
|
{
|
|
208
1939
|
"active": True,
|
|
@@ -211,16 +1942,10 @@ RATE_SHEETS_RESPONSE = {
|
|
|
211
1942
|
"id": ANY,
|
|
212
1943
|
"service_code": "ups_standard",
|
|
213
1944
|
"service_name": "UPS Standard",
|
|
214
|
-
"
|
|
215
|
-
|
|
216
|
-
"cities": ["New York", "Los Angeles"],
|
|
217
|
-
"label": "Zone 1",
|
|
218
|
-
"rate": 10.0,
|
|
219
|
-
}
|
|
220
|
-
],
|
|
1945
|
+
"zone_ids": ["zone_1"],
|
|
1946
|
+
"surcharge_ids": ["surch_fuel"],
|
|
221
1947
|
}
|
|
222
1948
|
],
|
|
223
|
-
"slug": "test_rate_sheet",
|
|
224
1949
|
}
|
|
225
1950
|
}
|
|
226
1951
|
]
|
|
@@ -238,13 +1963,8 @@ CREATE_RATE_SHEET_DATA = {
|
|
|
238
1963
|
"service_code": "fedex_ground",
|
|
239
1964
|
"carrier_service_code": "FEDEX_GROUND",
|
|
240
1965
|
"currency": "USD",
|
|
241
|
-
"
|
|
242
|
-
|
|
243
|
-
"rate": 15.0,
|
|
244
|
-
"label": "Zone A",
|
|
245
|
-
"postal_codes": ["12345", "67890"],
|
|
246
|
-
}
|
|
247
|
-
],
|
|
1966
|
+
"zone_ids": [],
|
|
1967
|
+
"surcharge_ids": [],
|
|
248
1968
|
}
|
|
249
1969
|
],
|
|
250
1970
|
}
|
|
@@ -257,19 +1977,16 @@ CREATE_RATE_SHEET_RESPONSE = {
|
|
|
257
1977
|
"id": ANY,
|
|
258
1978
|
"name": "New Rate Sheet",
|
|
259
1979
|
"carrier_name": "fedex",
|
|
1980
|
+
"zones": [],
|
|
1981
|
+
"surcharges": [],
|
|
260
1982
|
"services": [
|
|
261
1983
|
{
|
|
262
1984
|
"id": ANY,
|
|
263
1985
|
"service_name": "FedEx Ground",
|
|
264
1986
|
"service_code": "fedex_ground",
|
|
265
1987
|
"currency": "USD",
|
|
266
|
-
"
|
|
267
|
-
|
|
268
|
-
"rate": 15.0,
|
|
269
|
-
"label": "Zone A",
|
|
270
|
-
"postal_codes": ["12345", "67890"],
|
|
271
|
-
}
|
|
272
|
-
],
|
|
1988
|
+
"zone_ids": [],
|
|
1989
|
+
"surcharge_ids": [],
|
|
273
1990
|
}
|
|
274
1991
|
],
|
|
275
1992
|
}
|
|
@@ -277,76 +1994,133 @@ CREATE_RATE_SHEET_RESPONSE = {
|
|
|
277
1994
|
}
|
|
278
1995
|
}
|
|
279
1996
|
|
|
280
|
-
|
|
1997
|
+
UPDATE_RATE_SHEET_RESPONSE = {
|
|
281
1998
|
"data": {
|
|
282
|
-
"
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
"
|
|
286
|
-
"
|
|
1999
|
+
"update_rate_sheet": {
|
|
2000
|
+
"rate_sheet": {
|
|
2001
|
+
"id": ANY,
|
|
2002
|
+
"name": "Updated Rate Sheet",
|
|
2003
|
+
"services": [
|
|
2004
|
+
{
|
|
2005
|
+
"id": ANY,
|
|
2006
|
+
"service_name": "Updated Service",
|
|
2007
|
+
"zone_ids": ["zone_1"],
|
|
2008
|
+
}
|
|
2009
|
+
],
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
ADD_SHARED_ZONE_RESPONSE = {
|
|
2016
|
+
"data": {
|
|
2017
|
+
"add_shared_zone": {
|
|
2018
|
+
"rate_sheet": {
|
|
2019
|
+
"id": ANY,
|
|
2020
|
+
"zones": [
|
|
2021
|
+
{
|
|
2022
|
+
"id": "zone_1",
|
|
2023
|
+
"label": "Zone 1",
|
|
2024
|
+
"country_codes": ["US"],
|
|
2025
|
+
},
|
|
2026
|
+
{
|
|
2027
|
+
"id": ANY,
|
|
2028
|
+
"label": "Zone 2",
|
|
2029
|
+
"country_codes": ["CA", "MX"],
|
|
2030
|
+
},
|
|
2031
|
+
],
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
UPDATE_SHARED_ZONE_RESPONSE = {
|
|
2038
|
+
"data": {
|
|
2039
|
+
"update_shared_zone": {
|
|
2040
|
+
"rate_sheet": {
|
|
2041
|
+
"id": ANY,
|
|
287
2042
|
"zones": [
|
|
288
2043
|
{
|
|
289
|
-
"
|
|
290
|
-
"label": "Updated Zone",
|
|
2044
|
+
"id": "zone_1",
|
|
2045
|
+
"label": "Updated Zone 1",
|
|
291
2046
|
"country_codes": ["US", "CA"],
|
|
292
|
-
}
|
|
2047
|
+
},
|
|
293
2048
|
],
|
|
294
2049
|
}
|
|
295
|
-
|
|
2050
|
+
}
|
|
296
2051
|
}
|
|
297
2052
|
}
|
|
298
2053
|
|
|
299
|
-
|
|
2054
|
+
ADD_SHARED_SURCHARGE_RESPONSE = {
|
|
300
2055
|
"data": {
|
|
301
|
-
"
|
|
2056
|
+
"add_shared_surcharge": {
|
|
302
2057
|
"rate_sheet": {
|
|
303
2058
|
"id": ANY,
|
|
304
|
-
"
|
|
305
|
-
|
|
2059
|
+
"surcharges": [
|
|
2060
|
+
{
|
|
2061
|
+
"id": "surch_fuel",
|
|
2062
|
+
"name": "Fuel Surcharge",
|
|
2063
|
+
"amount": 10.0,
|
|
2064
|
+
"surcharge_type": "percentage",
|
|
2065
|
+
"active": True,
|
|
2066
|
+
},
|
|
306
2067
|
{
|
|
307
2068
|
"id": ANY,
|
|
308
|
-
"
|
|
309
|
-
"
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
"rate": 20.0,
|
|
314
|
-
}
|
|
315
|
-
],
|
|
316
|
-
}
|
|
2069
|
+
"name": "Energy Surcharge",
|
|
2070
|
+
"amount": 2.5,
|
|
2071
|
+
"surcharge_type": "fixed",
|
|
2072
|
+
"active": True,
|
|
2073
|
+
},
|
|
317
2074
|
],
|
|
318
2075
|
}
|
|
319
2076
|
}
|
|
320
2077
|
}
|
|
321
2078
|
}
|
|
322
2079
|
|
|
323
|
-
|
|
2080
|
+
UPDATE_SERVICE_RATE_RESPONSE = {
|
|
324
2081
|
"data": {
|
|
325
|
-
"
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
2082
|
+
"update_service_rate": {
|
|
2083
|
+
"rate_sheet": {
|
|
2084
|
+
"id": ANY,
|
|
2085
|
+
"service_rates": [
|
|
2086
|
+
{
|
|
2087
|
+
"service_id": ANY,
|
|
2088
|
+
"zone_id": "zone_1",
|
|
2089
|
+
"rate": 15.0,
|
|
2090
|
+
"cost": 12.0,
|
|
2091
|
+
},
|
|
2092
|
+
],
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
331
2095
|
}
|
|
332
2096
|
}
|
|
333
2097
|
|
|
334
|
-
|
|
2098
|
+
UPDATE_SERVICE_ZONE_IDS_RESPONSE = {
|
|
335
2099
|
"data": {
|
|
336
|
-
"
|
|
2100
|
+
"update_service_zone_ids": {
|
|
337
2101
|
"rate_sheet": {
|
|
338
2102
|
"id": ANY,
|
|
339
2103
|
"services": [
|
|
340
2104
|
{
|
|
341
2105
|
"id": ANY,
|
|
342
|
-
"
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
2106
|
+
"zone_ids": ["zone_1", "zone_2"],
|
|
2107
|
+
},
|
|
2108
|
+
],
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
UPDATE_SERVICE_SURCHARGE_IDS_RESPONSE = {
|
|
2115
|
+
"data": {
|
|
2116
|
+
"update_service_surcharge_ids": {
|
|
2117
|
+
"rate_sheet": {
|
|
2118
|
+
"id": ANY,
|
|
2119
|
+
"services": [
|
|
2120
|
+
{
|
|
2121
|
+
"id": ANY,
|
|
2122
|
+
"surcharge_ids": ["surch_fuel", "surch_energy"],
|
|
2123
|
+
},
|
|
350
2124
|
],
|
|
351
2125
|
}
|
|
352
2126
|
}
|