diff --git a/src/Event/EventType/EventType.php b/src/Event/EventType/EventType.php index cb5de4f6..45bca5f6 100755 --- a/src/Event/EventType/EventType.php +++ b/src/Event/EventType/EventType.php @@ -195,6 +195,11 @@ public function isLoginSkautisAllowed(): bool return false; } + public function enforceActiveSkautisMembership(): bool + { + return false; + } + public function isReceiptAllowed(): bool { return false; diff --git a/src/Event/EventType/Korbo/EventTypeKorbo.php b/src/Event/EventType/Korbo/EventTypeKorbo.php index eca2eaea..195e50ec 100755 --- a/src/Event/EventType/Korbo/EventTypeKorbo.php +++ b/src/Event/EventType/Korbo/EventTypeKorbo.php @@ -65,6 +65,12 @@ public function getLanguages(): array ]; } + #[\Override] + public function enforceActiveSkautisMembership(): bool + { + return true; + } + #[\Override] public function showFoodStats(): bool { diff --git a/src/Mailer/Mailer.php b/src/Mailer/Mailer.php index fc6698e5..d17d2427 100755 --- a/src/Mailer/Mailer.php +++ b/src/Mailer/Mailer.php @@ -131,6 +131,17 @@ public function sendCancelledPayment(Participant $participant, string $reason): ); } + public function sendPaidPartially(Participant $participant): void + { + $user = $participant->getUserButNotNull(); + + $this->sendMailFromTemplate( + $user->email, + $this->translator->trans('email.payment-successful-pay-more.subject'), + 'payment-successful-pay-more', + ); + } + public function sendRegistrationPaid(Participant $participant): void { $user = $participant->getUserButNotNull(); diff --git a/src/Participant/ParticipantService.php b/src/Participant/ParticipantService.php index 931e67a7..6711860e 100755 --- a/src/Participant/ParticipantService.php +++ b/src/Participant/ParticipantService.php @@ -19,6 +19,7 @@ use kissj\Participant\Troop\TroopParticipantRepository; use kissj\Payment\Payment; use kissj\Payment\PaymentService; +use kissj\User\UserLoginType; use kissj\User\UserService; use kissj\User\UserStatus; use Psr\Http\Message\ServerRequestInterface as Request; @@ -28,16 +29,17 @@ readonly class ParticipantService { public function __construct( - private ParticipantRepository $participantRepository, + private ParticipantRepository $participantRepository, private TroopParticipantRepository $troopParticipantRepository, - private PaymentService $paymentService, - private UserService $userService, - private FlashMessagesBySession $flashMessages, - private TranslatorInterface $translator, - private Mailer $mailer, - private SaveFileHandler $saveFileHandler, - private UploadFileHandler $uploadFileHandler, - ) { + private PaymentService $paymentService, + private UserService $userService, + private FlashMessagesBySession $flashMessages, + private TranslatorInterface $translator, + private Mailer $mailer, + private SaveFileHandler $saveFileHandler, + private UploadFileHandler $uploadFileHandler, + ) + { } /** @@ -157,6 +159,14 @@ public function isCloseRegistrationValid(Participant $participant): bool $validityFlag = false; } + if ($event->eventType->enforceActiveSkautisMembership() + && $participant->getUserButNotNull()->loginType === UserLoginType::Skautis + && !(bool)$participant->getUserButNotNull()->skautisHasMembership) { + $this->flashMessages->warning($this->translator->trans('flash.warning.missingSkautisMembership')); + + $validityFlag = false; + } + // to show all warnings return $validityFlag; } @@ -302,7 +312,7 @@ private function filterSameContingent(array $participants, ?string $contingent): { return array_filter( $participants, - fn (Participant $participant): bool => $participant->contingent === $contingent, + fn(Participant $participant): bool => $participant->contingent === $contingent, ); } @@ -430,7 +440,8 @@ public function generatePaymentsFor(array $participants): int public function getContentArbiterForParticipant( Participant $participant, - ): AbstractContentArbiter { + ): AbstractContentArbiter + { $eventType = $participant->getUserButNotNull()->event->eventType; return match ($participant->role) { @@ -459,6 +470,7 @@ public function setAsUnentered(Participant $participant): Participant return $participant; } + public function setAsLeaved(Participant $participant): Participant { $participant->leaveDate = DateTimeUtils::getDateTime(); diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentService.php index 579dbec9..20c2b20d 100755 --- a/src/Payment/PaymentService.php +++ b/src/Payment/PaymentService.php @@ -143,22 +143,23 @@ public function confirmPayment(Payment $payment): Payment $now = DateTimeUtils::getDateTime(); $participant = $payment->participant; - if ($participant->countWaitingPayments() === 0) { - // TODO set paid time in each payment - $this->setParticipantPaidWithTime($participant, $now); + if ($participant->countWaitingPayments() > 0) { + $this->mailer->sendPaidPartially($participant); - if ($participant instanceof TroopLeader) { - foreach ($participant->troopParticipants as $tp) { - $this->setParticipantPaidWithTime($tp, $now); - } - } + return $payment; + } - $this->mailer->sendRegistrationPaid($participant); - $this->flashMessages->success('flash.success.confirmPayment'); - } else { - // TODO add sending mail "thanks for payment, but you still needs to pay more" + $this->setParticipantPaidWithTime($participant, $now); + + if ($participant instanceof TroopLeader) { + foreach ($participant->troopParticipants as $tp) { + $this->setParticipantPaidWithTime($tp, $now); + } } + $this->mailer->sendRegistrationPaid($participant); + $this->flashMessages->success('flash.success.confirmPayment'); + return $payment; } diff --git a/src/Templates/cs.yaml b/src/Templates/cs.yaml index f4a1304a..6668e4d7 100755 --- a/src/Templates/cs.yaml +++ b/src/Templates/cs.yaml @@ -283,6 +283,11 @@ email: thanks: ". Děkujeme!" qrInfo: "Tady je QR kód, který budou chtít organizátoři při vstupu na akci:" enjoy: "Nyní si můžeš plně užít čekání na nadcházející akci! Taky si nic neudělej, ujisti se že tvůj stan je připraven a očekávej další informace. ;)" + payment-successful-pay-more: + subject: "platba obdržena, čekáme na dokončení plateb" + received: "Obdrželi jsme tvou platbu na" + thanks: ". Děkujeme!" + please: "Prosíme, zaplať zbývající platby co nejdříve, abychom mohli považovat tvou registraci za plně zaplacenou." finished: subject: "schváleno" approved: "Schválili jsme tvou přihlášku pro" @@ -546,6 +551,7 @@ flash: importCantStart: "Soubor importu se nepodařilo načíst" notApproved: "Účastník akce nebyl schválen, protože už schválen je" registrationNotAllowed: "Uzamknout registraci není zatím povoleno. Otevíráme za %difference%" + missingSkautisMembership: "Pro uzamčení registrace musí být tvůj skautIs účet propojený s reálnou osobou. Pokud jsi ho propojil v nedávné době, zkus se prosím odhlásit a zase přihlásit." nullParticipants: "Jeden nebo oba účastníci nebyli nalezeni v systému" differentParticipants: "Účastníci musí být různí (:" sameRole: "Účastníci musí mít stejné role" diff --git a/src/Templates/en.yaml b/src/Templates/en.yaml index 9982e8d2..95f93926 100755 --- a/src/Templates/en.yaml +++ b/src/Templates/en.yaml @@ -283,6 +283,11 @@ email: thanks: ". Thank you!" qrInfo: "Here is QR code, which organisers shall need during your event access:" enjoy: "Now you can fully enjoy the excitement for the upcoming event! Stay tuned for more information. ;)" + payment-successful-pay-more: + subject: "payment successful, waiting for more" + received: "We have received your payment for" + thanks: ". Thank you!" + please: "Please, pay the rest of the payment as soon as possible, so we can consider your registration as fully paid." finished: subject: "approved" approved: "We approved your registration for" @@ -546,6 +551,7 @@ flash: importCantStart: "Import file cannot be started" notApproved: "Participant is not approved, because it already has approved status" registrationNotAllowed: "Lock your registration is not yet allowed. We're opening after %difference%" + missingSkautisMembership: "To lock your registration, your ScoutIs account must be linked to a real person. If you have linked it recently, please try logging out and back in." nullParticipants: "One or both participants was not found in system" differentParticipants: "Participants must be different (:" sameRole: "Participants must have same roles" diff --git a/src/Templates/sk.yaml b/src/Templates/sk.yaml index 26842a5f..c3a76053 100755 --- a/src/Templates/sk.yaml +++ b/src/Templates/sk.yaml @@ -283,6 +283,11 @@ email: thanks: ". Vďaka!" qrInfo: "Tady je QR kód, který budou chtít organizátoři při vstupu na akci:" enjoy: "Teraz už sa môžeš plne tešiť na nadchádzajúcu akciu! Takže - nezlom si nohu, skontroluj stan, a priprav sa na pobyt na severe Slovenska! Sleduj nás pre viac informácií. ;)" + payment-successful-pay-more: + subject: "platba obdržaná, čakáme na dokončenie platieb" + received: "Obdržali sme tvoju platbu na" + thanks: ". Ďakujeme!" + please: "Prosíme, zaplať zvyšné platby čo najskôr, aby sme mohli považovať tvoju registráciu za plne zaplatenú." finished: subject: "schváleno" approved: "Schválili jsme tvou přihlášku pro" @@ -546,6 +551,7 @@ flash: importCantStart: "Soubor importu se nepodařilo načíst" notApproved: "Účastník akce nebyl schválen, protože už schválen je" registrationNotAllowed: "Uzamknout registraci není zatím povoleno. Otevíráme za %difference%" + missingSkautisMembership: "Ak chcete zablokovať svoju registráciu, vaše konto ScoutIs musí byť prepojené so skutočnou osobou. Ak ste ho prepojili nedávno, skúste sa odhlásiť a znova prihlásiť." nullParticipants: "Jedného alebo viacerých účastníkov sa nepodarilo nájsť v systéme" differentParticipants: "Účastníci musí být různí (:" sameRole: "Účastníci musí mít stejné role" diff --git a/src/Templates/translatable/emails/payment-successful-pay-more.twig b/src/Templates/translatable/emails/payment-successful-pay-more.twig new file mode 100755 index 00000000..d77ea1e4 --- /dev/null +++ b/src/Templates/translatable/emails/payment-successful-pay-more.twig @@ -0,0 +1,8 @@ +{% extends "emails/_mail-layout.twig" %} + +{% block content %} +
+

