mirror of
https://github.com/Karaka-Management/oms-Billing.git
synced 2026-01-11 15:18:42 +00:00
316 lines
11 KiB
PHP
Executable File
316 lines
11 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Jingga
|
|
*
|
|
* PHP Version 8.2
|
|
*
|
|
* @package Modules\Media
|
|
* @copyright Dennis Eichhorn
|
|
* @license OMS License 2.2
|
|
* @version 1.0.0
|
|
* @link https://jingga.app
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
use Modules\Billing\Models\NullBill;
|
|
use Modules\Media\Models\NullCollection;
|
|
use phpOMS\Localization\ISO3166NameEnum;
|
|
use phpOMS\Localization\Money;
|
|
use phpOMS\Stdlib\Base\FloatInt;
|
|
|
|
/** @var \phpOMS\Views\View $this */
|
|
|
|
/** @var \Modules\Media\Models\Collection $collection */
|
|
$collection = $this->data['defaultTemplates'] ?? new NullCollection();
|
|
|
|
require_once $collection->findFile('.pdf.php')->getAbsolutePath();
|
|
|
|
/** @var \Modules\Billing\Models\Bill $bill */
|
|
$bill = $this->data['bill'] ?? new NullBill();
|
|
|
|
// Set up default pdf template
|
|
/** @phpstan-import-type DefaultPdf from ../../../../Admin/Install/Media/PdfDefaultTemplate/pdfTemplate.pdf.php */
|
|
$pdf = new DefaultPdf();
|
|
|
|
$lang = include __DIR__ . '/lang.php';
|
|
|
|
$pdf->attributes['title_name'] = $this->data['bill_logo_name'] ?? 'Jingga';
|
|
$pdf->attributes['slogan'] = $this->data['bill_slogan'] ?? 'Business solutions made simple.';
|
|
|
|
$pdf->setHeaderData(
|
|
__DIR__ . '/logo.png', 15,
|
|
$pdf->attributes['title_name'],
|
|
$pdf->attributes['slogan'],
|
|
);
|
|
$pdf->setCreator((string) ($this->data['bill_creator'] ?? 'Jingga'));
|
|
$pdf->setAuthor((string) ($this->data['bill_creator'] ?? 'Jingga'));
|
|
$pdf->setTitle((string) ($this->data['bill_title'] ?? $bill->type->getL11n()));
|
|
$pdf->setSubject((string) ($this->data['bill_subtitle'] ?? ''));
|
|
$pdf->setKeywords(\implode(', ', (array) ($this->data['keywords'] ?? [])));
|
|
$pdf->language = $bill->language;
|
|
|
|
$pdf->attributes['legal_name'] = $this->data['legal_company_name'] ?? 'Jingga e. K.';
|
|
$pdf->attributes['address'] = $this->data['bill_company_address'] ?? 'Kirchstr. 33';
|
|
$pdf->attributes['city'] = $this->data['bill_company_city'] ?? '61191 Rosbach';
|
|
|
|
$pdf->attributes['ceo'] = $this->data['bill_company_ceo'] ?? 'Dennis Eichhorn';
|
|
$pdf->attributes['tax_office'] = $this->data['bill_company_tax_office'] ?? 'HRA 5058';
|
|
$pdf->attributes['tax_number'] = $this->data['bill_company_tax_id'] ?? 'DE362646968';
|
|
$pdf->attributes['terms'] = $this->data['bill_company_terms'] ?? 'https://jingga.app/terms';
|
|
|
|
$pdf->attributes['bank_name'] = $this->data['bill_company_bank_name'] ?? 'Volksbank Mittelhessen';
|
|
$pdf->attributes['swift'] = $this->data['bill_company_swift'] ?? 'VBMHDE5F';
|
|
$pdf->attributes['bank_account'] = $this->data['bill_company_bank_account'] ?? 'DE62 5139 0000 0084 8044 10';
|
|
|
|
$pdf->attributes['website'] = $this->data['bill_company_website'] ?? 'www.jingga.app';
|
|
$pdf->attributes['email'] = $this->data['bill_company_email'] ?? 'info@jingga.app';
|
|
$pdf->attributes['phone'] = $this->data['bill_company_phone'] ?? '+49 152 04337728';
|
|
|
|
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
|
|
|
|
// add a page
|
|
$pdf->AddPage();
|
|
$topPos = $pdf->getY();
|
|
|
|
// Set up default bill template
|
|
$billTypeName = \strtoupper($bill->type->getL11n());
|
|
|
|
// Address
|
|
$pdf->setY(50);
|
|
$pdf->setFont('helvetica', '', 10);
|
|
|
|
$toCountry = ISO3166NameEnum::getBy2Code($bill->billCountry);
|
|
|
|
$addressString = \trim(
|
|
$bill->billTo . "\n"
|
|
. (empty($bill->billAddress) ? '' : ($bill->billAddress . "\n"))
|
|
. (empty($bill->billCity) ? '' : ($bill->billCity . "\n"))
|
|
. (empty($toCountry) ? '' : ($toCountry . "\n")),
|
|
"\n "
|
|
);
|
|
|
|
// Count the char "\n" in $addressString
|
|
$addressLineCount = \substr_count($addressString, "\n") + 1;
|
|
|
|
$lineHeight = $pdf->getY();
|
|
$pdf->Write(
|
|
0,
|
|
$addressString,
|
|
'', false, 'L', false, 0, false, false, 0
|
|
);
|
|
$lineHeight = ($lineHeight - $pdf->getY()) / $addressLineCount;
|
|
|
|
$pageWidth = $pdf->getPageWidth();
|
|
$pageHeight = $pdf->getPageHeight();
|
|
|
|
// Bill head
|
|
$pdf->setFont('helvetica', 'B', 16);
|
|
$titleWidth = $pdf->getStringWidth($billTypeName, 'helvetica', 'B', 16);
|
|
$titleWidth = \is_array($titleWidth) ? \array_sum($titleWidth) : $titleWidth;
|
|
|
|
$pdf->setXY(
|
|
$rightPos = ($pageWidth - $titleWidth - \max(60 - $titleWidth, 0) - 15 - 2),
|
|
$topPos + 50 + $lineHeight * $addressLineCount - 38,
|
|
true
|
|
);
|
|
|
|
$pdf->setTextColor(255, 255, 255);
|
|
$pdf->setFillColor(255, 162, 7);
|
|
$pdf->Cell($pageWidth - $rightPos - 15, 0, $billTypeName, 0, 0, 'L', true);
|
|
|
|
$pdf->setFont('helvetica', '', 10);
|
|
$pdf->setTextColor(255, 162, 7);
|
|
|
|
$pdf->setXY($rightPos, $tempY = $pdf->getY() + 10, true);
|
|
$pdf->MultiCell(
|
|
29, 30,
|
|
$lang[$pdf->language]['InvoiceNo'] . "\n"
|
|
. $lang[$pdf->language]['InvoiceDate'] . "\n"
|
|
. $lang[$pdf->language]['ServiceDate'] . "\n"
|
|
. $lang[$pdf->language]['CustomerNo'] . "\n"
|
|
. $lang[$pdf->language]['REF'] . "\n"
|
|
. $lang[$pdf->language]['DueDate'],
|
|
0, 'L'
|
|
);
|
|
|
|
//$pdf->setFont('helvetica', '', 10);
|
|
$pdf->setTextColor(0, 0, 0);
|
|
|
|
$pdf->setXY($rightPos + 29 + 2, $tempY, true);
|
|
$pdf->MultiCell(
|
|
25, 30,
|
|
$bill->number . "\n"
|
|
. ($bill->billDate?->format('Y-m-d') ?? '0') . "\n"
|
|
. ($bill->performanceDate?->format('Y-m-d') ?? '0') . "\n"
|
|
. $bill->accountNumber . "\n"
|
|
. $bill->external . "\n"
|
|
. ($bill->billDate?->format('Y-m-d') ?? '0'), /* Consider to add dueDate in addition */
|
|
0, 'L'
|
|
);
|
|
$pdf->Ln();
|
|
|
|
$tempY = $pdf->getY();
|
|
$height = 0;
|
|
$pdf->setY($tempY - 20);
|
|
|
|
$header = [
|
|
$lang[$pdf->language]['Item'],
|
|
$lang[$pdf->language]['Quantity'],
|
|
$lang[$pdf->language]['UnitPrice'],
|
|
$lang[$pdf->language]['Total'],
|
|
];
|
|
|
|
// Header
|
|
$headerCount = \count($header);
|
|
$w = [$pageWidth - 20 - 20 - 20 - 2 * 15, 20, 20, 20];
|
|
|
|
$pdf->setCellPadding(1);
|
|
|
|
$taxes = [];
|
|
$first = true;
|
|
|
|
// Data
|
|
$fill = false;
|
|
foreach($bill->elements as $line) {
|
|
// @todo depending on amount of lines, there is a solution (html, or use backtracking of tcpdf)
|
|
if ($first || $pdf->getY() > $pageHeight - 40) {
|
|
$pdf->setFillColor(255, 162, 7);
|
|
$pdf->setTextColor(255);
|
|
$pdf->setDrawColor(255, 162, 7);
|
|
//$pdf->SetLineWidth(0.3);
|
|
$pdf->setFont('helvetica', 'B', 10);
|
|
|
|
if (!$first/* || $row === null*/) {
|
|
$pdf->AddPage();
|
|
$pdf->Ln();
|
|
}
|
|
|
|
for($i = 0; $i < $headerCount; ++$i) {
|
|
$pdf->Cell($w[$i], 7, $header[$i], 1, 0, 'L', true);
|
|
}
|
|
|
|
$pdf->Ln();
|
|
$pdf->setFillColor(245, 245, 245);
|
|
$pdf->setTextColor(0);
|
|
$pdf->setFont('helvetica', '', 10);
|
|
|
|
$first = false;
|
|
}
|
|
|
|
// Discounts are shown below the original price -> additional line
|
|
// We don't want discount columns because that hints at customers they might be able to get discounts.
|
|
$lines = 1
|
|
+ ((int) ($line->discountQ->value > 0))
|
|
+ ((int) ($line->singleDiscountP->value > 0))
|
|
+ ((int) ($line->singleDiscountR->value > 0));
|
|
|
|
$tempY = $pdf->getY();
|
|
//$pdf->writeHTMLCell($w[0], 10, null, null, $line->itemNumber . ' ' . $line->itemName, 0, 2, $fill);
|
|
$pdf->MultiCell($w[0], 10 * $lines, \trim($line->itemNumber . ' ' . $line->itemName), 0, 'L', $fill, 2, null, null, true, 0, true, true, 0, 'M', false);
|
|
$height = $pdf->getY() - $tempY;
|
|
|
|
$singleListPriceNet = Money::fromFloatInt($line->singleListPriceNet);
|
|
$totalSalesPriceNet = Money::fromFloatInt($line->totalSalesPriceNet);
|
|
|
|
if ($line->quantity->value === 0) {
|
|
$pdf->MultiCell($w[1] + $w[2] + $w[3], $height, '', 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
|
|
} else {
|
|
$pdf->MultiCell($w[1], $height, (string) $line->quantity->getAmount($line->container?->quantityDecimals ?? 0), 0, 'L', $fill, 0, 15 + $w[0], $tempY, true, 0, false, true, 0, 'M', true);
|
|
$pdf->MultiCell($w[2], $height, $singleListPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 0, 15 + $w[0] + $w[1], $tempY, true, 0, false, true, 0, 'M', true);
|
|
$pdf->MultiCell($w[3], $height, $totalSalesPriceNet->getCurrency(2, symbol: ''), 0, 'L', $fill, 1, 15 + $w[0] + $w[1] + $w[2], $tempY, true, 0, false, true, 0, 'M', true);
|
|
}
|
|
|
|
$fill = !$fill;
|
|
|
|
// get taxes
|
|
if (!isset($taxes[$line->taxR->value / FloatInt::DIVISOR])) {
|
|
$taxes[$line->taxR->value / FloatInt::DIVISOR] = $line->taxP;
|
|
} else {
|
|
$taxes[$line->taxR->value / FloatInt::DIVISOR]->add($line->taxP);
|
|
}
|
|
}
|
|
|
|
// We have to do the following because in some cases it doesn't set the Y position correctly after the table
|
|
// I assume it is related to if/else above. A html multicell might not correctly set the y position.
|
|
if (!empty($bill->elements)) {
|
|
$pdf->setY($tempY + $height);
|
|
|
|
$pdf->Cell(\array_sum($w), 0, '', 'T');
|
|
$pdf->Ln();
|
|
|
|
if ($pdf->getY() > $pageHeight - 40) {
|
|
$pdf->AddPage();
|
|
}
|
|
|
|
$pdf->setFillColor(240, 240, 240);
|
|
$pdf->setTextColor(0);
|
|
$pdf->setDrawColor(240, 240, 240);
|
|
$pdf->setFont('helvetica', 'B', 10);
|
|
|
|
$tempY = $pdf->getY();
|
|
|
|
$netSales = Money::fromFloatInt($bill->netSales);
|
|
|
|
$pdf->setX($w[0] + $w[1] + 12);
|
|
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Subtotal'], 0, 0, 'L', false);
|
|
$pdf->Cell($w[3], 7, $netSales->getCurrency(2, symbol: ''), 0, 0, 'L', false);
|
|
$pdf->Ln();
|
|
|
|
foreach ($taxes as $rate => $tax) {
|
|
$tax = Money::fromFloatInt($tax);
|
|
|
|
$pdf->setX($w[0] + $w[1] + 12);
|
|
$pdf->Cell($w[2], 7, $lang[$pdf->language]['Taxes'] . ' (' . $rate . '%)', 0, 0, 'L', false);
|
|
$pdf->Cell($w[3], 7, $tax->getCurrency(2, symbol: ''), 0, 0, 'L', false);
|
|
$pdf->Ln();
|
|
}
|
|
|
|
$pdf->setFillColor(255, 162, 7);
|
|
$pdf->setTextColor(255);
|
|
$pdf->setDrawColor(255, 162, 7);
|
|
//$pdf->setFont('helvetica', 'B', 10);
|
|
|
|
$grossSales = Money::fromFloatInt($bill->grossSales);
|
|
|
|
$pdf->setX($w[0] + $w[1] + 12);
|
|
$pdf->Cell($w[2], 7, \strtoupper($lang[$pdf->language]['Total']), 1, 0, 'L', true);
|
|
$pdf->Cell($w[3] + 3, 7, $grossSales->getCurrency(2, symbol: ''), 1, 0, 'L', true);
|
|
$pdf->Ln();
|
|
|
|
$tempY2 = $pdf->getY();
|
|
|
|
// @todo fix payment terms
|
|
$pdf->setTextColor(0);
|
|
$pdf->setFont('helvetica', 'B', 8);
|
|
$pdf->setY($tempY);
|
|
$pdf->Write(0, $lang[$pdf->language]['PaymentTerms'] . ': CreditCard', '', false, 'L', false, 0, false, false, 0);
|
|
|
|
$pdf->setFont('helvetica', '', 8);
|
|
$pdf->Write(0, $bill->paymentText, '', false, 'L', false, 0, false, false, 0);
|
|
$pdf->Ln();
|
|
|
|
// @todo fix terms
|
|
$pdf->setFont('helvetica', 'B', 8);
|
|
$pdf->Write(0, $lang[$pdf->language]['Terms'] . ': ' . $pdf->attributes['terms'], '', false, 'L', false, 0, false, false, 0);
|
|
$pdf->Ln();
|
|
|
|
//$pdf->setFont('helvetica', 'B', 8);
|
|
$pdf->Write(0, $lang[$pdf->language]['Currency'] . ': ' . $bill->currency, '', false, 'L', false, 0, false, false, 0);
|
|
$pdf->Ln();
|
|
|
|
//$pdf->setFont('helvetica', 'B', 8);
|
|
$pdf->Write(0, $lang[$pdf->language]['TaxRemark'], '', false, 'L', false, 0, false, false, 0);
|
|
$pdf->Ln();
|
|
|
|
$pdf->setFont('helvetica', '', 8);
|
|
$pdf->Write(0, $bill->termsText, '', false, 'L', false, 0, false, false, 0);
|
|
//$pdf->Ln();
|
|
|
|
//$pdf->setY($tempY2);
|
|
//$pdf->Ln();
|
|
}
|
|
|
|
//Close and output PDF document
|
|
$path = (string) ($this->data['path'] ?? (($bill->billDate?->format('Y-m-d') ?? '0') . '_' . $bill->number . '.pdf'));
|
|
$pdf->Output($path, 'I');
|