ts-glitter 20.5.7 → 20.5.9
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/lowcode/Entry.js +1 -1
- package/lowcode/Entry.ts +1 -1
- package/lowcode/cms-plugin/shopping-setting-basic.js +1 -1
- package/lowcode/cms-plugin/shopping-setting-basic.ts +1 -1
- package/lowcode/public-components/checkout/index.js +1 -0
- package/lowcode/public-components/checkout/index.ts +1 -0
- package/lowcode/public-components/user-manager/um-login.js +6 -1
- package/lowcode/public-components/user-manager/um-login.ts +7 -1
- package/package.json +1 -1
- package/src/api-public/controllers/shop.js +6 -5
- package/src/api-public/controllers/shop.js.map +1 -1
- package/src/api-public/controllers/shop.ts +6 -5
- package/src/api-public/models/glitter-finance.d.ts +1 -1
- package/src/api-public/models/glitter-finance.js +14 -11
- package/src/api-public/models/glitter-finance.js.map +1 -1
- package/src/api-public/models/glitter-finance.ts +12 -10
- package/src/api-public/services/checkout-event.d.ts +92 -0
- package/src/api-public/services/checkout-event.js +1103 -0
- package/src/api-public/services/checkout-event.js.map +1 -0
- package/src/api-public/services/checkout-event.ts +1460 -0
- package/src/api-public/services/checkout-service.d.ts +83 -0
- package/src/api-public/services/checkout-service.js +1074 -0
- package/src/api-public/services/checkout-service.js.map +1 -0
- package/src/api-public/services/data-analyze.d.ts +1 -1
- package/src/api-public/services/shopping.d.ts +1 -71
- package/src/api-public/services/shopping.js +3 -1044
- package/src/api-public/services/shopping.js.map +1 -1
- package/src/api-public/services/shopping.ts +3 -1391
- package/src/api-public/services/updated-table-checked.js +2 -2
- package/src/api-public/services/updated-table-checked.js.map +1 -1
- package/src/services/private_config.js +1 -1
- package/src/services/private_config.js.map +1 -1
- package/src/services/private_config.ts +1 -1
|
@@ -21,7 +21,6 @@ import { saasConfig } from '../../config.js';
|
|
|
21
21
|
import { SMS } from './sms.js';
|
|
22
22
|
import { LineMessage } from './line-message';
|
|
23
23
|
import { EcInvoice } from './EcInvoice';
|
|
24
|
-
import { onlinePayArray } from '../models/glitter-finance.js';
|
|
25
24
|
import { App } from '../../services/app.js';
|
|
26
25
|
import { Stock } from './stock';
|
|
27
26
|
import { OrderEvent } from './order-event.js';
|
|
@@ -35,6 +34,7 @@ import { ProductInitial } from './product-initial.js';
|
|
|
35
34
|
import { UtTimer } from '../utils/ut-timer.js';
|
|
36
35
|
import { AutoFcm } from '../../public-config-initial/auto-fcm.js';
|
|
37
36
|
import PaymentTransaction from './model/handlePaymentTransaction.js';
|
|
37
|
+
import { CartItem, CheckoutEvent } from './checkout-event.js';
|
|
38
38
|
|
|
39
39
|
type BindItem = {
|
|
40
40
|
id: string;
|
|
@@ -307,36 +307,7 @@ type Collection = {
|
|
|
307
307
|
hidden?: boolean;
|
|
308
308
|
};
|
|
309
309
|
|
|
310
|
-
|
|
311
|
-
id: string;
|
|
312
|
-
spec: string[];
|
|
313
|
-
count: number;
|
|
314
|
-
sale_price: number;
|
|
315
|
-
is_gift?: boolean;
|
|
316
|
-
collection: string[];
|
|
317
|
-
title: string;
|
|
318
|
-
preview_image: string;
|
|
319
|
-
shipment_obj: { type: string; value: number };
|
|
320
|
-
discount_price?: number;
|
|
321
|
-
weight: number;
|
|
322
|
-
rebate: number;
|
|
323
|
-
designated_logistics: {
|
|
324
|
-
type: 'all' | 'designated';
|
|
325
|
-
list: string[];
|
|
326
|
-
};
|
|
327
|
-
deduction_log?: {
|
|
328
|
-
[p: string]: number;
|
|
329
|
-
};
|
|
330
|
-
min_qty?: number;
|
|
331
|
-
max_qty?: number;
|
|
332
|
-
buy_history_count?: number;
|
|
333
|
-
sku: string;
|
|
334
|
-
stock: number;
|
|
335
|
-
show_understocking: 'true' | 'false';
|
|
336
|
-
is_add_on_items: CartItem | boolean;
|
|
337
|
-
pre_order: boolean;
|
|
338
|
-
is_hidden: boolean;
|
|
339
|
-
};
|
|
310
|
+
|
|
340
311
|
|
|
341
312
|
type MultiSaleType = 'store' | 'level' | 'tags';
|
|
342
313
|
|
|
@@ -1768,1366 +1739,7 @@ export class Shopping {
|
|
|
1768
1739
|
);
|
|
1769
1740
|
}
|
|
1770
1741
|
|
|
1771
|
-
async toCheckout(
|
|
1772
|
-
data: {
|
|
1773
|
-
line_items: CartItem[];
|
|
1774
|
-
customer_info?: any; //顧客資訊 訂單人
|
|
1775
|
-
email?: string;
|
|
1776
|
-
return_url: string;
|
|
1777
|
-
order_id?: string;
|
|
1778
|
-
user_info: any; //取貨人資訊
|
|
1779
|
-
code?: string;
|
|
1780
|
-
use_rebate?: number;
|
|
1781
|
-
use_wallet?: number;
|
|
1782
|
-
checkOutType?: 'manual' | 'auto' | 'POS' | 'group_buy';
|
|
1783
|
-
pos_store?: string;
|
|
1784
|
-
voucher?: any; //自定義的voucher
|
|
1785
|
-
discount?: number; //自定義金額
|
|
1786
|
-
total?: number; //自定義總額
|
|
1787
|
-
pay_status?: number; //自定義訂單狀態
|
|
1788
|
-
custom_form_format?: any; //自定義表單格式
|
|
1789
|
-
custom_form_data?: any; //自定義表單資料
|
|
1790
|
-
custom_receipt_form?: any; //自定義配送表單格式
|
|
1791
|
-
distribution_code?: string; //分銷連結代碼
|
|
1792
|
-
code_array: string[]; // 優惠券代碼列表
|
|
1793
|
-
give_away?: {
|
|
1794
|
-
id: number;
|
|
1795
|
-
spec: string[];
|
|
1796
|
-
count: number;
|
|
1797
|
-
voucher_id: string;
|
|
1798
|
-
}[];
|
|
1799
|
-
language?: 'en-US' | 'zh-CN' | 'zh-TW';
|
|
1800
|
-
pos_info?: any; //POS結帳資訊;
|
|
1801
|
-
invoice_select?: string;
|
|
1802
|
-
pre_order?: boolean;
|
|
1803
|
-
voucherList?: any;
|
|
1804
|
-
isExhibition?: boolean;
|
|
1805
|
-
client_ip_address?: string;
|
|
1806
|
-
fbc?: string;
|
|
1807
|
-
fbp?: string;
|
|
1808
|
-
temp_cart_id?: string;
|
|
1809
|
-
},
|
|
1810
|
-
type: 'add' | 'preview' | 'manual' | 'manual-preview' | 'POS' | 'split' = 'add',
|
|
1811
|
-
replace_order_id?: string
|
|
1812
|
-
) {
|
|
1813
|
-
try {
|
|
1814
|
-
const utTimer = new UtTimer('TO-CHECKOUT');
|
|
1815
|
-
const checkPoint = utTimer.checkPoint;
|
|
1816
|
-
|
|
1817
|
-
const userClass = new User(this.app);
|
|
1818
|
-
const rebateClass = new Rebate(this.app);
|
|
1819
|
-
const checkoutPayment = data.user_info?.payment;
|
|
1820
|
-
let scheduledData: any; // 不立刻查詢,只做占位宣告
|
|
1821
|
-
|
|
1822
|
-
// 確認預設值
|
|
1823
|
-
data.line_items = (data.line_items || (data as any).lineItems) ?? [];
|
|
1824
|
-
data.isExhibition = data.checkOutType === 'POS' && (data.pos_store?.includes('exhibition_') ?? false);
|
|
1825
|
-
|
|
1826
|
-
// 判斷是重新付款則取代
|
|
1827
|
-
if (replace_order_id) {
|
|
1828
|
-
const orderData = (
|
|
1829
|
-
await db.query(
|
|
1830
|
-
`SELECT *
|
|
1831
|
-
FROM \`${this.app}\`.t_checkout
|
|
1832
|
-
WHERE cart_token = ?
|
|
1833
|
-
AND status = 0;
|
|
1834
|
-
`,
|
|
1835
|
-
[replace_order_id]
|
|
1836
|
-
)
|
|
1837
|
-
)[0];
|
|
1838
|
-
|
|
1839
|
-
if (!orderData) {
|
|
1840
|
-
throw exception.BadRequestError('BAD_REQUEST', 'ToCheckout Error: Cannot find this orderID', null);
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
// 刪除指定的訂單記錄
|
|
1844
|
-
await db.query(
|
|
1845
|
-
`DELETE
|
|
1846
|
-
FROM \`${this.app}\`.t_checkout
|
|
1847
|
-
WHERE cart_token = ?
|
|
1848
|
-
AND status = 0;
|
|
1849
|
-
`,
|
|
1850
|
-
[replace_order_id]
|
|
1851
|
-
);
|
|
1852
|
-
|
|
1853
|
-
// 提取 orderData 中的相關資訊
|
|
1854
|
-
const { lineItems, user_info, code, customer_info, use_rebate } = orderData.orderData;
|
|
1855
|
-
|
|
1856
|
-
data.line_items = lineItems;
|
|
1857
|
-
data.email = orderData.email;
|
|
1858
|
-
data.user_info = user_info;
|
|
1859
|
-
data.code = code;
|
|
1860
|
-
data.customer_info = customer_info;
|
|
1861
|
-
data.use_rebate = use_rebate;
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
// 判斷是 POS 重新支付<例如:預購單>,則把原先商品庫存加回去
|
|
1865
|
-
if (data.order_id && type === 'POS') {
|
|
1866
|
-
const order = (
|
|
1867
|
-
await db.query(
|
|
1868
|
-
`SELECT *
|
|
1869
|
-
FROM \`${this.app}\`.t_checkout
|
|
1870
|
-
WHERE cart_token = ?
|
|
1871
|
-
`,
|
|
1872
|
-
[data.order_id]
|
|
1873
|
-
)
|
|
1874
|
-
)[0];
|
|
1875
|
-
if (order) {
|
|
1876
|
-
for (const b of order.orderData.lineItems) {
|
|
1877
|
-
const pdDqlData = (
|
|
1878
|
-
await this.getProduct({
|
|
1879
|
-
page: 0,
|
|
1880
|
-
limit: 50,
|
|
1881
|
-
id: b.id,
|
|
1882
|
-
status: 'inRange',
|
|
1883
|
-
channel: data.checkOutType === 'POS' ? (data.isExhibition ? 'exhibition' : 'pos') : undefined,
|
|
1884
|
-
whereStore: data.checkOutType === 'POS' ? data.pos_store : undefined,
|
|
1885
|
-
})
|
|
1886
|
-
).data;
|
|
1887
|
-
|
|
1888
|
-
const pd = pdDqlData.content;
|
|
1889
|
-
const variant = pd.variants.find((dd: any) => dd.spec.join('-') === b.spec.join('-'));
|
|
1890
|
-
|
|
1891
|
-
// 更新庫存
|
|
1892
|
-
await updateStock(variant, b.deduction_log);
|
|
1893
|
-
|
|
1894
|
-
// 更新變體資訊
|
|
1895
|
-
await this.updateVariantsWithSpec(variant, b.id, b.spec);
|
|
1896
|
-
|
|
1897
|
-
// 更新資料庫中的商品內容
|
|
1898
|
-
await db.query(
|
|
1899
|
-
`UPDATE \`${this.app}\`.t_manager_post
|
|
1900
|
-
SET content = ?
|
|
1901
|
-
WHERE id = ?
|
|
1902
|
-
`,
|
|
1903
|
-
[JSON.stringify(pd), pdDqlData.id]
|
|
1904
|
-
);
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
|
|
1909
|
-
// 更新庫存的輔助函數
|
|
1910
|
-
async function updateStock(variant: any, deductionLog: any) {
|
|
1911
|
-
Object.keys(deductionLog).forEach(key => {
|
|
1912
|
-
try {
|
|
1913
|
-
variant.stockList[key].count += deductionLog[key];
|
|
1914
|
-
} catch (e) {
|
|
1915
|
-
console.error(`Error updating stock for variant ${variant.id}:`, e);
|
|
1916
|
-
}
|
|
1917
|
-
});
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
|
-
// 判斷是checkOutType 是POS則清空token,因為結帳對象不是結帳人
|
|
1921
|
-
if (data.checkOutType === 'POS') {
|
|
1922
|
-
this.token = undefined;
|
|
1923
|
-
}
|
|
1924
|
-
|
|
1925
|
-
// 驗證使用者身份的輔助函數
|
|
1926
|
-
const hasAuthentication = (data: any): boolean => {
|
|
1927
|
-
return (
|
|
1928
|
-
(this.token && this.token.userID) ||
|
|
1929
|
-
data.email ||
|
|
1930
|
-
(data.user_info && data.user_info.email) ||
|
|
1931
|
-
(data.user_info && data.user_info.phone)
|
|
1932
|
-
);
|
|
1933
|
-
};
|
|
1934
|
-
|
|
1935
|
-
// 電話信箱擇一
|
|
1936
|
-
if (type !== 'preview' && !hasAuthentication(data)) {
|
|
1937
|
-
throw exception.BadRequestError('BAD_REQUEST', 'ToCheckout Error: No email and phone', null);
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
const checkOutType = data.checkOutType ?? 'manual';
|
|
1941
|
-
const getUserDataAsync = async (
|
|
1942
|
-
type: string,
|
|
1943
|
-
token: IToken | undefined,
|
|
1944
|
-
data: {
|
|
1945
|
-
email?: string;
|
|
1946
|
-
user_info: { email: string; phone: string };
|
|
1947
|
-
}
|
|
1948
|
-
) => {
|
|
1949
|
-
// 檢查預覽模式下的條件
|
|
1950
|
-
if (
|
|
1951
|
-
type === 'preview' &&
|
|
1952
|
-
!(token?.userID || (data.user_info && data.user_info.email) || (data.user_info && data.user_info.phone))
|
|
1953
|
-
) {
|
|
1954
|
-
return {};
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
// 根據 token 獲取用戶數據
|
|
1958
|
-
if (token?.userID && type !== 'POS' && checkOutType !== 'POS') {
|
|
1959
|
-
return await userClass.getUserData(`${token.userID}`, 'userID');
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
// 否則根據 email 或電話獲取數據
|
|
1963
|
-
return (
|
|
1964
|
-
(data.user_info.email && (await userClass.getUserData(data.user_info.email, 'email_or_phone'))) ||
|
|
1965
|
-
(data.user_info.phone && (await userClass.getUserData(data.user_info.phone, 'email_or_phone'))) ||
|
|
1966
|
-
{}
|
|
1967
|
-
);
|
|
1968
|
-
};
|
|
1969
|
-
|
|
1970
|
-
checkPoint('check user auth');
|
|
1971
|
-
|
|
1972
|
-
// 取得顧客資料
|
|
1973
|
-
const userData = await getUserDataAsync(type, this.token, data);
|
|
1974
|
-
|
|
1975
|
-
// 取得使用者 Email 或電話
|
|
1976
|
-
data.email = userData?.userData?.email || userData?.userData?.phone || '';
|
|
1977
|
-
|
|
1978
|
-
// 如果 email 無效,嘗試從 user_info 取得
|
|
1979
|
-
if (!data.email || data.email === 'no-email') {
|
|
1980
|
-
data.email =
|
|
1981
|
-
data.user_info?.email && data.user_info.email !== 'no-email'
|
|
1982
|
-
? data.user_info.email
|
|
1983
|
-
: data.user_info?.phone || '';
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
// 若 email 仍無效,且非預覽模式,設置預設值
|
|
1987
|
-
if (!data.email && type !== 'preview') {
|
|
1988
|
-
data.email = 'no-email';
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
// 判斷購物金是否可用
|
|
1992
|
-
const appStatus = await rebateClass.mainStatus();
|
|
1993
|
-
if (appStatus && userData && data.use_rebate && data.use_rebate > 0) {
|
|
1994
|
-
const userRebate = await rebateClass.getOneRebate({ user_id: userData.userID });
|
|
1995
|
-
const sum = userRebate ? userRebate.point : 0;
|
|
1996
|
-
if (sum < data.use_rebate) {
|
|
1997
|
-
data.use_rebate = 0;
|
|
1998
|
-
}
|
|
1999
|
-
} else {
|
|
2000
|
-
data.use_rebate = 0;
|
|
2001
|
-
}
|
|
2002
|
-
|
|
2003
|
-
checkPoint('check rebate');
|
|
2004
|
-
|
|
2005
|
-
// 運費設定
|
|
2006
|
-
const shipment: ShipmentConfig = await this.getShipmentRefer(data.user_info);
|
|
2007
|
-
|
|
2008
|
-
// 物流設定
|
|
2009
|
-
const shipment_setting: any = await (async () => {
|
|
2010
|
-
try {
|
|
2011
|
-
const config = await Private_config.getConfig({
|
|
2012
|
-
appName: this.app,
|
|
2013
|
-
key: 'logistics_setting',
|
|
2014
|
-
});
|
|
2015
|
-
|
|
2016
|
-
// 如果 config 為空,則返回預設值
|
|
2017
|
-
if (!config) {
|
|
2018
|
-
return {
|
|
2019
|
-
support: [],
|
|
2020
|
-
shipmentSupport: [],
|
|
2021
|
-
};
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
// 返回第一個元素的 value 屬性
|
|
2025
|
-
return config[0].value;
|
|
2026
|
-
} catch (e) {
|
|
2027
|
-
// 發生錯誤時返回空陣列
|
|
2028
|
-
return [];
|
|
2029
|
-
}
|
|
2030
|
-
})();
|
|
2031
|
-
|
|
2032
|
-
checkPoint('set shipment');
|
|
2033
|
-
|
|
2034
|
-
// 確保自訂配送表單的配置
|
|
2035
|
-
shipment_setting.custom_delivery = shipment_setting.custom_delivery
|
|
2036
|
-
? await Promise.all(
|
|
2037
|
-
shipment_setting.custom_delivery.map(async (form: any) => {
|
|
2038
|
-
const config = await new User(this.app).getConfigV2({
|
|
2039
|
-
user_id: 'manager',
|
|
2040
|
-
key: `form_delivery_${form.id}`,
|
|
2041
|
-
});
|
|
2042
|
-
|
|
2043
|
-
form.form = config.list || [];
|
|
2044
|
-
return form;
|
|
2045
|
-
})
|
|
2046
|
-
).then(dataArray => dataArray)
|
|
2047
|
-
: [];
|
|
2048
|
-
|
|
2049
|
-
// 確保 support 是一個陣列
|
|
2050
|
-
shipment_setting.support = shipment_setting.support ?? [];
|
|
2051
|
-
|
|
2052
|
-
// 獲取語言資料中的信息
|
|
2053
|
-
const languageInfo = shipment_setting.language_data?.[data.language as any]?.info;
|
|
2054
|
-
shipment_setting.info = languageInfo ?? shipment_setting.info;
|
|
2055
|
-
|
|
2056
|
-
// 購物車資料
|
|
2057
|
-
const carData: Cart = {
|
|
2058
|
-
customer_info: data.customer_info || {},
|
|
2059
|
-
lineItems: [],
|
|
2060
|
-
total: 0,
|
|
2061
|
-
email: data.email ?? data.user_info?.email ?? '',
|
|
2062
|
-
user_info: data.user_info,
|
|
2063
|
-
shipment_fee: 0,
|
|
2064
|
-
rebate: 0,
|
|
2065
|
-
goodsWeight: 0,
|
|
2066
|
-
use_rebate: data.use_rebate || 0,
|
|
2067
|
-
orderID: data.order_id || `${Date.now()}`,
|
|
2068
|
-
shipment_support: shipment_setting.support as any,
|
|
2069
|
-
shipment_info: shipment_setting.info as any,
|
|
2070
|
-
shipment_selector: [
|
|
2071
|
-
// 標準物流
|
|
2072
|
-
...Shipment_support_config.list.map(dd => ({
|
|
2073
|
-
name: dd.title,
|
|
2074
|
-
value: dd.value,
|
|
2075
|
-
})),
|
|
2076
|
-
// 自定義物流
|
|
2077
|
-
...(shipment_setting.custom_delivery ?? []).map((dd: any) => ({
|
|
2078
|
-
form: dd.form,
|
|
2079
|
-
name: dd.name,
|
|
2080
|
-
value: dd.id,
|
|
2081
|
-
system_form: dd.system_form,
|
|
2082
|
-
})),
|
|
2083
|
-
].filter(option => shipment_setting.support.includes(option.value)),
|
|
2084
|
-
use_wallet: 0,
|
|
2085
|
-
method: data.user_info?.method,
|
|
2086
|
-
user_email: userData?.account ?? data.email ?? data.user_info?.email ?? '',
|
|
2087
|
-
useRebateInfo: { point: 0 },
|
|
2088
|
-
custom_form_format: data.custom_form_format,
|
|
2089
|
-
custom_form_data: data.custom_form_data,
|
|
2090
|
-
custom_receipt_form: data.custom_receipt_form,
|
|
2091
|
-
orderSource: checkOutType === 'POS' ? 'POS' : '',
|
|
2092
|
-
code_array: data.code_array,
|
|
2093
|
-
give_away: data.give_away as any,
|
|
2094
|
-
user_rebate_sum: 0,
|
|
2095
|
-
language: data.language,
|
|
2096
|
-
pos_info: data.pos_info,
|
|
2097
|
-
client_ip_address: data.client_ip_address as string,
|
|
2098
|
-
fbc: data.fbc as string,
|
|
2099
|
-
fbp: data.fbp as string,
|
|
2100
|
-
editRecord: [],
|
|
2101
|
-
};
|
|
2102
|
-
|
|
2103
|
-
if (!data.user_info?.name && userData && userData.userData) {
|
|
2104
|
-
const { name, phone } = userData.userData;
|
|
2105
|
-
carData.user_info = {
|
|
2106
|
-
...carData.user_info,
|
|
2107
|
-
name,
|
|
2108
|
-
phone,
|
|
2109
|
-
};
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
|
-
const add_on_items: any[] = [];
|
|
2113
|
-
const gift_product: any[] = [];
|
|
2114
|
-
const saveStockArray: (() => Promise<boolean>)[] = [];
|
|
2115
|
-
|
|
2116
|
-
// 取得 Variant 物件
|
|
2117
|
-
function getVariant(prod: any, item: any): any {
|
|
2118
|
-
if (prod.product_category === 'kitchen') {
|
|
2119
|
-
let price = 0;
|
|
2120
|
-
let show_understocking = false;
|
|
2121
|
-
let stock = Infinity;
|
|
2122
|
-
if (prod.specs.length) {
|
|
2123
|
-
price = item.spec.reduce((total: number, spec: any, index: number) => {
|
|
2124
|
-
const dpe = prod.specs[index].option.find((dd: any) => dd.title === spec);
|
|
2125
|
-
|
|
2126
|
-
if (dpe) {
|
|
2127
|
-
const currentStock = Number(dpe.stock) || Infinity;
|
|
2128
|
-
stock = Math.min(stock, currentStock);
|
|
2129
|
-
if (dpe.stock !== undefined) {
|
|
2130
|
-
show_understocking = true;
|
|
2131
|
-
}
|
|
2132
|
-
return total + (Number(dpe.price) || 0);
|
|
2133
|
-
}
|
|
2134
|
-
return total;
|
|
2135
|
-
}, 0);
|
|
2136
|
-
} else {
|
|
2137
|
-
price = Number(prod.price) || 0;
|
|
2138
|
-
show_understocking = Boolean(prod.stock ?? '');
|
|
2139
|
-
stock = Number(prod.stock) || 0;
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
if (stock === Infinity) {
|
|
2143
|
-
show_understocking = false;
|
|
2144
|
-
}
|
|
2145
|
-
return {
|
|
2146
|
-
sku: '',
|
|
2147
|
-
spec: [],
|
|
2148
|
-
type: 'variants',
|
|
2149
|
-
stock,
|
|
2150
|
-
v_width: 0,
|
|
2151
|
-
product_id: prod.id,
|
|
2152
|
-
sale_price: price,
|
|
2153
|
-
origin_price: 0,
|
|
2154
|
-
compare_price: 0,
|
|
2155
|
-
preview_image: prod.preview_image && prod.preview_image[0],
|
|
2156
|
-
shipment_type: 'none',
|
|
2157
|
-
show_understocking: String(show_understocking), // 保持原本的 string 格式
|
|
2158
|
-
};
|
|
2159
|
-
} else {
|
|
2160
|
-
return prod.variants.find((dd: any) => dd.spec.join('-') === item.spec.join('-'));
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
|
|
2164
|
-
data.line_items = await Promise.all(
|
|
2165
|
-
data.line_items.map(async item => {
|
|
2166
|
-
const getProductData = (
|
|
2167
|
-
await this.getProduct({
|
|
2168
|
-
page: 0,
|
|
2169
|
-
limit: 1,
|
|
2170
|
-
id: `${item.id}`,
|
|
2171
|
-
status: 'inRange',
|
|
2172
|
-
channel: checkOutType === 'POS' ? (data.isExhibition ? 'exhibition' : 'pos') : undefined,
|
|
2173
|
-
whereStore: checkOutType === 'POS' ? data.pos_store : undefined,
|
|
2174
|
-
setUserID: `${userData?.userID || ''}`,
|
|
2175
|
-
})
|
|
2176
|
-
).data;
|
|
2177
|
-
|
|
2178
|
-
// 搜尋此商品資料並存在
|
|
2179
|
-
if (getProductData) {
|
|
2180
|
-
const content = getProductData.content;
|
|
2181
|
-
const variant = getVariant(content, item);
|
|
2182
|
-
const count = Number(item.count);
|
|
2183
|
-
if (
|
|
2184
|
-
(Number.isInteger(variant.stock) || variant.show_understocking === 'false') &&
|
|
2185
|
-
!isNaN(count) &&
|
|
2186
|
-
count > 0
|
|
2187
|
-
) {
|
|
2188
|
-
const isPOS = checkOutType === 'POS';
|
|
2189
|
-
const isUnderstockingVisible = variant.show_understocking !== 'false';
|
|
2190
|
-
const isManualType = type === 'manual' || type === 'manual-preview';
|
|
2191
|
-
|
|
2192
|
-
if (isPOS && isUnderstockingVisible && !data.isExhibition) {
|
|
2193
|
-
variant.stock = variant.stockList?.[data.pos_store!]?.count || 0;
|
|
2194
|
-
}
|
|
2195
|
-
|
|
2196
|
-
if (variant.stock < item.count && isUnderstockingVisible && !isManualType) {
|
|
2197
|
-
if (isPOS) {
|
|
2198
|
-
item.pre_order = true;
|
|
2199
|
-
} else {
|
|
2200
|
-
item.count = variant.stock;
|
|
2201
|
-
}
|
|
2202
|
-
}
|
|
2203
|
-
|
|
2204
|
-
if (variant && item.count > 0) {
|
|
2205
|
-
Object.assign(item, {
|
|
2206
|
-
specs: content.specs,
|
|
2207
|
-
language_data: content.language_data,
|
|
2208
|
-
product_category: content.product_category,
|
|
2209
|
-
preview_image: variant.preview_image || content.preview_image[0],
|
|
2210
|
-
title: content.title,
|
|
2211
|
-
sale_price: variant.sale_price,
|
|
2212
|
-
origin_price: variant.origin_price,
|
|
2213
|
-
collection: content.collection,
|
|
2214
|
-
sku: variant.sku,
|
|
2215
|
-
stock: variant.stock,
|
|
2216
|
-
show_understocking: variant.show_understocking,
|
|
2217
|
-
stockList: variant.stockList,
|
|
2218
|
-
weight: parseInt(variant.weight || '0', 10),
|
|
2219
|
-
designated_logistics: content.designated_logistics ?? { type: 'all', list: [] },
|
|
2220
|
-
});
|
|
2221
|
-
|
|
2222
|
-
const shipmentValue = (() => {
|
|
2223
|
-
if (!variant.shipment_type || variant.shipment_type === 'none') return 0;
|
|
2224
|
-
if (variant.shipment_type === 'weight') {
|
|
2225
|
-
return item.count * variant.weight;
|
|
2226
|
-
}
|
|
2227
|
-
if (variant.shipment_type === 'volume') {
|
|
2228
|
-
return item.count * variant.v_length * variant.v_width * variant.v_height;
|
|
2229
|
-
}
|
|
2230
|
-
return 0;
|
|
2231
|
-
})();
|
|
2232
|
-
|
|
2233
|
-
item.shipment_obj = {
|
|
2234
|
-
type: variant.shipment_type,
|
|
2235
|
-
value: shipmentValue,
|
|
2236
|
-
};
|
|
2237
|
-
|
|
2238
|
-
variant.shipment_weight = parseInt(variant.shipment_weight || '0', 10);
|
|
2239
|
-
carData.lineItems.push(item as any);
|
|
2240
|
-
|
|
2241
|
-
// Update total price if not manual or giveaway
|
|
2242
|
-
// 要將sale_price修改成scheduled裡的price
|
|
2243
|
-
if (checkOutType == 'group_buy') {
|
|
2244
|
-
if (!scheduledData) {
|
|
2245
|
-
// 如果之前沒查詢過,才執行查詢 不這樣寫的話 -> 再按自動縮排時會自己打開
|
|
2246
|
-
const sql = `WHERE JSON_CONTAINS(content->'$.pending_order', '"${data.temp_cart_id}"'`;
|
|
2247
|
-
const scheduledDataQuery = `
|
|
2248
|
-
SELECT *
|
|
2249
|
-
FROM \`${this.app}\`.\`t_live_purchase_interactions\` ${sql});
|
|
2250
|
-
`;
|
|
2251
|
-
scheduledData = (await db.query(scheduledDataQuery, []))[0];
|
|
2252
|
-
if (scheduledData) {
|
|
2253
|
-
const { content } = scheduledData;
|
|
2254
|
-
const productData = content.item_list.find((pb: any) => pb.id === item.id);
|
|
2255
|
-
|
|
2256
|
-
if (productData) {
|
|
2257
|
-
const variantData = productData.content.variants.find(
|
|
2258
|
-
(dd: any) => dd.spec.join('-') === item.spec.join('-')
|
|
2259
|
-
);
|
|
2260
|
-
|
|
2261
|
-
if (variantData) {
|
|
2262
|
-
item.sale_price = variantData.live_model.live_price;
|
|
2263
|
-
carData.total += item.sale_price * item.count;
|
|
2264
|
-
}
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
}
|
|
2268
|
-
} else if (type !== 'manual') {
|
|
2269
|
-
if (content.productType.giveaway) {
|
|
2270
|
-
variant.sale_price = 0;
|
|
2271
|
-
} else {
|
|
2272
|
-
carData.total += variant.sale_price * item.count;
|
|
2273
|
-
}
|
|
2274
|
-
}
|
|
2275
|
-
}
|
|
2276
|
-
|
|
2277
|
-
if (!['preview', 'manual', 'manual-preview'].includes(type) && variant.show_understocking !== 'false') {
|
|
2278
|
-
const remainingStock = Math.max(variant.stock - item.count, 0);
|
|
2279
|
-
variant.stock = remainingStock;
|
|
2280
|
-
|
|
2281
|
-
if (type === 'POS') {
|
|
2282
|
-
if (data.isExhibition) {
|
|
2283
|
-
if (data.pos_store) {
|
|
2284
|
-
await this.updateExhibitionActiveStock(data.pos_store, variant.variant_id, item.count);
|
|
2285
|
-
}
|
|
2286
|
-
} else {
|
|
2287
|
-
variant.deduction_log = { [data.pos_store!!]: item.count };
|
|
2288
|
-
variant.stockList[data.pos_store!!].count -= item.count;
|
|
2289
|
-
item.deduction_log = variant.deduction_log;
|
|
2290
|
-
}
|
|
2291
|
-
} else {
|
|
2292
|
-
const returnData = new Stock(this.app, this.token).allocateStock(variant.stockList, item.count);
|
|
2293
|
-
variant.deduction_log = returnData.deductionLog;
|
|
2294
|
-
item.deduction_log = returnData.deductionLog;
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
saveStockArray.push(
|
|
2298
|
-
() =>
|
|
2299
|
-
new Promise<boolean>(async (resolve, reject) => {
|
|
2300
|
-
try {
|
|
2301
|
-
if (data.checkOutType == 'group_buy') {
|
|
2302
|
-
if (!scheduledData) {
|
|
2303
|
-
// 如果之前沒查詢過,才執行查詢 ,不這樣寫的話 -> 再按自動縮排時會自己打開
|
|
2304
|
-
const sql = `WHERE JSON_CONTAINS(content->'$.pending_order', '"${data.temp_cart_id}"'`;
|
|
2305
|
-
const scheduledDataQuery = `
|
|
2306
|
-
SELECT *
|
|
2307
|
-
FROM \`${this.app}\`.\`t_live_purchase_interactions\` ${sql});
|
|
2308
|
-
`;
|
|
2309
|
-
scheduledData = (await db.query(scheduledDataQuery, []))[0];
|
|
2310
|
-
}
|
|
2311
|
-
// const scheduledData = (await db.query(scheduledDataQuery, []))[0];
|
|
2312
|
-
|
|
2313
|
-
if (scheduledData) {
|
|
2314
|
-
const { content } = scheduledData;
|
|
2315
|
-
const productData = content.item_list.find((pb: any) => pb.id === item.id);
|
|
2316
|
-
|
|
2317
|
-
if (productData) {
|
|
2318
|
-
const variantData = productData.content.variants.find(
|
|
2319
|
-
(dd: any) => dd.spec.join('-') === item.spec.join('-')
|
|
2320
|
-
);
|
|
2321
|
-
|
|
2322
|
-
if (variantData) {
|
|
2323
|
-
const stockService = new Stock(this.app, this.token);
|
|
2324
|
-
const { stockList, deductionLog } = stockService.allocateStock(
|
|
2325
|
-
variantData.stockList,
|
|
2326
|
-
item.count
|
|
2327
|
-
);
|
|
2328
|
-
|
|
2329
|
-
variantData.stockList = stockList;
|
|
2330
|
-
item.deduction_log = deductionLog;
|
|
2331
|
-
carData.scheduled_id = scheduledData.id;
|
|
2332
|
-
|
|
2333
|
-
// Update variants for scheduled data
|
|
2334
|
-
await this.updateVariantsForScheduled(content, scheduledData.id);
|
|
2335
|
-
}
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
} else {
|
|
2339
|
-
if (content.shopee_id) {
|
|
2340
|
-
await new Shopee(this.app, this.token).asyncStockToShopee({
|
|
2341
|
-
product: getProductData,
|
|
2342
|
-
callback: () => {},
|
|
2343
|
-
});
|
|
2344
|
-
}
|
|
2345
|
-
|
|
2346
|
-
if (content.product_category === 'kitchen' && variant.spec?.length) {
|
|
2347
|
-
// 餐廳類別的庫存處理方式
|
|
2348
|
-
variant.spec.forEach((d1: any, index: number) => {
|
|
2349
|
-
const option = content.specs[index].option.find((d2: any) => d2.title === d1);
|
|
2350
|
-
if (option?.stock !== undefined) {
|
|
2351
|
-
option.stock = parseInt(option.stock, 10) - item.count;
|
|
2352
|
-
}
|
|
2353
|
-
});
|
|
2354
|
-
|
|
2355
|
-
// 取得 store_config 並記錄扣庫存紀錄
|
|
2356
|
-
const store_config = await userClass.getConfigV2({
|
|
2357
|
-
key: 'store_manager',
|
|
2358
|
-
user_id: 'manager',
|
|
2359
|
-
});
|
|
2360
|
-
item.deduction_log = { [store_config.list[0].id]: item.count };
|
|
2361
|
-
} else {
|
|
2362
|
-
await this.updateVariantsWithSpec(variant, item.id, item.spec);
|
|
2363
|
-
}
|
|
2364
|
-
|
|
2365
|
-
// 更新資料庫
|
|
2366
|
-
await db.query(
|
|
2367
|
-
`UPDATE \`${this.app}\`.\`t_manager_post\`
|
|
2368
|
-
SET ?
|
|
2369
|
-
WHERE id = ${getProductData.id}`,
|
|
2370
|
-
[{ content: JSON.stringify(content) }]
|
|
2371
|
-
);
|
|
2372
|
-
}
|
|
2373
|
-
// 如果有 shopee_id,則同步庫存至蝦皮(Todo: 需要新增是否同步的選項)
|
|
2374
|
-
|
|
2375
|
-
resolve(true);
|
|
2376
|
-
} catch (error) {
|
|
2377
|
-
reject(error);
|
|
2378
|
-
}
|
|
2379
|
-
})
|
|
2380
|
-
);
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
|
-
Object.assign(item, {
|
|
2385
|
-
is_add_on_items: content.productType.addProduct && !content.productType.product,
|
|
2386
|
-
is_hidden: content.visible === 'false',
|
|
2387
|
-
is_gift: content.productType.giveaway,
|
|
2388
|
-
sale_price: content.productType.giveaway ? 0 : item.sale_price,
|
|
2389
|
-
min_qty: content.min_qty ?? item.min_qty,
|
|
2390
|
-
max_qty: content.max_qty ?? item.max_qty,
|
|
2391
|
-
});
|
|
2392
|
-
|
|
2393
|
-
// 推入對應的陣列
|
|
2394
|
-
item.is_add_on_items && add_on_items.push(item);
|
|
2395
|
-
item.is_gift && gift_product.push(item);
|
|
2396
|
-
}
|
|
2397
|
-
|
|
2398
|
-
return item;
|
|
2399
|
-
})
|
|
2400
|
-
).then(dataArray => dataArray);
|
|
2401
|
-
|
|
2402
|
-
checkPoint('get product info');
|
|
2403
|
-
|
|
2404
|
-
// 建立 Map 並檢查是否有 max_qty 限制的產品
|
|
2405
|
-
const maxProductMap = new Map();
|
|
2406
|
-
let hasMaxProduct = false;
|
|
2407
|
-
|
|
2408
|
-
for (const product of data.line_items) {
|
|
2409
|
-
if (product.max_qty && product.max_qty > 0) {
|
|
2410
|
-
maxProductMap.set(product.id, true);
|
|
2411
|
-
hasMaxProduct = true;
|
|
2412
|
-
}
|
|
2413
|
-
}
|
|
2414
|
-
|
|
2415
|
-
if (hasMaxProduct && data.email !== 'no-email') {
|
|
2416
|
-
// 查詢歷史訂單 SQL
|
|
2417
|
-
const cartTokenSQL = `
|
|
2418
|
-
SELECT cart_token
|
|
2419
|
-
FROM \`${this.app}\`.t_checkout
|
|
2420
|
-
WHERE email IN (${[-99, userData?.userData?.email, userData?.userData?.phone]
|
|
2421
|
-
.filter(Boolean)
|
|
2422
|
-
.map(item => db.escape(item))
|
|
2423
|
-
.join(',')})
|
|
2424
|
-
AND order_status <> '-1'
|
|
2425
|
-
`;
|
|
2426
|
-
|
|
2427
|
-
// 查詢商品購買紀錄
|
|
2428
|
-
const soldHistory = await db.query(
|
|
2429
|
-
`
|
|
2430
|
-
SELECT *
|
|
2431
|
-
FROM \`${this.app}\`.t_products_sold_history
|
|
2432
|
-
WHERE product_id IN (${[...maxProductMap.keys()].join(',')})
|
|
2433
|
-
AND order_id IN (${cartTokenSQL})
|
|
2434
|
-
`,
|
|
2435
|
-
[]
|
|
2436
|
-
);
|
|
2437
|
-
|
|
2438
|
-
// 使用 Map 計算歷史購買數量
|
|
2439
|
-
const purchaseHistory = new Map();
|
|
2440
|
-
for (const history of soldHistory) {
|
|
2441
|
-
const pid = Number(history.product_id);
|
|
2442
|
-
purchaseHistory.set(pid, (purchaseHistory.get(pid) ?? 0) + history.count);
|
|
2443
|
-
}
|
|
2444
|
-
|
|
2445
|
-
// 更新當前訂單項目的歷史購買數量
|
|
2446
|
-
for (const item of data.line_items) {
|
|
2447
|
-
if (maxProductMap.has(item.id)) {
|
|
2448
|
-
item.buy_history_count = purchaseHistory.get(item.id) || 0;
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
|
-
checkPoint('set max product');
|
|
2454
|
-
|
|
2455
|
-
carData.shipment_fee = this.getShipmentFee(data.user_info, carData.lineItems, shipment);
|
|
2456
|
-
carData.total += carData.shipment_fee;
|
|
2457
|
-
const f_rebate = await this.formatUseRebate(carData.total, carData.use_rebate);
|
|
2458
|
-
carData.useRebateInfo = f_rebate;
|
|
2459
|
-
carData.use_rebate = f_rebate.point;
|
|
2460
|
-
carData.total -= carData.use_rebate;
|
|
2461
|
-
carData.code = data.code;
|
|
2462
|
-
carData.voucherList = [];
|
|
2463
|
-
checkPoint('set carData');
|
|
2464
|
-
|
|
2465
|
-
if (userData && userData.account) {
|
|
2466
|
-
const userRebate = await rebateClass.getOneRebate({ user_id: userData.userID });
|
|
2467
|
-
carData.user_rebate_sum = userRebate?.point || 0;
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
// 判斷是否有分銷連結
|
|
2471
|
-
if (data.distribution_code) {
|
|
2472
|
-
const linkList = await new Recommend(this.app, this.token).getLinkList({
|
|
2473
|
-
page: 0,
|
|
2474
|
-
limit: 99999,
|
|
2475
|
-
code: data.distribution_code,
|
|
2476
|
-
status: true,
|
|
2477
|
-
no_detail: true,
|
|
2478
|
-
});
|
|
2479
|
-
if (linkList.data.length > 0) {
|
|
2480
|
-
const content = linkList.data[0].content;
|
|
2481
|
-
if (this.checkDuring(content)) {
|
|
2482
|
-
carData.distribution_info = content;
|
|
2483
|
-
}
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
|
-
checkPoint('distribution code');
|
|
2487
|
-
|
|
2488
|
-
// 自動新增訂單的優惠卷設定
|
|
2489
|
-
if (type !== 'manual' && type !== 'manual-preview') {
|
|
2490
|
-
// 過濾加購品與贈品
|
|
2491
|
-
carData.lineItems = carData.lineItems.filter(dd => {
|
|
2492
|
-
return !add_on_items.includes(dd) && !gift_product.includes(dd);
|
|
2493
|
-
});
|
|
2494
|
-
|
|
2495
|
-
// 濾出可用的加購商品,避免折扣被double所以要stringify
|
|
2496
|
-
const c_carData = await this.checkVoucher(structuredClone(carData));
|
|
2497
|
-
|
|
2498
|
-
add_on_items.forEach(dd => {
|
|
2499
|
-
try {
|
|
2500
|
-
const isAddOnItem = c_carData.voucherList?.some(voucher => {
|
|
2501
|
-
return (
|
|
2502
|
-
voucher.reBackType === 'add_on_items' &&
|
|
2503
|
-
(voucher.add_on_products as string[]).find(d2 => {
|
|
2504
|
-
return `${dd.id}` === `${d2}`;
|
|
2505
|
-
})
|
|
2506
|
-
);
|
|
2507
|
-
});
|
|
2508
|
-
|
|
2509
|
-
// 如果是加購品,則將其加入購物車
|
|
2510
|
-
if (isAddOnItem) {
|
|
2511
|
-
carData.lineItems.push(dd);
|
|
2512
|
-
}
|
|
2513
|
-
} catch (e) {
|
|
2514
|
-
console.error('Error processing add-on items:', e);
|
|
2515
|
-
}
|
|
2516
|
-
});
|
|
2517
|
-
|
|
2518
|
-
// 再次更新優惠內容
|
|
2519
|
-
await this.checkVoucher(carData);
|
|
2520
|
-
checkPoint('check voucher');
|
|
2521
|
-
|
|
2522
|
-
// 過濾可選贈品
|
|
2523
|
-
let can_add_gift: any[] = [];
|
|
2524
|
-
|
|
2525
|
-
// 收集可添加的贈品
|
|
2526
|
-
carData.voucherList
|
|
2527
|
-
?.filter(dd => dd.reBackType === 'giveaway')
|
|
2528
|
-
.forEach(dd => can_add_gift.push(dd.add_on_products));
|
|
2529
|
-
|
|
2530
|
-
// 處理每個贈品
|
|
2531
|
-
gift_product.forEach(dd => {
|
|
2532
|
-
const max_count = can_add_gift.filter(d1 => d1.includes(dd.id)).length;
|
|
2533
|
-
if (dd.count <= max_count) {
|
|
2534
|
-
for (let a = 0; a < dd.count; a++) {
|
|
2535
|
-
can_add_gift = can_add_gift.filter(d1 => !d1.includes(dd.id)); // 移除已添加的贈品
|
|
2536
|
-
}
|
|
2537
|
-
carData.lineItems.push(dd);
|
|
2538
|
-
}
|
|
2539
|
-
});
|
|
2540
|
-
|
|
2541
|
-
for (const giveawayData of carData.voucherList!!.filter(dd => dd.reBackType === 'giveaway')) {
|
|
2542
|
-
if (!giveawayData.add_on_products?.length) continue;
|
|
2543
|
-
|
|
2544
|
-
const productPromises = giveawayData.add_on_products.map(async id => {
|
|
2545
|
-
const getGiveawayData = (
|
|
2546
|
-
await this.getProduct({
|
|
2547
|
-
page: 0,
|
|
2548
|
-
limit: 1,
|
|
2549
|
-
id: `${id}`,
|
|
2550
|
-
status: 'inRange',
|
|
2551
|
-
channel: checkOutType === 'POS' ? (data.isExhibition ? 'exhibition' : 'pos') : undefined,
|
|
2552
|
-
whereStore: checkOutType === 'POS' ? data.pos_store : undefined,
|
|
2553
|
-
})
|
|
2554
|
-
).data.content;
|
|
2555
|
-
|
|
2556
|
-
getGiveawayData.voucher_id = giveawayData.id;
|
|
2557
|
-
return getGiveawayData;
|
|
2558
|
-
});
|
|
2559
|
-
|
|
2560
|
-
// 等待所有 add_on_products 產品資料同時獲取
|
|
2561
|
-
giveawayData.add_on_products = await Promise.all(productPromises);
|
|
2562
|
-
}
|
|
2563
|
-
}
|
|
2564
|
-
|
|
2565
|
-
// 付款資訊設定
|
|
2566
|
-
const configData = await Private_config.getConfig({
|
|
2567
|
-
appName: this.app,
|
|
2568
|
-
key: 'glitter_finance',
|
|
2569
|
-
});
|
|
2570
|
-
const keyData: any = configData[0]?.value;
|
|
2571
|
-
if (keyData) {
|
|
2572
|
-
(carData as any).payment_info_custom = keyData.payment_info_custom;
|
|
2573
|
-
}
|
|
2574
|
-
|
|
2575
|
-
await new Promise<void>(resolve => {
|
|
2576
|
-
let n = 0;
|
|
2577
|
-
(carData as any).payment_customer_form = (carData as any).payment_customer_form ?? [];
|
|
2578
|
-
keyData.payment_info_custom.map((item: any, index: number) => {
|
|
2579
|
-
userClass
|
|
2580
|
-
.getConfigV2({
|
|
2581
|
-
user_id: 'manager',
|
|
2582
|
-
key: `form_finance_${item.id}`,
|
|
2583
|
-
})
|
|
2584
|
-
.then(data => {
|
|
2585
|
-
(carData as any).payment_customer_form[index] = {
|
|
2586
|
-
id: item.id,
|
|
2587
|
-
list: data.list,
|
|
2588
|
-
};
|
|
2589
|
-
n++;
|
|
2590
|
-
if (keyData.payment_info_custom.length === n) {
|
|
2591
|
-
resolve();
|
|
2592
|
-
}
|
|
2593
|
-
});
|
|
2594
|
-
});
|
|
2595
|
-
if (n === 0) {
|
|
2596
|
-
resolve();
|
|
2597
|
-
}
|
|
2598
|
-
});
|
|
2599
|
-
checkPoint('set payment');
|
|
2600
|
-
|
|
2601
|
-
// 線下付款
|
|
2602
|
-
(keyData as any).cash_on_delivery = (keyData as any).cash_on_delivery ?? { shipmentSupport: [] };
|
|
2603
|
-
(carData as any).payment_info_line_pay = keyData.payment_info_line_pay;
|
|
2604
|
-
(carData as any).payment_info_atm = keyData.payment_info_atm;
|
|
2605
|
-
const defaultPayArray = onlinePayArray.map(item => item.key);
|
|
2606
|
-
(keyData as any).cash_on_delivery.shipmentSupport = (keyData as any).cash_on_delivery.shipmentSupport ?? [];
|
|
2607
|
-
|
|
2608
|
-
// 透過特定金流,取得指定物流
|
|
2609
|
-
carData.shipment_support = checkoutPayment
|
|
2610
|
-
? ((() => {
|
|
2611
|
-
if (checkoutPayment === 'cash_on_delivery') {
|
|
2612
|
-
return (keyData as any).cash_on_delivery;
|
|
2613
|
-
} else if (defaultPayArray.includes(checkoutPayment)) {
|
|
2614
|
-
return keyData[checkoutPayment];
|
|
2615
|
-
} else if (checkoutPayment === 'atm') {
|
|
2616
|
-
return keyData.payment_info_atm;
|
|
2617
|
-
} else if (checkoutPayment === 'line') {
|
|
2618
|
-
return keyData.payment_info_line_pay;
|
|
2619
|
-
} else {
|
|
2620
|
-
// 自訂線下付款
|
|
2621
|
-
const customPay = keyData.payment_info_custom.find((c: { id: string }) => c.id === checkoutPayment);
|
|
2622
|
-
return customPay ?? {};
|
|
2623
|
-
}
|
|
2624
|
-
})().shipmentSupport ?? [])
|
|
2625
|
-
: [];
|
|
2626
|
-
|
|
2627
|
-
// 防止帶入購物金時,總計小於0
|
|
2628
|
-
let subtotal = 0;
|
|
2629
|
-
carData.lineItems.map(item => {
|
|
2630
|
-
if (item.is_gift) {
|
|
2631
|
-
item.sale_price = 0;
|
|
2632
|
-
}
|
|
2633
|
-
if (!item.is_gift) {
|
|
2634
|
-
subtotal += item.count * (item.sale_price - (item.discount_price ?? 0));
|
|
2635
|
-
}
|
|
2636
|
-
});
|
|
2637
|
-
|
|
2638
|
-
if (carData.total < 0 || carData.use_rebate > subtotal) {
|
|
2639
|
-
carData.use_rebate = 0;
|
|
2640
|
-
carData.total = subtotal + carData.shipment_fee;
|
|
2641
|
-
}
|
|
2642
|
-
|
|
2643
|
-
// 商品材積重量與物流使用限制
|
|
2644
|
-
carData.lineItems.map(item => {
|
|
2645
|
-
carData.goodsWeight += item.weight * item.count;
|
|
2646
|
-
});
|
|
2647
|
-
|
|
2648
|
-
const excludedValuesByTotal = new Set(['UNIMARTC2C', 'FAMIC2C', 'HILIFEC2C', 'OKMARTC2C']);
|
|
2649
|
-
const excludedValuesByWeight = new Set(['normal', 'black_cat']);
|
|
2650
|
-
|
|
2651
|
-
const isExcludedByTotal = (dd: any) => {
|
|
2652
|
-
return carData.total > 20000 && excludedValuesByTotal.has(dd.value);
|
|
2653
|
-
};
|
|
2654
|
-
const isExcludedByWeight = (dd: any) => {
|
|
2655
|
-
return carData.goodsWeight > 20 && excludedValuesByWeight.has(dd.value);
|
|
2656
|
-
};
|
|
2657
|
-
const isIncludedInDesignatedLogistics = (dd: any) => {
|
|
2658
|
-
return carData.lineItems.every(item => {
|
|
2659
|
-
return (
|
|
2660
|
-
item.designated_logistics === undefined ||
|
|
2661
|
-
item.designated_logistics.type === 'all' ||
|
|
2662
|
-
item.designated_logistics.list.includes(dd.value)
|
|
2663
|
-
);
|
|
2664
|
-
});
|
|
2665
|
-
};
|
|
2666
|
-
|
|
2667
|
-
carData.shipment_selector = carData.shipment_selector
|
|
2668
|
-
.filter((dd: any) => {
|
|
2669
|
-
return isIncludedInDesignatedLogistics(dd);
|
|
2670
|
-
})
|
|
2671
|
-
.map(dd => {
|
|
2672
|
-
dd.isExcludedByTotal = isExcludedByTotal(dd);
|
|
2673
|
-
dd.isExcludedByWeight = isExcludedByWeight(dd);
|
|
2674
|
-
return dd;
|
|
2675
|
-
});
|
|
2676
|
-
|
|
2677
|
-
carData.code_array = (carData.code_array || []).filter(code => {
|
|
2678
|
-
return (carData.voucherList || []).find(dd => dd.code === code);
|
|
2679
|
-
});
|
|
2680
|
-
|
|
2681
|
-
// 驗證消費金額能否使用此金物流
|
|
2682
|
-
function getCartFormulaPass(keyData: {
|
|
2683
|
-
cartSetting?: {
|
|
2684
|
-
minimumTotal: number;
|
|
2685
|
-
maximumTotal: number;
|
|
2686
|
-
orderFormula?: string[];
|
|
2687
|
-
};
|
|
2688
|
-
}) {
|
|
2689
|
-
const data = keyData.cartSetting;
|
|
2690
|
-
if (!data || data.orderFormula === undefined) return true;
|
|
2691
|
-
|
|
2692
|
-
const formulaSet = new Set(data.orderFormula);
|
|
2693
|
-
const total =
|
|
2694
|
-
carData.total -
|
|
2695
|
-
(formulaSet.has('shipment_fee') ? 0 : carData.shipment_fee) +
|
|
2696
|
-
(formulaSet.has('discount') || !carData.discount ? 0 : carData.discount) +
|
|
2697
|
-
(formulaSet.has('use_rebate') ? 0 : carData.use_rebate);
|
|
2698
|
-
|
|
2699
|
-
return (!data.minimumTotal || total >= data.minimumTotal) && (!data.maximumTotal || total <= data.maximumTotal);
|
|
2700
|
-
}
|
|
2701
|
-
|
|
2702
|
-
// 線上金流是否可使用判斷,填入付款資訊與方式
|
|
2703
|
-
(carData as any).payment_setting = onlinePayArray.filter((dd: any) => {
|
|
2704
|
-
const k = (keyData as any)[dd.key];
|
|
2705
|
-
if (!k || !k.toggle || !getCartFormulaPass(k)) return false;
|
|
2706
|
-
|
|
2707
|
-
dd.custome_name = k.custome_name;
|
|
2708
|
-
|
|
2709
|
-
if (carData.orderSource === 'POS') {
|
|
2710
|
-
if (dd.key === 'ut_credit_card') {
|
|
2711
|
-
dd.pwd = k['pwd'];
|
|
2712
|
-
}
|
|
2713
|
-
return dd.type === 'pos';
|
|
2714
|
-
}
|
|
2715
|
-
return dd.type !== 'pos';
|
|
2716
|
-
});
|
|
2717
|
-
|
|
2718
|
-
// 線下金流是否可使用判斷
|
|
2719
|
-
(carData as any).off_line_support = keyData.off_line_support ?? {};
|
|
2720
|
-
|
|
2721
|
-
Object.entries((carData as any).off_line_support).map(([key, value]) => {
|
|
2722
|
-
if (!value) return;
|
|
2723
|
-
|
|
2724
|
-
if (key === 'cash_on_delivery') {
|
|
2725
|
-
(carData as any).off_line_support[key] = getCartFormulaPass(keyData[key]);
|
|
2726
|
-
} else if (key === 'atm') {
|
|
2727
|
-
(carData as any).off_line_support[key] = getCartFormulaPass(keyData.payment_info_atm);
|
|
2728
|
-
} else if (key === 'line') {
|
|
2729
|
-
(carData as any).off_line_support[key] = getCartFormulaPass(keyData.payment_info_line_pay);
|
|
2730
|
-
} else {
|
|
2731
|
-
// 自訂線下付款
|
|
2732
|
-
const customPay = keyData.payment_info_custom.find((c: { id: string }) => c.id === key);
|
|
2733
|
-
(carData as any).off_line_support[key] = getCartFormulaPass(customPay ?? {});
|
|
2734
|
-
}
|
|
2735
|
-
});
|
|
2736
|
-
|
|
2737
|
-
// 物流是否可使用判斷
|
|
2738
|
-
if (Array.isArray(carData.shipment_support)) {
|
|
2739
|
-
await Promise.all(
|
|
2740
|
-
carData.shipment_support.map(async sup => {
|
|
2741
|
-
return await userClass
|
|
2742
|
-
.getConfigV2({ key: 'shipment_config_' + sup, user_id: 'manager' })
|
|
2743
|
-
.then(r => {
|
|
2744
|
-
return getCartFormulaPass(r);
|
|
2745
|
-
})
|
|
2746
|
-
.catch(() => {
|
|
2747
|
-
return true;
|
|
2748
|
-
});
|
|
2749
|
-
})
|
|
2750
|
-
).then(dataArray => {
|
|
2751
|
-
carData.shipment_support = carData.shipment_support?.filter((_, index) => dataArray[index]);
|
|
2752
|
-
});
|
|
2753
|
-
}
|
|
2754
|
-
|
|
2755
|
-
// ================================ Preview UP ================================
|
|
2756
|
-
checkPoint('return preview');
|
|
2757
|
-
if (type === 'preview' || type === 'manual-preview') return { data: carData };
|
|
2758
|
-
// ================================ Add DOWN ================================
|
|
2759
|
-
|
|
2760
|
-
// 購物金與錢包金額移除
|
|
2761
|
-
if (userData && userData.userID) {
|
|
2762
|
-
await rebateClass.insertRebate(userData.userID, carData.use_rebate * -1, '使用折抵', {
|
|
2763
|
-
order_id: carData.orderID,
|
|
2764
|
-
});
|
|
2765
|
-
|
|
2766
|
-
if (carData.voucherList && (carData as any).voucherList.length > 0) {
|
|
2767
|
-
for (const voucher of (carData as any).voucherList) {
|
|
2768
|
-
await this.insertVoucherHistory(userData.userID, carData.orderID, voucher.id);
|
|
2769
|
-
}
|
|
2770
|
-
}
|
|
2771
|
-
// 判斷錢包是否有餘額
|
|
2772
|
-
const sum =
|
|
2773
|
-
(
|
|
2774
|
-
await db.query(
|
|
2775
|
-
`SELECT sum(money)
|
|
2776
|
-
FROM \`${this.app}\`.t_wallet
|
|
2777
|
-
WHERE status in (1, 2)
|
|
2778
|
-
and userID = ?`,
|
|
2779
|
-
[userData.userID]
|
|
2780
|
-
)
|
|
2781
|
-
)[0]['sum(money)'] || 0;
|
|
2782
|
-
carData.use_wallet = sum < carData.total ? sum : carData.total;
|
|
2783
|
-
}
|
|
2784
|
-
checkPoint('check user rebate');
|
|
2785
|
-
|
|
2786
|
-
// 手動結帳地方判定
|
|
2787
|
-
if (type === 'manual' || type === 'split') {
|
|
2788
|
-
carData.orderSource = type;
|
|
2789
|
-
let tempVoucher: VoucherData = {
|
|
2790
|
-
discount_total: data.voucher.discount_total,
|
|
2791
|
-
end_ISO_Date: '',
|
|
2792
|
-
for: 'all',
|
|
2793
|
-
forKey: [],
|
|
2794
|
-
method: data.voucher.method,
|
|
2795
|
-
overlay: false,
|
|
2796
|
-
rebate_total: data.voucher.rebate_total,
|
|
2797
|
-
reBackType: data.voucher.reBackType,
|
|
2798
|
-
rule: 'min_price',
|
|
2799
|
-
ruleValue: 0,
|
|
2800
|
-
startDate: '',
|
|
2801
|
-
startTime: '',
|
|
2802
|
-
start_ISO_Date: '',
|
|
2803
|
-
status: 1,
|
|
2804
|
-
target: '',
|
|
2805
|
-
targetList: [],
|
|
2806
|
-
title: data.voucher.title,
|
|
2807
|
-
trigger: 'auto',
|
|
2808
|
-
type: 'voucher',
|
|
2809
|
-
value: data.voucher.value,
|
|
2810
|
-
id: data.voucher.id,
|
|
2811
|
-
bind: [],
|
|
2812
|
-
bind_subtotal: 0,
|
|
2813
|
-
times: 1,
|
|
2814
|
-
counting: 'single',
|
|
2815
|
-
conditionType: 'item',
|
|
2816
|
-
includeDiscount: 'before',
|
|
2817
|
-
device: ['normal'],
|
|
2818
|
-
productOffStart: 'price_all',
|
|
2819
|
-
};
|
|
2820
|
-
carData.discount = data.discount;
|
|
2821
|
-
carData.voucherList = [tempVoucher];
|
|
2822
|
-
carData.customer_info = data.customer_info;
|
|
2823
|
-
carData.total = data.total ?? 0;
|
|
2824
|
-
carData.rebate = tempVoucher.rebate_total;
|
|
2825
|
-
|
|
2826
|
-
if (tempVoucher.reBackType == 'shipment_free' || type == 'split') {
|
|
2827
|
-
carData.shipment_fee = 0;
|
|
2828
|
-
}
|
|
2829
|
-
|
|
2830
|
-
if (tempVoucher.reBackType == 'rebate') {
|
|
2831
|
-
let customerData = await userClass.getUserData(data.email! || data.user_info.email, 'account');
|
|
2832
|
-
if (!customerData) {
|
|
2833
|
-
await userClass.createUser(
|
|
2834
|
-
data.email!,
|
|
2835
|
-
Tool.randomString(8),
|
|
2836
|
-
{
|
|
2837
|
-
email: data.email,
|
|
2838
|
-
name: data.customer_info.name,
|
|
2839
|
-
phone: data.customer_info.phone,
|
|
2840
|
-
},
|
|
2841
|
-
{},
|
|
2842
|
-
true
|
|
2843
|
-
);
|
|
2844
|
-
customerData = await userClass.getUserData(data.email! || data.user_info.email, 'account');
|
|
2845
|
-
}
|
|
2846
|
-
}
|
|
2847
|
-
|
|
2848
|
-
// 手動訂單新增
|
|
2849
|
-
await OrderEvent.insertOrder({
|
|
2850
|
-
cartData: carData,
|
|
2851
|
-
status: data.pay_status as any,
|
|
2852
|
-
app: this.app,
|
|
2853
|
-
});
|
|
2854
|
-
|
|
2855
|
-
new ManagerNotify(this.app).checkout({ orderData: carData, status: 0 });
|
|
2856
|
-
const emailList = new Set([carData.customer_info, carData.user_info].map(dd => dd && dd.email));
|
|
2857
|
-
for (const email of emailList) {
|
|
2858
|
-
if (email) {
|
|
2859
|
-
await AutoFcm.orderChangeInfo({
|
|
2860
|
-
app: this.app,
|
|
2861
|
-
tag: 'order-create',
|
|
2862
|
-
order_id: carData.orderID,
|
|
2863
|
-
phone_email: email,
|
|
2864
|
-
});
|
|
2865
|
-
AutoSendEmail.customerOrder(
|
|
2866
|
-
this.app,
|
|
2867
|
-
'auto-email-order-create',
|
|
2868
|
-
carData.orderID,
|
|
2869
|
-
email,
|
|
2870
|
-
carData.language!!
|
|
2871
|
-
);
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
|
|
2875
|
-
checkPoint('manual order done');
|
|
2876
|
-
return {
|
|
2877
|
-
data: carData,
|
|
2878
|
-
};
|
|
2879
|
-
} else if (type === 'POS') {
|
|
2880
|
-
carData.orderSource = 'POS';
|
|
2881
|
-
|
|
2882
|
-
if (checkOutType === 'POS' && Array.isArray(data.voucherList)) {
|
|
2883
|
-
const manualVoucher = data.voucherList.find((item: any) => item.id === 0);
|
|
2884
|
-
if (manualVoucher) {
|
|
2885
|
-
manualVoucher.discount = manualVoucher.discount_total ?? 0;
|
|
2886
|
-
carData.total -= manualVoucher.discount;
|
|
2887
|
-
carData.discount += manualVoucher.discount;
|
|
2888
|
-
carData.voucherList.push(manualVoucher);
|
|
2889
|
-
}
|
|
2890
|
-
}
|
|
2891
|
-
|
|
2892
|
-
const trans = await db.Transaction.build();
|
|
2893
|
-
if (data.pre_order) {
|
|
2894
|
-
(carData as any).progress = 'pre_order';
|
|
2895
|
-
(carData as any).orderStatus = '0';
|
|
2896
|
-
const payTotal = data.pos_info.payment
|
|
2897
|
-
.map((dd: any) => dd.total)
|
|
2898
|
-
.reduce((acc: any, val: any) => acc + val, 0);
|
|
2899
|
-
if (carData.total <= payTotal) {
|
|
2900
|
-
data.pay_status = 1;
|
|
2901
|
-
} else {
|
|
2902
|
-
data.pay_status = 3;
|
|
2903
|
-
}
|
|
2904
|
-
} else if (carData.user_info.shipment === 'now') {
|
|
2905
|
-
(carData as any).orderStatus = '1';
|
|
2906
|
-
(carData as any).progress = 'finish';
|
|
2907
|
-
}
|
|
2908
|
-
await OrderEvent.insertOrder({
|
|
2909
|
-
cartData: carData,
|
|
2910
|
-
status: data.pay_status as any,
|
|
2911
|
-
app: this.app,
|
|
2912
|
-
});
|
|
2913
|
-
if (data.invoice_select !== 'nouse') {
|
|
2914
|
-
(carData as any).invoice = await new Invoice(this.app).postCheckoutInvoice(
|
|
2915
|
-
carData,
|
|
2916
|
-
carData.user_info.send_type !== 'carrier'
|
|
2917
|
-
);
|
|
2918
|
-
}
|
|
2919
|
-
await trans.commit();
|
|
2920
|
-
await trans.release();
|
|
2921
|
-
await Promise.all(saveStockArray.map(dd => dd()));
|
|
2922
|
-
await this.releaseCheckout((data.pay_status as any) ?? 0, carData.orderID);
|
|
2923
|
-
checkPoint('release pos checkout');
|
|
2924
|
-
for (const email of new Set(
|
|
2925
|
-
[carData.customer_info, carData.user_info].map(dd => {
|
|
2926
|
-
return dd && dd.email;
|
|
2927
|
-
})
|
|
2928
|
-
)) {
|
|
2929
|
-
if (email) {
|
|
2930
|
-
await AutoFcm.orderChangeInfo({
|
|
2931
|
-
app: this.app,
|
|
2932
|
-
tag: 'order-create',
|
|
2933
|
-
order_id: carData.orderID,
|
|
2934
|
-
phone_email: email,
|
|
2935
|
-
});
|
|
2936
|
-
AutoSendEmail.customerOrder(
|
|
2937
|
-
this.app,
|
|
2938
|
-
'auto-email-order-create',
|
|
2939
|
-
carData.orderID,
|
|
2940
|
-
email,
|
|
2941
|
-
carData.language!!
|
|
2942
|
-
);
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
return { result: 'SUCCESS', message: 'POS訂單新增成功', data: carData };
|
|
2946
|
-
}
|
|
2947
|
-
|
|
2948
|
-
// Genetate notify redirect id
|
|
2949
|
-
const id = 'redirect_' + Tool.randomString(6);
|
|
2950
|
-
const redirect_url = new URL(data.return_url);
|
|
2951
|
-
redirect_url.searchParams.set('cart_token', carData.orderID);
|
|
2952
|
-
await redis.setValue(id, redirect_url.href);
|
|
2953
|
-
|
|
2954
|
-
// 當不需付款時直接寫入,並開發票
|
|
2955
|
-
if (carData.use_wallet === carData.total) {
|
|
2956
|
-
await db.query(
|
|
2957
|
-
`INSERT INTO \`${this.app}\`.t_wallet (orderID, userID, money, status, note)
|
|
2958
|
-
values (?, ?, ?, ?, ?);`,
|
|
2959
|
-
[
|
|
2960
|
-
carData.orderID,
|
|
2961
|
-
userData.userID,
|
|
2962
|
-
carData.use_wallet * -1,
|
|
2963
|
-
1,
|
|
2964
|
-
JSON.stringify({
|
|
2965
|
-
note: '使用錢包購物',
|
|
2966
|
-
orderData: carData,
|
|
2967
|
-
}),
|
|
2968
|
-
]
|
|
2969
|
-
);
|
|
2970
|
-
|
|
2971
|
-
carData.method = 'off_line';
|
|
2972
|
-
await OrderEvent.insertOrder({
|
|
2973
|
-
cartData: carData,
|
|
2974
|
-
status: 1,
|
|
2975
|
-
app: this.app,
|
|
2976
|
-
});
|
|
2977
|
-
if (carData.use_wallet > 0) {
|
|
2978
|
-
new Invoice(this.app).postCheckoutInvoice(carData.orderID, false);
|
|
2979
|
-
}
|
|
2980
|
-
await Promise.all(saveStockArray.map(dd => dd()));
|
|
2981
|
-
checkPoint('insert order & create invoice');
|
|
2982
|
-
|
|
2983
|
-
return {
|
|
2984
|
-
is_free: true,
|
|
2985
|
-
return_url: `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&return=${id}`,
|
|
2986
|
-
};
|
|
2987
|
-
} else {
|
|
2988
|
-
const keyData = (
|
|
2989
|
-
await Private_config.getConfig({
|
|
2990
|
-
appName: this.app,
|
|
2991
|
-
key: 'glitter_finance',
|
|
2992
|
-
})
|
|
2993
|
-
)[0].value;
|
|
2994
|
-
let kd = keyData[carData.customer_info.payment_select] ?? {
|
|
2995
|
-
ReturnURL: '',
|
|
2996
|
-
NotifyURL: '',
|
|
2997
|
-
};
|
|
2998
|
-
// 金流處理
|
|
2999
|
-
switch (carData.customer_info.payment_select) {
|
|
3000
|
-
case 'ecPay':
|
|
3001
|
-
case 'newWebPay':
|
|
3002
|
-
const subMitData = await new FinancialService(this.app, {
|
|
3003
|
-
HASH_IV: kd.HASH_IV,
|
|
3004
|
-
HASH_KEY: kd.HASH_KEY,
|
|
3005
|
-
ActionURL: kd.ActionURL,
|
|
3006
|
-
NotifyURL: `${process.env.DOMAIN}/api-public/v1/ec/notify?g-app=${this.app}&type=${carData.customer_info.payment_select}`,
|
|
3007
|
-
ReturnURL: `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&return=${id}`,
|
|
3008
|
-
MERCHANT_ID: kd.MERCHANT_ID,
|
|
3009
|
-
TYPE: carData.customer_info.payment_select,
|
|
3010
|
-
}).createOrderPage(carData);
|
|
3011
|
-
await Promise.all(
|
|
3012
|
-
saveStockArray.map(dd => {
|
|
3013
|
-
return dd();
|
|
3014
|
-
})
|
|
3015
|
-
);
|
|
3016
|
-
checkPoint('select newWebPay');
|
|
3017
|
-
|
|
3018
|
-
return {
|
|
3019
|
-
form: subMitData,
|
|
3020
|
-
};
|
|
3021
|
-
case 'paypal':
|
|
3022
|
-
kd.ReturnURL = `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&return=${id}`;
|
|
3023
|
-
kd.NotifyURL = `${process.env.DOMAIN}/api-public/v1/ec/notify?g-app=${this.app}&type=${carData.customer_info.payment_select}`;
|
|
3024
|
-
await Promise.all(
|
|
3025
|
-
saveStockArray.map(dd => {
|
|
3026
|
-
return dd();
|
|
3027
|
-
})
|
|
3028
|
-
);
|
|
3029
|
-
checkPoint('select paypal');
|
|
3030
|
-
return await new PayPal(this.app, kd).checkout(carData);
|
|
3031
|
-
case 'line_pay':
|
|
3032
|
-
kd.ReturnURL = `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&return=${id}&type=${carData.customer_info.payment_select}`;
|
|
3033
|
-
kd.NotifyURL = `${process.env.DOMAIN}/api-public/v1/ec/notify?g-app=${this.app}&type=${carData.customer_info.payment_select}`;
|
|
3034
|
-
await Promise.all(
|
|
3035
|
-
saveStockArray.map(dd => {
|
|
3036
|
-
return dd();
|
|
3037
|
-
})
|
|
3038
|
-
);
|
|
3039
|
-
checkPoint('select linepay');
|
|
3040
|
-
|
|
3041
|
-
return await new LinePay(this.app, kd).createOrder(carData);
|
|
3042
|
-
case 'paynow': {
|
|
3043
|
-
kd.ReturnURL = `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&return=${id}&type=${carData.customer_info.payment_select}`;
|
|
3044
|
-
kd.NotifyURL = `${process.env.DOMAIN}/api-public/v1/ec/notify?g-app=${this.app}&paynow=true&type=${carData.customer_info.payment_select}`;
|
|
3045
|
-
await Promise.all(
|
|
3046
|
-
saveStockArray.map(dd => {
|
|
3047
|
-
return dd();
|
|
3048
|
-
})
|
|
3049
|
-
);
|
|
3050
|
-
checkPoint('select paynow');
|
|
3051
|
-
return await new PayNow(this.app, kd).createOrder(carData);
|
|
3052
|
-
}
|
|
3053
|
-
case 'jkopay': {
|
|
3054
|
-
kd.ReturnURL = `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&jkopay=true&return=${id}`;
|
|
3055
|
-
kd.NotifyURL = `${process.env.DOMAIN}/api-public/v1/ec/notify?g-app=${this.app}&type=jkopay&return=${id}`;
|
|
3056
|
-
checkPoint('select jkopay');
|
|
3057
|
-
return await new JKO(this.app, kd).createOrder(carData);
|
|
3058
|
-
}
|
|
3059
|
-
default:
|
|
3060
|
-
carData.method = 'off_line';
|
|
3061
|
-
await OrderEvent.insertOrder({
|
|
3062
|
-
cartData: carData,
|
|
3063
|
-
status: 0,
|
|
3064
|
-
app: this.app,
|
|
3065
|
-
});
|
|
3066
|
-
await Promise.all(
|
|
3067
|
-
saveStockArray.map(dd => {
|
|
3068
|
-
return dd();
|
|
3069
|
-
})
|
|
3070
|
-
);
|
|
3071
|
-
// 訂單成立信件通知
|
|
3072
|
-
new ManagerNotify(this.app).checkout({
|
|
3073
|
-
orderData: carData,
|
|
3074
|
-
status: 0,
|
|
3075
|
-
});
|
|
3076
|
-
for (const phone of new Set(
|
|
3077
|
-
[carData.customer_info, carData.user_info].map(dd => {
|
|
3078
|
-
return dd && dd.phone;
|
|
3079
|
-
})
|
|
3080
|
-
)) {
|
|
3081
|
-
let sns = new SMS(this.app);
|
|
3082
|
-
await sns.sendCustomerSns('auto-sns-order-create', carData.orderID, phone);
|
|
3083
|
-
console.info('訂單簡訊寄送成功');
|
|
3084
|
-
}
|
|
3085
1742
|
|
|
3086
|
-
if (carData.customer_info.lineID) {
|
|
3087
|
-
let line = new LineMessage(this.app);
|
|
3088
|
-
await line.sendCustomerLine('auto-line-order-create', carData.orderID, carData.customer_info.lineID);
|
|
3089
|
-
console.info('訂單line訊息寄送成功');
|
|
3090
|
-
}
|
|
3091
|
-
// if (carData.customer_info.fb_id) {
|
|
3092
|
-
// let fb = new FbMessage(this.app)
|
|
3093
|
-
// await fb.sendCustomerFB('auto-fb-order-create', carData.orderID, carData.customer_info.fb_id);
|
|
3094
|
-
// console.info('訂單FB訊息寄送成功');
|
|
3095
|
-
// }
|
|
3096
|
-
for (const email of new Set(
|
|
3097
|
-
[carData.customer_info, carData.user_info].map(dd => {
|
|
3098
|
-
return dd && dd.email;
|
|
3099
|
-
})
|
|
3100
|
-
)) {
|
|
3101
|
-
if (email) {
|
|
3102
|
-
await AutoFcm.orderChangeInfo({
|
|
3103
|
-
app: this.app,
|
|
3104
|
-
tag: 'order-create',
|
|
3105
|
-
order_id: carData.orderID,
|
|
3106
|
-
phone_email: email,
|
|
3107
|
-
});
|
|
3108
|
-
AutoSendEmail.customerOrder(
|
|
3109
|
-
this.app,
|
|
3110
|
-
'auto-email-order-create',
|
|
3111
|
-
carData.orderID,
|
|
3112
|
-
email,
|
|
3113
|
-
carData.language!!
|
|
3114
|
-
);
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
|
-
|
|
3118
|
-
await this.releaseVoucherHistory(carData.orderID, 1);
|
|
3119
|
-
checkPoint('default release checkout');
|
|
3120
|
-
return {
|
|
3121
|
-
off_line: true,
|
|
3122
|
-
return_url: `${process.env.DOMAIN}/api-public/v1/ec/redirect?g-app=${this.app}&return=${id}`,
|
|
3123
|
-
};
|
|
3124
|
-
}
|
|
3125
|
-
}
|
|
3126
|
-
} catch (e) {
|
|
3127
|
-
console.error(e);
|
|
3128
|
-
throw exception.BadRequestError('BAD_REQUEST', 'ToCheckout Func Error:' + e, null);
|
|
3129
|
-
}
|
|
3130
|
-
}
|
|
3131
1743
|
|
|
3132
1744
|
async repayOrder(orderID: string, return_url: string) {
|
|
3133
1745
|
const app = this.app;
|
|
@@ -3620,7 +2232,7 @@ export class Shopping {
|
|
|
3620
2232
|
orderData,
|
|
3621
2233
|
});
|
|
3622
2234
|
for (const [index, order] of splitOrderArray.entries()) {
|
|
3623
|
-
await this.toCheckout(
|
|
2235
|
+
await (new CheckoutEvent(this.app, this.token)).toCheckout(
|
|
3624
2236
|
{
|
|
3625
2237
|
code_array: [],
|
|
3626
2238
|
order_id: orderData?.splitOrders?.[index] ?? '',
|