WIP 2025-03-17 RML Billing

This commit is contained in:
Frank Schubert
2025-03-18 02:10:53 +01:00
parent 361fc5ee9a
commit 2a7e7f1724
7 changed files with 877 additions and 128 deletions

View File

@@ -585,7 +585,7 @@
<?php foreach($preorder->history as $history): ?>
<?php if($history->key != "status_id") continue; ?>
<tr>
<td><?=date("d.m.Y H:i:s", $history->create)?></td>
<td class="text-monospace"><?=date("d.m.Y H:i:s", $history->changed)?></td>
<td><?=$history->creator->name?></td>
<td><?=$history->old->code?> - <?=$history->old->name?></td>
<td><?=$history->new->code?> - <?=$history->new->name?></td>
@@ -604,7 +604,7 @@
</tr>
<?php foreach($preorder->history as $history): ?>
<tr>
<td><?=date("d.m.Y H:i:s", $history->create)?></td>
<td class="text-monospace"><?=date("d.m.Y H:i:s", $history->create)?></td>
<td><?=$history->creator->name?></td>
<td><?=$history->getKey()?></td>
<td><?=$history->getText("old")?></td>

View File

@@ -32,21 +32,41 @@ $pagination_entity_name = "Billingrecords";
<form method="get" action="<?=self::getUrl("PreorderBilling")?>">
<div class="row">
<div class="col-1">
<label class="form-label" for="filter_customer_number">Kundennummer</label>
<input type="text" class="form-control" name="filter[customer_number]" id="filter_customer_number" value="<?=(array_key_exists("customer_number", $filter)) ? $filter['customer_number'] : ""?>"/>
<div class="col-2">
<label class="form-label" for="filter_netzgebiet_id">Kampagne</label>
<select class="form-control" name="filter[preordercampaign_id]" id="filter_preordercampaign_id">
<option></option>
<?php foreach($my_campaigns as $campaign): ?>
<option value="<?=$campaign->id?>" <?=(is_array($filter) && $filter["preordercampaign_id"] == $campaign->id) ? "selected='selected'" : ""?>><?=$campaign->name?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-1">
<label class="form-label" for="filter_customer">Kunde</label>
<input type="text" class="form-control" name="filter[customer]" id="filter_customer" value="<?=(array_key_exists("customer", $filter)) ? $filter['customer'] : ""?>"/>
<label class="form-label" for="filter_oaid">OAID</label>
<input type="text" class="form-control" name="filter[oaid]" id="filter_oaid" value="<?=(array_key_exists("oaid", $filter)) ? $filter['oaid'] : ""?>"/>
</div>
<div class="col-2">
<label class="form-label" for="filter_owner_id">Netzbetreiber</label>
<select class="form-control" name="filter[owner_id]" id="filter_owner_id">
<option></option>
<?php foreach($netoperators as $netop): ?>
<option value="<?=$netop->id?>" <?=(is_array($filter) && $filter["owner_id"] == $netop->id) ? "selected='selected'" : ""?>><?=$netop->getCompanyOrName()?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-1">
<label class="form-label" for="filter_address">Adresse</label>
<input type="text" class="form-control" name="filter[address]" id="filter_address" value="<?=(array_key_exists("address", $filter)) ? $filter['address'] : ""?>"/>
<label class="form-label" for="filter_fibu_account_number">Fibu Kontonummer</label>
<input type="text" class="form-control" name="filter[fibu_account_number]" id="filter_fibu_account_number" value="<?=(array_key_exists("fibu_account_number", $filter)) ? $filter['fibu_account_number'] : ""?>"/>
</div>
<div class="col-1">
<div class="col-2">
<label class="form-label" for="filter_product">Produkt</label>
<input type="text" class="form-control" name="filter[product]" id="filter_product" value="<?=(array_key_exists("product", $filter)) ? $filter['product'] : ""?>"/>
<select class="form-control" name="filter[product_id]" id="filter_product_id">
<option></option>
<?php foreach(PreorderProduct::getWithTypes() as $product): ?>
<option value="<?=$product->id?>" <?=(is_array($filter) && $filter["product_id"] == $product->id) ? "selected='selected'" : ""?>><?=$product->name?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-1">
<label class="form-label" for="filter_start_date_from">Periode von</label>
@@ -56,31 +76,6 @@ $pagination_entity_name = "Billingrecords";
<label class="form-label" for="filter_start_date_to">Periode bis</label>
<input type="text" class="form-control" name="filter[start_date_to]" id="filter_start_date_to" value="<?=(array_key_exists("start_date_to", $filter)) ? $filter['start_date_to'] : ""?>"/>
</div>
<div class="col-2">
<label class="form-label" for="filter_show_credit">Gutschriften</label>
<select class="form-control" name="filter[show_credit]" id="filter_show_credit">
<option value="0" <?=(array_key_exists("show_credit", $filter) && $filter['show_credit'] == 0) ? "selected='selected'" : ""?>>Ausblenden</option>
<option value="1" <?=(array_key_exists("show_credit", $filter) && $filter['show_credit'] == 1 ) ? "selected='selected'" : ""?>>Anzeigen</option>
</select>
</div>
<div class="col-2">
<label class="form-label" for="filter_show_credit">Rechnungsperiode</label>
<select class="form-control" name="filter[billing_period]" id="filter_billing_period">
<option></option>
<option value="1" <?=(array_key_exists("billing_period", $filter) && $filter['billing_period'] == 1) ? "selected='selected'" : ""?>>Monatlich</option>
<option value="12" <?=(array_key_exists("billing_period", $filter) &&$filter['billing_period'] == 12 ) ? "selected='selected'" : ""?>>Jährlich</option>
</select>
</div>
<!--div class="col-1">
<label class="form-label" for="filter_start_month">Zeitraum Monat</label>
<input type="text" class="form-control" name="filter[start_month]" id="filter_start_month" value="<?=(array_key_exists("start_month", $filter)) ? $filter['start_month'] : ""?>"/>
</div>
<div class="col-1">
<label class="form-label" for="filter_start_year">Zeitraum Jahr</label>
<input type="text" class="form-control" name="filter[start_year]" id="filter_start_year" value="<?=(array_key_exists("start_year", $filter)) ? $filter['start_year'] : ""?>"/>
</div-->
<div class="col-2">
<label class="form-label" for="filter_status">Status</label>
@@ -127,6 +122,7 @@ $pagination_entity_name = "Billingrecords";
<table class="table table-sm table-striped table-hover">
<tr>
<th>Netzgebiet</th>
<th>OAID</th>
<th>Bestelldatum</th>
<th>Periode</th>
@@ -141,7 +137,8 @@ $pagination_entity_name = "Billingrecords";
</tr>
<?php foreach($billings as $billing): ?>
<tr>
<td><a href="<?=self::getUrl("Preorder", "Index", ["filter" => ["oaid" => $billing->preorder->oaid]])?>" target="_blank"><?=$billing->preorder->oaid?></a></td>
<td><?=$billing->preorder->adb_hausnummer->netzgebiet->name?></td>
<td><a href="<?=self::getUrl("Preorder", "Index", ["filter" => ["oaid" => $billing->oaid]])?>" target="_blank"><?=$billing->oaid?></a></td>
<td><?=$billing->order_date?></td>
<td><?=$billing->start_date?> -<br /><?=$billing->end_date?></td>
<td>

