From b46a9ef2e350aa4e1aa2f0fd3978fd903791c59b Mon Sep 17 00:00:00 2001 From: Koen Caerels Date: Wed, 17 Jan 2024 11:58:03 +0100 Subject: [PATCH 1/6] Extra commando -> build all frontends. --- .github/workflows/php_build_and_qa_test.yml | 2 +- frontends/member_module/.env.development | 2 +- frontends/member_module/.env.production | 2 +- package.json | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/php_build_and_qa_test.yml b/.github/workflows/php_build_and_qa_test.yml index 2cecac4..b1ac54b 100644 --- a/.github/workflows/php_build_and_qa_test.yml +++ b/.github/workflows/php_build_and_qa_test.yml @@ -95,5 +95,5 @@ jobs: npm run build-only ## —— Testing ———————————————————————————————————————————————————————————— -# - name: Execute tests (Unit & Integration Tests) via PestPHP +# - name: Execute tests (Unit & Feature Tests) via PestPHP # run: ./vendor/bin/pest diff --git a/frontends/member_module/.env.development b/frontends/member_module/.env.development index 76a45ea..9506e47 100644 --- a/frontends/member_module/.env.development +++ b/frontends/member_module/.env.development @@ -1,2 +1,2 @@ VITE_API_URL=http://localhost.charlesproxy.com:8080/mm/api -VITE_VERSION=0.9.0 +VITE_VERSION=0.0.1 diff --git a/frontends/member_module/.env.production b/frontends/member_module/.env.production index 3320f62..8800d20 100644 --- a/frontends/member_module/.env.production +++ b/frontends/member_module/.env.production @@ -1,2 +1,2 @@ VITE_API_URL=/mm/api -VITE_VERSION=0.9.0 +VITE_VERSION=0.0.1 diff --git a/package.json b/package.json index c745906..e292d0e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "dev": "encore dev", "watch": "encore dev --watch", "build": "encore production --progress", - "cypress": "cypress open" + "cypress": "cypress open", + "build-admin": "rm -rf public/mm_module/assets/ && cd frontends/member_module && npm run build-only", + "build-all": "yarn build && yarn build-admin" }, "dependencies": { "@oruga-ui/oruga-next": "^0.5.9", From a09fc0ca213c47a0dbed3194ec7c4585cde662f4 Mon Sep 17 00:00:00 2001 From: Koen Caerels Date: Wed, 17 Jan 2024 14:28:46 +0100 Subject: [PATCH 2/6] Updated readme file. --- README.md | 18 ++++++++++++++++-- .../DatabaseModelFactory.php | 2 +- .../DatabaseTestCase.php | 2 +- .../Security/BasePermissionServiceTest.php | 4 ++-- 4 files changed, 20 insertions(+), 6 deletions(-) rename tests/{integration => Feature}/DatabaseModelFactory.php (83%) rename tests/{integration => Feature}/DatabaseTestCase.php (97%) rename tests/{integration/application => Feature/YoshiKan}/Application/Security/BasePermissionServiceTest.php (75%) diff --git a/README.md b/README.md index 1d9d840..16d5aaa 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Yoshi-Kan Website + Ledenbeheer --- -

+

GitHub license

