WIP Voicenumber Billing 2024-07-05
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
|
||||
@@ -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'];
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
Reference in New Issue
Block a user