diff --git a/application/YoshiKan/Application/Command/Member/AddFederation/AddFederation.php b/application/YoshiKan/Application/Command/Member/AddFederation/AddFederation.php index 749a515..4e06b86 100644 --- a/application/YoshiKan/Application/Command/Member/AddFederation/AddFederation.php +++ b/application/YoshiKan/Application/Command/Member/AddFederation/AddFederation.php @@ -21,6 +21,7 @@ private function __construct( protected string $code, protected string $name, protected int $yearlySubscriptionFee, + protected string $publicLabel, ) { } @@ -34,6 +35,7 @@ public static function hydrateFromJson($json): self trim($json->code), trim($json->name), intval($json->yearlySubscriptionFee), + trim($json->publicLabel), ); } @@ -55,4 +57,9 @@ public function getYearlySubscriptionFee(): int { return $this->yearlySubscriptionFee; } + + public function getPublicLabel(): string + { + return $this->publicLabel; + } } diff --git a/application/YoshiKan/Application/Command/Member/AddFederation/AddFederationHandler.php b/application/YoshiKan/Application/Command/Member/AddFederation/AddFederationHandler.php index 4a845ac..01505ff 100644 --- a/application/YoshiKan/Application/Command/Member/AddFederation/AddFederationHandler.php +++ b/application/YoshiKan/Application/Command/Member/AddFederation/AddFederationHandler.php @@ -36,7 +36,8 @@ public function go(AddFederation $command): bool 1, $command->getCode(), $command->getName(), - $command->getYearlySubscriptionFee() + $command->getYearlySubscriptionFee(), + $command->getPublicLabel() ); $this->federationRepo->save($model); diff --git a/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederation.php b/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederation.php index 7fbeb06..af5c3e7 100644 --- a/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederation.php +++ b/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederation.php @@ -22,6 +22,7 @@ private function __construct( protected string $code, protected string $name, protected int $yearlySubscriptionFee, + protected string $publicLabel, ) { } @@ -36,6 +37,7 @@ public static function hydrateFromJson($json): self trim($json->code), trim($json->name), intval($json->yearlySubscriptionFee), + trim($json->publicLabel) ); } @@ -62,4 +64,9 @@ public function getYearlySubscriptionFee(): int { return $this->yearlySubscriptionFee; } + + public function getPublicLabel(): string + { + return $this->publicLabel; + } } diff --git a/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederationHandler.php b/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederationHandler.php index 26931fe..1434599 100644 --- a/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederationHandler.php +++ b/application/YoshiKan/Application/Command/Member/ChangeFederation/ChangeFederationHandler.php @@ -28,13 +28,14 @@ public function __construct( // Handler // ————————————————————————————————————————————————————————————————————————— - public function Change(ChangeFederation $command): bool + public function go(ChangeFederation $command): bool { $model = $this->federationRepo->getById($command->getId()); $model->change( $command->getCode(), $command->getName(), - $command->getYearlySubscriptionFee() + $command->getYearlySubscriptionFee(), + $command->getPublicLabel() ); $this->federationRepo->save($model); diff --git a/application/YoshiKan/Application/Command/Member/ChangeMemberGrade/ChangeMemberGradeHandler.php b/application/YoshiKan/Application/Command/Member/ChangeMemberGrade/ChangeMemberGradeHandler.php index 35fa312..c467af9 100644 --- a/application/YoshiKan/Application/Command/Member/ChangeMemberGrade/ChangeMemberGradeHandler.php +++ b/application/YoshiKan/Application/Command/Member/ChangeMemberGrade/ChangeMemberGradeHandler.php @@ -14,9 +14,9 @@ namespace App\YoshiKan\Application\Command\Member\ChangeMemberGrade; use App\YoshiKan\Domain\Model\Member\GradeLog; +use App\YoshiKan\Domain\Model\Member\GradeLogRepository; use App\YoshiKan\Domain\Model\Member\GradeRepository; use App\YoshiKan\Domain\Model\Member\MemberRepository; -use App\YoshiKan\Infrastructure\Database\Member\GradeLogRepository; class ChangeMemberGradeHandler { diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/MarkSubscriptionAsCanceled.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/MarkSubscriptionAsCanceled.php new file mode 100644 index 0000000..7685bc4 --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/MarkSubscriptionAsCanceled.php @@ -0,0 +1,40 @@ +id, + ); + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getId(): int + { + return $this->id; + } +} diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/MarkSubscriptionAsCanceledHandler.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/MarkSubscriptionAsCanceledHandler.php new file mode 100644 index 0000000..0910515 --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/MarkSubscriptionAsCanceledHandler.php @@ -0,0 +1,37 @@ +subscriptionRepository->getById($command->getId()); + $result = false; + + if (SubscriptionStatus::NEW === $subscription->getStatus() + || SubscriptionStatus::AWAITING_PAYMENT === $subscription->getStatus()) { + $subscription->changeStatus(SubscriptionStatus::CANCELED); + $this->subscriptionRepository->save($subscription); + $result = true; + } + + return $result; + } +} diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/mark_subscription_as_canceled.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/mark_subscription_as_canceled.php new file mode 100644 index 0000000..426b98d --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsCanceled/mark_subscription_as_canceled.php @@ -0,0 +1,22 @@ +permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $handler = new MarkSubscriptionAsCanceledHandler($this->subscriptionRepository); + $result = $handler->go($command); + $this->entityManager->flush(); + + return $result; + } +} diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/MarkSubscriptionAsFinished.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/MarkSubscriptionAsFinished.php new file mode 100644 index 0000000..99a4b68 --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/MarkSubscriptionAsFinished.php @@ -0,0 +1,40 @@ +id, + ); + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getId(): int + { + return $this->id; + } +} diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/MarkSubscriptionAsFinishedHandler.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/MarkSubscriptionAsFinishedHandler.php new file mode 100644 index 0000000..84b4e3c --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/MarkSubscriptionAsFinishedHandler.php @@ -0,0 +1,35 @@ +subscriptionRepository->getById($command->getId()); + + if (SubscriptionStatus::PAYED === $subscription->getStatus()) { + $subscription->changeStatus(SubscriptionStatus::COMPLETE); + $this->subscriptionRepository->save($subscription); + $result = true; + } + + return $result; + } +} diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/mark_subscription_as_finished.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/mark_subscription_as_finished.php new file mode 100644 index 0000000..1a63cd4 --- /dev/null +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsFinished/mark_subscription_as_finished.php @@ -0,0 +1,22 @@ +permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $handler = new MarkSubscriptionAsFinishedHandler($this->subscriptionRepository); + $result = $handler->go($command); + $this->entityManager->flush(); + + return $result; + } +} diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayed.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayed.php index 2eff5bf..ccee86f 100644 --- a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayed.php +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayed.php @@ -4,4 +4,37 @@ class MarkSubscriptionAsPayed { + // ————————————————————————————————————————————————————————————————————————— + // Constructor + // ————————————————————————————————————————————————————————————————————————— + + private function __construct( + protected int $id, + ) { + } + + // ————————————————————————————————————————————————————————————————————————— + // Hydrate from a json command + // ————————————————————————————————————————————————————————————————————————— + + public static function make(int $subscriptionId): self + { + return new self($subscriptionId); + } + + public static function hydrateFromJson($json): self + { + return new self( + $json->id, + ); + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getId(): int + { + return $this->id; + } } diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayedHandler.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayedHandler.php index 9cb9bbb..f98c9b0 100644 --- a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayedHandler.php +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/MarkSubscriptionAsPayedHandler.php @@ -2,6 +2,63 @@ namespace App\YoshiKan\Application\Command\Member\MarkSubscriptionAsPayed; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsCanceled\MarkSubscriptionAsCanceled; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsCanceled\MarkSubscriptionAsCanceledHandler; +use App\YoshiKan\Domain\Model\Member\MemberRepository; +use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; +use App\YoshiKan\Domain\Model\Member\SubscriptionStatus; + class MarkSubscriptionAsPayedHandler { + // ————————————————————————————————————————————————————————————————————————— + // Constructor + // ————————————————————————————————————————————————————————————————————————— + + public function __construct( + protected SubscriptionRepository $subscriptionRepository, + protected MemberRepository $memberRepository + ) { + } + + // ————————————————————————————————————————————————————————————————————————— + // Handler + // ————————————————————————————————————————————————————————————————————————— + + public function go(MarkSubscriptionAsPayed $command): bool + { + $result = false; + $subscription = $this->subscriptionRepository->getById($command->getId()); + + if (SubscriptionStatus::AWAITING_PAYMENT === $subscription->getStatus()) { + $subscription->changeStatus(SubscriptionStatus::PAYED); + $this->subscriptionRepository->save($subscription); + $result = true; + } + + // mark the subscription and license as paid on the actual member + if ($result && !is_null($subscription->getMember())) { + $member = $subscription->getMember(); + if ($subscription->isMemberSubscriptionIsPartSubscription()) { + $member->markSubscriptionAsPayed(); + } + if ($subscription->isLicenseIsPartSubscription()) { + $member->markLicenseAsPayed(); + } + $this->memberRepository->save($member); + } + + // cancel all other pending subscriptions for this member + if ($result && !is_null($subscription->getMember())) { + $cancelHandler = new MarkSubscriptionAsCanceledHandler($this->subscriptionRepository); + $subscriptions = $this->subscriptionRepository->getByMember($subscription->getMember()); + foreach ($subscriptions as $subscription) { + if ($subscription->getId() !== $command->getId()) { + $cancelCommand = MarkSubscriptionAsCanceled::make($subscription->getId()); + $cancelHandler->go($cancelCommand); + } + } + } + + return $result; + } } diff --git a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/mark_subscription_as_paid.php b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/mark_subscription_as_paid.php index 34ab0d2..513a584 100644 --- a/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/mark_subscription_as_paid.php +++ b/application/YoshiKan/Application/Command/Member/MarkSubscriptionAsPayed/mark_subscription_as_paid.php @@ -2,6 +2,37 @@ namespace App\YoshiKan\Application\Command\Member\MarkSubscriptionAsPayed; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsFinished\MarkSubscriptionAsFinished; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsFinished\MarkSubscriptionAsFinishedHandler; + trait mark_subscription_as_paid { + /** + * @throws \Exception + */ + public function markSubscriptionAsPayed(\stdClass $jsonCommand): bool + { + $command = MarkSubscriptionAsPayed::hydrateFromJson($jsonCommand); + + $this->permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + // -- mark as paid + $handler = new MarkSubscriptionAsPayedHandler( + $this->subscriptionRepository, + $this->memberRepository + ); + $result = $handler->go($command); + $this->entityManager->flush(); + + // -- finish the subscription + $resultFinished = false; + if ($result) { + $finishedCommand = MarkSubscriptionAsFinished::make($command->getId()); + $finishedHandler = new MarkSubscriptionAsFinishedHandler($this->subscriptionRepository); + $resultFinished = $finishedHandler->go($finishedCommand); + $this->entityManager->flush(); + } + + return $resultFinished; + } } diff --git a/application/YoshiKan/Application/Command/Member/MemberExtendSubscription/MemberExtendSubscriptionHandler.php b/application/YoshiKan/Application/Command/Member/MemberExtendSubscription/MemberExtendSubscriptionHandler.php index e8f01d2..2caa637 100644 --- a/application/YoshiKan/Application/Command/Member/MemberExtendSubscription/MemberExtendSubscriptionHandler.php +++ b/application/YoshiKan/Application/Command/Member/MemberExtendSubscription/MemberExtendSubscriptionHandler.php @@ -63,6 +63,11 @@ public function go(MemberExtendSubscription $command): \stdClass throw new \Exception('Membership extension command is not valid.'); } + $extraTraining = false; + if (3 === $command->getNumberOfTraining()) { + $extraTraining = true; + } + // -- make a subscription $subscription = Subscription::make( $this->subscriptionRepository->nextIdentity(), @@ -76,7 +81,7 @@ public function go(MemberExtendSubscription $command): \stdClass Gender::from($command->getGender()), SubscriptionType::from($command->getType()), $command->getNumberOfTraining(), - $command->isExtraTraining(), + $extraTraining, $command->isNewMember(), $command->isReductionFamily(), $command->isJudogiBelt(), @@ -99,6 +104,7 @@ public function go(MemberExtendSubscription $command): \stdClass $subscription->setMember($member); $subscription->changeStatus(SubscriptionStatus::AWAITING_PAYMENT); + $subscription->calculate(); $this->subscriptionRepository->save($subscription); // -- make some subscription lines ----------------------------------------------------------------------------- diff --git a/application/YoshiKan/Application/Command/Member/MemberExtendSubscriptionMail/member_extend_subscription_mail.php b/application/YoshiKan/Application/Command/Member/MemberExtendSubscriptionMail/member_extend_subscription_mail.php index d4b8d04..9920944 100644 --- a/application/YoshiKan/Application/Command/Member/MemberExtendSubscriptionMail/member_extend_subscription_mail.php +++ b/application/YoshiKan/Application/Command/Member/MemberExtendSubscriptionMail/member_extend_subscription_mail.php @@ -13,6 +13,8 @@ namespace App\YoshiKan\Application\Command\Member\MemberExtendSubscriptionMail; +use App\YoshiKan\Application\Settings; + trait member_extend_subscription_mail { public function sendMemberExtendSubscriptionMail(int $subscriptionId): bool @@ -21,8 +23,8 @@ public function sendMemberExtendSubscriptionMail(int $subscriptionId): bool $command = new MemberExtendSubscriptionMail( $subscriptionId, - 'Yoshi-Kan', - 'no-reply@yoshi-kan.be' + Settings::FROM_NAME->value, + Settings::FROM_EMAIL->value ); $handler = new MemberExtendSubscriptionMailHandler( diff --git a/application/YoshiKan/Application/Command/Member/NewMemberSubscription/NewMemberSubscriptionHandler.php b/application/YoshiKan/Application/Command/Member/NewMemberSubscription/NewMemberSubscriptionHandler.php index 25d4ee3..7daca1c 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberSubscription/NewMemberSubscriptionHandler.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberSubscription/NewMemberSubscriptionHandler.php @@ -71,6 +71,11 @@ public function go(NewMemberSubscription $command): \stdClass // -- make a subscription -------------------------------------------------------------------------------------- + $extraTraining = false; + if (3 === $command->getNumberOfTraining()) { + $extraTraining = true; + } + $subscription = Subscription::make( $this->subscriptionRepository->nextIdentity(), $command->getContactFirstname(), @@ -83,7 +88,7 @@ public function go(NewMemberSubscription $command): \stdClass Gender::from($command->getGender()), SubscriptionType::from($command->getType()), $command->getNumberOfTraining(), - $command->isExtraTraining(), + $extraTraining, $command->isNewMember(), $command->isReductionFamily(), $command->isJudogiBelt(), @@ -114,6 +119,7 @@ public function go(NewMemberSubscription $command): \stdClass ); // -- flush the subscription and get the database id via the uuid + $subscription->calculate(); $this->subscriptionRepository->save($subscription); $this->entityManager->flush(); diff --git a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/new_member_subscription_mail.php b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/new_member_subscription_mail.php index 08d78fe..74465db 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/new_member_subscription_mail.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberSubscriptionMail/new_member_subscription_mail.php @@ -13,6 +13,8 @@ namespace App\YoshiKan\Application\Command\Member\NewMemberSubscriptionMail; +use App\YoshiKan\Application\Settings; + trait new_member_subscription_mail { public function sendMemberNewSubscriptionMail(int $subscriptionId): bool @@ -33,8 +35,8 @@ public function sendMemberNewSubscriptionMail(int $subscriptionId): bool $command = new NewMemberSubscriptionMail( $subscriptionId, - 'Yoshi-Kan', - 'no-reply@yoshi-kan.be' + Settings::FROM_NAME->value, + Settings::FROM_EMAIL->value ); $result = $handler->go($command); diff --git a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscription.php b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscription.php index 1d6c910..76b3d17 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscription.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscription.php @@ -15,4 +15,216 @@ class NewMemberWebSubscription { + // ————————————————————————————————————————————————————————————————————————— + // Constructor + // ————————————————————————————————————————————————————————————————————————— + + private function __construct( + protected string $type, + protected int $federationId, + protected int $locationId, + + protected string $contactFirstname, + protected string $contactLastname, + protected string $contactEmail, + protected string $contactPhone, + + protected string $addressStreet, + protected string $addressNumber, + protected string $addressBox, + protected string $addressZip, + protected string $addressCity, + + protected string $firstname, + protected string $lastname, + protected string $nationalRegisterNumber, + protected \DateTimeImmutable $dateOfBirth, + protected string $gender, + + protected bool $memberSubscriptionIsHalfYear, + protected int $numberOfTraining, + protected bool $isExtraTraining, + protected bool $isNewMember, + protected bool $isReductionFamily, + + protected float $total, + protected string $remarks, + + protected bool $isJudogiBelt, + protected string $honeyPot, + ) { + } + + // ————————————————————————————————————————————————————————————————————————— + // Hydrate from a json command + // ————————————————————————————————————————————————————————————————————————— + + /** + * @throws \Exception + */ + public static function hydrateFromJson($json): self + { + return new self( + 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->nationalRegisterNumber), + new \DateTimeImmutable($json->dateOfBirth), + trim($json->gender), + boolval($json->memberSubscriptionIsHalfYear), + intval($json->numberOfTraining), + boolval($json->isExtraTraining), + boolval($json->isNewMember), + boolval($json->isReductionFamily), + floatval($json->total), + trim($json->remarks), + boolval($json->isJudogiBelt), + trim($json->honeyPot), + ); + } + + // ————————————————————————————————————————————————————————————————————————— + // 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 getNationalRegisterNumber(): string + { + return $this->nationalRegisterNumber; + } + + public function getDateOfBirth(): \DateTimeImmutable + { + return $this->dateOfBirth; + } + + public function getGender(): string + { + return $this->gender; + } + + public function getNumberOfTraining(): int + { + return $this->numberOfTraining; + } + + public function isExtraTraining(): bool + { + return $this->isExtraTraining; + } + + public function isNewMember(): bool + { + return $this->isNewMember; + } + + 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 isMemberSubscriptionIsHalfYear(): bool + { + return $this->memberSubscriptionIsHalfYear; + } + + public function getHoneyPot(): string + { + return $this->honeyPot; + } } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscriptionHandler.php b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscriptionHandler.php index f326880..422d304 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscriptionHandler.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/NewMemberWebSubscriptionHandler.php @@ -13,6 +13,148 @@ namespace App\YoshiKan\Application\Command\Member\NewMemberWebSubscription; +use App\YoshiKan\Application\Query\Member\Readmodel\SettingsReadModel; +use App\YoshiKan\Domain\Model\Member\FederationRepository; +use App\YoshiKan\Domain\Model\Member\Gender; +use App\YoshiKan\Domain\Model\Member\LocationRepository; +use App\YoshiKan\Domain\Model\Member\MemberRepository; +use App\YoshiKan\Domain\Model\Member\Settings; +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\SubscriptionItemRepository; +use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; +use App\YoshiKan\Domain\Model\Member\SubscriptionType; +use Doctrine\ORM\EntityManagerInterface; + class NewMemberWebSubscriptionHandler { + // ——————————————————————————————————————————————————————————————— + // Constructor + // ——————————————————————————————————————————————————————————————— + + public function __construct( + protected FederationRepository $federationRepository, + protected LocationRepository $locationRepository, + protected SettingsRepository $settingsRepository, + protected MemberRepository $memberRepository, + protected SubscriptionRepository $subscriptionRepository, + protected SubscriptionItemRepository $subscriptionItemRepository, + protected EntityManagerInterface $entityManager, + ) { + } + + // ——————————————————————————————————————————————————————————————— + // Handle + // ——————————————————————————————————————————————————————————————— + /** + * @throws \Exception + */ + public function go(NewMemberWebSubscription $command): \stdClass + { + if ('' === $command->getHoneyPot()) { + $federation = $this->federationRepository->getById($command->getFederationId()); + $location = $this->locationRepository->getById($command->getLocationId()); + $settings = $this->settingsRepository->findByCode(SettingsCode::ACTIVE->value); + + // -- validate the command + $commandIsValid = $this->isCommandValid($command, $settings); + if (!$commandIsValid) { + throw new \Exception('Membership extension command is not valid.'); + } + + // -- dates calculation ------------------------------------------------------------------------------------ + $currentDate = new \DateTimeImmutable(); + $membershipStart = $currentDate->modify('first day of this month'); + $membershipEnd = $membershipStart->modify('+1 year'); + if ($command->isMemberSubscriptionIsHalfYear()) { + $addAmount = 5; + $startMonth = intval($currentDate->format('m')); + if (2 == $startMonth + || 3 == $startMonth || 4 == $startMonth || 5 == $startMonth + || 6 == $startMonth || 7 == $startMonth || 8 == $startMonth + ) { + $addAmount = 7; + } + $membershipEnd = $membershipStart->modify('+'.$addAmount.' months'); + } + $licenseStart = $currentDate->modify('first day of this month'); + $licenseEnd = $licenseStart->modify('+1 year'); + + // -- make a subscription ---------------------------------------------------------------------------------- + $extraTraining = false; + if (3 === $command->getNumberOfTraining()) { + $extraTraining = true; + } + + $subscription = Subscription::make( + $this->subscriptionRepository->nextIdentity(), + $command->getContactFirstname(), + $command->getContactLastname(), + $command->getContactEmail(), + $command->getContactPhone(), + $command->getFirstname(), + $command->getLastname(), + $command->getDateOfBirth(), + Gender::from($command->getGender()), + SubscriptionType::from($command->getType()), + $command->getNumberOfTraining(), + $extraTraining, + $command->isNewMember(), + $command->isReductionFamily(), + $command->isJudogiBelt(), + $command->getRemarks(), + $location, + json_decode(json_encode(SettingsReadModel::hydrateFromModel($settings)), true), + $federation, + $membershipStart, + $membershipEnd, + 0, + true, + $command->isMemberSubscriptionIsHalfYear(), + false, + $licenseStart, + $licenseEnd, + 0, + true, + false, + ); + + $subscription->setNewMemberFields( + $command->getNationalRegisterNumber(), + $command->getAddressStreet(), + $command->getAddressNumber(), + $command->getAddressBox(), + $command->getAddressZip(), + $command->getAddressCity() + ); + + // -- flush the subscription and get the database id via the uuid + $subscription->calculate(); + $this->subscriptionRepository->save($subscription); + $this->entityManager->flush(); + + $subscription = $this->subscriptionRepository->getByUuid($subscription->getUuid()); + $subscriptionId = $subscription->getId(); + + // -- compile a result class ------------------------------------------------------------------------------- + $result = new \stdClass(); + $result->id = $subscriptionId; + $result->reference = 'YKS-'.$subscriptionId.': '.$command->getFirstName().' '.$command->getLastName(); + } else { + // -- the honey-pot field was not empty + $result = new \stdClass(); + $result->id = 0; + $result->reference = 'YKS-0'; + } + + return $result; + } + + private function isCommandValid(NewMemberWebSubscription $command, Settings $settings): bool + { + // todo + + return true; + } } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/new_member_web_subscription.php b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/new_member_web_subscription.php index 892417e..2f46a59 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/new_member_web_subscription.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscription/new_member_web_subscription.php @@ -15,4 +15,22 @@ trait new_member_web_subscription { + public function newMemberWebSubscription(\stdClass $jsonCommand): \stdClass + { + $command = NewMemberWebSubscription::hydrateFromJson($jsonCommand); + $handler = new NewMemberWebSubscriptionHandler( + $this->federationRepository, + $this->locationRepository, + $this->settingsRepository, + $this->memberRepository, + $this->subscriptionRepository, + $this->subscriptionItemRepository, + $this->entityManager, + ); + + $result = $handler->go($command); + $this->entityManager->flush(); + + return $result; + } } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMail.php b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMail.php index b87520c..1edc498 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMail.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMail.php @@ -15,4 +15,39 @@ class NewMemberWebSubscriptionMail { + // ————————————————————————————————————————————————————————————————————————— + // Constructor + // ————————————————————————————————————————————————————————————————————————— + + public function __construct( + protected int $subscriptionId, + protected string $fromName, + protected string $fromEmail, + protected string $contactEmail, + ) { + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getSubscriptionId(): int + { + return $this->subscriptionId; + } + + public function getFromName(): string + { + return $this->fromName; + } + + public function getFromEmail(): string + { + return $this->fromEmail; + } + + public function getContactEmail(): string + { + return $this->contactEmail; + } } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMailHandler.php b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMailHandler.php index 1feb211..565773f 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMailHandler.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/NewMemberWebSubscriptionMailHandler.php @@ -13,6 +13,44 @@ namespace App\YoshiKan\Application\Command\Member\NewMemberWebSubscriptionMail; +use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Twig\Environment; + class NewMemberWebSubscriptionMailHandler { + public function __construct( + protected SubscriptionRepository $subscriptionRepository, + protected Environment $twig, + protected MailerInterface $mailer + ) { + } + + public function go(NewMemberWebSubscriptionMail $command): bool + { + $subscription = $this->subscriptionRepository->getById($command->getSubscriptionId()); + $subject = 'Yoshi-Kan: bevestiging inschrijving '.$subscription->getFirstname().' '.$subscription->getLastname(); + + $mailTemplate = $this->twig->render( + 'mail/web_confirmation_mail.html.twig', + [ + 'subject' => $subject, + 'subscription' => $subscription, + 'url' => $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'], + ] + ); + + $message = (new Email()) + ->subject($subject) + ->from(new Address($command->getFromEmail(), $command->getFromName())) + ->to(new Address($subscription->getContactEmail(), $subscription->getContactFirstname().' '.$subscription->getContactLastname())) + ->bcc(new Address($command->getContactEmail(), $command->getFromName())) + ->html($mailTemplate); + + $this->mailer->send($message); + + return true; + } } diff --git a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/new_member_web_subscription_mail.php b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/new_member_web_subscription_mail.php index 6f8e2c5..3ca6325 100644 --- a/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/new_member_web_subscription_mail.php +++ b/application/YoshiKan/Application/Command/Member/NewMemberWebSubscriptionMail/new_member_web_subscription_mail.php @@ -13,6 +13,24 @@ namespace App\YoshiKan\Application\Command\Member\NewMemberWebSubscriptionMail; +use App\YoshiKan\Application\Settings; + trait new_member_web_subscription_mail { + /** + * @throws \Exception + */ + public function newMemberWebSubscriptionMail(int $subscriptionId): bool + { + $command = new NewMemberWebSubscriptionMail( + $subscriptionId, + Settings::FROM_NAME->value, + Settings::FROM_EMAIL->value, + Settings::CONTACT_EMAIL->value, + ); + + $handler = new NewMemberWebSubscriptionMailHandler($this->subscriptionRepository, $this->twig, $this->mailer); + + return $handler->go($command); + } } diff --git a/application/YoshiKan/Application/Command/Member/OrderFederation/OrderFederationHandler.php b/application/YoshiKan/Application/Command/Member/OrderFederation/OrderFederationHandler.php index 3831637..c7441c6 100644 --- a/application/YoshiKan/Application/Command/Member/OrderFederation/OrderFederationHandler.php +++ b/application/YoshiKan/Application/Command/Member/OrderFederation/OrderFederationHandler.php @@ -10,7 +10,7 @@ class OrderFederationHandler // Constructor // ——————————————————————————————————————————————————————————————— - public function __construct(protected FederationRepository $repo) + public function __construct(protected FederationRepository $federationRepository) { } @@ -22,9 +22,9 @@ public function go(OrderFederation $command): bool { $sequence = 0; foreach ($command->getSequence() as $sequenceId) { - $model = $this->repo->getById($sequenceId); + $model = $this->federationRepository->getById($sequenceId); $model->setSequence($sequence); - $this->repo->save($model); + $this->federationRepository->save($model); ++$sequence; } diff --git a/application/YoshiKan/Application/Command/Member/SetupConfiguration/SetupConfigurationHandler.php b/application/YoshiKan/Application/Command/Member/SetupConfiguration/SetupConfigurationHandler.php index 3eb5758..bff5a8a 100644 --- a/application/YoshiKan/Application/Command/Member/SetupConfiguration/SetupConfigurationHandler.php +++ b/application/YoshiKan/Application/Command/Member/SetupConfiguration/SetupConfigurationHandler.php @@ -14,9 +14,9 @@ namespace App\YoshiKan\Application\Command\Member\SetupConfiguration; use App\YoshiKan\Domain\Model\Member\Period; +use App\YoshiKan\Domain\Model\Member\PeriodRepository; use App\YoshiKan\Domain\Model\Member\Settings; use App\YoshiKan\Domain\Model\Member\SettingsRepository; -use App\YoshiKan\Infrastructure\Database\Member\PeriodRepository; class SetupConfigurationHandler { diff --git a/application/YoshiKan/Application/CommandBus.php b/application/YoshiKan/Application/CommandBus.php index a11c99a..9c9b5cc 100644 --- a/application/YoshiKan/Application/CommandBus.php +++ b/application/YoshiKan/Application/CommandBus.php @@ -13,16 +13,17 @@ namespace App\YoshiKan\Application; +use App\YoshiKan\Application\Command\Member\NewMemberWebSubscription\new_member_web_subscription; +use App\YoshiKan\Application\Command\Member\NewMemberWebSubscriptionMail\new_member_web_subscription_mail; use App\YoshiKan\Application\Security\BasePermissionService; +use App\YoshiKan\Domain\Model\Member\FederationRepository; use App\YoshiKan\Domain\Model\Member\LocationRepository; +use App\YoshiKan\Domain\Model\Member\MemberRepository; +use App\YoshiKan\Domain\Model\Member\PeriodRepository; +use App\YoshiKan\Domain\Model\Member\SettingsRepository; +use App\YoshiKan\Domain\Model\Member\SubscriptionItemRepository; use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; use App\YoshiKan\Domain\Model\Product\JudogiRepository; -use App\YoshiKan\Infrastructure\Database\Member\FederationRepository; -use App\YoshiKan\Infrastructure\Database\Member\MemberRepository; -use App\YoshiKan\Infrastructure\Database\Member\PeriodRepository; -use App\YoshiKan\Infrastructure\Database\Member\SettingsRepository; -use backend\Command\WebConfirmationMail\web_confirmation_mail; -use backend\Command\WebSubscribe\web_subscribe; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Security\Core\Security; @@ -34,8 +35,8 @@ class CommandBus // —— Traits // —————————————————————————————————————————————————————————————————————————— - use web_subscribe; - use web_confirmation_mail; + use new_member_web_subscription; + use new_member_web_subscription_mail; // —————————————————————————————————————————————————————————————————————————— // —— Security @@ -55,6 +56,7 @@ public function __construct( protected MailerInterface $mailer, protected string $uploadFolder, protected SubscriptionRepository $subscriptionRepository, + protected SubscriptionItemRepository $subscriptionItemRepository, protected LocationRepository $locationRepository, protected PeriodRepository $periodRepository, protected JudogiRepository $judogiRepository, diff --git a/application/YoshiKan/Application/MemberCommandBus.php b/application/YoshiKan/Application/MemberCommandBus.php index 51ea07c..8a8f0ae 100644 --- a/application/YoshiKan/Application/MemberCommandBus.php +++ b/application/YoshiKan/Application/MemberCommandBus.php @@ -27,6 +27,9 @@ use App\YoshiKan\Application\Command\Member\ChangeMemberRemarks\change_member_remarks; use App\YoshiKan\Application\Command\Member\ChangePeriod\change_period; use App\YoshiKan\Application\Command\Member\DeleteMemberImage\delete_member_image; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsCanceled\mark_subscription_as_canceled; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsFinished\mark_subscription_as_finished; +use App\YoshiKan\Application\Command\Member\MarkSubscriptionAsPayed\mark_subscription_as_paid; use App\YoshiKan\Application\Command\Member\MemberExtendSubscription\member_extend_subscription; use App\YoshiKan\Application\Command\Member\MemberExtendSubscriptionMail\member_extend_subscription_mail; use App\YoshiKan\Application\Command\Member\NewMemberSubscription\new_member_subscription; @@ -94,6 +97,9 @@ class MemberCommandBus use member_extend_subscription_mail; use new_member_subscription; use new_member_subscription_mail; + use mark_subscription_as_paid; + use mark_subscription_as_finished; + use mark_subscription_as_canceled; // -- member images --------------------------------------------------------- use upload_member_image; diff --git a/application/YoshiKan/Application/MemberQueryBus.php b/application/YoshiKan/Application/MemberQueryBus.php index f8ea6c7..44f2c65 100644 --- a/application/YoshiKan/Application/MemberQueryBus.php +++ b/application/YoshiKan/Application/MemberQueryBus.php @@ -19,7 +19,9 @@ use App\YoshiKan\Application\Query\Member\get_member_image; use App\YoshiKan\Application\Query\Member\get_subscription; use App\YoshiKan\Application\Query\Message\get_message; +use App\YoshiKan\Application\Query\Reporting\get_reporting; use App\YoshiKan\Application\Security\BasePermissionService; +use App\YoshiKan\Domain\Model\Member\FederationRepository; use App\YoshiKan\Domain\Model\Member\GradeRepository; use App\YoshiKan\Domain\Model\Member\GroupRepository; use App\YoshiKan\Domain\Model\Member\LocationRepository; @@ -30,7 +32,6 @@ use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; use App\YoshiKan\Domain\Model\Message\MessageRepository; use App\YoshiKan\Domain\Model\Product\JudogiRepository; -use App\YoshiKan\Infrastructure\Database\Member\FederationRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\Security; use Twig\Environment; @@ -47,6 +48,7 @@ class MemberQueryBus use get_message; use get_subscription; use download_due_payments; + use get_reporting; // —————————————————————————————————————————————————————————————————————————— // —— Security diff --git a/application/YoshiKan/Application/Query/Member/ExportSubscriptions.php b/application/YoshiKan/Application/Query/Member/ExportSubscriptions.php new file mode 100644 index 0000000..3c624e4 --- /dev/null +++ b/application/YoshiKan/Application/Query/Member/ExportSubscriptions.php @@ -0,0 +1,82 @@ +subscriptionRepository->getByListId($listIds); + $activePeriod = $this->periodRepository->getActive(); + + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setTitle($activePeriod->getName()); + + // -- header ---------------------------------------------------------------- + $rowCounter = 1; + $sheet->setCellValue([1, $rowCounter], 'Ref.'); + $sheet->setCellValue([2, $rowCounter], 'Naam'); + $sheet->setCellValue([3, $rowCounter], 'Voornaam'); + $sheet->setCellValue([4, $rowCounter], 'Geboortedatum'); + $sheet->setCellValue([5, $rowCounter], 'Geslacht'); + $sheet->setCellValue([6, $rowCounter], 'Lidnr.'); + $sheet->setCellValue([7, $rowCounter], 'Graad'); + $sheet->setCellValue([8, $rowCounter], 'Contact'); + $sheet->setCellValue([9, $rowCounter], 'Email'); + + // -- data ----------------------------------------------------------------- + ++$rowCounter; + foreach ($subscriptions as $subscription) { + $sheet->setCellValue([1, $rowCounter], 'YKS-'.$subscription->getId()); + $sheet->setCellValue([2, $rowCounter], strtoupper($subscription->getLastname())); + $sheet->setCellValue([3, $rowCounter], $subscription->getFirstname()); + $sheet->setCellValue([4, $rowCounter], $subscription->getDateOfBirth()->format('d/m/Y')); + $sheet->setCellValue([5, $rowCounter], $subscription->getGenderAsString()); + if (!is_null($subscription->getMember())) { + $sheet->setCellValue([6, $rowCounter], 'YK-'.$subscription->getMember()->getId()); + $sheet->setCellValue([7, $rowCounter], $subscription->getMember()->getGrade()->getName()); + } else { + $sheet->setCellValue([6, $rowCounter], 'n/a'); + $sheet->setCellValue([7, $rowCounter], 'n/a'); + } + $sheet->setCellValue([8, $rowCounter], $subscription->getContactFirstname().' '.$subscription->getContactLastname()); + $sheet->setCellValue([9, $rowCounter], $subscription->getContactEmail()); + ++$rowCounter; + } + + // -- first row bold ------------------------------------------------------ + $highestColumn = $sheet->getHighestColumn(); + $sheet->getStyle('A1:'.$highestColumn.'1')->getFont()->setBold(true); + $sheet->setSelectedCell('A1'); + + // -- autosize the columns ------------------------------------------------ + for ($i = 'A'; $i != $sheet->getHighestColumn(); ++$i) { + $sheet->getColumnDimension($i)->setAutoSize(true); + } + $sheet->getColumnDimension($sheet->getHighestColumn())->setAutoSize(true); + + return $spreadsheet; + } +} diff --git a/application/YoshiKan/Application/Query/Member/GetConfiguration.php b/application/YoshiKan/Application/Query/Member/GetConfiguration.php index b7257da..2736ed0 100644 --- a/application/YoshiKan/Application/Query/Member/GetConfiguration.php +++ b/application/YoshiKan/Application/Query/Member/GetConfiguration.php @@ -28,6 +28,7 @@ use App\YoshiKan\Application\Query\Member\Readmodel\WebConfigurationReadModel; use App\YoshiKan\Application\Query\Product\JudogiReadModel; use App\YoshiKan\Application\Query\Product\JudogiReadModelCollection; +use App\YoshiKan\Domain\Model\Member\FederationRepository; use App\YoshiKan\Domain\Model\Member\GradeRepository; use App\YoshiKan\Domain\Model\Member\GroupRepository; use App\YoshiKan\Domain\Model\Member\LocationRepository; @@ -35,7 +36,6 @@ use App\YoshiKan\Domain\Model\Member\SettingsCode; use App\YoshiKan\Domain\Model\Member\SettingsRepository; use App\YoshiKan\Domain\Model\Product\JudogiRepository; -use App\YoshiKan\Infrastructure\Database\Member\FederationRepository; class GetConfiguration { @@ -103,24 +103,29 @@ public function getFullConfiguration(): ConfigurationReadModel public function getWebConfiguration(): WebConfigurationReadModel { - $grades = $this->gradeRepository->getAll(); $locations = $this->locationRepository->getAll(); - $groups = $this->groupRepository->getAll(); $activePeriod = $this->periodRepository->getActive(); $settings = $this->settingsRepository->findByCode(SettingsCode::ACTIVE->value); + $federations = $this->federationRepository->getAll(); $locationCollection = new LocationReadModelCollection(); foreach ($locations as $location) { $locationCollection->addItem(LocationReadModel::hydrateFromModel($location)); } + $federationCollection = new FederationReadModelCollection(); + foreach ($federations as $federation) { + $federationCollection->addItem(FederationReadModel::hydrateFromModel($federation)); + } + $activePeriodReadModel = PeriodReadModel::hydrateFromModel($activePeriod); $settingsReadModel = SettingsReadModel::hydrateFromModel($settings); return new WebConfigurationReadModel( $locationCollection, $activePeriodReadModel, - $settingsReadModel + $settingsReadModel, + $federationCollection ); } } diff --git a/application/YoshiKan/Application/Query/Member/GetSubscription.php b/application/YoshiKan/Application/Query/Member/GetSubscription.php index 52a5e45..ade873f 100644 --- a/application/YoshiKan/Application/Query/Member/GetSubscription.php +++ b/application/YoshiKan/Application/Query/Member/GetSubscription.php @@ -17,6 +17,7 @@ use App\YoshiKan\Application\Query\Member\Readmodel\SubscriptionReadModelCollection; use App\YoshiKan\Domain\Model\Member\MemberRepository; use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; +use App\YoshiKan\Domain\Model\Member\SubscriptionStatus; class GetSubscription { @@ -43,11 +44,14 @@ public function getByMemberId(int $memberId): SubscriptionReadModelCollection return $collection; } - public function getByStatus(string $status): SubscriptionReadModelCollection + public function getByStatus(SubscriptionStatus $status): SubscriptionReadModelCollection { $collection = new SubscriptionReadModelCollection(); - - // todo + $subscriptions = $this->subscriptionRepository->getByStatus($status); + $collection = new SubscriptionReadModelCollection(); + foreach ($subscriptions as $subscription) { + $collection->addItem(SubscriptionReadModel::hydrateFromModel($subscription)); + } return $collection; } diff --git a/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php b/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php new file mode 100644 index 0000000..360e8e3 --- /dev/null +++ b/application/YoshiKan/Application/Query/Member/PrintSubscriptions.php @@ -0,0 +1,64 @@ +subscriptionRepository->getByListId($listIds); + $renderList = new \stdClass(); + $renderList->generatedOn = new \DateTimeImmutable(); + $renderList->subscriptions = $subscriptions; + + $pdfHtml = $this->twig->render('pdf/subscription_detail.html.twig', ['list' => $renderList]); + + $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 = $renderList->generatedOn->format('YmdHis').'_yoshikan_inschrijvingen.pdf'; + + /** @var Subscription $subscription */ + foreach ($subscriptions as $subscription) { + $subscription->flagSubscriptionIsPrinted(); + $this->subscriptionRepository->save($subscription); + } + $this->entityManager->flush(); + + $dompdf->stream($fileName, ['Attachment' => false]); + + exit; + } +} diff --git a/application/YoshiKan/Application/Query/Member/Readmodel/FederationReadModel.php b/application/YoshiKan/Application/Query/Member/Readmodel/FederationReadModel.php index aea7250..7d02b7d 100644 --- a/application/YoshiKan/Application/Query/Member/Readmodel/FederationReadModel.php +++ b/application/YoshiKan/Application/Query/Member/Readmodel/FederationReadModel.php @@ -16,6 +16,7 @@ public function __construct( protected string $code, protected string $name, protected int $yearlySubscriptionFee, + protected string $publicLabel, ) { } @@ -30,6 +31,7 @@ public function jsonSerialize(): \stdClass $json->uuid = $this->getUuid(); $json->code = $this->getCode(); $json->name = $this->getName(); + $json->publicLabel = $this->getPublicLabel(); $json->yearlySubscriptionFee = $this->getYearlySubscriptionFee(); return $json; @@ -47,6 +49,7 @@ public static function hydrateFromModel(Federation $model): self $model->getCode(), $model->getName(), $model->getYearlySubscriptionFee(), + $model->getPublicLabel() ); } @@ -78,4 +81,9 @@ public function getYearlySubscriptionFee(): int { return $this->yearlySubscriptionFee; } + + public function getPublicLabel(): string + { + return $this->publicLabel; + } } diff --git a/application/YoshiKan/Application/Query/Member/Readmodel/SubscriptionReadModel.php b/application/YoshiKan/Application/Query/Member/Readmodel/SubscriptionReadModel.php index 334b969..61bc307 100644 --- a/application/YoshiKan/Application/Query/Member/Readmodel/SubscriptionReadModel.php +++ b/application/YoshiKan/Application/Query/Member/Readmodel/SubscriptionReadModel.php @@ -5,6 +5,7 @@ namespace App\YoshiKan\Application\Query\Member\Readmodel; use App\YoshiKan\Domain\Model\Member\Subscription; +use App\YoshiKan\Domain\Model\Message\Message; class SubscriptionReadModel implements \JsonSerializable { @@ -54,6 +55,7 @@ public function __construct( protected FederationReadModel $federation, protected array $subscriptionitems, protected ?int $memberId, + protected ?int $messageId, ) { } @@ -69,13 +71,14 @@ public function jsonSerialize(): \stdClass $json->status = $this->getStatus(); $json->type = $this->getType(); $json->memberId = $this->getMemberId(); + $json->messageId = $this->getMessageId(); $json->contactFirstname = $this->getContactFirstname(); $json->contactLastname = $this->getContactLastname(); $json->contactEmail = $this->getContactEmail(); $json->contactPhone = $this->getContactPhone(); $json->firstname = $this->getFirstname(); $json->lastname = $this->getLastname(); - $json->dateOfBirth = $this->getDateOfBirth(); + $json->dateOfBirth = $this->getDateOfBirth()->format(\DateTimeInterface::ATOM); $json->gender = $this->getGender(); $json->numberOfTraining = $this->getNumberOfTraining(); $json->isExtraTraining = $this->isExtraTraining(); @@ -125,6 +128,16 @@ public static function hydrateFromModel(Subscription $model): self $memberId = $model->getMember()->getId(); } + $messageId = null; + $messages = $model->getMessages(); + if (count($messages) > 0) { + /** @var Message $message */ + foreach ($messages as $message) { + $messageId = $message->getId(); + break; + } + } + return new self( $model->getId(), $model->getUuid()->toRfc4122(), @@ -166,7 +179,8 @@ public static function hydrateFromModel(Subscription $model): self LocationReadModel::hydrateFromModel($model->getLocation()), FederationReadModel::hydrateFromModel($model->getFederation()), $itemCollection->getCollection(), - $memberId + $memberId, + $messageId ); } @@ -378,4 +392,9 @@ public function getMemberId(): ?int { return $this->memberId; } + + public function getMessageId(): ?int + { + return $this->messageId; + } } diff --git a/application/YoshiKan/Application/Query/Member/Readmodel/WebConfigurationReadModel.php b/application/YoshiKan/Application/Query/Member/Readmodel/WebConfigurationReadModel.php index 15b4d4d..f13a888 100644 --- a/application/YoshiKan/Application/Query/Member/Readmodel/WebConfigurationReadModel.php +++ b/application/YoshiKan/Application/Query/Member/Readmodel/WebConfigurationReadModel.php @@ -18,7 +18,8 @@ class WebConfigurationReadModel implements \JsonSerializable public function __construct( protected LocationReadModelCollection $locations, protected PeriodReadModel $activePeriod, - protected SettingsReadModel $settings + protected SettingsReadModel $settings, + protected FederationReadModelCollection $federations ) { } @@ -32,6 +33,7 @@ public function jsonSerialize(): \stdClass $json->locations = $this->getLocations()->getCollection(); $json->activePeriod = $this->getActivePeriod(); $json->settings = $this->getSettings(); + $json->federations = $this->getFederations()->getCollection(); return $json; } @@ -54,4 +56,9 @@ public function getSettings(): SettingsReadModel { return $this->settings; } + + public function getFederations(): FederationReadModelCollection + { + return $this->federations; + } } diff --git a/application/YoshiKan/Application/Query/Member/get_subscription.php b/application/YoshiKan/Application/Query/Member/get_subscription.php index c6113db..4996cc6 100644 --- a/application/YoshiKan/Application/Query/Member/get_subscription.php +++ b/application/YoshiKan/Application/Query/Member/get_subscription.php @@ -15,6 +15,8 @@ use App\YoshiKan\Application\Query\Member\Readmodel\SubscriptionReadModel; use App\YoshiKan\Application\Query\Member\Readmodel\SubscriptionReadModelCollection; +use App\YoshiKan\Domain\Model\Member\SubscriptionStatus; +use PhpOffice\PhpSpreadsheet\Spreadsheet; trait get_subscription { @@ -41,4 +43,44 @@ public function getSubscriptionsByMemberId(int $memberId): SubscriptionReadModel return $query->getByMemberId($memberId); } + + public function getSubscriptionsByStatus(string $status): SubscriptionReadModelCollection + { + $this->permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $status = SubscriptionStatus::from($status); + $query = new GetSubscription( + $this->subscriptionRepository, + $this->memberRepository + ); + + return $query->getByStatus($status); + } + + public function exportSubscriptions(array $listIds): Spreadsheet + { + $this->permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $exporter = new ExportSubscriptions($this->subscriptionRepository, $this->periodRepository); + + return $exporter->exportSubscriptions($listIds); + } + + public function printSubscriptions(array $listIds): bool + { + $this->permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $document = new PrintSubscriptions( + $this->locationRepository, + $this->federationRepository, + $this->subscriptionRepository, + $this->twig, + $this->uploadFolder, + $this->entityManager, + ); + + $document->printOverview($listIds); + + return true; + } } diff --git a/application/YoshiKan/Application/Query/Message/GetMessage.php b/application/YoshiKan/Application/Query/Message/GetMessage.php index 170dfb8..e9ad964 100644 --- a/application/YoshiKan/Application/Query/Message/GetMessage.php +++ b/application/YoshiKan/Application/Query/Message/GetMessage.php @@ -15,9 +15,9 @@ use App\YoshiKan\Application\Query\Message\Readmodel\MessageReadModel; use App\YoshiKan\Application\Query\Message\Readmodel\MessageReadModelCollection; +use App\YoshiKan\Domain\Model\Member\MemberRepository; use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; use App\YoshiKan\Domain\Model\Message\MessageRepository; -use App\YoshiKan\Infrastructure\Database\Member\MemberRepository; class GetMessage { diff --git a/application/YoshiKan/Application/Query/Reporting/GetReporting.php b/application/YoshiKan/Application/Query/Reporting/GetReporting.php new file mode 100644 index 0000000..e56d2fa --- /dev/null +++ b/application/YoshiKan/Application/Query/Reporting/GetReporting.php @@ -0,0 +1,114 @@ +federationRepository->getAll(); + $locations = $this->locationRepository->getAll(); + $period = $this->periodRepository->getActive(); + + $locationReports = []; + + $report = new DashboardNumbersReadmodel(PeriodReadModel::hydrateFromModel($period)); + + // set numbers about subscriptions + $webSubscriptions = $this->subscriptionRepository->getByStatus(SubscriptionStatus::NEW); + $duePaymentSubscriptions = $this->subscriptionRepository->getByStatus(SubscriptionStatus::AWAITING_PAYMENT); + $report->setNumbers(count($webSubscriptions), count($duePaymentSubscriptions)); + + /** @var Federation $federation */ + foreach ($federations as $federation) { + $federationRM = FederationReadModel::hydrateFromModel($federation); + $federationReport = new FederationReport($federationRM); + /** @var Location $location */ + foreach ($locations as $location) { + $locationRM = LocationReadModel::hydrateFromModel($location); + $activeMembers = $this->memberRepository->getActiveMembersByFederationAndLocation($federation, $location); + $duePayments = 0; + $totalAmount = 0; + foreach ($activeMembers as $activeMember) { + $subscriptions = $activeMember->getSubscriptions(); + /** @var Subscription $subscription */ + foreach ($subscriptions as $subscription) { + // -- count amount from the start of the active period + if ($subscription->getLicenseStart() >= $period->getStartDate() + || $subscription->getMemberSubscriptionStart() >= $period->getStartDate()) { + if (SubscriptionStatus::COMPLETE === $subscription->getStatus() + || SubscriptionStatus::PAYED === $subscription->getStatus() + || SubscriptionStatus::AWAITING_PAYMENT === $subscription->getStatus() + ) { + $totalAmount += $subscription->getTotal(); + if (SubscriptionStatus::AWAITING_PAYMENT === $subscription->getStatus()) { + $duePayments += $subscription->getTotal(); + } + } + } + } + } + $locationReport = new LocationReport($locationRM, count($activeMembers), $duePayments, $totalAmount); + $locationReports[] = $locationReport; + $federationReport->addLocationReport($locationReport); + } + $report->addFederationReport($federationReport); + } + /** @var LocationReport $locationReport */ + foreach ($this->mergeLocationReports($locationReports) as $locationReport) { + $report->addLocationReport($locationReport); + } + + return $report; + } + + private function mergeLocationReports(array $locationReports): array + { + $result = []; + $resultObject = []; + /** @var LocationReport $locationReport */ + foreach ($locationReports as $locationReport) { + if (isset($resultObject[$locationReport->getLocation()->getCode()])) { + $resultObject[$locationReport->getLocation()->getCode()]->activeMembers += $locationReport->getActiveMembers(); + $resultObject[$locationReport->getLocation()->getCode()]->duePayments += $locationReport->getDuePayments(); + $resultObject[$locationReport->getLocation()->getCode()]->totalAmount += $locationReport->getTotalAmount(); + } else { + $resultObject[$locationReport->getLocation()->getCode()] = new \stdClass(); + $resultObject[$locationReport->getLocation()->getCode()]->activeMembers = $locationReport->getActiveMembers(); + $resultObject[$locationReport->getLocation()->getCode()]->duePayments = $locationReport->getDuePayments(); + $resultObject[$locationReport->getLocation()->getCode()]->totalAmount = $locationReport->getTotalAmount(); + $resultObject[$locationReport->getLocation()->getCode()]->location = $locationReport->getLocation(); + } + } + foreach ($resultObject as $key => $value) { + $result[] = new LocationReport($value->location, $value->activeMembers, $value->duePayments, $value->totalAmount); + } + + return $result; + } +} diff --git a/application/YoshiKan/Application/Query/Reporting/Readmodel/DashboardNumbersReadmodel.php b/application/YoshiKan/Application/Query/Reporting/Readmodel/DashboardNumbersReadmodel.php new file mode 100644 index 0000000..72f446b --- /dev/null +++ b/application/YoshiKan/Application/Query/Reporting/Readmodel/DashboardNumbersReadmodel.php @@ -0,0 +1,106 @@ +federationReports[] = $federationReport; + $this->activeMembers += $federationReport->getActiveMembers(); + $this->duePayments += $federationReport->getDuePayments(); + $this->totalAmount += $federationReport->getTotalAmount(); + } + + public function addLocationReport(LocationReport $locationReport): void + { + $this->locationReports[] = $locationReport; + } + + public function setNumbers($numberOfWebSubscriptions, $numberOfDuePayments): void + { + $this->numberOfWebSubscriptions = $numberOfWebSubscriptions; + $this->numberOfDuePayments = $numberOfDuePayments; + } + + // ————————————————————————————————————————————————————————————————————————— + // What to render as json + // ————————————————————————————————————————————————————————————————————————— + + public function jsonSerialize(): \stdClass + { + $json = new \stdClass(); + $json->activePeriod = $this->activePeriod; + $json->federationReports = $this->getFederationReports(); + $json->locationReports = $this->getLocationReports(); + $json->activeMembers = $this->getActiveMembers(); + $json->duePayments = $this->getDuePayments(); + $json->totalAmount = $this->getTotalAmount(); + $json->numberOfWebSubscriptions = $this->getNumberOfWebSubscriptions(); + $json->numberOfDuePayments = $this->getNumberOfDuePayments(); + + return $json; + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getFederationReports(): array + { + return $this->federationReports; + } + + public function getLocationReports(): array + { + return $this->locationReports; + } + + public function getActiveMembers(): int + { + return $this->activeMembers; + } + + public function getDuePayments(): float + { + return $this->duePayments; + } + + public function getTotalAmount(): float + { + return $this->totalAmount; + } + + public function getActivePeriod(): PeriodReadModel + { + return $this->activePeriod; + } + + public function getNumberOfWebSubscriptions(): int + { + return $this->numberOfWebSubscriptions; + } + + public function getNumberOfDuePayments(): int + { + return $this->numberOfDuePayments; + } +} diff --git a/application/YoshiKan/Application/Query/Reporting/Readmodel/FederationReport.php b/application/YoshiKan/Application/Query/Reporting/Readmodel/FederationReport.php new file mode 100644 index 0000000..18c9175 --- /dev/null +++ b/application/YoshiKan/Application/Query/Reporting/Readmodel/FederationReport.php @@ -0,0 +1,74 @@ +locationReports[] = $locationReport; + $this->activeMembers += $locationReport->getActiveMembers(); + $this->duePayments += $locationReport->getDuePayments(); + $this->totalAmount += $locationReport->getTotalAmount(); + } + + // ————————————————————————————————————————————————————————————————————————— + // What to render as json + // ————————————————————————————————————————————————————————————————————————— + + public function jsonSerialize(): \stdClass + { + $json = new \stdClass(); + $json->federation = $this->getFederation(); + $json->locationReports = $this->getLocationReports(); + $json->activeMembers = $this->getActiveMembers(); + $json->duePayments = $this->getDuePayments(); + $json->totalAmount = $this->getTotalAmount(); + + return $json; + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getFederation(): FederationReadModel + { + return $this->federation; + } + + public function getLocationReports(): array + { + return $this->locationReports; + } + + public function getActiveMembers(): int + { + return $this->activeMembers; + } + + public function getDuePayments(): float + { + return $this->duePayments; + } + + public function getTotalAmount(): float + { + return $this->totalAmount; + } +} diff --git a/application/YoshiKan/Application/Query/Reporting/Readmodel/LocationReport.php b/application/YoshiKan/Application/Query/Reporting/Readmodel/LocationReport.php new file mode 100644 index 0000000..84ccc1f --- /dev/null +++ b/application/YoshiKan/Application/Query/Reporting/Readmodel/LocationReport.php @@ -0,0 +1,58 @@ +location = $this->getLocation(); + $json->activeMembers = $this->getActiveMembers(); + $json->duePayments = $this->getDuePayments(); + $json->totalAmount = $this->getTotalAmount(); + + return $json; + } + + // ————————————————————————————————————————————————————————————————————————— + // Getters + // ————————————————————————————————————————————————————————————————————————— + + public function getLocation(): LocationReadModel + { + return $this->location; + } + + public function getActiveMembers(): int + { + return $this->activeMembers; + } + + public function getDuePayments(): float + { + return $this->duePayments; + } + + public function getTotalAmount(): float + { + return $this->totalAmount; + } +} diff --git a/application/YoshiKan/Application/Query/Reporting/get_reporting.php b/application/YoshiKan/Application/Query/Reporting/get_reporting.php new file mode 100644 index 0000000..4124d92 --- /dev/null +++ b/application/YoshiKan/Application/Query/Reporting/get_reporting.php @@ -0,0 +1,26 @@ +permission->CheckRole(['ROLE_DEVELOPER', 'ROLE_ADMIN', 'ROLE_CHIEF_EDITOR']); + + $query = new GetReporting( + $this->memberRepository, + $this->locationRepository, + $this->federationRepository, + $this->subscriptionRepository, + $this->periodRepository + ); + + return $query->getDashboardNumbers(); + } +} diff --git a/application/YoshiKan/Application/QueryBus.php b/application/YoshiKan/Application/QueryBus.php index 8063dd5..992da46 100644 --- a/application/YoshiKan/Application/QueryBus.php +++ b/application/YoshiKan/Application/QueryBus.php @@ -16,6 +16,7 @@ use App\YoshiKan\Application\Query\Member\get_configuration; use App\YoshiKan\Application\Query\Member\get_member; use App\YoshiKan\Application\Security\BasePermissionService; +use App\YoshiKan\Domain\Model\Member\FederationRepository; use App\YoshiKan\Domain\Model\Member\GradeRepository; use App\YoshiKan\Domain\Model\Member\GroupRepository; use App\YoshiKan\Domain\Model\Member\LocationRepository; @@ -24,7 +25,6 @@ use App\YoshiKan\Domain\Model\Member\SettingsRepository; use App\YoshiKan\Domain\Model\Member\SubscriptionRepository; use App\YoshiKan\Domain\Model\Product\JudogiRepository; -use App\YoshiKan\Infrastructure\Database\Member\FederationRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\Security; use Twig\Environment; diff --git a/application/YoshiKan/Application/Settings.php b/application/YoshiKan/Application/Settings.php new file mode 100644 index 0000000..ffa2042 --- /dev/null +++ b/application/YoshiKan/Application/Settings.php @@ -0,0 +1,10 @@ +uuid = $uuid; @@ -85,6 +97,7 @@ public static function make( string $code, string $name, int $yearlySubscriptionFee, + string $publicLabel, ): self { return new self( $uuid, @@ -92,6 +105,7 @@ public static function make( $code, $name, $yearlySubscriptionFee, + $publicLabel ); } @@ -99,10 +113,12 @@ public function change( string $code, string $name, int $yearlySubscriptionFee, + string $publicLabel, ): void { - $this->code = $code; - $this->name = $name; + $this->code = trim($code); + $this->name = trim($name); $this->yearlySubscriptionFee = $yearlySubscriptionFee; + $this->publicLabel = trim($publicLabel); } // ————————————————————————————————————————————————————————————————————————— @@ -113,16 +129,21 @@ public function change( // Getters // ————————————————————————————————————————————————————————————————————————— - public function getCode(): ?string + public function getCode(): string { return $this->code; } - public function getName(): ?string + public function getName(): string { return $this->name; } + public function getPublicLabel(): string + { + return $this->publicLabel; + } + public function getYearlySubscriptionFee(): ?int { return $this->yearlySubscriptionFee; diff --git a/application/YoshiKan/Domain/Model/Member/MemberRepository.php b/application/YoshiKan/Domain/Model/Member/MemberRepository.php index d560ba6..a7a6861 100644 --- a/application/YoshiKan/Domain/Model/Member/MemberRepository.php +++ b/application/YoshiKan/Domain/Model/Member/MemberRepository.php @@ -41,4 +41,6 @@ public function search( ): array; public function listActiveMembers(): array; + + public function getActiveMembersByFederationAndLocation(Federation $federation, Location $location): array; } diff --git a/application/YoshiKan/Domain/Model/Member/Subscription.php b/application/YoshiKan/Domain/Model/Member/Subscription.php index 547501c..5ee3a7e 100644 --- a/application/YoshiKan/Domain/Model/Member/Subscription.php +++ b/application/YoshiKan/Domain/Model/Member/Subscription.php @@ -628,9 +628,9 @@ public function isLicenseIsPayed(): bool return $this->licenseIsPayed; } - public function getMessages(): ?Collection + public function getMessages(): array { - return $this->messages; + return $this->messages->getValues(); } /** @@ -647,26 +647,59 @@ public function getItems(): array public function getSubscriptionFee(bool $withReduction = true): float { - $fee = 0; + $memberShipFee = 0; if ($this->memberSubscriptionIsHalfYear) { if (1 === $this->numberOfTraining) { - $fee = floatval($this->settings['halfYearlyFee1Training']); + $memberShipFee = floatval($this->settings['halfYearlyFee1Training']); } else { - $fee = floatval($this->settings['halfYearlyFee2Training']); + $memberShipFee = floatval($this->settings['halfYearlyFee2Training']); } } else { if (1 === $this->numberOfTraining) { - $fee = floatval($this->settings['yearlyFee1Training']); + $memberShipFee = floatval($this->settings['yearlyFee1Training']); } else { - $fee = floatval($this->settings['yearlyFee2Training']); + $memberShipFee = floatval($this->settings['yearlyFee2Training']); } } - if ($this->isReductionFamily && $withReduction) { - $reduction = floatval($this->settings['familyDiscount']) * $fee / 100; - $fee = ceil($fee - $reduction); + $reduction = floatval($this->settings['familyDiscount']) * $memberShipFee / 100; + $memberShipFee = ceil($memberShipFee - $reduction); + } + + return $memberShipFee; + } + + public function calculate(): float + { + $memberShipFee = $this->getSubscriptionFee(false); + + if ($this->isExtraTraining) { + $memberShipFee += floatval($this->settings['extraTrainingFee']); + } + if ($this->isReductionFamily) { + $reduction = floatval($this->settings['familyDiscount']) * $memberShipFee / 100; + $memberShipFee = ceil($memberShipFee - $reduction); + } + if ($this->isNewMember) { + $memberShipFee += floatval($this->settings['newMemberSubscriptionFee']); } - return $fee; + // -- set some total counts ------------------------------------------------------------------------------------ + + if ($this->isMemberSubscriptionIsPartSubscription()) { + $this->memberSubscriptionTotal = $memberShipFee; + } else { + $this->memberSubscriptionTotal = 0; + } + + if ($this->licenseIsPartSubscription()) { + $this->licenseTotal = $this->federation->getYearlySubscriptionFee(); + } else { + $this->licenseTotal = 0; + } + + $this->total = $this->memberSubscriptionTotal + $this->licenseTotal; + + return $this->total; } } diff --git a/application/YoshiKan/Domain/Model/Member/SubscriptionItemType.php b/application/YoshiKan/Domain/Model/Member/SubscriptionItemType.php index f3a49f6..5c5dbab 100644 --- a/application/YoshiKan/Domain/Model/Member/SubscriptionItemType.php +++ b/application/YoshiKan/Domain/Model/Member/SubscriptionItemType.php @@ -17,8 +17,9 @@ enum SubscriptionItemType: string { case LICENSE = 'license'; case MEMBERSHIP = 'membership'; - case EXTRA_TRAINING = 'extra_training'; + case EXTRA_TRAINING = 'extra-training'; case REDUCTION = 'reduction'; - case SUBSCRIPTION_WELCOME = 'subscription_welcome'; + case SUBSCRIPTION_WELCOME = 'subscription-welcome'; + case JUDOGI = 'judogi'; case OTHER = 'other'; } diff --git a/application/YoshiKan/Domain/Model/Member/SubscriptionStatus.php b/application/YoshiKan/Domain/Model/Member/SubscriptionStatus.php index 13ccd09..77c752f 100644 --- a/application/YoshiKan/Domain/Model/Member/SubscriptionStatus.php +++ b/application/YoshiKan/Domain/Model/Member/SubscriptionStatus.php @@ -14,7 +14,7 @@ enum SubscriptionStatus: string { case NEW = 'nieuw'; - case AWAITING_PAYMENT = 'wachtend op betaling'; + case AWAITING_PAYMENT = 'wachtend-op-betaling'; case PAYED = 'betaald'; case COMPLETE = 'afgewerkt'; case CANCELED = 'canceled'; diff --git a/application/YoshiKan/Domain/Model/Member/SubscriptionType.php b/application/YoshiKan/Domain/Model/Member/SubscriptionType.php index 85e5fa5..2837f44 100644 --- a/application/YoshiKan/Domain/Model/Member/SubscriptionType.php +++ b/application/YoshiKan/Domain/Model/Member/SubscriptionType.php @@ -13,8 +13,8 @@ enum SubscriptionType: string { - case NEW_SUBSCRIPTION = 'nieuwe_inschrijving'; - case RENEWAL_FULL = 'volledige_hernieuwing'; - case RENEWAL_MEMBERSHIP = 'hernieuwing_lidmaatschap'; - case RENEWAL_LICENSE = 'hernieuwing_vergunning'; + case NEW_SUBSCRIPTION = 'nieuwe-inschrijving'; + case RENEWAL_FULL = 'volledige-hernieuwing'; + case RENEWAL_MEMBERSHIP = 'hernieuwing-lidmaatschap'; + case RENEWAL_LICENSE = 'hernieuwing-vergunning'; } diff --git a/application/YoshiKan/Infrastructure/Database/Member/FederationRepository.php b/application/YoshiKan/Infrastructure/Database/Member/FederationRepository.php index aee01b4..fc105a6 100644 --- a/application/YoshiKan/Infrastructure/Database/Member/FederationRepository.php +++ b/application/YoshiKan/Infrastructure/Database/Member/FederationRepository.php @@ -84,7 +84,7 @@ public function getByUuid(Uuid $uuid): Federation public function getAll(): array { $q = $this->createQueryBuilder('t')->andWhere('0 = 0'); - $q->addOrderBy('t.id', 'DESC'); + $q->addOrderBy('t.sequence', 'ASC'); return $q->getQuery()->getResult(); } diff --git a/application/YoshiKan/Infrastructure/Database/Member/MemberRepository.php b/application/YoshiKan/Infrastructure/Database/Member/MemberRepository.php index 10a5dea..c3ca847 100644 --- a/application/YoshiKan/Infrastructure/Database/Member/MemberRepository.php +++ b/application/YoshiKan/Infrastructure/Database/Member/MemberRepository.php @@ -13,6 +13,7 @@ namespace App\YoshiKan\Infrastructure\Database\Member; +use App\YoshiKan\Domain\Model\Member\Federation; use App\YoshiKan\Domain\Model\Member\Grade; use App\YoshiKan\Domain\Model\Member\Location; use App\YoshiKan\Domain\Model\Member\Member; @@ -166,4 +167,18 @@ public function listActiveMembers(): array return $q->getQuery()->getResult(); } + + public function getActiveMembersByFederationAndLocation(Federation $federation, Location $location): array + { + $q = $this->createQueryBuilder('t') + ->where('t.status = :status') + ->setParameter('status', MemberStatus::ACTIVE->value) + ->andWhere('t.location = :locationId') + ->setParameter('locationId', $location->getId()) + ->andWhere('t.federation = :federationId') + ->setParameter('federationId', $federation->getId()) + ->addOrderBy('t.id', 'DESC'); + + return $q->getQuery()->getResult(); + } } diff --git a/application/YoshiKan/Infrastructure/Templates/mail/member_extendMemberSubscription_mail.html.twig b/application/YoshiKan/Infrastructure/Templates/mail/member_extendMemberSubscription_mail.html.twig index e7997f1..3cbdd05 100644 --- a/application/YoshiKan/Infrastructure/Templates/mail/member_extendMemberSubscription_mail.html.twig +++ b/application/YoshiKan/Infrastructure/Templates/mail/member_extendMemberSubscription_mail.html.twig @@ -10,13 +10,13 @@ Beste {{ subscription.contactFirstname }} {{ subscription.contactLastname }},

- {% if(subscription.type.value == 'hernieuwing_lidmaatschap') %} + {% if(subscription.type.value == 'hernieuwing-lidmaatschap') %} Het lidmaatschap {% endif %} - {% if(subscription.type.value == 'hernieuwing_vergunning') %} + {% if(subscription.type.value == 'hernieuwing-vergunning') %} De vergunning {% endif %} - {% if(subscription.type.value == 'volledige_hernieuwing') %} + {% if(subscription.type.value == 'volledige-hernieuwing') %} Het lidmaatschap en de vergunning {% endif %} is verlopen of staat op het punt binnenkort te verlopen. diff --git a/application/YoshiKan/Infrastructure/Templates/mail/web_confirmation_mail.html.twig b/application/YoshiKan/Infrastructure/Templates/mail/web_confirmation_mail.html.twig index 530bfe7..a114912 100644 --- a/application/YoshiKan/Infrastructure/Templates/mail/web_confirmation_mail.html.twig +++ b/application/YoshiKan/Infrastructure/Templates/mail/web_confirmation_mail.html.twig @@ -3,53 +3,46 @@ {% block title %}{{ subject }}{% endblock %} {% block body %} -

Dag {{ subscription.contactFirstname }},

+ + {# judoka ------------------------------------------------------------------------------------------------------ #} +

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

- Bedankt voor je {% if(subscription.isNewMember) %}{% else %}(her){% endif %}inschrijving van - {{ subscription.firstname }} {{ subscription.lastname }} - (° {{ subscription.dateOfBirth | date('d/m/Y') }} - {% if(subscription.isNewMember) %}- {{ subscription.gender.value }}{% endif %}) - {% if(subscription.isNewMember) %} - als nieuw lid. - {% else %} - . - {% endif %} + Bedankt voor je inschrijving van + {{ subscription.lastname | upper }} {{ subscription.firstname }} + (° {{ subscription.dateOfBirth | date('d/m/Y') }} - {{ subscription.gender.value }}) + als nieuw lid.

{# extra paragraph for a new member ----------------------------------------------------------------------------- #} - {% if(subscription.isNewMember) %} -

- Contact -
{{ subscription.contactFirstname }} {{ subscription.contactLastname }} -
{{ subscription.addressStreet }} {{ subscription.addressNumber }} - {% if(subscription.addressBox) != '' %} bus {{ subscription.adressBox }}{% endif %} -
{{ subscription.addressZip }} {{ subscription.addressCity }} -

- {% endif %} +

+ Contact +
{{ subscription.contactLastname }} {{ subscription.contactFirstname }} +
{{ subscription.addressStreet }} {{ subscription.addressNumber }} + {% if(subscription.addressBox) != '' %} bus {{ subscription.adressBox }}{% endif %} +
{{ subscription.addressZip }} {{ subscription.addressCity }} +

+ {# summary ------------------------------------------------------------------------------------------------------ #}

Referentie: YKS-{{ subscription.id }} -

{{ subscription.period.name }}
- Locatie: {{ subscription.location.name }} -
- Type: {{ subscription.type.value }}, - {% if(subscription.numberOfTraining == 1) %} - 1 training per week +
- Lidmaatschap: + {% if(subscription.memberSubscriptionIsHalfYear == 1) %} + Halfjaarlijks {% else %} - 2 trainingen per week - {% endif %} - {% if(subscription.isExtraTraining) %} -
- Extra supplement 3 tot 5 trainingen per week. - {% endif %} - {% if(subscription.isNewMember) %} -
- Inschrijvingspakket: judogids, judopaspoort, leskaart + sportzak voor judopak. + Jaarlijks {% endif %} - {% if(subscription.isJudogiBelt) %} -
- Judopak + gordel + {% if(subscription.numberOfTraining == 1) %} +
- 1 training per week + {% elseif(subscription.numberOfTraining == 2) %} +
- 2 trainingen per week + {% else %} +
- 3 tot 5 trainingen per week. {% endif %} +
- Inschrijvingspakket: judogids, judopaspoort, leskaart + sportzak voor judopak. {% if(subscription.isReductionFamily) %}
- 10% Korting als 2e en 3e kind van éénzelfde familie. {% endif %}

-

 

We kijken alles nog eens na. Van zodra alles in orde is, krijg je van ons een definitieve bevestiging en de betalingsinstructies via email. @@ -58,7 +51,7 @@ Tot binnenkort.

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

{% endblock %} diff --git a/application/YoshiKan/Infrastructure/Templates/pdf/subscription_detail.html.twig b/application/YoshiKan/Infrastructure/Templates/pdf/subscription_detail.html.twig new file mode 100644 index 0000000..3150dce --- /dev/null +++ b/application/YoshiKan/Infrastructure/Templates/pdf/subscription_detail.html.twig @@ -0,0 +1,178 @@ +{# #} +{# 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. #} +{# #} + + + + + + + +{# ------------------------------------------------------------------------------------------------------------------ #} + +{% for subscription in list.subscriptions %} + + + + + + +
+ + + + + + +
Datum  {{ list.generatedOn |date('d/m/Y') }}Plaats  {{ subscription.location.name }}Ref.   + YKS-{{ subscription.id }} +
+ + + + + + + + + + + + + + + + + +
Naam{{ subscription.lastname | upper }} {{ subscription.firstname }}
Gebdatum + ° {{ subscription.dateOfBirth |date('d/m/Y') }} ( {{ subscription.gender.value }} ) +
Adres + {{ subscription.member.addressStreet }} + {{ subscription.member.addressNumber }} + {% if(subscription.member.addressBox != '') %} + bus {{ subscription.member.addressBox }} + {% endif %} +
{{ subscription.member.addressZip }} + {{ subscription.member.addressCity }} +
Contact + {{ subscription.contactLastname }} {{ subscription.contactFirstname }} + <{{ subscription.contactEmail }}> + {% if(subscription.contactPhone != '') %} +
{{ subscription.contactPhone }} + {% endif %} +
+ + + {% for item in subscription.items %} + {% if loop.first %} + + {% else %} + + {% endif %} + + {% if(item.price == 0) %} + + + {% else %} + + + + {% endif %} + {% endfor %} +
{{ item.name }}
{{ item.name }} {{ item.price }} €
+
+
+
+ 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.yoshi-kan.be +
+
+
+
+
+ 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:       + {{ subscription.total }} € + +
+
+
+ Handtekening ouder of voogd: +


  +
+
+ +{% endfor %} + +{# ------------------------------------------------------------------------------------------------------------------ #} + + + + diff --git a/application/YoshiKan/Infrastructure/Web/Controller/ApiController.php b/application/YoshiKan/Infrastructure/Web/Controller/ApiController.php index e9b8294..f944f51 100644 --- a/application/YoshiKan/Infrastructure/Web/Controller/ApiController.php +++ b/application/YoshiKan/Infrastructure/Web/Controller/ApiController.php @@ -23,6 +23,7 @@ use App\YoshiKan\Domain\Model\Member\Period; use App\YoshiKan\Domain\Model\Member\Settings; use App\YoshiKan\Domain\Model\Member\Subscription; +use App\YoshiKan\Domain\Model\Member\SubscriptionItem; use App\YoshiKan\Domain\Model\Product\Judogi; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -89,6 +90,7 @@ public function __construct( $this->mailer, $this->uploadFolder, $this->entityManager->getRepository(Subscription::class), + $this->entityManager->getRepository(SubscriptionItem::class), $this->entityManager->getRepository(Location::class), $this->entityManager->getRepository(Period::class), $this->entityManager->getRepository(Judogi::class), @@ -133,12 +135,15 @@ public function getWebConfiguration(): JsonResponse return new JsonResponse($response, 200, $this->apiAccess); } + /** + * @throws \Exception + */ #[Route('/inschrijving/api/subscribe', name: 'inschrijving_subscribe', methods: ['POST', 'PUT'])] public function subscribeAction(Request $request): JsonResponse { $jsonCommand = json_decode($request->request->get('subscription')); - $response = $this->commandBus->WebSubscriptionAction($jsonCommand); - $result = $this->commandBus->WebConfirmationMail($response->id); + $response = $this->commandBus->newMemberWebSubscription($jsonCommand); + $result = $this->commandBus->newMemberWebSubscriptionMail($response->id); return new JsonResponse($response, 200, $this->apiAccess); } diff --git a/application/YoshiKan/Infrastructure/Web/Controller/MemberApiController.php b/application/YoshiKan/Infrastructure/Web/Controller/MemberApiController.php index 6e6f185..e35a52e 100644 --- a/application/YoshiKan/Infrastructure/Web/Controller/MemberApiController.php +++ b/application/YoshiKan/Infrastructure/Web/Controller/MemberApiController.php @@ -40,6 +40,7 @@ use App\YoshiKan\Infrastructure\Web\Controller\Routes\Member\settings_routes; use App\YoshiKan\Infrastructure\Web\Controller\Routes\Member\subscription_routes; use App\YoshiKan\Infrastructure\Web\Controller\Routes\Message\message_routes; +use App\YoshiKan\Infrastructure\Web\Controller\Routes\Reporting\reporting_routes; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -70,6 +71,7 @@ class MemberApiController extends AbstractController use member_image_routes; use federation_routes; use message_routes; + use reporting_routes; // —————————————————————————————————————————————————————————————————————————— // Attributes diff --git a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/subscription_routes.php b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/subscription_routes.php index acb5453..f9600d8 100644 --- a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/subscription_routes.php +++ b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Member/subscription_routes.php @@ -29,6 +29,38 @@ public function getSubscriptionById(int $id): JsonResponse return new JsonResponse($response, 200, $this->apiAccess); } + /** + * @throws \Exception + */ + #[Route('/mm/api/subscription/{id}/mark-as-paid', requirements: ['id' => '\d+'], methods: ['POST', 'PUT'])] + public function markSubscriptionAsPayed(int $id, Request $request): JsonResponse + { + $jsonCommand = json_decode($request->request->get('command')); + $response = $this->commandBus->markSubscriptionAsPayed($jsonCommand); + + return new JsonResponse($response, 200, $this->apiAccess); + } + + /** + * @throws \Exception + */ + #[Route('/mm/api/subscription/{id}/cancel', requirements: ['id' => '\d+'], methods: ['POST', 'PUT'])] + public function markSubscriptionAsCanceled(int $id, Request $request): JsonResponse + { + $jsonCommand = json_decode($request->request->get('command')); + $response = $this->commandBus->markSubscriptionAsCanceled($jsonCommand); + + return new JsonResponse($response, 200, $this->apiAccess); + } + + #[Route('/mm/api/subscription/{status}', methods: ['GET'])] + public function getAllSubscriptions(string $status, Request $request): JsonResponse + { + $response = $this->queryBus->getSubscriptionsByStatus($status); + + return new JsonResponse($response->getCollection(), 200, $this->apiAccess); + } + /** * @throws Exception */ @@ -36,10 +68,9 @@ public function getSubscriptionById(int $id): JsonResponse public function exportSubscriptions(Request $request): void { $listIds = $request->query->get('ids'); - $arListIds = explode(',', $listIds); - $spreadsheet = $this->queryBus->exportSubscriptions($arListIds); + $spreadsheet = $this->queryBus->exportSubscriptions($this->convertToArrayOfIds($listIds)); $now = new \DateTimeImmutable(); - $fileName = $now->format('Ymd').'_yoshi-kan_inschrijvingen.xlsx'; + $fileName = $now->format('Ymd').'_yoshi-kan-inschrijvingen.xlsx'; $writer = new Xlsx($spreadsheet); ob_end_clean(); @@ -49,6 +80,25 @@ public function exportSubscriptions(Request $request): void exit; } + #[Route('/mm/api/subscriptions/print', methods: ['GET'])] + public function printSubscriptions(Request $request): void + { + $listIds = $request->query->get('ids'); + $document = $this->queryBus->printSubscriptions($this->convertToArrayOfIds($listIds)); + + exit; + } + + private function convertToArrayOfIds(string $ids): array + { + $arListIdsInt = []; + foreach (explode(',', $ids) as $id) { + $arListIdsInt[] = intval($id); + } + + return $arListIdsInt; + } + // #[Route('/mm/api/subscribe', name: 'backend_subscribe', methods: ['POST', 'PUT'])] // public function backendSubscribeAction(Request $request): JsonResponse // { diff --git a/application/YoshiKan/Infrastructure/Web/Controller/Routes/Reporting/reporting_routes.php b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Reporting/reporting_routes.php new file mode 100644 index 0000000..3cb3044 --- /dev/null +++ b/application/YoshiKan/Infrastructure/Web/Controller/Routes/Reporting/reporting_routes.php @@ -0,0 +1,19 @@ +queryBus->getDashboardNumbers(), 200, $this->apiAccess); + } +} diff --git a/assets/components/appInschrijving.vue b/assets/components/appInschrijving.vue index ab5c7f9..1d59f43 100644 --- a/assets/components/appInschrijving.vue +++ b/assets/components/appInschrijving.vue @@ -1,41 +1,83 @@ @@ -59,10 +57,10 @@ import {useMemberStore} from "@/store/member"; import {ref} from "vue"; import type {Subscription} from "@/api/query/model"; import moment from "moment"; -import SubscriptionBadge from "@/components/subscription/common/SubscriptionBadge.vue"; -import SubscriptionStatus from "@/components/subscription/common/SubscriptionStatus.vue"; -import SubscriptionType from "@/components/subscription/common/SubscriptionType.vue"; -import SubscriptionDetail from "@/components/subscription/detail/SubscriptionDetail.vue"; +import SubscriptionBadge from "@/components/subscription/common/subscriptionBadge.vue"; +import SubscriptionStatus from "@/components/subscription/common/subscriptionStatus.vue"; +import SubscriptionType from "@/components/subscription/common/subscriptionType.vue"; +import SubscriptionDetail from "@/components/subscription/detail/subscriptionDetail.vue"; const memberStore = useMemberStore(); const showSubscriptionDetail = ref(false); @@ -74,6 +72,10 @@ async function showSubscriptionDetailFn(subscription: Subscription) { showSubscriptionDetail.value = true; } +function hideSubscriptionDetailFn() { + showSubscriptionDetail.value = false; +} + diff --git a/frontends/member_module/src/components/subscription/common/SubscriptionBadge.vue b/frontends/member_module/src/components/subscription/common/SubscriptionBadge.vue index 783eae6..37426cd 100644 --- a/frontends/member_module/src/components/subscription/common/SubscriptionBadge.vue +++ b/frontends/member_module/src/components/subscription/common/SubscriptionBadge.vue @@ -1,5 +1,5 @@ @@ -7,6 +7,7 @@ + + diff --git a/frontends/member_module/src/components/subscription/common/SubscriptionStatus.vue b/frontends/member_module/src/components/subscription/common/subscriptionStatus.vue similarity index 68% rename from frontends/member_module/src/components/subscription/common/SubscriptionStatus.vue rename to frontends/member_module/src/components/subscription/common/subscriptionStatus.vue index 5b6b1a2..7548330 100644 --- a/frontends/member_module/src/components/subscription/common/SubscriptionStatus.vue +++ b/frontends/member_module/src/components/subscription/common/subscriptionStatus.vue @@ -1,5 +1,5 @@ @@ -7,6 +7,7 @@ + + diff --git a/frontends/member_module/src/components/subscription/detail/SubscriptionDetail.vue b/frontends/member_module/src/components/subscription/detail/SubscriptionDetail.vue deleted file mode 100644 index 877e57f..0000000 --- a/frontends/member_module/src/components/subscription/detail/SubscriptionDetail.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/frontends/member_module/src/components/subscription/detail/subscriptionDetail.vue b/frontends/member_module/src/components/subscription/detail/subscriptionDetail.vue new file mode 100644 index 0000000..68f525b --- /dev/null +++ b/frontends/member_module/src/components/subscription/detail/subscriptionDetail.vue @@ -0,0 +1,268 @@ + + + + + diff --git a/frontends/member_module/src/components/subscription/overview/overviewArchive.vue b/frontends/member_module/src/components/subscription/overview/overviewArchive.vue new file mode 100644 index 0000000..2fd9d9e --- /dev/null +++ b/frontends/member_module/src/components/subscription/overview/overviewArchive.vue @@ -0,0 +1,15 @@ + + + diff --git a/frontends/member_module/src/components/subscription/overview/overviewDuePayment.vue b/frontends/member_module/src/components/subscription/overview/overviewDuePayment.vue new file mode 100644 index 0000000..52fae64 --- /dev/null +++ b/frontends/member_module/src/components/subscription/overview/overviewDuePayment.vue @@ -0,0 +1,15 @@ + + + diff --git a/frontends/member_module/src/components/subscription/overview/overviewNew.vue b/frontends/member_module/src/components/subscription/overview/overviewNew.vue new file mode 100644 index 0000000..753f9a5 --- /dev/null +++ b/frontends/member_module/src/components/subscription/overview/overviewNew.vue @@ -0,0 +1,20 @@ + + + diff --git a/frontends/member_module/src/components/subscription/overview/overviewSubscriptionsTable.vue b/frontends/member_module/src/components/subscription/overview/overviewSubscriptionsTable.vue new file mode 100644 index 0000000..194a025 --- /dev/null +++ b/frontends/member_module/src/components/subscription/overview/overviewSubscriptionsTable.vue @@ -0,0 +1,381 @@ + + + diff --git a/frontends/member_module/src/main.ts b/frontends/member_module/src/main.ts index 17ff7b8..eec4381 100644 --- a/frontends/member_module/src/main.ts +++ b/frontends/member_module/src/main.ts @@ -53,6 +53,7 @@ import ColumnGroup from 'primevue/columngroup'; import Row from 'primevue/row'; import TriStateCheckbox from 'primevue/tristatecheckbox'; import InputNumber from 'primevue/inputnumber'; +import Chart from 'primevue/chart'; // ----------------------------------------------------------------------------------- services import ToastService from "primevue/toastservice"; @@ -111,6 +112,7 @@ app.component("ColumnGroup", ColumnGroup); app.component("Row", Row); app.component("TriStateCheckbox", TriStateCheckbox); app.component("InputNumber", InputNumber); +app.component("Chart", Chart); app.directive('tooltip', Tooltip); @@ -121,7 +123,7 @@ import VueProgressBar from '@aacassandra/vue3-progressbar'; const options = { color: "#324bed", failedColor: "#ff0000", - thickness: "2px", + thickness: "10px", transition: { speed: "0.2s", opacity: "0.6s", @@ -165,7 +167,7 @@ app.component('font-awesome-icon', FontAwesomeIcon); // --------------------------------------------------------------------------------------- app.use(router) app.use(createPinia()) -app.use(PrimeVue, {ripple: true}); +app.use(PrimeVue, { ripple: true, inputStyle: "filled" , unstyled: false}); app.use(ConfirmationService); app.use(ToastService); diff --git a/frontends/member_module/src/router/index.ts b/frontends/member_module/src/router/index.ts index 3e8957e..9ec5ffc 100644 --- a/frontends/member_module/src/router/index.ts +++ b/frontends/member_module/src/router/index.ts @@ -25,12 +25,12 @@ const router = createRouter({ { path: 'web', name: 'web', - component: () => import('../views/subscription/SubscriptionNew.vue') + component: () => import('../views/subscription/SubscriptionNewView.vue') }, { path: 'te-betalen', name: 'te-betalen', - component: () => import('../views/subscription/SubscriptionDuePayment.vue') + component: () => import('../views/subscription/SubscriptionDuePaymentView.vue') }, { path: 'export', diff --git a/frontends/member_module/src/store/app.ts b/frontends/member_module/src/store/app.ts index b666d7c..153c0fd 100644 --- a/frontends/member_module/src/store/app.ts +++ b/frontends/member_module/src/store/app.ts @@ -10,29 +10,34 @@ import {defineStore} from 'pinia' import type {Configuration} from "@/api/query/model"; import {getConfiguration} from "@/api/query/getConfiguration"; +import type {DashboardNumbers} from "@/api/query/reportModel"; +import {getDashboardNumbers} from "@/api/query/getDashboardNumbers"; export type AppState = { - toastLifeTime: number; - isLoading: boolean; - isConfigurationLoaded: boolean; - configuration?: Configuration; + toastLifeTime: number; + isLoading: boolean; + isConfigurationLoaded: boolean; + configuration?: Configuration; + dashboardNumbers?: DashboardNumbers; } export const useAppStore = defineStore({ - id: "app", - state: (): AppState => ({ - toastLifeTime: 3000, - isLoading: false, - isConfigurationLoaded: false, - configuration: undefined, - }), - actions: { - async loadConfiguration() { - this.isLoading = true; - this.configuration = await getConfiguration(); - this.isConfigurationLoaded = true; - this.isLoading = false; + id: "app", + state: (): AppState => ({ + toastLifeTime: 3000, + isLoading: false, + isConfigurationLoaded: false, + configuration: undefined, + dashboardNumbers: undefined + }), + actions: { + async loadConfiguration() { + this.isLoading = true; + this.configuration = await getConfiguration(); + this.dashboardNumbers = await getDashboardNumbers(); + this.isConfigurationLoaded = true; + this.isLoading = false; + }, }, - }, - getters: {}, + getters: {}, }); diff --git a/frontends/member_module/src/store/subscriptionOverview.ts b/frontends/member_module/src/store/subscriptionOverview.ts new file mode 100644 index 0000000..0f93a53 --- /dev/null +++ b/frontends/member_module/src/store/subscriptionOverview.ts @@ -0,0 +1,28 @@ +import {defineStore} from "pinia"; +import {ref} from "vue"; +import type {Subscription} from "@/api/query/model"; +import {getSubscriptionsNew} from "@/api/query/getSubscriptionsNew"; +import {getSubscriptionsDuePayment} from "@/api/query/getSubscriptionsDuePayment"; +import {getSubscriptionsPaid} from "@/api/query/getSubscriptionsPaid"; +import {getSubscriptionsComplete} from "@/api/query/getSubscriptionsComplete"; + +export const useSubscriptionOverviewStore = defineStore('subscriptionOverview', () => { + + const subscriptionsNew = ref>([]); + const subscriptionsDuePayment = ref>([]); + const subscriptionsArchive = ref>([]); + const isLoading = ref(false); + + async function loadSubscriptions() { + isLoading.value = true; + subscriptionsNew.value = await getSubscriptionsNew(); + subscriptionsDuePayment.value = await getSubscriptionsDuePayment(); + const subscriptionsPaid = await getSubscriptionsPaid(); + const subscriptionsComplete = await getSubscriptionsComplete(); + subscriptionsArchive.value = [...subscriptionsPaid, ...subscriptionsComplete]; + isLoading.value = false; + } + + return {subscriptionsNew, subscriptionsDuePayment, subscriptionsArchive, loadSubscriptions} + +}); diff --git a/frontends/member_module/src/views/DashboardView.vue b/frontends/member_module/src/views/DashboardView.vue index 4f4d0bf..ac58d44 100644 --- a/frontends/member_module/src/views/DashboardView.vue +++ b/frontends/member_module/src/views/DashboardView.vue @@ -1,10 +1,110 @@ diff --git a/frontends/member_module/src/views/subscription/ExportView.vue b/frontends/member_module/src/views/subscription/ExportView.vue index 260221f..6eb6976 100644 --- a/frontends/member_module/src/views/subscription/ExportView.vue +++ b/frontends/member_module/src/views/subscription/ExportView.vue @@ -11,7 +11,7 @@ diff --git a/frontends/member_module/src/views/subscription/SubscriptionArchiveView.vue b/frontends/member_module/src/views/subscription/SubscriptionArchiveView.vue index 07eae4f..f09b093 100644 --- a/frontends/member_module/src/views/subscription/SubscriptionArchiveView.vue +++ b/frontends/member_module/src/views/subscription/SubscriptionArchiveView.vue @@ -11,10 +11,11 @@ diff --git a/frontends/member_module/src/views/subscription/SubscriptionDuePayment.vue b/frontends/member_module/src/views/subscription/SubscriptionDuePaymentView.vue similarity index 72% rename from frontends/member_module/src/views/subscription/SubscriptionDuePayment.vue rename to frontends/member_module/src/views/subscription/SubscriptionDuePaymentView.vue index 7fb64c7..d24eb3f 100644 --- a/frontends/member_module/src/views/subscription/SubscriptionDuePayment.vue +++ b/frontends/member_module/src/views/subscription/SubscriptionDuePaymentView.vue @@ -11,10 +11,11 @@ diff --git a/frontends/member_module/src/views/subscription/SubscriptionNew.vue b/frontends/member_module/src/views/subscription/SubscriptionNewView.vue similarity index 75% rename from frontends/member_module/src/views/subscription/SubscriptionNew.vue rename to frontends/member_module/src/views/subscription/SubscriptionNewView.vue index 0fe5332..fdef5bb 100644 --- a/frontends/member_module/src/views/subscription/SubscriptionNew.vue +++ b/frontends/member_module/src/views/subscription/SubscriptionNewView.vue @@ -11,10 +11,10 @@ diff --git a/frontends/member_module/tailwind.config.js b/frontends/member_module/tailwind.config.js index 63487c8..503af1d 100644 --- a/frontends/member_module/tailwind.config.js +++ b/frontends/member_module/tailwind.config.js @@ -3,6 +3,7 @@ module.exports = { content: [ "./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}", + "./node_modules/primevue/**/*.{vue,js,ts,jsx,tsx}", ], theme: { extend: { @@ -12,4 +13,4 @@ module.exports = { }, }, plugins: [], -} \ No newline at end of file +} diff --git a/src/AdminController/MemberModuleController.php b/src/AdminController/MemberModuleController.php index 8119f3a..1826ac9 100644 --- a/src/AdminController/MemberModuleController.php +++ b/src/AdminController/MemberModuleController.php @@ -78,7 +78,7 @@ public function member_module(): Response // Profile image route // —————————————————————————————————————————————————————————————————————————— /** - * @Route("/miu/", name="app_member_image_upload") + * @Route("/foto/", name="app_member_image_upload") */ public function image_upload(Request $request): Response {