From 3b9fccff1ec55603c529824fcf1bb15858318f97 Mon Sep 17 00:00:00 2001 From: Koen Caerels Date: Sat, 20 Jan 2024 18:03:48 +0100 Subject: [PATCH] YK-70 + YK-45 --- .../Member/ChangeLicense/ChangeLicense.php | 53 +++++++ .../ChangeLicense/ChangeLicenseHandler.php | 145 ++++++++++++++++++ .../ChangeLicense/ChangeLicenseTrait.php | 38 +++++ .../YoshiKan/Application/MemberCommandBus.php | 2 + .../Application/Query/Member/GetMember.php | 3 +- .../Member/Readmodel/MemberSearchModel.php | 13 +- .../Controller/Routes/Member/MemberRoutes.php | 12 ++ .../src/api/command/changeMemberLicense.ts | 22 +++ .../src/api/query/searchMember.ts | 1 + .../src/components/member/memberBadge.vue | 4 +- .../src/components/member/memberList.vue | 30 +++- .../member/profile/profileDetail.vue | 83 +++++++++- .../changeSubscriptionForm.vue | 102 ++++++++++-- .../MemberModuleController.php | 1 + 14 files changed, 482 insertions(+), 27 deletions(-) create mode 100644 application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicense.php create mode 100644 application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseHandler.php create mode 100644 application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseTrait.php create mode 100644 frontends/member_module/src/api/command/changeMemberLicense.ts diff --git a/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicense.php b/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicense.php new file mode 100644 index 0000000..288bb4d --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicense.php @@ -0,0 +1,53 @@ +memberId, + $json->federationId, + ); + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getMemberId(): int + { + return $this->memberId; + } + + public function getFederationId(): int + { + return $this->federationId; + } +} diff --git a/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseHandler.php b/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseHandler.php new file mode 100644 index 0000000..b8c72be --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseHandler.php @@ -0,0 +1,145 @@ +memberRepository->getById($command->getMemberId()); + $federation = $this->federationRepository->getById($command->getFederationId()); + $settings = $this->settingsRepository->findByCode(SettingsCode::ACTIVE->value); + + $extraTraining = false; + if (3 === $member->getNumberOfTraining()) { + $extraTraining = true; + } + + // -- calculate the new license dates ------------------------------- + + $now = new \DateTimeImmutable(); + $licenseStart = $now->setDate((int) $now->format('Y'), (int) $now->format('m'), 1); + $licenseEnd = $licenseStart->modify('+1 year'); + + // -- create a new subscription ------------------------------------- + + $subscription = Subscription::make( + $this->subscriptionRepository->nextIdentity(), + $member->getContactFirstname(), + $member->getContactLastname(), + $member->getContactEmail(), + $member->getContactPhone(), + $member->getFirstname(), + $member->getLastname(), + $member->getDateOfBirth(), + $member->getGender(), + SubscriptionType::RENEWAL_LICENSE, + $member->getNumberOfTraining(), + $extraTraining, + false, + false, + false, + 'Wijziging vergunning naar '.$federation->getName(), + $member->getLocation(), + json_decode(json_encode(SettingsReadModel::hydrateFromModel($settings)), true), + $federation, + $member->getMemberSubscriptionStart(), + $member->getMemberSubscriptionEnd(), + 0, + false, + false, + true, + $licenseStart, + $licenseEnd, + $federation->getYearlySubscriptionFee(), + true, + false, + ); + + $subscription->setMember($member); + $subscription->changeStatus(SubscriptionStatus::AWAITING_PAYMENT); + $subscription->calculate(); + $this->subscriptionRepository->save($subscription); + $this->entityManager->flush(); + + // -- make some subscription lines ---------------------------------- + + $subscriptionItemFactory = new SubscriptionItemsFactory( + $this->subscriptionRepository, + $this->subscriptionItemRepository + ); + $resultItems = $subscriptionItemFactory->saveItemsFromSubscription( + $subscription, + $federation, + $settings + ); + + // -- flag new dates in the member ---------------------------------- + + $member->setLicenseDates( + $subscription->getLicenseStart(), + $subscription->getLicenseEnd() + ); + $member->syncFromSubscription( + federation: $federation, + numberOfTraining: $subscription->getNumberOfTraining(), + isHalfYearSubscription: $subscription->isMemberSubscriptionIsHalfYear(), + ); + + $this->memberRepository->save($member); + $this->entityManager->flush(); + + // -- compile a result class ---------------------------------------- + + $subscriptionId = $this->subscriptionRepository->getMaxId(); + $result = new \stdClass(); + $result->id = $subscriptionId; + $result->reference = 'YKS-'.$subscriptionId.': '.$member->getFirstname().' '.$member->getLastName(); + + return $result; + } +} diff --git a/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseTrait.php b/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseTrait.php new file mode 100644 index 0000000..b77b053 --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/ChangeLicense/ChangeLicenseTrait.php @@ -0,0 +1,38 @@ +permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $command = ChangeLicense::hydrateFromJson($jsonCommand); + $handler = new ChangeLicenseHandler( + memberRepository: $this->memberRepository, + subscriptionRepository: $this->subscriptionRepository, + subscriptionItemRepository: $this->subscriptionItemRepository, + federationRepository: $this->federationRepository, + locationRepository: $this->locationRepository, + settingsRepository: $this->settingsRepository, + entityManager: $this->entityManager, + ); + + $result = $handler->change($command); + $this->entityManager->flush(); + + return $result; + } +} diff --git a/application/YoshiKan/Application/MemberCommandBus.php b/application/YoshiKan/Application/MemberCommandBus.php index e394c68..9a812d5 100644 --- a/application/YoshiKan/Application/MemberCommandBus.php +++ b/application/YoshiKan/Application/MemberCommandBus.php @@ -21,6 +21,7 @@ use App\YoshiKan\Application\Command\Member\ChangeFederation\ChangeFederationTrait; use App\YoshiKan\Application\Command\Member\ChangeGrade\ChangeGradeTrait; use App\YoshiKan\Application\Command\Member\ChangeGroup\ChangeGroupTrait; +use App\YoshiKan\Application\Command\Member\ChangeLicense\ChangeLicenseTrait; use App\YoshiKan\Application\Command\Member\ChangeLocation\ChangeLocationTrait; use App\YoshiKan\Application\Command\Member\ChangeMemberDetails\ChangeMemberDetailsTrait; use App\YoshiKan\Application\Command\Member\ChangeMemberGrade\ChangeMemberGradeTrait; @@ -115,6 +116,7 @@ class MemberCommandBus use SendPaymentReceivedConfirmationMailTrait; use NewMemberSubscriptionMailTrait; use ChangeSubscriptionDetailsTrait; + use ChangeLicenseTrait; // -- member images --------------------------------------------------------- use UploadProfileImageTrait; diff --git a/application/YoshiKan/Application/Query/Member/GetMember.php b/application/YoshiKan/Application/Query/Member/GetMember.php index 6e6e469..b4b4db6 100644 --- a/application/YoshiKan/Application/Query/Member/GetMember.php +++ b/application/YoshiKan/Application/Query/Member/GetMember.php @@ -63,7 +63,8 @@ public function search(MemberSearchModel $searchModel): MemberReadModelCollectio $location, $grade, $minYearOfBirth, - $maxYearOfBirth + $maxYearOfBirth, + $searchModel->isActive(), ); // -- covert to readmodel collection ------------------------------------------ diff --git a/application/YoshiKan/Application/Query/Member/Readmodel/MemberSearchModel.php b/application/YoshiKan/Application/Query/Member/Readmodel/MemberSearchModel.php index c2ae6fe..5570694 100644 --- a/application/YoshiKan/Application/Query/Member/Readmodel/MemberSearchModel.php +++ b/application/YoshiKan/Application/Query/Member/Readmodel/MemberSearchModel.php @@ -25,6 +25,7 @@ private function __construct( protected int $gradeId, protected int $yearOfBirth, protected int $groupId, + protected ?bool $isActive = null, ) { } @@ -39,6 +40,7 @@ public static function hydrateFromJson(\stdClass $json): self $gradeId = 0; $yearOfBirth = 0; $groupId = 0; + $isActive = null; if (isset($json->locationId)) { $locationId = intval($json->locationId); } @@ -51,13 +53,17 @@ public static function hydrateFromJson(\stdClass $json): self if (isset($json->group)) { $groupId = intval($json->group->id); } + if (isset($json->isActive)) { + $isActive = boolval($json->isActive); + } return new self( $keyword, $locationId, $gradeId, $yearOfBirth, - $groupId + $groupId, + $isActive, ); } @@ -89,4 +95,9 @@ public function getGroupId(): int { return $this->groupId; } + + public function isActive(): ?bool + { + return $this->isActive; + } } diff --git a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php index 96849df..40b4dfb 100644 --- a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php +++ b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php @@ -145,6 +145,18 @@ public function extendMemberSubscription(int $id, Request $request): JsonRespons return new JsonResponse($response, 200, $this->apiAccess); } + #[Route('/mm/api/member/{id}/change-license', requirements: ['id' => '\d+'], methods: ['POST', 'PUT'])] + public function changeMemberLicense(int $id, Request $request): JsonResponse + { + $command = json_decode($request->request->get('command')); + $response = $this->commandBus->changeLicense($command); + + $result_mollie = $this->commandBus->createMolliePaymentLink($response->id); + $result_mail = $this->commandBus->sendMemberExtendSubscriptionMail($response->id); + + return new JsonResponse($response, 200, $this->apiAccess); + } + /** * @throws \Exception */ diff --git a/frontends/member_module/src/api/command/changeMemberLicense.ts b/frontends/member_module/src/api/command/changeMemberLicense.ts new file mode 100644 index 0000000..ff1e6e4 --- /dev/null +++ b/frontends/member_module/src/api/command/changeMemberLicense.ts @@ -0,0 +1,22 @@ +/* + * This file is part of the Yoshi-Kan software. + * + * (c) Koen Caerels + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import axios from "axios"; + +export interface ChangeMemberLicenseCommand { + memberId: number; + federationId: number; +} + +export async function changeMemberLicense(command: ChangeMemberLicenseCommand) { + const formData = new FormData(); + formData.append('command', JSON.stringify(command)); + const response= await axios.post(`/member/${command.memberId}/change-license`, formData); + return response.data; +} diff --git a/frontends/member_module/src/api/query/searchMember.ts b/frontends/member_module/src/api/query/searchMember.ts index e033f05..cce816c 100644 --- a/frontends/member_module/src/api/query/searchMember.ts +++ b/frontends/member_module/src/api/query/searchMember.ts @@ -15,6 +15,7 @@ export interface MemberSearchModel { grade?: Grade, yearOfBirth?: string, group?: Group, + isActive?: boolean, } export async function searchMembers(searchModel: MemberSearchModel) { diff --git a/frontends/member_module/src/components/member/memberBadge.vue b/frontends/member_module/src/components/member/memberBadge.vue index a79a6bd..d76b059 100644 --- a/frontends/member_module/src/components/member/memberBadge.vue +++ b/frontends/member_module/src/components/member/memberBadge.vue @@ -5,8 +5,8 @@ :style="'background-color: #'+member.grade.color">
- +
diff --git a/frontends/member_module/src/components/member/memberList.vue b/frontends/member_module/src/components/member/memberList.vue index 5ed3694..4eec60c 100644 --- a/frontends/member_module/src/components/member/memberList.vue +++ b/frontends/member_module/src/components/member/memberList.vue @@ -4,11 +4,22 @@
+ +
+
Status
+
+ +
+
+
Naam of lidnr.
-
@@ -135,7 +146,7 @@
 
