@lancom/shared 0.0.167 → 0.0.169

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.
@@ -13,6 +13,7 @@ export function groupSimpleProducts(entity, isGroupByColor, isPopulateEmptyProdu
13
13
  printsThumbnails: entity.printsThumbnails,
14
14
  product: entity.product,
15
15
  simpleProducts: [],
16
+ unitCosts: [],
16
17
  amount: 0,
17
18
  productsTotal: 0
18
19
  };
@@ -23,7 +24,11 @@ export function groupSimpleProducts(entity, isGroupByColor, isPopulateEmptyProdu
23
24
  const amount = simpleProduct.amount || 0;
24
25
  group.amount += amount;
25
26
 
26
- group.productsTotal += amount * (simpleProduct.productCost || 0);
27
+ const productCost = (simpleProduct.productCost || 0);
28
+ group.productsTotal += amount * productCost;
29
+ if (!group.unitCosts.includes(productCost) && simpleProduct.amount > 0) {
30
+ group.unitCosts.push(productCost);
31
+ }
27
32
  groups.set(key, group);
28
33
  }
29
34
  });
@@ -18,13 +18,28 @@ const gtm = {
18
18
  ...products,
19
19
  ...simpleProducts
20
20
  .filter(({ amount }) => amount > 0)
21
- .map(({ SKU, amount, _id }) => ({
22
- item_id: SKU,
23
- item_name: product.name,
24
- item_brand: product.brand.name,
25
- currency: 'AUD',
26
- price: pricing.products[product._id]?.products[_id]?.totalPriceWithoutTax,
27
- quantity: amount
21
+ .map((sp) => ({
22
+ ...getOrderItem(product, sp),
23
+ price: pricing.products[product._id]?.products[sp._id]?.priceWithoutTax
24
+ }))
25
+ ];
26
+ }, [])
27
+ });
28
+ },
29
+ viewCart(entities, pricing) {
30
+ this.push({
31
+ event: 'view_cart',
32
+ value: pricing.totalPriceWithoutTax,
33
+ currency: 'AUD',
34
+ coupon: pricing.coupon?.code,
35
+ items: entities.reduce((products, { guid: productGuid, product, simpleProducts }) => {
36
+ return [
37
+ ...products,
38
+ ...simpleProducts
39
+ .filter(({ amount }) => amount > 0)
40
+ .map((sp) => ({
41
+ ...getOrderItem(product, sp),
42
+ price: pricing.products[productGuid]?.products[sp.guid]?.priceWithoutTax
28
43
  }))
29
44
  ];
30
45
  }, [])
@@ -35,17 +50,15 @@ const gtm = {
35
50
  const spPricing = Object.keys(pricing.products)
36
51
  .filter(k => !!pricing.products[k].products)
37
52
  .reduce((res, k) => ({ ...res, ...pricing.products[k].products }), {});
38
- gtm.push({
39
- event: 'remove_from_cart',
40
- value: removeSimpleProducts.reduce((sum, { guid }) => sum + (spPricing[guid]?.totalPriceWithoutTax || 0), 0),
41
- currency: 'AUD',
42
- items: removeSimpleProducts.map(({ SKU, amount, guid }) => ({
43
- item_id: SKU,
44
- currency: 'AUD',
45
- price: spPricing[guid]?.totalPriceWithoutTax,
46
- quantity: amount
47
- }))
48
- });
53
+ // gtm.push({
54
+ // event: 'remove_from_cart',
55
+ // value: removeSimpleProducts.reduce((sum, { guid }) => sum + (spPricing[guid]?.totalPriceWithoutTax || 0), 0),
56
+ // currency: 'AUD',
57
+ // items: removeSimpleProducts.map((sp) => ({
58
+ // ...getOrderItem(product, sp),
59
+ // price: spPricing[sp.guid]?.totalPriceWithoutTax
60
+ // }))
61
+ // });
49
62
  },
50
63
  purchase(order) {
51
64
  const event = {
@@ -56,25 +69,61 @@ const gtm = {
56
69
  coupon: order.couponCode,
57
70
  shipping: order.shippingTotal,
58
71
  tax: +(order.totalGST - order.total).toFixed(2),
59
- items: order.products.reduce((products, { product, simpleProducts }) => {
60
- return [
61
- ...products,
62
- ...simpleProducts
63
- .filter(({ amount }) => amount > 0)
64
- .map(({ SKU, productCost, amount, color, size }) => ({
65
- item_id: SKU,
66
- item_name: `${product.name} ${color?.name || ''} ${size?.name || ''}`.trim(),
67
- item_brand: product.brand.name,
68
- price: productCost,
69
- currency: 'AUD',
70
- quantity: amount
71
- }))
72
- ];
73
- }, [])
72
+ items: getOrderItems(order)
73
+ };
74
+ gtm.push(event);
75
+ },
76
+ shippingInfo(order) {
77
+ const shipping = (order.suppliersWithRates || []).reduce((suppliersRates, supplierRates) => {
78
+ const rate = supplierRates.rates.find(({ selected }) => !!selected);
79
+ return rate ? [...suppliersRates, `${supplierRates.name}. ${rate.name}`] : suppliersRates;
80
+ }, []).join(', ');
81
+ const event = {
82
+ event: 'add_shipping_info',
83
+ value: order.shippingTotal,
84
+ coupon: order.couponCode,
85
+ currency: 'AUD',
86
+ shipping_tier: shipping,
87
+ items: getOrderItems(order)
88
+ };
89
+ gtm.push(event);
90
+ },
91
+ paymentInfo(order) {
92
+ const event = {
93
+ event: 'add_payment_info',
94
+ value: order.total,
95
+ coupon: order.couponCode,
96
+ currency: 'AUD',
97
+ payment_type: order.paymentMethod,
98
+ items: getOrderItems(order)
74
99
  };
75
- console.log('purchase: ', event);
76
100
  gtm.push(event);
77
101
  }
78
102
  };
79
103
 
104
+ function getOrderItems(order) {
105
+ return order.products.reduce((products, { product, simpleProducts }) => {
106
+ return [
107
+ ...products,
108
+ ...simpleProducts
109
+ .filter(({ amount }) => amount > 0)
110
+ .map(sp => getOrderItem(product, sp))
111
+ ];
112
+ }, [])
113
+ }
114
+
115
+ function getOrderItem(product, simpleProduct) {
116
+ const { SKU, productCost, amount, color, size } = simpleProduct;
117
+ return {
118
+ item_id: product.SKU,
119
+ item_variant: `${product.name} ${color?.name || ''}-${size?.shortName || ''}`.trim(),
120
+ item_name: product.name.trim(),
121
+ item_brand: product.brand.name,
122
+ price: productCost,
123
+ currency: 'AUD',
124
+ quantity: amount
125
+ };
126
+ }
127
+
128
+
80
129
  export default gtm;
@@ -72,3 +72,18 @@ export function populateProductsFields(products, pricing) {
72
72
  return product;
73
73
  });
74
74
  };
75
+
76
+ export function generateOrderData(data, cartEntities, pricing) {
77
+ const order = { ...data, products: populateProductsFields(cartEntities, pricing) };
78
+ if (pricing) {
79
+ order.totalGST = pricing.totalPrice;
80
+ order.total = pricing.totalPriceWithoutTax;
81
+ order.couponTotal = pricing.coupon?.totalPrice || 0;
82
+ order.couponCode = pricing.coupon?.code || null;
83
+ order.productsTotal = pricing.products?.products?.totalPriceWithoutTax || 0;
84
+ order.printsTotal = pricing.products?.prints?.totalPriceWithoutTax || 0;
85
+ order.shippingTotal = pricing.shipping?.totalPriceWithoutTax || 0;
86
+ order.suppliersWithRates = pricing.shipping?.suppliersWithRates || [];
87
+ }
88
+ return order;
89
+ }
@@ -1,6 +1,7 @@
1
1
  export function convertQuoteToOrder(quote, option) {
2
2
  const files = [quote.file, ...(quote.files || [])].filter(f => !!f);
3
3
  return {
4
+ referenceField: quote.reference,
4
5
  paymentMethod: option.paymentMethod || 'deposit',
5
6
  billingAddress: quote.address,
6
7
  notes: (quote.notes || []).filter(({ text }) => !!text),
@@ -15,6 +16,7 @@ export function convertQuoteToOrder(quote, option) {
15
16
  productsTotal: option.productsTotal,
16
17
  printsTotal: option.printsTotal,
17
18
  shippingTotal: option.shippingTotal,
19
+ suppliersWithRates: option.suppliersWithRates,
18
20
  adminShippingTotal: option.adminShippingTotal,
19
21
  quote: quote._id,
20
22
  resources: files.map(f => ({
@@ -16,6 +16,7 @@ export default {
16
16
  ...mapGetters('auth', ['user']),
17
17
  ...mapGetters('cart', [
18
18
  'entities',
19
+ 'cartPricing',
19
20
  'simpleProducts',
20
21
  'simpleProductsQuantity',
21
22
  'bigSizeSimpleProductsQuantity',
@@ -8,6 +8,21 @@
8
8
  {{ product.name }}
9
9
  </nuxt-link>
10
10
  </div>
11
+ <div
12
+ v-if="product.sameDayDispatch"
13
+ class="lc_body-small">
14
+ <div class="mt-5">
15
+ <i class="icon-delivery"></i>
16
+ <span>
17
+ This product qualifies for same day dispatch.
18
+ <nuxt-link
19
+ class="lc_black"
20
+ to="/faq?group=delivery&id=636f6b3fc305bd0304700d1f">
21
+ read more
22
+ </nuxt-link>
23
+ </span>
24
+ </div>
25
+ </div>
11
26
  <div class="CartEntity__features">
12
27
  <div class="CartEntity__feature">
13
28
  <div class="lc_title-small">
@@ -89,7 +89,10 @@ export default {
89
89
  },
90
90
  mixins: [
91
91
  CartEntityColorSimpleProducts
92
- ]
92
+ ],
93
+ methods: {
94
+ onChangeQty() {}
95
+ }
93
96
  };
94
97
  </script>
95
98
 
@@ -25,6 +25,8 @@
25
25
  </template>
26
26
 
27
27
  <script>
28
+ import gtm from '@lancom/shared/assets/js/utils/gtm';
29
+ import { generateOrderData } from '@lancom/shared/assets/js/utils/order';
28
30
  import CartQuantityErrors from '@lancom/shared/components/checkout/cart/cart_quantity_errors/cart-quantity-errors';
29
31
  import CartMixin from '@lancom/shared/components/checkout/cart/cart.mixin';
30
32
  import AddressForm from '@lancom/shared/components/checkout/order/address-form/address-form';
@@ -59,6 +61,9 @@ export default {
59
61
  return;
60
62
  }
61
63
 
64
+ const orderInfo = generateOrderData(this.order, this.entities, this.cartPricing);
65
+ gtm.shippingInfo(orderInfo);
66
+
62
67
  if (this.copyToShippingAddress) {
63
68
  this.order.shippingAddress = { ...this.order.shippingAddress };
64
69
  this.$emit('next');
@@ -73,6 +73,8 @@
73
73
 
74
74
  <script>
75
75
  import { mapGetters, mapMutations, mapActions } from 'vuex';
76
+ import { generateOrderData } from '@lancom/shared/assets/js/utils/order';
77
+ import gtm from '@lancom/shared/assets/js/utils/gtm';
76
78
  import PaymentCart from '@lancom/shared/components/checkout/payment/payment-cart/payment-cart';
77
79
  import ProgressStepsControls from '@lancom/shared/components/common/progress_steps/progress_steps_controls/progress-steps-controls';
78
80
  import { ORDER_PAYMENT_METHOD } from '@lancom/shared/assets/js/constants/order';
@@ -126,6 +128,10 @@ export default {
126
128
  async submit() {
127
129
  this.creating = true;
128
130
  this.errorMessage = null;
131
+
132
+ const orderInfo = this.orderData || generateOrderData(this.order, this.entities, this.cartPricing);
133
+ gtm.paymentInfo(orderInfo);
134
+
129
135
  if (this.isDepositPayment) {
130
136
  this.setCard(null);
131
137
  await this.submitOrder();
@@ -40,14 +40,32 @@ export default {
40
40
  depositInfo() {
41
41
  return this.order.shop.settings?.depositInfo || {};
42
42
  },
43
+ fullName() {
44
+ return this.invoice?.address?.fullName || this.order.shippingAddress.fullName;
45
+ },
46
+ company() {
47
+ return this.invoice?.address?.company || this.order.shippingAddress.company;
48
+ },
49
+ phone() {
50
+ return this.invoice?.address?.phone || this.order.shippingAddress.phone;
51
+ },
52
+ email() {
53
+ return this.invoice?.address?.email || this.order.shippingAddress.email;
54
+ },
55
+ additionalInfo() {
56
+ return this.invoice?.address?.additionalInfo || this.order.shippingAddress.additionalInfo;
57
+ },
58
+ purchaseOrderNumber() {
59
+ return this.invoice?.purchaseOrderNumber || this.order.purchaseOrderNumber;
60
+ },
43
61
  orderAddress() {
44
62
  return [
45
- this.order.shippingAddress.addressLine1,
46
- this.order.shippingAddress.addressLine2,
47
- this.order.shippingAddress.city,
48
- this.order.shippingAddress.postcode,
49
- this.order.shippingAddress.state,
50
- this.order.shippingAddress.country
63
+ this.invoice?.address?.addressLine1 || this.order.shippingAddress.addressLine1,
64
+ this.invoice?.address?.addressLine2 || this.order.shippingAddress.addressLine2,
65
+ this.invoice?.address?.city || this.order.shippingAddress.city,
66
+ this.invoice?.address?.postcode || this.order.shippingAddress.postcode,
67
+ this.invoice?.address?.state || this.order.shippingAddress.state,
68
+ this.invoice?.address?.country || this.order.shippingAddress.country
51
69
  ].filter(i => !!i).join(', ');
52
70
  },
53
71
  gstTax() {
@@ -21,9 +21,9 @@
21
21
  Tax invoice
22
22
  </h1>
23
23
  <h5
24
- v-if="order.purchaseOrderNumber"
24
+ v-if="purchaseOrderNumber"
25
25
  class="text-secondary lc_h5">
26
- PO: {{ order.purchaseOrderNumber }}
26
+ PO: {{ purchaseOrderNumber }}
27
27
  </h5>
28
28
  </div>
29
29
  </div>
@@ -58,26 +58,26 @@
58
58
  <b>Order</b>
59
59
  </div>
60
60
  <div class="lc_regular16">
61
- {{ order.shippingAddress.fullName }}
61
+ {{ fullName }}
62
62
  </div>
63
63
  <div
64
- v-if="order.shippingAddress.company"
64
+ v-if="company"
65
65
  class="lc_regular16">
66
- {{ order.shippingAddress.company }}
66
+ {{ company }}
67
67
  </div>
68
68
  <div
69
- v-if="order.shippingAddress.phone"
69
+ v-if="phone"
70
70
  class="lc_regular16">
71
- {{ order.shippingAddress.phone }}
71
+ {{ phone }}
72
72
  </div>
73
73
  <div class="lc_regular16">
74
- {{ order.shippingAddress.email }}
74
+ {{ email }}
75
75
  </div>
76
76
  <div class="lc_regular16">
77
77
  {{ orderAddress }}
78
78
  </div>
79
79
  <div class="lc_regular16">
80
- {{ order.additionalInfo }}
80
+ {{ additionalInfo }}
81
81
  </div>
82
82
  </td>
83
83
  <td
@@ -1,5 +1,6 @@
1
1
  import { mapGetters, mapActions, mapMutations } from 'vuex';
2
2
  import api from '@lancom/shared/assets/js/api';
3
+ import gtm from '@lancom/shared/assets/js/utils/gtm';
3
4
  import { price, shortDate, tax } from '@lancom/shared/assets/js/utils/filters';
4
5
  import { convertQuoteToOrder } from '@lancom/shared/assets/js/utils/quote';
5
6
 
@@ -35,6 +36,7 @@ export default {
35
36
  this.processing = true;
36
37
  this.order = await this.createOrder(option);
37
38
  this.setOrder(this.order);
39
+ gtm.purchase(this.order);
38
40
  this.clear();
39
41
  } catch (e) {
40
42
  const { message } = (e.response && e.response.data) || e;
@@ -40,6 +40,16 @@
40
40
  :simple-product="simpleProduct" />
41
41
  </div>
42
42
  <div class="QuoteProductColorSimpleProducts__totals">
43
+ <div
44
+ v-if="group.unitCosts.length === 1"
45
+ class="QuoteProductColorSimpleProducts__total mb-6">
46
+ <div class="lc_title-small">
47
+ Unit Cost:
48
+ </div>
49
+ <div class="lc_body-small">
50
+ {{ group.unitCosts[0] | price }}
51
+ </div>
52
+ </div>
43
53
  <div class="QuoteProductColorSimpleProducts__total">
44
54
  <div class="lc_title-small">
45
55
  Total Qty:
@@ -48,14 +58,14 @@
48
58
  {{ group.amount }}
49
59
  </div>
50
60
  </div>
51
- <!-- <div class="QuoteProductColorSimpleProducts__total mt-6">
61
+ <div class="QuoteProductColorSimpleProducts__total mt-6">
52
62
  <div class="lc_title-small">
53
- Total price:
63
+ Subtotal:
54
64
  </div>
55
65
  <div class="lc_body-small">
56
66
  {{ group.productsTotal | price }}
57
67
  </div>
58
- </div> -->
68
+ </div>
59
69
  </div>
60
70
  </div>
61
71
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lancom/shared",
3
- "version": "0.0.167",
3
+ "version": "0.0.169",
4
4
  "description": "lancom common scripts",
5
5
  "author": "e.tokovenko <e.tokovenko@gmail.com>",
6
6
  "repository": {
package/store/cart.js CHANGED
@@ -31,11 +31,11 @@ const getProductsQuantities = entities => {
31
31
  };
32
32
 
33
33
  const getPrintsQuantities = entities => {
34
- const printTypes = entities.reduce((types, e) => [...types, ...e.prints.map(({ printType }) => printType)], []);
35
- const grouped = groupBy(printTypes, '_id');
36
- const quantities = Object.keys(grouped).map(_id => {
37
- const [{ name, minQuantity }] = grouped[_id];
38
- const printTypeEntities = entities.filter(e => (e.prints || []).some(({ printType }) => printType?._id === _id));
34
+ const printTypes = entities.reduce((types, e) => [...types, ...e.prints.map(({ printType }) => ({ ...printType, guid: `${e.guid}-${printType._id}` }))], []);
35
+ const grouped = groupBy(printTypes, 'guid');
36
+ const quantities = Object.keys(grouped).map(guid => {
37
+ const [{ name, minQuantity }] = grouped[guid];
38
+ const printTypeEntities = entities.filter(e => (e.prints || []).some(({ printType }) => `${e.guid}-${printType?._id}` === guid));
39
39
  return { name, minQuantity, quantity: getEntitiesQuantity(printTypeEntities) };
40
40
  });
41
41
  return quantities;
package/store/order.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import Vue from 'vue';
2
2
  import api from '@lancom/shared/assets/js/api';
3
- import { populateProductsFields } from '@lancom/shared/assets/js/utils/order';
3
+ import { generateOrderData } from '@lancom/shared/assets/js/utils/order';
4
4
 
5
5
  export const state = () => ({
6
6
  orderData: null,
@@ -14,18 +14,8 @@ export const getters = {
14
14
 
15
15
  export const actions = {
16
16
  async createOrder({ commit }, data) {
17
- const { pricing, products, shop } = data;
18
- const order = { ...data, products: populateProductsFields(products, pricing) };
19
- if (pricing) {
20
- order.totalGST = pricing.totalPrice;
21
- order.total = pricing.totalPriceWithoutTax;
22
- order.couponTotal = pricing.coupon?.totalPrice || 0;
23
- order.couponCode = pricing.coupon?.code || null;
24
- order.productsTotal = pricing.products?.products?.totalPriceWithoutTax || 0;
25
- order.printsTotal = pricing.products?.prints?.totalPriceWithoutTax || 0;
26
- order.shippingTotal = pricing.shipping?.totalPriceWithoutTax || 0;
27
- order.suppliersWithRates = pricing.shipping?.suppliersWithRates || [];
28
- }
17
+ const { shop, products, pricing } = data;
18
+ const order = generateOrderData(data, products, pricing);
29
19
  const response = await api.createOrder(order, shop);
30
20
  commit('setOrderData', response);
31
21
  },