Skip to content

Commit

Permalink
Přenos vstupenky (#1386)
Browse files Browse the repository at this point in the history
* ticket transfer form

* ticket transfer form

* states

* states

* fixes

* format fix

* composer update

* composer update

* rename

* useless condition removed

* phpstan fix

* phpstan fix

* phpstan fix

* fixes

---------

Co-authored-by: Jan Staněk <[email protected]>
  • Loading branch information
jan-stanek and Jan Staněk authored Nov 9, 2024
1 parent 4dc2968 commit cc2315e
Show file tree
Hide file tree
Showing 17 changed files with 510 additions and 272 deletions.
2 changes: 1 addition & 1 deletion app/AdminModule/Components/UsersGridControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public function createComponentUsersGrid(string $name): DataGrid
->andWhere('uA.validTo IS NULL')
->andWhere('uA.state IN (:states)')
->setParameter('sids', (array) $values)
->setParameter('states', [ApplicationState::PAID, ApplicationState::PAID_FREE, ApplicationState::WAITING_FOR_PAYMENT]);
->setParameter('states', [ApplicationState::PAID, ApplicationState::PAID_FREE, ApplicationState::PAID_TRANSFERED, ApplicationState::WAITING_FOR_PAYMENT]);
});

$columnApproved = $grid->addColumnStatus('approved', 'admin.users.users_approved');
Expand Down
78 changes: 78 additions & 0 deletions app/AdminModule/Forms/EditUserTransferFormFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace App\AdminModule\Forms;

use App\AdminModule\Presenters\AdminBasePresenter;
use App\Model\User\Repositories\UserRepository;
use App\Model\User\User;
use App\Services\ApplicationService;
use Contributte\Translation\Translator;
use Nette;
use Nette\Application\UI\Form;
use Nette\Utils\ImageException;
use stdClass;

use function assert;

/**
* Formulář pro předání registrace jinému uživateli.
*/
class EditUserTransferFormFactory
{
use Nette\SmartObject;

/**
* Upravovaný uživatel.
*/
private User|null $user = null;

public function __construct(
private readonly BaseFormFactory $baseFormFactory,
private readonly UserRepository $userRepository,
private readonly ApplicationService $applicationService,
private readonly Translator $translator,
) {
}

public function create(int $id): Form
{
$this->user = $this->userRepository->findById($id);

$form = $this->baseFormFactory->create();

$form->addSelect('targetUser', 'admin.users.users_target_user', $this->userRepository->getUsersOptions(true))
->addRule(Form::NOT_EQUAL, 'admin.users.users_target_user_empty', 0)
->addRule(Form::NOT_EQUAL, 'admin.users.users_target_user_same', $this->user->getId())
->setHtmlAttribute('data-live-search', 'true');

$form->addSubmit('submit', 'admin.users.users_transfer')
->setDisabled(! $this->user->isRegistered() || ! $this->user->hasPaidAnyApplication())
->setHtmlAttribute('class', 'btn btn-danger')
->setHtmlAttribute('data-toggle', 'confirmation')
->setHtmlAttribute('data-content', $this->translator->translate('admin.users.users_transfer_confirm'));

$form->onSuccess[] = [$this, 'processForm'];

return $form;
}

/**
* Zpracuje formulář.
*
* @throws Nette\Utils\UnknownImageFileException
* @throws ImageException
*/
public function processForm(Form $form, stdClass $values): void
{
$presenter = $form->getPresenter();
assert($presenter instanceof AdminBasePresenter);

$loggedUser = $presenter->getDbUser();

$targetUser = $this->userRepository->findById($values->targetUser);

$this->applicationService->transferRegistration($this->user, $targetUser, $loggedUser);
}
}
34 changes: 17 additions & 17 deletions app/AdminModule/Presenters/UsersPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use App\AdminModule\Forms\AddLectorFormFactory;
use App\AdminModule\Forms\EditUserPersonalDetailsFormFactory;
use App\AdminModule\Forms\EditUserSeminarFormFactory;
use App\AdminModule\Forms\EditUserTransferFormFactory;
use App\Model\Acl\Permission;
use App\Model\Acl\Role;
use App\Model\Acl\SrsResource;
Expand Down Expand Up @@ -48,6 +49,9 @@ class UsersPresenter extends AdminBasePresenter
#[Inject]
public EditUserSeminarFormFactory $editUserSeminarFormFactory;