@@ -12,7 +12,21 @@ Yoshi-Kan Website + Ledenbeheer ## Requirements -... +* A webserver (Apache, NGINX, ...) with PHP 8.2 or higher. +* [Symfony](https://symfony.com/): PHP 8.2 or higher and these PHP extensions (which are installed and enabled by default in most PHP 8 installations): +Ctype, iconv, PCRE, Session, SimpleXML, and Tokenizer. +* [Composer](https://getcomposer.org/download/), which is used to install PHP packages. +* A database server (MySQL, PostgreSQL, SQLite, ... ) that is compatible with [Doctrine](https://www.doctrine-project.org/). +* Node.js,Yarn & NPM for the frontends build process. + +### Third party services + +* https://www.resend.com/ for sending emails concerning the two factor authentication +* https://www.brevo.com/ for sending the transactional emails +* https://www.mollie.com/ for the online payment services +* https://www.sentry.io/ for error logging and monitoring + +You can configure these services in the `.env` file. ## Getting Started diff --git a/tests/integration/DatabaseModelFactory.php b/tests/Feature/DatabaseModelFactory.php similarity index 83% rename from tests/integration/DatabaseModelFactory.php rename to tests/Feature/DatabaseModelFactory.php index 7cb3d7a..00155a9 100644 --- a/tests/integration/DatabaseModelFactory.php +++ b/tests/Feature/DatabaseModelFactory.php @@ -1,6 +1,6 @@ Date: Thu, 18 Jan 2024 12:58:28 +0100 Subject: [PATCH 3/6] YK-59 / YK-68 / YK-65 --- .../Query/Member/GetSubscriptionTrait.php | 20 ++ .../Query/Member/PrintSubscriptions.php | 31 ++ .../pdf/empty_subscription_form.html.twig | 322 ++++++++++++++++++ .../Routes/Member/SubscriptionRoutes.php | 8 + .../member_module/src/views/DashboardView.vue | 21 +- public/inschrijven.png | Bin 0 -> 31340 bytes 6 files changed, 398 insertions(+), 4 deletions(-) create mode 100644 application/YoshiKan/Infrastructure/Templates/pdf/empty_subscription_form.html.twig create mode 100644 public/inschrijven.png diff --git a/application/YoshiKan/Application/Query/Member/GetSubscriptionTrait.php b/application/YoshiKan/Application/Query/Member/GetSubscriptionTrait.php index 6428f83..7f7e496 100644 --- a/application/YoshiKan/Application/Query/Member/GetSubscriptionTrait.php +++ b/application/YoshiKan/Application/Query/Member/GetSubscriptionTrait.php @@ -81,6 +81,7 @@ public function printSubscriptions(array $listIds): bool $this->locationRepository, $this->federationRepository, $this->subscriptionRepository, + $this->settingsRepository, $this->twig, $this->uploadFolder, $this->entityManager, @@ -90,4 +91,23 @@ public function printSubscriptions(array $listIds): bool return true; } + + public function printEmptySubscriptionForm(): bool + { + $this->permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $document = new PrintSubscriptions( + $this->locationRepository, + $this->federationRepository, + $this->subscriptionRepository, + $this->settingsRepository, + $this->twig, + $this->uploadFolder, + $this->entityManager, + ); + + $document->printEmptySubscriptionForm(); + + return true; + } } diff --git a/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php b/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php index 9a0d303..4771612 100644 --- a/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php +++ b/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php @@ -15,6 +15,8 @@ use App\YoshiKan\Domain\Model\Member\FederationRepository; use App\YoshiKan\Domain\Model\Member\LocationRepository; +use App\YoshiKan\Domain\Model\Member\SettingsCode; +use App\YoshiKan\Domain\Model\Member\SettingsRepository; use App\YoshiKan\Domain\Model\Member\Subscription; use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; use Doctrine\ORM\EntityManagerInterface; @@ -32,6 +34,7 @@ public function __construct( protected LocationRepository $locationRepository, protected FederationRepository $federationRepository, protected SubscriptionRepository $subscriptionRepository, + protected SettingsRepository $settingsRepository, protected Environment $twig, protected string $uploadFolder, protected EntityManagerInterface $entityManager, @@ -72,4 +75,32 @@ public function printOverview(array $listIds): void exit; } + + public function printEmptySubscriptionForm(): void + { + $settings = $this->settingsRepository->findByCode(SettingsCode::ACTIVE->value); + $federations = $this->federationRepository->getAll(); + $locations = $this->locationRepository->getAll(); + + $data = new \stdClass(); + $data->generatedOn = new \DateTimeImmutable(); + $data->settings = $settings; + $data->federations = $federations; + $data->locations = $locations; + + $pdfHtml = $this->twig->render('pdf/empty_subscription_form.html.twig', ['data' => $data]); + + $options = new Options(); + $options->set('isRemoteEnabled', true); + $options->set('isPhpEnabled', true); + $dompdf = new Dompdf($options); + $dompdf->loadHtml($pdfHtml); + $dompdf->setPaper('A4', 'portrait'); + $dompdf->render(); + + $fileName = $data->generatedOn->format('YmdHis').'_yoshikan_inschrijving_formulier.pdf'; + $dompdf->stream($fileName, ['Attachment' => false]); + + exit; + } } diff --git a/application/YoshiKan/Infrastructure/Templates/pdf/empty_subscription_form.html.twig b/application/YoshiKan/Infrastructure/Templates/pdf/empty_subscription_form.html.twig new file mode 100644 index 0000000..a3f7bae --- /dev/null +++ b/application/YoshiKan/Infrastructure/Templates/pdf/empty_subscription_form.html.twig @@ -0,0 +1,322 @@ +{# #} +{# 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. #} +{# #} + + + + + + + +{# ------------------------------------------------------------------------------------------------------------------ #} + + + + + + + {# right side of the template -------------------------------------------- #} + + +
+ + + + + +
+ Datum +

.......... / ........... / ..............

+
+ Plaats  +

........................................................

+
+ + + + + + + + + + + + + + + + + + + + + +
Naam +

+ ..............................................................................................

+
Voornaam +

+ ...............................................................................................

+
Geb.datum +

+ ........ / ........ / .............. + +          + O    M       + O    V       + O    X + +

+


Adres
+

Straat: + ...................................................................................

+

Postcode: + .............................................................................

+

Gemeente: + ............................................................................

+

Contact (ouder)
+

Naam: + ..................................................................................

+

Email: + ...................................................................................

+

Telefoon: + .............................................................................

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Locatie +

+ {% for location in data.locations %} + O   + {{ location.name }} +    + {% endfor %} +

+
Vergunning +

+ {% for federation in data.federations %} + O    + {{ federation.name }} +      {{ federation.yearlySubscriptionFee }} € +       + {% endfor %} +

+
Welkomspakket +

