diff --git a/Layout/default/Invoice/PDF_FOOTER.html b/Layout/default/Invoice/PDF_FOOTER.html new file mode 100644 index 000000000..b97ab5254 --- /dev/null +++ b/Layout/default/Invoice/PDF_FOOTER.html @@ -0,0 +1,39 @@ + + +Xinon Rechnung + + + + +
+
+ XINON GmbH | Fladnitz 150 | 8322 Studenzen
+ Tel.: +43 3115 40800 | E-Mail: office@xinon.at
+ UID: ATU68711968 | FN: 416556h | LG: Feldbach
+
+ +
Seite von
+ +
+ + diff --git a/Layout/default/Invoice/PDF_MAIN.php b/Layout/default/Invoice/PDF_MAIN.php new file mode 100644 index 000000000..a51a45e46 --- /dev/null +++ b/Layout/default/Invoice/PDF_MAIN.php @@ -0,0 +1,241 @@ +total + $invoice->total_setup; +$gross_total = $invoice->total_gross + $invoice->total_setup_gross; +$is_credit = $net_total < 0; + +$this->setReturnValue(['filename' => $invoice->invoice_number . ".pdf"]); + +//die(json_encode($invoice->positions)); + +?> + + + + + Rechnung + + + + + + + + + +
+ +

Ihre Xinon Rechnung vom invoice_date)?>

