Compare commits

...

10 commits

10 changed files with 476 additions and 270 deletions

View file

@ -1,3 +1,3 @@
install: install:
mkdir -p $(DESTDIR) mkdir -p $(DESTDIR)
cp vtdirektmarketing.php $(DESTDIR)/ cp heinrichmalerbetrieb.php $(DESTDIR)/

View file

@ -0,0 +1,56 @@
## Invoiceplane Template for Heinrich-Malerbetrieb.de
### Setup
Run development server
```
nix run
```
Visit http://localhost:8080 , run the setup and after login browse to system settings. In the sub menu invoice, change default PDF template to `heinrichmalerbetrieb`.
### Configuration
General default settings which should be set
- User profile (company contact information), such as mail, address, phone and mail
- System settings in general and invoice: Upload company logo for login and invoice logo
(WebP image format currently not supported https://github.com/InvoicePlane/InvoicePlane/issues/1189 ).
- System settings - invoice
- Enable embed ZUGFeRD XML into PDF (e-invoice)
- PDF footer
```
<hr class="footer">
<table class="footer" border=0 width=100%>
<tr>
<td class="first-child">
Geschäftsführer:<br>
Engelbert Heinrich<br>
Jürgen Heinrich
</td>
<td>
Sparkasse Pforzheim-Calw<br>
BLZ 666 500 85 Konto-Nr. 89 187 67<br>
IBAN: DE70 6665 0085 0008 9187 67<br>
SWIFT-BIC: PZHSDE66XXX
</td>
<td>
Amtsgericht Mannheim HRB 719187<br>
Steuer-Nummer: 48 051 23774<br>
Sitz der Gesellschaft in Tiefenbronn<br>
USt-IdNr. DE293948256
</td>
</table>
<div class="page-number">Seite: {PAGENO}/{nb}</div>
```
- System settings - general, currency settings
- Change symbol to: €
- Symbol after sum with space
- Currency code EUR
- Number format to European format
- System settings - general, time format: j.n.Y
- Product units: m², Std.

28
flake.lock generated Normal file
View file

@ -0,0 +1,28 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1741310760,
"narHash": "sha256-aizILFrPgq/W53Jw8i0a1h1GZAAKtlYOrG/A5r46gVM=",
"ref": "nixpkgs-unstable",
"rev": "de0fe301211c267807afd11b12613f5511ff7433",
"shallow": true,
"type": "git",
"url": "https://github.com/NixOS/nixpkgs"
},
"original": {
"ref": "nixpkgs-unstable",
"shallow": true,
"type": "git",
"url": "https://github.com/NixOS/nixpkgs"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

72
flake.nix Normal file
View file

@ -0,0 +1,72 @@
{
description = "Invoiceplane invoice template development shell";
inputs.nixpkgs.url = "nixpkgs/nixos-25.05";
outputs = { self, nixpkgs, ... }@inputs:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
start =
pkgs.writeShellScriptBin "start" ''
set -e
export QEMU_NET_OPTS="hostfwd=tcp::8080-:80"
${pkgs.nixos-shell}/bin/nixos-shell --flake .
'';
in {
nixosConfigurations.vm = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs.inputs = inputs;
pkgs = import nixpkgs {
overlays = [
(self: super: {
invoiceplane = super.invoiceplane.overrideAttrs (oldAttrs: rec {
# Add new page numbers support
patches = oldAttrs.patches ++ [
(fetchpatch {
url = "https://github.com/InvoicePlane/InvoicePlane/commit/bfcf81266399575e90b83612d59b457d76e3538e.patch";
hash = "";
})
];
installPhase = oldAttrs.installPhase + ''
rm -r $out/application/views/invoice_templates/pdf
ln -sf /var/lib/invoiceplane/localhost/pdf $out/application/views/invoice_templates/pdf
'';
});
})
];
};
modules = [
({ lib, config, pkgs, ... }: {
services.invoiceplane.sites."localhost" = {
enable = true;
settings.IP_URL = "http://localhost:8080";
};
nixos-shell.mounts.extraMounts = {
"/var/lib/invoiceplane/localhost/pdf" = {
target = /home/onny/projects/invoiceplane-heinrichmalerbetrieb;
cache = "none";
};
};
system.stateVersion = "25.05";
services.getty.autologinUser = "root";
documentation = {
info.enable = false;
man.enable = false;
nixos.enable = false;
};
nix = {
registry.nixpkgs.flake = inputs.nixpkgs;
settings.experimental-features = [ "nix-command" "flakes" ];
};
})
];
};
packages = { inherit start; };
defaultPackage.x86_64-linux = start;
};
}

