WIP Voicenumber Billing 2024-07-05

This commit is contained in:
Frank Schubert
2024-07-06 18:37:40 +02:00
parent 92edb9c812
commit 200af4802a
16 changed files with 417 additions and 220 deletions

View File

@@ -76,8 +76,23 @@
}
$inputid = "itemvalues_".$item->id;
$array_count = 0;
?>
<?php if($item->multiple): ?>
<?php // TODO: spezial configs besser machen ?>
<?php if($item->name == "voicenumberblock_voiceplan_id"): ?>
<tr id="tr-<?=$inputid?>_0">
<th style="max-width: 50vw;"><?=$item->displayname?>:</th>
<td style="width: 50vw;">
<select class="form-control" name="<?=$inputname?>" id="<?=$inputid?>" <?=($item->multiple) ? "data-item-multiple='true'" : ""?>>
<option value="0"></option>
<?php foreach(VoiceplanModel::getAll() as $voiceplan): ?>
<option value="<?=$voiceplan->id?>" <?=($item->getValue() == $voiceplan->id) ? "selected='selected'" : ""?>><?=$voiceplan->name?></option>
<?php endforeach; ?>
</select>
<small><?=$item->description?></small>
</td>
</tr>
<?php elseif($item->multiple): ?>
<?php foreach($item->getValue() as $item_value): ?>
<tr id="tr-<?=$inputid?>_<?=$array_count?>">
<th style="max-width: 50vw;"><?=$item->displayname?><span class="array_counter"> (<?=$array_count + 1?>)</span>:</th>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -1,10 +1,21 @@
<?php
class BillingVoicenumberModel {
public $invoice_id;
public $billing_id;
public $contract_id;
public $voicenumber;
public $start_date;
public $end_date;
public $voiceplan;
public $zone;
public $call_count;
public $duration;
public $price;
public $price_total;
public $increment;
public $increment_first;
public $create_by;
public $edit_by;
@@ -39,7 +50,7 @@ class BillingVoicenumberModel {
$db = FronkDB::singleton();
$res = $db->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'];

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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

View File

@@ -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 = [];

View File

@@ -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)) {

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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'];
}
}

View File

@@ -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;

View File

@@ -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]);

View File

@@ -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]);