+ O    + Judogids, judopaspoort, leskaart en sportzak +    {{ data.settings.newMemberSubscriptionFee }} € +

+
Frequentie +

+        +        +        +        +        +        +       + Halfjaarlijks +        +    + Jaarlijks +

+

+ O    + 1 x per week +        +        + {{ data.settings.halfYearlyFee1Training }} € +              + {{ data.settings.yearlyFee1Training }} € +       +

+

+ O    + 2 x per week +        +        + {{ data.settings.halfYearlyFee2Training }} € +              + {{ data.settings.yearlyFee2Training }} € +       +

+

+ O    + 3-5 x per week +             +             +             +         +         + + {{ data.settings.extraTrainingFee }} € +       +

+
Gezinskorting +

+ O    + + 2e en 3e kind van éénzelfde familie geniet {{ data.settings.familyDiscount }}% korting + op lidgeld +

+
Opmerkingen +

Judopak : + ..................................................................................

+

Gordel : + .....................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+

+ ...................................................................................................

+
+ +
+ + + + +
+
Inschrijven kan ook online via onze website: +
https://www.yoshikan.be/inschrijven +


+
+ +
+
+ +
+ JC Yoshi-Kan v.z.w. +
+
+
Secr: Spekstraat 80 +
2220 Heist o/d Berg +
+
+ G  0474 51 13 98 +
E  judo.yoshikan@gmail.com +
+
+
IBAN: BE37 7330 0101 8328 +
BIC: KRED BE BB +
+
+
+ + Totaal:       + +

....................... €

+ +
+
+
+ Handtekening ouder of voogd: +


  +
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+ Door het ondertekenen of het uitvoeren van de betaling, gaat U akkoord met ons + reglement en privacy verklaring, terug te vinden op onze website + www.yoshikan.be +
+
+
+ +
+ + + diff --git a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/SubscriptionRoutes.php b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/SubscriptionRoutes.php index 4b4b9a4..dff0e74 100644 --- a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/SubscriptionRoutes.php +++ b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/SubscriptionRoutes.php @@ -102,6 +102,14 @@ public function printSubscriptions(Request $request): void exit; } + #[Route('/mm/api/subscriptions/print/empty', methods: ['GET'])] + public function printEmptySubscriptionsForm(Request $request): void + { + $document = $this->queryBus->printEmptySubscriptionForm(); + + exit; + } + private function convertToArrayOfIds(string $ids): array { $arListIdsInt = []; diff --git a/frontends/member_module/src/views/DashboardView.vue b/frontends/member_module/src/views/DashboardView.vue index 3923486..fac4dda 100644 --- a/frontends/member_module/src/views/DashboardView.vue +++ b/frontends/member_module/src/views/DashboardView.vue @@ -2,6 +2,14 @@
+ +
+
+

Algemeen

{{appStore.dashboardNumbers.activePeriod.name}}

