Files
thetool/application/PreorderBillingInvoice/PreorderBillingInvoiceController.php
2025-09-17 12:45:42 +02:00

1078 lines
42 KiB
PHP

<?php
class PreorderBillingInvoiceController extends mfBaseController {
private $billing_minimum_date = "2025-03-01";
protected function init() : void
{
$this->needlogin = true;
$me = new User();
$me->loadMe();
$this->me = $me;
$this->layout()->set("me", $me);
if(!$me->can(["preorderbilling", "preorderbillingReadonly"]) && (!defined("MFBASE_BYPASS_LOGIN") || !MFBASE_BYPASS_LOGIN)) {
$this->redirect("Dashboard");
}
}
protected function indexAction() : void {
$this->layout()->setTemplate("PreorderBillingInvoice/Index");
if ($this->request->resetFilter) {
unset($_SESSION[MFAPPNAME . '-PreorderBillingInvoice-filter']);
}
$filter = [];
if (is_array($this->request->filter)) {
$filter = $this->request->filter;
$_SESSION[MFAPPNAME . '-PreorderBillingInvoice-filter'] = $filter;
} else {
if (array_key_exists(MFAPPNAME . '-PreorderBillingInvoice-filter', $_SESSION) && count($_SESSION[MFAPPNAME . '-PreorderBillingInvoice-filter'])) {
$filter = $_SESSION[MFAPPNAME . '-PreorderBillingInvoice-filter'];
}
}
$this->layout->set("filter", $filter);
$filter = $this->getPreparedFilter($filter);
// pagination defaults
$pagination = [];
$pagination['start'] = 0;
$pagination['count'] = 25;
$pagination['maxItems'] = 0;
if (is_numeric($this->request->s)) {
$pagination['start'] = intval($this->request->s);
}
$filter["netowner_id"] = $this->me->address_id;
$pagination['maxItems'] = PreorderBillingInvoice::count($filter);
$invoices = PreorderBillingInvoice::search($filter, $pagination);
$this->layout()->set("invoices", $invoices);
$this->layout()->set("pagination", $pagination);
$now = new DateTime("now");
$email_jobs = InvoiceJobModel::search(["task" => "send-preorder-invoice-email", "to_date>=" => $now->format("Y-m-d")]);
$this->layout()->set("email_jobs", $email_jobs);
$netoperators = [];
foreach(PreordercampaignModel::search(["owner_id" => $this->me->address_id]) as $campaign) {
foreach($campaign->active_operators as $op) {
if(!array_key_exists($op->operator_id, $netoperators)) {
$nop = new Address($op->operator_id);
if($nop->id) {
$netoperators[$nop->id] = $nop;
}
}
}
foreach($campaign->passive_operators as $op) {
if(!array_key_exists($op->operator_id, $netoperators)) {
$nop = new Address($op->operator_id);
if($nop->id) {
$netoperators[$nop->id] = $nop;
}
}
}
}
$this->layout()->set("netoperators", $netoperators);
// get last BMD export dates
$bmd_export_date_invoice = new mfConfig("preorder.invoice.bmd.export.invoice.ts.".$this->me->address_id);
$bmd_export_date_persion = new mfConfig("preorder.invoice.bmd.export.person.ts.".$this->me->address_id);
$bmd_export = [
"invoice" => $bmd_export_date_invoice->value(),
"person" => $bmd_export_date_persion->value(),
];
$this->layout()->set("bmd_export", $bmd_export);
}
private function getPreparedFilter($filter) {
$new_filter = [];
if(array_key_exists("name", $filter)) {
if (array_key_exists("name", $filter)) {
if (array_key_exists("name", $filter) && $filter["name"]) {
$kunde = $this->db()->escape(trim($filter['name']));
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("start_date_from", $filter)) {
if($filter["start_date_from"]) {
try {
$from = DateTime::createFromFormat("d.m.Y", $filter["start_date_from"]);
} catch (Exception $e) {}
$new_filter["start_date>="] = $from->format("Y-m-d");
}
unset($filter["start_date_from"]);
}
if(array_key_exists("start_date_to", $filter)) {
if($filter["start_date_to"]) {
try {
$to = DateTime::createFromFormat("d.m.Y", $filter["start_date_to"]);
} catch (Exception $e) {}
$new_filter["start_date<="] = $to->format("Y-m-d");
}
unset($filter["start_date_to"]);
}
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 PreorderBillingInvoice($id);
if (!$invoice->id) {
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
$this->redirect("Invoice");
}
$pdf = $invoice->pdf;
$pdf = false;
//var_dump($pdf, !$pdf);exit;
//var_dump($pdf->name);exit;
if(!$pdf || !$pdf->name) {
$ifile = PreorderBillingInvoiceFile::createFromInvoice($invoice);
if(!$ifile) {
$this->layout()->setFlash("Fehler beim PDF erstellen");
$this->redirect("PreorderBillingInvoice");
}
$pdf = $ifile->file;
}
$pdf_path = $pdf->getFullPath();
$filename = $pdf->filename;
if(!file_exists($pdf_path)) {
$this->layout()->setFlash("PDF-Datei nicht gefunden");
$this->redirect("Invoice");
}
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="'.$filename.'"');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Type: ' . mime_content_type($pdf_path));
header("Content-Length: " . filesize($pdf_path));
readfile($pdf_path);
exit;
}
protected function downloadCsv() {
$id = $this->request->id;
if (!is_numeric($id) || !$id) {
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
$this->redirect("Invoice");
}
$invoice = new PreorderBillingInvoice($id);
if (!$invoice->id) {
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
$this->redirect("Invoice");
}
$csv = $invoice->csv;
$csv_path = $csv->getFullPath();
$filename = $csv->filename;
if(!file_exists($csv_path)) {
$this->layout()->setFlash("CSV-Datei nicht gefunden");
$this->redirect("Invoice");
}
header('Content-Type: text/csv; charset=utf-8');
header('Content-disposition: attachment; filename="'.$filename.'"');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Length: " . filesize($csv_path));
readfile($csv_path);
exit;
}
protected function createJob() {
$r = $this->request;
//var_dump($r->get());exit;
$task = $r->task;
if($task != "send-preorder-invoice-email") {
$this->layout()->setFlash("Ungültiger Task", "error");
$this->redirect("PreorderBillingInvoice");
}
if(!$r->from_date) {
$this->layout()->setFlash("Startdatum wird benötigt", "error");
$this->redirect("PreorderBillingInvoice");
}
try {
$from_date = DateTime::createFromFormat("d.m.Y", $r->from_date, new DateTimeZone("Europe/Vienna"));
$from_date->setTime(0,0,0);
$to_date = clone $from_date;
$to_date->modify("+7 days");
$to_date->setTime(23,59,59);
} catch(Exception $e) {
$this->layout()->setFlash("Von- oder Bisdatum ungültig", "error");
$this->redirect("PreorderBillingInvoice");
}
$job = InvoiceJobModel::create([
"task" => $task,
"from_date" => $from_date->format("Y-m-d"),
"to_date" => $to_date->format("Y-m-d"),
]);
if(!$job->save()) {
$this->layout()->setFlash("Fehler beim Speichern", "error");
$this->redirect("PreorderBillingInvoice");
}
$this->layout()->setFlash("Task erfolgreich gespeichert", "success");
$this->redirect("PreorderBillingInvoice");
}
protected function createAction() {
$netowner_id = $this->me->address_id;
$today = new DateTime();
$bill_month = clone $today;
$bill_month->modify("-1 month");
$fmt = new IntlDateFormatter(
MFLOCALE_TIME,
IntlDateFormatter::NONE,
IntlDateFormatter::NONE,
"Europe/Vienna",
IntlDateFormatter::GREGORIAN,
'MMMM'
);
$bill_month_year_text = $fmt->format($bill_month)." ".$bill_month->format("Y");
$bill_quarter = ceil($bill_month->format("n") / 3);
$billing_row_count = 0;
$positions_count = 0;
$bill_id_count = 0;
//$products = PreorderProduct::getAll(true);
$base_rows = PreorderBilling::getInvoiceBaseData(['invoice_id' => null, "netowner_id" => $netowner_id]);
//var_dump($base_rows);exit;
$invoice_count = 0;
foreach($base_rows as $base) {
$invoice_detail_data = [];
$preorderbillingcustomer_id = $base["preorderbillingcustomer_id"];
$owner_id = $base["owner_id"];
$billingaddress_id = $base["billingaddress_id"];
$billing_delivery = $base["billing_delivery"];
$campaign_id = $base["campaign_id"];
$campaign = new Preordercampaign($campaign_id);
if(!$campaign->id) {
die("Kampagne $campaign_id nicht gefunden");
}
$campaign_name = $campaign->name;
$campaign_name = preg_replace('/^RML Liezen\s+-\s+/', '', $campaign_name);
$cluster = array_shift($campaign->salesclusters);
$cluster_name = $cluster->extref;
$bill_positions = [];
$credit_positions = [];
$invoice_voicenumbers = [];
$bill_filter = [
"netowner_id" => $netowner_id,
"preorderbillingcustomer_id" => $preorderbillingcustomer_id,
"owner_id" => $owner_id,
"billingaddress_id" => $billingaddress_id,
"preordercampaign_id" => $campaign_id,
"billing_delivery" => $billing_delivery,
"invoice_id" => null,
];
$billing_rows = PreorderBilling::search($bill_filter);
if(!count($billing_rows)) {
var_dump($bill_filter);
die("Keine Billing rows");
continue;
}
$positions_to_sort = [];
$sorted_positions = [];
$invoice_positions = [];
$invoice_vatrate = 20;
//$price_total_sum = 0;
foreach($billing_rows as $bill) {
$billing_row_count++;
$netoperator_id = false;
if ($bill->owner_id) {
$netoperator_id = $bill->owner_id;
}
$price = 0;
$price_gross = 0;
if ($bill->price > 0.000) {
$price = $bill->price;
}
if ($bill->price_setup > 0.000) {
$price = $bill->price_setup;
}
if ($bill->vatrate > 0 && $price) {
$price_gross = $price + ($price / 100 * $bill->vatrate);
}
$start_date = new DateTime($bill->start_date);
$end_date = new DateTime($bill->end_date);
$year_month = $start_date->format("Ym");
if ($netoperator_id) {
//if (!array_key_exists($netoperator_id, $invoice_detail_data)) $invoice_detail_data[$netoperator_id] = [];
$detail_data = [
"owner_id" => $bill->owner_id,
"company" => ($bill->company) ?: $bill->firstname . " " . $bill->lastname,
"network_name" => $campaign_name,
"oaid" => $bill->oaid,
"extref" => trim($bill->extref),
"order_date" => $bill->order_date,
"start_date" => $start_date->format("Y-m-d"),
"end_date" => $end_date->format("Y-m-d"),
"article_number" => $bill->article_number,
"product_name" => $bill->product_name,
"amount" => $bill->amount,
"billing_periodic" => $bill->billing_period,
"price" => $price,
"price_gross" => $price_gross,
"vatrate" => $bill->vatrate,
];
$invoice_detail_data[] = $detail_data;
}
$position_data = [];
$position_data["product_id"] = $bill->product_id;
$position_data["product_type"] = $bill->product_type;
$position_data["article_number"] = $bill->article_number;
$position_data["product_name"] = $bill->product_name;
$position_data["article_info"] = $bill->product_info;
$position_data["total"] = $price;
$position_data["total_gross"] = $price_gross;
$position_data["vatrate"] = $bill->vatrate;
$position_data["billing_id"] = $bill->id;
$position_data["fibu_cost_account"] = $bill->fibu_cost_account;
$position_data["fibu_revenue_account"] = $bill->fibu_revenue_account;
if (!array_key_exists($bill->product_id, $invoice_positions)) {
$invoice_positions[$bill->product_id] = [];
}
if (!array_key_exists($year_month, $invoice_positions[$bill->product_id])) {
$invoice_positions[$bill->product_id][$year_month] = [];
}
$invoice_positions[$bill->product_id][$year_month][] = $position_data;
}
//var_dump($invoice_positions);exit;
foreach($invoice_positions as $product_id => $year_months) {
foreach($year_months as $year_month => $positions) {
$new_pos_data = [
"count" => 0,
"amount" => 0,
"unit" => "Stk",
"price" => 0,
"price_total" => 0,
"price_gross" => 0,
"vatrate" => 20,
"preorder_billings" => [],
];
foreach($positions as $position) {
//var_dump($position);exit;
$new_pos_data["count"]++;
$new_pos_data["amount"]++;
$new_pos_data["price"] = $position["total"];
$new_pos_data["price_total"] += $position["total"];
$new_pos_data["price_gross"] += $position["total_gross"];
$new_pos_data["vatrate"] = $position_data["vatrate"];
$new_pos_data["product_id"] = $position["product_id"];
$new_pos_data["product_type"] = $position["product_type"];
$new_pos_data["article_number"] = $position["article_number"];
$new_pos_data["article_name"] = $position["product_name"];
$new_pos_data["article_info"] = $position["article_info"];
$new_pos_data["fibu_cost_account"] = $position["fibu_cost_account"];
$new_pos_data["fibu_revenue_account"] = $position["fibu_revenue_account"];
$new_pos_data["preorder_billings"][] = $position["billing_id"];
$positions_count++;
}
if($product_id == 3) {
$new_pos_data["amount"] = 1;
$new_pos_data["unit"] = "Pau";
$new_pos_data["price"] = $new_pos_data["price_total"];
}
$new_position = PreorderBillingInvoiceposition::create($new_pos_data);
$new_position->preorder_billings = $new_pos_data["preorder_billings"];
$new_position->count = $new_pos_data["count"];
$new_position->fibu_cost_account = $new_pos_data["fibu_cost_account"];
$new_position->fibu_revenue_account = $new_pos_data["fibu_revenue_account"];
$sort_key = round(3 / $product_id)."-".$year_month;
$positions_to_sort[$sort_key] = $new_position;
}
//var_dump($year_months, $new_pos_data);
//var_dump($year_month, $product_id, $positions);exit;
}
ksort($positions_to_sort);
$positions_to_sort = array_reverse($positions_to_sort);
foreach($positions_to_sort as $key => $sort_pos) {
$sorted_positions[] = $sort_pos;
}
//exit;
//var_dump($sorted_positions);exit;
//exit;
$invoice_data = [];
$invoice_data["netowner_id"] = $netowner_id;
$invoice_data["preorderbillingcustomer_id"] = $bill->preorderbillingcustomer_id;
$invoice_data["owner_id"] = $bill->owner_id;
$invoice_data["billingaddress_id"] = $bill->billingaddress_id;
$invoice_data["fibu_account_number"] = $bill->fibu_account_number;
$invoice_data["fibu_tax_code"] = 1;
$invoice_data["tax_text"] = null;
$invoice_data["head_text"] = null;
$invoice_data["uid"] = $bill->uid;
$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["billing_type"] = "invoice";
$invoice_data["billing_delivery"] = "email";
$invoice_data["total"] = 0;
$invoice_data["total_gross"] = 0;
$invoice = PreorderBillingInvoice::create($invoice_data);
$invoice->startTransaction();
try {
if (!$invoice->save()) {
var_dump($invoice);
$invoice->rollbackTransaction();
die("Error saving Invoice");
}
$total_net = 0;
$total_gross = 0;
$fibu_cost_account = "";
$fibu_revenue_account = "";
foreach($sorted_positions as $position) {
//var_dump($position);
$this->log->debug(__METHOD__.": count: ".$position->count);
$billing_ids = $position->preorder_billings;
$bill_id_count += count($billing_ids);
unset($position->preorder_billings);
unset($position->count);
$fibu_cost_account = $position->fibu_cost_account;
$fibu_revenue_account = $position->fibu_revenue_account;
unset($position->fibu_cost_account);
unset($position->fibu_revenue_account);
if($position->product_type != "enduser_setup") {
if(array_key_exists($netoperator_id, TT_PREORDER_BILLING[$netowner_id]["netoperators"]) && TT_PREORDER_BILLING[$netowner_id]["netoperators"][$netoperator_id]["billing-period"] == "quarterly") {
$invoice->head_text = "Abrechnung Q$bill_quarter ".$bill_month->format("Y")."\n$campaign_name\nPOP-Cluster: $cluster_name";
} else {
$invoice->head_text = "Abrechnung $bill_month_year_text\n$campaign_name\nPOP-Cluster: $cluster_name";
}
}
$total_net += $position->price_total;
$total_gross += $position->price_gross;
$position->price_total = round($position->price_total, 2);
$position->price_gross = round($position->price_gross, 2);
if (!$position->save()) {
$invoice->rollbackTransaction();
die("Error saving Invoiceposition");
}
$position->invoice_id = $invoice->id;
if (!$position->save()) {
$invoice->rollbackTransaction();
die("Error saving Invoiceposition");
}
// add Invoice::id to Bill
foreach($billing_ids as $bill_id) {
$pbill = new PreorderBilling($bill_id);
if (!$pbill->id) {
$invoice->rollbackTransaction();
die("Bill for Invoiceposition not found");
}
if($position->product_type == "enduser_setup") {
if(!$pbill->adb_wohneinheit) {
$invoice->rollbackTransaction();
die("Keine Wohneinheit für Preorder " . $pbill->preorder_id . " / bill " . $pbill->id);
}
$pbill->adb_wohneinheit->enduser_setup_invoice_date = $today->format("Y-m-d");
if(!$pbill->adb_wohneinheit->save()) {
$invoice->rollbackTransaction();
die("Error saving enduser_setup_invoice_date");
}
}
$pbill->invoice_id = $invoice->id;
if (!$pbill->save()) {
$invoice->rollbackTransaction();
die("error saving invoice_id to bill");
}
}
}
// generate Invoice number
$new_num = PreorderBillingInvoice::getNextInvoiceNumber($netowner_id);
$invoice->total = $total_net;
$invoice->total_gross = $total_gross;
$invoice->invoice_number = $new_num;
$invoice->invoice_date = $today->format("Y-m-d");
$invoice->fibu_cost_account = $fibu_cost_account;
$invoice->fibu_revenue_account = $fibu_revenue_account;
// 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();
$invoice_count++;
if(count($invoice_detail_data)) {
// create CSV file
//var_dump($invoice_detail_data);exit;
$csv = "\u{FEFF}Netzbetreiber;Rechungsnummer;Rechnungsdatum;Netzgebiet;OAID;Extref;Bestelldatum;Periode von;Periode bis;Artikelnummer;Produkt;Anzahl;Preis Netto\n";
foreach ($invoice_detail_data as $detail) {
//var_dump($detail);
//exit;
$csv .= '"'.str_replace(["\r","\n", '"'], [" "," ",'""'], $detail["company"]).'";';
$csv .= '"'.$invoice->invoice_number.'";';
$csv .= '"'.$invoice->invoice_date.'";';
$csv .= '"'.str_replace('"','""',$detail["network_name"]).'";';
$csv .= '"'.$detail["oaid"].'";';
$csv .= '"'.str_replace('"','""',$detail["extref"]).'";';
$csv .= '"'.$detail["order_date"].'";';
$csv .= '"'.$detail["start_date"].'";';
$csv .= '"'.$detail["end_date"].'";';
$csv .= '"'.$detail["article_number"].'";';
$csv .= '"'.$detail["product_name"].'";';
$csv .= round($detail["amount"], 3).';';
$csv .= '"'.number_format($detail["price"], 2, ",","").'"'."\n";
}
$subfolder = TT_PREORDER_BILLING[$invoice->netowner_id]["subfolder"]."/".$today->format("Y");
$invoice_path = MFUPLOAD_FILE_SAVE_PATH."/$subfolder";
if(!file_exists($invoice_path)) {
mkdir($invoice_path, 0777, true);
}
$filename = $invoice->invoice_number.".csv";
$filepath = "$invoice_path/$filename";
file_put_contents($filepath, $csv);
try {
$file = FileModel::create([
"name" => $filename,
"filename" => $filename,
"subfolder" => $subfolder,
"store_filename" => $filename,
"orig_filename" => $filename,
]);
if (!$file->save()) {
$this->log->error(__METHOD__ . ": Error saving PDF file");
return false;
}
} catch(Exception $e) {
$this->log->error(__METHOD__ . ": Error saving PDF file");
die("Fehler beim Erzeugen der Rechnungsdetailliste");
}
$ifile = PreorderBillingInvoiceFile::create([
"invoice_id" => $invoice->id,
"file_id" => $file->id,
"name" => $filename,
"description" => ""
]);
if(!$ifile->save()) {
$this->log->error(__METHOD__.": Error saving PDF Invoice Detail CSV");
die("Fehler beim Erzeugen der Rechnungsdetailliste");
}
}
}
$this->log->debug(__METHOD__.": $billing_row_count billing rows | $positions_count positions count | $bill_id_count bill_id count");
$this->layout()->setFlash("$invoice_count Rechnungen erstellt", "success");
$this->redirect("PreorderBillingInvoice");
}
protected function sendCopyAction() {
$id = $this->request->id;
if(!is_numeric($id) || $id < 1) {
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
$this->redirect("PreorderBillingInvoice");
}
$invoice = new PreorderBillingInvoice($id);
if(!$invoice->id) {
$this->layout()->setFlash("Rechnung nicht gefunden", "error");
$this->redirect("PreorderBillingInvoice");
}
$email = trim($this->request->email_to);
if(!$email) {
$this->layout()->setFlash("Ungültige Emailadresse", "error");
$this->redirect("PreorderBillingInvoice");
}
$invoice->sendByEmail($email);
$this->layout()->setFlash("Rechnungskopie erfolgreich versendet", "success");
$this->redirect("PreorderBillingInvoice");
}
public function _sendEmailInvoices($limit = false) {
$sent = 0;
$defer = 0;
$invoices = PreorderBillingInvoice::search(["billing_delivery" => "email", "date_delivered" => false]);
foreach($invoices as $invoice) {
if($limit && $sent >= $limit) {
return ["sent" => $sent, "defer" => $defer];
}
/*$pdf = $invoice->pdf;
$pdf = false;
if(!$pdf || !$pdf->name) {
$ifile = PreorderBillingInvoiceFile::createFromInvoice($invoice);
if(!$ifile) {
$this->layout()->setFlash("Fehler beim PDF erstellen");
$this->redirect("PreorderBillingInvoice");
}
$pdf = $ifile->file;
}
$pdf_file = false;
try {
$pdf_file = $pdf->getFullPath();
} catch (Exception $e) {
$this->log->error(__METHOD__.": File for Invoice ".$invoice->id." not found");
continue;
}
if(!file_exists($pdf_file)) {
$this->log->error(__METHOD__.": Datei ".$pdf->filename." nicht gefunden");
continue;
}
if($invoice->total == 0) {
$this->log->info(__METHOD__.": Skipping ".$invoice->invoice_number." because total is zero");
$invoice->date_delivered = date("U");
$invoice->save();
continue;
}
*/
if(!$invoice->sendByEmail()) {
$this->log->warning(__METHOD__.": Error sending ".$invoice->invoice_number." to ".$invoice->email);
$invoice->date_delivered = date("U");
$invoice->save();
continue;
}
$invoice->date_delivered = date("U");
$invoice->save();
$sent++;
}
return ["sent" => $sent, "defer" => $defer];
}
protected function bmdExportPerson() {
$netowner_id = $this->me->address_id;
$netowner_config = TT_PREORDER_BILLING[$netowner_id];
if(!$netowner_config) {
$this->layout()->setFlash("Interner Fehler", "error");
$this->redirect("PreorderBillingInvoice");
}
$last_export = new mfConfig("preorder.invoice.bmd.export.person.ts.".$this->me->address_id);
$last_export_date = $last_export->value();
$csv = "\u{FEFF}Konto;Vorname;Nachname;Straße;Postleitzahl;Ort;Land;Telefon;Mail;UID\n";
if(!PreorderBillingCustomer::count(["edit>" => $last_export_date])) {
$this->layout()->setFlash("Keine neuen Personendaten zum Exportieren vorhanden", "info");
$this->redirect("PreorderBillingInvoice");
}
foreach(PreorderBillingCustomer::search(["edit>" => $last_export_date]) as $person) {
$konto = $person->fibu_account_number;
if($person->company) {
$vorname = "";
$nachname = $person->company;
} else {
$vorname = $person->firstname;
$nachname = $person->lastname;
}
$strasse = $person->street;
$plz = $person->zip;
$ort = $person->city;
$land = $person->country;
$telefon = $person->phone;
$mail = $person->email;
$uid = $person->uid;
if($konto) {
$csv .= "$konto;$vorname;$nachname;$strasse;$plz;$ort;$land;$telefon;$mail;$uid\n";
}
}
$subfolder = $netowner_config["subfolder"];
$today = new DateTime();
$csv_path = MFUPLOAD_FILE_SAVE_PATH."/$subfolder";
if(!file_exists($csv_path)) {
mkdir($csv_path, 0777, true);
}
$filename = "thetool-bmd-person-export-".$today->format("Y-m-d_H-i-s").".csv";
$export_filename = "personenkonten.csv";
$filepath = "$csv_path/$filename";
if(file_put_contents($filepath, $csv) === false) {
$this->layout()->setFlash("Fehler beim Erstellen des BMD-Exports", "error");
$this->redirect("PreorderBillingInvoice");
}
$file = FileModel::create([
"name" => $filename,
"filename" => $filename,
"subfolder" => $subfolder,
"store_filename" => $filename,
"orig_filename" => $filename,
]);
$file->save();
// copy csv file to bmd export transfer directory
$transfer_path = $netowner_config["bmd-export-transfer-path"];
$transfer_file = "$transfer_path/$export_filename";
$this->log->debug(__METHOD__.": Copying $filepath to $transfer_file");
if(!copy($filepath, $transfer_file)) {
$this->layout()->setFlash("Fehler beim Kopieren des BMD-Exports", "error");
$this->redirect("PreorderBillingInvoice");
}
$last_export->value(date("U"));
$last_export->save();
$this->layout()->setFlash("Personenexport erfolgreich erstellt", "success");
$this->redirect("PreorderBillingInvoice");
}
protected function bmdExport() {
$type = $this->request->type;
$netowner_id = $this->me->address_id;
$netowner_config = TT_PREORDER_BILLING[$netowner_id];
if(!$netowner_config) {
$this->layout()->setFlash("Interner Fehler", "error");
$this->redirect("PreorderBillingInvoice");
}
if($type != "addresses" && $type != "invoice") {
$this->layout()->setFlash("Ungültiger Export-Typ", "error");
$this->redirect("PreorderBillingInvoice");
}
if($type == "addresses") {
return $this->bmdExportPerson();
}
$satzart = 0;
$buchsymbol = "ABR";
$buchcode = "1";
$prozent = 20;
$steuercode = 1;
$csv = "\u{FEFF}satzart;konto;gkonto;belegnr;belegdatum;buchsymbol;buchcode;prozent;steuercode;betrag;steuer;text;kost;kotraeger;kobetrag;dokument\n";
$invoices = [];
if(!PreorderBillingInvoice::count(["netowner_id" => $netowner_id, "bmd_export_date" => null])) {
$this->layout()->setFlash("Keine neuen Rechnungen zum exportieren vorhanden", "info");
$this->redirect("PreorderBillingInvoice");
}
foreach(PreorderBillingInvoice::search(["netowner_id" => $netowner_id, "bmd_export_date" => null]) as $invoice) {
$invoice->bmd_export_date = date("U");
$invoices[] = $invoice;
$kostentraeger = [];
foreach($invoice->positions as $position) {
if(!array_key_exists($position->article_number, $kostentraeger)) {
$kostentraeger[$position->article_number] = 0;
}
$kostentraeger[$position->article_number] += $position->price_total;
}
$invoice_date = new DateTime($invoice->invoice_date);
$konto = $invoice->fibu_account_number;
$gkonto = $invoice->fibu_revenue_account;
$belegnr = $invoice->invoice_number;
$belegdatum = $invoice_date->format("d.m.Y");
$betrag = number_format($invoice->total_gross, 2, ",", "");
$steuer = number_format(($invoice->total_gross - $invoice->total) * -1, 2, ",", "");
$text = ($invoice->company ?: $invoice->firstname." ".$invoice->lastname)." $belegnr";
$text = str_replace(["\r","\n", '"'], [" "," ",'""'], $text);
$kost = $invoice->fibu_cost_account;
$dokument = $invoice->invoice_number.".pdf";
if(count($kostentraeger) < 2) {
$csv_line = "$satzart;$konto;$gkonto;$belegnr;$belegdatum;$buchsymbol;$buchcode;$prozent;$steuercode;$betrag;$steuer;\"$text\";$kost;;;$dokument";
} else {
$csv_line = "$satzart;$konto;$gkonto;$belegnr;$belegdatum;$buchsymbol;$buchcode;$prozent;$steuercode;$betrag;$steuer;\"$text\";;;;$dokument";
foreach($kostentraeger as $kotraeger => $kobetrag) {
$kobetrag_text = number_format($kobetrag, 2, ",", "");
$csv_line .= "\n1;;;;;;;;;;;;$kost;$kotraeger;$kobetrag_text;";
}
}
$csv .= "$csv_line\n";
}
/*echo $csv;
exit;*/
$subfolder = $netowner_config["subfolder"];
$today = new DateTime();
$csv_path = MFUPLOAD_FILE_SAVE_PATH."/$subfolder";
if(!file_exists($csv_path)) {
mkdir($csv_path, 0777, true);
}
$filename = "thetool-bmd-invoice-export-".$today->format("Y-m-d_H-i-s").".csv";
$export_filename = "buchungen.csv";
$filepath = "$csv_path/$filename";
if(file_put_contents($filepath, $csv) === false) {
$this->layout()->setFlash("Fehler beim Erstellen des BMD-Exports", "error");
$this->redirect("PreorderBillingInvoice");
}
$file = FileModel::create([
"name" => $filename,
"filename" => $filename,
"subfolder" => $subfolder,
"store_filename" => $filename,
"orig_filename" => $filename,
]);
$file->save();
// save invoice PDFs to bmd export transfer path
foreach($invoices as $invoice) {
$pdf = $invoice->pdf;
if(!$pdf || !$pdf->name || !file_exists($pdf->getFullPath())) {
$ifile = PreorderBillingInvoiceFile::createFromInvoice($invoice);
if(!$ifile) {
$this->layout()->setFlash("Fehler beim PDF erstellen");
$this->redirect("PreorderBillingInvoice");
}
$pdf = $ifile->file;
}
$pdf_file = false;
try {
$pdf_file = $pdf->getFullPath();
} catch (Exception $e) {
$this->log->error(__METHOD__.": File for Invoice ".$invoice->id." not found");
continue;
}
if(!file_exists($pdf_file)) {
$this->log->error(__METHOD__.": Datei ".$pdf->filename." nicht gefunden");
continue;
}
// copy pdf file to bmd export transfer directory
$transfer_path = $netowner_config["bmd-export-transfer-path"];
$transfer_file = "$transfer_path/".$invoice->invoice_number.".pdf";
if(!copy($pdf_file, $transfer_file)) {
$this->log->error(__METHOD__.": Error copying ".$pdf_file." to ".$transfer_file);
}
}
// copy csv file to bmd export transfer directory
$transfer_path = $netowner_config["bmd-export-transfer-path"];
$transfer_file = "$transfer_path/$export_filename";
$this->log->debug(__METHOD__.": Copying $filepath to $transfer_file");
if(!copy($filepath, $transfer_file)) {
$this->layout()->setFlash("Fehler beim Kopieren des BMD-Exports", "error");
$this->redirect("PreorderBillingInvoice");
}
$bmd_export_date = new mfConfig("preorder.invoice.bmd.export.invoice.ts.".$this->me->address_id);
$bmd_export_date->value(date("U"));
$bmd_export_date->save();
foreach($invoices as $invoice) {
$invoice->save();
}
$this->layout()->setFlash("Rechnungsexport erfolgreich erstellt", "success");
$this->redirect("PreorderBillingInvoice");
}
protected function apiAction() {
$do = $this->request->do;
$data = [];
switch($do) {
case "getActiveJobs":
$return = $this->getActiveJobsApi();
break;
case "getLoggedEmail":
$return = $this->getLoggedEmail();
break;
default:
$return = false;
}
if(!is_array($return) || !count($return)) {
$data = ["status" => "error"];
$this->returnJson($data);
}
$data['status'] = "OK";
$data['result'] = $return;
$this->returnJson($data);
}
protected function getLoggedEmail() {
$invoice_id = $this->request->oid;
$emaillog_id = $this->request->eid;
if(!is_numeric($invoice_id) || $invoice_id < 1) {
return false;
}
if(!is_numeric($emaillog_id) || $emaillog_id < 1) {
return false;
}
$invoice = new PreorderBillingInvoice($invoice_id);
if(!$invoice->id) {
return false;
}
$emaillog = new EmailLog($emaillog_id);
if(!$emaillog->id) {
return false;
}
$return = [
"invoice_id" => $invoice_id,
"emaillog_id" => $emaillog_id,
"from" => $emaillog->from,
"to" => $emaillog->to,
"subject" => $emaillog->subject,
"body" => ($emaillog->body_html) ? $emaillog->body_html : $emaillog->body_text,
"bodyIsHtml" => (bool) $emaillog->body_html,
"sent" => date("d.m.Y H:i", $emaillog->create),
"headers" => json_decode($emaillog->headers),
"attachments" => [],
];
if(is_array($emaillog->attachments) && count($emaillog->attachments)) {
foreach($emaillog->attachments as $attachment) {
$return["attachments"][] = [
"id" => $attachment->id,
"hash" => $attachment->content->sha256,
"filename" => $attachment->filename,
"filesize" => ($attachment->content) ? $attachment->content->filesize : 0,
"mimetype" => ($attachment->content) ? $attachment->content->mimetype : "",
];
}
}
return $return;
}
private function getActiveJobsApi() {
$now = new DateTime("now");
$jobs = [];
foreach(InvoiceJobModel::search(["to_date>=" => $now->format("Y-m-d")]) as $job) {
if(!str_contains($job->task,"preorder")) continue;
$j = $job->data;
$j->id = $job->id;
$jobs[] = $j;
}
return ["jobs" => $jobs];
}
}