@viur/shop-components 0.12.0 → 0.13.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viur/shop-components",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "description": "Frontend Vue components for the shop module of ViUR",
5
5
  "repository": {
6
6
  "type": "git",
@@ -110,7 +110,7 @@ sl-tab-group {
110
110
  }
111
111
  }
112
112
 
113
- sl-tap-panel {
113
+ sl-tab-panel {
114
114
  height: 100%;
115
115
  &::part(base) {
116
116
  height: 100%;
@@ -76,7 +76,7 @@
76
76
  </sl-bar>
77
77
 
78
78
  <template v-if="shopStore.state.order?.['payment_provider'] !== null && shopStore.state.order?.['payment_provider'].startsWith('unzer-')">
79
- <sl-dialog v-if="state.paymentPopup" :label="$t('viur.shop.order_pay')" :open="state.paymentPopup" @sl-after-hide="state.paymentPopup=false">
79
+ <sl-dialog v-if="state.paymentPopup" :label="$t('viur.shop.order_pay')" :open="state.paymentPopup" @sl-after-hide="paymentCanceled">
80
80
  <payment-provider-unzer @cancel="paymentCanceled"></payment-provider-unzer>
81
81
  </sl-dialog>
82
82
  </template>
@@ -132,6 +132,7 @@ function getOrderCart(){
132
132
 
133
133
  function paymentCanceled(){
134
134
  state.paymentPopup=false
135
+ shopStore.state.paymentProviderData = null;
135
136
  }
136
137
 
137
138
  //open popup and freeze cart
@@ -1,213 +1,264 @@
1
1
  <template>
2
- <div class="loading-wrapper" v-if="state.loading">
3
- <sl-spinner class="loading"></sl-spinner>
4
- </div>
5
-
6
- <div class="loading-wrapper" v-if="PaymentCheckIsActive">
7
- <sl-spinner class="loading"></sl-spinner>
8
- {{ $t('messages.wait_for_payment') }}
9
- </div>
10
- <div class="form-wrapper">
11
- <sl-alert :open="state.hasError" variant="danger">{{ state.errorMessage }}</sl-alert>
12
- <form class="unzerUI form" novalidate>
13
- <template v-if="shopStore.state.order?.['payment_provider'] === 'unzer-card'">
14
- <div class="field">
15
- <div id="card-element-id-number" class="unzerInput">
16
- <!-- Card number UI Element is inserted here. -->
17
- </div>
18
- </div>
19
- <div class="two fields">
20
- <div class="field ten wide">
21
- <div id="card-element-id-expiry" class="unzerInput">
22
- <!-- Card expiry date UI Element is inserted here. -->
23
- </div>
24
- </div>
25
- <div class="field six wide">
26
- <div id="card-element-id-cvc" class="unzerInput">
27
- <!-- Card CVC UI Element is inserted here. -->
28
- </div>
29
- </div>
30
- </div>
31
- </template>
32
-
33
- <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-paypal'">
34
- <sl-alert open variant="danger">{{ $t('viur.shop.paypal_client_popup_info') }}</sl-alert>
35
- <div id="paypal-element" class="field"></div>
36
- </template>
37
-
38
- <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-ideal'">
39
- <div id="ideal-element" class="field"></div>
40
- </template>
41
-
42
- <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-googlepay'">
43
- <div id="googlepay-element" class="field"></div>
44
- </template>
45
- <p
46
- v-if="!!shopStore.state?.paymentProviderData?.redirectUrl"
47
- v-html="$t('viur.shop.payment_link', {url: shopStore.state.paymentProviderData.redirectUrl})"
48
- />
49
- </form>
50
-
51
- <button
52
- v-if="shopStore.state.order?.['payment_provider'] !== 'unzer-googlepay'"
53
- :disabled="state.loading"
54
- class="unzerUI primary button fluid"
55
- @click="submitFormToUnzer"
56
- >{{ $t('viur.shop.pay') }}
57
- </button>
58
- <sl-button :disabled="state.loading" variant="danger" @click="cancelPayment">
59
- {{ $t('actions.cancel') }}
60
- </sl-button>
61
- </div>
2
+ <div class="loading-wrapper" v-if="state.loading">
3
+ <sl-spinner class="loading"></sl-spinner>
4
+ </div>
5
+
6
+ <div class="loading-wrapper" v-if="PaymentCheckIsActive">
7
+ <sl-spinner class="loading"></sl-spinner>
8
+ {{ $t('messages.wait_for_payment') }}
9
+ </div>
10
+ <div class="form-wrapper">
11
+ <sl-alert :open="state.hasError" variant="danger">{{ state.errorMessage }}</sl-alert>
12
+ <form class="unzerUI form" novalidate>
13
+ <template v-if="shopStore.state.order?.['payment_provider'] === 'unzer-card'">
14
+ <div class="field">
15
+ <div id="card-element-id-number" class="unzerInput">
16
+ <!-- Card number UI Element is inserted here. -->
17
+ </div>
18
+ </div>
19
+ <div class="two fields">
20
+ <div class="field ten wide">
21
+ <div id="card-element-id-expiry" class="unzerInput">
22
+ <!-- Card expiry date UI Element is inserted here. -->
23
+ </div>
24
+ </div>
25
+ <div class="field six wide">
26
+ <div id="card-element-id-cvc" class="unzerInput">
27
+ <!-- Card CVC UI Element is inserted here. -->
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-paypal'">
34
+ <sl-alert open variant="danger">{{ $t('viur.shop.paypal_client_popup_info') }}</sl-alert>
35
+ <div id="paypal-element" class="field"></div>
36
+ </template>
37
+
38
+ <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-ideal'">
39
+ <div id="ideal-element" class="field"></div>
40
+ </template>
41
+
42
+ <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-googlepay'">
43
+ <div id="googlepay-element" class="field"></div>
44
+ </template>
45
+
46
+ <template v-else-if="shopStore.state.order?.['payment_provider'] === 'unzer-paylater_invoice'">
47
+ <p v-html="$t('viur.shop.missing_birthdate', shopStore.state.order.billing_address.dest)"/>
48
+ <sl-input
49
+ slot="left"
50
+ type="date"
51
+ min="1900-01-01"
52
+ :max="new Date().toISOString().slice(0, 10)"
53
+ :placeholder="$t('viur.shop.birthdate')"
54
+ :label="$t('viur.shop.birthdate')"
55
+ :value="state.birthdate"
56
+ @sl-change="birthdateChange"
57
+ :disabled="state.loading"
58
+ ></sl-input>
59
+ <div id="paylater-invoice-element" class="field"></div>
60
+ </template>
61
+
62
+ <p
63
+ v-if="!!shopStore.state?.paymentProviderData?.redirectUrl"
64
+ v-html="$t('viur.shop.payment_link', {url: shopStore.state.paymentProviderData.redirectUrl})"
65
+ />
66
+ </form>
67
+
68
+ <button
69
+ v-if="shopStore.state.order?.['payment_provider'] !== 'unzer-googlepay'"
70
+ :disabled="state.loading || state.birthdateIsInvalid"
71
+ class="unzerUI primary button fluid"
72
+ @click="submitFormToUnzer"
73
+ >{{ $t('viur.shop.pay') }}
74
+ </button>
75
+ <sl-button :disabled="state.loading" variant="danger" @click="cancelPayment">
76
+ {{ $t('actions.cancel') }}
77
+ </sl-button>
78
+ </div>
62
79
  </template>
63
80
 
64
81
  <script setup>
65
82
  import {Request} from '@viur/vue-utils';
83
+ import {HTTPError} from '@viur/vue-utils/utils/request.js';
66
84
  import {useIntervalFn} from '@vueuse/core';
67
85
  import {computed, onBeforeMount, reactive} from 'vue';
86
+ import {useAddress} from '../composables/address.js';
68
87
  import {useOrder} from '../composables/order';
69
88
  import {useViurShopStore} from '../shop';
70
89
 
71
90
  const shopStore = useViurShopStore();
72
91
  const {fetchOrder} = useOrder();
92
+ const {saveBirthdate} = useAddress();
73
93
 
74
94
  const emits = defineEmits(['cancel']);
75
95
 
76
96
  const {pause: PaymentCheckPause, resume: PaymentCheckResume, isActive: PaymentCheckIsActive} = useIntervalFn(() => {
77
- console.debug('checking ...');
78
-
79
- fetchOrder(shopStore.state.orderKey).then(() => {
80
- if (shopStore.state.order?.['is_paid']) {
81
- console.debug('Order is paid');
82
- shopStore.navigateToTab('complete');
83
- PaymentCheckPause();
84
- }
85
- });
97
+ console.debug('checking ...');
98
+
99
+ fetchOrder(shopStore.state.orderKey).then(() => {
100
+ if (shopStore.state.order?.['is_paid']) {
101
+ console.debug('Order is paid');
102
+ shopStore.navigateToTab('complete');
103
+ PaymentCheckPause();
104
+ }
105
+ });
86
106
 
87
107
  }, 2000, {immediate: false});
88
108
 
89
109
 
90
110
  const state = reactive({
91
- unzer: computed(() => {
92
- if (!shopStore.state.paymentProviderData) return null;
93
- return new unzer(shopStore.state.paymentProviderData['public_key'], {locale: shopStore.state.locale});
94
- }),
95
- paymentHandler: {},
96
- loading: false,
97
- hasError: false,
98
- errorMessage: null,
99
- waitPayment: false,
111
+ unzer: computed(() => {
112
+ if (!shopStore.state.paymentProviderData) return null;
113
+ return new unzer(shopStore.state.paymentProviderData['public_key'], {locale: shopStore.state.locale});
114
+ }),
115
+ paymentHandler: {},
116
+ loading: false,
117
+ hasError: false,
118
+ errorMessage: null,
119
+ waitPayment: false,
120
+ birthdate: null,
121
+ birthdateIsInvalid: false,
100
122
  });
101
123
 
102
124
  /**
103
125
  * Initialize the payment type creation with Unzer-UI components
104
126
  */
105
127
  function initUnzerForm() {
106
- //Unzer field definition
107
- if (shopStore.state.order?.['payment_provider'] === 'unzer-card') {
108
- const card = state.unzer.Card();
109
- // Rendering input field card number
110
- card.create('number', {
111
- containerId: 'card-element-id-number',
112
- onlyIframe: false,
113
- });
114
- // Rendering input field card expiry
115
- card.create('expiry', {
116
- containerId: 'card-element-id-expiry',
117
- onlyIframe: false,
118
- });
119
- // Rendering input field card cvc
120
- card.create('cvc', {
121
- containerId: 'card-element-id-cvc',
122
- onlyIframe: false,
123
- });
124
- state.paymentHandler['unzer-card'] = card;
125
- } else if (shopStore.state.order?.['payment_provider'] === 'unzer-paypal') {
126
- // Creating a PayPal instance
127
- const paypal = state.unzer.Paypal();
128
- // Rendering input field
129
- //paypal.create('email', {
130
- // containerId: 'paypal-element',
131
- //});
132
- state.paymentHandler['unzer-paypal'] = paypal;
133
- } else if (shopStore.state.order?.['payment_provider'] === 'unzer-sofort') {
134
- const sofort = state.unzer.Sofort();
135
- state.paymentHandler['unzer-sofort'] = sofort;
136
- } else if (shopStore.state.order?.['payment_provider'] === 'unzer-ideal') {
137
- const ideal = state.unzer.Ideal();
138
- ideal.create('ideal', {
139
- containerId: 'ideal-element',
140
- });
141
- state.paymentHandler['unzer-ideal'] = ideal;
142
- } else if (shopStore.state.order?.['payment_provider'] === 'unzer-bancontact') {
143
- const bancontact = state.unzer.Bancontact();
144
- state.paymentHandler['unzer-bancontact'] = bancontact;
145
- } else if (shopStore.state.order?.['payment_provider'] === 'unzer-googlepay') {
146
- const googlepayScriptPromise = new Promise((resolve, reject) => {
147
- const googlepayScript = document.createElement('script');
148
- googlepayScript.setAttribute('src', 'https://pay.google.com/gp/p/js/pay.js');
149
- googlepayScript.onload = () => {
150
- resolve(googlepayScript);
128
+ //Unzer field definition
129
+ if (shopStore.state.order?.['payment_provider'] === 'unzer-card') {
130
+ const card = state.unzer.Card();
131
+ // Rendering input field card number
132
+ card.create('number', {
133
+ containerId: 'card-element-id-number',
134
+ onlyIframe: false,
135
+ });
136
+ // Rendering input field card expiry
137
+ card.create('expiry', {
138
+ containerId: 'card-element-id-expiry',
139
+ onlyIframe: false,
140
+ });
141
+ // Rendering input field card cvc
142
+ card.create('cvc', {
143
+ containerId: 'card-element-id-cvc',
144
+ onlyIframe: false,
145
+ });
146
+ state.paymentHandler['unzer-card'] = card;
147
+ } else if (shopStore.state.order?.['payment_provider'] === 'unzer-paypal') {
148
+ // Creating a PayPal instance
149
+ const paypal = state.unzer.Paypal();
150
+ // Rendering input field
151
+ //paypal.create('email', {
152
+ // containerId: 'paypal-element',
153
+ //});
154
+ state.paymentHandler['unzer-paypal'] = paypal;
155
+ } else if (shopStore.state.order?.['payment_provider'] === 'unzer-sofort') {
156
+ const sofort = state.unzer.Sofort();
157
+ state.paymentHandler['unzer-sofort'] = sofort;
158
+ } else if (shopStore.state.order?.['payment_provider'] === 'unzer-ideal') {
159
+ const ideal = state.unzer.Ideal();
160
+ ideal.create('ideal', {
161
+ containerId: 'ideal-element',
162
+ });
163
+ state.paymentHandler['unzer-ideal'] = ideal;
164
+ } else if (shopStore.state.order?.['payment_provider'] === 'unzer-bancontact') {
165
+ const bancontact = state.unzer.Bancontact();
166
+ state.paymentHandler['unzer-bancontact'] = bancontact;
167
+ } else if (shopStore.state.order?.['payment_provider'] === 'unzer-googlepay') {
168
+ const googlepayScriptPromise = new Promise((resolve, reject) => {
169
+ const googlepayScript = document.createElement('script');
170
+ googlepayScript.setAttribute('src', 'https://pay.google.com/gp/p/js/pay.js');
171
+ googlepayScript.onload = () => {
172
+ resolve(googlepayScript);
173
+ };
174
+ googlepayScript.onerror = reject;
175
+ document.head.appendChild(googlepayScript);
176
+ });
177
+ const googlepay = state.unzer.Googlepay();
178
+ state.paymentHandler['unzer-googlepay'] = googlepay;
179
+ const paymentDataRequestObject = googlepay.initPaymentDataRequestObject({
180
+ gatewayMerchantId: shopStore.state.paymentProviderData.channel,
181
+ merchantInfo: {
182
+ merchantId: shopStore.state.paymentProviderData.merchant_id,
183
+ merchantName: shopStore.state.paymentProviderData.merchant_name,
184
+ },
185
+ transactionInfo: {
186
+ countryCode: shopStore.state.order.billing_address.dest['country'].toUpperCase(),
187
+ currencyCode: 'EUR',
188
+ totalPrice: shopStore.state.order.total.toString(),
189
+ totalPriceStatus: 'ESTIMATED', // backend should have the last words
190
+ // totalPriceStatus: 'FINAL',
191
+ // checkoutOption: 'COMPLETE_IMMEDIATE_PURCHASE',
192
+ },
193
+ // buttonColor: 'white',
194
+ allowedCardNetworks: shopStore.state.paymentProviderData.brands,
195
+ allowCreditCards: shopStore.state.paymentProviderData.allow_credit_cards,
196
+ allowPrepaidCards: shopStore.state.paymentProviderData.allow_prepaid_cards,
197
+
198
+ onPaymentAuthorizedCallback: (paymentData) => {
199
+ PaymentCheckPause();
200
+ state.loading = true;
201
+ state.hasError = false;
202
+
203
+ return googlepay.createResource(paymentData)
204
+ .then(result => {
205
+ console.debug(result);
206
+ saveType(result.id);
207
+ return {status: 'success'}; // Tell Google Pay we could handle it
208
+ })
209
+ .catch(function (error) {
210
+ paymentError(error);
211
+ return { // Tell Google Pay we could NOT handle it
212
+ status: 'error',
213
+ message: error.customerMessage || error.message || error || 'Unexpected error',
151
214
  };
152
- googlepayScript.onerror = reject;
153
- document.head.appendChild(googlepayScript);
154
- });
155
- const googlepay = state.unzer.Googlepay();
156
- state.paymentHandler['unzer-googlepay'] = googlepay;
157
- const paymentDataRequestObject = googlepay.initPaymentDataRequestObject({
158
- gatewayMerchantId: shopStore.state.paymentProviderData.channel,
159
- merchantInfo: {
160
- merchantId: shopStore.state.paymentProviderData.merchant_id,
161
- merchantName: shopStore.state.paymentProviderData.merchant_name,
162
- },
163
- transactionInfo: {
164
- countryCode: shopStore.state.order.billing_address.dest['country'].toUpperCase(),
165
- currencyCode: 'EUR',
166
- totalPrice: shopStore.state.order.total.toString(),
167
- totalPriceStatus: 'ESTIMATED', // backend should have the last words
168
- // totalPriceStatus: 'FINAL',
169
- // checkoutOption: 'COMPLETE_IMMEDIATE_PURCHASE',
170
- },
171
- // buttonColor: 'white',
172
- allowedCardNetworks: shopStore.state.paymentProviderData.brands,
173
- allowCreditCards: shopStore.state.paymentProviderData.allow_credit_cards,
174
- allowPrepaidCards: shopStore.state.paymentProviderData.allow_prepaid_cards,
175
-
176
- onPaymentAuthorizedCallback: (paymentData) => {
177
- PaymentCheckPause();
178
- state.loading = true;
179
- state.hasError = false;
180
-
181
- return googlepay.createResource(paymentData)
182
- .then(result => {
183
- console.debug(result);
184
- saveType(result.id);
185
- return {status: 'success'}; // Tell Google Pay we could handle it
186
- })
187
- .catch(function (error) {
188
- paymentError(error);
189
- return { // Tell Google Pay we could NOT handle it
190
- status: 'error',
191
- message: error.customerMessage || error.message || error || 'Unexpected error',
192
- };
193
- });
194
- },
195
- });
196
- console.debug('unzer-googlepay', googlepay, paymentDataRequestObject);
197
- // TODO: How can we catch >Uncaught (in promise) AbortError: User closed the Payment Request UI.< ?
198
- googlepayScriptPromise.then(() => {
199
- // gpay script has been loaded, we can start the payment
200
- googlepay.create(
201
- {containerId: 'googlepay-element'},
202
- paymentDataRequestObject,
203
- );
204
- });
205
- } else {
206
- console.warn(`Unknown payment provider: ${shopStore.state.order?.['payment_provider']}`);
207
- }
208
- state.loading = false;
215
+ });
216
+ },
217
+ });
218
+ console.debug('unzer-googlepay', googlepay, paymentDataRequestObject);
219
+ // TODO: How can we catch >Uncaught (in promise) AbortError: User closed the Payment Request UI.< ?
220
+ googlepayScriptPromise.then(() => {
221
+ // gpay script has been loaded, we can start the payment
222
+ googlepay.create(
223
+ {containerId: 'googlepay-element'},
224
+ paymentDataRequestObject,
225
+ );
226
+ });
227
+ } else if (shopStore.state.order?.['payment_provider'] === 'unzer-paylater_invoice') {
228
+ state.birthdateIsInvalid = true; // no value --> invalid
229
+ const paylaterInvoice = state.unzer.PaylaterInvoice();
230
+ paylaterInvoice.create({
231
+ containerId: 'paylater-invoice-element',
232
+ customerType: 'B2C', // or B2B
233
+ });
234
+ state.paymentHandler['unzer-paylater_invoice'] = paylaterInvoice;
235
+ } else {
236
+ console.warn(`Unknown payment provider: ${shopStore.state.order?.['payment_provider']}`);
237
+ }
238
+ state.loading = false;
209
239
  }
210
240
 
241
+ function birthdateChange(event) {
242
+ console.debug('birthdateChange', arguments);
243
+ if (!event.target.value || !event.target.checkValidity()) {
244
+ // state.birthdate = null;
245
+ state.birthdateIsInvalid = true;
246
+ } else {
247
+ state.birthdate = event.target.value;
248
+ state.birthdateIsInvalid = false;
249
+ state.loading = true;
250
+ saveBirthdate(shopStore.state.order.billing_address.dest['key'], event.target.value)
251
+ .then(result => {
252
+ console.debug(result);
253
+ })
254
+ .catch(paymentError)
255
+ .finally(() => {
256
+ state.loading = false;
257
+ });
258
+ }
259
+ }
260
+
261
+
211
262
  /**
212
263
  * Handle an error
213
264
  *
@@ -215,10 +266,17 @@ function initUnzerForm() {
215
266
  * with a translated (and detailed) description for the customer
216
267
  */
217
268
  function paymentError(error) {
218
- console.error(error);
219
- state.loading = false;
220
- state.hasError = true;
269
+ console.error(error);
270
+ state.loading = false;
271
+ state.hasError = true;
272
+ if (error && error.constructor.name === HTTPError.name && error.response.headers.get('x-viur-shop-error')) {
273
+ error.response.json().then(res => {
274
+ console.error(res.errors);
275
+ state.errorMessage = res.errors.map(err => err.customer_message || err.message).join(', ');
276
+ });
277
+ } else {
221
278
  state.errorMessage = error.customerMessage || error.message || error || 'Error';
279
+ }
222
280
  }
223
281
 
224
282
  /**
@@ -227,13 +285,15 @@ function paymentError(error) {
227
285
  * This function is used by all unzer pyment types, except Google Pay.
228
286
  */
229
287
  function submitFormToUnzer() {
230
- PaymentCheckPause();
231
- state.loading = true;
232
- state.hasError = false;
233
- state.paymentHandler[shopStore.state.order?.['payment_provider']].createResource().then((result) => {
234
- saveType(result.id);
235
- }).catch((error) => {
236
- paymentError(error);
288
+ PaymentCheckPause();
289
+ state.loading = true;
290
+ state.hasError = false;
291
+ state.paymentHandler[shopStore.state.order?.['payment_provider']].createResource()
292
+ .then((result) => {
293
+ saveType(result.id);
294
+ })
295
+ .catch((error) => {
296
+ paymentError(error);
237
297
  });
238
298
  }
239
299
 
@@ -245,73 +305,86 @@ function submitFormToUnzer() {
245
305
  * @param typeId The type-id of the created Type, e.g. ``s-crd-abc123def456``
246
306
  */
247
307
  function saveType(typeId) {
248
- const paymenttarget = shopStore.state.order?.['payment_provider'].split('-')[1];
249
- Request.post(`${shopStore.state.shopUrl}/pp_unzer_${paymenttarget}/save_type`, {
250
- dataObj: {
251
- order_key: shopStore.state.orderKey,
252
- type_id: typeId,
253
- },
254
- }).then(async (resp) => {
255
- shopStore.state.order = await resp.json();
256
- shopStore.checkoutOrder().then((resp) => {
257
- state.loading = false;
258
- state.hasError = false;
259
- if (shopStore.state.paymentProviderData?.redirectUrl) {
260
- state.waitPayment = true;
261
- window.open(shopStore.state.paymentProviderData.redirectUrl, '_blank', 'popup');
262
- PaymentCheckResume();
263
- }
264
- }).catch(async (error) => {
265
- paymentError(error);
266
- });
267
-
268
- }).catch(error => {
269
- paymentError(error);
308
+ const paymenttarget = shopStore.state.order?.['payment_provider'].split('-').slice(1).join('-');
309
+ Request.post(`${shopStore.state.shopUrl}/pp_unzer_${paymenttarget}/save_type`, {
310
+ dataObj: {
311
+ order_key: shopStore.state.orderKey,
312
+ type_id: typeId,
313
+ },
314
+ }).then(async (resp) => {
315
+ shopStore.state.order = await resp.json();
316
+ shopStore.checkoutOrder().then((resp) => {
317
+ state.loading = false;
318
+ state.hasError = false;
319
+ if (shopStore.state.paymentProviderData?.redirectUrl) {
320
+ state.waitPayment = true;
321
+ window.open(shopStore.state.paymentProviderData.redirectUrl, '_blank', 'popup');
322
+ PaymentCheckResume();
323
+ }
324
+ }).catch(async (error) => {
325
+ paymentError(error);
270
326
  });
327
+
328
+ }).catch(error => {
329
+ paymentError(error);
330
+ });
271
331
  }
272
332
 
273
333
 
274
334
  function cancelPayment() {
275
- PaymentCheckPause();
276
- emits('cancel');
335
+ PaymentCheckPause();
336
+ emits('cancel');
277
337
  }
278
338
 
279
339
  onBeforeMount(() => {
280
- state.loading = true;
281
- if (!shopStore.state.paymentProviderData) {
282
- shopStore.checkout().then(() => {
283
- initUnzerForm();
284
- }).catch((error) => {
285
- console.log(error);
286
- });
287
- } else {
288
- initUnzerForm();
289
- }
340
+ state.loading = true;
341
+ if (!shopStore.state.paymentProviderData) {
342
+ shopStore.checkout().then(() => {
343
+ initUnzerForm();
344
+ fetchOrder(shopStore.state.orderKey); // refresh order after checkout_start freeze
345
+ }).catch((error) => {
346
+ console.log(error);
347
+ });
348
+ } else {
349
+ initUnzerForm();
350
+ }
290
351
  });
291
352
 
292
353
  </script>
293
354
 
294
355
  <style scoped>
295
356
  .loading-wrapper {
296
- display: flex;
297
- flex-direction: column;
298
- align-items: center;
357
+ display: flex;
358
+ flex-direction: column;
359
+ align-items: center;
299
360
  }
300
361
 
301
362
  .form-wrapper {
302
- display: flex;
303
- flex-direction: column;
304
- gap: 20px;
363
+ display: flex;
364
+ flex-direction: column;
365
+ gap: 20px;
305
366
  }
306
367
 
307
368
  .loading {
308
- font-size: 3rem;
369
+ font-size: 3rem;
309
370
  }
310
371
  </style>
311
372
 
312
373
  <style>
313
374
  /* global style to overwrite UnzerCSS */
314
375
  .unzerUI.primary.button, .unzerUI.primary.buttons .button {
315
- background-color: var(--ignt-color-primary) !important;
376
+ background-color: var(--ignt-color-primary) !important;
377
+ }
378
+
379
+ .unzerSandboxNotify:not(:first-of-type) {
380
+ display: none;
381
+ }
382
+
383
+ .unzerUI.form {
384
+ margin-top: 1em;
385
+
386
+ .opt-in a.unzerUI {
387
+ line-height: inherit;
388
+ }
316
389
  }
317
390
  </style>
@@ -4,6 +4,7 @@ import {useCart} from '../composables/cart';
4
4
  import {useOrder} from '../composables/order';
5
5
  import {useViurShopStore} from '../shop';
6
6
  import {useShipping} from './shipping.js';
7
+ import {Request} from '@viur/vue-utils';
7
8
 
8
9
  export const useAddress = defineStore('useAddressStore', () => {
9
10
  const shopStore = useViurShopStore();
@@ -110,10 +111,34 @@ export const useAddress = defineStore('useAddressStore', () => {
110
111
  }
111
112
  }
112
113
 
114
+ function saveBirthdate(addressKey, birthdate) {
115
+ return new Promise((resolve, reject) => {
116
+ Request.securePost(
117
+ `/json/${shopStore.state.moduleName}/address/edit/${addressKey}`, {
118
+ dataObj: {
119
+ '@order': shopStore.state.orderKey,
120
+ birthdate,
121
+ },
122
+ },
123
+ )
124
+ .then(async (res) => {
125
+ const data = await res.json();
126
+ if (data['action'] === 'editSuccess') {
127
+ resolve(data);
128
+ } else {
129
+ reject(`Update failed`);
130
+ }
131
+ })
132
+ .catch(reject);
133
+ });
134
+ }
135
+
136
+
113
137
  return {
114
138
  state,
115
139
  saveForm,
116
140
  updateAddresses,
117
141
  saveAddresses,
142
+ saveBirthdate,
118
143
  };
119
144
  });
@@ -59,6 +59,8 @@ export default {
59
59
  'order_step_complete': 'Bestellung Abgeschlossen',
60
60
  'paypal_client_popup_info': 'Bitte prüfen Sie, ob Ihr Browser das PayPal-Popup zulässt.',
61
61
  'payment_link': 'Ihr Browser öffnet kein Popup? Dann klicken Sie bitte <a href="{url}" target="_blank">hier</a>.',
62
+ 'birthdate': 'Geburtsdatum',
63
+ 'missing_birthdate': 'Bei der ausgewählten Bezahlmethode benötigen wir zur Rechnungsadresse noch das Geburtsdatum von <i>{firstname}&nbsp;{lastname}</i>.',
62
64
  },
63
65
  },
64
66
  messages: {
@@ -58,6 +58,8 @@ export default {
58
58
  'order_step_complete': 'Order complete',
59
59
  'paypal_client_popup_info': 'Please make sure your browser allows the PayPal popup.',
60
60
  'payment_link': 'Your browser does not open a popup? Then please click <a href="{url}" target="_blank">here</a>.',
61
+ 'birthdate': 'date of birth',
62
+ 'missing_birthdate': 'For the selected payment method, we require the date of birth of <i>{firstname}&nbsp;{lastname}</i> in addition to the billing address.',
61
63
  },
62
64
  },
63
65
  messages: {
@@ -59,6 +59,8 @@ export default {
59
59
  'order_step_complete': 'Valider la commande',
60
60
  'paypal_client_popup_info':"Assurez-vous que votre navigateur autorise la fenêtre contextuelle PayPal.",
61
61
  'payment_link': 'Votre navigateur n\'ouvre pas de popup ? Alors cliquez <a href="{url}" target="_blank">ici</a>.',
62
+ 'birthdate': 'date de naissance',
63
+ 'missing_birthdate': 'Pour le mode de paiement sélectionné, nous avons besoin, en plus de l\'adresse de facturation, de la date de naissance de <i>{firstname}&nbsp;{lastname}</i>.',
62
64
  },
63
65
  },
64
66
  messages: {