- Introduced `repairText` and `containsSuspiciousEncoding` utilities for handling corrupted text encodings. - Added unit tests (`encoding-repair.spec.js`) to validate encoding repair and encoding marker detection. - Integrated encoding check into unit test workflows (`text:check-encoding` and `text:fix-encoding` scripts). - Replaced corrupted strings across multiple components and locales with proper UTF-8 encodings.
1315 lines
44 KiB
Vue
1315 lines
44 KiB
Vue
<script setup>
|
|
import { useI18n } from "vue-i18n";
|
|
import { showEditOrderItemForm } from "@/components/forms/superUser/editOrderItemForm.vue";
|
|
import { removeOrderItem } from "@/components/shop/OrdersItems.vue";
|
|
import { computed, ref, watch, defineProps, useSlots, defineEmits } from "vue";
|
|
import PosOrderDetailItemsTable from "@/components/displays/department/pos/order/PosOrderDetailItemsTable.vue";
|
|
import PosOrderItemsDefaultTable from "@/components/displays/department/pos/order/PosOrderItemsDefaultTable.vue";
|
|
import PosOrderItemEditModal from "@/components/displays/department/pos/order/PosOrderItemEditModal.vue";
|
|
const props = defineProps({
|
|
orderItems: Array,
|
|
orderId: [Number, String],
|
|
loadOrderItems: Function,
|
|
editPossible: Boolean,
|
|
isLarge: Boolean,
|
|
stackMetadata: Boolean,
|
|
reg_1: String,
|
|
reg_2: String,
|
|
reg_3: String,
|
|
customer_name: String,
|
|
emitEventsOnly: Boolean,
|
|
disallowItemEdit: Boolean,
|
|
variant: {
|
|
type: String,
|
|
default: "default",
|
|
validator: (value) => ["default", "order-detail", "sidebar"].includes(value),
|
|
},
|
|
});
|
|
const emits = defineEmits(["update:orderItems", "onDestroyItem"]);
|
|
import { showPopper, removePopperIfOpen, popperBox } from "@/components/displays/PopperDefault.vue";
|
|
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
|
import ActionSettingsWheelButton from "@/components/displays/buttons/ActionSettingsWheelButton.vue";
|
|
import ActionSettingsWheelItem from "@/components/displays/buttons/ActionSettingsWheelItem.vue";
|
|
import {
|
|
customer_name,
|
|
customerRequiresReferenceNumber,
|
|
fetchAttachments,
|
|
customerUsesPONumbers,
|
|
getOrderDetails,
|
|
setOrderId,
|
|
order_id,
|
|
reference,
|
|
order_notes,
|
|
order_po,
|
|
order_safety_seal,
|
|
} from "@/components/shop/POSDepartmentProcess.vue";
|
|
import SpanSkeleton from "@/components/displays/skeletons/SpanSkeleton.vue";
|
|
import PosOrderLicensePlates from "@/components/displays/department/pos/order/PosOrderLicensePlates.vue";
|
|
import POSOrderCustomerWishes from "@/components/displays/department/pos/order/POSOrderCustomerWishes.vue";
|
|
import POSOrderNote from "@/components/displays/department/pos/order/POSOrderNote.vue";
|
|
import { doesOrderContainWashCertificateProduct } from "@/components/displays/department/pos/utils/washCertificate.js";
|
|
|
|
const { t } = useI18n();
|
|
const slots = useSlots();
|
|
// Tabs
|
|
|
|
const panel_tabs = ref([
|
|
{
|
|
id: "cart",
|
|
icon: "fas fa-shopping-cart",
|
|
name: t("admin.pos.cart"),
|
|
active: true,
|
|
},
|
|
]);
|
|
|
|
const handleCustomerWishesFieldSaved = async (fieldKey) => {
|
|
if (fieldKey !== "safety_seal") {
|
|
return;
|
|
}
|
|
|
|
await loadOrder();
|
|
};
|
|
// Check if the size is large
|
|
const isLarge = props.isLarge !== undefined ? props.isLarge : false;
|
|
const isOrderDetailVariant = computed(() => props.variant === "order-detail");
|
|
const isSidebarVariant = computed(() => props.variant === "sidebar");
|
|
const showInlineActionButtons = computed(() => isOrderDetailVariant.value);
|
|
const showSidebarTabsInHeader = computed(() => isSidebarVariant.value && panel_tabs.value.length > 1);
|
|
const rootClasses = computed(() => ({
|
|
"pos-order-items": true,
|
|
"pos-order-items--large": isLarge,
|
|
"pos-order-items--order-detail": isOrderDetailVariant.value,
|
|
"pos-order-items--sidebar": isSidebarVariant.value,
|
|
"pos-order-items--stacked-metadata": props.stackMetadata,
|
|
}));
|
|
const titleClasses = computed(() => ({
|
|
title: true,
|
|
"is-5": !isSidebarVariant.value,
|
|
"is-6": isSidebarVariant.value,
|
|
"pos-order-items__title": true,
|
|
}));
|
|
const displayCustomerName = computed(() => props.customer_name || customer_name.value || "");
|
|
const showHeaderActions = computed(() => slots.headerActions !== undefined);
|
|
const pendingRemovedOrderItemIds = ref([]);
|
|
const selectedOrderItem = ref(null);
|
|
const isOrderItemEditModalOpen = ref(false);
|
|
const referenceRequired = computed(() => customerRequiresReferenceNumber());
|
|
const poRequired = computed(() => customerUsesPONumbers());
|
|
const showSafetySealField = computed(() => doesOrderContainWashCertificateProduct(visibleOrderItems.value));
|
|
|
|
const buildVisibleOrderItems = (sourceOrderItems = []) => {
|
|
const pendingIds = new Set(pendingRemovedOrderItemIds.value);
|
|
const orderItems = (sourceOrderItems || []).filter((orderItem) => !pendingIds.has(orderItem.id));
|
|
const visibleItems = [];
|
|
|
|
for (const orderItem of orderItems) {
|
|
if (orderItem.related_item_id) {
|
|
continue;
|
|
}
|
|
|
|
visibleItems.push(orderItem);
|
|
visibleItems.push(...orderItems.filter((candidate) => candidate.related_item_id === orderItem.id));
|
|
}
|
|
|
|
return visibleItems;
|
|
};
|
|
|
|
const visibleOrderItems = computed(() => buildVisibleOrderItems(props.orderItems ?? []));
|
|
const totalPrice = computed(() => {
|
|
return visibleOrderItems.value.reduce((accumulator, orderItem) => {
|
|
return accumulator + Number(orderItem?.price ?? 0) * Number(orderItem?.quantity ?? 0);
|
|
}, 0);
|
|
});
|
|
const canEditOrderItems = computed(
|
|
() => Boolean(props.editPossible) && SessionUser.hasPermission("edit_order_items") && !props.disallowItemEdit
|
|
);
|
|
const orderDetailRows = computed(() => {
|
|
return visibleOrderItems.value.map((orderItem) => {
|
|
const siblingItems = orderItem.related_item_id
|
|
? visibleOrderItems.value.filter((candidate) => candidate.related_item_id === orderItem.related_item_id)
|
|
: [];
|
|
|
|
return {
|
|
rowKey: `order-item-${orderItem.id}`,
|
|
orderItem,
|
|
isRelated: Boolean(orderItem.related_item_id),
|
|
hasRelatedItems: visibleOrderItems.value.some((candidate) => candidate.related_item_id === orderItem.id),
|
|
isLastRelatedItem: !orderItem.related_item_id || siblingItems[siblingItems.length - 1]?.id === orderItem.id,
|
|
};
|
|
});
|
|
});
|
|
|
|
// Check if the other slot is present
|
|
const hasOtherSlot = slots.other !== undefined;
|
|
const hasAttachmentsSlot = slots.attachments !== undefined;
|
|
|
|
if (hasAttachmentsSlot) {
|
|
panel_tabs.value.push({
|
|
id: "attachments",
|
|
icon: "fas fa-paperclip",
|
|
name: t("admin.pos.attachments"),
|
|
active: false,
|
|
});
|
|
}
|
|
|
|
// If so, add the other tab
|
|
if (hasOtherSlot) {
|
|
panel_tabs.value.push({
|
|
id: "settings",
|
|
name: t("admin.pos.settings"),
|
|
active: false,
|
|
icon: "fas fa-cog",
|
|
});
|
|
}
|
|
|
|
const hasDetailsSlot = slots.details !== undefined;
|
|
|
|
// If so, add the other tab
|
|
if (hasDetailsSlot) {
|
|
panel_tabs.value.push({
|
|
id: "details",
|
|
name: t("admin.pos.details"),
|
|
active: false,
|
|
icon: "fas fa-info",
|
|
});
|
|
}
|
|
|
|
const getOrderItemProductName = (orderItem) => {
|
|
return orderItem?.product?.name || t("global.no_data");
|
|
};
|
|
|
|
const getItemRelatedItems = (orderItems, orderItemId) => {
|
|
return (orderItems || []).filter((orderItem) => orderItem.related_item_id === orderItemId);
|
|
};
|
|
|
|
const getOrderItemBasePrice = (orderItem) => {
|
|
return Number(orderItem?.product?.price ?? orderItem?.price ?? 0);
|
|
};
|
|
|
|
const isLastRelatedItem = (orderItems, orderItem) => {
|
|
const relatedItems = getItemRelatedItems(orderItems, orderItem.related_item_id);
|
|
if (relatedItems.length === 0) {
|
|
return true;
|
|
}
|
|
return relatedItems[relatedItems.length - 1].id === orderItem.id;
|
|
};
|
|
|
|
const createEmptyRegistrationNumbers = () => ({
|
|
1: "",
|
|
2: "",
|
|
3: "",
|
|
});
|
|
|
|
const registration_numbers = ref(createEmptyRegistrationNumbers());
|
|
const registrationNumbersLoading = ref(false);
|
|
const loadedRegistrationNumbersForOrderId = ref(null);
|
|
|
|
const normalizeRegistrationValue = (value) => (value == null ? "" : String(value));
|
|
|
|
const parseOrderId = (candidateOrderId) => {
|
|
const normalizedOrderId = Number.parseInt(candidateOrderId, 10);
|
|
if (!Number.isInteger(normalizedOrderId) || normalizedOrderId <= 0) {
|
|
return null;
|
|
}
|
|
return normalizedOrderId;
|
|
};
|
|
|
|
const activeOrderId = computed(() => {
|
|
return parseOrderId(props.orderId) ?? parseOrderId(order_id.value);
|
|
});
|
|
|
|
const syncRegistrationNumbers = (orderDetails = null) => {
|
|
const reg_numbers = registration_numbers.value;
|
|
reg_numbers[1] = normalizeRegistrationValue(orderDetails?.reg_1);
|
|
reg_numbers[2] = normalizeRegistrationValue(orderDetails?.reg_2);
|
|
reg_numbers[3] = normalizeRegistrationValue(orderDetails?.reg_3);
|
|
};
|
|
|
|
const loadOrder = (candidateOrderId = activeOrderId.value ?? props.orderId) => {
|
|
const normalizedOrderId = parseOrderId(candidateOrderId);
|
|
if (!normalizedOrderId) {
|
|
registrationNumbersLoading.value = false;
|
|
loadedRegistrationNumbersForOrderId.value = null;
|
|
syncRegistrationNumbers();
|
|
return Promise.resolve();
|
|
}
|
|
const shouldShowRegistrationSkeleton = loadedRegistrationNumbersForOrderId.value !== normalizedOrderId;
|
|
if (shouldShowRegistrationSkeleton) {
|
|
registrationNumbersLoading.value = true;
|
|
}
|
|
// Wait 100ms before loading the order.
|
|
// This is to ensure that the order_id is set before loading the order.
|
|
return new Promise((resolve) => {
|
|
setTimeout(() => {
|
|
setOrderId(normalizedOrderId);
|
|
getOrderDetails()
|
|
.then((orderDetails) => {
|
|
syncRegistrationNumbers(orderDetails);
|
|
loadedRegistrationNumbersForOrderId.value = normalizedOrderId;
|
|
return fetchAttachments(normalizedOrderId);
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
syncRegistrationNumbers();
|
|
})
|
|
.finally(() => {
|
|
registrationNumbersLoading.value = false;
|
|
resolve();
|
|
});
|
|
}, 100);
|
|
});
|
|
};
|
|
|
|
const isTabZeroExpanded = ref(isOrderDetailVariant.value);
|
|
const toggleIsSelected = () => {
|
|
isTabZeroExpanded.value = !isTabZeroExpanded.value;
|
|
};
|
|
const expandIcon = ref(null);
|
|
|
|
watch(
|
|
isOrderDetailVariant,
|
|
(isOrderDetail) => {
|
|
if (isOrderDetail) {
|
|
isTabZeroExpanded.value = true;
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
if (props.orderId === -1) {
|
|
registration_numbers.value = {
|
|
1: normalizeRegistrationValue(props.reg_1),
|
|
2: normalizeRegistrationValue(props.reg_2),
|
|
3: normalizeRegistrationValue(props.reg_3),
|
|
};
|
|
registrationNumbersLoading.value = false;
|
|
loadedRegistrationNumbersForOrderId.value = null;
|
|
customer_name.value = props.customer_name;
|
|
watch(
|
|
() => props.orderId,
|
|
(newOrderId) => {
|
|
if (newOrderId !== -1) {
|
|
loadOrder(newOrderId);
|
|
}
|
|
}
|
|
);
|
|
} else {
|
|
watch(
|
|
() => props.orderId,
|
|
(newOrderId) => {
|
|
loadOrder(newOrderId);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
}
|
|
|
|
watch(
|
|
() => props.orderItems,
|
|
() => {
|
|
pendingRemovedOrderItemIds.value = [];
|
|
},
|
|
{ deep: true }
|
|
);
|
|
|
|
const removeItem = async (id) => {
|
|
// If the order id is -1, emit the updated order items
|
|
if (props.orderId === -1 || props.emitEventsOnly) {
|
|
const orderItemsExcludingRemovedItem = props.orderItems.filter(
|
|
(orderItem) => orderItem.id !== id && orderItem.related_item_id !== id
|
|
);
|
|
emits("onDestroyItem", id);
|
|
//console.warn('Emitting onDestroyItem event, new order items:', orderItemsExcludingRemovedItem);
|
|
emits(
|
|
"update:orderItems",
|
|
orderItemsExcludingRemovedItem.map((orderItem) => orderItem.product)
|
|
);
|
|
} else if (props.orderId > 0) {
|
|
// Otherwise remove the order item
|
|
await removeOrderItem(id);
|
|
}
|
|
};
|
|
|
|
const reloadOrderItems = async () => {
|
|
if (typeof props.loadOrderItems === "function") {
|
|
await props.loadOrderItems();
|
|
}
|
|
};
|
|
|
|
const closeOrderItemEditor = () => {
|
|
isOrderItemEditModalOpen.value = false;
|
|
selectedOrderItem.value = null;
|
|
};
|
|
|
|
const activateTab = (selectedTab) => {
|
|
panel_tabs.value.forEach((tab) => {
|
|
tab.active = tab === selectedTab;
|
|
});
|
|
};
|
|
|
|
const openOrderItemEditor = (orderItem) => {
|
|
if (isOrderDetailVariant.value) {
|
|
selectedOrderItem.value = {
|
|
...orderItem,
|
|
product: orderItem?.product ? { ...orderItem.product } : null,
|
|
};
|
|
isOrderItemEditModalOpen.value = true;
|
|
return;
|
|
}
|
|
|
|
return showEditOrderItemForm(
|
|
orderItem.id,
|
|
getOrderItemProductName(orderItem),
|
|
orderItem.price,
|
|
orderItem.notes,
|
|
orderItem.reference,
|
|
orderItem.quantity,
|
|
canEditOrderItems.value,
|
|
() => reloadOrderItems()
|
|
);
|
|
};
|
|
|
|
const handleOrderItemSaved = async () => {
|
|
await reloadOrderItems();
|
|
closeOrderItemEditor();
|
|
};
|
|
|
|
const getRemovalIds = (orderItemId) => {
|
|
const relatedIds = (props.orderItems ?? [])
|
|
.filter((orderItem) => orderItem.related_item_id === orderItemId)
|
|
.map((orderItem) => orderItem.id);
|
|
|
|
return [...new Set([orderItemId, ...relatedIds])];
|
|
};
|
|
|
|
const deleteOrderItem = async (orderItemId) => {
|
|
pendingRemovedOrderItemIds.value = [...new Set([...pendingRemovedOrderItemIds.value, ...getRemovalIds(orderItemId)])];
|
|
|
|
try {
|
|
await removeItem(orderItemId);
|
|
await reloadOrderItems();
|
|
} finally {
|
|
pendingRemovedOrderItemIds.value = [];
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
:class="rootClasses"
|
|
:data-auto-excel-export-scope="isOrderDetailVariant ? null : '1'"
|
|
:data-disable-auto-excel-export="isOrderDetailVariant ? '1' : null"
|
|
>
|
|
<article class="pos-order-items__surface">
|
|
<header class="pos-order-items__header">
|
|
<div class="pos-order-items__header-main">
|
|
<div class="pos-order-items__heading">
|
|
<SpanSkeleton
|
|
:class="titleClasses"
|
|
:isSkeleton="!displayCustomerName"
|
|
width="100%"
|
|
height="1.5rem"
|
|
skeleton-class="is-size-4"
|
|
>
|
|
<span data-testid="pos-order-customer-name">{{ displayCustomerName }}</span>
|
|
</SpanSkeleton>
|
|
<div class="pos-order-items__subheading">
|
|
<p class="is-7 subtitle mb-0 pos-order-items__transaction" data-testid="pos-order-transaction-label">
|
|
{{ $t("admin.pos.transaction") }} #{{ orderId }}
|
|
</p>
|
|
<div class="pos-order-items__headingcenter">
|
|
<slot name="headingcenter"></slot>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="pos-order-items__header-aside">
|
|
<div v-if="$slots.default" class="pos-order-items__status">
|
|
<slot></slot>
|
|
</div>
|
|
<div
|
|
v-if="showHeaderActions && panel_tabs[0].active"
|
|
class="pos-order-items__utility-actions"
|
|
data-auto-excel-export-actions="1"
|
|
data-testid="pos-order-header-export-actions"
|
|
>
|
|
<slot name="headerActions"></slot>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="showSidebarTabsInHeader"
|
|
class="tabs is-small is-centered pos-order-items__sidebar-tabs pos-sidebar-panel-tabs is-hidden-touch"
|
|
data-testid="pos-order-sidebar-tabs"
|
|
>
|
|
<ul>
|
|
<li v-for="(tab, index) in panel_tabs" :key="index" :class="{ 'is-active': tab.active }">
|
|
<a @click="activateTab(tab)">
|
|
<span v-if="tab.icon" class="icon is-small">
|
|
<i :class="tab.icon"></i>
|
|
</span>
|
|
<span>{{ tab.name }}</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</header>
|
|
<nav class="pos-order-items__tabs-row is-hidden-touch" v-if="!showSidebarTabsInHeader && panel_tabs.length > 1">
|
|
<p class="panel-tabs pos-order-items__tabs">
|
|
<a
|
|
v-for="(tab, index) in panel_tabs"
|
|
:key="index"
|
|
:class="{ 'is-active': tab.active }"
|
|
:data-testid="isOrderDetailVariant ? `pos-order-tab-${tab.id}` : undefined"
|
|
@click="activateTab(tab)"
|
|
>
|
|
<span v-if="tab.icon" class="icon is-small">
|
|
<i :class="tab.icon"></i>
|
|
</span>
|
|
{{ tab.name }}
|
|
</a>
|
|
</p>
|
|
</nav>
|
|
<!-- Mobile nav -->
|
|
<div class="is-hidden-desktop mt-2">
|
|
<div class="buttons is-centered is-mobile pos-order-items__mobile-tabs" data-testid="pos-order-mobile-tabs">
|
|
<button
|
|
v-for="(tab, index) in panel_tabs"
|
|
:key="index"
|
|
:class="['button', 'is-fullwidth', tab.active ? 'is-link' : 'is-light']"
|
|
:data-testid="isOrderDetailVariant ? `pos-order-tab-${tab.id}` : undefined"
|
|
@click="activateTab(tab)"
|
|
>
|
|
<!-- If the tab has an icon, show it -->
|
|
<span v-if="tab.icon" class="icon is-small">
|
|
<i :class="tab.icon"></i>
|
|
</span>
|
|
<span>{{ tab.name }}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- Cart -->
|
|
<div
|
|
v-if="panel_tabs[0].active"
|
|
class="pos-order-items__tab-panel"
|
|
:data-testid="isOrderDetailVariant ? 'pos-order-panel-cart' : undefined"
|
|
>
|
|
<div class="panel-block pos-order-items__panel-block pos-order-items__panel-block--cart">
|
|
<div v-if="isOrderDetailVariant" class="pos-order-items__order-detail-cart">
|
|
<div v-if="$slots.beforeItems" class="pos-order-items__table-banner">
|
|
<slot name="beforeItems"></slot>
|
|
</div>
|
|
<PosOrderDetailItemsTable
|
|
:rows="orderDetailRows"
|
|
:total-price="totalPrice"
|
|
:show-actions="Boolean(editPossible)"
|
|
:can-edit-order-items="canEditOrderItems"
|
|
@edit="openOrderItemEditor"
|
|
@delete="deleteOrderItem"
|
|
/>
|
|
<div v-if="$slots['bottom-order-items']" class="pos-order-items__table-actions">
|
|
<slot name="bottom-order-items"></slot>
|
|
</div>
|
|
</div>
|
|
<div v-else class="pos-order-items__default-cart">
|
|
<div v-if="$slots.beforeItems" class="pos-order-items__table-banner">
|
|
<slot name="beforeItems"></slot>
|
|
</div>
|
|
<PosOrderItemsDefaultTable
|
|
:rows="orderDetailRows"
|
|
:total-price="totalPrice"
|
|
:show-actions="Boolean(editPossible)"
|
|
:can-edit-order-items="canEditOrderItems"
|
|
@edit="openOrderItemEditor"
|
|
@delete="deleteOrderItem"
|
|
/>
|
|
<div v-if="$slots['bottom-order-items']" class="pos-order-items__table-actions">
|
|
<slot name="bottom-order-items"></slot>
|
|
</div>
|
|
</div>
|
|
<table v-if="false" class="table is-fullwidth pos-order-items__table">
|
|
<thead>
|
|
<tr>
|
|
<th>{{ $t("admin.pos.product") }}</th>
|
|
<th style="width: 20%; text-align: right">{{ $t("admin.pos.price_dkk") }}</th>
|
|
<th
|
|
v-if="editPossible"
|
|
class="pos-order-items__actions-header"
|
|
:style="{ width: isOrderDetailVariant ? '18%' : '15%' }"
|
|
>
|
|
{{ isOrderDetailVariant ? $t("global.actions") : "" }}
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Slot -->
|
|
<slot name="beforeItems"></slot>
|
|
<template v-for="orderItem in visibleOrderItems" :key="orderItem.id">
|
|
<tr
|
|
:id="'order-item-' + orderItem.id"
|
|
v-if="!orderItem.related_item_id"
|
|
:style="{
|
|
'border-bottom-style':
|
|
getItemRelatedItems(visibleOrderItems, orderItem.id).length > 0 ? 'hidden' : '',
|
|
}"
|
|
style="border-top: 1px solid #f5f5f5"
|
|
>
|
|
<td>
|
|
<span>{{ getOrderItemProductName(orderItem) }}</span>
|
|
<!-- Notes (If there are any) -->
|
|
<span
|
|
v-if="orderItem.notes"
|
|
@mouseover="showPopper(popperBox('Note', orderItem.notes), $event.target)"
|
|
@mouseleave="removePopperIfOpen()"
|
|
@click="openOrderItemEditor(orderItem)"
|
|
class="ml-2 is-size-7 has-text-grey is-clickable"
|
|
>
|
|
<i class="fas fa-comment"></i>
|
|
{{ $t("admin.pos.see_note") }}
|
|
</span>
|
|
<!-- Reference (If there are any) -->
|
|
<span
|
|
v-if="orderItem.reference"
|
|
@mouseover="showPopper(popperBox('Reference', orderItem.reference), $event.target)"
|
|
@mouseleave="removePopperIfOpen()"
|
|
@click="openOrderItemEditor(orderItem)"
|
|
class="ml-2 is-size-7 has-text-grey is-clickable"
|
|
>
|
|
<i class="fas fa-link"></i>
|
|
{{ $t("admin.pos.see_reference") }}
|
|
</span>
|
|
<!-- Quantity (If it is more than 1) -->
|
|
<span
|
|
v-if="orderItem.quantity > 1"
|
|
@mouseover="showPopper(popperBox('Antal', orderItem.quantity), $event.target)"
|
|
@mouseleave="removePopperIfOpen()"
|
|
@click="openOrderItemEditor(orderItem)"
|
|
class="ml-2 is-size-7 has-text-grey is-clickable"
|
|
>
|
|
<i class="fas fa-box"></i>
|
|
{{ $t("admin.pos.quantity") }}: {{ orderItem.quantity }}
|
|
</span>
|
|
</td>
|
|
<!-- If the price has been changed, show the new price (With a strike-through) and the old price -->
|
|
<td style="width: 20%; text-align: right" v-if="orderItem.price !== getOrderItemBasePrice(orderItem)">
|
|
<span
|
|
@mouseover="
|
|
showPopper(
|
|
popperBox(
|
|
'Pris',
|
|
'Pris ændret fra ' +
|
|
getOrderItemBasePrice(orderItem) +
|
|
' DKK til ' +
|
|
orderItem.price +
|
|
' DKK / Enhed (' +
|
|
orderItem.price * orderItem.quantity +
|
|
' DKK i alt)'
|
|
),
|
|
$event.target
|
|
)
|
|
"
|
|
@mouseleave="removePopperIfOpen()"
|
|
>
|
|
<span style="text-decoration: line-through" class="has-text-dark">{{
|
|
getOrderItemBasePrice(orderItem) * orderItem.quantity
|
|
}}</span>
|
|
<span>{{ orderItem.price * orderItem.quantity }}</span>
|
|
</span>
|
|
</td>
|
|
<td style="width: 20%; text-align: right" v-else>
|
|
<span
|
|
@mouseover="
|
|
showPopper(
|
|
popperBox(
|
|
'Pris',
|
|
orderItem.price + ' DKK / Enhed (' + orderItem.price * orderItem.quantity + ' DKK i alt)'
|
|
),
|
|
$event.target
|
|
)
|
|
"
|
|
@mouseleave="removePopperIfOpen()"
|
|
>
|
|
{{ orderItem.price * orderItem.quantity }}
|
|
</span>
|
|
</td>
|
|
<td
|
|
v-if="editPossible"
|
|
class="pos-order-items__action-cell"
|
|
:style="{ width: isOrderDetailVariant ? '18%' : '15%' }"
|
|
>
|
|
<div v-if="showInlineActionButtons" class="pos-order-items__item-actions">
|
|
<button
|
|
class="button is-small pos-order-items__item-action pos-order-items__item-action--edit"
|
|
type="button"
|
|
:data-testid="`pos-order-item-edit-${orderItem.id}`"
|
|
:disabled="!canEditOrderItems"
|
|
:aria-label="$t('admin.pos.edit')"
|
|
:title="$t('admin.pos.edit')"
|
|
@click="openOrderItemEditor(orderItem)"
|
|
>
|
|
<span class="icon is-small"><i class="fas fa-pen"></i></span>
|
|
</button>
|
|
<button
|
|
class="button is-small pos-order-items__item-action pos-order-items__item-action--delete"
|
|
type="button"
|
|
:data-testid="`pos-order-item-delete-${orderItem.id}`"
|
|
:aria-label="$t('admin.pos.delete')"
|
|
:title="$t('admin.pos.delete')"
|
|
@click="deleteOrderItem(orderItem.id)"
|
|
>
|
|
<span class="icon is-small"><i class="fas fa-trash"></i></span>
|
|
</button>
|
|
</div>
|
|
<div v-else class="buttons is-narrow">
|
|
<ActionSettingsWheelButton>
|
|
<template #actions>
|
|
<ActionSettingsWheelItem
|
|
:label="$t('admin.pos.delete')"
|
|
icon="fas fa-trash"
|
|
template="danger"
|
|
@click="deleteOrderItem(orderItem.id)"
|
|
/>
|
|
<ActionSettingsWheelItem
|
|
:label="$t('admin.pos.edit')"
|
|
icon="fas fa-edit"
|
|
template="warning"
|
|
:disabled="!SessionUser.hasPermission('edit_order_items') || props.disallowItemEdit"
|
|
@click="openOrderItemEditor(orderItem)"
|
|
/>
|
|
</template>
|
|
</ActionSettingsWheelButton>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<!-- Related items -->
|
|
<template
|
|
v-for="relatedItem in getItemRelatedItems(visibleOrderItems, orderItem.id)"
|
|
:key="relatedItem.id"
|
|
>
|
|
<tr
|
|
:id="'order-item-' + relatedItem.id"
|
|
:style="{
|
|
'border-bottom-style': isLastRelatedItem(visibleOrderItems, relatedItem) ? '' : 'hidden',
|
|
}"
|
|
>
|
|
<td>
|
|
<span class="related-item-text is-one-line-hide-overflow">
|
|
<span
|
|
>+ <template v-if="relatedItem.quantity > 1">{{ relatedItem.quantity }} x</template
|
|
>{{ getOrderItemProductName(relatedItem) }}</span
|
|
>
|
|
</span>
|
|
<span class="is-size-7 has-text-grey">
|
|
<!-- Notes (If there are any) -->
|
|
<span
|
|
v-if="relatedItem.notes"
|
|
@mouseover="showPopper(popperBox('Note', relatedItem.notes), $event.target)"
|
|
@mouseleave="removePopperIfOpen()"
|
|
@click="openOrderItemEditor(relatedItem)"
|
|
class="ml-2 is-size-7 has-text-grey is-clickable"
|
|
>
|
|
<i class="fas fa-comment"></i>
|
|
{{ $t("admin.pos.see_note") }}
|
|
</span>
|
|
<!-- Reference (If there are any) -->
|
|
<span
|
|
v-if="relatedItem.reference"
|
|
@mouseover="showPopper(popperBox('Reference', relatedItem.reference), $event.target)"
|
|
@mouseleave="removePopperIfOpen()"
|
|
@click="openOrderItemEditor(relatedItem)"
|
|
class="ml-2 is-size-7 has-text-grey is-clickable"
|
|
>
|
|
<i class="fas fa-link"></i>
|
|
{{ $t("admin.pos.see_reference") }}
|
|
</span>
|
|
</span>
|
|
</td>
|
|
<!-- If the price has been changed, show the new price (With a strike-through) and the old price -->
|
|
<td
|
|
style="width: 20%; text-align: right"
|
|
v-if="relatedItem.price !== getOrderItemBasePrice(relatedItem)"
|
|
>
|
|
<span
|
|
@mouseover="
|
|
showPopper(
|
|
popperBox(
|
|
'Pris',
|
|
'Pris ændret fra ' +
|
|
getOrderItemBasePrice(relatedItem) +
|
|
' DKK til ' +
|
|
relatedItem.price +
|
|
' DKK / Enhed (' +
|
|
relatedItem.price * relatedItem.quantity +
|
|
' DKK i alt)'
|
|
),
|
|
$event.target
|
|
)
|
|
"
|
|
@mouseleave="removePopperIfOpen()"
|
|
>
|
|
<span style="text-decoration: line-through" class="has-text-dark related-item-text">{{
|
|
getOrderItemBasePrice(relatedItem) * relatedItem.quantity
|
|
}}</span>
|
|
<span>{{ relatedItem.price * relatedItem.quantity }} DKK</span>
|
|
</span>
|
|
</td>
|
|
<td style="width: 20%; text-align: right" v-else>
|
|
<span
|
|
class="related-item-text"
|
|
@mouseover="
|
|
showPopper(
|
|
popperBox(
|
|
'Pris',
|
|
relatedItem.price +
|
|
' DKK / Enhed (' +
|
|
relatedItem.price * relatedItem.quantity +
|
|
' DKK i alt)'
|
|
),
|
|
$event.target
|
|
)
|
|
"
|
|
@mouseleave="removePopperIfOpen()"
|
|
>
|
|
{{ relatedItem.price * relatedItem.quantity }}
|
|
</span>
|
|
</td>
|
|
<td
|
|
v-if="editPossible"
|
|
class="pos-order-items__action-cell"
|
|
:style="{ width: isOrderDetailVariant ? '18%' : '15%' }"
|
|
>
|
|
<div v-if="showInlineActionButtons" class="pos-order-items__item-actions">
|
|
<button
|
|
class="button is-small pos-order-items__item-action pos-order-items__item-action--edit"
|
|
type="button"
|
|
:data-testid="`pos-order-item-edit-${relatedItem.id}`"
|
|
:disabled="!canEditOrderItems"
|
|
:aria-label="$t('admin.pos.edit')"
|
|
:title="$t('admin.pos.edit')"
|
|
@click="openOrderItemEditor(relatedItem)"
|
|
>
|
|
<span class="icon is-small"><i class="fas fa-pen"></i></span>
|
|
</button>
|
|
<button
|
|
class="button is-small pos-order-items__item-action pos-order-items__item-action--delete"
|
|
type="button"
|
|
:data-testid="`pos-order-item-delete-${relatedItem.id}`"
|
|
:aria-label="$t('admin.pos.delete')"
|
|
:title="$t('admin.pos.delete')"
|
|
@click="deleteOrderItem(relatedItem.id)"
|
|
>
|
|
<span class="icon is-small"><i class="fas fa-trash"></i></span>
|
|
</button>
|
|
</div>
|
|
<div v-else class="buttons is-narrow">
|
|
<ActionSettingsWheelButton>
|
|
<template #actions>
|
|
<ActionSettingsWheelItem
|
|
:label="$t('admin.pos.delete')"
|
|
icon="fas fa-trash"
|
|
template="danger"
|
|
@click="deleteOrderItem(relatedItem.id)"
|
|
/>
|
|
<ActionSettingsWheelItem
|
|
:label="$t('admin.pos.edit')"
|
|
icon="fas fa-edit"
|
|
template="warning"
|
|
:disabled="!SessionUser.hasPermission('edit_order_items') || props.disallowItemEdit"
|
|
@click="openOrderItemEditor(relatedItem)"
|
|
/>
|
|
</template>
|
|
</ActionSettingsWheelButton>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
</template>
|
|
<slot name="bottom-order-items"></slot>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr>
|
|
<td>{{ $t("admin.pos.total") }}</td>
|
|
<td colspan="1" style="width: 20%; text-align: right">
|
|
<span
|
|
@mouseover="
|
|
showPopper(popperBox('Total', 'Total pris for ordren: ' + totalPrice + ' DKK'), $event.target)
|
|
"
|
|
@mouseleave="removePopperIfOpen()"
|
|
>
|
|
{{ totalPrice }} DKK
|
|
</span>
|
|
</td>
|
|
<td v-if="editPossible" style="width: 15%"></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
<div
|
|
class="panel-block pos-order-items__panel-block pos-order-items__panel-block--secondary"
|
|
v-if="$slots.bottom"
|
|
>
|
|
<!-- Bottom slot -->
|
|
<slot name="bottom"></slot>
|
|
</div>
|
|
</div>
|
|
<!-- Attachments -->
|
|
<div
|
|
v-if="panel_tabs[1] && panel_tabs[1].active"
|
|
:data-testid="isOrderDetailVariant ? 'pos-order-panel-attachments' : undefined"
|
|
>
|
|
<div class="panel-block is-fullwidth pos-order-items__panel-block pos-order-items__panel-block--secondary">
|
|
<!-- Attachments slot -->
|
|
<slot name="attachments"></slot>
|
|
</div>
|
|
</div>
|
|
<!-- Advanced -->
|
|
<div
|
|
v-if="panel_tabs[2] && panel_tabs[2].active"
|
|
:data-testid="isOrderDetailVariant ? 'pos-order-panel-settings' : undefined"
|
|
>
|
|
<div class="panel-block is-fullwidth pos-order-items__panel-block pos-order-items__panel-block--secondary">
|
|
<!-- Other slot -->
|
|
<slot name="other"></slot>
|
|
</div>
|
|
</div>
|
|
<!-- Details -->
|
|
<div
|
|
v-if="panel_tabs[3] && panel_tabs[3].active"
|
|
:data-testid="isOrderDetailVariant ? 'pos-order-panel-details' : undefined"
|
|
>
|
|
<div class="panel-block is-fullwidth pos-order-items__panel-block pos-order-items__panel-block--secondary">
|
|
<!-- Details slot -->
|
|
<slot name="details"></slot>
|
|
</div>
|
|
</div>
|
|
<div v-if="panel_tabs[0].active" class="pos-order-items__footer">
|
|
<div
|
|
class="pos-order-items__metadata"
|
|
:data-testid="isOrderDetailVariant ? 'pos-order-metadata' : undefined"
|
|
v-if="isTabZeroExpanded"
|
|
>
|
|
<div class="pos-order-metadata-grid" data-testid="pos-order-metadata-grid">
|
|
<section
|
|
class="pos-order-metadata-card pos-order-metadata-card--license-plates"
|
|
data-testid="pos-order-metadata-license-plates"
|
|
>
|
|
<p class="pos-order-metadata-label">{{ $t("admin.pos.license_plates") }}</p>
|
|
<PosOrderLicensePlates
|
|
v-bind:registration_numbers="registration_numbers"
|
|
v-bind:is-loading="registrationNumbersLoading"
|
|
v-bind:loadOrder="loadOrder"
|
|
v-bind:order_id="activeOrderId"
|
|
/>
|
|
</section>
|
|
<section
|
|
class="pos-order-metadata-card pos-order-metadata-card--customer-wishes"
|
|
data-testid="pos-order-metadata-customer-wishes"
|
|
>
|
|
<p class="pos-order-metadata-label">{{ $t("admin.pos.customer_wishes") }}</p>
|
|
<POSOrderCustomerWishes
|
|
v-bind:order_id="activeOrderId"
|
|
v-bind:reference="reference"
|
|
v-bind:po="order_po"
|
|
v-bind:safetySeal="order_safety_seal"
|
|
v-bind:showSafetySeal="showSafetySealField"
|
|
v-bind:referenceRequired="referenceRequired"
|
|
v-bind:poRequired="poRequired"
|
|
v-bind:onFieldSaved="handleCustomerWishesFieldSaved"
|
|
/>
|
|
</section>
|
|
<section
|
|
class="pos-order-metadata-card pos-order-metadata-card--note"
|
|
data-testid="pos-order-metadata-note"
|
|
>
|
|
<p class="pos-order-metadata-label">{{ $t("admin.pos.order_note") }}</p>
|
|
<POSOrderNote v-bind:order_id="activeOrderId" v-bind:loadOrder="loadOrder" v-bind:note="order_notes" />
|
|
</section>
|
|
</div>
|
|
</div>
|
|
<!-- Expander -->
|
|
<div class="pos-order-items__expander">
|
|
<p
|
|
class="has-text-centered pos-order-items__expander-trigger"
|
|
@click="toggleIsSelected"
|
|
@mouseover="expandIcon?.classList.add('has-text-link')"
|
|
@mouseleave="expandIcon?.classList.remove('has-text-link')"
|
|
>
|
|
<span class="icon is-small" style="color: #c7c7c7">
|
|
<i
|
|
class="fas fa-angle-down fa-lg"
|
|
:class="{ 'fa-rotate-180': isTabZeroExpanded }"
|
|
aria-hidden="true"
|
|
ref="expandIcon"
|
|
></i>
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<PosOrderItemEditModal
|
|
v-if="isOrderDetailVariant"
|
|
v-model="isOrderItemEditModalOpen"
|
|
:order-item="selectedOrderItem"
|
|
:can-edit="canEditOrderItems"
|
|
@saved="handleOrderItemSaved"
|
|
@update:modelValue="
|
|
(value) => {
|
|
if (!value) {
|
|
closeOrderItemEditor();
|
|
}
|
|
}
|
|
"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.pos-order-items {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0;
|
|
}
|
|
|
|
.pos-order-items__header {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
padding: 1.1rem 1.25rem 0;
|
|
}
|
|
|
|
.pos-order-items__header-main {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
gap: 1rem 1.25rem;
|
|
align-items: start;
|
|
}
|
|
|
|
.pos-order-items__heading {
|
|
min-width: 0;
|
|
}
|
|
|
|
.pos-order-items__title {
|
|
margin: 0;
|
|
line-height: 1.15;
|
|
}
|
|
|
|
.pos-order-items--sidebar .pos-order-items__header {
|
|
gap: 0.75rem;
|
|
padding: 0.95rem 1rem 0.75rem;
|
|
border-bottom: 1px solid #e6edf7;
|
|
}
|
|
|
|
.pos-order-items--sidebar .pos-order-items__title {
|
|
font-size: 1.05rem;
|
|
line-height: 1.2;
|
|
color: #26384c;
|
|
}
|
|
|
|
.pos-order-items--sidebar .pos-order-items__subheading {
|
|
margin-top: 0.35rem;
|
|
}
|
|
|
|
.pos-order-items__sidebar-tabs {
|
|
width: 100%;
|
|
}
|
|
|
|
.pos-order-items--sidebar .pos-order-items__tabs-row {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
|
|
.pos-order-items--sidebar .pos-order-items__panel-block,
|
|
.pos-order-items--sidebar .pos-order-items__footer {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
|
|
.pos-order-items__subheading {
|
|
--pos-order-subheading-font-size: 0.75rem;
|
|
--pos-order-subheading-line-height: 1.5;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 0.55rem 1rem;
|
|
margin-top: 0.45rem;
|
|
}
|
|
|
|
.pos-order-items__transaction {
|
|
margin: 0;
|
|
color: #6b7a90;
|
|
font-size: var(--pos-order-subheading-font-size);
|
|
font-weight: 600;
|
|
line-height: var(--pos-order-subheading-line-height);
|
|
}
|
|
|
|
.pos-order-items__headingcenter {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.55rem;
|
|
min-width: min(100%, 34rem);
|
|
}
|
|
|
|
.pos-order-items__header-aside {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
align-items: flex-start;
|
|
gap: 0.75rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
.pos-order-items__status {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.pos-order-items__status :deep(.tag) {
|
|
margin: 0;
|
|
}
|
|
|
|
.pos-order-items__utility-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: flex-end;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.pos-order-items__utility-actions:empty {
|
|
display: none;
|
|
}
|
|
|
|
.pos-order-items__tabs-row {
|
|
padding: 0 1.25rem;
|
|
border-top: 1px solid #e6edf7;
|
|
}
|
|
|
|
.pos-order-items__tabs {
|
|
margin: 0;
|
|
border-bottom: 0;
|
|
}
|
|
|
|
.pos-order-items__tabs a {
|
|
min-height: 2.4rem;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
border: none;
|
|
border-radius: 999px;
|
|
padding: 0.45rem 0.9rem;
|
|
color: #56657a;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.pos-order-items__tabs a.is-active,
|
|
.pos-order-items__tabs .is-active {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.pos-order-items__tabs a.is-active,
|
|
.pos-order-items__tabs .is-active a {
|
|
background: #eef4ff;
|
|
color: #21446d;
|
|
}
|
|
|
|
.pos-order-items--order-detail .pos-order-items__tabs-row {
|
|
padding-top: 0.15rem;
|
|
padding-bottom: 0.2rem;
|
|
}
|
|
|
|
.pos-order-items--order-detail .pos-order-items__tabs ul {
|
|
justify-content: flex-start;
|
|
gap: 0.35rem;
|
|
flex-wrap: wrap;
|
|
border-bottom: none;
|
|
}
|
|
|
|
.pos-order-items--order-detail .pos-order-items__tabs a {
|
|
min-height: 2.1rem;
|
|
padding: 0.45rem 0.85rem;
|
|
border: none;
|
|
background: transparent;
|
|
color: #5a6980;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.pos-order-items--order-detail .pos-order-items__tabs a:hover {
|
|
background: #f6f9ff;
|
|
color: #21446d;
|
|
}
|
|
|
|
.pos-order-items--order-detail .pos-order-items__tabs a.is-active,
|
|
.pos-order-items--order-detail .pos-order-items__tabs .is-active a {
|
|
background: #eef4ff;
|
|
color: #21446d;
|
|
}
|
|
|
|
.pos-order-items__panel-block {
|
|
padding-left: 1.25rem;
|
|
padding-right: 1.25rem;
|
|
}
|
|
|
|
.pos-order-items__panel-block--cart {
|
|
padding-top: 0.85rem;
|
|
padding-bottom: 1.25rem;
|
|
}
|
|
|
|
.pos-order-items__panel-block--secondary {
|
|
padding-top: 1rem;
|
|
padding-bottom: 1.25rem;
|
|
}
|
|
|
|
.pos-order-items__table {
|
|
table-layout: fixed;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.pos-order-items__order-detail-cart {
|
|
width: 100%;
|
|
display: grid;
|
|
gap: 0.9rem;
|
|
}
|
|
|
|
.pos-order-items__default-cart {
|
|
width: 100%;
|
|
display: grid;
|
|
gap: 0.9rem;
|
|
}
|
|
|
|
.pos-order-items__table-banner:empty,
|
|
.pos-order-items__table-actions:empty {
|
|
display: none;
|
|
}
|
|
|
|
.pos-order-items__metadata {
|
|
margin: 0;
|
|
}
|
|
|
|
.pos-order-items--order-detail.pos-order-items--stacked-metadata .pos-order-metadata-grid {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
grid-template-areas:
|
|
"license-plates"
|
|
"customer-wishes"
|
|
"note";
|
|
}
|
|
|
|
.pos-order-items__footer {
|
|
padding: 0 1.25rem 0.4rem;
|
|
}
|
|
|
|
.pos-order-items__expander {
|
|
padding-top: 0.35rem;
|
|
}
|
|
|
|
.pos-order-items__expander-trigger {
|
|
margin: 0;
|
|
color: #8fa0b7;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.pos-order-items__actions-header {
|
|
text-align: right;
|
|
color: #6b7a90;
|
|
font-size: 0.8rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.pos-order-items__action-cell {
|
|
white-space: nowrap;
|
|
text-align: right;
|
|
}
|
|
|
|
.pos-order-items__item-actions {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: 0.45rem;
|
|
}
|
|
|
|
.pos-order-items__item-action {
|
|
min-width: 2.2rem;
|
|
min-height: 2.2rem;
|
|
border-radius: 0.75rem;
|
|
}
|
|
|
|
.pos-order-items__item-action--edit {
|
|
border-color: #d8e2ee;
|
|
background: #f7f9fc;
|
|
color: #22446d;
|
|
}
|
|
|
|
.pos-order-items__item-action--edit:hover,
|
|
.pos-order-items__item-action--edit:focus-visible {
|
|
border-color: #9bb3cf;
|
|
background: #eef4fb;
|
|
color: #173558;
|
|
}
|
|
|
|
.pos-order-items__item-action--delete {
|
|
border-color: #f0d2d2;
|
|
background: #fff6f6;
|
|
color: #b24141;
|
|
}
|
|
|
|
.pos-order-items__item-action--delete:hover,
|
|
.pos-order-items__item-action--delete:focus-visible {
|
|
border-color: #e4b5b5;
|
|
background: #ffecec;
|
|
color: #9a2d2d;
|
|
}
|
|
|
|
.related-item-text {
|
|
color: #4a4a4a;
|
|
font-size: 0.9rem;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
}
|
|
|
|
@media screen and (max-width: 768px) {
|
|
.pos-order-items__header {
|
|
padding: 1rem 1rem 0;
|
|
}
|
|
|
|
.pos-order-items__mobile-tabs {
|
|
padding-left: 0.75rem;
|
|
padding-right: 0.75rem;
|
|
}
|
|
|
|
.pos-order-items__header-main {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.pos-order-items__headingcenter {
|
|
min-width: 0;
|
|
}
|
|
|
|
.pos-order-items__header-aside,
|
|
.pos-order-items__status,
|
|
.pos-order-items__utility-actions {
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.pos-order-items__tabs-row {
|
|
padding: 0 1rem;
|
|
}
|
|
|
|
.pos-order-items__panel-block {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
|
|
.pos-order-items__footer {
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
|
|
.pos-order-items__action-cell {
|
|
text-align: left;
|
|
}
|
|
|
|
.pos-order-items__item-actions {
|
|
justify-content: flex-start;
|
|
}
|
|
}
|
|
</style>
|