needlogin = true; $me = new User(); $me->loadMe(); $this->me = $me; $this->layout()->set("me", $me); if (!$me->is(["Admin"])) { $this->redirect("Dashboard"); } } protected function indexAction() { $this->layout()->setTemplate("Invoice/Index"); if ($this->request->resetFilter) { unset($_SESSION[MFAPPNAME . '-Invoice-filter']); } $filter = []; if (is_array($this->request->filter)) { $filter = $this->request->filter; $_SESSION[MFAPPNAME . '-Invoice-filter'] = $filter; } else { if (array_key_exists(MFAPPNAME . '-Invoice-filter', $_SESSION) && count($_SESSION[MFAPPNAME . '-Invoice-filter'])) { $filter = $_SESSION[MFAPPNAME . '-Invoice-filter']; } } $this->layout->set("filter", $filter); $filter = $this->getPreparedFilter($filter); // pagination defaults $pagination = []; $pagination['start'] = 0; $pagination['count'] = 50; $pagination['maxItems'] = 0; if (is_numeric($this->request->s)) { $pagination['start'] = intval($this->request->s); } //var_dump($filter);exit; $pagination['maxItems'] = InvoiceModel::count($filter); $billings = InvoiceModel::search($filter, $pagination); $this->layout()->set("invoices", $billings); $this->layout()->set("pagination", $pagination); } private function getPreparedFilter($filter) { $new_filter = []; 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"] = ""; $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($filter["address"]) { $search = $this->db()->escape($filter['address']); 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%')"; } } if (is_array($filter) && count($filter)) { foreach ($filter as $name => $value) { $new_filter[$name] = $value; } } return $new_filter; } protected function downloadInvoice() { $id = $this->request->id; if (!is_numeric($id) || !$id) { $this->layout()->setFlash("Rechnung nicht gefunden", "error"); $this->redirect("Invoice"); } $invoice = new Invoice($id); if (!$invoice->id) { $this->layout()->setFlash("Rechnung nicht gefunden", "error"); $this->redirect("Invoice"); } $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 * $p->amount); } $pdf_vars = ["invoice" => $invoice, "vat" => $vat]; // 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 }}", $invoice->fibu_account_number, $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); $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() { $i = 0; $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) { //var_dump($base); continue; $owner_id = $base["owner_id"]; $billingaddress_id = $base["billingaddress_id"]; $billing_type = $base["billing_type"]; $billing_delivery = $base["billing_delivery"]; $bill_positions = []; $credit_positions = []; $invoice_voicenumbers = []; $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)) { die("Keine nicht verrechneten Billing records für billingaddress_id"); } //var_dump($owner_id, $billingaddress_id, $bills);exit; $invoice_data = []; $invoice_vatrate = 20; foreach($billing_rows as $bill) { $vatarea = $bill->vatarea; $invoice_vatrate = $bill->vatgroup->rates[$vatarea]->rate; $vatrate = $invoice_vatrate; $price = $bill->price; $price_total = $bill->price * $bill->amount; $price_gross = ($vatrate) ? $price_total + ($price_total / 100) * $vatrate : $price_total; $price_setup = $bill->price_setup; $price_setup_total = $bill->price_setup * $bill->amount; $price_setup_gross = ($vatrate) ? $price_setup_total + ($price_setup_total / 100) * $vatrate : $price_setup_total; $add_setup_position = ($price > 0 && $price_setup > 0); $is_setup_only = ($price < 0.00001 && $price_setup > 0); $position_data = []; $position_data["billing_id"] = $bill->id; $position_data["contract_id"] = $bill->contract_id; $position_data["start_date"] = $bill->start_date; $position_data["end_date"] = $bill->end_date; $position_data["matchcode"] = $bill->matchcode; $position_data["product_id"] = $bill->product_id; $position_data["product_name"] = $bill->product_name; $position_data["product_info"] = $bill->product_info; $position_data["amount"] = $bill->amount; $position_data["billing_period"] = $bill->billing_period; $position_data["fibu_cost_account"] = $bill->vatgroup->rates[$vatarea]->account; $position_data["fibu_cost_account_legacy"] = $bill->vatgroup->rates[$vatarea]->legacy_account; $position_data["fibu_taxcode"] = $bill->vatgroup->rates[$vatarea]->taxcode; 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; $position_data["vatrate"] = $vatrate; $position_data["end_date"] = $position_data["start_date"]; } else { $position_data["price"] = $price; $position_data["price_total"] = $price_total; $position_data["price_gross"] = $price_gross; $position_data["vatrate"] = $vatrate; } $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); $setup_data = $position_data; $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; $setup_data["price_gross"] = $price_setup_gross; $setup_data["vatrate"] = $vatrate; $setup_data["end_date"] = $setup_data["start_date"]; $setup_position = InvoicepositionModel::create($setup_data); $bill_positions[] = $setup_position; } /* * *************************************** * Get Voicenumber Billing to Billing row * *************************************** */ $voicebills = BillingVoicenumberModel::search(["billing_id" => $bill->id]); //var_dump($voicebills);exit; if(count($voicebills)) { $voice_start_date = reset($voicebills)->start_date; $voice_end_date = reset($voicebills)->end_date; $voiceplan = reset($voicebills)->voiceplan; $inc = reset($voicebills)->increment; $inc_first = reset($voicebills)->increment_first; $voice_rows = []; foreach($voicebills as $voicebill) { $number = $voicebill->voicenumber; $zone = $voicebill->zone; $call_count = $voicebill->call_count; $duration = $voicebill->duration; $price = $voicebill->price; $price_total = $voicebill->price_total; if(!array_key_exists($number, $voice_rows)) { $voice_rows[$number] = []; } if(!array_key_exists($zone, $voice_rows[$number])) { $voice_rows[$number][$zone] = []; } if(!array_key_exists($price, $voice_rows[$number][$zone])) { $voice_rows[$number][$zone][$price] = []; $voice_rows[$number][$zone][$price]["call_count"] = 0; $voice_rows[$number][$zone][$price]["duration"] = 0; $voice_rows[$number][$zone][$price]["price_total"] = 0; } $voice_rows[$number][$zone][$price]["call_count"] += $call_count; $voice_rows[$number][$zone][$price]["duration"] = $duration; $voice_rows[$number][$zone][$price]["price_total"] = $price_total; } //var_dump($voice_rows);exit; $total_voice_price = 0; foreach($voice_rows as $number => $zones) { $voicenumber_data = []; $voicenumber_data["voicenumber"] = $number; $voicenumber_data["start_date"] = $voice_start_date; $voicenumber_data["end_date"] = $voice_end_date; $voicenumber_data["voiceplan"] = $voiceplan; $voicenumber_data["increment"] = $inc; $voicenumber_data["increment_first"] = $inc_first; $invoice_voicenumber = InvoiceVoicenumberModel::create($voicenumber_data); $invoice_voicenumber->voicenumberzones = []; foreach($zones as $zone => $prices) { foreach($prices as $price => $row_values) { $zone_data = []; $zone_data["zone"] = $zone; $zone_data["call_count"] = $row_values["call_count"]; $zone_data["duration"] = $row_values["duration"]; $zone_data["price"] = $price; $zone_data["price_total"] = $row_values["price_total"]; $zone_data["price_total_gross"] = $row_values["price_total"]; if($invoice_vatrate) { $zone_data["price_total_gross"] = $row_values["price_total"] + (($row_values["price_total"] / 100) * $invoice_vatrate); } $zone_data["vatrate"] = $invoice_vatrate; $total_voice_price += $row_values["price_total"]; $voicenumber_zone = InvoiceVoicenumberZoneModel::create($zone_data); //var_dump($voicenumber_zone); $invoice_voicenumber->data->voicenumberzones[] = $voicenumber_zone; } } //var_dump($invoice_voicenumber);exit; $invoice_voicenumbers[] = $invoice_voicenumber; } //var_dump($invoice_voicenumbers);exit; $this->log->debug("Adding Voice Invoiceposition for Contract ID " . $bill->contract_id); $voice_data = $position_data; $voice_data["product_name"] = "Gesprächsgebühren zu " . $bill->product_name; $voice_data["product_info"] = null; $voice_data["matchcode"] = null; $voice_data["price"] = $total_voice_price; $voice_data["price_total"] = $total_voice_price; $voice_data["price_gross"] = $total_voice_price + (($total_voice_price / 100) * 20); $voice_data["vatrate"] = $invoice_vatrate; $voice_data["start_date"] = $voice_start_date; $voice_data["end_date"] = $voice_end_date; $voice_position = InvoicepositionModel::create($voice_data); $voice_position->setOption("timerange_month_only", true); $bill_positions[] = $voice_position; } /*if($bill->price >= 0 || $bill->price_setup >= 0) { $bill_positions[] = InvoicepositionModel::create($position_data); } else { $credit_positions[] = InvoicepositionModel::create($position_data);; }*/ $invoice_data["owner_id"] = $owner_id; $invoice_data["billingaddress_id"] = $billingaddress_id; $invoice_data["customer_number"] = $bill->customer_number; $invoice_data["fibu_account_number"] = $bill->fibu_account_number; $invoice_data["company"] = $bill->company; $invoice_data["firstname"] = $bill->firstname; $invoice_data["lastname"] = $bill->lastname; $invoice_data["street"] = $bill->street; $invoice_data["zip"] = $bill->zip; $invoice_data["city"] = $bill->city; $invoice_data["country"] = $bill->country; $invoice_data["email"] = $bill->email; $invoice_data["uid"] = $bill->uid; $invoice_data["billing_type"] = $billing_type; $invoice_data["billing_delivery"] = $billing_delivery; $invoice_data["bank_account_bank"] = $bill->bank_account_bank; $invoice_data["bank_account_owner"] = $bill->bank_account_owner; $invoice_data["bank_account_iban"] = $bill->bank_account_iban; $invoice_data["bank_account_bic"] = $bill->bank_account_bic; $invoice_data["total"] = 0; $invoice_data["total_gross"] = 0; //$invoice_data["total_vat"] = 0; $invoice_data["fibu_cost_area"] = $vatarea; $invoice_data["fibu_cost_account"] = $bill->vatgroup->rates[$vatarea]->account; $invoice_data["fibu_cost_account_legacy"] = $bill->vatgroup->rates[$vatarea]->legacy_account; $invoice_data["fibu_taxcode"] = $bill->vatgroup->rates[$vatarea]->taxcode; $invoice_data["tax_text"] = $bill->vatgroup->rates[$vatarea]->invoice_text; } /* * ******************************* * Save invoice and add positions * ******************************* */ // create Invoice $invoice = InvoiceModel::create($invoice_data); $invoice->startTransaction(); try { if (!$invoice->save()) { $invoice->rollbackTransaction(); die("Error saving Invoice"); } $total_net = 0; $total_gross = 0; //$total_vat = 0; foreach ($bill_positions as $position) { // on error: rollback transaction // add Invoice::id to Invoiceposition $position->invoice_id = $invoice->id; if(!$invoice_vatrate || !$position->vatrate) { $total_net += $position->price_total; $total_gross += $position->price_total; } else { //$total_vat += ($position->price_total / 100) * $position->vatrate; $total_net += $position->price_total; $total_gross += $position->price_gross; } // save Invoiceposition if (!$position->save()) { $invoice->rollbackTransaction(); die("Error saving Invoiceposition"); } // ad Invoice::id to Bill $bill = new Billing($position->billing_id); if (!$bill->id) { $invoice->rollbackTransaction(); die("Bill for Invoiceposition not found"); } $bill->invoice_id = $invoice->id; if (!$bill->save()) { $invoice->rollbackTransaction(); die("error saving invoice_id to bill"); } $p++; } $invoice->total = $total_net; $invoice->total_gross = $total_gross; //$invoice->total_vat = $total_vat; if (!$invoice->save()) { $invoice->rollbackTransaction(); die("Error saving totals in Invoice"); } if(count($invoice_voicenumbers)) { foreach($invoice_voicenumbers as $inv_vn) { $invnz_s = $inv_vn->voicenumberzones; unset($inv_vn->voicenumberzones); $inv_vn->invoice_id = $invoice->id; if(!$inv_vn->save()) { $invoice->rollbackTransaction(); die("Error saving InvoiceVoicenumber"); } foreach($invnz_s as $invnz) { $invnz->invoicevoicenumber_id = $inv_vn->id; if(!$invnz->save()) { $invoice->rollbackTransaction(); die("Error saving InvoiceVoicenumberZone"); } } } } // generate Invoice number $new_num = InvoiceModel::getNextInvoiceNUmber(); $invoice->invoice_number = $new_num; $invoice->invoice_date = date("U"); // voicenumbers //var_dump($invoice_voicenumbers);exit; if (!$invoice->save()) { $invoice->rollbackTransaction(); die("Error saving Invoice number and date"); } } catch (Exception $e) { if ($invoice) { $invoice->rollbackTransaction(); } die("Error saving Invoice!\n"); } // commit transaction $invoice->commitTransaction(); $i++; // Create Invoice PDF // if billing_delivery == paper -> add to pdf collection // else -> send by email //var_dump($invoice); //exit; } $this->layout()->setFlash("$i Rechnungen mit $p Rechnungspositionen erstellt"); $this->redirect("Invoice"); } }