-
Lidnr.
+
Lidnr.
Naam
Geboortedatum
Groep / Locatie
@@ -143,7 +154,7 @@
Graad
- +
({ grade: undefined, yearOfBirth: undefined, group: undefined, + isActive: undefined, }); const members = ref([]); const isSearching = ref(false); @@ -262,6 +274,12 @@ watch(counter, (): void => { void searchMemberHandler(); }); +const statusOptions = ref([ + {name: 'niet van toepassing', value: undefined}, + {name: 'Actief', value: true}, + {name: 'Archief', value: false,} +]); + function selectedClass(id: number) { let style = ''; if (id === memberStore.memberId) { @@ -281,7 +299,9 @@ function resetSearch() { keyword: '', locationId: undefined, grade: undefined, - yearOfBirth: undefined + yearOfBirth: undefined, + group: undefined, + isActive: undefined, } searchMemberHandler(); } diff --git a/frontends/member_module/src/components/member/profile/profileDetail.vue b/frontends/member_module/src/components/member/profile/profileDetail.vue index e7ad80d..f0923d5 100644 --- a/frontends/member_module/src/components/member/profile/profileDetail.vue +++ b/frontends/member_module/src/components/member/profile/profileDetail.vue @@ -81,6 +81,12 @@ class="p-button-sm p-button-secondary" icon="pi pi-send"/>
+
+
@@ -146,20 +152,54 @@ + +
+
+
naar
+
+
+ + + + +
+
+
+
+
+
+
+ diff --git a/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue b/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue index c68803c..eef8c50 100644 --- a/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue +++ b/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue @@ -250,7 +250,7 @@
+ class="flex flex-row border-t-[1px] border-b-[1px] border-gray-400 my-8 py-4">
Type vergunning *
@@ -267,7 +267,7 @@
-
+
-
-
-
- Vanaf +
+ + +
+
+
+ Vanaf +
+
+ + + + + +
+
+ / +
+
+ + + + + +
-
+
+ +
+
+
+ Vanaf +
+
-
-
- / -
-
+
+
+ / +
+
+
-
@@ -318,9 +354,16 @@ tot {{ memberSubscriptionEndMM }} / {{ memberSubscriptionEndYY }}
- Vergunning van - {{ licenseStartMM }} / {{ licenseStartYY }} - tot {{ licenseEndMM }} / {{ licenseEndYY }} +
+ Vergunning van + {{ command.licenseStartMM }} / {{ command.licenseStartYY }} + tot {{ licenseEndMM }} / {{ licenseEndYY }} +
+
+ Vergunning van + {{ licenseStartMM }} / {{ licenseStartYY }} + tot {{ licenseEndMM }} / {{ licenseEndYY }} +
@@ -576,6 +619,20 @@ const rules = { maxValueValue: maxValue(2400), memberSubscriptionDateValidator }, + licenseStartMM: { + required, + numeric, + maxValueValue: maxValue(12), + minValueValue: minValue(1), + memberSubscriptionDateValidator + }, + licenseStartYY: { + required, + numeric, + minValueValue: minValue(1900), + maxValueValue: maxValue(2400), + memberSubscriptionDateValidator + }, }; const new$ = useVuelidate(rules, command); @@ -678,6 +735,17 @@ const licenseEnd = computed((): Date => { 0, 0 ); + if (command.value.type === SubscriptionTypeEnum.RENEWAL_LICENSE) { + _startDate = new Date( + parseInt(command.value.licenseStartYY), + parseInt(command.value.licenseStartMM) - 1, + 1, + 8, + 0, + 0, + 0 + ); + } let _startDateMoment = moment(_startDate); let _endDateMoment = _startDateMoment.add(1, 'years'); command.value.licenseEnd = _endDateMoment.toDate(); @@ -732,7 +800,7 @@ const totalAmount = computed((): number => { command.value.memberSubscriptionTotal = Math.ceil(_totalMemberSubscription); command.value.licenseTotal = _totalLicense; - if(command.value.type === SubscriptionTypeEnum.RENEWAL_MEMBERSHIP) { + if (command.value.type === SubscriptionTypeEnum.RENEWAL_MEMBERSHIP) { command.value.total = Math.ceil(_totalMemberSubscription); } else if (command.value.type === SubscriptionTypeEnum.RENEWAL_LICENSE) { command.value.total = _totalLicense; diff --git a/src/AdminController/MemberModuleController.php b/src/AdminController/MemberModuleController.php index 84aaed7..f863de2 100644 --- a/src/AdminController/MemberModuleController.php +++ b/src/AdminController/MemberModuleController.php @@ -166,6 +166,7 @@ public function image_upload(Request $request): Response $searchModel->group = new \stdClass(); $searchModel->group->id = $groupId; $searchModel->locationId = $locationId; + $searchModel->isActive = true; $members = $queryBus->searchMembers($searchModel); } else { $members = new \stdClass();