From d8b3002cfa11df1a5ec2f6e34ad27c3f2f61ecf2 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Tue, 23 Jul 2024 13:03:45 +0200 Subject: [PATCH 1/5] WIP 2024-07-22 --- Layout/default/Contract/ProductchangeForm.php | 6 +- Layout/default/Contract/View.php | 2 +- Layout/default/Order/Index.php | 3 +- Layout/default/Order/Productchange.php | 78 +++++++++++++++++++ application/Contract/trigger/Finished.php | 7 +- application/Order/OrderController.php | 26 +++---- application/Order/OrderModel.php | 10 ++- 7 files changed, 107 insertions(+), 25 deletions(-) create mode 100644 Layout/default/Order/Productchange.php diff --git a/Layout/default/Contract/ProductchangeForm.php b/Layout/default/Contract/ProductchangeForm.php index d1ef26abc..c7132826b 100644 --- a/Layout/default/Contract/ProductchangeForm.php +++ b/Layout/default/Contract/ProductchangeForm.php @@ -31,7 +31,7 @@ -
+

product_name?> (id?>)

@@ -77,7 +77,7 @@
-
+

Neuer Contract

@@ -309,7 +309,7 @@
- +
diff --git a/Layout/default/Contract/View.php b/Layout/default/Contract/View.php index 357065e4f..a32bf419b 100644 --- a/Layout/default/Contract/View.php +++ b/Layout/default/Contract/View.php @@ -231,7 +231,7 @@ $contract->id])?>"> $contract->id])?>"> - + finish_date): ?> $contract->id])?>" onclick="if(!confirm('Jetzt fertigstellen und in Verrechnung geben?')) return false"> diff --git a/Layout/default/Order/Index.php b/Layout/default/Order/Index.php index 9f947a7d5..ad50c05d8 100644 --- a/Layout/default/Order/Index.php +++ b/Layout/default/Order/Index.php @@ -142,7 +142,8 @@ diff --git a/Layout/default/Order/Productchange.php b/Layout/default/Order/Productchange.php new file mode 100644 index 000000000..ce0b820f8 --- /dev/null +++ b/Layout/default/Order/Productchange.php @@ -0,0 +1,78 @@ + + + + +
+
+
+
+ +
+

Bestellungen

+
+
+
+ + +
+
+ +
+
+

Produktwechsel

+ +
+
+
+ +
+
+ + +
+ +
+

Vertragsinhaber auswählen

