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"/>
-
+
Textelemente
-
+
@@ -478,16 +482,16 @@ Vue.component('warehouse-shipping-note-modal', {
Positionen
-
+
+
+ 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', {
-
-
-
-
-
+
+
+
+
+ Adresse: {{ delAddrLine }}, {{ delAddrPLZ }} {{ delAddrCity }}
+
+
+
`,
@@ -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')
}
}
|