823 lines
36 KiB
PHP
823 lines
36 KiB
PHP
<?php
|
|
|
|
class PreorderBillingController extends mfBaseController {
|
|
private $billing_minimum_date = "2025-03-01";
|
|
private $marketshare = [];
|
|
|
|
protected function init() : void
|
|
{
|
|
$this->needlogin = true;
|
|
$me = new User();
|
|
$me->loadMe();
|
|
$this->me = $me;
|
|
$this->layout()->set("me", $me);
|
|
|
|
if(!$me->can(["preorderbilling", "preorderbillingReadonly"])) {
|
|
$this->redirect("Dashboard");
|
|
}
|
|
}
|
|
|
|
protected function indexAction() : void {
|
|
$this->layout()->setTemplate("PreorderBilling/Index");
|
|
|
|
if ($this->request->resetFilter) {
|
|
unset($_SESSION[MFAPPNAME . '-PreorderBilling-filter']);
|
|
}
|
|
|
|
$filter = [];
|
|
if (is_array($this->request->filter)) {
|
|
$filter = $this->request->filter;
|
|
$_SESSION[MFAPPNAME . '-PreorderBilling-filter'] = $filter;
|
|
} else {
|
|
if (array_key_exists(MFAPPNAME . '-PreorderBilling-filter', $_SESSION) && count($_SESSION[MFAPPNAME . '-PreorderBilling-filter'])) {
|
|
$filter = $_SESSION[MFAPPNAME . '-PreorderBilling-filter'];
|
|
}
|
|
}
|
|
|
|
$this->layout->set("filter", $filter);
|
|
$filter = $this->getPreparedFilter($filter);
|
|
|
|
// pagination defaults
|
|
$pagination = [];
|
|
$pagination['start'] = 0;
|
|
$pagination['count'] = 25;
|
|
$pagination['maxItems'] = 0;
|
|
|
|
if (is_numeric($this->request->s)) {
|
|
$pagination['start'] = intval($this->request->s);
|
|
}
|
|
|
|
$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);
|
|
|
|
$billings = PreorderBilling::search($filter, $pagination);
|
|
$this->layout()->set("billings", $billings);
|
|
$this->layout()->set("pagination", $pagination);
|
|
|
|
}
|
|
|
|
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) {
|
|
$new_filter[$name] = $value;
|
|
}
|
|
}
|
|
|
|
return $new_filter;
|
|
}
|
|
|
|
protected function importPreorders() {
|
|
$netowner_id = $this->me->address_id;
|
|
$netowner = new Address($netowner_id);
|
|
|
|
if(!defined("TT_PREORDER_BILLING") || !is_array(TT_PREORDER_BILLING)) {
|
|
die("Config Variable 'TT_PREORDER_BILLING' not found!");
|
|
}
|
|
$netowner_config = TT_PREORDER_BILLING[$netowner_id];
|
|
|
|
$earliest_bill_date = new DateTime(PreorderBilling::$earliest_bill_date); // TODO: auslagern in config file
|
|
|
|
$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-03-13");
|
|
$today->setTime(2,0,0);
|
|
$today->setTimezone(new DateTimeZone("Europe/Vienna"));
|
|
|
|
$bill_date = clone $today;
|
|
$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");
|
|
|
|
$this_quarter_start = clone $today;
|
|
$this_quarter_start->modify("first day of this month");
|
|
$q_subtractor = ($this_quarter_start->format("m") - 1) % 3;
|
|
$this_quarter_start->modify("- $q_subtractor months");
|
|
|
|
$this_quarter_end = clone $this_quarter_start;
|
|
$this_quarter_end->modify("+ 3 months");
|
|
$this_quarter_end->modify("last day of this month");
|
|
|
|
$latest_quarter_bill_date = clone $this_quarter_start;
|
|
$latest_quarter_bill_date->modify("-1 day");
|
|
|
|
$del = 0;
|
|
// first delete all non-invoiced billing records
|
|
foreach(PreorderBilling::search(["invoice_id" => null]) as $bill) {
|
|
$bill->delete();
|
|
$del++;
|
|
}
|
|
$this->log->notice(__METHOD__.": $del Billing records deleted");
|
|
|
|
$campaign_ids = [];
|
|
foreach(PreordercampaignModel::search(["owner_id" => $this->me->address_id]) as $campaign) {
|
|
$campaign_ids[] = $campaign->id;
|
|
}
|
|
|
|
$preorder_search = [
|
|
"preordercampaign_id" => $campaign_ids,
|
|
">=status_code" => 244,
|
|
//"oaid" => "AT-8943-f2c2ae10.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);
|
|
} else {
|
|
$order_date = new DateTime('@'.$preorder->create);
|
|
}
|
|
$order_date->setTime(4,0,0);
|
|
$order_date->setTimezone(new DateTimeZone("Europe/Vienna"));
|
|
|
|
if($order_date->format("Ymd") < $earliest_bill_date->format("Ymd")) {
|
|
// start billing from 2025-01-01
|
|
$this->log->debug(__METHOD__.": Preorder ".$preorder->id." ordered before 2025-01-01, so billing no enduser setup");
|
|
$bill_enduser_setup = false;
|
|
}
|
|
|
|
$operator_id = false;
|
|
$po = PreordercampaignOperatorModel::getFirst(["preordercampaign_id" => $preorder->preordercampaign_id, "isp_id" => $preorder->partner_id]);
|
|
if(!$po) {
|
|
$po = PreordercampaignOperatorModel::getFirst(["preordercampaign_id" => $preorder->preordercampaign_id, "operator_id" => $preorder->partner_id]);
|
|
}
|
|
if(!$po) {
|
|
die("No operator found for preorder ".$preorder->id);
|
|
}
|
|
$netoperator = new Address($po->operator_id);
|
|
if(!$netoperator) {
|
|
die("No netoperator found for preorder ".$preorder->id);
|
|
}
|
|
|
|
if(!is_array($netowner_config["netoperators"]) || !array_key_exists($netoperator->id, $netowner_config["netoperators"])) {
|
|
die("netoperator config missing for ".$netoperator->id);
|
|
}
|
|
$netoperator_config = $netowner_config["netoperators"][$netoperator->id];
|
|
|
|
$fibu_cost_code = TT_PREORDER_BILLING[$netowner_id]["fibu-cost-code"];
|
|
if($fibu_cost_code == "=from-campaign") {
|
|
$campaign_cost_code = $preorder->campaign->netowner_fibu_cost_code;
|
|
if(!$campaign_cost_code) {
|
|
die("campaign cost_code not found for preorder ".$preorder->id." campaign ".$preorder->campaign->id);
|
|
}
|
|
$fibu_cost_code = $campaign_cost_code;
|
|
}
|
|
//var_dump($fibu_cost_code);exit;
|
|
if(!$fibu_cost_code) {
|
|
die("fibu_cost_code not found for preorder ".$preorder->id);
|
|
}
|
|
|
|
$bill_params = [
|
|
"netowner" => $netowner,
|
|
"netowner_config" => $netowner_config,
|
|
"netoperator" => $netoperator,
|
|
"netoperator_config" => $netoperator_config,
|
|
"order_date" => $order_date,
|
|
"today" => $today,
|
|
"bill_date" => $bill_date,
|
|
"earliest_bill_date" => $earliest_bill_date,
|
|
"latest_bill_date" => $latest_bill_date,
|
|
"latest_quarter_bill_date" => $latest_quarter_bill_date,
|
|
"fibu_cost_code" => $fibu_cost_code,
|
|
];
|
|
|
|
if($preorder->status->code >= 241) {
|
|
if($bill_enduser_setup) $this->billSetup($preorder, "enduser_setup", $bill_params);
|
|
}
|
|
if($preorder->status->code >= 500) {
|
|
if($bill_operator_setup) $this->billSetup($preorder, "operator_setup", $bill_params);
|
|
if($bill_usage) $this->billOperatorPeriodic($preorder, $bill_params);
|
|
}
|
|
}
|
|
|
|
//echo "<pre>".print_r($this->marketshare, true)."</pre>";exit;
|
|
|
|
$this->Layout()->setFlash("Billing records erstellt", "success");
|
|
$this->redirect("PreorderBilling");
|
|
|
|
}
|
|
|
|
/*********************************
|
|
* Enduser Setup & Netoperator Setup Billing
|
|
*/
|
|
private function billSetup($preorder, $type, $options) {
|
|
$netowner = $options['netowner'];
|
|
$netowner_config = $options['netowner_config'];
|
|
$netoperator = $options['netoperator'];
|
|
$netoperator_config = $options['netoperator_config'];
|
|
$order_date = $options['order_date'];
|
|
$today = $options['today'];
|
|
$bill_date = $options['bill_date'];
|
|
$latest_bill_date = $options['latest_bill_date'];
|
|
$earliest_bill_date = $options['earliest_bill_date'];
|
|
$latest_quarter_bill_date = $options["latest_quarter_bill_date"];
|
|
$fibu_cost_code = $options['fibu_cost_code'];
|
|
|
|
$this->log->debug(__METHOD__.": bill $type Preorder ".$preorder->id);
|
|
|
|
// get price_setup
|
|
$product = PreorderProduct::getFirst(["type" => $type]);
|
|
if(!$product) {
|
|
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__.": Preorder ".$preorder->id." / ".$preorder->oaid." already cancelled");
|
|
return true;
|
|
}
|
|
|
|
$product->setNetownerId($netowner->id);
|
|
$product->setNetoperatorId($netoperator->id);
|
|
$price = $product->getCampaignPrice($preorder->preordercampaign_id, $order_date->format("Y-m-d"));
|
|
if(!$price) {
|
|
die("operator_setup price not found for netoperator ".$netoperator->id.", campaign ".$preorder->preordercampaign_id." and date ".$order_date->format("Y-m-d"));
|
|
}
|
|
|
|
// check for existing billing record
|
|
//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
|
|
}
|
|
|
|
|
|
$article_number = $product->article_number;
|
|
if(!$article_number) {
|
|
$article_number = $product->getDefaultArticlenumber();
|
|
}
|
|
|
|
// get change to 241/244/245
|
|
$status_change = PreorderHistoryModel::getFirstStatusChangeTo($preorder->id, 245);
|
|
if(!$status_change) {
|
|
$status_change = PreorderHistoryModel::getFirstStatusChangeTo($preorder->id, 244);
|
|
}
|
|
if(!$status_change) {
|
|
$status_change = PreorderHistoryModel::getFirstStatusChangeToOrHigher($preorder->id, 241);
|
|
}
|
|
|
|
if($status_change) {
|
|
$status_244_change_date = new DateTime("@".$status_change->changed);
|
|
} else {
|
|
$this->log->debug(__METHOD__.": No status change found for preorder ".$preorder->id." so using creation date");
|
|
$status_244_change_date = new DateTime("@".$preorder->create);
|
|
}
|
|
|
|
/*if($status_change_date < $earliest_bill_date) {
|
|
$this->log->debug(__METHOD__.": Not billing setups for preorder ".$preorder->id." because status change date ".$status_change_date->format("Y-m-d")." is before earliest_bill_date ".$earliest_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}*/
|
|
|
|
if($status_244_change_date->format("Ymd") > $latest_bill_date->format("Ymd")) {
|
|
$this->log->debug(__METHOD__.": Skipping setup for preorder ".$preorder->id." because billing date (status change date) ".$status_244_change_date->format("Y-m-d")." is after latest_bill_date ".$latest_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
|
|
$billing_data = [
|
|
"netowner_id" => $netowner->id,
|
|
"preorder_id" => $preorder->id,
|
|
"oaid" => $preorder->oaid,
|
|
"adb_wohneinheit_id" => $preorder->adb_wohneinheit_id,
|
|
"extref" => ($preorder->extref) ?: null,
|
|
"order_date" => $order_date->format("Y-m-d"),
|
|
"start_date" => $status_244_change_date->format("Y-m-d"),
|
|
"end_date" => $status_244_change_date->format("Y-m-d"),
|
|
"billing_delivery" => "email",
|
|
"product_id" => $product->id,
|
|
"product_type" => $product->type,
|
|
"product_info" => "",
|
|
"article_number" => $article_number,
|
|
"amount" => 1,
|
|
"unit" => "Stk.",
|
|
"price" => "0",
|
|
"price_setup" => round($price->price_setup, 2),
|
|
"vatrate" => 20,
|
|
"billing_period" => 0,
|
|
"fibu_cost_account" => $fibu_cost_code,
|
|
];
|
|
|
|
$fibu_revenue_code = "";
|
|
|
|
if($type == "enduser_setup") {
|
|
// Endkunde Setup Gebühr
|
|
|
|
if($status_244_change_date < $earliest_bill_date) {
|
|
$this->log->debug(__METHOD__.": Not billing enduser_setup for preorder ".$preorder->id." because status 244 change date ".$status_244_change_date->format("Y-m-d")." is before earliest_bill_date ".$earliest_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
|
|
$fibu_revenue_code = $netowner_config["fibu-revenue-code"];
|
|
if(!$fibu_revenue_code) {
|
|
die("fibu_revenue_code not found for preorder ".$preorder->id);
|
|
}
|
|
|
|
if($order_date->format("Ymd") < $earliest_bill_date->format("Ymd")) {
|
|
return true;
|
|
}
|
|
|
|
if(PreorderBilling::getFirst(["adb_wohneinheit_id" => $preorder->adb_wohneinheit_id, "product_id" => $product->id])) {
|
|
$this->log->debug(__METHOD__.": billing record for enduser setup for wohneinheit ".$preorder->adb_wohneinheit_id." exists");
|
|
return true; // already billed
|
|
}
|
|
|
|
// search for customer
|
|
$customer_data = [
|
|
"company" => trim($preorder->company),
|
|
"firstname" => trim($preorder->firstname),
|
|
"lastname" => trim($preorder->lastname),
|
|
"street" => trim($preorder->street) . (trim($preorder->housenumber) ? " " . trim($preorder->housenumber) : ""),
|
|
"zip" => trim($preorder->zip),
|
|
"city" => trim($preorder->city),
|
|
"country" => trim($preorder->country),
|
|
"phone" => trim($preorder->phone),
|
|
"email" => trim($preorder->email),
|
|
"uid" => trim($preorder->uid)
|
|
];
|
|
$customer = PreorderBillingCustomer::getFirst($customer_data);
|
|
if(!$customer) {
|
|
// create customer
|
|
$customer = PreorderBillingCustomer::create($customer_data);
|
|
if(!$customer->save()) {
|
|
die("Customer record could not be saved!");
|
|
}
|
|
$customer->createFibuAccountNumber($netowner->id);
|
|
$customer->save();
|
|
}
|
|
|
|
foreach($customer_data as $key => $value) {
|
|
$billing_data[$key] = $value;
|
|
}
|
|
|
|
$address = $preorder->adb_hausnummer->strasse->name." ".$preorder->adb_hausnummer->hausnummer.($preorder->adb_hausnummer->stiege ? " /".$preorder->adb_hausnummer->stiege : "").", ".$preorder->adb_hausnummer->plz->plz." ".$preorder->adb_hausnummer->ortschaft->name;
|
|
$billing_data["preorderbillingcustomer_id"] = $customer->id;
|
|
$billing_data["fibu_account_number"] = $customer->fibu_account_number;
|
|
$billing_data["fibu_revenue_account"] = $fibu_revenue_code;
|
|
$billing_data["product_name"] = "Herstellungsentgelt Glasfaser-Internetanschluss";
|
|
$billing_data["product_info"] = $address;
|
|
|
|
} elseif($type == "operator_setup") {
|
|
if(array_key_exists("fibu-revenue-code", $netoperator_config) && $netoperator_config["fibu-revenue-code"]) {
|
|
$fibu_revenue_code = $netoperator_config["fibu-revenue-code"];
|
|
}
|
|
if(!$fibu_revenue_code) {
|
|
die("fibu_revenue code not found for preorder ".$preorder->id);
|
|
}
|
|
|
|
$change_to_active = PreorderHistoryModel::getFirstStatusChangeTo($preorder->id, 500);
|
|
if($change_to_active) {
|
|
$status_change_date = new DateTime("@".$change_to_active->changed);
|
|
$billing_data["start_date"] = $status_change_date->format("Y-m-d");
|
|
$billing_data["end_date"] = $status_change_date->format("Y-m-d");
|
|
}
|
|
|
|
if(!$change_to_active) {
|
|
$status_change_date = $status_244_change_date;
|
|
}
|
|
|
|
if($status_change_date < $earliest_bill_date) {
|
|
$this->log->debug(__METHOD__.": Not billing operator_setup for preorder ".$preorder->id." because status change date ".$status_change_date->format("Y-m-d")." is before earliest_bill_date ".$earliest_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
|
|
if($netoperator_config["billing-period"] == "quarterly" && $status_change_date->format("Ymd") > $latest_quarter_bill_date->format("Ymd")) {
|
|
$this->log->debug(__METHOD__.": Skipping operator_setup for preorder ".$preorder->id." because Billing date ".$status_change_date->format("Y-m-d")." is after latest_quarter_bill_date ".$latest_quarter_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
|
|
if($status_change_date->format("Ymd") > $latest_bill_date->format("Ymd")) {
|
|
$this->log->debug(__METHOD__.": Skipping setup for preorder ".$preorder->id." because billing date (status change date) ".$status_change_date->format("Y-m-d")." is after latest_bill_date ".$latest_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
|
|
// Netzbetreiber Setup Gebühr
|
|
$billing_data["product_name"] = "Bereitstellungsentgelt ".$status_change_date->format("m/Y");
|
|
$billing_data["owner_id"] = $netoperator->id;
|
|
$billing_data["billingaddress_id"] = $netoperator->id;
|
|
$billing_data["fibu_account_number"] = $netoperator->attributes['rml-fibu-account']->value;
|
|
$billing_data["fibu_revenue_account"] = $fibu_revenue_code;
|
|
$billing_data["company"] = trim($netoperator->company);
|
|
$billing_data["firstname"] = trim($netoperator->firstname);
|
|
$billing_data["lastname"] = trim($netoperator->lastname);
|
|
$billing_data["street"] = trim($netoperator->street);
|
|
$billing_data["zip"] = trim($netoperator->zip);
|
|
$billing_data["city"] = trim($netoperator->city);
|
|
$billing_data["country"] = trim($netoperator->country->name);
|
|
$billing_data["email"] = trim($netoperator_config["email"]);
|
|
$billing_data["uid"] = trim($netoperator->uid);
|
|
} else {
|
|
die("Unknown billing type $type");
|
|
}
|
|
|
|
|
|
$billing = PreorderBilling::create($billing_data);
|
|
if(!$billing->save()) {
|
|
die("Billing record could not be saved!");
|
|
}
|
|
|
|
//var_dump($billing);
|
|
$this->log->debug(__METHOD__.": Billed");
|
|
return true;
|
|
}
|
|
|
|
/*********************************
|
|
* Usage Billing
|
|
*/
|
|
private function billOperatorPeriodic($preorder, $options) {
|
|
$netowner = $options['netowner'];
|
|
$netowner_config = $options['netowner_config'];
|
|
$netoperator = $options['netoperator'];
|
|
$netoperator_config = $options['netoperator_config'];
|
|
$order_date = $options['order_date'];
|
|
$today = $options['today'];
|
|
$bill_date = $options['bill_date'];
|
|
$latest_bill_date = $options['latest_bill_date'];
|
|
$earliest_bill_date = $options['earliest_bill_date'];
|
|
$latest_quarter_bill_date = $options["latest_quarter_bill_date"];
|
|
$fibu_cost_code = $options['fibu_cost_code'];
|
|
|
|
$cancel_date = false;
|
|
|
|
|
|
$campaign = new PreorderCampaign($preorder->preordercampaign_id);
|
|
if(!$campaign) {
|
|
die("Campaign ".$preorder->preordercampaign_id." not found!");
|
|
}
|
|
|
|
$fibu_revenue_code = "";
|
|
if(array_key_exists("fibu-revenue-code", $netoperator_config) && $netoperator_config["fibu-revenue-code"]) {
|
|
$fibu_revenue_code = $netoperator_config["fibu-revenue-code"];
|
|
}
|
|
if(!$fibu_revenue_code) {
|
|
die("fibu_revenue code not found for preorder ".$preorder->id);
|
|
}
|
|
|
|
if(!array_key_exists($campaign->id, $this->marketshare)) {
|
|
$this->marketshare[$campaign->id] = [];
|
|
$this->marketshare[$campaign->id]["max"] = $campaign->getUnitCount();
|
|
$this->marketshare[$campaign->id]["netops"] = [];
|
|
}
|
|
|
|
if(!array_key_exists($netoperator->id, $this->marketshare[$campaign->id]["netops"])) {
|
|
$this->marketshare[$campaign->id]["netops"][$netoperator->id] = [];
|
|
$this->marketshare[$campaign->id]["netops"][$netoperator->id]["bracket_price"] = [];
|
|
}
|
|
|
|
// get price_setup
|
|
$product = PreorderProduct::getFirst(["type" => "operator_usage"]);
|
|
if(!$product) {
|
|
die("operator_setup price not found!");
|
|
}
|
|
|
|
$product->setNetownerId($netowner->id);
|
|
$product->setNetoperatorId($netoperator->id);
|
|
$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"));
|
|
}
|
|
|
|
//var_dump($product, $price);exit;
|
|
|
|
$status_change = PreorderHistoryModel::getLastStatusChangeTo($preorder->id, 500);
|
|
if($status_change) {
|
|
$status_change_date = new DateTime("@".$status_change->changed);
|
|
} else {
|
|
$this->log->debug(__METHOD__.": No status change to 500 found for preorder ".$preorder->id." so using creation date");
|
|
$status_change_date = new DateTime("@".$preorder->create);
|
|
|
|
}
|
|
|
|
if($status_change_date->format("Ymd") > $earliest_bill_date->format("Ymd")) {
|
|
$earliest_bill_date = $status_change_date;
|
|
}
|
|
|
|
if($status_change_date->format("Ymd") > $latest_bill_date->format("Ymd")) {
|
|
$this->log->debug(__METHOD__.": Skipping usage for preorder ".$preorder->id." because billing date (status change date) ".$status_change_date->format("Y-m-d")." is after latest_bill_date ".$latest_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
|
|
if($preorder->status->code >= 899) {
|
|
$this->log->debug(__METHOD__.": Preorder ".$preorder->id." / ".$preorder->oaid." is cancelled");
|
|
// get cancel date
|
|
|
|
if(!$status_change) {
|
|
$this->log->debug(__METHOD__.": But was never 500, so skipping");
|
|
return true;
|
|
}
|
|
|
|
$cancel_change = PreorderHistoryModel::getLastStatusChangeToOrHigher($preorder->id, 899);
|
|
if(!$cancel_change) {
|
|
die("Preorder ".$preorder->oaid." gekündigt (Status ".$preorder->status->code."), aber kein Cancel date gefunden");
|
|
}
|
|
$cancel_date = new DateTime("@".$cancel_change->changed);
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 = [];
|
|
|
|
/*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');
|
|
|
|
// 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";
|
|
|
|
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");
|
|
}
|
|
|
|
//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;
|
|
}
|
|
|
|
$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) {
|
|
if($netoperator_config["billing-period"] == "quarterly" && $create_date->format("Ymd") > $latest_quarter_bill_date->format("Ymd")) {
|
|
$this->log->debug(__METHOD__.": Skipping operator_usage ".$create_date->format("m/Y")." for preorder ".$preorder->id." because Billing date ".$create_date->format("Y-m-d")." is after latest_quarter_bill_date ".$latest_quarter_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
$new_create_date = clone $create_date;
|
|
$to_bill_dates[] = $new_create_date;
|
|
$create_date->modify("-1 months");
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if($preorder->activation_billing) {
|
|
// bill from activation_date, even if it's before earliest_bill_date
|
|
$first_bill_date = clone $status_change_date;
|
|
$create_date = clone $earliest_bill_date;
|
|
$create_date->modify("first day of this month");
|
|
$create_date->modify("-1 month");
|
|
$create_date->setTime(0,0,0);
|
|
|
|
//var_dump($first_bill_date);
|
|
/*var_dump($create_date);
|
|
var_dump($earliest_bill_date);*/
|
|
|
|
// get months from activation date
|
|
$last_create_date = false;
|
|
while($create_date->format("Ym") < $earliest_bill_date->format("Ym")) {
|
|
//var_dump($create_date);
|
|
if($last_create_date) {
|
|
//var_dump($create_dates);
|
|
// just for safety / shouldn't happen
|
|
break;
|
|
//die("need-date ran out of dates");
|
|
}
|
|
|
|
//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") == $first_bill_date->format("Y") && $create_date->format("m") == $first_bill_date->format("m")) {
|
|
// this is the finish month, so set day back to day of finish_date
|
|
$create_date->setDate($first_bill_date->format("Y"), $first_bill_date->format("m"), $first_bill_date->format("d"));
|
|
$last_create_date = true;
|
|
}
|
|
|
|
$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) {
|
|
if($netoperator_config["billing-period"] == "quarterly" && $create_date->format("Ymd") > $latest_quarter_bill_date->format("Ymd")) {
|
|
$this->log->debug(__METHOD__.": Skipping operator_usage ".$create_date->format("m/Y")." for preorder ".$preorder->id." because Billing date ".$create_date->format("Y-m-d")." is after latest_quarter_bill_date ".$latest_quarter_bill_date->format("Y-m-d"));
|
|
return true;
|
|
}
|
|
$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;
|
|
|
|
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");
|
|
|
|
if($cancel_date && $cancel_date->format("Ym") == $start_date->format("Ym")) {
|
|
$end_date = clone $cancel_date;
|
|
}
|
|
|
|
$sday = $start_date->format("d");
|
|
$eday = $end_date->format("d");
|
|
|
|
$price_id = $price->id;
|
|
$base_price = $price->price_inet;
|
|
|
|
if($netoperator_config["marketshare-discount"]) {
|
|
// get current percentage of billed homes
|
|
$ms_bill_month = $start_date->format("Ym");
|
|
if(!array_key_exists("billed-$ms_bill_month", $this->marketshare[$campaign->id]["netops"][$netoperator->id])) {
|
|
$this->marketshare[$campaign->id]["netops"][$netoperator->id]["billed-$ms_bill_month"] = 0;
|
|
}
|
|
|
|
$max_homes = $this->marketshare[$campaign->id]["max"];
|
|
$billed_homes = $this->marketshare[$campaign->id]["netops"][$netoperator->id]["billed-$ms_bill_month"];
|
|
|
|
if($billed_homes) {
|
|
$billed_pct = (100 * $billed_homes) / $max_homes;
|
|
|
|
foreach([15,20,25,30,35,40,45,50] as $bracket) {
|
|
if ($billed_pct >= $bracket) {
|
|
if(array_key_exists("$bracket-$price_id", $this->marketshare[$campaign->id]["netops"][$netoperator->id]["bracket_price"])) {
|
|
$base_price = $this->marketshare[$campaign->id]["netops"][$netoperator->id]["bracket_price"]["$bracket-$price_id"]->price_inet;
|
|
} else {
|
|
$bracket_price = $price->getMarketshareBracket($bracket);
|
|
if ($bracket_price) {
|
|
$this->marketshare[$campaign->id]["netops"][$netoperator->id]["bracket_price"]["$bracket-$price_id"] = $bracket_price;
|
|
$base_price = $bracket_price->price_inet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$this->log->debug(__METHOD__.": ".$netoperator->getCompanyOrName()." (month: $ms_bill_month; campaign: ".$campaign->name.") Marketshare Price: $base_price (max: $max_homes | billed: $billed_homes | billed% $billed_pct ");
|
|
}
|
|
|
|
$bill_price = $base_price;
|
|
|
|
if ($base_price && ($sday > 1 || $cancel_date)) {
|
|
// 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($base_price / 100 * $pc, 2);
|
|
}
|
|
|
|
$article_number = $product->article_number;
|
|
if (!$article_number) {
|
|
$article_number = $product->getDefaultArticlenumber();
|
|
}
|
|
|
|
$billing_data = [
|
|
"netowner_id" => $netowner->id,
|
|
"preorder_id" => $preorder->id,
|
|
"oaid" => $preorder->oaid,
|
|
"adb_wohneinheit_id" => $preorder->adb_wohneinheit_id,
|
|
"extref" => ($preorder->extref) ?: null,
|
|
"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_type" => $product->type,
|
|
"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,
|
|
"fibu_cost_account" => $fibu_cost_code,
|
|
"fibu_revenue_account" => $fibu_revenue_code,
|
|
"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_config["email"]),
|
|
"uid" => trim($netoperator->uid),
|
|
];
|
|
|
|
$billing = PreorderBilling::create($billing_data);
|
|
//var_dump($billing);exit;
|
|
if (!$billing->save()) {
|
|
die("Billing record could not be saved!");
|
|
}
|
|
|
|
$ms_bill_month = $start_date->format("Ym");
|
|
if(!array_key_exists("billed-$ms_bill_month", $this->marketshare[$campaign->id]["netops"][$netoperator->id])) {
|
|
$this->marketshare[$campaign->id]["netops"][$netoperator->id]["billed-$ms_bill_month"] = 0;
|
|
}
|
|
$this->marketshare[$campaign->id]["netops"][$netoperator->id]["billed-$ms_bill_month"]++;
|
|
//$this->marketshare[$campaign->id]["netops"][$netoperator->id]["billed-$ms_bill_month"]
|
|
}
|
|
|
|
|
|
//var_dump($this->marketshare);exit;
|
|
|
|
//var_dump($billing);
|
|
}
|
|
|
|
} |