{% trans %}email.payment-successful-pay-more.received{% endtrans %} {{ event.readableName }}{% trans %}email.payment-successful-pay-more.thanks{% endtrans %}

+

{% trans %}email.payment-successful-pay-more.please{% endtrans %}

+
+{% endblock %} diff --git a/src/User/UserController.php b/src/User/UserController.php index 427506a7..3fd8a756 100755 --- a/src/User/UserController.php +++ b/src/User/UserController.php @@ -9,6 +9,7 @@ use kissj\Application\CookieHandler; use kissj\Event\Event; use kissj\Participant\ParticipantRepository; +use kissj\Participant\ParticipantRole; use kissj\Participant\ParticipantService; use kissj\Skautis\SkautisService; use Psr\Http\Message\ResponseInterface as Response; @@ -109,29 +110,47 @@ public function logout(Request $request, Response $response): Response return $this->redirect($request, $response, 'landing'); } - public function chooseRole(User $user, Response $response): Response + public function chooseRole(User $user, Request $request, Response $response): Response { + $roles = $user->event->getAvailableRoles(); + if (count($roles) === 1) { + $role = $roles[0]; + if ( + $user->loginType === UserLoginType::Skautis && + !$this->skautisService->isUserLoggedIn() + ) { + $this->flashMessages->error('flash.error.skautisUserNotLoggedIn'); + return $this->redirect($request, $response, 'landing'); + } + + $this->userService->createParticipantSetRole( + $user, + $role, + ); + + return $this->redirect($request, $response, 'getDashboard'); + + } // TODO add preference into get parameter return $this->view->render($response, 'kissj/choose-role.twig', ['event' => $user->event,]); } public function setRole(User $user, Request $request, Response $response): Response { - $participant = $this->userService->createParticipantSetRole( + if ( + $user->loginType === UserLoginType::Skautis && + !$this->skautisService->isUserLoggedIn() + ) { + $this->flashMessages->error('flash.error.skautisUserNotLoggedIn'); + return $this->redirect($request, $response, 'landing'); + } + + $participantRole = ParticipantRole::from($this->getParameterFromBody($request, 'role')); + $this->userService->createParticipantSetRole( $user, - $this->getParameterFromBody($request, 'role'), + $participantRole, ); - if ($participant->getUserButNotNull()->loginType === UserLoginType::Skautis) { - if (!$this->skautisService->isUserLoggedIn()) { - $this->flashMessages->error('flash.error.skautisUserNotLoggedIn'); - - return $this->redirect($request, $response, 'landing'); - } - - $this->skautisService->prefillDataFromSkautis($participant); - } - return $this->redirect($request, $response, 'getDashboard'); } diff --git a/src/User/UserService.php b/src/User/UserService.php index 6e44f660..fc5270fa 100755 --- a/src/User/UserService.php +++ b/src/User/UserService.php @@ -10,6 +10,7 @@ use kissj\Participant\Participant; use kissj\Participant\ParticipantRepository; use kissj\Participant\ParticipantRole; +use kissj\Skautis\SkautisService; use Psr\Http\Message\ServerRequestInterface as Request; use Slim\Routing\RouteContext; @@ -18,6 +19,7 @@ public function __construct( private LoginTokenRepository $loginTokenRepository, private ParticipantRepository $participantRepository, + protected SkautisService $skautisService, private UserRepository $userRepository, private Mailer $mailer, ) { @@ -116,9 +118,8 @@ public function invalidateAllLoginTokens(User $user): void } } - public function createParticipantSetRole(User $user, string $role): Participant + public function createParticipantSetRole(User $user, ParticipantRole $participantRole): Participant { - $participantRole = ParticipantRole::from($role); $participant = new Participant(); $participant->user = $user; @@ -128,6 +129,10 @@ public function createParticipantSetRole(User $user, string $role): Participant $user->role = UserRole::Participant; // TODO move into entity creation (simple) $user->status = UserStatus::Open; $this->userRepository->persist($user); + + if ($user->loginType === UserLoginType::Skautis) { + $this->skautisService->prefillDataFromSkautis($participant); + } return $participant; }