Skip to content

Commit

Permalink
Merge pull request #2309 from marekdedic/education-budget
Browse files Browse the repository at this point in the history
Přidána záložka rozpočtu pro vzdělávací akce
  • Loading branch information
marekdedic authored Oct 25, 2023
2 parents 920fd2a + 8f54df0 commit bf3fb0e
Show file tree
Hide file tree
Showing 15 changed files with 491 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace App\AccountancyModule\EducationModule;

use Model\Auth\Resources\Education;
use Model\Cashbook\Cashbook\CashbookId;
use Model\Cashbook\Commands\Cashbook\UpdateEducationCategoryTotals;
use Model\Cashbook\ReadModel\Queries\CategoriesSummaryQuery;
use Model\Cashbook\ReadModel\Queries\EducationCashbookIdQuery;
use Model\Cashbook\ReadModel\Queries\InconsistentEducationCategoryTotalsQuery;
use Model\Event\SkautisEducationId;
use Model\Skautis\ReadModel\Queries\EducationBudgetQuery;

use function count;

class BudgetPresenter extends BasePresenter
{
public function __construct()
{
parent::__construct();
}

protected function startup(): void
{
parent::startup();

if ($this->aid) {
return;
}

$this->flashMessage('Musíš vybrat akci', 'danger');
$this->redirect('Default:');
}

public function renderDefault(int $aid): void
{
if (! $this->authorizator->isAllowed(Education::ACCESS_BUDGET, $this->aid)) {
$this->flashMessage('Nemáte právo prohlížet rozpočet akce', 'danger');
$this->redirect('Education:');
}

$educationId = new SkautisEducationId($aid);

$inconsistentTotals = $this->queryBus->handle(new InconsistentEducationCategoryTotalsQuery($educationId));
$this->template->setParameters([
'isConsistent' => count($inconsistentTotals) === 0,
'toRepair' => $inconsistentTotals,
'budgetEntries' => $this->queryBus->handle(new EducationBudgetQuery($educationId, $this->event->grantId)),
'categoriesSummary' => $this->queryBus->handle(new CategoriesSummaryQuery($this->getCashbookId($aid))),
'isUpdateStatementAllowed' => $this->authorizator->isAllowed(Education::UPDATE_REAL_BUDGET_SPENDING, $aid),
]);
if (! $this->isAjax()) {
return;
}

$this->redrawControl('contentSnip');
}

/**
* přepočte hodnoty v jednotlivých kategorich
*/
public function handleConvert(int $aid): void
{
$this->editableOnly();

$this->commandBus->handle(new UpdateEducationCategoryTotals($this->getCashbookId($aid)));
$this->flashMessage('Kategorie byly přepočítány.');

if ($this->isAjax()) {
$this->redrawControl('flash');
} else {
$this->redirect('this', $aid);
}
}

private function getCashbookId(int $educationId): CashbookId
{
return $this->queryBus->handle(new EducationCashbookIdQuery(new SkautisEducationId($educationId)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{block #title}{$event->getDisplayName()} - rozpočet{/block}

{define #budgetTable $entries, $income}
<table n:ifset="$entries" class="table myTable table-bordered table-sm">
<thead>
<tr>
<th>Položka</th>
<th>Částka</th>
</tr>
</thead>
<tr n:foreach="$entries as $entry" n:if="$entry->isIncome() === $income">
<td>{$entry->name}</td>
<td class="text-right">
{$entry->total|price}
</td>
</tr>
</table>
{/define}

{define #categoriesTable $categoriesSummary, $income}
<table n:ifset="$categoriesSummary" class="table myTable table-bordered table-sm">
<thead>
<tr>
<th>Položka</th>
<th>Částka</th>
</tr>
</thead>
{var $balance = 0}
<tr n:foreach="$categoriesSummary as $categorySummary" n:if="$categorySummary->isIncome() === $income && ! $categorySummary->isVirtual()">
{do $balance += (float)$categorySummary->total->getAmount()/100}
<td>{$categorySummary->name}</td>
<td n:class="text-right,text-nowrap, array_key_exists($categorySummary->id, $toRepair) ? bg-danger-lighter"
n:attr="[title => array_key_exists($categorySummary->id, $toRepair) ? 'Částka ve SkautISu je ' . $toRepair[$categorySummary->id]]">
{$categorySummary->total|price}
</td>
</tr>
<tr>
<td><b>Celkem</b></td>
<td class="text-right text-nowrap"><b>{$balance|price}</b></td>
</tr>
</table>
{/define}

{block #content}

{include ../header.latte}

<div class="alert alert-warning mb-5" n:if="!$isConsistent">
<h4 class="alert-heading">Nekonzistentní data!</h4>
<p class="mb-0">Součet paragonů v kategoriích neodpovídá částkám uvedeným ve SkautISu.</p>
{if $isEditable}
<p>Hospodaření může aktualizovat data ve SkautISu tak, aby byla shodná s evidencí plateb.</p>
<hr>
{if $isUpdateStatementAllowed}
<a n:href="convert! $aid" class="alert-link">
<i class="fas fa-tools"></i>
Aktualizovat data ve SkautISu
</a>
{else}
<p class="text-muted mb-0">
<i class="far fa-times-circle"></i>
Nemáte oprávnění pro úpravu částek v rozpočtu uvedených ve skautisu.
</p>
{/if}
{/if}
</div>

<div class="row">
<div class="col-md-3 col-sm-6">
<h3>Skutečné náklady</h3>
{include #categoriesTable $categoriesSummary, FALSE}
</div>
<div class="col-md-3 col-sm-6">
<h3>Skutečné výnosy</h3>
{include #categoriesTable $categoriesSummary, TRUE}
</div>

<div class="clearfix visible-sm-block"></div>

<div class="col-md-3 col-sm-6 ">
<h3>Předpokl. náklady</h3>
{include #budgetTable $budgetEntries, FALSE}
</div>
<div class="col-md-3">
<h3>Předpokládané výnosy</h3>
{include #budgetTable $budgetEntries, TRUE}
</div>
</div>
4 changes: 4 additions & 0 deletions app/AccountancyModule/EducationModule/templates/header.latte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<a class="nav-link" n:href="Cashbook: $event->getId()->toInt()"><i
class="fas fa-clipboard-list"></i> Evidence plateb</a>
</li>
<li n:class="nav-item, $presenterName === 'Budget' ? active">
<a class="nav-link" n:href="Budget: $event->getId()->toInt()"><i
class="fas fa-chart-pie"></i> Rozpočet</a>
</li>
</ul>
<ul class="navbar-nav align-items-center justify-content-center">
<li n:class="nav-item, $presenterName === 'Privileges' ? active">
Expand Down
4 changes: 4 additions & 0 deletions app/config/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ services:
bus: queryBus

# Skautis read model
- factory: Model\Skautis\ReadModel\QueryHandlers\EducationBudgetQueryHandler(@skautis.cached.grants)
tags:
messenger.messageHandler:
bus: queryBus
- factory: Model\Skautis\ReadModel\QueryHandlers\CampBudgetQueryHandler(@skautis.cached.event)
tags:
messenger.messageHandler:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Model\Cashbook\Commands\Cashbook;

use Model\Cashbook\Cashbook\CashbookId;
use Model\Cashbook\Handlers\Cashbook\UpdateEducationCategoryTotalHandler;

/**
* Updates category total for education event in Skautis
*
* @see UpdateEducationCategoryTotalHandler
*/
final class UpdateEducationCategoryTotals
{
public function __construct(private CashbookId $cashbookId)
{
}

public function getCashbookId(): CashbookId
{
return $this->cashbookId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Model\Cashbook\Handlers\Cashbook;

use Model\Cashbook\Commands\Cashbook\UpdateEducationCategoryTotals;
use Model\Cashbook\ReadModel\Queries\CategoriesSummaryQuery;
use Model\Cashbook\Repositories\ICashbookRepository;
use Model\Cashbook\Services\IEducationCategoryUpdater;
use Model\Common\Services\QueryBus;
use Model\DTO\Cashbook\CategorySummary;
use Model\Utils\MoneyFactory;

use function assert;

class UpdateEducationCategoryTotalHandler
{
public function __construct(private ICashbookRepository $cashbooks, private IEducationCategoryUpdater $updater, private QueryBus $queryBus)
{
}

public function __invoke(UpdateEducationCategoryTotals $command): void
{
$cashbook = $this->cashbooks->find($command->getCashbookId());

$totals = [];
foreach ($this->queryBus->handle(new CategoriesSummaryQuery($cashbook->getId())) as $category) {
assert($category instanceof CategorySummary);
$totals[$category->getId()] = MoneyFactory::toFloat($category->getTotal());
}

$this->updater->updateCategories(
$cashbook->getId(),
$totals,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Model\Cashbook\ReadModel\Queries;

use Model\Cashbook\ReadModel\QueryHandlers\InconsistentEducationCategoryTotalsQueryHandler;
use Model\Event\SkautisEducationId;

/**
* Returns categories with different total in app and Skautis
*
* @see InconsistentEducationCategoryTotalsQueryHandler
*/
final class InconsistentEducationCategoryTotalsQuery
{
public function __construct(private SkautisEducationId $educationId)
{
}

public function getEducationId(): SkautisEducationId
{
return $this->educationId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Model\Cashbook\ReadModel\QueryHandlers;

use Model\Cashbook\ReadModel\Queries\CategoriesSummaryQuery;
use Model\Cashbook\ReadModel\Queries\EducationCashbookIdQuery;
use Model\Cashbook\ReadModel\Queries\InconsistentEducationCategoryTotalsQuery;
use Model\Cashbook\Repositories\IEducationCategoryRepository;
use Model\Common\Services\QueryBus;
use Model\DTO\Cashbook\CategorySummary;
use Model\Utils\MoneyFactory;

use function assert;

class InconsistentEducationCategoryTotalsQueryHandler
{
public function __construct(private IEducationCategoryRepository $educationCategories, private QueryBus $queryBus)
{
}

/** @return float[] */
public function __invoke(InconsistentEducationCategoryTotalsQuery $query): array
{
$cashbookId = $this->queryBus->handle(new EducationCashbookIdQuery($query->getEducationId()));
$categories = $this->queryBus->handle(new CategoriesSummaryQuery($cashbookId));

$skautisTotals = [];

foreach ($this->educationCategories->findForEducation($query->getEducationId()->toInt()) as $educationCategory) {
$id = $educationCategory->getId();
$total = $educationCategory->getTotal();
$category = $categories[$id];

assert($category instanceof CategorySummary);

$isConsistent = $category->getTotal()->equals($total);

if ($isConsistent) {
continue;
}

$skautisTotals[$id] = MoneyFactory::toFloat($total);
}

return $skautisTotals;
}
}
20 changes: 20 additions & 0 deletions app/model/Cashbook/Services/IEducationCategoryUpdater.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Model\Cashbook\Services;

use InvalidArgumentException;
use Model\Cashbook\Cashbook\CashbookId;

interface IEducationCategoryUpdater
{
/**
* Updates statistics in Skautis
*
* @param array<int, float> $cashbookTotals Category totals indexed by category ID
*
* @throws InvalidArgumentException
*/
public function updateCategories(CashbookId $cashbookId, array $cashbookTotals): void;
}
2 changes: 1 addition & 1 deletion app/model/Grant/SkautisGrantId.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

final class SkautisGrantId
{
public function __construct(private int $value)
public function __construct(private int|null $value)
{
}

Expand Down
Loading

0 comments on commit bf3fb0e

Please sign in to comment.