From 8a0cb38272bb0edbf38331aaedea4f9d3189b8c8 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Tue, 9 Dec 2025 17:11:14 +0100 Subject: [PATCH 1/4] PreorderBilling: Fixed using first status change to 500 as activation date --- application/PreorderBilling/PreorderBillingController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/PreorderBilling/PreorderBillingController.php b/application/PreorderBilling/PreorderBillingController.php index 2785de0f4..d11104877 100644 --- a/application/PreorderBilling/PreorderBillingController.php +++ b/application/PreorderBilling/PreorderBillingController.php @@ -446,7 +446,7 @@ class PreorderBillingController extends mfBaseController { die("fibu_revenue code not found for preorder ".$preorder->id); } - $change_to_active = PreorderHistoryModel::getFirstStatusChangeTo($preorder->id, 500); + $change_to_active = PreorderHistoryModel::getLastStatusChangeTo($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"); From 62cbcc72f092b161f25df94327552e9a290111c9 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Wed, 10 Dec 2025 16:23:49 +0100 Subject: [PATCH 2/4] PreorderBilling: Fixed not immediately billing some usage in quater billing --- .../PreorderBilling/PreorderBillingController.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/application/PreorderBilling/PreorderBillingController.php b/application/PreorderBilling/PreorderBillingController.php index d11104877..232ee4915 100644 --- a/application/PreorderBilling/PreorderBillingController.php +++ b/application/PreorderBilling/PreorderBillingController.php @@ -637,7 +637,14 @@ class PreorderBillingController extends mfBaseController { //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")); + // if this preorder was never billed before and activation date is before latest quarterly billing date, we still need to consider earlier months + $any_previous_bill = PreorderBilling::getFirst(["product_id" => $product->id, "preorder_id" => $preorder->id]); + if(!$any_previous_bill && $status_change_date->format("Ym") < $latest_quarter_bill_date->format("Ym")) { + $create_date->modify("-1 months"); + continue; + } + // otherwise if activation was this month, then we need not bill anything now + $this->log->debug(__METHOD__.": Skipping operator_usage blubb ".$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")." (status 500 change date: ".$status_change_date->format("Y-m-d").")"); return true; } $new_create_date = clone $create_date; From 7bed81ec46dae6b306e3de9ca916465511030de3 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Wed, 10 Dec 2025 17:11:19 +0100 Subject: [PATCH 3/4] Fixed errors when user has no flags --- application/User/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/User/User.php b/application/User/User.php index 7370f1771..e8eaab15b 100644 --- a/application/User/User.php +++ b/application/User/User.php @@ -7,7 +7,7 @@ */ class User extends mfBaseModel { public $permissions; - public $flags; + public $flags = []; public $address; protected $forcestr = ['mobile','twofactorcode']; From d209a5b13d9c21115ec1e48369790f697493ef32 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Fri, 12 Dec 2025 12:10:26 +0100 Subject: [PATCH 4/4] WIP Citycom ONT Status 2025-12-11 --- .../Modules/Operationaldata/SnoppCitycom.php | 59 +++++++++ .../Api/v1/OperationaldataApicontroller.php | 3 +- lib/Citycom/OanApiClient.php | 116 ++++++++++++++++++ 3 files changed, 177 insertions(+), 1 deletion(-) diff --git a/application/Api/v1/Modules/Operationaldata/SnoppCitycom.php b/application/Api/v1/Modules/Operationaldata/SnoppCitycom.php index 0420f7e42..75bdbade4 100644 --- a/application/Api/v1/Modules/Operationaldata/SnoppCitycom.php +++ b/application/Api/v1/Modules/Operationaldata/SnoppCitycom.php @@ -17,6 +17,65 @@ class SnoppCitycom extends Modules\ApiControllerModule } + public function getOntStatus($req_id) { + if(!$req_id) { + return \mfResponse::BadRequest(["message" => "id missing"]); + } + + $wohneinheit = false; + if(is_numeric($req_id)) { + $id = $req_id; + $wohneinheit = new \ADBWohneinheit($id); + } + if(!$wohneinheit || !$wohneinheit->id) { + $oaid = $req_id; + $wohneinheit = \ADBWohneinheitModel::getFirst(["oaid" => $oaid]); + if (!$wohneinheit) { + return \mfResponse::NotFound(["message" => "Home not found"]); + } + } + + $cc = new \Citycom_OanApiClient(CITYCOM_OAN_API_USER, CITYCOM_OAN_API_PASS); + $data = $cc->getOntStatus($wohneinheit->oaid); + + $status = []; + $status["online"] = ($data->{"oper-status"} == "present" && $data->status == "Confirmed") ? 1 : 0; + $status["uptime"] = ($data->up_time) ? (date('U') - $data->up_time) : null; + $status["downtime"] = null; + $status["rx"] = $data->{"opt-signal-level"}; + $status["tx"] = $data->tx_opt_level_dbm; + $status["distance"] = null; + + + return \mfResponse::Ok(["status" => $status]); + } + + public function getOntTelemetry($req_id) { + if(!$req_id) { + return \mfResponse::BadRequest(["message" => "id missing"]); + } + + $wohneinheit = false; + if(is_numeric($req_id)) { + $id = $req_id; + $wohneinheit = new \ADBWohneinheit($id); + } + if(!$wohneinheit || !$wohneinheit->id) { + $oaid = $req_id; + $wohneinheit = \ADBWohneinheitModel::getFirst(["oaid" => $oaid]); + if (!$wohneinheit) { + return \mfResponse::NotFound(["message" => "Home not found"]); + } + } + + $cc = new \Citycom_OanApiClient(CITYCOM_OAN_API_USER, CITYCOM_OAN_API_PASS); + $data = $cc->getOntStatusDetail($wohneinheit->oaid); + + print_r($data);exit; + + return \mfResponse::Ok(["status" => $status]); + } + public function orderService($req_id) { if(!$req_id) { return \mfResponse::BadRequest(["message" => "id missing"]); diff --git a/application/Api/v1/OperationaldataApicontroller.php b/application/Api/v1/OperationaldataApicontroller.php index da17d35dc..c0f70186b 100644 --- a/application/Api/v1/OperationaldataApicontroller.php +++ b/application/Api/v1/OperationaldataApicontroller.php @@ -50,8 +50,9 @@ class OperationaldataApicontroller extends mfBaseApicontroller $this->addRoute("/operationaldata/home/:id/connected", [$modules["Snopp"], "setPreorderConnected"], "POST"); $this->addRoute("/operationaldata/home/:id/active", [$modules["Snopp"], "setPreorderActive"], "POST"); - //$this->addRoute("/operationaldata/preorder/:id/orderServiceTest", [$modules["SnoppCitycom"], "orderServiceTest"], "POST"); $this->addRoute("/operationaldata/preorder/:id/orderService", [$modules["SnoppCitycom"], "orderService"], "POST"); + $this->addRoute("/operationaldata/preorder/:id/ontStatus", [$modules["SnoppCitycom"], "getOntStatus"], "GET"); + $this->addRoute("/operationaldata/preorder/:id/ontTelemetry", [$modules["SnoppCitycom"], "getOntTelemetry"], "GET"); } diff --git a/lib/Citycom/OanApiClient.php b/lib/Citycom/OanApiClient.php index 24cac04c8..c5f61c546 100644 --- a/lib/Citycom/OanApiClient.php +++ b/lib/Citycom/OanApiClient.php @@ -266,6 +266,122 @@ class Citycom_OanApiClient { return $types; } + public function getOntStatus($oan_id) { + if(!$this->token) { + $this->getAuthToken(); + if(!$this->token) { + return false; + } + } + + $url = $this->baseurl.CITYCOM_OAN_API_EP_GET_ONT_STATUS; + $url = str_replace("{oan_id}", $oan_id, $url); + $ctx_options = [ + "http" => [ + "ignore_errors" => true, + "method" => "GET", + "header" => [ + "Accept: application/json", + "Authorization: Bearer ".$this->token, + ], + ] + ]; + + $ctx = stream_context_create($ctx_options); + $output = file_get_contents($url, false, $ctx); + + $resp = json_decode($output); + if(!is_object($resp)) { + return false; + } + if(!property_exists($resp, "success") || !$resp->success || !property_exists($resp, "data")) { + return false; + } + + return $resp->data; + } + + public function getOntPortStatus($oan_id) { + if(!$this->token) { + $this->getAuthToken(); + if(!$this->token) { + return false; + } + } + + $url = $this->baseurl.CITYCOM_OAN_API_EP_GET_ONT_PORTSTATUS; + $url = str_replace("{oan_id}", $oan_id, $url); + $ctx_options = [ + "http" => [ + "ignore_errors" => true, + "method" => "GET", + "header" => [ + "Accept: application/json", + "Authorization: Bearer ".$this->token, + ], + ] + ]; + + $ctx = stream_context_create($ctx_options); + $output = file_get_contents($url, false, $ctx); + + $resp = json_decode($output); + if(!is_object($resp)) { + return false; + } + if(!property_exists($resp, "success") || !$resp->success || !property_exists($resp, "data")) { + return false; + } + + return $resp->data; + } + + public function getOntMacAddresses($oan_id) { + if(!$this->token) { + $this->getAuthToken(); + if(!$this->token) { + return false; + } + } + + $url = $this->baseurl.CITYCOM_OAN_API_EP_GET_ONT_MACADDRESSES; + $url = str_replace("{oan_id}", $oan_id, $url); + $ctx_options = [ + "http" => [ + "ignore_errors" => true, + "method" => "GET", + "header" => [ + "Accept: application/json", + "Authorization: Bearer ".$this->token, + ], + ] + ]; + + $ctx = stream_context_create($ctx_options); + $output = file_get_contents($url, false, $ctx); + + $resp = json_decode($output); + if(!is_object($resp)) { + return false; + } + if(!property_exists($resp, "success") || !$resp->success || !property_exists($resp, "data")) { + return false; + } + return $resp->data; + } + + public function getOntStatusDetail($oan_id) { + $ont_status = $this->getOntStatus($oan_id); + $ont_port_status = $this->getOntPortStatus($oan_id); + $ont_mac_addresses = $this->getOntMacAddresses($oan_id); + + return [ + $ont_status, + $ont_port_status, + $ont_mac_addresses + ]; + } + private function getAuthToken() { $token = new mfConfig("adb.import.citycom.auth.token"); if($token && $token->value()) {