View File

@@ -6,6 +6,7 @@ class PreorderBilling extends mfBaseModel {
private $invoice;
private $vatgroup;
public static $earliest_bill_date = "2025-01-01";
public function getProperty($name) {
if($this->$name == null) {
@@ -76,9 +77,9 @@ class PreorderBilling extends mfBaseModel {
$model = new PreorderBilling();
$table_fields = [
"invoice_id", "preorder_id", "adb_wohneinheit_id", "order_date", "start_date", "end_date", "preorderbillingcustomer_id", "owner_id", "billingaddress_id",
"fibu_account_number", "company", "firstname", "lastname", "street", "zip", "city", "country", "email", "uid", "billing_delivery",
"product_id", "product_name", "product_info", "article_number", "amount", "unit", "price", "price_setup", "vatrate", "billing_period",
"invoice_id", "preorder_id", "oaid", "adb_wohneinheit_id", "order_date", "start_date", "end_date", "preorderbillingcustomer_id", "owner_id",
"billingaddress_id", "fibu_account_number", "company", "firstname", "lastname", "street", "zip", "city", "country", "email", "uid",
"billing_delivery", "product_id", "product_name", "product_info", "article_number", "amount", "unit", "price", "price_setup", "vatrate", "billing_period",
"create_by","edit_by","create","edit"
];
@@ -120,7 +121,8 @@ class PreorderBilling extends mfBaseModel {
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
$sql = "SELECT * FROM PreorderBilling
$sql = "SELECT PreorderBilling.* FROM PreorderBilling
LEFT JOIN Preorder ON Preorder.id = PreorderBilling.preorder_id
WHERE $where
ORDER BY preorder_id LIMIT 1";
//var_dump($sql);exit;
@@ -143,6 +145,7 @@ class PreorderBilling extends mfBaseModel {
$where = self::getSqlFilter($filter);
$sql = "SELECT COUNT(*) as cnt FROM PreorderBilling
LEFT JOIN Preorder ON Preorder.id = PreorderBilling.preorder_id
WHERE $where";
//mfLoghandler::singleton()->debug($sql);
@@ -166,7 +169,8 @@ class PreorderBilling extends mfBaseModel {
$db = FronkDB::singleton();
$where = self::getSqlFilter($filter);
$sql = "SELECT * FROM PreorderBilling
$sql = "SELECT PreorderBilling.* FROM PreorderBilling
LEFT JOIN Preorder ON Preorder.id = PreorderBilling.preorder_id
WHERE $where
ORDER BY $order";
@@ -178,7 +182,7 @@ class PreorderBilling extends mfBaseModel {
}
}
//mfLoghandler::singleton()->debug($sql);
mfLoghandler::singleton()->debug($sql);
$res = $db->query($sql);
if($db->num_rows($res)) {
@@ -217,7 +221,14 @@ class PreorderBilling extends mfBaseModel {
$where .= " AND PreorderBilling.adb_wohneinheit_id=$adb_wohneinheit_id";
}
}
if(array_key_exists("oaid", $filter)) {
$oaid = FronkDB::singleton()->escape($filter['oaid']);
if($oaid) {
$where .= " AND PreorderBilling.oaid = '$oaid'";
}
}
if(array_key_exists("order_date", $filter)) {
$order_date = FronkDB::singleton()->escape($filter['order_date']);
if($order_date) {
@@ -398,7 +409,12 @@ class PreorderBilling extends mfBaseModel {
}
}
if(array_key_exists("preordercampaign_id", $filter)) {
$preordercampaign_id = $filter['preordercampaign_id'];
if(is_numeric($preordercampaign_id)) {
$where .= " AND Preorder.preordercampaign_id = $preordercampaign_id";
}
}
if(array_key_exists("add-where", $filter)) {
$where .= " ".$filter['add-where'];

View File

@@ -46,11 +46,46 @@ class PreorderBillingController extends mfBaseController {
if (is_numeric($this->request->s)) {
$pagination['start'] = intval($this->request->s);
}
/*$my_campaigns = [];
$my_networks = $this->me->myNetworks(["netowner", "salespartner"]);
foreach($my_networks as $network) {
foreach(PreordercampaignModel::search(['network_id' => $network->id]) as $campaign) {
if(!array_key_exists($campaign->id, $my_campaigns)) $my_campaigns[] = $campaign;
}
}*/
$my_campaigns = PreordercampaignModel::search(["owner_id" => $this->me->address_id]);
//var_dump($my_network_ids,$my_campaign_ids);exit;
$this->layout()->set("my_campaigns", $my_campaigns);
$netoperators = [];
foreach(PreordercampaignModel::search(["owner_id" => $this->me->address_id]) as $campaign) {
foreach($campaign->active_operators as $op) {
if(!array_key_exists($op->operator_id, $netoperators)) {
$nop = new Address($op->operator_id);
if($nop->id) {
$netoperators[$nop->id] = $nop;
}
}
}
foreach($campaign->passive_operators as $op) {
if(!array_key_exists($op->operator_id, $netoperators)) {
$nop = new Address($op->operator_id);
if($nop->id) {
$netoperators[$nop->id] = $nop;
}
}
}
}
$this->layout()->set("netoperators", $netoperators);
//var_dump($filter);exit;
$pagination['maxItems'] = PreorderBilling::count($filter);
$projects = PreorderBilling::getAll();
$this->layout()->set("billings", $projects);
$billings = PreorderBilling::search($filter, $pagination);
$this->layout()->set("billings", $billings);
$this->layout()->set("pagination", $pagination);
}
@@ -58,7 +93,35 @@ class PreorderBillingController extends mfBaseController {
private function getPreparedFilter($filter) {
$new_filter = [];
if(array_key_exists("status", $filter)) {
if($filter["status"] == "billed") {
$new_filter["invoice_id"] = true;
} else {
$new_filter["invoice_id"] = null;
}
} else {
$new_filter["invoice_id"] = null;
}
if(array_key_exists("start_date_from", $filter)) {
if($filter["start_date_from"]) {
try {
$from = DateTime::createFromFormat("d.m.Y", $filter["start_date_from"]);
} catch (Exception $e) {}
$new_filter["start_date>="] = $from->format("Y-m-d");
}
unset($filter["start_date_from"]);
}
if(array_key_exists("start_date_to", $filter)) {
if($filter["start_date_to"]) {
try {
$to = DateTime::createFromFormat("d.m.Y", $filter["start_date_to"]);
} catch (Exception $e) {}
$new_filter["start_date<="] = $to->format("Y-m-d");
}
unset($filter["start_date_to"]);
}
if (is_array($filter) && count($filter)) {
foreach ($filter as $name => $value) {
@@ -70,15 +133,14 @@ class PreorderBillingController extends mfBaseController {
}
protected function importPreorders() {
$today = new DateTime("now");
$today->setTime(0,0,0);
$earliest_bill_date = new DateTime(PreorderBilling::$earliest_bill_date);
$now_year = date("Y");
$now_month = date("m");
$now_day = date("d");
//$today = new DateTime("$now_year-$now_month-$now_day");
$today = new DateTime("2025-02-13");
$today = new DateTime("$now_year-$now_month-$now_day");
//$today = new DateTime("2025-02-13");
$today->setTime(2,0,0);
$today->setTimezone(new DateTimeZone("Europe/Vienna"));
@@ -86,6 +148,9 @@ class PreorderBillingController extends mfBaseController {
$bill_date->modify("first day of this month");
$bill_date->modify("-1 month");
$latest_bill_date = clone $bill_date;
$latest_bill_date->modify("last day of this month");
$del = 0;
// first delete all non-invoiced billing records
foreach(PreorderBilling::search(["invoice_id" => null]) as $bill) {
@@ -101,12 +166,24 @@ class PreorderBillingController extends mfBaseController {
$preorder_search = [
"preordercampaign_id" => $campaign_ids,
">=status_code" => 241
">=status_code" => 241,
//"oaid" => "AT-8943-a1116acf.001",
];
$billing_records = [];
foreach(PreorderModel::search($preorder_search) as $preorder) {
$bill_enduser_setup = true;
$bill_operator_setup = true;
$bill_usage = true;
if($preorder->deleted) continue;
if(!$preorder->adb_wohneinheit_id) {
$this->log->info(__METHOD__.": Ignoring Preorder ".$preorder->id." without adb_wohneinheit_id");
continue;
}
//$order_date = false;
if($preorder->order_date) {
$order_date = new DateTime('@'.$preorder->order_date);
@@ -118,7 +195,8 @@ class PreorderBillingController extends mfBaseController {
if($order_date->format("Ymd") < "2025-01-01") {
// start billing from 2025-01-01
continue;
$this->log->debug(__METHOD__.": Preorder ".$preorder->id." ordered before 2025-01-01, so billing no enduser setup");
$bill_enduser_setup = false;
}
$operator_id = false;
@@ -140,14 +218,16 @@ class PreorderBillingController extends mfBaseController {
"order_date" => $order_date,
"today" => $today,
"bill_date" => $bill_date,
"earliest_bill_date" => $earliest_bill_date,
"latest_bill_date" => $latest_bill_date,
];
if($preorder->status->code >= 241) {
$this->billSetup($preorder, "enduser_setup", $bill_params);
if($bill_enduser_setup) $this->billSetup($preorder, "enduser_setup", $bill_params);
}
if($preorder->status->code >= 500) {
$this->billSetup($preorder, "operator_setup", $bill_params);
$this->billEnduserPeriodic($preorder, $bill_params);
if($bill_operator_setup) $this->billSetup($preorder, "operator_setup", $bill_params);
if($bill_usage) $this->billOperatorPeriodic($preorder, $bill_params);
//exit;
}
}
@@ -163,6 +243,9 @@ class PreorderBillingController extends mfBaseController {
$order_date = $options['order_date'];
$today = $options['today'];
$bill_date = $options['bill_date'];
$earliest_bill_date = $options['earliest_bill_date'];
$this->log->debug(__METHOD__.": bill $type Preorder ".$preorder->id);
// get price_setup
$product = PreorderProduct::getFirst(["type" => $type]);
@@ -170,6 +253,12 @@ class PreorderBillingController extends mfBaseController {
die("operator_setup price not found!");
}
if($preorder->status->code >= 899) {
// TODO is canceled, need to determine if setup still needs to be billed
$this->log->debug(__METHOD__." already cancelled");
return true;
}
$product->setNetownerId($netowner->id);
$product->setNetoperatorId($netoperator->id);
$price = $product->getCampaignPrice($preorder->preordercampaign_id, $order_date->format("Y-m-d"));
@@ -181,6 +270,7 @@ class PreorderBillingController extends mfBaseController {
//var_dump($product);
if(PreorderBilling::getFirst(["preorder_id" => $preorder->id, "product_id" => $product->id])) {
//echo "billing record exists\n<br />";
$this->log->debug(__METHOD__."billing record exists");
return true; // already billed
}
@@ -203,10 +293,17 @@ class PreorderBillingController extends mfBaseController {
$status_change = $preorder;
}
$status_change_date = new DateTime("@".$status_change->create);
if($preorder->oaid == 'AT-8943-8392e815.001') {
//var_dump($status_change, $status_change_date);
}
$billing_data = [
"preorder_id" => $preorder->id,
"oaid" => $preorder->oaid,
"adb_wohneinheit_id" => $preorder->adb_wohneinheit_id,
"order_date" => $order_date->format("Y-m-d"),
"start_date" => $status_change_date->format("Y-m-d"),
@@ -265,6 +362,17 @@ class PreorderBillingController extends mfBaseController {
$billing_data["product_info"] = "Bestellung vom ".$order_date->format("d.m.Y");
} elseif($type == "operator_setup") {
$change_to_active = PreorderHistoryModel::getFirstStatusChangeTo($preorder->id, 500);
if($change_to_active) {
$status_change_date = new DateTime("@".$change_to_active->create);
$billing_data["start_date"] = $status_change_date->format("Y-m-d");
$billing_data["end_date"] = $status_change_date->format("Y-m-d");
}
if($preorder->oaid == 'AT-8943-8392e815.001') {
//var_dump($change_to_active, $status_change_date);exit;
}
// Netzbetreiber Setup Gebühr
$billing_data["product_name"] = "Brereitstellungsentgelt ".$bill_date->format("m/Y");
$billing_data["owner_id"] = $netoperator->id;
@@ -290,18 +398,24 @@ class PreorderBillingController extends mfBaseController {
}
//var_dump($billing);
$this->log->debug(__METHOD__.": Billed");
return true;
}
private function billEnduserPeriodic($preorder, $options) {
private function billOperatorPeriodic($preorder, $options) {
$netowner = $options['netowner'];
$netoperator = $options['netoperator'];
$order_date = $options['order_date'];
$today = $options['today'];
$bill_date = $options['bill_date'];
$earliest_bill_date = $options['earliest_bill_date'];
$latest_bill_date = $options['latest_bill_date'];
if($preorder->status->code >= 899) {
$this->log->debug(__METHOD__.": Preorder is cancelled");
// TODO is cancelled, so determine if refund is necessary
return true;
}
// get price_setup
$product = PreorderProduct::getFirst(["type" => "operator_usage"]);
@@ -311,7 +425,7 @@ class PreorderBillingController extends mfBaseController {
$product->setNetownerId($netowner->id);
$product->setNetoperatorId($netoperator->id);
$price = $product->getCampaignPrice($preorder->preordercampaign_id, $order_date->format("Y-m-d"));
$price = $product->getCampaignPrice($preorder->preordercampaign_id, $bill_date->format("Y-m-d"));
if(!$price) {
die("operator_setup price not found for campaign ".$preorder->preordercampaign_id." and date ".$order_date->format("Y-m-d"));
}
@@ -325,87 +439,134 @@ class PreorderBillingController extends mfBaseController {
}
$status_change_date = new DateTime("@".$status_change->create);
$first_bill_day = clone $status_change_date;
$first_day = clone $today;
$first_day->modify("first day of this month");
$last_day = clone $today;
$last_day->modify("last day of this month");
//var_dump($first_bill_day);
//var_dump($first_day);
if($first_bill_day->format("Ymd") > $first_day->format("Ymd")) {
$first_day = clone $first_bill_day;
if($status_change_date->format("Ymd") > $earliest_bill_date->format("Ymd")) {
$earliest_bill_date = $status_change_date;
}
$start_date = clone($first_day);
$end_date = clone($last_day);
$first_bill_date = clone $status_change_date;
// get earlier missing billing records and bill them too
$create_date = clone $bill_date;
$create_date->modify("first day of this month");
$create_date->setTime(0,0,0);
$last_create_date = false;
$to_bill_dates = [];
$sday = $start_date->format("d");
$eday = $end_date->format("d");
/*var_dump($today);
var_dump($bill_date);
var_dump($earliest_bill_date);
var_dump($status_change_date);exit;
*/
$earliest_bill_year = $status_change_date->format('Y');
$earliest_bill_month = $status_change_date->format('m');
$earliest_bill_day = $status_change_date->format('d');
$bill_price = $price->price_inet;
// earliest bill date is before this month
//echo "\$create_date ".$create_date->format("Y-m-d H:i:s")."<br />\n";
//echo "\$earliest_bill_date ".$earliest_bill_date->format("Y-m-d H:i:s")."<br /><br />\n";
if($price->price_inet && ($sday > 1)) {
// Aliquoten Preis errechnen
$first_of_period = clone $start_date;
$first_of_period->modify("first day of this month");
while($create_date->format("Ym") >= $earliest_bill_date->format("Ym")) {
if($last_create_date) {
//var_dump($create_dates);
// just for safety / shouldn't happen
break;
//die("need-date ran out of dates");
}
$last_of_period = clone $start_date;
$last_of_period->modify("last day of this month");
//echo " - \$create_date ".$create_date->format("Y-m-d H:i:s")."<br />\n";
//echo " - \$earliest_bill_date ".$earliest_bill_date->format("Y-m-d H:i:s")."<br /><br />\n";
if($create_date->format("Y") == $earliest_bill_date->format("Y") && $create_date->format("m") == $earliest_bill_date->format("m")) {
// this is the finish month, so set day back to day of finish_date
$create_date->setDate($earliest_bill_date->format("Y"), $earliest_bill_date->format("m"), $earliest_bill_date->format("d"));
$last_create_date = true;
}
$total_days = $last_of_period->diff($first_of_period)->format("%a") + 1;
$period_days = ($end_date->diff($start_date)->format("%a")) + 1;
if($period_days < 0) return true; // don't bill for negative time range
$pc = $period_days / $total_days * 100;
$bill_price = round($price->price_inet / 100 * $pc, 4);
$existing_bill = PreorderBilling::getFirst(["product_id" => $product->id, "preorder_id" => $preorder->id, "start_date" => $create_date->format("Y-m-d")]);
//var_dump($existing_bill);
if(!$existing_bill) {
$new_create_date = clone $create_date;
$to_bill_dates[] = $new_create_date;
$create_date->modify("-1 months");
continue;
}
break;
}
//var_dump($to_bill_dates);
//exit;
$article_number = $product->article_number;
if(!$article_number) {
$article_number = $product->getDefaultArticlenumber();
}
$billing_data = [
"preorder_id" => $preorder->id,
"adb_wohneinheit_id" => $preorder->adb_wohneinheit_id,
"order_date" => $order_date->format("Y-m-d"),
"start_date" => $start_date->format("Y-m-d"),
"end_date" => $end_date->format("Y-m-d"),
"billing_delivery" => "email",
"product_id" => $product->id,
"product_info" => "",
"article_number" => $article_number,
"amount" => 1,
"unit" => "Stk.",
"price" => $bill_price,
"price_setup" => 0,
"vatrate" => 20,
"billing_period" => 0,
"product_name" => "Nutzungsentgelt " . $start_date->format("m/Y"),
"owner_id" => $netoperator->id,
"billingaddress_id" => $netoperator->id,
"fibu_account_number" => $netoperator->attributes['rml-fibu-account']->value,
"company" => trim($netoperator->company),
"firstname" => trim($netoperator->firstname),
"lastname" => trim($netoperator->lastname),
"street" => trim($netoperator->street),
"zip" => trim($netoperator->zip),
"city" => trim($netoperator->city),
"country" => trim($netoperator->country->name),
"email" => trim($netoperator->email),
"uid" => trim($netoperator->uid),
];
foreach($to_bill_dates as $start_date) {
$end_date = clone $start_date;
$end_date->modify("first day of this month");
$end_date->modify("+1 months");
$end_date->modify("-1 day");
$billing = PreorderBilling::create($billing_data);
//var_dump($billing);exit;
if(!$billing->save()) {
die("Billing record could not be saved!");
$sday = $start_date->format("d");
$eday = $end_date->format("d");
$bill_price = $price->price_inet;
if ($price->price_inet && ($sday > 1)) {
// Aliquoten Preis errechnen
$first_of_period = clone $start_date;
$first_of_period->modify("first day of this month");
$last_of_period = clone $start_date;
$last_of_period->modify("last day of this month");
$total_days = $last_of_period->diff($first_of_period)->format("%a") + 1;
$period_days = ($end_date->diff($start_date)->format("%a")) + 1;
if ($period_days < 0) return true; // don't bill for negative time range
$pc = $period_days / $total_days * 100;
$bill_price = round($price->price_inet / 100 * $pc, 4);
}
$article_number = $product->article_number;
if (!$article_number) {
$article_number = $product->getDefaultArticlenumber();
}
$billing_data = [
"preorder_id" => $preorder->id,
"oaid" => $preorder->oaid,
"adb_wohneinheit_id" => $preorder->adb_wohneinheit_id,
"order_date" => $order_date->format("Y-m-d"),
"start_date" => $start_date->format("Y-m-d"),
"end_date" => $end_date->format("Y-m-d"),
"billing_delivery" => "email",
"product_id" => $product->id,
"product_info" => "",
"article_number" => $article_number,
"amount" => 1,
"unit" => "Stk.",
"price" => $bill_price,
"price_setup" => 0,
"vatrate" => 20,
"billing_period" => 0,
"product_name" => "Nutzungsentgelt " . $start_date->format("m/Y"),
"owner_id" => $netoperator->id,
"billingaddress_id" => $netoperator->id,
"fibu_account_number" => $netoperator->attributes['rml-fibu-account']->value,
"company" => trim($netoperator->company),
"firstname" => trim($netoperator->firstname),
"lastname" => trim($netoperator->lastname),
"street" => trim($netoperator->street),
"zip" => trim($netoperator->zip),
"city" => trim($netoperator->city),
"country" => trim($netoperator->country->name),
"email" => trim($netoperator->email),
"uid" => trim($netoperator->uid),
];
$billing = PreorderBilling::create($billing_data);
//var_dump($billing);exit;
if (!$billing->save()) {
die("Billing record could not be saved!");
}
}
//var_dump($billing);

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class PreorderBillingAddOaid extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("PreorderBilling");
$table->addColumn("oaid", "string", ["null" => false, "limit" => 64, "after" => "preorder_id"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("PreorderBilling");
$table->removeColumn("oaid");
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class PreorderHistoryAddChanged extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table('PreorderHistory');
$table->addColumn('changed', 'integer', ["null" => true, "after" => "new_value"]);
$table->update();
$builder = $this->getQueryBuilder();
$q = $builder->select("*")->from("PreorderHistory")->execute();
$this->query("UPDATE PreorderHistory SET `changed` = `create`");
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table('PreorderHistory');
$table->removeColumn('changed');
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,504 @@
#!/usr/bin/php
<?php
//require 'vendor/autoload.php';
require("../../config/config.php");
define('FRONKDB_SQLDEBUG', false);
error_reporting(E_ALL & ~(E_NOTICE | E_STRICT | E_DEPRECATED));
require_once(LIBDIR . "/mvcfronk/mfRouter/mfRouter.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseModel.php");
require_once(LIBDIR . "/mvcfronk/mfBase/mfBaseController.php");
$me = new User(1);
define("INTERNAL_USER_ID", $me->id);
define("INTERNAL_USER_USERNAME", $me->username);
define("MFBASE_BYPASS_LOGIN", true);
$oaids_jan = [
"AT-8952-23ffab62.001",
"AT-8952-99faa819.001",
"AT-8952-c2a464e4.001",
"AT-8952-a3b92ec9.001",
"AT-8952-e1945541.001",
"AT-8952-45285e35.001",
"AT-8952-2de897a5.001",
"AT-8952-98443134.001",
"AT-8952-7aded06c.001",
"AT-8952-5616e098.001",
"AT-8952-2cbe64bc.001",
"AT-8952-10ff5831.001",
"AT-8952-9a7460b4.002",
"AT-8952-bcad283f.001",
"AT-8952-29f918bc.001",
"AT-8943-d972ba1c.001",
"AT-8952-47e52775.002",
"AT-8952-479e52b8.001",
"AT-8952-03e9c108.001",
"AT-8952-0923e13a.001",
"AT-8952-1629b7f4.001",
"AT-8952-18354d50.001",
"AT-8952-20559f13.001",
"AT-8952-2ce0dc06.001",
"AT-8952-46bb7fff.001",
"AT-8952-49928eab.001",
"AT-8952-4e7fa84f.001",
"AT-8952-544d23e8.001",
"AT-8952-5dfb7093.001",
"AT-8952-a0784e8d.001",
"AT-8952-a9ef64c5.001",
"AT-8952-b92fcb7d.001",
"AT-8952-d150720b.001",
"AT-8952-d5efb0c5.001",
"AT-8952-e2aac412.001",
"AT-8952-e41153d0.001",
"AT-8952-f15a2ca7.001",
"AT-8952-fc73db80.001",
"AT-8952-db66a8b5.001",
"AT-8952-a2959a59.001",
"AT-8952-d82544fa.001",
"AT-8952-eb1f181f.001",
"AT-8952-ab64ee00.001",
"AT-8952-9298eb35.001",
"AT-8952-907f3e5b.001",
"AT-8952-e3ead452.001",
"AT-8952-6825d3ae.001",
"AT-8952-5badd1cd.001",
"AT-8952-d63f3b4a.001",
"AT-8952-730c7315.001",
"AT-8943-090108fa.001",
"AT-8952-56809ead.001",
"AT-8952-0f09116b.001",
"AT-8952-7a957a9e.001",
"AT-8952-8ff3a2c9.001",
"AT-8952-fccc732a.001",
"AT-8952-8307773c.001",
"AT-8952-d510b7aa.001",
"AT-8952-39b3f98f.001",
"AT-8952-f2a0a99d.001",
"AT-8952-cfd374ef.001",
"AT-8952-84e38d21.001",
"AT-8952-a95bda77.001",
"AT-8952-5df56224.001",
"AT-8952-047a8d82.001",
"AT-8952-174a11aa.001",
"AT-8943-ac155257.001",
"AT-8943-d906ff07.001",
"AT-8952-be7a0660.001",
"AT-8952-4bffce63.001",
"AT-8952-aed7e5ed.001",
"AT-8952-cd78c3e5.001",
"AT-8952-af85f1e0.001",
"AT-8952-b9749ec9.001",
"AT-8952-f63e9d2c.001",
"AT-8952-affe64f2.001",
"AT-8952-f4468002.001",
"AT-8952-e80422e6.001",
"AT-8943-5565dba0.001",
"AT-8952-a7c37d89.001",
"AT-8952-a8bd4bd9.001",
"AT-8952-d4fb7422.001",
"AT-8952-8ea45971.001",
"AT-8943-820efe44.001",
"AT-8943-6e670739.001",
"AT-8943-a1116acf.001",
"AT-8952-5eea3a46.001",
"AT-8952-3083a5c1.001",
"AT-8952-64e40186.003",
"AT-8952-c291163a.003",
"AT-8952-47e52775.003",
"AT-8952-64e40186.002",
"AT-8952-64e40186.001",
"AT-8952-39d2c630.001",
"AT-8943-cc2e08c3.001",
"AT-8943-d029b6d2.001",
"AT-8943-7472b260.001",
"AT-8943-426cda48.003",
"AT-8943-426cda48.005",
"AT-8943-f2c2ae10.006",
"AT-8943-0281f0db.004",
"AT-8943-0281f0db.001",
"AT-8943-ff7298d6.001",
"AT-8943-fffb3d90.005",
"AT-8943-9389a188.003",
"AT-8943-ad0ba787.003",
"AT-8943-ad0ba787.002",
"AT-8943-8fad635a.001",
"AT-8943-9389a188.004",
"AT-8943-8bde59fc.003",
"AT-8943-0281f0db.002",
"AT-8943-ef64ab98.001",
"AT-8943-fd1e7b0c.004",
"AT-8943-c10d87c7.003",
"AT-8943-a5762d93.003",
"AT-8943-a5762d93.004",
"AT-8943-bc7bb96c.001",
"AT-8943-2a911dab.001",
"AT-8943-65b57745.001",
"AT-8943-40c99c0d.002",
"AT-8943-40c99c0d.004",
"AT-8943-40c99c0d.001",
"AT-8943-40c99c0d.003",
"AT-8943-dcab7caf.001",
"AT-8943-cf48ccef.001",
"AT-8943-2c01ac8d.001",
"AT-8943-3f07dd46.001",
"AT-8943-f2c2ae10.002",
"AT-8943-fa78f417.001",
"AT-8943-05505f1e.001",
"AT-8943-b8e526a2.002",
"AT-8943-b8e526a2.001",
"AT-8943-54e2caa3.001",
"AT-8943-91b15e79.001",
"AT-8943-a28e1bce.001",
"AT-8943-e29b3cd4.001",
"AT-8943-1277b7eb.001",
"AT-8943-5d391327.001",
"AT-8943-b4c1b606.001",
"AT-8943-6e424945.001",
"AT-8943-339cdc17.001",
"AT-8943-a443cbe2.001",
"AT-8943-dd7e2b71.005",
"AT-8943-9389a188.002",
"AT-8943-9389a188.001",
"AT-8943-ad0ba787.001",
"AT-8943-8bde59fc.004",
"AT-8943-ad0ba787.004",
"AT-8943-13e70f36.001",
"AT-8943-426cda48.002",
"AT-8943-0281f0db.003",
"AT-8943-426cda48.001",
"AT-8943-a464c429.001",
"AT-8943-fffb3d90.006",
"AT-8943-ad6205f0.001",
"AT-8943-dd7e2b71.003",
"AT-8943-fce5a31f.003",
"AT-8943-49b0c91c.001",
"AT-8943-fffb3d90.003",
"AT-8943-fffb3d90.004",
"AT-8943-c964421e.001",
"AT-8943-77d4537b.001",
"AT-8943-3c8f8152.003",
"AT-8943-9c8937e8.001",
"AT-8943-3c8f8152.002",
"AT-8943-3c8f8152.001",
"AT-8943-ed3620c0.001",
"AT-8943-399bd714.001",
"AT-8943-69ae30fb.001",
"AT-8943-46ec6651.001",
"AT-8943-d61452be.002",
"AT-8943-c10d87c7.002",
"AT-8943-fffb3d90.002",
"AT-8943-fffb3d90.001",
"AT-8943-fce5a31f.002",
"AT-8943-8f89a4af.001",
"AT-8943-3455667d.001",
"AT-8943-ac0c2308.001",
"AT-8943-b87f265d.001",
"AT-8943-33925d44.001",
"AT-8982-4f2a215b.001",
"AT-8982-a89c4335.001",
"AT-8982-e6265b67.001",
"AT-8982-a415bb94.001",
"AT-8982-6a510a7a.001",
"AT-8982-66f307a0.001",
"AT-8982-dbab4714.002",
"AT-8982-2827d3aa.001",
"AT-8982-a1ada847.001",
"AT-8982-0208e8be.001",
"AT-8982-580833dd.001",
"AT-8982-614920ab.001",
"AT-8982-af3a8d63.001",
"AT-8982-d798cd99.001",
"AT-8982-c6d7e4f2.001",
"AT-8982-9641fb2e.001",
"AT-8982-aded99c2.001",
"AT-8982-abd61a0b.001",
"AT-8982-451c1eb1.001",
"AT-8982-3126a5dc.001",
"AT-8982-06484e3f.001",
"AT-8982-63977aa7.001",
"AT-8982-7edf2184.001",
"AT-8982-edc6a443.001",
"AT-8982-bce86ac9.001",
"AT-8982-d448ba70.001",
"AT-8982-be11d84d.001",
"AT-8982-92020d96.001",
"AT-8983-e66b3f80.001",
"AT-8983-ae426106.001",
"AT-8983-2bf3214f.001",
];
$oaids_feb = [
"AT-8952-23ffab62.001",
"AT-8952-99faa819.001",
"AT-8952-c2a464e4.001",
"AT-8952-a3b92ec9.001",
"AT-8952-e1945541.001",
"AT-8952-45285e35.001",
"AT-8952-2de897a5.001",
"AT-8952-98443134.001",
"AT-8952-7aded06c.001",
"AT-8952-5616e098.001",
"AT-8952-2cbe64bc.001",
"AT-8952-10ff5831.001",
"AT-8952-9a7460b4.002",
"AT-8952-bcad283f.001",
"AT-8952-29f918bc.001",
"AT-8943-d972ba1c.001",
"AT-8952-47e52775.002",
"AT-8952-479e52b8.001",
"AT-8952-47e52775.001",
"AT-8952-54a90298.001",
"AT-8952-03e9c108.001",
"AT-8952-0923e13a.001",
"AT-8952-1629b7f4.001",
"AT-8952-18354d50.001",
"AT-8952-20559f13.001",
"AT-8952-2ce0dc06.001",
"AT-8952-46bb7fff.001",
"AT-8952-49928eab.001",
"AT-8952-4e7fa84f.001",
"AT-8952-544d23e8.001",
"AT-8952-5dfb7093.001",
"AT-8952-a0784e8d.001",
"AT-8952-a9ef64c5.001",
"AT-8952-b92fcb7d.001",
"AT-8952-d150720b.001",
"AT-8952-d5efb0c5.001",
"AT-8952-e2aac412.001",
"AT-8952-e41153d0.001",
"AT-8952-f15a2ca7.001",
"AT-8952-fc73db80.001",
"AT-8952-db66a8b5.001",
"AT-8952-a2959a59.001",
"AT-8952-d82544fa.001",
"AT-8952-eb1f181f.001",
"AT-8952-ab64ee00.001",
"AT-8952-9298eb35.001",
"AT-8952-907f3e5b.001",
"AT-8952-e3ead452.001",
"AT-8952-6825d3ae.001",
"AT-8952-5badd1cd.001",
"AT-8952-d63f3b4a.001",
"AT-8952-730c7315.001",
"AT-8943-090108fa.001",
"AT-8952-56809ead.001",
"AT-8952-0f09116b.001",
"AT-8952-7a957a9e.001",
"AT-8952-8ff3a2c9.001",
"AT-8952-fccc732a.001",
"AT-8952-8307773c.001",
"AT-8952-d510b7aa.001",
"AT-8952-39b3f98f.001",
"AT-8952-f2a0a99d.001",
"AT-8952-cfd374ef.001",
"AT-8952-84e38d21.001",
"AT-8952-a95bda77.001",
"AT-8952-5df56224.001",
"AT-8952-047a8d82.001",
"AT-8952-174a11aa.001",
"AT-8943-ac155257.001",
"AT-8943-d906ff07.001",
"AT-8952-be7a0660.001",
"AT-8952-4bffce63.001",
"AT-8952-aed7e5ed.001",
"AT-8952-cd78c3e5.001",
"AT-8952-af85f1e0.001",
"AT-8952-b9749ec9.001",
"AT-8952-f63e9d2c.001",
"AT-8952-affe64f2.001",
"AT-8952-f4468002.001",
"AT-8952-e80422e6.001",
"AT-8943-5565dba0.001",
"AT-8952-a7c37d89.001",
"AT-8952-a8bd4bd9.001",
"AT-8952-d4fb7422.001",
"AT-8952-8ea45971.001",
"AT-8943-820efe44.001",
"AT-8943-6e670739.001",
"AT-8943-a1116acf.001",
"AT-8952-5eea3a46.001",
"AT-8952-3083a5c1.001",
"AT-8952-64e40186.003",
"AT-8952-c291163a.003",
"AT-8952-47e52775.003",
"AT-8952-64e40186.002",
"AT-8952-64e40186.001",
"AT-8952-ec0bd13d.001",
"AT-8952-2c5c1a88.001",
"AT-8952-ad79e49e.003",
"AT-8952-ad79e49e.002",
"AT-8952-8e408a37.002",
"AT-8952-91880329.001",
"AT-8952-39d2c630.001",
"AT-8952-ee1bcdc3.001",
"AT-8943-cc2e08c3.001",
"AT-8943-d029b6d2.001",
"AT-8943-7472b260.001",
"AT-8943-426cda48.003",
"AT-8943-426cda48.005",
"AT-8943-f2c2ae10.006",
"AT-8943-0281f0db.004",
"AT-8943-0281f0db.001",
"AT-8943-ff7298d6.001",
"AT-8943-fffb3d90.005",
"AT-8943-9389a188.003",
"AT-8943-ad0ba787.003",
"AT-8943-ad0ba787.002",
"AT-8943-8fad635a.001",
"AT-8943-9389a188.004",
"AT-8943-8bde59fc.003",
"AT-8943-0281f0db.002",
"AT-8943-ef64ab98.001",
"AT-8943-fd1e7b0c.004",
"AT-8943-c10d87c7.003",
"AT-8943-a5762d93.003",
"AT-8943-a5762d93.004",
"AT-8943-bc7bb96c.001",
"AT-8943-a5762d93.002",
"AT-8943-8392e815.001",
"AT-8943-2a911dab.001",
"AT-8943-65b57745.001",
"AT-8943-40c99c0d.002",
"AT-8943-40c99c0d.004",
"AT-8943-40c99c0d.001",
"AT-8943-40c99c0d.003",
"AT-8943-dcab7caf.001",
"AT-8943-cf48ccef.001",
"AT-8943-2c01ac8d.001",
"AT-8943-3f07dd46.001",
"AT-8943-f2c2ae10.002",
"AT-8943-fa78f417.001",
"AT-8943-05505f1e.001",
"AT-8943-b8e526a2.002",
"AT-8943-b8e526a2.001",
"AT-8943-54e2caa3.001",
"AT-8943-91b15e79.001",
"AT-8943-a28e1bce.001",
"AT-8943-e29b3cd4.001",
"AT-8943-1277b7eb.001",
"AT-8943-5d391327.001",
"AT-8943-b4c1b606.001",
"AT-8943-6e424945.001",
"AT-8943-339cdc17.001",
"AT-8943-a443cbe2.001",
"AT-8943-dd7e2b71.005",
"AT-8943-9389a188.002",
"AT-8943-9389a188.001",
"AT-8943-ad0ba787.001",
"AT-8943-8bde59fc.004",
"AT-8943-ad0ba787.004",
"AT-8943-13e70f36.001",
"AT-8943-426cda48.002",
"AT-8943-0281f0db.003",
"AT-8943-426cda48.001",
"AT-8943-a464c429.001",
"AT-8943-fffb3d90.006",
"AT-8943-ad6205f0.001",
"AT-8943-dd7e2b71.003",
"AT-8943-fce5a31f.003",
"AT-8943-49b0c91c.001",
"AT-8943-fffb3d90.003",
"AT-8943-fffb3d90.004",
"AT-8943-c964421e.001",
"AT-8943-77d4537b.001",
"AT-8943-3c8f8152.003",
"AT-8943-9c8937e8.001",
"AT-8943-3c8f8152.002",
"AT-8943-3c8f8152.001",
"AT-8943-ed3620c0.001",
"AT-8943-399bd714.001",
"AT-8943-69ae30fb.001",
"AT-8943-46ec6651.001",
"AT-8943-d61452be.002",
"AT-8943-c10d87c7.002",
"AT-8943-fffb3d90.002",
"AT-8943-fffb3d90.001",
"AT-8943-fce5a31f.002",
"AT-8943-9db3a055.002",
"AT-8943-9db3a055.001",
"AT-8943-122f171a.001",
"AT-8943-a72c5637.002",
"AT-8943-bba3a3bc.001",
"AT-8943-8f89a4af.001",
"AT-8943-3455667d.001",
"AT-8943-ac0c2308.001",
"AT-8943-b87f265d.001",
"AT-8943-33925d44.001",
"AT-8982-4f2a215b.001",
"AT-8982-a89c4335.001",
"AT-8982-e6265b67.001",
"AT-8982-a415bb94.001",
"AT-8982-6a510a7a.001",
"AT-8982-66f307a0.001",
"AT-8982-dbab4714.002",
"AT-8982-2827d3aa.001",
"AT-8982-a1ada847.001",
"AT-8982-0208e8be.001",
"AT-8982-580833dd.001",
"AT-8982-614920ab.001",
"AT-8982-af3a8d63.001",
"AT-8982-d798cd99.001",
"AT-8982-c6d7e4f2.001",
"AT-8982-9641fb2e.001",
"AT-8982-aded99c2.001",
"AT-8982-abd61a0b.001",
"AT-8982-451c1eb1.001",
"AT-8982-3126a5dc.001",
"AT-8982-06484e3f.001",
"AT-8982-63977aa7.001",
"AT-8982-7edf2184.001",
"AT-8982-edc6a443.001",
"AT-8982-bce86ac9.001",
"AT-8982-d448ba70.001",
"AT-8982-be11d84d.001",
"AT-8982-8ecff7fc.001",
"AT-8982-f02e6c7d.002",
"AT-8982-f02e6c7d.001",
"AT-8982-92020d96.001",
"AT-8983-e66b3f80.001",
"AT-8983-ae426106.001",
"AT-8983-2bf3214f.001",
];
$from = "2025-01-01";
$to = "2025-01-31";
foreach($oaids_jan as $oaid) {
if(!PreorderBilling::getFirst(["product_id" => 3, "oaid" => $oaid, "start_date>=" => $from, "start_date<=" => $to])) {
echo "OAID $oaid not found in billing\n";
}
}
foreach(PreorderBilling::search(["product_id" => 3, "start_date>=" => $from, "start_date<=" => $to]) as $bill) {
if(!in_array($bill->oaid, $oaids_jan)) {
$preorder = $bill->preorder;
if($preorder->order_date) {
$order_date = new DateTime('@'.$preorder->order_date);
} else {
$order_date = new DateTime('@'.$preorder->create);
}
$order_date->setTime(4,0,0);
$order_date->setTimezone(new DateTimeZone("Europe/Vienna"));
$status_change = PreorderHistoryModel::getFirstStatusChangeToOrHigher($preorder->id, 500);
if(!$status_change) {
$status_change = $preorder;
}
$status_change_date = new DateTime("@".$status_change->create);
echo "OAID ".$bill->oaid." not found in excel | order_date: ".$order_date->format("Y-m-d")." | status 500: ".$status_change_date->format("Y-m-d")."\n";
}
}