+ + + + + + + + + + + + positions as $p): + $start_date = new DateTime($p->start_date); + $end_date = new DateTime($p->end_date); + $amount = (float) number_format($p->amount, 3, ",", "."); + $price = number_format($p->price, 2, ",","."); + $price_total = number_format($p->price_total, 2, ",","."); + $price_gross = number_format($p->price_gross, 2, ",","."); + $vatrate = number_format($p->vatrate, 2, ",","."); + + ?> + + "> + + + + + + + + + matchcode): ?> + "> + + + + + + + + + $vat_total): ?> + + 0): ?> + + + + + + + + + + + + + +
DienstleistungZeitraumPreisMengeNetto €Ust. %Brutto €
product_name?> + billing_period > 1 ? + $start_date->format("m.Y") . " - " . $end_date->format("m.Y") : + $start_date->format("d.m.Y") . " - " . $end_date->format("d.m.Y") + ?> + + %
matchcode?>
Gesamt Netto:
USt. %:
Gesamt Brutto:
+ + + + + + \ No newline at end of file diff --git a/application/Invoice/InvoiceController.php b/application/Invoice/InvoiceController.php index 61b014674..59dc1a169 100644 --- a/application/Invoice/InvoiceController.php +++ b/application/Invoice/InvoiceController.php @@ -1,9 +1,13 @@ needlogin = true; $me = new User(); $me->loadMe(); @@ -41,7 +45,7 @@ class InvoiceController extends mfBaseController { $pagination['count'] = 50; $pagination['maxItems'] = 0; - if(is_numeric($this->request->s)) { + if (is_numeric($this->request->s)) { $pagination['start'] = intval($this->request->s); } //var_dump($filter);exit; @@ -52,22 +56,21 @@ class InvoiceController extends mfBaseController { $this->layout()->set("pagination", $pagination); } - private function getPreparedFilter($filter) - { + private function getPreparedFilter($filter) { $new_filter = []; - if(array_key_exists("customer", $filter)) { - if(array_key_exists("customer", $filter) && $filter["customer"]) { + if (array_key_exists("customer", $filter)) { + if (array_key_exists("customer", $filter) && $filter["customer"]) { $kunde = $this->db()->escape($filter['customer']); - if(!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = ""; + if (!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = ""; $new_filter['add-where'] .= " AND (company like '%$kunde%' OR firstname like '%$kunde%' OR lastname like '%$kunde%' OR concat(firstname, ' ', lastname) like '%$kunde%' OR concat(lastname, ' ', firstname) like '%$kunde%')"; } } - if(array_key_exists("address", $filter)) { - if(array_key_exists("address", $filter) && $filter["address"]) { + if (array_key_exists("address", $filter)) { + if (array_key_exists("address", $filter) && $filter["address"]) { $search = $this->db()->escape($filter['address']); - if(!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = ""; + if (!array_key_exists("add-where", $new_filter)) $new_filter["add-where"] = ""; $new_filter['add-where'] .= " AND (street like '%$search%' OR zip like '%$search%' OR city like '%$search%' OR country like '%$search%')"; } } @@ -91,37 +94,62 @@ class InvoiceController extends mfBaseController { $invoice = new Invoice($id); if (!$invoice->id) { $this->layout()->setFlash("Rechnung nicht gefunden", "error"); - $this->redirect("Rechnung"); + $this->redirect("Invoice"); } - $vat = []; - - foreach($invoice->positions as $p) { - if(!array_key_exists($p->vatrate, $vat)) { + foreach ($invoice->positions as $p) { + if (!array_key_exists($p->vatrate, $vat)) { $vat[$p->vatrate] = 0; } $vat[$p->vatrate] += $p->price_gross - $p->price; } - $pdf_vars = [ - "invoice" => $invoice, - "vat" => $vat - ]; + $pdf_vars = ["invoice" => $invoice, "vat" => $vat]; - /*$this->layout()->setTemplate("Invoice/Print.pdf"); - $this->layout()->set("invoice", $invoice); - $this->layout()->set("vat", $vat); - $this->layout()->set("ressourcePathPrefix", MFFANCYBASEURL."/"); - return true;*/ + // Replace placeholders in header + $headerHtml = file_get_contents(BASEDIR . "/Layout/default/Invoice/PDF_HEADER.html"); + $headerHtml = str_replace("{{ basedir }}", BASEDIR, $headerHtml); + $headerHtml = str_replace("{{ addressLine_1 }}", $invoice->company ? $invoice->company : "", $headerHtml); + $headerHtml = str_replace("{{ addressLine_2 }}", $invoice->firstname . " " . $invoice->lastname, $headerHtml); + $headerHtml = str_replace("{{ addressLine_3 }}", nl2br($invoice->street), $headerHtml); + $headerHtml = str_replace("{{ addressLine_4 }}", $invoice->zip . " " . $invoice->city, $headerHtml); + $headerHtml = str_replace("{{ addressLine_5 }}", $invoice->country != "Österreich" ? $invoice->country : "", $headerHtml); + $headerHtml = str_replace("{{ customerNumber }}", $invoice->customer_number, $headerHtml); + $headerHtml = str_replace("{{ billingAccount }}", "testtest", $headerHtml); + $headerHtml = str_replace("{{ invoiceNumber }}", $invoice->invoice_number, $headerHtml); + $headerHtml = str_replace("{{ invoiceDate }}", date("d.m.Y", $invoice->invoice_date), $headerHtml); + $headerHtml = str_replace("{{ vatHtml }}", $invoice->uid ? "Ihre UID:" . $invoice->uid . "" : "", $headerHtml); + $headerHtml = str_replace("{{ qrCodeSrc }}", $this->getBankQRCode($invoice->invoice_number, $invoice->total_gross), $headerHtml); - $pdf = new PdfForm("Invoice/Print.pdf", $pdf_vars); - //$pdfpath = $pdf->render(); - $pdf->download($invoice->invoice_number.".pdf"); + $headerFile = BASEDIR . "/var/temp/" . date("U") . "-" . rand(1000, 9999) . ".html"; + file_put_contents($headerFile, $headerHtml); + $pdf = new PdfForm("Invoice/PDF_MAIN", $pdf_vars); + $wkhtmltopdfArgs = "--header-html $headerFile --footer-html " . BASEDIR . "/Layout/default/Invoice/PDF_FOOTER.html"; + $pdf->download($invoice->invoice_number . ".pdf", $wkhtmltopdfArgs); + } + public function getBankQRCode($paymentReference, $amount) { + $xinonIBAN = "DE89370400440532013000"; + $xinonBIC = "COBADEFFXXX"; + + $epc = "BCD +001 +1 +SCT +$xinonBIC +Xinon GmbH +$xinonIBAN +EUR$amount +XINO +$paymentReference + +XINON GmbH"; + + return (new QRCode)->render($epc); } protected function runInvoicingAction() { @@ -129,7 +157,7 @@ class InvoiceController extends mfBaseController { $p = 0; // get pairs of owner_id and billingaddress_id, so each will be its own invoice - foreach(BillingModel::getInvoiceBaseData(['invoice_id' => null]) as $base) { + foreach (BillingModel::getInvoiceBaseData(['invoice_id' => null]) as $base) { //var_dump($base); continue; $owner_id = $base["owner_id"]; $billingaddress_id = $base["billingaddress_id"]; @@ -139,14 +167,13 @@ class InvoiceController extends mfBaseController { $bill_positions = []; $credit_positions = []; - $billing_rows = BillingModel::search([ - "owner_id" => $owner_id, - "billingaddress_id" => $billingaddress_id, - "billing_type" => $billing_type, - "billing_delivery" => $billing_delivery, - "invoice_id" => null]); + $billing_rows = BillingModel::search(["owner_id" => $owner_id, + "billingaddress_id" => $billingaddress_id, + "billing_type" => $billing_type, + "billing_delivery" => $billing_delivery, + "invoice_id" => null]); - if(!count($billing_rows)) { + if (!count($billing_rows)) { die("Keine nicht verrechneten Billing records für billingaddress_id"); } @@ -154,7 +181,7 @@ class InvoiceController extends mfBaseController { $invoice_data = []; - foreach($billing_rows as $bill) { + foreach ($billing_rows as $bill) { $vatrate = $bill->vatrate; $price = $bill->price; $price_total = $bill->price * $bill->amount; @@ -178,8 +205,8 @@ class InvoiceController extends mfBaseController { $position_data["billing_period"] = $bill->billing_period; - if($is_setup_only) { - $this->log->debug("Contract ID ". $bill->contract_id." is setup only"); + if ($is_setup_only) { + $this->log->debug("Contract ID " . $bill->contract_id . " is setup only"); $position_data["price"] = $price_setup; $position_data["price_total"] = $price_setup_total; $position_data["price_gross"] = $price_setup_gross; @@ -195,10 +222,10 @@ class InvoiceController extends mfBaseController { $new_position = InvoicepositionModel::create($position_data); $bill_positions[] = $new_position; - if($add_setup_position) { - $this->log->debug("Adding Setup Invoiceposition for Contract ID ". $bill->contract_id); + if ($add_setup_position) { + $this->log->debug("Adding Setup Invoiceposition for Contract ID " . $bill->contract_id); $setup_data = $position_data; - $setup_data["product_name"] = "Herstellungskosten ".$bill->product_name; + $setup_data["product_name"] = "Herstellungskosten " . $bill->product_name; $setup_data["product_info"] = ""; $setup_data["price"] = $price_setup; $setup_data["price_total"] = $price_setup * $bill->amount; @@ -239,7 +266,6 @@ class InvoiceController extends mfBaseController { $invoice_data["total_vat"] = 0; - } @@ -251,7 +277,7 @@ class InvoiceController extends mfBaseController { $invoice->startTransaction(); try { - if(!$invoice->save()) { + if (!$invoice->save()) { $invoice->rollbackTransaction(); die("Error saving Invoice"); } @@ -260,13 +286,13 @@ class InvoiceController extends mfBaseController { $total_gross = 0; $total_vat = 0; - foreach($bill_positions as $position) { + foreach ($bill_positions as $position) { // on error: rollback transaction // add Invoice::id to Invoiceposition $position->invoice_id = $invoice->id; - if(!$position->vatrate) { + if (!$position->vatrate) { $total_net += $position->price_total; } else { $total_vat += ($position->price_total / 100) * $position->vatrate; @@ -275,20 +301,20 @@ class InvoiceController extends mfBaseController { } // save Invoiceposition - if(!$position->save()) { + if (!$position->save()) { $invoice->rollbackTransaction(); die("Error saving Invoiceposition"); } // ad Invoice::id to Bill $bill = new Billing($position->billing_id); - if(!$bill->id) { + if (!$bill->id) { $invoice->rollbackTransaction(); die("Bill for Invoiceposition not found"); } $bill->invoice_id = $invoice->id; - if(!$bill->save()) { + if (!$bill->save()) { $invoice->rollbackTransaction(); die("error saving invoice_id to bill"); } @@ -300,7 +326,7 @@ class InvoiceController extends mfBaseController { $invoice->total_gross = $total_gross; $invoice->total_vat = $total_vat; - if(!$invoice->save()) { + if (!$invoice->save()) { $invoice->rollbackTransaction(); die("Error saving totals in Invoice"); } @@ -310,7 +336,7 @@ class InvoiceController extends mfBaseController { $invoice->invoice_number = $new_num; $invoice->invoice_date = date("U"); - if(!$invoice->save()) { + if (!$invoice->save()) { $invoice->rollbackTransaction(); die("Error saving Invoice number and date"); } @@ -319,7 +345,7 @@ class InvoiceController extends mfBaseController { $invoice->commitTransaction(); $i++; } catch (Exception $e) { - if($invoice) { + if ($invoice) { $invoice->rollbackTransaction(); } diff --git a/lib/PdfForm/PdfForm.php b/lib/PdfForm/PdfForm.php index ac0b5ceae..3af38535f 100644 --- a/lib/PdfForm/PdfForm.php +++ b/lib/PdfForm/PdfForm.php @@ -16,23 +16,23 @@ class PdfForm { } - public function render() { + public function render($additionalArgs = false): string { $this->layout->setTemplate($this->template); $this->layout->set("ressourcePathPrefix", BASEDIR."/public/"); foreach($this->variables as $name => $value) { $this->layout->set($name, $value); } - $fullpath = $this->layout->renderPDF(); + $fullpath = $this->layout->renderPDF(false, $additionalArgs); $this->fullpath = $fullpath; $this->returnValues = $this->layout->getReturnedValue(); return $fullpath; } - public function download($filename = false) { + public function download($filename = false, $additionalArgs = false) { if(!$this->fullpath) { - $this->render(); + $this->render($additionalArgs); } $filepath = $this->fullpath;