diff --git a/Layout/default/Preorder/Index.php b/Layout/default/Preorder/Index.php index e3a4002d2..e912d9909 100644 --- a/Layout/default/Preorder/Index.php +++ b/Layout/default/Preorder/Index.php @@ -512,6 +512,14 @@ $pagination_entity_name = "Vorbestellungen"; + \ No newline at end of file diff --git a/Layout/default/PreorderProduct/Index.php b/Layout/default/PreorderProduct/Index.php index 06bbc571a..fa2d4ee67 100644 --- a/Layout/default/PreorderProduct/Index.php +++ b/Layout/default/PreorderProduct/Index.php @@ -137,7 +137,12 @@ }); function toggleCollapseIndicator(elem) { - var selector = "#" + $(elem).attr("id"); + if(typeof elem === 'object') { + var selector = "#" + $(elem).attr("id"); + } else { + var selector = elem; + } + var itype = $(elem).data("collapse-indicator"); //console.log("selector: " + selector); @@ -183,6 +188,7 @@ if(typeof match[2] !== 'undefined') { let prod_id = match[2]; $("#price-detail-" + netop + "-" + prod_id).collapse('toggle'); + toggleCollapseIndicator("#price-detail-" + netop + "-" + prod_id + "-collapse"); } } diff --git a/Layout/default/PreorderProduct/include/netoperator-prices-usage.php b/Layout/default/PreorderProduct/include/netoperator-prices-usage.php index 361fbaa32..761b64893 100644 --- a/Layout/default/PreorderProduct/include/netoperator-prices-usage.php +++ b/Layout/default/PreorderProduct/include/netoperator-prices-usage.php @@ -154,6 +154,15 @@ +
+
+
+ + +
+
+
+
diff --git a/Layout/default/PreorderProduct/include/prices-setup.php b/Layout/default/PreorderProduct/include/prices-setup.php index 8ed2c69be..2c4287448 100644 --- a/Layout/default/PreorderProduct/include/prices-setup.php +++ b/Layout/default/PreorderProduct/include/prices-setup.php @@ -121,6 +121,15 @@
+
+
+
+ + +
+
+
+
diff --git a/application/Api/v1/AddressdbApicontroller.php b/application/Api/v1/AddressdbApicontroller.php index dbdfccecc..5d1b34f65 100644 --- a/application/Api/v1/AddressdbApicontroller.php +++ b/application/Api/v1/AddressdbApicontroller.php @@ -25,6 +25,7 @@ class AddressdbApicontroller extends mfBaseApicontroller { $this->addRoute("/addressdb/findDistrict", "findDistrict", "GET"); $this->addRoute("/addressdb/findDistrict", "findDistrict", "POST"); $this->addRoute("/addressdb/fullexport", "exportAddresses", "GET"); + $this->addRoute("/addressdb/:oaid/pricing", "getAddressPricing", "GET"); $this->allowMissingOrigin = true; } @@ -884,6 +885,70 @@ class AddressdbApicontroller extends mfBaseApicontroller { return mfResponse::Ok(['addresses' => $addresses]); } + protected function getAddressPricing($oaid) { + if(!$oaid) { + return mfResponse::BadRequest(['message' => "OAID missing"]); + } + + $unit = ADBWohneinheitModel::getFirst(["oaid" => $oaid]); + if($unit) { + $hausnummer = $unit->hausnummer; + } else { + $hausnummer = ADBHausnummerModel::getFirst(["oaid" => $oaid]); + } + + if(!$hausnummer) { + return mfResponse::NotFound(['message' => "Address not found"]); + } + + $network = NetworkModel::getFirst(["adb_netzgebiet_id" => $hausnummer->netzgebiet_id]); + $netowner_id = $network->owner_id; + + $campaign = PreordercampaignModel::getFirst(["network_id" => $network->id]); + $netop = PreordercampaignOperatorModel::getFirst(["isp_id" => $this->me->address_id, "preordercampaign_id" => $campaign->id]); + + if(!$netop) { + $netop = PreordercampaignOperatorModel::getFirst(["operator_id" => $this->me->address_id, "preordercampaign_id" => $campaign->id]); + } + if(!$netop) { + return mfResponse::Unauthorized(); + } + + $netoperator = $netop->operator; + + $prices = []; + $enduser_setup_product_id = false; + foreach(PreorderProduct::getWithTypes() as $product) { + if($product->type == "enduser_setup") { + $enduser_setup_product_id = $product->id; + } + $product->setNetownerId($netowner_id); + $product->setNetoperatorId($netoperator->id); + + $prices[$product->type] = $product->getCampaignPrice($campaign->id); + } + + $prices_return = [ + "oaid" => $oaid, + "enduser_setup_price_net" => (float)$prices["enduser_setup"]->price_setup, + "enduser_setup_price_gross" => (float)$prices["enduser_setup"]->price_setup * 1.2, + "enduser_setup_info" => $prices["enduser_setup"]->description, + "enduser_setup_valid_until" => $prices["enduser_setup"]->end_date, + + "vatrate" => 20, + ]; + + //$paid = $unit->enduser_setup_paid; + if(PreorderBilling::getFirst(["adb_wohneinheit_id" => $unit->id, "product_id" => $enduser_setup_product_id, "invoice_id" => false])) { + $prices_return["enduser_setup_price_net"] = 0; + $prices_return["enduser_setup_price_gross"] = 0; + $prices_return["enduser_setup_info"] = "paid"; + $prices_return["enduser_setup_valid_until"] = null; + } + + return mfResponse::Ok($prices_return); + } + protected function exportAddresses() { //if($this->me->username != 'r.eschner@rmlinfrastruktur.at') { // return mfResponse::Forbidden(); diff --git a/application/Api/v1/Modules/Preorder/Activation.php b/application/Api/v1/Modules/Preorder/Activation.php index a669547bf..5aeee653e 100644 --- a/application/Api/v1/Modules/Preorder/Activation.php +++ b/application/Api/v1/Modules/Preorder/Activation.php @@ -21,6 +21,11 @@ class Activation extends Modules\ApiControllerModule { if($this->me->is("Preorderreadonly")) return \mfResponse::Forbidden(); $code = trim($code); + $activation_date = false; + if(array_key_exists("activation_date", $this->get)) { + $activation_date = trim($this->get['activation_date']); + } + if(!$code) { return \mfResponse::NotFound(["message" => "Preorder not found"]); } @@ -42,15 +47,42 @@ class Activation extends Modules\ApiControllerModule { if($preorder->partner_id != $this->me->address_id) { return \mfResponse::NotFound(["message" => "Preorder not found"]); } - + + + if($activation_date) { + try { + $adate = new \DateTime($activation_date); + $adate->setTimezone(new \DateTimeZone("Europe/Vienna")); + $adate->setTime(2, 0, 0); // set time to 2:00:00 + // activation date cannot be in the future + if($adate > new \DateTime()) { + return \mfResponse::BadRequest(["message" => "Activation date can only be in the past"]); + } + } catch(\Exception $e) { + return \mfResponse::BadRequest(["message" => "Invalid activation_date format"]); + } + } + // set status to 500 if($preorder->status->code < 500) { + if($preorder->status->code < 242) { + return \mfResponse::BadRequest(["message" => "Service cannot be activated, because Construction work is not yet finished"]); + } + $new_status = \PreorderstatusModel::getFirst(["code" => 500]); if(!$new_status) { return \mfResponse::InternalServerError(); } $preorder->status_id = $new_status->id; $preorder->save(); + + if($adate) { + $history = \PreorderHistoryModel::getLastStatusChangeTo($preorder->id, 500); + if($history) { + $history->changed = $adate->getTimestamp(); + $history->save(); + } + } } return \mfResponse::Ok(["message" => "Status successfully updated."]); diff --git a/application/Api/v1/PreorderApicontroller.php b/application/Api/v1/PreorderApicontroller.php index 08dc84c99..07226ec11 100644 --- a/application/Api/v1/PreorderApicontroller.php +++ b/application/Api/v1/PreorderApicontroller.php @@ -856,11 +856,31 @@ class PreorderApicontroller extends mfBaseApicontroller { } if(trim($this->post['orderDate'])) { - $order_date = trim($this->post['orderDate']); + try { + $order_date = new DateTime(trim($this->post['orderDate'])); + $order_date->setTime(4, 0, 0); + $order_date->setTimezone(new DateTimeZone('Europe/Vienna')); + + // cannot be older than 14 days + $now = new DateTime(); + $now->setTime(4, 0, 0); + $now->setTimezone(new DateTimeZone('Europe/Vienna')); + $diff = $now->diff($order_date); + if($diff->days > 14) { + return mfResponse::BadRequest(["message" => "orderDate cannot be older than 14 days"]); + } + $preorder_data['order_date'] = $order_date->getTimestamp(); + } catch(Exception $e) { + $this->log->debug(__METHOD__.": Error parsing orderDate: " . $e->getMessage()); + // ignore + } + + + /*$order_date = trim($this->post['orderDate']); $m = []; if(preg_match('/^(\d\d\d\d)-(\d\d)-(\d\d)$/', $order_date, $m)) { $preorder_data['order_date'] = mktime(4, 0, 0, $m[2], $m[3], $m[1]); - } + }*/ } if($is_additional_order) { diff --git a/application/Preorder/Preorder.php b/application/Preorder/Preorder.php index 69e097ee5..a79e157d8 100644 --- a/application/Preorder/Preorder.php +++ b/application/Preorder/Preorder.php @@ -99,6 +99,20 @@ class Preorder extends mfBaseModel { mfValuecache::singleton()->delete("preorder-save-nesting-level-" . $this->id); } + public function getStatuschangeTo($status_code) { + $status = PreorderstatusModel::getFirst(["code" => $status_code]); + if(!$status) { + return false; + } + + $history = PreorderHistoryModel::getLastStatusChangeTo($this->id, $status_code); + if(!$history) { + return false; + } + + return $history->changed; + } + public function updateRimoWorkorderContact() { $contact_fields = [ "company", @@ -141,7 +155,8 @@ class Preorder extends mfBaseModel { "preorder_id" => $this->id, "key" => $field, "old_value" => $this->_old_data->$field, - "new_value" => $this->data->$field + "new_value" => $this->data->$field, + "changed" => date("U") ]); $history->save(); } diff --git a/application/Preorder/PreorderController.php b/application/Preorder/PreorderController.php index 1def2ffe4..b1c223a2b 100644 --- a/application/Preorder/PreorderController.php +++ b/application/Preorder/PreorderController.php @@ -1064,6 +1064,9 @@ class PreorderController extends mfBaseController { case "saveOrderdate": $return = $this->saveOrderdateApi(); break; + case "saveActivationdate": + $return = $this->saveActivationdateApi(); + break; default: $return = false; } @@ -1097,6 +1100,34 @@ class PreorderController extends mfBaseController { return ["message" => "Orderdate saved successfully", "preorder_id" => $preorder_id, "order_date" => $order_date]; } + private function saveActivationdateApi() { + $preorder_id = $this->request->id; + $activation_date = $this->request->activation_date; + + $preorder = new Preorder($preorder_id); + if(!$preorder->id) { + $this->log->debug(__METHOD__.": preorder ($preorder_id) not found"); + return false; + } + + try { + $activationdate = DateTime::createFromFormat("d.m.Y", $activation_date, new DateTimeZone("Europe/Vienna")); + $activationdate->getTimestamp(); + } catch(Exception $e) { + return false; + } + + $history = PreorderHistoryModel::getLastStatusChangeTo($preorder->id, 500); + if(!$history) { + return false; + } + + $history->changed = $activationdate->getTimestamp(); + $history->save(); + + return ["message" => "Activationdate saved successfully", "preorder_id" => $preorder_id, "activation_date" => $activation_date]; + } + private function addWorkorderRemarkApi() { $preorder_id = $this->request->preorder_id; $workorder_id = $this->request->workorder_id; diff --git a/application/Preorder/PreorderModel.php b/application/Preorder/PreorderModel.php index a2e083eaa..1cebc6490 100644 --- a/application/Preorder/PreorderModel.php +++ b/application/Preorder/PreorderModel.php @@ -658,6 +658,20 @@ class PreorderModel } } + if (array_key_exists("<=status_code", $filter)) { + $status_code = $filter['<=status_code']; + if (is_numeric($status_code)) { + $where .= " AND tt_preorderstatus.code <= $status_code"; + } + } + + if (array_key_exists(">=status_code", $filter)) { + $status_code = $filter['>=status_code']; + if (is_numeric($status_code)) { + $where .= " AND tt_preorderstatus.code >= $status_code"; + } + } + if (array_key_exists("preordercampaign_id", $filter)) { $preordercampaign_id = $filter['preordercampaign_id']; diff --git a/application/PreorderBilling/PreorderBilling.php b/application/PreorderBilling/PreorderBilling.php new file mode 100644 index 000000000..91fdd64af --- /dev/null +++ b/application/PreorderBilling/PreorderBilling.php @@ -0,0 +1,427 @@ +$name == null) { + + if($name == "invoice") { + if(!$this->invoice_id) return null; + $invoice = new PreorderInvoice($this->invoice_id); + if($invoice->id) { + $this->invoice = $invoice; + return $this->invoice; + } + return null; + } + + if($name == "creator") { + $creator = mfValuecache::singleton()->get("Worker-id-".$this->create_by); + if($creator) { + $this->creator = $creator; + return $this->creator; + } + $this->creator = new User($this->create_by); + + if(!$this->creator->id) { + return null; + } + mfValuecache::singleton()->set("Worker-id-".$this->create_by, $this->creator); + return $this->creator; + } + + if($name == "editor") { + $editor = mfValuecache::singleton()->get("Worker-id-".$this->edit_by); + if($editor) { + $this->editor = $editor; + return $this->editor; + } + $this->editor = new User($this->edit_by); + if(!$this->editor->id) { + return null; + } + mfValuecache::singleton()->set("Worker-id-".$this->edit_by, $this->editor); + return $this->editor; + } + + $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; + + } + + /******************************** + * Begin static Model functions + */ + + public static function create(Array $data) { + $model = new PreorderBilling(); + + $table_fields = [ + "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" + ]; + + foreach($data as $field => $value) { + if(in_array($field, $table_fields)) { + $model->$field = $value; + } + } + + $me = new User(); + $me->loadMe(); + + if($model->create_by === null) { + $model->create_by = $me->id; + } + if($model->edit_by === null) { + $model->edit_by = $me->id; + } + + return $model; + } + + public static function getAll() { + $items = []; + + $db = FronkDB::singleton(); + + $res = $db->select("PreorderBilling", "*", "1 = 1 ORDER BY preorder_id"); + if($db->num_rows($res)) { + while($data = $db->fetch_object($res)) { + $items[] = new PreorderBilling($data); + } + } + return $items; + + } + + public static function getFirst($filter) { + $db = FronkDB::singleton(); + + $where = self::getSqlFilter($filter); + $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; + //mfLoghandler::singleton()->debug($sql); + $res = $db->query($sql); + if($db->num_rows($res)) { + $data = $db->fetch_object($res); + $item = new PreorderBilling($data); + if($item->id) { + return $item; + } else { + return null; + } + } + return null; + } + + public static function count($filter) { + $db = FronkDB::singleton(); + + $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); + + $res = $db->query($sql); + if($db->num_rows($res)) { + $data = $db->fetch_object($res); + return $data->cnt; + } + return 0; + } + + public static function search($filter, $limit = false, $order = false) { + //var_dump($filter);exit; + $items = []; + + if(!$order) { + $order = "preorder_id ASC"; + } + + $db = FronkDB::singleton(); + + $where = self::getSqlFilter($filter); + $sql = "SELECT PreorderBilling.* FROM PreorderBilling + LEFT JOIN Preorder ON Preorder.id = PreorderBilling.preorder_id + WHERE $where + ORDER BY $order"; + + if(is_array($limit) && count($limit)) { + if(is_numeric($limit['start']) && is_numeric($limit['count'])) { + $sql .= " LIMIT ".$limit['start'].", ".$limit['count']; + } elseif(is_numeric($limit['count'])) { + $sql .= " LIMIT ".$limit['count']; + } + } + + mfLoghandler::singleton()->debug($sql); + + $res = $db->query($sql); + if($db->num_rows($res)) { + while($data = $db->fetch_object($res)) { + $items[$data->id] = new PreorderBilling($data); + } + } + + return $items; + } + + private static function getSqlFilter($filter) { + $where = "1=1 "; + + if(array_key_exists("invoice_id", $filter)) { + $invoice_id = $filter['invoice_id']; + if($invoice_id === null || $invoice_id === false) { + $where .= " AND (PreorderBilling.invoice_id IS NULL OR PreorderBilling.invoice_id=0)"; + } elseif($invoice_id === true) { + $where .= " AND (PreorderBilling.invoice_id IS NOT NULL AND PreorderBilling.invoice_id > 0)"; + } elseif(is_numeric($invoice_id)) { + $where .= " AND PreorderBilling.invoice_id=$invoice_id"; + } + } + + if(array_key_exists("preorder_id", $filter)) { + $preorder_id = $filter['preorder_id']; + if(is_numeric($preorder_id)) { + $where .= " AND PreorderBilling.preorder_id=$preorder_id"; + } + } + + if(array_key_exists("adb_wohneinheit_id", $filter)) { + $adb_wohneinheit_id = $filter['adb_wohneinheit_id']; + if(is_numeric($adb_wohneinheit_id)) { + $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) { + $where .= " AND PreorderBilling.order_date='$order_date'"; + } + } + + if(array_key_exists("start_date", $filter)) { + $start_date = FronkDB::singleton()->escape($filter['start_date']); + if($start_date) { + $where .= " AND PreorderBilling.start_date='$start_date'"; + } + } + + if(array_key_exists("start_date>", $filter)) { + $start_date = FronkDB::singleton()->escape($filter['start_date>']); + if($start_date) { + $where .= " AND PreorderBilling.start_date > '$start_date'"; + } + } + + if(array_key_exists("start_date<", $filter)) { + $start_date = FronkDB::singleton()->escape($filter['start_date<']); + if($start_date) { + $where .= " AND PreorderBilling.start_date < '$start_date'"; + } + } + + if(array_key_exists("start_date>=", $filter)) { + $start_date = FronkDB::singleton()->escape($filter['start_date>=']); + if($start_date) { + $where .= " AND PreorderBilling.start_date >= '$start_date'"; + } + } + + if(array_key_exists("start_date<=", $filter)) { + $start_date = FronkDB::singleton()->escape($filter['start_date<=']); + if($start_date) { + $where .= " AND PreorderBilling.start_date <= '$start_date'"; + } + } + + if(array_key_exists("owner_id", $filter)) { + $owner_id = $filter['owner_id']; + if(is_numeric($owner_id)) { + $where .= " AND PreorderBilling.owner_id=$owner_id"; + } + } + + if(array_key_exists("billingaddress_id", $filter)) { + $billingaddress_id = $filter['billingaddress_id']; + if(is_numeric($billingaddress_id)) { + $where .= " AND PreorderBilling.billingaddress_id=$billingaddress_id"; + } + } + + 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("product_id", $filter)) { + $product_id = $filter['product_id']; + if(is_numeric($product_id)) { + $where .= " AND PreorderBilling.product_id=$product_id"; + } + } + + if(array_key_exists("product_name", $filter)) { + $product_name = FronkDB::singleton()->escape($filter['product_name']); + if($product_name) { + $where .= " AND product_name like '%$product_name%')"; + } + } + + if(array_key_exists("price<", $filter)) { + $price = $filter['price<']; + if(is_numeric($price)) { + $where .= " AND PreorderBilling.price < $price"; + } + } + if(array_key_exists("price<=", $filter)) { + $price = $filter['price<=']; + if(is_numeric($price)) { + $where .= " AND PreorderBilling.price <= $price"; + } + } + + if(array_key_exists("price>", $filter)) { + $price = $filter['price>']; + if(is_numeric($price)) { + $where .= " AND PreorderBilling.price > $price"; + } + } + if(array_key_exists("price>=", $filter)) { + $price = $filter['price>=']; + if(is_numeric($price)) { + $where .= " AND PreorderBilling.price >= $price"; + } + } + + if(array_key_exists("billing_delivery", $filter)) { + $billing_delivery = FronkDB::singleton()->escape($filter['billing_delivery']); + if($billing_delivery) { + $where .= " AND PreorderBilling.billing_delivery = '$billing_delivery'"; + } + } + + if(array_key_exists("vatgroup_id", $filter)) { + $vatgroup_id = $filter['vatgroup_id']; + if(is_numeric($vatgroup_id)) { + $where .= " AND PreorderBilling.vatgroup_id = $vatgroup_id"; + } + } + + if(array_key_exists("!vatgroup_id", $filter)) { + $vatgroup_id = $filter['!vatgroup_id']; + if(is_numeric($vatgroup_id)) { + $where .= " AND PreorderBilling.vatgroup_id <> $vatgroup_id"; + } + } + + 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']; + } + + //var_dump($filter, $where);exit; + return $where; + } + +} \ No newline at end of file diff --git a/application/PreorderBilling/PreorderBillingController.php b/application/PreorderBilling/PreorderBillingController.php new file mode 100644 index 000000000..d12b34ecb --- /dev/null +++ b/application/PreorderBilling/PreorderBillingController.php @@ -0,0 +1,574 @@ +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 = []; + $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); + + $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() { + $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->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"); + + $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" => 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); + } 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") < "2025-01-01") { + // 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); + } + + $bill_params = [ + "netowner" => new Address($this->me->address_id), + "netoperator" => $netoperator, + "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) { + 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); + //exit; + } + } + + $this->Layout()->setFlash("Billing records erstellt", "success"); + $this->redirect("PreorderBilling"); + + } + + private function billSetup($preorder, $type, $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']; + + $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__.": 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
"; + $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) { + $this->log->debug(__METHOD__.": No status change found for preorder ".$preorder->id." so using creation date"); + $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"), + "end_date" => $status_change_date->format("Y-m-d"), + "billing_delivery" => "email", + "product_id" => $product->id, + "product_info" => "", + "article_number" => $article_number, + "amount" => 1, + "unit" => "Stk.", + "price" => "0", + "price_setup" => $price->price_setup, + "vatrate" => 20, + "billing_period" => 0, + ]; + + if($type == "enduser_setup") { + // Endkunde Setup Gebühr + + 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; + } + + $billing_data["preorderbillingcustomer_id"] = $customer->id; + $billing_data["fibu_account_number"] = $customer->fibu_account_number; + $billing_data["product_name"] = "Bereitstellungsentgelt Glasfaseranschluss"; + $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; + $billing_data["billingaddress_id"] = $netoperator->id; + $billing_data["fibu_account_number"] = $netoperator->attributes['rml-fibu-account']->value; + $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->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; + } + + 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"]); + 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) { + $this->log->debug(__METHOD__.": No status change to 500 found for preorder ".$preorder->id." so using creation date"); + $status_change = $preorder; + } + + $status_change_date = new DateTime("@".$status_change->create); + if($status_change_date->format("Ymd") > $earliest_bill_date->format("Ymd")) { + $earliest_bill_date = $status_change_date; + } + + $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 = []; + + /*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")."
\n"; + //echo "\$earliest_bill_date ".$earliest_bill_date->format("Y-m-d H:i:s")."

\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")."
\n"; + //echo " - \$earliest_bill_date ".$earliest_bill_date->format("Y-m-d H:i:s")."

\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) { + $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"); + + + $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); + } +} \ No newline at end of file diff --git a/application/PreorderBillingCustomer/PreorderBillingCustomer.php b/application/PreorderBillingCustomer/PreorderBillingCustomer.php new file mode 100644 index 000000000..b05aca065 --- /dev/null +++ b/application/PreorderBillingCustomer/PreorderBillingCustomer.php @@ -0,0 +1,288 @@ +loadMe(); + $data["edit_by"] = $me->id; + } + + return $data; + } + + public function createFibuAccountNumber($netowner_id) { + if($this->fibu_account_number) return true; + + // get last FibuAccountNumber + $last_fibu_account_number_row = PreorderBillingCustomer::getLast(["netowner_id" => $netowner_id, "fibu_account_number" => true], "fibu_account_number DESC"); + if($last_fibu_account_number_row) { + $new_num = $last_fibu_account_number_row->fibu_account_number + 1; + } else { + $new_num = 250001; + } + + $this->fibu_account_number = $new_num; + + + } + + public function getProperty($name) { + if($this->$name == null) { + + + + $classname = ucfirst($name); + $idfield = $name."_id"; + $this->$name = mfValuecache::singleton()->getMfObject($classname, $this->$idfield); + if(!$this->$name) { + return null; + } + } + + return $this->$name; + } + + /******************************** + * Begin static Model functions + */ + + public static function create(Array $data) { + $model = new PreorderBillingCustomer(); + + $table_fields = [ + "fibu_account_number", "company", "firstname", "lastname", "street", "zip", "city", "country", "phone", "email", "uid", + "create_by","edit_by","create","edit" + ]; + + foreach($data as $field => $value) { + if(in_array($field, $table_fields)) { + $model->$field = $value; + } + } + + $me = new User(); + $me->loadMe(); + + if($model->create_by === null) { + $model->create_by = $me->id; + } + if($model->edit_by === null) { + $model->edit_by = $me->id; + } + + return $model; + } + + public static function getAll() { + $items = []; + + $db = FronkDB::singleton(); + + $res = $db->select("PreorderBillingCustomer", "*", "1 = 1 ORDER BY id"); + if($db->num_rows($res)) { + while($data = $db->fetch_object($res)) { + $items[] = new PreorderBillingCustomer($data); + } + } + return $items; + + } + + public static function getFirst($filter) { + $db = FronkDB::singleton(); + + $where = self::getSqlFilter($filter); + $sql = "SELECT * FROM PreorderBillingCustomer + WHERE $where + ORDER BY id LIMIT 1"; + //var_dump($sql);exit; + //mfLoghandler::singleton()->debug($sql); + $res = $db->query($sql); + if($db->num_rows($res)) { + $data = $db->fetch_object($res); + $item = new PreorderBillingCustomer($data); + if($item->id) { + return $item; + } else { + return null; + } + } + return null; + } + + public static function getLast($filter, $order = false) { + $db = FronkDB::singleton(); + + if(!$order) { + $order = "id DESC"; + } + + $where = self::getSqlFilter($filter); + $sql = "SELECT * FROM PreorderBillingCustomer + WHERE $where + ORDER BY $order LIMIT 1"; + //var_dump($sql);exit; + $res = $db->query($sql); + if($db->num_rows($res)) { + $data = $db->fetch_object($res); + $item = new PreorderBillingCustomer($data); + if($item->id) { + return $item; + } else { + return null; + } + } + return null; + } + + public static function count($filter) { + $db = FronkDB::singleton(); + + $where = self::getSqlFilter($filter); + $sql = "SELECT COUNT(*) as cnt FROM PreorderBillingCustomer + WHERE $where"; + + //mfLoghandler::singleton()->debug($sql); + + $res = $db->query($sql); + if($db->num_rows($res)) { + $data = $db->fetch_object($res); + return $data->cnt; + } + return 0; + } + + public static function search($filter, $limit = false, $order = false) { + //var_dump($filter);exit; + $items = []; + + if(!$order) { + $order = "id ASC"; + } + + $db = FronkDB::singleton(); + + $where = self::getSqlFilter($filter); + $sql = "SELECT * FROM PreorderBillingCustomer + WHERE $where + ORDER BY $order"; + + if(is_array($limit) && count($limit)) { + if(is_numeric($limit['start']) && is_numeric($limit['count'])) { + $sql .= " LIMIT ".$limit['start'].", ".$limit['count']; + } elseif(is_numeric($limit['count'])) { + $sql .= " LIMIT ".$limit['count']; + } + } + + mfLoghandler::singleton()->debug($sql); + + $res = $db->query($sql); + if($db->num_rows($res)) { + while($data = $db->fetch_object($res)) { + $items[$data->id] = new PreorderBillingCustomer($data); + } + } + + return $items; + } + + private static function getSqlFilter($filter) { + $where = "1=1 "; + + if(array_key_exists("fibu_account_number", $filter)) { + $fibu_account_number = $filter["fibu_account_number"]; + if($fibu_account_number === true) { + $where .= " AND (fibu_account_number IS NOT NULL AND fibu_account_number <> '')"; + } elseif($fibu_account_number === false || $fibu_account_number === null) { + $where .= " AND (fibu_account_number IS NULL OR fibu_account_number = '' || fibu_account_number = '0')"; + } elseif($fibu_account_number) { + $fibu_account_number = FronkDB::singleton()->escape($filter["fibu_account_number"]); + $where .= " AND fibu_account_number='$fibu_account_number'"; + } + } + + if(array_key_exists("company", $filter)) { + $company = FronkDB::singleton()->escape($filter["company"]); + if($company) { + $where .= " AND company='$company'"; + } + } + + if(array_key_exists("firstname", $filter)) { + $firstname = FronkDB::singleton()->escape($filter["firstname"]); + if($firstname) { + $where .= " AND firstname='$firstname'"; + } + } + + if(array_key_exists("lastname", $filter)) { + $lastname = FronkDB::singleton()->escape($filter["lastname"]); + if($lastname) { + $where .= " AND lastname='$lastname'"; + } + } + + if(array_key_exists("street", $filter)) { + $street = FronkDB::singleton()->escape($filter["street"]); + if($street) { + $where .= " AND street='$street'"; + } + } + + if(array_key_exists("zip", $filter)) { + $zip = FronkDB::singleton()->escape($filter["zip"]); + if($zip) { + $where .= " AND zip='$zip'"; + } + } + + if(array_key_exists("city", $filter)) { + $city = FronkDB::singleton()->escape($filter["city"]); + if($city) { + $where .= " AND city='$city'"; + } + } + + if(array_key_exists("country", $filter)) { + $country = FronkDB::singleton()->escape($filter["country"]); + if($country) { + $where .= " AND country='$country'"; + } + } + + if(array_key_exists("phone", $filter)) { + $phone = FronkDB::singleton()->escape($filter["phone"]); + if($phone) { + $where .= " AND phone='$phone'"; + } + } + + if(array_key_exists("email", $filter)) { + $email = FronkDB::singleton()->escape($filter["email"]); + if($email) { + $where .= " AND email='$email'"; + } + } + + if(array_key_exists("uid", $filter)) { + $uid = FronkDB::singleton()->escape($filter["uid"]); + if($uid) { + $where .= " AND uid='$uid'"; + } + } + + + if(array_key_exists("add-where", $filter)) { + $where .= " ".$filter['add-where']; + } + + //var_dump($filter, $where);exit; + return $where; + } + +} \ No newline at end of file diff --git a/application/PreorderHistory/PreorderHistory.php b/application/PreorderHistory/PreorderHistory.php index 2cc9f59dd..61d4066cd 100644 --- a/application/PreorderHistory/PreorderHistory.php +++ b/application/PreorderHistory/PreorderHistory.php @@ -9,6 +9,35 @@ class PreorderHistory extends mfBaseModel { private $old; private $new; + public function afterSave() { + $this->createHistoryEntry(); + } + + protected function createHistoryEntry() { + if(!$this->id) return true; + + $changed = $this->getChangedFields(); + + if($this->key == "status_id" && in_array("changed", $changed) && $this->_old_data->changed) { + try { + $status = new Preorderstatus($this->new_value); + if(!$status->id) return true; + + $this->log->debug(__METHOD__ . ": 'changed' changed from '" . $this->_old_data->changed . "' to '" . $this->data->changed . "'"); + $history = PreorderHistoryModel::create([ + "preorder_id" => $this->preorder_id, + "key" => "status_changed-".$status->code, + "old_value" => $this->_old_data->changed, + "new_value" => $this->data->changed, + "changed" => date("U") + ]); + $history->save(); + } catch(Exception $e) { + $this->log->debug($e->getTraceAsString()); + } + } + } + public function getValue($type = "new", $raw = false) { if($type != "old" && $type != "new") return null; @@ -51,6 +80,16 @@ class PreorderHistory extends mfBaseModel { return "Status Flag ".$psf->code." - ".$psf->name; } } + if(preg_match('/status_changed-(\d+)/', $key, $m)) { + if(array_key_exists(1, $m)) { + $code = $m[1]; + $ps = PreorderstatusModel::getFirst(["code" => $code]); + if($code == 500) { + return "Aktivierungsdatum (Status 500)"; + } + return "Status ".$ps->code." Timestamp"; + } + } return $key; } @@ -69,6 +108,14 @@ class PreorderHistory extends mfBaseModel { } } + if($this->key == "order_date" && $value) { + return date("d.m.Y", $value); + } + + if(preg_match('/^status_changed-/', $this->key)) { + return date("d.m.Y", $value); + } + if(!is_object($value)) { return $value; } @@ -88,6 +135,8 @@ class PreorderHistory extends mfBaseModel { if(get_class($value) == "Preordercampaign") { return $value->name; } + + return ""; } public function getProperty($name) { diff --git a/application/PreorderHistory/PreorderHistoryModel.php b/application/PreorderHistory/PreorderHistoryModel.php index 97575a27d..0552dff68 100644 --- a/application/PreorderHistory/PreorderHistoryModel.php +++ b/application/PreorderHistory/PreorderHistoryModel.php @@ -6,6 +6,7 @@ class PreorderHistoryModel { public $key; public $old_value; public $new_value; + public $changed; public $create_by; public $edit_by; public $create; @@ -37,6 +38,58 @@ class PreorderHistoryModel { return $model; } + + public static function getStatusChange($type = "first", $preorder_id, $status_code) { + $status = PreorderstatusModel::getFirst(["code" => $status_code]); + if(!$status) { + return false; + } + + $status_id = $status->id; + $sql = "SELECT * FROM PreorderHistory WHERE preorder_id = $preorder_id AND `key` = 'status_id' AND new_value = $status_id"; + if($type == "first") { + $sql .= " ORDER BY `create` ASC LIMIT 1"; + } else { + $sql .= " ORDER BY `create` DESC LIMIT 1"; + } + //mfLoghandler::singleton()->debug($sql); + $res = FronkDB::singleton()->query($sql); + if(FronkDB::singleton()->num_rows($res)) { + $data = FronkDB::singleton()->fetch_object($res); + return new PreorderHistory($data); + } + return false; + } + public static function getFirstStatusChangeTo($preorder_id, $status_code) { + return self::getStatusChange("first", $preorder_id, $status_code); + } + + public static function getLastStatusChangeTo($preorder_id, $status_code) { + return self::getStatusChange("last", $preorder_id, $status_code); + } + + public static function getFirstStatusChangeToOrHigher($preorder_id, $status_code) { + foreach(PreorderstatusModel::getAll() as $status) { + if($status->code < $status_code) continue; + + $change = self::getStatusChange("first", $preorder_id, $status_code); + if($change) return $change; + } + + return false; + } + + public static function getLastStatusChangeToOrHigher($preorder_id, $status_code) { + foreach(PreorderstatusModel::getAll() as $status) { + if($status->code < $status_code) continue; + + $change = self::getStatusChange("last", $preorder_id, $status_code); + if($change) return $change; + } + + return false; + } + public static function getFirst($filter = []) { $db = FronkDB::singleton(); diff --git a/application/PreorderProduct/PreorderProduct.php b/application/PreorderProduct/PreorderProduct.php index 432126f5b..a235b7ddf 100644 --- a/application/PreorderProduct/PreorderProduct.php +++ b/application/PreorderProduct/PreorderProduct.php @@ -53,6 +53,29 @@ class PreorderProduct extends mfBaseModel { return $this->today_date; } + public function getDefaultArticlenumber() { + $prices = PreorderProductPrice::search([ + "article_number" => true, + "netowner_id" => $this->filter_netowner_id, + "netoperator_id" => $this->filter_netoperator_id, + "preorderproduct_id" => $this->id + ]); + foreach($prices as $price) { + if($price->article_number) return $price->article_number; + } + + $prices = PreorderProductPrice::search([ + "article_number" => true, + "netowner_id" => $this->filter_netowner_id, + "preorderproduct_id" => $this->id + ]); + foreach($prices as $price) { + if($price->article_number) return $price->article_number; + } + + return ""; + } + public function getCampaignFirstPrice($campaign_id, $date = null) { if(!$date) $date = date("Y-m-d"); @@ -90,7 +113,7 @@ class PreorderProduct extends mfBaseModel { return $price; //return $this->current_campaign_regular_price; } else { - $this->log->debug(__METHOD__.": TRY FIRST PRICE"); + //$this->log->debug(__METHOD__.": TRY FIRST PRICE"); return $this->getCampaignFirstPrice($campaign_id, $date); } return null; @@ -130,23 +153,23 @@ class PreorderProduct extends mfBaseModel { $this->log->debug("=== in ".__METHOD__); if(!$date) $date = date("Y-m-d"); - $this->log->debug(__METHOD__.": TRY CURRENT PRICE"); + //$this->log->debug(__METHOD__.": TRY CURRENT PRICE"); $price = $this->getCampaignCurrentPrice($campaign_id, $date); if(!$price) { - $this->log->debug(__METHOD__.": TRY CURRENT REGULAR PRICE"); + //$this->log->debug(__METHOD__.": TRY CURRENT REGULAR PRICE"); $price = $this->getCampaignCurrentRegularPrice($campaign_id, $date); } if(!$price) { - $this->log->debug(__METHOD__.": TRY FIRST PRICE"); + //$this->log->debug(__METHOD__.": TRY FIRST PRICE"); $price = $this->getCampaignFirstPrice($campaign_id, $date); } if(!$price) { - $this->log->debug(__METHOD__.": No Campaign price found. GET NETOP CURRENT PRICE"); + //$this->log->debug(__METHOD__.": No Campaign price found. GET NETOP CURRENT PRICE"); $price = $this->getPrice(); } if($price) { - $this->log->debug("=== done in ".__METHOD__); + //$this->log->debug("=== done in ".__METHOD__); return $price; } return null; @@ -191,7 +214,7 @@ class PreorderProduct extends mfBaseModel { ], "start_date DESC, `create` DESC"); if(!$price && $allowCascading) { - $this->log->debug(__METHOD__.": Cascading to getFirstPrice()"); + //$this->log->debug(__METHOD__.": Cascading to getFirstPrice()"); return $this->getFirstPrice($date, true); } return $price; @@ -230,7 +253,7 @@ class PreorderProduct extends mfBaseModel { } if(!$price && $allowCascading) { - $this->log->debug(__METHOD__.": Cascading to getCurrentRegularPrice()"); + //$this->log->debug(__METHOD__.": Cascading to getCurrentRegularPrice()"); return $this->getCurrentRegularPrice($date, true); } return $price; @@ -239,23 +262,23 @@ class PreorderProduct extends mfBaseModel { public function getPrice($date = null) { if(!$date) $date = date("Y-m-d"); - $this->log->debug("=== in ".__METHOD__); - $this->log->debug(__METHOD__.": TRY CURRENT PRICE"); + //$this->log->debug("=== in ".__METHOD__); + //$this->log->debug(__METHOD__.": TRY CURRENT PRICE"); $price = $this->getCurrentPrice($date); if(!$price) { - $this->log->debug(__METHOD__.": TRY CURRENT REGULAR PRICE"); + //$this->log->debug(__METHOD__.": TRY CURRENT REGULAR PRICE"); $price = $this->getCurrentRegularPrice($date); } if(!$price) { - $this->log->debug(__METHOD__.": TRY FIRST PRICE"); + //$this->log->debug(__METHOD__.": TRY FIRST PRICE"); $price = $this->getFirstPrice($date); } if(!$price) { - $this->log->error(__METHOD__.": Unable to find price! netowner_id: ".$this->filter_netowner_id, " netoperator_id: ".$this->filter_netoperator_id." date: $date"); + //$this->log->error(__METHOD__.": Unable to find price! netowner_id: ".$this->filter_netowner_id, " netoperator_id: ".$this->filter_netoperator_id." date: $date"); return null; } - $this->log->debug("=== done in ".__METHOD__); + //$this->log->debug("=== done in ".__METHOD__); return $price; } @@ -608,7 +631,7 @@ class PreorderProduct extends mfBaseModel { } } - mfLoghandler::singleton()->debug($sql); + //mfLoghandler::singleton()->debug($sql); $res = $db->query($sql); if($db->num_rows($res)) { @@ -623,101 +646,11 @@ class PreorderProduct extends mfBaseModel { private static function getSqlFilter($filter) { $where = "1=1 "; - if(array_key_exists("project_id", $filter)) { - $project_id = $filter['project_id']; - if(is_numeric($project_id)) { - $where .= " AND PreorderProduct.preorderProductproject_id=$project_id"; - } - } - if(array_key_exists("preorderProductproject_id", $filter)) { - $preorderProductproject_id = $filter['preorderProductproject_id']; - if(is_numeric($preorderProductproject_id)) { - $where .= " AND PreorderProduct.preorderProductproject_id=$preorderProductproject_id"; - } - } - - if(array_key_exists("adb_wohneinheit_id", $filter)) { - $adb_wohneinheit_id = $filter['adb_wohneinheit_id']; - if(is_numeric($adb_wohneinheit_id)) { - $where .= " AND PreorderProduct.adb_wohneinheit_id=$adb_wohneinheit_id"; - } - } - - if(array_key_exists("termination_id", $filter)) { - $termination_id = $filter['termination_id']; - if(is_numeric($termination_id)) { - $where .= " AND PreorderProduct.termination_id=$termination_id"; - } - } - - if(array_key_exists("object_type", $filter)) { - $object_type = FronkDB::singleton()->escape($filter["object_type"]); - if($object_type) { - $where .= " AND object_type='$object_type'"; - } - } - - if(array_key_exists("ez", $filter)) { - $ez = FronkDB::singleton()->escape($filter["ez"]); - if($ez) { - $where .= " AND ez='$ez'"; - } - } - - if(array_key_exists("status", $filter)) { - $status = FronkDB::singleton()->escape($filter["status"]); - if($status) { - $where .= " AND status='$status'"; - } - } - - if(array_key_exists("result", $filter)) { - $result = FronkDB::singleton()->escape($filter["result"]); - if($result) { - $where .= " AND result='$result'"; - } - } - - if(array_key_exists("owner_name", $filter)) { - $owner_name = FronkDB::singleton()->escape($filter["owner_name"]); - if($owner_name) { - $where .= " AND owner_name like '%$owner_name%'"; - } - } - - if(array_key_exists("owner_street", $filter)) { - $owner_street = FronkDB::singleton()->escape($filter["owner_street"]); - if($owner_street) { - $where .= " AND owner_street like '%$owner_street%'"; - } - } - - if(array_key_exists("owner_zip", $filter)) { - $owner_zip = FronkDB::singleton()->escape($filter["owner_zip"]); - if($owner_zip) { - $where .= " AND owner_zip like '%$owner_zip%'"; - } - } - - if(array_key_exists("owner_city", $filter)) { - $owner_city = FronkDB::singleton()->escape($filter["owner_city"]); - if($owner_city) { - $where .= " AND owner_city like '%$owner_city%'"; - } - } - - if(array_key_exists("owner_country", $filter)) { - $owner_country = FronkDB::singleton()->escape($filter["owner_country"]); - if($owner_country) { - $where .= " AND owner_country like '%$owner_country%'"; - } - } - - if(array_key_exists("network", $filter)) { - $network = FronkDB::singleton()->escape($filter["network"]); - if($network) { - $where .= " AND view_hausnummer.netzgebiet_id=$network"; + if(array_key_exists("type", $filter)) { + $type = FronkDB::singleton()->escape($filter["type"]); + if($type) { + $where .= " AND type='$type'"; } } diff --git a/application/PreorderProduct/PreorderProductController.php b/application/PreorderProduct/PreorderProductController.php index b91695625..f30037f22 100644 --- a/application/PreorderProduct/PreorderProductController.php +++ b/application/PreorderProduct/PreorderProductController.php @@ -9,7 +9,7 @@ class PreorderProductController extends mfBaseController { $this->me = $me; $this->layout()->set("me",$me); - if(!$me->is(["Admin", "netowner", "salespartner"]) && !$me->can("Preorder")) { + if(!$me->can(["preorderpricing", "preorderpricingReadonly", "preorderbilling", "preorderbillingReadonly"])) { $this->redirect("Dashboard"); } } @@ -17,7 +17,7 @@ class PreorderProductController extends mfBaseController { protected function indexAction() { $this->layout()->setTemplate("PreorderProduct/Index"); - $netowner_id = 4807; // $this->me->address_id; + $netowner_id = $this->me->address_id; // 4807 == rml $netowner = new Address($netowner_id); $products = PreorderProduct::getWithTypes($netowner_id); @@ -62,7 +62,7 @@ class PreorderProductController extends mfBaseController { $r = $this->request; //var_dump($r->get());exit; - $netowner_id = 4807; // $this->me->address_id; + $netowner_id = $this->me->address_id; // 4807 == rml foreach($r->netoperators as $netoperator_id => $product_data) { $netoperator = new Address($netoperator_id); @@ -83,6 +83,7 @@ class PreorderProductController extends mfBaseController { "netowner_id" => $netowner_id, "preorderproduct_id" => $product->id, "netoperator_id" => $netoperator_id, + "article_number" => $price_data["article_number"], ]); if($price_data["description"]) $price->description = trim($price_data["description"]); @@ -127,7 +128,9 @@ class PreorderProductController extends mfBaseController { if(array_key_exists("marketshareprice", $price_data) && is_array($price_data["marketshareprice"])) { foreach($price_data["marketshareprice"] as $msbracket => $msprice) { if(!is_numeric($msbracket)) continue; - if(!$msbracket) continue; // dont save 0 + if(!$msbracket) continue; // dont save bracket 0 - 15% + + if(empty(trim($msprice["inet"])) && empty(trim($msprice["inet_tv"])) && empty(trim($msprice["catv"])) && empty(trim($msprice["passive"]))) continue; $msp = PreorderProductMarketshareDiscount::create([ "preorderproductprice_id" => $price->id, diff --git a/application/PreorderProductPrice/PreorderProductPrice.php b/application/PreorderProductPrice/PreorderProductPrice.php index a7e1a0e4c..d41609483 100644 --- a/application/PreorderProductPrice/PreorderProductPrice.php +++ b/application/PreorderProductPrice/PreorderProductPrice.php @@ -117,7 +117,7 @@ class PreorderProductPrice extends mfBaseModel { $model = new PreorderProductPrice(); $table_fields = [ - "preorderproduct_id", "netowner_id", "netoperator_id", "preordercampaign_id", "description", + "preorderproduct_id", "netowner_id", "netoperator_id", "article_number", "description", "start_date", "end_date", "price_inet", "price_inet_tv", "price_catv", "price_passive", "billing_delay", "billing_period", "contract_term", "description", "note", "create_by","edit_by","create","edit" @@ -235,7 +235,7 @@ class PreorderProductPrice extends mfBaseModel { } } - mfLoghandler::singleton()->debug($sql); + //mfLoghandler::singleton()->debug($sql); $res = $db->query($sql); if($db->num_rows($res)) { @@ -291,7 +291,21 @@ class PreorderProductPrice extends mfBaseModel { } } - + if(array_key_exists("article_number", $filter)) { + $article_number = $filter['article_number']; + if($article_number === null || $article_number === false) { + $where .= " AND (article_number IS NULL OR article_number = '')"; + } elseif($article_number === true) { + $where .= " AND (article_number IS NOT NULL AND article_number <> '')"; + } elseif(is_numeric($article_number)) { + $article_number = FronkDB::singleton()->escape($filter['article_number']); + $where .= " AND article_number='$article_number'"; + } + } + + + + if(array_key_exists("start_date", $filter)) { $start_date = $filter["start_date"]; if($start_date === null || $start_date === false) { diff --git a/application/PreordercampaignOperator/PreordercampaignOperator.php b/application/PreordercampaignOperator/PreordercampaignOperator.php index ba1c58344..8a8cbcc47 100644 --- a/application/PreordercampaignOperator/PreordercampaignOperator.php +++ b/application/PreordercampaignOperator/PreordercampaignOperator.php @@ -40,8 +40,8 @@ class PreordercampaignOperator extends mfBaseModel } if($name == "operator") { - $operator = mfValuecache::singleton()->getMfObject("Address", $this->operator_id); - if(!$operator) { + $operator = new Address($this->operator_id); + if(!$operator->id) { return null; } diff --git a/application/PreordercampaignOperator/PreordercampaignOperatorModel.php b/application/PreordercampaignOperator/PreordercampaignOperatorModel.php index 68056e83f..e2e110dd0 100644 --- a/application/PreordercampaignOperator/PreordercampaignOperatorModel.php +++ b/application/PreordercampaignOperator/PreordercampaignOperatorModel.php @@ -52,8 +52,13 @@ class PreordercampaignOperatorModel { $db = FronkDB::singleton(); $where = self::getSqlFilter($filter); - mfLoghandler::singleton()->debug($where); - $res = $db->select("PreordercampaignOperator", "*", "$where ORDER BY id"); + $sql = "SELECT PreordercampaignOperator.* FROM PreordercampaignOperator + LEFT JOIN PreordercampaignOperatorIsp ON (PreordercampaignOperator.id = PreordercampaignOperatorIsp.campaignoperator_id) + WHERE $where + ORDER BY id + LIMIT 1"; + //mfLoghandler::singleton()->debug($sql); + $res = $db->query($sql); if($db->num_rows($res)) { $data = $db->fetch_object($res); $item = new PreordercampaignOperator($data); @@ -66,32 +71,14 @@ class PreordercampaignOperatorModel { return null; } - public static function getFirstOaid($oaid) { - $db = FronkDB::singleton(); - - if(!$oaid) return null; - - $where = self::getSqlFilter(["oaid" => $oaid]); - //mfLoghandler::singleton()->debug($where); - $res = $db->select("PreordercampaignOperator", "*", "$where ORDER BY id"); - if($db->num_rows($res)) { - $data = $db->fetch_object($res); - $item = new PreordercampaignOperator($data); - if($item->id) { - return $item; - } else { - return null; - } - } - return null; - } public static function count($filter) { $db = FronkDB::singleton(); $where = self::getSqlFilter($filter); $sql = "SELECT COUNT(*) as cnt FROM PreordercampaignOperator - WHERE $where + LEFT JOIN PreordercampaignOperatorIsp ON (PreordercampaignOperator.id = PreordercampaignOperatorIsp.campaignoperator_id) + WHERE $where "; $res = $db->query($sql); @@ -107,9 +94,10 @@ class PreordercampaignOperatorModel { $db = FronkDB::singleton(); $where = self::getSqlFilter($filter); - $sql = "SELECT * FROM PreordercampaignOperator - WHERE $where - ORDER BY id"; + $sql = "SELECT PreordercampaignOperator.* FROM PreordercampaignOperator + LEFT JOIN PreordercampaignOperatorIsp ON (PreordercampaignOperator.id = PreordercampaignOperatorIsp.campaignoperator_id) + WHERE $where + ORDER BY id"; if(is_array($limit) && count($limit)) { if(is_numeric($limit['start']) && is_numeric($limit['count'])) { @@ -142,14 +130,21 @@ class PreordercampaignOperatorModel { if(array_key_exists("preordercampaign_id", $filter)) { $preordercampaign_id = $filter['preordercampaign_id']; if(is_numeric($preordercampaign_id)) { - $where .= " AND preordercampaign_id = $preordercampaign_id"; + $where .= " AND PreordercampaignOperator.preordercampaign_id = $preordercampaign_id"; } } if(array_key_exists("operator_id", $filter)) { $operator_id = $filter['operator_id']; if(is_numeric($operator_id)) { - $where .= " AND operator_id = $operator_id"; + $where .= " AND PreordercampaignOperator.operator_id = $operator_id"; + } + } + + if(array_key_exists("isp_id", $filter)) { + $isp_id = $filter['isp_id']; + if(is_numeric($isp_id)) { + $where .= " AND PreordercampaignOperatorIsp.isp_id = $isp_id"; } } diff --git a/application/PreordercampaignOperatorIsp/PreordercampaignOperatorIspModel.php b/application/PreordercampaignOperatorIsp/PreordercampaignOperatorIspModel.php index 4220f390d..30805400a 100644 --- a/application/PreordercampaignOperatorIsp/PreordercampaignOperatorIspModel.php +++ b/application/PreordercampaignOperatorIsp/PreordercampaignOperatorIspModel.php @@ -52,28 +52,13 @@ class PreordercampaignOperatorIspModel { $db = FronkDB::singleton(); $where = self::getSqlFilter($filter); + $sql = "SELECT PreordercampaignOperatorIsp.* FROM PreordercampaignOperatorIsp + LEFT JOIN PreordercampaignOperator ON (PreordercampaignOperatorIsp.campaignoperator_id = PreordercampaignOperator.id) + WHERE $where + ORDER BY id + LIMIT 1"; mfLoghandler::singleton()->debug($where); - $res = $db->select("PreordercampaignOperatorIsp", "*", "$where ORDER BY id"); - if($db->num_rows($res)) { - $data = $db->fetch_object($res); - $item = new PreordercampaignOperatorIsp($data); - if($item->id) { - return $item; - } else { - return null; - } - } - return null; - } - - public static function getFirstOaid($oaid) { - $db = FronkDB::singleton(); - - if(!$oaid) return null; - - $where = self::getSqlFilter(["oaid" => $oaid]); - //mfLoghandler::singleton()->debug($where); - $res = $db->select("PreordercampaignOperatorIsp", "*", "$where ORDER BY id"); + $res = $db->query($sql); if($db->num_rows($res)) { $data = $db->fetch_object($res); $item = new PreordercampaignOperatorIsp($data); @@ -90,8 +75,9 @@ class PreordercampaignOperatorIspModel { $db = FronkDB::singleton(); $where = self::getSqlFilter($filter); - $sql = "SELECT COUNT(*) as cnt FROM PreordercampaignOperatorIsp - WHERE $where + $sql = "SELECT COUNT(PreordercampaignOperatorIsp.*) as cnt FROM PreordercampaignOperatorIsp + LEFT JOIN PreordercampaignOperator ON (PreordercampaignOperatorIsp.campaignoperator_id = PreordercampaignOperator.id) + WHERE $where "; $res = $db->query($sql); @@ -107,9 +93,10 @@ class PreordercampaignOperatorIspModel { $db = FronkDB::singleton(); $where = self::getSqlFilter($filter); - $sql = "SELECT * FROM PreordercampaignOperatorIsp - WHERE $where - ORDER BY id"; + $sql = "SELECT PreordercampaignOperatorIsp.* FROM PreordercampaignOperatorIsp + LEFT JOIN PreordercampaignOperator ON (PreordercampaignOperatorIsp.campaignoperator_id = PreordercampaignOperator.id) + WHERE $where + ORDER BY id"; if(is_array($limit) && count($limit)) { if(is_numeric($limit['start']) && is_numeric($limit['count'])) { @@ -153,6 +140,14 @@ class PreordercampaignOperatorIspModel { } } + if(array_key_exists("preordercampaign_id", $filter)) { + $preordercampaign_id = $filter['preordercampaign_id']; + if(is_numeric($preordercampaign_id)) { + $where .= " AND preordercampaign_id = $preordercampaign_id"; + } + } + + //var_dump($filter, $where);exit; return $where; } diff --git a/db/migrations/20250311131722_create_preorder_billing.php b/db/migrations/20250311131722_create_preorder_billing.php new file mode 100644 index 000000000..faab3a963 --- /dev/null +++ b/db/migrations/20250311131722_create_preorder_billing.php @@ -0,0 +1,65 @@ +getEnvironment() == "thetool") { + $billing = $this->table('PreorderBilling'); + $billing->addColumn("invoice_id", "integer", ["null" => true]); + $billing->addColumn("preorder_id", "integer", ["null" => false]); + $billing->addColumn("order_date", "date", ["null" => false]); + $billing->addColumn("start_date", "date", ["null" => false]); + $billing->addColumn("end_date", "date", ["null" => false]); + $billing->addColumn("owner_id", "integer", ["null" => false]); + $billing->addColumn("billingaddress_id", "integer", ["null" => false]); + $billing->addColumn("fibu_account_number", "integer", ["null" => false]); + $billing->addColumn("company", "string", ["null" => true, "default" => null, "length" => 1024]); + $billing->addColumn("firstname", "string", ["null" => true, "default" => null, "length" => 1024]); + $billing->addColumn("lastname", "string", ["null" => true, "default" => null, "length" => 1024]); + $billing->addColumn("street", "string", ["null" => false, "length" => 1024]); + $billing->addColumn("zip", "string", ["null" => false, "length" => 1024]); + $billing->addColumn("city", "string", ["null" => false, "length" => 1024]); + $billing->addColumn("country", "string", ["null" => true, "default" => null, "length" => 1024]); + $billing->addColumn("email", "string", ["null" => true, "default" => null, "length" => 1024]); + $billing->addColumn("uid", "string", ["null" => true, "default" => null, "length" => 1024]); + $billing->addColumn("billing_delivery", "enum", ["null" => false, "values" => "email,paper"]); + $billing->addColumn("product_id", "integer", ["null" => false]); + $billing->addColumn("product_name", "string", ["null" => false, "length" => 255]); + $billing->addColumn("product_info", "text", ["null" => true, "default" => null]); + $billing->addColumn("article_number", "string", ["null" => false, "length" => 32]); + $billing->addColumn("amount", "decimal", ["null" => false, "precision" => 9, "scale" => 6]); + $billing->addColumn("unit", "string", ["null" => false, "length" => 64]); + $billing->addColumn("price", "decimal", ["null" => false, "precision" => 14, "scale" => 4]); + $billing->addColumn("price_setup", "decimal", ["null" => false, "default" => 0, "precision" => 14, "scale" => 4]); + $billing->addColumn("vatrate", "decimal", ["null" => false, "precision" => 14, "scale" => 4]); + $billing->addColumn("billing_period", "integer", ["null" => false, "default" => 0]); + $billing->addColumn("create_by", "integer", ["null" => false]); + $billing->addColumn("edit_by", "integer", ["null" => false]); + $billing->addColumn("create", "integer", ["null" => false]); + $billing->addColumn("edit", "integer", ["null" => false]); + $billing->create(); + + + + } + + if($this->getEnvironment() == "addressdb") { + + } + } + + public function down(): void + { + if($this->getEnvironment() == "thetool") { + $this->table("PreorderBilling")->drop()->save(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } +} diff --git a/db/migrations/20250312124757_preorder_product_price_add_articlenumber.php b/db/migrations/20250312124757_preorder_product_price_add_articlenumber.php new file mode 100644 index 000000000..ef1629eb7 --- /dev/null +++ b/db/migrations/20250312124757_preorder_product_price_add_articlenumber.php @@ -0,0 +1,33 @@ +getEnvironment() == "thetool") { + $table = $this->table("PreorderProductPrice"); + $table->addColumn("article_number", "string", ["limit" => 255, "null" => true, "after" => "netoperator_id"]); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } + + public function down(): void + { + if($this->getEnvironment() == "thetool") { + $table = $this->table("PreorderProductPrice"); + $table->removeColumn("article_number"); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } +} diff --git a/db/migrations/20250312143819_create_preorder_billing_customer.php b/db/migrations/20250312143819_create_preorder_billing_customer.php new file mode 100644 index 000000000..3bc0c6166 --- /dev/null +++ b/db/migrations/20250312143819_create_preorder_billing_customer.php @@ -0,0 +1,46 @@ +getEnvironment() == "thetool") { + $table = $this->table('PreorderBillingCustomer'); + $table->addColumn("netowner_id", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("fibu_account_number", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("company", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("firstname", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("lastname", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("street", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("zip", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("city", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("country", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("phone", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("email", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("uid", "string", ["limit" => 255, "null" => true, "default" => null]); + $table->addColumn("create_by", "integer", ["null" => false]); + $table->addColumn("edit_by", "integer", ["null" => false]); + $table->addColumn("create", "integer", ["null" => false]); + $table->addColumn("edit", "integer", ["null" => false]); + $table->create(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } + + public function down(): void + { + if($this->getEnvironment() == "thetool") { + $this->table('PreorderBillingCustomer')->drop()->save(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } +} diff --git a/db/migrations/20250312152751_preorder_billing_add_customer_id.php b/db/migrations/20250312152751_preorder_billing_add_customer_id.php new file mode 100644 index 000000000..a81d0fc05 --- /dev/null +++ b/db/migrations/20250312152751_preorder_billing_add_customer_id.php @@ -0,0 +1,35 @@ +getEnvironment() == "thetool") { + $table = $this->table('PreorderBilling'); + $table->addColumn("preorderbillingcustomer_id", "integer", ["null" => true, "default" => null, "after" => "end_date"]); + $table->changeColumn("owner_id", "integer", ["null" => true, "default" => null]); + $table->changeColumn("billingaddress_id", "integer", ["null" => true, "default" => null]); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } + + public function down(): void + { + if($this->getEnvironment() == "thetool") { + $table = $this->table('PreorderBilling'); + $table->removeColumn("preorderbillingcustomer_id"); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } +} diff --git a/db/migrations/20250313135536_preorder_billing_add_adb_hausnummer_id.php b/db/migrations/20250313135536_preorder_billing_add_adb_hausnummer_id.php new file mode 100644 index 000000000..c7d98ce51 --- /dev/null +++ b/db/migrations/20250313135536_preorder_billing_add_adb_hausnummer_id.php @@ -0,0 +1,33 @@ +getEnvironment() == "thetool") { + $table = $this->table("PreorderBilling"); + $table->addColumn("adb_wohneinheit_id", "integer", ["null" => false, "after" => "preorder_id"]); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } + + public function down(): void + { + if($this->getEnvironment() == "thetool") { + $table = $this->table("PreorderBilling"); + $table->removeColumn("adb_wohneinheit_id"); + $table->update(); + } + + if($this->getEnvironment() == "addressdb") { + + } + } +} diff --git a/db/migrations/20250317131349_preorder_billing_add_oaid.php b/db/migrations/20250317131349_preorder_billing_add_oaid.php new file mode 100644 index 000000000..701ffd96a --- /dev/null +++ b/db/migrations/20250317131349_preorder_billing_add_oaid.php @@ -0,0 +1,33 @@ +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") { + + } + } +} diff --git a/db/migrations/20250317133633_preorder_history_add_changed.php b/db/migrations/20250317133633_preorder_history_add_changed.php new file mode 100644 index 000000000..33c034741 --- /dev/null +++ b/db/migrations/20250317133633_preorder_history_add_changed.php @@ -0,0 +1,38 @@ +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") { + + } + } +} diff --git a/public/docs/preorder-api.yaml b/public/docs/preorder-api.yaml index a9f5e2772..d60fa89fe 100644 --- a/public/docs/preorder-api.yaml +++ b/public/docs/preorder-api.yaml @@ -234,6 +234,69 @@ paths: Parameter missing or malformed '401': description: Unauthorized + /addressdb/{oaid}/pricing: + get: + tags: + - addressdb + summary: Liefert Endkundenpreise + description: Liefert Endkundenpreise für die angegebene Adresse + operationId: getAddressPricing + parameters: + - name: oaid + description: "**OAID** der Wohneinheit; Wie in `searchAddress` oder `findAddress` zurückgegeben. Preise sind `0`, wenn Herstellungsentgelt bereits bezahlt wurde." + in: path + schema: + type: string + required: true + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + properties: + status: + type: string + description: Status string + example: OK + result: + type: object + properties: + oaid: + type: string + description: OAID der Wohneinheit + example: "AT-9999-abcdef01" + enduser_setup_price_net: + type: number + description: Herstellungsentgelt für Endkunde Netto + example: 1250 + enduser_setup_price_gross: + type: number + description: Herstellungsentgelt für Endkunde Brutto + example: 1500 + enduser_setup_info: + type: string + description: Zusätzliche Information zum Preis + example: Rabattaktion in Gemeinde + nullable: true + enduser_setup_valid_until: + type: string + format: date-time + description: Gültigkeitsdatum des Herstellungsentgelts, sofern in Aktionszeitraum, sonst `null` + example: "2025-05-31" + nullable: true + vatrate: + type: number + description: "Mehrwertsteuersatz in %" + example: 20 + '400': + description: | + Bad Request + + Parameter missing or malformed + '401': + description: Unauthorized /addressdb/findStreet: get: tags: @@ -831,8 +894,8 @@ paths: tags: - preorder summary: Bestellung auf Status 500 - Fertiggestellt setzen - description: Setzt Status der Bestellung auf 500 - Fertiggestellt. Wird gesetzt, wenn beim Kunden alle Installationsarbeiten abgeschlossen sind und der Service aktiv ist. - operationId: setInhouseIntallationFinished + description: Setzt Status der Bestellung auf 500 - Fertiggestellt. Wird gesetzt, wenn beim Kunden alle Installationsarbeiten abgeschlossen sind und der Service aktiv ist. Optional mit Aktivierungsdateum + operationId: setInhouseIntallationFinishedWithActivationDate parameters: - name: id in: path @@ -840,6 +903,13 @@ paths: required: true schema: type: string + - name: activation_date + in: query + description: (Optional) Tatsächliches Aktivierungsdatum bei nachträglicher Aktivmeldung. Muss in der Vergangenheit liegen. ISO 8601 Format + required: false + schema: + type: string + format: date-time responses: '200': description: Successful operation @@ -1262,7 +1332,7 @@ components: orderDate: type: string format: date - description: Bestell- oder Vertragsdatum ISO 8601 Format + description: Bestell- oder Vertragsdatum ISO 8601 Format. Darf nicht älter als 14 Tage sein example: "2023-02-01" preorderType: type: string diff --git a/scripts/rml-billing/test.php b/scripts/rml-billing/test.php new file mode 100644 index 000000000..1ca91f95d --- /dev/null +++ b/scripts/rml-billing/test.php @@ -0,0 +1,504 @@ +#!/usr/bin/php +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"; + } +} \ No newline at end of file