ts-glitter 20.6.7 → 20.6.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.
Files changed (160) hide show
  1. package/lowcode/Entry.js +2 -2
  2. package/lowcode/Entry.ts +2 -2
  3. package/lowcode/backend-manager/bg-blog.js +617 -621
  4. package/lowcode/backend-manager/bg-blog.ts +2323 -2325
  5. package/lowcode/backend-manager/bg-line.js +5 -4
  6. package/lowcode/backend-manager/bg-line.ts +5 -4
  7. package/lowcode/backend-manager/bg-list-component.js +9 -0
  8. package/lowcode/backend-manager/bg-list-component.ts +15 -1
  9. package/lowcode/backend-manager/bg-notify.js +6 -4
  10. package/lowcode/backend-manager/bg-notify.ts +6 -4
  11. package/lowcode/backend-manager/bg-product.js +145 -0
  12. package/lowcode/backend-manager/bg-product.ts +153 -0
  13. package/lowcode/backend-manager/bg-sns.js +5 -3
  14. package/lowcode/backend-manager/bg-sns.ts +5 -3
  15. package/lowcode/backend-manager/bg-widget.js +92 -4
  16. package/lowcode/backend-manager/bg-widget.ts +122 -6
  17. package/lowcode/backend-manager/splitPage.js +0 -39
  18. package/lowcode/backend-manager/splitPage.ts +0 -40
  19. package/lowcode/cms-plugin/auto-fcm-advertise.js +17 -5
  20. package/lowcode/cms-plugin/auto-fcm-advertise.ts +19 -6
  21. package/lowcode/cms-plugin/auto-fcm-history.js +2732 -0
  22. package/lowcode/cms-plugin/auto-fcm-history.ts +2995 -0
  23. package/lowcode/cms-plugin/cms-router.js +5 -0
  24. package/lowcode/cms-plugin/cms-router.ts +6 -0
  25. package/lowcode/cms-plugin/filter-options.js +80 -27
  26. package/lowcode/cms-plugin/filter-options.ts +83 -27
  27. package/lowcode/cms-plugin/language-backend.js +50 -39
  28. package/lowcode/cms-plugin/language-backend.ts +109 -95
  29. package/lowcode/cms-plugin/menus-setting.js +175 -151
  30. package/lowcode/cms-plugin/menus-setting.ts +620 -591
  31. package/lowcode/cms-plugin/model/order.d.ts +1 -0
  32. package/lowcode/cms-plugin/module/data.js +7 -7
  33. package/lowcode/cms-plugin/module/data.ts +262 -233
  34. package/lowcode/cms-plugin/module/delivery-html.js +18 -10
  35. package/lowcode/cms-plugin/module/delivery-html.ts +26 -10
  36. package/lowcode/cms-plugin/module/order-setting.js +458 -328
  37. package/lowcode/cms-plugin/module/order-setting.ts +622 -351
  38. package/lowcode/cms-plugin/module/product-excel.js +1 -1
  39. package/lowcode/cms-plugin/module/product-excel.ts +2 -1
  40. package/lowcode/cms-plugin/order/order-module.js +90 -1
  41. package/lowcode/cms-plugin/order/order-module.ts +106 -1
  42. package/lowcode/cms-plugin/pos-pages/payment-page.js +11 -8
  43. package/lowcode/cms-plugin/pos-pages/payment-page.ts +28 -15
  44. package/lowcode/cms-plugin/pos-pages/products-page.js +0 -39
  45. package/lowcode/cms-plugin/pos-pages/products-page.ts +0 -40
  46. package/lowcode/cms-plugin/shopping-collections.ts +1 -3
  47. package/lowcode/cms-plugin/shopping-finance-setting.js +19 -80
  48. package/lowcode/cms-plugin/shopping-finance-setting.ts +19 -87
  49. package/lowcode/cms-plugin/shopping-order-manager.js +122 -38
  50. package/lowcode/cms-plugin/shopping-order-manager.ts +160 -58
  51. package/lowcode/cms-plugin/shopping-product-setting.js +364 -376
  52. package/lowcode/cms-plugin/shopping-product-setting.ts +406 -415
  53. package/lowcode/cms-plugin/shopping-setting-advance.js +57 -16
  54. package/lowcode/cms-plugin/shopping-setting-advance.ts +69 -18
  55. package/lowcode/cms-plugin/user/user-module.js +2 -43
  56. package/lowcode/cms-plugin/user/user-module.ts +2 -46
  57. package/lowcode/cms-plugin/user-list.js +4 -6
  58. package/lowcode/cms-plugin/user-list.ts +35 -38
  59. package/lowcode/css/editor.css +42 -3
  60. package/lowcode/glitter-base/global/language.js +6 -1
  61. package/lowcode/glitter-base/global/language.ts +10 -4
  62. package/lowcode/glitter-base/global/payment-config.js +19 -16
  63. package/lowcode/glitter-base/global/payment-config.ts +22 -16
  64. package/lowcode/glitter-base/global/shipment-config.js +6 -5
  65. package/lowcode/glitter-base/global/shipment-config.ts +12 -10
  66. package/lowcode/glitter-base/route/fcm.js +21 -1
  67. package/lowcode/glitter-base/route/fcm.ts +22 -2
  68. package/lowcode/glitter-base/route/shopping.js +8 -32
  69. package/lowcode/glitter-base/route/shopping.ts +10 -33
  70. package/lowcode/glitter-base/route/user.js +11 -2
  71. package/lowcode/glitter-base/route/user.ts +23 -12
  72. package/lowcode/jspage/function-page/setting_editor.js +9 -0
  73. package/lowcode/jspage/function-page/setting_editor.ts +9 -0
  74. package/lowcode/public-components/blogs/list.js +223 -195
  75. package/lowcode/public-components/blogs/list.ts +383 -352
  76. package/lowcode/public-components/product/product-list.js +8 -4
  77. package/lowcode/public-components/product/product-list.ts +9 -4
  78. package/lowcode/public-components/terms-related/index.js +1 -1
  79. package/lowcode/public-components/terms-related/index.ts +1 -1
  80. package/lowcode/public-components/user-manager/um-login.js +1 -1
  81. package/lowcode/public-components/user-manager/um-login.ts +2 -2
  82. package/lowcode/public-components/user-manager/um-order.js +41 -5
  83. package/lowcode/public-components/user-manager/um-order.ts +58 -20
  84. package/lowcode/public-components/user-manager/um-voucher.ts +2 -2
  85. package/nhi4veq3gk.json +1 -0
  86. package/package.json +1 -1
  87. package/src/Language.d.ts +2 -0
  88. package/src/Language.js +66 -65
  89. package/src/Language.js.map +1 -1
  90. package/src/Language.ts +719 -715
  91. package/src/api-public/config/shipment-config.js +3 -2
  92. package/src/api-public/config/shipment-config.js.map +1 -1
  93. package/src/api-public/config/shipment-config.ts +3 -2
  94. package/src/api-public/controllers/ai-chat.js.map +1 -1
  95. package/src/api-public/controllers/ai-chat.ts +1 -2
  96. package/src/api-public/controllers/fcm.js +23 -58
  97. package/src/api-public/controllers/fcm.js.map +1 -1
  98. package/src/api-public/controllers/fcm.ts +28 -56
  99. package/src/api-public/controllers/shop.js +7 -1
  100. package/src/api-public/controllers/shop.js.map +1 -1
  101. package/src/api-public/controllers/shop.ts +17 -10
  102. package/src/api-public/controllers/user.js +1 -0
  103. package/src/api-public/controllers/user.js.map +1 -1
  104. package/src/api-public/controllers/user.ts +2 -0
  105. package/src/api-public/services/auto-send-email.js +247 -187
  106. package/src/api-public/services/auto-send-email.js.map +1 -1
  107. package/src/api-public/services/auto-send-email.ts +568 -505
  108. package/src/api-public/services/delivery.js +1 -1
  109. package/src/api-public/services/delivery.js.map +1 -1
  110. package/src/api-public/services/delivery.ts +6 -5
  111. package/src/api-public/services/financial-service.js +1 -2
  112. package/src/api-public/services/financial-service.js.map +1 -1
  113. package/src/api-public/services/financial-service.ts +4 -6
  114. package/src/api-public/services/manager.d.ts +4 -3
  115. package/src/api-public/services/manager.js +8 -12
  116. package/src/api-public/services/manager.js.map +1 -1
  117. package/src/api-public/services/manager.ts +57 -59
  118. package/src/api-public/services/model/handlePaymentTransaction.d.ts +1 -1
  119. package/src/api-public/services/model/handlePaymentTransaction.js +23 -3
  120. package/src/api-public/services/model/handlePaymentTransaction.js.map +1 -1
  121. package/src/api-public/services/model/handlePaymentTransaction.ts +25 -36
  122. package/src/api-public/services/schedule.d.ts +1 -0
  123. package/src/api-public/services/schedule.js +27 -0
  124. package/src/api-public/services/schedule.js.map +1 -1
  125. package/src/api-public/services/schedule.ts +30 -0
  126. package/src/api-public/services/shopping.d.ts +22 -2
  127. package/src/api-public/services/shopping.js +362 -90
  128. package/src/api-public/services/shopping.js.map +1 -1
  129. package/src/api-public/services/shopping.ts +481 -134
  130. package/src/api-public/services/user.d.ts +1 -0
  131. package/src/api-public/services/user.js +36 -16
  132. package/src/api-public/services/user.js.map +1 -1
  133. package/src/api-public/services/user.ts +42 -23
  134. package/src/api-public/services/workers.js +3 -3
  135. package/src/api-public/services/workers.js.map +1 -1
  136. package/src/api-public/services/workers.ts +103 -103
  137. package/src/app-project/serverless/src/modules/database.js +1 -1
  138. package/src/app-project/serverless/src/modules/database.js.map +1 -1
  139. package/src/app-project/serverless/src/modules/database.ts +171 -171
  140. package/src/controllers/template.d.ts +1 -1
  141. package/src/controllers/template.js +16 -16
  142. package/src/controllers/template.js.map +1 -1
  143. package/src/controllers/template.ts +98 -84
  144. package/src/modules/database.js +3 -1
  145. package/src/modules/database.js.map +1 -1
  146. package/src/modules/database.ts +185 -181
  147. package/src/modules/firebase.d.ts +17 -0
  148. package/src/modules/firebase.js +126 -0
  149. package/src/modules/firebase.js.map +1 -1
  150. package/src/modules/firebase.ts +169 -0
  151. package/src/public-config-initial/auto-fcm.js +8 -2
  152. package/src/public-config-initial/auto-fcm.js.map +1 -1
  153. package/src/public-config-initial/auto-fcm.ts +15 -6
  154. package/src/services/app.d.ts +2 -1
  155. package/src/services/app.js.map +1 -1
  156. package/src/services/app.ts +2 -1
  157. package/src/services/template.d.ts +3 -2
  158. package/src/services/template.js +2 -1
  159. package/src/services/template.js.map +1 -1
  160. package/src/services/template.ts +13 -20