#[Inject]
public EditUserTransferFormFactory $editUserTransferFormFactory;

#[Inject]
public IApplicationsGridControlFactory $applicationsGridControlFactory;

Expand All @@ -73,7 +77,6 @@ public function startup(): void
$this->template->results = [];
$this->template->editPersonalDetails = false;
$this->template->editSeminar = false;
$this->template->editPayment = false;
}

public function renderDetail(int $id): void
Expand Down Expand Up @@ -137,22 +140,6 @@ public function handleEditSeminar(): void
}
}

/**
* Zobrazí formulář pro editaci údajů o platbě uživatele.
*
* @throws AbortException
*/
public function handleEditPayment(): void
{
$this->template->editPayment = true;

if ($this->isAjax()) {
$this->redrawControl('userDetail');
} else {
$this->redirect('this');
}
}

/** @throws Throwable */
public function handleCancelRegistration(): void
{
Expand Down Expand Up @@ -235,6 +222,19 @@ protected function createComponentEditUserSeminarForm(): Form
return $form;
}

/** @throws JsonException */
protected function createComponentEditUserTransferForm(): Form
{
$form = $this->editUserTransferFormFactory->create((int) $this->getParameter('id'));

$form->onSuccess[] = function (Form $form, stdClass $values): void {
$this->flashMessage('admin.users.users_transfered', 'success');
$this->redirect('this');
};

return $form;
}

