Add product note handling and enhance additional item management in POS Mobile components
- Added `PosDepartmentStepMobilePopupAddProductNote.vue` for managing product notes via popups. - Updated `PosProduct` to include optional `notes` field in product definition. - Modified additional item logic in `PosDepartmentStepMobileFlow.vue` to handle product notes and quantities. - Enhanced `PosDepartmentStepMobile2AdditionalItems.vue` with dynamic toggles, improved layout, and localized labels. - Updated translations and button labels for additional item actions. - Adjusted `WhiteBoxCard.vue` to support `forceState` prop for toggle control.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { defineProps, defineEmits, onMounted, ref } from 'vue';
|
||||
import {defineProps, defineEmits, onMounted, ref, watch} from 'vue';
|
||||
|
||||
import WhiteBox from "@/components/displays/boxes/WhiteBox.vue";
|
||||
|
||||
@@ -19,6 +19,10 @@ const props = defineProps({
|
||||
hideHeader: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
forceState: {
|
||||
type: Boolean,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
/**
|
||||
@@ -42,6 +46,13 @@ const toggle = () => {
|
||||
isOpen.value = !isOpen.value;
|
||||
emit('toggle', isOpen.value);
|
||||
};
|
||||
|
||||
/** Watch for changes in forceState prop to control isOpen */
|
||||
watch(() => props.forceState, (newVal) => {
|
||||
if (newVal !== null) {
|
||||
isOpen.value = newVal;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -182,7 +182,7 @@ const onBeforeComplete = () => {
|
||||
product_id: primaryItem.value.id, // The product ID of the primary item
|
||||
quantity: 1,
|
||||
price: primaryItem.value.price,
|
||||
notes: '', // Notes can be added here if needed
|
||||
notes: primaryItem?.notes || '', // Notes can be added here if needed
|
||||
related_item_id: null,
|
||||
}, // The order item to create
|
||||
{authenticated: true}
|
||||
@@ -199,12 +199,31 @@ const onBeforeComplete = () => {
|
||||
product_id: addon.product.id, // The product ID of the addon
|
||||
quantity: addon.quantity,
|
||||
price: addon.product.price,
|
||||
notes: '', // Notes can be added here if needed
|
||||
notes: addon.product?.notes || '', // Notes can be added here if needed
|
||||
related_item_id: relatedItemId, // Link the addon to the primary item
|
||||
},
|
||||
{authenticated: true}
|
||||
);
|
||||
});
|
||||
// Create the additional items (With a quantity of > 0)
|
||||
const additionalItems = transactionItems.additionalItems.value.filter(item => item.quantity > 0);
|
||||
const additionalPromises = additionalItems.map(item => {
|
||||
// For each additional item, create an order item
|
||||
return SessionUser.objects.global.add.object(
|
||||
'/order/items',
|
||||
{
|
||||
order_id: parseInt(order_id.value), // The order ID to which the additional item will be added
|
||||
product_id: item.id, // The product ID of the additional item
|
||||
quantity: item.quantity,
|
||||
price: item.price,
|
||||
notes: item?.notes || '', // Notes can be added here if needed
|
||||
related_item_id: null, // Additional items are not linked to the primary item
|
||||
},
|
||||
{authenticated: true}
|
||||
);
|
||||
});
|
||||
// Combine addon and additional item promises
|
||||
addonPromises.push(...additionalPromises);
|
||||
// Wait for all addon items to be created
|
||||
return Promise.all(addonPromises);
|
||||
}).then(() => {
|
||||
@@ -316,7 +335,7 @@ watch(() => vehicles.vehicle_1.value.reference, (newValue, oldValue) => {
|
||||
<PosDepartmentStep2MobileVehicleSelection @close="vehicleSelection = false"/>
|
||||
</template>
|
||||
<template v-else-if="additionalItemSelection">
|
||||
<PosDepartmentStepMobile2AdditionalItems/>
|
||||
<PosDepartmentStepMobile2AdditionalItems :label="SessionUser.objects.global.language.additional_items" :subtitle="''" @close="additionalItemSelection = false"/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="is-flex is-flex-direction-column is-justify-content-space-between is-gap-2">
|
||||
@@ -331,7 +350,7 @@ watch(() => vehicles.vehicle_1.value.reference, (newValue, oldValue) => {
|
||||
:product="transactionItems.primaryItem.value"
|
||||
/>
|
||||
<!-- Additional items -->
|
||||
<!--<PosDepartmentStepMobile2AdditionalItems/>-->
|
||||
<PosDepartmentStepMobile2AdditionalItems :label="SessionUser.objects.global.language.additional_items" :subtitle="''"/>
|
||||
<!-- Last order details -->
|
||||
<PosDepartmentStepMobile2LastOrder
|
||||
v-show="lastOrders.get(1)"
|
||||
|
||||
+49
-15
@@ -19,6 +19,7 @@ import {
|
||||
} from "@/components/displays/department/pos/steps/mobile/objects/PosDepartmentStepMobileFlow.vue";
|
||||
import PosDepartmentStep2MobileVehicleSelection
|
||||
from "@/components/displays/department/pos/steps/mobile/views/PosDepartmentStep2MobileVehicleSelection.vue";
|
||||
import GenericButton from "@/components/viewport/page/templates/generic/graphics/GenericButton.vue";
|
||||
|
||||
const props = defineProps({
|
||||
label: {
|
||||
@@ -69,6 +70,10 @@ const displaySubtitle = computed(() => {
|
||||
// Emit event on toggle
|
||||
function onToggle(isOpen: boolean) {
|
||||
checked.value = isOpen;
|
||||
// Open the additional item selection view if toggled open
|
||||
if (isOpen) {
|
||||
pos.views.additionalItemSelection.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Additional item management logic */
|
||||
@@ -89,7 +94,7 @@ const exampleProducts = ref<PosProduct[]>([
|
||||
}
|
||||
]);
|
||||
const convertProductToAddon = (product: PosProduct, options: {quantity?: number, min?: number, max?: number} = {}): Addon => {
|
||||
console.warn("Converting product to addon:", product, options);
|
||||
//console.warn("Converting product to addon:", product, options);
|
||||
return {
|
||||
id: product.id,
|
||||
name: product.name,
|
||||
@@ -129,6 +134,7 @@ watch(() => pos.transactionItems.additionalItems.value, (newVal) => {
|
||||
if (!newVal) return;
|
||||
if (newVal.length === 0) {
|
||||
availableAdditionalItems.value = [];
|
||||
//
|
||||
return;
|
||||
}
|
||||
// Prevent recursive loop by checking if availableAdditionalItems already matches newVal
|
||||
@@ -138,61 +144,89 @@ watch(() => pos.transactionItems.additionalItems.value, (newVal) => {
|
||||
if (isSame) return;
|
||||
availableAdditionalItems.value = getAvailableAdditionalItems();
|
||||
}, { deep: true });
|
||||
|
||||
const onClickAddProduct = async (product: PosProduct) => {
|
||||
// If the product requires note, open note input.
|
||||
pos.transactionItems.addAdditionalItem(product);
|
||||
// If the view is fullscreen, close it after adding
|
||||
if (pos.views.additionalItemSelection.value) {
|
||||
pos.views.additionalItemSelection.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Minimal view, when not set as fullscreen view -->
|
||||
<WhiteBoxCard :toggleable="true" @toggle="onToggle" v-if="!pos.views.additionalItemSelection.value">
|
||||
<WhiteBoxCard :toggleable="pos.transactionItems.additionalItems.value && pos.transactionItems.additionalItems.value.length == 0"
|
||||
:defaultOpen="pos.transactionItems.additionalItems.value && pos.transactionItems.additionalItems.value.length > 0"
|
||||
@toggle="onToggle"
|
||||
:forceState="(pos.transactionItems.additionalItems.value && pos.transactionItems.additionalItems.value.length > 0) ? true : (pos.views.additionalItemSelection.value)"
|
||||
v-if="!pos.views.additionalItemSelection.value">
|
||||
<!-- Header -->
|
||||
<template #header>
|
||||
<div class="card-header-title">{{ displayLabel }}</div>
|
||||
<div class="card-header-icon">
|
||||
<!-- Toggle Switch -->
|
||||
<label class="switch">
|
||||
<input type="checkbox" v-model="checked" />
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
<!-- Right arrow, if there's no items, down arrow if there are items -->
|
||||
<span class="icon">
|
||||
<i v-if="!pos.transactionItems.additionalItems.value || pos.transactionItems.additionalItems.value.length === 0" class="fas fa-angle-right"></i>
|
||||
<i v-else class="fas fa-angle-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Content -->
|
||||
<template #content>
|
||||
<!-- Suggested items -->
|
||||
<div>
|
||||
<!-- No items added yet -->
|
||||
<div v-if="!availableAdditionalItems || availableAdditionalItems.length === 0">
|
||||
<p>{{ SessionUser.objects.global.language.no_additional_items }}</p>
|
||||
</div>
|
||||
<PosDepartmentStepMobile2Addons :label="''" :addons="availableAdditionalItems" />
|
||||
</div>
|
||||
</template>
|
||||
<!-- Footer -->
|
||||
<template #footer>
|
||||
<!-- Select other product button -->
|
||||
<a class="card-footer-item" @click="onClickAddOtherProduct">Vælg andre produkter</a>
|
||||
<a class="card-footer-item" @click="onClickAddOtherProduct">
|
||||
<span class="icon">
|
||||
<i class="fas fa-plus"></i>
|
||||
</span>
|
||||
<span>{{ SessionUser.objects.global.language.add_other_product }}</span>
|
||||
</a>
|
||||
</template>
|
||||
</WhiteBoxCard>
|
||||
<!-- Fullscreen view, when selecting other products -->
|
||||
<template v-else>
|
||||
<!-- Shortcuts / recommendations -->
|
||||
<WhiteBoxCard :toggleable="true">
|
||||
<!-- Header -->
|
||||
<!--<WhiteBoxCard :toggleable="true" v-show="false">
|
||||
Header
|
||||
<template #header>
|
||||
<div class="card-header-title">{{ SessionUser.objects.global.language.recommended }}</div>
|
||||
<div class="card-header-icon">
|
||||
<span class="icon">
|
||||
<!-- Arrow right icon -->
|
||||
Arrow right icon
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</WhiteBoxCard>
|
||||
</WhiteBoxCard> -->
|
||||
<!-- Categories of products -->
|
||||
<PosDepartmentStep2MobileVehicleSelection :onAddProduct="pos.transactionItems.addAdditionalItem" :onSearchClick="() => console.warn('AdditionalItem Search Clicked')"/><!-- :asAddons="true" :addons="availableAdditionalItems" @update:addons="availableAdditionalItems = $event"/>-->
|
||||
<PosDepartmentStep2MobileVehicleSelection :onAddProduct="onClickAddProduct" :onSearchClick="() => console.warn('AdditionalItem Search Clicked')"/><!-- :asAddons="true" :addons="availableAdditionalItems" @update:addons="availableAdditionalItems = $event"/>-->
|
||||
<!--{{ availableAdditionalItems }}-->
|
||||
<!-- Products in category -->
|
||||
<!-- Back button -->
|
||||
|
||||
<!-- Buttons -->
|
||||
<PosDepartmentStepMobileFixedBottomControl>
|
||||
<!-- Complete button -->
|
||||
<PosDepartmentStepMobileButtonNextStep :customAction="onClickAddOtherProduct"/>
|
||||
<!-- Next button -->
|
||||
<PosDepartmentStepMobileButtonNextStep class="has-background-black" :customAction="onClickAddOtherProduct">
|
||||
<span class="is-float-left has-text-white">{{ SessionUser.objects.global.language.next }}</span>
|
||||
<span class="is-float-right has-text-white">
|
||||
<!-- Arrow right icon -->
|
||||
<i class="fas fa-arrow-right"></i>
|
||||
</span>
|
||||
</PosDepartmentStepMobileButtonNextStep>
|
||||
</PosDepartmentStepMobileFixedBottomControl>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
+1
@@ -184,6 +184,7 @@ const finalizeStep1 = () => {
|
||||
|
||||
const step2 = () => {
|
||||
/** This function can be used to perform any specific actions for step 2 */
|
||||
// Add all additional items to the order
|
||||
popups.select('completed_transaction', {
|
||||
message: `Order #${order_id.value} successfully created.`,
|
||||
});
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, defineEmits, watch, ref } from "vue";
|
||||
import { pos } from "../objects/PosDepartmentStepMobileFlow.vue";
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void;
|
||||
}>();
|
||||
const props = pos.popups.get()?.props;
|
||||
const product = props.product;
|
||||
const note = ref(product.notes || "");
|
||||
watch(note, (newNote) => {
|
||||
product.notes = newNote;
|
||||
// If the note is empty, remove it from the product
|
||||
if (newNote === "") {
|
||||
delete product.notes;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- Input field with underline -->
|
||||
<div class="field underlined-input-field">
|
||||
<div class="control has-icons-right">
|
||||
<input
|
||||
class="input is-searched"
|
||||
v-model="note"
|
||||
type="text"
|
||||
placeholder="Indtast note"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
input {
|
||||
/* input-fields */
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
/* Auto layout */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 0px;
|
||||
border-bottom: none;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
|
||||
gap: 10px;
|
||||
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
|
||||
background: #FFFFFF;
|
||||
border-color: transparent;
|
||||
border-radius: 4px;
|
||||
|
||||
/* Inside auto layout */
|
||||
flex: none;
|
||||
order: 1;
|
||||
align-self: stretch;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
input:focus-visible {
|
||||
border-color: transparent;
|
||||
outline: none;
|
||||
}
|
||||
.underlined-input-field {
|
||||
padding-bottom: 0;
|
||||
border-bottom: #929292 1px solid;
|
||||
}
|
||||
.debug-input {
|
||||
/* input-fields */
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
/* Auto layout */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0px 8px;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #A6A5A5;
|
||||
border-radius: 4px;
|
||||
|
||||
/* Inside auto layout */
|
||||
flex: none;
|
||||
order: 1;
|
||||
align-self: stretch;
|
||||
flex-grow: 0;
|
||||
}
|
||||
input.is-searched {
|
||||
/* input-fields */
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
/* Auto layout */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 12px 8px;
|
||||
gap: 10px;
|
||||
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #000000;
|
||||
border-radius: 4px;
|
||||
border-bottom: none;
|
||||
|
||||
/* Inside auto layout */
|
||||
flex: none;
|
||||
order: 1;
|
||||
align-self: stretch;
|
||||
flex-grow: 0;
|
||||
|
||||
}
|
||||
</style>
|
||||
+58
-15
@@ -114,16 +114,16 @@ const locations = {
|
||||
const defaultActionButtons = ref<{ [key: string]: PosActionButton }>({
|
||||
/** General purpose action buttons (used by PosAddons)*/
|
||||
cancel: {
|
||||
label: 'Cancel',
|
||||
description: 'Close this popup',
|
||||
label: 'Annuller',
|
||||
description: 'Luk denne popup uden at gemme ændringer',
|
||||
onClick: () => {
|
||||
clearPopup(); // Close the popup
|
||||
},
|
||||
color: 'light'
|
||||
},
|
||||
close: {
|
||||
label: 'Close',
|
||||
description: 'Close this popup',
|
||||
label: 'Luk',
|
||||
description: 'Luk denne popup',
|
||||
onClick: () => {
|
||||
clearPopup(); // Close the popup
|
||||
},
|
||||
@@ -131,8 +131,8 @@ const defaultActionButtons = ref<{ [key: string]: PosActionButton }>({
|
||||
},
|
||||
/** Customer selection action buttons */
|
||||
selectCustomer: {
|
||||
label: 'Select Customer',
|
||||
description: 'Select a customer for this transaction',
|
||||
label: 'Vælg kunde',
|
||||
description: 'Vælg en kunde til denne transaktion',
|
||||
onClick: () => {
|
||||
console.warn('Select Customer button clicked');
|
||||
// Open the select customer popup
|
||||
@@ -141,8 +141,8 @@ const defaultActionButtons = ref<{ [key: string]: PosActionButton }>({
|
||||
color: 'primary'
|
||||
},
|
||||
editReference: {
|
||||
label: 'Edit Reference',
|
||||
description: 'Edit the reference for this transaction',
|
||||
label: 'Redigér reference',
|
||||
description: 'Redigér reference for denne transaktion',
|
||||
onClick: () => {
|
||||
console.warn('Edit Reference button clicked');
|
||||
// Open the edit reference popup
|
||||
@@ -229,7 +229,16 @@ const addDefaultPopups = () => {
|
||||
component: 'error',
|
||||
hideHeader: true,
|
||||
actionButtons: [{...defaultActionButtons.value.close}],
|
||||
})
|
||||
});
|
||||
// Add product note
|
||||
addPopup({
|
||||
id: 'add_product_note',
|
||||
title: 'Add Product Note',
|
||||
message: 'Please enter notes for the product.',
|
||||
component: 'add_product_note', // This component should handle input and return the notes
|
||||
hideHeader: true,
|
||||
actionButtons: [{...defaultActionButtons.value.cancel}],
|
||||
});
|
||||
}
|
||||
// Function to check if a popup is defined in the list
|
||||
const isPopupDefined = (id: string): boolean => {
|
||||
@@ -377,6 +386,14 @@ const additionalItems = ref<PosProduct[]>([]);
|
||||
|
||||
// Function to add another item to the transaction
|
||||
const addAdditionalItem = (item: PosProduct) => {
|
||||
// If the additional item requires a note, prompt for it before adding
|
||||
if (item.requires_note) {
|
||||
promptForNotesIfRequired(item, (notes: string) => {
|
||||
item.notes = notes;
|
||||
additionalItems.value.push(item);
|
||||
});
|
||||
return;
|
||||
}
|
||||
additionalItems.value.push(item);
|
||||
};
|
||||
// Function to remove an additional item from the transaction
|
||||
@@ -398,7 +415,7 @@ const setAdditionalItems = (items: PosProduct[]) => {
|
||||
const getAdditionalItemsTotal = () => {
|
||||
let total = 0;
|
||||
additionalItems.value.forEach(item => {
|
||||
total += item.price;
|
||||
total += item.price * (item.quantity || 1);
|
||||
// Add the addons prices if they exist
|
||||
if (item.addons && item.addons.length > 0) {
|
||||
// Make sure that there is a quantity for each addon, if not, assume 0 quantity
|
||||
@@ -496,16 +513,45 @@ const updateTransactionProduct = (updatedProduct: PosProduct) => {
|
||||
const updateTransactionPrices = (updatedProducts: PosProduct[] | null = null) => {
|
||||
// If no updated products are provided, take the current product list
|
||||
if (!updatedProducts) {
|
||||
console.warn('No updated products provided, using current product list.');
|
||||
//console.warn('No updated products provided, using current product list.');
|
||||
updatedProducts = productList.list.value;
|
||||
}
|
||||
// Update prices for each product in the transaction
|
||||
updatedProducts.forEach(product => {
|
||||
console.warn(`Updating transaction prices for product with id: ${product.id}`);
|
||||
//console.warn(`Updating transaction prices for product with id: ${product.id}`);
|
||||
updateTransactionProduct(product);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to prompt for notes if required (input is a PosProduct)
|
||||
const promptForNotesIfRequired = (product: PosProduct, callback: (notes: string) => void) => {
|
||||
if (product.requires_note) {
|
||||
// Open a popup to prompt for notes
|
||||
popups.select('add_product_note', {
|
||||
title: 'Tilføj note',
|
||||
message: `Tilføj venligst en note for produktet: ${product.name}`,
|
||||
component: 'add_product_note', // This component should handle input and return the notes
|
||||
style: {maxHeight: '40vh'},
|
||||
props: { product },
|
||||
actionButtons: [
|
||||
{
|
||||
label: 'Bekræft',
|
||||
description: 'Bekræft noten og fortsæt',
|
||||
onClick: () => {
|
||||
callback(popups.get()?.props?.product?.notes || '');
|
||||
clearPopup();
|
||||
},
|
||||
color: 'primary'
|
||||
},
|
||||
{...defaultActionButtons.value.cancel}
|
||||
],
|
||||
});
|
||||
} else {
|
||||
// If no notes are required, call the callback with an empty string
|
||||
callback('');
|
||||
}
|
||||
}
|
||||
|
||||
const transactionItems = {
|
||||
// Additional items are separate from the primary item
|
||||
additionalItems,
|
||||
@@ -1304,9 +1350,6 @@ watch(
|
||||
},
|
||||
{deep: true}
|
||||
);
|
||||
|
||||
|
||||
// Define component with exports
|
||||
export default defineComponent({
|
||||
name: 'PosDepartmentStepMobileFlow',
|
||||
setup() {
|
||||
|
||||
@@ -10,14 +10,17 @@ import PosDepartmentStepMobilePopupCompleteBooking
|
||||
import PosDepartmentStepMobilePopupError
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobilePopupError.vue";
|
||||
import type { PosActionButton } from './PosActionButton.vue';
|
||||
import PosDepartmentStepMobilePopupAddProductNote
|
||||
from "@/components/displays/department/pos/steps/mobile/elements/PosDepartmentStepMobilePopupAddProductNote.vue";
|
||||
|
||||
export type PopupComponentKey = 'select_customer' | 'completed_transaction' | 'complete_booking' | 'error';
|
||||
export type PopupComponentKey = 'select_customer' | 'completed_transaction' | 'complete_booking' | 'error' | 'add_product_note';
|
||||
|
||||
export const PopupComponents = {
|
||||
select_customer: PosDepartmentStepMobilePopupSelectCustomer,
|
||||
completed_transaction: PosDepartmentStepMobilePopupCompletedTransaction,
|
||||
complete_booking: PosDepartmentStepMobilePopupCompleteBooking,
|
||||
error: PosDepartmentStepMobilePopupError,
|
||||
add_product_note: PosDepartmentStepMobilePopupAddProductNote,
|
||||
} as const;
|
||||
|
||||
export const popupComponentKeyToComponent = (key: PopupComponentKey) => PopupComponents[key];
|
||||
@@ -44,6 +47,7 @@ export default defineComponent({
|
||||
PosDepartmentStepMobilePopupCompletedTransaction,
|
||||
PosDepartmentStepMobilePopupCompleteBooking,
|
||||
PosDepartmentStepMobilePopupError,
|
||||
PosDepartmentStepMobilePopupAddProductNote,
|
||||
},
|
||||
props: {
|
||||
popup: {
|
||||
|
||||
@@ -18,5 +18,6 @@ export type PosProduct = {
|
||||
// Addons
|
||||
addons?: Addon[]; // Optional array of addons
|
||||
quantity?: number;
|
||||
notes?: string; // Optional notes for the product, used as a part of order item generation
|
||||
};
|
||||
</script>
|
||||
+2
-2
@@ -74,10 +74,10 @@ const onSearchClick = () => {
|
||||
<!--<PosDepartmentStepMobile2ProductRecommendations/>-->
|
||||
<!-- Products -->
|
||||
<PosDepartmentStepMobile2Products @addProduct="onAddProduct" :asAddons="props.asAddons" :addons="props.addons"/>
|
||||
<!-- Next button -->
|
||||
<!-- Next button
|
||||
<GenericButton class="p-5" @click="emit('close')">
|
||||
Next
|
||||
</GenericButton>
|
||||
</GenericButton> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -24,7 +24,11 @@ export const ObjectsGlobal = {
|
||||
generated: "Genereret",
|
||||
requires_action: "Kræver handling",
|
||||
expand: "Udfold",
|
||||
add_other_product: "Tilføj andet produkt",
|
||||
no_additional_items: "Ingen yderligere varer",
|
||||
additional_items: "Yderligere varer",
|
||||
showing_of_separator: "af",
|
||||
next: "Næste",
|
||||
send_as_is: "Send som den er",
|
||||
ignore_customer_arrangements: "Ignorer kundeaftaler",
|
||||
recommended: "Anbefalet",
|
||||
|
||||
Reference in New Issue
Block a user