Add POS order synchronization components, including sync columns, tables, pagination, and dynamic filtering options

This commit is contained in:
Jepp9350
2025-06-16 10:49:59 +02:00
parent f737d77587
commit f352b11f41
16 changed files with 1574 additions and 12 deletions
@@ -116,6 +116,10 @@ const props = defineProps({
*/
]
})
},
is_button_hover_effect: {
type: Boolean,
default: false // If true, the button will have a hover effect
}
});
@@ -201,7 +205,7 @@ const label_shortened = computed(() => {
</script>
<template>
<div class="color-indicator" @click="onClick" @mouseover="onHover" @mouseleave="onLeave">
<div class="color-indicator" @click="onClick" @mouseover="onHover" @mouseleave="onLeave" v-bind:class="{ 'is-button-hover-effect': props.is_button_hover_effect }">
<span class="icon-text is-flex-wrap-nowrap">
<span class="icon" v-show="visibility.icon">
<!-- Loading -->
@@ -346,4 +350,12 @@ const label_shortened = computed(() => {
.no-underline-text {
text-decoration: none !important;
}
.is-button-hover-effect {
transition: background-color 0.3s ease, color 0.3s ease;
}
.is-button-hover-effect:hover {
background-color: var(--button-hover-bg-color, #f5f5f5);
color: var(--button-hover-text-color, #363636);
}
</style>
@@ -338,7 +338,7 @@ const selectAllInvoiceCollections = () => {
const getUniqueInvoiceCollections = () => {
// Get a list of unique invoice collections from the orders
return [...new Set(props.orders.map(order => order.invoice_collection_id))];
return [...new Set(props.objects.map(order => order.invoice_collection_id))];
};
const invoiceCollectionQueueInProgress = ref([]);
@@ -414,7 +414,7 @@ const processNextInvoiceCollection = () => {
const getFirstInvoiceWithCollectionId = (invoiceCollectionId) => {
// Get the first invoice with the given collection id
return props.orders.find(order => order.invoice_collection_id === invoiceCollectionId);
return props.objects.find(order => order.invoice_collection_id === invoiceCollectionId);
};
const processInvoiceCollection = (invoiceCollectionId) => {
@@ -0,0 +1,81 @@
<script setup lang="ts">
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import WhiteBox from "@/components/displays/boxes/WhiteBox.vue";
import PosOrdersSyncColumn from "@/components/displays/department/pos/sync/displays/PosOrdersSyncColumn.vue";
import ColorIndicator from "@/components/displays/buttons/ColorIndicator.vue";
</script>
<template>
<div class="columns is-vcentered">
<!-- Potential duplicates -->
<PosOrdersSyncColumn
:title="SessionUser.objects.global.language.warnings"
icon="fas fa-exclamation-triangle"
iconColor="has-text-warning"
>
<template #default>
Test
</template>
<template #footer>
<div class="card-footer-item has-text-centered">
<color-indicator
v-bind:label="{ text: SessionUser.objects.global.language.warnings, classes: [], max_length: 20 }"
v-bind:visibility="{ dropdown: false, icon: true }"
v-bind:color_class="'has-text-warning'"
v-bind:is_button_hover_effect="true"
style="width: 100%; text-align: center;"
class="p-2 is-clickable"
/>
</div>
</template>
</PosOrdersSyncColumn>
<!-- Successful Syncs -->
<PosOrdersSyncColumn
:title="SessionUser.objects.global.language.successful_syncs"
icon="fas fa-check-circle"
iconColor="has-text-success"
>
<template #default>
Test
</template>
<template #footer>
<div class="card-footer-item has-text-centered">
<color-indicator
v-bind:label="{ text: SessionUser.objects.orders.meta.title, classes: [], max_length: 20 }"
v-bind:visibility="{ dropdown: false, icon: true }"
v-bind:color_class="'has-text-success'"
v-bind:is_button_hover_effect="true"
style="width: 100%; text-align: center;"
class="p-2 is-clickable"
/>
</div>
</template>
</PosOrdersSyncColumn>
<!-- Customers applicable -->
<PosOrdersSyncColumn
:title="SessionUser.objects.global.language.customers"
icon="fas fa-users"
iconColor="has-text-info"
>
<template #default>
Test
</template>
<template #footer>
<div class="card-footer-item has-text-centered">
<color-indicator
v-bind:label="{ text: SessionUser.objects.global.language.customers, classes: [], max_length: 20 }"
v-bind:visibility="{ dropdown: false, icon: true }"
v-bind:color_class="'has-text-info'"
v-bind:is_button_hover_effect="true"
style="width: 100%; text-align: center;"
class="p-2 is-clickable"
/>
</div>
</template>
</PosOrdersSyncColumn>
</div>
</template>
<style scoped>
</style>
@@ -0,0 +1,63 @@
<script setup lang="ts">
import { defineProps, defineEmits } from "vue";
import WhiteBox from "@/components/displays/boxes/WhiteBox.vue";
const props = defineProps({
title: {
type: String,
default: "Unnamed"
},
icon: {
type: String,
default: "fas fa-box"
},
iconColor: {
type: String,
default: "has-text-info"
},
});
</script>
<template>
<div class="column">
<WhiteBox class="card p-0">
<div class="card-header">
<div class="card-header-icon">
<span class="icon" :class="props.iconColor">
<i :class="props.icon"></i>
</span>
</div>
<h2 class="card-header-title">
{{ props.title }}
</h2>
<button class="card-header-icon" aria-label="more options">
<span class="icon">
<i class="fas fa-ellipsis-v"></i>
</span>
</button>
</div>
<div class="card-content">
<slot></slot>
</div>
<footer class="card-footer">
<slot name="footer"></slot>
<!--
<span class="card-footer-item has-text-centered">
<strong>Footer</strong>
</span>
<span class="card-footer-item has-text-centered">
<a href="#" class="has-text-info">Link</a>
</span>
<span class="card-footer-item has-text-centered">
<a href="#" class="has-text-info">Another link</a>
</span>
-->
</footer>
</WhiteBox>
</div>
</template>
<style scoped>
</style>
@@ -0,0 +1,181 @@
<script setup>
const props = defineProps({
objects: {
type: Object,
required: true,
},
allowSelectMultiple: {
type: Boolean,
default: false,
},
});
import {ref, watch} from 'vue';
import { departments, getDepartments, isLoading, getDepartmentName} from "@/components/pagination/departmentTabs.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import {orderBy, orderDirection, setOrder, loadList} from "@/components/pagination/paginatedList.vue";
const redirectDepartmentOrderPage = (orderId, departmentId) => {
// Send the user to the order page (In a new tab)
// `/admin/${departmentId}/modules/pos/orders/${orderId}`
window.open(`/admin/${departmentId}/modules/pos/orders/${orderId}`, '_blank');
};
const redirectSuperUserInvoiceCollectionPage = (invoiceCollectionId) => {
// Send the user to the invoice collection page (In a new tab)
window.open(`/superuser/invoices/${invoiceCollectionId}`, '_blank');
};
// Get the departments (If the departments are not already loaded)
if (departments.value.length === 0) {
getDepartments();
}
const clickUser = (customer_id) => {
if (!SessionUser.canAccessSuperUser()) {
return;
}
// Send the user to the user page
SessionUser.adminUser.customers.fromCustomerNumber.getUserId(customer_id).then(response => window.open('/superuser/users/' + response.data.data.user_id, '_blank'));
};
const isColumnCurrentlyBeingSortedBy = (column) => {
// Check if the column is currently being sorted by
return orderBy.value === column;
};
const isCurrentSortDirectionAscending = () => {
// Check if the current sort direction is ascending
return orderDirection.value === 'asc';
};
const isCurrentSortDirectionDescending = () => {
// Check if the current sort direction is descending
return orderDirection.value === 'desc';
};
const onTableHeaderClick = (column) => {
// Check if the column is already sorted
if (orderBy.value === column) {
// If the column is already sorted, toggle the direction
const direction = orderDirection.value === 'asc' ? 'desc' : 'asc';
setOrder(
column,
direction
);
} else {
// If the column is not sorted, set the order to the new column and default to ascending
const direction = 'asc';
setOrder(
column,
direction
);
}
// Load the list
loadList();
};
const tableHeaders = ref([
{
name: 'id',
title: 'Id',
sortable: true,
},
{
name: 'department',
title: 'Afdeling',
sortable: true,
},
{
name: 'customer_number',
title: SessionUser.objects.global.language.customer,
sortable: true,
},
{
name: 'order_id',
title: SessionUser.functions.ucFirst(SessionUser.objects.orders.meta.labels.single),
sortable: true,
},
{
name: 'created_at',
title: 'Dato',
sortable: true,
},
]);
</script>
<template>
<table class="table is-fullwidth is-hoverable">
<thead>
<tr>
<template v-for="tableHeaders in tableHeaders" :key="tableHeaders">
<th
v-if="tableHeaders.sortable"
:class="{
'is-clickable': tableHeaders.sortable,
'has-text-centered': tableHeaders.name === 'id'
}"
@click="onTableHeaderClick(tableHeaders.name)"
>
<span class="is-flex-wrap-nowrap">
<span class="has-text-weight-bold">{{ tableHeaders.title }}</span>
<span
v-if="isColumnCurrentlyBeingSortedBy(tableHeaders.name)"
:class="{
'fas fa-sort-up': isCurrentSortDirectionAscending(),
'fas fa-sort-down': isCurrentSortDirectionDescending()
}"
class="icon is-small"
/>
</span>
</th>
<th
v-else
:class="{
'has-text-centered': tableHeaders.name === 'id'
}"
>
<span class="is-flex-wrap-nowrap">
<span class="has-text-weight-bold">{{ tableHeaders.title }}</span>
</span>
</th>
</template>
</tr>
</thead>
<tbody>
<template v-for="object in objects" :key="object.id">
<tr>
<!-- Id -->
<td class="has-text-centered">
{{object.id}}
</td>
<!-- Department -->
<td>
{{ getDepartmentName(object.department) }}
</td>
<!-- Customer Number -->
<td>
{{ object.customer_number }}
</td>
<!-- Order Id -->
<td>
{{ object.order_id }}
</td>
<!-- Created At -->
<td>
{{ object.created_at }}
</td>
</tr>
</template>
</tbody>
<tfoot>
<tr>
<td colspan="100%">Viser {{ objects.length }} transaktioner</td>
</tr>
</tfoot>
</table>
</template>
<style scoped>
</style>
@@ -0,0 +1,929 @@
<script setup>
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
const props = defineProps({
orders: {
type: Object,
required: true,
},
invoiceView: {
type: Boolean,
default: false,
},
allowSelectMultiple: {
type: Boolean,
default: false,
},
isCustomerView: {
type: Boolean,
default: false,
}
});
import {ref, watch} from 'vue';
import { departments, getDepartments, isLoading, getDepartmentName} from "@/components/pagination/departmentTabs.vue";
import {showPopper, removePopperIfOpen, popperBox} from "@/components/displays/PopperDefault.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import {orderBy, orderDirection, setOrder, loadList} from "@/components/pagination/paginatedList.vue";
import ActionSettingsWheelItem from "@/components/displays/buttons/ActionSettingsWheelItem.vue";
import OrderContentTable from "@/components/displays/superuser/tables/OrderContentTable.vue";
import InvoiceMultipleCollectionsModal from "@/components/displays/modals/InvoiceMultipleCollectionsModal.vue";
import Swal from "sweetalert2";
import ColorIndicator from "@/components/displays/buttons/ColorIndicator.vue";
const redirectDepartmentOrderPage = (orderId, departmentId) => {
// Send the user to the order page (In a new tab)
// `/admin/${departmentId}/modules/pos/orders/${orderId}`
window.open(`/admin/${departmentId}/modules/pos/orders/${orderId}`, '_blank');
};
const redirectSuperUserInvoiceCollectionPage = (invoiceCollectionId) => {
// Send the user to the invoice collection page (In a new tab)
window.open(`/superuser/invoices/${invoiceCollectionId}`, '_blank');
};
// Get the departments (If the departments are not already loaded)
if (departments.value.length === 0) {
getDepartments();
}
const isOrderInvoicedWithEconomic = (order) => {
return order.economic_invoice_module.invoice_id !== null || order.economic_invoice_module.invoice_draft_id !== null;
};
const isOrderEconomicInvoiceBooked = (order) => {
return order.economic_invoice_module.invoice_id !== null;
};
const isOrderInvoicedWithStripe = (order) => {
return order.stripe_invoice_module !== undefined;
};
const isOrderInvoiced = (order) => {
return isOrderInvoicedWithEconomic(order) || isOrderInvoicedWithStripe(order);
};
const doesOrderHaveInvoiceCollection = (order) => {
return order.invoice_collection !== undefined && order.invoice_collection !== null;
};
const isOrderInvoiceCollectionClosed = (order) => {
return order.invoice_collection.closed_at !== null;
};
const isOrderInvoiceCollectionBooked = (order) => {
return order.invoice_collection.booked_invoice_id !== null;
};
const isOrderStripeInvoicePaid = (order) => {
if (order.stripe_invoice_module) {
return order.stripe_invoice_module.paid;
}
return false;
};
const doesOrderHaveErrorMessage = (order) => {
return order.error_message !== null && order.error_message !== undefined;
};
const getOrderInvoiceStatusBarColor = (order) => {
if (order.economic_invoice_module) {
// Check the invoice status
var color_class = 'has-text-danger';
if (isOrderInvoicedWithStripe(order)) {
isOrderStripeInvoicePaid(order)
? color_class = 'has-text-success'
: color_class = 'has-text-warning';
}
if (isOrderInvoicedWithEconomic(order)) {
isOrderEconomicInvoiceBooked(order)
? color_class = 'has-text-success'
: color_class = 'has-text-warning';
}
if (doesOrderHaveInvoiceCollection(order)) {
color_class = 'has-text-grey';
// Check if the invoice collection is closed
if (isOrderInvoiceCollectionClosed(order)) {
color_class = 'has-text-warning';
// Check if the invoice collection is booked
if (isOrderInvoiceCollectionBooked(order)) {
color_class = 'has-text-success';
}
}
}
if (doesOrderHaveErrorMessage(order)) {
color_class = 'has-text-danger';
}
// Return the color class
return color_class;
}
return '';
};
const getOrderInvoiceStatusContent = (order) => {
const content = [];
if (isOrderInvoiced(order)) {
// If the order is invoiced with e-conomic, show the invoice id
if (isOrderInvoicedWithEconomic(order)) {
isOrderEconomicInvoiceBooked(order)
? content.push('Bogført i e-conomic')
: content.push('Gemt som kladde i e-conomic');
isOrderEconomicInvoiceBooked(order)
? content.push('Faktura ID: <strong>' + order.economic_invoice_module.invoice_id + '</strong>')
: content.push('Faktura Kladde ID: <strong>' + order.economic_invoice_module.invoice_draft_id + '</strong>');
}
// If the order is invoiced with stripe, show the invoice id
if (isOrderInvoicedWithStripe(order)) {
isOrderStripeInvoicePaid(order)
? content.push('Fakturaen er <strong>betalt</strong>')
: content.push('Fakturaen er <strong>ikke betalt</strong>');
content.push('Faktura ID: <strong>' + order.stripe_invoice_module.id + '</strong>');
}
content.push(''); // Add a line break
isOrderInvoicedWithEconomic(order)
? content.push('<span class="has-text-grey">Faktureret med e-conomic</span>')
: content.push('<span class="has-text-grey">Faktureret med stripe</span>');
} else {
// Check if the order has an invoice collection
if (doesOrderHaveInvoiceCollection(order)) {
// Check if the invoice collection is closed
if (isOrderInvoiceCollectionClosed(order)) {
content.push('Faktura samlingen er <strong>lukket</strong>');
// Check if the invoice collection is booked
if (isOrderInvoiceCollectionBooked(order)) {
content.push('Faktura samlingen er <strong>bogført</strong>');
}
}
content.push(''); // Add a line break
content.push('Faktura samling ID: <strong>' + order.invoice_collection.id + '</strong>');
// Add the Error message if it exists
if (doesOrderHaveErrorMessage(order)) {
content.push('Fejl: <strong class="has-text-danger">' + order.error_message + '</strong>');
}
} else {
content.push(''); // Add a line break
content.push('<strong class="has-text-grey">Transaktionen er ikke faktureret</strong>');
}
}
// Return the list of content as a string, with line breaks between each item
return content.join('<br>');
};
const getOrderInvoiceStatusTitle = (order) => {
return isOrderInvoiced(order) ? 'Faktura status' : 'Transaktion status';
};
const clickUser = (customer_id) => {
if (!SessionUser.canAccessSuperUser()) {
return;
}
// Send the user to the user page
SessionUser.adminUser.customers.fromCustomerNumber.getUserId(customer_id).then(response => window.open('/superuser/users/' + response.data.data.user_id, '_blank'));
};
const isColumnCurrentlyBeingSortedBy = (column) => {
// Check if the column is currently being sorted by
return orderBy.value === column;
};
const isCurrentSortDirectionAscending = () => {
// Check if the current sort direction is ascending
return orderDirection.value === 'asc';
};
const isCurrentSortDirectionDescending = () => {
// Check if the current sort direction is descending
return orderDirection.value === 'desc';
};
const onTableHeaderClick = (column) => {
// Check if the column is already sorted
if (orderBy.value === column) {
// If the column is already sorted, toggle the direction
const direction = orderDirection.value === 'asc' ? 'desc' : 'asc';
setOrder(
column,
direction
);
} else {
// If the column is not sorted, set the order to the new column and default to ascending
const direction = 'asc';
setOrder(
column,
direction
);
}
// Load the list
loadList();
};
const tableHeaders = ref([
{
name: 'id',
title: 'Id',
sortable: true,
},
...(props.isCustomerView) ? [] : [{
name: 'customer_id',
title: 'Kunde',
sortable: true,
}],
...(props.isCustomerView) ? [] : [{
name: 'cashier_id',
title: 'Kassør',
sortable: true,
}],
{
name: 'department_id',
title: 'Afdeling',
sortable: true,
},
{
name: 'reg_1',
title: 'Reg. 1',
sortable: true,
},
{
name: 'reg_2',
title: 'Reg. 2',
sortable: true,
},
{
name: 'reg_3',
title: 'Reg. 3',
sortable: true,
},
{
name: 'reference',
title: 'Reference',
sortable: true,
},
{
name: 'notes',
title: 'Noter',
sortable: true,
},
{
name: 'created_at',
title: 'Dato',
sortable: true,
},
{
name: 'total_net_amount',
title: 'Total',
sortable: false,
},
{
name: 'completed_at',
title: 'Gennemført',
sortable: true,
},
{
name: 'actions',
title: 'Actions',
sortable: false,
},
]);
const active_dropdown_object_ids = ref([]);
const toggleDropdown = (object) => {
// Check if the object is already in the active dropdown list
if (active_dropdown_object_ids.value.includes(object.id)) {
// If it is, remove it from the list
active_dropdown_object_ids.value = active_dropdown_object_ids.value.filter(id => id !== object.id);
} else {
// If it is not, add it to the list
active_dropdown_object_ids.value.push(object.id);
}
};
const isDropdownActive = (object) => {
// Check if the object is in the active dropdown list
return active_dropdown_object_ids.value.includes(object.id);
};
/**
* Invoice collection selection
*/
const selectedInvoiceCollections = ref([]);
const toggleInvoiceCollectionSelection = (invoiceCollectionId) => {
// Check if the invoice collection is already selected
if (selectedInvoiceCollections.value.includes(invoiceCollectionId)) {
// If it is, remove it from the list
selectedInvoiceCollections.value = selectedInvoiceCollections.value.filter(id => id !== invoiceCollectionId);
} else {
// If it is not, add it to the list
selectedInvoiceCollections.value.push(invoiceCollectionId);
}
};
const isInvoiceCollectionSelected = (invoiceCollectionId) => {
// Check if the invoice collection is in the selected list
return selectedInvoiceCollections.value.includes(invoiceCollectionId);
};
const isInvoiceCollectionSelectedAll = () => {
// Check if all invoice collections are selected
return selectedInvoiceCollections.value.length === getUniqueInvoiceCollections().length;
};
const selectAllInvoiceCollections = () => {
// Check if all invoice collections are selected
if (isInvoiceCollectionSelectedAll()) {
// If they are, deselect all
selectedInvoiceCollections.value = [];
} else {
// If they are not, select all
selectedInvoiceCollections.value = getUniqueInvoiceCollections();
}
};
const getUniqueInvoiceCollections = () => {
// Get a list of unique invoice collections from the orders
return [...new Set(props.objects.map(order => order.invoice_collection_id))];
};
const invoiceCollectionQueueInProgress = ref([]);
const invoiceCollectionQueueFailed = ref([]);
const invoiceCollectionQueueSuccess = ref([]);
const invoiceCollectionQueue = ref([]);
const invoiceCollectionMaxConnections = 2;
const isInvoiceMultipleCollectionsModalOpen = ref(false);
const invoiceSelectedCollections = () => {
// Open the invoice multiple collections modal
isInvoiceMultipleCollectionsModalOpen.value = true;
// Check if any invoice collections are selected
if (selectedInvoiceCollections.value.length > 0) {
// If they are, show a message
console.log('Selected invoice collections: ' + selectedInvoiceCollections.value);
for (const invoiceCollectionId of selectedInvoiceCollections.value) {
// Log the invoice collection id
console.log('Invoice collection id: ', invoiceCollectionId);
// Add the invoice collection to the queue
addInvoiceCollectionToQueue(invoiceCollectionId);
}
// Process the invoice collection queue
processInvoiceCollectionQueue();
} else {
// If they are not, show a message
console.log('No invoice collections selected');
}
};
const addInvoiceCollectionToQueue = (invoiceCollectionId) => {
// Check if the invoice collection is already in the queue
if (invoiceCollectionQueue.value.includes(invoiceCollectionId)) {
// If it is, remove it from the queue
invoiceCollectionQueue.value = invoiceCollectionQueue.value.filter(id => id !== invoiceCollectionId);
} else {
// If it is not, add it to the queue
invoiceCollectionQueue.value.push(invoiceCollectionId);
}
};
const processInvoiceCollectionQueue = () => {
// Check if the queue is empty
if (invoiceCollectionQueue.value.length === 0) {
// If it is, show a message
console.log('Invoice collection queue is empty');
return;
}
// Check if the max connections are reached
if (invoiceCollectionQueueInProgress.value.length >= invoiceCollectionMaxConnections) {
// If they are, show a message
console.log('Max connections reached');
return;
}
while (invoiceCollectionQueueInProgress.value.length < invoiceCollectionMaxConnections && invoiceCollectionQueue.value.length > 0) {
// Process the next invoice collection
processNextInvoiceCollection();
}
};
const processNextInvoiceCollection = () => {
// Check if the queue is empty
if (invoiceCollectionQueue.value.length === 0) {
// If it is, show a message
console.log('Invoice collection queue is empty');
return;
}
// Get the next invoice collection from the queue
const invoiceCollectionId = invoiceCollectionQueue.value.shift();
// Process the invoice collection
processInvoiceCollection(invoiceCollectionId);
};
const getFirstInvoiceWithCollectionId = (invoiceCollectionId) => {
// Get the first invoice with the given collection id
return props.objects.find(order => order.invoice_collection_id === invoiceCollectionId);
};
const processInvoiceCollection = (invoiceCollectionId) => {
// Check if the invoice collection is already in progress
if (invoiceCollectionQueueInProgress.value.includes(invoiceCollectionId)) {
// If it is, remove it from the in progress list
invoiceCollectionQueueInProgress.value = invoiceCollectionQueueInProgress.value.filter(id => id !== invoiceCollectionId);
} else {
// If it is not, add it to the in progress list
invoiceCollectionQueueInProgress.value.push(invoiceCollectionId);
}
// Process the invoice collection
console.log('Processing invoice collection: ' + invoiceCollectionId);
// Send the invoice collection request to the server
// Send the request
SessionUser.request(
'/collected-invoices/economic',
'POST',
{
id: parseInt(invoiceCollectionId)
}
).then((response) => {
if (response.data && response.data.data && response.data.success) {
// If the request was successful, add the invoice collection to the success list
console.log('Invoice collection processed successfully: ' + invoiceCollectionId, response);
addInvoiceCollectionToSuccess(invoiceCollectionId);
addCollectionQueueLog(
true, // Success state
invoiceCollectionId, // Invoice collection id
'Invoice collection processed successfully', // Error message
);
} else {
// If the request failed, add the invoice collection to the failed list
console.log('Invoice collection processing failed: ' + invoiceCollectionId, response);
invoiceCollectionQueueFailed.value.push(invoiceCollectionId);
addCollectionQueueLog(
false, // Success state
invoiceCollectionId, // Invoice collection id
'Unknown error', // Error message
);
}
}
).catch((error) => {
// If the request failed, add the invoice collection to the failed list
console.log('Invoice collection processing failed 2: ' + invoiceCollectionId, error);
invoiceCollectionQueueFailed.value.push(invoiceCollectionId);
let errorMessage = error.response.data.data.message;
addCollectionQueueLog(
false, // Success state
invoiceCollectionId, // Invoice collection id
errorMessage, // Error message
);
}).finally(() => {
// Remove the invoice collection from the in progress list
invoiceCollectionQueueInProgress.value = invoiceCollectionQueueInProgress.value.filter(id => id !== invoiceCollectionId);
// Process the next invoice collection in the queue
processInvoiceCollectionQueue();
});
};
const collectionQueueLog = ref([]);
const addCollectionQueueLog = (success, invoiceCollectionId, errorMessage) => {
// Add the log to the collection queue log
collectionQueueLog.value.push({
success: success,
invoiceCollectionId: invoiceCollectionId,
errorMessage: errorMessage
});
};
const addInvoiceCollectionToSuccess = (invoiceCollectionId) => {
// Check if the invoice collection is already in the success list
if (invoiceCollectionQueueSuccess.value.includes(invoiceCollectionId)) {
// If it is, remove it from the success list
invoiceCollectionQueueSuccess.value = invoiceCollectionQueueSuccess.value.filter(id => id !== invoiceCollectionId);
} else {
// If it is not, add it to the success list
invoiceCollectionQueueSuccess.value.push(invoiceCollectionId);
}
};
const confirmCloseModal = () => {
Swal.fire(
{
title: 'Er du sikker på at du vil lukke vinduet?',
text: "Du vil ikke kunne få den visualiseret igen!",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ja, luk vinduet!'
}).then((result) => {
if (result.isConfirmed) {
isInvoiceMultipleCollectionsModalOpen.value = false;
}
});
};
</script>
<template>
<table class="table is-fullwidth is-hoverable">
<thead>
<tr v-if="props.invoiceView && props.allowSelectMultiple">
<td colspan="100%">
<div class="buttons">
<button
class="button is-small"
@click="invoiceSelectedCollections()"
>
{{SessionUser.objects.global.language.invoice}} {{SessionUser.objects.global.language.selected_multiple}} ({{selectedInvoiceCollections.length}})
</button>
<button
class="button is-small"
@click="selectAllInvoiceCollections()"
:class="{
'is-light': !isInvoiceCollectionSelectedAll(),
'is-dark': isInvoiceCollectionSelectedAll()
}"
>
{{ isInvoiceCollectionSelectedAll() ? SessionUser.objects.global.language.unselect : SessionUser.objects.global.language.select }} {{ SessionUser.objects.global.language.all.toLowerCase() }}
</button>
</div>
</td>
</tr>
<tr>
<th class="is-narrow" v-if="props.invoiceView && props.allowSelectMultiple"></th>
<th class="is-narrow" v-if="props.invoiceView"></th>
<template v-for="tableHeaders in tableHeaders" :key="tableHeaders">
<th
v-if="tableHeaders.sortable"
:class="{
'is-clickable': tableHeaders.sortable,
'has-text-centered': tableHeaders.name === 'id'
}"
@click="onTableHeaderClick(tableHeaders.name)"
>
<span class="is-flex-wrap-nowrap">
<span class="has-text-weight-bold">{{ tableHeaders.title }}</span>
<span
v-if="isColumnCurrentlyBeingSortedBy(tableHeaders.name)"
:class="{
'fas fa-sort-up': isCurrentSortDirectionAscending(),
'fas fa-sort-down': isCurrentSortDirectionDescending()
}"
class="icon is-small"
/>
</span>
</th>
<th
v-else
:class="{
'has-text-centered': tableHeaders.name === 'id'
}"
>
<span class="is-flex-wrap-nowrap">
<span class="has-text-weight-bold">{{ tableHeaders.title }}</span>
</span>
</th>
</template>
</tr>
</thead>
<tbody>
<template v-for="order in orders" :key="order.id">
<tr>
<template v-if="props.invoiceView && props.allowSelectMultiple">
<td class="is-narrow">
<button
class="button is-small"
@click="toggleInvoiceCollectionSelection(order.invoice_collection_id)"
:class="{
'is-light': !isInvoiceCollectionSelected(parseInt(order.invoice_collection_id)),
'is-dark': isInvoiceCollectionSelected(parseInt(order.invoice_collection_id))
}"
>
{{ isInvoiceCollectionSelected(parseInt(order.invoice_collection_id)) ? SessionUser.objects.global.language.unselect : SessionUser.objects.global.language.select }}
</button>
</td>
</template>
<template v-if="props.invoiceView">
<td class="is-narrow">
<button
class="button is-small"
@click="toggleDropdown(order)"
>
<span
class="icon"
:class="isDropdownActive(order) ? 'has-text-link' : ''"
:style="isDropdownActive(order) ? 'transform: rotate(90deg);' : ''"
>
<!-- Dropdown icon -->
<i class="fas fa-angle-right"></i>
</span>
</button>
</td>
</template>
<td>
<ColorIndicator
v-bind:color_class="getOrderInvoiceStatusBarColor(order)"
v-bind:is_narrow="true"
v-bind:label="{
text: order.id,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: true,
dropdown: true,
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
// Transaction
{
text: SessionUser.functions.ucFirst(SessionUser.objects.orders.meta.labels.single),
action: () => {
redirectDepartmentOrderPage(order.id, order.department_id);
},
...(SessionUser.canAccessSuperUser() ? {} : { disabled: true }),
button_classes: ['no-underline-text', 'is-text'],
button: true,
button_text: order.id,
v_centered: true,
},
// Invoice collection
{
text: SessionUser.objects.global.language.invoice + ' ' + SessionUser.objects.global.language.collection.toLowerCase(),
action: () => {
redirectSuperUserInvoiceCollectionPage(order.invoice_collection_id);
},
...(SessionUser.canAccessSuperUser() ? {} : { disabled: true }),
button_classes: ['no-underline-text', 'is-text'],
button: true,
button_text: order.invoice_collection_id,
v_centered: true,
},
// Completed status
{
text: SessionUser.objects.orders.columns.completed_at.label,
action: () => {
redirectDepartmentOrderPage(order.id, order.department_id);
},
...(SessionUser.canAccessSuperUser() ? {} : { disabled: true }),
button_classes: ['no-underline-text', 'is-text', ...(order.completed_at !== null ? [] : ['has-text-warning'])],
button: true,
button_text: (order.completed_at !== null ? SessionUser.objects.global.language.yes : SessionUser.objects.global.language.no),
v_centered: true,
},
],
buttons: [],
}"
/>
</td>
<td v-if="!props.isCustomerView">
<ColorIndicator
v-bind:label="{
text: order.customer_name,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: false,
dropdown: true
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
{
text: order.customer_name,
action: () => {
clickUser(order.customer_id);
},
...(SessionUser.canAccessSuperUser() ? {} : { disabled: true }),
button: true,
button_text: 'Vis kunde',
}
],
buttons: [],
}"
/>
</td>
<!--
<td>
<span
@mouseover="showPopper(
popperBox(
'Customer ID',
order.customer_id,
),
$event.target
)"
@mouseleave="removePopperIfOpen()"
@click="clickUser(order.customer_id)"
:class="{ 'is-clickable': SessionUser.canAccessSuperUser() }"
>
{{ order.customer_name }}
</span>
</td> -->
<td v-if="!props.isCustomerView">{{ order.cashier_id }}</td>
<td>{{ getDepartmentName(order.department_id) }}</td>
<td>
<ColorIndicator
v-bind:label="{
text: order.reg_1,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: false,
dropdown: (order.reg_1.length > 7),
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
{
text: order.reg_1,
action: () => {},
}
],
buttons: [],
}"
/>
</td>
<td>
<ColorIndicator
v-show="order.reg_2 !== ''"
v-bind:label="{
text: order.reg_2,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: false,
dropdown: (order.reg_2.length > 7),
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
{
text: order.reg_2,
action: () => {},
}
],
buttons: [],
}"
/>
</td>
<td>
<ColorIndicator
v-show="order.reg_3 !== ''"
v-bind:label="{
text: order.reg_3,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: false,
dropdown: (order.reg_3.length > 7),
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
{
text: order.reg_3,
action: () => {},
}
],
buttons: [],
}"
/>
</td>
<td>
<ColorIndicator
v-show="order.reference !== ''"
v-bind:label="{
text: order.reference,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: false,
dropdown: (order.reference.length > 7),
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
{
text: order.reference,
action: () => {},
}
],
buttons: [],
}"
/>
</td>
<td>
<ColorIndicator
v-show="order.notes !== ''"
v-bind:label="{
text: order.notes,
classes: [],
max_length: 7,
}"
v-bind:visibility="{
icon: false,
dropdown: (order.notes.length > 7),
}"
v-bind:dropdown_content="{
title: null,
buttons_title: null,
content: [
{
text: order.notes,
action: () => {},
}
],
buttons: [],
}"
/>
</td>
<td>{{ order.created_at }}</td>
<td>{{ SessionUser.functions.currency.toLocal(order.total_net_amount) }}</td>
<td>{{ order.completed_at }}</td>
<td>
<!-- Dropdown -->
<ActionSettingsWheelButton
v-bind:user_id="order.user_id"
v-bind:order_id="order.id"
v-bind:invoice_collection_id="order.invoice_collection_id"
v-bind:reg_1="order.reg_1"
>
<template v-slot:actions>
<!--
Go to the order page, in a new tab
<action-settings-wheel-item
label="Se transaktion i ny fane"
icon="fas fa-external-link-alt"
:click-action="() => redirectDepartmentOrderPage(order.id, order.department_id)"
:disabled="false"
/>
Show the invoice collection, in a new tab
<action-settings-wheel-item
label="Vis faktura samling i ny fane"
icon="fas fa-file-invoice-dollar"
:click-action="() => redirectSuperUserInvoiceCollectionPage(order.invoice_collection.id)"
:disabled="!doesOrderHaveInvoiceCollection(order)"
/>
-->
</template>
</ActionSettingsWheelButton>
</td>
</tr>
<!-- Dropdown content (if the invoice view is enabled,and the dropdown is active) -->
<tr v-if="props.invoiceView && isDropdownActive(order)">
<!-- Order line items -->
<td colspan="100%">
<!-- Content -->
<div class="content">
<OrderContentTable
:order-id="order.id"
/>
</div>
</td>
</tr>
</template>
</tbody>
<tfoot>
<tr>
<td colspan="100%">Viser {{ orders.length }} transaktioner</td>
</tr>
</tfoot>
</table>
<InvoiceMultipleCollectionsModal
v-if="isInvoiceMultipleCollectionsModalOpen"
v-bind:in-progress="invoiceCollectionQueueInProgress"
v-bind:failed="invoiceCollectionQueueFailed"
v-bind:succeeded="invoiceCollectionQueueSuccess"
v-bind:queued="invoiceCollectionQueue"
v-bind:log="collectionQueueLog"
@closeModal="confirmCloseModal()"
/>
</template>
<style scoped>
.status-bar-table-header {
max-width: 5px;
padding-left: 0;
padding-right: 0;
}
.status-bar-table-row {
border-radius: 5px;
width: 5px;
padding-left: 0;
padding-right: 0;
}
.status-bar.has-text-danger {
border-color: #ff3860;
}
.status-bar.has-text-warning {
border-color: #ffdd57;
}
.status-bar.has-text-success {
border-color: #48c774;
}
</style>
@@ -0,0 +1,126 @@
<script setup>
import OrdersSyncTable from "@/components/displays/department/pos/sync/ordersSyncTable.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
const props = defineProps({
onlyFromInvoiceCollection: {
type: Number,
default: 0
},
autoLoad: {
type: Boolean,
default: true
},
setCustomerFilter: {
type: Number,
default: 0
},
hideSearch: {
type: Boolean,
default: false
}
})
import { defineProps } from "vue";
import { useRouter } from "vue-router";
import {
isLoaded,
isLoading,
list,
loadList,
metaCurrentPage,
metaItemsPerPage,
metaTotalItems,
setEndpoint,
setMetaItemsPerPage,
setPage,
metaSearch,
search,
setFilter,
setOrder,
hideSearchField,
setHideSearchField,
} from "@/components/pagination/paginatedList.vue";
import PaginationNavigation from "@/components/displays/pagination/PaginationNavigation.vue";
import LoadButtonWhileAwait from "@/components/request/LoadButtonWhileAwait.vue";
import PaginationDisplay from "@/components/displays/pagination/PaginationDisplay.vue";
import OrdersTable from "@/components/displays/department/pos/orders/ordersTable.vue";
import ColorIndicator from "@/components/displays/buttons/ColorIndicator.vue";
const router = useRouter();
setEndpoint("/orders", false);
// If the customer filter is set, filter the orders by the customer number
if (props.setCustomerFilter > 0) {
setFilter("customer_id", props.setCustomerFilter);
console.log("Setting customer filter to: " + props.setCustomerFilter);
}
setFilter("cashier_id", 2285, false);
// Hide the search field
if (props.hideSearch) {
setHideSearchField(true);
console.log("Hiding search field");
} else {
setHideSearchField(false);
}
// If the departmentId is set, in the route, filter the orders by the departmentId
if (router.currentRoute.value.params.departmentId) {
setOrder("created_at", "desc");
setFilter("department_id", router.currentRoute.value.params.departmentId, false);
} else {
setOrder("created_at", "desc");
}
// If the onlyFromInvoiceCollection prop is set, filter the orders by the invoice collection id
if (props.onlyFromInvoiceCollection > 0) {
setFilter("invoice_collection_id", props.onlyFromInvoiceCollection, false);
}
// Load the list automatically if the autoLoad prop is set
if (props.autoLoad) {
loadList();
}
</script>
<template>
<div class="level mb-3">
<div class="level-left">
<div class="level-item">
<h1 class="title is-4">{{SessionUser.objects.orders.meta.title}} ({{SessionUser.objects.global.language.synchronized}})</h1>
</div>
<div class="level-item">
<h2 class="subtitle is-6">{{SessionUser.objects.global.language.showing}} {{ list.length }} {{SessionUser.objects.global.language.showing_of_separator}} {{ metaTotalItems }} {{SessionUser.objects.orders.meta.title.toLowerCase()}}</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<LoadButtonWhileAwait class="is-dark" :isLoading="isLoading" :loadFunction="loadList" icon="fas fa-sync-alt">{{SessionUser.objects.global.language.reload}}</LoadButtonWhileAwait>
</div>
</div>
</div>
<input @input="search($event.target.value)" class="input" type="text" placeholder="Søg i transaktioner" v-if="!hideSearchField"/>
<PaginationDisplay :metaItemsPerPage="metaItemsPerPage" :loadFunction="loadList" :isLoading="isLoading" :setMetaItemsPerPage="setMetaItemsPerPage">
<template #paginationColumns>
<!-- Sort by created_at -->
<div class="column is-narrow my-3">
<label class="label">Order direction</label>
<div class="control">
<div class="select">
<select @change="setOrder('created_at', $event.target.value); loadList();">
<option value="asc">Ascending (Oldest first)</option>
<option value="desc" selected>Descending (Newest first)</option>
</select>
</div>
</div>
</div>
</template>
</PaginationDisplay>
<OrdersSyncTable :orders="list" />
<PaginationNavigation :currentPage="metaCurrentPage" :totalPages="Math.ceil(metaTotalItems / metaItemsPerPage)" :loadFunction="loadList" :setPage="setPage" :isLoading="isLoading" />
</template>
<style scoped>
</style>
@@ -0,0 +1,115 @@
<script setup>
import OrdersSyncTable from "@/components/displays/department/pos/sync/ordersSyncTable.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
const props = defineProps({
autoLoad: {
type: Boolean,
default: true
},
setCustomerFilter: {
type: Number,
default: 0
},
hideSearch: {
type: Boolean,
default: false
}
})
import { defineProps } from "vue";
import { useRouter } from "vue-router";
import {
isLoaded,
isLoading,
list,
loadList,
metaCurrentPage,
metaItemsPerPage,
metaTotalItems,
setEndpoint,
setMetaItemsPerPage,
setPage,
metaSearch,
search,
setFilter,
setOrder,
hideSearchField,
setHideSearchField,
} from "@/components/pagination/paginatedList.vue";
import PaginationNavigation from "@/components/displays/pagination/PaginationNavigation.vue";
import LoadButtonWhileAwait from "@/components/request/LoadButtonWhileAwait.vue";
import PaginationDisplay from "@/components/displays/pagination/PaginationDisplay.vue";
import OrdersTable from "@/components/displays/department/pos/orders/ordersTable.vue";
import ColorIndicator from "@/components/displays/buttons/ColorIndicator.vue";
import OrdersSyncPossibleDuplicateTable
from "@/components/displays/department/pos/sync/ordersSyncPossibleDuplicateTable.vue";
const router = useRouter();
setEndpoint("/orders/sync/potential-matches", false);
// If the customer filter is set, filter the orders by the customer number
if (props.setCustomerFilter > 0) {
setFilter("customer_number", props.setCustomerFilter);
console.log("Setting customer filter to: " + props.setCustomerFilter);
}
// Hide the search field
if (props.hideSearch) {
setHideSearchField(true);
console.log("Hiding search field");
} else {
setHideSearchField(false);
}
// If the departmentId is set, in the route, filter the orders by the departmentId
if (router.currentRoute.value.params.departmentId) {
setOrder("created_at", "desc");
setFilter("department", router.currentRoute.value.params.departmentId, false);
} else {
setOrder("created_at", "desc");
}
// Load the list automatically if the autoLoad prop is set
if (props.autoLoad) {
loadList();
}
</script>
<template>
<div class="level mb-3">
<div class="level-left">
<div class="level-item">
<h1 class="title is-4">{{SessionUser.objects.orders.meta.title}} ({{SessionUser.objects.global.language.synchronized}})</h1>
</div>
<div class="level-item">
<h2 class="subtitle is-6">{{SessionUser.objects.global.language.showing}} {{ list.length }} {{SessionUser.objects.global.language.showing_of_separator}} {{ metaTotalItems }} {{SessionUser.objects.orders.meta.title.toLowerCase()}}</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<LoadButtonWhileAwait class="is-dark" :isLoading="isLoading" :loadFunction="loadList" icon="fas fa-sync-alt">{{SessionUser.objects.global.language.reload}}</LoadButtonWhileAwait>
</div>
</div>
</div>
<input @input="search($event.target.value)" class="input" type="text" placeholder="Søg i transaktioner" v-if="!hideSearchField"/>
<PaginationDisplay :metaItemsPerPage="metaItemsPerPage" :loadFunction="loadList" :isLoading="isLoading" :setMetaItemsPerPage="setMetaItemsPerPage">
<template #paginationColumns>
<!-- Sort by created_at -->
<div class="column is-narrow my-3">
<label class="label">Order direction</label>
<div class="control">
<div class="select">
<select @change="setOrder('created_at', $event.target.value); loadList();">
<option value="asc">Ascending (Oldest first)</option>
<option value="desc" selected>Descending (Newest first)</option>
</select>
</div>
</div>
</div>
</template>
</PaginationDisplay>
<OrdersSyncPossibleDuplicateTable :objects="list" />
<PaginationNavigation :currentPage="metaCurrentPage" :totalPages="Math.ceil(metaTotalItems / metaItemsPerPage)" :loadFunction="loadList" :setPage="setPage" :isLoading="isLoading" />
</template>
<style scoped>
</style>
@@ -161,7 +161,7 @@ const getOrders = (object) => {
for (let i = 0; i < invoices.length; i++) {
let invoice = invoices[i];
// Get the orders for the invoice
let invoice_orders = invoice.orders;
let invoice_orders = invoice.objects;
// For each order, add the customer_number to the order
for (let j = 0; j < invoice_orders.length; j++) {
let order = invoice_orders[j];
@@ -180,7 +180,7 @@ const getOrders = (object) => {
}
return 0;
});
console.log('orders', orders);
console.log('objects', orders);
return orders;
}
@@ -47,7 +47,7 @@ const getOrders = (object) => {
let orders = [];
for (let i = 0; i < invoices.length; i++) {
let invoice = invoices[i];
let invoice_orders = invoice.orders;
let invoice_orders = invoice.objects;
orders = orders.concat(invoice_orders);
}
return orders;
@@ -106,7 +106,7 @@ getDepartments();
<!-- Active invoice count -->
<td>{{ object.active_invoices.length }}</td>
<!-- Active invoice count -->
<td>{{ object.orders }}</td>
<td>{{ object.objects }}</td>
<!-- Status -->
<!-- Total net amount -->
<td>{{ SessionUser.functions.currency.toLocal(object.total_net_amount) }}</td>
@@ -73,7 +73,7 @@ const onSelect = (id) => {
</thead>
<tbody>
<template v-for="object in props.objects" :key="object.id">
<tr v-if="object.orders > 0 || props.showEmpty">
<tr v-if="object.objects > 0 || props.showEmpty">
<td>{{ object.id }}</td>
<!-- Customer name -->
<EditableTableColumn
@@ -146,7 +146,10 @@ const onSelect = (id) => {
</tr>
<!-- Show a count of the total number of objects -->
<tr>
<td colspan="9">Viser {{ objects.length - objects.filter(object => object.orders === 0).length }} af {{objects.length}} {{ SessionUser.objects.collectedOrderInvoices.meta.labels.multiple }}<template v-if="!props.showEmpty">, skjuler {{ objects.filter(object => object.orders === 0).length }} {{ SessionUser.objects.collectedOrderInvoices.meta.labels.multiple }} uden ordre</template></td>
<td colspan="9">Viser {{ objects.length - objects.filter(object => object.objects === 0).length }} af
{{ objects.length }} {{ SessionUser.objects.collectedOrderInvoices.meta.labels.multiple }}<template v-if="!props.showEmpty">,
skjuler {{ objects.filter(object => object.objects === 0).length }}
{{ SessionUser.objects.collectedOrderInvoices.meta.labels.multiple }} uden ordre</template></td>
</tr>
</tbody>
</table>
@@ -17,7 +17,7 @@ const su_object = SessionUser.objects.collectedOrderInvoices;
const isInvoiceCancelled = (object) => {
// Check if the invoice has been canceled (There's no orders attached to it)
if (object.orders.length === 0) {
if (object.objects.length === 0) {
return true
}
};
@@ -96,7 +96,7 @@ const dropdown_content = (object) => {
button: true,
button_classes: ['has-text-grey', 'is-text'],
v_centered: true,
button_text: object.orders.length > 0 ? object.orders.length : SessionUser.objects.global.language.no_data,
button_text: object.objects.length > 0 ? object.objects.length : SessionUser.objects.global.language.no_data,
},
],
buttons: []
@@ -108,6 +108,16 @@ const menu_items = ref([
'list_orders'
],
},
{
name: 'Synkronisering',
route: '/admin/' + SessionUser.functions.getDepartmentIdFromUrl() + '/modules/pos/sync',
icon: 'fas fa-exchange-alt',
children: [],
hidden: (SessionUser.functions.getDepartmentIdFromUrl() === undefined),
permissions: [
'department_pos_sync'
],
},
],
hidden: (SessionUser.functions.getDepartmentIdFromUrl() === undefined)
},
@@ -19,8 +19,13 @@ export const ObjectsGlobal = {
return `Rediger ${object.columns[column].label.toLowerCase()}`;
},
collection: "Samling",
showing_of_separator: "af",
split: "Opdel",
successful_syncs: "Succesfulde synkroniseringer",
save: "Gem",
synchronized: "Synkroniseret",
warnings: "Advarsler",
warning: "Advarsel",
tank_cleaning: "Tankcleaning",
default: "Standard",
required: "Påkrævet",
@@ -0,0 +1,37 @@
<script setup>
import DepartmentDashboardHero from "@/views/dashboards/departmentDashboard/DepartmentDashboardHero.vue";
import DepartmentPosNavigation from "@/views/dashboards/departmentDashboard/modules/Pos/DepartmentPosNavigation.vue";
import OrdersPagination from "@/components/displays/pagination/models/DepartmentPos/OrdersPagination.vue";
import RestrictedPageWrapper from "@/components/page/wrappers/RestrictedPageWrapper.vue";
import { SessionUser } from "@/components/session/token/SessionUser.vue";
import DepartmentDashboardPageWrapper from "@/views/dashboards/departmentDashboard/DepartmentDashboardPageWrapper.vue";
import NotFoundFallBackPageWrapper from "@/components/page/wrappers/NotFoundFallBackPageWrapper.vue";
import OrdersSyncPagination from "@/components/displays/pagination/models/DepartmentPos/OrdersSyncPagination.vue";
import PosOrdersSync from "@/components/displays/department/pos/sync/displays/PosOrdersSync.vue";
import OrdersSyncPossibleDuplicatesPagination
from "@/components/displays/pagination/models/DepartmentPos/OrdersSyncPossibleDuplicatesPagination.vue";
</script>
<template>
<RestrictedPageWrapper :hasPermission="SessionUser.canAccessAdmin()">
<DepartmentDashboardPageWrapper title="Kassesystem" subtitle="Point of Sale">
<NotFoundFallBackPageWrapper :exists="SessionUser.functions.getDepartmentIdFromUrl() && SessionUser.canAccessDepartment(SessionUser.functions.getDepartmentIdFromUrl())" error="Please select a department, that you have access to. If you believe this is an error, please contact support.">
<template #default>
<DepartmentDashboardHero />
<PosOrdersSync />
<OrdersSyncPossibleDuplicatesPagination />
<!--
Successful Orders Syncs
<OrdersSyncPagination />
-->
</template>
</NotFoundFallBackPageWrapper>
</DepartmentDashboardPageWrapper>
</RestrictedPageWrapper>
</template>
<style scoped>
</style>
@@ -43,7 +43,7 @@ const getCollectedOrderInvoice = async () => {
SessionUser.objects.collectedOrderInvoices.get.single(collectedOrderInvoiceId).then((response) => {
const raw_data = response;
console.log(raw_data);
orders.value = raw_data.orders || [];
orders.value = raw_data.objects || [];
user.value = raw_data.user;
collectedOrderInvoice.value = raw_data;
isLoading.value = false;