+ + + +
+
+
+
+
+
+ +
+
+
+ +
+
+ + + + + diff --git a/application/Contract/trigger/Finished.php b/application/Contract/trigger/Finished.php index bc81bc6ce..7c257414a 100644 --- a/application/Contract/trigger/Finished.php +++ b/application/Contract/trigger/Finished.php @@ -48,6 +48,7 @@ class ContractTrigger_Finished { $now->setTime(2,0,0); $cancel_date = clone($now); + $cancel_date->modify("-1 day"); $cancel_date->setTime(23,59,59); $origin = $link->origin; @@ -74,7 +75,7 @@ class ContractTrigger_Finished { // verlinkten Contract kündigen (wenn nicht schon gekündigt) if ($old_link->change_action == "cancel" && !$old_link->origin->cancel_date) { $old_link->origin->update([ - 'cancel_date' => $now->getTimestamp(), + 'cancel_date' => $cancel_date->getTimestamp(), 'cancel_date_by' => $this->me->id, 'edit_by' => $this->me->id ]); @@ -100,7 +101,7 @@ class ContractTrigger_Finished { // verlinkten Contract kündigen (wenn nicht schon gekündigt) if ($old_link->change_action == "cancel" && !$old_link->contract->cancel_date) { $old_link->contract->update([ - 'cancel_date' => $now->getTimestamp(), + 'cancel_date' => $cancel_date->getTimestamp(), 'cancel_date_by' => $this->me->id, 'edit_by' => $this->me->id ]); @@ -126,7 +127,7 @@ class ContractTrigger_Finished { // Alte Gutschrift kündigen und neue anlegen //var_dump($old_credit->contract); $old_credit->contract->update([ - 'cancel_date' => $now->getTimestamp(), + 'cancel_date' => $cancel_date->getTimestamp(), 'cancel_date_by' => $this->me->id, 'edit_by' => $this->me->id ]); diff --git a/application/Order/OrderController.php b/application/Order/OrderController.php index 2e8e1e52e..954d1aff1 100644 --- a/application/Order/OrderController.php +++ b/application/Order/OrderController.php @@ -150,18 +150,11 @@ class OrderController extends mfBaseController { } } - //if(!$showLonelies) { - //var_dump($order_search);exit; - $pagination['maxItems'] = OrderModel::count($order_search); - foreach(OrderModel::search($order_search, $pagination) as $order) { - if(!array_key_exists($order->id, $orders)) { - $orders[$order->id] = $order; - } - } - //} - + $pagination['maxItems'] = OrderModel::count($order_search); + $orders = OrderModel::search($order_search, $pagination, true); + $showLoneliesCount = false; - foreach(["owner", "owner_address", "partner_number"] as $key) { + foreach(["owner", "owner_address", "partner_number"] as $key) { if(array_key_exists($key, $filter) && $filter[$key]) { $showLoneliesCount = true; break; @@ -192,7 +185,6 @@ class OrderController extends mfBaseController { if($this->me->isAdmin()) { if(!$this->request->filter['network_id']) { $lonelies = OrderModel::search($order_search); - } } else { $order_search['create_by'] = $userIds; @@ -225,7 +217,7 @@ class OrderController extends mfBaseController { foreach($lonelies as $order) { // check for voice or special products only - $this->log->debug("Order id ".$order->id); + //$this->log->debug("Order id ".$order->id); /*if($order->id == 38) { var_dump($order); exit; @@ -476,7 +468,13 @@ class OrderController extends mfBaseController { $this->layout()->setFlash("Wartestatus erfolgreich gespeichert", "success"); $this->redirect("Order","Index", $qs); } - + + protected function addUpgrade() { + $this->layout()->setTemplate("Order/Productchange"); + + + } + protected function saveAction() { $r = $this->request; //var_dump($r->products); diff --git a/application/Order/OrderModel.php b/application/Order/OrderModel.php index db4a8ca51..48527d8f2 100644 --- a/application/Order/OrderModel.php +++ b/application/Order/OrderModel.php @@ -180,7 +180,7 @@ class OrderModel { return 0; } - public static function search($filter, $limit=false) { + public static function search($filter, $limit=false, $withId = false) { $items = []; $db = FronkDB::singleton(); @@ -210,7 +210,7 @@ class OrderModel { if(is_array($limit) && count($limit)) { if(is_numeric($limit['start']) && is_numeric($limit['count'])) { $sql .= " LIMIT ".$limit['start'].", ".$limit['count']; - } elseif(is_numeric($count)) { + } elseif(is_numeric($limit['count'])) { $sql .= " LIMIT ".$limit['count']; } } @@ -218,7 +218,11 @@ class OrderModel { $res = $db->query($sql); if($db->num_rows($res)) { while($data = $db->fetch_object($res)) { - $items[] = new Order($data); + if($withId) { + $items[$data->id] = new Order($data); + } else { + $items[] = new Order($data); + } } } From 56be9eea818cc9d969c1a5bfb0fb9abbadc2b28d Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Tue, 23 Jul 2024 15:51:39 +0200 Subject: [PATCH 2/5] Started Order productchange --- Layout/default/Order/Productchange.php | 22 +++++++- application/Contract/ContractController.php | 24 ++++++++ application/Order/OrderController.php | 6 +- .../OrderProductchange/OrderProductchange.js | 55 +++++++++++++++++++ 4 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 public/js/pages/OrderProductchange/OrderProductchange.js diff --git a/Layout/default/Order/Productchange.php b/Layout/default/Order/Productchange.php index ce0b820f8..73c0ba386 100644 --- a/Layout/default/Order/Productchange.php +++ b/Layout/default/Order/Productchange.php @@ -55,6 +55,25 @@ $posturl = self::getUrl("Order", "save", $urlfilter);
+ +
+
+ + + + + + + + + + + + + +
Contract IDProduktMatchcodePreis p.P.HerstellungskostenFertigstellungKündigung
+
+
@@ -70,7 +89,8 @@ $posturl = self::getUrl("Order", "save", $urlfilter); diff --git a/application/Contract/ContractController.php b/application/Contract/ContractController.php index ec6cf2ebb..26f6bccda 100644 --- a/application/Contract/ContractController.php +++ b/application/Contract/ContractController.php @@ -797,8 +797,15 @@ class ContractController extends mfBaseController case "getContract": $return = $this->getContractApi(); break; + case "findContracts": + $return = $this->getContractsApi(); + break; case "findContract": $return = $this->findContractApi(); + break; + case "": + $return = ""; + break; default: $return = false; } @@ -834,6 +841,23 @@ class ContractController extends mfBaseController return ["contract" => $data, "form_id" => $form_id]; } + private function getContractsApi() { + $owner_id = $this->request->owner_id; + if(!$owner_id) return false; + + $return = []; + + foreach(ContractModel::search(["owner_id" => $owner_id]) as $contract) { + $c = get_object_vars($contract->data); + $c["id"] = $contract->id; + $return[] = $c; + } + + header("Content-type: application/json"); + echo json_encode($return); + exit; + } + private function findContractApi() { $search = trim($this->request->q); diff --git a/application/Order/OrderController.php b/application/Order/OrderController.php index 954d1aff1..f7d086513 100644 --- a/application/Order/OrderController.php +++ b/application/Order/OrderController.php @@ -470,8 +470,10 @@ class OrderController extends mfBaseController { } protected function addUpgrade() { - $this->layout()->setTemplate("Order/Productchange"); - + //$this->layout()->setTemplate("Order/Productchange"); + Helper::renderVue($this, "OrderProductchange", $this->mod, ["CONTRACT_API_URL" => $this->getUrl("Contract", "api"), + "ADDRESS_API_URL" => $this->getUrl("Address", "api"), + "CONTRACT_PRODUCTCHANGE_URL" => $this->getUrl("Contract", "productchange")]); } diff --git a/public/js/pages/OrderProductchange/OrderProductchange.js b/public/js/pages/OrderProductchange/OrderProductchange.js new file mode 100644 index 000000000..4dfb315ca --- /dev/null +++ b/public/js/pages/OrderProductchange/OrderProductchange.js @@ -0,0 +1,55 @@ +Vue.component('OrderProductchange', { + //language=Vue + template: ` + + + + + + + + + + + `, data() { + return { + window: window, + OrderProductchangeTableConfig: { + headers: [ + {text: "Contract ID", key: "id", filter: false, order: false}, + {text: "Produkt", key: "product_id", filter: false, order: false}, + {text: "Matchcode", key: "matchcode", filter: false, order: false}, + {text: "Preis p.P.", key: "price", filter: false, order: false}, + {text: "Herstellungskosten", key: "price_setup", filter: false, order: false}, + {text: "Fertigstellung", key: "finish_date", filter: false, order: false}, + {text: "Kündigung", key: "cancel_date", filter: false, order: false}, + {text: "Aktion", key: "actions", filter: false, order: false} + ], + tableHeader: 'Aktive Produkte', + key: 'OrderProductchange', + }, + owner_id: "", + } + }, + methods: { + + }, + watch: { + owner_id: { + async handler() { + console.log(this.owner_id); + //this.$refs.contractTable.$set(this.$refs.contractTable.fetchUrl, `${this.window['TT_CONFIG']['CONTRACT_API_URL']}?do=findContracts&owner_id=${this.owner_id}`); + //this.$refs.contractTable.$set(this.$refs.contractTable.filters, 'owner_id', this.owner_id); + //await this.$refs.contractTable.fetchData(); + } + } + } +}) + From a4f6b3b98c03fdf2aef51bea013c2f0d6f75dd85 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Wed, 24 Jul 2024 13:34:39 +0200 Subject: [PATCH 3/5] Partner Producthchange WIP 2024-07-23 --- Layout/default/Contract/ProductchangeForm.php | 249 +----------- .../Contract/include/productchange-action.php | 359 ++++++++++++++++++ Layout/default/Order/ProductchangeForm.php | 95 +++++ application/Billing/BillingController.php | 2 + application/Contract/ContractController.php | 175 ++++++++- application/Order/OrderController.php | 77 +++- application/Product/ProductController.php | 25 +- .../OrderProductchange/OrderProductchange.js | 105 +++-- 8 files changed, 784 insertions(+), 303 deletions(-) create mode 100644 Layout/default/Contract/include/productchange-action.php create mode 100644 Layout/default/Order/ProductchangeForm.php diff --git a/Layout/default/Contract/ProductchangeForm.php b/Layout/default/Contract/ProductchangeForm.php index c7132826b..2b3b7e5a4 100644 --- a/Layout/default/Contract/ProductchangeForm.php +++ b/Layout/default/Contract/ProductchangeForm.php @@ -1,3 +1,7 @@ + @@ -12,7 +16,7 @@ - +

Aktives Produkt

@@ -77,246 +81,7 @@ -
-
-

Neuer Contract

- -
"> - - -
-
- -
- -
- -
-
- -
- -
- - Eindeutige Identifizierung das Produkts. Z.B. - Anschlussadresse, Domainname usw. -
-
- - product->attributes) && count($contract->product->attributes)) - && (array_key_exists(TT_ATTRIB_TERMINATION_REQUIRED_NAME, $contract->product->attributes) - && $contract->product->attributes[TT_ATTRIB_TERMINATION_REQUIRED_NAME]->value == 1) - || $contract->termination_id - ): ?> -
- - - -
- -
- - Scheint statt dem echten Produktnamen auf der - Rechnung auf -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - - linkFrom) && count($contract->linkFrom)) || (is_array($contract->linkTo) && count($contract->linkTo))): ?> -

