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"); } } + })