@@ -71,12 +79,13 @@
- - - +
@@ -118,6 +127,10 @@ function downloadMemberListAsExcel(locationId) { window.open(url, '_blank'); } +function downloadEmptySubscriptionForm() { + let url = apiUrl + '/subscriptions/print/empty'; + window.open(url, '_blank'); +} const subscriptionCounter = computed((): number => memberStore.refreshCounter); watch(subscriptionCounter, (): void => { diff --git a/public/inschrijven.png b/public/inschrijven.png new file mode 100644 index 0000000000000000000000000000000000000000..728188ffdd1c74dc16942e25caddce96f5a35a46 GIT binary patch literal 31340 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 literal 0 HcmV?d00001 From 60ebf2c32c82f02c28bf4ae26e754c837bf22965 Mon Sep 17 00:00:00 2001 From: Koen Caerels Date: Sat, 20 Jan 2024 13:34:58 +0100 Subject: [PATCH 4/6] YK-69 Wijzigen inschrijving nadat alles verstuurd is geweest. --- .../Common/SubscriptionItemsFactory.php | 13 + .../ChangeSubscriptionDetails.php | 338 ++++++++ .../ChangeSubscriptionDetailsHandler.php | 199 +++++ .../ChangeSubscriptionDetailsTrait.php | 44 + .../CreateMolliePaymentLinkHandler.php | 5 +- .../NewMemberSubscriptionMail.php | 6 + .../NewMemberSubscriptionMailHandler.php | 34 +- .../NewMemberSubscriptionMailTrait.php | 5 +- .../YoshiKan/Application/MemberCommandBus.php | 2 + .../Domain/Model/Member/Subscription.php | 5 + ...member_changed_subscription_mail.html.twig | 97 +++ .../Controller/Routes/Member/MemberRoutes.php | 13 + .../subscription/changeSubscription.ts | 75 ++ .../changeSubscriptionForm.vue | 756 ++++++++++++++++++ .../changeSubscriptionFormOverview.vue | 182 +++++ .../detail/subscriptionDetail.vue | 34 +- .../overview/overviewSubscriptionsTable.vue | 1 + .../reviewNewMember/reviewNewMemberForm.vue | 4 - 18 files changed, 1792 insertions(+), 21 deletions(-) create mode 100644 application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetails.php create mode 100644 application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsHandler.php create mode 100644 application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsTrait.php create mode 100644 application/YoshiKan/Infrastructure/Templates/mail/member_changed_subscription_mail.html.twig create mode 100644 frontends/member_module/src/api/command/subscription/changeSubscription.ts create mode 100644 frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue create mode 100644 frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionFormOverview.vue diff --git a/application/YoshiKan/Application/Command/Common/SubscriptionItemsFactory.php b/application/YoshiKan/Application/Command/Common/SubscriptionItemsFactory.php index c274208..aa8057f 100644 --- a/application/YoshiKan/Application/Command/Common/SubscriptionItemsFactory.php +++ b/application/YoshiKan/Application/Command/Common/SubscriptionItemsFactory.php @@ -29,6 +29,19 @@ public function __construct( ) { } + public function resetItemsFromSubscription(Subscription $subscription): bool + { + $subscription = $this->subscriptionRepository->getById($subscription->getId()); + $items = $this->subscriptionItemRepository->getBySubscription($subscription); + foreach ($items as $item) { + $this->subscriptionItemRepository->delete($item); + } + $subscription->clearItems(); + $this->subscriptionRepository->save($subscription); + + return true; + } + public function saveItemsFromSubscription( Subscription $subscription, Federation $federation, diff --git a/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetails.php b/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetails.php new file mode 100644 index 0000000..41a14fa --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetails.php @@ -0,0 +1,338 @@ +subscriptionId), + intval($json->memberId), + trim($json->type), + intval($json->federationId), + intval($json->locationId), + trim($json->contactFirstname), + trim($json->contactLastname), + trim($json->contactEmail), + trim($json->contactPhone), + trim($json->addressStreet), + trim($json->addressNumber), + trim($json->addressBox), + trim($json->addressZip), + trim($json->addressCity), + trim($json->firstname), + trim($json->lastname), + trim($json->email), + '', + new \DateTimeImmutable($json->dateOfBirth), + trim($json->gender), + new \DateTimeImmutable($json->memberSubscriptionStart), + trim($json->memberSubscriptionStartMM), + trim($json->memberSubscriptionStartYY), + new \DateTimeImmutable($json->memberSubscriptionEnd), + floatval($json->memberSubscriptionTotal), + boolval($json->memberSubscriptionIsPartSubscription), + boolval($json->memberSubscriptionIsHalfYear), + boolval($json->memberSubscriptionIsPayed), + new \DateTimeImmutable($json->licenseStart), + trim($json->licenseStartMM), + trim($json->licenseStartYY), + new \DateTimeImmutable($json->licenseEnd), + floatval($json->licenseTotal), + boolval($json->licenseIsPartSubscription), + boolval($json->licenseIsPayed), + intval($json->numberOfTraining), + boolval($json->isExtraTraining), + boolval($json->isReductionFamily), + floatval($json->total), + trim($json->remarks), + boolval($json->isJudogiBelt), + ); + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getType(): string + { + return $this->type; + } + + public function getFederationId(): int + { + return $this->federationId; + } + + public function getLocationId(): int + { + return $this->locationId; + } + + public function getContactFirstname(): string + { + return $this->contactFirstname; + } + + public function getContactLastname(): string + { + return $this->contactLastname; + } + + public function getContactEmail(): string + { + return $this->contactEmail; + } + + public function getContactPhone(): string + { + return $this->contactPhone; + } + + public function getAddressStreet(): string + { + return $this->addressStreet; + } + + public function getAddressNumber(): string + { + return $this->addressNumber; + } + + public function getAddressBox(): string + { + return $this->addressBox; + } + + public function getAddressZip(): string + { + return $this->addressZip; + } + + public function getAddressCity(): string + { + return $this->addressCity; + } + + public function getFirstname(): string + { + return $this->firstname; + } + + public function getLastname(): string + { + return $this->lastname; + } + + public function getEmail(): string + { + return $this->email; + } + + public function getNationalRegisterNumber(): string + { + return $this->nationalRegisterNumber; + } + + public function getDateOfBirth(): \DateTimeImmutable + { + return $this->dateOfBirth; + } + + public function getGender(): string + { + return $this->gender; + } + + public function getMemberSubscriptionStart(): \DateTimeImmutable + { + return $this->memberSubscriptionStart; + } + + public function getMemberSubscriptionStartMM(): string + { + return $this->memberSubscriptionStartMM; + } + + public function getMemberSubscriptionStartYY(): string + { + return $this->memberSubscriptionStartYY; + } + + public function getMemberSubscriptionEnd(): \DateTimeImmutable + { + return $this->memberSubscriptionEnd; + } + + public function getMemberSubscriptionTotal(): float + { + return $this->memberSubscriptionTotal; + } + + public function getLicenseStart(): \DateTimeImmutable + { + return $this->licenseStart; + } + + public function getLicenseStartMM(): string + { + return $this->licenseStartMM; + } + + public function getLicenseStartYY(): string + { + return $this->licenseStartYY; + } + + public function getLicenseEnd(): \DateTimeImmutable + { + return $this->licenseEnd; + } + + public function getLicenseTotal(): float + { + return $this->licenseTotal; + } + + public function isLicenseIsPartSubscription(): bool + { + return $this->licenseIsPartSubscription; + } + + public function isLicenseIsPayed(): bool + { + return $this->licenseIsPayed; + } + + public function getNumberOfTraining(): int + { + return $this->numberOfTraining; + } + + public function isExtraTraining(): bool + { + return $this->isExtraTraining; + } + + public function isReductionFamily(): bool + { + return $this->isReductionFamily; + } + + public function getTotal(): float + { + return $this->total; + } + + public function getRemarks(): string + { + return $this->remarks; + } + + public function isJudogiBelt(): bool + { + return $this->isJudogiBelt; + } + + public function isMemberSubscriptionIsPartSubscription(): bool + { + return $this->memberSubscriptionIsPartSubscription; + } + + public function isMemberSubscriptionIsHalfYear(): bool + { + return $this->memberSubscriptionIsHalfYear; + } + + public function isMemberSubscriptionIsPayed(): bool + { + return $this->memberSubscriptionIsPayed; + } + + public function getSubscriptionId(): int + { + return $this->subscriptionId; + } + + public function getMemberId(): int + { + return $this->memberId; + } +} diff --git a/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsHandler.php b/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsHandler.php new file mode 100644 index 0000000..23152ef --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsHandler.php @@ -0,0 +1,199 @@ +federationRepository->getById($command->getFederationId()); + $location = $this->locationRepository->getById($command->getLocationId()); + $settings = $this->settingsRepository->findByCode(SettingsCode::ACTIVE->value); + $subscription = $this->subscriptionRepository->getById($command->getSubscriptionId()); + $oldTotal = $subscription->getTotal(); + + // -- validate the command ---------------------------------------- + $commandIsValid = $this->isCommandValid($command, $settings); + if (!$commandIsValid) { + throw new \Exception('Membership change command is not valid.'); + } + + if (SubscriptionStatus::PAYED === $subscription->getStatus()) { + throw new \Exception('Membership change command is not possible .'); + } + if (SubscriptionStatus::COMPLETE === $subscription->getStatus()) { + throw new \Exception('Membership change command is not possible .'); + } + if (SubscriptionStatus::ARCHIVED === $subscription->getStatus()) { + throw new \Exception('Membership change command is not possible .'); + } + + $subscription->fullChange( + contactFirstname: $command->getContactFirstname(), + contactLastname: $command->getContactLastname(), + contactEmail: $command->getContactEmail(), + contactPhone: $command->getContactPhone(), + firstname: $command->getFirstname(), + lastname: $command->getLastname(), + dateOfBirth: $command->getDateOfBirth(), + gender: Gender::from($command->getGender()), + type: SubscriptionType::from($command->getType()), + numberOfTraining: $command->getNumberOfTraining(), + isExtraTraining: $command->isExtraTraining(), + isNewMember: $subscription->isNewMember(), + isReductionFamily: $command->isReductionFamily(), + isJudogiBelt: $command->isJudogiBelt(), + remarks: $command->getRemarks(), + location: $location, + federation: $federation, + memberSubscriptionStart: $command->getMemberSubscriptionStart(), + memberSubscriptionEnd: $command->getMemberSubscriptionEnd(), + memberSubscriptionTotal: $command->getMemberSubscriptionTotal(), + memberSubscriptionIsPartSubscription: $subscription->isMemberSubscriptionIsPartSubscription(), + memberSubscriptionIsHalfYear: $command->isMemberSubscriptionIsHalfYear(), + memberSubscriptionIsPayed: $subscription->isMemberSubscriptionIsPayed(), + licenseStart: $command->getLicenseStart(), + licenseEnd: $command->getLicenseEnd(), + licenseTotal: $command->getLicenseTotal(), + licenseIsPartSubscription: $subscription->isLicenseIsPartSubscription(), + licenseIsPayed: $subscription->isLicenseIsPayed(), + ); + $subscription->setNewMemberFields( + nationalRegisterNumber: $command->getNationalRegisterNumber(), + addressStreet: $command->getAddressStreet(), + addressNumber: $command->getAddressNumber(), + addressBox: $command->getAddressBox(), + addressZip: $command->getAddressZip(), + addressCity: $command->getAddressCity(), + ); + + $this->subscriptionRepository->save($subscription); + $this->entityManager->flush(); + + if (0 !== $command->getMemberId()) { + // -- update the member fields -------------------------------- + $member = $this->memberRepository->getById($command->getMemberId()); + + // -- set contact info ---------------------------------------- + $member->setContactInformation( + contactFirstname: $subscription->getContactFirstname(), + contactLastname: $subscription->getContactLastname(), + contactEmail: $subscription->getContactEmail(), + contactPhone: $subscription->getContactPhone() + ); + // -- set subscription dates ---------------------------------- + $member->setSubscriptionDates( + start: $subscription->getMemberSubscriptionStart(), + end: $subscription->getMemberSubscriptionEnd(), + isHalfYearSubscription: $subscription->isMemberSubscriptionIsHalfYear() + ); + // -- set license dates --------------------------------------- + $member->setLicenseDates( + start: $subscription->getLicenseStart(), + end: $subscription->getLicenseEnd() + ); + + // -- save and connect the member ----------------------------- + $this->memberRepository->save($member); + $subscription->setMember($member); + $this->subscriptionRepository->save($subscription); + } + + // -- recalculate subscription and send new mollie link if needed ---- + $subscription->calculate(); + $this->subscriptionRepository->save($subscription); + $this->entityManager->flush(); + + // -- make some new subscription lines --------------------------------- + $subscriptionItemFactory = new SubscriptionItemsFactory( + $this->subscriptionRepository, + $this->subscriptionItemRepository + ); + $resultClearItems = $subscriptionItemFactory->resetItemsFromSubscription($subscription); + $this->entityManager->flush(); + $resultItems = $subscriptionItemFactory->saveItemsFromSubscription( + $subscription, + $federation, + $settings + ); + + $this->subscriptionRepository->save($subscription); + $this->entityManager->flush(); + + // -- make a new mollie link for online payment ---------------- + + if ($oldTotal !== $subscription->getTotal()) { + $mollieCommand = CreateMolliePaymentLink::make($subscription->getId()); + $mollieCommandHandler = new CreateMolliePaymentLinkHandler( + $this->subscriptionRepository, + $this->mollieConfig, + ); + $resultMollie = $mollieCommandHandler->create($mollieCommand, true); + $this->entityManager->flush(); + } + + // -- compile a result class for giving feedback -------------------- + $result = new \stdClass(); + $result->id = $subscription->getId(); + $result->reference = 'YKS-'.$subscription->getId().': '.$command->getFirstName().' '.$command->getLastName(); + + return $result; + } + + private function isCommandValid(ChangeSubscriptionDetails $command, Settings $settings): bool + { + return true; + } +} diff --git a/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsTrait.php b/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsTrait.php new file mode 100644 index 0000000..7e5021d --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/ChangeSubscriptionDetails/ChangeSubscriptionDetailsTrait.php @@ -0,0 +1,44 @@ +permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $handler = new ChangeSubscriptionDetailsHandler( + $this->federationRepository, + $this->locationRepository, + $this->settingsRepository, + $this->memberRepository, + $this->gradeRepository, + $this->subscriptionRepository, + $this->subscriptionItemRepository, + $this->mollieConfig, + $this->entityManager, + ); + + $result = $handler->change($command); + $this->entityManager->flush(); + + return $result; + } +} diff --git a/application/YoshiKan/Application/Command/Member/CreateMolliePaymentLink/CreateMolliePaymentLinkHandler.php b/application/YoshiKan/Application/Command/Member/CreateMolliePaymentLink/CreateMolliePaymentLinkHandler.php index 57a83ef..1bfcc7c 100644 --- a/application/YoshiKan/Application/Command/Member/CreateMolliePaymentLink/CreateMolliePaymentLinkHandler.php +++ b/application/YoshiKan/Application/Command/Member/CreateMolliePaymentLink/CreateMolliePaymentLinkHandler.php @@ -25,12 +25,13 @@ public function __construct( ) { } - public function create(CreateMolliePaymentLink $command): bool + public function create(CreateMolliePaymentLink $command, bool $force = false): bool { $subscription = $this->subscriptionRepository->getById($command->getSubscriptionId()); // -- link already created - if (!(0 === mb_strlen($subscription->getPaymentId()))) { + + if (!$force && !(0 === mb_strlen($subscription->getPaymentId()))) { return false; } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMail.php b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMail.php index ea27fbe..150417d 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMail.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMail.php @@ -23,6 +23,7 @@ public function __construct( protected int $subscriptionId, protected string $fromName, protected string $fromEmail, + protected bool $isChange = false, ) { } @@ -44,4 +45,9 @@ public function getFromEmail(): string { return $this->fromEmail; } + + public function isChange(): bool + { + return $this->isChange; + } } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailHandler.php b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailHandler.php index 507f932..24b2672 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailHandler.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailHandler.php @@ -56,16 +56,30 @@ public function go(NewMemberSubscriptionMail $command): bool { $subscription = $this->subscriptionRepository->getById($command->getSubscriptionId()); $items = $this->subscriptionItemRepository->getBySubscription($subscription); - $subject = 'JC Yoshi-Kan: Nieuwe inschrijving voor '.$subscription->getFirstname().' '.$subscription->getLastname(); - $mailTemplate = $this->twig->render( - 'mail/member_newMemberSubscription_mail.html.twig', - [ - 'subject' => $subject, - 'subscription' => $subscription, - 'items' => $items, - 'url' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'], - ] - ); + + if ($command->isChange()) { + $subject = 'JC Yoshi-Kan: Wijziging inschrijving voor '.$subscription->getFirstname().' '.$subscription->getLastname(); + $mailTemplate = $this->twig->render( + 'mail/member_changed_subscription_mail.html.twig', + [ + 'subject' => $subject, + 'subscription' => $subscription, + 'items' => $items, + 'url' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'], + ] + ); + } else { + $subject = 'JC Yoshi-Kan: Nieuwe inschrijving voor '.$subscription->getFirstname().' '.$subscription->getLastname(); + $mailTemplate = $this->twig->render( + 'mail/member_newMemberSubscription_mail.html.twig', + [ + 'subject' => $subject, + 'subscription' => $subscription, + 'items' => $items, + 'url' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'], + ] + ); + } // -- send email ---------------------------------------------------------- diff --git a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailTrait.php b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailTrait.php index 0c1131b..39f8128 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailTrait.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/NewMemberSubscriptionMailTrait.php @@ -17,7 +17,7 @@ trait NewMemberSubscriptionMailTrait { - public function sendMemberNewSubscriptionMail(int $subscriptionId): bool + public function sendMemberNewSubscriptionMail(int $subscriptionId, bool $isChange = false): bool { $this->permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); @@ -36,7 +36,8 @@ public function sendMemberNewSubscriptionMail(int $subscriptionId): bool $command = new NewMemberSubscriptionMail( $subscriptionId, Settings::FROM_NAME->value, - Settings::FROM_EMAIL->value + Settings::FROM_EMAIL->value, + $isChange, ); $result = $handler->go($command); diff --git a/application/YoshiKan/Application/MemberCommandBus.php b/application/YoshiKan/Application/MemberCommandBus.php index 745e816..e394c68 100644 --- a/application/YoshiKan/Application/MemberCommandBus.php +++ b/application/YoshiKan/Application/MemberCommandBus.php @@ -26,6 +26,7 @@ use App\YoshiKan\Application\Command\Member\ChangeMemberGrade\ChangeMemberGradeTrait; use App\YoshiKan\Application\Command\Member\ChangeMemberRemarks\ChangeMemberRemarksTrait; use App\YoshiKan\Application\Command\Member\ChangePeriod\ChangePeriodTrait; +use App\YoshiKan\Application\Command\Member\ChangeSubscriptionDetails\ChangeSubscriptionDetailsTrait; use App\YoshiKan\Application\Command\Member\ConfirmMemberWebSubscription\ConfirmMemberWebSubscriptionTrait; use App\YoshiKan\Application\Command\Member\CreateMolliePaymentLink\CreateMolliePaymentLinkTrait; use App\YoshiKan\Application\Command\Member\DeleteMemberImage\DeleteMemberImageTrait; @@ -113,6 +114,7 @@ class MemberCommandBus use CreateMolliePaymentLinkTrait; use SendPaymentReceivedConfirmationMailTrait; use NewMemberSubscriptionMailTrait; + use ChangeSubscriptionDetailsTrait; // -- member images --------------------------------------------------------- use UploadProfileImageTrait; diff --git a/application/YoshiKan/Domain/Model/Member/Subscription.php b/application/YoshiKan/Domain/Model/Member/Subscription.php index 4a34331..0aee9c7 100644 --- a/application/YoshiKan/Domain/Model/Member/Subscription.php +++ b/application/YoshiKan/Domain/Model/Member/Subscription.php @@ -481,6 +481,11 @@ public function updateSettings(array $settings): void $this->settings = $settings; } + public function clearItems(): void + { + $this->items = new ArrayCollection(); + } + // ————————————————————————————————————————————————————————————————————————— // Payment information setters // ————————————————————————————————————————————————————————————————————————— diff --git a/application/YoshiKan/Infrastructure/Templates/mail/member_changed_subscription_mail.html.twig b/application/YoshiKan/Infrastructure/Templates/mail/member_changed_subscription_mail.html.twig new file mode 100644 index 0000000..bcfb004 --- /dev/null +++ b/application/YoshiKan/Infrastructure/Templates/mail/member_changed_subscription_mail.html.twig @@ -0,0 +1,97 @@ +{% extends 'mail/base_mail.html.twig' %} + +{% block title %}{{ subject }}{% endblock %} + +{% block body %} +

