@shopbite-de/storefront 1.14.0 → 1.14.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,7 +66,7 @@ jobs:
66
66
  - name: Install pnpm
67
67
  uses: pnpm/action-setup@v4
68
68
  with:
69
- version: 10.29.3
69
+ version: 10.30.1
70
70
 
71
71
  - name: Install dependencies
72
72
  run: pnpm install --frozen-lockfile
package/app/app.vue CHANGED
@@ -1,22 +1,15 @@
1
1
  <script setup lang="ts">
2
2
  import type { Schemas } from "#shopware";
3
- import * as Sentry from "@sentry/nuxt";
4
3
  import type { Toast } from "#ui/composables/useToast";
5
4
 
6
5
  // Composables
7
6
  const toast = useToast();
8
7
  const appConfig = useAppConfig();
9
- const runtimeConfig = useRuntimeConfig();
10
8
  const { apiClient } = useShopwareContext();
11
9
  const { refresh: refreshToppings } = useShopBiteConfig();
12
10
  const { refreshCart } = useCart();
13
11
  const { getWishlistProducts } = useWishlist();
14
12
 
15
- // Initialize Sentry
16
- Sentry.init({
17
- dsn: runtimeConfig.public.sentry.dsn,
18
- });
19
-
20
13
  const {
21
14
  getNextOpeningTime,
22
15
  isStoreOpen,
@@ -109,7 +109,7 @@ defineExpose({
109
109
  >
110
110
  <template #title>
111
111
  An diese Adresse können wir leider nicht liefern.
112
- <ULink to="/unternehmen/zahlung-und-versand">Weitere Infos.</ULink>
112
+ <ULink to="/zahlung-und-versand">Weitere Infos.</ULink>
113
113
  </template>
114
114
  </UAlert>
115
115
 
@@ -58,7 +58,7 @@ const {
58
58
  defaultSearchCriteria: searchCriteria,
59
59
  });
60
60
 
61
- const { category } = useCategory(categoryId);
61
+ const { category } = await useCategory(categoryId);
62
62
 
63
63
  useCategorySeo(category);
64
64
 
@@ -89,7 +89,7 @@ watch(
89
89
  <UIcon name="i-lucide-badge-euro" class="size-8" />
90
90
  <h2 class="text-2xl text-blackish my-8">Zahlungsarten</h2>
91
91
  <UButton
92
- to="/unternehmen/zahlung-und-versand"
92
+ to="/zahlung-und-versand"
93
93
  size="md"
94
94
  variant="ghost"
95
95
  icon="i-lucide-circle-question-mark"
@@ -106,7 +106,7 @@ watch(
106
106
  <UIcon name="i-lucide-car" class="size-8" />
107
107
  <h2 class="text-2xl text-blackish my-8">Versandarten</h2>
108
108
  <UButton
109
- to="/unternehmen/zahlung-und-versand"
109
+ to="/zahlung-und-versand"
110
110
  size="md"
111
111
  variant="ghost"
112
112
  icon="i-lucide-circle-question-mark"
@@ -1,28 +1,33 @@
1
1
  <script setup lang="ts">
2
2
  import { useNavigation } from "~/composables/useNavigation";
3
- import type { Schemas } from "#shopware";
4
- import type { NavigationMenuItem } from "@nuxt/ui";
3
+ import type {
4
+ FooterColumn,
5
+ FooterColumnLink,
6
+ NavigationMenuItem,
7
+ } from "@nuxt/ui";
5
8
 
6
- const { footerNavigation } = useNavigation();
9
+ const { footerMenu } = useNavigation(true);
7
10
 
8
- const mapCategoryToNavItem = (
9
- category: Schemas["Category"],
10
- ): NavigationMenuItem => {
11
- const label = category.translated?.name ?? "";
11
+ const menuItemToFooterColumnLink = (
12
+ item: NavigationMenuItem,
13
+ ): FooterColumnLink => ({
14
+ label: item.label ?? "",
15
+ to: item.to as string | undefined,
16
+ target: item.target as string | undefined,
17
+ icon: item.icon,
18
+ });
12
19
 
13
- return {
14
- label,
15
- description: `${label} Kategorie`,
16
- to: category.seoUrl,
17
- defaultOpen: true,
18
- icon: category.customFields?.shopbite_category_icon,
19
- children: (category.children ?? []).map(mapCategoryToNavItem),
20
- };
21
- };
20
+ const menuItemsToFooterColumns = (
21
+ items: NavigationMenuItem[],
22
+ ): FooterColumn[] =>
23
+ items.map((item) => ({
24
+ label: item.label ?? "",
25
+ children: item.children?.map(menuItemToFooterColumnLink) ?? [],
26
+ }));
22
27
 
23
- const navItems = computed<NavigationMenuItem[]>(() => {
24
- return (footerNavigation.value ?? []).map(mapCategoryToNavItem);
25
- });
28
+ const footerColumns = computed<FooterColumn[]>(() =>
29
+ menuItemsToFooterColumns(footerMenu.value),
30
+ );
26
31
  </script>
27
32
 
28
33
  <template>
@@ -31,7 +36,7 @@ const navItems = computed<NavigationMenuItem[]>(() => {
31
36
  <UFooter :ui="{ top: 'border-b border-default' }">
32
37
  <template #top>
33
38
  <UContainer>
34
- <UFooterColumns :columns="navItems" />
39
+ <UFooterColumns :columns="footerColumns" />
35
40
  </UContainer>
36
41
  </template>
37
42
 
@@ -1,36 +1,24 @@
1
1
  <script setup lang="ts">
2
- import type { NavigationMenuItem } from "@nuxt/ui";
2
+ import { useNavigation } from "~/composables/useNavigation";
3
3
 
4
- const route = useRoute();
4
+ const config = useRuntimeConfig();
5
5
 
6
- const { data: navigationData } = useAsyncData("navigation", () =>
7
- queryCollection("navigation").first(),
6
+ const multiChannelEnabled = computed(
7
+ () => config.public.shopBite.feature.multiChannel === "true",
8
8
  );
9
9
 
10
- const navi = computed<NavigationMenuItem[]>(() => {
11
- if (!navigationData.value?.main) return [];
12
-
13
- return navigationData.value.main.map((item) => ({
14
- label: item.label,
15
- icon: item.icon,
16
- to: item.to,
17
- target: item.target,
18
- active:
19
- item.to === "/"
20
- ? route.path.length === 1
21
- : route.path.startsWith(item.to),
22
- }));
23
- });
10
+ console.log(multiChannelEnabled.value);
11
+ const { mainMenu } = useNavigation(false);
24
12
  </script>
25
13
 
26
14
  <template>
27
15
  <UNavigationMenu
28
16
  color="primary"
29
- :items="navi"
17
+ :items="mainMenu"
30
18
  orientation="vertical"
31
19
  class="-mx-2.5"
32
20
  />
33
- <div class="my-4">
21
+ <div v-if="multiChannelEnabled" class="my-4">
34
22
  <SalesChannelSwitch />
35
23
  </div>
36
24
  </template>
@@ -3,9 +3,10 @@ import { useUser } from "@shopware/composables";
3
3
  import type { DropdownMenuItem } from "@nuxt/ui";
4
4
 
5
5
  const cartQuickViewOpen = ref(false);
6
- const { count } = useCart();
6
+ const { count: cartCount } = useCart();
7
+ const { count: wishListCount } = useWishlist();
7
8
  const { isCheckoutEnabled } = useShopBiteConfig();
8
- const { isLoggedIn, isGuestSession, user, logout } = useUser();
9
+ const { isLoggedIn, isGuestSession, logout } = useUser();
9
10
  const toast = useToast();
10
11
 
11
12
  const logoutHandler = () => {
@@ -17,50 +18,58 @@ const logoutHandler = () => {
17
18
  });
18
19
  };
19
20
 
20
- const { data: navigationData } = await useAsyncData("navigation:right", () =>
21
- queryCollection("navigation").first(),
22
- );
23
-
24
- const accountHoverText = computed(() => {
25
- return isLoggedIn.value || isGuestSession.value
26
- ? `${user.value?.firstName} ${user.value?.lastName}`
27
- : "Hallo";
28
- });
29
-
30
- const loggedInDropDown = computed<DropdownMenuItem[][]>(() => {
31
- if (!navigationData.value?.account.loggedIn) return [];
32
-
33
- return navigationData.value.account.loggedIn
34
- .map((group) =>
35
- group
36
- .filter((item) => {
37
- if (isGuestSession.value) {
38
- return item.type === "label" || item.action === "logout";
39
- }
40
- return true;
41
- })
42
- .map((item) => ({
43
- label: item.type === "label" ? accountHoverText.value : item.label,
44
- type: item.type,
45
- icon: item.icon,
46
- to: item.to,
47
- onSelect: item.action === "logout" ? logoutHandler : undefined,
48
- })),
49
- )
50
- .filter((group) => group.length > 0);
51
- });
52
-
53
- const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
54
- if (!navigationData.value?.account.loggedOut) return [];
55
-
56
- return navigationData.value.account.loggedOut.map((group) =>
57
- group.map((item) => ({
58
- label: item.label,
59
- type: item.type,
60
- icon: item.icon,
61
- to: item.to,
62
- })),
63
- );
21
+ const dropDownMenu = computed<DropdownMenuItem[][]>(() => {
22
+ if (isLoggedIn.value) {
23
+ return [
24
+ [
25
+ {
26
+ label: "Mein Konto",
27
+ type: "label",
28
+ },
29
+ {
30
+ label: "Übersicht",
31
+ icon: "i-lucide-user",
32
+ to: "/konto",
33
+ },
34
+ {
35
+ label: "Bestellungen",
36
+ icon: "i-lucide-pizza",
37
+ to: "/konto/bestellungen",
38
+ },
39
+ {
40
+ label: "Adressen",
41
+ icon: "i-lucide-house",
42
+ to: "/konto/adressen",
43
+ },
44
+ ],
45
+ [
46
+ {
47
+ label: "Abmelden",
48
+ icon: "i-lucide-log-out",
49
+ onSelect: () => logoutHandler(),
50
+ },
51
+ ],
52
+ ];
53
+ } else {
54
+ return [
55
+ [
56
+ {
57
+ label: "Mein Konto",
58
+ type: "label",
59
+ },
60
+ {
61
+ label: "Anmelden",
62
+ icon: "i-lucide-user",
63
+ to: "/anmelden",
64
+ },
65
+ {
66
+ label: "Registrieren",
67
+ icon: "i-lucide-user-plus",
68
+ to: "/registrierung",
69
+ },
70
+ ],
71
+ ];
72
+ }
64
73
  });
65
74
  </script>
66
75
 
@@ -73,9 +82,7 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
73
82
  icon="i-lucide-phone"
74
83
  aria-label="Anrufen"
75
84
  />
76
- <UDropdownMenu
77
- :items="isLoggedIn || isGuestSession ? loggedInDropDown : loggedOutDropDown"
78
- >
85
+ <UDropdownMenu :items="dropDownMenu">
79
86
  <UChip v-if="isLoggedIn || isGuestSession" size="3xl" text="✓">
80
87
  <UButton
81
88
  aria-label="Konto Dropdown öffnen"
@@ -89,29 +96,42 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
89
96
  aria-label="Konto Dropdown öffnen"
90
97
  icon="i-lucide-user"
91
98
  color="neutral"
92
- variant="outline"
99
+ variant="ghost"
93
100
  />
94
101
  </UDropdownMenu>
102
+ <div>
103
+ <UChip :text="wishListCount" size="3xl">
104
+ <UButton
105
+ aria-label="Zur Merkliste"
106
+ color="neutral"
107
+ variant="ghost"
108
+ to="/merkliste"
109
+ icon="i-lucide-heart"
110
+ />
111
+ </UChip>
112
+ </div>
95
113
  <UDrawer
96
114
  v-if="isCheckoutEnabled"
97
115
  v-model:open="cartQuickViewOpen"
98
116
  title="Warenkorb"
99
117
  direction="right"
100
118
  >
101
- <UChip :text="count" size="3xl">
119
+ <UChip :text="cartCount" size="3xl">
102
120
  <UButton
103
121
  aria-label="Zum Warenkorb"
104
122
  color="neutral"
105
- variant="outline"
106
- icon="i-lucide-shopping-cart"
123
+ variant="ghost"
124
+ icon="i-lucide-shopping-bag"
107
125
  />
108
126
  </UChip>
109
127
 
110
128
  <template #header>
111
- <h2 class="text-3xl md:text-4xl mt-8 mb-3 pb-2">
112
- <UIcon name="i-lucide-shopping-cart" class="size-8" color="primary" />
113
- Warenkorb
114
- </h2>
129
+ <div class="h-full flex flex-col justify-center">
130
+ <h2 class="flex items-center gap-2 text-3xl md:text-4xl mt-8 mb-3 pb-2">
131
+ <UIcon name="i-lucide-shopping-bag" class="size-8" color="primary" />
132
+ Warenkorb
133
+ </h2>
134
+ </div>
115
135
  </template>
116
136
  <template #body>
117
137
  <CartQuickView
@@ -122,5 +142,3 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
122
142
  </template>
123
143
  </UDrawer>
124
144
  </template>
125
-
126
- <style scoped></style>
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { useNavigation } from "~/composables/useNavigation";
3
3
 
4
- const { mainMenu } = useNavigation();
4
+ const { mainMenu } = useNavigation(false);
5
5
 
6
6
  const loginSlide = ref(false);
7
7
  </script>
@@ -3,7 +3,7 @@ import type { NavigationMenuItem } from "@nuxt/ui";
3
3
  import type { Schemas } from "#shopware";
4
4
  import { useNavigation } from "~/composables/useNavigation";
5
5
 
6
- const { mainNavigation } = useNavigation();
6
+ const { mainNavigation } = useNavigation(false);
7
7
 
8
8
  const mapCategoryToNavItem = (
9
9
  category: Schemas["Category"],
@@ -14,7 +14,7 @@ const props = withDefaults(
14
14
  },
15
15
  );
16
16
 
17
- const { mainNavigation } = useNavigation();
17
+ const { mainNavigation } = useNavigation(true);
18
18
 
19
19
  const navItems = computed<NavigationMenuItem[]>(() => {
20
20
  const elements = mainNavigation.value ?? [];
@@ -7,7 +7,7 @@ const { apiClient } = useShopwareContext();
7
7
  const config = useRuntimeConfig();
8
8
 
9
9
  const isMultiChannel = computed(
10
- () => !!config.public.shopBite.feature.multiChannel,
10
+ () => config.public.shopBite.feature.multiChannel === "true",
11
11
  );
12
12
 
13
13
  const storeUrl = computed(() => config.public.storeUrl);
@@ -1,6 +1,6 @@
1
1
  import { encodeForQuery } from "@shopware/api-client/helpers";
2
2
 
3
- export function useCategory(categoryId: Ref<string>) {
3
+ export async function useCategory(categoryId: Ref<string>) {
4
4
  const { apiClient } = useShopwareContext();
5
5
 
6
6
  const criteria = encodeForQuery({
@@ -17,7 +17,7 @@ export function useCategory(categoryId: Ref<string>) {
17
17
 
18
18
  const cacheKey = computed(() => `category-${categoryId.value}`);
19
19
 
20
- const { data } = useAsyncData(cacheKey, async () => {
20
+ const { data } = await useAsyncData(cacheKey, async () => {
21
21
  const response = await apiClient.invoke(
22
22
  "readCategoryGet get /category/{navigationId}",
23
23
  {
@@ -1,7 +1,8 @@
1
1
  import type { NavigationMenuItem } from "@nuxt/ui";
2
2
  import { encodeForQuery } from "@shopware/api-client/helpers";
3
+ import type { Schemas } from "#shopware";
3
4
 
4
- export function useNavigation() {
5
+ export function useNavigation(withChildren: boolean | undefined) {
5
6
  const { apiClient } = useShopwareContext();
6
7
 
7
8
  const criteria = encodeForQuery({
@@ -32,15 +33,24 @@ export function useNavigation() {
32
33
  return response.data;
33
34
  });
34
35
 
36
+ const mapCategoryToMenuItem = (
37
+ category: Schemas["Category"],
38
+ ): NavigationMenuItem => ({
39
+ label: category.translated?.name ?? category.name,
40
+ to: category.translated?.seoUrl ?? category.seoUrl,
41
+ target: category.linkNewTab ? "_blank" : undefined,
42
+ icon: (category.customFields as Record<string, string> | null)
43
+ ?.shopbite_category_icon,
44
+ children:
45
+ category.children?.length && withChildren
46
+ ? category.children.map(mapCategoryToMenuItem)
47
+ : undefined,
48
+ });
49
+
35
50
  const mainMenu = computed<NavigationMenuItem[]>(() => {
36
51
  if (!mainNavigation.value) return [];
37
52
 
38
- return mainNavigation.value?.map((item) => ({
39
- label: item.translated.name,
40
- to: item.seoUrl,
41
- target: item.linkNewTab ? "_blank" : undefined,
42
- icon: item.customFields?.shopbite_category_icon,
43
- }));
53
+ return mainNavigation.value?.map(mapCategoryToMenuItem);
44
54
  });
45
55
 
46
56
  const { data: footerNavigation } = useAsyncData(
@@ -64,12 +74,7 @@ export function useNavigation() {
64
74
  const footerMenu = computed<NavigationMenuItem[]>(() => {
65
75
  if (!footerNavigation.value) return [];
66
76
 
67
- return footerNavigation.value?.map((item) => ({
68
- label: item.translated.name,
69
- to: item.seoUrl,
70
- target: item.linkNewTab ? "_blank" : undefined,
71
- icon: item.customFields?.shopbite_category_icon,
72
- }));
77
+ return footerNavigation.value?.map(mapCategoryToMenuItem);
73
78
  });
74
79
 
75
80
  return {
package/nuxt.config.ts CHANGED
@@ -66,9 +66,6 @@ export default defineNuxtConfig({
66
66
  countryId: "",
67
67
  },
68
68
  storeUrl: "",
69
- sentry: {
70
- dsn: process.env.NUXT_PUBLIC_SENTRY_DSN,
71
- },
72
69
  },
73
70
  },
74
71
 
@@ -184,6 +181,9 @@ export default defineNuxtConfig({
184
181
  ],
185
182
  },
186
183
  $production: {
184
+ sentry: {
185
+ dsn: process.env.NUXT_PUBLIC_SENTRY_DSN,
186
+ },
187
187
  scripts: {
188
188
  registry: {
189
189
  matomoAnalytics: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopbite-de/storefront",
3
- "version": "1.14.0",
3
+ "version": "1.14.4",
4
4
  "main": "nuxt.config.ts",
5
5
  "description": "Shopware storefront for food delivery shops",
6
6
  "keywords": [
@@ -33,6 +33,7 @@
33
33
  "@vite-pwa/nuxt": "^1.0.7",
34
34
  "@vueuse/core": "^14.0.0",
35
35
  "dotenv": "^17.2.3",
36
+ "fflate": "^0.8.2",
36
37
  "nuxt": "^4.2.1",
37
38
  "nuxt-vitalizer": "2.0.0",
38
39
  "uuid": "^13.0.0"
@@ -28,7 +28,7 @@ test("Simple Checkout As Recurring Customer", async ({ page }) => {
28
28
 
29
29
  async function clearCart(page: Page) {
30
30
  const cartButton = page
31
- .locator("button .i-lucide\\:shopping-cart")
31
+ .locator("button .i-lucide\\:shopping-bag")
32
32
  .locator("..");
33
33
 
34
34
  await expect(cartButton).toBeVisible({ timeout: 5000 });
@@ -89,8 +89,7 @@ describe("HeaderRight", () => {
89
89
  const dropdown = component.findComponent({ name: "UDropdownMenu" });
90
90
  const items = dropdown.props("items");
91
91
 
92
- expect(items[0][0].label).toBe("Jetzt anmelden");
93
- expect(items[1][0].to).toBe("/anmelden");
92
+ expect(items[0][0].label).toBe("Mein Konto");
94
93
  });
95
94
 
96
95
  it("shows logged in dropdown items when logged in", async () => {
@@ -101,18 +100,7 @@ describe("HeaderRight", () => {
101
100
  const dropdown = component.findComponent({ name: "UDropdownMenu" });
102
101
  const items = dropdown.props("items");
103
102
 
104
- expect(items[0][0].label).toBe("Jane Doe");
105
- expect(items[1][0].to).toBe("/konto/bestellungen");
106
- expect(items[2][0].label).toBe("Abmelden");
107
- });
108
-
109
- it("shows cart drawer with correct count when checkout is enabled", async () => {
110
- const component = await mountSuspended(HeaderRight);
111
- const drawer = component.findComponent({ name: "UDrawer" });
112
- expect(drawer.exists()).toBe(true);
113
-
114
- const chip = component.findComponent({ name: "UChip" });
115
- expect(chip.props("text")).toBe(5);
103
+ expect(items[0][0].label).toBe("Mein Konto");
116
104
  });
117
105
 
118
106
  it("calls logout and updates state when logout is selected", async () => {
@@ -70,9 +70,7 @@ describe("PaymentAndDelivery", () => {
70
70
 
71
71
  it("renders help buttons with correct links", async () => {
72
72
  const wrapper = await mountSuspended(PaymentAndDelivery);
73
- const helpButtons = wrapper.findAll(
74
- 'a[href="/unternehmen/zahlung-und-versand"]',
75
- );
73
+ const helpButtons = wrapper.findAll('a[href="/zahlung-und-versand"]');
76
74
  expect(helpButtons.length).toBe(2);
77
75
  });
78
76
  });
@@ -1,57 +0,0 @@
1
- main:
2
- - label: Speisekarte
3
- icon: i-lucide-utensils
4
- to: /speisekarte/
5
- - label: Routenplaner
6
- icon: i-lucide-map-pinned
7
- to: https://www.openstreetmap.org/directions?from=&to=50.080610%2C8.863783#map=19/50.080323/8.864079
8
- target: _blank
9
- - label: Merkliste
10
- icon: i-lucide-book-heart
11
- to: /merkliste
12
-
13
- account:
14
- loggedIn:
15
- - - label: Mein Konto
16
- type: label
17
- - - label: Konto
18
- icon: i-lucide-user
19
- to: /konto
20
- - label: Bestellungen
21
- icon: i-lucide-pizza
22
- to: /konto/bestellungen
23
- - label: Adressen
24
- icon: i-lucide-house
25
- to: /konto/adressen
26
- - - label: Abmelden
27
- icon: i-lucide-log-out
28
- action: logout
29
- loggedOut:
30
- - - label: Jetzt anmelden
31
- type: label
32
- - - label: Zur Anmeldung
33
- icon: i-lucide-user
34
- to: /anmelden
35
-
36
- footer:
37
- withGithubLink: true
38
- withColorModeSwitch: true
39
- text: Alle Preise inkl. gesetzlicher Mehrwertsteuer zzgl. Versandkosten, wenn nicht anders beschrieben
40
- columns:
41
- - label: Informationen
42
- children:
43
- - label: Impressum
44
- to: /impressum
45
- - label: Datenschutz
46
- to: /datenschutz
47
- - label: AGB
48
- to: /agb
49
- - label: Top Kategorien
50
- children:
51
- - label: Pizza
52
- to: /speisekarte/pizza/
53
- - label: Unternehmen
54
- children:
55
- - label: 'Tel: 06104 71427'
56
- - label: Kantstraße 6
57
- - label: 631679 Oberthsuasen
@@ -1,6 +0,0 @@
1
- ---
2
- title: AGB
3
- description: Allgemeine Geschäftsbedingungen
4
- ---
5
-
6
- # AGB
@@ -1,6 +0,0 @@
1
- ---
2
- title: Datenschutz
3
- description: Datenschutzbestimmungen für unsere Website
4
- ---
5
-
6
- # Datenschutz
@@ -1,34 +0,0 @@
1
- ---
2
- title: Zahlungs- und Lieferinformationen
3
- description: Zahlungs- und Lieferinformationen
4
- ---
5
-
6
- # Zahlungs- und Lieferinformationen
7
-
8
- ### Liefermethoden
9
-
10
- Wir bieten Ihnen zwei Möglichkeiten, Ihre Bestellung zu erhalten:
11
-
12
- - **Lieferung:** Wir bringen Ihre Bestellung direkt zu Ihnen nach Hause (beachten Sie bitte unsere Liefergebiete).
13
- - **Abholung:** Sie können Ihre Bestellung auch direkt bei uns abholen (Kantstraße 6, 63179 Obertshausen).
14
-
15
- ### Zahlungsmöglichkeiten
16
-
17
- - **Bei Lieferung:** Die Zahlung erfolgt ausschließlich **bar**.
18
- - **Bei Abholung:** Sie können bar oder elektronisch mit **EC-Karte** bezahlen.
19
-
20
- ### Lieferbedingungen
21
-
22
- Wir liefern ausschließlich in folgende Gebiete:
23
-
24
- - **63179 Obertshausen** (Stadtteile Obertshausen und Hausen)
25
- - **63165 Mühlheim** (Stadtteil Lämmerspiel)
26
-
27
- ### Lieferkosten
28
-
29
- - **Ab 15,00 € Bestellwert:** Lieferung frei Haus (versandkostenfrei).
30
- - **Unter 15,00 € Bestellwert:** Wir erheben eine Lieferpauschale von **2,00 €**.
31
-
32
- ### Lieferzeit
33
-
34
- Die Lieferzeit beträgt in der Regel ca. **30 Minuten**. Bitte beachten Sie, dass es zu Stoßzeiten zu Abweichungen kommen kann.