@@ -34,8 +34,8 @@ import { ProductInitial } from './product-initial.js';
34
34
  import { UtTimer } from '../utils/ut-timer.js';
35
35
  import { AutoFcm } from '../../public-config-initial/auto-fcm.js';
36
36
  import PaymentTransaction from './model/handlePaymentTransaction.js';
37
+ import { Language, LanguageLocation } from '../../Language.js';
37
38
  import { CartItem, CheckoutEvent } from './checkout-event.js';
38
-
39
39
  type BindItem = {
40
40
  id: string;
41
41
  spec: string[];
@@ -206,16 +206,17 @@ class OrderDetail {
206
206
  custom_form_delivery?: any;
207
207
  shipment:
208
208
  | 'normal'
209
- | 'FAMIC2C'
210
209
  | 'black_cat_freezing'
211
- | 'UNIMARTC2C'
212
- | 'HILIFEC2C'
213
- | 'OKMARTC2C'
214
210
  | 'now'
215
211
  | 'shop'
216
212
  | 'global_express'
217
213
  | 'black_cat'
218
- | 'UNIMARTFREEZE';
214
+ | 'UNIMARTC2C'
215
+ | 'FAMIC2C'
216
+ | 'HILIFEC2C'
217
+ | 'OKMARTC2C'
218
+ | 'UNIMARTFREEZE'
219
+ | 'FAMIC2CFREEZE';
219
220
  CVSStoreName: string;
220
221
  CVSStoreID: string;
221
222
  CVSTelephone: string;
@@ -396,6 +397,8 @@ export class Shopping {
396
397
  max_price?: string;
397
398
  status?: string;
398
399
  channel?: string;
400
+ general_tag?: string;
401
+ manager_tag?: string;
399
402
  whereStore?: string;
400
403
  order_by?: string;
401
404
  id_list?: string;
@@ -424,6 +427,9 @@ export class Shopping {
424
427
  query.language = query.language ?? store_info.language_setting.def;
425
428
  query.show_hidden = query.show_hidden ?? 'true';
426
429
 
430
+ // 初始化商品與管理員標籤 Config
431
+ // await Promise.all([this.initProductCustomizeTagConifg(), this.initProductGeneralTagConifg()]);
432
+
427
433
  const orderMapping: Record<string, string> = {
428
434
  title: `ORDER BY JSON_EXTRACT(content, '$.title')`,
429
435
  max_price: `ORDER BY CAST(JSON_UNQUOTE(JSON_EXTRACT(content, '$.max_price')) AS SIGNED) DESC , id DESC`,
@@ -521,12 +527,12 @@ export class Shopping {
521
527
  // 當非管理員時,檢查是否顯示隱形商品
522
528
  if (query.filter_visible) {
523
529
  if (query.filter_visible === 'true') {
524
- querySql.push(`(content->>'$.visible' is null || content->>'$.visible' = 'true')`);
530
+ querySql.push(`(content->>'$.visible' IS NULL || content->>'$.visible' = 'true')`);
525
531
  } else {
526
532
  querySql.push(`(content->>'$.visible' = 'false')`);
527
533
  }
528
534
  } else if (!query.is_manger && `${query.show_hidden}` !== 'true') {
529
- querySql.push(`(content->>'$.visible' is null || content->>'$.visible' = 'true')`);
535
+ querySql.push(`(content->>'$.visible' IS NULL || content->>'$.visible' = 'true')`);
530
536
  }
531
537
 
532
538
  // 判斷有帶入商品類型時,顯示商品類型,反之預設折是一班商品
@@ -685,6 +691,29 @@ export class Shopping {
685
691
  }
686
692
  }
687
693
 
694
+ if (query.manager_tag) {
695
+ const tagSplit = query.manager_tag.split(',').map(tag => tag.trim());
696
+ if (tagSplit.length > 0) {
697
+ const tagJoin = tagSplit.map(tag => {
698
+ return `JSON_CONTAINS(content->>'$.product_customize_tag', '"${tag}"')`;
699
+ });
700
+ querySql.push(`(${tagJoin.join(' OR ')})`);
701
+ }
702
+ }
703
+
704
+ if (query.general_tag) {
705
+ const tagSplit = query.general_tag.split(',').map(tag => tag.trim());
706
+ if (tagSplit.length > 0) {
707
+ const tagJoin = tagSplit.map(tag => {
708
+ return `(JSON_CONTAINS(
709
+ JSON_EXTRACT(content, '$.product_tag.language."${query.language ?? 'zh-TW'}"'),
710
+ JSON_QUOTE('${tag}')
711
+ ))`;
712
+ });
713
+ querySql.push(`(${tagJoin.join(' OR ')})`);
714
+ }
715
+ }
716
+
688
717
  if (query.id_list && idStr) {
689
718
  querySql.push(`(id in (${idStr}))`);
690
719
  }
@@ -967,6 +996,7 @@ export class Shopping {
967
996
 
968
997
  products.data = foundProduct || products.data[0];
969
998
  }
999
+
970
1000
  if (query.id && products.data.length > 0) {
971
1001
  products.data = products.data[0];
972
1002
  }
@@ -1168,6 +1198,176 @@ export class Shopping {
1168
1198
  }
1169
1199
  }
1170
1200
 
1201
+ async initProductCustomizeTagConifg() {
1202
+ try {
1203
+ const managerTags = await new User(this.app).getConfigV2({ key: 'product_manager_tags', user_id: 'manager' });
1204
+ console.log(`initProductCustomizeTagConifg=>getData=>`,managerTags)
1205
+ if (managerTags && Array.isArray(managerTags.list)) {
1206
+ return managerTags;
1207
+ }
1208
+ console.log(`query_sql=>`,`SELECT
1209
+ GROUP_CONCAT(DISTINCT JSON_UNQUOTE(JSON_EXTRACT(content, '$.product_customize_tag')) SEPARATOR ',') AS unique_tags
1210
+ FROM \`${this.app}\`.t_manager_post
1211
+ WHERE JSON_UNQUOTE(JSON_EXTRACT(content, '$.type')) = 'product'`)
1212
+ const getData = await db.query(
1213
+ `
1214
+ SELECT
1215
+ GROUP_CONCAT(DISTINCT JSON_UNQUOTE(JSON_EXTRACT(content, '$.product_customize_tag')) SEPARATOR ',') AS unique_tags
1216
+ FROM \`${this.app}\`.t_manager_post
1217
+ WHERE JSON_UNQUOTE(JSON_EXTRACT(content, '$.type')) = 'product'
1218
+ `,
1219
+ []
1220
+ );
1221
+
1222
+ const unique_tags_string = getData[0]?.unique_tags ?? '';
1223
+ console.log(`JSON_STRING=>`,`[${unique_tags_string}]`)
1224
+ const unique_tags_array = JSON.parse(`[${unique_tags_string}]`);
1225
+ const unique_tags_flot = Array.isArray(unique_tags_array) ? unique_tags_array.flat() : [];
1226
+ const data = { list: [...new Set(unique_tags_flot)] };
1227
+ console.log(`product_manager_tags=>setData=>`,managerTags)
1228
+ await new User(this.app).setConfig({
1229
+ key: 'product_manager_tags',
1230
+ user_id: 'manager',
1231
+ value: data,
1232
+ });
1233
+
1234
+ return data;
1235
+ } catch (error) {
1236
+ throw exception.BadRequestError('BAD_REQUEST', 'Set product customize tag conifg Error:' + error, null);
1237
+ }
1238
+ }
1239
+
1240
+ async setProductCustomizeTagConifg(add_tags: string[]) {
1241
+ const tagConfig = await new User(this.app).getConfigV2({ key: 'product_manager_tags', user_id: 'manager' });
1242
+ const tagList = tagConfig?.list ?? [];
1243
+ const data = { list: [...new Set([...tagList, ...add_tags])] };
1244
+
1245
+ await new User(this.app).setConfig({
1246
+ key: 'product_manager_tags',
1247
+ user_id: 'manager',
1248
+ value: data,
1249
+ });
1250
+
1251
+ return data;
1252
+ }
1253
+
1254
+ async initProductGeneralTagConifg() {
1255
+ try {
1256
+ const generalTags = await new User(this.app).getConfigV2({ key: 'product_general_tags', user_id: 'manager' });
1257
+
1258
+ if (generalTags && Array.isArray(generalTags.list)) {
1259
+ return generalTags;
1260
+ }
1261
+ console.log(`initProductCustomizeTagConifg=>getData=>`,generalTags)
1262
+ const getData = await db.query(
1263
+ `
1264
+ SELECT
1265
+ GROUP_CONCAT(DISTINCT JSON_UNQUOTE(JSON_EXTRACT(content, '$.product_tag.language')) SEPARATOR ',') AS unique_tags
1266
+ FROM \`${this.app}\`.t_manager_post
1267
+ WHERE JSON_UNQUOTE(JSON_EXTRACT(content, '$.type')) = 'product'
1268
+ `,
1269
+ []
1270
+ );
1271
+ const unique_tags_string = getData[0]?.unique_tags ?? '';
1272
+ console.log(`JSON_STRING=>`,`[${unique_tags_string}]`)
1273
+ const unique_tags_array = JSON.parse(`[${unique_tags_string}]`);
1274
+ console.log(`JSON_DATA=>`,unique_tags_array)
1275
+ const unique_tags_flot = Array.isArray(unique_tags_array) ? unique_tags_array.flat() : [];
1276
+ const list: { [k in LanguageLocation]?: string[] } = {};
1277
+
1278
+ unique_tags_flot.map(item => {
1279
+ Language.locationList.map(lang => {
1280
+ list[lang] = [...(list[lang] ?? []), ...item[lang]];
1281
+ });
1282
+ });
1283
+
1284
+ Language.locationList.map(lang => {
1285
+ list[lang] = [...new Set(list[lang])];
1286
+ });
1287
+
1288
+ const data = { list };
1289
+ await new User(this.app).setConfig({
1290
+ key: 'product_general_tags',
1291
+ user_id: 'manager',
1292
+ value: data,
1293
+ });
1294
+
1295
+ return data;
1296
+ } catch (error) {
1297
+ throw exception.BadRequestError('BAD_REQUEST', 'Set product general tag conifg Error:' + error, null);
1298
+ }
1299
+ }
1300
+
1301
+ async setProductGeneralTagConifg(add_tags: { [k in LanguageLocation]: string[] }) {
1302
+ const tagConfig =
1303
+ (await new User(this.app).getConfigV2({ key: 'product_general_tags', user_id: 'manager' })) ??
1304
+ (await this.initProductGeneralTagConifg());
1305
+
1306
+ tagConfig.list ??= {};
1307
+
1308
+ Language.locationList.map(lang => {
1309
+ const originList = tagConfig.list[lang] ?? [];
1310
+ const updateList = add_tags[lang];
1311
+ tagConfig.list[lang] = [...new Set([...originList, ...updateList])];
1312
+ });
1313
+
1314
+ await new User(this.app).setConfig({
1315
+ key: 'product_general_tags',
1316
+ user_id: 'manager',
1317
+ value: tagConfig,
1318
+ });
1319
+
1320
+ return tagConfig;
1321
+ }
1322
+
1323
+ async initOrderCustomizeTagConifg() {
1324
+ try {
1325
+ const managerTags = await new User(this.app).getConfigV2({ key: 'order_manager_tags', user_id: 'manager' });
1326
+
1327
+ if (managerTags && Array.isArray(managerTags.list)) {
1328
+ return managerTags;
1329
+ }
1330
+
1331
+ const getData = await db.query(
1332
+ `
1333
+ SELECT
1334
+ GROUP_CONCAT(DISTINCT JSON_UNQUOTE(JSON_EXTRACT(orderData, '$.tags')) SEPARATOR ',') AS unique_tags
1335
+ FROM \`${this.app}\`.t_checkout
1336
+ WHERE JSON_UNQUOTE(JSON_EXTRACT(orderData, '$.tags')) IS NOT NULL
1337
+ `,
1338
+ []
1339
+ );
1340
+ const unique_tags_string = getData[0]?.unique_tags ?? '';
1341
+ const unique_tags_array = JSON.parse(`[${unique_tags_string}]`);
1342
+ const unique_tags_flot = Array.isArray(unique_tags_array) ? unique_tags_array.flat() : [];
1343
+ const data = { list: [...new Set(unique_tags_flot)] };
1344
+
1345
+ await new User(this.app).setConfig({
1346
+ key: 'order_manager_tags',
1347
+ user_id: 'manager',
1348
+ value: data,
1349
+ });
1350
+
1351
+ return data;
1352
+ } catch (error) {
1353
+ throw exception.BadRequestError('BAD_REQUEST', 'Set order customize tag conifg Error:' + e, null);
1354
+ }
1355
+ }
1356
+
1357
+ async setOrderCustomizeTagConifg(add_tags: string[]) {
1358
+ const tagConfig = await new User(this.app).getConfigV2({ key: 'order_manager_tags', user_id: 'manager' });
1359
+ const tagList = tagConfig?.list ?? [];
1360
+ const data = { list: [...new Set([...tagList, ...add_tags])] };
1361
+
1362
+ await new User(this.app).setConfig({
1363
+ key: 'order_manager_tags',
1364
+ user_id: 'manager',
1365
+ value: data,
1366
+ });
1367
+
1368
+ return data;
1369
+ }
1370
+
1171
1371
  async getAllUseVoucher(userID: any): Promise<VoucherData[]> {
1172
1372
  const now = Date.now();
1173
1373
 
@@ -1792,7 +1992,7 @@ export class Shopping {
1792
1992
  count: number;
1793
1993
  voucher_id: string;
1794
1994
  }[];
1795
- language?: 'en-US' | 'zh-CN' | 'zh-TW';
1995
+ language?: LanguageLocation;
1796
1996
  pos_info?: any; //POS結帳資訊;
1797
1997
  invoice_select?: string;
1798
1998
  pre_order?: boolean;
@@ -1843,8 +2043,11 @@ export class Shopping {
1843
2043
  ReturnURL: '',
1844
2044
  NotifyURL: '',
1845
2045
  };
2046
+ //現在是new一個新的版本
2047
+ //todo 新增一個fake單號 直接做付款的動作 同時做訂單上的更新把這個付款單號記錄下來
1846
2048
  const newOrderID = Date.now();
1847
2049
  const carData: Cart = {
2050
+ orderID: `${newOrderID}`,
1848
2051
  discount: orderData.discount ?? 0,
1849
2052
  customer_info: orderData.customer_info || {},
1850
2053
  lineItems: orderData.lineItems ?? [],
@@ -1855,7 +2058,6 @@ export class Shopping {
1855
2058
  rebate: orderData.rebate ?? 0,
1856
2059
  goodsWeight: 0,
1857
2060
  use_rebate: orderData.use_rebate || 0,
1858
- orderID: `${newOrderID}`,
1859
2061
  shipment_support: shipment_setting.support as any,
1860
2062
  shipment_info: shipment_setting.info as any,
1861
2063
  shipment_selector: [
@@ -1890,10 +2092,17 @@ export class Shopping {
1890
2092
  fbp: sqlData.fbp as string,
1891
2093
  editRecord: [],
1892
2094
  };
1893
- console.log("orderData.customer_info.payment_select -- " , orderData.customer_info.payment_select);
1894
- const result = await new PaymentTransaction(this.app, orderData.customer_info.payment_select).processPayment(carData);
2095
+ await OrderEvent.insertOrder({
2096
+ cartData: orderData,
2097
+ status: 0,
2098
+ app: this.app,
2099
+ });
2100
+ const result = await new PaymentTransaction(this.app, orderData.customer_info.payment_select).processPayment(
2101
+ carData,
2102
+ return_url
2103
+ );
1895
2104
 
1896
- return result
2105
+ return result;
1897
2106
  }
1898
2107
 
1899
2108
  // return result
@@ -1967,7 +2176,7 @@ export class Shopping {
1967
2176
  if (query.archived === 'true') {
1968
2177
  querySql.push(`(archived="${query.archived}")`);
1969
2178
  } else if (query.archived === 'false') {
1970
- querySql.push(`((archived is null) or (archived!='true'))`);
2179
+ querySql.push(`((archived IS NULL) or (archived!='true'))`);
1971
2180
  }
1972
2181
  //退貨貨款狀態
1973
2182
  query.status && querySql.push(`status IN (${query.status})`);
@@ -2188,6 +2397,56 @@ export class Shopping {
2188
2397
 
2189
2398
  async splitOrder(obj: { orderData: Cart; splitOrderArray: OrderDetail[] }) {
2190
2399
  try {
2400
+ async function processCheckoutsStaggered(
2401
+ splitOrderArray: any[],
2402
+ orderData: any,
2403
+ context: any
2404
+ ): Promise<boolean | { result: string; reason: any }> {
2405
+ const promises = splitOrderArray.map((order, index) => {
2406
+ // 為每個操作返回一個新的 Promise
2407
+ return new Promise<void>((resolve, reject) => {
2408
+ // 可以定義更精確的 resolve 型別,這裡用 void 示意
2409
+ const delay = 1000 * index; // 計算延遲時間
2410
+
2411
+ setTimeout(() => {
2412
+ // 在 setTimeout 回呼中執行非同步操作
2413
+ const payload = {
2414
+ code_array: [],
2415
+ order_id: orderData?.splitOrders?.[index] ?? '',
2416
+ line_items: order.lineItems as any,
2417
+ customer_info: order.customer_info,
2418
+ return_url: '',
2419
+ user_info: order.user_info,
2420
+ discount: order.discount,
2421
+ voucher: order.voucher,
2422
+ total: order.total,
2423
+ pay_status: Number(order.pay_status),
2424
+ };
2425
+
2426
+ // 假設 context.toCheckout 本身返回一個 Promise
2427
+ context
2428
+ .toCheckout(payload, 'split')
2429
+ .then(() => {
2430
+ resolve(); // 當 toCheckout 成功時,resolve 外層的 Promise
2431
+ })
2432
+ .catch((error: any) => {
2433
+ reject(error); // 當 toCheckout 失敗時,reject 外層的 Promise
2434
+ });
2435
+ }, delay); // 使用計算出的延遲
2436
+ });
2437
+ }); // map 結束
2438
+
2439
+ try {
2440
+ await Promise.all(promises);
2441
+ return true; // 全部成功
2442
+ } catch (e) {
2443
+ console.error('處理拆分訂單結帳時至少發生一個錯誤 (從 Promise.all 捕獲):', e);
2444
+ return {
2445
+ result: 'failure',
2446
+ reason: e, // 返回捕獲到的錯誤
2447
+ };
2448
+ }
2449
+ }
2191
2450
  const currentTime = new Date().toISOString();
2192
2451
 
2193
2452
  //給定訂單編號 產生 編號A 編號B... 依此類推
@@ -2203,8 +2462,7 @@ export class Shopping {
2203
2462
 
2204
2463
  return orderIdArray;
2205
2464
  }
2206
-
2207
- //整理原本訂單的總價 優惠卷
2465
+ //整理原本訂單的總價 優惠卷的資訊 方便原本的訂單更新
2208
2466
  function refreshOrder(orderData: Cart, splitOrderArray: OrderDetail[]) {
2209
2467
  const { newTotal, newDiscount } = splitOrderArray.reduce(
2210
2468
  (acc, order) => {
@@ -2231,37 +2489,7 @@ export class Shopping {
2231
2489
  cart_token: orderData.orderID,
2232
2490
  orderData,
2233
2491
  });
2234
- for (const [index, order] of splitOrderArray.entries()) {
2235
- await (new CheckoutEvent(this.app, this.token)).toCheckout(
2236
- {
2237
- code_array: [],
2238
- order_id: orderData?.splitOrders?.[index] ?? '',
2239
- line_items: order.lineItems as any,
2240
- customer_info: order.customer_info,
2241
- return_url: '',
2242
- user_info: order.user_info,
2243
- discount: order.discount,
2244
- voucher: order.voucher,
2245
- total: order.total,
2246
- pay_status: Number(order.pay_status),
2247
- },
2248
- 'split'
2249
- );
2250
- }
2251
-
2252
- // try {
2253
- // await db.query(
2254
- // `UPDATE \`${this.app}\`.t_checkout
2255
- // SET orderData = ?
2256
- // WHERE cart_token = ?;`,
2257
- // [JSON.stringify(orderData), orderData.orderID]
2258
- // );
2259
- // }catch (e:any){
2260
- // console.error(e);
2261
- // throw exception.BadRequestError('BAD_REQUEST', 'putOrder Error:' + e, null);
2262
- // }
2263
-
2264
- return true;
2492
+ return await processCheckoutsStaggered(splitOrderArray, orderData, this);
2265
2493
  } catch (e) {
2266
2494
  throw exception.BadRequestError('BAD_REQUEST', 'splitOrder Error:' + e, null);
2267
2495
  }
@@ -2737,7 +2965,6 @@ export class Shopping {
2737
2965
  // 恢復取消訂單的庫存
2738
2966
  orderData.lineItems = resetLineItems(orderData.lineItems);
2739
2967
  origin.orderData.lineItems = resetLineItems(origin.orderData.lineItems);
2740
-
2741
2968
  // 釋放優惠券
2742
2969
  await this.releaseVoucherHistory(orderData.orderID, orderData.orderStatus === '-1' ? 0 : 1);
2743
2970
 
@@ -2783,7 +3010,14 @@ export class Shopping {
2783
3010
 
2784
3011
  // 當訂單出貨狀態變更,觸發通知事件
2785
3012
  const updateProgress = update.orderData.progress;
2786
- if (prevProgress !== updateProgress) {
3013
+
3014
+ if (
3015
+ updateProgress === 'wait' &&
3016
+ update.orderData.user_info.shipment_number &&
3017
+ update.orderData.user_info.shipment_number !== origin.orderData.user_info.shipment_number
3018
+ ) {
3019
+ await this.sendNotifications(orderData, 'in_stock');
3020
+ } else if (prevProgress !== updateProgress) {
2787
3021
  if (updateProgress === 'shipping') {
2788
3022
  await this.sendNotifications(orderData, 'shipment');
2789
3023
  } else if (updateProgress === 'arrived') {
@@ -2812,13 +3046,16 @@ export class Shopping {
2812
3046
  {}
2813
3047
  );
2814
3048
  await db.query(
2815
- `UPDATE \`${this.app}\`.t_checkout
2816
- SET ?
2817
- WHERE id = ?;
3049
+ `UPDATE \`${this.app}\`.t_checkout SET ? WHERE id = ?;
2818
3050
  `,
2819
3051
  [updateData, origin.id]
2820
3052
  );
2821
3053
 
3054
+ // 更新訂單現有標籤
3055
+ if (Array.isArray(update.orderData.tags)) {
3056
+ await this.setOrderCustomizeTagConifg(update.orderData.tags);
3057
+ }
3058
+
2822
3059
  // 同步蝦皮商品
2823
3060
  await Promise.all(
2824
3061
  origin.orderData.lineItems.map(async (lineItem: any) => {
@@ -2999,12 +3236,13 @@ export class Shopping {
2999
3236
  /**
3000
3237
  * 寄送同時寄送購買人和寄件人
3001
3238
  * */
3002
- private async sendNotifications(orderData: any, type: 'shipment' | 'arrival') {
3239
+ private async sendNotifications(orderData: any, type: 'shipment' | 'arrival' | 'in_stock') {
3003
3240
  const { lineID } = orderData.customer_info;
3004
3241
  const messages = [];
3005
3242
  const typeMap = {
3006
3243
  shipment: 'shipment',
3007
3244
  arrival: 'shipment-arrival',
3245
+ in_stock: 'in-stock',
3008
3246
  };
3009
3247
 
3010
3248
  if (lineID) {
@@ -3245,12 +3483,19 @@ export class Shopping {
3245
3483
  payment_select?: string;
3246
3484
  is_reconciliation?: boolean;
3247
3485
  reconciliation_status?: string[];
3486
+ manager_tag?: string;
3487
+ member_levels?: string;
3248
3488
  }) {
3249
3489
  try {
3250
- let querySql = ['1=1'];
3251
- let orderString = 'order by id desc';
3252
3490
  const timer = new UtTimer('get-checkout-info');
3253
3491
  timer.checkPoint('start');
3492
+
3493
+ const querySql = ['o.id IS NOT NULL'];
3494
+ let orderString = 'order by created_time desc';
3495
+
3496
+ // 初始化訂單現有標籤
3497
+ await this.initOrderCustomizeTagConifg();
3498
+
3254
3499
  if (query.search && query.searchType) {
3255
3500
  switch (query.searchType) {
3256
3501
  case 'cart_token':
@@ -3305,7 +3550,7 @@ export class Shopping {
3305
3550
  let search: string[] = [];
3306
3551
  query.reconciliation_status!!.map(status => {
3307
3552
  if (status === 'pending_entry') {
3308
- search.push(`total_received is NULL`);
3553
+ search.push(`total_received IS NULL`);
3309
3554
  } else if (status === 'completed_entry') {
3310
3555
  search.push(`total_received = total`);
3311
3556
  } else if (status === 'refunded') {
@@ -3313,9 +3558,9 @@ export class Shopping {
3313
3558
  } else if (status === 'completed_offset') {
3314
3559
  search.push(`(total_received < total) && ((total_received + offset_amount) = total)`);
3315
3560
  } else if (status === 'pending_offset') {
3316
- search.push(`(total_received < total) && (offset_amount is null)`);
3561
+ search.push(`(total_received < total) && (offset_amount IS NULL)`);
3317
3562
  } else if (status === 'pending_refund') {
3318
- search.push(`(total_received > total) && (offset_amount is null)`);
3563
+ search.push(`(total_received > total) && (offset_amount IS NULL)`);
3319
3564
  }
3320
3565
  });
3321
3566
  querySql.push(
@@ -3326,6 +3571,7 @@ export class Shopping {
3326
3571
  .join(' or ')})`
3327
3572
  );
3328
3573
  }
3574
+
3329
3575
  if (query.orderStatus) {
3330
3576
  let orderArray = query.orderStatus.split(',');
3331
3577
  let temp = '';
@@ -3341,12 +3587,15 @@ export class Shopping {
3341
3587
 
3342
3588
  querySql.push(countingSQL);
3343
3589
  }
3590
+
3344
3591
  if (query.is_shipment) {
3345
3592
  querySql.push(`(shipment_number IS NOT NULL) and (shipment_number != '')`);
3346
3593
  }
3594
+
3347
3595
  if (query.is_reconciliation) {
3348
3596
  querySql.push(`((o.status in (1,-2)) or ((payment_method='cash_on_delivery' and progress='finish') ))`);
3349
3597
  }
3598
+
3350
3599
  if (query.payment_select) {
3351
3600
  querySql.push(
3352
3601
  `payment_method in (${query.payment_select
@@ -3355,13 +3604,14 @@ export class Shopping {
3355
3604
  .join(',')})`
3356
3605
  );
3357
3606
  }
3607
+
3358
3608
  if (query.progress) {
3359
3609
  //備貨中
3360
3610
  if (query.progress === 'in_stock') {
3361
3611
  query.progress = 'wait';
3362
3612
  querySql.push(`shipment_number is NOT null`);
3363
3613
  } else if (query.progress === 'wait') {
3364
- querySql.push(`shipment_number is null`);
3614
+ querySql.push(`shipment_number IS NULL`);
3365
3615
  }
3366
3616
  let newArray = query.progress.split(',');
3367
3617
  let temp = '';
@@ -3371,6 +3621,7 @@ export class Shopping {
3371
3621
  temp += `progress IN (${newArray.map(status => `"${status}"`).join(',')})`;
3372
3622
  querySql.push(`(${temp})`);
3373
3623
  }
3624
+
3374
3625
  if (query.distribution_code) {
3375
3626
  let codes = query.distribution_code.split(',');
3376
3627
  let temp = '';
@@ -3381,8 +3632,9 @@ export class Shopping {
3381
3632
  if (query.is_pos === 'true') {
3382
3633
  querySql.push(`order_source='POS'`);
3383
3634
  } else if (query.is_pos === 'false') {
3384
- querySql.push(`(order_source!='POS' or order_source is null)`);
3635
+ querySql.push(`(order_source!='POS' or order_source IS NULL)`);
3385
3636
  }
3637
+
3386
3638
  if (query.shipment) {
3387
3639
  let shipment = query.shipment.split(',');
3388
3640
  let temp = '';
@@ -3402,6 +3654,7 @@ export class Shopping {
3402
3654
  `);
3403
3655
  }
3404
3656
  }
3657
+
3405
3658
  if (query.shipment_time) {
3406
3659
  const shipment_time = query.shipment_time.split(',');
3407
3660
  if (shipment_time.length > 1) {
@@ -3428,37 +3681,104 @@ export class Shopping {
3428
3681
  break;
3429
3682
  }
3430
3683
  }
3431
- query.status && querySql.push(`o.status IN (${query.status})`);
3432
- const orderMath = [];
3433
3684
 
3434
- // JSON_EXTRACT(orderData, '$.customer_info.phone')
3685
+ if (query.manager_tag) {
3686
+ const tagSplit = query.manager_tag.split(',').map(tag => tag.trim());
3687
+ if (tagSplit.length > 0) {
3688
+ const tagJoin = tagSplit.map(tag => {
3689
+ return `JSON_CONTAINS(orderData->>'$.tags', '"${tag}"')`;
3690
+ });
3691
+ querySql.push(`(${tagJoin.join(' OR ')})`);
3692
+ }
3693
+ }
3694
+
3695
+ if (query.status) {
3696
+ querySql.push(`o.status IN (${query.status})`);
3697
+ }
3698
+
3699
+ const orderMath = [];
3435
3700
  query.email && orderMath.push(`(email=${db.escape(query.email)})`);
3436
3701
  query.phone && orderMath.push(`(email=${db.escape(query.phone)})`);
3437
3702
  if (orderMath.length) {
3438
- querySql.push(`(${orderMath.join(' or ')})`);
3703
+ querySql.push(`(${orderMath.join(' OR ')})`);
3704
+ }
3705
+
3706
+ if (query.member_levels) {
3707
+ let temp: string[] = [];
3708
+ const queryLevel = query.member_levels.split(',');
3709
+ const queryIdLevel = queryLevel.filter(level => level !== 'null');
3710
+
3711
+ if (queryLevel.includes('null')) {
3712
+ temp = [`u.member_level IS NULL`, `u.member_level = ''`];
3713
+ }
3714
+
3715
+ if (queryIdLevel.length > 0) {
3716
+ temp = [
3717
+ ...temp,
3718
+ `u.member_level IN (${queryIdLevel
3719
+ .map(level => {
3720
+ return db.escape(level);
3721
+ })
3722
+ .join(',')})`,
3723
+ ];
3724
+ }
3725
+
3726
+ if (temp.length > 0) {
3727
+ querySql.push(`(${temp.join(' OR ')})`);
3728
+ }
3439
3729
  }
3440
3730
 
3441
3731
  if (query.filter_type === 'true' || query.archived) {
3442
3732
  if (query.archived === 'true') {
3443
- querySql.push(`(archived="${query.archived}")
3444
- AND (order_status IS NULL OR order_status NOT IN (-99))`);
3733
+ querySql.push(`(archived="${query.archived}") AND (order_status IS NULL OR order_status NOT IN (-99))`);
3445
3734
  } else {
3446
- querySql.push(`((archived="${query.archived}") or (archived is null))`);
3735
+ querySql.push(`((archived="${query.archived}") or (archived IS NULL))`);
3447
3736
  }
3448
3737
  } else if (query.filter_type === 'normal') {
3449
- querySql.push(`((archived is null) or (archived!='true'))`);
3738
+ querySql.push(`((archived IS NULL) or (archived!='true'))`);
3450
3739
  }
3740
+
3451
3741
  if (!(query.filter_type === 'true' || query.archived)) {
3452
- querySql.push(`((order_status is null) or (order_status NOT IN (-99)))`);
3453
- }
3454
- let sql = `SELECT i.invoice_no,
3455
- i.invoice_data,
3456
- i.\`status\` as invoice_status,
3457
- o.*
3458
- FROM \`${this.app}\`.t_checkout o
3459
- LEFT JOIN \`${this.app}\`.t_invoice_memory i ON o.cart_token = i.order_id and i.status = 1
3460
- WHERE ${querySql.join(' and ')} ${orderString}`;
3461
- timer.checkPoint('start-query-sql');
3742
+ querySql.push(`((order_status IS NULL) or (order_status NOT IN (-99)))`);
3743
+ }
3744
+
3745
+ // 定義基礎查詢結構
3746
+ const baseSelect = `
3747
+ SELECT
3748
+ o.*,
3749
+ i.invoice_no,
3750
+ i.invoice_data,
3751
+ i.\`status\` as invoice_status
3752
+ FROM`;
3753
+
3754
+ const joinClause = `LEFT JOIN \`${this.app}\`.t_invoice_memory i ON o.cart_token = i.order_id AND i.status = 1`;
3755
+ const whereClause = `WHERE ${querySql.join(' AND ')}`;
3756
+
3757
+ let sql: string;
3758
+
3759
+ if (query.member_levels) {
3760
+ // 查詢會員等級資料
3761
+ sql = `
3762
+ (
3763
+ (
3764
+ ${baseSelect} \`${this.app}\`.t_user u
3765
+ LEFT JOIN \`${this.app}\`.t_checkout o ON o.email = u.phone
3766
+ ${joinClause}
3767
+ ${whereClause}
3768
+ )
3769
+ UNION
3770
+ (
3771
+ ${baseSelect} \`${this.app}\`.t_user u
3772
+ LEFT JOIN \`${this.app}\`.t_checkout o ON o.email = u.email
3773
+ ${joinClause}
3774
+ ${whereClause}
3775
+ )
3776
+ ) ${orderString}`;
3777
+ } else {
3778
+ // 直接查詢結帳資料
3779
+ sql = `${baseSelect} \`${this.app}\`.t_checkout o ${joinClause} ${whereClause} ${orderString}`;
3780
+ }
3781
+
3462
3782
  if (query.returnSearch == 'true') {
3463
3783
  const data = await db.query(
3464
3784
  `SELECT *
@@ -3487,43 +3807,35 @@ export class Shopping {
3487
3807
  }
3488
3808
  return data[0];
3489
3809
  }
3490
- const response_data: any = await new Promise(async (resolve, reject) => {
3491
- timer.checkPoint('start-query-response_data');
3810
+
3811
+ const response_data: any = await new Promise(async resolve => {
3492
3812
  if (query.id) {
3493
3813
  const data = (
3494
3814
  await db.query(
3495
- `SELECT *
3496
- FROM (${sql}) as subqyery limit ${query.page * query.limit}, ${query.limit}
3815
+ `SELECT * FROM (${sql}) as subqyery limit ${query.page * query.limit}, ${query.limit}
3497
3816
  `,
3498
3817
  []
3499
3818
  )
3500
3819
  )[0];
3820
+ timer.checkPoint('get response_data (has query.id)');
3501
3821
  resolve({
3502
3822
  data: data,
3503
3823
  result: !!data,
3504
3824
  });
3505
3825
  } else {
3506
3826
  const data = await db.query(
3507
- `SELECT *
3508
- FROM (${sql}) as subqyery limit ${query.page * query.limit}, ${query.limit}
3827
+ `SELECT * FROM (${sql}) as subqyery limit ${query.page * query.limit}, ${query.limit}
3509
3828
  `,
3510
3829
  []
3511
3830
  );
3512
- timer.checkPoint('finish-query-response_data');
3513
- console.log(sql);
3831
+ timer.checkPoint('get response_data (not query.id)');
3514
3832
  resolve({
3515
3833
  data: data,
3516
- total: (
3517
- await db.query(
3518
- `SELECT count(1)
3519
- FROM (${sql}) as subqyery
3520
- `,
3521
- []
3522
- )
3523
- )[0]['count(1)'],
3834
+ total: (await db.query(`SELECT count(1) FROM (${sql}) as subqyery`, []))[0]['count(1)'],
3524
3835
  });
3525
3836
  }
3526
3837
  });
3838
+
3527
3839
  const obMap = Array.isArray(response_data.data) ? response_data.data : [response_data.data];
3528
3840
  const keyData = (
3529
3841
  await Private_config.getConfig({
@@ -3531,6 +3843,7 @@ export class Shopping {
3531
3843
  key: 'glitter_finance',
3532
3844
  })
3533
3845
  )[0].value;
3846
+
3534
3847
  await Promise.all(
3535
3848
  obMap
3536
3849
  .map(async (order: any) => {
@@ -3601,7 +3914,7 @@ export class Shopping {
3601
3914
  page: 0,
3602
3915
  limit: 1,
3603
3916
  search: order.cart_token,
3604
- searchType: order.orderData.order_number,
3917
+ searchType: order.orderData?.order_number,
3605
3918
  })
3606
3919
  ).data[0];
3607
3920
  order.invoice_number = invoice && invoice.invoice_no;
@@ -3614,7 +3927,9 @@ export class Shopping {
3614
3927
  })
3615
3928
  )
3616
3929
  );
3930
+
3617
3931
  timer.checkPoint('finish-query-all');
3932
+
3618
3933
  return response_data;
3619
3934
  } catch (e) {
3620
3935
  throw exception.BadRequestError('BAD_REQUEST', 'getCheckOut Error:' + e, null);
@@ -3969,8 +4284,7 @@ export class Shopping {
3969
4284
  }
3970
4285
 
3971
4286
  const insertData = await db.query(
3972
- `INSERT INTO \`${this.app}\`.t_variants
3973
- SET ?
4287
+ `INSERT INTO \`${this.app}\`.t_variants SET ?
3974
4288
  `,
3975
4289
  [
3976
4290
  {
@@ -3991,7 +4305,15 @@ export class Shopping {
3991
4305
  return insertData;
3992
4306
  });
3993
4307
 
3994
- await Promise.all(insertPromises);
4308
+ const chunk = 10;
4309
+ const chunkLength = Math.ceil(insertPromises.length / chunk);
4310
+
4311
+ for (let i = 0; i < chunkLength; i++) {
4312
+ const promisesArray = insertPromises.slice(i * chunk, (i + 1) * chunk);
4313
+ setTimeout(async () => {
4314
+ await Promise.all(promisesArray);
4315
+ }, 200);
4316
+ }
3995
4317
 
3996
4318
  const exhibitionConfig = await _user.getConfigV2({ key: 'exhibition_manager', user_id: 'manager' });
3997
4319
  exhibitionConfig.list = exhibitionConfig.list ?? [];
@@ -4679,6 +5001,7 @@ export class Shopping {
4679
5001
  delete product['content'];
4680
5002
  delete product['preview_image'];
4681
5003
  const og_content = og_data['content'];
5004
+
4682
5005
  if (og_content.language_data && og_content.language_data[store_info.language_setting.def]) {
4683
5006
  og_content.language_data[store_info.language_setting.def].seo = product.seo;
4684
5007
  og_content.language_data[store_info.language_setting.def].title = product.title;
@@ -4692,10 +5015,10 @@ export class Shopping {
4692
5015
  product.preview_image = og_data['content'].preview_image || [];
4693
5016
  productArray[index] = product;
4694
5017
  } else {
4695
- console.error('Product id not exist:', product);
5018
+ console.error('Product id not exist:', product.title);
4696
5019
  }
4697
5020
  } else {
4698
- console.error('Product has not id:', product);
5021
+ console.error('Product has not id:', product.title);
4699
5022
  }
4700
5023
  resolve(true);
4701
5024
  });
@@ -4729,8 +5052,8 @@ export class Shopping {
4729
5052
 
4730
5053
  if (productArray.length) {
4731
5054
  const data = await db.query(
4732
- `replace
4733
- INTO \`${this.app}\`.\`t_manager_post\` (id,userID,content) values ?`,
5055
+ `REPLACE INTO \`${this.app}\`.\`t_manager_post\` (id,userID,content) values ?
5056
+ `,
4734
5057
  [
4735
5058
  productArray.map((product: any) => {
4736
5059
  if (!product.id) {
@@ -4759,37 +5082,55 @@ export class Shopping {
4759
5082
  product.id = product.id || insertIDStart++;
4760
5083
  return new Shopping(this.app, this.token).postVariantsAndPriceValue(product);
4761
5084
  });
4762
- await Promise.all(promises);
4763
- }
4764
5085
 
4765
- async putProduct(content: any) {
4766
- if (content.language_data) {
4767
- const language = await App.getSupportLanguage(this.app);
4768
- for (const b of language) {
4769
- const find_conflict = await db.query(
4770
- `select count(1)
4771
- from \`${this.app}\`.\`t_manager_post\`
4772
- where content ->>'$.language_data."${b}".seo.domain'='${decodeURIComponent(content.language_data[b].seo.domain)}'
4773
- and id != ${content.id}`,
4774
- []
4775
- );
4776
- if (find_conflict[0]['count(1)'] > 0) {
4777
- throw exception.BadRequestError('BAD_REQUEST', 'DOMAIN ALREADY EXISTS:', {
4778
- message: '網域已被使用',
4779
- code: '733',
4780
- });
4781
- }
4782
- }
5086
+ const chunk = 10;
5087
+ const chunkLength = Math.ceil(promises.length / chunk);
5088
+
5089
+ for (let i = 0; i < chunkLength; i++) {
5090
+ const promisesArray = promises.slice(i * chunk, (i + 1) * chunk);
5091
+ setTimeout(async () => {
5092
+ await Promise.all(promisesArray);
5093
+ }, 200);
4783
5094
  }
5095
+ }
4784
5096
 
5097
+ async putProduct(content: any) {
4785
5098
  try {
4786
5099
  content.type = 'product';
4787
5100
 
5101
+ // 檢查 seo domain 是否重複
5102
+ if (content.language_data) {
5103
+ const language = await App.getSupportLanguage(this.app);
5104
+ for (const b of language) {
5105
+ const find_conflict = await db.query(
5106
+ `SELECT count(1)
5107
+ FROM \`${this.app}\`.t_manager_post
5108
+ WHERE content ->>'$.language_data."${b}".seo.domain'='${decodeURIComponent(content.language_data[b].seo.domain)}'
5109
+ AND id != ${content.id}`,
5110
+ []
5111
+ );
5112
+ if (find_conflict[0]['count(1)'] > 0) {
5113
+ throw exception.BadRequestError('BAD_REQUEST', 'DOMAIN ALREADY EXISTS:', {
5114
+ message: '網域已被使用',
5115
+ code: '733',
5116
+ });
5117
+ }
5118
+ }
5119
+ }
5120
+
5121
+ // 檢查 Variant 資料屬性
4788
5122
  this.checkVariantDataType(content.variants);
4789
- const data = await db.query(
4790
- `update \`${this.app}\`.\`t_manager_post\`
4791
- SET ?
4792
- where id = ?`,
5123
+
5124
+ // 重新設置管理員標籤
5125
+ await Promise.all([
5126
+ this.setProductCustomizeTagConifg(content.product_customize_tag ?? []),
5127
+ this.setProductGeneralTagConifg(content.product_tag?.language ?? []),
5128
+ ]);
5129
+
5130
+ // 更新商品
5131
+ await db.query(
5132
+ `UPDATE \`${this.app}\`.\`t_manager_post\` SET ? WHERE id = ?
5133
+ `,
4793
5134
  [
4794
5135
  {
4795
5136
  content: JSON.stringify(content),
@@ -4797,7 +5138,11 @@ export class Shopping {
4797
5138
  content.id,
4798
5139
  ]
4799
5140
  );
5141
+
5142
+ // 更新商品 Variant
4800
5143
  await new Shopping(this.app, this.token).postVariantsAndPriceValue(content);
5144
+
5145
+ // 同步更新蝦皮
4801
5146
  if (content.shopee_id) {
4802
5147
  await new Shopee(this.app, this.token).asyncStockToShopee({
4803
5148
  product: {
@@ -5000,9 +5345,11 @@ export class Shopping {
5000
5345
  query.id && querySql.push(`(v.id = ${query.id})`);
5001
5346
  if (query.id_list) {
5002
5347
  if (query.id_list?.includes('-')) {
5003
- querySql.push(`(v.product_id in (${query.id_list.split(',').map((dd)=>{
5004
- return dd.split('-')[0]
5005
- })}))`);
5348
+ querySql.push(
5349
+ `(v.product_id in (${query.id_list.split(',').map(dd => {
5350
+ return dd.split('-')[0];
5351
+ })}))`
5352
+ );
5006
5353
  } else {
5007
5354
  querySql.push(`(v.id in (${query.id_list}))`);
5008
5355
  }
@@ -5102,11 +5449,11 @@ export class Shopping {
5102
5449
  if (query.id_list) {
5103
5450
  //過濾出需要的商品規格
5104
5451
  if (query.id_list?.includes('-')) {
5105
- data.data=data.data.filter((dd:any)=>{
5106
- return query.id_list?.split(',').find((d1)=>{
5107
- return d1 === [dd.product_id,...dd.variant_content.spec].join('-')
5108
- })
5109
- })
5452
+ data.data = data.data.filter((dd: any) => {
5453
+ return query.id_list?.split(',').find(d1 => {
5454
+ return d1 === [dd.product_id, ...dd.variant_content.spec].join('-');
5455
+ });
5456
+ });
5110
5457
  }
5111
5458
  }
5112
5459
  const shopee_data_list: { id: string; data: any }[] = [];