@zenky/storefront-vue 0.9.35 → 0.9.39
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 +1102 -2
- package/dist/esm/index.js +1089 -7
- package/dist/zenky.d.ts +8991 -5
- 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 }; }
|
|
@@ -579,7 +580,7 @@ const useCategoriesStore = pinia.defineStore({
|
|
|
579
580
|
}
|
|
580
581
|
this.loading = true;
|
|
581
582
|
try {
|
|
582
|
-
this.tree = await api.getCategoriesTree({ visibility:
|
|
583
|
+
this.tree = await api.getCategoriesTree({ visibility: api.Visibility.Visible, with: 'media' });
|
|
583
584
|
this.loaded = true;
|
|
584
585
|
}
|
|
585
586
|
catch (e) {
|
|
@@ -754,7 +755,7 @@ const useCollectionsStore = pinia.defineStore({
|
|
|
754
755
|
this.loading = true;
|
|
755
756
|
try {
|
|
756
757
|
this.collections = (await api.getProductsCollections({
|
|
757
|
-
visibility:
|
|
758
|
+
visibility: api.Visibility.Visible,
|
|
758
759
|
order_by: 'name',
|
|
759
760
|
with: 'media',
|
|
760
761
|
count: 100,
|
|
@@ -1556,6 +1557,970 @@ 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
|
+
|
|
1559
2524
|
function useProductsPricesRange(categoryId, errorHandler) {
|
|
1560
2525
|
return useDataLoader(async () => api.getProductsPricesRange(categoryId), getApiErrorHandler(errorHandler, function (e) {
|
|
1561
2526
|
ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось загрузить диапазон цен.'));
|
|
@@ -1957,6 +2922,123 @@ function getProductsSource(source) {
|
|
|
1957
2922
|
}
|
|
1958
2923
|
}
|
|
1959
2924
|
|
|
2925
|
+
const usePromotionsStore = pinia.defineStore({
|
|
2926
|
+
id: 'zenky:storefront:promotions',
|
|
2927
|
+
state: () => ({
|
|
2928
|
+
checking: false,
|
|
2929
|
+
failed: false,
|
|
2930
|
+
selector: {
|
|
2931
|
+
available: false,
|
|
2932
|
+
closed: false,
|
|
2933
|
+
offer: null,
|
|
2934
|
+
promotion_id: '',
|
|
2935
|
+
reward_id: '',
|
|
2936
|
+
max_quantity: 0,
|
|
2937
|
+
context: null,
|
|
2938
|
+
},
|
|
2939
|
+
}),
|
|
2940
|
+
getters: {
|
|
2941
|
+
hasSelector() {
|
|
2942
|
+
if (this.checking) {
|
|
2943
|
+
return false;
|
|
2944
|
+
}
|
|
2945
|
+
else if (!this.selector.available) {
|
|
2946
|
+
return false;
|
|
2947
|
+
}
|
|
2948
|
+
else if (!this.selector.promotion_id || !this.selector.reward_id) {
|
|
2949
|
+
return false;
|
|
2950
|
+
}
|
|
2951
|
+
return true;
|
|
2952
|
+
},
|
|
2953
|
+
hasSelectorContext() {
|
|
2954
|
+
if (this.selector.context === null) {
|
|
2955
|
+
return false;
|
|
2956
|
+
}
|
|
2957
|
+
return !!this.selector.context.id && !!this.selector.context.type;
|
|
2958
|
+
},
|
|
2959
|
+
},
|
|
2960
|
+
actions: {
|
|
2961
|
+
setCheckerState(value, timedOut = false) {
|
|
2962
|
+
this.checking = value;
|
|
2963
|
+
this.failed = timedOut;
|
|
2964
|
+
},
|
|
2965
|
+
disableRewardsSelector() {
|
|
2966
|
+
this.selector.available = false;
|
|
2967
|
+
this.selector.offer = null;
|
|
2968
|
+
this.selector.promotion_id = '';
|
|
2969
|
+
this.selector.reward_id = '';
|
|
2970
|
+
this.selector.max_quantity = 0;
|
|
2971
|
+
this.selector.context = null;
|
|
2972
|
+
},
|
|
2973
|
+
enableRewardsSelector(selector) {
|
|
2974
|
+
this.selector.available = true;
|
|
2975
|
+
this.selector.offer = selector.offer;
|
|
2976
|
+
this.selector.promotion_id = selector.promotion_id;
|
|
2977
|
+
this.selector.reward_id = selector.reward_id;
|
|
2978
|
+
this.selector.max_quantity = selector.limit;
|
|
2979
|
+
this.selector.context = selector.context;
|
|
2980
|
+
},
|
|
2981
|
+
closeRewardsSelector() {
|
|
2982
|
+
this.selector.closed = true;
|
|
2983
|
+
},
|
|
2984
|
+
openRewardsSelector() {
|
|
2985
|
+
this.selector.closed = false;
|
|
2986
|
+
},
|
|
2987
|
+
initialize() {
|
|
2988
|
+
events.usePromotionsCheckerStarted().subscribe('storefront.promotions.initialize', () => this.setCheckerState(true));
|
|
2989
|
+
events.usePromotionsCheckerCompleted().subscribe('storefront.promotions.initialize', (params) => this.setCheckerState(false, params && params.timeout === true));
|
|
2990
|
+
events.useDisplayOrderPromotionRewardSelection().subscribe('storefront.promotions.initialize', ({ data }) => this.enableRewardsSelector(data));
|
|
2991
|
+
events.useOrderPromotionsNotFound().subscribe('storefront.promotions.initialize', () => this.disableRewardsSelector());
|
|
2992
|
+
},
|
|
2993
|
+
},
|
|
2994
|
+
});
|
|
2995
|
+
|
|
2996
|
+
function initializePromotions(order, timeout = 10000) {
|
|
2997
|
+
const promotionsStore = usePromotionsStore();
|
|
2998
|
+
promotionsStore.initialize();
|
|
2999
|
+
const promotionsAreChecking = vue.computed(() => promotionsStore.checking);
|
|
3000
|
+
let manualTimeout = undefined;
|
|
3001
|
+
const checker = async () => {
|
|
3002
|
+
if (promotionsAreChecking.value) {
|
|
3003
|
+
return;
|
|
3004
|
+
}
|
|
3005
|
+
if (manualTimeout) {
|
|
3006
|
+
clearTimeout(manualTimeout);
|
|
3007
|
+
}
|
|
3008
|
+
events.usePromotionsCheckerStarted().publish();
|
|
3009
|
+
await api.checkCompletedPromotions({ id: order.id, token: order.token });
|
|
3010
|
+
manualTimeout = setTimeout(() => {
|
|
3011
|
+
if (promotionsAreChecking.value) {
|
|
3012
|
+
events.usePromotionsCheckerCompleted().publish({ timeout: true });
|
|
3013
|
+
}
|
|
3014
|
+
}, timeout);
|
|
3015
|
+
};
|
|
3016
|
+
events.useProductQuantityIncreased().subscribe('promotions.init', checker);
|
|
3017
|
+
events.useProductQuantityDecreased().subscribe('promotions.init', checker);
|
|
3018
|
+
api.checkCompletedPromotions({ id: order.id, token: order.token }).then(() => {
|
|
3019
|
+
console.log('[storefront/promotions] Promotions checker has been initialized.');
|
|
3020
|
+
});
|
|
3021
|
+
}
|
|
3022
|
+
function useRewardsSelector() {
|
|
3023
|
+
const promotionsStore = usePromotionsStore();
|
|
3024
|
+
const selector = vue.computed(() => promotionsStore.selector);
|
|
3025
|
+
const checking = vue.computed(() => promotionsStore.checking);
|
|
3026
|
+
const failed = vue.computed(() => promotionsStore.failed);
|
|
3027
|
+
const available = vue.computed(() => selector.value.available);
|
|
3028
|
+
const collapsed = vue.computed(() => selector.value.closed);
|
|
3029
|
+
const close = () => promotionsStore.closeRewardsSelector();
|
|
3030
|
+
const open = () => promotionsStore.openRewardsSelector();
|
|
3031
|
+
return {
|
|
3032
|
+
checking,
|
|
3033
|
+
failed,
|
|
3034
|
+
available,
|
|
3035
|
+
collapsed,
|
|
3036
|
+
selector,
|
|
3037
|
+
open,
|
|
3038
|
+
close,
|
|
3039
|
+
};
|
|
3040
|
+
}
|
|
3041
|
+
|
|
1960
3042
|
exports.ZenkyWebsocketEvent = void 0;
|
|
1961
3043
|
(function (ZenkyWebsocketEvent) {
|
|
1962
3044
|
ZenkyWebsocketEvent["OrderPriceRecalculated"] = "orders.price.recalculated";
|
|
@@ -2038,7 +3120,10 @@ exports.getSelectedAddressDisplayValue = getSelectedAddressDisplayValue;
|
|
|
2038
3120
|
exports.getStockAddress = getStockAddress;
|
|
2039
3121
|
exports.getStockSchedule = getStockSchedule;
|
|
2040
3122
|
exports.getStorage = getStorage;
|
|
3123
|
+
exports.getUpdatedVariants = getUpdatedVariants;
|
|
2041
3124
|
exports.getWebsocketsConnection = getWebsocketsConnection;
|
|
3125
|
+
exports.initializeOrderCustomer = initializeOrderCustomer;
|
|
3126
|
+
exports.initializePromotions = initializePromotions;
|
|
2042
3127
|
exports.subscribeToOrderEvents = subscribeToOrderEvents;
|
|
2043
3128
|
exports.useAddressFormValue = useAddressFormValue;
|
|
2044
3129
|
exports.useArticleCategoriesList = useArticleCategoriesList;
|
|
@@ -2046,22 +3131,29 @@ exports.useArticleItem = useArticleItem;
|
|
|
2046
3131
|
exports.useArticlesList = useArticlesList;
|
|
2047
3132
|
exports.useAuthenticationForm = useAuthenticationForm;
|
|
2048
3133
|
exports.useAuthenticationStatusChecker = useAuthenticationStatusChecker;
|
|
3134
|
+
exports.useBillSuggestions = useBillSuggestions;
|
|
2049
3135
|
exports.useCategories = useCategories;
|
|
2050
3136
|
exports.useCategoriesStore = useCategoriesStore;
|
|
2051
3137
|
exports.useCategoriesTree = useCategoriesTree;
|
|
2052
3138
|
exports.useCategory = useCategory;
|
|
2053
3139
|
exports.useCategoryFeaturesGroupsList = useCategoryFeaturesGroupsList;
|
|
2054
3140
|
exports.useCategoryFeaturesList = useCategoryFeaturesList;
|
|
3141
|
+
exports.useCheckoutConfirmation = useCheckoutConfirmation;
|
|
3142
|
+
exports.useCheckoutSummary = useCheckoutSummary;
|
|
3143
|
+
exports.useCheckoutTotal = useCheckoutTotal;
|
|
2055
3144
|
exports.useCollection = useCollection;
|
|
2056
3145
|
exports.useCollections = useCollections;
|
|
2057
3146
|
exports.useCollectionsStore = useCollectionsStore;
|
|
2058
3147
|
exports.useCustomer = useCustomer;
|
|
3148
|
+
exports.useCustomerCheckoutForm = useCustomerCheckoutForm;
|
|
2059
3149
|
exports.useCustomerStore = useCustomerStore;
|
|
2060
3150
|
exports.useDadata = useDadata;
|
|
2061
3151
|
exports.useDataDestroyer = useDataDestroyer;
|
|
2062
3152
|
exports.useDataLoader = useDataLoader;
|
|
2063
3153
|
exports.useDeliveryAddressDestroyer = useDeliveryAddressDestroyer;
|
|
2064
3154
|
exports.useDeliveryAddressesList = useDeliveryAddressesList;
|
|
3155
|
+
exports.useDeliveryCheckoutForm = useDeliveryCheckoutForm;
|
|
3156
|
+
exports.useDeliveryPaymentsForm = useDeliveryPaymentsForm;
|
|
2065
3157
|
exports.useEditAddressForm = useEditAddressForm;
|
|
2066
3158
|
exports.useFeaturesFilters = useFeaturesFilters;
|
|
2067
3159
|
exports.useFeaturesGroupsFilters = useFeaturesGroupsFilters;
|
|
@@ -2072,7 +3164,10 @@ exports.useLogin = useLogin;
|
|
|
2072
3164
|
exports.useLogout = useLogout;
|
|
2073
3165
|
exports.useOfferItem = useOfferItem;
|
|
2074
3166
|
exports.useOffersList = useOffersList;
|
|
3167
|
+
exports.useOrderCheckout = useOrderCheckout;
|
|
2075
3168
|
exports.useOrderItem = useOrderItem;
|
|
3169
|
+
exports.useOrderStore = useOrderStore;
|
|
3170
|
+
exports.useOrderVariants = useOrderVariants;
|
|
2076
3171
|
exports.useOrdersList = useOrdersList;
|
|
2077
3172
|
exports.usePaginatedLoader = usePaginatedLoader;
|
|
2078
3173
|
exports.usePasswordReset = usePasswordReset;
|
|
@@ -2082,9 +3177,14 @@ exports.usePhoneConfirmation = usePhoneConfirmation;
|
|
|
2082
3177
|
exports.useProductsList = useProductsList;
|
|
2083
3178
|
exports.useProductsPricesRange = useProductsPricesRange;
|
|
2084
3179
|
exports.useProductsPricesRangeFilters = useProductsPricesRangeFilters;
|
|
3180
|
+
exports.usePromotionsStore = usePromotionsStore;
|
|
2085
3181
|
exports.useRegistration = useRegistration;
|
|
2086
3182
|
exports.useReversedTree = useReversedTree;
|
|
3183
|
+
exports.useRewardsSelector = useRewardsSelector;
|
|
2087
3184
|
exports.useSplittedCategoriesTree = useSplittedCategoriesTree;
|
|
2088
3185
|
exports.useStateDataLoader = useStateDataLoader;
|
|
2089
3186
|
exports.useStoreStore = useStoreStore;
|
|
2090
3187
|
exports.useSuggestionsRestrictedToCity = useSuggestionsRestrictedToCity;
|
|
3188
|
+
exports.useTotalPrice = useTotalPrice;
|
|
3189
|
+
exports.useTotalQuantity = useTotalQuantity;
|
|
3190
|
+
exports.useVariantControls = useVariantControls;
|