diff --git a/Layout/default/Billing/Index.php b/Layout/default/Billing/Index.php index 2f21d5d7c..c1591b1cc 100644 --- a/Layout/default/Billing/Index.php +++ b/Layout/default/Billing/Index.php @@ -48,6 +48,14 @@ $pagination_entity_name = "Billingrecords"; "/> +
+ + "/> +
+
+ + "/> +
- + diff --git a/Layout/default/Invoice/Index.php b/Layout/default/Invoice/Index.php index a1e553470..af3c9ba0b 100644 --- a/Layout/default/Invoice/Index.php +++ b/Layout/default/Invoice/Index.php @@ -103,7 +103,8 @@ $pagination_entity_name = "Rechnungen";

Rechnungen

diff --git a/application/Billing/BillingController.php b/application/Billing/BillingController.php index b6135e4f4..06b1615b4 100644 --- a/application/Billing/BillingController.php +++ b/application/Billing/BillingController.php @@ -88,6 +88,26 @@ class BillingController extends mfBaseController { $new_filter["invoice_id"] = null; } + 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(array_key_exists("customer", $filter)) { if(array_key_exists("customer", $filter) && $filter["customer"]) { $kunde = $this->db()->escape($filter['customer']); @@ -135,12 +155,13 @@ class BillingController extends mfBaseController { $now_month = date("m"); $now_day = date("d"); - //$now_year = 2024; - //$now_month = 6; - //$now_day = 3; // XXX for debugging only, must be removed + $now_year = 2024; + $now_month = 7; + $now_day = 10; // XXX for debugging only, must be removed // XXX only for 1st Billing after IVT Import - $yearly_not_before = new DateTime("$now_year-$now_month-01"); + // Locking to July 2024 and keeping it for now + $yearly_not_before = new DateTime("2024-07-01"); $del = 0; // first delete all non-invoiced billing records @@ -303,15 +324,15 @@ class BillingController extends mfBaseController { $end_date = (array_key_exists("end_date", $bill_data)) ? $bill_data["end_date"] : null; $price_setup = $bill_data["price_setup"]; - if($contract->billing_period > 1 && $start_date < $yearly_not_before) { + if ($contract->billing_period > 1 && $start_date < $yearly_not_before) { // XXX only for 1st Billing after IVT Import - $this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." with start_date ".$start_date->format("Y-m-d")." because is yearly and before ".$yearly_not_before->format("Y-m-d")); + $this->log->debug(__METHOD__ . ": Ignoring Contract " . $contract->id . " with start_date " . $start_date->format("Y-m-d") . " because is yearly and before " . $yearly_not_before->format("Y-m-d")); continue; } - if($contract->billing_period == 1 && ($start_date->format("Y") < 2024 || ($start_date->format("Y") == 2024 && $start_date->format("m") < 7))) { + if ($contract->billing_period == 1 && ($start_date->format("Y") < 2024 || ($start_date->format("Y") == 2024 && $start_date->format("m") < 7))) { // XXX only for 1st Billing after IVT Import - $this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." with start_date ".$start_date->format("Y-m-d")." because is before this month"); + $this->log->debug(__METHOD__ . ": Ignoring Contract " . $contract->id . " with start_date " . $start_date->format("Y-m-d") . " because is before this month"); continue; } @@ -319,7 +340,7 @@ class BillingController extends mfBaseController { // use cancel date as end_date if ($cancel_date) { $end_date = clone $cancel_date; - } elseif(!$end_date) { + } elseif (!$end_date) { // else calculate last of month $end_date = clone $start_date; $end_date->modify("first day of this month"); @@ -346,7 +367,7 @@ class BillingController extends mfBaseController { $total_days = $last_of_period->diff($first_of_period)->format("%a") + 1; $period_days = ($end_date->diff($start_date)->format("%a")) + 1; - if($period_days < 0) continue; // don't bill for negative time range + if ($period_days < 0) continue; // don't bill for negative time range $pc = $period_days / $total_days * 100; $price = round($contract->price / 100 * $pc, 4); @@ -377,7 +398,11 @@ class BillingController extends mfBaseController { $owner = $contract->owner; - $billingaddress = $contract->billingaddress; + if ($contract->billingaddress_id) { + $billingaddress = $contract->billingaddress; + } else { + $billingaddress = $owner; + } $billing_type = "invoice"; $billing_delivery = "paper"; @@ -396,9 +421,16 @@ class BillingController extends mfBaseController { $billing_delivery = $billingaddress->billing_delivery; } - $fibu_account_num = $contract->billingaddress->fibu_account_number; - if(!$fibu_account_num) { - die("Keine Fibu Account Nummer in Rechnungskontakt in Contract ID ".$contract->id); + if($contract->vatgroup_id == TT_VATGROUP_CREDIT) { + $fibu_account_num = $billingaddress->fibu_supplier_number; + if(!$fibu_account_num) { + die("Partner " . $billingaddress->customer_number . " hat keine Lieferantennummer (" . $billingaddress->getCompanyOrName().")"); + } + } else { + $fibu_account_num = $billingaddress->fibu_account_number; + if(!$fibu_account_num) { + die("Keine Fibu Account Nummer in Rechnungskontakt in Contract ID ".$contract->id); + } } $data = []; @@ -430,13 +462,12 @@ class BillingController extends mfBaseController { $data["price"] = $price; $data["price_setup"] = $price_setup; $data["billing_period"] = $contract->billing_period; - $data["matchcode"] = $contract->matchcode; - if(!$contract->billingaddress->country_id) { + if(!$billingaddress->country_id) { $billcountry = CountryModel::getFirst(["isocode" => TT_HOMECOUNTRY_ISOCODE]); } else { - $billcountry = $contract->billingaddress->country; + $billcountry = $billingaddress->country; } $vatgroup = $contract->vatgroup; @@ -453,14 +484,14 @@ class BillingController extends mfBaseController { $data["vatarea"] = $vatarea; if($billing_type == "sepa") { - if($contract->billingaddress->sepa_date) { - $sepa_date = new DateTime("@".$contract->billingaddress->sepa_date); + if($billingaddress->sepa_date) { + $sepa_date = new DateTime("@".$billingaddress->sepa_date); $sepa_date->setTimezone(new DateTimeZone("Europe/Vienna")); $data["sepa_date"] = $sepa_date->format("Y-m-d"); } - if($contract->billingaddress->last_invoice_date) { - $sepa_last_date = new DateTime("@".$contract->billingaddress->last_invoice_date); + if($billingaddress->last_invoice_date) { + $sepa_last_date = new DateTime("@".$billingaddress->last_invoice_date); $sepa_last_date->setTimezone(new DateTimeZone("Europe/Vienna")); $data["sepa_last_date"] = $sepa_last_date->format("Y-m-d"); } @@ -482,6 +513,7 @@ class BillingController extends mfBaseController { /* * Create Voice Billing, if contract has voicenumbers */ + $voicenumbers = VoicenumberModel::search(["contract_id" => $contract->id]); if(count($voicenumbers)) { @@ -522,82 +554,122 @@ class BillingController extends mfBaseController { foreach ($voicenumbers as $voicenumber) { $vbill = BillingVoicenumberModel::getFirst(["contract_id" => $contract->id, "voicenumber" => $voicenumber->number, "start_date" => $voice_start_date->format("Y-m-d")]); - if ($vbill) { //var_dump($vbill);exit; continue; // number was already billed in this period } - $calls = VoiceCallHistoryModel::getVoiceCallHistoryAsEntity(["contract_id" => $contract->id, "voice_account" => $voicenumber->number, "start" => ["from" => $voice_start_date->getTimestamp(), "to" => $voice_end_date->getTimestamp()]]); - foreach ($calls as $call) { - //var_dump($call); - $number = $call->voice_account; - $dest_nummer = $call->destination; - if(substr($dest_nummer, 0, 2) == "00") { - $dest_nummer = substr($dest_nummer, 2); - } - if(substr($dest_nummer, 0, 1) == "+") { - $dest_nummer = substr($dest_nummer, 1); - } + // check for unbilled call records in earlier months + $call_dates = []; + $earlier_voice_start_date = clone $voice_start_date; - if (array_key_exists($dest_nummer, $destinations_cache)) { - $destination = $destinations_cache[$dest_nummer]; - } else { - $destination = $voiceplan->getDestinationByNumber($dest_nummer); - if(!$destination) { - die("Destination für Zielrufnummer ".$call->destination." nicht gefunden"); - } - $destinations_cache[$dest_nummer] = $destination; - } - //var_dump($destination); + //$historic_call_count = 0; + do { + $earlier_voice_start_date->modify("-1 month"); + // not before first billing in thetool + if($earlier_voice_start_date->format("Y-m-d") < "2024-07-01") break; - $zone = $destination->voiceplanzone; + $earlier_voice_end_date = clone $earlier_voice_start_date; + $earlier_voice_end_date->modify("last day of this month"); + $earlier_voice_end_date->setTime(23, 59, 59); - if(!$zone) { - die("Keine Zone für Destination ".$dest_nummer." gefunden"); - } - - //var_dump($zone); - - // inc_first - first minimumm duration to bill - // inc - subsequent minimum duration to bill - $inc_first = $zone->increment_first; - $inc = $zone->increment; - - $billable_duration = $call->duration; - if($billable_duration <= 0) continue; - - // calculate price of first duration unit - // then subtract first minimum duration from duration - $sec_price = $zone->price / 60; - $call_price = $inc_first * $sec_price; - $billable_duration -= $inc_first; - - // calculate price of remaining duration and make sure to bill in full duration units - if($billable_duration > 0) { - $multi = ceil($billable_duration / $inc); - $call_price += ($multi * $inc) * $sec_price; - } - - if (!array_key_exists($number, $voicebills)) { - $voicebills[$number] = []; - } - if (!array_key_exists($zone->id, $voicebills[$number])) { - $voicebills[$number][$zone->id] = [ - "zone_name" => $zone->name, - "voiceplan" => $voiceplan->name, - "duration" => 0, - "price" => $sec_price, - "zone_total" => 0, - "increment_first" => $zone->increment_first, - "increment" => $zone->increment, - "count" => 0 + $historic_call_count = VoiceCallHistoryModel::countVoiceCallHistory(["contract_id" => $contract->id, "voice_account" => $voicenumber->number, "start" => ["from" => $earlier_voice_start_date->getTimestamp(), "to" => $earlier_voice_end_date->getTimestamp()]]); + //var_dump($historic_call_count);exit; + if ($historic_call_count) { + $call_dates[] = [ + "start_date" => clone $earlier_voice_start_date, + "end_date" => clone $earlier_voice_end_date, ]; } + //var_dump($historic_call_count > 0);exit; + } while ($historic_call_count > 0); - $voicebills[$number][$zone->id]["count"]++; - $voicebills[$number][$zone->id]["zone_total"] += $call_price; - $voicebills[$number][$zone->id]["duration"] += $call->duration; + $call_dates = array_reverse($call_dates); + + $call_dates[] = [ + "start_date" => clone $voice_start_date, + "end_date" => clone $voice_end_date, + ]; + + if(count($call_dates) > 1) { + var_dump($call_dates);exit; + } + + foreach ($call_dates as $call_date) { + $calls = VoiceCallHistoryModel::getVoiceCallHistoryAsEntity(["contract_id" => $contract->id, "voice_account" => $voicenumber->number, "start" => ["from" => $call_date["start_date"]->getTimestamp(), "to" => $call_date["end_date"]->getTimestamp()]]); + foreach ($calls as $call) { + //var_dump($call); + $number = $call->voice_account; + $dest_nummer = $call->destination; + if (substr($dest_nummer, 0, 2) == "00") { + $dest_nummer = substr($dest_nummer, 2); + } + + if (substr($dest_nummer, 0, 1) == "+") { + $dest_nummer = substr($dest_nummer, 1); + } + + if (array_key_exists($dest_nummer, $destinations_cache)) { + $destination = $destinations_cache[$dest_nummer]; + } else { + $destination = $voiceplan->getDestinationByNumber($dest_nummer); + if (!$destination) { + die("Destination für Zielrufnummer " . $call->destination . " nicht gefunden"); + } + $destinations_cache[$dest_nummer] = $destination; + } + //var_dump($destination); + + $zone = $destination->voiceplanzone; + + if (!$zone) { + die("Keine Zone für Destination " . $dest_nummer . " gefunden"); + } + + //var_dump($zone); + + // inc_first - first minimumm duration to bill + // inc - subsequent minimum duration to bill + $inc_first = $zone->increment_first; + $inc = $zone->increment; + + $billable_duration = $call->duration; + if ($billable_duration <= 0) continue; + + // calculate price of first duration unit + // then subtract first minimum duration from duration + $sec_price = $zone->price / 60; + $call_price = $inc_first * $sec_price; + $billable_duration -= $inc_first; + + // calculate price of remaining duration and make sure to bill in full duration units + if ($billable_duration > 0) { + $multi = ceil($billable_duration / $inc); + $call_price += ($multi * $inc) * $sec_price; + } + + if (!array_key_exists($number, $voicebills)) { + $voicebills[$number] = []; + } + if (!array_key_exists($zone->id, $voicebills[$number])) { + $voicebills[$number][$zone->id] = [ + "zone_name" => $zone->name, + "voiceplan" => $voiceplan->name, + "duration" => 0, + "price" => $sec_price, + "zone_total" => 0, + "increment_first" => $zone->increment_first, + "increment" => $zone->increment, + "count" => 0, + "start_date" => $call_date["start_date"]->format("Y-m-d"), + "end_date" => $call_date["end_date"]->format("Y-m-d"), + ]; + } + + $voicebills[$number][$zone->id]["count"]++; + $voicebills[$number][$zone->id]["zone_total"] += $call_price; + $voicebills[$number][$zone->id]["duration"] += $call->duration; + } } } @@ -609,8 +681,8 @@ class BillingController extends mfBaseController { $vbdata["billing_id"] = $billing->id; $vbdata["contract_id"] = $contract->id; $vbdata["voicenumber"] = $vbnumber; - $vbdata["start_date"] = $voice_start_date->format("Y-m-d"); - $vbdata["end_date"] = $voice_end_date->format("Y-m-d"); + $vbdata["start_date"] = $vb["start_date"]; + $vbdata["end_date"] = $vb["end_date"]; $vbdata["voiceplan"] = $vb["voiceplan"]; $vbdata["zone"] = $vb["zone_name"]; $vbdata["call_count"] = $vb["count"]; @@ -633,14 +705,6 @@ class BillingController extends mfBaseController { } - - /*foreach(VoiceCallHistoryModel::getVoiceCallHistoryAsEntity(["contract_id" => $contract->id, "start" => ["from" => $start_date->getTimestamp()]]) as $call) { - // find BillingVoicenumber record for this call - $vbill = BillingVoicenumberModel::getFirst(["contract_id" => $contract->id, "voicenumber" => $call->voice_account, "start_date" => ]); - if($vbill) { - - } - }*/ } diff --git a/application/Billing/BillingModel.php b/application/Billing/BillingModel.php index cd8c990c0..fbe5e68e0 100644 --- a/application/Billing/BillingModel.php +++ b/application/Billing/BillingModel.php @@ -205,10 +205,10 @@ class BillingModel { $items = []; $where = self::getSqlFilter($filter); - $sql = "SELECT owner_id, billingaddress_id, billing_type, billing_delivery FROM Billing + $sql = "SELECT owner_id, billingaddress_id, billing_type, billing_delivery, vatgroup_id FROM Billing WHERE $where - GROUP BY owner_id, billingaddress_id, billing_type, billing_delivery - ORDER BY owner_id, billingaddress_id, billing_type, billing_delivery"; + GROUP BY owner_id, billingaddress_id, billing_type, billing_delivery, vatgroup_id + ORDER BY owner_id, billingaddress_id, billing_type, billing_delivery, vatgroup_id"; //var_dump($sql);exit; $res = $db->query($sql); if($db->num_rows($res)) { @@ -217,7 +217,8 @@ class BillingModel { "owner_id" => $data->owner_id, "billingaddress_id" => $data->billingaddress_id, "billing_type" => $data->billing_type, - "billing_delivery" => $data->billing_delivery + "billing_delivery" => $data->billing_delivery, + "vatgroup_id" => $data->vatgroup_id ]; } } @@ -490,11 +491,6 @@ class BillingModel { } } - if(array_key_exists("add-where", $filter)) { - $where .= " ".$filter['add-where']; - } - - if(array_key_exists("billing_type", $filter)) { $billing_type = $filter['billing_type']; if(is_numeric($billing_type)) { @@ -515,7 +511,26 @@ class BillingModel { $where .= " AND Billing.billing_delivery = '$billing_delivery'"; } } - + + if(array_key_exists("vatgroup_id", $filter)) { + $vatgroup_id = $filter['vatgroup_id']; + if(is_numeric($vatgroup_id)) { + $where .= " AND Billing.vatgroup_id = $vatgroup_id"; + } + } + + if(array_key_exists("!vatgroup_id", $filter)) { + $vatgroup_id = $filter['!vatgroup_id']; + if(is_numeric($vatgroup_id)) { + $where .= " AND Billing.vatgroup_id <> $vatgroup_id"; + } + } + + + if(array_key_exists("add-where", $filter)) { + $where .= " ".$filter['add-where']; + } + //var_dump($filter, $where);exit; return $where; } diff --git a/application/Contract/ContractController.php b/application/Contract/ContractController.php index 7032d1b5e..063b0a4e7 100644 --- a/application/Contract/ContractController.php +++ b/application/Contract/ContractController.php @@ -465,6 +465,9 @@ class ContractController extends mfBaseController } } + // TODO: Contractconfig übernehmen + + if($contract_cancel_date) { $contract->cancel_date = $contract_cancel_date->getTimestamp(); $contract->edit_by = $this->me->id; @@ -768,7 +771,7 @@ class ContractController extends mfBaseController $contract_data = []; $contract_data["owner_id"] = (int)$r->owner_id; - $contract_data["billingaddress_id"] = ($r->billingaddress_id) ? (int)$r->billingaddress_id : null; + $contract_data["billingaddress_id"] = ($r->billingaddress_id) ? (int)$r->billingaddress_id : $r->owner_id; $contract_data["product_id"] = (int)$r->product_id; $contract_data["matchcode"] = $r->matchcode; $contract_data["product_name"] = $r->product_name; @@ -822,6 +825,7 @@ class ContractController extends mfBaseController if ($mode == "add") { $contract = ContractModel::create($contract_data); } else { + $contract->edit_by = $this->me->id; $contract->update($contract_data); } @@ -851,6 +855,7 @@ class ContractController extends mfBaseController //var_dump($contract);exit; + $contract_id = $contract->save(); if (!$contract_id) { $this->layout()->setFlash("Fehler beim Speichern.", "error"); diff --git a/application/Contract/ContractModel.php b/application/Contract/ContractModel.php index 8b1385be6..ef52a750b 100644 --- a/application/Contract/ContractModel.php +++ b/application/Contract/ContractModel.php @@ -179,6 +179,7 @@ class ContractModel { $data["price_setup"] = 0; $data["price_nne"] = 0; $data["price_nbe"] = 0; + $data["vatgroup_id"] = TT_VATGROUP_CREDIT; } $contract = ContractModel::create($data); @@ -187,13 +188,19 @@ class ContractModel { return $contract; } + /** + * To create Credit Contract for Partner (NNE) + * + * @param Contract $contract + * @return bool|Contract + */ public static function createCreditForContract($contract) { $log = mfLoghandler::singleton(); $me = new User(); $me->loadMe(); if(!$contract->id) { - $log->warning(__METHOD__."(): Invalid Contractqueue object"); + $log->warning(__METHOD__."(): Invalid Contract object"); return false; } @@ -281,8 +288,7 @@ class ContractModel { $data["price_setup"] = 0; $data["price_nne"] = 0; $data["price_nbe"] = 0; - $data["vatgroup_id"] = $contract->vatgroup_id; - + $data["vatgroup_id"] = TT_VATGROUP_CREDIT; $credit = ContractModel::create($data); diff --git a/application/Invoice/InvoiceController.php b/application/Invoice/InvoiceController.php index 466082d50..45acad4e3 100644 --- a/application/Invoice/InvoiceController.php +++ b/application/Invoice/InvoiceController.php @@ -163,28 +163,39 @@ class InvoiceController extends mfBaseController { $i = 0; $p = 0; + $base_rows_bill = BillingModel::getInvoiceBaseData(['invoice_id' => null, "!vatgroup_id" => TT_VATGROUP_CREDIT]); + $base_rows_credit = BillingModel::getInvoiceBaseData(['invoice_id' => null, "vatgroup_id" => TT_VATGROUP_CREDIT]); + + $base_rows = array_merge($base_rows_bill, $base_rows_credit); + // 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; + foreach ($base_rows as $base) { + //var_dump($base);exit; $owner_id = $base["owner_id"]; $billingaddress_id = $base["billingaddress_id"]; $billing_type = $base["billing_type"]; $billing_delivery = $base["billing_delivery"]; + $base_vatgroup_id = $base["vatgroup_id"]; $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]); + $bill_filter = ["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"); + if($base_vatgroup_id == TT_VATGROUP_CREDIT) { + $bill_filter["vatgroup_id"] = TT_VATGROUP_CREDIT; + } else { + $bill_filter["!vatgroup_id"] = TT_VATGROUP_CREDIT; } + $billing_rows = BillingModel::search($bill_filter); + if(!count($billing_rows)) continue; + //var_dump($billing_rows);exit; //var_dump($owner_id, $billingaddress_id, $bills);exit; $invoice_data = []; @@ -192,6 +203,7 @@ class InvoiceController extends mfBaseController { $price_total_sum = 0; foreach($billing_rows as $bill) { + $vatgroup_id = $bill->vatgroup_id; $vatarea = $bill->vatarea; $invoice_vatrate = $bill->vatgroup->rates[$vatarea]->rate; @@ -263,7 +275,7 @@ class InvoiceController extends mfBaseController { $voicebills = BillingVoicenumberModel::search(["billing_id" => $bill->id]); //var_dump($voicebills);exit; - if(count($voicebills)) { + if (count($voicebills)) { $voice_start_date = reset($voicebills)->start_date; $voice_end_date = reset($voicebills)->end_date; $voiceplan = reset($voicebills)->voiceplan; @@ -271,7 +283,7 @@ class InvoiceController extends mfBaseController { $inc_first = reset($voicebills)->increment_first; $voice_rows = []; - foreach($voicebills as $voicebill) { + foreach ($voicebills as $voicebill) { $number = $voicebill->voicenumber; $zone = $voicebill->zone; $call_count = $voicebill->call_count; @@ -280,15 +292,15 @@ class InvoiceController extends mfBaseController { $price_total = $voicebill->price_total; - if(!array_key_exists($number, $voice_rows)) { + if (!array_key_exists($number, $voice_rows)) { $voice_rows[$number] = []; } - if(!array_key_exists($zone, $voice_rows[$number])) { + if (!array_key_exists($zone, $voice_rows[$number])) { $voice_rows[$number][$zone] = []; } - if(!array_key_exists($price, $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; @@ -304,7 +316,7 @@ class InvoiceController extends mfBaseController { $total_voice_price = 0; - foreach($voice_rows as $number => $zones) { + foreach ($voice_rows as $number => $zones) { $voicenumber_data = []; $voicenumber_data["voicenumber"] = $number; $voicenumber_data["start_date"] = $voice_start_date; @@ -317,9 +329,8 @@ class InvoiceController extends mfBaseController { $invoice_voicenumber->voicenumberzones = []; - - foreach($zones as $zone => $prices) { - foreach($prices as $price => $row_values) { + 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"]; @@ -327,7 +338,7 @@ class InvoiceController extends mfBaseController { $zone_data["price"] = $price; $zone_data["price_total"] = $row_values["price_total"]; $zone_data["price_total_gross"] = $row_values["price_total"]; - if($invoice_vatrate) { + if ($invoice_vatrate) { $zone_data["price_total_gross"] = $row_values["price_total"] + (($row_values["price_total"] / 100) * $invoice_vatrate); } $zone_data["vatrate"] = $invoice_vatrate; @@ -345,7 +356,7 @@ class InvoiceController extends mfBaseController { } $price_total_sum += $total_voice_price; - //var_dump($invoice_voicenumbers);exit; + //var_dump($invoice_voicenumbers);exit; $this->log->debug("Adding Voice Invoiceposition for Contract ID " . $bill->contract_id); @@ -374,6 +385,8 @@ class InvoiceController extends mfBaseController { $invoice_data["billingaddress_id"] = $billingaddress_id; $invoice_data["customer_number"] = $bill->customer_number; $invoice_data["fibu_account_number"] = $bill->fibu_account_number; + + $invoice_data["sepa_date"] = $bill->sepa_date; $invoice_data["sepa_id"] = $bill->sepa_id; $invoice_data["sepa_last_date"] = $bill->sepa_last_date; @@ -395,6 +408,7 @@ class InvoiceController extends mfBaseController { $invoice_data["bank_account_bic"] = $bill->bank_account_bic; $invoice_data["total"] = 0; $invoice_data["total_gross"] = 0; + $invoice_data["vatgroup_id"] = $vatgroup_id; //$invoice_data["total_vat"] = 0; @@ -404,7 +418,6 @@ class InvoiceController extends mfBaseController { $invoice_data["fibu_taxcode"] = $bill->vatgroup->rates[$vatarea]->taxcode; $invoice_data["tax_text"] = $bill->vatgroup->rates[$vatarea]->invoice_text; - } @@ -414,7 +427,7 @@ class InvoiceController extends mfBaseController { continue; }*/ - + //var_dump($invoice_data);exit; /* * ******************************* * Save invoice and add positions @@ -426,6 +439,7 @@ class InvoiceController extends mfBaseController { try { if (!$invoice->save()) { + var_dump($invoice); $invoice->rollbackTransaction(); die("Error saving Invoice"); } @@ -556,14 +570,37 @@ class InvoiceController extends mfBaseController { * 0;234325;40010;TEST-2;23.01.2024;GU;1;20;1;-1,2;0,2;GSTEST-01;;;;;;;;10;0 */ - $csv_header = "satzart;konto;gkonto;belegnr;belegdatum;buchsymbol;buchcode;prozent;steuercode;betrag;steuer;text;kost;bank-iban-nr;bank-swiftcode;bank-mandatsid;bank-mandatsdatum;bank-mandatskz;bank-letztereinzug;zvsperre;bankeinzug"; + //var_dump($this->request->type);exit; + $type = "normal"; + if($this->request->type == "credit") { + $type = "credit"; + } + + $csv_header = "satzart;konto;gkonto;belegnr;belegdatum;buchsymbol;buchcode;prozent;steuercode;betrag;steuer;text;kost;"; + + if($type == "credit") { + $csv_header .= "extbelegnr"; + } else { + $csv_header .= "bank-iban-nr;bank-swiftcode;bank-mandatsid;bank-mandatsdatum;bank-mandatskz;bank-letztereinzug;zvsperre;bankeinzug"; + } $csv_out = ""; - if(!InvoiceModel::search(["bmd_export_date" => null])) { + $filter = [ + "bmd_export_date" => null, + ]; + + if($type == "credit") { + $filter["vatgroup_id"] = TT_VATGROUP_CREDIT; + } else { + $filter["!vatgroup_id"] = TT_VATGROUP_CREDIT; + } + + + if(!InvoiceModel::search($filter)) { $this->layout()->setFlash("Keine neuen Rechnungen seit letztem BMD-Export vorhanden."); $this->redirect("Invoice"); } - foreach(InvoiceModel::search(["bmd_export_date" => null]) as $invoice) { + foreach(InvoiceModel::search($filter) as $invoice) { if($invoice->bmd_export_date) { die("wtf"); } @@ -579,9 +616,10 @@ class InvoiceController extends mfBaseController { $buchsymbol = "GU"; } else { $buchsymbol = "AR"; - } + $fibu_account = $invoice->fibu_account_number; + $buchungstext = "[".$invoice->customer_number."]"; if($invoice->company) { $buchungstext .= " ".$invoice->company; @@ -590,7 +628,7 @@ class InvoiceController extends mfBaseController { } $buchungstext = str_replace(["\n","\r", ";"], "", $buchungstext); - + $buchcode = "1"; $is_sepa = ($invoice->billing_type == "sepa"); $iban = ""; @@ -620,27 +658,41 @@ class InvoiceController extends mfBaseController { } + if($type == "credit") { + $buchsymbol = "ER"; + $buchcode = "2"; + + if($invoice->fibu_supplier_number) { + $this->layout()->setFlash("Lieferant ".$invoice->customer_number." - ".$invoice->company." ".$invoice->firstname." ".$invoice->lastname. " hat keine Lieferantennummer! Bitte nachtragen."); + $this->redirect("Invoice"); + } + $fibu_account = $invoice->fibu_account_number; + } + $csv_out .= "0;"; - $csv_out .= $invoice->fibu_account_number.";"; + $csv_out .= $fibu_account.";"; $csv_out .= $invoice->fibu_cost_account.";"; $csv_out .= $invoice->invoice_number.";"; $csv_out .= date("d.m.Y", $invoice->invoice_date).";"; $csv_out .= $buchsymbol.";"; - $csv_out .= "1;"; + $csv_out .= $buchcode.";"; $csv_out .= $vatrate.";"; $csv_out .= $invoice->fibu_taxcode.";"; $csv_out .= number_format($invoice->total_gross, 2, ",", "").";"; $csv_out .= number_format($vat, 2, ",", "").";"; $csv_out .= $buchungstext.";"; $csv_out .= ";"; // kostenstelle - $csv_out .= $iban.";"; - $csv_out .= $bic.";"; - $csv_out .= $sepa_id.";"; - $csv_out .= ($sepa_date ? $sepa_date->format("d.m.Y") : "").";"; - $csv_out .= $mandatskz.";"; - $csv_out .= ($last_invoice_date ? $last_invoice_date->format("d.m.Y") : "").";"; - $csv_out .= ($is_sepa ? 0 : 10).";"; - $csv_out .= ($is_sepa ? 1 : 0); + + if($type != "credit") { + $csv_out .= $iban.";"; + $csv_out .= $bic.";"; + $csv_out .= $sepa_id.";"; + $csv_out .= ($sepa_date ? $sepa_date->format("d.m.Y") : "").";"; + $csv_out .= $mandatskz.";"; + $csv_out .= ($last_invoice_date ? $last_invoice_date->format("d.m.Y") : "").";"; + $csv_out .= ($is_sepa ? 0 : 10).";"; + $csv_out .= ($is_sepa ? 1 : 0); + } $csv_out .= "\n"; } @@ -648,7 +700,12 @@ class InvoiceController extends mfBaseController { $this->redirect("Invoice");*/ header("Content-type: text/csv"); - header('Content-disposition: attachment; filename="tt-rech-export-bmd-'.date('Y-m-d_H-i-s').'.csv"'); + if($type == "credit") { + header('Content-disposition: attachment; filename="tt-prov-export-bmd-'.date('Y-m-d_H-i-s').'.csv"'); + } else { + header('Content-disposition: attachment; filename="tt-rech-export-bmd-'.date('Y-m-d_H-i-s').'.csv"'); + } + echo $csv_header."\n".$csv_out; exit; diff --git a/application/Invoice/InvoiceModel.php b/application/Invoice/InvoiceModel.php index 45345e299..1ca115c31 100644 --- a/application/Invoice/InvoiceModel.php +++ b/application/Invoice/InvoiceModel.php @@ -32,6 +32,7 @@ class InvoiceModel { public $bank_account_bic; public $total; public $total_gross; + public $vatgroup_id; public $bmd_export_date; public $date_delivered; public $total_vat; @@ -407,6 +408,19 @@ class InvoiceModel { } } + if(array_key_exists("vatgroup_id", $filter)) { + $vatgroup_id = $filter['vatgroup_id']; + if(is_numeric($vatgroup_id)) { + $where .= " AND Invoice.vatgroup_id = '$vatgroup_id'"; + } + } + + if(array_key_exists("!vatgroup_id", $filter)) { + $vatgroup_id = $filter['!vatgroup_id']; + if(is_numeric($vatgroup_id)) { + $where .= " AND Invoice.vatgroup_id <> '$vatgroup_id'"; + } + } if(array_key_exists("add-where", $filter)) { $where .= " ".$filter['add-where']; diff --git a/application/VoiceCallHistory/VoiceCallHistoryModel.php b/application/VoiceCallHistory/VoiceCallHistoryModel.php index 85006b2a8..618b6c060 100644 --- a/application/VoiceCallHistory/VoiceCallHistoryModel.php +++ b/application/VoiceCallHistory/VoiceCallHistoryModel.php @@ -152,6 +152,7 @@ class VoiceCallHistoryModel { public static function countVoiceCallHistory($filters) { $db = FronkDB::singleton(); $sql = "SELECT COUNT(*) as `total_rows` FROM `VoiceCallHistory` WHERE 1 " . self::getSqlFilter($filters); + mfLoghandler::singleton()->debug($sql); $result = $db->query($sql); return $result->fetch_assoc()['total_rows']; } diff --git a/db/migrations/20240805142826_invoice_add_vatgroup_id.php b/db/migrations/20240805142826_invoice_add_vatgroup_id.php new file mode 100644 index 000000000..9aaed0db2 --- /dev/null +++ b/db/migrations/20240805142826_invoice_add_vatgroup_id.php @@ -0,0 +1,31 @@ +getEnvironment() == "thetool") { + $table = $this->table('Invoice'); + $table->addColumn("vatgroup_id", "integer", ["null" => false, "after" => "total_gross"]); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } + + public function down(): void + { + if($this->getEnvironment() == "thetool") { + $this->table('Invoice')->removeColumn("vatgroup_id")->save(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } +} diff --git a/scripts/adb-rimo-import/rimo-import.php b/scripts/adb-rimo-import/rimo-import.php index 72e142937..32dabe594 100755 --- a/scripts/adb-rimo-import/rimo-import.php +++ b/scripts/adb-rimo-import/rimo-import.php @@ -221,7 +221,7 @@ foreach ($clusters as $cluster_data) { continue; }*/ $hausnummer_count++; - if($hausnummer_count < 300) continue; + //if($hausnummer_count < 300) continue; /* // ignore buildings without units diff --git a/scripts/fibu-check/export-address-and-billingaddress.php b/scripts/fibu-check/export-address-and-billingaddress.php new file mode 100644 index 000000000..b8b7ab58e --- /dev/null +++ b/scripts/fibu-check/export-address-and-billingaddress.php @@ -0,0 +1,82 @@ +#!/usr/bin/php + "billing"]) as $link) { + if($link->address_id == $link->origin_address_id) continue; + + $address = $link->address; + $origin = $link->origin; + + $in_use = ""; + if(ContractModel::getFirst(["billingaddress_id" => $address->id])) { + $in_use = "contract-billingaddress"; + } elseif(ContractModel::getFirst(["owner_id" => $address->id])) { + $in_use = "contract-billingaddress"; + } elseif(OrderModel::getFirst(["billingaddress_id" => $address->id])) { + $in_use = "order-billingaddress"; + } elseif(OrderModel::getFirst(["owner_id" => $address->id])) { + $in_use = "order-billingaddress"; + } + + + $csv = $address->id.';'; + $csv .= '"'.$in_use.'";'; + $csv .= $address->customer_number.';'; + $csv .= $address->fibu_account_number.';'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $address->company).'";'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $address->firstname).'";'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $address->lastname).'";'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $address->street).'";'; + $csv .= '"'.$address->zip.'";'; + $csv .= '"'.$address->city.'";'; + $csv .= '"'.$address->country->name.'";'; + $csv .= '"'.$address->email.'";'; + $csv .= '"'.$address->phone.'";'; + $csv .= '"'.$address->mobile.'";'; + $csv .= '"'.$address->billing_type.'";'; + $csv .= '"'.$address->billing_delivery.'";'; + $csv .= '"'.$address->bank_account_owner.'";'; + $csv .= '"'.$address->bank_account_iban.'";'; + $csv .= '"'.$address->bank_account_bic.'";'; + + $csv .= $origin->id.';'; + $csv .= $origin->customer_number.';'; + $csv .= $origin->fibu_account_number.';'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $origin->company).'";'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $origin->firstname).'";'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $origin->lastname).'";'; + $csv .= '"'.str_replace(["\n","\r","\t"], "", $origin->street).'";'; + $csv .= '"'.$origin->zip.'";'; + $csv .= '"'.$origin->city.'";'; + $csv .= '"'.$origin->country->name.'";'; + $csv .= '"'.$origin->email.'";'; + $csv .= '"'.$origin->phone.'";'; + $csv .= '"'.$origin->mobile.'";'; + $csv .= '"'.$origin->billing_type.'";'; + $csv .= '"'.$origin->billing_delivery.'";'; + $csv .= '"'.$origin->bank_account_owner.'";'; + $csv .= '"'.$origin->bank_account_iban.'";'; + $csv .= '"'.$origin->bank_account_bic.'"'; + + $lines[] = $csv; +} + +echo "$header\n"; +foreach($lines as $line) { + echo "$line\n"; +}