Verknüpfte Verträge

- - - - - - - - - - - - - - - linksWithCredit as $link): ?> - contract_id == $contract->id) { - $linkcontract = $link->origin; - } else { - $linkcontract = $link->contract; - } - - if($linkcontract->isCancelled()) continue; - - ?> - - - - - - - - - - - - - - - - - - - -
- -
- -
-
- -
-
- - -
-
- -
-
- - - -
-
+
@@ -435,7 +200,7 @@ function linkActionChange(link_id) { //console.log($("#link-" + link_id + "-action-cancel").prop("checked")); - if($("#link-" + link_id + "-action-cancel").prop("checked")) { + if($("#link-" + link_id + "-action-cancel").prop("checked") && $("#finish_date").val()) { $("#link-" + link_id + "-cancel_date").show(); } else { $("#link-" + link_id + "-cancel_date").hide(); diff --git a/Layout/default/Contract/include/productchange-action.php b/Layout/default/Contract/include/productchange-action.php new file mode 100644 index 000000000..58470eb0d --- /dev/null +++ b/Layout/default/Contract/include/productchange-action.php @@ -0,0 +1,359 @@ +
+
+

Neuer Contract

+ +
"> + + + + + + +
+
+ +
+ +
+ +
+
+ +
+ +
+ + Eindeutige Identifizierung das Produkts. Z.B. + Anschlussadresse, Domainname usw. +
+
+ + product->attributes) && count($contract->product->attributes)) + && (array_key_exists(TT_ATTRIB_TERMINATION_REQUIRED_NAME, $contract->product->attributes) + && $contract->product->attributes[TT_ATTRIB_TERMINATION_REQUIRED_NAME]->value == 1) + || $contract->termination_id + ): ?> +
+ + + +
+ +
+ + Scheint statt dem echten Produktnamen auf der + Rechnung auf +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
"> + +
+ +
+
+ +
"> + +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + + linkFrom) && count($contract->linkFrom)) || (is_array($contract->linkTo) && count($contract->linkTo))): ?> +

Verknüpfte Verträge

+ + + + + + + + + + + + + + + linksWithCredit as $link): ?> + contract_id == $contract->id) { + $linkcontract = $link->origin; + } else { + $linkcontract = $link->contract; + } + + if($linkcontract->isCancelled()) continue; + + ?> + "> + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+
+ + +
+
+ +
+
+ + + +
+
+ + \ No newline at end of file diff --git a/Layout/default/Order/ProductchangeForm.php b/Layout/default/Order/ProductchangeForm.php new file mode 100644 index 000000000..b3673bebc --- /dev/null +++ b/Layout/default/Order/ProductchangeForm.php @@ -0,0 +1,95 @@ + + + + +
+
+
+
+ +
+

Aktives Produkt

+
+
+
+ + +
+
+ + + +
+
+

product_name?> (id?>)

