From 23185bedb5056a1193bec372ecfbbe1c70b3a6bc Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Tue, 11 Feb 2025 15:00:53 +0100 Subject: [PATCH 01/19] Devicecontroller Bugfix * Admin hat keine Devices mehr gesehen --- application/Device/DeviceController.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/application/Device/DeviceController.php b/application/Device/DeviceController.php index f810e44d2..b55d259a0 100644 --- a/application/Device/DeviceController.php +++ b/application/Device/DeviceController.php @@ -18,7 +18,7 @@ class DeviceController extends mfBaseController $this->allowedPops = null; } else { $networkIds = array_column($this->me->getProperty('my_networks'), 'id'); - $pops=PopNetworkModel::search(['Networks' => $networkIds]); + $pops = PopNetworkModel::search(['Networks' => $networkIds]); foreach ($pops as $pop) { $popIds[] = $pop->pop_id; } @@ -28,7 +28,7 @@ class DeviceController extends mfBaseController protected function indexAction() { - $deviceManufacturers = array_map(function($deviceManufacturer) { + $deviceManufacturers = array_map(function ($deviceManufacturer) { return [ "id" => $deviceManufacturer->id, "name" => $deviceManufacturer->name, @@ -37,7 +37,7 @@ class DeviceController extends mfBaseController ]; }, DevicemanufactorModel::getAll()); - $deviceTypes = array_map(function($deviceType) { + $deviceTypes = array_map(function ($deviceType) { return [ "id" => $deviceType->id, "name" => $deviceType->name, @@ -96,7 +96,7 @@ class DeviceController extends mfBaseController $this->layout()->setTemplate("Device/Detail"); $devicesconfig = DeviceModel::getconifg($id); $devices = DeviceModel::getOne($id); - $devicesall= DeviceModel::getAll(); + $devicesall = DeviceModel::getAll(); if ($devices->devicetype->olt == "1") { $customer = DeviceModel::getOltCustomer($device->ip); @@ -417,6 +417,9 @@ class DeviceController extends mfBaseController private function getDevices() { + if (!$this->me->is(["Admin"])) { + if ($this->allowedPops === null) return []; + } $devices = DeviceModel::search(['popIds' => $this->allowedPops]); foreach ($devices as $device) { From 114378ded76671c18ef3eda5b7b28f41ffec9887 Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Tue, 11 Feb 2025 15:28:50 +0100 Subject: [PATCH 02/19] Devicecontroller Bugfix * Admin hat keine Devices mehr gesehen --- application/Device/DeviceController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/Device/DeviceController.php b/application/Device/DeviceController.php index ac050b9b0..b55d259a0 100644 --- a/application/Device/DeviceController.php +++ b/application/Device/DeviceController.php @@ -417,9 +417,9 @@ class DeviceController extends mfBaseController private function getDevices() { - - if ($this->allowedPops === null) return []; - + if (!$this->me->is(["Admin"])) { + if ($this->allowedPops === null) return []; + } $devices = DeviceModel::search(['popIds' => $this->allowedPops]); foreach ($devices as $device) { From 1e868e9b847c75cdd8080317113359318554e660 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Wed, 12 Feb 2025 11:13:33 +0100 Subject: [PATCH 03/19] Updated Shipping Note so that Status is now a iconSelect --- .../WarehouseShippingNoteController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/application/WarehouseShippingNote/WarehouseShippingNoteController.php b/application/WarehouseShippingNote/WarehouseShippingNoteController.php index fa683a50e..2861ac418 100644 --- a/application/WarehouseShippingNote/WarehouseShippingNoteController.php +++ b/application/WarehouseShippingNote/WarehouseShippingNoteController.php @@ -8,12 +8,17 @@ class WarehouseShippingNoteController extends TTCrud { protected array $columns = [ ['key' => 'id', 'text' => 'LS-Nr.', 'required' => false, 'modal' => false, 'table' => ['class' => 'text-nowrap']], ['key' => 'billingAddressId', 'text' => 'Rechnungsadresse', 'required' => true, 'type' => 'autocomplete', 'table' => ['class' => 'text-nowrap', 'filter' => 'autocomplete'], 'modal' => ['apiUrl' => 'Address/api?do=findAddress', 'items' => '/Address/Api?do=findAddress', 'type' => 'autocomplete']], + ['key' => 'status', 'text' => 'Status', 'required' => true, 'table' => ['filter' => 'iconSelect'], 'modal' => ['type' => 'iconSelect', 'items' => [ + ['value' => 'new', 'text' => 'Neu', 'icon' => 'fas fa-star text-primary'], + ['value' => 'in_progress', 'text' => 'In Bearbeitung', 'icon' => 'fas fa-cog text-warning'], + ['value' => 'accepted', 'text' => 'Akzeptiert', 'icon' => 'fas fa-check text-success'], + ['value' => 'invoiced', 'text' => 'In Rechnung gestellt', 'icon' => 'fas fa-file-invoice-dollar text-info'], + ]]], ['key' => 'deliveryAddressName', 'text' => 'L.-Adr. Name', 'required' => true], ['key' => 'deliveryAddressLine', 'text' => 'L.-Adr.', 'required' => true], ['key' => 'deliveryAddressPLZ', 'text' => 'L.-Adr. PLZ', 'required' => true], ['key' => 'deliveryAddressEMail', 'text' => 'L.-Adr. EMail', 'required' => false, 'table' => false], ['key' => 'note', 'text' => 'Art der Arbeit', 'required' => true, 'table' => false], - ['key' => 'status', 'text' => 'Status', 'required' => true, 'table' => ['filter' => 'select'], 'modal' => ['type' => 'select', 'items' => [['value' => 'new', 'text' => 'Neu'], ['value' => 'in_progress', 'text' => 'In Bearbeitung'], ['value' => 'accepted', 'text' => 'Akzeptiert'], ['value' => 'invoiced', 'text' => 'In Rechnung gestellt'],]]], ['key' => 'positions', 'text' => 'Positionen', 'required' => true, 'table' => false, 'modal' => false], ['key' => 'create', 'text' => 'Erstellt', 'required' => false, 'modal' => ['visible' => false], 'table' => ['filter' => 'date']], ['key' => 'createBy', 'text' => 'Erstellt von', 'required' => false, 'type' => 'autocomplete', 'table' => ['class' => 'text-nowrap', 'filter' => 'select'], 'modal' => ['items' => [], 'type' => 'select',]], From 14308d3285b442e8373098f4f5c773b6efbbf773 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Wed, 12 Feb 2025 17:51:29 +0100 Subject: [PATCH 04/19] Changed Dashboard --- public/js/pages/DashboardNew/DashboardNew.css | 6 + public/js/pages/DashboardNew/DashboardNew.js | 138 ++++++++++++------ 2 files changed, 98 insertions(+), 46 deletions(-) diff --git a/public/js/pages/DashboardNew/DashboardNew.css b/public/js/pages/DashboardNew/DashboardNew.css index 756e7268f..9f6a4480a 100644 --- a/public/js/pages/DashboardNew/DashboardNew.css +++ b/public/js/pages/DashboardNew/DashboardNew.css @@ -38,6 +38,12 @@ margin-top: 20px; } +.dashboard-buttons { + display: flex; + gap: 1rem; + margin-top: 20px; +} + @media (min-width: 768px) { .dashboard-cards { diff --git a/public/js/pages/DashboardNew/DashboardNew.js b/public/js/pages/DashboardNew/DashboardNew.js index 201f0f166..c08acbdda 100644 --- a/public/js/pages/DashboardNew/DashboardNew.js +++ b/public/js/pages/DashboardNew/DashboardNew.js @@ -190,6 +190,39 @@ Vue.component('tt-timeline-chart', { Vue.component('dashboard-default', { props: ['dashboardData'], + data() { + return { + selectedTimeframe: 'all', + window: window, + moment: moment + } + }, + methods: { + exportTimeline() { + // we need all timelines with "ONT installiert", "Leerrohr", "Bestellungen" + const data = this.dashboardData.timeline[0].map((item, index) => ({ + date: item.date, + bestellungen: item.value, + leerrohr: this.dashboardData.timeline_leerrohr[0][index].value, + ont_installiert: this.dashboardData.timeline_ont_installed[0][index].value + })); + + // dont use any library for the csv + const csv = [ + ['Datum', 'Bestellungen', 'Leerrohr', 'ONT installiert'], + ...data.map(item => [item.date, item.bestellungen, item.leerrohr, item.ont_installiert]) + ].map(row => row.join(',')).join('\n'); + + const blob = new Blob([csv], {type: 'text/csv'}); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + + a.href = url; + a.download = 'timeline.csv'; + a.click(); + URL.revokeObjectURL(url); + } + }, template: `

Bestellungen

@@ -307,13 +340,25 @@ Vue.component('dashboard-default', {

Bestellverlauf

+ + +
+ + + + + +
+
Bestellungen @@ -439,57 +491,51 @@ Vue.component('dashboard-rml', {

Bestellverlauf

+
+ + + + + +
+
{ + return selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1])) + }), + color: 'rgb(75, 192, 192)', + fill: true, + yAxisID: 'y', + order: 3 + }, + { + label: 'Leerrohr', + data: dashboardData.timeline_leerrohr[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), + color: 'rgb(255, 99, 132)', + fill: false, + yAxisID: 'y', + order: 2 + }, + { + label: 'ONT installiert', + data: dashboardData.timeline_ont_installed[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), + color: 'rgb(54, 162, 235)', + fill: false, + yAxisID: 'y', + order: 1 + } + ]" label="KW" :showGrid="false" /> +
-
- ` +
` }) From cc58b323125c356e42239a1f18e6607e6777f7d1 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Wed, 12 Feb 2025 17:56:34 +0100 Subject: [PATCH 05/19] Changed Dashboard --- public/js/pages/DashboardNew/DashboardNew.js | 54 +++++++++++++++++--- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/public/js/pages/DashboardNew/DashboardNew.js b/public/js/pages/DashboardNew/DashboardNew.js index c08acbdda..fa80d9671 100644 --- a/public/js/pages/DashboardNew/DashboardNew.js +++ b/public/js/pages/DashboardNew/DashboardNew.js @@ -399,6 +399,32 @@ Vue.component('dashboard-rml', { moment: moment } }, + methods: { + exportTimeline() { + // we need all timelines with "ONT installiert", "Leerrohr", "Bestellungen" + const data = this.dashboardData.timeline[0].map((item, index) => ({ + date: item.date, + bestellungen: item.value, + leerrohr: this.dashboardData.timeline_leerrohr[0][index].value, + ont_installiert: this.dashboardData.timeline_ont_installed[0][index].value + })); + + // dont use any library for the csv + const csv = [ + ['Datum', 'Bestellungen', 'Leerrohr', 'ONT installiert'], + ...data.map(item => [item.date, item.bestellungen, item.leerrohr, item.ont_installiert]) + ].map(row => row.join(',')).join('\n'); + + const blob = new Blob([csv], {type: 'text/csv'}); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + + a.href = url; + a.download = 'timeline.csv'; + a.click(); + URL.revokeObjectURL(url); + } + }, template: `

Bestellungen

@@ -514,17 +540,33 @@ Vue.component('dashboard-rml', { order: 3 }, { - label: 'Leerrohr', - data: dashboardData.timeline_leerrohr[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), - color: 'rgb(255, 99, 132)', + label: 'Summe von 244+245', + data: dashboardData.timeline_inhouse_kabel_verlegt_efh[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), + color: 'rgb(0, 123, 255)', fill: false, yAxisID: 'y', order: 2 }, { - label: 'ONT installiert', - data: dashboardData.timeline_ont_installed[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), - color: 'rgb(54, 162, 235)', + label: 'Status 500 Energie Steiermark', + data: dashboardData.timeline_status_500_energie_steiermark[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), + color: 'rgb(40, 167, 69)', + fill: false, + yAxisID: 'y', + order: 1 + }, + { + label: 'Status 500 Magenta', + data: dashboardData.timeline_status_500_magenta[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), + color: 'rgb(226, 0, 116)', + fill: false, + yAxisID: 'y', + order: 1 + }, + { + label: 'Status 500 Salzburg AG', + data: dashboardData.timeline_status_500_salzburg_ag[0].filter(item => selectedTimeframe === 'all' || moment(item.date).isAfter(moment().subtract(selectedTimeframe.split(' ')[0], selectedTimeframe.split(' ')[1]))), + color: 'rgb(0, 102, 179)', fill: false, yAxisID: 'y', order: 1 From bb5a993c27045e0344368499909709d55ef1363f Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Wed, 12 Feb 2025 17:03:08 +0000 Subject: [PATCH 06/19] Update DashboardNew.js --- public/js/pages/DashboardNew/DashboardNew.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/pages/DashboardNew/DashboardNew.js b/public/js/pages/DashboardNew/DashboardNew.js index fa80d9671..e7ebf9043 100644 --- a/public/js/pages/DashboardNew/DashboardNew.js +++ b/public/js/pages/DashboardNew/DashboardNew.js @@ -211,7 +211,7 @@ Vue.component('dashboard-default', { const csv = [ ['Datum', 'Bestellungen', 'Leerrohr', 'ONT installiert'], ...data.map(item => [item.date, item.bestellungen, item.leerrohr, item.ont_installiert]) - ].map(row => row.join(',')).join('\n'); + ].map(row => row.join(';')).join('\n'); const blob = new Blob([csv], {type: 'text/csv'}); const url = URL.createObjectURL(blob); @@ -413,7 +413,7 @@ Vue.component('dashboard-rml', { const csv = [ ['Datum', 'Bestellungen', 'Leerrohr', 'ONT installiert'], ...data.map(item => [item.date, item.bestellungen, item.leerrohr, item.ont_installiert]) - ].map(row => row.join(',')).join('\n'); + ].map(row => row.join(';')).join('\n'); const blob = new Blob([csv], {type: 'text/csv'}); const url = URL.createObjectURL(blob); From 5e8ec1d07d4024917390a6c2a393c22812ddcc79 Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Wed, 12 Feb 2025 18:19:20 +0100 Subject: [PATCH 07/19] =?UTF-8?q?Kalender=20Bugfix=20*=20Ab=20und=20zu=20p?= =?UTF-8?q?assiert=20es=20das=20Kalendereintr=C3=A4ge=20doppelt=20angezeig?= =?UTF-8?q?t=20werden.=20Es=20gab=20eine=20=C3=BCberschneidung=20mit=20den?= =?UTF-8?q?=20Event=20id=20->=20gefixt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Layout/default/Calendar/View.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Layout/default/Calendar/View.php b/Layout/default/Calendar/View.php index 8a5813aec..d590b86b6 100644 --- a/Layout/default/Calendar/View.php +++ b/Layout/default/Calendar/View.php @@ -34,6 +34,8 @@ endforeach; type="text/css"/> + + + + + + + diff --git a/application/WarehouseOffer/WarehouseOfferController.php b/application/WarehouseOffer/WarehouseOfferController.php index e9a80096b..66fa5008f 100644 --- a/application/WarehouseOffer/WarehouseOfferController.php +++ b/application/WarehouseOffer/WarehouseOfferController.php @@ -30,6 +30,10 @@ class WarehouseOfferController extends TTCrud { ['key' => 'sendOffer', 'title' => 'Angebot senden', 'class' => 'fas fa-paper-plane text-success'] ]; + protected array $additionalJS = [' + https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js + https://cdn.jsdelivr.net/npm/vue-draggable-next@2.1.0']; + protected array $infoMessages = [ 'create' => 'Angebot wurde erfolgreich erstellt.', 'update' => 'Angebot wurde aktualisiert.', diff --git a/application/WarehouseOrder/WarehouseOrderController.php b/application/WarehouseOrder/WarehouseOrderController.php index 19548172d..e45cebabc 100644 --- a/application/WarehouseOrder/WarehouseOrderController.php +++ b/application/WarehouseOrder/WarehouseOrderController.php @@ -9,18 +9,18 @@ class WarehouseOrderController extends TTCrud { protected array $columns = [ ['key' => 'id', 'text' => 'ID', 'modal' => false, 'table' => false], ['key' => 'orderNumber', 'text' => 'Bestellnummer', 'required' => true, 'modal' => false], - ['key' => 'distributor', 'text' => 'Lieferant', 'required' => false, 'modal' => false, 'table' => ['filter' => false]], + ['key' => 'distributorId', 'text' => 'Lieferant', 'required' => false, 'modal' => ['type' => 'select', 'items' => []], 'table' => ['filter' => 'select']], ['key' => 'delAddrCity', 'text' => 'Stadt', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrEMail', 'text' => 'E-Mail', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrLine', 'text' => 'Adresse', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrName', 'text' => 'Name', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrPLZ', 'text' => 'PLZ', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'editor', 'text' => 'Bearbeiter', 'required' => true, 'modal' => ['type' => 'select'], 'table' => ['filter' => 'select']], - ['key' => 'note', 'text' => 'Notiz', 'required' => true, 'modal' => false, 'table' => false], + ['key' => 'note', 'text' => 'Notiz', 'required' => false, 'modal' => false, 'table' => false], ['key' => 'sum', 'text' => 'Summe', 'required' => false, 'modal' => false, 'table' => ['class' => 'text-right']], ['key' => 'status', 'text' => 'Status', 'required' => false, 'modal' => ['type' => 'select', 'items' => []], 'table' => ['filter' => 'select']], ['key' => 'positions', 'text' => 'Positionen', 'required' => true, 'modal' => false, 'table' => false], - ['key' => 'extReference', 'text' => 'Externe Referenz', 'required' => true, 'modal' => false], + ['key' => 'extReference', 'text' => 'Externe Referenz', 'required' => false, 'modal' => false], ['key' => 'createBy', 'text' => 'Erstellt von', 'required' => true, 'modal' => ['type' => 'select'], 'table' => ['filter' => 'select']], ['key' => 'create', 'text' => 'Erstellt', 'required' => true, 'modal' => false], ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']], @@ -32,6 +32,8 @@ class WarehouseOrderController extends TTCrud { 'delete' => 'Bestellung wurde gelöscht', 'noChanges' => 'Keine Änderungen',]; + protected array $additionalActions = [['key' => 'openpdf', 'title' => 'PDF öffnen', 'class' => 'fas fa-file-pdf', 'color' => 'primary']]; + protected function prepareCrudConfig(): void { $editorColumnIndex = array_search('editor', array_column($this->columns, 'key')); $this->columns[$editorColumnIndex]['modal']['items'] = array_map(function ($user) { @@ -48,6 +50,11 @@ class WarehouseOrderController extends TTCrud { ['value' => 'fullyDelivered', 'text' => 'Geliefert'], ['value' => 'cancelled', 'text' => 'Storniert'], ]; + + $distributorIndex = array_search('distributorId', array_column($this->columns, 'key')); + $this->columns[$distributorIndex]['modal']['items'] = array_map(function ($distributor) { + return ['value' => intval($distributor->id), 'text' => $distributor->name]; + }, WarehouseDistributorModel::getAll()); } protected function beforeCreate(): bool { @@ -91,40 +98,43 @@ class WarehouseOrderController extends TTCrud { // we need to get the article name and distributor name for the pdf $position['distributorName'] = WarehouseDistributorModel::get($position['distributorId'])->name; $position['articleName'] = WarehouseArticleModel::get($position['article'])->title; + $position['articleDescription'] = WarehouseArticleModel::get($position['article'])->description; $order['positions'][$key] = $position; } $pdf_vars = ['order' => $order, 'distributor' => WarehouseDistributorModel::get($distributorId), + 'distributorCountryText' => (new Country(WarehouseDistributorModel::get($distributorId)->countryId))->name, "bank_iban" => TT_INVOICE_BANK_IBAN, "bank_bic" => TT_INVOICE_BANK_BIC, "bank_bank" => TT_INVOICE_BANK_BANK, "bank_owner" => TT_INVOICE_BANK_OWNER]; - - $countryText = CountryModel::search(['id' => WarehouseDistributorModel::get($distributorId)->countryId])[0]->name; + $countryText = (new Country(WarehouseDistributorModel::get($distributorId)->countryId))->name; + $shouldGenerateEnglisch = !in_array($countryText, ['Österreich', 'Deutschland', 'Schweiz']); $headerHtml = file_get_contents(BASEDIR . "/Layout/default/WarehouseOrder/PDF_HEADER.html"); $headerHtml = str_replace("{{ basedir }}", BASEDIR, $headerHtml); - $headerHtml = str_replace("{{ externalReference }}","Ihre Referenz: ". $order['extReference'], $headerHtml); + $headerHtml = str_replace("{{ externalReference }}", count($order['extReference']) > 0 ? "Ext. Ref.: ". $order['extReference'] : "", $headerHtml); + $headerHtml = str_replace("{{ addressLine_header }}", $shouldGenerateEnglisch ? "Supplier" : "Lieferant", $headerHtml); $headerHtml = str_replace("{{ addressLine_1 }}", WarehouseDistributorModel::get($distributorId)->name, $headerHtml); $headerHtml = str_replace("{{ addressLine_2 }}", WarehouseDistributorModel::get($distributorId)->address, $headerHtml); $headerHtml = str_replace("{{ addressLine_3 }}", WarehouseDistributorModel::get($distributorId)->plz . " " . WarehouseDistributorModel::get($distributorId)->city, $headerHtml); $headerHtml = str_replace("{{ addressLine_4 }}", $countryText, $headerHtml); + $headerHtml = str_replace("{{ billingAddressLine_header }}", $shouldGenerateEnglisch ? "Billing Address" : "Rechnungsadresse", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_1 }}", "Xinon GmbH", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_2 }}", "Fladnitz im Raabtal 150", $headerHtml); - $headerHtml = str_replace("{{ billingAddressLine_3 }}", "8322 Studenzen", $headerHtml); - $headerHtml = str_replace("{{ billingAddressLine_4 }}", "Österreich", $headerHtml); - $headerHtml = str_replace("{{ billingAddressLine_5 }}", "einkauf@xinon.at", $headerHtml); + $headerHtml = str_replace("{{ billingAddressLine_3 }}", "A-8322 Studenzen", $headerHtml); + $headerHtml = str_replace("{{ billingAddressLine_4 }}", "UID: ATU68711968", $headerHtml); + $headerHtml = str_replace("{{ billingAddressLine_5 }}", "EORI-Nr.: ATEOS1000085074", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_6 }}", "Referenz: ". $order["orderNumber"] . "", $headerHtml); - // if order dellAddrLine is Fladnitz im Raabtal 150 we need to set all template strings to empty - $chk = $order['delAddrLine'] == "Fladnitz im Raabtal 150"; + $headerHtml = str_replace("{{ shippingAddressLine_header }}", $chk ? "" : ($shouldGenerateEnglisch ? "Shipping Address" : "Lieferadresse"), $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_1 }}", $chk ? "" : $order['delAddrName'], $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_2 }}", $chk ? "" : $order['delAddrLine'], $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_3 }}", $chk ? "" : $order['delAddrPLZ'] . " " . $order['delAddrCity'], $headerHtml); diff --git a/public/js/pages/WarehouseOffer/WarehouseOffer.js b/public/js/pages/WarehouseOffer/WarehouseOffer.js index fe1365051..c57ea2186 100644 --- a/public/js/pages/WarehouseOffer/WarehouseOffer.js +++ b/public/js/pages/WarehouseOffer/WarehouseOffer.js @@ -15,24 +15,22 @@ Vue.component('warehouse-offer-modal', { sm row v-model="offer.editor"/> - + +

Kundenadresse

-
+
+ -

Positionen

- -
-

Alternative Artikel

- +
@@ -45,6 +43,7 @@ Vue.component('warehouse-offer-modal', { `, data() { return { + billAddrAutoCompleteUrl: window.TT_CONFIG['BASE_PATH'] + '/Address/Api?do=findAddress&fibu_primary_account=1', window: window, positionsConfig: { fields: { @@ -57,6 +56,7 @@ Vue.component('warehouse-offer-modal', { amount: {type: 'input', label: 'Menge', inputType: 'number'}, unit: {type: 'input', label: 'Einheit'}, articleNumber: {type: 'input', label: 'Artikelnummer'}, + isAlternative: {type: 'checkbox', label: 'Alternativposition'}, unitPrice: {type: 'input', label: 'Einzelpreis', inputType: 'number'}, discount: {type: 'input', label: 'Rabatt (%)', inputType: 'number'}, }, @@ -71,12 +71,6 @@ Vue.component('warehouse-offer-modal', { return true; }, }, - alternativePositionsConfig: { - fields: { - article: {type: 'input', label: 'Artikel'}, - description: {type: 'textarea', label: 'Beschreibung'}, - }, - }, paymentTerms: [ {value: 'net30', text: '30 Tage netto'}, {value: 'net60', text: '60 Tage netto'}, diff --git a/public/js/pages/WarehouseOrder/WarehouseOrder.js b/public/js/pages/WarehouseOrder/WarehouseOrder.js index c9b937d86..c274ae0ca 100644 --- a/public/js/pages/WarehouseOrder/WarehouseOrder.js +++ b/public/js/pages/WarehouseOrder/WarehouseOrder.js @@ -218,19 +218,20 @@ Vue.component('warehouse-order', { - + - - `, data() { return { + window: window, orderModalId: null, } }, diff --git a/public/plugins/vue/tt-components/tt-position-manager.js b/public/plugins/vue/tt-components/tt-position-manager.js index 7d8996bbd..26aaee48a 100644 --- a/public/plugins/vue/tt-components/tt-position-manager.js +++ b/public/plugins/vue/tt-components/tt-position-manager.js @@ -1,13 +1,42 @@ +Vue.component('tt-resolver', { + props: { + value: {type: Number, required: true}, + reference: {type: String, required: true}, + }, + data() { + return { + window: window, + loading: true, + text: '', + } + }, + template: ` +
+
+ Loading... +
+
+ {{ text }} + `, + async created() { + const entry = await axios.get(window.TT_CONFIG['BASE_PATH'] + '/' + this.reference + '/getById?id=' + this.value); + this.text = entry.data.name ?? entry.data.title ?? entry.data.text ?? '[E] Key not found'; + this.loading = false; + } +}) + Vue.component('tt-positions-manager', { props: { - value: {type: Array, required: false}, - config: {type: Object, required: true}, + value: {type: Array, required: false}, + config: {type: Object, required: true}, + groupMode: {type: Boolean, default: false}, }, data() { return { window: window, positions: this.value, formData: {}, + groupName: '', selectedIndex: null, resolvingFields: {}, } @@ -63,6 +92,12 @@ Vue.component('tt-positions-manager', {
+ +
+ + +
+ @@ -71,24 +106,50 @@ Vue.component('tt-positions-manager', { - -
-
@@ -110,6 +171,10 @@ Vue.component('tt-positions-manager', { this.$emit('input', this.positions); this.resetForm(); }, + addGroup() { + this.positions.push({_group: this.groupName}); + this.groupName = ''; + }, editEntry(index) { this.selectedIndex = index; this.formData = {...this.positions[index]}; @@ -133,7 +198,7 @@ Vue.component('tt-positions-manager', { this.$set(this.resolvingFields, i + key, true); const textValue = await this.config.fields[key].customFieldResolver(this.positions[i][key]); this.$set(this.resolvingFields, i + key, textValue); - } else if (this.config.fields[key].customFieldReference) { + } else if (this.config.fields[key].customFieldReference && this.positions[i][key]) { this.$set(this.resolvingFields, i + key, true); if (this.config.fields[key].customFieldReference) { const entry = await axios.get(window.TT_CONFIG['BASE_PATH'] + @@ -153,7 +218,21 @@ Vue.component('tt-positions-manager', { created() { if (this.config.customMethods) Object.assign(this, this.config.customMethods); }, - watch: { + computed: { + groupedPositions() { + const groups = {}; + for (const position of this.positions) { + const group = position._group ?? 'Keine Gruppe'; + if (!groups[group]) groups[group] = []; + if (Object.keys(position).length !== 1) groups[group].push(position); + } + return groups; + }, + allGroups() { + return Object.keys(this.groupedPositions); + } + }, + watch: { positions: { handler() { this.resolveFields().then(); From 8f20ce39d6b8846108a781c64f2dee462710d0bb Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Thu, 13 Feb 2025 12:09:35 +0100 Subject: [PATCH 11/19] Allowed ingena for cons consent --- Layout/default/menu.php | 2 +- .../ConstructionConsent/ConstructionConsentController.php | 2 +- .../ConstructionConsentProjectController.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Layout/default/menu.php b/Layout/default/menu.php index 0acf0392f..a361821d2 100644 --- a/Layout/default/menu.php +++ b/Layout/default/menu.php @@ -198,7 +198,7 @@ is(["Admin","salespartner"]) && $me->can("Order")): ?>
  • "> Bestellungen
  • - is(["Admin","netowner","salespartner"]) && in_array($me->address_id, [1,209,5908])): ?> + is(["Admin","netowner","salespartner"]) && in_array($me->address_id, [1,209,5908,2187])): ?>
  • "> Zustimmungserklärungen
  • diff --git a/application/ConstructionConsent/ConstructionConsentController.php b/application/ConstructionConsent/ConstructionConsentController.php index 7ed55d299..369bbe1b2 100644 --- a/application/ConstructionConsent/ConstructionConsentController.php +++ b/application/ConstructionConsent/ConstructionConsentController.php @@ -10,7 +10,7 @@ class ConstructionConsentController extends mfBaseController { $this->me = $me; $this->layout()->set("me", $me); - if (!($me->is(["Admin","netowner","salespartner"]) && in_array($me->address_id, [1,209,5908]))) $this->redirect("Dashboard"); + if (!($me->is(["Admin","netowner","salespartner"]) && in_array($me->address_id, [1,209,5908,2187]))) $this->redirect("Dashboard"); } protected function indexAction() : void { diff --git a/application/ConstructionConsentProject/ConstructionConsentProjectController.php b/application/ConstructionConsentProject/ConstructionConsentProjectController.php index fa6b13769..0086383c2 100644 --- a/application/ConstructionConsentProject/ConstructionConsentProjectController.php +++ b/application/ConstructionConsentProject/ConstructionConsentProjectController.php @@ -10,7 +10,7 @@ class ConstructionConsentProjectController extends mfBaseController { $this->me = $me; $this->layout()->set("me", $me); - if (!($me->is(["Admin","netowner","salespartner"]) && in_array($me->address_id, [1,209,5908]))) $this->redirect("Dashboard"); + if (!($me->is(["Admin","netowner","salespartner"]) && in_array($me->address_id, [1,209,5908,2187]))) $this->redirect("Dashboard"); } protected function indexAction() : void { From 71b72151f6d19f7c439272684c8f787658101b71 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Thu, 13 Feb 2025 12:33:21 +0100 Subject: [PATCH 12/19] Fixed WarehouseOrderModel.php --- application/WarehouseOrder/WarehouseOrderModel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/WarehouseOrder/WarehouseOrderModel.php b/application/WarehouseOrder/WarehouseOrderModel.php index ac4677800..3d7cbf339 100644 --- a/application/WarehouseOrder/WarehouseOrderModel.php +++ b/application/WarehouseOrder/WarehouseOrderModel.php @@ -23,7 +23,7 @@ class WarehouseOrderModel extends TTCrudBaseModel { public int $id; public string $orderNumber; - public string $extReference; + public ?string $extReference; public int $distributorId; public string $delAddrCity; public string $delAddrEMail; @@ -31,7 +31,7 @@ class WarehouseOrderModel extends TTCrudBaseModel { public string $delAddrName; public string $delAddrPLZ; public int $editor; - public string $note; + public ?string $note; public string $positions; public int $create; public int $createBy; From ac5c09c8be5dc4b5e2b5cfcd50819872edb6484f Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Thu, 13 Feb 2025 12:37:10 +0100 Subject: [PATCH 13/19] Fixed WarehouseOffer Modal --- .../js/pages/WarehouseOffer/WarehouseOffer.js | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/public/js/pages/WarehouseOffer/WarehouseOffer.js b/public/js/pages/WarehouseOffer/WarehouseOffer.js index c57ea2186..38b0b53c9 100644 --- a/public/js/pages/WarehouseOffer/WarehouseOffer.js +++ b/public/js/pages/WarehouseOffer/WarehouseOffer.js @@ -35,7 +35,7 @@ Vue.component('warehouse-offer-modal', { - +
    @@ -81,11 +81,6 @@ Vue.component('warehouse-offer-modal', { {value: 'free_delivery', text: 'Frei Haus'}, {value: 'fob', text: 'FOB'}, ], - closingTexts: [ - {value: 'standard', text: 'Standardtext'}, - {value: 'custom1', text: 'Angepasster Text 1'}, - {value: 'custom2', text: 'Angepasster Text 2'}, - ], offer: { editor: window.TT_CONFIG['USER_ID'], customerNumber: '', @@ -101,7 +96,18 @@ Vue.component('warehouse-offer-modal', { totalDiscount: 0, paymentTerms: 'net30', deliveryTerms: 'ex_works', - closingText: 'standard', + closingText: 'Sollten sich die Rohstoffpreise bzw. die Preise unserer Zulieferer um mehr als 10% innerhalb der Angebots bzw.\n' + + '\n' + + 'Auftragsgültigkeit erhöhen (Stichtag Datum), sind wir gezwungen die Preise anzupassen.\n' + + '\n' + + 'Diese Angebot hat eine Gültigkeit von 4 Wochen.\n' + + '\n' + + 'Verrechnung erfolgt nach tatsächlichem Aufwand.\n' + + '\n' + + 'Wir sind sicher, Ihnen ein konkurenzfähiges Angebot unterbreitet zu haben und sehen gern Ihrer Bestellung entgegen.\n' + + '\n' + + 'Sollten Sie noch Fragen oder weitere Informationen benötigen stehen wir Ihnen jederzeit gern zu Verfügung.\n' + + ' ', notes: '', } } From 9e513dfb357e2227ec4151e45e2c5556b9759abd Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Thu, 13 Feb 2025 12:47:54 +0100 Subject: [PATCH 14/19] Added Popover to Inform Users --- Layout/default/ConstructionConsent/Form.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Layout/default/ConstructionConsent/Form.php b/Layout/default/ConstructionConsent/Form.php index 3f518f870..14a73ad35 100644 --- a/Layout/default/ConstructionConsent/Form.php +++ b/Layout/default/ConstructionConsent/Form.php @@ -55,9 +55,9 @@
    - +
    - " placeholder="z.B. Straße oder Adresse" /> + " placeholder="z.B. Straße oder Adresse" data-toggle="popover" data-trigger="focus" data-placement="left" data-content="Wird in der Zustimmungserklärung in der Objektanschrift verwendet." />
    @@ -391,6 +391,20 @@ $("#gstnr").val(kg + gst); } + $(document).ready(function(){ + $('[data-toggle="popover"]').popover(); + }); + + + + \ No newline at end of file From cb17eba40be2f3230b12006d989646f590973848 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Fri, 14 Feb 2025 10:00:43 +0000 Subject: [PATCH 15/19] Update tt-modal.js --- public/plugins/vue/tt-components/tt-modal.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/plugins/vue/tt-components/tt-modal.js b/public/plugins/vue/tt-components/tt-modal.js index 1b64e2814..72ab3af7f 100644 --- a/public/plugins/vue/tt-components/tt-modal.js +++ b/public/plugins/vue/tt-components/tt-modal.js @@ -55,7 +55,6 @@ Vue.component('tt-modal', { tabindex="-1" style="background: rgba(0, 0, 0, 0.5);" ref="modal" - @mousedown="!isMobile ? $emit('update:show', false) : null" @keydown.esc="$emit('update:show', false)" v-if="show"> ` -}) \ No newline at end of file +}) From d0404f515dd1b136c197399af850fa25d216d671 Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Fri, 14 Feb 2025 12:30:21 +0100 Subject: [PATCH 16/19] =?UTF-8?q?Zeiterfassung=20Update=20=20*=20Gesammtsu?= =?UTF-8?q?mme=20bei=20Admin=20Only=20Mitarbeitern=20einfef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Layout/default/Timerecording/Index.php | 29 ++++++++++++++----- .../Timerecording/TimerecordingController.php | 6 ++++ .../Timerecording/TimerecordingModel.php | 15 ++++++++++ public/js/pages/timerecording/index.js | 4 +++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/Layout/default/Timerecording/Index.php b/Layout/default/Timerecording/Index.php index d4bbd8b9c..7a96f9097 100644 --- a/Layout/default/Timerecording/Index.php +++ b/Layout/default/Timerecording/Index.php @@ -95,6 +95,10 @@ $mindate = date("Y-m-d", strtotime("+ 1 Month", $closedmonth)); .holiday-text { color: #d70000; } + .height-unset + { + height: unset; + } @@ -314,16 +318,12 @@ $mindate = date("Y-m-d", strtotime("+ 1 Month", $closedmonth));
    - +
    - +
    @@ -332,19 +332,32 @@ $mindate = date("Y-m-d", strtotime("+ 1 Month", $closedmonth));
    -
    -
    + +
    + + diff --git a/application/Timerecording/TimerecordingController.php b/application/Timerecording/TimerecordingController.php index db4bcde7e..e1446ab49 100644 --- a/application/Timerecording/TimerecordingController.php +++ b/application/Timerecording/TimerecordingController.php @@ -680,6 +680,7 @@ class TimerecordingController extends mfBaseController $holiDays = 0; $plusHours = 0; $startdate = time(); + $allhours=0; if (!$userid) { $userid = $this->me->id; } @@ -697,6 +698,10 @@ class TimerecordingController extends mfBaseController } $overtime = $employee[0]->overtime_now; + if ($employee[0]->only_admin) { + $getAllHours=TimerecordingModel::getAllHours($userid); + $getAllHours=$getAllHours[0]->gesamt_summe; + } } $workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $userid]); $holidays = TimerecordingHolidayModel::getAll(); @@ -1155,6 +1160,7 @@ class TimerecordingController extends mfBaseController $json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60)); $json['time']['holidays'] = $holiDays; $json['time']['plushours'] = $plusHours; + $json['time']['AllHours'] = sprintf('%02dh:%02dm', floor($getAllHours / 3600), floor($getAllHours / 60 % 60));; $json['data'] = $rows; $json['recordsFiltered'] = $responsecount; $json['recordsTotal'] = $responsecount; diff --git a/application/Timerecording/TimerecordingModel.php b/application/Timerecording/TimerecordingModel.php index 1d7b16a17..b942f640e 100644 --- a/application/Timerecording/TimerecordingModel.php +++ b/application/Timerecording/TimerecordingModel.php @@ -73,6 +73,21 @@ class TimerecordingModel } return $item; } + public static function getAllHours($user_id) + { + $items = []; + + $db = FronkDB::singleton(); + $sql="SELECT SUM(`end` - `start`) AS gesamt_summe FROM Timerecording where user_id=$user_id AND `timerecordingCategory_id` =1"; + $res = $db->query($sql); + if ($db->num_rows($res)) { + while ($data = $db->fetch_object($res)) { + $items[] = new Timerecording($data); + } + } + return $items; + + } public static function getAll() { diff --git a/public/js/pages/timerecording/index.js b/public/js/pages/timerecording/index.js index 8bebe8264..e159e2480 100644 --- a/public/js/pages/timerecording/index.js +++ b/public/js/pages/timerecording/index.js @@ -87,6 +87,10 @@ table = $('#datatable').DataTable({ $('#must-time').text(json.time.must); $('#holidays').text(json.time.holidays); $('#plushours').text(json.time.plushours); + if (json.time.AllHours>0) { + $('#AllHours-div').show(); + $('#AllHours').text(json.time.AllHours); + } if ($("#plushours").text().includes("-")) { $('#plushours-label').css('background-color', '#fda7a7'); } else { From 38e405a2cdf1545d52f86df264927b6de36afb78 Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Fri, 14 Feb 2025 12:47:49 +0100 Subject: [PATCH 17/19] =?UTF-8?q?Zeiterfassung=20Update=20=20*=20Gesammtsu?= =?UTF-8?q?mme=20bei=20Admin=20Only=20Mitarbeitern=20einfef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/pages/timerecording/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/pages/timerecording/index.js b/public/js/pages/timerecording/index.js index e159e2480..b54a528e1 100644 --- a/public/js/pages/timerecording/index.js +++ b/public/js/pages/timerecording/index.js @@ -87,7 +87,7 @@ table = $('#datatable').DataTable({ $('#must-time').text(json.time.must); $('#holidays').text(json.time.holidays); $('#plushours').text(json.time.plushours); - if (json.time.AllHours>0) { + if (json.time.AllHours!=0) { $('#AllHours-div').show(); $('#AllHours').text(json.time.AllHours); } From e822ffe718ea1bf87e41c01a2c542712546d7ac6 Mon Sep 17 00:00:00 2001 From: Daniel Spitzer Date: Fri, 14 Feb 2025 12:51:20 +0100 Subject: [PATCH 18/19] =?UTF-8?q?Zeiterfassung=20Update=20=20*=20Gesammtsu?= =?UTF-8?q?mme=20bei=20Admin=20Only=20Mitarbeitern=20einfef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/pages/timerecording/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/pages/timerecording/index.js b/public/js/pages/timerecording/index.js index b54a528e1..0e20748d9 100644 --- a/public/js/pages/timerecording/index.js +++ b/public/js/pages/timerecording/index.js @@ -87,7 +87,7 @@ table = $('#datatable').DataTable({ $('#must-time').text(json.time.must); $('#holidays').text(json.time.holidays); $('#plushours').text(json.time.plushours); - if (json.time.AllHours!=0) { + if (json.time.AllHours!="00h:00m") { $('#AllHours-div').show(); $('#AllHours').text(json.time.AllHours); } From f89a2c7ea3799a698f95d4595fac8d019a869083 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Fri, 14 Feb 2025 11:51:45 +0000 Subject: [PATCH 19/19] Added ConstructionConsentProject to preorderfront if address is correct --- Layout/default/menu.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Layout/default/menu.php b/Layout/default/menu.php index a361821d2..4ac0041c7 100644 --- a/Layout/default/menu.php +++ b/Layout/default/menu.php @@ -11,6 +11,9 @@