diff --git a/Layout/default/Contractconfig/Form.php b/Layout/default/Contractconfig/Form.php
index 77f3dc988..ad575bd7e 100644
--- a/Layout/default/Contractconfig/Form.php
+++ b/Layout/default/Contractconfig/Form.php
@@ -76,8 +76,23 @@
}
$inputid = "itemvalues_".$item->id;
$array_count = 0;
+
?>
- multiple): ?>
+
+ name == "voicenumberblock_voiceplan_id"): ?>
+
+ | =$item->displayname?>: |
+
+
+ =$item->description?>
+ |
+
+ multiple): ?>
getValue() as $item_value): ?>
| =$item->displayname?> (=$array_count + 1?>): |
diff --git a/application/Admin/functions/IvtContractImport.php b/application/Admin/functions/IvtContractImport.php
index 7230ab5d0..5bd14a773 100644
--- a/application/Admin/functions/IvtContractImport.php
+++ b/application/Admin/functions/IvtContractImport.php
@@ -6,6 +6,12 @@ class Admin_IvtContractImport {
private $static_ivt_order_match = [];
private $no_matchcode = [];
private $ownerIdToBillingAddress = [];
+ private $ivt_to_voiceplan = [
+ 1 => 1, // Ivt Standard
+ 2 => 4, // Ivt Privat Plus
+ 3 => 3, // Ivt Business Easy
+ 4 => 1 // ESIT Partner Tarif
+ ];
public function __construct($request = false) {
$this->request = $request;
@@ -185,6 +191,7 @@ class Admin_IvtContractImport {
$contract_data['billingaddress_id'] = $billingaddress_id;
$contract_data['product_id'] = $product->id;
$contract_data['product_name'] = $ip->name;
+ $contract_data['vatgroup_id'] = $product->vatgroup_id;
$contract_data['amount'] = 1;
$contract_data['price'] = $ivt_product->price;
$contract_data['price_setup'] = 0;
@@ -853,10 +860,10 @@ class Admin_IvtContractImport {
private function addVoipData($ivt_customer_id, $contracts) {
//$this->log->debug("in addVoipData(): cid ".$ivt_customer_id);
- if($ivt_customer_id == 1376) {
+ /*if($ivt_customer_id == 1376) {
$this->log->debug("Not importing reseller voicenumbers for PROMETHEUS - Markus Paar [1376]");
return true;
- }
+ }*/
$ported_in = [];
$voicenumbers = [];
@@ -867,7 +874,19 @@ class Admin_IvtContractImport {
return false;
}
$this->log->debug("$ivt_num_count voicenumbers in ivt for cid ".$ivt_customer_id);
- foreach(IvtCustomerTelephoneNrModel::search(["cid" => $ivt_customer_id]) as $ivtnum) {
+ $ivtnumbers = IvtCustomerTelephoneNrModel::search(["cid" => $ivt_customer_id]);
+
+ if($ivt_customer_id == 1840) {
+ $injecting_ivtnumber = new IvtCustomerTelephoneNr();
+ $injecting_ivtnumber->number = "433152255410";
+ $ivtnumbers[] = $injecting_ivtnumber;
+
+ $injecting_ivtnumber = new IvtCustomerTelephoneNr();
+ $injecting_ivtnumber->number = "433159258910";
+ $ivtnumbers[] = $injecting_ivtnumber;
+ }
+
+ foreach($ivtnumbers as $ivtnum) {
$number = preg_replace('/^0043/', '43', $ivtnum->number);
if(!$number) continue;
@@ -895,22 +914,35 @@ class Admin_IvtContractImport {
$voice_contract = false;
+ // always create new voice contract for special customers
+ $new_nolink_contract = false;
if($ivt_customer_id == 1376) {
+ $new_nolink_contract = true;
+ /*echo "is PROMETHEUS number\n";
//if(in_array($number, [43313228451, 43313228406, 43720666572, 43313228400, 4331324890, 43720103806])) {
$prometheus_primary_contract = ContractModel::getFirst(["customer_number" => 1376]);
- $voice_contract = $this->createVoiceContract($prometheus_primary_contract, true);
- } else {
- foreach($contracts as $contract) {
- if(array_key_exists("needs_number", $contract->product->attributes) && $contract->product->attributes["needs_number"] == 1) {
+ $voice_contract = $this->createVoiceContract($contracts, true);*/
+ } elseif($ivt_customer_id == 1840) {
+ $new_nolink_contract = true;
+ /*//if(in_array($number, [433152255410, 433159258910])) {
+ $lugitsch_primary_contract = ContractModel::getFirst(["customer_number" => 1840]);
+ $voice_contract = $this->createVoiceContract($contracts, true);*/
+ }
+
+ if(!$new_nolink_contract) {
+ // try finding voice contract, otherwise create it
+ foreach ($contracts as $contract) {
+ if (array_key_exists("needs_number", $contract->product->attributes) && $contract->product->attributes["needs_number"] == 1) {
$voice_contract = $contract;
}
}
-
- if(!$voice_contract) {
- $voice_contract = $this->createVoiceContract($contracts);
- }
}
+ if(!$voice_contract) {
+ $voice_contract = $this->createVoiceContract($contracts, $new_nolink_contract);
+ }
+
+
//var_dump($voice_contract);exit;
@@ -971,6 +1003,9 @@ class Admin_IvtContractImport {
$confitem->value->set($contract_new_numbers);
$confitem->save();
+ // import Voiceplan
+ $this->getVoiceplan($voice_contract);
+
$voice_contract->matchcode = implode(", ", $contract_matchcode_numbers);
$voice_contract->save();
@@ -980,6 +1015,31 @@ class Admin_IvtContractImport {
return true;
}
+ /**
+ * @var Contract $contract
+ */
+ private function getVoiceplan($contract) {
+ $cid = $contract->owner->customer_number;
+ $ivt_customer = new IvtCustomer($cid);
+ if(!$ivt_customer) {
+ die(__METHOD__.": Ivt Customer nicht gefunden\n");
+ }
+
+ $ivt_plan = $ivt_customer->telephony_pricelist;
+ if(!array_key_exists($ivt_plan, $this->ivt_to_voiceplan)) {
+ die("Invalid Ivt Voiceplan: ".$ivt_plan."\n");
+ }
+
+ $new_plan = $this->ivt_to_voiceplan[$ivt_plan];
+ $contract->setConfigValue("voicenumberblock_voiceplan_id", $new_plan);
+ /*$voiceplan_item = $contract->getConfigValue("voicenumberblock_voiceplan_id");
+ $voiceplan_item->set($new_plan);
+ $voiceplan_item->save();
+ */
+ return true;
+
+ }
+
private function createVoiceContract($contracts, $nolink = false) {
// find rufnummer only product (residential or business)
$product = new Product(101); // Telefonie (nur Rufnummer - Privat)
@@ -1010,6 +1070,7 @@ class Admin_IvtContractImport {
$data["price_setup"] = $product->price_setup;
$data["price_nne"] = $product->price_nne;
$data["price_nbe"] = $product->price_nbe;
+ $data["vatgroup_id"] = $product->vatgroup_id;
$data["billing_delay"] = $product->billing_delay;
$data["billing_period"] = $product->billing_period;
$data["order_date"] = $fc->order_date;
diff --git a/application/Admin/functions/IvtCreditImport.php b/application/Admin/functions/IvtCreditImport.php
index d90d05fad..e636f31eb 100644
--- a/application/Admin/functions/IvtCreditImport.php
+++ b/application/Admin/functions/IvtCreditImport.php
@@ -154,6 +154,7 @@ class Admin_IvtCreditImport {
$data["billing_period"] = $primary_contract->billing_period;
$data["contract_term"] = $primary_contract->contract_term;
$data["order_date"] = $primary_contract->order_date;
+ $data["vatgroup_id"] = $primary_contract->product->vatgroup_id;
$data["finish_date"] = $primary_contract->finish_date;
$data["finish_date_by"] = $primary_contract->finish_date_by;
@@ -190,6 +191,7 @@ class Admin_IvtCreditImport {
$data["sla_id"] = 4;
$data["product_external"] = 0;
$data["product_external_id"] = null;
+ $data["vatgroup_id"] = 1;
$data["billing_delay"] = 0;
$data["billing_period"] = 1;
$data["contract_term"] = 12;
diff --git a/application/Billing/BillingController.php b/application/Billing/BillingController.php
index 6321227c5..19fac8430 100644
--- a/application/Billing/BillingController.php
+++ b/application/Billing/BillingController.php
@@ -101,6 +101,7 @@ class BillingController extends mfBaseController {
//$tomorrow->setTime(0,0,0);
$i = 0;
+ $v = 0;
//$yearly_not_before = new DateTime("2023-06-01");
@@ -160,10 +161,6 @@ class BillingController extends mfBaseController {
$this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." because billing_period == 0");
continue;
}*/
- if($contract->price == 0 && $contract->price_setup == 0) {
- $this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." because price and price_setup == 0");
- continue;
- }
$cancel_date = false;
if($contract->cancel_date) {
@@ -295,6 +292,10 @@ class BillingController extends mfBaseController {
}
+ /*if($contract->price != 0 || $contract->price_setup != 0) {
+ $this->log->debug(__METHOD__.": Ignoring Contract ".$contract->id." because price and price_setup == 0");
+ continue;
+ }*/
$sday = $start_date->format("d");
$eday = $end_date->format("d");
@@ -369,7 +370,6 @@ class BillingController extends mfBaseController {
$data["bank_account_owner"] = $billingaddress->bank_account_owner;
$data["bank_account_iban"] = $billingaddress->bank_account_iban;
$data["bank_account_bic"] = $billingaddress->bank_account_bic;
- $data["matchcode"] = $contract->matchcode;
$data["product_id"] = $contract->product_id;
$data["product_name"] = $contract->product_name;
$data["product_info"] = $contract->product_info;
@@ -378,6 +378,13 @@ class BillingController extends mfBaseController {
$data["price_setup"] = $price_setup;
$data["billing_period"] = $contract->billing_period;
+ $matchcode = $contract->matchcode;
+ // if voice product and matchcode consists oh phonenumbers only, remove matchcode
+ if(array_key_exists("needs_number", $contract->product->attributes) && $contract->product->attributes["needs_number"] == 1 && preg_match('/^[0-9, ]+$]/', $matchcode)) {
+ $matchcode = "";
+ }
+ $data["matchcode"] = $matchcode;
+
if(!$contract->billingaddress->country_id) {
$billcountry = CountryModel::getFirst(["isocode" => TT_HOMECOUNTRY_ISOCODE]);
} else {
@@ -405,10 +412,170 @@ class BillingController extends mfBaseController {
}
$i++;
+
+ /*
+ * Create Voice Billing, if contract has voicenumbers
+ */
+
+
+ $voicenumbers = VoicenumberModel::search(["contract_id" => $contract->id]);
+
+
+
+ if(count($voicenumbers)) {
+ //var_dump($voicenumbers);exit;
+ $voice_start_date = clone $start_date;
+ $voice_start_date->modify("-1 month");
+ $voice_start_date->setTime(0,0,0);
+
+ $voice_end_date = clone $voice_start_date;
+ $voice_end_date->modify("first day of this month");
+ $voice_end_date->modify("+1 months");
+ $voice_end_date->modify("-1 day");
+ $voice_end_date->setTime(23,59,59);
+ $this->log->debug("Voice End Date: ".$voice_end_date->format("Y-m-d H:i:s"));
+ $earliest_start_date = $start_date;
+
+ $voicebills = [];
+ $zones = [];
+ $destinations_cache = [];
+
+ $voiceplan_id = $contract->getConfigValue("voicenumberblock_voiceplan_id")->int;
+
+ if (!$voiceplan_id) {
+ $this->log->debug(__METHOD__ . ": No voiceplan_id in Contract " . $contract->id. ". Numbers: ".count($voicenumbers));
+ continue;
+ }
+ $voiceplan = new Voiceplan($voiceplan_id);
+
+
+ // always look for whole month
+ // numbers usually don't change owner without at least a few months being stale
+ if($voice_start_date->format("d") > 1) {
+ $voice_start_date->modify("first day of this month");
+ }
+
+ 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, "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 (array_key_exists($dest_nummer, $destinations_cache)) {
+ $destination = $destinations_cache[$dest_nummer];
+ } else {
+ $destination = $voiceplan->getDestinationByNumber($dest_nummer);
+ $destinations_cache[$dest_nummer] = $destination;
+ }
+ //var_dump($destination);
+
+ $zone = $destination->voiceplanzone;
+
+ //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
+ ];
+ }
+
+ $voicebills[$number][$zone->id]["count"]++;
+ $voicebills[$number][$zone->id]["zone_total"] += $call_price;
+ $voicebills[$number][$zone->id]["duration"] += $call->duration;
+ }
+ if(!count($voicebills)) {
+ continue;
+ }
+ //var_dump($voicebills);exit;
+
+ foreach($voicebills as $vbnumber => $zones) {
+ foreach($zones as $zone_id => $vb) {
+ $vbdata = [];
+ $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["voiceplan"] = $vb["voiceplan"];
+ $vbdata["zone"] = $vb["zone_name"];
+ $vbdata["call_count"] = $vb["count"];
+ $vbdata["duration"] = $vb["duration"];
+ $vbdata["price"] = $vb["price"];
+ $vbdata["price_total"] = $vb["zone_total"];
+ $vbdata["increment"] = $vb["increment"];
+ $vbdata["increment_first"] = $vb["increment_first"];
+
+ $bill_voice = BillingVoicenumberModel::create($vbdata);
+ if(!$bill_voice->save()) {
+ var_dump($vbdata);
+ die("Error saving Billing Voicenumber!");
+ }
+ }
+ }
+ $v++;
+
+ // save to BillingVoicenumber
+
+
+
+
+ }
+
+ }
+
+
+ /*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) {
+
+ }
+ }*/
}
+
+
+
+
}
- $this->layout()->setFlash("$i Billing records generiert");
+ $this->layout()->setFlash("$i Contract Billing records generiert. $v Voicenumber Billing records generiert");
$this->redirect("Billing");
}
diff --git a/application/BillingVoicenumber/BillingVoicenumberModel.php b/application/BillingVoicenumber/BillingVoicenumberModel.php
index ccbc226f2..0d155f480 100644
--- a/application/BillingVoicenumber/BillingVoicenumberModel.php
+++ b/application/BillingVoicenumber/BillingVoicenumberModel.php
@@ -1,10 +1,21 @@
select("BillingVoicenumber", "*", "1 = 1 ORDER BY BillingVoicenumberaddress_id");
+ $res = $db->select("BillingVoicenumber", "*", "1 = 1 ORDER BY id");
if($db->num_rows($res)) {
while($data = $db->fetch_object($res)) {
$items[] = new BillingVoicenumber($data);
@@ -55,7 +66,7 @@ class BillingVoicenumberModel {
$where = self::getSqlFilter($filter);
$sql = "SELECT * FROM BillingVoicenumber
WHERE $where
- ORDER BY BillingVoicenumberaddress_id LIMIT 1";
+ ORDER BY id LIMIT 1";
//var_dump($sql);exit;
$res = $db->query($sql);
if($db->num_rows($res)) {
@@ -91,31 +102,6 @@ class BillingVoicenumberModel {
return null;
}
- public static function getInvoiceBaseData($filter) {
- $db = FronkDB::singleton();
-
- $items = [];
-
- $where = self::getSqlFilter($filter);
- $sql = "SELECT owner_id, BillingVoicenumberaddress_id, BillingVoicenumber_type, BillingVoicenumber_delivery FROM BillingVoicenumber
- WHERE $where
- GROUP BY owner_id, BillingVoicenumberaddress_id, BillingVoicenumber_type, BillingVoicenumber_delivery
- ORDER BY owner_id, BillingVoicenumberaddress_id, BillingVoicenumber_type, BillingVoicenumber_delivery";
- //var_dump($sql);exit;
- $res = $db->query($sql);
- if($db->num_rows($res)) {
- while($data = $db->fetch_object($res)) {
- $items[] = [
- "owner_id" => $data->owner_id,
- "BillingVoicenumberaddress_id" => $data->BillingVoicenumberaddress_id,
- "BillingVoicenumber_type" => $data->BillingVoicenumber_type,
- "BillingVoicenumber_delivery" => $data->BillingVoicenumber_delivery
- ];
- }
- }
- return $items;
- }
-
public static function count($filter) {
$db = FronkDB::singleton();
@@ -191,14 +177,15 @@ class BillingVoicenumberModel {
}
}
- if(array_key_exists("invoice_id", $filter)) {
- $invoice_id = $filter['invoice_id'];
- if(is_numeric($invoice_id)) {
- $where .= " AND BillingVoicenumber.invoice_id=$invoice_id";
- } elseif($invoice_id === null || $invoice_id === false) {
- $where .= " AND (BillingVoicenumber.invoice_id IS NULL OR BillingVoicenumber.invoice_id=0)";
+ if(array_key_exists("billing_id", $filter)) {
+ $billing_id = $filter['billing_id'];
+ if(is_numeric($billing_id)) {
+ $where .= " AND BillingVoicenumber.billing_id=$billing_id";
+ } elseif($billing_id === null || $billing_id === false) {
+ $where .= " AND (BillingVoicenumber.billing_id IS NULL OR BillingVoicenumber.billing_id=0)";
}
}
+
if(array_key_exists("contract_id", $filter)) {
$contract_id = $filter['contract_id'];
@@ -207,6 +194,14 @@ class BillingVoicenumberModel {
}
}
+ if(array_key_exists("voicenumber", $filter)) {
+ $voicenumber = FronkDB::singleton()->escape($filter['voicenumber']);
+ if($voicenumber) {
+ $where .= " AND BillingVoicenumber.voicenumber='$voicenumber'";
+ }
+ }
+
+
if(array_key_exists("start_date", $filter)) {
$start_date = FronkDB::singleton()->escape($filter['start_date']);
if($start_date) {
@@ -249,136 +244,8 @@ class BillingVoicenumberModel {
}
}
- if(array_key_exists("BillingVoicenumberaddress_id", $filter)) {
- $BillingVoicenumberaddress_id = $filter['BillingVoicenumberaddress_id'];
- if(is_numeric($BillingVoicenumberaddress_id)) {
- $where .= " AND BillingVoicenumber.BillingVoicenumberaddress_id=$BillingVoicenumberaddress_id";
- }
- }
- if(array_key_exists("customer_number", $filter)) {
- $customer_number = $filter['customer_number'];
- if(is_numeric($customer_number)) {
- $where .= " AND BillingVoicenumber.customer_number LIKE $customer_number";
- }
- }
- if (array_key_exists("company", $filter)) {
- $company = FronkDB::singleton()->escape($filter["company"]);
- if ($company) {
- $where .= " AND company like '%$company%'";
- }
- }
-
- if (array_key_exists("firstname", $filter)) {
- $firstname = FronkDB::singleton()->escape($filter["firstname"]);
- if ($firstname) {
- $where .= " AND firstname like '%$firstname%'";
- }
- }
-
- if (array_key_exists("lastname", $filter)) {
- $lastname = FronkDB::singleton()->escape($filter["lastname"]);
- if ($lastname) {
- $where .= " AND lastname like '%$lastname%'";
- }
- }
-
- if (array_key_exists("mergedName", $filter)) {
- $name = FronkDB::singleton()->escape($filter["mergedName"]);
- if ($name) {
- $where .= " AND (CONCAT(firstname, ' ', lastname) like '%$name%' OR CONCAT(lastname, ' ', firstname) like '%$name%' )";
- }
- }
-
- if (array_key_exists("street", $filter)) {
- $street = FronkDB::singleton()->escape($filter["street"]);
- if ($street) {
- $where .= " AND street like '%$street%'";
- }
- }
-
- if (array_key_exists("zip", $filter)) {
- $zip = FronkDB::singleton()->escape($filter["zip"]);
- if ($zip) {
- $where .= " AND zip like '%$zip%'";
- }
- }
-
- if (array_key_exists("city", $filter)) {
- $city = FronkDB::singleton()->escape($filter["city"]);
- if ($city) {
- $where .= " AND city like '%$city%'";
- }
- }
-
- if (array_key_exists("country", $filter)) {
- $country = FronkDB::singleton()->escape($filter["country"]);
- if ($country) {
- $where .= " AND country like '%$country%'";
- }
- }
-
- if (array_key_exists("email", $filter)) {
- $email = FronkDB::singleton()->escape($filter["email"]);
- if ($email) {
- $where .= " AND email like '%$email%'";
- }
- }
-
- if(array_key_exists("matchcode", $filter)) {
- $matchcode = FronkDB::singleton()->escape($filter["matchcode"]);
- if($matchcode) {
- $where .= " AND matchcode like '%$matchcode%'";
- }
- }
-
- if(array_key_exists("product_id", $filter)) {
- $product_id = $filter['product_id'];
- if(is_numeric($product_id)) {
- $where .= " AND BillingVoicenumber.product_id=$product_id";
- }
- }
-
- if(array_key_exists("product_name", $filter)) {
- $product_name = $db->escape($filter['product_name']);
- if($product_name) {
- $where .= " AND product_name like '%$product_name%')";
- }
- }
-
- if(array_key_exists("matchcode", $filter)) {
- $matchcode = $db->escape($filter['matchcode']);
- if($matchcode) {
- $where .= " AND BillingVoicenumber.`matchcode` like '%$matchcode%'";
- }
- }
-
- if(array_key_exists("price<", $filter)) {
- $price = $filter['price<'];
- if(is_numeric($price)) {
- $where .= " AND BillingVoicenumber.price < $price";
- }
- }
- if(array_key_exists("price<=", $filter)) {
- $price = $filter['price<='];
- if(is_numeric($price)) {
- $where .= " AND BillingVoicenumber.price <= $price";
- }
- }
-
- if(array_key_exists("price>", $filter)) {
- $price = $filter['price>'];
- if(is_numeric($price)) {
- $where .= " AND BillingVoicenumber.price > $price";
- }
- }
- if(array_key_exists("price>=", $filter)) {
- $price = $filter['price>='];
- if(is_numeric($price)) {
- $where .= " AND BillingVoicenumber.price >= $price";
- }
- }
if(array_key_exists("add-where", $filter)) {
$where .= " ".$filter['add-where'];
diff --git a/application/Contract/Contract.php b/application/Contract/Contract.php
index 9736f4053..2d0eb89ad 100644
--- a/application/Contract/Contract.php
+++ b/application/Contract/Contract.php
@@ -200,8 +200,20 @@ class Contract extends mfBaseModel {
if(!$configvalues) return null;
if(!array_key_exists($itemname, $configvalues)) return null;
- $confitem = $configvalues[$itemname];
- return $confitem->value;
+ $configitem = $configvalues[$itemname];
+ return $configitem->value;
+ }
+
+ public function setConfigValue($itemname, $value) {
+ $configvalues = $this->getProperty("configvalues");
+ if(!$configvalues) return null;
+ if(!array_key_exists($itemname, $configvalues)) return null;
+
+ $configitem = $configvalues[$itemname];
+
+ $configitem->value->set($value);
+ $configitem->value->save();
+ return true;
}
public function getProperty($name) {
diff --git a/application/Contract/ContractModel.php b/application/Contract/ContractModel.php
index 300fd5ef1..3862ba2e5 100644
--- a/application/Contract/ContractModel.php
+++ b/application/Contract/ContractModel.php
@@ -15,7 +15,7 @@ class ContractModel {
public $product_external_id;
public $price = null;
public $price_setup = null;
- public $vatrate = null;
+ public $vatgroup_id = null;
public $price_nne = null;
public $price_nbe = null;
public $billing_delay = null;
diff --git a/application/VoiceCallHistory/VoiceCallHistoryController.php b/application/VoiceCallHistory/VoiceCallHistoryController.php
index 96d38c093..5669c6199 100644
--- a/application/VoiceCallHistory/VoiceCallHistoryController.php
+++ b/application/VoiceCallHistory/VoiceCallHistoryController.php
@@ -108,15 +108,23 @@ class VoiceCallHistoryController extends mfBaseController {
}
public function addContractIds() {
+ $ignore_numbers = [
+ "4331641220846",
+ "43623237705",
+ "4367761737195"
+ ];
$unknown_numbers = [];
// get calls without contract id
- foreach(VoiceCallHistoryModel::getVoiceCallHistoryAsEntity(["contract_id" => null, "billable" => "1", "duration" => ["from" => 1], "end" => "2024-06-01"]) as $call) {
+ foreach(VoiceCallHistoryModel::getVoiceCallHistoryAsEntity(["contract_id" => null, "billable" => "1", "duration" => ["from" => 1]]) as $call) {
//var_dump($call);exit;
//echo "\n";
$number = $call->voice_account;
if(!$number) continue;
+ // server side failed/disconnected calls
+ if($call->duration == 1 && $call->state == 38) continue;
+
if(in_array($number, $unknown_numbers)) continue;
$voicenumber = VoicenumberModel::getFirst(["number" => $number]);
@@ -132,12 +140,24 @@ class VoiceCallHistoryController extends mfBaseController {
continue;
}
+ $contract = new Contract($voicenumber->contract_id);
+ if(!$contract) {
+ $this->log->debug(__METHOD__.": No Contract with Contract_ID ".$voicenumber->contract_id." in Voicenumber ".$voicenumber->number);
+ continue;
+ }
+
+ if($contract->isCancelled()) {
+ // mail an office
+ $this->log->warning(__METHOD__.": Contract ".$voicenumber->contract_id." for Voicenumber ".$voicenumber->number." is cancelled!");
+ }
+
+
$calldate = new DateTime($call->start);
$calldate->setTimezone(new DateTimeZone("Europe/Vienna"));
- $contract = $voicenumber->contract;
+
// calls from before first IVT Import must be right, we don't have historic contract data
diff --git a/application/VoiceCallHistory/VoiceCallHistoryModel.php b/application/VoiceCallHistory/VoiceCallHistoryModel.php
index d5c48caee..399e33a99 100644
--- a/application/VoiceCallHistory/VoiceCallHistoryModel.php
+++ b/application/VoiceCallHistory/VoiceCallHistoryModel.php
@@ -110,7 +110,7 @@ class VoiceCallHistoryModel {
$sql .= isset($filters['destination']) ? Helper::generateFilterCondition($filters['destination'], "destination") : "";
$sql .= isset($filters['billable']) ? Helper::generateFilterCondition($filters['billable'], "billable") : "";
$sql .= isset($filters['duration']) ? Helper::generateFilterCondition($filters['duration'], "duration") : "";
- $sql .= array_key_exists("contract_id", $filters) ? Helper::generateFilterCondition($filters['contract_id'], "contract_id") : "";
+ $sql .= array_key_exists("contract_id", $filters) ? Helper::generateFilterCondition($filters['contract_id'], "contract_id", true) : "";
return $sql;
}
@@ -138,7 +138,7 @@ class VoiceCallHistoryModel {
$sql .= $order === null || $order['key'] === null ? " ORDER BY `start` DESC" : " ORDER BY `" . $order['key'] . "` " . $order['order'];
$sql .= $limit === null ? "" : " LIMIT " . $limit . " OFFSET " . $offset;
- //mfLoghandler::singleton()->debug($sql);exit;
+ mfLoghandler::singleton()->debug($sql);
// die($sql);
$result = $db->query($sql);
$rows = [];
diff --git a/application/Voicenumber/VoicenumberModel.php b/application/Voicenumber/VoicenumberModel.php
index 97555b4e3..28da70fb8 100644
--- a/application/Voicenumber/VoicenumberModel.php
+++ b/application/Voicenumber/VoicenumberModel.php
@@ -109,7 +109,7 @@ class VoicenumberModel {
if(is_array($limit) && count($limit)) {
if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
$sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
- } elseif(is_numeric($count)) {
+ } elseif(is_numeric($limit['count'])) {
$sql .= " LIMIT ".$limit['count'];
}
}
@@ -144,6 +144,13 @@ class VoicenumberModel {
$where .= " AND voicenumberblock_id = $block_id";
}
}
+
+ if(array_key_exists("contract_id", $filter)) {
+ $contract_id = $filter['contract_id'];
+ if(is_numeric($contract_id)) {
+ $where .= " AND contract_id = $contract_id";
+ }
+ }
//var_dump($filter);exit;
if(array_key_exists("countrycode", $filter)) {
diff --git a/application/Voiceplan/Voiceplan.php b/application/Voiceplan/Voiceplan.php
index 7b8cd0f27..7da3fd94b 100644
--- a/application/Voiceplan/Voiceplan.php
+++ b/application/Voiceplan/Voiceplan.php
@@ -8,7 +8,36 @@ class Voiceplan extends mfBaseModel {
private $destinations;
public $import_errors;
-
+
+
+ public function getDestinationByNumber($number) {
+ if(!$number) return false;
+
+ $prefix = $number;
+
+ while(strlen($prefix)) {
+ $destination = VoiceplandestinationModel::getFirst(["prefix" => $prefix, "voiceplan_id" => $this->id]);
+ if($destination) {
+ break;
+ }
+ $prefix = substr($prefix, 0, strlen($prefix) - 1);
+ }
+
+ if(!$destination) return false;
+
+ return $destination;
+ }
+ public function getZoneByNumber($number) {
+ if(!$number) return false;
+
+ $destination = $this->getDestinationByNumber($number);
+ if(!$destination) return false;
+
+ return $destination->voiceplanzone;
+
+
+ }
+
public function importDestinationsFromCsv(File $file) {
if(!$this->id) {
return false;
@@ -169,7 +198,7 @@ class Voiceplan extends mfBaseModel {
return true;
}
-
+
public function getProperty($name) {
if($this->$name == null) {
diff --git a/application/Voiceplandestination/Voiceplandestination.php b/application/Voiceplandestination/Voiceplandestination.php
index d140c6367..6bf20ae74 100644
--- a/application/Voiceplandestination/Voiceplandestination.php
+++ b/application/Voiceplandestination/Voiceplandestination.php
@@ -23,16 +23,20 @@ class Voiceplandestination extends mfBaseModel {
}
return $this->voiceplan;
}
-
- $classname = ucfirst($name);
- $idfield = $name."_id";
- $this->$name = new $classname($this->$idfield);
-
- if($this->$name->id) {
- return $this->$name;
- } else {
- return null;
- }
+
+ $classname = ucfirst($name);
+ $idfield = $name."_id";
+ $this->$name = mfValuecache::singleton()->get("mfObjectmodel-$name-".$this->$idfield);
+ if(!$this->$name) {
+ $this->$name = new $classname($this->$idfield);
+ }
+
+ if($this->$name->id) {
+ mfValuecache::singleton()->set("mfObjectmodel-$name-".$this->$name->id, $this->$name);
+ return $this->$name;
+ } else {
+ return null;
+ }
}
return $this->$name;
diff --git a/application/Voiceplandestination/VoiceplandestinationModel.php b/application/Voiceplandestination/VoiceplandestinationModel.php
index fe9b88164..c1f5f0b47 100644
--- a/application/Voiceplandestination/VoiceplandestinationModel.php
+++ b/application/Voiceplandestination/VoiceplandestinationModel.php
@@ -52,8 +52,16 @@ class VoiceplandestinationModel {
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
- mfLoghandler::singleton()->debug($where);
- $res = $db->select("Voiceplandestination", "*", "$where ORDER BY destination,prefix");
+
+ $sql = "SELECT * FROM Voiceplandestination WHERE $where ORDER BY destination,prefix";
+ $sql = "SELECT Voiceplandestination.* FROM Voiceplandestination
+ LEFT JOIN Voiceplanzone ON (Voiceplanzone.id = Voiceplandestination.voiceplanzone_id)
+ WHERE $where
+ ORDER BY destination,prefix LIMIT 1
+ ";
+ mfLoghandler::singleton()->debug($sql);
+ $res = $db->query($sql);
+ //$res = $db->select("Voiceplandestination", "*", "$where ORDER BY destination,prefix");
if($db->num_rows($res)) {
$data = $db->fetch_object($res);
$item = new Voiceplandestination($data);
@@ -99,7 +107,7 @@ class VoiceplandestinationModel {
if(is_array($limit) && count($limit)) {
if(is_numeric($limit['start']) && is_numeric($limit['count'])) {
$sql .= " LIMIT ".$limit['start'].", ".$limit['count'];
- } elseif(is_numeric($count)) {
+ } elseif(is_numeric($limit['count'])) {
$sql .= " LIMIT ".$limit['count'];
}
}
diff --git a/application/Voiceplanzone/Voiceplanzone.php b/application/Voiceplanzone/Voiceplanzone.php
index 193cfc8da..4c209d701 100644
--- a/application/Voiceplanzone/Voiceplanzone.php
+++ b/application/Voiceplanzone/Voiceplanzone.php
@@ -25,16 +25,20 @@ class Voiceplanzone extends mfBaseModel {
$this->destinations = VoiceplandestinationModel::search(["voiceplanzone_id" => $this->id]);
return $this->destinations;
}
-
- $classname = ucfirst($name);
- $idfield = $name."_id";
- $this->$name = new $classname($this->$idfield);
-
- if($this->$name->id) {
- return $this->$name;
- } else {
- return null;
- }
+
+ $classname = ucfirst($name);
+ $idfield = $name."_id";
+ $this->$name = mfValuecache::singleton()->get("mfObjectmodel-$name-".$this->$idfield);
+ if(!$this->$name) {
+ $this->$name = new $classname($this->$idfield);
+ }
+
+ if($this->$name->id) {
+ mfValuecache::singleton()->set("mfObjectmodel-$name-".$this->$name->id, $this->$name);
+ return $this->$name;
+ } else {
+ return null;
+ }
}
return $this->$name;
diff --git a/db/migrations/20240620160026_create_billing.php b/db/migrations/20240620160026_create_billing.php
index 0fdaba2c1..5db6ebdf8 100644
--- a/db/migrations/20240620160026_create_billing.php
+++ b/db/migrations/20240620160026_create_billing.php
@@ -38,7 +38,7 @@ final class CreateBilling extends AbstractMigration
$table->addColumn("amount", "decimal", ["null" => false, "precision" => 9, "scale" => 6]);
$table->addColumn("price", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
$table->addColumn("price_setup", "decimal", ["null" => false, "default" => 0, "precision" => 14, "scale" => 4]);
- $table->addColumn("total_vat", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
+ $table->addColumn("vatrate", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
$table->addColumn("billing_period", "integer", ["null" => false, "default" => 0]);
$table->addColumn("create_by", "integer", ["null" => false]);
diff --git a/db/migrations/20240704170016_create_billing_voicenumber.php b/db/migrations/20240704170016_create_billing_voicenumber.php
index 5d2c78e11..19e9a17e1 100644
--- a/db/migrations/20240704170016_create_billing_voicenumber.php
+++ b/db/migrations/20240704170016_create_billing_voicenumber.php
@@ -9,18 +9,19 @@ final class CreateBillingVoicenumber extends AbstractMigration
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("BillingVoicenumber");
- $table->addColumn("invoice_id", "integer", ["null" => true, "default" => null]);
+ $table->addColumn("billing_id", "integer", ["null" => true, "default" => null]);
$table->addColumn("contract_id", "integer", ["null" => false]);
- $table->addColumn("owner_id", "integer", ["null" => false]);
- $table->addColumn("billingaddress_id", "integer", ["null" => false]);
$table->addColumn("voicenumber", "string", ["null" => false, "limit" => 64]);
$table->addColumn("start_date", "date", ["null" => false]);
$table->addColumn("end_date", "date", ["null" => false]);
+ $table->addColumn("voiceplan", "string", ["null" => false, "limit" => 255]);
$table->addColumn("zone", "string", ["null" => false, "limit" => 64]);
+ $table->addColumn("call_count", "integer", ["null" => false]);
$table->addColumn("duration", "integer", ["null" => false]);
- $table->addColumn("price", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
- $table->addColumn("total_vat", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
-
+ $table->addColumn("price", "decimal", ["null" => false, "precision" => 14, "scale" => 8]);
+ $table->addColumn("price_total", "decimal", ["null" => false, "precision" => 14, "scale" => 4]);
+ $table->addColumn("increment", "integer", ["null" => false]);
+ $table->addColumn("increment_first", "integer", ["null" => false]);
$table->addColumn("create_by", "integer", ["null" => false]);
$table->addColumn("edit_by", "integer", ["null" => false]);
$table->addColumn("create", "integer", ["null" => false]);