+ + + + + + + + + + + + + + + + + + + + + + + + +
Matchcode:matchcode?>
Vertragsinhaber: + $contract->owner->id])?>">owner->getCompanyOrName()?> + (owner->customer_number?>) + +
Produkt:product_name?> [product_id?> + ]product_name != $contract->product->name) ? " (" . $contract->product->name . ")" : ""?>
Produkt Info:product_info?>
Preis Netto:">€ amount != 1) ? $contract->price * $contract->amount : $contract->price, 4, ",", ".")?>
Preis Brutto:">€ + price && $contract->vatrate): ?> + amount != 1): ?> + price + ($contract->price / 100) * $contract->vatrate, 4, ",", ".")?> + + price + ($contract->price / 100) * $contract->vatrate) * $contract->amount, 4, ",", ".")?> + + +
Fertigstellungsdatum:finish_date)?>
+ +
+
+ + + + + + + +
+
+ + + + + \ No newline at end of file diff --git a/application/Billing/BillingController.php b/application/Billing/BillingController.php index 3e37c96f1..b6135e4f4 100644 --- a/application/Billing/BillingController.php +++ b/application/Billing/BillingController.php @@ -346,6 +346,8 @@ class BillingController extends mfBaseController { $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) continue; // don't bill for negative time range + $pc = $period_days / $total_days * 100; $price = round($contract->price / 100 * $pc, 4); diff --git a/application/Contract/ContractController.php b/application/Contract/ContractController.php index 26f6bccda..bb216f2e8 100644 --- a/application/Contract/ContractController.php +++ b/application/Contract/ContractController.php @@ -11,7 +11,7 @@ class ContractController extends mfBaseController $this->me = $me; $this->layout()->set("me", $me); - if (!$me->is(["Admin"])) { + if (!$me->is(["Admin", "salespartner", "netowner"])) { $this->redirect("Dashboard"); } } @@ -19,6 +19,10 @@ class ContractController extends mfBaseController protected function indexAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } + $this->layout()->setTemplate("Contract/Index"); if ($this->request->resetFilter) { @@ -87,6 +91,10 @@ class ContractController extends mfBaseController protected function viewAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } + $this->layout()->setTemplate("Contract/View"); $id = $this->request->contract_id; @@ -116,6 +124,9 @@ class ContractController extends mfBaseController } protected function cancelAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $this->layout()->setTemplate("Contract/CancelForm"); $id = $this->request->contract_id; @@ -154,6 +165,9 @@ class ContractController extends mfBaseController } protected function saveCancel() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $r = $this->request; $id = $r->contract_id; @@ -212,6 +226,9 @@ class ContractController extends mfBaseController } protected function sendCancelNotification() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $contract_id = $this->request->contract_id; $contract = new Contract($contract_id); @@ -238,23 +255,65 @@ class ContractController extends mfBaseController { $this->layout()->setTemplate("Contract/ProductchangeForm"); + $f = $this->request->f; + if(!$f) { + $f = "c"; // from Contract + } + $this->layout()->set("f", $f); + $id = $this->request->contract_id; if (!$id) { $id = $this->request->id; } if (!is_numeric($id) || !$id) { $this->layout()->setFlash("Vertrag nicht gefunden", "error"); - $this->redirect("Contract"); + if($f == "o") { + $this->redirect("Order", "addUpgrade"); + } else { + $this->redirect("Contract"); + } + } $contract = new Contract($id); if (!$contract->id) { $this->layout()->setFlash("Vertrag nicht gefunden", "error"); - $this->redirect("Contract"); + if($f == "o") { + $this->redirect("Order", "addUpgrade"); + } else { + $this->redirect("Contract"); + } } + if($this->me->isAdmin()) { + $this->layout()->set("terminations", TerminationModel::getAll()); + } else { + // check permissions + // check if correct network + + $my_network_ids = []; + foreach($this->me->my_networks as $network) { + $my_network_ids[] = $network->id; + } + + if($contract->termination_id) { + if(!in_array($contract->termination->network_id, $my_network_ids)) { + if($f == "o") { + // from Order, redirect back to Order + $this->layout()->setFlash("Keine Berechtigung", "error"); + $this->redirect("Order", "addUpgrade", ["owner_id" => $contract->owner_id]); + } + } + } + + + $terms = TerminationModel::search(["network_id" => $my_network_ids]); + $this->layout()->set("terminations", $terms); + } + + $this->layout()->set("contract", $contract); - $this->layout()->set("terminations", TerminationModel::getAll()); + if ($this->request->filter) { $this->layout()->set("filter", $this->request->filter); @@ -266,19 +325,36 @@ class ContractController extends mfBaseController protected function saveProductchangeAction() { + if(!$this->me->is(["Admin", "salespartner", "netowner"])) { + $this->redirect("Dashboard"); + } + $r = $this->request; //var_dump($r->links);exit; + $f = $r->f; + if(!$f) { + $f = "c"; // from Contract + } + $id = $r->contract_id; if (!is_numeric($id) || !$id) { $this->layout()->setFlash("Vertrag nicht gefunden", "error"); - $this->redirect("Contract"); + if($f == "o") { + $this->redirect("Order", "addUpgrade"); + } else { + $this->redirect("Contract"); + } } $contract = new Contract($id); if (!$contract->id) { $this->layout()->setFlash("Vertrag nicht gefunden", "error"); - $this->redirect("Contract"); + if($f == "o") { + $this->redirect("Order", "addUpgrade"); + } else { + $this->redirect("Contract"); + } } $new_contract = clone($contract); @@ -303,7 +379,12 @@ class ContractController extends mfBaseController $product = new Product($r->product_id); if (!$product->id) { $this->layout()->setFlash("Produkt nicht gefunden", "error"); - $this->redirect("Contract", "productchange", ["contract_id" => $id]); + if($f == "o") { + $this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]); + } else { + $this->redirect("Contract", "productchange", ["contract_id" => $id]); + } + } $contract_data['product_external'] = $product->external; @@ -315,7 +396,11 @@ class ContractController extends mfBaseController $finish_date = DateTime::createFromFormat("d.m.Y", $r->finish_date, new DateTimeZone("Europe/Vienna")); } catch (Exception $e) { $this->layout()->setFlash("Ungültiges Kündigungsdateum", "error"); - $this->redirect("Contract", "productchange", ["contract_id" => $id]); + if($f == "o") { + $this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]); + } else { + $this->redirect("Contract", "productchange", ["contract_id" => $id]); + } } $finish_date->setTime(0,0,0); @@ -334,7 +419,11 @@ class ContractController extends mfBaseController if (!$contract_data['termination_id'] || !$termination->id) { $this->layout()->setFlash("Produkt erfordert Anschluss.", "error"); - $this->redirect("Contract", "productchange", ["contract_id" => $id]); + if($f == "o") { + $this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]); + } else { + $this->redirect("Contract", "productchange", ["contract_id" => $id]); + } } } else { $contract_data['termination_id'] = null; @@ -371,7 +460,11 @@ class ContractController extends mfBaseController $cancel_date = DateTime::createFromFormat("d.m.Y", $link_data["cancel_date"], new DateTimeZone("Europe/Vienna")); } catch (Exception $e) { $this->layout()->setFlash("Ungültiges Kündigungsdateum", "error"); - $this->redirect("Contract", "productchange", ["contract_id" => $id]); + if($f == "o") { + $this->redirect("Contract", "productchange", ["contract_id" => $id, "f" => $f]); + } else { + $this->redirect("Contract", "productchange", ["contract_id" => $id]); + } } } @@ -408,7 +501,7 @@ class ContractController extends mfBaseController } if ($action == "cancel") { - if($cancel_date) { + if($cancel_date && $contract_cancel_date) { // insert cancel_date in old contract $lc = new Contract($origin_id); $lc->cancel_date = $cancel_date->getTimestamp(); @@ -497,13 +590,21 @@ class ContractController extends mfBaseController } $this->layout()->setFlash("Neuer Contract erfolgreich erstellt", "success"); - $this->redirect("Contract", "view", ["contract_id" => $new_contract_id]); + if($f == "o") { + $this->redirect("Order"); + } else { + $this->redirect("Contract", "view", ["contract_id" => $new_contract_id]); + } + } protected function finishContractAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $r = $this->request; $id = $r->contract_id; @@ -550,6 +651,9 @@ class ContractController extends mfBaseController protected function addAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $this->layout()->setTemplate("Contract/Form"); $this->layout()->set("terminations", TerminationModel::getAll()); @@ -569,6 +673,9 @@ class ContractController extends mfBaseController protected function editAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $id = $this->request->contract_id; if (!$id) { $id = $this->request->id; @@ -602,6 +709,9 @@ class ContractController extends mfBaseController protected function saveAction() { + if(!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $r = $this->request; //var_dump($r); @@ -787,7 +897,7 @@ class ContractController extends mfBaseController protected function apiAction() { - if (!$this->me->is(["Admin"])) { + if (!$this->me->is(["Admin", "salespartner", "netowner"])) { $this->redirect("Dashboard"); } $do = $this->request->do; @@ -821,6 +931,10 @@ class ContractController extends mfBaseController private function getContractApi() { + if (!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } + $contract_id = $this->request->contract_id; if (!is_numeric($contract_id) || $contract_id < 1) { return false; @@ -847,7 +961,37 @@ class ContractController extends mfBaseController $return = []; - foreach(ContractModel::search(["owner_id" => $owner_id]) as $contract) { + $contracts = ContractModel::search(["owner_id" => $owner_id]); + if(!$contracts) { + header("Content-type: application/json"); + echo json_encode([]); + exit; + } + $is_valid_owner = false; + + if(!$this->me->is("Admin")) { + foreach($contracts as $contract) { + foreach(ContractLinkModel::includesContractId($contract->id) as $link) { + if($link->type != "credit") continue; + $link_contract = $link->contract; + if($link->contract_id == $contract->id) $link_contract = $link->origin; + if($link_contract->owner_id == $this->me->address_id) { + $is_valid_owner = true; + break; + } + } + } + + if(!$is_valid_owner) { + header("Content-type: application/json"); + echo json_encode([]); + exit; + } + } + + + + foreach($contracts as $contract) { $c = get_object_vars($contract->data); $c["id"] = $contract->id; $return[] = $c; @@ -860,6 +1004,9 @@ class ContractController extends mfBaseController private function findContractApi() { + if (!$this->me->is(["Admin"])) { + $this->redirect("Dashboard"); + } $search = trim($this->request->q); $autocomplete = $this->request->autocomplete; diff --git a/application/Order/OrderController.php b/application/Order/OrderController.php index f7d086513..2c7cd1697 100644 --- a/application/Order/OrderController.php +++ b/application/Order/OrderController.php @@ -371,18 +371,7 @@ class OrderController extends mfBaseController { $users = []; foreach($this->me->my_networks as $network) { $network_ids[] = $network->id; - /*$tmp_users = $network->getAddressUsersByAddresstype("salespartner"); - foreach($tmp_users as $user) { - if(!in_array($user->id, $users)) { - $users[] = $user->id; - } - }*/ } - /* - // get addresses from salespartner address' user ids - $addresses = AddressModel::search(["create_by" => $users]); - $this->layout()->set("addresses", $addresses); - */ // get terminations in my networks $terms = TerminationModel::search(["network_id" => $network_ids]); $this->layout()->set("terminations", $terms); @@ -437,6 +426,10 @@ class OrderController extends mfBaseController { return $this->addAction(); } + + protected function upgradesAction() { + + } protected function setwaitingAction() { $order_id = $this->request->id; @@ -471,12 +464,70 @@ class OrderController extends mfBaseController { protected function addUpgrade() { //$this->layout()->setTemplate("Order/Productchange"); - Helper::renderVue($this, "OrderProductchange", $this->mod, ["CONTRACT_API_URL" => $this->getUrl("Contract", "api"), + Helper::renderVue($this, "OrderProductchange", "Neuer Produktwechsel", ["CONTRACT_API_URL" => $this->getUrl("Contract", "api"), "ADDRESS_API_URL" => $this->getUrl("Address", "api"), - "CONTRACT_PRODUCTCHANGE_URL" => $this->getUrl("Contract", "productchange")]); + "ORDER_PRODUCTCHANGE_URL" => $this->getUrl("Order", "productchange")]); } + protected function productchangeAction() { + $this->layout()->setTemplate("Order/ProductchangeForm"); + + $f = $this->request->f; + if(!$f) { + $f = "c"; // from Contract + } + $this->layout()->set("f", $f); + + $id = $this->request->contract_id; + if (!$id) { + $id = $this->request->id; + } + if (!is_numeric($id) || !$id) { + $this->layout()->setFlash("Vertrag nicht gefunden", "error"); + $this->redirect("Order", "addUpgrade"); + } + + $contract = new Contract($id); + if (!$contract->id) { + $this->layout()->setFlash("Vertrag nicht gefunden", "error"); + $this->redirect("Order", "addUpgrade"); + } + + if($this->me->isAdmin()) { + $this->layout()->set("terminations", TerminationModel::getAll()); + } else { + // check permissions + // check if correct network + + $my_network_ids = []; + foreach($this->me->my_networks as $network) { + $my_network_ids[] = $network->id; + } + + if($contract->termination_id) { + if(!in_array($contract->termination->network_id, $my_network_ids)) { + $this->layout()->setFlash("Keine Berechtigung", "error"); + $this->redirect("Order", "addUpgrade", ["owner_id" => $contract->owner_id]); + } + } + + $terms = TerminationModel::search(["network_id" => $my_network_ids]); + $this->layout()->set("terminations", $terms); + } + + + $this->layout()->set("contract", $contract); + + + if ($this->request->filter) { + $this->layout()->set("filter", $this->request->filter); + } + if ($this->request->s) { + $this->layout()->set("filter", $this->request->s); + } + } + protected function saveAction() { $r = $this->request; //var_dump($r->products); diff --git a/application/Product/ProductController.php b/application/Product/ProductController.php index ef758bd55..5578dd379 100644 --- a/application/Product/ProductController.php +++ b/application/Product/ProductController.php @@ -421,9 +421,32 @@ class ProductController extends mfBaseController { } $results = []; - + + + + if(!$this->me->isAdmin()) { + $my_product_ids = []; + $my_network_ids = []; + foreach($this->me->my_networks as $network) { + $my_network_ids[] = $network->id; + } + + foreach(ProductNetworkModel::search(["network_id" => $my_network_ids]) as $pn) { + if(!$pn->product->active) continue; + if(!array_key_exists($pn->product_id, $my_product_ids)) { + $my_product_ids[] = $pn->product_id; + } + } + } + // return bootstrap-autocomplete format foreach($products as $product) { + if(!$this->me->isAdmin()) { + if(!in_array($product->id, $my_product_ids)) continue; + } + + + $result = ['value' => $product->id, 'text' => str_replace("'", "\\'", str_replace(["\n", "\r"], " ",$product->name))]; $results[] = $result; if(count($results) > 15) { diff --git a/public/js/pages/OrderProductchange/OrderProductchange.js b/public/js/pages/OrderProductchange/OrderProductchange.js index 4dfb315ca..8854eec28 100644 --- a/public/js/pages/OrderProductchange/OrderProductchange.js +++ b/public/js/pages/OrderProductchange/OrderProductchange.js @@ -1,55 +1,94 @@ Vue.component('OrderProductchange', { //language=Vue template: ` - - - + - +
+ +