+ Heist op den Berg, {{ 'now' | date('d/m/Y') }} +

+

+ Beste {{ subscription.contactFirstname }} {{ subscription.contactLastname }}, +

+

+ We hebben de inschrijving van {{ subscription.firstname }} {{ subscription.lastname }} aangepast. + Hieronder vind je een overzicht van de wijzigingen. +

+

+ Om de inschrijving definitief te maken en ervoor te zorgen dat je volop kunt genieten + van onze judolessen, verzoeken wij je vriendelijk om een bedrag van {{ subscription.total }} € + over te maken naar onze bankrekening op het volgende nummer: BE37 7330 0101 8328 met vermelding + van volgende referentie + "YKS-{{ subscription.id }} {{ subscription.lastname }} {{ subscription.firstname }}". + Zo kunnen we je betaling snel identificeren. +

+ {% if (subscription.paymentLink is not empty) %} +

+ Of betaal online via deze Mollie-link: + {{ subscription.paymentLink }}. +

+ {% endif %} +

+ Wanneer we je betaling hebben ontvangen, zullen we je officieel + inschrijven en krijg je toegang tot al onze trainingen en evenementen. + We staan te popelen om je te verwelkomen op de mat. +

+

+ Mocht je nog vragen hebben of extra informatie nodig hebben, aarzel dan niet om contact + met ons op te nemen via judo.yoshikan@gmail.com. + Ons team staat altijd klaar om je te helpen. +

