331 lines
16 KiB
JavaScript
331 lines
16 KiB
JavaScript
// noinspection JSUnusedLocalSymbols
|
|
|
|
const articleAPIUrl = `${window['TT_CONFIG']['BASE_PATH']}/WarehouseArticle/autocomplete`;
|
|
const articlePacketAPIUrl = `${window['TT_CONFIG']['BASE_PATH']}/WarehouseArticlePacket/autocomplete`;
|
|
|
|
Vue.component('warehouse-e-shop-order-modal-positions-mgmt', {
|
|
props: {
|
|
id: {type: [String, Number], required: true},
|
|
}, data() {
|
|
return {
|
|
window: window,
|
|
positions: [],
|
|
articleAPIUrl: articleAPIUrl,
|
|
articlePacketAPIUrl: articlePacketAPIUrl,
|
|
articleNames: {},
|
|
articlePacketNames: {},
|
|
articleId: null,
|
|
articlePacketId: null,
|
|
amount: null,
|
|
editIndex: null,
|
|
}
|
|
}, async mounted() {
|
|
// get all positions by /WarehouseEShopOrder/getAllItemsPerOrder?orderId=ID
|
|
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/getAllItemsPerOrder?orderId=${this.id}`);
|
|
this.positions = response.data;
|
|
}, methods: {
|
|
async fetchNames() {
|
|
console.log("hallohallo");
|
|
// TODO: there must be a better way to do this
|
|
for (const position of this.positions) {
|
|
if (position.articleId) this.$set(this.articleNames, position.articleId, 'Loading...');
|
|
if (position.articlePacketId) this.$set(this.articlePacketNames, position.articlePacketId, 'Loading...');
|
|
}
|
|
|
|
const articlePromises = this.positions.filter(position => position.articleId)
|
|
.map(position => axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseArticle/autoComplete?searchedID=' + position.articleId));
|
|
const articlePacketPromises = this.positions.filter(position => position.articlePacketId)
|
|
.map(position => axios.get(window.TT_CONFIG["BASE_PATH"] + '/WarehouseArticlePacket/autoComplete?searchedID=' + position.articlePacketId));
|
|
|
|
const articleResponses = await Promise.all(articlePromises);
|
|
const articlePacketResponses = await Promise.all(articlePacketPromises);
|
|
|
|
for (const response of articleResponses) {
|
|
this.$set(this.articleNames, response.data[0].value, response.data[0].text);
|
|
}
|
|
|
|
for (const response of articlePacketResponses) {
|
|
this.$set(this.articlePacketNames, response.data[0].value, response.data[0].text);
|
|
}
|
|
|
|
},
|
|
async addPosition() {
|
|
if (!this.articleId && !this.articlePacketId) return window.notify('error', 'Bitte wählen Sie einen Artikel oder ein Artikel Packet aus.');
|
|
if (this.editIndex !== null) return this.updatePosition();
|
|
|
|
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/addPosition`, {
|
|
orderId: this.id,
|
|
articleId: this.articleId,
|
|
articlePacketId: this.articlePacketId,
|
|
quantity: this.amount,
|
|
});
|
|
|
|
if (response.data.success) {
|
|
this.positions.push(response.data.position);
|
|
this.articleId = null;
|
|
this.articlePacketId = null;
|
|
this.amount = null;
|
|
window.notify('success', 'Position hinzugefügt');
|
|
} else {
|
|
window.notify('error', response.data.message);
|
|
}
|
|
},
|
|
async updatePosition() {
|
|
const position = this.positions[this.editIndex];
|
|
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/updatePosition`, {
|
|
id: position.id,
|
|
articleId: this.articleId,
|
|
articlePacketId: this.articlePacketId,
|
|
quantity: this.amount,
|
|
});
|
|
|
|
if (response.data.success) {
|
|
this.positions[this.editIndex] = response.data.position;
|
|
this.articleId = null;
|
|
this.articlePacketId = null;
|
|
this.amount = null;
|
|
this.editIndex = null;
|
|
window.notify('success', response.data.message);
|
|
} else {
|
|
window.notify('error', response.data.message);
|
|
}
|
|
},
|
|
async deletePosition(id) {
|
|
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/deletePosition`, {id});
|
|
|
|
if (response.data.success) {
|
|
this.positions = this.positions.filter(position => position.id !== id);
|
|
window.notify('success', response.data.message);
|
|
} else {
|
|
window.notify('error', response.data.message);
|
|
}
|
|
},
|
|
async editPosition(id) {
|
|
const position = this.positions.find(position => position.id === id);
|
|
this.articleId = position.articleId;
|
|
this.articlePacketId = position.articlePacketId;
|
|
this.amount = position.quantity;
|
|
this.editIndex = this.positions.indexOf(position);
|
|
},
|
|
}, watch: {positions: {handler: 'fetchNames', immediate: true}}, //language=Vue
|
|
template: `
|
|
<div>
|
|
|
|
<div style="display: grid;grid-template-columns: 2fr 1fr 0.5fr 1fr;grid-gap: 10px;">
|
|
<tt-autocomplete v-model="articleId" :api-url="articleAPIUrl" label="Artikel" sm ref="article"/>
|
|
<tt-autocomplete v-model="articlePacketId" :api-url="articlePacketAPIUrl" label="Artikel Packet" sm/>
|
|
<tt-input v-model="amount" label="Menge" sm/>
|
|
<div style="display: flex;flex-direction: column;justify-content: center;padding-top: 13px;">
|
|
<button @click="addPosition" class="btn btn-primary">Hinzufügen</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display: flex; align-items: center; justify-content: center;">
|
|
<table class="table table-striped table-sm" style="width: max-content">
|
|
<thead>
|
|
<tr>
|
|
<th>Artikel</th>
|
|
<th>Menge</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-if="positions.length === 0">
|
|
<td colspan="4" class="text-center">Keine Einträge</td>
|
|
</tr>
|
|
<tr v-for="(position, index) in positions" :key="index">
|
|
<td>{{ position.articleId ? articleNames[position.articleId] : position.articlePacketId ? articlePacketNames[position.articlePacketId] :
|
|
'Loading...' }}
|
|
</td>
|
|
<td>{{ position.quantity }}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-danger" @click="deletePosition(position.id)">Löschen</button>
|
|
<button class="btn btn-sm btn-primary" @click="editPosition(position.id)">Bearbeiten</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
`,
|
|
|
|
|
|
})
|
|
|
|
Vue.component('warehouse-e-shop-order', {
|
|
//language=Vue
|
|
template: `
|
|
<tt-card>
|
|
<tt-table-crud @openHistory="historyModal = true; historyModalId = $event.id"
|
|
@openSingleOrderEmail="openSingleOrderEmailModal = true; singleOrderEmailModalId = $event.id"
|
|
@createShippingNote="createShippingNote($event.id)"
|
|
@showTrackingHistory="openTrackingHistoryModal = true; trackingHistoryModalId = $event.id"
|
|
ref="table">
|
|
|
|
<template v-slot:table-top-buttons>
|
|
<button @click="createCSVExportAndMarkAsAccepted" type="button" class="btn btn-outline-success">
|
|
<i class="fas fa-file-excel"></i>
|
|
Excel Export für neue Bestellungen
|
|
</button>
|
|
</template>
|
|
|
|
<template v-slot:create="{ row }">
|
|
{{ window.moment(row.create * 1000).format('DD.MM.YYYY HH:mm:ss') }}
|
|
</template>
|
|
|
|
<template v-slot:expandedRow="{ row }">
|
|
<div>
|
|
<ul class="list-group" v-if="articleItems && articleItems[row.id]">
|
|
<li class="list-group-item" v-for="item in articleItems[row.id]">
|
|
Menge: {{ item.quantity }} | {{ item.articlePacketTitle || item.articleTitle }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-slot:positions-modal="{ crudModalData }">
|
|
<div>
|
|
<warehouse-e-shop-order-modal-positions-mgmt :id="crudModalData.id"/>
|
|
</div>
|
|
</template>
|
|
|
|
</tt-table-crud>
|
|
<warehouse-history-modal :show.sync="historyModal" :id="historyModalId"/>
|
|
|
|
<!-- add a tt-modal which just shows some text from the api to show a email for a single order-->
|
|
<tt-modal :show.sync="openSingleOrderEmailModal"
|
|
:title="'Email für Bestellung ' + singleOrderEmailModalId"
|
|
@close="openSingleOrderEmailModal = false"
|
|
save-text="E-Mail senden"
|
|
@submit="sendSingleOrderEmail"
|
|
:delete="false"
|
|
>
|
|
<div v-if="singleOrderEmailModalId && singleOrderEmailModalText">
|
|
<p v-html="singleOrderEmailModalText.body.replaceAll('\\n', '<br>')"></p>
|
|
</div>
|
|
<!-- else show loader-->
|
|
<div v-else>
|
|
<tt-loader/>
|
|
</div>
|
|
</tt-modal>
|
|
|
|
<tt-modal :show.sync="openTrackingHistoryModal"
|
|
:title="'Tracking Historie für Bestellung ' + trackingHistoryModalId"
|
|
@close="openTrackingHistoryModal = false"
|
|
:delete="false"
|
|
:save="false"
|
|
>
|
|
<div v-if="trackingHistoryModalData">
|
|
<ul class="list-group">
|
|
<li class="list-group item" v-for="entry in trackingHistoryModalData.history">
|
|
<strong>{{ entry.date }} {{ entry.time }}</strong> - {{ entry.evtDscr }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
</tt-modal>
|
|
|
|
|
|
</tt-card>
|
|
`, data() {
|
|
return {
|
|
window: window,
|
|
historyModal: false,
|
|
historyModalId: null,
|
|
articleItems: null,
|
|
openSingleOrderEmailModal: false,
|
|
singleOrderEmailModalId: null,
|
|
singleOrderEmailModalText: null,
|
|
openTrackingHistoryModal: false,
|
|
trackingHistoryModalId: null,
|
|
trackingHistoryModalData: null, // modal
|
|
positionsEntryArticleId: null,
|
|
positionsEntryArticlePacketId: null,
|
|
positionsEntryAmount: null,
|
|
}
|
|
}, async mounted() {
|
|
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/getAllItemsPerOrder`);
|
|
this.articleItems = response.data;
|
|
}, methods: {
|
|
async createShippingNote(id) {
|
|
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/createShippingNote?id=${id}`);
|
|
|
|
window.notify(response.data.success === true ? 'success' : 'info', response.data.message);
|
|
if (response.data.shippingNoteId) {
|
|
window.open(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseShippingNote/createPDF?id=${response.data.shippingNoteId}&price=true`, '_blank');
|
|
}
|
|
}, async sendSingleOrderEmail() {
|
|
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/singleOrderEmail?id=${this.singleOrderEmailModalId}`);
|
|
if (response.data.message) {
|
|
window.notify(response.data.success === true ? 'success' : 'error', response.data.message);
|
|
this.openSingleOrderEmailModal = false;
|
|
} else {
|
|
window.notify('error', 'Ein Fehler ist aufgetreten');
|
|
}
|
|
await this.$refs.table.$refs.table.fetchData();
|
|
}, async createCSVExportAndMarkAsAccepted() {
|
|
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/CSVExportNewOrdersMarkAccepted`);
|
|
|
|
if (response.data.message) {
|
|
window.notify(response.data.success === true ? 'success' : 'error', response.data.message);
|
|
return;
|
|
}
|
|
|
|
await new Promise((resolve, reject) => {
|
|
const script = document.createElement('script');
|
|
script.src = '/plugins/xlsx/xlsx.min.js';
|
|
script.onload = resolve;
|
|
script.onerror = reject;
|
|
document.head.appendChild(script);
|
|
})
|
|
|
|
const wb = this.window.XLSX.utils.book_new();
|
|
|
|
const ws = this.window.XLSX.utils.json_to_sheet(response.data);
|
|
|
|
for (const cell in ws) {
|
|
if (cell.startsWith('!')) continue; // Skip non-cell properties like '!ref'
|
|
const cellValue = ws[cell].v;
|
|
if (cellValue?.toString().includes('\n')) {
|
|
// console.log('Found newline in cell:', cell, cellValue);
|
|
if (!ws[cell].s) ws[cell].s = {};
|
|
ws[cell].s.alignment = {wrapText: true, vertical: 'center'};
|
|
} else {
|
|
ws[cell].s = {alignment: {vertical: 'center'}};
|
|
}
|
|
}
|
|
|
|
this.window.XLSX.utils.book_append_sheet(wb, ws, "Export");
|
|
this.window.XLSX.writeFile(wb, 'Export.xlsx');
|
|
|
|
await this.$refs.table.$refs.table.fetchData();
|
|
}
|
|
}, watch: {
|
|
singleOrderEmailModalId() {
|
|
this.openSingleOrderEmailModal = !!this.singleOrderEmailModalId;
|
|
this.singleOrderEmailModalText = null;
|
|
if (this.singleOrderEmailModalId) {
|
|
axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/singleOrderEmail?id=${this.singleOrderEmailModalId}&dryRun=true`)
|
|
.then(response => this.singleOrderEmailModalText = response.data)
|
|
.catch(error => window.notify('error', error.response?.data?.message || 'Ein Fehler ist aufgetreten'));
|
|
}
|
|
}, async trackingHistoryModalId() {
|
|
this.openTrackingHistoryModal = !!this.trackingHistoryModalId;
|
|
this.trackingHistoryModalData = null;
|
|
if (this.trackingHistoryModalId) {
|
|
const response = await axios.get(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/fetchGLSTracking?id=${this.trackingHistoryModalId}`);
|
|
const data = response.data;
|
|
// if data is a empty string, show error
|
|
if (!data) {
|
|
window.notify('error', data.message || 'Keine Daten gefunden');
|
|
return;
|
|
}
|
|
// if data is not empty, show data
|
|
this.$set(this, 'trackingHistoryModalData', data);
|
|
}
|
|
}
|
|
}
|
|
})
|