added confirmation email for eshop

This commit is contained in:
2024-09-10 13:43:32 +02:00
parent 39c1604db4
commit 11e2b6f2e2
5 changed files with 137 additions and 17 deletions

View File

@@ -27,6 +27,7 @@ class WarehouseEShopOrderController extends TTCrud {
protected array $additionalActions = [
['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'],
['key' => 'openSingleOrderEmail', 'title' => 'Bestellbestätigung', 'class' => 'fas fa-envelope text-primary'],
];
protected array $infoMessages = [
@@ -48,6 +49,50 @@ class WarehouseEShopOrderController extends TTCrud {
$this->columns[8]['modal']['items'] = $users;
}
protected function singleOrderEmailAction() {
// this has dryRun and id in get parameter create a E-Mail Body like the things below
$isDryRun = $this->request->dryRun ?? false;
$id = $this->request->id;
$order = WarehouseEShopOrderModel::get($id);
$orderItems = WarehouseEShopOrderItemModel::getAll(['orderId' => $id]);
$articles = WarehouseArticleModel::getAll();
$articlePackets = WarehouseArticlePacketModel::getAll();
$paddedId = str_pad($id, 3, '0', STR_PAD_LEFT);
$body = "Bestellung #$paddedId\n\n";
$body .= "Lieferadresse:\n";
$body .= $order->deliveryAddressName . "\n";
$body .= $order->deliveryAddressLine . "\n";
$body .= $order->deliveryAddressPLZ . ' ' . $order->deliveryAddressCity . "\n\n";
$body .= "Bestellte Artikel:\n";
foreach ($orderItems as $item) {
$article = $item->articleId ? array_search($item->articleId, array_column($articles, 'id')) : null;
$articlePacket = $item->articlePacketId ? array_search($item->articlePacketId, array_column($articlePackets, 'id')) : null;
$articleTitle = $item->articleId ? $articles[$article]->title : $articlePackets[$articlePacket]->title;
$quantity = $item->quantity;
$body .= "$quantity x $articleTitle\n";
}
$body .= "\n\n";
$body .= "CSV der Bestellung ist im Anhang.\n\n";
$body .= "XINON GmbH\nFladnitz im Raabtal 150\n8322 Studenzen\n";
if ($isDryRun) {
self::returnJson(['success' => true, 'message' => 'E-Mail Body wurde erstellt', 'body' => $body]);
} else {
$email = new Emailnotification();
$email->setSubject("Bestellbestätigung Bestellung #$paddedId");
$email->setBody($body);
$email->setFrom(TT_OUTGOING_EMAIL_2FA, TT_OUTGOING_EMAIL_2FA);
// $email->setTo('ftth-versand@triotronik.com');
$email->setTo('luca.haid@xinon.eu');
$csvContent = $this->CSVExportNewOrdersMarkAcceptedAction(true, [$id]);
$email->addAttachment(null, $csvContent, "Bestellung_$paddedId.csv", "text/csv");
self::returnJson(['success' => true, 'message' => 'E-Mail wurde versendet']);
}
}
protected function getAllOrderItemsPerOrder(): array {
$items = WarehouseEShopOrderItemModel::getAll();
$articles = WarehouseArticleModel::getAll();
@@ -146,13 +191,14 @@ class WarehouseEShopOrderController extends TTCrud {
$user = UserModel::getOne($json['createBy']);
$email = new Emailnotification();
$email->setSubject("Bestellbestätigung Bestellung #$subjectId");
$email->setBody($body);
$email->setFrom(TT_OUTGOING_EMAIL_2FA, TT_OUTGOING_EMAIL_2FA);
$email->setTo($user->email);
$email->send();
foreach (["office@xinon.at", $user->email] as $emailAddr) {
$email = new Emailnotification();
$email->setSubject("Bestellbestätigung Bestellung #$subjectId");
$email->setBody($body);
$email->setFrom(TT_OUTGOING_EMAIL_2FA, TT_OUTGOING_EMAIL_2FA);
$email->setTo($emailAddr);
$email->send();
}
self::returnJson(['success' => true,
'message' => $this->infoMessages['create'],
@@ -162,12 +208,18 @@ class WarehouseEShopOrderController extends TTCrud {
die(json_encode($json));
}
protected function CSVExportNewOrdersMarkAcceptedAction() {
protected function CSVExportNewOrdersMarkAcceptedAction($returnCSV = false, $orderIds = []) {
$orders = WarehouseEShopOrderModel::getAll(['status' => 'new']);
$orders = array_map(function($order) {
return (array) $order;
}, $orders);
if (!empty($orderIds)) {
$orders = array_filter($orders, function($order) use ($orderIds) {
return in_array($order['id'], $orderIds);
});
}
if (empty($orders)) {
self::returnJson(['success' => false, 'message' => 'Keine neuen Bestellungen']);
die();
@@ -210,6 +262,10 @@ class WarehouseEShopOrderController extends TTCrud {
WarehouseEShopOrderModel::update($order);
}
if ($returnCSV) {
return Helper::arrayToCsv($rows);
}
self::returnJson($rows);
}

View File

@@ -135,5 +135,26 @@ class Helper {
$controller->layout()->setTemplate("VueViews/Vue");
}
/**
* Converts an array of objects to a CSV file.
* @param array $rows The array of objects to convert to CSV.
* @return string The CSV file content.
*/
public static function arrayToCsv(array $rows): string {
$output = fopen('php://temp', 'w');
// Add headers
fputcsv($output, array_keys((array) $rows[0]));
// Add rows
foreach ($rows as $row) {
fputcsv($output, (array) $row);
}
rewind($output);
$csv = stream_get_contents($output);
fclose($output);
return $csv;
}
}

View File

@@ -103,10 +103,10 @@ Vue.component('warehouse-e-shop', {
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/createOrder`, {
shoppingCart: this.shoppingCart,
deliveryMode: this.createOrderDialogData.deliveryMode,
deliveryAddressName: this.createOrderDialogData.deliveryAddressName,
deliveryAddressLine: this.createOrderDialogData.deliveryAddressLine,
deliveryAddressPLZ: this.createOrderDialogData.deliveryAddressPLZ,
deliveryAddressCity: this.createOrderDialogData.deliveryAddressCity,
deliveryAddressName: this.createOrderDialogData.deliveryAddressName.trim(),
deliveryAddressLine: this.createOrderDialogData.deliveryAddressLine.trim(),
deliveryAddressPLZ: this.createOrderDialogData.deliveryAddressPLZ.trim(),
deliveryAddressCity: this.createOrderDialogData.deliveryAddressCity.trim(),
});
if (response.data.success) {
this.window.notify('success', response.data.message || 'Erfolgreich gespeichert');

View File

@@ -3,7 +3,9 @@ Vue.component('warehouse-e-shop-order', {
//language=Vue
template: `
<tt-card>
<tt-table-crud @openHistory="historyModal = true; historyModalId = $event.id" ref="table">
<tt-table-crud @openHistory="historyModal = true; historyModalId = $event.id"
@openSingleOrderEmail="openSingleOrderEmailModal = true; singleOrderEmailModalId = $event.id"
ref="table">
<template v-slot:table-top-buttons>
<button @click="createCSVExportAndMarkAsAccepted" type="button" class="btn btn-outline-success">
@@ -28,10 +30,29 @@ Vue.component('warehouse-e-shop-order', {
</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-card>
`, data() {
return {
window: window, historyModal: false, historyModalId: null, articleItems: null
window: window, historyModal: false, historyModalId: null, articleItems: null, openSingleOrderEmailModal: false, singleOrderEmailModalId: null, singleOrderEmailModalText: null
}
},
async mounted() {
@@ -40,11 +61,20 @@ Vue.component('warehouse-e-shop-order', {
this.articleItems = response.data;
},
methods: {
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');
}
},
async createCSVExportAndMarkAsAccepted() {
const response = await axios.post(`${window['TT_CONFIG']['BASE_PATH']}/WarehouseEShopOrder/CSVExportNewOrdersMarkAccepted`);
if (response.data.message) {
window.notify('info', response.data.message);
window.notify('success', response.data.message);
return;
}
@@ -77,5 +107,16 @@ Vue.component('warehouse-e-shop-order', {
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'));
}
}
}
})

View File

@@ -3,7 +3,9 @@ Vue.component('tt-modal', {
show: { type: Boolean, default: false },
title: { type: String, default: 'Modal Title' },
delete: { type: Boolean, default: true },
deleteText: { type: String, default: 'Delete' },
save: { type: Boolean, default: true },
saveText: { type: String, default: 'Save' },
},
watch: {
show(newVal) {
@@ -35,8 +37,8 @@ Vue.component('tt-modal', {
</div>
<div class="modal-footer">
<slot name="footer">
<button v-if="save" class="btn btn-primary" @click="$emit('submit')">Save</button>
<button v-if="$props.delete" class="btn btn-danger" @click="$emit('delete')">Delete</button>
<button v-if="save" class="btn btn-primary" @click="$emit('submit')">{{saveText}}</button>
<button v-if="$props.delete" class="btn btn-danger" @click="$emit('delete')">{{deleteText}}</button>
<button class="btn btn-secondary" @click="$emit('update:show', false)">Close</button>
</slot>
</div>