@stamhoofd/backend 2.75.0 → 2.75.2

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.
@@ -1,6 +1,6 @@
1
1
  import { Request } from '@simonbackx/simple-endpoints';
2
- import { BalanceItemFactory, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, OrganizationRegistrationPeriod, Platform, RegistrationFactory, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
3
- import { AdministrationFeeSettings, BalanceItemCartItem, BalanceItemType, DefaultAgeGroup, FreeContributionSettings, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PlatformMembershipType, PlatformMembershipTypeConfig, ReceivableBalanceType, ReduceablePrice, RegisterItemOption, Version } from '@stamhoofd/structures';
2
+ import { BalanceItemFactory, GroupFactory, MemberFactory, MemberWithRegistrations, Organization, OrganizationFactory, OrganizationRegistrationPeriod, Platform, RegistrationPeriod, RegistrationPeriodFactory, Token, UserFactory } from '@stamhoofd/models';
3
+ import { AdministrationFeeSettings, BalanceItemCartItem, BalanceItemStatus, BalanceItemType, BooleanStatus, DefaultAgeGroup, FreeContributionSettings, GroupOption, GroupOptionMenu, IDRegisterCart, IDRegisterCheckout, IDRegisterItem, PaymentMethod, PermissionLevel, Permissions, PlatformMembershipType, PlatformMembershipTypeConfig, ReceivableBalanceType, ReduceablePrice, RegisterItemOption, Version } from '@stamhoofd/structures';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
5
  import { GetMemberFamilyEndpoint } from '../../src/endpoints/global/members/GetMemberFamilyEndpoint';
6
6
  import { RegisterMembersEndpoint } from '../../src/endpoints/global/registration/RegisterMembersEndpoint';
@@ -87,6 +87,7 @@ describe('E2E.Register', () => {
87
87
  const group = await new GroupFactory({
88
88
  organization,
89
89
  price: 25,
90
+ reducedPrice: 21,
90
91
  stock: 5,
91
92
  })
92
93
  .create();
@@ -152,10 +153,6 @@ describe('E2E.Register', () => {
152
153
  // #endregion
153
154
  });
154
155
 
155
- // todo: test max option + allowAmount
156
- // todo: test stock?
157
- // todo: test reduced price?
158
-
159
156
  test('Should create balance items for options', async () => {
160
157
  // #region arrange
161
158
  const { organization, group, groupPrice, token, member } = await initData();
@@ -492,19 +489,195 @@ describe('E2E.Register', () => {
492
489
  ]));
493
490
  // #endregion
494
491
  });
492
+
493
+ test('Should apply reduced price if member requires financial support', async () => {
494
+ // #region arrange
495
+ const { organization, group, groupPrice, token, member } = await initData();
496
+ member.details.requiresFinancialSupport = BooleanStatus.create({
497
+ value: true,
498
+ });
499
+
500
+ await member.save();
501
+
502
+ const body = IDRegisterCheckout.create({
503
+ cart: IDRegisterCart.create({
504
+ items: [
505
+ IDRegisterItem.create({
506
+ id: uuidv4(),
507
+ replaceRegistrationIds: [],
508
+ options: [],
509
+ groupPrice,
510
+ organizationId: organization.id,
511
+ groupId: group.id,
512
+ memberId: member.id,
513
+ }),
514
+ ],
515
+ balanceItems: [
516
+ ],
517
+ deleteRegistrationIds: [],
518
+ }),
519
+ administrationFee: 0,
520
+ freeContribution: 0,
521
+ paymentMethod: PaymentMethod.PointOfSale,
522
+ totalPrice: 21,
523
+ customer: null,
524
+ });
525
+ // #endregion
526
+
527
+ // #region act and assert
528
+ const balanceBefore = await getBalance(member.id, organization, token);
529
+ expect(balanceBefore).toBeDefined();
530
+ expect(balanceBefore.body.length).toBe(0);
531
+
532
+ await register(body, organization, token);
533
+
534
+ const balance = await getBalance(member.id, organization, token);
535
+ expect(balance).toBeDefined();
536
+ expect(balance.body.length).toBe(1);
537
+ expect(balance.body[0].price).toBe(21);
538
+ expect(balance.body[0].pricePaid).toBe(0);
539
+ // #endregion
540
+ });
541
+
542
+ test('Should apply reduced price for options if member requires financial support', async () => {
543
+ // #region arrange
544
+ const { organization, group, groupPrice, token, member } = await initData();
545
+ member.details.requiresFinancialSupport = BooleanStatus.create({
546
+ value: true,
547
+ });
548
+
549
+ await member.save();
550
+
551
+ const option1 = GroupOption.create({
552
+ name: 'option 1',
553
+ price: ReduceablePrice.create({
554
+ price: 5,
555
+ reducedPrice: 3,
556
+ }),
557
+ });
558
+
559
+ const option2 = GroupOption.create({
560
+ name: 'option 2',
561
+ price: ReduceablePrice.create({
562
+ price: 3,
563
+ reducedPrice: 1,
564
+ }),
565
+ });
566
+
567
+ const optionMenu = GroupOptionMenu.create({
568
+ name: 'option menu 1',
569
+ multipleChoice: true,
570
+ options: [option1, option2],
571
+ });
572
+
573
+ group.settings.optionMenus = [
574
+ optionMenu,
575
+ ];
576
+
577
+ await group.save();
578
+
579
+ const body = IDRegisterCheckout.create({
580
+ cart: IDRegisterCart.create({
581
+ items: [
582
+ IDRegisterItem.create({
583
+ id: uuidv4(),
584
+ replaceRegistrationIds: [],
585
+ options: [
586
+ RegisterItemOption.create({
587
+ option: option1,
588
+ amount: 2,
589
+ optionMenu,
590
+ }),
591
+ RegisterItemOption.create({
592
+ option: option2,
593
+ amount: 5,
594
+ optionMenu,
595
+ }),
596
+ ],
597
+ groupPrice,
598
+ organizationId: organization.id,
599
+ groupId: group.id,
600
+ memberId: member.id,
601
+ }),
602
+ ],
603
+ balanceItems: [
604
+ ],
605
+ deleteRegistrationIds: [],
606
+ }),
607
+ administrationFee: 0,
608
+ freeContribution: 0,
609
+ paymentMethod: PaymentMethod.PointOfSale,
610
+ totalPrice: 32,
611
+ customer: null,
612
+ });
613
+ // #endregion
614
+
615
+ // #region act and assert
616
+ const balanceBefore = await getBalance(member.id, organization, token);
617
+ expect(balanceBefore).toBeDefined();
618
+ expect(balanceBefore.body.length).toBe(0);
619
+
620
+ await register(body, organization, token);
621
+
622
+ const balance = await getBalance(member.id, organization, token);
623
+ expect(balance).toBeDefined();
624
+ expect(balance.body.length).toBe(3);
625
+ expect.arrayContaining([
626
+ expect.objectContaining({
627
+ price: 6,
628
+ pricePaid: 0,
629
+ status: BalanceItemStatus.Due,
630
+ }),
631
+ expect.objectContaining({
632
+ price: 5,
633
+ pricePaid: 0,
634
+ status: BalanceItemStatus.Due,
635
+ }),
636
+ expect.objectContaining({
637
+ price: 25,
638
+ pricePaid: 0,
639
+ status: BalanceItemStatus.Due,
640
+ }),
641
+ ]);
642
+ // #endregion
643
+ });
495
644
  });