319
heinrichmalerbetrieb.php Executable file
View file

@ -0,0 +1,319 @@
<!DOCTYPE html>
<html lang="<?php _trans('cldr'); ?>">
<head>
<meta charset="utf-8">
<title><?php _trans('invoice'); ?></title>
<link rel="stylesheet"
href="<?php echo base_url(); ?>assets/<?php echo get_setting('system_theme', 'invoiceplane'); ?>/css/templates.css">
<link rel="stylesheet" href="<?php echo base_url(); ?>assets/core/css/custom-pdf.css">
<style>
.highlight {
color: #050582;
}
.logo {
width: 200px;
float: right;
}
.company {
font-size: 0.9rem;
}
.invoice-details table {
width: 200px;
}
.client {
margin-top: 6rem;
}
.client small.sender {
color: #408236;
font-size: 0.7rem;
}
.client .client_address {
margin-top: 0.4rem;
}
table.footer th, table.footer td {
vertical-align: top;
color: #408236;
font-size: 0.8rem;
}
.page-number {
font-size: 0.8rem;
margin-top: 1.5rem;
text-align: center;
}
table.footer td.first-child {
width: 180px;
}
hr.footer {
color: #408236;
}
h1.invoice-title {
color: #3a3a3a;
margin-bottom: 0rem;
font-weight: 800;
}
p.invoice-subtitle {
color: #3a3a3a;
font-weight: bold;
margin-top: 0.5rem;
margin-bottom: 2rem;
}
</style>
</head>
<body>
<header class="clearfix">
<div id="logo" class="logo">
<?php echo invoice_logo_pdf(); ?>
</div>
<div id="client" class="client">
<small class="sender">Heinrich GmbH Blumenstraße 16-18 75233 Tiefenbronn</small>
<div class="client_address">
<?php if ($invoice->client_email && $custom_fields['invoice']['Via Email']) {
echo '<b>per Email: ' . $invoice->client_email . '</b><br>';
} ?>
<?php if ($invoice->client_title) {
echo $invoice->client_title . '<br>';
} ?>
<?php if ($invoice->client_name) {
echo $invoice->client_name;
} ?>
<?php if ($invoice->client_surname) {
echo $invoice->client_surname;
} ?>
</div>
<?php if ($invoice->client_vat_id) {
echo '<div>' . trans('vat_id_short') . ': ' . $invoice->client_vat_id . '</div>';
}
if ($invoice->client_tax_code) {
echo '<div>' . trans('tax_code_short') . ': ' . $invoice->client_tax_code . '</div>';
}
if ($invoice->client_address_1) {
echo '<div>' . htmlsc($invoice->client_address_1) . '</div>';
}
if ($invoice->client_address_2) {
echo '<div>' . htmlsc($invoice->client_address_2) . '</div>';
}
echo '<br/>';
if ($invoice->client_city || $invoice->client_state || $invoice->client_zip) {
echo '<div>';
if ($invoice->client_zip) {
echo htmlsc($invoice->client_zip) . ' ';
}
if ($invoice->client_city) {
echo htmlsc($invoice->client_city);
}
echo '</div>';
} ?>
</div>
<div id="company" class="company">
<?php if ($invoice->user_address_1) {
echo '<div>' . htmlsc($invoice->user_address_1) . '</div>';
}
if ($invoice->user_address_2) {
echo '<div>' . htmlsc($invoice->user_address_2) . '</div>';
}
if ($invoice->user_city || $invoice->user_state || $invoice->user_zip) {
echo '<div>';
if ($invoice->user_zip) {
echo htmlsc($invoice->user_zip) . ' ';
}
if ($invoice->user_city) {
echo htmlsc($invoice->user_city);
}
echo '</div>';
}
if ($invoice->user_country) {
echo '<div>' . get_country_name(trans('cldr'), $invoice->user_country) . '</div>';
}
if ($invoice->user_vat_id) {
echo '<div>' . trans('vat_id_short') . ': ' . $invoice->user_vat_id . '</div>';
}
if ($invoice->user_tax_code) {
echo '<div>' . trans('tax_code_short') . ': ' . $invoice->user_tax_code . '</div>';
}
if ($invoice->user_phone) {
echo '<div>' . trans('phone_abbr') . ': ' . htmlsc($invoice->user_phone) . '</div>';
}
if ($invoice->user_fax) {
echo '<div>' . trans('fax_abbr') . ': ' . htmlsc($invoice->user_fax) . '</div>';
}
if ($invoice->user_email) {
echo '<div class="highlight">' . htmlsc($invoice->user_email) . '</div>';
}
if ($invoice->user_web) {
echo '<div class="highlight">' . htmlsc($invoice->user_web) . '</div>';
}
?>
</div>
</header>
<main>
<div class="invoice-details clearfix">
<table>
<tr>
<td>Rechnung Nr.:</td>
<td><?php echo $invoice->invoice_number; ?></td>
</tr>
<tr>
<td colspan=2><small>(Bitte bei Zahlungen immer angeben.)</small></td>
</tr>
<tr>
<td><?php echo trans('invoice_date') . ':'; ?></td>
<td><?php echo date_from_mysql($invoice->invoice_date_created, true); ?></td>
</tr>
<?php if ($payment_method): ?>
<tr>
<td><?php echo trans('payment_method') . ': '; ?></td>
<td><?php _htmlsc($payment_method->payment_method_name); ?></td>
</tr>
<?php endif; ?>
</table>
</div>
<h1 class="invoice-title"><?php echo trans('invoice') ?></h1>
<?php
$rechnungs_betreff = $custom_fields['invoice']['Betreff'];
$rechnungs_text = $custom_fields['invoice']['Text'];
if ($rechnungs_betreff) {
echo '<p class="invoice-subtitle">' . $rechnungs_betreff . '</p>';
}
if ($rechnungs_text) {
echo '<p>' . $rechnungs_text . '</p>';
}
?>
<table class="item-table">
<thead>
<tr>
<th class="item-name"><?php _trans('item'); ?></th>
<th class="item-desc"><?php _trans('description'); ?></th>
<th class="item-amount text-right"><?php _trans('qty'); ?></th>
<th class="item-price text-right"><?php _trans('price'); ?></th>
<?php if ($show_item_discounts) : ?>
<th class="item-discount text-right"><?php _trans('discount'); ?></th>
<?php endif; ?>
<th class="item-total text-right">Gesamt</th>
</tr>
</thead>
<tbody>
<?php
foreach ($items as $item) { ?>
<tr>
<td><?php _htmlsc($item->item_name); ?></td>
<td><?php echo nl2br(htmlsc($item->item_description)); ?></td>
<td class="text-right">
<?php echo format_amount($item->item_quantity); ?>
<?php if ($item->item_product_unit) : ?>
<br>
<small><?php _htmlsc($item->item_product_unit); ?></small>
<?php endif; ?>
</td>
<td class="text-right">
<?php echo format_currency($item->item_price); ?>
</td>
<?php if ($show_item_discounts) : ?>
<td class="text-right">
<?php echo format_currency($item->item_discount); ?>
</td>
<?php endif; ?>
<td class="text-right">
<?php echo format_currency($item->item_total); ?>
</td>
</tr>
<?php } ?>
</tbody>
<tbody class="invoice-sums">
<tr>
<td <?php echo($show_item_discounts ? 'colspan="5"' : 'colspan="4"'); ?> class="text-right">
Summe
</td>
<td class="text-right"><?php echo format_currency($invoice->invoice_item_subtotal); ?></td>
</tr>
<?php if ($invoice->invoice_item_tax_total > 0) { ?>
<tr>
<td <?php echo($show_item_discounts ? 'colspan="5"' : 'colspan="4"'); ?> class="text-right">
19% MwSt.
</td>
<td class="text-right">
<?php echo format_currency($invoice->invoice_item_tax_total); ?>
</td>
</tr>
<?php } ?>
<?php foreach ($invoice_tax_rates as $invoice_tax_rate) : ?>
<tr>
<td <?php echo($show_item_discounts ? 'colspan="5"' : 'colspan="4"'); ?> class="text-right">
<?php echo htmlsc($invoice_tax_rate->invoice_tax_rate_name) . ' (' . format_amount($invoice_tax_rate->invoice_tax_rate_percent) . '%)'; ?>
</td>
<td class="text-right">
<?php echo format_currency($invoice_tax_rate->invoice_tax_rate_amount); ?>
</td>
</tr>
<?php endforeach ?>
<?php if ($invoice->invoice_discount_percent != '0.00') : ?>
<tr>
<td <?php echo($show_item_discounts ? 'colspan="5"' : 'colspan="4"'); ?> class="text-right">
<?php _trans('discount'); ?>
</td>
<td class="text-right">
<?php echo format_amount($invoice->invoice_discount_percent); ?>%
</td>
</tr>
<?php endif; ?>
<?php if ($invoice->invoice_discount_amount != '0.00') : ?>
<tr>
<td <?php echo($show_item_discounts ? 'colspan="5"' : 'colspan="4"'); ?> class="text-right">
<?php _trans('discount'); ?>
</td>
<td class="text-right">
<?php echo format_currency($invoice->invoice_discount_amount); ?>
</td>
</tr>
<?php endif; ?>
<tr>
<td <?php echo($show_item_discounts ? 'colspan="5"' : 'colspan="4"'); ?> class="text-right">
<b>Endsumme</b>
</td>
<td class="text-right">
<b><?php echo format_currency($invoice->invoice_balance); ?></b>
</td>
</tr>
</tbody>
</table>
</main>
<footer class="footer">
<?php if ($invoice->invoice_terms) : ?>
<div class="notes">
<b><?php _trans('terms'); ?></b><br/>
<?php echo nl2br(htmlsc($invoice->invoice_terms)); ?>
</div>
<?php endif; ?>
</footer>
<div>
Zahlungsbedingungen: zahlbar ab Rechnungsdatum innerhalb 8 Tagen rein netto.
<br><br>
Bitte überweisen Sie den Rechnungsbetrag unter Angabe der Rechnungsnummer auf unser Geschäftskonto. Vielen Dank.<br><br>
Wir weisen Sie darauf hin, dass Sie nach § 14b Abs. 1 S. 5 UStG verpflichtet sind, diese Rechnung zwei Jahre lang aufzubewahren.<br><br>
</div>
<sethtmlpagefooter name="defaultFooter" value="on" />
<sethtmlpagefooter name="footerWithPageNumbers" value="on" />
</body>
</html>

