Add initial version of Manual Invoice functionality with PDF generation and management
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Xinon Rechnung</title>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body style="border:0; margin: 0;font-family: sans-serif, Verdana;font-size: 11px;" onload="subst()">
|
||||
|
||||
<script>
|
||||
function subst() {
|
||||
var vars = {};
|
||||
var query_strings_from_url = document.location.search.substring(1).split('&');
|
||||
for (var query_string in query_strings_from_url) {
|
||||
if (query_strings_from_url.hasOwnProperty(query_string)) {
|
||||
var temp_var = query_strings_from_url[query_string].split('=', 2);
|
||||
vars[temp_var[0]] = decodeURI(temp_var[1]);
|
||||
}
|
||||
}
|
||||
var css_selector_classes = ['page', 'frompage', 'topage', 'webpage', 'section', 'subsection', 'date', 'isodate', 'time', 'title', 'doctitle', 'sitepage', 'sitepages'];
|
||||
for (var css_class in css_selector_classes) {
|
||||
if (css_selector_classes.hasOwnProperty(css_class)) {
|
||||
var element = document.getElementsByClassName(css_selector_classes[css_class]);
|
||||
for (var j = 0; j < element.length; ++j) {
|
||||
element[j].textContent = vars[css_selector_classes[css_class]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div style="margin-bottom: 16px;height: 1px"></div>
|
||||
<div style="color:grey;text-align: center;margin-bottom: 0">
|
||||
<span>XINON GmbH | Fladnitz 150 | 8322 Studenzen</span><br>
|
||||
<span>Tel.: +43 3115 40800 | E-Mail: office@xinon.at</span><br>
|
||||
<span>UID: ATU68711968 | FN: 416556h | LG: Feldbach</span><br>
|
||||
<span>IBAN: {{ bank_iban }} | BIC: {{ bank_bic }}</span><br>
|
||||
</div>
|
||||
|
||||
<div style="text-align: right">Seite <span class="page"></span> von <span class="topage"></span></div>
|
||||
|
||||
<div style="margin-top: 16px;height: 1px"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,107 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>XINON Invoice Header</title>
|
||||
<meta charset="utf-8" />
|
||||
<style>
|
||||
body {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
font-family: sans-serif, Verdana;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.info-table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.customer-details {
|
||||
vertical-align: bottom;
|
||||
font-size: 14px;
|
||||
padding-left: 30pt;
|
||||
width: 35%;
|
||||
}
|
||||
|
||||
.invoice-details {
|
||||
border: 2px solid #e1e1e1;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.invoice-details td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.invoice-details td:first-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin-top: 24px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
#topSpacer {
|
||||
margin-bottom: 32px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="topSpacer"></div>
|
||||
|
||||
<div style="height: 50px; margin-bottom: 8px">
|
||||
<img alt="Xinon Logo" src="{{ basedir }}/public/assets/images/xinon-full.png" style="text-align:left;height: 85px;">
|
||||
</div>
|
||||
|
||||
<table style="width: 100%; border-collapse: collapse;">
|
||||
<tr>
|
||||
<td class="customer-details">
|
||||
<div>{{ addressLine_1 }}</div>
|
||||
<div>{{ addressLine_2 }}</div>
|
||||
<div>{{ addressLine_3 }}</div>
|
||||
<div>{{ addressLine_4 }}</div>
|
||||
<div>{{ addressLine_5 }}</div>
|
||||
</td>
|
||||
<td style="float: right">
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>
|
||||
<table class="invoice-details">
|
||||
<tr>
|
||||
<td>Kundennummer:</td>
|
||||
<td>{{ customerNumber }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Verrechnungskonto:</td>
|
||||
<td>{{ billingAccount }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rechnungsnummer:</td>
|
||||
<td>{{ invoiceNumber }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Belegdatum:</td>
|
||||
<td>{{ invoiceDate }}</td>
|
||||
</tr>
|
||||
{{ vatHtml }}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
|
||||
<td style="float: right; vertical-align: top; margin-top: 0; padding-top: 0">
|
||||
<img alt="QR-Code" src="{{ qrCodeSrc }}" style="text-align:right;height: 3.5cm;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
/**
|
||||
* @var string $ressourcePathPrefix
|
||||
* @var ManualInvoice $invoice
|
||||
* @var array $vat
|
||||
*/
|
||||
$net_total = $invoice->total;
|
||||
$gross_total = $invoice->total_gross;
|
||||
$is_credit = $net_total < 0;
|
||||
|
||||
$this->setReturnValue(['filename' => $invoice->invoice_number . ".pdf"]);
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Rechnung</title>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin-top: 0;
|
||||
/*padding-top: 20pt;*/
|
||||
font-family: "Open Sans", sans-serif, Verdana;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
tr {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.uneven {
|
||||
background-color: #ebebeb;
|
||||
}
|
||||
|
||||
|
||||
table tr td:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.additionalRow td:first-child {
|
||||
text-align: left;
|
||||
padding-left: 20pt;
|
||||
}
|
||||
|
||||
th {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
#invoiceTable tr *:nth-child(5),
|
||||
#invoiceTable tr *:nth-child(4),
|
||||
#invoiceTable tr *:nth-child(3) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#invoiceTable tr *:not(:first-child) {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
#invoiceTable tr td {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
tr.position td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
tr.position td:first-child {
|
||||
vertical-align: middle !important;
|
||||
padding-left: 4pt;
|
||||
}
|
||||
|
||||
#invoiceTable tr td:first-child {
|
||||
max-width: 200pt;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
|
||||
<h2 style="text-align: center;color: #005384">Ihre Xinon <?=($is_credit) ? "Gutschrift" : "Rechnung"?> vom <?=date("d.m.Y",$invoice->invoice_date)?></h2>
|
||||
|
||||
<table style="border-collapse: collapse; width: 100%;" id="invoiceTable">
|
||||
<tr style="font-weight: bold; border-bottom: 1px solid black;" class="uneven">
|
||||
<th style="text-align: center">Leistung / Produkt</th>
|
||||
<th style="text-align: center">Zeitraum</th>
|
||||
<th style="text-align: right">Preis</th>
|
||||
<th style="text-align: center">Menge</th>
|
||||
<th style="text-align: right">Netto €</th>
|
||||
<th style="text-align: right">Ust. %</th>
|
||||
<th style="text-align: right; padding-right: 4pt">Brutto €</th>
|
||||
</tr>
|
||||
<?php
|
||||
$i = 0;
|
||||
foreach($invoice->positions as $p):
|
||||
$timerange_month_only = method_exists($p, 'getOption') ? $p->getOption('timerange_month_only') : (isset($p->options) ? (json_decode($p->options, true)['timerange_month_only'] ?? false) : false);
|
||||
|
||||
// Handle dates safely
|
||||
$start_date = null;
|
||||
$end_date = null;
|
||||
if (!empty($p->start_date)) {
|
||||
try {
|
||||
$start_date = new DateTime($p->start_date);
|
||||
} catch (Exception $e) {
|
||||
$start_date = null;
|
||||
}
|
||||
}
|
||||
if (!empty($p->end_date)) {
|
||||
try {
|
||||
$end_date = new DateTime($p->end_date);
|
||||
} catch (Exception $e) {
|
||||
$end_date = $start_date;
|
||||
}
|
||||
} else {
|
||||
$end_date = $start_date;
|
||||
}
|
||||
|
||||
$amount = (float) number_format($p->amount ?? 0, 3, ",", ".");
|
||||
$price = number_format($p->price ?? 0, 2, ",",".");
|
||||
$price_total = number_format($p->price_total ?? 0, 2, ",",".");
|
||||
$price_gross = number_format($p->price_gross ?? 0, 2, ",",".");
|
||||
$vatrate = number_format($p->vatrate ?? 0, 0, ",",".");
|
||||
|
||||
?>
|
||||
|
||||
<tr class="position <?=($i%2 == 0) ? "even" : "uneven" ?>">
|
||||
<td>
|
||||
<?=htmlspecialchars($p->product_name ?? '')?>
|
||||
<?php if(isset($p->matchcode) && $p->matchcode): ?>
|
||||
<div style="padding-left: 12pt"><?=htmlspecialchars($p->matchcode)?></div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td style="text-align: center;">
|
||||
<?php if($start_date && $end_date): ?>
|
||||
<?php if($timerange_month_only): ?>
|
||||
<?=$start_date->format("m.Y")?>
|
||||
<?php elseif(isset($p->billing_period) && $p->billing_period > 1): ?>
|
||||
<?=$start_date->format("m.Y")?> - <?=$end_date->format("m.Y") ?>
|
||||
<?php else: ?>
|
||||
<?php if($start_date->format("d.m.Y") == $end_date->format("d.m.Y")): ?>
|
||||
<?=$start_date->format("d.m.Y")?>
|
||||
<?php else: ?>
|
||||
<?=$start_date->format("d.m.Y")?> - <?=$end_date->format("d.m.Y") ?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php elseif($start_date): ?>
|
||||
<?=$start_date->format("d.m.Y")?>
|
||||
<?php else: ?>
|
||||
-
|
||||
<?php endif; ?>
|
||||
|
||||
</td>
|
||||
<td><?=$price?> €</td>
|
||||
<td style="text-align: center"><?=$amount?></td>
|
||||
<td><?=$price_total?> €</td>
|
||||
<td style="text-align: right;"><?=$vatrate?>%</td>
|
||||
<td style="padding-right: 4pt;"><?=$price_gross?> €</td>
|
||||
</tr>
|
||||
<?php
|
||||
$i++;
|
||||
endforeach;
|
||||
?>
|
||||
<tr style="font-weight: bold; background-color: #ebebeb; border-bottom: 1px solid black;border-top: 1px solid black">
|
||||
<td colspan="5">Gesamt Netto:</td>
|
||||
<td colspan="2" style="text-align: right; padding-right: 4pt;"><?=number_format($net_total, 2, ",","."). " €"?></td>
|
||||
</tr>
|
||||
|
||||
<?php foreach ($vat as $rate => $vat_total): ?>
|
||||
|
||||
<?php if($rate > 0): ?>
|
||||
<tr style="font-size: 11px;border-bottom: 1px solid black;">
|
||||
<td colspan="5">USt. <?=number_format($rate, 0, ",", ".")?>%:</td>
|
||||
<td colspan="2" style="text-align: right; padding-right: 4pt;"><?=number_format($vat_total, 2, ",","."). " €"?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endforeach; ?>
|
||||
|
||||
<!-- double underline border on bottom -->
|
||||
<tr style="font-weight: bold; border-bottom: 3px double black; background-color: #ebebeb;">
|
||||
<td colspan="5">Gesamt Brutto:</td>
|
||||
<td colspan="2" style="text-align: right; padding-right: 4pt;"><?=number_format($gross_total, 2, ",","."). " €"?></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div style="margin-top: 20pt;">
|
||||
<?php if($invoice->tax_text): ?>
|
||||
<p style="font-weight: bold;"><?=$invoice->tax_text?></p>
|
||||
<?php endif; ?>
|
||||
<?php if($is_credit): ?>
|
||||
<p style="color: #FF0000; font-weight: bold">Gutschrift! Bitte nicht überweisen.</p>
|
||||
<?php elseif($invoice->billing_type == "sepa"): ?>
|
||||
<p style="color: #FF0000; font-weight: bold">BITTE NICHT EINZAHLEN, DER BETRAG WIRD AUTOMATISCH VON IHREM KONTO ABGEBUCHT !</p>
|
||||
<?php else: ?>
|
||||
Bitte <b>überweisen</b> Sie den Rechnungsbetrag bis zum <b><?=(new DateTime("@".$invoice->invoice_date))->modify("+14 days")->format("d.m.Y")?></b> auf folgendes Konto:<br />
|
||||
<b style="padding-left: 4pt;">IBAN: <?=$bank_iban?></b><br />
|
||||
<b style="padding-left: 4pt;">BIC: <?=$bank_bic?></b><br /><br />
|
||||
Bitte geben Sie als Verwendungszweck unbedingt die Rechnungsnummer an, nur so können wir Ihre Zahlung eindeutig zuordnen
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user