protected function createComponentApplicationsGrid(): ApplicationsGridControl
{
return $this->applicationsGridControlFactory->create();
Expand Down
5 changes: 5 additions & 0 deletions app/AdminModule/Presenters/templates/Users/detail.latte
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@
{/if}
</div>

<h3>{_admin.users.users_detail_transfer}</h3>
<div class="card card-body bg-light pb-1 mb-3">
{control editUserTransferForm}
</div>

<h3>{_admin.users.users_detail_schedule}</h3>
<table class="table table-sm table-bordered table-striped">
<thead>
Expand Down
2 changes: 1 addition & 1 deletion app/ApiModule/Presenters/TicketsPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function actionCheckTicket(int $userId, int $subeventId): void
$subevents = [];
$hasSubevent = false;

foreach ($user->getPaidAndFreeApplications() as $application) {
foreach ($user->getPaidAndTransferedAndFreeApplications() as $application) {
if ($application instanceof RolesApplication) {
foreach ($application->getRoles() as $r) {
$roles[] = $r->getName();
Expand Down
4 changes: 2 additions & 2 deletions app/Model/Application/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,12 @@ public function isValid(): bool

public function isCanceled(): bool
{
return $this->state === ApplicationState::CANCELED || $this->state === ApplicationState::CANCELED_NOT_PAID;
return $this->state === ApplicationState::CANCELED || $this->state === ApplicationState::CANCELED_NOT_PAID || $this->state === ApplicationState::CANCELED_TRANSFERED;
}

public function isPaid(): bool
{
return $this->state === ApplicationState::PAID || $this->getState() === ApplicationState::PAID_FREE;
return $this->state === ApplicationState::PAID || $this->getState() === ApplicationState::PAID_FREE || $this->getState() === ApplicationState::PAID_TRANSFERED;
}

public function isWaitingForPayment(): bool
Expand Down
22 changes: 16 additions & 6 deletions app/Model/Enums/ApplicationState.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,37 @@
class ApplicationState
{
/**
* Čeká na platbu.
* Čeká na platbu
*/
public const WAITING_FOR_PAYMENT = 'waiting_for_payment';

/**
* Automaticky zrušeno kvůli nezaplacení.
* Zrušeno
*/
public const CANCELED = 'canceled';

/**
* Zrušeno (automaticky kvůli nezaplacení)
*/
public const CANCELED_NOT_PAID = 'canceled_not_paid';

/**
* Zrušeno.
* Zrušeno (převod na jiného účastníka)
*/
public const CANCELED = 'canceled';
public const CANCELED_TRANSFERED = 'canceled_transfered';

/**
* Zaplaceno.
* Zaplaceno
*/
public const PAID = 'paid';

/**
* Zaplaceno (zdarma).
* Zaplaceno (zdarma)
*/
public const PAID_FREE = 'paid_free';

/**
* Zaplaceno (převedeno od jiného účastníka)
*/
public const PAID_TRANSFERED = 'paid_transfered';
}
3 changes: 2 additions & 1 deletion app/Model/Structure/Subevent.php
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ public function countUsers(): int
return $this->applications->filter(static fn (Application $application) => $application->getValidTo() === null && (
$application->getState() === ApplicationState::WAITING_FOR_PAYMENT ||
$application->getState() === ApplicationState::PAID_FREE ||
$application->getState() === ApplicationState::PAID))->count();
$application->getState() === ApplicationState::PAID ||
$application->getState() === ApplicationState::PAID_TRANSFERED))->count();
}

public function countUnoccupied(): int|null
Expand Down
9 changes: 7 additions & 2 deletions app/Model/User/Repositories/UserRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public function findAllWithSubevents(array $subeventsIds): Collection
->where('a.validTo IS NULL')
->andWhere('a.state IN (:states)')
->andWhere('s.id IN (:ids)')
->setParameter('states', [ApplicationState::PAID, ApplicationState::PAID_FREE, ApplicationState::WAITING_FOR_PAYMENT])
->setParameter('states', [ApplicationState::PAID, ApplicationState::PAID_FREE, ApplicationState::PAID_TRANSFERED, ApplicationState::WAITING_FOR_PAYMENT])
->setParameter('ids', $subeventsIds)
->getQuery()
->getResult();
Expand Down Expand Up @@ -213,7 +213,7 @@ public function findProgramFirstAlternate(Program $program): User|null
*
* @return string[]
*/
public function getUsersOptions(): array
public function getUsersOptions(bool $empty = false): array
{
$users = $this->createQueryBuilder('u')
->select('u.id, u.displayName')
Expand All @@ -222,6 +222,11 @@ public function getUsersOptions(): array
->getResult();

$options = [];

if ($empty) {
$options[0] = '';
}

foreach ($users as $user) {
$options[$user['id']] = $user['displayName'];
}
Expand Down
35 changes: 31 additions & 4 deletions app/Model/User/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,11 @@ public function isInRoleWithSystemName(string $name): bool
return $this->roles->exists(static fn (int $key, Role $role) => $role->getSystemName() === $name);
}

public function isRegistered(): bool
{
return ! $this->isInRoleWithSystemName(Role::NONREGISTERED);
}

/**
* Vrací, zda má uživatel nějakou roli, která nemá cenu podle podakcí.
*/
Expand Down Expand Up @@ -784,7 +789,7 @@ public function getNotCanceledSubeventsApplications(): Collection
}

/**
* Vrácí zaplacené přihlášky.
* Vrací zaplacené přihlášky.
*
* @return Collection<int, Application>
*/
Expand All @@ -804,11 +809,13 @@ public function getPaidApplications(): Collection
*
* @return Collection<int, Application>
*/
public function getPaidAndFreeApplications(): Collection
public function getPaidAndTransferedAndFreeApplications(): Collection
{
return $this->applications->filter(static fn (Application $application) => $application->getValidTo() === null && (
$application->getState() === ApplicationState::PAID ||
$application->getState() === ApplicationState::PAID_FREE ||
$application->getState() === ApplicationState::PAID));
$application->getState() === ApplicationState::PAID_TRANSFERED
));
}

/**
Expand Down Expand Up @@ -1089,12 +1096,32 @@ public function hasSubevent(Subevent $subevent): bool
return $this->getSubevents()->contains($subevent);
}

/**
* Vrací zaplacné podakce uživatele.
*
* @return Collection<int, Subevent>
*/
public function getPaidSubevents(): Collection
{
$subevents = new ArrayCollection();

foreach ($this->getPaidAndTransferedAndFreeApplications() as $application) {
if ($application instanceof SubeventsApplication) {
foreach ($application->getSubevents() as $subevent) {
$subevents->add($subevent);
}
}
}

return $subevents;
}

/**
* Vrácí, zda má uživatel zaplacenou přihlášku s podakcí.
*/
public function hasPaidSubevent(Subevent $subevent): bool
{
foreach ($this->getPaidAndFreeApplications() as $application) {
foreach ($this->getPaidAndTransferedAndFreeApplications() as $application) {
if ($application instanceof SubeventsApplication && $application->getSubevents()->contains($subevent)) {
return true;
}
Expand Down
Loading

0 comments on commit cc2315e

Please sign in to comment.