+
+

+

+ {{ subscription.lastname | upper }} {{ subscription.firstname }} + (° {{ subscription.dateOfBirth | date('d/m/Y') }} - {{ subscription.gender.value }}) +
+
+ {{ subscription.member.addressStreet }} + {{ subscription.member.addressNumber }} + {% if(subscription.member.addressBox != '') %} + bus {{ subscription.member.addressBox }} + {% endif %} +
+
+ {{ subscription.member.addressZip }} + {{ subscription.member.addressCity }} +
+

+

+ + {% for item in items %} + {% if(item.price == 0) %} + + + + {% else %} + + + + + {% endif %} + {% endfor %} + + + + +
{{ item.name }}
{{ item.name }} {{ item.price }} €
Totaal{{ subscription.total }} € +
+

+

 

+ {% if(subscription.remarks != '') %} +
 
+

+ {{ subscription.remarks }} +

+ {% endif %} +

+ Met sportieve groeten, +
Team Yoshi-Kan. +

+

 

+

+ Door het uitvoeren van de betaling gaat U akkoord met ons reglement + en privacyverklaring, terug te vinden op onze website + www.yoshi-kan.be +

+ +{% endblock %} diff --git a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php index a9a5d2d..96849df 100644 --- a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php +++ b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/MemberRoutes.php @@ -194,6 +194,19 @@ public function confirmWebSubscription(Request $request): JsonResponse return new JsonResponse($response, 200, $this->apiAccess); } + /** + * @throws \Exception + */ + #[Route('/mm/api/member/change-subscription-details', methods: ['POST', 'PUT'])] + public function changeSubscriptionDetails(Request $request): JsonResponse + { + $command = json_decode($request->request->get('command')); + $response = $this->commandBus->changeSubscriptionDetails($command); + $result_mail = $this->commandBus->sendMemberNewSubscriptionMail($response->id, true); + + return new JsonResponse($response, 200, $this->apiAccess); + } + #[Route('/mm/api/member/overview-due-payments', methods: ['GET'])] public function downloadOverviewDuePayments(Request $request): JsonResponse { diff --git a/frontends/member_module/src/api/command/subscription/changeSubscription.ts b/frontends/member_module/src/api/command/subscription/changeSubscription.ts new file mode 100644 index 0000000..82acae2 --- /dev/null +++ b/frontends/member_module/src/api/command/subscription/changeSubscription.ts @@ -0,0 +1,75 @@ +/* + * 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 changeSubscriptionCommand { + + subscriptionId: number; + memberId: number; + + type: string; + federationId: number; + locationId: number; + + contactFirstname: string; + contactLastname: string; + contactEmail: string; + contactPhone: string; + + addressStreet: string; + addressNumber: string; + addressBox: string; + addressZip: string; + addressCity: string; + + firstname: string; + lastname: string; + email: string; + nationalRegisterNumber: string; + dateOfBirthDD: '', + dateOfBirthMM: '', + dateOfBirthYYYY: '', + dateOfBirth: Date; + gender: string; + + memberSubscriptionStart: Date; + memberSubscriptionStartMM: string; + memberSubscriptionStartYY: string; + memberSubscriptionEnd: Date; + memberSubscriptionTotal: number; + memberSubscriptionIsPartSubscription: boolean; + memberSubscriptionIsHalfYear: boolean; + memberSubscriptionIsPayed: boolean; + + licenseStart: Date; + licenseStartMM: string; + licenseStartYY: string; + licenseEnd: Date; + licenseTotal: number; + licenseIsPartSubscription: boolean; + licenseIsPayed: boolean; + + numberOfTraining: number; + isExtraTraining: boolean; + isNewMember: boolean; + isReductionFamily: boolean; + + total: number; + remarks: string; + + isJudogiBelt: boolean; +} + +export async function changeSubscription(command: changeSubscriptionCommand) { + const formData = new FormData(); + formData.append('command', JSON.stringify(command)); + const response = await axios.post(`/member/change-subscription-details`, formData); + return response.data; +} diff --git a/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue b/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue new file mode 100644 index 0000000..c68803c --- /dev/null +++ b/frontends/member_module/src/components/subscription/changeSubscription/changeSubscriptionForm.vue @@ -0,0 +1,756 @@ + + +