karrio-server-graph 2025.5.4__py3-none-any.whl → 2025.5.6__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.4.dist-info → karrio_server_graph-2025.5.6.dist-info}/METADATA +1 -1
- {karrio_server_graph-2025.5.4.dist-info → karrio_server_graph-2025.5.6.dist-info}/RECORD +10 -10
- {karrio_server_graph-2025.5.4.dist-info → karrio_server_graph-2025.5.6.dist-info}/WHEEL +0 -0
- {karrio_server_graph-2025.5.4.dist-info → karrio_server_graph-2025.5.6.dist-info}/top_level.txt +0 -0
|
@@ -204,7 +204,11 @@ class RequestEmailChangeMutation(utils.BaseMutation):
|
|
|
204
204
|
expiry=(datetime.datetime.now() + datetime.timedelta(hours=2)),
|
|
205
205
|
)
|
|
206
206
|
except Exception as e:
|
|
207
|
-
logger.exception(
|
|
207
|
+
logger.exception(
|
|
208
|
+
"Email change request failed",
|
|
209
|
+
user_id=info.context.request.user.id,
|
|
210
|
+
error=str(e),
|
|
211
|
+
)
|
|
208
212
|
raise e
|
|
209
213
|
|
|
210
214
|
return RequestEmailChangeMutation(user=info.context.request.user) # type:ignore
|
|
@@ -263,7 +267,9 @@ class RegisterUserMutation(utils.BaseMutation):
|
|
|
263
267
|
|
|
264
268
|
return RegisterUserMutation(user=user) # type:ignore
|
|
265
269
|
except Exception as e:
|
|
266
|
-
logger.exception(
|
|
270
|
+
logger.exception(
|
|
271
|
+
"User registration failed", email=input.get("email"), error=str(e)
|
|
272
|
+
)
|
|
267
273
|
raise e
|
|
268
274
|
|
|
269
275
|
|
|
@@ -505,16 +511,24 @@ class CreateRateSheetMutation(utils.BaseMutation):
|
|
|
505
511
|
) -> "CreateRateSheetMutation":
|
|
506
512
|
data = input.copy()
|
|
507
513
|
carriers = data.pop("carriers", [])
|
|
514
|
+
zones_data = data.pop("zones", [])
|
|
515
|
+
surcharges_data = data.pop("surcharges", [])
|
|
516
|
+
service_rates_data = data.pop("service_rates", [])
|
|
517
|
+
services_data = [
|
|
518
|
+
(svc.copy() if isinstance(svc, dict) else dict(svc))
|
|
519
|
+
for svc in data.get("services", [])
|
|
520
|
+
]
|
|
521
|
+
|
|
508
522
|
slug = f"{input.get('name', '').lower()}_sheet".replace(" ", "").lower()
|
|
509
523
|
serializer = serializers.RateSheetModelSerializer(
|
|
510
524
|
data={**data, "slug": slug},
|
|
511
525
|
context=info.context.request,
|
|
512
526
|
)
|
|
513
|
-
|
|
514
527
|
serializer.is_valid(raise_exception=True)
|
|
515
528
|
rate_sheet = serializer.save()
|
|
516
529
|
|
|
517
|
-
|
|
530
|
+
# Create services and build temp-to-real ID mapping
|
|
531
|
+
if services_data:
|
|
518
532
|
save_many_to_many_data(
|
|
519
533
|
"services",
|
|
520
534
|
serializers.ServiceLevelModelSerializer,
|
|
@@ -522,16 +536,24 @@ class CreateRateSheetMutation(utils.BaseMutation):
|
|
|
522
536
|
payload=data,
|
|
523
537
|
context=info.context.request,
|
|
524
538
|
)
|
|
539
|
+
rate_sheet.refresh_from_db()
|
|
540
|
+
|
|
541
|
+
temp_to_real_id = serializer.build_temp_to_real_service_map(services_data)
|
|
525
542
|
|
|
543
|
+
# Link carriers
|
|
526
544
|
if any(carriers):
|
|
527
|
-
(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
)
|
|
545
|
+
providers.Carrier.access_by(info.context.request).filter(
|
|
546
|
+
carrier_code=rate_sheet.carrier_name,
|
|
547
|
+
id__in=carriers,
|
|
548
|
+
).update(rate_sheet=rate_sheet)
|
|
549
|
+
|
|
550
|
+
# Process zones, surcharges, and service_rates via serializer
|
|
551
|
+
if zones_data:
|
|
552
|
+
serializer.process_zones(zones_data)
|
|
553
|
+
if surcharges_data:
|
|
554
|
+
serializer.process_surcharges(surcharges_data)
|
|
555
|
+
if service_rates_data:
|
|
556
|
+
serializer.process_service_rates(service_rates_data, temp_to_real_id)
|
|
535
557
|
|
|
536
558
|
return CreateRateSheetMutation(rate_sheet=rate_sheet)
|
|
537
559
|
|
|
@@ -551,17 +573,17 @@ class UpdateRateSheetMutation(utils.BaseMutation):
|
|
|
551
573
|
)
|
|
552
574
|
data = input.copy()
|
|
553
575
|
carriers = data.pop("carriers", [])
|
|
576
|
+
|
|
554
577
|
serializer = serializers.RateSheetModelSerializer(
|
|
555
578
|
instance,
|
|
556
579
|
data=data,
|
|
557
580
|
context=info.context.request,
|
|
558
581
|
partial=True,
|
|
559
582
|
)
|
|
560
|
-
|
|
561
583
|
serializer.is_valid(raise_exception=True)
|
|
562
584
|
rate_sheet = serializer.save()
|
|
563
585
|
|
|
564
|
-
# Handle services updates
|
|
586
|
+
# Handle services updates
|
|
565
587
|
if "services" in data:
|
|
566
588
|
save_many_to_many_data(
|
|
567
589
|
"services",
|
|
@@ -571,25 +593,14 @@ class UpdateRateSheetMutation(utils.BaseMutation):
|
|
|
571
593
|
context=info.context.request,
|
|
572
594
|
)
|
|
573
595
|
|
|
596
|
+
# Link/unlink carriers
|
|
574
597
|
if any(carriers):
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
providers.Carrier.access_by(info.context.request)
|
|
578
|
-
.filter(
|
|
579
|
-
carrier_code=rate_sheet.carrier_name,
|
|
580
|
-
id__in=carriers,
|
|
581
|
-
)
|
|
582
|
-
.update(rate_sheet=rate_sheet)
|
|
598
|
+
carrier_qs = providers.Carrier.access_by(info.context.request).filter(
|
|
599
|
+
carrier_code=rate_sheet.carrier_name
|
|
583
600
|
)
|
|
584
|
-
|
|
585
|
-
(
|
|
586
|
-
|
|
587
|
-
.filter(
|
|
588
|
-
carrier_code=rate_sheet.carrier_name,
|
|
589
|
-
rate_sheet=rate_sheet,
|
|
590
|
-
)
|
|
591
|
-
.exclude(id__in=carriers)
|
|
592
|
-
.update(rate_sheet=None)
|
|
601
|
+
carrier_qs.filter(id__in=carriers).update(rate_sheet=rate_sheet)
|
|
602
|
+
carrier_qs.filter(rate_sheet=rate_sheet).exclude(id__in=carriers).update(
|
|
603
|
+
rate_sheet=None
|
|
593
604
|
)
|
|
594
605
|
|
|
595
606
|
return UpdateRateSheetMutation(
|
|
@@ -598,115 +609,317 @@ class UpdateRateSheetMutation(utils.BaseMutation):
|
|
|
598
609
|
|
|
599
610
|
|
|
600
611
|
@strawberry.type
|
|
601
|
-
class
|
|
612
|
+
class DeleteRateSheetServiceMutation(utils.BaseMutation):
|
|
602
613
|
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
603
614
|
|
|
604
615
|
@staticmethod
|
|
605
616
|
@transaction.atomic
|
|
606
617
|
@utils.authentication_required
|
|
607
618
|
def mutate(
|
|
608
|
-
info: Info, **input: inputs.
|
|
609
|
-
) -> "
|
|
619
|
+
info: Info, **input: inputs.DeleteRateSheetServiceMutationInput
|
|
620
|
+
) -> "DeleteRateSheetServiceMutation":
|
|
610
621
|
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
611
|
-
id=input["
|
|
622
|
+
id=input["rate_sheet_id"]
|
|
612
623
|
)
|
|
613
624
|
service = rate_sheet.services.get(id=input["service_id"])
|
|
614
625
|
|
|
626
|
+
# Remove service from rate sheet and delete it
|
|
627
|
+
rate_sheet.services.remove(service)
|
|
628
|
+
service.delete()
|
|
629
|
+
|
|
630
|
+
return DeleteRateSheetServiceMutation(rate_sheet=rate_sheet)
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
634
|
+
# SHARED ZONE MUTATIONS (Rate Sheet Level)
|
|
635
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
@strawberry.type
|
|
639
|
+
class AddSharedZoneMutation(utils.BaseMutation):
|
|
640
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
641
|
+
|
|
642
|
+
@staticmethod
|
|
643
|
+
@transaction.atomic
|
|
644
|
+
@utils.authentication_required
|
|
645
|
+
def mutate(
|
|
646
|
+
info: Info, **input: inputs.AddSharedZoneMutationInput
|
|
647
|
+
) -> "AddSharedZoneMutation":
|
|
648
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
649
|
+
id=input["rate_sheet_id"]
|
|
650
|
+
)
|
|
651
|
+
zone_data = input["zone"]
|
|
652
|
+
zone_dict = {k: v for k, v in zone_data.items() if not utils.is_unset(v)}
|
|
653
|
+
|
|
615
654
|
try:
|
|
616
|
-
|
|
617
|
-
zone_id=input["zone_id"], field=input["field"], value=input["value"]
|
|
618
|
-
)
|
|
655
|
+
rate_sheet.add_zone(zone_dict)
|
|
619
656
|
except ValueError as e:
|
|
620
|
-
|
|
621
|
-
raise exceptions.ValidationError({"zone_id": "invalid zone id"})
|
|
657
|
+
raise exceptions.ValidationError({"zone": str(e)})
|
|
622
658
|
|
|
623
|
-
return
|
|
659
|
+
return AddSharedZoneMutation(rate_sheet=rate_sheet)
|
|
624
660
|
|
|
625
661
|
|
|
626
662
|
@strawberry.type
|
|
627
|
-
class
|
|
663
|
+
class UpdateSharedZoneMutation(utils.BaseMutation):
|
|
628
664
|
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
629
665
|
|
|
630
666
|
@staticmethod
|
|
631
667
|
@transaction.atomic
|
|
632
668
|
@utils.authentication_required
|
|
633
669
|
def mutate(
|
|
634
|
-
info: Info, **input: inputs.
|
|
635
|
-
) -> "
|
|
670
|
+
info: Info, **input: inputs.UpdateSharedZoneMutationInput
|
|
671
|
+
) -> "UpdateSharedZoneMutation":
|
|
636
672
|
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
637
|
-
id=input["
|
|
673
|
+
id=input["rate_sheet_id"]
|
|
638
674
|
)
|
|
675
|
+
zone_data = input["zone"]
|
|
676
|
+
zone_dict = {k: v for k, v in zone_data.items() if not utils.is_unset(v)}
|
|
677
|
+
|
|
678
|
+
try:
|
|
679
|
+
rate_sheet.update_zone(input["zone_id"], zone_dict)
|
|
680
|
+
except ValueError as e:
|
|
681
|
+
raise exceptions.ValidationError({"zone_id": str(e)})
|
|
639
682
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
683
|
+
return UpdateSharedZoneMutation(rate_sheet=rate_sheet)
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
@strawberry.type
|
|
687
|
+
class DeleteSharedZoneMutation(utils.BaseMutation):
|
|
688
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
689
|
+
|
|
690
|
+
@staticmethod
|
|
691
|
+
@transaction.atomic
|
|
692
|
+
@utils.authentication_required
|
|
693
|
+
def mutate(
|
|
694
|
+
info: Info, **input: inputs.DeleteSharedZoneMutationInput
|
|
695
|
+
) -> "DeleteSharedZoneMutation":
|
|
696
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
697
|
+
id=input["rate_sheet_id"]
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
try:
|
|
701
|
+
rate_sheet.remove_zone(input["zone_id"])
|
|
702
|
+
except ValueError as e:
|
|
703
|
+
raise exceptions.ValidationError({"zone_id": str(e)})
|
|
704
|
+
|
|
705
|
+
return DeleteSharedZoneMutation(rate_sheet=rate_sheet)
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
709
|
+
# SHARED SURCHARGE MUTATIONS (Rate Sheet Level)
|
|
710
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
@strawberry.type
|
|
714
|
+
class AddSharedSurchargeMutation(utils.BaseMutation):
|
|
715
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
716
|
+
|
|
717
|
+
@staticmethod
|
|
718
|
+
@transaction.atomic
|
|
719
|
+
@utils.authentication_required
|
|
720
|
+
def mutate(
|
|
721
|
+
info: Info, **input: inputs.AddSharedSurchargeMutationInput
|
|
722
|
+
) -> "AddSharedSurchargeMutation":
|
|
723
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
724
|
+
id=input["rate_sheet_id"]
|
|
725
|
+
)
|
|
726
|
+
surcharge_data = input["surcharge"]
|
|
727
|
+
surcharge_dict = {k: v for k, v in surcharge_data.items() if not utils.is_unset(v)}
|
|
728
|
+
|
|
729
|
+
try:
|
|
730
|
+
rate_sheet.add_surcharge(surcharge_dict)
|
|
731
|
+
except ValueError as e:
|
|
732
|
+
raise exceptions.ValidationError({"surcharge": str(e)})
|
|
733
|
+
|
|
734
|
+
return AddSharedSurchargeMutation(rate_sheet=rate_sheet)
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
@strawberry.type
|
|
738
|
+
class UpdateSharedSurchargeMutation(utils.BaseMutation):
|
|
739
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
740
|
+
|
|
741
|
+
@staticmethod
|
|
742
|
+
@transaction.atomic
|
|
743
|
+
@utils.authentication_required
|
|
744
|
+
def mutate(
|
|
745
|
+
info: Info, **input: inputs.UpdateSharedSurchargeMutationInput
|
|
746
|
+
) -> "UpdateSharedSurchargeMutation":
|
|
747
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
748
|
+
id=input["rate_sheet_id"]
|
|
749
|
+
)
|
|
750
|
+
surcharge_data = input["surcharge"]
|
|
751
|
+
surcharge_dict = {k: v for k, v in surcharge_data.items() if not utils.is_unset(v)}
|
|
752
|
+
|
|
753
|
+
try:
|
|
754
|
+
rate_sheet.update_surcharge(input["surcharge_id"], surcharge_dict)
|
|
755
|
+
except ValueError as e:
|
|
756
|
+
raise exceptions.ValidationError({"surcharge_id": str(e)})
|
|
757
|
+
|
|
758
|
+
return UpdateSharedSurchargeMutation(rate_sheet=rate_sheet)
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
@strawberry.type
|
|
762
|
+
class DeleteSharedSurchargeMutation(utils.BaseMutation):
|
|
763
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
764
|
+
|
|
765
|
+
@staticmethod
|
|
766
|
+
@transaction.atomic
|
|
767
|
+
@utils.authentication_required
|
|
768
|
+
def mutate(
|
|
769
|
+
info: Info, **input: inputs.DeleteSharedSurchargeMutationInput
|
|
770
|
+
) -> "DeleteSharedSurchargeMutation":
|
|
771
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
772
|
+
id=input["rate_sheet_id"]
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
try:
|
|
776
|
+
rate_sheet.remove_surcharge(input["surcharge_id"])
|
|
777
|
+
except ValueError as e:
|
|
778
|
+
raise exceptions.ValidationError({"surcharge_id": str(e)})
|
|
779
|
+
|
|
780
|
+
return DeleteSharedSurchargeMutation(rate_sheet=rate_sheet)
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
@strawberry.type
|
|
784
|
+
class BatchUpdateSurchargesMutation(utils.BaseMutation):
|
|
785
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
786
|
+
|
|
787
|
+
@staticmethod
|
|
788
|
+
@transaction.atomic
|
|
789
|
+
@utils.authentication_required
|
|
790
|
+
def mutate(
|
|
791
|
+
info: Info, **input: inputs.BatchUpdateSurchargesMutationInput
|
|
792
|
+
) -> "BatchUpdateSurchargesMutation":
|
|
793
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
794
|
+
id=input["rate_sheet_id"]
|
|
795
|
+
)
|
|
796
|
+
surcharges = [
|
|
797
|
+
{k: v for k, v in s.items() if not utils.is_unset(v)}
|
|
798
|
+
for s in input["surcharges"]
|
|
799
|
+
]
|
|
800
|
+
|
|
801
|
+
try:
|
|
802
|
+
rate_sheet.batch_update_surcharges(surcharges)
|
|
803
|
+
except ValueError as e:
|
|
804
|
+
raise exceptions.ValidationError({"surcharges": str(e)})
|
|
805
|
+
|
|
806
|
+
return BatchUpdateSurchargesMutation(rate_sheet=rate_sheet)
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
810
|
+
# SERVICE RATE MUTATIONS (Service-Zone Rate Mapping)
|
|
811
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
@strawberry.type
|
|
815
|
+
class UpdateServiceRateMutation(utils.BaseMutation):
|
|
816
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
817
|
+
|
|
818
|
+
@staticmethod
|
|
819
|
+
@transaction.atomic
|
|
820
|
+
@utils.authentication_required
|
|
821
|
+
def mutate(
|
|
822
|
+
info: Info, **input: inputs.UpdateServiceRateMutationInput
|
|
823
|
+
) -> "UpdateServiceRateMutation":
|
|
824
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
825
|
+
id=input["rate_sheet_id"]
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
# Build the rate update dict from input fields
|
|
829
|
+
rate_data = {}
|
|
830
|
+
rate_fields = ["rate", "cost", "min_weight", "max_weight", "transit_days", "transit_time"]
|
|
831
|
+
for field in rate_fields:
|
|
832
|
+
if field in input and not utils.is_unset(input[field]):
|
|
833
|
+
rate_data[field] = input[field]
|
|
834
|
+
|
|
835
|
+
# Update or create the service-zone rate mapping
|
|
836
|
+
try:
|
|
837
|
+
rate_sheet.update_service_rate(
|
|
838
|
+
service_id=input["service_id"],
|
|
839
|
+
zone_id=input["zone_id"],
|
|
840
|
+
rate_data=rate_data
|
|
652
841
|
)
|
|
842
|
+
except ValueError as e:
|
|
843
|
+
raise exceptions.ValidationError({"rate": str(e)})
|
|
653
844
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
except Exception as e:
|
|
671
|
-
logger.error("Failed to batch update rate sheet", rate_sheet_id=input["id"], error=str(e))
|
|
672
|
-
raise exceptions.ValidationError(
|
|
673
|
-
{"rate_sheet": "failed to update rate sheet"}
|
|
674
|
-
)
|
|
675
|
-
else:
|
|
676
|
-
# Fall back to legacy per-service updates
|
|
677
|
-
for service_id, updates in service_updates.items():
|
|
678
|
-
try:
|
|
679
|
-
service = rate_sheet.services.get(id=service_id)
|
|
680
|
-
service.batch_update_cells(updates)
|
|
681
|
-
except ValueError as e:
|
|
682
|
-
logger.error("Failed to update service", service_id=service_id, error=str(e))
|
|
683
|
-
raise exceptions.ValidationError(
|
|
684
|
-
{"service_id": "failed to update service"}
|
|
685
|
-
)
|
|
845
|
+
return UpdateServiceRateMutation(rate_sheet=rate_sheet)
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
@strawberry.type
|
|
849
|
+
class BatchUpdateServiceRatesMutation(utils.BaseMutation):
|
|
850
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
851
|
+
|
|
852
|
+
@staticmethod
|
|
853
|
+
@transaction.atomic
|
|
854
|
+
@utils.authentication_required
|
|
855
|
+
def mutate(
|
|
856
|
+
info: Info, **input: inputs.BatchUpdateServiceRatesMutationInput
|
|
857
|
+
) -> "BatchUpdateServiceRatesMutation":
|
|
858
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
859
|
+
id=input["rate_sheet_id"]
|
|
860
|
+
)
|
|
686
861
|
|
|
687
|
-
|
|
862
|
+
# Convert rates to the format expected by batch_update_service_rates
|
|
863
|
+
# Format: [{'service_id': str, 'zone_id': str, 'rate': float, 'cost': float, ...}]
|
|
864
|
+
updates = []
|
|
865
|
+
|
|
866
|
+
for rate in input["rates"]:
|
|
867
|
+
rate_dict = {k: v for k, v in rate.items() if not utils.is_unset(v)}
|
|
868
|
+
updates.append(rate_dict)
|
|
869
|
+
|
|
870
|
+
try:
|
|
871
|
+
rate_sheet.batch_update_service_rates(updates)
|
|
872
|
+
except ValueError as e:
|
|
873
|
+
raise exceptions.ValidationError({"rates": str(e)})
|
|
874
|
+
|
|
875
|
+
return BatchUpdateServiceRatesMutation(rate_sheet=rate_sheet)
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
879
|
+
# SERVICE ZONE/SURCHARGE ASSIGNMENT MUTATIONS
|
|
880
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
688
881
|
|
|
689
882
|
|
|
690
883
|
@strawberry.type
|
|
691
|
-
class
|
|
884
|
+
class UpdateServiceZoneIdsMutation(utils.BaseMutation):
|
|
692
885
|
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
693
886
|
|
|
694
887
|
@staticmethod
|
|
695
888
|
@transaction.atomic
|
|
696
889
|
@utils.authentication_required
|
|
697
890
|
def mutate(
|
|
698
|
-
info: Info, **input: inputs.
|
|
699
|
-
) -> "
|
|
891
|
+
info: Info, **input: inputs.UpdateServiceZoneIdsMutationInput
|
|
892
|
+
) -> "UpdateServiceZoneIdsMutation":
|
|
700
893
|
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
701
894
|
id=input["rate_sheet_id"]
|
|
702
895
|
)
|
|
703
896
|
service = rate_sheet.services.get(id=input["service_id"])
|
|
704
897
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
service.delete()
|
|
898
|
+
service.zone_ids = input["zone_ids"]
|
|
899
|
+
service.save(update_fields=["zone_ids"])
|
|
708
900
|
|
|
709
|
-
return
|
|
901
|
+
return UpdateServiceZoneIdsMutation(rate_sheet=rate_sheet)
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
@strawberry.type
|
|
905
|
+
class UpdateServiceSurchargeIdsMutation(utils.BaseMutation):
|
|
906
|
+
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
907
|
+
|
|
908
|
+
@staticmethod
|
|
909
|
+
@transaction.atomic
|
|
910
|
+
@utils.authentication_required
|
|
911
|
+
def mutate(
|
|
912
|
+
info: Info, **input: inputs.UpdateServiceSurchargeIdsMutationInput
|
|
913
|
+
) -> "UpdateServiceSurchargeIdsMutation":
|
|
914
|
+
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
915
|
+
id=input["rate_sheet_id"]
|
|
916
|
+
)
|
|
917
|
+
service = rate_sheet.services.get(id=input["service_id"])
|
|
918
|
+
|
|
919
|
+
service.surcharge_ids = input["surcharge_ids"]
|
|
920
|
+
service.save(update_fields=["surcharge_ids"])
|
|
921
|
+
|
|
922
|
+
return UpdateServiceSurchargeIdsMutation(rate_sheet=rate_sheet)
|
|
710
923
|
|
|
711
924
|
|
|
712
925
|
@strawberry.type
|
|
@@ -736,7 +949,9 @@ class PartialShipmentMutation(utils.BaseMutation):
|
|
|
736
949
|
|
|
737
950
|
return PartialShipmentMutation(errors=None, shipment=update) # type:ignore
|
|
738
951
|
except Exception as e:
|
|
739
|
-
logger.exception(
|
|
952
|
+
logger.exception(
|
|
953
|
+
"Shipment mutation failed", shipment_id=input.get("id"), error=str(e)
|
|
954
|
+
)
|
|
740
955
|
raise e
|
|
741
956
|
|
|
742
957
|
|
|
@@ -934,30 +1149,6 @@ class SystemCarrierMutation(utils.BaseMutation):
|
|
|
934
1149
|
) # type: ignore
|
|
935
1150
|
|
|
936
1151
|
|
|
937
|
-
@strawberry.type
|
|
938
|
-
class UpdateServiceZoneMutation(utils.BaseMutation):
|
|
939
|
-
rate_sheet: typing.Optional[types.RateSheetType] = None
|
|
940
|
-
|
|
941
|
-
@staticmethod
|
|
942
|
-
@transaction.atomic
|
|
943
|
-
@utils.authentication_required
|
|
944
|
-
def mutate(
|
|
945
|
-
info: Info, **input: inputs.UpdateServiceZoneMutationInput
|
|
946
|
-
) -> "UpdateServiceZoneMutation":
|
|
947
|
-
rate_sheet = providers.RateSheet.access_by(info.context.request).get(
|
|
948
|
-
id=input["id"]
|
|
949
|
-
)
|
|
950
|
-
service = rate_sheet.services.get(id=input["service_id"])
|
|
951
|
-
|
|
952
|
-
serializer = serializers.ServiceLevelModelSerializer(
|
|
953
|
-
service,
|
|
954
|
-
context=info.context.request,
|
|
955
|
-
)
|
|
956
|
-
serializer.update_zone(input["zone_index"], input["zone"])
|
|
957
|
-
|
|
958
|
-
return UpdateServiceZoneMutation(rate_sheet=rate_sheet) # type:ignore
|
|
959
|
-
|
|
960
|
-
|
|
961
1152
|
@strawberry.type
|
|
962
1153
|
class CreateMetafieldMutation(utils.BaseMutation):
|
|
963
1154
|
metafield: typing.Optional[types.MetafieldType] = None
|