add new table view
This commit is contained in:
@@ -51,6 +51,7 @@ export default class extends Controller {
|
||||
this.resultTarget.innerHTML = '';
|
||||
this.hideError();
|
||||
this.stepValue = 1;
|
||||
// window.history.pushState(null, null, "/");
|
||||
}
|
||||
|
||||
// ---- pliki ----
|
||||
@@ -93,7 +94,8 @@ export default class extends Controller {
|
||||
|
||||
const res = await fetch(this.endpointUrl, { method: 'POST', body: fd });
|
||||
if (!res.ok) throw new Error('Błąd serwera (' + res.status + ')');
|
||||
|
||||
// const hashSummary = res.url.replace(/^https?:\/\/[^/]+\//, "/").replace(this.endpointUrl, "");
|
||||
// window.history.pushState(null, null, hashSummary);
|
||||
this.resultTarget.innerHTML = await res.text();
|
||||
this.stepValue = 3;
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@import "table";
|
||||
.main-container {
|
||||
font-family: 'Public Sans', system-ui, sans-serif;
|
||||
color: #1C1C1A;
|
||||
@@ -12,7 +13,7 @@
|
||||
.card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 660px;
|
||||
max-width: 750px;
|
||||
background: #FBFBF9;
|
||||
border: 1px solid #E6E5E0;
|
||||
border-radius: 18px;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
.summaryTable {
|
||||
.table-head { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
|
||||
.table-title { font-size: 13px; font-weight: 600; }
|
||||
|
||||
|
||||
.table-wrap {
|
||||
border: 1px solid #E6E5E0; border-radius: 10px; overflow-x: auto; background: #FFFFFF;
|
||||
|
||||
table { width: 100%; border-collapse: collapse; font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 11.5px; }
|
||||
th {
|
||||
padding: 9px; font-weight: 600; color: #6B6A64; font-size: 10px;
|
||||
text-transform: uppercase; letter-spacing: .03em;
|
||||
border-bottom: 1px solid #E6E5E0; white-space: nowrap; background: #FAFAF7;
|
||||
}
|
||||
td { padding: 9px; border-bottom: 1px solid #F0EFEB; white-space: nowrap; }
|
||||
tfoot tr { background: #FAFAF7; }
|
||||
|
||||
|
||||
.foot-label {
|
||||
font-family: 'Public Sans', sans-serif; font-size: 12px; font-weight: 600;
|
||||
color: #6B6A64; text-transform: uppercase; letter-spacing: .04em;
|
||||
}
|
||||
.foot-value { text-align: right; font-weight: 700; color: #1C1C1A; font-size: 14px; }
|
||||
|
||||
}
|
||||
|
||||
.note { margin-top: 10px; font-size: 12px; color: #6B6A64; }
|
||||
.actions { display: flex; gap: 10px; margin-top: 22px; }
|
||||
.btn-accent {
|
||||
color: #FFFFFF; border: none; border-radius: 9px; padding: 11px 18px;
|
||||
font-size: 13.5px; font-weight: 600; cursor: pointer; font-family: inherit;
|
||||
}
|
||||
.btn-ghost {
|
||||
background: none; border: 1px solid #E6E5E0; border-radius: 9px; padding: 11px 18px;
|
||||
font-size: 13.5px; font-weight: 600; color: #3B3A36; cursor: pointer; font-family: inherit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,57 +23,57 @@ use Symfony\Component\Validator\Constraints\File;
|
||||
|
||||
class TaxesController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/taxes/{type}', name: 'app_taxes')]
|
||||
public function index(Request $request, string $type): Response
|
||||
{
|
||||
if (!in_array($type, ["crypto", "dividend"])) {
|
||||
return $this->redirectToRoute("homepage");
|
||||
}
|
||||
|
||||
$a=[];
|
||||
$form = $this->createFormBuilder([])
|
||||
->add("uploads",FileType::class, [
|
||||
'data_class' => null,
|
||||
'multiple' => true,
|
||||
'attr'=>[
|
||||
'multiple' => 'multiple',
|
||||
],
|
||||
'constraints' => [
|
||||
new All([
|
||||
'constraints' => [
|
||||
new File([
|
||||
'maxSize' => '2048k',
|
||||
'mimeTypes' => [
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/atom+xml',
|
||||
'application/xml',
|
||||
'text/xml',
|
||||
'text/xml-external-parsed-entity',
|
||||
'text/csv',
|
||||
'text/plain',
|
||||
// 'application/x-pdf',
|
||||
],
|
||||
'mimeTypesMessage' => 'Please upload a valid XLSX or XML document',
|
||||
])
|
||||
]
|
||||
])
|
||||
],
|
||||
])
|
||||
->add("upload",SubmitType::class)
|
||||
->getForm();
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$files = $form->get('uploads')->getData();
|
||||
$hash = $this->saveFiles($files);
|
||||
return $this->redirectToRoute("app_taxes_{$type}_show",["hash" => $hash]);
|
||||
}
|
||||
|
||||
return $this->renderForm('taxes/index.html.twig', [
|
||||
'controller_name' => 'TaxesController',
|
||||
'form' => $form,
|
||||
'sheet' => $a
|
||||
]);
|
||||
}
|
||||
// #[Route(path: '/taxes/{type}', name: 'app_taxes')]
|
||||
// public function index(Request $request, string $type): Response
|
||||
// {
|
||||
// if (!in_array($type, ["crypto", "dividend"])) {
|
||||
// return $this->redirectToRoute("homepage");
|
||||
// }
|
||||
//
|
||||
// $a=[];
|
||||
// $form = $this->createFormBuilder([])
|
||||
// ->add("uploads",FileType::class, [
|
||||
// 'data_class' => null,
|
||||
// 'multiple' => true,
|
||||
// 'attr'=>[
|
||||
// 'multiple' => 'multiple',
|
||||
// ],
|
||||
// 'constraints' => [
|
||||
// new All([
|
||||
// 'constraints' => [
|
||||
// new File([
|
||||
// 'maxSize' => '2048k',
|
||||
// 'mimeTypes' => [
|
||||
// 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
// 'application/atom+xml',
|
||||
// 'application/xml',
|
||||
// 'text/xml',
|
||||
// 'text/xml-external-parsed-entity',
|
||||
// 'text/csv',
|
||||
// 'text/plain',
|
||||
//// 'application/x-pdf',
|
||||
// ],
|
||||
// 'mimeTypesMessage' => 'Please upload a valid XLSX or XML document',
|
||||
// ])
|
||||
// ]
|
||||
// ])
|
||||
// ],
|
||||
// ])
|
||||
// ->add("upload",SubmitType::class)
|
||||
// ->getForm();
|
||||
// $form->handleRequest($request);
|
||||
// if ($form->isSubmitted() && $form->isValid()) {
|
||||
// $files = $form->get('uploads')->getData();
|
||||
// $hash = $this->saveFiles($files);
|
||||
// return $this->redirectToRoute("app_taxes_{$type}_show",["hash" => $hash]);
|
||||
// }
|
||||
//
|
||||
// return $this->renderForm('taxes/index.html.twig', [
|
||||
// 'controller_name' => 'TaxesController',
|
||||
// 'form' => $form,
|
||||
// 'sheet' => $a
|
||||
// ]);
|
||||
// }
|
||||
|
||||
private function saveFiles(array $files) : string
|
||||
{
|
||||
@@ -99,28 +99,13 @@ class TaxesController extends AbstractController
|
||||
return $hash;
|
||||
}
|
||||
|
||||
#[Route(path: '/taxes/summary/{type}', name: 'app_taxes_summary', methods: ['POST'])]
|
||||
#[Route(path: '/taxes/{type}', name: 'app_taxes_summary', methods: ['POST'])]
|
||||
public function takeSummary(string $type, Request $request, DividendsService $tax, ?MarketNames $market): Response
|
||||
{
|
||||
$files = $request->files->all()['pliki'];
|
||||
$hash = $this->saveFiles($files);
|
||||
if ($hash) {
|
||||
$tax->setHash($hash);
|
||||
if ($tax->readFiles($market)) {
|
||||
$gen = $tax->generate();
|
||||
// dd($gen);
|
||||
return $this->render("taxes/show.html.twig", [
|
||||
"taxes" => $gen->getSummaryByCountry(),
|
||||
"errorDividend" => $gen->getErrorDividend(),
|
||||
"errorString" => $gen->getErrorString(),
|
||||
"rawCount" => $gen->takeCountRawData(),
|
||||
"markets" => $gen->getMarkets(),
|
||||
"markets_all" => MarketNames::cases(),
|
||||
"hash_param" => $tax->takeHash(),
|
||||
"current_market" => $market,
|
||||
]);
|
||||
|
||||
}
|
||||
return $this->redirectToRoute("app_taxes_{$type}_show", ["hash" => $hash]);
|
||||
}
|
||||
return $this->json([
|
||||
"type" => $type,
|
||||
@@ -133,8 +118,10 @@ class TaxesController extends AbstractController
|
||||
{
|
||||
if ($tax->readFiles($market)) {
|
||||
$gen = $tax->generate();
|
||||
// dd($gen);
|
||||
return $this->render("taxes/show.html.twig", [
|
||||
$taxes = $gen->getSummaryByCountry();
|
||||
$sum = $taxes['sum'];
|
||||
unset($taxes['sum']);
|
||||
return $this->render("taxes/table.html.twig", [
|
||||
"taxes" => $gen->getSummaryByCountry(),
|
||||
"errorDividend" => $gen->getErrorDividend(),
|
||||
"errorString" => $gen->getErrorString(),
|
||||
@@ -143,6 +130,7 @@ class TaxesController extends AbstractController
|
||||
"markets_all" => MarketNames::cases(),
|
||||
"hash_param" => $tax->takeHash(),
|
||||
"current_market" => $market,
|
||||
"sum" => $sum,
|
||||
]);
|
||||
}
|
||||
return new Response("Brak danych do wyświetlenia.");
|
||||
|
||||
@@ -42,12 +42,19 @@ class DividendsSummary
|
||||
$this->countFromSheets();
|
||||
|
||||
if (count($this->allData) > 0) {
|
||||
$sum = 0;
|
||||
$profitSum = 0;
|
||||
$summaryRow = [
|
||||
"tax" => 0,
|
||||
"profit" => 0,
|
||||
"origin" => 0,
|
||||
"destiny" => 0,
|
||||
];
|
||||
foreach ($this->allData as $key => $item) {
|
||||
$val = round($item['tax'], 2);
|
||||
$sum += $val;
|
||||
$profitSum += $item['incomeAll'];
|
||||
$summaryRow["tax"] += $val;
|
||||
$summaryRow["profit"] += $item['incomeAll'];
|
||||
$summaryRow["origin"] += $item['destiny_tax'];
|
||||
$summaryRow["destiny"] += $item['tax_cost'];
|
||||
|
||||
$return[$key] = [
|
||||
"country" => \Locale::getDisplayRegion("-".$key),
|
||||
"income" => $item['incomeAll'],
|
||||
@@ -58,11 +65,11 @@ class DividendsSummary
|
||||
"incomesArray" => $item['incomes']
|
||||
];
|
||||
}
|
||||
$summaryRow = array_map(function ($item) {
|
||||
return intval(ceil($item));
|
||||
}, $summaryRow);
|
||||
// >
|
||||
$return['sum'] = [
|
||||
"tax" => intval(ceil($sum)),
|
||||
"profit" => $profitSum
|
||||
];
|
||||
$return['sum'] = $summaryRow;
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<div class="summaryTable">
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>L.p.</th>
|
||||
<th>Country</th>
|
||||
<th>Income</th>
|
||||
{% if taxes|first.cost is defined %}
|
||||
<th>Cost</th>
|
||||
{% endif %}
|
||||
{% if taxes|first.destiny_tax is defined %}
|
||||
<th>Origin tax</th>
|
||||
{% endif %}
|
||||
{% if taxes|first.tax_cost is defined %}
|
||||
<th>Deductable tax (15%)</th>
|
||||
{% endif %}
|
||||
{% if taxes|first.profit is defined %}
|
||||
<th>Profit/Loss</th>
|
||||
{% endif %}
|
||||
<th>Tax</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for key,tax in taxes %}
|
||||
{% if tax.country is defined %}
|
||||
{% set colspan = tax|length %}
|
||||
{% if tax.income > 0 %}
|
||||
<tr class="{% if tax.profit is defined and tax.profit < 0 %}table-danger{% else %}table-success{% endif %}">
|
||||
<td>{{ loop.index }}</td>
|
||||
<td>{{ tax.country }}</td>
|
||||
<td>{{ tax.income|price }}</td>
|
||||
{% if tax.cost is defined %}
|
||||
<td>{{ tax.cost|price }}</td>
|
||||
{% endif %}
|
||||
{% if tax.destiny_tax is defined %}
|
||||
<td>{{ tax.destiny_tax|price }}</td>
|
||||
{% endif %}
|
||||
{% if tax.tax_cost is defined %}
|
||||
<td>{{ tax.tax_cost|price }}</td>
|
||||
{% endif %}
|
||||
{% if tax.profit is defined %}
|
||||
<td>{{ tax.profit|price }}</td>
|
||||
{% endif %}
|
||||
<td>{{ tax.tax|price }}</td>
|
||||
</tr>
|
||||
{% if tax.incomesArray is defined and tax.incomesArray|length > 0 %}
|
||||
{% set colspan = colspan-1 %}
|
||||
{% for incomePerc,value in tax.incomesArray %}
|
||||
<tr>
|
||||
<td colspan="2"></td>
|
||||
<td>{{ incomePerc }}% - {{ value|price }}</td>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% elseif key == "sum" %}
|
||||
{# <tr class="">#}
|
||||
{# <td colspan="{{ colspan-2 }}">Summary:</td>#}
|
||||
{# <td>{{ tax.profit|price("PLN",0) }}</td>#}
|
||||
{# <td>{{ tax.tax|price("PLN",0) }}</td>#}
|
||||
{# </tr>#}
|
||||
{% else %}
|
||||
<tr class="">
|
||||
<td colspan="{{ colspan-1 }}">Summary:</td>
|
||||
<td>{{ tax|price("PLN",0) }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="2" class="foot-label">Podsumowanie</td>
|
||||
<td class="foot-label">{{ sum.profit|price("PLN",0) }}</td>
|
||||
<td class="foot-label">{{ sum.origin|price("PLN",0) }}</td>
|
||||
<td class="foot-label">{{ sum.destiny|price("PLN",0) }}</td>
|
||||
<td colspan="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="foot-label">Do zaplaty</td>
|
||||
<td class="foot-value" colspan="4">{{ sum.tax|price("PLN",0) }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{#{% if wynik.footNote %}#}
|
||||
<div class="note">Kwota do dopłaty w Polsce po uwzględnieniu podatku zapłaconego za granicą.</div>
|
||||
{#{% endif %}#}
|
||||
|
||||
<div class="actions">
|
||||
{# <button type="button" class="btn-accent" style="background: {{ wynik.accent }}">Eksportuj do PIT</button>#}
|
||||
<button type="button" class="btn-ghost" data-action="app#restart">Od nowa</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user