BIN
logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 KiB

BIN
logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
logo_subtext.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
logo_subtext.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View file

@ -1,269 +0,0 @@
<!DOCTYPE html>
<html lang="<?php _trans('cldr'); ?>">
<head>
<meta charset="utf-8">
<title><?php _trans('invoice'); ?></title>
<link rel="stylesheet" href="<?php echo base_url(); ?>assets/default/css/style.css">
<style>
body {
color: #555;
font-size: 1em;
font-family: Arial, Verdana, sans-serif;
}
table {
width:100%;
border-spacing:0;
border-collapse: collapse;
}
.text-right {
text-align: right;
}
.text-left {
text-align: left;
}
.color-l { color: #aaa; }
.color-n { color: #888; }
.color-d { color: #555; }
.border-bottom-l {
border-bottom-width: 1px;
border-style: solid;
border-color: #aaa;
}
.border-bottom-n {
border-bottom-width: 1px;
border-style: solid;
border-color: #888;
}
.border-bottom-d {
border-bottom-width: 1px;
border-style: solid;
border-color: #555;
}
.border-top-l {
border-top-width: 1px;
border-style: solid;
border-color: #aaa;
}
.border-top-n {
border-top-width: 1px;
border-style: solid;
border-color: #888;
}
.border-top-d {
border-top-width: 1px;
border-style: solid;
border-color: #555;
}
.background-l { background-color: #eee; }
header table {
width:100%;
padding: 0;
}
.company-details,
.company-details h3,
.company-details p,
.invoice-details {
text-align: right;
}
.company-name,
.invoice-id {
color: #333 !important;
}
.invoice-details td {
padding: 0.2em 0.3em;
}
.invoice-items td,
.invoice-items th {
padding: 0.2em 0.4em 0.4em;
}
.seperator {
height: 25px;
margin-bottom: 15px;
}
.amount-summary {
margin-right: -5px;
}
</style>
</head>
<body>
<header>
<table>
<tr>
<td style="width:70%">
<div style="display: block; height: 2cm"></div>
<div class="invoice-to">
<p><b><?php echo lang('bill_to'); ?>:</b></p>
<p><?php echo $custom_fields['client']['anrede'] ?><br/>
<?php echo $invoice->client_name; ?><br/>
<?php if ($invoice->client_address_1) {
echo $invoice->client_address_1 . '<br/>';
} ?>
<?php if ($invoice->client_address_2) {
echo $invoice->client_address_2 . '<br/>';
} ?>
<?php if ($invoice->client_zip) {
echo $invoice->client_zip . ' ';
} ?>
<?php if ($invoice->client_city) {
echo $invoice->client_city . '<br/><br/>';
} ?>
<?php if ($invoice->client_phone) { ?>
<abbr>Tel: </abbr><?php echo $invoice->client_phone; ?><br/>
<?php } ?>
</p>
</div>
</td>
<td class="text-right" style="width:30%;">
<div class="company-details">
<?php echo invoice_logo_pdf(); ?>
<?php echo $invoice->user_name; ?>
<p class="text-right">
<?php if ($invoice->user_address_1) {
echo $invoice->user_address_1 . '<br/>';
}?>
<?php if ($invoice->user_address_2) {
echo $invoice->user_address_2 . '<br/>';
} ?>
<?php if ($invoice->user_zip) {
echo $invoice->user_zip . ' ';
} ?>
<?php if ($invoice->user_city) {
echo $invoice->user_city . '<br/><br/>';
} ?>
<?php if ($invoice->user_tax_code) {
echo '<div>' . trans('tax_code_short') . ': ' . $invoice->user_tax_code . '</div>';
} ?>
<?php if ($invoice->user_phone) {
?><abbr>Tel: </abbr><?php echo $invoice->user_phone; ?><br><?php
} ?>
</p>
</div>
<br/>
<div class="invoice-details">
<table>
<tbody>
<tr>
<td class="text-right color-n">
<?php echo lang('invoice_date'); ?>:
</td>
<td class="text-right color-n">
<?php echo date_from_mysql($invoice->invoice_date_created, TRUE); ?>
</td>
</tr>
<tr>
<td class="text-right color-n">
<?php echo lang('due_date'); ?>:
</td>
<td class="text-right color-n">
<?php echo date_from_mysql($invoice->invoice_date_due, TRUE); ?>
</td>
</tr>
<tr>
<td class="text-right color-n">
<?php echo lang('amount_due'); ?>:
</td>
<td class="text-right color-n">
<?php echo format_currency($invoice->invoice_balance); ?>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</table>
</header>
<main>
<br/>
<h2 class="invoice-id"><?php echo lang('invoice'); ?> Nr. <?php echo $invoice->invoice_number; ?></h2>
Leistungszeitraum: <?php echo $custom_fields['invoice']['leistung_von'] ?> bis <?php echo $custom_fields['invoice']['leistung_bis'] ?><br/>
Leistungsort: <?php echo $custom_fields['invoice']['leistung_ort'] ?><br/>
<br/>
<div class="invoice-items">
<table class="table table-striped" style="width: 100%;">
<thead>
<tr class="border-bottom-d">
<th class="color-d"><?php echo lang('item'); ?></th>
<th class="color-d text-left"><?php echo lang('description'); ?></th>
<th class="text-right color-d">Menge</th>
<th class="text-right color-d">EP</th>
<th class="text-right color-d">Gesamt</th>
</tr>
</thead>
<tbody>
<?php
$linecounter = 0;
foreach ($items as $item) { ?>
<tr class="<?php echo ($linecounter % 2 ? 'background-l' : '')?>">
<td><?php echo $item->item_name; ?></td>
<td><?php echo nl2br($item->item_description); ?></td>
<td class="text-right">
<?php echo format_amount($item->item_quantity); ?>
<?php if ($item->item_product_unit) : ?>
<small><?php _htmlsc($item->item_product_unit); ?></small>
<?php endif; ?>
</td>
<td class="text-right">
<?php echo format_currency($item->item_price); ?>
</td>
<td class="text-right">
<?php echo format_currency($item->item_subtotal); ?>
</td>
</tr>
<?php $linecounter++; ?>
<?php } ?>
</tbody>
</table>
<br/>
<table>
<tr>
<td class="text-right">
<table class="amount-summary" style="width: 40%;">
<tr>
<td class="text-right color-n">
Nettosumme:
</td>
<td class="text-right color-n">
<?php echo format_currency($invoice->invoice_item_subtotal); ?>
</td>
</tr>
<tr>
<td class="text-right color-n">
0% MwSt:
</td>
<td class="text-right color-n">
0,00
</td>
</tr>
<tr style="border-bottom-width: 1px; border-style: solid;">
<td class="text-right color-d">
<b>Gesamtbetrag:</b>
</td>
<td class="text-right color-d">
<b><?php echo format_currency($invoice->invoice_balance) ?></b>
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>
</main>
<footer>
<?php if ($invoice->invoice_terms) : ?>
<div class="notes">
<b><?php _trans('terms'); ?></b><br/>
<?php echo nl2br(htmlsc($invoice->invoice_terms)); ?>
</div>
<?php endif; ?>
</footer>
</body>
</html>