@zenky/storefront-vue 0.9.37 → 0.9.40
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/dist/cjs/index.js +1516 -26
- package/dist/esm/index.js +1469 -5
- package/dist/zenky.d.ts +9108 -3
- package/package.json +3 -2
package/dist/cjs/index.js
CHANGED
|
@@ -8,6 +8,7 @@ var api = require('@zenky/api');
|
|
|
8
8
|
var pinia = require('pinia');
|
|
9
9
|
var ui = require('@zenky/ui');
|
|
10
10
|
var events = require('@zenky/events');
|
|
11
|
+
var dateFns = require('date-fns');
|
|
11
12
|
var Pusher = require('pusher-js');
|
|
12
13
|
|
|
13
14
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -1556,6 +1557,1352 @@ function useOfferItem(errorHandler) {
|
|
|
1556
1557
|
}));
|
|
1557
1558
|
}
|
|
1558
1559
|
|
|
1560
|
+
function getUpdatedVariants(currentOrder, order) {
|
|
1561
|
+
var _a, _b;
|
|
1562
|
+
if (!((_a = order === null || order === void 0 ? void 0 : order.variants) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
1563
|
+
return [];
|
|
1564
|
+
}
|
|
1565
|
+
else if (!((_b = currentOrder === null || currentOrder === void 0 ? void 0 : currentOrder.variants) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
1566
|
+
return (order === null || order === void 0 ? void 0 : order.variants) || [];
|
|
1567
|
+
}
|
|
1568
|
+
let current = lodashEs.cloneDeep(currentOrder.variants);
|
|
1569
|
+
let currentVariants = [];
|
|
1570
|
+
const currentlyHasVariants = current && current.length > 0;
|
|
1571
|
+
if (currentlyHasVariants) {
|
|
1572
|
+
currentVariants = current.map((variant) => variant.uuid);
|
|
1573
|
+
}
|
|
1574
|
+
const actualVariantIds = order.variants.map((variant) => variant.uuid);
|
|
1575
|
+
const createdVariantIds = order.variants
|
|
1576
|
+
.filter((variant) => currentVariants.indexOf(variant.uuid) === -1)
|
|
1577
|
+
.map((variant) => variant.uuid);
|
|
1578
|
+
if (currentlyHasVariants) {
|
|
1579
|
+
current = current.filter((variant) => actualVariantIds.indexOf(variant.uuid) !== -1);
|
|
1580
|
+
}
|
|
1581
|
+
if (createdVariantIds.length > 0) {
|
|
1582
|
+
current = current || [];
|
|
1583
|
+
order.variants.filter((variant) => createdVariantIds.indexOf(variant.uuid) !== -1)
|
|
1584
|
+
.forEach((variant) => current.push(variant));
|
|
1585
|
+
}
|
|
1586
|
+
order.variants.forEach((variant) => {
|
|
1587
|
+
const index = current.findIndex((item) => item.uuid === variant.uuid);
|
|
1588
|
+
if (index === -1) {
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
current[index].quantity = variant.quantity;
|
|
1592
|
+
current[index].original_total_price = variant.original_total_price;
|
|
1593
|
+
current[index].total_price = variant.total_price;
|
|
1594
|
+
current[index].discount_difference = variant.discount_difference;
|
|
1595
|
+
current[index].has_discount = variant.has_discount;
|
|
1596
|
+
});
|
|
1597
|
+
return current;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
function initializeOrderCustomer(credentialsResolver) {
|
|
1601
|
+
events.useCustomerAuthenticated().subscribe('order.customer.initialize', async ({ customer }) => {
|
|
1602
|
+
const credentials = credentialsResolver();
|
|
1603
|
+
if (credentials === null) {
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
try {
|
|
1607
|
+
await api.setOrderCheckoutCustomer(credentials, {
|
|
1608
|
+
phone: {
|
|
1609
|
+
number: customer.phone.e164,
|
|
1610
|
+
country: customer.phone.country,
|
|
1611
|
+
},
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
catch (e) {
|
|
1615
|
+
console.error('[orders/customer] Unable to attach customer to order.', { e });
|
|
1616
|
+
}
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
const useOrderStore = pinia.defineStore({
|
|
1621
|
+
id: 'zenky:storefront:order',
|
|
1622
|
+
state: () => ({
|
|
1623
|
+
order: null,
|
|
1624
|
+
token: null,
|
|
1625
|
+
loading: false,
|
|
1626
|
+
inclusions: null,
|
|
1627
|
+
orderSettings: {
|
|
1628
|
+
loaded: false,
|
|
1629
|
+
loading: false,
|
|
1630
|
+
settings: null,
|
|
1631
|
+
},
|
|
1632
|
+
}),
|
|
1633
|
+
getters: {
|
|
1634
|
+
credentials() {
|
|
1635
|
+
if (!this.order || !this.order.id || this.token === null) {
|
|
1636
|
+
return null;
|
|
1637
|
+
}
|
|
1638
|
+
return {
|
|
1639
|
+
id: this.order.id,
|
|
1640
|
+
token: this.token,
|
|
1641
|
+
};
|
|
1642
|
+
},
|
|
1643
|
+
settings() {
|
|
1644
|
+
return this.orderSettings.settings;
|
|
1645
|
+
},
|
|
1646
|
+
settingsLoaded() {
|
|
1647
|
+
return this.orderSettings.loaded;
|
|
1648
|
+
},
|
|
1649
|
+
},
|
|
1650
|
+
actions: {
|
|
1651
|
+
async initialize(storeId, cityId, inclusions) {
|
|
1652
|
+
this.inclusions = inclusions;
|
|
1653
|
+
const storage = getStorage();
|
|
1654
|
+
const orderId = storage.get('order.id');
|
|
1655
|
+
const orderToken = storage.get('order.token');
|
|
1656
|
+
initializeOrderCustomer(() => this.credentials);
|
|
1657
|
+
this.loading = true;
|
|
1658
|
+
if (orderId && orderToken) {
|
|
1659
|
+
return this.load(storeId, cityId, orderId, orderToken);
|
|
1660
|
+
}
|
|
1661
|
+
return this.create(storeId, cityId);
|
|
1662
|
+
},
|
|
1663
|
+
async load(storeId, cityId, orderId, token) {
|
|
1664
|
+
var _a, _b, _c;
|
|
1665
|
+
const { item, load } = useOrderItem();
|
|
1666
|
+
await load({ id: orderId, token }, this.inclusions !== null ? { with: this.inclusions.order } : {});
|
|
1667
|
+
if (((_c = (_b = (_a = item.value) === null || _a === void 0 ? void 0 : _a.current_status) === null || _b === void 0 ? void 0 : _b.status) === null || _c === void 0 ? void 0 : _c.kind.id) === 'pending') {
|
|
1668
|
+
this.order = item.value;
|
|
1669
|
+
this.token = item.value.token;
|
|
1670
|
+
this.loading = false;
|
|
1671
|
+
events.useOrderLoaded().publish(this.order);
|
|
1672
|
+
await this.loadSettings();
|
|
1673
|
+
return true;
|
|
1674
|
+
}
|
|
1675
|
+
return this.create(storeId, cityId);
|
|
1676
|
+
},
|
|
1677
|
+
async loadSettings() {
|
|
1678
|
+
if (this.orderSettings.loading) {
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
else if (!this.credentials || !this.order || !this.order.city_id) {
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
this.orderSettings.loading = true;
|
|
1685
|
+
try {
|
|
1686
|
+
this.orderSettings.settings = await api.getOrderSettings(this.credentials, this.order.city_id);
|
|
1687
|
+
}
|
|
1688
|
+
catch (e) {
|
|
1689
|
+
console.error('[storefront/order] Unable to load order settings.', { e });
|
|
1690
|
+
}
|
|
1691
|
+
finally {
|
|
1692
|
+
this.orderSettings.loading = false;
|
|
1693
|
+
this.orderSettings.loaded = true;
|
|
1694
|
+
}
|
|
1695
|
+
},
|
|
1696
|
+
async create(storeId, cityId) {
|
|
1697
|
+
try {
|
|
1698
|
+
const order = await api.createOrder({ city_id: cityId });
|
|
1699
|
+
const storage = getStorage();
|
|
1700
|
+
storage.set('order.id', order.id);
|
|
1701
|
+
storage.set('order.token', order.token);
|
|
1702
|
+
return await this.load(storeId, cityId, order.id, order.token);
|
|
1703
|
+
}
|
|
1704
|
+
catch (e) {
|
|
1705
|
+
ui.useNotification('error', 'Ошибка инициализации заказа', 'Не удалось инициализировать заказ. Обновите страницу.');
|
|
1706
|
+
}
|
|
1707
|
+
return false;
|
|
1708
|
+
},
|
|
1709
|
+
reset() {
|
|
1710
|
+
const storage = getStorage();
|
|
1711
|
+
storage.delete('order.id');
|
|
1712
|
+
storage.delete('order.token');
|
|
1713
|
+
},
|
|
1714
|
+
async add(productVariantId, quantity, modifiers = [], promotion = null) {
|
|
1715
|
+
if (!this.credentials) {
|
|
1716
|
+
throw new Error('Order is not yet initialized.');
|
|
1717
|
+
}
|
|
1718
|
+
try {
|
|
1719
|
+
const params = {
|
|
1720
|
+
quantity,
|
|
1721
|
+
modifiers,
|
|
1722
|
+
product_variant_id: productVariantId,
|
|
1723
|
+
};
|
|
1724
|
+
if (promotion && promotion.id && promotion.reward_id) {
|
|
1725
|
+
params.promotion_id = promotion.id;
|
|
1726
|
+
params.promotion_reward_id = promotion.reward_id;
|
|
1727
|
+
}
|
|
1728
|
+
const order = await api.addOrderProductVariant(this.credentials, params, this.inclusions !== null ? { with: this.inclusions.product } : {});
|
|
1729
|
+
events.useProductQuantityIncreased().publish({
|
|
1730
|
+
order,
|
|
1731
|
+
productVariantId,
|
|
1732
|
+
quantity,
|
|
1733
|
+
modifiers,
|
|
1734
|
+
promotion,
|
|
1735
|
+
});
|
|
1736
|
+
this.update(order);
|
|
1737
|
+
return true;
|
|
1738
|
+
}
|
|
1739
|
+
catch (e) {
|
|
1740
|
+
ui.useNotification('error', 'Товар не добавлен', api.getApiErrorMessage(e, 'Не удалось добавить товар в корзину. Повторите попытку'));
|
|
1741
|
+
}
|
|
1742
|
+
return false;
|
|
1743
|
+
},
|
|
1744
|
+
async remove(productVariantId, quantity, modifiers = [], promotion = null) {
|
|
1745
|
+
if (!this.credentials) {
|
|
1746
|
+
throw new Error('Order is not yet initialized.');
|
|
1747
|
+
}
|
|
1748
|
+
try {
|
|
1749
|
+
const params = {
|
|
1750
|
+
quantity,
|
|
1751
|
+
modifiers,
|
|
1752
|
+
product_variant_id: productVariantId,
|
|
1753
|
+
};
|
|
1754
|
+
if (promotion && promotion.id && promotion.reward_id) {
|
|
1755
|
+
params.promotion_id = promotion.id;
|
|
1756
|
+
params.promotion_reward_id = promotion.reward_id;
|
|
1757
|
+
}
|
|
1758
|
+
const order = await api.removeOrderProductVariant(this.credentials, params, this.inclusions !== null ? { with: this.inclusions.product } : {});
|
|
1759
|
+
events.useProductQuantityDecreased().publish({
|
|
1760
|
+
order,
|
|
1761
|
+
productVariantId,
|
|
1762
|
+
quantity,
|
|
1763
|
+
modifiers,
|
|
1764
|
+
promotion,
|
|
1765
|
+
});
|
|
1766
|
+
this.update(order);
|
|
1767
|
+
return true;
|
|
1768
|
+
}
|
|
1769
|
+
catch (e) {
|
|
1770
|
+
ui.useNotification('error', 'Товар не удалён', api.getApiErrorMessage(e, 'Не удалось удалить товар из корзины. Повторите попытку'));
|
|
1771
|
+
}
|
|
1772
|
+
return false;
|
|
1773
|
+
},
|
|
1774
|
+
update(order) {
|
|
1775
|
+
if (this.order === null) {
|
|
1776
|
+
this.order = order;
|
|
1777
|
+
return;
|
|
1778
|
+
}
|
|
1779
|
+
this.order.total_price = order.total_price;
|
|
1780
|
+
this.order.original_total_price = order.original_total_price;
|
|
1781
|
+
this.order.discount_difference = order.discount_difference;
|
|
1782
|
+
this.order.has_discount = order.has_discount;
|
|
1783
|
+
this.order.variants = getUpdatedVariants(this.order, order);
|
|
1784
|
+
},
|
|
1785
|
+
async recreate(storeId, cityId, inclusions = null) {
|
|
1786
|
+
this.reset();
|
|
1787
|
+
if (!this.inclusions && inclusions) {
|
|
1788
|
+
this.inclusions = inclusions;
|
|
1789
|
+
}
|
|
1790
|
+
this.loading = true;
|
|
1791
|
+
return this.create(storeId, cityId);
|
|
1792
|
+
},
|
|
1793
|
+
},
|
|
1794
|
+
});
|
|
1795
|
+
|
|
1796
|
+
function useStageDetectors(order) {
|
|
1797
|
+
const hasCustomer = () => !!order.customer && !!order.customer.id;
|
|
1798
|
+
const hasDelivery = () => {
|
|
1799
|
+
var _a;
|
|
1800
|
+
if (['pickup', 'on_premise'].indexOf(order.delivery_method.id) > -1) {
|
|
1801
|
+
return !!order.stock && !!order.stock.id;
|
|
1802
|
+
}
|
|
1803
|
+
return !!(order === null || order === void 0 ? void 0 : order.delivery_address) && !!((_a = order === null || order === void 0 ? void 0 : order.delivery_address) === null || _a === void 0 ? void 0 : _a.id);
|
|
1804
|
+
};
|
|
1805
|
+
return {
|
|
1806
|
+
hasCustomer,
|
|
1807
|
+
hasDelivery,
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
exports.CheckoutStage = void 0;
|
|
1811
|
+
(function (CheckoutStage) {
|
|
1812
|
+
CheckoutStage["Customer"] = "customer";
|
|
1813
|
+
CheckoutStage["Delivery"] = "delivery";
|
|
1814
|
+
CheckoutStage["Payments"] = "payments";
|
|
1815
|
+
CheckoutStage["Summary"] = "summary";
|
|
1816
|
+
})(exports.CheckoutStage || (exports.CheckoutStage = {}));
|
|
1817
|
+
function useOrderCheckout() {
|
|
1818
|
+
const currentStage = vue.ref(exports.CheckoutStage.Customer);
|
|
1819
|
+
const stages = vue.ref({
|
|
1820
|
+
[exports.CheckoutStage.Customer]: {
|
|
1821
|
+
active: false,
|
|
1822
|
+
completed: false,
|
|
1823
|
+
},
|
|
1824
|
+
[exports.CheckoutStage.Delivery]: {
|
|
1825
|
+
active: false,
|
|
1826
|
+
completed: false,
|
|
1827
|
+
},
|
|
1828
|
+
[exports.CheckoutStage.Payments]: {
|
|
1829
|
+
active: false,
|
|
1830
|
+
completed: false,
|
|
1831
|
+
},
|
|
1832
|
+
[exports.CheckoutStage.Summary]: {
|
|
1833
|
+
active: false,
|
|
1834
|
+
completed: false,
|
|
1835
|
+
},
|
|
1836
|
+
});
|
|
1837
|
+
const { order, settingsLoaded } = pinia.storeToRefs(useOrderStore());
|
|
1838
|
+
const { loaded: customerLoaded } = pinia.storeToRefs(useCustomerStore());
|
|
1839
|
+
const ready = vue.computed(() => {
|
|
1840
|
+
if (!order.value || !order.value.id || !order.value.token) {
|
|
1841
|
+
return false;
|
|
1842
|
+
}
|
|
1843
|
+
else if (!customerLoaded.value) {
|
|
1844
|
+
return false;
|
|
1845
|
+
}
|
|
1846
|
+
else if (!settingsLoaded.value) {
|
|
1847
|
+
return false;
|
|
1848
|
+
}
|
|
1849
|
+
return true;
|
|
1850
|
+
});
|
|
1851
|
+
const setStage = (newStage) => {
|
|
1852
|
+
currentStage.value = newStage;
|
|
1853
|
+
Object.keys(stages.value).forEach((key) => {
|
|
1854
|
+
stages.value[key].active = false;
|
|
1855
|
+
stages.value[key].completed = false;
|
|
1856
|
+
});
|
|
1857
|
+
stages.value[newStage].active = true;
|
|
1858
|
+
switch (newStage) {
|
|
1859
|
+
case exports.CheckoutStage.Customer:
|
|
1860
|
+
break;
|
|
1861
|
+
case exports.CheckoutStage.Delivery:
|
|
1862
|
+
stages.value.customer.completed = true;
|
|
1863
|
+
break;
|
|
1864
|
+
case exports.CheckoutStage.Payments:
|
|
1865
|
+
stages.value.customer.completed = true;
|
|
1866
|
+
stages.value.delivery.completed = true;
|
|
1867
|
+
break;
|
|
1868
|
+
case exports.CheckoutStage.Summary:
|
|
1869
|
+
stages.value.customer.completed = true;
|
|
1870
|
+
stages.value.delivery.completed = true;
|
|
1871
|
+
stages.value.payments.completed = true;
|
|
1872
|
+
break;
|
|
1873
|
+
default:
|
|
1874
|
+
console.error(`[checkout] Unknown stage provided: "${newStage}", resetting to customer stage.`);
|
|
1875
|
+
stages.value.customer.completed = false;
|
|
1876
|
+
stages.value.delivery.completed = false;
|
|
1877
|
+
stages.value.payments.completed = false;
|
|
1878
|
+
break;
|
|
1879
|
+
}
|
|
1880
|
+
};
|
|
1881
|
+
vue.watch(ready, () => {
|
|
1882
|
+
if (!ready.value || order.value === null) {
|
|
1883
|
+
return setStage(exports.CheckoutStage.Customer);
|
|
1884
|
+
}
|
|
1885
|
+
const detectors = useStageDetectors(order.value);
|
|
1886
|
+
if (!detectors.hasCustomer()) {
|
|
1887
|
+
return setStage(exports.CheckoutStage.Customer);
|
|
1888
|
+
}
|
|
1889
|
+
else if (!detectors.hasDelivery()) {
|
|
1890
|
+
return setStage(exports.CheckoutStage.Delivery);
|
|
1891
|
+
}
|
|
1892
|
+
return setStage(exports.CheckoutStage.Payments);
|
|
1893
|
+
}, { immediate: true });
|
|
1894
|
+
return {
|
|
1895
|
+
ready,
|
|
1896
|
+
order,
|
|
1897
|
+
stages,
|
|
1898
|
+
currentStage,
|
|
1899
|
+
setStage,
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
function useCheckoutConfirmation(order) {
|
|
1904
|
+
const form = vue.ref({ code: '' });
|
|
1905
|
+
const confirming = vue.ref(false);
|
|
1906
|
+
const resending = vue.ref(false);
|
|
1907
|
+
const credentials = vue.computed(() => ({
|
|
1908
|
+
id: order.value.id,
|
|
1909
|
+
token: order.value.token,
|
|
1910
|
+
}));
|
|
1911
|
+
const confirm = async () => {
|
|
1912
|
+
if (confirming.value) {
|
|
1913
|
+
return null;
|
|
1914
|
+
}
|
|
1915
|
+
else if (!form.value.code) {
|
|
1916
|
+
ui.useNotification('error', 'Ошибка', 'Нужно указать код из SMS.');
|
|
1917
|
+
return null;
|
|
1918
|
+
}
|
|
1919
|
+
confirming.value = true;
|
|
1920
|
+
try {
|
|
1921
|
+
return await api.confirmOrder(credentials.value, form.value);
|
|
1922
|
+
}
|
|
1923
|
+
catch (e) {
|
|
1924
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось подтвердить заказ.'));
|
|
1925
|
+
}
|
|
1926
|
+
finally {
|
|
1927
|
+
confirming.value = false;
|
|
1928
|
+
}
|
|
1929
|
+
return null;
|
|
1930
|
+
};
|
|
1931
|
+
const resendCode = async () => {
|
|
1932
|
+
if (resending.value) {
|
|
1933
|
+
return;
|
|
1934
|
+
}
|
|
1935
|
+
resending.value = true;
|
|
1936
|
+
try {
|
|
1937
|
+
const result = await api.resendOrderConfirmationCode(credentials.value);
|
|
1938
|
+
if (result.success) {
|
|
1939
|
+
ui.useNotification('success', 'Код выслан', 'Код был повторно выслан на ваш телефон.');
|
|
1940
|
+
}
|
|
1941
|
+
else {
|
|
1942
|
+
ui.useNotification('error', 'Ошибка', 'Не удалось выслать код подтверждения. Повторите попытку позднее.');
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
catch (e) {
|
|
1946
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось выслать код подтверждения.'));
|
|
1947
|
+
}
|
|
1948
|
+
finally {
|
|
1949
|
+
resending.value = false;
|
|
1950
|
+
}
|
|
1951
|
+
};
|
|
1952
|
+
return {
|
|
1953
|
+
form,
|
|
1954
|
+
confirming,
|
|
1955
|
+
confirm,
|
|
1956
|
+
resending,
|
|
1957
|
+
resendCode,
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
function useCustomerCheckoutForm(emit) {
|
|
1962
|
+
var _a;
|
|
1963
|
+
const ready = vue.ref(false);
|
|
1964
|
+
const saving = vue.ref(false);
|
|
1965
|
+
const form = vue.ref({
|
|
1966
|
+
phone: {
|
|
1967
|
+
number: '',
|
|
1968
|
+
country: 'RU',
|
|
1969
|
+
},
|
|
1970
|
+
first_name: '',
|
|
1971
|
+
last_name: '',
|
|
1972
|
+
});
|
|
1973
|
+
const { customer } = pinia.storeToRefs(useCustomerStore());
|
|
1974
|
+
const { order, credentials } = pinia.storeToRefs(useOrderStore());
|
|
1975
|
+
if (((_a = order.value) === null || _a === void 0 ? void 0 : _a.customer) && order.value.customer.id) {
|
|
1976
|
+
form.value.phone.number = order.value.customer.phone.national;
|
|
1977
|
+
form.value.phone.country = order.value.customer.phone.country;
|
|
1978
|
+
form.value.first_name = order.value.customer.first_name || '';
|
|
1979
|
+
form.value.last_name = order.value.customer.last_name || '';
|
|
1980
|
+
}
|
|
1981
|
+
else if (customer.value && customer.value.id) {
|
|
1982
|
+
form.value.phone.number = customer.value.phone.national;
|
|
1983
|
+
form.value.phone.country = customer.value.phone.country;
|
|
1984
|
+
form.value.first_name = customer.value.first_name || '';
|
|
1985
|
+
form.value.last_name = customer.value.last_name || '';
|
|
1986
|
+
}
|
|
1987
|
+
const save = async () => {
|
|
1988
|
+
if (!credentials.value) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
else if (saving.value) {
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
else if (!form.value.phone.number || !form.value.phone.country) {
|
|
1995
|
+
ui.useNotification('error', 'Ошибка', 'Нужно указать номер телефона.');
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
else if (!form.value.first_name) {
|
|
1999
|
+
ui.useNotification('error', 'Ошибка', 'Нужно указать имя.');
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
saving.value = true;
|
|
2003
|
+
try {
|
|
2004
|
+
await api.setOrderCheckoutCustomer(credentials.value, form.value);
|
|
2005
|
+
emit('completed');
|
|
2006
|
+
}
|
|
2007
|
+
catch (e) {
|
|
2008
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось сохранить контактные данные.'));
|
|
2009
|
+
}
|
|
2010
|
+
finally {
|
|
2011
|
+
saving.value = false;
|
|
2012
|
+
}
|
|
2013
|
+
};
|
|
2014
|
+
return {
|
|
2015
|
+
ready,
|
|
2016
|
+
saving,
|
|
2017
|
+
customer,
|
|
2018
|
+
form,
|
|
2019
|
+
save,
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
function useTotalPrice() {
|
|
2024
|
+
const { order } = pinia.storeToRefs(useOrderStore());
|
|
2025
|
+
return {
|
|
2026
|
+
totalPrice: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.total_price; }),
|
|
2027
|
+
originalTotalPrice: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.original_total_price; }),
|
|
2028
|
+
hasDiscount: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.has_discount; }),
|
|
2029
|
+
discountDifference: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.discount_difference; }),
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
function useTotalQuantity() {
|
|
2033
|
+
const { order } = pinia.storeToRefs(useOrderStore());
|
|
2034
|
+
const quantity = vue.computed(() => {
|
|
2035
|
+
var _a;
|
|
2036
|
+
if (!order.value) {
|
|
2037
|
+
return 0;
|
|
2038
|
+
}
|
|
2039
|
+
return (((_a = order.value) === null || _a === void 0 ? void 0 : _a.variants) || [])
|
|
2040
|
+
.map((variant) => variant.quantity)
|
|
2041
|
+
.reduce((variantQuantity, total) => variantQuantity + total, 0);
|
|
2042
|
+
});
|
|
2043
|
+
return {
|
|
2044
|
+
order,
|
|
2045
|
+
quantity,
|
|
2046
|
+
};
|
|
2047
|
+
}
|
|
2048
|
+
function useOrderVariants() {
|
|
2049
|
+
const { order } = pinia.storeToRefs(useOrderStore());
|
|
2050
|
+
const variants = vue.computed(() => {
|
|
2051
|
+
if (!order.value || !order.value.variants || !order.value.variants.length) {
|
|
2052
|
+
return [];
|
|
2053
|
+
}
|
|
2054
|
+
return order.value.variants;
|
|
2055
|
+
});
|
|
2056
|
+
return {
|
|
2057
|
+
variants,
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
const useVariantControls = (variant, modifiers, modifiersHash, promotion) => {
|
|
2061
|
+
const { order } = pinia.storeToRefs(useOrderStore());
|
|
2062
|
+
const { add: addVariant, remove: removeVariant } = useOrderStore();
|
|
2063
|
+
const loading = vue.ref(false);
|
|
2064
|
+
const operation = vue.ref(null);
|
|
2065
|
+
const orderVariant = vue.computed(() => {
|
|
2066
|
+
var _a, _b;
|
|
2067
|
+
if (!((_b = (_a = order.value) === null || _a === void 0 ? void 0 : _a.variants) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
2068
|
+
return null;
|
|
2069
|
+
}
|
|
2070
|
+
return order.value.variants.find((item) => {
|
|
2071
|
+
if (item.product_variant_id !== variant.value.id || item.modifiers_hash !== modifiersHash.value) {
|
|
2072
|
+
return false;
|
|
2073
|
+
}
|
|
2074
|
+
else if (promotion.value === null) {
|
|
2075
|
+
return item.promotion_id === null;
|
|
2076
|
+
}
|
|
2077
|
+
return item.promotion_id === promotion.value.id && item.promotion_reward_id === promotion.value.reward_id;
|
|
2078
|
+
});
|
|
2079
|
+
});
|
|
2080
|
+
const totalQuantity = vue.computed(() => (orderVariant.value ? orderVariant.value.quantity : 0));
|
|
2081
|
+
const quantityModel = vue.ref(totalQuantity.value);
|
|
2082
|
+
const updateVariant = async (type, quantity) => {
|
|
2083
|
+
if (loading.value) {
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
loading.value = true;
|
|
2087
|
+
operation.value = type;
|
|
2088
|
+
let result;
|
|
2089
|
+
if (type === 'add') {
|
|
2090
|
+
result = await addVariant(variant.value.id, quantity, modifiers.value, promotion.value);
|
|
2091
|
+
}
|
|
2092
|
+
else {
|
|
2093
|
+
result = await removeVariant(variant.value.id, quantity, modifiers.value, promotion.value);
|
|
2094
|
+
ui.useNotification('success', 'Товар удалён', `Товар${variant.value.name ? ` «${variant.value.name}»` : ''} удалён из корзины!`);
|
|
2095
|
+
}
|
|
2096
|
+
if (result) {
|
|
2097
|
+
ui.useNotification('success', `Товар ${type === 'add' ? 'добавлен' : 'удалён'}`, `Товар${variant.value.name ? ` «${variant.value.name}»` : ''} ${type === 'add' ? 'добавлен в корзину' : 'удалён из корзины'}!`);
|
|
2098
|
+
}
|
|
2099
|
+
loading.value = false;
|
|
2100
|
+
};
|
|
2101
|
+
const add = async () => updateVariant('add', 1);
|
|
2102
|
+
const remove = async () => updateVariant('remove', totalQuantity.value);
|
|
2103
|
+
const getQuantity = (value) => {
|
|
2104
|
+
if (typeof value === 'string') {
|
|
2105
|
+
return parseInt(value, 10);
|
|
2106
|
+
}
|
|
2107
|
+
return value;
|
|
2108
|
+
};
|
|
2109
|
+
const increase = async (quantity = 1) => {
|
|
2110
|
+
quantityModel.value = getQuantity(quantityModel.value) + quantity;
|
|
2111
|
+
};
|
|
2112
|
+
const decrease = async (quantity = 1) => {
|
|
2113
|
+
quantityModel.value = Math.max(0, getQuantity(quantityModel.value) - quantity);
|
|
2114
|
+
};
|
|
2115
|
+
vue.watch(totalQuantity, () => {
|
|
2116
|
+
quantityModel.value = totalQuantity.value;
|
|
2117
|
+
});
|
|
2118
|
+
vue.watch(quantityModel, lodashEs.debounce(async (val) => {
|
|
2119
|
+
const difference = getQuantity(val) - totalQuantity.value;
|
|
2120
|
+
if (difference < 0) {
|
|
2121
|
+
await updateVariant('remove', Math.abs(difference));
|
|
2122
|
+
}
|
|
2123
|
+
else if (difference > 0) {
|
|
2124
|
+
await updateVariant('add', difference);
|
|
2125
|
+
}
|
|
2126
|
+
}, 1000));
|
|
2127
|
+
return {
|
|
2128
|
+
orderVariant,
|
|
2129
|
+
totalQuantity,
|
|
2130
|
+
quantityModel,
|
|
2131
|
+
add,
|
|
2132
|
+
increase,
|
|
2133
|
+
decrease,
|
|
2134
|
+
remove,
|
|
2135
|
+
loading,
|
|
2136
|
+
operation,
|
|
2137
|
+
};
|
|
2138
|
+
};
|
|
2139
|
+
|
|
2140
|
+
function getDeliveryMethod(order, settings) {
|
|
2141
|
+
if (!order.value || !settings.value) {
|
|
2142
|
+
return 'delivery';
|
|
2143
|
+
}
|
|
2144
|
+
const methods = settings.value.delivery_methods.map((method) => method.id);
|
|
2145
|
+
if (methods.indexOf(order.value.delivery_method.id) !== -1) {
|
|
2146
|
+
return order.value.delivery_method.id;
|
|
2147
|
+
}
|
|
2148
|
+
return methods[0];
|
|
2149
|
+
}
|
|
2150
|
+
function getStockId(order, stocks) {
|
|
2151
|
+
const availableStocks = stocks.value.map((stock) => stock.id);
|
|
2152
|
+
if (order.value && order.value.stock_id !== null && availableStocks.indexOf(order.value.stock_id) !== -1) {
|
|
2153
|
+
return order.value.stock_id;
|
|
2154
|
+
}
|
|
2155
|
+
return availableStocks[0];
|
|
2156
|
+
}
|
|
2157
|
+
function useCustomerAddresses(customer) {
|
|
2158
|
+
const addresses = vue.ref([]);
|
|
2159
|
+
const loaded = vue.ref(false);
|
|
2160
|
+
if (!customer.value || !customer.value.id) {
|
|
2161
|
+
loaded.value = true;
|
|
2162
|
+
}
|
|
2163
|
+
else {
|
|
2164
|
+
api.getCustomerAddresses({ count: 100 }).then((response) => {
|
|
2165
|
+
addresses.value = response.items;
|
|
2166
|
+
loaded.value = true;
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
return {
|
|
2170
|
+
addresses,
|
|
2171
|
+
loaded,
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
function getDeliveryPayload(form, addressesResolver) {
|
|
2175
|
+
const data = { delivery_method: form.method };
|
|
2176
|
+
const errors = [];
|
|
2177
|
+
if (form.method === 'pickup') {
|
|
2178
|
+
if (form.pickup.stock_id) {
|
|
2179
|
+
data.stock_id = form.pickup.stock_id;
|
|
2180
|
+
}
|
|
2181
|
+
else {
|
|
2182
|
+
errors.push('Нужно выбрать точку самовывоза.');
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
else if (form.method === 'on_premise') {
|
|
2186
|
+
if (form.on_premise.stock_id) {
|
|
2187
|
+
data.stock_id = form.on_premise.stock_id;
|
|
2188
|
+
}
|
|
2189
|
+
else {
|
|
2190
|
+
errors.push('Нужно выбрать точку самовывоза.');
|
|
2191
|
+
}
|
|
2192
|
+
if (form.on_premise.table) {
|
|
2193
|
+
data.on_premise = { table: form.on_premise.table };
|
|
2194
|
+
}
|
|
2195
|
+
else {
|
|
2196
|
+
errors.push('Нужно указать номер стола.');
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
else if (form.method === 'delivery') {
|
|
2200
|
+
if (form.delivery.address.id) {
|
|
2201
|
+
data.delivery_address = { id: form.delivery.address.id };
|
|
2202
|
+
}
|
|
2203
|
+
else {
|
|
2204
|
+
const { errors: addressErrors, data: address } = useAddressFormValue(form.delivery.address, addressesResolver);
|
|
2205
|
+
if (addressErrors.length > 0) {
|
|
2206
|
+
errors.push(addressErrors[0]);
|
|
2207
|
+
}
|
|
2208
|
+
else {
|
|
2209
|
+
data.delivery_address = address;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
if (form.deliver_at.mode === 'select' && form.deliver_at.date) {
|
|
2214
|
+
data.deliver_at = dateFns.format(Date.parse(form.deliver_at.date), 'yyyy-MM-dd HH:mm');
|
|
2215
|
+
}
|
|
2216
|
+
return {
|
|
2217
|
+
data,
|
|
2218
|
+
errors,
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
function useDeliveryCheckoutForm(emit) {
|
|
2222
|
+
var _a, _b, _c, _d;
|
|
2223
|
+
const { credentials, order, settings } = pinia.storeToRefs(useOrderStore());
|
|
2224
|
+
const { customer } = pinia.storeToRefs(useCustomerStore());
|
|
2225
|
+
const { stocks, addressesResolver } = pinia.storeToRefs(useStoreStore());
|
|
2226
|
+
const { addresses, loaded } = useCustomerAddresses(customer);
|
|
2227
|
+
const { totalPrice } = useTotalPrice();
|
|
2228
|
+
const ready = vue.computed(() => loaded.value);
|
|
2229
|
+
const currentAddress = vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.delivery_address; });
|
|
2230
|
+
const saving = vue.ref(false);
|
|
2231
|
+
const form = vue.ref({
|
|
2232
|
+
method: getDeliveryMethod(order, settings),
|
|
2233
|
+
delivery: {
|
|
2234
|
+
address: getAddressForm(),
|
|
2235
|
+
},
|
|
2236
|
+
pickup: {
|
|
2237
|
+
stock_id: getStockId(order, stocks),
|
|
2238
|
+
},
|
|
2239
|
+
on_premise: {
|
|
2240
|
+
stock_id: getStockId(order, stocks),
|
|
2241
|
+
table: '',
|
|
2242
|
+
},
|
|
2243
|
+
deliver_at: {
|
|
2244
|
+
mode: 'asap',
|
|
2245
|
+
date: '',
|
|
2246
|
+
},
|
|
2247
|
+
});
|
|
2248
|
+
form.value.delivery.address.id = ((_b = (_a = order.value) === null || _a === void 0 ? void 0 : _a.delivery_address) === null || _b === void 0 ? void 0 : _b.id) || '';
|
|
2249
|
+
if ((_d = (_c = order.value) === null || _c === void 0 ? void 0 : _c.deliver_at_local) === null || _d === void 0 ? void 0 : _d.datetime) {
|
|
2250
|
+
form.value.deliver_at.mode = 'select';
|
|
2251
|
+
form.value.deliver_at.date = dateFns.format(Date.parse(order.value.deliver_at_local.iso), 'yyyy-MM-dd HH:mm');
|
|
2252
|
+
}
|
|
2253
|
+
const priceIsNotEnough = vue.computed(() => {
|
|
2254
|
+
var _a, _b;
|
|
2255
|
+
const method = (_a = settings.value) === null || _a === void 0 ? void 0 : _a.delivery_methods.find((item) => item.id === form.value.method);
|
|
2256
|
+
if (!method || !method.min_price || !method.min_price.value) {
|
|
2257
|
+
return false;
|
|
2258
|
+
}
|
|
2259
|
+
return method.min_price.value > (((_b = totalPrice.value) === null || _b === void 0 ? void 0 : _b.value) || 0);
|
|
2260
|
+
});
|
|
2261
|
+
const save = async () => {
|
|
2262
|
+
if (!credentials.value || !addressesResolver.value) {
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
else if (saving.value) {
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
const { data, errors } = getDeliveryPayload(form.value, addressesResolver.value);
|
|
2269
|
+
if (errors.length > 0) {
|
|
2270
|
+
ui.useNotification('error', 'Ошибка', errors[0]);
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
saving.value = true;
|
|
2274
|
+
try {
|
|
2275
|
+
await api.setOrderCheckoutDelivery(credentials.value, data);
|
|
2276
|
+
emit('completed');
|
|
2277
|
+
}
|
|
2278
|
+
catch (e) {
|
|
2279
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось сохранить способ доставки.'));
|
|
2280
|
+
}
|
|
2281
|
+
finally {
|
|
2282
|
+
saving.value = false;
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2285
|
+
return {
|
|
2286
|
+
ready,
|
|
2287
|
+
form,
|
|
2288
|
+
addresses,
|
|
2289
|
+
currentAddress,
|
|
2290
|
+
addressesResolver,
|
|
2291
|
+
priceIsNotEnough,
|
|
2292
|
+
saving,
|
|
2293
|
+
save,
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
function getPaymentMethod(settings) {
|
|
2298
|
+
if (!settings.value) {
|
|
2299
|
+
return 'cash';
|
|
2300
|
+
}
|
|
2301
|
+
const available = settings.value.payment_methods.map((method) => method.id);
|
|
2302
|
+
return available[0];
|
|
2303
|
+
}
|
|
2304
|
+
function useBillSuggestions(unpaidAmount, staticAmounts = [10, 50, 200, 5000], availableBills = [100, 500, 1000]) {
|
|
2305
|
+
const { totalPrice } = useTotalPrice();
|
|
2306
|
+
const getClosestMultipleOf = (price, amount) => Math.ceil(price / amount) * amount;
|
|
2307
|
+
const suggestions = vue.computed(() => {
|
|
2308
|
+
const items = new Set([
|
|
2309
|
+
...staticAmounts,
|
|
2310
|
+
...availableBills.map((billItem) => getClosestMultipleOf(unpaidAmount.value, billItem)),
|
|
2311
|
+
unpaidAmount.value,
|
|
2312
|
+
]);
|
|
2313
|
+
const bills = [...items]
|
|
2314
|
+
.filter((suggestion) => suggestion > unpaidAmount.value)
|
|
2315
|
+
.sort((first, second) => (first - second))
|
|
2316
|
+
.map((amount) => {
|
|
2317
|
+
var _a, _b;
|
|
2318
|
+
return ({
|
|
2319
|
+
value: amount,
|
|
2320
|
+
label: `${(_a = totalPrice.value) === null || _a === void 0 ? void 0 : _a.currency.prefix}${amount}${(_b = totalPrice.value) === null || _b === void 0 ? void 0 : _b.currency.suffix}`,
|
|
2321
|
+
});
|
|
2322
|
+
});
|
|
2323
|
+
bills.unshift({
|
|
2324
|
+
label: 'Без сдачи',
|
|
2325
|
+
value: '',
|
|
2326
|
+
});
|
|
2327
|
+
bills.push({
|
|
2328
|
+
label: 'Другая',
|
|
2329
|
+
value: 'custom',
|
|
2330
|
+
});
|
|
2331
|
+
return bills;
|
|
2332
|
+
});
|
|
2333
|
+
return {
|
|
2334
|
+
suggestions,
|
|
2335
|
+
};
|
|
2336
|
+
}
|
|
2337
|
+
function useBonusesPreviewChecker(order, credentials, bonuses, setBonuses) {
|
|
2338
|
+
var _a;
|
|
2339
|
+
const bonusesAreChecking = vue.ref(false);
|
|
2340
|
+
const unpaidAmount = vue.ref((_a = order.value) === null || _a === void 0 ? void 0 : _a.total_price);
|
|
2341
|
+
const bonusesChecker = async () => {
|
|
2342
|
+
var _a;
|
|
2343
|
+
if (!credentials.value) {
|
|
2344
|
+
return;
|
|
2345
|
+
}
|
|
2346
|
+
else if (bonusesAreChecking.value) {
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
else if (!bonuses.value) {
|
|
2350
|
+
unpaidAmount.value = (_a = order.value) === null || _a === void 0 ? void 0 : _a.total_price;
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
bonusesAreChecking.value = true;
|
|
2354
|
+
try {
|
|
2355
|
+
const preview = await api.getOrderBonusesPaymentPreview(credentials.value, bonuses.value);
|
|
2356
|
+
unpaidAmount.value = preview.unpaid;
|
|
2357
|
+
if (parseFloat(bonuses.value) > parseFloat(preview.bonuses.trimmed)) {
|
|
2358
|
+
setBonuses(preview.bonuses.trimmed);
|
|
2359
|
+
ui.useNotification('warning', 'Сумма бонусов изменена', 'Вы указали сумму бонусов, превышающую лимит списания. Мы изменили сумму на максимально доступную.');
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
catch (e) {
|
|
2363
|
+
//
|
|
2364
|
+
}
|
|
2365
|
+
finally {
|
|
2366
|
+
bonusesAreChecking.value = false;
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
vue.watch(bonuses, lodashEs.debounce(async () => bonusesChecker(), 1000));
|
|
2370
|
+
return {
|
|
2371
|
+
unpaidAmount,
|
|
2372
|
+
bonusesAreChecking,
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
function getPaymentsPayload(form) {
|
|
2376
|
+
const payments = [];
|
|
2377
|
+
if (parseFloat(form.bonuses) > 0.0) {
|
|
2378
|
+
payments.push({
|
|
2379
|
+
method: 'bonuses',
|
|
2380
|
+
amount: form.bonuses,
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
const payment = { method: form.method };
|
|
2384
|
+
if (form.method === 'cash' && form.bill) {
|
|
2385
|
+
payment.bill = form.bill;
|
|
2386
|
+
}
|
|
2387
|
+
else if (form.method === 'card_token') {
|
|
2388
|
+
payment.card_token_id = form.card_token_id;
|
|
2389
|
+
}
|
|
2390
|
+
else if (form.method === 'cloudpayments') {
|
|
2391
|
+
payment.save_card = form.save_card === true;
|
|
2392
|
+
}
|
|
2393
|
+
payments.push(payment);
|
|
2394
|
+
return payments;
|
|
2395
|
+
}
|
|
2396
|
+
function useDeliveryPaymentsForm(emit) {
|
|
2397
|
+
const { order, credentials, settings } = pinia.storeToRefs(useOrderStore());
|
|
2398
|
+
const form = vue.ref({
|
|
2399
|
+
method: getPaymentMethod(settings),
|
|
2400
|
+
bill: '',
|
|
2401
|
+
save_card: false,
|
|
2402
|
+
bonuses: '',
|
|
2403
|
+
card_token_id: '',
|
|
2404
|
+
});
|
|
2405
|
+
const saving = vue.ref(false);
|
|
2406
|
+
const bonuses = vue.computed(() => form.value.bonuses);
|
|
2407
|
+
const { unpaidAmount, bonusesAreChecking } = useBonusesPreviewChecker(order, credentials, bonuses, (amount) => {
|
|
2408
|
+
form.value.bonuses = amount;
|
|
2409
|
+
});
|
|
2410
|
+
const save = async () => {
|
|
2411
|
+
if (!credentials.value) {
|
|
2412
|
+
return;
|
|
2413
|
+
}
|
|
2414
|
+
else if (saving.value) {
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
2417
|
+
const payments = getPaymentsPayload(form.value);
|
|
2418
|
+
try {
|
|
2419
|
+
await api.setOrderCheckoutPayment(credentials.value, { payments });
|
|
2420
|
+
emit('completed');
|
|
2421
|
+
}
|
|
2422
|
+
catch (e) {
|
|
2423
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось сохранить способ оплаты.'));
|
|
2424
|
+
}
|
|
2425
|
+
finally {
|
|
2426
|
+
saving.value = false;
|
|
2427
|
+
}
|
|
2428
|
+
};
|
|
2429
|
+
return {
|
|
2430
|
+
form,
|
|
2431
|
+
unpaidAmount,
|
|
2432
|
+
bonusesAreChecking,
|
|
2433
|
+
saving,
|
|
2434
|
+
save,
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
function useCheckoutSummary(emit) {
|
|
2439
|
+
const orderStore = useOrderStore();
|
|
2440
|
+
const { credentials, settings } = pinia.storeToRefs(orderStore);
|
|
2441
|
+
const { store, city } = pinia.storeToRefs(useStoreStore());
|
|
2442
|
+
const form = vue.ref({
|
|
2443
|
+
persons_count: '',
|
|
2444
|
+
notes: '',
|
|
2445
|
+
});
|
|
2446
|
+
const hasPersonsCount = vue.computed(() => {
|
|
2447
|
+
if (!settings.value) {
|
|
2448
|
+
return false;
|
|
2449
|
+
}
|
|
2450
|
+
const index = settings.value.options.findIndex((option) => option.kind === 'persons_count');
|
|
2451
|
+
return index !== -1;
|
|
2452
|
+
});
|
|
2453
|
+
const saving = vue.ref(false);
|
|
2454
|
+
const save = async () => {
|
|
2455
|
+
if (!credentials.value) {
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2458
|
+
else if (saving.value) {
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
2461
|
+
const payload = {
|
|
2462
|
+
notes: form.value.notes,
|
|
2463
|
+
};
|
|
2464
|
+
if (hasPersonsCount.value && form.value.persons_count) {
|
|
2465
|
+
payload.notes = `Персон: ${form.value.persons_count}\n\n${payload.notes}`.trim();
|
|
2466
|
+
}
|
|
2467
|
+
saving.value = true;
|
|
2468
|
+
try {
|
|
2469
|
+
const response = await api.checkoutOrder(credentials.value, payload);
|
|
2470
|
+
if (response.confirmation_required) {
|
|
2471
|
+
emit('confirmation', credentials.value);
|
|
2472
|
+
}
|
|
2473
|
+
else {
|
|
2474
|
+
emit('completed', response);
|
|
2475
|
+
}
|
|
2476
|
+
if (store.value && city.value) {
|
|
2477
|
+
await orderStore.recreate(store.value.id, city.value.id);
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
catch (e) {
|
|
2481
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось оформить заказ.'));
|
|
2482
|
+
}
|
|
2483
|
+
finally {
|
|
2484
|
+
saving.value = false;
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
return {
|
|
2488
|
+
form,
|
|
2489
|
+
hasPersonsCount,
|
|
2490
|
+
saving,
|
|
2491
|
+
save,
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
function useCheckoutTotal() {
|
|
2496
|
+
const { credentials } = pinia.storeToRefs(useOrderStore());
|
|
2497
|
+
const loading = vue.ref(false);
|
|
2498
|
+
const total = vue.ref(null);
|
|
2499
|
+
const load = async () => {
|
|
2500
|
+
if (loading.value) {
|
|
2501
|
+
return;
|
|
2502
|
+
}
|
|
2503
|
+
else if (!credentials.value) {
|
|
2504
|
+
return;
|
|
2505
|
+
}
|
|
2506
|
+
loading.value = true;
|
|
2507
|
+
try {
|
|
2508
|
+
total.value = await api.getOrderCheckoutTotal(credentials.value);
|
|
2509
|
+
}
|
|
2510
|
+
catch (e) {
|
|
2511
|
+
//
|
|
2512
|
+
}
|
|
2513
|
+
finally {
|
|
2514
|
+
loading.value = false;
|
|
2515
|
+
}
|
|
2516
|
+
};
|
|
2517
|
+
return {
|
|
2518
|
+
loading,
|
|
2519
|
+
load,
|
|
2520
|
+
total,
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
function useSingleModifier(props, emit) {
|
|
2525
|
+
const value = vue.computed({
|
|
2526
|
+
get: () => props.modelValue,
|
|
2527
|
+
set: (val) => emit('update:modelValue', val),
|
|
2528
|
+
});
|
|
2529
|
+
const checked = vue.computed({
|
|
2530
|
+
get: () => value.value.quantity > 0,
|
|
2531
|
+
set: (val) => {
|
|
2532
|
+
value.value.quantity = val ? 1 : 0;
|
|
2533
|
+
},
|
|
2534
|
+
});
|
|
2535
|
+
const shouldUseQuantityControls = vue.computed(() => props.modifier.max_quantity > 1);
|
|
2536
|
+
const increase = () => {
|
|
2537
|
+
if (props.limitReached) {
|
|
2538
|
+
return;
|
|
2539
|
+
}
|
|
2540
|
+
value.value.quantity = Math.min(value.value.quantity + 1, props.modifier.max_quantity);
|
|
2541
|
+
};
|
|
2542
|
+
const decrease = () => {
|
|
2543
|
+
value.value.quantity = Math.max(value.value.quantity - 1, props.modifier.min_quantity);
|
|
2544
|
+
};
|
|
2545
|
+
return {
|
|
2546
|
+
value,
|
|
2547
|
+
checked,
|
|
2548
|
+
shouldUseQuantityControls,
|
|
2549
|
+
increase,
|
|
2550
|
+
decrease,
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
function getModifierQuantity(modifier, value) {
|
|
2555
|
+
const index = value.value.findIndex((item) => item.modifier_id === modifier.modifier.id);
|
|
2556
|
+
if (index === -1) {
|
|
2557
|
+
return 0;
|
|
2558
|
+
}
|
|
2559
|
+
return value.value[index].quantity;
|
|
2560
|
+
}
|
|
2561
|
+
function getDefaultModifiersGroupModifiers(group, value) {
|
|
2562
|
+
const modifiers = {};
|
|
2563
|
+
group.modifiers.forEach((modifier) => {
|
|
2564
|
+
const quantity = Array.isArray(value.value) ? getModifierQuantity(modifier, value) : 0;
|
|
2565
|
+
modifiers[modifier.modifier.id] = {
|
|
2566
|
+
quantity,
|
|
2567
|
+
modifier_id: modifier.modifier.id,
|
|
2568
|
+
};
|
|
2569
|
+
});
|
|
2570
|
+
return modifiers;
|
|
2571
|
+
}
|
|
2572
|
+
function getSelectedModifiers$1(group, modifiers) {
|
|
2573
|
+
const selected = [];
|
|
2574
|
+
Object.keys(modifiers).forEach((modifierId) => {
|
|
2575
|
+
if (!modifiers[modifierId].quantity) {
|
|
2576
|
+
return;
|
|
2577
|
+
}
|
|
2578
|
+
selected.push({
|
|
2579
|
+
modifiers_group_id: group.group.id,
|
|
2580
|
+
modifier_id: modifierId,
|
|
2581
|
+
quantity: modifiers[modifierId].quantity,
|
|
2582
|
+
});
|
|
2583
|
+
});
|
|
2584
|
+
return selected;
|
|
2585
|
+
}
|
|
2586
|
+
function useModifiersGroup(props, emit) {
|
|
2587
|
+
const value = vue.computed({
|
|
2588
|
+
get: () => props.modelValue,
|
|
2589
|
+
set: (val) => emit('update:modelValue', val),
|
|
2590
|
+
});
|
|
2591
|
+
const selectedModifier = vue.ref('');
|
|
2592
|
+
const modifiers = vue.ref(getDefaultModifiersGroupModifiers(props.group, value));
|
|
2593
|
+
const shouldUseQuantityControls = vue.computed(() => props.group.max_quantity > 1);
|
|
2594
|
+
const totalSelectedCount = vue.computed(() => {
|
|
2595
|
+
return value.value
|
|
2596
|
+
.map((modifier) => modifier.quantity)
|
|
2597
|
+
.reduce((current, total) => current + total, 0);
|
|
2598
|
+
});
|
|
2599
|
+
const limitReached = vue.computed(() => {
|
|
2600
|
+
if (!shouldUseQuantityControls.value) {
|
|
2601
|
+
return selectedModifier.value !== '';
|
|
2602
|
+
}
|
|
2603
|
+
return totalSelectedCount.value >= props.group.max_quantity;
|
|
2604
|
+
});
|
|
2605
|
+
const requiredModifierIsMissing = vue.computed(() => {
|
|
2606
|
+
if (!props.group.is_required) {
|
|
2607
|
+
return false;
|
|
2608
|
+
}
|
|
2609
|
+
else if (props.group.min_quantity === 0) {
|
|
2610
|
+
return false;
|
|
2611
|
+
}
|
|
2612
|
+
return totalSelectedCount.value < props.group.min_quantity;
|
|
2613
|
+
});
|
|
2614
|
+
vue.watch(selectedModifier, (val) => {
|
|
2615
|
+
if (!val) {
|
|
2616
|
+
value.value = [];
|
|
2617
|
+
return;
|
|
2618
|
+
}
|
|
2619
|
+
value.value = [{
|
|
2620
|
+
modifiers_group_id: props.group.group.id,
|
|
2621
|
+
modifier_id: val,
|
|
2622
|
+
quantity: 1,
|
|
2623
|
+
}];
|
|
2624
|
+
});
|
|
2625
|
+
vue.watch(modifiers, (val) => {
|
|
2626
|
+
value.value = getSelectedModifiers$1(props.group, val);
|
|
2627
|
+
}, { deep: true });
|
|
2628
|
+
return {
|
|
2629
|
+
selectedModifier,
|
|
2630
|
+
modifiers,
|
|
2631
|
+
shouldUseQuantityControls,
|
|
2632
|
+
requiredModifierIsMissing,
|
|
2633
|
+
limitReached,
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
function getModifiers(product, variant) {
|
|
2638
|
+
const modifiers = {};
|
|
2639
|
+
((product === null || product === void 0 ? void 0 : product.modifiers) || []).forEach((modifier) => {
|
|
2640
|
+
modifiers[modifier.modifier.id] = {
|
|
2641
|
+
modifier_id: modifier.modifier.id,
|
|
2642
|
+
quantity: 0,
|
|
2643
|
+
};
|
|
2644
|
+
});
|
|
2645
|
+
((product === null || product === void 0 ? void 0 : product.modifiers_groups) || []).forEach((group) => {
|
|
2646
|
+
modifiers[group.group.id] = [];
|
|
2647
|
+
});
|
|
2648
|
+
if (!variant.value || !variant.value.selected_modifiers || !variant.value.selected_modifiers.modifiers) {
|
|
2649
|
+
return modifiers;
|
|
2650
|
+
}
|
|
2651
|
+
else if (!variant.value.selected_modifiers.modifiers.length) {
|
|
2652
|
+
return modifiers;
|
|
2653
|
+
}
|
|
2654
|
+
variant.value.selected_modifiers.modifiers.forEach((modifier) => {
|
|
2655
|
+
if (typeof modifier.modifiers_group_id !== 'undefined' && modifier.modifiers_group_id) {
|
|
2656
|
+
modifiers[modifier.modifiers_group_id].push(modifier);
|
|
2657
|
+
}
|
|
2658
|
+
else if (typeof modifier.modifier_id !== 'undefined' && modifier.modifier_id) {
|
|
2659
|
+
modifiers[modifier.modifier_id] = {
|
|
2660
|
+
modifier_id: modifier.modifier_id,
|
|
2661
|
+
quantity: modifier.quantity,
|
|
2662
|
+
};
|
|
2663
|
+
}
|
|
2664
|
+
});
|
|
2665
|
+
return modifiers;
|
|
2666
|
+
}
|
|
2667
|
+
function getSelectedModifiers(modifiers) {
|
|
2668
|
+
const selected = [];
|
|
2669
|
+
Object.keys(modifiers.value).forEach((modifierId) => {
|
|
2670
|
+
const isGroup = Array.isArray(modifiers.value[modifierId]);
|
|
2671
|
+
if (!isGroup && !modifiers.value[modifierId].quantity) {
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
else if (!isGroup) {
|
|
2675
|
+
selected.push({
|
|
2676
|
+
modifier_id: modifierId,
|
|
2677
|
+
quantity: modifiers.value[modifierId].quantity,
|
|
2678
|
+
});
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2681
|
+
modifiers.value[modifierId].forEach((modifier) => {
|
|
2682
|
+
if (!modifier.modifier_id || !modifier.quantity || !modifier.modifiers_group_id) {
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2685
|
+
selected.push({
|
|
2686
|
+
modifiers_group_id: modifier.modifiers_group_id,
|
|
2687
|
+
modifier_id: modifier.modifier_id,
|
|
2688
|
+
quantity: modifier.quantity,
|
|
2689
|
+
});
|
|
2690
|
+
});
|
|
2691
|
+
});
|
|
2692
|
+
return selected;
|
|
2693
|
+
}
|
|
2694
|
+
function useModifiers(product, variant, recalculate) {
|
|
2695
|
+
var _a, _b;
|
|
2696
|
+
const modifiersHash = vue.ref(((_b = (_a = variant.value) === null || _a === void 0 ? void 0 : _a.selected_modifiers) === null || _b === void 0 ? void 0 : _b.hash) || null);
|
|
2697
|
+
const modifiers = vue.ref(getModifiers(product, variant));
|
|
2698
|
+
const selectedModifiers = vue.computed(() => getSelectedModifiers(modifiers));
|
|
2699
|
+
vue.watch(variant, () => {
|
|
2700
|
+
modifiers.value = getModifiers(product, variant);
|
|
2701
|
+
});
|
|
2702
|
+
vue.watch(selectedModifiers, async () => {
|
|
2703
|
+
const hash = await recalculate(selectedModifiers);
|
|
2704
|
+
if (hash === null) {
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
modifiersHash.value = hash;
|
|
2708
|
+
});
|
|
2709
|
+
return {
|
|
2710
|
+
modifiers,
|
|
2711
|
+
selectedModifiers,
|
|
2712
|
+
modifiersHash,
|
|
2713
|
+
};
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
async function recalculatePrice(variant, modifiers) {
|
|
2717
|
+
if (!variant.value) {
|
|
2718
|
+
return null;
|
|
2719
|
+
}
|
|
2720
|
+
else if (!modifiers.value.length) {
|
|
2721
|
+
return null;
|
|
2722
|
+
}
|
|
2723
|
+
const { cityId } = pinia.storeToRefs(useStoreStore());
|
|
2724
|
+
try {
|
|
2725
|
+
return await api.getProductVariantPrice(variant.value.product_id, variant.value.id, modifiers.value, {
|
|
2726
|
+
city_id: cityId.value || undefined,
|
|
2727
|
+
});
|
|
2728
|
+
}
|
|
2729
|
+
catch (e) {
|
|
2730
|
+
//
|
|
2731
|
+
}
|
|
2732
|
+
return null;
|
|
2733
|
+
}
|
|
2734
|
+
function getProductVariantsPricesRange(variants) {
|
|
2735
|
+
if (!variants.length) {
|
|
2736
|
+
return null;
|
|
2737
|
+
}
|
|
2738
|
+
const sorted = [...variants].sort((first, second) => Math.sign(first.price.value - second.price.value));
|
|
2739
|
+
return {
|
|
2740
|
+
min: sorted[0].price,
|
|
2741
|
+
max: sorted[sorted.length - 1].price,
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
function useVariantPrice(variants, variant) {
|
|
2745
|
+
const result = vue.ref(null);
|
|
2746
|
+
const recalculating = vue.ref(false);
|
|
2747
|
+
const totalPrice = vue.computed(() => {
|
|
2748
|
+
if (result.value !== null) {
|
|
2749
|
+
return {
|
|
2750
|
+
recalculated: true,
|
|
2751
|
+
recalculating: recalculating.value,
|
|
2752
|
+
price: result.value.price,
|
|
2753
|
+
original_price: result.value.original_price,
|
|
2754
|
+
has_discount: result.value.has_discount,
|
|
2755
|
+
discount_id: result.value.discount_id,
|
|
2756
|
+
discount_difference: result.value.discount_difference,
|
|
2757
|
+
discount_percentage: result.value.discount_percentage,
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
else if (!variant.value) {
|
|
2761
|
+
return null;
|
|
2762
|
+
}
|
|
2763
|
+
return {
|
|
2764
|
+
recalculated: false,
|
|
2765
|
+
recalculating: recalculating.value,
|
|
2766
|
+
price: variant.value.price,
|
|
2767
|
+
original_price: variant.value.original_price,
|
|
2768
|
+
has_discount: variant.value.has_discount,
|
|
2769
|
+
discount_id: variant.value.discount_id,
|
|
2770
|
+
discount_difference: variant.value.discount_difference,
|
|
2771
|
+
discount_percentage: variant.value.discount_percentage,
|
|
2772
|
+
};
|
|
2773
|
+
});
|
|
2774
|
+
const pricesRange = vue.computed(() => getProductVariantsPricesRange(variants));
|
|
2775
|
+
const recalculate = async (modifiers) => {
|
|
2776
|
+
if (recalculating.value) {
|
|
2777
|
+
return null;
|
|
2778
|
+
}
|
|
2779
|
+
recalculating.value = true;
|
|
2780
|
+
result.value = await recalculatePrice(variant, modifiers);
|
|
2781
|
+
recalculating.value = false;
|
|
2782
|
+
return result.value !== null ? result.value.modifiers_hash : null;
|
|
2783
|
+
};
|
|
2784
|
+
return {
|
|
2785
|
+
totalPrice,
|
|
2786
|
+
pricesRange,
|
|
2787
|
+
recalculating,
|
|
2788
|
+
recalculate,
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
function getOptionsList(variants) {
|
|
2793
|
+
const options = [];
|
|
2794
|
+
if (variants.length <= 1) {
|
|
2795
|
+
return options;
|
|
2796
|
+
}
|
|
2797
|
+
variants.forEach((variant) => {
|
|
2798
|
+
if (!variant.option_values || !variant.option_values.length) {
|
|
2799
|
+
return;
|
|
2800
|
+
}
|
|
2801
|
+
variant.option_values.forEach((optionValue) => {
|
|
2802
|
+
if (!optionValue.option || !optionValue.option.id) {
|
|
2803
|
+
return;
|
|
2804
|
+
}
|
|
2805
|
+
const optionIndex = options.findIndex((option) => { var _a; return option.id === ((_a = optionValue.option) === null || _a === void 0 ? void 0 : _a.id); });
|
|
2806
|
+
if (optionIndex === -1) {
|
|
2807
|
+
options.push({
|
|
2808
|
+
id: optionValue.option.id,
|
|
2809
|
+
name: optionValue.option.name,
|
|
2810
|
+
type: optionValue.option.type,
|
|
2811
|
+
values: [optionValue],
|
|
2812
|
+
});
|
|
2813
|
+
return;
|
|
2814
|
+
}
|
|
2815
|
+
const valueIndex = options[optionIndex].values.findIndex((item) => item.id === optionValue.id);
|
|
2816
|
+
if (valueIndex !== -1) {
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
options[optionIndex].values.push(optionValue);
|
|
2820
|
+
});
|
|
2821
|
+
});
|
|
2822
|
+
return options;
|
|
2823
|
+
}
|
|
2824
|
+
function useVariant(variants) {
|
|
2825
|
+
const options = vue.ref(getOptionsList(variants));
|
|
2826
|
+
const selectedOptions = vue.ref({});
|
|
2827
|
+
options.value.forEach((option) => {
|
|
2828
|
+
selectedOptions.value[option.id] = option.values.length > 0 ? option.values[0].id : null;
|
|
2829
|
+
});
|
|
2830
|
+
const variant = vue.computed(() => {
|
|
2831
|
+
if (!Array.isArray(variants) || !variants.length) {
|
|
2832
|
+
return null;
|
|
2833
|
+
}
|
|
2834
|
+
else if (variants.length === 1) {
|
|
2835
|
+
return variants[0];
|
|
2836
|
+
}
|
|
2837
|
+
else if (!Object.keys(selectedOptions.value).length) {
|
|
2838
|
+
return variants[0];
|
|
2839
|
+
}
|
|
2840
|
+
const variantIndex = variants.findIndex((item) => {
|
|
2841
|
+
if (!item.option_values || !item.option_values.length) {
|
|
2842
|
+
return false;
|
|
2843
|
+
}
|
|
2844
|
+
return item.option_values.every((optionValue) => {
|
|
2845
|
+
if (!optionValue.option || !optionValue.option.id) {
|
|
2846
|
+
return false;
|
|
2847
|
+
}
|
|
2848
|
+
else if (typeof selectedOptions.value[optionValue.option.id] === 'undefined') {
|
|
2849
|
+
return false;
|
|
2850
|
+
}
|
|
2851
|
+
else if (selectedOptions.value[optionValue.option.id] !== optionValue.id) {
|
|
2852
|
+
return false;
|
|
2853
|
+
}
|
|
2854
|
+
return true;
|
|
2855
|
+
});
|
|
2856
|
+
});
|
|
2857
|
+
if (variantIndex === -1) {
|
|
2858
|
+
return null;
|
|
2859
|
+
}
|
|
2860
|
+
return variants[variantIndex];
|
|
2861
|
+
});
|
|
2862
|
+
return {
|
|
2863
|
+
variant,
|
|
2864
|
+
options,
|
|
2865
|
+
selectedOptions,
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
function useProductItem(errorHandler) {
|
|
2870
|
+
return useItemLoader(api.getProduct, getApiErrorHandler(errorHandler, function (e) {
|
|
2871
|
+
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Товар не найден.'));
|
|
2872
|
+
}));
|
|
2873
|
+
}
|
|
2874
|
+
function useProductCard(item) {
|
|
2875
|
+
var _a;
|
|
2876
|
+
const product = vue.ref({
|
|
2877
|
+
id: item.id,
|
|
2878
|
+
short_id: item.short_id,
|
|
2879
|
+
category_id: Array.isArray(item.categories) && item.categories.length > 0 ? item.categories[0].id : null,
|
|
2880
|
+
slug: item.slug,
|
|
2881
|
+
name: item.name,
|
|
2882
|
+
description: item.description,
|
|
2883
|
+
images: item.media || [],
|
|
2884
|
+
modifiers: item.modifiers || [],
|
|
2885
|
+
modifiers_groups: item.modifiers_groups || [],
|
|
2886
|
+
variants_count: ((_a = item.variants) === null || _a === void 0 ? void 0 : _a.length) || 0,
|
|
2887
|
+
has_images: (item.media || []).length > 0,
|
|
2888
|
+
has_modifiers: (item.modifiers || []).length > 0 || (item.modifiers_groups || []).length > 0,
|
|
2889
|
+
});
|
|
2890
|
+
const { variant, options, selectedOptions, } = useVariant(item.variants || []);
|
|
2891
|
+
const { totalPrice, pricesRange, recalculate, } = useVariantPrice(item.variants || [], variant);
|
|
2892
|
+
const { modifiers, selectedModifiers, modifiersHash, } = useModifiers(item, variant, recalculate);
|
|
2893
|
+
return {
|
|
2894
|
+
product,
|
|
2895
|
+
variant,
|
|
2896
|
+
options,
|
|
2897
|
+
selectedOptions,
|
|
2898
|
+
pricesRange,
|
|
2899
|
+
totalPrice,
|
|
2900
|
+
modifiers,
|
|
2901
|
+
modifiersHash,
|
|
2902
|
+
selectedModifiers,
|
|
2903
|
+
};
|
|
2904
|
+
}
|
|
2905
|
+
|
|
1559
2906
|
function useProductsPricesRange(categoryId, errorHandler) {
|
|
1560
2907
|
return useDataLoader(async () => api.getProductsPricesRange(categoryId), getApiErrorHandler(errorHandler, function (e) {
|
|
1561
2908
|
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось загрузить диапазон цен.'));
|
|
@@ -1607,7 +2954,7 @@ function useProductsPricesRangeFilters(categoryId, values) {
|
|
|
1607
2954
|
};
|
|
1608
2955
|
}
|
|
1609
2956
|
|
|
1610
|
-
|
|
2957
|
+
exports.ProductsSourceType = void 0;
|
|
1611
2958
|
(function (ProductsSourceType) {
|
|
1612
2959
|
ProductsSourceType["Category"] = "category";
|
|
1613
2960
|
ProductsSourceType["Collection"] = "collection";
|
|
@@ -1615,20 +2962,20 @@ var ProductsSourceType;
|
|
|
1615
2962
|
ProductsSourceType["GroupContext"] = "group_context";
|
|
1616
2963
|
ProductsSourceType["VariantOptionContext"] = "variant_option_context";
|
|
1617
2964
|
ProductsSourceType["VariantOptionValueContext"] = "variant_option_value_context";
|
|
1618
|
-
})(ProductsSourceType || (ProductsSourceType = {}));
|
|
1619
|
-
|
|
2965
|
+
})(exports.ProductsSourceType || (exports.ProductsSourceType = {}));
|
|
2966
|
+
exports.ProductsSorting = void 0;
|
|
1620
2967
|
(function (ProductsSorting) {
|
|
1621
2968
|
ProductsSorting["Manual"] = "manual";
|
|
1622
2969
|
ProductsSorting["NameAsc"] = "name";
|
|
1623
2970
|
ProductsSorting["NameDesc"] = "-name";
|
|
1624
2971
|
ProductsSorting["PriceAsc"] = "price";
|
|
1625
2972
|
ProductsSorting["PriceDesc"] = "-price";
|
|
1626
|
-
})(ProductsSorting || (ProductsSorting = {}));
|
|
1627
|
-
|
|
2973
|
+
})(exports.ProductsSorting || (exports.ProductsSorting = {}));
|
|
2974
|
+
exports.ProductsFiltersType = void 0;
|
|
1628
2975
|
(function (ProductsFiltersType) {
|
|
1629
2976
|
ProductsFiltersType["Features"] = "features";
|
|
1630
2977
|
ProductsFiltersType["FeaturesGroups"] = "featuresGroups";
|
|
1631
|
-
})(ProductsFiltersType || (ProductsFiltersType = {}));
|
|
2978
|
+
})(exports.ProductsFiltersType || (exports.ProductsFiltersType = {}));
|
|
1632
2979
|
|
|
1633
2980
|
function getSourceParams(source, promotion) {
|
|
1634
2981
|
if (source === null || !source.id || !source.type) {
|
|
@@ -1638,26 +2985,26 @@ function getSourceParams(source, promotion) {
|
|
|
1638
2985
|
return {};
|
|
1639
2986
|
}
|
|
1640
2987
|
switch (source.type) {
|
|
1641
|
-
case ProductsSourceType.Category:
|
|
2988
|
+
case exports.ProductsSourceType.Category:
|
|
1642
2989
|
return { category_id: source.id };
|
|
1643
|
-
case ProductsSourceType.Collection:
|
|
2990
|
+
case exports.ProductsSourceType.Collection:
|
|
1644
2991
|
return { collection_id: source.id };
|
|
1645
|
-
case ProductsSourceType.CategoryContext:
|
|
2992
|
+
case exports.ProductsSourceType.CategoryContext:
|
|
1646
2993
|
return {
|
|
1647
2994
|
context_type: 'category',
|
|
1648
2995
|
context_id: source.id,
|
|
1649
2996
|
};
|
|
1650
|
-
case ProductsSourceType.GroupContext:
|
|
2997
|
+
case exports.ProductsSourceType.GroupContext:
|
|
1651
2998
|
return {
|
|
1652
2999
|
context_type: 'group',
|
|
1653
3000
|
context_id: source.id,
|
|
1654
3001
|
};
|
|
1655
|
-
case ProductsSourceType.VariantOptionContext:
|
|
3002
|
+
case exports.ProductsSourceType.VariantOptionContext:
|
|
1656
3003
|
return {
|
|
1657
3004
|
context_type: 'variant_option',
|
|
1658
3005
|
context_id: source.id,
|
|
1659
3006
|
};
|
|
1660
|
-
case ProductsSourceType.VariantOptionValueContext:
|
|
3007
|
+
case exports.ProductsSourceType.VariantOptionValueContext:
|
|
1661
3008
|
return {
|
|
1662
3009
|
context_type: 'variant_option_value',
|
|
1663
3010
|
context_id: source.id,
|
|
@@ -1671,11 +3018,11 @@ function getSortingParams(sorting) {
|
|
|
1671
3018
|
return {};
|
|
1672
3019
|
}
|
|
1673
3020
|
switch (sorting) {
|
|
1674
|
-
case ProductsSorting.Manual:
|
|
1675
|
-
case ProductsSorting.NameAsc:
|
|
1676
|
-
case ProductsSorting.NameDesc:
|
|
1677
|
-
case ProductsSorting.PriceAsc:
|
|
1678
|
-
case ProductsSorting.PriceDesc:
|
|
3021
|
+
case exports.ProductsSorting.Manual:
|
|
3022
|
+
case exports.ProductsSorting.NameAsc:
|
|
3023
|
+
case exports.ProductsSorting.NameDesc:
|
|
3024
|
+
case exports.ProductsSorting.PriceAsc:
|
|
3025
|
+
case exports.ProductsSorting.PriceDesc:
|
|
1679
3026
|
return { order_by: sorting };
|
|
1680
3027
|
default:
|
|
1681
3028
|
return {};
|
|
@@ -1751,7 +3098,7 @@ function getCategoryIdFromSource(source) {
|
|
|
1751
3098
|
if (!source || !source.type || !source.id || source.error) {
|
|
1752
3099
|
return null;
|
|
1753
3100
|
}
|
|
1754
|
-
else if (source.type !== ProductsSourceType.Category) {
|
|
3101
|
+
else if (source.type !== exports.ProductsSourceType.Category) {
|
|
1755
3102
|
return null;
|
|
1756
3103
|
}
|
|
1757
3104
|
return source.id;
|
|
@@ -1762,9 +3109,9 @@ function useProductsList(config, errorHandler) {
|
|
|
1762
3109
|
}));
|
|
1763
3110
|
const store = useStoreStore();
|
|
1764
3111
|
const cityId = vue.computed(() => store.cityId);
|
|
1765
|
-
const sorting = vue.ref(config.value.sorting || ProductsSorting.Manual);
|
|
3112
|
+
const sorting = vue.ref(config.value.sorting || exports.ProductsSorting.Manual);
|
|
1766
3113
|
const search = vue.ref(config.value.search || '');
|
|
1767
|
-
const { filters, load: loadFilters, items: features, } = config.value.filtersType === ProductsFiltersType.Features
|
|
3114
|
+
const { filters, load: loadFilters, items: features, } = config.value.filtersType === exports.ProductsFiltersType.Features
|
|
1768
3115
|
? useFeaturesFilters(getCategoryIdFromSource(config.value.source), config.value.filters)
|
|
1769
3116
|
: useFeaturesGroupsFilters(getCategoryIdFromSource(config.value.source), config.value.filters);
|
|
1770
3117
|
const { filters: pricesFilters, load: loadPricesRange, range, } = useProductsPricesRangeFilters(getCategoryIdFromSource(config.value.source), config.value.pricesFilters);
|
|
@@ -1940,23 +3287,140 @@ function getProductsSource(source) {
|
|
|
1940
3287
|
return null;
|
|
1941
3288
|
}
|
|
1942
3289
|
switch (injected) {
|
|
1943
|
-
case ProductsSourceType.Category:
|
|
3290
|
+
case exports.ProductsSourceType.Category:
|
|
1944
3291
|
return getInjectedSource(exports.ZenkyInjection.Category, exports.ZenkyInjection.CategoryNotFound, injected);
|
|
1945
|
-
case ProductsSourceType.Collection:
|
|
3292
|
+
case exports.ProductsSourceType.Collection:
|
|
1946
3293
|
return getInjectedSource(exports.ZenkyInjection.Collection, exports.ZenkyInjection.CollectionNotFound, injected);
|
|
1947
|
-
case ProductsSourceType.CategoryContext:
|
|
3294
|
+
case exports.ProductsSourceType.CategoryContext:
|
|
1948
3295
|
return getInjectedSource(exports.ZenkyInjection.CategoryContext, exports.ZenkyInjection.CategoryContextNotFound, injected);
|
|
1949
|
-
case ProductsSourceType.GroupContext:
|
|
3296
|
+
case exports.ProductsSourceType.GroupContext:
|
|
1950
3297
|
return getInjectedSource(exports.ZenkyInjection.GroupContext, exports.ZenkyInjection.GroupContextNotFound, injected);
|
|
1951
|
-
case ProductsSourceType.VariantOptionContext:
|
|
3298
|
+
case exports.ProductsSourceType.VariantOptionContext:
|
|
1952
3299
|
return getInjectedSource(exports.ZenkyInjection.VariantOptionContext, exports.ZenkyInjection.VariantOptionContextNotFound, injected);
|
|
1953
|
-
case ProductsSourceType.VariantOptionValueContext:
|
|
3300
|
+
case exports.ProductsSourceType.VariantOptionValueContext:
|
|
1954
3301
|
return getInjectedSource(exports.ZenkyInjection.VariantOptionValueContext, exports.ZenkyInjection.VariantOptionValueContextNotFound, injected);
|
|
1955
3302
|
default:
|
|
1956
3303
|
return null;
|
|
1957
3304
|
}
|
|
1958
3305
|
}
|
|
1959
3306
|
|
|
3307
|
+
const usePromotionsStore = pinia.defineStore({
|
|
3308
|
+
id: 'zenky:storefront:promotions',
|
|
3309
|
+
state: () => ({
|
|
3310
|
+
checking: false,
|
|
3311
|
+
failed: false,
|
|
3312
|
+
selector: {
|
|
3313
|
+
available: false,
|
|
3314
|
+
closed: false,
|
|
3315
|
+
offer: null,
|
|
3316
|
+
promotion_id: '',
|
|
3317
|
+
reward_id: '',
|
|
3318
|
+
max_quantity: 0,
|
|
3319
|
+
context: null,
|
|
3320
|
+
},
|
|
3321
|
+
}),
|
|
3322
|
+
getters: {
|
|
3323
|
+
hasSelector() {
|
|
3324
|
+
if (this.checking) {
|
|
3325
|
+
return false;
|
|
3326
|
+
}
|
|
3327
|
+
else if (!this.selector.available) {
|
|
3328
|
+
return false;
|
|
3329
|
+
}
|
|
3330
|
+
else if (!this.selector.promotion_id || !this.selector.reward_id) {
|
|
3331
|
+
return false;
|
|
3332
|
+
}
|
|
3333
|
+
return true;
|
|
3334
|
+
},
|
|
3335
|
+
hasSelectorContext() {
|
|
3336
|
+
if (this.selector.context === null) {
|
|
3337
|
+
return false;
|
|
3338
|
+
}
|
|
3339
|
+
return !!this.selector.context.id && !!this.selector.context.type;
|
|
3340
|
+
},
|
|
3341
|
+
},
|
|
3342
|
+
actions: {
|
|
3343
|
+
setCheckerState(value, timedOut = false) {
|
|
3344
|
+
this.checking = value;
|
|
3345
|
+
this.failed = timedOut;
|
|
3346
|
+
},
|
|
3347
|
+
disableRewardsSelector() {
|
|
3348
|
+
this.selector.available = false;
|
|
3349
|
+
this.selector.offer = null;
|
|
3350
|
+
this.selector.promotion_id = '';
|
|
3351
|
+
this.selector.reward_id = '';
|
|
3352
|
+
this.selector.max_quantity = 0;
|
|
3353
|
+
this.selector.context = null;
|
|
3354
|
+
},
|
|
3355
|
+
enableRewardsSelector(selector) {
|
|
3356
|
+
this.selector.available = true;
|
|
3357
|
+
this.selector.offer = selector.offer;
|
|
3358
|
+
this.selector.promotion_id = selector.promotion_id;
|
|
3359
|
+
this.selector.reward_id = selector.reward_id;
|
|
3360
|
+
this.selector.max_quantity = selector.limit;
|
|
3361
|
+
this.selector.context = selector.context;
|
|
3362
|
+
},
|
|
3363
|
+
closeRewardsSelector() {
|
|
3364
|
+
this.selector.closed = true;
|
|
3365
|
+
},
|
|
3366
|
+
openRewardsSelector() {
|
|
3367
|
+
this.selector.closed = false;
|
|
3368
|
+
},
|
|
3369
|
+
initialize() {
|
|
3370
|
+
events.usePromotionsCheckerStarted().subscribe('storefront.promotions.initialize', () => this.setCheckerState(true));
|
|
3371
|
+
events.usePromotionsCheckerCompleted().subscribe('storefront.promotions.initialize', (params) => this.setCheckerState(false, params && params.timeout === true));
|
|
3372
|
+
events.useDisplayOrderPromotionRewardSelection().subscribe('storefront.promotions.initialize', ({ data }) => this.enableRewardsSelector(data));
|
|
3373
|
+
events.useOrderPromotionsNotFound().subscribe('storefront.promotions.initialize', () => this.disableRewardsSelector());
|
|
3374
|
+
},
|
|
3375
|
+
},
|
|
3376
|
+
});
|
|
3377
|
+
|
|
3378
|
+
function initializePromotions(order, timeout = 10000) {
|
|
3379
|
+
const promotionsStore = usePromotionsStore();
|
|
3380
|
+
promotionsStore.initialize();
|
|
3381
|
+
const promotionsAreChecking = vue.computed(() => promotionsStore.checking);
|
|
3382
|
+
let manualTimeout = undefined;
|
|
3383
|
+
const checker = async () => {
|
|
3384
|
+
if (promotionsAreChecking.value) {
|
|
3385
|
+
return;
|
|
3386
|
+
}
|
|
3387
|
+
if (manualTimeout) {
|
|
3388
|
+
clearTimeout(manualTimeout);
|
|
3389
|
+
}
|
|
3390
|
+
events.usePromotionsCheckerStarted().publish();
|
|
3391
|
+
await api.checkCompletedPromotions({ id: order.id, token: order.token });
|
|
3392
|
+
manualTimeout = setTimeout(() => {
|
|
3393
|
+
if (promotionsAreChecking.value) {
|
|
3394
|
+
events.usePromotionsCheckerCompleted().publish({ timeout: true });
|
|
3395
|
+
}
|
|
3396
|
+
}, timeout);
|
|
3397
|
+
};
|
|
3398
|
+
events.useProductQuantityIncreased().subscribe('promotions.init', checker);
|
|
3399
|
+
events.useProductQuantityDecreased().subscribe('promotions.init', checker);
|
|
3400
|
+
api.checkCompletedPromotions({ id: order.id, token: order.token }).then(() => {
|
|
3401
|
+
console.log('[storefront/promotions] Promotions checker has been initialized.');
|
|
3402
|
+
});
|
|
3403
|
+
}
|
|
3404
|
+
function useRewardsSelector() {
|
|
3405
|
+
const promotionsStore = usePromotionsStore();
|
|
3406
|
+
const selector = vue.computed(() => promotionsStore.selector);
|
|
3407
|
+
const checking = vue.computed(() => promotionsStore.checking);
|
|
3408
|
+
const failed = vue.computed(() => promotionsStore.failed);
|
|
3409
|
+
const available = vue.computed(() => selector.value.available);
|
|
3410
|
+
const collapsed = vue.computed(() => selector.value.closed);
|
|
3411
|
+
const close = () => promotionsStore.closeRewardsSelector();
|
|
3412
|
+
const open = () => promotionsStore.openRewardsSelector();
|
|
3413
|
+
return {
|
|
3414
|
+
checking,
|
|
3415
|
+
failed,
|
|
3416
|
+
available,
|
|
3417
|
+
collapsed,
|
|
3418
|
+
selector,
|
|
3419
|
+
open,
|
|
3420
|
+
close,
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3423
|
+
|
|
1960
3424
|
exports.ZenkyWebsocketEvent = void 0;
|
|
1961
3425
|
(function (ZenkyWebsocketEvent) {
|
|
1962
3426
|
ZenkyWebsocketEvent["OrderPriceRecalculated"] = "orders.price.recalculated";
|
|
@@ -2029,6 +3493,7 @@ exports.getApiErrorHandler = getApiErrorHandler;
|
|
|
2029
3493
|
exports.getExistedAddress = getExistedAddress;
|
|
2030
3494
|
exports.getExistedAddressDisplayValue = getExistedAddressDisplayValue;
|
|
2031
3495
|
exports.getFirstMedium = getFirstMedium;
|
|
3496
|
+
exports.getProductVariantsPricesRange = getProductVariantsPricesRange;
|
|
2032
3497
|
exports.getProductsListParamsFromQuery = getProductsListParamsFromQuery;
|
|
2033
3498
|
exports.getProductsListQueryParams = getProductsListQueryParams;
|
|
2034
3499
|
exports.getProductsPaginationRequest = getProductsPaginationRequest;
|
|
@@ -2038,7 +3503,10 @@ exports.getSelectedAddressDisplayValue = getSelectedAddressDisplayValue;
|
|
|
2038
3503
|
exports.getStockAddress = getStockAddress;
|
|
2039
3504
|
exports.getStockSchedule = getStockSchedule;
|
|
2040
3505
|
exports.getStorage = getStorage;
|
|
3506
|
+
exports.getUpdatedVariants = getUpdatedVariants;
|
|
2041
3507
|
exports.getWebsocketsConnection = getWebsocketsConnection;
|
|
3508
|
+
exports.initializeOrderCustomer = initializeOrderCustomer;
|
|
3509
|
+
exports.initializePromotions = initializePromotions;
|
|
2042
3510
|
exports.subscribeToOrderEvents = subscribeToOrderEvents;
|
|
2043
3511
|
exports.useAddressFormValue = useAddressFormValue;
|
|
2044
3512
|
exports.useArticleCategoriesList = useArticleCategoriesList;
|
|
@@ -2046,22 +3514,29 @@ exports.useArticleItem = useArticleItem;
|
|
|
2046
3514
|
exports.useArticlesList = useArticlesList;
|
|
2047
3515
|
exports.useAuthenticationForm = useAuthenticationForm;
|
|
2048
3516
|
exports.useAuthenticationStatusChecker = useAuthenticationStatusChecker;
|
|
3517
|
+
exports.useBillSuggestions = useBillSuggestions;
|
|
2049
3518
|
exports.useCategories = useCategories;
|
|
2050
3519
|
exports.useCategoriesStore = useCategoriesStore;
|
|
2051
3520
|
exports.useCategoriesTree = useCategoriesTree;
|
|
2052
3521
|
exports.useCategory = useCategory;
|
|
2053
3522
|
exports.useCategoryFeaturesGroupsList = useCategoryFeaturesGroupsList;
|
|
2054
3523
|
exports.useCategoryFeaturesList = useCategoryFeaturesList;
|
|
3524
|
+
exports.useCheckoutConfirmation = useCheckoutConfirmation;
|
|
3525
|
+
exports.useCheckoutSummary = useCheckoutSummary;
|
|
3526
|
+
exports.useCheckoutTotal = useCheckoutTotal;
|
|
2055
3527
|
exports.useCollection = useCollection;
|
|
2056
3528
|
exports.useCollections = useCollections;
|
|
2057
3529
|
exports.useCollectionsStore = useCollectionsStore;
|
|
2058
3530
|
exports.useCustomer = useCustomer;
|
|
3531
|
+
exports.useCustomerCheckoutForm = useCustomerCheckoutForm;
|
|
2059
3532
|
exports.useCustomerStore = useCustomerStore;
|
|
2060
3533
|
exports.useDadata = useDadata;
|
|
2061
3534
|
exports.useDataDestroyer = useDataDestroyer;
|
|
2062
3535
|
exports.useDataLoader = useDataLoader;
|
|
2063
3536
|
exports.useDeliveryAddressDestroyer = useDeliveryAddressDestroyer;
|
|
2064
3537
|
exports.useDeliveryAddressesList = useDeliveryAddressesList;
|
|
3538
|
+
exports.useDeliveryCheckoutForm = useDeliveryCheckoutForm;
|
|
3539
|
+
exports.useDeliveryPaymentsForm = useDeliveryPaymentsForm;
|
|
2065
3540
|
exports.useEditAddressForm = useEditAddressForm;
|
|
2066
3541
|
exports.useFeaturesFilters = useFeaturesFilters;
|
|
2067
3542
|
exports.useFeaturesGroupsFilters = useFeaturesGroupsFilters;
|
|
@@ -2070,21 +3545,36 @@ exports.useItemLoader = useItemLoader;
|
|
|
2070
3545
|
exports.useListLoader = useListLoader;
|
|
2071
3546
|
exports.useLogin = useLogin;
|
|
2072
3547
|
exports.useLogout = useLogout;
|
|
3548
|
+
exports.useModifiers = useModifiers;
|
|
3549
|
+
exports.useModifiersGroup = useModifiersGroup;
|
|
2073
3550
|
exports.useOfferItem = useOfferItem;
|
|
2074
3551
|
exports.useOffersList = useOffersList;
|
|
3552
|
+
exports.useOrderCheckout = useOrderCheckout;
|
|
2075
3553
|
exports.useOrderItem = useOrderItem;
|
|
3554
|
+
exports.useOrderStore = useOrderStore;
|
|
3555
|
+
exports.useOrderVariants = useOrderVariants;
|
|
2076
3556
|
exports.useOrdersList = useOrdersList;
|
|
2077
3557
|
exports.usePaginatedLoader = usePaginatedLoader;
|
|
2078
3558
|
exports.usePasswordReset = usePasswordReset;
|
|
2079
3559
|
exports.usePaymentMethodDestroyer = usePaymentMethodDestroyer;
|
|
2080
3560
|
exports.usePaymentMethodsList = usePaymentMethodsList;
|
|
2081
3561
|
exports.usePhoneConfirmation = usePhoneConfirmation;
|
|
3562
|
+
exports.useProductCard = useProductCard;
|
|
3563
|
+
exports.useProductItem = useProductItem;
|
|
2082
3564
|
exports.useProductsList = useProductsList;
|
|
2083
3565
|
exports.useProductsPricesRange = useProductsPricesRange;
|
|
2084
3566
|
exports.useProductsPricesRangeFilters = useProductsPricesRangeFilters;
|
|
3567
|
+
exports.usePromotionsStore = usePromotionsStore;
|
|
2085
3568
|
exports.useRegistration = useRegistration;
|
|
2086
3569
|
exports.useReversedTree = useReversedTree;
|
|
3570
|
+
exports.useRewardsSelector = useRewardsSelector;
|
|
3571
|
+
exports.useSingleModifier = useSingleModifier;
|
|
2087
3572
|
exports.useSplittedCategoriesTree = useSplittedCategoriesTree;
|
|
2088
3573
|
exports.useStateDataLoader = useStateDataLoader;
|
|
2089
3574
|
exports.useStoreStore = useStoreStore;
|
|
2090
3575
|
exports.useSuggestionsRestrictedToCity = useSuggestionsRestrictedToCity;
|
|
3576
|
+
exports.useTotalPrice = useTotalPrice;
|
|
3577
|
+
exports.useTotalQuantity = useTotalQuantity;
|
|
3578
|
+
exports.useVariant = useVariant;
|
|
3579
|
+
exports.useVariantControls = useVariantControls;
|
|
3580
|
+
exports.useVariantPrice = useVariantPrice;
|