diff --git a/Layout/default/VueViews/Vue.php b/Layout/default/VueViews/Vue.php
index 35a73afdd..5869d53b1 100644
--- a/Layout/default/VueViews/Vue.php
+++ b/Layout/default/VueViews/Vue.php
@@ -21,6 +21,7 @@ $additionalCSS = [
...$additionalCSS,
'plugins/daterangepicker/daterangepicker.css',
'plugins/vue/tt-components/css/tt-table.css',
+ 'plugins/vue/tt-components/css/tt-tooltip.css',
'plugins/vue/tt-components/css/tt-loader.css',
'plugins/vue/tt-components/css/tt-position-manager.css',
];
diff --git a/public/bundler.php b/public/bundler.php
index 9bd9e99eb..2f6228deb 100644
--- a/public/bundler.php
+++ b/public/bundler.php
@@ -48,6 +48,7 @@ $jsFiles = [
"plugins/vue/tt-components/tt-checkbox.js",
"plugins/vue/tt-components/tt-textarea.js",
"plugins/vue/tt-components/tt-position-manager.js",
+ "plugins/vue/tt-components/tt-tooltip.js",
];
diff --git a/public/js/pages/WarehouseOrder/WarehouseOrder.js b/public/js/pages/WarehouseOrder/WarehouseOrder.js
index 7d958f542..bb8b9b4e7 100644
--- a/public/js/pages/WarehouseOrder/WarehouseOrder.js
+++ b/public/js/pages/WarehouseOrder/WarehouseOrder.js
@@ -373,23 +373,26 @@ Vue.component('warehouse-order-modal', {
return;
}
- const orderRequest = JSON.parse(localStorage.getItem('WarehouseOrder_create'));
- if (!orderRequest) return;
+ const orderRequests = JSON.parse(localStorage.getItem('WarehouseOrder_create'));
+ if (!orderRequests) return;
- const positions = JSON.parse(orderRequest.positions);
- this.order.positions = await Promise.all(positions.map(async p => {
- const distributor = (await axios.get(`${window.TT_CONFIG.BASE_PATH}/WarehouseOrder/getArticleDistributorData`,
- {params: {articleId: p.articleId}})).data[0];
- return {
- article: p.articleId,
- amount: p.amount,
- buyPrice: distributor.purchasePrice,
- distributorId: distributor.id,
- distributorArticleNumber: distributor.externalArticleNumber,
- verwendung: `${p.hasOwnProperty('purpose') ? p.purpose : ''} [Bestellwunsch: #${orderRequest.id}]`,
- linkedOrderRequestId: orderRequest.id
- };
- }));
+ for (const orderRequest of orderRequests) {
+ const positions = JSON.parse(orderRequest.positions);
+ const parsedPositions = await Promise.all(positions.map(async p => {
+ const distributor = (await axios.get(`${window.TT_CONFIG.BASE_PATH}/WarehouseOrder/getArticleDistributorData`,
+ {params: {articleId: p.articleId}})).data[0];
+ return {
+ article: p.articleId,
+ amount: p.amount,
+ buyPrice: distributor.purchasePrice,
+ distributorId: distributor.id,
+ distributorArticleNumber: distributor.externalArticleNumber,
+ verwendung: `${p.hasOwnProperty('purpose') ? p.purpose : ''} [Bestellwunsch: #${orderRequest.id}]`,
+ linkedOrderRequestId: orderRequest.id
+ };
+ }));
+ this.order.positions = [...this.order.positions, ...parsedPositions];
+ }
localStorage.removeItem('WarehouseOrder_create');
},
diff --git a/public/js/pages/WarehouseOrderRequest/WarehouseOrderRequest.js b/public/js/pages/WarehouseOrderRequest/WarehouseOrderRequest.js
index 3a1b94baf..13cb73efb 100644
--- a/public/js/pages/WarehouseOrderRequest/WarehouseOrderRequest.js
+++ b/public/js/pages/WarehouseOrderRequest/WarehouseOrderRequest.js
@@ -17,8 +17,8 @@ window.TT_CONFIG["CRUD_CONFIG"]["additionalActions"] = [
condition: (row) => window.TT_CONFIG['WAREHOUSE_ADMIN'] === '1' && row.cancelled === 1,
},
{
- key: "createOrder",
- title: "Bestellung erstellen",
+ key: "addOrderToCart",
+ title: "Bestellung in den Warenkorb",
class: "fas fa-shopping-cart text-primary", // Use shopping-cart to indicate order creation
condition: (row) => window.TT_CONFIG['WAREHOUSE_ADMIN'] === '1'
&& row.cancelled === 0 && (!row.linkedOrderIds || row.linkedOrderIds.length === 0)
@@ -203,7 +203,18 @@ Vue.component('warehouse-order-request', {
@undoneOrder="undoneOrder"
@createLog="createLog"
@createOrder="createOrder"
+ @addOrderToCart="addOrderToCart"
ref="crud">
+
+
+
+
+
+
@@ -229,7 +240,8 @@ Vue.component('warehouse-order-request', {
addLogModalId: null,
showHiddenRequests: false,
showCanceledRequests: false,
- orderRequestModalId: null
+ orderRequestModalId: null,
+ orderShoppingCart: [],
}),
methods: {
openHistory(e) {
@@ -263,12 +275,26 @@ Vue.component('warehouse-order-request', {
uncancelRequest(row) {
this.cancelRequest(row, '0');
},
- async createOrder(row) {
- const res = await axios.get(`${window.TT_CONFIG.BASE_PATH}/WarehouseOrderRequest/getById?id=${row.id}`);
+ async createOrder() {
+ if (this.orderShoppingCart.length > 0) {
+ localStorage.setItem('WarehouseOrder_create', JSON.stringify(this.orderShoppingCart));
+ window.location.href = `${window.TT_CONFIG["BASE_PATH"]}/WarehouseOrder`;
+ } else window.notify('warning', 'Warenkorb ist leer');
+ },
+ async addOrderToCart(row) {
+ const res = await axios.get(`${window.TT_CONFIG["BASE_PATH"]}/WarehouseOrderRequest/getById?id=${row.id}`);
if (res.data?.positions && typeof res.data.positions === 'string') {
- localStorage.setItem('WarehouseOrder_create', JSON.stringify(res.data));
- window.location.href = `${window.TT_CONFIG.BASE_PATH}/WarehouseOrder`;
- } else window.notify('error', res.data.message || 'Fehler beim erstellen der Bestellung');
+ this.orderShoppingCart.push(res.data);
+ window.notify('success', 'Bestellung in den Warenkorb gelegt');
+ } else window.notify('error', res.data.message || 'Fehler beim hinzufügen der Bestellung');
+ }
+ },
+ computed: {
+ createOrdersButtonText: function () {
+ return this.orderShoppingCart.length > 0 ? `${this.orderShoppingCart.length} Bestellung(en) erstellen` : 'Bestellung(en) erstellen';
+ },
+ createOrdersButtonToolTipText: function () {
+ return this.orderShoppingCart.length > 0 ? `Erstellt ${this.orderShoppingCart.length} Bestellung(en)` : 'Keine Bestellung im Warenkorb';
}
}
});
diff --git a/public/plugins/vue/tt-components/css/tt-tooltip.css b/public/plugins/vue/tt-components/css/tt-tooltip.css
new file mode 100644
index 000000000..38f74f779
--- /dev/null
+++ b/public/plugins/vue/tt-components/css/tt-tooltip.css
@@ -0,0 +1,96 @@
+.tt-tooltip-wrapper {
+ position: relative;
+ display: inline-block; /* Or 'block' depending on your layout needs */
+ cursor: pointer;
+}
+
+.tt-tooltip-box {
+ position: absolute;
+ background-color: #333; /* Dark background */
+ color: #fff; /* White text */
+ padding: 5px 10px;
+ border-radius: 4px;
+ font-size: 12px;
+ white-space: nowrap;
+ z-index: 10; /* Ensure it's above other elements */
+ opacity: 0; /* Hidden by default, fade in */
+ transition: opacity 0.3s;
+ pointer-events: none; /* Prevent tooltip from interfering with mouse events */
+ text-align: center; /* Center text */
+}
+
+/* Make tooltip visible when showTooltip is true */
+.tt-tooltip-wrapper:hover .tt-tooltip-box {
+ opacity: 1;
+}
+
+
+/* Positioning */
+.tt-tooltip-top {
+ bottom: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ margin-bottom: 5px; /* Space between element and tooltip */
+}
+
+.tt-tooltip-bottom {
+ top: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ margin-top: 5px;
+}
+
+.tt-tooltip-left {
+ right: 100%;
+ top: 50%;
+ transform: translateY(-50%);
+ margin-right: 5px;
+}
+
+.tt-tooltip-right {
+ left: 100%;
+ top: 50%;
+ transform: translateY(-50%);
+ margin-left: 5px;
+}
+
+/* Optional: Add arrows */
+.tt-tooltip-box::after {
+ content: '';
+ position: absolute;
+ border-width: 5px;
+ border-style: solid;
+}
+
+.tt-tooltip-top::after {
+ top: 100%;
+ left: 50%;
+ margin-left: -5px;
+ border-color: #333 transparent transparent transparent;
+}
+
+.tt-tooltip-bottom::after {
+ bottom: 100%;
+ left: 50%;
+ margin-left: -5px;
+ border-color: transparent transparent #333 transparent;
+}
+
+.tt-tooltip-left::after {
+ top: 50%;
+ left: 100%;
+ margin-top: -5px;
+ border-color: transparent transparent transparent #333;
+}
+
+.tt-tooltip-right::after {
+ top: 50%;
+ right: 100%;
+ margin-top: -5px;
+ border-color: transparent #333 transparent transparent;
+}
+
+.tt-tooltip-wrapper > * {
+ display: inline-block; /* Ensure the tooltip wrapper behaves correctly */
+ width: 100% !important;
+}
\ No newline at end of file
diff --git a/public/plugins/vue/tt-components/tt-button.js b/public/plugins/vue/tt-components/tt-button.js
index 472ae9cb7..c88220236 100644
--- a/public/plugins/vue/tt-components/tt-button.js
+++ b/public/plugins/vue/tt-components/tt-button.js
@@ -2,9 +2,7 @@
Vue.component('tt-button', {
//language=Vue
template: `
-
`,
props: {
sm: {type: Boolean, default: false},
diff --git a/public/plugins/vue/tt-components/tt-table-crud.js b/public/plugins/vue/tt-components/tt-table-crud.js
index feac23f5a..860c07c1a 100644
--- a/public/plugins/vue/tt-components/tt-table-crud.js
+++ b/public/plugins/vue/tt-components/tt-table-crud.js
@@ -65,7 +65,7 @@ Vue.component('tt-table-crud', {
-
+
diff --git a/public/plugins/vue/tt-components/tt-tooltip.js b/public/plugins/vue/tt-components/tt-tooltip.js
new file mode 100644
index 000000000..308236fbc
--- /dev/null
+++ b/public/plugins/vue/tt-components/tt-tooltip.js
@@ -0,0 +1,31 @@
+Vue.component('tt-tooltip', {
+ props: {
+ text: {
+ type: String,
+ required: true,
+ default: 'Tooltip text'
+ },
+ position: {
+ type: String,
+ default: 'top', // Options: top, bottom, left, right
+ validator: function (value) {
+ // The value must match one of these strings
+ return ['top', 'bottom', 'left', 'right'].indexOf(value) !== -1;
+ }
+ }
+ },
+ data() {
+ return {
+ showTooltip: true
+ };
+ },
+ template: `
+
+ `
+});
\ No newline at end of file