496
645
 
497
646
  describe('Delete registrations', () => {
498
- // todo: should include call to other endpoints?
499
- test.skip('Should create negative balance items', async () => {
647
+ test('Should cancel balance item for deleted registration', async () => {
500
648
  // #region arrange
501
649
  const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
502
650
 
503
- const registration = await new RegistrationFactory({
504
- member,
505
- group: group1,
506
- groupPrice: groupPrice1,
507
- }).create();
651
+ const body1 = IDRegisterCheckout.create({
652
+ cart: IDRegisterCart.create({
653
+ items: [
654
+ IDRegisterItem.create({
655
+ id: uuidv4(),
656
+ replaceRegistrationIds: [],
657
+ options: [],
658
+ groupPrice: groupPrice1,
659
+ organizationId: organization.id,
660
+ groupId: group1.id,
661
+ memberId: member.id,
662
+ }),
663
+ ],
664
+ balanceItems: [
665
+ ],
666
+ deleteRegistrationIds: [],
667
+ }),
668
+ administrationFee: 0,
669
+ freeContribution: 0,
670
+ paymentMethod: PaymentMethod.PointOfSale,
671
+ totalPrice: 25,
672
+ customer: null,
673
+ asOrganizationId: organization.id,
674
+ });
675
+
676
+ const response1 = await register(body1, organization, token);
677
+ expect(response1.body).toBeDefined();
678
+ expect(response1.body.registrations.length).toBe(1);
679
+
680
+ const registrationToDelete = response1.body.registrations[0];
508
681
 
509
682
  const group = await new GroupFactory({
510
683
  organization,
@@ -514,7 +687,7 @@ describe('E2E.Register', () => {
514
687
 
515
688
  const groupPrice = group.settings.prices[0];
516
689
 
517
- const body = IDRegisterCheckout.create({
690
+ const body2 = IDRegisterCheckout.create({
518
691
  cart: IDRegisterCart.create({
519
692
  items: [
520
693
  IDRegisterItem.create({
@@ -527,31 +700,293 @@ describe('E2E.Register', () => {
527
700
  memberId: member.id,
528
701
  }),
529
702
  ],
530
- balanceItems: [],
531
- deleteRegistrationIds: [registration.id],
703
+ balanceItems: [
704
+ ],
705
+ deleteRegistrationIds: [registrationToDelete.id],
532
706
  }),
533
707
  administrationFee: 0,
534
708
  freeContribution: 0,
535
709
  paymentMethod: PaymentMethod.PointOfSale,
536
- totalPrice: 5,
537
- asOrganizationId: organization.id,
710
+ totalPrice: 30,
538
711
  customer: null,
712
+ asOrganizationId: organization.id,
539
713
  });
540
714
  // #endregion
541
715
 
542
716
  // #region act and assert
543
- const response = await register(body, organization, token);
717
+ const balanceBefore = await getBalance(member.id, organization, token);
718
+ expect(balanceBefore).toBeDefined();
719
+ expect(balanceBefore.body.length).toBe(1);
720
+ expect(balanceBefore.body[0].price).toBe(25);
721
+ expect(balanceBefore.body[0].pricePaid).toBe(0);
722
+
723
+ await register(body2, organization, token);
724
+
725
+ const balance = await getBalance(member.id, organization, token);
726
+ expect(balance).toBeDefined();
727
+ expect(balance.body.length).toBe(2);
544
728
 
545
- throw new Error('not implemented');
729
+ expect.arrayContaining([
730
+ expect.objectContaining({
731
+ price: 25,
732
+ pricePaid: 0,
733
+ status: BalanceItemStatus.Canceled,
734
+ }),
735
+ expect.objectContaining({
736
+ price: 30,
737
+ pricePaid: 0,
738
+ status: BalanceItemStatus.Due,
739
+ }),
740
+ ]);
546
741
  // #endregion
547
742
  });
548
743
 
549
- test.skip('Should apply cancelation fee', async () => {
550
- throw new Error('Not implemented');
744
+ test('Should cancel all related balance item for deleted registration', async () => {
745
+ // #region arrange
746
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
747
+
748
+ const option1 = GroupOption.create({
749
+ name: 'option 1',
750
+ price: ReduceablePrice.create({
751
+ price: 5,
752
+ reducedPrice: 3,
753
+ }),
754
+ });
755
+
756
+ const option2 = GroupOption.create({
757
+ name: 'option 2',
758
+ price: ReduceablePrice.create({
759
+ price: 3,
760
+ reducedPrice: 1,
761
+ }),
762
+ });
763
+
764
+ const optionMenu = GroupOptionMenu.create({
765
+ name: 'option menu 1',
766
+ multipleChoice: true,
767
+ options: [option1, option2],
768
+ });
769
+
770
+ group1.settings.optionMenus = [
771
+ optionMenu,
772
+ ];
773
+
774
+ await group1.save();
775
+
776
+ const body1 = IDRegisterCheckout.create({
777
+ cart: IDRegisterCart.create({
778
+ items: [
779
+ IDRegisterItem.create({
780
+ id: uuidv4(),
781
+ replaceRegistrationIds: [],
782
+ options: [
783
+ RegisterItemOption.create({
784
+ option: option1,
785
+ amount: 2,
786
+ optionMenu,
787
+ }),
788
+ RegisterItemOption.create({
789
+ option: option2,
790
+ amount: 5,
791
+ optionMenu,
792
+ }),
793
+ ],
794
+ groupPrice: groupPrice1,
795
+ organizationId: organization.id,
796
+ groupId: group1.id,
797
+ memberId: member.id,
798
+ }),
799
+ ],
800
+ balanceItems: [
801
+ ],
802
+ deleteRegistrationIds: [],
803
+ }),
804
+ administrationFee: 0,
805
+ freeContribution: 0,
806
+ paymentMethod: PaymentMethod.PointOfSale,
807
+ totalPrice: 50,
808
+ customer: null,
809
+ asOrganizationId: organization.id,
810
+ });
811
+
812
+ const response1 = await register(body1, organization, token);
813
+ expect(response1.body).toBeDefined();
814
+ expect(response1.body.registrations.length).toBe(1);
815
+
816
+ const registrationToDelete = response1.body.registrations[0];
817
+
818
+ const group = await new GroupFactory({
819
+ organization,
820
+ price: 30,
821
+ stock: 5,
822
+ }).create();
823
+
824
+ const groupPrice = group.settings.prices[0];
825
+
826
+ const body2 = IDRegisterCheckout.create({
827
+ cart: IDRegisterCart.create({
828
+ items: [
829
+ IDRegisterItem.create({
830
+ id: uuidv4(),
831
+ replaceRegistrationIds: [],
832
+ options: [],
833
+ groupPrice,
834
+ organizationId: organization.id,
835
+ groupId: group.id,
836
+ memberId: member.id,
837
+ }),
838
+ ],
839
+ balanceItems: [
840
+ ],
841
+ deleteRegistrationIds: [registrationToDelete.id],
842
+ }),
843
+ administrationFee: 0,
844
+ freeContribution: 0,
845
+ paymentMethod: PaymentMethod.PointOfSale,
846
+ totalPrice: 30,
847
+ customer: null,
848
+ asOrganizationId: organization.id,
849
+ });
850
+ // #endregion
851
+
852
+ // #region act and assert
853
+ const balanceBefore = await getBalance(member.id, organization, token);
854
+ expect(balanceBefore).toBeDefined();
855
+ expect(balanceBefore.body.length).toBe(3);
856
+
857
+ await register(body2, organization, token);
858
+
859
+ const balance = await getBalance(member.id, organization, token);
860
+ expect(balance).toBeDefined();
861
+ expect(balance.body.length).toBe(4);
862
+
863
+ expect.arrayContaining([
864
+ expect.objectContaining({
865
+ price: 10,
866
+ pricePaid: 0,
867
+ status: BalanceItemStatus.Canceled,
868
+ }),
869
+ expect.objectContaining({
870
+ price: 15,
871
+ pricePaid: 0,
872
+ status: BalanceItemStatus.Canceled,
873
+ }),
874
+ expect.objectContaining({
875
+ price: 25,
876
+ pricePaid: 0,
877
+ status: BalanceItemStatus.Canceled,
878
+ }),
879
+ expect.objectContaining({
880
+ price: 30,
881
+ pricePaid: 0,
882
+ status: BalanceItemStatus.Due,
883
+ }),
884
+ ]);
885
+ // #endregion
551
886
  });
552
887
 
553
- test.skip('Should fail if invalid cancelation fee', async () => {
554
- throw new Error('Not implemented');
888
+ test('Should apply cancelation fee', async () => {
889
+ // #region arrange
890
+ const { member, group: group1, groupPrice: groupPrice1, organization, token } = await initData();
891
+
892
+ const body1 = IDRegisterCheckout.create({
893
+ cart: IDRegisterCart.create({
894
+ items: [
895
+ IDRegisterItem.create({
896
+ id: uuidv4(),
897
+ replaceRegistrationIds: [],
898
+ options: [],
899
+ groupPrice: groupPrice1,
900
+ organizationId: organization.id,
901
+ groupId: group1.id,
902
+ memberId: member.id,
903
+ }),
904
+ ],
905
+ balanceItems: [
906
+ ],
907
+ deleteRegistrationIds: [],
908
+ }),
909
+ administrationFee: 0,
910
+ freeContribution: 0,
911
+ paymentMethod: PaymentMethod.PointOfSale,
912
+ totalPrice: 25,
913
+ customer: null,
914
+ asOrganizationId: organization.id,
915
+ });
916
+
917
+ const response1 = await register(body1, organization, token);
918
+ expect(response1.body).toBeDefined();
919
+ expect(response1.body.registrations.length).toBe(1);
920
+
921
+ const registrationToDelete = response1.body.registrations[0];
922
+
923
+ const group = await new GroupFactory({
924
+ organization,
925
+ price: 30,
926
+ stock: 5,
927
+ }).create();
928
+
929
+ const groupPrice = group.settings.prices[0];
930
+
931
+ const body2 = IDRegisterCheckout.create({
932
+ cart: IDRegisterCart.create({
933
+ items: [
934
+ IDRegisterItem.create({
935
+ id: uuidv4(),
936
+ replaceRegistrationIds: [],
937
+ options: [],
938
+ groupPrice,
939
+ organizationId: organization.id,
940
+ groupId: group.id,
941
+ memberId: member.id,
942
+ }),
943
+ ],
944
+ balanceItems: [
945
+ ],
946
+ deleteRegistrationIds: [registrationToDelete.id],
947
+ }),
948
+ administrationFee: 0,
949
+ freeContribution: 0,
950
+ paymentMethod: PaymentMethod.PointOfSale,
951
+ totalPrice: 30,
952
+ customer: null,
953
+ asOrganizationId: organization.id,
954
+ cancellationFeePercentage: 2000,
955
+ });
956
+ // #endregion
957
+
958
+ // #region act and assert
959
+ const balanceBefore = await getBalance(member.id, organization, token);
960
+ expect(balanceBefore).toBeDefined();
961
+ expect(balanceBefore.body.length).toBe(1);
962
+ expect(balanceBefore.body[0].price).toBe(25);
963
+ expect(balanceBefore.body[0].pricePaid).toBe(0);
964
+
965
+ await register(body2, organization, token);
966
+
967
+ const balance = await getBalance(member.id, organization, token);
968
+ expect(balance).toBeDefined();
969
+ expect(balance.body.length).toBe(3);
970
+
971
+ expect.arrayContaining([
972
+ expect.objectContaining({
973
+ price: 25,
974
+ pricePaid: 0,
975
+ status: BalanceItemStatus.Canceled,
976
+ }),
977
+ expect.objectContaining({
978
+ price: 30,
979
+ pricePaid: 0,
980
+ status: BalanceItemStatus.Due,
981
+ }),
982
+ expect.objectContaining({
983
+ price: 5,
984
+ pricePaid: 0,
985
+ type: BalanceItemType.CancellationFee,
986
+ status: BalanceItemStatus.Due,
987
+ }),
988
+ ]);
989
+ // #endregion
555
990
  });
556
991
  });
557
992