@lancom/shared 0.0.238 → 0.0.240
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/assets/js/api/admin.js +2 -2
- package/assets/js/constants/country.js +4 -0
- package/assets/js/utils/gapis.js +5 -2
- package/assets/js/utils/gtm.js +17 -4
- package/components/checkout/order/order-payment-information/order-payment-information.vue +1 -1
- package/components/product/product_size_selector/product_size_selector_color/product_size_selector_color_cell/product-size-selector-color-cell.vue +2 -2
- package/components/quotes/quote_request/quote-request.vue +25 -2
- package/components/quotes/quote_view/quote-view.mixin.js +3 -4
- package/feeds/google-shopping.js +108 -0
- package/feeds/index.js +7 -0
- package/feeds/reviews.js +112 -0
- package/nuxt.config.js +3 -201
- package/package.json +1 -1
- package/store/product.js +3 -0
package/assets/js/api/admin.js
CHANGED
|
@@ -263,8 +263,8 @@ export default {
|
|
|
263
263
|
fetchInventoryHistory(params) {
|
|
264
264
|
return _get('admin/inventory-history', params);
|
|
265
265
|
},
|
|
266
|
-
|
|
267
|
-
return
|
|
266
|
+
removeInventoryHistory(id) {
|
|
267
|
+
return _delete(`admin/inventory-history/${id}`);
|
|
268
268
|
},
|
|
269
269
|
fetchInventory(params) {
|
|
270
270
|
return _get('admin/inventory');
|
package/assets/js/utils/gapis.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import { COUNTRIES_CODES } from '@lancom/shared/assets/js/constants/country';
|
|
3
|
+
|
|
1
4
|
function surveyOptin(order, shop) {
|
|
2
5
|
if (!window.renderOptIn) {
|
|
3
6
|
const tag = document.createElement('script');
|
|
@@ -42,12 +45,12 @@ function surveyoptinRender(order, shop) {
|
|
|
42
45
|
.filter(gtin => !!gtin)
|
|
43
46
|
];
|
|
44
47
|
}, []);
|
|
45
|
-
const estimated_delivery_date =
|
|
48
|
+
const estimated_delivery_date = dayjs(new Date()).add(15, 'day').format('YYYY-MM-DD');
|
|
46
49
|
const data = {
|
|
47
50
|
merchant_id: MERCHANT_ID,
|
|
48
51
|
order_id: order.code,
|
|
49
52
|
email: order.shippingAddress.email,
|
|
50
|
-
delivery_country: order.shippingAddress.country,
|
|
53
|
+
delivery_country: COUNTRIES_CODES[order.shippingAddress.country] || order.shippingAddress.country,
|
|
51
54
|
estimated_delivery_date,
|
|
52
55
|
products,
|
|
53
56
|
opt_in_style: "BOTTOM_RIGHT_DIALOG"
|
package/assets/js/utils/gtm.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { COUNTRIES_CODES } from '@lancom/shared/assets/js/constants/country';
|
|
2
|
+
|
|
1
3
|
const gtm = {
|
|
2
4
|
push(data, skipReset) {
|
|
3
5
|
console.log('push:data: ', data);
|
|
@@ -9,6 +11,15 @@ const gtm = {
|
|
|
9
11
|
}
|
|
10
12
|
window.dataLayer.push(data);
|
|
11
13
|
},
|
|
14
|
+
viewItem(product) {
|
|
15
|
+
this.push({
|
|
16
|
+
value: product.minPrice,
|
|
17
|
+
items: [{
|
|
18
|
+
id: product.SKU,
|
|
19
|
+
google_business_vertical: 'retail'
|
|
20
|
+
}]
|
|
21
|
+
});
|
|
22
|
+
},
|
|
12
23
|
addToCart(entities, pricing) {
|
|
13
24
|
this.push({
|
|
14
25
|
event: 'add_to_cart',
|
|
@@ -30,7 +41,7 @@ const gtm = {
|
|
|
30
41
|
viewCart(entities, pricing) {
|
|
31
42
|
if (pricing) {
|
|
32
43
|
this.push({
|
|
33
|
-
event: '
|
|
44
|
+
event: 'view_item_list',
|
|
34
45
|
value: pricing.totalPriceWithoutTax,
|
|
35
46
|
currency: 'AUD',
|
|
36
47
|
coupon: pricing.coupon?.code,
|
|
@@ -88,7 +99,7 @@ const gtm = {
|
|
|
88
99
|
city,
|
|
89
100
|
region: state,
|
|
90
101
|
postal_code: +postcode,
|
|
91
|
-
country
|
|
102
|
+
country: COUNTRIES_CODES[country] || country
|
|
92
103
|
};
|
|
93
104
|
}
|
|
94
105
|
gtm.push(event);
|
|
@@ -135,13 +146,15 @@ function getOrderItems(order) {
|
|
|
135
146
|
function getOrderItem(product, simpleProduct) {
|
|
136
147
|
const { SKU, productCost, amount, color, size } = simpleProduct;
|
|
137
148
|
return {
|
|
138
|
-
|
|
149
|
+
id: product.SKU,
|
|
150
|
+
item_id: SKU,
|
|
139
151
|
item_variant: `${product.name} ${color?.name || ''}-${size?.shortName || ''}`.trim(),
|
|
140
152
|
item_name: product.name.trim(),
|
|
141
153
|
item_brand: product.brand.name,
|
|
142
154
|
price: productCost,
|
|
143
155
|
currency: 'AUD',
|
|
144
|
-
quantity: amount
|
|
156
|
+
quantity: amount,
|
|
157
|
+
google_business_vertical: 'retail'
|
|
145
158
|
};
|
|
146
159
|
}
|
|
147
160
|
|
|
@@ -179,7 +179,7 @@ export default {
|
|
|
179
179
|
this.$emit('next');
|
|
180
180
|
} else {
|
|
181
181
|
this.$nextTick(async () => {
|
|
182
|
-
const message = `Unfortunately our payment gateway has reported the following error: '${this.errorMessage}'. Please check your card number and try again. Alternatively you can proceed with a 'pay later' order and receive
|
|
182
|
+
const message = `Unfortunately our payment gateway has reported the following error: '${this.errorMessage}'. Please check your card number and try again. Alternatively you can proceed with a 'pay later' order and receive an email confirmation now and pay via credit card or direct deposit`;
|
|
183
183
|
const options = { submitLabel: 'PAY LATER', cancelLabel: 'TRY AGAIN', warning: true };
|
|
184
184
|
const isSwitchToDeposit = await this.showConfirmationModal(message, options);
|
|
185
185
|
if (isSwitchToDeposit) {
|
|
@@ -84,7 +84,7 @@ export default {
|
|
|
84
84
|
data() {
|
|
85
85
|
return {
|
|
86
86
|
uniqueFieldId: `size-selector-${this.color._id}-${this.size._id}`,
|
|
87
|
-
defaultValue:
|
|
87
|
+
defaultValue: null
|
|
88
88
|
};
|
|
89
89
|
},
|
|
90
90
|
computed: {
|
|
@@ -122,7 +122,7 @@ export default {
|
|
|
122
122
|
this.defaultValue = '';
|
|
123
123
|
},
|
|
124
124
|
onBlur() {
|
|
125
|
-
this.defaultValue =
|
|
125
|
+
this.defaultValue = null;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
};
|
|
@@ -366,7 +366,8 @@ export default {
|
|
|
366
366
|
};
|
|
367
367
|
},
|
|
368
368
|
computed: {
|
|
369
|
-
...mapGetters(['shop'])
|
|
369
|
+
...mapGetters(['shop']),
|
|
370
|
+
...mapGetters('cart', ['entities']),
|
|
370
371
|
},
|
|
371
372
|
methods: {
|
|
372
373
|
handleUploaded(file) {
|
|
@@ -403,7 +404,29 @@ export default {
|
|
|
403
404
|
recaptchaToken,
|
|
404
405
|
...this.quote,
|
|
405
406
|
quoteTypes: Object.keys(this.selectedQuoteTypes),
|
|
406
|
-
shop: this.shop._id
|
|
407
|
+
shop: this.shop._id,
|
|
408
|
+
referer: window.location.href,
|
|
409
|
+
cartInfo: {
|
|
410
|
+
entities: (this.entities || [])
|
|
411
|
+
.map(({ product, simpleProducts, prints }) => {
|
|
412
|
+
return {
|
|
413
|
+
product: product ? { _id: product.name, name: product.name, SKU: product.SKU } : null,
|
|
414
|
+
prints: (prints || [])
|
|
415
|
+
.map(({ layers, printArea, printSize, printType }) => ({
|
|
416
|
+
layers,
|
|
417
|
+
printArea: printArea ? { _id: printArea._id, name: printArea.name } : null,
|
|
418
|
+
printSize: printSize ? { _id: printSize._id, name: printSize.name} : null,
|
|
419
|
+
printType: printType ? { _id: printType._id, name: printType.name} : null,
|
|
420
|
+
})),
|
|
421
|
+
simpleProducts: (simpleProducts || [])
|
|
422
|
+
.filter(({ amount }) => amount > 0)
|
|
423
|
+
.map(({ amount, SKU }) => ({
|
|
424
|
+
amount,
|
|
425
|
+
SKU,
|
|
426
|
+
}))
|
|
427
|
+
};
|
|
428
|
+
})
|
|
429
|
+
}
|
|
407
430
|
};
|
|
408
431
|
const quote = await api.saveQuoteRequest(body, this.shop._id);
|
|
409
432
|
|
|
@@ -35,8 +35,7 @@ export default {
|
|
|
35
35
|
async convertToOrder(option) {
|
|
36
36
|
try {
|
|
37
37
|
this.processing = true;
|
|
38
|
-
|
|
39
|
-
this.order = await this.createOrder({ ...option, recaptchaToken });
|
|
38
|
+
this.order = await this.createOrder({ ...option });
|
|
40
39
|
this.setOrder(this.order);
|
|
41
40
|
gtm.purchase(this.order);
|
|
42
41
|
gapis.surveyOptin(this.order, this.shop);
|
|
@@ -51,11 +50,11 @@ export default {
|
|
|
51
50
|
async createOrder(option) {
|
|
52
51
|
const recaptchaToken = await this.getRecaptcha('create_order');
|
|
53
52
|
const orderData = {
|
|
54
|
-
recaptchaToken,
|
|
55
53
|
shop: this.shop._id,
|
|
56
54
|
country: this.country?._id,
|
|
57
55
|
currency: this.currency?._id,
|
|
58
|
-
...convertQuoteToOrder(this.quote, option)
|
|
56
|
+
...convertQuoteToOrder(this.quote, option),
|
|
57
|
+
recaptchaToken
|
|
59
58
|
};
|
|
60
59
|
return await api.createOrder(orderData, this.shop._id);
|
|
61
60
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
async function googleShoppingFeed(axios, config, availableStores) {
|
|
2
|
+
const { data } = await axios.get(`${config.LOCAL_API_URL}/feed/products?host=${config.HOST_NAME}`);
|
|
3
|
+
const spliceFirstImage = images => (images || []).splice(0, 1)[0];
|
|
4
|
+
const getImages = images => (images || []).length > 0 ? images : null;
|
|
5
|
+
const channel = {
|
|
6
|
+
title: { _text: 'All products' },
|
|
7
|
+
link: { _text: `https://${config.HOST_NAME}` },
|
|
8
|
+
generator: { _text: config.HOST_NAME },
|
|
9
|
+
item: data
|
|
10
|
+
.reduce((items, product) => {
|
|
11
|
+
return [
|
|
12
|
+
...items,
|
|
13
|
+
...(product.simpleProducts || [])
|
|
14
|
+
.filter(sp => {
|
|
15
|
+
return !availableStores || availableStores.includes(sp.storeCode);
|
|
16
|
+
})
|
|
17
|
+
.map(sp => {
|
|
18
|
+
const feedImages = (product.images || []).filter(i => (i.types || []).includes('feed_primary') && sp.color._id === i.color).map(i => i.image);
|
|
19
|
+
const frontImages = (product.images || []).filter(i => (i.types || []).includes('front') && sp.color._id === i.color).map(i => i.image);
|
|
20
|
+
const backImages = (product.images || []).filter(i => (i.types || []).includes('back') && sp.color._id === i.color).map(i => i.image);
|
|
21
|
+
const catalogFrontImages = (product.images || []).filter(i => (i.types || []).includes('catalog_front')).map(i => i.image);
|
|
22
|
+
const image = spliceFirstImage(feedImages) || spliceFirstImage(frontImages) || spliceFirstImage(catalogFrontImages) || spliceFirstImage(backImages) || {};
|
|
23
|
+
const images = getImages(backImages) || getImages(frontImages) || [];
|
|
24
|
+
const feedTitle = (product.feedTitle || '')
|
|
25
|
+
.replace(/{colour}/g, sp.color.name)
|
|
26
|
+
.replace(/{size}/g, sp.size.name)
|
|
27
|
+
.replace(/{brand}/g, product.brand.name)
|
|
28
|
+
const title = feedTitle || `${product.name} ${sp.color.name}`;
|
|
29
|
+
const description = `${product.description || product.fabricInfoShort || product.name || ''}`
|
|
30
|
+
.replace(/ /g, ' ')
|
|
31
|
+
.replace(/·/, '·');
|
|
32
|
+
const link = `https://${config.HOST_NAME}/${product.brand.alias}/${product.productType.alias}/${product.alias}?color=${sp.color.alias}`;
|
|
33
|
+
const info = {
|
|
34
|
+
title: { _text: title },
|
|
35
|
+
description: { _text: description },
|
|
36
|
+
link: { _text: link },
|
|
37
|
+
'g:id': { _text: sp.SKU },
|
|
38
|
+
'g:item_group_id': { _text: product.SKU },
|
|
39
|
+
'g:size': { _text: sp.size.name },
|
|
40
|
+
'g:size_system': 'AU',
|
|
41
|
+
'g:size_type': 'regular',
|
|
42
|
+
'g:gender': { _text: product.gender },
|
|
43
|
+
'g:material': { _text: product.fabricInfoShort },
|
|
44
|
+
'g:brand': { _text: product.brand.name },
|
|
45
|
+
'g:condition': { _text: 'new' },
|
|
46
|
+
'g:mpn': { _text: sp.SKU },
|
|
47
|
+
'g:color': { _text: sp.color.name },
|
|
48
|
+
'g:image_link': { _text: image },
|
|
49
|
+
'g:additional_image_link': images.map(i => ({ _text: i })),
|
|
50
|
+
'g:price': { _text: `${(sp.price || 0)} AUD` },
|
|
51
|
+
'g:availability': { _text: sp.quantityStock > 0 ? 'in_stock' : 'out_of_stock' },
|
|
52
|
+
'g:google_product_category': { _text: 2047 },
|
|
53
|
+
'g:product_type': { _text: `Home > Products > ${product.productType.name}`, },
|
|
54
|
+
'g:is_bundle': { _text: product.prePrint ? 'yes' : 'no' },
|
|
55
|
+
'g:identifier_exists': sp.gtin ? 'yes' : 'no',
|
|
56
|
+
'g:product_weight': { _text: `${product.weight} kg` },
|
|
57
|
+
'g:shipping_weight': { _text: `${((product.weight || 0) + (product.weight || 0) * 0.05).toFixed(3)} kg` },
|
|
58
|
+
'g:quantity': { _text: sp.quantityStock },
|
|
59
|
+
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (sp.gtin) {
|
|
63
|
+
info['g:gtin'] = { _text: sp.gtin || '' };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (sp.storeCode) {
|
|
67
|
+
info['g:store_code'] = { _text: sp.storeCode };
|
|
68
|
+
info['g:link_template'] = { _text: `${link}&store={store_code}` };
|
|
69
|
+
if (availableStores) {
|
|
70
|
+
info['g:pickup_method'] = { _text: 'buy' };
|
|
71
|
+
info['g:pickup_sla'] = { _text: product.prePrint ? 'next day' : 'same day' };
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
info['g:pickup_method'] = { _text: 'not_supported' };
|
|
75
|
+
}
|
|
76
|
+
if (product.volume) {
|
|
77
|
+
if (product.volume.length) {
|
|
78
|
+
info['g:shipping_length'] = { _text: `${product.volume.length} cm` };
|
|
79
|
+
}
|
|
80
|
+
if (product.volume.width) {
|
|
81
|
+
info['g:shipping_width'] = { _text: `${product.volume.width} cm` };
|
|
82
|
+
}
|
|
83
|
+
if (product.volume.height) {
|
|
84
|
+
info['g:shipping_height'] = { _text: `${product.volume.height} cm` };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return info;
|
|
88
|
+
})
|
|
89
|
+
];
|
|
90
|
+
}, [])
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
_declaration: { _attributes: { version: "1.0", encoding: "utf-8" } },
|
|
95
|
+
rss: {
|
|
96
|
+
_attributes: { version: "2.0", 'xmlns:g': "http://base.google.com/ns/1.0" },
|
|
97
|
+
channel: {
|
|
98
|
+
lastBuildDate: { _text: new Date().toUTCString() },
|
|
99
|
+
docs: { _text: "https://validator.w3.org/feed/docs/rss2.html" },
|
|
100
|
+
...channel
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
googleShoppingFeed
|
|
108
|
+
};
|
package/feeds/index.js
ADDED
package/feeds/reviews.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
async function reviewsFeed(axios, config) {
|
|
2
|
+
const { data } = await axios.get(`${config.LOCAL_API_URL}/feed/reviews?host=${config.HOST_NAME}`);
|
|
3
|
+
|
|
4
|
+
return {
|
|
5
|
+
_declaration: { _attributes: { version: "1.0", encoding: "utf-8" } },
|
|
6
|
+
feed: {
|
|
7
|
+
_attributes: {
|
|
8
|
+
'xmlns:vc': 'http://www.w3.org/2007/XMLSchema-versioning',
|
|
9
|
+
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
|
10
|
+
'xsi:noNamespaceSchemaLocation': 'http://www.google.com/shopping/reviews/schema/product/2.3/product_reviews.xsd'
|
|
11
|
+
},
|
|
12
|
+
version: { _text: '2.3' },
|
|
13
|
+
publisher: {
|
|
14
|
+
name: { _text: 'Workdepot Australia' },
|
|
15
|
+
favicon: { _text: 'https://www.workdepot.com.au/favicon.png' }
|
|
16
|
+
},
|
|
17
|
+
reviews: {
|
|
18
|
+
review: [
|
|
19
|
+
...data
|
|
20
|
+
.filter(review => !!review.product)
|
|
21
|
+
.map(review => {
|
|
22
|
+
const { product } = review;
|
|
23
|
+
const productUrl = `https://${config.HOST_NAME}/${product.brand.alias}/${product.productType.alias}/${product.alias}`;
|
|
24
|
+
const item = {
|
|
25
|
+
review_id: { _text: review._id },
|
|
26
|
+
reviewer: {
|
|
27
|
+
name: {
|
|
28
|
+
_attributes: {
|
|
29
|
+
is_anonymous: 'false'
|
|
30
|
+
},
|
|
31
|
+
_text: review.name
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
review_timestamp: { _text: review.createdAt },
|
|
35
|
+
title: { _text: product.name },
|
|
36
|
+
content: { _text: review.text },
|
|
37
|
+
pros: {
|
|
38
|
+
pro: (review.pro || '').split(/\n/).map(pro => ({ _text: pro }))
|
|
39
|
+
},
|
|
40
|
+
cons: {
|
|
41
|
+
con: (review.cons || '').split(/\n/).map(cons => ({ _text: cons }))
|
|
42
|
+
},
|
|
43
|
+
review_url: {
|
|
44
|
+
_attributes: {
|
|
45
|
+
type: 'singleton'
|
|
46
|
+
},
|
|
47
|
+
_text: `${productUrl}#review-${review._id}`
|
|
48
|
+
},
|
|
49
|
+
reviewer_images: {
|
|
50
|
+
reviewer_image: [{
|
|
51
|
+
url: { _text: review.image?.large }
|
|
52
|
+
}]
|
|
53
|
+
},
|
|
54
|
+
ratings: {
|
|
55
|
+
overall: {
|
|
56
|
+
_attributes: {
|
|
57
|
+
min: 1,
|
|
58
|
+
max: 5
|
|
59
|
+
},
|
|
60
|
+
_text: review.mark
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
products: {
|
|
64
|
+
product: {
|
|
65
|
+
product_ids: {
|
|
66
|
+
gtins: {
|
|
67
|
+
gtin: { _text: product.simpleProduct?.gtin }
|
|
68
|
+
},
|
|
69
|
+
skus: {
|
|
70
|
+
sku: { _text: product.simpleProduct?.SKU }
|
|
71
|
+
},
|
|
72
|
+
brands: {
|
|
73
|
+
brand: { _text: product.brand.name }
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
product_name: { _text: product.name },
|
|
77
|
+
product_url: { _text: productUrl }
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
is_spam: { _text: 'false' }
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (!product.simpleProduct?.gtin) {
|
|
84
|
+
delete item.products.product.product_ids.gtins;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!product.simpleProduct?.SKU) {
|
|
88
|
+
delete item.products.product.product_ids.skus;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!review.pro) {
|
|
92
|
+
delete item.pros;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!review.cons) {
|
|
96
|
+
delete item.cons;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!review.image) {
|
|
100
|
+
delete item.reviewer_images;
|
|
101
|
+
}
|
|
102
|
+
return item;
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = {
|
|
111
|
+
reviewsFeed
|
|
112
|
+
};
|
package/nuxt.config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const sharedRoutes = require('./routes');
|
|
2
|
+
const feeds = require('./feeds');
|
|
2
3
|
|
|
3
4
|
module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
|
|
4
5
|
globalName: 'appLancom',
|
|
@@ -122,211 +123,12 @@ module.exports = (config, axios, { raygunClient, publicPath } = {}) => ({
|
|
|
122
123
|
feed: [{
|
|
123
124
|
path: '/pr-rev-au.xml',
|
|
124
125
|
async get() {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
_declaration: { _attributes: { version: "1.0", encoding: "utf-8" } },
|
|
129
|
-
feed: {
|
|
130
|
-
_attributes: {
|
|
131
|
-
'xmlns:vc': 'http://www.w3.org/2007/XMLSchema-versioning',
|
|
132
|
-
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
|
133
|
-
'xsi:noNamespaceSchemaLocation': 'http://www.google.com/shopping/reviews/schema/product/2.3/product_reviews.xsd'
|
|
134
|
-
},
|
|
135
|
-
version: { _text: '2.3' },
|
|
136
|
-
publisher: {
|
|
137
|
-
name: { _text: 'Workdepot Australia' },
|
|
138
|
-
favicon: { _text: 'https://www.workdepot.com.au/favicon.png' }
|
|
139
|
-
},
|
|
140
|
-
reviews: {
|
|
141
|
-
review: [
|
|
142
|
-
...data
|
|
143
|
-
.filter(review => !!review.product)
|
|
144
|
-
.map(review => {
|
|
145
|
-
const { product } = review;
|
|
146
|
-
const productUrl = `https://${config.HOST_NAME}/${product.brand.alias}/${product.productType.alias}/${product.alias}`;
|
|
147
|
-
const item = {
|
|
148
|
-
review_id: { _text: review._id },
|
|
149
|
-
reviewer: {
|
|
150
|
-
name: {
|
|
151
|
-
_attributes: {
|
|
152
|
-
is_anonymous: 'false'
|
|
153
|
-
},
|
|
154
|
-
_text: review.name
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
review_timestamp: { _text: review.createdAt },
|
|
158
|
-
title: { _text: product.name },
|
|
159
|
-
content: { _text: review.text },
|
|
160
|
-
pros: {
|
|
161
|
-
pro: (review.pro || '').split(/\n/).map(pro => ({ _text: pro }))
|
|
162
|
-
},
|
|
163
|
-
cons: {
|
|
164
|
-
con: (review.cons || '').split(/\n/).map(cons => ({ _text: cons }))
|
|
165
|
-
},
|
|
166
|
-
review_url: {
|
|
167
|
-
_attributes: {
|
|
168
|
-
type: 'singleton'
|
|
169
|
-
},
|
|
170
|
-
_text: `${productUrl}#review-${review._id}`
|
|
171
|
-
},
|
|
172
|
-
reviewer_images: {
|
|
173
|
-
reviewer_image: [{
|
|
174
|
-
url: { _text: review.image?.large }
|
|
175
|
-
}]
|
|
176
|
-
},
|
|
177
|
-
ratings: {
|
|
178
|
-
overall: {
|
|
179
|
-
_attributes: {
|
|
180
|
-
min: 1,
|
|
181
|
-
max: 5
|
|
182
|
-
},
|
|
183
|
-
_text: review.mark
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
products: {
|
|
187
|
-
product: {
|
|
188
|
-
product_ids: {
|
|
189
|
-
gtins: {
|
|
190
|
-
gtin: { _text: product.simpleProduct?.gtin }
|
|
191
|
-
},
|
|
192
|
-
skus: {
|
|
193
|
-
sku: { _text: product.simpleProduct?.SKU }
|
|
194
|
-
},
|
|
195
|
-
brands: {
|
|
196
|
-
brand: { _text: product.brand.name }
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
product_name: { _text: product.name },
|
|
200
|
-
product_url: { _text: productUrl }
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
is_spam: { _text: 'false' }
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
if (!product.simpleProduct?.gtin) {
|
|
207
|
-
delete item.products.product.product_ids.gtins;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (!product.simpleProduct?.SKU) {
|
|
211
|
-
delete item.products.product.product_ids.skus;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (!review.pro) {
|
|
215
|
-
delete item.pros;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (!review.cons) {
|
|
219
|
-
delete item.cons;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (!review.image) {
|
|
223
|
-
delete item.reviewer_images;
|
|
224
|
-
}
|
|
225
|
-
return item;
|
|
226
|
-
})
|
|
227
|
-
]
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
};
|
|
126
|
+
return await feeds.reviewsFeed(axios, config);
|
|
231
127
|
}
|
|
232
128
|
}, {
|
|
233
129
|
path: '/google-shopping.xml',
|
|
234
130
|
async get() {
|
|
235
|
-
|
|
236
|
-
const spliceFirstImage = images => (images || []).splice(0, 1)[0];
|
|
237
|
-
const getImages = images => (images || []).length > 0 ? images : null;
|
|
238
|
-
const channel = {
|
|
239
|
-
title: { _text: 'All products' },
|
|
240
|
-
link: { _text: `https://${config.HOST_NAME}` },
|
|
241
|
-
generator: { _text: config.HOST_NAME },
|
|
242
|
-
item: data.reduce((items, product) => {
|
|
243
|
-
return [
|
|
244
|
-
...items,
|
|
245
|
-
...(product.simpleProducts || []).map(sp => {
|
|
246
|
-
const feedImages = (product.images || []).filter(i => (i.types || []).includes('feed_primary') && sp.color._id === i.color).map(i => i.image);
|
|
247
|
-
const frontImages = (product.images || []).filter(i => (i.types || []).includes('front') && sp.color._id === i.color).map(i => i.image);
|
|
248
|
-
const backImages = (product.images || []).filter(i => (i.types || []).includes('back') && sp.color._id === i.color).map(i => i.image);
|
|
249
|
-
const catalogFrontImages = (product.images || []).filter(i => (i.types || []).includes('catalog_front')).map(i => i.image);
|
|
250
|
-
const image = spliceFirstImage(feedImages) || spliceFirstImage(frontImages) || spliceFirstImage(catalogFrontImages) || spliceFirstImage(backImages) || {};
|
|
251
|
-
const images = getImages(backImages) || getImages(frontImages) || [];
|
|
252
|
-
const feedTitle = (product.feedTitle || '')
|
|
253
|
-
.replace(/{colour}/g, sp.color.name)
|
|
254
|
-
.replace(/{size}/g, sp.size.name)
|
|
255
|
-
.replace(/{brand}/g, product.brand.name)
|
|
256
|
-
const title = feedTitle || `${product.name} ${sp.color.name}`;
|
|
257
|
-
const description = `${product.description || product.fabricInfoShort || product.name || ''}`
|
|
258
|
-
.replace(/ /g, ' ')
|
|
259
|
-
.replace(/·/, '·');
|
|
260
|
-
const link = `https://${config.HOST_NAME}/${product.brand.alias}/${product.productType.alias}/${product.alias}?color=${sp.color.alias}`;
|
|
261
|
-
const info = {
|
|
262
|
-
title: { _text: title },
|
|
263
|
-
description: { _text: description },
|
|
264
|
-
link: { _text: link },
|
|
265
|
-
'g:id': { _text: sp.SKU },
|
|
266
|
-
'g:item_group_id': { _text: product.SKU },
|
|
267
|
-
'g:size': { _text: sp.size.name },
|
|
268
|
-
'g:size_system': 'AU',
|
|
269
|
-
'g:size_type': 'regular',
|
|
270
|
-
'g:gender': { _text: product.gender },
|
|
271
|
-
'g:material': { _text: product.fabricInfoShort },
|
|
272
|
-
'g:brand': { _text: product.brand.name },
|
|
273
|
-
'g:condition': { _text: 'new' },
|
|
274
|
-
'g:mpn': { _text: sp.SKU },
|
|
275
|
-
'g:color': { _text: sp.color.name },
|
|
276
|
-
'g:image_link': { _text: image },
|
|
277
|
-
'g:additional_image_link': images.map(i => ({ _text: i })),
|
|
278
|
-
'g:price': { _text: `${(sp.price || 0)} AUD` },
|
|
279
|
-
'g:availability': { _text: sp.quantityStock > 0 ? 'in_stock' : 'out_of_stock' },
|
|
280
|
-
'g:google_product_category': { _text: 2047 },
|
|
281
|
-
'g:product_type': { _text: `Home > Products > ${product.productType.name}`, },
|
|
282
|
-
'g:is_bundle': { _text: product.prePrint ? 'yes' : 'no' },
|
|
283
|
-
'g:identifier_exists': sp.gtin ? 'yes' : 'no',
|
|
284
|
-
'g:product_weight': { _text: `${product.weight} kg` },
|
|
285
|
-
'g:shipping_weight': { _text: `${((product.weight || 0) + (product.weight || 0) * 0.05).toFixed(3)} kg` },
|
|
286
|
-
'g:quantity': { _text: sp.quantityStock },
|
|
287
|
-
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
if (sp.gtin) {
|
|
291
|
-
info['g:gtin'] = { _text: sp.gtin || '' };
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
if (sp.storeCode) {
|
|
295
|
-
info['g:store_code'] = { _text: sp.storeCode };
|
|
296
|
-
info['g:link_template'] = { _text: `${link}&store={store_code}` };
|
|
297
|
-
info['g:pickup_method'] = { _text: 'buy' };
|
|
298
|
-
info['g:pickup_sla'] = { _text: 'next day' };
|
|
299
|
-
} else {
|
|
300
|
-
info['g:pickup_method'] = { _text: 'not_supported' };
|
|
301
|
-
}
|
|
302
|
-
if (product.volume) {
|
|
303
|
-
if (product.volume.length) {
|
|
304
|
-
info['g:shipping_length'] = { _text: `${product.volume.length} cm` };
|
|
305
|
-
}
|
|
306
|
-
if (product.volume.width) {
|
|
307
|
-
info['g:shipping_width'] = { _text: `${product.volume.width} cm` };
|
|
308
|
-
}
|
|
309
|
-
if (product.volume.height) {
|
|
310
|
-
info['g:shipping_height'] = { _text: `${product.volume.height} cm` };
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return info;
|
|
314
|
-
})
|
|
315
|
-
];
|
|
316
|
-
}, [])
|
|
317
|
-
};
|
|
318
|
-
|
|
319
|
-
return {
|
|
320
|
-
_declaration: { _attributes: { version: "1.0", encoding: "utf-8" } },
|
|
321
|
-
rss: {
|
|
322
|
-
_attributes: { version: "2.0", 'xmlns:g': "http://base.google.com/ns/1.0" },
|
|
323
|
-
channel: {
|
|
324
|
-
lastBuildDate: { _text: new Date().toUTCString() },
|
|
325
|
-
docs: { _text: "https://validator.w3.org/feed/docs/rss2.html" },
|
|
326
|
-
...channel
|
|
327
|
-
},
|
|
328
|
-
},
|
|
329
|
-
}
|
|
131
|
+
return await feeds.googleShoppingFeed(axios, config);
|
|
330
132
|
}
|
|
331
133
|
}],
|
|
332
134
|
router: {
|
package/package.json
CHANGED
package/store/product.js
CHANGED
|
@@ -196,6 +196,9 @@ export const actions = {
|
|
|
196
196
|
const response = await api.fetchPrintTypes(shop);
|
|
197
197
|
commit('setPrintTypes', response);
|
|
198
198
|
},
|
|
199
|
+
async updatePriceIncludeGST({ commit }, value) {
|
|
200
|
+
commit('setPriceIncludeGST', value);
|
|
201
|
+
},
|
|
199
202
|
async calculateProductPrice({ state: { template, product, isPrintPricing }, commit, getters }, shop) {
|
|
200
203
|
commit('setCalculatingPrice', true);
|
|
201
204
|
const entities = getProductsForCalculatePricing(product, getters.usedSimpleProducts, template.layers, isPrintPricing, true);
|