From 5bb51fd676899710168d430d7683ef739acdae92 Mon Sep 17 00:00:00 2001 From: Luca Haid Date: Wed, 20 Nov 2024 12:26:22 +0000 Subject: [PATCH] switched 2 inputs --- .../WarehouseShippingNoteController.php | 35 +++++- .../WarehouseShippingNote.css | 4 + .../WarehouseShippingNoteModal.js | 116 ++++++++++++------ .../vue/tt-components/tt-autocomplete.js | 5 +- public/plugins/vue/tt-components/tt-modal.js | 4 +- 5 files changed, 118 insertions(+), 46 deletions(-) diff --git a/application/WarehouseShippingNote/WarehouseShippingNoteController.php b/application/WarehouseShippingNote/WarehouseShippingNoteController.php index e8181f742..3c87f0861 100644 --- a/application/WarehouseShippingNote/WarehouseShippingNoteController.php +++ b/application/WarehouseShippingNote/WarehouseShippingNoteController.php @@ -15,7 +15,7 @@ class WarehouseShippingNoteController extends TTCrud { ['key' => 'deliveryAddressLine', 'text' => 'L.-Adr.', 'required' => true], ['key' => 'deliveryAddressPLZ', 'text' => 'L.-Adr. PLZ', 'required' => true], ['key' => 'deliveryAddressEMail', 'text' => 'L.-Adr. EMail', 'required' => true, 'table' => false], - ['key' => 'note', 'text' => 'Notiz', 'required' => true, 'table' => false], + ['key' => 'note', 'text' => 'Art der Arbeit', 'required' => true, 'table' => false], ['key' => 'status', 'text' => 'Status', 'required' => true, @@ -387,6 +387,37 @@ class WarehouseShippingNoteController extends TTCrud { die(json_encode(['success' => true, 'status' => 'USER_NO_CAR'])); } + protected function geoAutocompleteAction() { + $search = $this->request->q; + $search = urlencode($search); + $url = "https://nominatim.haid.in/search?q=$search&format=json"; + $data = json_decode(file_get_contents($url), true); + $out = []; + + + + foreach ($data as $entry) { + $parsedDisplayNameParts = []; + foreach(explode(',', $entry['display_name']) as $part) { + // if str_includes Bezirk remove it + if (strpos($part, 'Bezirk') !== false) { + continue; + } + $parsedDisplayNameParts[] = $part; + } + $out[] = ['value' => $entry['lat'] . "," . $entry['lon'], 'text' => implode(',', $parsedDisplayNameParts)]; + } + self::returnJson($out); + } + + protected function geoReverseAction() { + $lat = $this->request->lat; + $lon = $this->request->lon; + $url = "https://nominatim.haid.in/reverse?lat=$lat&lon=$lon&format=json"; + $data = json_decode(file_get_contents($url), true); + self::returnJson($data); + } + //TODO: export this to an api class for openstreetmap protected function getDistanceAction() { @@ -413,7 +444,7 @@ class WarehouseShippingNoteController extends TTCrud { $curl = curl_init(); curl_setopt_array($curl, [ - CURLOPT_URL => "https://nominatim.openstreetmap.org/search?q=$address&format=json", + CURLOPT_URL => "https://nominatim.haid.in/search?q=$address&format=json", CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_ENCODING => "", diff --git a/public/js/pages/WarehouseShippingNote/WarehouseShippingNote.css b/public/js/pages/WarehouseShippingNote/WarehouseShippingNote.css index 4cde1ab0c..c4baf9c04 100644 --- a/public/js/pages/WarehouseShippingNote/WarehouseShippingNote.css +++ b/public/js/pages/WarehouseShippingNote/WarehouseShippingNote.css @@ -36,6 +36,10 @@ grid-gap: 10px; } + .warehouse-shipping-note-modal-positions-entry-actions, .warehouse-shipping-note-modal-hours-entry-actions { + grid-column: 2; + } + .signModal > div { margin: 0; width: 100vw; diff --git a/public/js/pages/WarehouseShippingNote/WarehouseShippingNoteModal.js b/public/js/pages/WarehouseShippingNote/WarehouseShippingNoteModal.js index 47813c404..09d95b9b0 100644 --- a/public/js/pages/WarehouseShippingNote/WarehouseShippingNoteModal.js +++ b/public/js/pages/WarehouseShippingNote/WarehouseShippingNoteModal.js @@ -96,9 +96,11 @@ Vue.component('warehouse-shipping-note-modal-hours-entry', { this.kilometerCount = response.data.distance }, async updateCarId() { + if (!this.userId || this.carId) return; const response = await axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseShippingNote/timerecordingCarForUser?userId=' + this.userId); if (response.data.status === 'USER_NO_CAR') { this.window.notify('info', 'Kein zugewiesenes Fahrzeug gefunden'); + this.carId = ''; return; } this.carId = response.data.id; @@ -114,8 +116,8 @@ Vue.component('warehouse-shipping-note-modal-hours-entry', { } }, async mounted() { - if (!this.carId) this.updateCarId().then(); if (!this.userId) this.userId = this.window.TT_CONFIG['USER_ID']; + if (!this.carId) this.updateCarId().then(); if (!this.date) this.updateDate(); if (!this.kilometerCount) this.updateKilometerCount().then(); @@ -273,7 +275,7 @@ Vue.component('warehouse-shipping-note-modal-positions-entry', { if (!this.price) return this.window.notify('error', 'Bitte füllen sie den Preis aus'); const data = { amount: this.amount, - price: parseFloat(this.price) + price: parseFloat(this.price) } if (!this.articleId && this.$refs.article.displayValue) { data.articleText = this.$refs.article.displayValue; @@ -331,7 +333,9 @@ Vue.component('warehouse-shipping-note-modal-positions-view', { Keine Einträge - {{ position.article ? articleNames[position.article] : position.articlePacket ? articlePacketNames[position.articlePacket] : position.articleText }} + {{ position.article ? articleNames[position.article] : position.articlePacket ? articlePacketNames[position.articlePacket] : + position.articleText }} + {{ position.amount }} {{ (position.price?.toFixed(2)) }} € @@ -415,7 +419,7 @@ Vue.component('warehouse-shipping-note-modal-positions', { }, editEntry(entry) { this.selectedUpdateIndex = this.positions.indexOf(entry); - if (entry.article)this.$refs.entry.articleId = entry.article; + if (entry.article) this.$refs.entry.articleId = entry.article; if (entry.articlePacket) this.$refs.entry.articlePacketId = entry.articlePacket; if (entry.articleText) this.$refs.entry.$refs.article.displayValue = entry.articleText; this.$refs.entry.amount = entry.amount; @@ -460,14 +464,14 @@ Vue.component('warehouse-shipping-note-modal', { :del-addr-e-mail.sync="delAddrEMail"/> - + + +
Bitte füllen Sie die Rechnungs- und Lieferadresse aus
-
Bitte füllen Sie die Rechnungs- und Lieferadresse aus
- `, @@ -553,13 +557,15 @@ Vue.component('warehouse-shipping-note-modal', { computed: { title() { return this.id === 'create' ? 'Lieferschein erstellen' : `Lieferschein #${this.id} bearbeiten`; + }, + delAddrFilled() { + return !this.delAddrName || !this.delAddrLine || !this.delAddrPLZ || !this.delAddrCity; } } }) Vue.component('warehouse-shipping-note-modal-address', { - // also add props for delAddrName, delAddrLine, delAddrPLZ, delAddrCity which we will sync with the parent component props: { billAddrId: {type: [String, Number], required: true}, delAddrName: {type: String, required: true}, @@ -578,6 +584,7 @@ Vue.component('warehouse-shipping-note-modal-address', { addresses: [], fetchedBillAddr: null, selectedAddr: '', + newAddrGeoLatLon: '', } }, //language=Vue @@ -590,11 +597,14 @@ Vue.component('warehouse-shipping-note-modal-address', { `, @@ -602,24 +612,34 @@ Vue.component('warehouse-shipping-note-modal-address', { billAddrId: {handler: 'updateBillingMode', immediate: false}, addressMode: {handler: 'fetchDeliveryAddresses', immediate: false}, selectedAddr: {handler: 'setSelectedAddrValues', immediate: false}, + newAddrGeoLatLon: {handler: 'fetchGeoAddress', immediate: false}, }, methods: { + async fetchGeoAddress() { + if (!this.newAddrGeoLatLon) return; + const [lat, lon] = this.newAddrGeoLatLon.split(','); + const response = await axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseShippingNote/geoReverse?lat=' + lat + '&lon=' + lon); + + if (response.data.address.road) { + this.$emit('update:delAddrLine', `${response.data.address.road}${response.data.address.house_number ? ' ' + response.data.address.house_number : ''}`); + } else { + this.$emit('update:delAddrLine', `${response.data.address.village}${response.data.address.house_number ? ' ' + response.data.address.house_number : ''}`); + } + + this.$emit('update:delAddrPLZ', response.data.address.postcode); + this.$emit('update:delAddrCity', response.data.address.village || response.data.address.city || response.data.address.town); + }, async updateBillingMode() { await this.fetchDeliveryAddresses(); - // this.addressMode = 'billing'; - - console.log('updateBillingMode'); // Here we check if the address is already in the list of addresses, if not we will set the addressMode to billing and fetch the billing address if (this.delAddrName && this.delAddrLine && this.delAddrPLZ && this.delAddrCity) { - const foundAddress = this.addresses.find(address => address.deliveryAddressName === - this.delAddrName && - address.deliveryAddressLine === - this.delAddrLine && - address.deliveryAddressPLZ === - this.delAddrPLZ && - address.deliveryAddressCity === - this.delAddrCity && address.deliveryAddressEMail === this.delAddrEMail); + const foundAddress = this.addresses.find(address => + address.deliveryAddressName === this.delAddrName && + address.deliveryAddressLine === this.delAddrLine && + address.deliveryAddressPLZ === this.delAddrPLZ && + address.deliveryAddressCity === this.delAddrCity && + address.deliveryAddressEMail === this.delAddrEMail); if (foundAddress) { this.addressMode = 'existing'; this.selectedAddr = foundAddress.id; @@ -631,11 +651,21 @@ Vue.component('warehouse-shipping-note-modal-address', { await this.fetchBillingAddress(); } }, - async fetchDeliveryAddresses() { + async fetchDeliveryAddresses(newVal, oldVal) { + if ((oldVal === 'billing' || oldVal === 'existing') && newVal === 'new') { + this.$emit('update:delAddrName', ''); + this.$emit('update:delAddrLine', ''); + this.$emit('update:delAddrPLZ', ''); + this.$emit('update:delAddrCity', ''); + this.$emit('update:delAddrEMail', ''); + return; + } + if (this.addressMode === 'billing' && this.billAddrId) { await this.fetchBillingAddress(); return; } + if (!this.billAddrId || this.addressMode !== 'existing' || this.fetchedBillAddr === this.billAddrId) return; const response = await axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseShippingNote/getDeliveryAddresses?billingAddressId=' + this.billAddrId); @@ -667,7 +697,8 @@ Vue.component('warehouse-shipping-note-modal-address', { this.window.notify('error', 'Rechnungsadresse konnte nicht gefunden werden'); return; } - this.window.notify('success', 'Rechnungsadresse gefunden'); + // TODO: here is still a bug that we fetch the billing address twice + // this.window.notify('success', 'Rechnungsadresse gefunden'); this.$emit('update:delAddrName', response.data.result.address.company || response.data.result.address.firstname + ' ' + response.data.result.address.lastname); @@ -690,9 +721,9 @@ Vue.component('warehouse-shipping-note-signature-pad', { }, data() { return { - window: window, - signaturePad: null, - shippingNote: null, + window: window, + signaturePad: null, + shippingNote: null, signatureName: '', } }, @@ -700,19 +731,24 @@ Vue.component('warehouse-shipping-note-signature-pad', { template: `
-
-
-
- - -
+
+ +
+
+ +
+
+ + +
`, methods: { async submit() { const data = this.signaturePad.toDataURL(); - const response = await axios.post(window.TT_CONFIG['BASE_PATH'] + '/WarehouseShippingNote/sign?id=' + this.shippingNoteId, {signature: data, signatureName: this.signatureName}); + const response = await axios.post(window.TT_CONFIG['BASE_PATH'] + '/WarehouseShippingNote/sign?id=' + this.shippingNoteId, + {signature: data, signatureName: this.signatureName}); if (response.data.success) { this.window.notify('success', response.data.message || 'Erfolgreich unterschrieben'); this.$emit('close'); diff --git a/public/plugins/vue/tt-components/tt-autocomplete.js b/public/plugins/vue/tt-components/tt-autocomplete.js index e50065751..7163312b5 100644 --- a/public/plugins/vue/tt-components/tt-autocomplete.js +++ b/public/plugins/vue/tt-components/tt-autocomplete.js @@ -99,7 +99,7 @@ Vue.component('tt-autocomplete', { if (this.value && this.apiUrl) { - const response = await axios.get(`${this.apiUrl}&autocomplete=1&searchedID=${this.value}`); + const response = await axios.get(`${this.apiUrl}${this.apiUrl.includes('?') ? '&' : '?'}autocomplete=1&searchedID=${this.value}`); this.displayValue = response.data[0].text; } else if (this.value) { const selectedItem = this.items.find(item => item.value === this.value); @@ -145,7 +145,6 @@ Vue.component('tt-autocomplete', { this.isLoading = true; clearTimeout(this.fetchSuggestionsDebounceTimer); - console.log(this.displayValue); this.fetchSuggestionsDebounceTimer = setTimeout(() => { setTimeout(async () => { @@ -155,7 +154,7 @@ Vue.component('tt-autocomplete', { return; } - const response = await axios.get(`${this.apiUrl}&autocomplete=1&q=${encodeURIComponent(this.displayValue)}`); + const response = await axios.get(`${this.apiUrl}${this.apiUrl.includes('?') ? '&' : '?'}autocomplete=1&q=${encodeURIComponent(this.displayValue)}`); if (response.data?.status === 'error') { this.displayingItems = []; } else { diff --git a/public/plugins/vue/tt-components/tt-modal.js b/public/plugins/vue/tt-components/tt-modal.js index fe1ee8e9d..35ca21eac 100644 --- a/public/plugins/vue/tt-components/tt-modal.js +++ b/public/plugins/vue/tt-components/tt-modal.js @@ -38,7 +38,9 @@ Vue.component('tt-modal', { this.$emit('update:show', false) } if (event.key === 'Enter' && this.save) { - // only submit + if (event.target.tagName === 'TEXTAREA' || event.target.tagName === 'INPUT') { + return + } this.$emit('submit') } }