Billing changes

This commit is contained in:
Frank Schubert
2024-08-05 21:09:13 +02:00
parent 75f75b6327
commit a6389f014f
10 changed files with 357 additions and 149 deletions
+27 -2
View File
@@ -48,6 +48,14 @@ $pagination_entity_name = "Billingrecords";
<label class="form-label" for="filter_product">Produkt</label> <label class="form-label" for="filter_product">Produkt</label>
<input type="text" class="form-control" name="filter[product]" id="filter_product" value="<?=(array_key_exists("product", $filter)) ? $filter['product'] : ""?>"/> <input type="text" class="form-control" name="filter[product]" id="filter_product" value="<?=(array_key_exists("product", $filter)) ? $filter['product'] : ""?>"/>
</div> </div>
<div class="col-1">
<label class="form-label" for="filter_start_date_from">Periode von</label>
<input type="text" class="form-control" name="filter[start_date_from]" id="filter_start_date_from" value="<?=(array_key_exists("start_date_from", $filter)) ? $filter['start_date_from'] : ""?>"/>
</div>
<div class="col-1">
<label class="form-label" for="filter_start_date_to">Periode bis</label>
<input type="text" class="form-control" name="filter[start_date_to]" id="filter_start_date_to" value="<?=(array_key_exists("start_date_to", $filter)) ? $filter['start_date_to'] : ""?>"/>
</div>
<div class="col-2"> <div class="col-2">
<label class="form-label" for="filter_show_credit">Gutschriften</label> <label class="form-label" for="filter_show_credit">Gutschriften</label>
<select class="form-control" name="filter[show_credit]" id="filter_show_credit"> <select class="form-control" name="filter[show_credit]" id="filter_show_credit">
@@ -105,7 +113,7 @@ $pagination_entity_name = "Billingrecords";
</div> </div>
<div class="float-right"> <div class="float-right">
<a class="btn btn-outline-primary mb-2" href="<?=self::getUrl("Billing", "importContracts")?>"> <a class="btn btn-outline-primary mb-2" href="<?=self::getUrl("Billing", "importContracts")?>">
<i class="fas fa-fw fa-file-import"></i> Aktuell verrechenbare Contracts neu importieren <i class="fas fa-fw fa-file-import"></i> Rechnungsdatensätze aus Contracts erstellen
</a> </a>
</div> </div>
</div> </div>
@@ -218,5 +226,22 @@ $pagination_entity_name = "Billingrecords";
</div> </div>
<script>
$("#filter_start_date_from").datepicker({
orientation: "bottom",
language: 'de',
format: "dd.mm.yyyy",
showWeekDays: true,
todayBtn: 'linked',
autoclose: true
});
$("#filter_start_date_to").datepicker({
orientation: "bottom",
language: 'de',
format: "dd.mm.yyyy",
showWeekDays: true,
todayBtn: 'linked',
autoclose: true
});
</script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?> <?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>
+2 -1
View File
@@ -103,7 +103,8 @@ $pagination_entity_name = "Rechnungen";
<div class="col-12"> <div class="col-12">
<h4 class="header-title">Rechnungen</h4> <h4 class="header-title">Rechnungen</h4>
<div class="float-right"> <div class="float-right">
<a href="<?=self::getUrl("Invoice", "exportBmd")?>" class="btn btn-outline-primary"><i class="far fa-fw fa-file-export"></i> Rechnungsexport für BMD</a> <a href="<?=self::getUrl("Invoice", "exportBmd", ["type" => "credit"])?>" class="btn btn-outline-danger"><i class="far fa-fw fa-file-export"></i> Provisionsexport für BMD</a>
<a href="<?=self::getUrl("Invoice", "exportBmd")?>" class="btn btn-outline-primary ml-2"><i class="far fa-fw fa-file-export"></i> Rechnungsexport für BMD</a>
</div> </div>
</div> </div>
+160 -96
View File
@@ -88,6 +88,26 @@ class BillingController extends mfBaseController {
$new_filter["invoice_id"] = null; $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)) {
if(array_key_exists("customer", $filter) && $filter["customer"]) { if(array_key_exists("customer", $filter) && $filter["customer"]) {
$kunde = $this->db()->escape($filter['customer']); $kunde = $this->db()->escape($filter['customer']);
@@ -135,12 +155,13 @@ class BillingController extends mfBaseController {
$now_month = date("m"); $now_month = date("m");
$now_day = date("d"); $now_day = date("d");
//$now_year = 2024; $now_year = 2024;
//$now_month = 6; $now_month = 7;
//$now_day = 3; // XXX for debugging only, must be removed $now_day = 10; // XXX for debugging only, must be removed
// XXX only for 1st Billing after IVT Import // 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; $del = 0;
// first delete all non-invoiced billing records // 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; $end_date = (array_key_exists("end_date", $bill_data)) ? $bill_data["end_date"] : null;
$price_setup = $bill_data["price_setup"]; $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 // 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; 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 // 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; continue;
} }
@@ -319,7 +340,7 @@ class BillingController extends mfBaseController {
// use cancel date as end_date // use cancel date as end_date
if ($cancel_date) { if ($cancel_date) {
$end_date = clone $cancel_date; $end_date = clone $cancel_date;
} elseif(!$end_date) { } elseif (!$end_date) {
// else calculate last of month // else calculate last of month
$end_date = clone $start_date; $end_date = clone $start_date;
$end_date->modify("first day of this month"); $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; $total_days = $last_of_period->diff($first_of_period)->format("%a") + 1;
$period_days = ($end_date->diff($start_date)->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; $pc = $period_days / $total_days * 100;
$price = round($contract->price / 100 * $pc, 4); $price = round($contract->price / 100 * $pc, 4);
@@ -377,7 +398,11 @@ class BillingController extends mfBaseController {
$owner = $contract->owner; $owner = $contract->owner;
$billingaddress = $contract->billingaddress; if ($contract->billingaddress_id) {
$billingaddress = $contract->billingaddress;
} else {
$billingaddress = $owner;
}
$billing_type = "invoice"; $billing_type = "invoice";
$billing_delivery = "paper"; $billing_delivery = "paper";
@@ -396,9 +421,16 @@ class BillingController extends mfBaseController {
$billing_delivery = $billingaddress->billing_delivery; $billing_delivery = $billingaddress->billing_delivery;
} }
$fibu_account_num = $contract->billingaddress->fibu_account_number; if($contract->vatgroup_id == TT_VATGROUP_CREDIT) {
if(!$fibu_account_num) { $fibu_account_num = $billingaddress->fibu_supplier_number;
die("Keine Fibu Account Nummer in Rechnungskontakt in Contract ID ".$contract->id); 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 = []; $data = [];
@@ -430,13 +462,12 @@ class BillingController extends mfBaseController {
$data["price"] = $price; $data["price"] = $price;
$data["price_setup"] = $price_setup; $data["price_setup"] = $price_setup;
$data["billing_period"] = $contract->billing_period; $data["billing_period"] = $contract->billing_period;
$data["matchcode"] = $contract->matchcode; $data["matchcode"] = $contract->matchcode;
if(!$contract->billingaddress->country_id) { if(!$billingaddress->country_id) {
$billcountry = CountryModel::getFirst(["isocode" => TT_HOMECOUNTRY_ISOCODE]); $billcountry = CountryModel::getFirst(["isocode" => TT_HOMECOUNTRY_ISOCODE]);
} else { } else {
$billcountry = $contract->billingaddress->country; $billcountry = $billingaddress->country;
} }
$vatgroup = $contract->vatgroup; $vatgroup = $contract->vatgroup;
@@ -453,14 +484,14 @@ class BillingController extends mfBaseController {
$data["vatarea"] = $vatarea; $data["vatarea"] = $vatarea;
if($billing_type == "sepa") { if($billing_type == "sepa") {
if($contract->billingaddress->sepa_date) { if($billingaddress->sepa_date) {
$sepa_date = new DateTime("@".$contract->billingaddress->sepa_date); $sepa_date = new DateTime("@".$billingaddress->sepa_date);
$sepa_date->setTimezone(new DateTimeZone("Europe/Vienna")); $sepa_date->setTimezone(new DateTimeZone("Europe/Vienna"));
$data["sepa_date"] = $sepa_date->format("Y-m-d"); $data["sepa_date"] = $sepa_date->format("Y-m-d");
} }
if($contract->billingaddress->last_invoice_date) { if($billingaddress->last_invoice_date) {
$sepa_last_date = new DateTime("@".$contract->billingaddress->last_invoice_date); $sepa_last_date = new DateTime("@".$billingaddress->last_invoice_date);
$sepa_last_date->setTimezone(new DateTimeZone("Europe/Vienna")); $sepa_last_date->setTimezone(new DateTimeZone("Europe/Vienna"));
$data["sepa_last_date"] = $sepa_last_date->format("Y-m-d"); $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 * Create Voice Billing, if contract has voicenumbers
*/ */
$voicenumbers = VoicenumberModel::search(["contract_id" => $contract->id]); $voicenumbers = VoicenumberModel::search(["contract_id" => $contract->id]);
if(count($voicenumbers)) { if(count($voicenumbers)) {
@@ -522,82 +554,122 @@ class BillingController extends mfBaseController {
foreach ($voicenumbers as $voicenumber) { foreach ($voicenumbers as $voicenumber) {
$vbill = BillingVoicenumberModel::getFirst(["contract_id" => $contract->id, "voicenumber" => $voicenumber->number, "start_date" => $voice_start_date->format("Y-m-d")]); $vbill = BillingVoicenumberModel::getFirst(["contract_id" => $contract->id, "voicenumber" => $voicenumber->number, "start_date" => $voice_start_date->format("Y-m-d")]);
if ($vbill) { if ($vbill) {
//var_dump($vbill);exit; //var_dump($vbill);exit;
continue; // number was already billed in this period 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) == "+") { // check for unbilled call records in earlier months
$dest_nummer = substr($dest_nummer, 1); $call_dates = [];
} $earlier_voice_start_date = clone $voice_start_date;
if (array_key_exists($dest_nummer, $destinations_cache)) { //$historic_call_count = 0;
$destination = $destinations_cache[$dest_nummer]; do {
} else { $earlier_voice_start_date->modify("-1 month");
$destination = $voiceplan->getDestinationByNumber($dest_nummer); // not before first billing in thetool
if(!$destination) { if($earlier_voice_start_date->format("Y-m-d") < "2024-07-01") break;
die("Destination für Zielrufnummer ".$call->destination." nicht gefunden");
}
$destinations_cache[$dest_nummer] = $destination;
}
//var_dump($destination);
$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) { $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()]]);
die("Keine Zone für Destination ".$dest_nummer." gefunden"); //var_dump($historic_call_count);exit;
} if ($historic_call_count) {
$call_dates[] = [
//var_dump($zone); "start_date" => clone $earlier_voice_start_date,
"end_date" => clone $earlier_voice_end_date,
// 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
]; ];
} }
//var_dump($historic_call_count > 0);exit;
} while ($historic_call_count > 0);
$voicebills[$number][$zone->id]["count"]++; $call_dates = array_reverse($call_dates);
$voicebills[$number][$zone->id]["zone_total"] += $call_price;
$voicebills[$number][$zone->id]["duration"] += $call->duration; $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["billing_id"] = $billing->id;
$vbdata["contract_id"] = $contract->id; $vbdata["contract_id"] = $contract->id;
$vbdata["voicenumber"] = $vbnumber; $vbdata["voicenumber"] = $vbnumber;
$vbdata["start_date"] = $voice_start_date->format("Y-m-d"); $vbdata["start_date"] = $vb["start_date"];
$vbdata["end_date"] = $voice_end_date->format("Y-m-d"); $vbdata["end_date"] = $vb["end_date"];
$vbdata["voiceplan"] = $vb["voiceplan"]; $vbdata["voiceplan"] = $vb["voiceplan"];
$vbdata["zone"] = $vb["zone_name"]; $vbdata["zone"] = $vb["zone_name"];
$vbdata["call_count"] = $vb["count"]; $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) {
}
}*/
} }
+25 -10
View File
@@ -205,10 +205,10 @@ class BillingModel {
$items = []; $items = [];
$where = self::getSqlFilter($filter); $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 WHERE $where
GROUP 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"; ORDER BY owner_id, billingaddress_id, billing_type, billing_delivery, vatgroup_id";
//var_dump($sql);exit; //var_dump($sql);exit;
$res = $db->query($sql); $res = $db->query($sql);
if($db->num_rows($res)) { if($db->num_rows($res)) {
@@ -217,7 +217,8 @@ class BillingModel {
"owner_id" => $data->owner_id, "owner_id" => $data->owner_id,
"billingaddress_id" => $data->billingaddress_id, "billingaddress_id" => $data->billingaddress_id,
"billing_type" => $data->billing_type, "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)) { if(array_key_exists("billing_type", $filter)) {
$billing_type = $filter['billing_type']; $billing_type = $filter['billing_type'];
if(is_numeric($billing_type)) { if(is_numeric($billing_type)) {
@@ -515,7 +511,26 @@ class BillingModel {
$where .= " AND Billing.billing_delivery = '$billing_delivery'"; $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; //var_dump($filter, $where);exit;
return $where; return $where;
} }
+1 -1
View File
@@ -768,7 +768,7 @@ class ContractController extends mfBaseController
$contract_data = []; $contract_data = [];
$contract_data["owner_id"] = (int)$r->owner_id; $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["product_id"] = (int)$r->product_id;
$contract_data["matchcode"] = $r->matchcode; $contract_data["matchcode"] = $r->matchcode;
$contract_data["product_name"] = $r->product_name; $contract_data["product_name"] = $r->product_name;
+1 -1
View File
@@ -189,7 +189,7 @@ class ContractModel {
} }
/** /**
* To create Credit Contract for Partner * To create Credit Contract for Partner (NNE)
* *
* @param Contract $contract * @param Contract $contract
* @return bool|Contract * @return bool|Contract
+95 -38
View File
@@ -163,28 +163,39 @@ class InvoiceController extends mfBaseController {
$i = 0; $i = 0;
$p = 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 // get pairs of owner_id and billingaddress_id, so each will be its own invoice
foreach (BillingModel::getInvoiceBaseData(['invoice_id' => null]) as $base) { foreach ($base_rows as $base) {
//var_dump($base); continue; //var_dump($base);exit;
$owner_id = $base["owner_id"]; $owner_id = $base["owner_id"];
$billingaddress_id = $base["billingaddress_id"]; $billingaddress_id = $base["billingaddress_id"];
$billing_type = $base["billing_type"]; $billing_type = $base["billing_type"];
$billing_delivery = $base["billing_delivery"]; $billing_delivery = $base["billing_delivery"];
$base_vatgroup_id = $base["vatgroup_id"];
$bill_positions = []; $bill_positions = [];
$credit_positions = []; $credit_positions = [];
$invoice_voicenumbers = []; $invoice_voicenumbers = [];
$billing_rows = BillingModel::search(["owner_id" => $owner_id, $bill_filter = ["owner_id" => $owner_id,
"billingaddress_id" => $billingaddress_id, "billingaddress_id" => $billingaddress_id,
"billing_type" => $billing_type, "billing_type" => $billing_type,
"billing_delivery" => $billing_delivery, "billing_delivery" => $billing_delivery,
"invoice_id" => null]); "invoice_id" => null];
if (!count($billing_rows)) { if($base_vatgroup_id == TT_VATGROUP_CREDIT) {
die("Keine nicht verrechneten Billing records für billingaddress_id"); $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; //var_dump($owner_id, $billingaddress_id, $bills);exit;
$invoice_data = []; $invoice_data = [];
@@ -192,6 +203,7 @@ class InvoiceController extends mfBaseController {
$price_total_sum = 0; $price_total_sum = 0;
foreach($billing_rows as $bill) { foreach($billing_rows as $bill) {
$vatgroup_id = $bill->vatgroup_id;
$vatarea = $bill->vatarea; $vatarea = $bill->vatarea;
$invoice_vatrate = $bill->vatgroup->rates[$vatarea]->rate; $invoice_vatrate = $bill->vatgroup->rates[$vatarea]->rate;
@@ -263,7 +275,7 @@ class InvoiceController extends mfBaseController {
$voicebills = BillingVoicenumberModel::search(["billing_id" => $bill->id]); $voicebills = BillingVoicenumberModel::search(["billing_id" => $bill->id]);
//var_dump($voicebills);exit; //var_dump($voicebills);exit;
if(count($voicebills)) { if (count($voicebills)) {
$voice_start_date = reset($voicebills)->start_date; $voice_start_date = reset($voicebills)->start_date;
$voice_end_date = reset($voicebills)->end_date; $voice_end_date = reset($voicebills)->end_date;
$voiceplan = reset($voicebills)->voiceplan; $voiceplan = reset($voicebills)->voiceplan;
@@ -271,7 +283,7 @@ class InvoiceController extends mfBaseController {
$inc_first = reset($voicebills)->increment_first; $inc_first = reset($voicebills)->increment_first;
$voice_rows = []; $voice_rows = [];
foreach($voicebills as $voicebill) { foreach ($voicebills as $voicebill) {
$number = $voicebill->voicenumber; $number = $voicebill->voicenumber;
$zone = $voicebill->zone; $zone = $voicebill->zone;
$call_count = $voicebill->call_count; $call_count = $voicebill->call_count;
@@ -280,15 +292,15 @@ class InvoiceController extends mfBaseController {
$price_total = $voicebill->price_total; $price_total = $voicebill->price_total;
if(!array_key_exists($number, $voice_rows)) { if (!array_key_exists($number, $voice_rows)) {
$voice_rows[$number] = []; $voice_rows[$number] = [];
} }
if(!array_key_exists($zone, $voice_rows[$number])) { if (!array_key_exists($zone, $voice_rows[$number])) {
$voice_rows[$number][$zone] = []; $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] = [];
$voice_rows[$number][$zone][$price]["call_count"] = 0; $voice_rows[$number][$zone][$price]["call_count"] = 0;
$voice_rows[$number][$zone][$price]["duration"] = 0; $voice_rows[$number][$zone][$price]["duration"] = 0;
@@ -304,7 +316,7 @@ class InvoiceController extends mfBaseController {
$total_voice_price = 0; $total_voice_price = 0;
foreach($voice_rows as $number => $zones) { foreach ($voice_rows as $number => $zones) {
$voicenumber_data = []; $voicenumber_data = [];
$voicenumber_data["voicenumber"] = $number; $voicenumber_data["voicenumber"] = $number;
$voicenumber_data["start_date"] = $voice_start_date; $voicenumber_data["start_date"] = $voice_start_date;
@@ -317,9 +329,8 @@ class InvoiceController extends mfBaseController {
$invoice_voicenumber->voicenumberzones = []; $invoice_voicenumber->voicenumberzones = [];
foreach ($zones as $zone => $prices) {
foreach($zones as $zone => $prices) { foreach ($prices as $price => $row_values) {
foreach($prices as $price => $row_values) {
$zone_data = []; $zone_data = [];
$zone_data["zone"] = $zone; $zone_data["zone"] = $zone;
$zone_data["call_count"] = $row_values["call_count"]; $zone_data["call_count"] = $row_values["call_count"];
@@ -327,7 +338,7 @@ class InvoiceController extends mfBaseController {
$zone_data["price"] = $price; $zone_data["price"] = $price;
$zone_data["price_total"] = $row_values["price_total"]; $zone_data["price_total"] = $row_values["price_total"];
$zone_data["price_total_gross"] = $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["price_total_gross"] = $row_values["price_total"] + (($row_values["price_total"] / 100) * $invoice_vatrate);
} }
$zone_data["vatrate"] = $invoice_vatrate; $zone_data["vatrate"] = $invoice_vatrate;
@@ -345,7 +356,7 @@ class InvoiceController extends mfBaseController {
} }
$price_total_sum += $total_voice_price; $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); $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["billingaddress_id"] = $billingaddress_id;
$invoice_data["customer_number"] = $bill->customer_number; $invoice_data["customer_number"] = $bill->customer_number;
$invoice_data["fibu_account_number"] = $bill->fibu_account_number; $invoice_data["fibu_account_number"] = $bill->fibu_account_number;
$invoice_data["sepa_date"] = $bill->sepa_date; $invoice_data["sepa_date"] = $bill->sepa_date;
$invoice_data["sepa_id"] = $bill->sepa_id; $invoice_data["sepa_id"] = $bill->sepa_id;
$invoice_data["sepa_last_date"] = $bill->sepa_last_date; $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["bank_account_bic"] = $bill->bank_account_bic;
$invoice_data["total"] = 0; $invoice_data["total"] = 0;
$invoice_data["total_gross"] = 0; $invoice_data["total_gross"] = 0;
$invoice_data["vatgroup_id"] = $vatgroup_id;
//$invoice_data["total_vat"] = 0; //$invoice_data["total_vat"] = 0;
@@ -404,7 +418,6 @@ class InvoiceController extends mfBaseController {
$invoice_data["fibu_taxcode"] = $bill->vatgroup->rates[$vatarea]->taxcode; $invoice_data["fibu_taxcode"] = $bill->vatgroup->rates[$vatarea]->taxcode;
$invoice_data["tax_text"] = $bill->vatgroup->rates[$vatarea]->invoice_text; $invoice_data["tax_text"] = $bill->vatgroup->rates[$vatarea]->invoice_text;
} }
@@ -414,7 +427,7 @@ class InvoiceController extends mfBaseController {
continue; continue;
}*/ }*/
//var_dump($invoice_data);exit;
/* /*
* ******************************* * *******************************
* Save invoice and add positions * Save invoice and add positions
@@ -426,6 +439,7 @@ class InvoiceController extends mfBaseController {
try { try {
if (!$invoice->save()) { if (!$invoice->save()) {
var_dump($invoice);
$invoice->rollbackTransaction(); $invoice->rollbackTransaction();
die("Error saving Invoice"); 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 * 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 = ""; $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->layout()->setFlash("Keine neuen Rechnungen seit letztem BMD-Export vorhanden.");
$this->redirect("Invoice"); $this->redirect("Invoice");
} }
foreach(InvoiceModel::search(["bmd_export_date" => null]) as $invoice) { foreach(InvoiceModel::search($filter) as $invoice) {
if($invoice->bmd_export_date) { if($invoice->bmd_export_date) {
die("wtf"); die("wtf");
} }
@@ -579,9 +616,10 @@ class InvoiceController extends mfBaseController {
$buchsymbol = "GU"; $buchsymbol = "GU";
} else { } else {
$buchsymbol = "AR"; $buchsymbol = "AR";
} }
$fibu_account = $invoice->fibu_account_number;
$buchungstext = "[".$invoice->customer_number."]"; $buchungstext = "[".$invoice->customer_number."]";
if($invoice->company) { if($invoice->company) {
$buchungstext .= " ".$invoice->company; $buchungstext .= " ".$invoice->company;
@@ -590,7 +628,7 @@ class InvoiceController extends mfBaseController {
} }
$buchungstext = str_replace(["\n","\r", ";"], "", $buchungstext); $buchungstext = str_replace(["\n","\r", ";"], "", $buchungstext);
$buchcode = "1";
$is_sepa = ($invoice->billing_type == "sepa"); $is_sepa = ($invoice->billing_type == "sepa");
$iban = ""; $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 .= "0;";
$csv_out .= $invoice->fibu_account_number.";"; $csv_out .= $fibu_account.";";
$csv_out .= $invoice->fibu_cost_account.";"; $csv_out .= $invoice->fibu_cost_account.";";
$csv_out .= $invoice->invoice_number.";"; $csv_out .= $invoice->invoice_number.";";
$csv_out .= date("d.m.Y", $invoice->invoice_date).";"; $csv_out .= date("d.m.Y", $invoice->invoice_date).";";
$csv_out .= $buchsymbol.";"; $csv_out .= $buchsymbol.";";
$csv_out .= "1;"; $csv_out .= $buchcode.";";
$csv_out .= $vatrate.";"; $csv_out .= $vatrate.";";
$csv_out .= $invoice->fibu_taxcode.";"; $csv_out .= $invoice->fibu_taxcode.";";
$csv_out .= number_format($invoice->total_gross, 2, ",", "").";"; $csv_out .= number_format($invoice->total_gross, 2, ",", "").";";
$csv_out .= number_format($vat, 2, ",", "").";"; $csv_out .= number_format($vat, 2, ",", "").";";
$csv_out .= $buchungstext.";"; $csv_out .= $buchungstext.";";
$csv_out .= ";"; // kostenstelle $csv_out .= ";"; // kostenstelle
$csv_out .= $iban.";";
$csv_out .= $bic.";"; if($type != "credit") {
$csv_out .= $sepa_id.";"; $csv_out .= $iban.";";
$csv_out .= ($sepa_date ? $sepa_date->format("d.m.Y") : "").";"; $csv_out .= $bic.";";
$csv_out .= $mandatskz.";"; $csv_out .= $sepa_id.";";
$csv_out .= ($last_invoice_date ? $last_invoice_date->format("d.m.Y") : "").";"; $csv_out .= ($sepa_date ? $sepa_date->format("d.m.Y") : "").";";
$csv_out .= ($is_sepa ? 0 : 10).";"; $csv_out .= $mandatskz.";";
$csv_out .= ($is_sepa ? 1 : 0); $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"; $csv_out .= "\n";
} }
@@ -648,7 +700,12 @@ class InvoiceController extends mfBaseController {
$this->redirect("Invoice");*/ $this->redirect("Invoice");*/
header("Content-type: text/csv"); 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; echo $csv_header."\n".$csv_out;
exit; exit;
+14
View File
@@ -32,6 +32,7 @@ class InvoiceModel {
public $bank_account_bic; public $bank_account_bic;
public $total; public $total;
public $total_gross; public $total_gross;
public $vatgroup_id;
public $bmd_export_date; public $bmd_export_date;
public $date_delivered; public $date_delivered;
public $total_vat; 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)) { if(array_key_exists("add-where", $filter)) {
$where .= " ".$filter['add-where']; $where .= " ".$filter['add-where'];
@@ -152,6 +152,7 @@ class VoiceCallHistoryModel {
public static function countVoiceCallHistory($filters) { public static function countVoiceCallHistory($filters) {
$db = FronkDB::singleton(); $db = FronkDB::singleton();
$sql = "SELECT COUNT(*) as `total_rows` FROM `VoiceCallHistory` WHERE 1 " . self::getSqlFilter($filters); $sql = "SELECT COUNT(*) as `total_rows` FROM `VoiceCallHistory` WHERE 1 " . self::getSqlFilter($filters);
mfLoghandler::singleton()->debug($sql);
$result = $db->query($sql); $result = $db->query($sql);
return $result->fetch_assoc()['total_rows']; return $result->fetch_assoc()['total_rows'];
} }
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class InvoiceAddVatgroupId extends AbstractMigration
{
public function up(): void
{
if($this->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") {
}
}
}