Wählen Sie den Vertragsinhaber aus, um die aktiven Produkte anzuzeigen.
+ Produktwechsel sollten immer mit dem Hauptprodukt durchgeführt werden. Dies ist fast immer das Internetzugangsprodukt.

+ + + +
+ + {{owner.name}}
+ {{owner.street}}
+ {{owner.zip}} {{owner.city}} +
+ + - - - - + :config="OrderProductchangeTableConfig" :small="false" class="sm" + disable-filtering ref="contractTable"> + + + + + + + + + + +
+ +
+
+ `, data() { return { window: window, OrderProductchangeTableConfig: { headers: [ - {text: "Contract ID", key: "id", filter: false, order: false}, - {text: "Produkt", key: "product_id", filter: false, order: false}, - {text: "Matchcode", key: "matchcode", filter: false, order: false}, - {text: "Preis p.P.", key: "price", filter: false, order: false}, - {text: "Herstellungskosten", key: "price_setup", filter: false, order: false}, - {text: "Fertigstellung", key: "finish_date", filter: false, order: false}, - {text: "Kündigung", key: "cancel_date", filter: false, order: false}, - {text: "Aktion", key: "actions", filter: false, order: false} + {text: "", key: "actions", class: "text-right", headerClass: "text-right"}, + {text: "Contract ID", key: "id", class: "text-right", headerClass: "text-right"}, + {text: "Produkt", key: "product_name", headerClass: "text-left"}, + {text: "Matchcode", key: "matchcode", headerClass: "text-left"}, + {text: "Preis", key: "price", headerClass: "text-left"}, + {text: "Periode", key: "billing_period", headerClass: "text-left"}, + {text: "Herstellungskosten", key: "price_setup", headerClass: "text-left"}, + {text: "Fertigstellung", key: "finish_date", filter: "date", headerClass: "text-left"}, + {text: "Kündigung", key: "cancel_date", filter: "date", headerClass: "text-left"} ], - tableHeader: 'Aktive Produkte', + tableHeader: 'Zu änderndes Produkt wählen', key: 'OrderProductchange', }, owner_id: "", + owner: false } }, - methods: { - + filters: { + formatPrice(price) { + roundedPrice = Math.round((parseFloat(price) + Number.EPSILON) * 100) / 100; + return roundedPrice.toFixed(4); + } }, - watch: { - owner_id: { - async handler() { - console.log(this.owner_id); - //this.$refs.contractTable.$set(this.$refs.contractTable.fetchUrl, `${this.window['TT_CONFIG']['CONTRACT_API_URL']}?do=findContracts&owner_id=${this.owner_id}`); - //this.$refs.contractTable.$set(this.$refs.contractTable.filters, 'owner_id', this.owner_id); - //await this.$refs.contractTable.fetchData(); - } + beforeMount() { + const urlSearchParams = new URLSearchParams(window.location.search); + if (urlSearchParams.has("owner_id")) { + this.owner_id = urlSearchParams.get("owner_id"); } } + }) From 210ba2e771b8e91af2443883ac59d24d327de020 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Thu, 25 Jul 2024 14:25:29 +0200 Subject: [PATCH 4/5] Added fullscreen mode to maps --- Layout/default/Building/Index.php | 2 +- Layout/default/Preorder/Index.php | 2 +- Layout/default/header.php | 2 ++ public/assets/css/fullscreen.png | Bin 0 -> 299 bytes public/assets/css/fullscreen@2x.png | Bin 0 -> 420 bytes public/assets/css/leaflet.fullscreen.css | 40 +++++++++++++++++++++ public/assets/js/Leaflet.fullscreen.min.js | 1 + 7 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 public/assets/css/fullscreen.png create mode 100644 public/assets/css/fullscreen@2x.png create mode 100644 public/assets/css/leaflet.fullscreen.css create mode 100644 public/assets/js/Leaflet.fullscreen.min.js diff --git a/Layout/default/Building/Index.php b/Layout/default/Building/Index.php index 7a34278b9..b53781942 100644 --- a/Layout/default/Building/Index.php +++ b/Layout/default/Building/Index.php @@ -397,7 +397,7 @@ }); } } else { - buildingMap = L.map('building-map').setView([, ], 12); + buildingMap = L.map('building-map', {fullscreenControl: true}).setView([, ], 12); } if(!(currentTileset in tileLayers)) { diff --git a/Layout/default/Preorder/Index.php b/Layout/default/Preorder/Index.php index 973776820..245bb7e86 100644 --- a/Layout/default/Preorder/Index.php +++ b/Layout/default/Preorder/Index.php @@ -437,7 +437,7 @@ }); } } else { - preorderMap = L.map('preorder-map').setView([, ], 12); + preorderMap = L.map('preorder-map', {fullscreenControl: true}).setView([, ], 12); } if(!(currentTileset in tileLayers)) { diff --git a/Layout/default/header.php b/Layout/default/header.php index f73c6b3f6..1a1f26627 100644 --- a/Layout/default/header.php +++ b/Layout/default/header.php @@ -19,6 +19,7 @@ + @@ -39,6 +40,7 @@ + diff --git a/public/assets/css/fullscreen.png b/public/assets/css/fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..7384960aeb574240163a493a151fead20dc0611a GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^Qb26N!3HF!ywT_YQY^(zo*^7SP{WY|;&T>wL>2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4qJR0?c|VVoi#&H*nzk><=VJ7@HQU1Z_V>w`?l#_f{i*8umu)iddGww* z>3vx+!GG1OU;EWUx0X~hxG2rq^x@2zjVbjX|F1ZfDD>^!i>Z@e=`4{;y0s+g&91Al p8%^ww-;@2hQY^(zo*^7SP{WbZ0pxQQctjR6 zFi5WlVa7PAi84Sz$r9IylHmNblJdl&REF~Ma=pyF?Be9af>gcyqV(DCY@`?%7!^HT z978JRyuIbf*JL2VaIybmlC5OHCOKa72`f5-7F_i-&hI_2WYN~Lh-s=-MZdrEUP%*} z>sZ2eQPQPc-_~GhNruVq5#|tNZ+oU=grd-gUnYNV=qh zG%mj`vhJT;R_We%ZYLD1nqTlNvfit=eS6-uth>4XAS32xbAe3_xBA?>tb=y5HuU z3;cF;mu&UdD*aXc7p&&~tXS+n%cpkMnWxvJ=SIz`_Afs_0puwZOTbRIWrz!l?^k@w RJ`)(C44$rjF6*2UngH1ls0082 literal 0 HcmV?d00001 diff --git a/public/assets/css/leaflet.fullscreen.css b/public/assets/css/leaflet.fullscreen.css new file mode 100644 index 000000000..f4892578e --- /dev/null +++ b/public/assets/css/leaflet.fullscreen.css @@ -0,0 +1,40 @@ +.leaflet-control-fullscreen a { + background:#fff url(fullscreen.png) no-repeat 0 0; + background-size:26px 52px; + } + .leaflet-touch .leaflet-control-fullscreen a { + background-position: 2px 2px; + } + .leaflet-fullscreen-on .leaflet-control-fullscreen a { + background-position:0 -26px; + } + .leaflet-touch.leaflet-fullscreen-on .leaflet-control-fullscreen a { + background-position: 2px -24px; + } + +/* Do not combine these two rules; IE will break. */ +.leaflet-container:-webkit-full-screen { + width:100%!important; + height:100%!important; + } +.leaflet-container.leaflet-fullscreen-on { + width:100%!important; + height:100%!important; + } + +.leaflet-pseudo-fullscreen { + position:fixed!important; + width:100%!important; + height:100%!important; + top:0!important; + left:0!important; + z-index:99999; + } + +@media + (-webkit-min-device-pixel-ratio:2), + (min-resolution:192dpi) { + .leaflet-control-fullscreen a { + background-image:url(fullscreen@2x.png); + } + } diff --git a/public/assets/js/Leaflet.fullscreen.min.js b/public/assets/js/Leaflet.fullscreen.min.js new file mode 100644 index 000000000..fc2eb24a3 --- /dev/null +++ b/public/assets/js/Leaflet.fullscreen.min.js @@ -0,0 +1 @@ +(function(factory){var L;if(typeof define==="function"&&define.amd){define(["leaflet"],factory)}else if(typeof module!=="undefined"){L=require("leaflet");module.exports=factory(L)}else{if(typeof window.L==="undefined"){throw new Error("Leaflet must be loaded first")}factory(window.L)}})(function(L){L.Control.Fullscreen=L.Control.extend({options:{position:"topleft",title:{"false":"View Fullscreen","true":"Exit Fullscreen"}},onAdd:function(map){var container=L.DomUtil.create("div","leaflet-control-fullscreen leaflet-bar leaflet-control");this.link=L.DomUtil.create("a","leaflet-control-fullscreen-button leaflet-bar-part",container);this.link.href="#";this._map=map;this._map.on("fullscreenchange",this._toggleTitle,this);this._toggleTitle();L.DomEvent.on(this.link,"click",this._click,this);return container},_click:function(e){L.DomEvent.stopPropagation(e);L.DomEvent.preventDefault(e);this._map.toggleFullscreen(this.options)},_toggleTitle:function(){this.link.title=this.options.title[this._map.isFullscreen()]}});L.Map.include({isFullscreen:function(){return this._isFullscreen||false},toggleFullscreen:function(options){var container=this.getContainer();if(this.isFullscreen()){if(options&&options.pseudoFullscreen){this._disablePseudoFullscreen(container)}else if(document.exitFullscreen){document.exitFullscreen()}else if(document.mozCancelFullScreen){document.mozCancelFullScreen()}else if(document.webkitCancelFullScreen){document.webkitCancelFullScreen()}else if(document.msExitFullscreen){document.msExitFullscreen()}else{this._disablePseudoFullscreen(container)}}else{if(options&&options.pseudoFullscreen){this._enablePseudoFullscreen(container)}else if(container.requestFullscreen){container.requestFullscreen()}else if(container.mozRequestFullScreen){container.mozRequestFullScreen()}else if(container.webkitRequestFullscreen){container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else if(container.msRequestFullscreen){container.msRequestFullscreen()}else{this._enablePseudoFullscreen(container)}}},_enablePseudoFullscreen:function(container){L.DomUtil.addClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(true);this.fire("fullscreenchange")},_disablePseudoFullscreen:function(container){L.DomUtil.removeClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(false);this.fire("fullscreenchange")},_setFullscreen:function(fullscreen){this._isFullscreen=fullscreen;var container=this.getContainer();if(fullscreen){L.DomUtil.addClass(container,"leaflet-fullscreen-on")}else{L.DomUtil.removeClass(container,"leaflet-fullscreen-on")}this.invalidateSize()},_onFullscreenChange:function(e){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(fullscreenElement===this.getContainer()&&!this._isFullscreen){this._setFullscreen(true);this.fire("fullscreenchange")}else if(fullscreenElement!==this.getContainer()&&this._isFullscreen){this._setFullscreen(false);this.fire("fullscreenchange")}}});L.Map.mergeOptions({fullscreenControl:false});L.Map.addInitHook(function(){if(this.options.fullscreenControl){this.fullscreenControl=new L.Control.Fullscreen(this.options.fullscreenControl);this.addControl(this.fullscreenControl)}var fullscreenchange;if("onfullscreenchange"in document){fullscreenchange="fullscreenchange"}else if("onmozfullscreenchange"in document){fullscreenchange="mozfullscreenchange"}else if("onwebkitfullscreenchange"in document){fullscreenchange="webkitfullscreenchange"}else if("onmsfullscreenchange"in document){fullscreenchange="MSFullscreenChange"}if(fullscreenchange){var onFullscreenChange=L.bind(this._onFullscreenChange,this);this.whenReady(function(){L.DomEvent.on(document,fullscreenchange,onFullscreenChange)});this.on("unload",function(){L.DomEvent.off(document,fullscreenchange,onFullscreenChange)})}});L.control.fullscreen=function(options){return new L.Control.Fullscreen(options)}}); \ No newline at end of file From fdecf142e1b3ae9dbab4cbc6c7e407522e964209 Mon Sep 17 00:00:00 2001 From: Frank Schubert Date: Thu, 25 Jul 2024 14:27:20 +0200 Subject: [PATCH 5/5] Temp disabled upgrade button in Order/Index --- Layout/default/Order/Index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Layout/default/Order/Index.php b/Layout/default/Order/Index.php index ad50c05d8..95ec4fe67 100644 --- a/Layout/default/Order/Index.php +++ b/Layout/default/Order/Index.php @@ -143,7 +143,7 @@