flexbiz-server 12.6.13 → 12.6.16

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 (129) hide show
  1. package/README.md +439 -4
  2. package/package.json +4 -3
  3. package/server/agents/agents.js +1 -0
  4. package/server/agents/ai_memory_manager.js +6 -0
  5. package/server/agents/ceoAgent.js +43 -0
  6. package/server/agents/chatController.js +6 -0
  7. package/server/agents/cskhAgent.js +43 -0
  8. package/server/agents/flowAgent.js +43 -0
  9. package/server/agents/prompts/ceo.js +2 -0
  10. package/server/agents/prompts/flow.js +2 -0
  11. package/server/agents/staffAgent.js +44 -0
  12. package/server/agents/tools/financeTools.js +57 -0
  13. package/server/agents/tools/flowTools.js +36 -0
  14. package/server/agents/tools/kpiTools.js +104 -0
  15. package/server/agents/tools/masterDataTools.js +74 -0
  16. package/server/agents/tools/okrTools.js +21 -0
  17. package/server/agents/tools/ragTools.js +21 -0
  18. package/server/agents/tools/reportTools.js +43 -0
  19. package/server/agents/tools/staffTools.js +13 -0
  20. package/server/agents/tools/stockTools.js +41 -0
  21. package/server/agents/tools/systemTools.js +52 -0
  22. package/server/agents/tools/taskTools.js +23 -0
  23. package/server/agents/tools/utils.js +57 -0
  24. package/server/app.js +7 -7
  25. package/server/controllers/controller.js +31 -29
  26. package/server/controllers/controllerRPT.js +31 -29
  27. package/server/controllers/findHandler.js +22 -21
  28. package/server/controllers/importFromExcelHandler.js +17 -14
  29. package/server/controllers/importHandler.js +26 -41
  30. package/server/controllers/importHandler_old.js +41 -0
  31. package/server/controllers/rptHandler.js +14 -11
  32. package/server/controllers/viewHandler.js +7 -7
  33. package/server/flow/FlowEngine.js +49 -45
  34. package/server/flow/WebhookManager.js +1 -1
  35. package/server/flow/handlers.js +2 -2
  36. package/server/flow/nodes/userform.js +28 -0
  37. package/server/flow/utils.js +12 -4
  38. package/server/global.js +4 -3
  39. package/server/libs/cdpstk.js +1 -1
  40. package/server/libs/ckvt.js +12 -11
  41. package/server/libs/ckvtcapphat.js +5 -5
  42. package/server/libs/ckvtnpp.js +8 -8
  43. package/server/libs/ckvttt.js +6 -5
  44. package/server/libs/ctvt.js +7 -6
  45. package/server/libs/ctvtnpp.js +7 -6
  46. package/server/libs/ctvttt.js +6 -6
  47. package/server/libs/databanle.js +17 -18
  48. package/server/libs/databanle_old.js +18 -0
  49. package/server/libs/databanletheongay.js +25 -29
  50. package/server/libs/dktk.js +3 -3
  51. package/server/libs/dkvt.js +11 -11
  52. package/server/libs/dkvtnpp.js +7 -6
  53. package/server/libs/dkvttt.js +7 -6
  54. package/server/libs/docs.js +72 -36
  55. package/server/libs/dtbanletheosp.js +16 -19
  56. package/server/libs/fifo_dk.js +8 -0
  57. package/server/libs/fifo_group.js +4 -0
  58. package/server/libs/fifo_trace_query.js +12 -0
  59. package/server/libs/getGiaban.js +59 -70
  60. package/server/libs/getGiaban_old.js +70 -0
  61. package/server/libs/joinData.js +3 -3
  62. package/server/libs/joinData_bk.js +44 -0
  63. package/server/libs/kpistatus.js +24 -17
  64. package/server/libs/permission.js +54 -56
  65. package/server/libs/permission_old.js +58 -0
  66. package/server/libs/post-book.js +1 -1
  67. package/server/libs/post-socai.js +2 -1
  68. package/server/libs/post-sokho.js +11 -11
  69. package/server/libs/prototypes.js +13 -12
  70. package/server/libs/queryBuilding.js +11 -10
  71. package/server/libs/redis-cache.js +22 -10
  72. package/server/libs/sctcnkh.js +19 -17
  73. package/server/libs/socaitk.js +1 -1
  74. package/server/libs/thnxt.js +17 -14
  75. package/server/libs/thnxtnpp.js +8 -8
  76. package/server/libs/thnxttt.js +8 -7
  77. package/server/libs/tinhgia1vt_fifo.js +22 -0
  78. package/server/libs/tinhgiafifo.js +28 -0
  79. package/server/libs/utils.js +37 -19
  80. package/server/models/app.js +1 -1
  81. package/server/models/approve.js +8 -8
  82. package/server/models/cacheDataReport.js +2 -2
  83. package/server/models/cacheSessionReport.js +5 -1
  84. package/server/models/cdvt.js +2 -2
  85. package/server/models/checkin.js +2 -2
  86. package/server/models/chitietluongds.js +1 -1
  87. package/server/models/contract.js +1 -1
  88. package/server/models/csluongtheods.js +2 -2
  89. package/server/models/ctds2.js +7 -6
  90. package/server/models/custom_report.js +1 -0
  91. package/server/models/dmdt.js +2 -2
  92. package/server/models/dmkho.js +5 -4
  93. package/server/models/dmnvt.js +5 -4
  94. package/server/models/fifo_dk.js +2 -0
  95. package/server/models/fifo_lot.js +3 -0
  96. package/server/models/fifo_trace.js +4 -0
  97. package/server/models/flowpending.js +2 -0
  98. package/server/models/group.js +3 -5
  99. package/server/models/listinfo.js +61 -33
  100. package/server/models/schedule.js +4 -3
  101. package/server/models/task.js +1 -1
  102. package/server/models/trangthai.js +2 -2
  103. package/server/modules/lists/bg-fifo_dk.js +8 -0
  104. package/server/modules/lists/ls-checkin.js +1 -1
  105. package/server/modules/lists/ls-customer.js +23 -26
  106. package/server/modules/lists/ls-dmbp.js +5 -5
  107. package/server/modules/lists/ls-dmkho.js +7 -1
  108. package/server/modules/lists/ls-dmnhtask.js +1 -1
  109. package/server/modules/lists/ls-dmvt.js +52 -70
  110. package/server/modules/lists/ls-flowpending.js +3 -0
  111. package/server/modules/lists/ls-participant.js +6 -4
  112. package/server/modules/lists/ls-task.js +6 -6
  113. package/server/modules/reports/calc-tinhgiafifo.js +8 -0
  114. package/server/modules/reports/calc-tinhluong.js +17 -16
  115. package/server/modules/reports/rp-baoCaoFifoKy.js +1 -0
  116. package/server/modules/reports/rp-congviectheobp.js +4 -4
  117. package/server/modules/reports/rp-congviectheodt.js +1 -1
  118. package/server/modules/reports/rp-congviectheokh.js +1 -1
  119. package/server/modules/reports/rp-congviectheonv.js +1 -1
  120. package/server/modules/reports/rp-dtbanletheoct.js +22 -23
  121. package/server/modules/reports/rp-dtbanletheokh.js +17 -20
  122. package/server/modules/reports/rp-dtbanletheokho.js +15 -18
  123. package/server/modules/reports/rp-hoahong.js +1 -1
  124. package/server/modules/reports/rp-sctvt.js +1 -1
  125. package/server/modules/reports/rp-sosanhkhvatt2.js +1 -1
  126. package/server/modules/reports/rp-thnxt.js +8 -8
  127. package/server/modules/reports/rp-tongquannvbh.js +1 -1
  128. package/server/modules/systems/sys-app.js +5 -5
  129. package/server/modules/vouchers/vo-so1.js +14 -14
@@ -0,0 +1,43 @@
1
+ const {tool}=require("ai"),{z}=require("zod"),{resolveDirectRefFilter,resolveHopChain,normalizeHops}=require("./utils"),{evalute2:evalute}=require("../../libs/utils"),{buildJsonSchema}=require("../../libs/docs"),moment=require("moment"),dktk=require("../../libs/dktk"),cktk=require("../../libs/cktk"),dkcn=require("../../libs/dkcn"),ckcn=require("../../libs/ckcn"),dkvt=require("../../libs/dkvt"),ckvt=require("../../libs/ckvt"),thnxt=require("../../libs/thnxt"),cdpstk=require("../../libs/cdpstk");
2
+ async function getReportConditionSchema($formConditionInfoCode_listinfoDoc$$,$id_app$$){if(!$formConditionInfoCode_listinfoDoc$$)return{};$formConditionInfoCode_listinfoDoc$$=await global.getModel("listinfo").findOne({code:$formConditionInfoCode_listinfoDoc$$}).lean();return $formConditionInfoCode_listinfoDoc$$?.fields?.length?await buildJsonSchema($formConditionInfoCode_listinfoDoc$$.fields,0,$id_app$$,$formConditionInfoCode_listinfoDoc$$):{}}
3
+ async function resolveDirectReportRefFilter($filter$$,$conditionSchema_pathDef$$,$id_app$$){$conditionSchema_pathDef$$=$conditionSchema_pathDef$$[$filter$$.field];if(!$conditionSchema_pathDef$$)return{error:`Tr\u01b0\u1eddng '${$filter$$.field}' kh\u00f4ng t\u1ed3n t\u1ea1i trong \u0111i\u1ec1u ki\u1ec7n l\u1ecdc c\u1ee7a b\u00e1o c\u00e1o n\u00e0y.`};$id_app$$=await resolveDirectRefFilter($conditionSchema_pathDef$$,$filter$$.keyword,$id_app$$);return $id_app$$.error?{error:`${$id_app$$.error} (tr\u01b0\u1eddng '${$filter$$.field}').`}:
4
+ {field:$filter$$.field,condition:{[$filter$$.field]:{$in:$id_app$$.values}},count:$id_app$$.count}}
5
+ async function resolveHopReportRefFilter($filter$$,$id_app$jscomp$2_resolved$$){const $hops$$=normalizeHops($filter$$);$id_app$jscomp$2_resolved$$=await resolveHopChain($hops$$,$filter$$.keyword,$id_app$jscomp$2_resolved$$);return $id_app$jscomp$2_resolved$$.error?{error:$id_app$jscomp$2_resolved$$.error}:{field:$filter$$.field,condition:{[$filter$$.field]:{$in:$id_app$jscomp$2_resolved$$.values}},count:$id_app$jscomp$2_resolved$$.count}}
6
+ function createReportTools($id_app$$,$user_id$$){return{runReportTool:tool({description:'C\u00f4ng c\u1ee5 CH\u1ea0Y B\u00c1O C\u00c1O (Run Report).\n S\u1eec D\u1ee4NG KHI: S\u1ebfp y\u00eau c\u1ea7u xem s\u1ed1 li\u1ec7u, xu\u1ea5t ho\u1eb7c ch\u1ea1y m\u1ed9t b\u00e1o c\u00e1o c\u1ee5 th\u1ec3 (VD: "Cho anh xem b\u00e1o c\u00e1o doanh thu", "Xu\u1ea5t b\u00e1o c\u00e1o t\u1ed3n kho").\n L\u01afU \u00dd QUAN TR\u1eccNG: \n 1. C\u1ea7n truy\u1ec1n ch\u00ednh x\u00e1c m\u00e3 b\u00e1o c\u00e1o (report_code). N\u1ebfu ch\u01b0a bi\u1ebft m\u00e3, h\u00e3y d\u00f9ng tool th\u0103m d\u00f2 c\u1ea5u tr\u00fac b\u00e1o c\u00e1o tr\u01b0\u1edbc.\n 2. HI\u1ec2N TH\u1eca \u0110\u1ea6Y \u0110\u1ee6: Tr\u00ecnh b\u00e0y TO\u00c0N B\u1ed8 s\u1ed1 li\u1ec7u c\u1ee7a trang hi\u1ec7n t\u1ea1i ra d\u1ea1ng b\u1ea3ng Markdown. B\u1eaeT BU\u1ed8C gi\u1eef nguy\u00ean c\u00e1c d\u00f2ng d\u1eef li\u1ec7u v\u00e0 c\u00e1c c\u1ed9t \u0111\u01b0\u1ee3c tr\u1ea3 v\u1ec1 t\u1eeb Output Schema, TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG t\u1ef1 \u00fd t\u00f3m t\u1eaft, g\u1ed9p d\u00f2ng hay c\u1eaft b\u1edbt d\u1eef li\u1ec7u.\n 3. N\u1ebfu S\u1ebfp mu\u1ed1n xem trang ti\u1ebfp theo, B\u1eaeT BU\u1ed8C truy\u1ec1n \'id_session\' t\u1eeb k\u1ebft qu\u1ea3 l\u1ea7n ch\u1ea1y tr\u01b0\u1edbc v\u00e0o c\u00f9ng v\u1edbi s\u1ed1 \'page\' t\u01b0\u01a1ng \u1ee9ng.\n\n \ud83d\udd25 L\u1eccC THEO DANH M\u1ee4C KH\u00d4NG C\u00d3 TR\u1ef0C TI\u1ebeP TRONG SCHEMA B\u00c1O C\u00c1O (B\u1eaeT BU\u1ed8C \u0110\u1eccC K\u1ef8):\n B\u00e1o c\u00e1o th\u01b0\u1eddng CH\u1ec8 h\u1ed7 tr\u1ee3 l\u1ecdc theo v\u00e0i field c\u1ed1 \u0111\u1ecbnh (VD: ma_vt, ma_nvt, ma_kho) \u2014 KH\u00d4NG c\u00f3 field cho m\u1ecdi kh\u00e1i ni\u1ec7m S\u1ebfp c\u00f3 th\u1ec3 h\u1ecfi (VD: "ng\u00e0nh h\u00e0ng", "nh\u00f3m kh\u00e1ch h\u00e0ng theo khu v\u1ef1c"...).\n N\u1ebeU S\u1ebfp h\u1ecfi theo m\u1ed9t kh\u00e1i ni\u1ec7m KH\u00d4NG c\u00f3 field tr\u1ef1c ti\u1ebfp trong \u0111i\u1ec1u ki\u1ec7n b\u00e1o c\u00e1o:\n \u274c TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG g\u1ecdi lookupMasterDataTool \u0111\u1ec3 l\u1ea5y C\u1ea2 DANH S\u00c1CH M\u00c3 (c\u00f3 th\u1ec3 h\u00e0ng tr\u0103m/ng\u00e0n m\u00e3) r\u1ed3i nh\u1ed3i v\u00e0o \'condition\' \u2014 danh s\u00e1ch d\u00e0i s\u1ebd \u0111i qua context c\u1ee7a b\u1ea1n 2 l\u1ea7n (nh\u1eadn v\u1ec1 + g\u1eedi \u0111i) v\u00e0 G\u00c2Y L\u1ed6I V\u01af\u1ee2T GI\u1edaI H\u1ea0N TOKEN (Request too large), l\u00e0m h\u1ecfng to\u00e0n b\u1ed9 phi\u00ean l\u00e0m vi\u1ec7c.\n \u2705 H\u00c3Y d\u00f9ng tham s\u1ed1 \'ref_filters\'. Tool s\u1ebd T\u1ef0 ph\u00e2n gi\u1ea3i to\u00e0n b\u1ed9 N\u1ed8I B\u1ed8 \u2014 b\u1ea1n KH\u00d4NG c\u1ea7n v\u00e0 KH\u00d4NG \u0111\u01b0\u1ee3c nh\u00ecn th\u1ea5y danh s\u00e1ch m\u00e3, ch\u1ec9 nh\u1eadn l\u1ea1i s\u1ed1 l\u01b0\u1ee3ng \u0111\u00e3 kh\u1edbp.\n\n \u01afU TI\u00caN FIELD TH\u00d4 H\u01a0N N\u1ebeU B\u00c1O C\u00c1O C\u00d3 S\u1eb4N: N\u1ebfu kh\u00e1i ni\u1ec7m S\u1ebfp h\u1ecfi g\u1ea7n v\u1edbi m\u1ed9t field l\u1ecdc TH\u00d4 H\u01a1N b\u00e1o c\u00e1o \u0111\u00e3 h\u1ed7 tr\u1ee3 s\u1eb5n (VD: S\u1ebfp h\u1ecfi theo "nh\u00f3m v\u1eadt t\u01b0" v\u00e0 b\u00e1o c\u00e1o c\u00f3 s\u1eb5n field \'ma_nvt\'), h\u00e3y b\u1eafc c\u1ea7u t\u1edbi CH\u00cdNH field \u0111\u00f3 thay v\u00ec lu\u00f4n c\u1ed1 drill xu\u1ed1ng t\u1edbi \'ma_vt\' \u2014 \u00edt b\u01b0\u1edbc h\u01a1n, danh s\u00e1ch trung gian nh\u1ecf h\u01a1n, nhanh h\u01a1n. Ch\u1ec9 drill xu\u1ed1ng c\u1ea5p chi ti\u1ebft nh\u1ea5t khi b\u00e1o c\u00e1o KH\u00d4NG c\u00f3 field c\u1ea5p trung gian ph\u00f9 h\u1ee3p.\n\n VD 1 \u2014 B\u1eafc c\u1ea7u 1 B\u01af\u1edaC (b\u00e1o c\u00e1o ch\u1ec9 c\u00f3 \'ma_vt\', kh\u00f4ng c\u00f3 field ng\u00e0nh h\u00e0ng):\n ref_filters: [{ field: "ma_vt", keyword: "N\u00f4ng s\u1ea3n Vi\u1ec7t Thi\u00ean", hop_controller: "DMVT", hop_field: "ma_nganh_hang", hop_extract_field: "ma_vt" }]\n\n VD 2 \u2014 B\u1eafc c\u1ea7u NHI\u1ec0U B\u01af\u1edaC li\u00ean ti\u1ebfp (khi chu\u1ed7i quan h\u1ec7 c\u00f3 t\u1eeb 3 c\u1ea5p tr\u1edf l\u00ean, VD \u0111\u00fang c\u1ea5u tr\u00fac d\u1eef li\u1ec7u th\u1ef1c t\u1ebf: ng\u00e0nh h\u00e0ng -> nh\u00f3m v\u1eadt t\u01b0 -> v\u1eadt t\u01b0 \u2014 d\u00f9ng khi b\u00e1o c\u00e1o CH\u1ec8 c\u00f3 \'ma_vt\', KH\u00d4NG c\u00f3 \'ma_nvt\'):\n ref_filters: [{\n field: "ma_vt", keyword: "N\u00f4ng s\u1ea3n Vi\u1ec7t Thi\u00ean",\n hops: [\n { controller: "DMNVT", field: "ma_nganh_hang", extract_field: "_id" },\n { controller: "DMVT", field: "ma_nvt", extract_field: "ma_vt" }\n ]\n }]\n (B\u01b0\u1edbc 1 l\u1ea5y danh s\u00e1ch "nh\u00f3m v\u1eadt t\u01b0" thu\u1ed9c ng\u00e0nh h\u00e0ng \u0111\u00f3; B\u01b0\u1edbc 2 d\u00f9ng CH\u00cdNH danh s\u00e1ch \u0111\u00f3 \u2014 kh\u00f4ng fuzzy l\u1ea1i \u2014 \u0111\u1ec3 l\u1ea5y "v\u1eadt t\u01b0" thu\u1ed9c c\u00e1c nh\u00f3m \u0111\u00f3. M\u1ed7i b\u01b0\u1edbc c\u1ea7n \u0111\u00fang t\u00ean controller + t\u00ean field b\u1eafc c\u1ea7u tr\u00ean b\u1ea3ng \u0111\u00f3 \u2014 d\u00f9ng exploreSystemSchemaTool n\u1ebfu ch\u01b0a ch\u1eafc.)\n ',inputSchema:z.object({report_code:z.string().describe('M\u00e3 code c\u1ee7a b\u00e1o c\u00e1o c\u1ea7n ch\u1ea1y (B\u1eaeT BU\u1ed8C, V\u00ed d\u1ee5: "BC_DOANH_THU").'),
7
+ condition:z.record(z.any()).optional().default({}).describe('Object (JSON) ch\u1ee9a c\u00e1c \u0111i\u1ec1u ki\u1ec7n l\u1ecdc b\u00e1o c\u00e1o, CH\u1ec8 d\u00f9ng cho gi\u00e1 tr\u1ecb NG\u1eaeN, \u0111\u00e3 bi\u1ebft tr\u01b0\u1edbc (VD: {"tu_ngay": "2026-01-01", "ma_kh": "KH001"}). KH\u00d4NG nh\u1ed3i danh s\u00e1ch m\u00e3 d\u00e0i v\u00e0o \u0111\u00e2y \u2014 d\u00f9ng "ref_filters" thay th\u1ebf.'),ref_filters:z.array(z.object({field:z.string().describe('T\u00ean field trong \u0111i\u1ec1u ki\u1ec7n l\u1ecdc c\u1ee7a b\u00e1o c\u00e1o c\u1ea7n g\u00e1n gi\u00e1 tr\u1ecb (VD: "ma_vt").'),
8
+ keyword:z.string().describe('T\u1eeb kh\u00f3a S\u1ebfp mu\u1ed1n l\u1ecdc (VD: "N\u00f4ng s\u1ea3n Vi\u1ec7t Thi\u00ean").'),hop_controller:z.string().optional().describe('B\u1eafc c\u1ea7u 1 B\u01af\u1edaC (khi chu\u1ed7i quan h\u1ec7 ch\u1ec9 c\u00f3 1 b\u1ea3ng trung gian): M\u00e3 Controller c\u1ee7a b\u1ea3ng trung gian (VD: "DMVT").'),hop_field:z.string().optional().describe('B\u1eafc c\u1ea7u 1 B\u01af\u1edaC: T\u00ean field b\u1eafc c\u1ea7u tr\u00ean b\u1ea3ng trung gian (VD: "ma_nganh_hang").'),
9
+ hop_extract_field:z.string().optional().describe('B\u1eafc c\u1ea7u 1 B\u01af\u1edaC: Field gi\u00e1 tr\u1ecb c\u1ea7n tr\u00edch t\u1eeb b\u1ea3ng trung gian \u0111\u1ec3 g\u00e1n v\u00e0o "field" (VD: "ma_vt").'),hops:z.array(z.object({controller:z.string().describe('M\u00e3 Controller c\u1ee7a b\u1ea3ng trung gian \u1edf b\u01b0\u1edbc n\u00e0y (VD: "DMNVT").'),field:z.string().describe('Field b\u1eafc c\u1ea7u \u1edf b\u01b0\u1edbc n\u00e0y (VD: "ma_nganh_hang" \u1edf b\u01b0\u1edbc 1, "ma_nvt" \u1edf b\u01b0\u1edbc 2).'),
10
+ extract_field:z.string().describe('Field gi\u00e1 tr\u1ecb tr\u00edch ra \u1edf b\u01b0\u1edbc n\u00e0y \u0111\u1ec3 l\u00e0m \u0111i\u1ec1u ki\u1ec7n cho b\u01b0\u1edbc k\u1ebf ti\u1ebfp (ho\u1eb7c g\u00e1n v\u00e0o "field" n\u1ebfu l\u00e0 b\u01b0\u1edbc cu\u1ed1i, VD: "_id" \u1edf b\u01b0\u1edbc 1, "ma_vt" \u1edf b\u01b0\u1edbc cu\u1ed1i).')})).optional().describe('B\u1eafc c\u1ea7u NHI\u1ec0U B\u01af\u1edaC li\u00ean ti\u1ebfp khi chu\u1ed7i quan h\u1ec7 c\u00f3 t\u1eeb 3 c\u1ea5p tr\u1edf l\u00ean (VD: ng\u00e0nh h\u00e0ng -> nh\u00f3m v\u1eadt t\u01b0 -> v\u1eadt t\u01b0). N\u1ebfu d\u00f9ng "hops" th\u00ec B\u1ece QUA hop_controller/hop_field/hop_extract_field \u2014 ch\u1ec9 d\u00f9ng M\u1ed8T trong hai c\u00e1ch.')})).optional().describe("B\u1ed8 L\u1eccC \u0110\u1ed8NG: d\u00f9ng khi c\u1ea7n l\u1ecdc theo kh\u00e1i ni\u1ec7m kh\u00f4ng c\u00f3 field tr\u1ef1c ti\u1ebfp trong \u0111i\u1ec1u ki\u1ec7n b\u00e1o c\u00e1o. Tool t\u1ef1 ph\u00e2n gi\u1ea3i N\u1ed8I B\u1ed8 (1 b\u01b0\u1edbc ho\u1eb7c nhi\u1ec1u b\u01b0\u1edbc li\u00ean ti\u1ebfp) \u2014 KH\u00d4NG tr\u1ea3 danh s\u00e1ch m\u00e3 v\u1ec1 cho AI, ch\u1ec9 tr\u1ea3 s\u1ed1 l\u01b0\u1ee3ng \u0111\u00e3 kh\u1edbp."),
11
+ id_session:z.string().optional().describe("M\u00e3 Session ID tr\u1ea3 v\u1ec1 t\u1eeb l\u1ea7n ch\u1ea1y tr\u01b0\u1edbc. D\u00f9ng l\u00e0m \u0111i\u1ec1u ki\u1ec7n b\u1eafc c\u1ea7u \u0111\u1ec3 t\u1ea3i nhanh c\u00e1c trang ti\u1ebfp theo (trang 2, 3...)."),page:z.number().optional().default(1).describe("Trang k\u1ebft qu\u1ea3 c\u1ea7n xem. M\u1eb7c \u0111\u1ecbnh 1."),limit:z.number().optional().default(20).describe("S\u1ed1 l\u01b0\u1ee3ng d\u00f2ng d\u1eef li\u1ec7u tr\u00ean m\u1ed7i trang. Kh\u00f4ng \u0111\u01b0\u1ee3c qu\u00e1 20")}),
12
+ execute:async $finalCondition_finnalCode_query$$=>{let {report_code:$report_code$$,condition:$condition$$,ref_filters:$ref_filters$$,id_session:$id_session$$,page:$page$$,limit:$limit$$}=$finalCondition_finnalCode_query$$;try{Logger.warn("[AI Agent][runReportTool]",JSON.stringify($finalCondition_finnalCode_query$$,null,2));var $conditionSize_resolvedFiltersSummary$$=JSON.stringify($condition$$||{}).length;if($conditionSize_resolvedFiltersSummary$$>5E3)return{status:"error",message:`Tham s\u1ed1 'condition' qu\u00e1 l\u1edbn (${$conditionSize_resolvedFiltersSummary$$} k\u00fd t\u1ef1) \u2014 c\u00f3 th\u1ec3 b\u1ea1n \u0111ang nh\u1ed3i m\u1ed9t danh s\u00e1ch m\u00e3 d\u00e0i (VD: h\u00e0ng tr\u0103m/ng\u00e0n m\u00e3 v\u1eadt t\u01b0) tr\u1ef1c ti\u1ebfp v\u00e0o condition. KH\u00d4NG l\u00e0m v\u1eady. H\u00e3y d\u00f9ng tham s\u1ed1 'ref_filters' \u0111\u1ec3 h\u1ec7 th\u1ed1ng t\u1ef1 ph\u00e2n gi\u1ea3i n\u1ed9i b\u1ed9, kh\u00f4ng c\u1ea7n b\u1ea1n c\u1ea7m danh s\u00e1ch m\u00e3. Xem v\u00ed d\u1ee5 trong ph\u1ea7n m\u00f4 t\u1ea3 c\u1ee7a tool.`};
13
+ $finalCondition_finnalCode_query$$=$report_code$$;var $message$$=await global.getModel("reportinfo").findOne({code:$report_code$$.toLowerCase()},{api_code:1,code:1,form_condition_info:1}).lean();$message$$?.api_code&&($finalCondition_finnalCode_query$$=$message$$.api_code);const $ctrlCode$$=$finalCondition_finnalCode_query$$.toUpperCase(),$controller$$=global.report_controllers[$ctrlCode$$];if(!$controller$$)return{status:"error",message:`Kh\u00f4ng t\u00ecm th\u1ea5y Report Controller n\u00e0o c\u00f3 m\u00e3 '${$ctrlCode$$}'. Vui l\u00f2ng d\u00f9ng tool th\u0103m d\u00f2 b\u00e1o c\u00e1o \u0111\u1ec3 t\u00ecm m\u00e3 code ch\u00ednh x\u00e1c.`};
14
+ if(typeof $controller$$.runReport!=="function")return{status:"error",message:`Report Controller '${$ctrlCode$$}' ch\u01b0a h\u1ed7 tr\u1ee3 h\u00e0m runReport.`};$finalCondition_finnalCode_query$$={...$condition$$};$conditionSize_resolvedFiltersSummary$$=[];if($ref_filters$$&&$ref_filters$$.length>0){let $conditionSchema$$=null;for(const $filter$$ of $ref_filters$$){let $result$$;$filter$$.hop_controller&&$filter$$.hop_field&&$filter$$.hop_extract_field||$filter$$.hops&&$filter$$.hops.length>0?$result$$=
15
+ await resolveHopReportRefFilter($filter$$,$id_app$$):($conditionSchema$$===null&&($conditionSchema$$=await getReportConditionSchema($message$$?.form_condition_info,$id_app$$)),$result$$=await resolveDirectReportRefFilter($filter$$,$conditionSchema$$,$id_app$$));if(!$result$$||$result$$.error)return{status:"error",message:$result$$?.error||`Kh\u00f4ng th\u1ec3 ph\u00e2n gi\u1ea3i b\u1ed9 l\u1ecdc cho tr\u01b0\u1eddng '${$filter$$.field}'.`};Object.assign($finalCondition_finnalCode_query$$,$result$$.condition);
16
+ $conditionSize_resolvedFiltersSummary$$.push(`${$filter$$.field} (kh\u1edbp '${$filter$$.keyword}'): ${$result$$.count} m\u00e3`)}Logger.info("[runReportTool] \u0110\u00e3 ph\u00e2n gi\u1ea3i ref_filters n\u1ed9i b\u1ed9:",$conditionSize_resolvedFiltersSummary$$.join(" | "))}$id_session$$&&($finalCondition_finnalCode_query$$.id_session=$id_session$$);$finalCondition_finnalCode_query$$.id_app=$id_app$$;const $res$$=await $controller$$.runReport($user_id$$,$finalCondition_finnalCode_query$$,{pagination:1,
17
+ page:$page$$,limit:Math.min($limit$$,20)}),$docs$$=$res$$&&$res$$.data?$res$$.data:[];if($docs$$.length===0)return{status:"success_empty",report_code:$ctrlCode$$,resolved_filters:$conditionSize_resolvedFiltersSummary$$.length>0?$conditionSize_resolvedFiltersSummary$$:void 0,message:`B\u00e1o c\u00e1o '${$ctrlCode$$}' ch\u1ea1y th\u00e0nh c\u00f4ng nh\u01b0ng kh\u00f4ng c\u00f3 d\u1eef li\u1ec7u n\u00e0o kh\u1edbp v\u1edbi \u0111i\u1ec1u ki\u1ec7n l\u1ecdc.`,hint:"L\u01afU \u00dd QUAN TR\u1eccNG: K\u1ebft qu\u1ea3 r\u1ed7ng c\u00f3 th\u1ec3 do b\u00e1o c\u00e1o chu\u1ea9n b\u1ecb gi\u1edbi h\u1ea1n. TR\u01af\u1edaC KHI B\u00c1O C\u00c1O S\u1ebeP L\u00c0 KH\u00d4NG C\u00d3 D\u1eee LI\u1ec6U, b\u1ea1n B\u1eaeT BU\u1ed8C ph\u1ea3i th\u1eed ph\u01b0\u01a1ng \u00e1n cu\u1ed1i: G\u1ecdi 'exploreSystemSchemaTool' (t\u00ecm model ch\u1ee9a d\u1eef li\u1ec7u) r\u1ed3i d\u00f9ng 'codeInterpreterTool' \u0111\u1ec3 t\u1ef1 vi\u1ebft code truy v\u1ea5n s\u00e2u v\u00e0o DB. CH\u1ec8 KHI C\u1ea2 CODE INTERPRETER C\u0168NG KH\u00d4NG T\u00ccM TH\u1ea4Y, B\u1ea0N M\u1edaI \u0110\u01af\u1ee2C B\u00c1O CHO S\u1ebeP."};
18
+ const $paginationInfo$$=$res$$.pagination||{limit:$limit$$,page:$page$$,total:$docs$$.length,totalPages:1},$returnedSessionId$$=$res$$.id_session||$id_session$$,$cleanDocs$$=JSON.parse(JSON.stringify($docs$$)),$cleanPagination$$=JSON.parse(JSON.stringify($paginationInfo$$));return{status:"success",report_code:$ctrlCode$$,id_session:$returnedSessionId$$,pagination:$cleanPagination$$,resolved_filters:$conditionSize_resolvedFiltersSummary$$.length>0?$conditionSize_resolvedFiltersSummary$$:void 0,data:$cleanDocs$$,
19
+ hint:`AI L\u01afU \u00dd KHI TR\u1ea2 L\u1edcI:
20
+ 1. Tr\u00ecnh b\u00e0y s\u1ed1 li\u1ec7u quan tr\u1ecdng ra d\u1ea1ng b\u1ea3ng Markdown (ch\u1ec9 ch\u1ecdn l\u1ecdc 3-5 c\u1ed9t quan tr\u1ecdng nh\u1ea5t cho d\u1ec5 nh\u00ecn).
21
+ ${$conditionSize_resolvedFiltersSummary$$.length>0?`2. B\u00e1o S\u1ebfp bi\u1ebft \u0111\u00e3 l\u1ecdc theo: ${$conditionSize_resolvedFiltersSummary$$.join("; ")} (ch\u1ec9 n\u00eau S\u1ed0 L\u01af\u1ee2NG, KH\u00d4NG li\u1ec7t k\u00ea danh s\u00e1ch m\u00e3 chi ti\u1ebft).\n 3`:"2"}. ${$paginationInfo$$.totalPages>$paginationInfo$$.page?`B\u00e1o c\u00e1o \u0111ang \u1edf trang ${$paginationInfo$$.page}/${$paginationInfo$$.totalPages}. H\u00e3y h\u1ecfi S\u1ebfp: "D\u1ea1, b\u00e1o c\u00e1o c\u00f2n trang ti\u1ebfp theo, S\u1ebfp c\u00f3 mu\u1ed1n em l\u1eadt sang trang ${$paginationInfo$$.page+
22
+ 1} kh\u00f4ng \u1ea1?". (Khi S\u1ebfp \u0111\u1ed3ng \u00fd, truy\u1ec1n id_session: "${$returnedSessionId$$}" v\u00e0o tool \u0111\u1ec3 l\u1ea5y ti\u1ebfp).`:"\u0110\u00e2y l\u00e0 trang d\u1eef li\u1ec7u cu\u1ed1i c\u00f9ng."}`}}catch($error$$){return $message$$=$error$$.message||$error$$.error||$error$$.toString(),Logger.info(`[L\u1ed7i t\u1eeb runReportTool - ${$report_code$$}]:`,$message$$),{status:"error",message:`L\u1ed7i h\u1ec7 th\u1ed1ng khi ch\u1ea1y b\u00e1o c\u00e1o: ${$message$$}`}}}}),
23
+ codeInterpreterTool:tool({description:"C\u00f4ng c\u1ee5 PH\u00c2N T\u00cdCH D\u1eee LI\u1ec6U \u0110\u1ed8NG CAO C\u1ea4P (Code Interpreter).\n S\u1eec D\u1ee4NG KHI:\n 1. (PH\u01af\u01a0NG \u00c1N CU\u1ed0I C\u00d9NG cho b\u00e1o c\u00e1o ph\u1ee9c t\u1ea1p) Kh\u00f4ng c\u00f3 s\u1eb5n b\u00e1o c\u00e1o t\u01b0\u01a1ng \u1ee9ng trong h\u1ec7 th\u1ed1ng v\u00e0 S\u1ebfp y\u00eau c\u1ea7u t\u1ed5ng h\u1ee3p d\u1eef li\u1ec7u, t\u00ednh to\u00e1n \u0111\u1eb7c th\u00f9 ch\u00e9o nhi\u1ec1u b\u1ea3ng.\n 2. (L\u1ef0A CH\u1eccN TR\u1ef0C TI\u1ebeP \u2014 kh\u00f4ng c\u1ea7n th\u1eed tool kh\u00e1c tr\u01b0\u1edbc) S\u1ebfp h\u1ecfi TH\u1ed0NG K\u00ca S\u1ed0 L\u01af\u1ee2NG b\u1ea3n ghi trong m\u1ed9t danh m\u1ee5c/b\u1ea3ng: \"c\u00f3 bao nhi\u00eau kh\u00e1ch h\u00e0ng/s\u1ea3n ph\u1ea9m/nh\u00e2n vi\u00ean...\", \"t\u0103ng tr\u01b0\u1edfng/ph\u00e1t sinh m\u1edbi trong k\u1ef3 so v\u1edbi k\u1ef3 tr\u01b0\u1edbc\", \"ph\u00e2n b\u1ed5 nh\u00e2n vi\u00ean theo ph\u00f2ng ban\", \"c\u00f3 bao nhi\u00eau \u0111\u01a1n h\u00e0ng th\u00e1ng n\u00e0y\"... \u0110\u00e2y l\u00e0 nh\u00f3m c\u00e2u h\u1ecfi \u0110\u1ebeM/TH\u1ed0NG K\u00ca DANH M\u1ee4C (\u0111\u00e3 \u0111\u01b0\u1ee3c chuy\u1ec3n t\u1eeb lookupMasterDataTool sang \u0111\u00e2y). KH\u00d4NG nh\u1ea7m v\u1edbi h\u1ecfi s\u1ed1 li\u1ec7u TI\u1ec0N/T\u1ed2N KHO (xem m\u1ee5c H\u00c0M K\u1ebe TO\u00c1N & KHO L\u00d5I b\u00ean d\u01b0\u1edbi \u2014 ph\u1ea3i d\u00f9ng calcSoCai/calcDoanhThu/dktk/cktk/dkvt/ckvt, KH\u00d4NG t\u1ef1 countDocuments tr\u00ean data_socai/data_sokho).\n \n L\u01afU \u00dd PH\u00c2N BI\u1ec6T: N\u1ebfu S\u1ebfp ch\u1ec9 mu\u1ed1n T\u00ccM/XEM m\u1ed9t v\u00e0i h\u1ed3 s\u01a1 c\u1ee5 th\u1ec3 theo t\u00ean/m\u00e3 (kh\u00f4ng ph\u1ea3i \u0111\u1ebfm/th\u1ed1ng k\u00ea s\u1ed1 l\u01b0\u1ee3ng) -> d\u00f9ng lookupMasterDataTool, KH\u00d4NG vi\u1ebft script \u0111\u1ebfm \u1edf \u0111\u00e2y.\n \n LU\u1eacT S\u1ed0NG C\u00d2N TR\u01af\u1edaC KHI CH\u1ea0Y CODE:\n 1. B\u1eaeT BU\u1ed8C TH\u0102M D\u00d2: Ph\u1ea3i g\u1ecdi 'exploreSystemSchemaTool' tr\u01b0\u1edbc \u0111\u1ec3 l\u1ea5y c\u1ea5u tr\u00fac c\u1ee7a c\u00e1c collection c\u1ea7n d\u00f9ng. V\u1edbi th\u1ed1ng k\u00ea danh m\u1ee5c, th\u0103m d\u00f2 \u0111\u1ec3 bi\u1ebft \u0110\u00daNG tr\u01b0\u1eddng l\u01b0u ng\u00e0y t\u1ea1o (th\u01b0\u1eddng l\u00e0 'date_created', \u0111\u00f4i khi 'ngay_ct' ho\u1eb7c 'start_date' t\u00f9y b\u1ea3ng) \u2014 KH\u00d4NG \u0111o\u00e1n b\u1eeba.\n 2. \u0110\u1eccC K\u1ef8 KHO\u00c1 NGO\u1ea0I (REF): N\u1ebfu tr\u01b0\u1eddng d\u1eef li\u1ec7u c\u00f3 object 'ref', B\u1eaeT BU\u1ed8C ph\u1ea3i d\u00f9ng getModel(ref.ref_model) \u0111\u1ec3 query l\u1ea5y 'label_field' t\u01b0\u01a1ng \u1ee9ng v\u00e0 gh\u00e9p v\u00e0o k\u1ebft qu\u1ea3 (Kh\u00f4ng \u0111\u01b0\u1ee3c ph\u00e9p ch\u1ec9 hi\u1ec3n th\u1ecb m\u00e3 th\u00f4).\n \n H\u01af\u1edaNG D\u1eaaN VI\u1ebeT M\u00c3 SCRIPT (JAVASCRIPT):\n - D\u1eef li\u1ec7u v\u1ec1 TI\u1ec0N (doanh thu, chi ph\u00ed...) l\u1ea5y t\u1eeb model 'socai'. D\u1eef li\u1ec7u v\u1ec1 H\u00c0NG (nh\u1eadp/xu\u1ea5t/t\u1ed3n) l\u1ea5y t\u1eeb model 'sokho'. \u0110\u1ea3m b\u1ea3o b\u1ea1n \u0111\u00e3 th\u0103m d\u00f2 ch\u00fang tr\u01b0\u1edbc.\n - B\u1ea1n c\u00f3 s\u1eb5n h\u00e0m 'getModel(t\u00ean_b\u1ea3ng)'. Ch\u1ec9 d\u00f9ng c\u00e1c h\u00e0m: .find(), .findOne(), .aggregate(), .countDocuments(). LU\u00d4N d\u00f9ng .lean() \u0111\u1ec3 t\u1ed1i \u01b0u RAM.\n - B\u1ea1n c\u00f3 s\u1eb5n bi\u1ebfn m\u00f4i tr\u01b0\u1eddng: 'id_app' v\u00e0 th\u01b0 vi\u1ec7n 'moment'.\n - B\u1ea0N C\u00d3 S\u1eb4N OBJECT 'params': H\u00e3y r\u00e8n luy\u1ec7n th\u00f3i quen KH\u00d4NG hardcode (g\u1eafn c\u1ee9ng) ng\u00e0y th\u00e1ng hay t\u1eeb kh\u00f3a v\u00e0o script. H\u00e3y truy\u1ec1n n\u00f3 qua tham s\u1ed1 'params' v\u00e0 g\u1ecdi 'params.tu_ngay', 'params.ma_nv' b\u00ean trong script.\n \n \ud83d\udd25 C\u00c1C H\u00c0M K\u1ebe TO\u00c1N & KHO L\u00d5I (B\u1eaeT BU\u1ed8C D\u00d9NG KHI T\u00cdNH S\u1ed0 D\u01af, T\u1ed2N KHO):\n H\u1ec7 th\u1ed1ng cung c\u1ea5p s\u1eb5n c\u00e1c h\u00e0m t\u00ednh \u0110\u1ea7u k\u1ef3 / Cu\u1ed1i k\u1ef3, c\u1ea7n \u0111\u1ed1i ph\u00e1t sinh t\u00e0i kho\u1ea3n, t\u1ed5ng h\u1ee3p nh\u1eadp xu\u1ea5t t\u1ed3n. B\u1ea1n PH\u1ea2I d\u00f9ng c\u00e1c h\u00e0m n\u00e0y thay v\u00ec t\u1ef1 vi\u1ebft aggregate tr\u00ean data_socai/data_sokho. (H\u1ec7 th\u1ed1ng \u0111\u00e3 t\u1ef1 g\u00e1n id_app, B\u1ea0N CH\u1ec8 TRUY\u1ec0N C\u00c1C THAM S\u1ed0 C\u00d2N L\u1ea0I, v\u00e0 B\u1eaeT BU\u1ed8C ph\u1ea3i d\u00f9ng t\u1eeb kh\u00f3a 'await'):\n 1. await dktk({ tk, ngay }) -> Tr\u1ea3 v\u1ec1 m\u1ea3ng: [{tk, du_no00, du_co00}]\n 2. await cktk({ tk, ngay }) -> Tr\u1ea3 v\u1ec1 m\u1ea3ng: [{tk, du_no00, du_co00}]\n 3. await dkcn({ ma_kh, phu_trach, tk, ngay, groupBy: [\"tk\", \"ma_kh\", \"ma_bp\"...] }) -> Tr\u1ea3 v\u1ec1: [{tk, ma_kh, du_no00, du_co00}]\n 4. await ckcn({ ma_kh, phu_trach, tk, ngay, groupBy }) -> Tr\u1ea3 v\u1ec1: [{tk, ma_kh, du_no00, du_co00}]\n 5. await dkvt({ ma_vt, ma_kho, ma_kh, ngay, ma_lo, han_sd }) -> Tr\u1ea3 v\u1ec1: [{ma_vt, ma_kho, ma_kh, ton00, du00}]\n 6. await ckvt({ ma_vt, ma_kho, ma_kh, ngay, ma_lo, han_sd }) -> Tr\u1ea3 v\u1ec1: [{ma_vt, ma_kho, ma_kh, ton00, du00}]\n 7. await cdpstk({ tk,tu_ngay,den_ngay,chi_lay_tk_con,bac_tk }) -> Tr\u1ea3 v\u1ec1: [{tk, dk_no,dk_co,ps_no,ps_co, ck_no, ck_co}]\n 8. await thnxt({ ma_vt (Array),tu_ngay,den_ngay,ma_kho,ma_kh,groupBy=[\"ma_vt\"] }) -> Tr\u1ea3 v\u1ec1: [{ma_vt, du_dau,ton_dau,sl_nhap,tien_nhap,sl_xuat, tien_xuat, du_cuoi,ton_cuoi}]\n \n \ud83d\udd25 TH\u1ed0NG K\u00ca DANH M\u1ee4C MASTER DATA (\u0110\u1ebeM S\u1ed0 L\u01af\u1ee2NG / T\u0102NG TR\u01af\u1edeNG THEO K\u1ef2 / PH\u00c2N B\u1ed4 THEO NH\u00d3M):\n D\u00f9ng cho kh\u00e1ch h\u00e0ng, s\u1ea3n ph\u1ea9m, nh\u00e2n vi\u00ean, d\u1ef1 \u00e1n, \u0111\u01a1n h\u00e0ng, ho\u1eb7c b\u1ea5t k\u1ef3 danh m\u1ee5c/ch\u1ee9ng t\u1eeb n\u00e0o khi c\u00e2u h\u1ecfi l\u00e0 \u0110\u1ebeM S\u1ed0 L\u01af\u1ee2NG b\u1ea3n ghi \u2014 KH\u00d4NG ph\u1ea3i h\u1ecfi ti\u1ec1n hay t\u1ed3n kho.\n \n A. C\u00d4NG TH\u1ee8C \"K\u1ef2 TR\u01af\u1edaC \u0110\u1ec2 SO S\u00c1NH\" (k\u1ef3 tr\u01b0\u1edbc = c\u00f9ng \u0111\u1ed9 d\u00e0i, li\u1ec1n k\u1ec1 ngay tr\u01b0\u1edbc k\u1ef3 hi\u1ec7n t\u1ea1i):\n const diffDays = Math.ceil(Math.abs(den_ngay - tu_ngay) / (1000*60*60*24)) || 1;\n const prevEnd = new Date(tu_ngay.getTime() - 1);\n const prevStart = new Date(prevEnd.getTime() - (diffDays*24*60*60*1000) + 1);\n \n B. C\u00d4NG TH\u1ee8C T\u0102NG TR\u01af\u1edeNG (% so v\u1edbi k\u1ef3 tr\u01b0\u1edbc, an to\u00e0n chia 0):\n const growthRate = soLuongKyTruoc > 0\n ? ((soLuongKyNay - soLuongKyTruoc) / soLuongKyTruoc) * 100\n : (soLuongKyNay > 0 ? 100 : 0);\n \n C. VD K\u1ecaCH B\u1ea2N 1 \u2014 Th\u1ed1ng k\u00ea kh\u00e1ch h\u00e0ng m\u1edbi k\u1ef3 n\u00e0y so v\u1edbi k\u1ef3 tr\u01b0\u1edbc (m\u1eabu chu\u1ea9n thay th\u1ebf analytics c\u0169):\n const Customer = getModel('customer');\n const tu_ngay = moment(params.tu_ngay).startOf('day').toDate();\n const den_ngay = moment(params.den_ngay).endOf('day').toDate();\n \n const tongSoLuongHeThong = await Customer.countDocuments({});\n const soLuongMoiKyNay = await Customer.countDocuments({ date_created: { $gte: tu_ngay, $lte: den_ngay } });\n \n const diffDays = Math.ceil(Math.abs(den_ngay - tu_ngay) / (1000*60*60*24)) || 1;\n const prevEnd = new Date(tu_ngay.getTime() - 1);\n const prevStart = new Date(prevEnd.getTime() - (diffDays*24*60*60*1000) + 1);\n const soLuongMoiKyTruoc = await Customer.countDocuments({ date_created: { $gte: prevStart, $lte: prevEnd } });\n \n const growthRate = soLuongMoiKyTruoc > 0\n ? ((soLuongMoiKyNay - soLuongMoiKyTruoc) / soLuongMoiKyTruoc) * 100\n : (soLuongMoiKyNay > 0 ? 100 : 0);\n \n RESULT = {\n thoi_gian_phan_tich: { tu_ngay: params.tu_ngay, den_ngay: params.den_ngay, ky_truoc_tu: prevStart, ky_truoc_den: prevEnd },\n tong_so_luong_he_thong: tongSoLuongHeThong,\n so_luong_moi_ky_nay: soLuongMoiKyNay,\n so_luong_moi_ky_truoc: soLuongMoiKyTruoc,\n tang_truong_so_voi_ky_truoc: `${growthRate.toFixed(2)}%`\n };\n \n D. VD K\u1ecaCH B\u1ea2N 2 \u2014 Ph\u00e2n b\u1ed5 s\u1ed1 l\u01b0\u1ee3ng theo nh\u00f3m (VD: s\u1ed1 s\u1ea3n ph\u1ea9m theo t\u1eebng nh\u00f3m h\u00e0ng):\n const DmVt = getModel('dmvt');\n const phanBo = await DmVt.aggregate([\n { $group: { _id: \"$ma_nvt\", so_luong: { $sum: 1 } } },\n { $sort: { so_luong: -1 } }\n ]);\n // Gh\u00e9p t\u00ean nh\u00f3m \u2014 KH\u00d4NG hi\u1ec3n th\u1ecb m\u00e3 th\u00f4 (theo LU\u1eacT S\u1ed0NG C\u00d2N s\u1ed1 2)\n const DmNvt = getModel('dmnvt');\n for (let row of phanBo) {\n const nhom = await DmNvt.findOne({ _id: row._id }).lean();\n row.ten_nhom = nhom ? nhom.ten_nvt : 'Ch\u01b0a ph\u00e2n nh\u00f3m';\n }\n RESULT = { phan_bo_theo_nhom: phanBo };\n \n - X\u1eec L\u00dd BI\u00caN TH\u1edcI GIAN V\u1edaI MOMENT (R\u1ea4T QUAN TR\u1eccNG): \n + Khi so s\u00e1nh L\u1edbn h\u01a1n/b\u1eb1ng ($gte/$gt) -> D\u00f9ng: moment(params.tu_ngay).startOf('day').toDate()\n + Khi so s\u00e1nh Nh\u1ecf h\u01a1n/b\u1eb1ng ($lte/$lt) -> D\u00f9ng: moment(params.den_ngay).endOf('day').toDate()\n \n - T\u1ed0I \u01afU B\u1ed8 NH\u1eda (TOKEN LIMIT): Nhi\u1ec7m v\u1ee5 c\u1ee7a b\u1ea1n l\u00e0 d\u00f9ng Javascript \u0111\u1ec3 T\u1ed4NG H\u1ee2P (T\u00ednh t\u1ed5ng, \u0110\u1ebfm, Gom nh\u00f3m) ngay b\u00ean trong script. \n -> G\u00e1n v\u00e0o bi\u1ebfn 'RESULT' m\u1ed9t Object ho\u1eb7c m\u1ea3ng \u0110\u00c3 \u0110\u01af\u1ee2C T\u1ed4NG H\u1ee2P (V\u00ed d\u1ee5: C\u00e1c ch\u1ec9 ti\u00eau doanh thu, chi ph\u00ed, l\u1ee3i nhu\u1eadn, ho\u1eb7c s\u1ed1 l\u01b0\u1ee3ng/t\u0103ng tr\u01b0\u1edfng/ph\u00e2n b\u1ed5 nh\u01b0 tr\u00ean).\n -> TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG tr\u1ea3 v\u1ec1 m\u1ea3ng ch\u1ee9a h\u00e0ng ng\u00e0n d\u00f2ng chi ti\u1ebft ch\u1ee9ng t\u1eeb th\u00f4 (raw data). \u0110i\u1ec1u n\u00e0y s\u1ebd l\u00e0m s\u1eadp h\u1ec7 th\u1ed1ng v\u00ec v\u01b0\u1ee3t qu\u00e1 gi\u1edbi h\u1ea1n Token (Request too large). N\u1ebfu c\u1ea7n hi\u1ec3n th\u1ecb chi ti\u1ebft, ch\u1ec9 .slice(0, 5) \u0111\u1ec3 l\u1ea5y 5 d\u00f2ng \u0111\u1ea1i di\u1ec7n.\n ",
24
+ inputSchema:z.object({explored_models:z.array(z.string()).describe("Danh s\u00e1ch c\u00e1c model b\u1ea1n \u0110\u00c3 TH\u0102M D\u00d2 qua exploreSystemSchemaTool."),params:z.record(z.any()).optional().default({}).describe('Object ch\u1ee9a c\u00e1c bi\u1ebfn \u0111\u1ed9ng truy\u1ec1n v\u00e0o script (V\u00ed d\u1ee5: {"tu_ngay": "2026-06-01", "den_ngay": "2026-06-11"}).'),script:z.string().describe("\u0110o\u1ea1n m\u00e3 JS. V\u00ed d\u1ee5:\n const Invoice = getModel('hd2');\n const Customer = getModel('customer');\n \n // X\u1eed l\u00fd th\u1eddi gian an to\u00e0n\n const tu_ngay = moment(params.tu_ngay).startOf('day').toDate();\n const den_ngay = moment(params.den_ngay).endOf('day').toDate();\n \n const invoices = await Invoice.find({ \n id_app, \n ngay_ct: { $gte: tu_ngay, $lte: den_ngay } \n }).lean();\n \n // X\u1eed l\u00fd kho\u00e1 ngo\u1ea1i (Ref Mapping)\n for(let inv of invoices) {\n const kh = await Customer.findOne({ id_app, ma_kh: inv.ma_kh }).lean();\n inv.ten_kh = kh ? kh.ten_kh : 'Kh\u00e1ch l\u1ebb';\n }\n RESULT = { data: invoices };\n \n // Xem th\u00eam 2 v\u00ed d\u1ee5 TH\u1ed0NG K\u00ca DANH M\u1ee4C (\u0111\u1ebfm s\u1ed1 l\u01b0\u1ee3ng, t\u0103ng tr\u01b0\u1edfng theo k\u1ef3,\n // ph\u00e2n b\u1ed5 theo nh\u00f3m) trong ph\u1ea7n \"\ud83d\udd25 TH\u1ed0NG K\u00ca DANH M\u1ee4C MASTER DATA\" c\u1ee7a\n // description ch\u00ednh \u1edf tr\u00ean.\n "),
25
+ rationale:z.string().describe("Gi\u1ea3i th\u00edch logic truy v\u1ea5n v\u00e0 c\u00e1ch b\u1ea1n map c\u00e1c tr\u01b0\u1eddng kho\u00e1 ngo\u1ea1i.")}),execute:async({explored_models:$cleanData_explored_models$$,params:$params$$,script:$script$$,rationale:$rationale$$})=>{Logger.warn("[AI Agent][codeInterpreterTool] Rationale:",$rationale$$);Logger.info("[AI Agent][codeInterpreterTool] \u0110\u00e3 th\u0103m d\u00f2 c\u00e1c model:",$cleanData_explored_models$$.join(", "));Logger.info("[AI Agent][codeInterpreterTool] Params nh\u1eadn v\u00e0o:",
26
+ JSON.stringify($params$$));try{const $executionResult$$=await evalute(`
27
+ ${$script$$}
28
+ return typeof RESULT !== 'undefined' ? RESULT : null;
29
+ `,{id_app:$id_app$$,moment,params:$params$$,RESULT:null,console:{log:(...$args$$)=>Logger.info("[AI Sandbox Log]:",...$args$$),error:(...$args$$)=>Logger.error("[AI Sandbox Error]:",...$args$$)},dktk:async($opts$$={})=>await dktk({...$opts$$,id_app:$id_app$$}),cktk:async($opts$$={})=>await cktk({...$opts$$,id_app:$id_app$$}),dkcn:async($opts$$={})=>await dkcn({...$opts$$,id_app:$id_app$$}),ckcn:async($opts$$={})=>await ckcn({...$opts$$,id_app:$id_app$$}),dkvt:async($opts$$={})=>await dkvt({...$opts$$,
30
+ id_app:$id_app$$}),ckvt:async($opts$$={})=>await ckvt({...$opts$$,id_app:$id_app$$}),thnxt:async($opts$$={})=>await thnxt({...$opts$$,id_app:$id_app$$}),cdpstk:async($opts$$={})=>await cdpstk({...$opts$$,id_app:$id_app$$}),getModel:$cleanModelName_modelName$$=>{$cleanModelName_modelName$$=$cleanModelName_modelName$$.toLowerCase().trim();const $Model$$=global.getModel($cleanModelName_modelName$$);if(!$Model$$)throw Error(`Model '${$cleanModelName_modelName$$}' kh\u00f4ng t\u1ed3n t\u1ea1i. Y\u00eau c\u1ea7u AI xem l\u1ea1i exploreSystemSchemaTool.`);
31
+ const $enforceIdApp$$=($cond_query$$={})=>{$cond_query$$={...$cond_query$$};$Model$$.schema.paths.id_app?$cond_query$$.id_app=$id_app$$:delete $cond_query$$.id_app;$Model$$.schema.paths.id_apps&&$Model$$.schema.paths.id_apps.instance==="Array"?($cond_query$$.$and||($cond_query$$.$and=[]),$cond_query$$.$and.push({$or:[{id_apps:$id_app$$},{id_apps:null},{"id_apps.0":{$exists:!1}}]})):delete $cond_query$$.id_apps;return $cond_query$$},$enforcePipeline$$=($newPipeline_pipeline$$=[])=>{$newPipeline_pipeline$$=
32
+ [...$newPipeline_pipeline$$];$newPipeline_pipeline$$.length>0&&$newPipeline_pipeline$$[0].$match?$newPipeline_pipeline$$[0].$match.id_app=$id_app$$:$newPipeline_pipeline$$.unshift({$match:{id_app:$id_app$$}});return $newPipeline_pipeline$$};return{find:($cond$$,$proj$$,$opts$$)=>$Model$$.find($enforceIdApp$$($cond$$),$proj$$,$opts$$),findOne:($cond$$,$proj$$,$opts$$)=>$Model$$.findOne($enforceIdApp$$($cond$$),$proj$$,$opts$$),countDocuments:$cond$$=>$Model$$.countDocuments($enforceIdApp$$($cond$$)),
33
+ aggregate:$pipeline$$=>$Model$$.aggregate($enforcePipeline$$($pipeline$$))}}},15E3);$cleanData_explored_models$$=null;if($executionResult$$!==void 0&&$executionResult$$!==null){const $stringifiedData$$=JSON.stringify($executionResult$$);if($stringifiedData$$.length>5E4)return{status:"error",message:"L\u1ed6I TR\u00c0N B\u1ed8 NH\u1eda (TOKEN OVERLOAD): Script c\u1ee7a b\u1ea1n tr\u1ea3 v\u1ec1 qu\u00e1 nhi\u1ec1u d\u1eef li\u1ec7u th\u00f4. H\u00e3y s\u1eeda l\u1ea1i script, ch\u1ec9 t\u00ednh to\u00e1n t\u1ed5ng (SUM) ho\u1eb7c gom nh\u00f3m (GROUP BY) v\u00e0 tr\u1ea3 v\u1ec1 c\u00e1c ch\u1ec9 ti\u00eau b\u00e1o c\u00e1o, TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG in ra danh s\u00e1ch chi ti\u1ebft ch\u1ee9ng t\u1eeb."};
34
+ $cleanData_explored_models$$=JSON.parse($stringifiedData$$)}return{status:"success",message:"Truy xu\u1ea5t v\u00e0 t\u00ednh to\u00e1n d\u1eef li\u1ec7u th\u00e0nh c\u00f4ng.",data:$cleanData_explored_models$$,hint:'QUY T\u1eaeC TR\u1ea2 L\u1edcI B\u1eaeT BU\u1ed8C (MINH B\u1ea0CH S\u1ed0 LI\u1ec6U):\n 1. Tr\u00ecnh b\u00e0y d\u1eef li\u1ec7u b\u00e1o c\u00e1o d\u1ea1ng b\u1ea3ng Markdown r\u00f5 r\u00e0ng.\n 2. \u0110\u1ec2 USER C\u00d3 TH\u1ec2 KI\u1ec2M CH\u1ee8NG, B\u1ea0N B\u1eaeT BU\u1ed8C ph\u1ea3i t\u1ea1o m\u1ed9t ph\u1ea7n gi\u1ea3i th\u00edch c\u00e1ch t\u00ednh to\u00e1n v\u00e0 \u0111\u1eb7t n\u00f3 trong th\u1ebb \u0111\u00f3ng/m\u1edf HTML <details> ngay d\u01b0\u1edbi b\u1ea3ng b\u00e1o c\u00e1o theo format sau:\n \n <details>\n <summary>\ud83d\udd0d <b>B\u1ea5m v\u00e0o \u0111\u00e2y \u0111\u1ec3 xem chi ti\u1ebft c\u00e1ch AI t\u00ednh to\u00e1n</b></summary>\n \n - **Ngu\u1ed3n d\u1eef li\u1ec7u:** N\u00eau r\u00f5 l\u1ea5y t\u1eeb b\u1ea3ng n\u00e0o (VD: data_socai, ho\u1eb7c danh m\u1ee5c customer/dmvt...).\n - **\u0110i\u1ec1u ki\u1ec7n l\u1ecdc:** N\u00eau r\u00f5 m\u1ed1c th\u1eddi gian v\u00e0 c\u00e1c \u0111i\u1ec1u ki\u1ec7n l\u1ecdc (VD: Ch\u1ec9 l\u1ea5y tr\u1ea1ng th\u00e1i = 1).\n - **C\u00f4ng th\u1ee9c:** N\u00eau r\u00f5 c\u00e1c t\u00e0i kho\u1ea3n k\u1ebf to\u00e1n/logic \u0111\u00e3 c\u1ed9ng tr\u1eeb, HO\u1eb6C c\u00f4ng th\u1ee9c \u0111\u1ebfm/t\u0103ng tr\u01b0\u1edfng/ph\u00e2n b\u1ed5 \u0111\u00e3 d\u00f9ng.\n - **M\u00e3 Script (T\u00f9y ch\u1ecdn):** \u0110\u01b0a \u0111o\u1ea1n code JS c\u1ed1t l\u00f5i v\u00e0o block ```javascript \u0111\u1ec3 user am hi\u1ec3u k\u1ef9 thu\u1eadt c\u00f3 th\u1ec3 review.\n </details>\n \n 3. CU\u1ed0I C\u00d9NG: H\u00e3y h\u1ecfi "S\u1ebfp c\u00f3 mu\u1ed1n em l\u01b0u l\u1ea1i m\u1eabu b\u00e1o c\u00e1o n\u00e0y th\u00e0nh B\u00e1o c\u00e1o t\u1ef1 \u0111\u1ed9ng \u0111\u1ec3 l\u1ea7n sau d\u00f9ng nhanh kh\u00f4ng \u1ea1?" (N\u1ebfu S\u1ebfp \u0111\u1ed3ng \u00fd, h\u00e3y d\u00f9ng saveCustomReportTool).'}}catch($error$$){return console.error("[L\u1ed7i codeInterpreterTool]:",
35
+ $error$$),{status:"error",message:`L\u1ed7i khi ch\u1ea1y Script: ${$error$$.message}. H\u01af\u1edaNG D\u1eaaN AI: H\u00e3y \u0111\u1ecdc k\u1ef9 l\u1ed7i, ki\u1ec3m tra l\u1ea1i logic (V\u00ed d\u1ee5: qu\u00ean await, sai t\u00ean bi\u1ebfn, truy\u1ec1n sai params, g\u1ecdi sai t\u00ean Collection/Field) v\u00e0 g\u1ecdi l\u1ea1i tool \u0111\u1ec3 s\u1eeda l\u1ed7i.`,failed_script:$script$$}}}}),saveCustomReportTool:tool({description:"C\u00f4ng c\u1ee5 L\u01afU K\u1ecaCH B\u1ea2N B\u00c1O C\u00c1O (Save Custom Report).\n S\u1eec D\u1ee4NG KHI: S\u1ebfp y\u00eau c\u1ea7u l\u01b0u l\u1ea1i k\u1ebft qu\u1ea3 ph\u00e2n t\u00edch/b\u00e1o c\u00e1o v\u1eeba t\u1ea1o ra \u0111\u1ec3 d\u00f9ng cho c\u00e1c l\u1ea7n sau.\n L\u01afU \u00dd: \u0110o\u1ea1n 'script' b\u1ea1n truy\u1ec1n v\u00e0o PH\u1ea2I \u0110\u01af\u1ee2C T\u1ed4NG QU\u00c1T H\u00d3A. \u0110\u1eebng hardcode ng\u00e0y th\u00e1ng, h\u00e3y thay b\u1eb1ng 'params.tu_ngay' v\u00e0 'params.den_ngay'.",
36
+ inputSchema:z.object({report_code:z.string().describe("M\u00e3 b\u00e1o c\u00e1o vi\u1ebft hoa kh\u00f4ng d\u1ea5u (VD: BC_KHACH_VIP)."),report_name:z.string().describe("T\u00ean b\u00e1o c\u00e1o r\u00f5 ngh\u0129a."),description:z.string().describe("M\u00f4 t\u1ea3 m\u1ee5c \u0111\u00edch b\u00e1o c\u00e1o."),expected_params:z.array(z.string()).describe('Danh s\u00e1ch c\u00e1c bi\u1ebfn h\u1ec7 th\u1ed1ng c\u1ea7n (VD: ["tu_ngay", "den_ngay"]).'),script:z.string().describe('\u0110o\u1ea1n m\u00e3 JS \u0111\u00e3 t\u1ed5ng qu\u00e1t h\u00f3a (s\u1eed d\u1ee5ng object "params" \u0111\u1ec3 nh\u1eadn bi\u1ebfn).')}),
37
+ execute:async $payload$$=>{Logger.warn("[AI Agent][saveCustomReportTool]",$payload$$.report_name);try{const $CustomReport$$=global.getModel("custom_report");$payload$$.id_app=$id_app$$;$payload$$.created_by="AI_AGENT";await $CustomReport$$.create($payload$$);return{status:"success",message:`\u0110\u00e3 l\u01b0u b\u00e1o c\u00e1o '${$payload$$.report_name}' th\u00e0nh c\u00f4ng v\u1edbi m\u00e3 ${$payload$$.report_code}.`}}catch($e$$){return{status:"error",message:$e$$.message}}}}),runSavedCustomReportTool:tool({description:"C\u00f4ng c\u1ee5 CH\u1ea0Y B\u00c1O C\u00c1O T\u00d9Y CH\u1ec8NH (Run Custom Report).\n S\u1eec D\u1ee4NG KHI: S\u1ebfp y\u00eau c\u1ea7u ch\u1ea1y m\u1ed9t b\u00e1o c\u00e1o \u0111\u1eb7c th\u00f9 m\u00e0 AI \u0110\u00c3 T\u1eeaNG L\u01afU TR\u01af\u1edaC \u0110\u00d3.\n H\u01af\u1edaNG D\u1eaaN: Truy\u1ec1n v\u00e0o t\u1eeb kh\u00f3a t\u00ecm ki\u1ebfm (t\u00ean b\u00e1o c\u00e1o) v\u00e0 c\u00e1c tham s\u1ed1 (n\u1ebfu c\u00f3).",
38
+ inputSchema:z.object({keyword:z.string().describe('T\u1eeb kh\u00f3a t\u00ean b\u00e1o c\u00e1o (VD: "Kh\u00e1ch VIP").'),params:z.record(z.any()).describe('Tham s\u1ed1 truy\u1ec1n v\u00e0o cho Script (VD: { "tu_ngay": "2026-06-01", "den_ngay": "2026-06-11" }).')}),execute:async({keyword:$keyword$$,params:$params$$})=>{Logger.warn("[AI Agent][runSavedCustomReportTool]",JSON.stringify({keyword:$keyword$$,params:$params$$},null,2));try{const $report$$=await global.getModel("custom_report").findOne({id_app:$id_app$$,
39
+ $or:[{report_code:{$regex:$keyword$$,$options:"i"}},{report_name:{$regex:$keyword$$,$options:"i"}}]}).lean();if(!$report$$)return{status:"not_found",message:`Kh\u00f4ng t\u00ecm th\u1ea5y b\u00e1o c\u00e1o n\u00e0o t\u00ean '${$keyword$$}'.`};const $executionResult$$=await evalute(`${$report$$.script}\n return typeof RESULT !== 'undefined' ? RESULT : null;`,{id_app:$id_app$$,moment,params:$params$$,RESULT:null,console:{log:(...$args$$)=>Logger.info("[Saved Script Log]:",...$args$$)},dktk:async($opts$$=
40
+ {})=>await dktk({...$opts$$,id_app:$id_app$$}),cktk:async($opts$$={})=>await cktk({...$opts$$,id_app:$id_app$$}),dkcn:async($opts$$={})=>await dkcn({...$opts$$,id_app:$id_app$$}),ckcn:async($opts$$={})=>await ckcn({...$opts$$,id_app:$id_app$$}),dkvt:async($opts$$={})=>await dkvt({...$opts$$,id_app:$id_app$$}),ckvt:async($opts$$={})=>await ckvt({...$opts$$,id_app:$id_app$$}),getModel:$cleanModelName$jscomp$1_modelName$$=>{$cleanModelName$jscomp$1_modelName$$=$cleanModelName$jscomp$1_modelName$$.toLowerCase().trim();
41
+ const $Model$$=global.getModel($cleanModelName$jscomp$1_modelName$$);if(!$Model$$)throw Error(`Model '${$cleanModelName$jscomp$1_modelName$$}' kh\u00f4ng t\u1ed3n t\u1ea1i. Y\u00eau c\u1ea7u AI xem l\u1ea1i exploreSystemSchemaTool.`);const $enforceIdApp$$=($cond$$={})=>({...$cond$$,id_app:$id_app$$}),$enforcePipeline$$=($newPipeline$jscomp$1_pipeline$$=[])=>{$newPipeline$jscomp$1_pipeline$$=[...$newPipeline$jscomp$1_pipeline$$];$newPipeline$jscomp$1_pipeline$$.length>0&&$newPipeline$jscomp$1_pipeline$$[0].$match?
42
+ $newPipeline$jscomp$1_pipeline$$[0].$match.id_app=$id_app$$:$newPipeline$jscomp$1_pipeline$$.unshift({$match:{id_app:$id_app$$}});return $newPipeline$jscomp$1_pipeline$$};return{find:($cond$$,$proj$$,$opts$$)=>$Model$$.find($enforceIdApp$$($cond$$),$proj$$,$opts$$),findOne:($cond$$,$proj$$,$opts$$)=>$Model$$.findOne($enforceIdApp$$($cond$$),$proj$$,$opts$$),countDocuments:$cond$$=>$Model$$.countDocuments($enforceIdApp$$($cond$$)),aggregate:$pipeline$$=>$Model$$.aggregate($enforcePipeline$$($pipeline$$))}}},
43
+ 15E3);return{status:"success",report_name:$report$$.report_name,data:$executionResult$$}}catch($e$$){return{status:"error",message:`L\u1ed7i ch\u1ea1y b\u00e1o c\u00e1o l\u01b0u s\u1eb5n: ${$e$$.message}`}}}})}}module.exports={createReportTools};
@@ -0,0 +1,13 @@
1
+ const {tool}=require("ai"),{z}=require("zod"),getKqChamCong=require("../../libs/kqchamcong");
2
+ function createStaffTools($id_app$$,$user_id$$){return{getAttendanceReportTool:tool({description:"C\u00f4ng c\u1ee5 l\u1ea5y b\u00e1o c\u00e1o v\u00e0 th\u1ed1ng k\u00ea t\u00ecnh h\u00ecnh ch\u1ea5m c\u00f4ng, ng\u00e0y c\u00f4ng c\u1ee7a nh\u00e2n vi\u00ean t\u1eeb th\u01b0 vi\u1ec7n g\u1ed1c h\u1ec7 th\u1ed1ng.\n S\u1eec D\u1ee4NG KHI: \n 1. S\u1ebfp ho\u1eb7c Nh\u00e2n s\u1ef1/K\u1ebf to\u00e1n l\u01b0\u01a1ng c\u1ea7n tra c\u1ee9u t\u00ecnh h\u00ecnh ch\u1ea5m c\u00f4ng c\u1ee7a m\u1ed9t ph\u00f2ng ban ho\u1eb7c m\u1ed9t c\u00e1 nh\u00e2n b\u1ea5t k\u1ef3.\n 2. Ch\u00ednh ng\u01b0\u1eddi \u0111ang s\u1eed d\u1ee5ng h\u1ec7 th\u1ed1ng h\u1ecfi v\u1ec1 t\u00ecnh h\u00ecnh \u0111i l\u00e0m, ng\u00e0y c\u00f4ng ho\u1eb7c s\u1ed1 ng\u00e0y ngh\u1ec9 ph\u00e9p c\u1ee7a B\u1ea2N TH\u00c2N h\u1ecd.",inputSchema:z.object({tu_ngay:z.string().describe("T\u1eeb ng\u00e0y b\u1eaft \u0111\u1ea7u ch\u1ea5m c\u00f4ng (\u0110\u1ecbnh d\u1ea1ng: YYYY-MM-DD)."),
3
+ den_ngay:z.string().describe("\u0110\u1ebfn ng\u00e0y k\u1ebft th\u00fac ch\u1ea5m c\u00f4ng (\u0110\u1ecbnh d\u1ea1ng: YYYY-MM-DD)."),is_self_service:z.boolean().default(!1).describe('R\u1ea4T QUAN TR\u1eccNG: B\u1eadt TRUE n\u1ebfu ng\u01b0\u1eddi d\u00f9ng \u0111ang h\u1ecfi v\u1ec1 t\u00ecnh h\u00ecnh ch\u1ea5m c\u00f4ng c\u1ee7a CH\u00cdNH B\u1ea2N TH\u00c2N H\u1ecc (V\u00ed d\u1ee5: "Th\u00e1ng n\u00e0y em \u0111\u01b0\u1ee3c bao nhi\u00eau c\u00f4ng?", "Anh/ch\u1ecb xem gi\u00f9m c\u00f4ng c\u1ee7a t\u00f4i"). \u0110\u1ec3 FALSE (M\u1eb7c \u0111\u1ecbnh) n\u1ebfu ng\u01b0\u1eddi d\u00f9ng l\u00e0 Qu\u1ea3n l\u00fd/K\u1ebf to\u00e1n \u0111ang tra c\u1ee9u s\u1ed1 li\u1ec7u cho nh\u00e2n vi\u00ean kh\u00e1c ho\u1eb7c cho ph\u00f2ng ban.'),
4
+ ma_nv:z.string().optional().describe("M\u00e3 nh\u00e2n vi\u00ean c\u1ee5 th\u1ec3 c\u1ea7n tra c\u1ee9u (D\u00f9ng khi k\u1ebf to\u00e1n/qu\u1ea3n l\u00fd xem cho ng\u01b0\u1eddi kh\u00e1c. KH\u00d4NG truy\u1ec1n tr\u01b0\u1eddng n\u00e0y n\u1ebfu is_self_service l\u00e0 true)."),ma_bp:z.string().optional().describe("M\u00e3 b\u1ed9 ph\u1eadn/ph\u00f2ng ban n\u1ebfu mu\u1ed1n xem ch\u1ea5m c\u00f4ng c\u1ee7a c\u1ea3 ph\u00f2ng (Ch\u1ec9 d\u00e0nh cho Qu\u1ea3n l\u00fd/K\u1ebf to\u00e1n)."),lam_thu_7:z.boolean().default(!0).describe("C\u1ea5u h\u00ecnh c\u00f4ng ty c\u00f3 l\u00e0m vi\u1ec7c v\u00e0o ng\u00e0y Th\u1ee9 7 hay kh\u00f4ng. M\u1eb7c \u0111\u1ecbnh l\u00e0 true."),
5
+ only_summary:z.boolean().default(!0).describe("N\u1ebfu TRUE: Ch\u1ec9 tr\u1ea3 v\u1ec1 s\u1ed1 t\u1ed5ng c\u1ed9ng (Ti\u1ebft ki\u1ec7m token). N\u1ebfu FALSE: Tr\u1ea3 v\u1ec1 danh s\u00e1ch chi ti\u1ebft t\u1eebng ng\u00e0y ph\u00e1t sinh.")}),execute:async({tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$,is_self_service:$is_self_service$$,ma_nv:$ma_nv_target_type$$,ma_bp:$ma_bp$$,lam_thu_7:$lam_thu_7$$,only_summary:$only_summary$$})=>{try{const $DmnvModel$$=global.getModel("dmnv");if(typeof getKqChamCong!==
6
+ "function")return{status:"error",message:"Th\u01b0 vi\u1ec7n kqchamcong kh\u00f4ng export m\u1ed9t function h\u1ee3p l\u1ec7."};let $final_ma_nv$$=$ma_nv_target_type$$?$ma_nv_target_type$$.toUpperCase().trim():void 0;$ma_nv_target_type$$="others";if($is_self_service$$){if(!$DmnvModel$$)return{status:"error",message:"Model 'dmnv' kh\u00f4ng t\u1ed3n t\u1ea1i tr\u00ean h\u1ec7 th\u1ed1ng \u0111\u1ec3 qu\u00e9t m\u00e3 nh\u00e2n vi\u00ean."};const $employeeDoc$$=$user_id$$?await $DmnvModel$$.findOne({id_app:$id_app$$,
7
+ user:$user_id$$},{ma_nv:1}).lean():null;if(!$employeeDoc$$||!$employeeDoc$$.ma_nv)return{status:"error",message:"T\u00e0i kho\u1ea3n c\u1ee7a b\u1ea1n hi\u1ec7n ch\u01b0a \u0111\u01b0\u1ee3c li\u00ean k\u1ebft v\u1edbi b\u1ea5t k\u1ef3 m\u00e3 nh\u00e2n vi\u00ean n\u00e0o trong danh m\u1ee5c dmnv. Vui l\u00f2ng li\u00ean h\u1ec7 nh\u00e2n s\u1ef1."};$final_ma_nv$$=$employeeDoc$$.ma_nv;$ma_bp$$=void 0;$ma_nv_target_type$$="self"}const $condition$$={id_app:$id_app$$,tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$,
8
+ ma_nv:$final_ma_nv$$,ma_bp:$ma_bp$$?$ma_bp$$.toUpperCase().trim():void 0,lam_thu_7:$lam_thu_7$$?"true":"false"},$report$$=await getKqChamCong($condition$$);if(!$report$$||!$report$$.data||$report$$.data.length===0)return{status:"success",message:`Kh\u00f4ng t\u00ecm th\u1ea5y d\u1eef li\u1ec7u ph\u00e1t sinh ch\u1ea5m c\u00f4ng n\u00e0o t\u1eeb ng\u00e0y ${$tu_ngay$$} \u0111\u1ebfn ${$den_ngay$$}.`};if($final_ma_nv$$)return{status:"success",view_mode:$ma_nv_target_type$$,target_employee:$final_ma_nv$$,
9
+ period:{tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$},data:$report$$.data,hint:$ma_nv_target_type$$==="self"?"AI l\u01b0u \u00fd: \u0110\u00e2y l\u00e0 d\u1eef li\u1ec7u ch\u1ea5m c\u00f4ng chi ti\u1ebft c\u1ee7a CH\u00cdNH NG\u01af\u1edcI \u0110ANG CHAT. H\u00e3y t\u1ed5ng h\u1ee3p t\u1ed5ng s\u1ed1 ng\u00e0y c\u00f4ng t\u00ednh l\u01b0\u01a1ng, s\u1ed1 ng\u00e0y ngh\u1ec9 ph\u00e9p, ngh\u1ec9 kh\u00f4ng l\u01b0\u01a1ng v\u00e0 li\u1ec7t k\u00ea b\u1ea3ng chi ti\u1ebft l\u1ecbch tr\u00ecnh c\u1ee7a t\u1eebng ng\u00e0y v\u1edbi th\u00e1i \u0111\u1ed9 chu \u0111\u00e1o.":
10
+ "AI l\u01b0u \u00fd: \u0110\u00e2y l\u00e0 d\u1eef li\u1ec7u chi ti\u1ebft c\u1ee7a nh\u00e2n vi\u00ean do K\u1ebf to\u00e1n/Qu\u1ea3n l\u00fd y\u00eau c\u1ea7u tra c\u1ee9u. H\u00e3y v\u1ebd b\u1ea3ng Markdown r\u00f5 r\u00e0ng \u0111\u1ec3 h\u1ecd x\u1eed l\u00fd c\u00f4ng vi\u1ec7c."};if($only_summary$$){const $summary$$=$report$$.data.reduce(($acc$$,$curr$$)=>{$acc$$.tong_ngay_cong_tinh_luong+=$curr$$.ngay_cong_tinh_luong||0;$acc$$.tong_ngay_khong_luong+=$curr$$.tong_ngay_khong_luong||0;$report$$.loaicong&&
11
+ $report$$.loaicong.forEach($l$$=>{$acc$$.chi_tiet_loai_cong[$l$$.ma_loai_cong]=($acc$$.chi_tiet_loai_cong[$l$$.ma_loai_cong]||0)+($curr$$[$l$$.ma_loai_cong]||0)});return $acc$$},{tong_so_nhan_su_phat_sinh:$report$$.data.length,tong_ngay_cong_tinh_luong:0,tong_ngay_khong_luong:0,chi_tiet_loai_cong:{}});return{status:"success",is_summary_data:!0,period:{tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$},filter:{ma_bp:$ma_bp$$||"To\u00e0n c\u00f4ng ty/Ph\u00f2ng ban"},data:$summary$$,hint:"AI l\u01b0u \u00fd: \u0110\u00e2y l\u00e0 d\u1eef li\u1ec7u t\u1ed5ng h\u1ee3p r\u00fat g\u1ecdn c\u1ee7a t\u1eadp th\u1ec3 nh\u00e2n s\u1ef1. H\u00e3y d\u00f9ng c\u00e1c s\u1ed1 t\u1ed5ng n\u00e0y \u0111\u1ec3 tr\u1ea3 l\u1eddi b\u00e1o c\u00e1o v\u0129 m\u00f4."}}return{status:"success",
12
+ is_summary_data:!1,total_records:$report$$.data.length,data:$report$$.data.slice(0,50),hint:"D\u1eef li\u1ec7u danh s\u00e1ch nhi\u1ec1u nh\u00e2n vi\u00ean (\u0110\u00e3 c\u1eaft l\u00e1t 50 d\u00f2ng \u0111\u1ec3 b\u1ea3o v\u1ec7 token). H\u00e3y v\u1ebd b\u1ea3ng Markdown."}}catch($error$$){return console.error("[L\u1ed7i t\u1ea1i getAttendanceReportTool - B\u1ea3n c\u1eadp nh\u1eadt ph\u00e2n lo\u1ea1i Self-Service]:",$error$$),{status:"error",message:`L\u1ed7i khi k\u1ebft n\u1ed1i v\u1edbi ph\u00e2n h\u1ec7 ch\u1ea5m c\u00f4ng: ${$error$$.message||
13
+ String($error$$)}`}}}})}}module.exports={createStaffTools};
@@ -0,0 +1,41 @@
1
+ const {tool}=require("ai"),{z}=require("zod"),moment=require("moment"),ckvt=require("../../libs/ckvt"),getStockSummary=require("../../libs/thnxt"),getPriceCalculation=require("../../libs/getGiaban");
2
+ function createStockTools($id_app$$){return{getProductPriceAndPromotionTool:tool({description:'L\u1ea5y th\u00f4ng tin Gi\u00e1 b\u00e1n, Chi\u1ebft kh\u1ea5u v\u00e0 Ch\u01b0\u01a1ng tr\u00ecnh Khuy\u1ebfn m\u00e3i \u00e1p d\u1ee5ng cho m\u1ed9t s\u1ea3n ph\u1ea9m. S\u1eec D\u1ee4NG khi s\u1ebfp h\u1ecfi: "Gi\u00e1 c\u1ee7a s\u1ea3n ph\u1ea9m X l\u00e0 bao nhi\u00eau?", "Mua 10 c\u00e1i c\u00f3 \u0111\u01b0\u1ee3c gi\u1ea3m gi\u00e1 hay t\u1eb7ng qu\u00e0 g\u00ec kh\u00f4ng?", "Kh\u00e1ch h\u00e0ng A mua m\u1eb7t h\u00e0ng n\u00e0y th\u00ec gi\u00e1 th\u1ebf n\u00e0o?".',inputSchema:z.object({ma_vt:z.string().describe("M\u00e3 s\u1ea3n ph\u1ea9m/v\u1eadt t\u01b0 c\u1ea7n tra c\u1ee9u gi\u00e1. L\u01afU \u00dd QUAN TR\u1eccNG: N\u1ebfu s\u1ebfp ch\u1ec9 nh\u1eafc t\u00ean s\u1ea3n ph\u1ea9m m\u00e0 b\u1ea1n ch\u01b0a bi\u1ebft m\u00e3, B\u1eaeT BU\u1ed8C ph\u1ea3i g\u1ecdi `lookupMasterDataTool` \u0111\u1ec3 l\u1ea5y m\u00e3 (ma_vt) tr\u01b0\u1edbc khi g\u1ecdi tool n\u00e0y."),
3
+ ma_kh:z.string().optional().describe("M\u00e3 kh\u00e1ch h\u00e0ng. Truy\u1ec1n v\u00e0o n\u1ebfu s\u1ebfp mu\u1ed1n ki\u1ec3m tra gi\u00e1/chi\u1ebft kh\u1ea5u \u00e1p d\u1ee5ng ri\u00eang cho m\u1ed9t kh\u00e1ch h\u00e0ng c\u1ee5 th\u1ec3. L\u1ea1i nh\u1edb d\u00f9ng lookupMasterDataTool n\u1ebfu ch\u1ec9 c\u00f3 t\u00ean."),so_luong:z.number().optional().describe("S\u1ed1 l\u01b0\u1ee3ng mua d\u1ef1 ki\u1ebfn. Truy\u1ec1n s\u1ed1 l\u01b0\u1ee3ng v\u00e0o \u0111\u00e2y \u0111\u1ec3 h\u1ec7 th\u1ed1ng t\u1ef1 \u0111\u1ed9ng ki\u1ec3m tra xem c\u00f3 \u0111\u1ea1t m\u1ed1c h\u01b0\u1edfng chi\u1ebft kh\u1ea5u hay nh\u1eadn qu\u00e0 khuy\u1ebfn m\u00e3i kh\u00f4ng. M\u1eb7c \u0111\u1ecbnh l\u00e0 1."),
4
+ ngay_ct:z.string().optional().describe("Ng\u00e0y d\u1ef1 ki\u1ebfn b\u00e1o gi\u00e1/b\u00e1n h\u00e0ng (YYYY-MM-DD). M\u1eb7c \u0111\u1ecbnh l\u00e0 h\u00f4m nay."),ma_tt1:z.string().optional().describe("M\u00e3 thu\u1ed9c t\u00ednh 1 (VD: M\u00e0u s\u1eafc, Size) n\u1ebfu s\u1ea3n ph\u1ea9m c\u00f3 ph\u00e2n lo\u1ea1i thu\u1ed9c t\u00ednh \u1ea3nh h\u01b0\u1edfng \u0111\u1ebfn gi\u00e1.")}),execute:async $query$$=>{Logger.info("[AI Agent][getProductPriceAndPromotionTool]",JSON.stringify($query$$));
5
+ try{const {ma_vt:$ma_vt$$,ma_kh:$ma_kh$$,so_luong:$so_luong$$,ngay_ct:$ngay_ct$$,ma_tt1:$ma_tt1$$}=$query$$,$condition$$={id_app:$id_app$$,ma_vt:$ma_vt$$,ma_kh:$ma_kh$$,so_luong:$so_luong$$||1,ngay_ct:$ngay_ct$$?new Date($ngay_ct$$):new Date,ma_tt1:$ma_tt1$$,get_price:!0,get_discount:!0,get_promotion:!0};Object.keys($condition$$).forEach($key$$=>$condition$$[$key$$]===void 0&&delete $condition$$[$key$$]);return{status:"success",data:await new Promise(($resolve$$,$reject$$)=>{getPriceCalculation($condition$$,
6
+ ($err$$,$rs$$)=>{if($err$$)return $reject$$($err$$);$resolve$$($rs$$)})}),hint:"Gi\u00e1 b\u00e1n g\u1ed1c: Xem 'gia_ban_le'/'gia_ban_buon'. Chi\u1ebft kh\u1ea5u: Xem 'ty_le_ck', 'tien_ck'. Khuy\u1ebfn m\u00e3i: Xem 'default_promotion'."}}catch($error$$){return{status:"error",message:$error$$.message||$error$$.error||String($error$$)}}}}),getInventorySummaryTool:tool({description:'C\u00f4ng c\u1ee5 l\u1ea5y d\u1eef li\u1ec7u T\u1ed5ng h\u1ee3p Nh\u1eadp Xu\u1ea5t T\u1ed3n.\n [BI\u1ec2N C\u1ea4M]: TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG S\u1eec D\u1ee4NG tool n\u00e0y n\u1ebfu ng\u01b0\u1eddi d\u00f9ng CH\u1ec8 h\u1ecfi v\u1ec1 "T\u1ed3n kho hi\u1ec7n t\u1ea1i" ho\u1eb7c "S\u1ed1 d\u01b0 \u0111\u1ea7u/cu\u1ed1i k\u1ef3". B\u00e1o c\u00e1o n\u00e0y r\u1ea5t n\u1eb7ng.\n - N\u1ebfu ch\u1ec9 c\u1ea7n T\u1ed3n kho/S\u1ed1 d\u01b0: B\u1eaft bu\u1ed9c g\u1ecdi \'getAccountingBalancesTool\' (d\u00f9ng dkvt ho\u1eb7c ckvt).\n - CH\u1ec8 S\u1eec D\u1ee4NG tool n\u00e0y khi ng\u01b0\u1eddi d\u00f9ng y\u00eau c\u1ea7u B\u1ee8C TRANH TO\u00c0N C\u1ea2NH trong m\u1ed9t kho\u1ea3ng th\u1eddi gian (c\u1ea7n xem c\u1ea3 s\u1ed1 Nh\u1eadp v\u00e0 s\u1ed1 Xu\u1ea5t trong k\u1ef3) c\u1ee7a m\u1ed9t v\u1eadt t\u01b0 c\u1ee5 th\u1ec3.',
7
+ inputSchema:z.object({tu_ngay:z.string().describe('Ng\u00e0y b\u1eaft \u0111\u1ea7u (YYYY-MM-DD). N\u1ebfu s\u1ebfp n\u00f3i "th\u00e1ng n\u00e0y" th\u00ec l\u00e0 ng\u00e0y 1 c\u1ee7a th\u00e1ng.'),den_ngay:z.string().describe('Ng\u00e0y k\u1ebft th\u00fac (YYYY-MM-DD). M\u1eb7c \u0111\u1ecbnh l\u00e0 h\u00f4m nay n\u1ebfu s\u1ebfp h\u1ecfi "hi\u1ec7n t\u1ea1i".'),ma_vt:z.string().describe("M\u00e3 v\u1eadt t\u01b0, h\u00e0ng h\u00f3a. L\u01afU \u00dd: N\u1ebfu ch\u1ec9 c\u00f3 t\u00ean s\u1ea3n ph\u1ea9m, h\u00e3y g\u1ecdi `lookupMasterDataTool` \u0111\u1ec3 t\u00ecm m\u00e3. B\u1ecf tr\u1ed1ng \u0111\u1ec3 xem to\u00e0n b\u1ed9."),
8
+ ma_kho:z.string().optional().describe("M\u00e3 kho h\u00e0ng. D\u00f9ng khi s\u1ebfp ki\u1ec3m tra t\u1ed3n kho t\u1ea1i 1 kho c\u1ee5 th\u1ec3."),ma_lo:z.string().optional().describe("M\u00e3 l\u00f4 h\u00e0ng."),groupBy:z.array(z.string()).optional().describe('Tr\u01b0\u1eddng g\u1ed9p nh\u00f3m. M\u1eb7c \u0111\u1ecbnh ["ma_vt"]. Truy\u1ec1n ["ma_vt", "ma_kho"] \u0111\u1ec3 xem chi ti\u1ebft kho.'),exclude_ct_dc:z.boolean().optional().describe("Lo\u1ea1i tr\u1eeb c\u00e1c phi\u1ebfu \u0111i\u1ec1u chuy\u1ec3n n\u1ed9i b\u1ed9. M\u1eb7c \u0111\u1ecbnh true."),
9
+ tinh_tong_cong:z.boolean().optional().describe("Truy\u1ec1n true n\u1ebfu mu\u1ed1n d\u00f2ng T\u1ed5ng c\u1ed9ng \u1edf cu\u1ed1i."),chi_hien_tong_cong:z.boolean().optional().describe('R\u1ea4T QUAN TR\u1eccNG: Truy\u1ec1n true n\u1ebfu s\u1ebfp CH\u1ec8 H\u1eceI C\u00c1C S\u1ed0 T\u1ed4NG (VD: "T\u1ed5ng s\u1ed1 l\u01b0\u1ee3ng t\u1ed3n kho?").')}),execute:async $query$$=>{Logger.info("[AI Agent][getInventorySummaryTool]",JSON.stringify($query$$));try{const {tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$,
10
+ ma_vt:$ma_vt$$,ma_kho:$ma_kho$$,ma_lo:$ma_lo$$,groupBy:$groupBy$$,exclude_ct_dc:$exclude_ct_dc$$,tinh_tong_cong:$tinh_tong_cong$$,chi_hien_tong_cong:$chi_hien_tong_cong$$}=$query$$,$condition$$={id_app:$id_app$$,tu_ngay:moment($tu_ngay$$).startOf("date").toDate(),den_ngay:moment($den_ngay$$).endOf("date").toDate(),ma_vt:$ma_vt$$,ma_kho:$ma_kho$$,ma_lo:$ma_lo$$,groupBy:$groupBy$$||["ma_vt"],exclude_ct_dc:$exclude_ct_dc$$!==void 0?$exclude_ct_dc$$:!0,tinh_tong_cong:$tinh_tong_cong$$,chi_hien_tong_cong:$chi_hien_tong_cong$$};
11
+ Object.keys($condition$$).forEach($key$$=>$condition$$[$key$$]===void 0&&delete $condition$$[$key$$]);return{status:"success",data:await new Promise(($resolve$$,$reject$$)=>{getStockSummary($condition$$,($err$$,$result$$)=>{if($err$$)return $reject$$($err$$);$resolve$$($result$$)})})}}catch($error$$){return{status:"error",message:$error$$.message||$error$$.error||String($error$$)}}}}),adviseCostFactorSetupTool:tool({description:'C\u00f4ng c\u1ee5 chuy\u00ean gia t\u01b0 v\u1ea5n thi\u1ebft l\u1eadp Y\u1ebfu t\u1ed1 Gi\u00e1 th\u00e0nh (dmyt). D\u00f9ng khi k\u1ebf to\u00e1n h\u1ecfi c\u00e1ch khai b\u00e1o chi ph\u00ed (VD: "Thi\u1ebft l\u1eadp chi ph\u00ed \u0111i\u1ec7n n\u01b0\u1edbc th\u1ebf n\u00e0o?").',
12
+ inputSchema:z.object({loai_nghiep_vu:z.enum(["chi_phi_truc_tiep","chi_phi_gian_tiep","giam_tru_gia_thanh","yeu_to_trung_gian"]).describe("Lo\u1ea1i nghi\u1ec7p v\u1ee5 chi ph\u00ed. H\u00e3y t\u1ef1 \u0111\u1ed9ng ph\u00e2n lo\u1ea1i."),cach_phan_bo:z.enum(["khong_phan_bo","theo_so_luong","theo_yeu_to_chi_phi","theo_he_so"]).describe("Ph\u01b0\u01a1ng ph\u00e1p ph\u00e2n b\u1ed5.")}),execute:async({loai_nghiep_vu:$loai_nghiep_vu$$,cach_phan_bo:$cach_phan_bo$$})=>{try{let $configAdvice$$={fields_to_set:{},
13
+ explanation:[]};switch($loai_nghiep_vu$$){case "chi_phi_truc_tiep":$configAdvice$$.fields_to_set={th_sp:!0,th_nvl:!0,cong_tru:"1",yt_trung_gian:!1};$configAdvice$$.explanation.push("B\u1eadt th_sp (T\u1eadp h\u1ee3p theo s\u1ea3n ph\u1ea9m).");break;case "chi_phi_gian_tiep":$configAdvice$$.fields_to_set={th_sp:!1,th_bp:!0,cong_tru:"1",yt_trung_gian:!1};$configAdvice$$.explanation.push("T\u1eaft th_sp v\u00e0 b\u1eadt th_bp (T\u1eadp h\u1ee3p theo b\u1ed9 ph\u1eadn).");break;case "giam_tru_gia_thanh":$configAdvice$$.fields_to_set=
14
+ {cong_tru:"2",yt_trung_gian:!1};$configAdvice$$.explanation.push("B\u1eaeT BU\u1ed8C set cong_tru = '2' \u0111\u1ec3 gi\u1ea3m tr\u1eeb.");break;case "yeu_to_trung_gian":$configAdvice$$.fields_to_set={yt_trung_gian:!0,cong_tru:"1"},$configAdvice$$.explanation.push("B\u1eadt yt_trung_gian = true. L\u00e0m m\u1ed1c ph\u00e2n b\u1ed5.")}switch($cach_phan_bo$$){case "khong_phan_bo":$configAdvice$$.fields_to_set.pt_phan_bo="0";break;case "theo_so_luong":$configAdvice$$.fields_to_set.pt_phan_bo="1";break;
15
+ case "theo_yeu_to_chi_phi":$configAdvice$$.fields_to_set.pt_phan_bo="2";$configAdvice$$.fields_to_set.yt_tinh_hs_pb="C\u1ea6N_NH\u1eacP_M\u00c3_Y\u1ebeU_T\u1ed0_G\u1ed0C (VD: NVL)";$configAdvice$$.fields_to_set.pt_tinh_hs_pb="1";break;case "theo_he_so_dinh_muc":$configAdvice$$.fields_to_set.pt_phan_bo="5"}$configAdvice$$.explanation.push("Nh\u1eafc ng\u01b0\u1eddi d\u00f9ng khai b\u00e1o tk_no v\u00e0 tk_dd.");return{status:"success",data:$configAdvice$$,ai_instruction:"Tr\u00ecnh b\u00e0y l\u1ea1i cho ng\u01b0\u1eddi d\u00f9ng theo t\u1eebng b\u01b0\u1edbc c\u1ea5u h\u00ecnh."}}catch($error$$){return{status:"error",
16
+ message:$error$$.message||String($error$$)}}}}),getProductCostReportTool:tool({description:"L\u1ea5y B\u00e1o c\u00e1o Chi ti\u1ebft Gi\u00e1 th\u00e0nh s\u1ea3n ph\u1ea9m (gt_ctgt). Cung c\u1ea5p: Chi ph\u00ed d\u1edf dang, Chi ph\u00ed ph\u00e1t sinh, T\u1ed5ng gi\u00e1 th\u00e0nh v\u00e0 Gi\u00e1 th\u00e0nh \u0111\u01a1n v\u1ecb.",inputSchema:z.object({nam:z.number().describe("N\u0103m t\u00ednh gi\u00e1 th\u00e0nh (VD: 2026)."),thang:z.number().describe("Th\u00e1ng t\u00ednh gi\u00e1 th\u00e0nh (1-12)."),
17
+ ma_sp:z.string().optional().describe("M\u00e3 s\u1ea3n ph\u1ea9m. L\u01afU \u00dd: G\u1ecdi lookupMasterDataTool tr\u01b0\u1edbc n\u1ebfu ch\u1ec9 c\u00f3 t\u00ean."),ma_bp:z.string().optional().describe("M\u00e3 b\u1ed9 ph\u1eadn s\u1ea3n xu\u1ea5t."),ma_yt:z.string().optional().describe("M\u00e3 y\u1ebfu t\u1ed1 chi ph\u00ed."),chi_hien_tong_cong:z.boolean().optional().describe('Truy\u1ec1n true n\u1ebfu C\u1ea6N S\u1ed0 T\u1ed4NG (VD: "T\u1ed5ng gi\u00e1 th\u00e0nh s\u1ea3n ph\u1ea9m A?"). Truy\u1ec1n false xem chi ti\u1ebft.')}),
18
+ execute:async({nam:$matchQuery_nam$$,thang:$thang$$,ma_sp:$ma_sp$$,ma_bp:$ma_bp$$,ma_yt:$ma_yt$$,chi_hien_tong_cong:$chi_hien_tong_cong$$})=>{try{const $Model$$=global.getModel("gt_ctgt");$matchQuery_nam$$={id_app:$id_app$$,nam:$matchQuery_nam$$,thang:$thang$$,status:!0};$ma_sp$$&&($matchQuery_nam$$.ma_sp=Array.isArray($ma_sp$$)?{$in:$ma_sp$$}:$ma_sp$$);$ma_bp$$&&($matchQuery_nam$$.ma_bp=$ma_bp$$);$ma_yt$$&&($matchQuery_nam$$.ma_yt=$ma_yt$$);if($chi_hien_tong_cong$$){const $results$$=await $Model$$.aggregate([{$match:$matchQuery_nam$$},
19
+ {$match:{yt_trung_gian:{$ne:!0}}},{$group:{_id:"$ma_sp",tong_dd_dk:{$sum:{$cond:[{$eq:["$cong_tru","1"]},"$dd_dk",{$multiply:["$dd_dk",-1]}]}},tong_ps_tk:{$sum:{$cond:[{$eq:["$cong_tru","1"]},"$ps_tk",{$multiply:["$ps_tk",-1]}]}},tong_dd_ck:{$sum:{$cond:[{$eq:["$cong_tru","1"]},"$dd_ck",{$multiply:["$dd_ck",-1]}]}},tong_gia_thanh:{$sum:{$cond:[{$eq:["$cong_tru","1"]},"$t_gt",{$multiply:["$t_gt",-1]}]}},sl_nk_tk:{$max:"$sl_nk_tk"},sl_sx_tk:{$max:"$sl_sx_tk"}}},{$project:{_id:0,ma_sp:"$_id",tong_dd_dk:1,
20
+ tong_ps_tk:1,tong_dd_ck:1,tong_gia_thanh:1,sl_nk_tk:1,sl_sx_tk:1,gia_thanh_don_vi:{$cond:[{$gt:["$sl_nk_tk",0]},{$divide:["$tong_gia_thanh","$sl_nk_tk"]},0]}}}]);return{status:"success",data:$results$$.length?$results$$:[],message:$results$$.length?void 0:"Kh\u00f4ng c\u00f3 d\u1eef li\u1ec7u."}}return{status:"success",data:await $Model$$.find($matchQuery_nam$$).select("ma_sp ma_yt ma_bp ma_nvl sl_dd_dk sl_sx_tk sl_nk_tk sl_dd_ck dd_dk ps_tk dd_ck t_gt gt yt_trung_gian cong_tru").lean()}}catch($error$$){return{status:"error",
21
+ message:$error$$.message||String($error$$)}}}}),getPurchaseAnalyticsTool:tool({description:"C\u00f4ng c\u1ee5 ph\u00e2n t\u00edch d\u1eef li\u1ec7u \u0110\u1ea7u v\u00e0o / T\u1ed3n kho. Xem gi\u00e1 nh\u1eadp mua, xu h\u01b0\u1edbng, t\u1ed3n kho hi\u1ec7n t\u1ea1i, tu\u1ed5i h\u00e0ng t\u1ed3n.",inputSchema:z.object({analysis_type:z.enum(["stock_status","latest_import","price_trend","top_suppliers","cost_summary"]).describe("Lo\u1ea1i ph\u00e2n t\u00edch."),ma_vt:z.string().optional().describe("M\u00e3 v\u1eadt t\u01b0. B\u1eaft bu\u1ed9c v\u1edbi stock_status, latest_import, price_trend."),
22
+ ma_kho:z.string().optional().describe("M\u00e3 kho."),tu_ngay:z.string().optional().describe("Ng\u00e0y b\u1eaft \u0111\u1ea7u (YYYY-MM-DD)."),den_ngay:z.string().optional().describe("Ng\u00e0y k\u1ebft th\u00fac (YYYY-MM-DD)."),limit:z.number().optional().describe("S\u1ed1 l\u01b0\u1ee3ng k\u1ebft qu\u1ea3. M\u1eb7c \u0111\u1ecbnh 5.")}),execute:async({analysis_type:$analysis_type_ton$$,ma_vt:$days_in_stock_ma_vt$$,ma_kho:$du_ma_kho$$,tu_ngay:$queryLimit_tu_ngay$$,den_ngay:$den_ngay$$,limit:$limit$$})=>
23
+ {try{var $Sokho_last_import_date$$=global.getModel("sokho");const $matchQuery$$={id_app:$id_app$$,nxt:1};$days_in_stock_ma_vt$$&&($matchQuery$$.ma_vt=$days_in_stock_ma_vt$$);if($queryLimit_tu_ngay$$||$den_ngay$$)$matchQuery$$.ngay_ct={},$queryLimit_tu_ngay$$&&($matchQuery$$.ngay_ct.$gte=moment($queryLimit_tu_ngay$$).startOf("date").toDate()),$den_ngay$$&&($matchQuery$$.ngay_ct.$lte=moment($den_ngay$$).endOf("date").toDate());$queryLimit_tu_ngay$$=$limit$$||5;switch($analysis_type_ton$$){case "stock_status":if(!$days_in_stock_ma_vt$$)return{status:"error",
24
+ message:"C\u1ea7n m\u00e3 v\u1eadt t\u01b0 (ma_vt)."};const $ckvtCond$$={id_app:$id_app$$,ngay:new Date,ma_vt:$days_in_stock_ma_vt$$};$du_ma_kho$$&&($ckvtCond$$.ma_kho=$du_ma_kho$$);const $stockData$$=await ckvt($ckvtCond$$);$du_ma_kho$$=$analysis_type_ton$$=0;Array.isArray($stockData$$)?($analysis_type_ton$$=$stockData$$[0]||0,$du_ma_kho$$=$stockData$$[1]||0):$stockData$$&&($analysis_type_ton$$=$stockData$$.ton00||$stockData$$.ton||0,$du_ma_kho$$=$stockData$$.du00||$stockData$$.du||0);const $lastImportForAge$$=
25
+ await $Sokho_last_import_date$$.findOne({id_app:$id_app$$,ma_vt:$days_in_stock_ma_vt$$,nxt:1}).sort({ngay_ct:-1}).select("ngay_ct sl_nhap gia_von tien_nhap").lean();$Sokho_last_import_date$$=$days_in_stock_ma_vt$$=null;$lastImportForAge$$&&$analysis_type_ton$$>0&&($Sokho_last_import_date$$=$lastImportForAge$$.ngay_ct,$days_in_stock_ma_vt$$=Math.floor(((new Date).getTime()-(new Date($Sokho_last_import_date$$)).getTime())/864E5));return{status:"success",data:{ton_kho_hien_tai:$analysis_type_ton$$,gia_tri_ton_kho:$du_ma_kho$$,
26
+ ngay_nhap_gan_nhat:$Sokho_last_import_date$$,so_ngay_tu_lan_nhap_cuoi:$days_in_stock_ma_vt$$,chi_tiet_lan_nhap_cuoi:$lastImportForAge$$},hint:"N\u1ebfu ton_kho = 0 l\u00e0 H\u1ebeT H\u00c0NG. N\u1ebfu so_ngay l\u1edbn, c\u1ea3nh b\u00e1o ch\u00f4n v\u1ed1n."};case "latest_import":return{status:"success",data:(await $Sokho_last_import_date$$.find($matchQuery$$).sort({ngay_ct:-1}).limit(1).select("ngay_ct so_ct ma_kh sl_nhap gia_von tien_nhap tien_cp tien_phi").lean())[0]||null};case "price_trend":return{status:"success",
27
+ data:await $Sokho_last_import_date$$.find($matchQuery$$).sort({ngay_ct:-1}).limit($queryLimit_tu_ngay$$).select("ngay_ct ma_kh sl_nhap gia_von").lean()};case "top_suppliers":return{status:"success",data:await $Sokho_last_import_date$$.aggregate([{$match:$matchQuery$$},{$match:{$or:[{ma_kh:{$ne:""}},{ma_kh:{$ne:null}}]}},{$group:{_id:"$ma_kh",tong_so_luong:{$sum:"$sl_nhap"},tong_tien_nhap:{$sum:"$tien_nhap"},so_lan_nhap:{$sum:1}}},{$sort:{tong_tien_nhap:-1}},{$limit:$queryLimit_tu_ngay$$},{$project:{_id:0,
28
+ ma_kh:"$_id",tong_so_luong:1,tong_tien_nhap:1,so_lan_nhap:1}}])};case "cost_summary":return{status:"success",data:(await $Sokho_last_import_date$$.aggregate([{$match:$matchQuery$$},{$group:{_id:null,tong_tien_hang:{$sum:"$tien_hang"},tong_tien_chi_phi:{$sum:"$tien_cp"},tong_tien_phi:{$sum:"$tien_phi"},tong_thue_nhap_khau:{$sum:"$tien_thue_nk"},tong_tri_gia_nhap:{$sum:"$tien_nhap"}}},{$project:{_id:0}}]))[0]||null}}}catch($error$$){return{status:"error",message:$error$$.message||String($error$$)}}}}),
29
+ analyzeInventoryLedgerTool:tool({description:"C\u00f4ng c\u1ee5 ph\u00e2n t\u00edch d\u1eef li\u1ec7u th\u1ef1c t\u1ebf t\u1eeb S\u1ed5 Kho (sokho).\n S\u1eec D\u1ee4NG KHI: C\u00e1c c\u00f4ng c\u1ee5 b\u00e1o c\u00e1o kho ho\u1eb7c b\u00e1n h\u00e0ng ti\u00eau chu\u1ea9n kh\u00e1c KH\u00d4NG \u0110\u00c1P \u1ee8NG \u0110\u01af\u1ee2C y\u00eau c\u1ea7u c\u1ee7a s\u1ebfp v\u00ec c\u1ea7n b\u1ed9 l\u1ecdc qu\u00e1 chi ti\u1ebft.\n V\u00ed d\u1ee5: T\u00ecm ki\u1ebfm theo S\u1ed1 ch\u1ee9ng t\u1eeb c\u1ee5 th\u1ec3, l\u1ecdc theo S\u1ed1 l\u00f4/H\u1ea1n s\u1eed d\u1ee5ng, theo Thu\u1ed9c t\u00ednh s\u1ea3n ph\u1ea9m (m\u00e0u s\u1eafc, size - ma_tt1, ma_tt2), ki\u1ec3m tra c\u00e1c phi\u1ebfu \u0111i\u1ec1u chuy\u1ec3n kho n\u1ed9i b\u1ed9, ho\u1eb7c t\u00ednh to\u00e1n chi ti\u1ebft ti\u1ec1n h\u00e0ng/ti\u1ec1n thu\u1ebf/ti\u1ec1n chi\u1ebft kh\u1ea5u ph\u00e1t sinh t\u1ea1i kho theo Nh\u00e2n vi\u00ean giao h\u00e0ng, Ph\u1ee5 xe, hay Lo\u1ea1i ph\u01b0\u01a1ng ti\u1ec7n.",
30
+ inputSchema:z.object({tu_ngay:z.string().optional().describe("T\u1eeb ng\u00e0y (YYYY-MM-DD)"),den_ngay:z.string().optional().describe("\u0110\u1ebfn ng\u00e0y (YYYY-MM-DD)"),ma_ct:z.string().optional().describe('M\u00e3 lo\u1ea1i ch\u1ee9ng t\u1eeb (V\u00ed d\u1ee5: "pn1" - phi\u1ebfu nh\u1eadp mua, "hd2" - h\u00f3a \u0111\u01a1n b\u00e1n s\u1ec9, "pbl" - phi\u1ebfu b\u00e1n l\u1ebb).'),so_ct:z.string().optional().describe("S\u1ed1 ch\u1ee9ng t\u1eeb c\u1ee5 th\u1ec3 c\u1ea7n tra c\u1ee9u."),nxt:z.number().int().min(1).max(2).optional().describe("H\u01b0\u1edbng h\u00e0ng h\u00f3a: 1 = Nh\u1eadp kho, 2 = Xu\u1ea5t kho."),
31
+ ma_vt:z.string().optional().describe("M\u00e3 v\u1eadt t\u01b0/s\u1ea3n ph\u1ea9m (B\u1eaeT BU\u1ed8C d\u00f9ng lookupMasterDataTool \u0111\u1ec3 l\u1ea5y m\u00e3 tr\u01b0\u1edbc n\u1ebfu ch\u1ec9 bi\u1ebft t\u00ean)."),ma_kho:z.string().optional().describe("M\u00e3 kho ho\u1eb7c c\u1eeda h\u00e0ng ph\u00e1t sinh giao d\u1ecbch."),ma_kh:z.string().optional().describe("M\u00e3 kh\u00e1ch h\u00e0ng ho\u1eb7c nh\u00e0 cung c\u1ea5p li\u00ean quan."),ma_bp:z.string().optional().describe("M\u00e3 b\u1ed9 ph\u1eadn ph\u00e1t sinh."),
32
+ ma_nv:z.string().optional().describe("M\u00e3 nh\u00e2n vi\u00ean b\u00e1n h\u00e0ng."),ma_dt:z.string().optional().describe("M\u00e3 v\u1ee5 vi\u1ec7c, d\u1ef1 \u00e1n, \u0111\u1ed1i t\u01b0\u1ee3ng."),ma_hd:z.string().optional().describe("M\u00e3 h\u1ee3p \u0111\u1ed3ng."),ma_lo:z.string().optional().describe("L\u1ecdc theo m\u00e3 s\u1ed1 l\u00f4 s\u1ea3n xu\u1ea5t."),ma_tt1:z.string().optional().describe("L\u1ecdc theo m\u00e3 thu\u1ed9c t\u00ednh 1 (V\u00ed d\u1ee5: M\u00e0u s\u1eafc, Size...)."),
33
+ ma_tt2:z.string().optional().describe("L\u1ecdc theo m\u00e3 thu\u1ed9c t\u00ednh 2."),ma_nv_giao_hang:z.string().optional().describe("M\u00e3 nh\u00e2n vi\u00ean giao h\u00e0ng."),phu_xe:z.string().optional().describe("T\u00ean ho\u1eb7c m\u00e3 ph\u1ee5 xe."),loai_phuong_tien:z.string().optional().describe("Lo\u1ea1i ph\u01b0\u01a1ng ti\u1ec7n v\u1eadn chuy\u1ec3n (Xe t\u1ea3i, xe m\u00e1y...)."),group_by:z.enum("none thang so_ct ma_vt ma_kho ma_lo ma_kh ma_nv ma_nv_giao_hang loai_phuong_tien".split(" ")).default("none").describe('Ti\u00eau ch\u00ed gom nh\u00f3m. Ch\u1ecdn "none" n\u1ebfu ch\u1ec9 mu\u1ed1n t\u00ednh 1 s\u1ed1 t\u1ed5ng duy nh\u1ea5t. Ch\u1ecdn c\u00e1c m\u1ee5c kh\u00e1c n\u1ebfu mu\u1ed1n l\u00e0m b\u1ea3ng k\u00ea chi ti\u1ebft.')}),
34
+ execute:async $mapping_query$$=>{Logger.info("[AI Agent][analyzeInventoryLedgerTool]",JSON.stringify($mapping_query$$));try{const {tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$,ma_ct:$ma_ct$$,so_ct:$so_ct$$,nxt:$nxt$$,ma_vt:$ma_vt$$,ma_kho:$ma_kho$$,ma_kh:$ma_kh$$,ma_bp:$ma_bp$$,ma_nv:$ma_nv$$,ma_dt:$ma_dt$$,ma_hd:$ma_hd$$,ma_lo:$ma_lo$$,ma_tt1:$ma_tt1$$,ma_tt2:$ma_tt2$$,ma_nv_giao_hang:$ma_nv_giao_hang$$,phu_xe:$phu_xe$$,loai_phuong_tien:$loai_phuong_tien$$,group_by:$group_by$$}=$mapping_query$$;$mapping_query$$=
35
+ {ma_vt:{model:"dmvt",title_field:"ten_vt"},ma_kho:{model:"dmkho",title_field:"ten_kho"},ma_kh:{model:"customer",value_field:"ma_kh",title_field:"ten_kh"},ma_bp:{model:"dmbp",title_field:"ten_bp"},ma_nv:{model:"dmnv",title_field:"ten_nv"},ma_dt:{model:"dmdt",title_field:"ten_dt"}};const $Sokho$$=global.getModel("sokho");if(!$Sokho$$)return{status:"error",message:"Model 'sokho' kh\u00f4ng t\u1ed3n t\u1ea1i tr\u00ean h\u1ec7 th\u1ed1ng."};const $matchQuery$$={id_app:$id_app$$};if($tu_ngay$$||$den_ngay$$)$matchQuery$$.ngay_ct=
36
+ {},$tu_ngay$$&&($matchQuery$$.ngay_ct.$gte=moment($tu_ngay$$).startOf("date").toDate()),$den_ngay$$&&($matchQuery$$.ngay_ct.$lte=moment($den_ngay$$).endOf("date").toDate());$ma_ct$$&&($matchQuery$$.ma_ct=$ma_ct$$.toUpperCase().trim());$so_ct$$&&($matchQuery$$.so_ct={$regex:$so_ct$$.trim(),$options:"i"});$nxt$$&&($matchQuery$$.nxt=$nxt$$);$ma_vt$$&&($matchQuery$$.ma_vt=$ma_vt$$.toUpperCase().trim());$ma_kho$$&&($matchQuery$$.ma_kho=$ma_kho$$.toUpperCase().trim());$ma_kh$$&&($matchQuery$$.ma_kh=$ma_kh$$.toUpperCase().trim());
37
+ $ma_bp$$&&($matchQuery$$.ma_bp=$ma_bp$$.toUpperCase().trim());$ma_nv$$&&($matchQuery$$.ma_nv=$ma_nv$$.toUpperCase().trim());$ma_dt$$&&($matchQuery$$.ma_dt=$ma_dt$$.toUpperCase().trim());$ma_hd$$&&($matchQuery$$.ma_hd=$ma_hd$$.toUpperCase().trim());$ma_lo$$&&($matchQuery$$.ma_lo={$regex:$ma_lo$$.trim(),$options:"i"});$ma_tt1$$&&($matchQuery$$.ma_tt1=$ma_tt1$$.toUpperCase().trim());$ma_tt2$$&&($matchQuery$$.ma_tt2=$ma_tt2$$.toUpperCase().trim());$ma_nv_giao_hang$$&&($matchQuery$$.ma_nv_giao_hang=$ma_nv_giao_hang$$.toUpperCase().trim());
38
+ $phu_xe$$&&($matchQuery$$.phu_xe={$regex:$phu_xe$$.trim(),$options:"i"});$loai_phuong_tien$$&&($matchQuery$$.loai_phuong_tien={$regex:$loai_phuong_tien$$.trim(),$options:"i"});let $groupId$$=null;$group_by$$==="thang"?$groupId$$={thang:{$month:"$ngay_ct"},nam:{$year:"$ngay_ct"}}:$group_by$$!=="none"&&($groupId$$=`$${$group_by$$}`);const $results$$=await $Sokho$$.aggregate([{$match:$matchQuery$$},{$group:{_id:$groupId$$,tong_sl_nhap:{$sum:"$sl_nhap_qd"},tong_sl_xuat:{$sum:"$sl_xuat_qd"},tong_tien_hang:{$sum:"$tien_hang"},
39
+ tong_tien_ck:{$sum:"$tien_ck"},tong_tien_thue:{$sum:"$tien_thue"},tong_tien_xuat_kho:{$sum:"$tien_xuat"},tong_doanh_thu_kho:{$sum:"$tien"},so_luong_dong_phat_sinh:{$sum:1}}},{$sort:{tong_sl_xuat:-1,tong_sl_nhap:-1}},{$limit:30}]);if($results$$.length===0)return{status:"success",message:"Kh\u00f4ng t\u00ecm th\u1ea5y d\u1eef li\u1ec7u ph\u00e1t sinh n\u00e0o trong s\u1ed5 kho th\u1ecfa m\u00e3n b\u1ed9 l\u1ecdc."};$mapping_query$$[$group_by$$]&&await $results$$.asyncJoinModel2($id_app$$,$mapping_query$$[$group_by$$].model,
40
+ {where:{_id:$mapping_query$$[$group_by$$].value_field||$group_by$$},field:[$mapping_query$$[$group_by$$].title_field]});return{status:"success",data:$results$$,hint:"AI l\u01b0u \u00fd: '_id' \u0111\u1ea1i di\u1ec7n cho ti\u00eau ch\u00ed b\u1ea1n v\u1eeba ch\u1ecdn \u0111\u1ec3 group_by. H\u00e3y tr\u00ecnh b\u00e0y to\u00e0n b\u1ed9 c\u00e1c c\u1ed9t s\u1ed1 l\u01b0\u1ee3ng nh\u1eadp/xu\u1ea5t v\u00e0 doanh thu/ti\u1ec1n h\u00e0ng d\u01b0\u1edbi d\u1ea1ng m\u1ed9t b\u1ea3ng bi\u1ec3u Markdown th\u1eadt tinh g\u1ecdn, chuy\u00ean nghi\u1ec7p \u0111\u1ec3 S\u1ebfp d\u1ec5 \u0111\u1ed1i chi\u1ebfu."}}catch($error$$){return console.error("[L\u1ed7i t\u1eeb analyzeInventoryLedgerTool]:",
41
+ $error$$),{status:"error",message:$error$$.message||String($error$$)}}}})}}module.exports={createStockTools};
@@ -0,0 +1,52 @@
1
+ const {tool}=require("ai"),{z}=require("zod"),{buildJsonSchema,getAgentReportDefinition}=require("../../libs/docs"),{searchActiveListInfo,extractFeatureKeywords,escapeRegex,bangTuDienDanhMuc}=require("./utils");function createSystemTools($id_app$$,$user_id$$,$session_id$$){return{exploreSystemSchemaTool:tool({description:`C\u00f4ng c\u1ee5 TH\u0102M D\u00d2 C\u1ea4U TR\u00daC D\u1eee LI\u1ec6U (Schema Explorer).
2
+ S\u1eec D\u1ee4NG KHI: B\u1ea1n c\u1ea7n bi\u1ebft ch\u00ednh x\u00e1c t\u00ean c\u00e1c tr\u01b0\u1eddng (fields), ki\u1ec3u d\u1eef li\u1ec7u (String, Number, Date...) v\u00e0 m\u00e3 Controller c\u1ee7a m\u1ed9t ch\u1ee9c n\u0103ng TR\u01af\u1edaC KHI b\u1ea1n s\u1eed d\u1ee5ng c\u00f4ng c\u1ee5 codeInterpreterTool ho\u1eb7c c\u00e1c c\u00f4ng c\u1ee5 c\u1ea7n c\u1ea5u tr\u00fac ch\u00ednh x\u00e1c.
3
+ H\u01af\u1edaNG D\u1eaaN: Truy\u1ec1n v\u00e0o t\u1eeb kh\u00f3a v\u1ec1 ch\u1ee9c n\u0103ng b\u1ea1n mu\u1ed1n t\u00ecm (VD: "h\u00f3a \u0111\u01a1n", "kh\u00e1ch h\u00e0ng", "phi\u1ebfu thu").
4
+
5
+ \ud83d\udd25 B\u1ea2NG T\u1eea \u0110I\u1ec2N M\u00c3 CHU\u1ea8N (CORE DICTIONARY) B\u1eaeT BU\u1ed8C D\u00d9NG:
6
+ N\u1ebfu S\u1ebfp h\u1ecfi v\u1ec1 c\u00e1c \u0111\u1ed1i t\u01b0\u1ee3ng c\u1ed1t l\u00f5i d\u01b0\u1edbi \u0111\u00e2y, B\u1eaeT BU\u1ed8C truy\u1ec1n ch\u00ednh x\u00e1c M\u00c3 CODE v\u00e0o tham s\u1ed1 'exact_code':
7
+ ${bangTuDienDanhMuc("exact_code")}
8
+ (KHI V\u00c0 CH\u1ec8 KHI \u0111\u1ed1i t\u01b0\u1ee3ng S\u1ebfp h\u1ecfi KH\u00d4NG C\u00d3 trong danh s\u00e1ch tr\u00ean, b\u1ea1n m\u1edbi \u0111\u01b0\u1ee3c d\u00f9ng tham s\u1ed1 'keywords' \u0111\u1ec3 t\u00ecm ki\u1ebfm t\u01b0\u01a1ng \u0111\u1ed1i)..
9
+ `,inputSchema:z.object({exact_code:z.string().optional().describe('B\u1eaeT BU\u1ed8C d\u00f9ng n\u1ebfu \u0111\u1ed1i t\u01b0\u1ee3ng n\u1eb1m trong B\u1ea3ng T\u1eeb \u0110i\u1ec3n M\u00e3 Chu\u1ea9n \u1edf tr\u00ean (VD: "customer", "data_socai").'),keywords:z.array(z.string()).optional().describe("Ch\u1ec9 d\u00f9ng \u0111\u1ec3 t\u00ecm ki\u1ebfm m\u1edd n\u1ebfu \u0111\u1ed1i t\u01b0\u1ee3ng kh\u00f4ng c\u00f3 trong danh s\u00e1ch chu\u1ea9n.")}),execute:async({exact_code:$exact_code$$,
10
+ keywords:$keywords$$})=>{Logger.warn("[exploreSystemSchemaTool]",JSON.stringify({keywords:$keywords$$},null,2));try{let $docs$$=[];if($exact_code$$){const $exactDoc$$=await global.getModel("listinfo").findOne({$or:[{code:$exact_code$$},{api_code:$exact_code$$}]}).lean();if($exactDoc$$)$docs$$.push($exactDoc$$);else return{status:"not_found",message:`[C\u1ea2NH B\u00c1O] Kh\u00f4ng t\u00ecm th\u1ea5y ch\u1ee9c n\u0103ng n\u00e0o c\u00f3 m\u00e3 ch\u00ednh x\u00e1c l\u00e0 '${$exact_code$$}'. AI h\u00e3y th\u1eed d\u00f9ng 'keywords' \u0111\u1ec3 t\u00ecm ki\u1ebfm m\u1edd.`}}$docs$$=
11
+ (await searchActiveListInfo({keywords:$keywords$$,include_fields_schema:!0,limit:20}))?.docs||[];return $docs$$===0?{status:"not_found",message:`Kh\u00f4ng t\u00ecm th\u1ea5y ch\u1ee9c n\u0103ng n\u00e0o kh\u1edbp v\u1edbi t\u1eeb kh\u00f3a: [${$keywords$$.join(", ")}]. H\u00e3y th\u1eed t\u1eeb kh\u00f3a kh\u00e1c kh\u00e1i qu\u00e1t h\u01a1n.`}:{status:"success",message:"\u0110\u00e3 t\u00ecm th\u1ea5y c\u1ea5u tr\u00fac d\u1eef li\u1ec7u. AI h\u00e3y \u0111\u1ecdc k\u1ef9 C\u1ea4U TR\u00daC (cau_truc_du_lieu_db) \u0111\u1ec3 l\u1ea5y \u0111\u00fang t\u00ean tr\u01b0\u1eddng v\u00e0 ki\u1ec3u d\u1eef li\u1ec7u (Number, Date, String) tr\u01b0\u1edbc khi vi\u1ebft Aggregation Pipeline.",
12
+ results:await Promise.all($docs$$.map($doc$$=>(async()=>{let $cau_truc_du_lieu_db$$=await buildJsonSchema($doc$$.fields,void 0,$id_app$$);$cau_truc_du_lieu_db$$=JSON.parse(JSON.stringify($cau_truc_du_lieu_db$$));return{chuc_nang:$doc$$.title,controller_code:$doc$$.finalCode,cau_truc_du_lieu_db:$cau_truc_du_lieu_db$$}})()))}}catch($error$$){return console.error("[L\u1ed7i exploreSystemSchemaTool]:",$error$$),{status:"error",message:`L\u1ed7i khi th\u0103m d\u00f2 h\u1ec7 th\u1ed1ng: ${$error$$.message}`}}}}),
13
+ exploreReportSchemaTool:tool({description:'C\u00f4ng c\u1ee5 TH\u0102M D\u00d2 C\u1ea4U TR\u00daC B\u00c1O C\u00c1O (Report Schema Explorer).\n S\u1eec D\u1ee4NG KHI: B\u1ea1n c\u1ea7n bi\u1ebft ch\u00ednh x\u00e1c c\u00e1ch g\u1ecdi m\u1ed9t b\u00e1o c\u00e1o t\u1eeb h\u1ec7 th\u1ed1ng, bao g\u1ed3m API Endpoint, c\u00e1c tham s\u1ed1 \u0111i\u1ec1u ki\u1ec7n l\u1ecdc c\u1ea7n thi\u1ebft (Input) v\u00e0 danh s\u00e1ch c\u00e1c c\u1ed9t d\u1eef li\u1ec7u tr\u1ea3 v\u1ec1 (Output) TR\u01af\u1edaC KHI b\u1ea1n g\u1ecdi API xu\u1ea5t b\u00e1o c\u00e1o.\n H\u01af\u1edaNG D\u1eaaN: Truy\u1ec1n v\u00e0o t\u1eeb kh\u00f3a v\u1ec1 b\u00e1o c\u00e1o b\u1ea1n mu\u1ed1n t\u00ecm (VD: "doanh thu", "t\u1ed3n kho", "c\u00f4ng n\u1ee3", "BC_DOANH_THU").',
14
+ inputSchema:z.object({keyword:z.string().describe('T\u1eeb kh\u00f3a t\u00ecm ki\u1ebfm t\u00ean b\u00e1o c\u00e1o ho\u1eb7c m\u00e3 code c\u1ee7a b\u00e1o c\u00e1o (V\u00ed d\u1ee5: "doanh thu", "BC_DOANH_THU").')}),execute:async({keyword:$keyword$$})=>{Logger.warn("[exploreReportSchemaTool]",JSON.stringify({keyword:$keyword$$},null,2));try{const $reportDef$$=await getAgentReportDefinition($keyword$$,$id_app$$);if($reportDef$$.error)return{status:"not_found",message:$reportDef$$.error,query_used:$reportDef$$.query_used};
15
+ if($reportDef$$.status==="multiple_matches")return{status:"multiple_matches",message:$reportDef$$.message,suggestions:$reportDef$$.suggestions};const $cleanReport$$=JSON.parse(JSON.stringify($reportDef$$));return{status:"success",message:`\u0110\u00e3 t\u00ecm th\u1ea5y c\u1ea5u tr\u00fac b\u00e1o c\u00e1o [${$reportDef$$.report_info.title}]. AI h\u00e3y \u0111\u1ecdc 'input_conditions_schema' \u0111\u1ec3 bi\u1ebft c\u00e1ch truy\u1ec1n Body JSON \u0111i\u1ec1u ki\u1ec7n l\u1ecdc, v\u00e0 xem 'output_columns_schema' \u0111\u1ec3 hi\u1ec3u d\u1eef li\u1ec7u s\u1ebd nh\u1eadn \u0111\u01b0\u1ee3c.`,
16
+ report_info:$cleanReport$$.report_info,input_conditions_schema:$cleanReport$$.input_conditions_schema,output_columns_schema:$cleanReport$$.output_columns_schema}}catch($error$$){return console.error("[L\u1ed7i exploreReportSchemaTool]:",$error$$),{status:"error",message:`L\u1ed7i khi th\u0103m d\u00f2 c\u1ea5u tr\u00fac b\u00e1o c\u00e1o: ${$error$$.message}`}}}}),navigateToFeatureTool:tool({description:`C\u00f4ng c\u1ee5 T\u00ccM \u0110\u01af\u1edcNG D\u1eaaN \u0110I\u1ec0U H\u01af\u1edaNG (Navigation Guide).
17
+ S\u1eec D\u1ee4NG KHI: User h\u1ecfi "T\u00f4i mu\u1ed1n l\u00e0m vi\u1ec7c X th\u00ec v\u00e0o link n\u00e0o?", "M\u00e0n h\u00ecnh qu\u1ea3n l\u00fd Y \u1edf \u0111\u00e2u?",
18
+ ho\u1eb7c b\u1ea5t k\u1ef3 c\u00e2u h\u1ecfi n\u00e0o li\u00ean quan \u0111\u1ebfn vi\u1ec7c T\u00ccM \u0110\u01af\u1edcNG LINK \u0111\u1ec3 truy c\u1eadp m\u1ed9t ch\u1ee9c n\u0103ng trong h\u1ec7 th\u1ed1ng.
19
+
20
+ V\u00ed d\u1ee5 c\u00e2u h\u1ecfi k\u00edch ho\u1ea1t tool n\u00e0y:
21
+ - "T\u00f4i mu\u1ed1n xem danh s\u00e1ch kh\u00e1ch h\u00e0ng th\u00ec v\u00e0o \u0111\u00e2u?"
22
+ - "Link t\u1ea1o h\u00f3a \u0111\u01a1n b\u00e1n h\u00e0ng l\u00e0 g\u00ec?"
23
+ - "B\u00e1o c\u00e1o doanh thu theo th\u00e1ng \u1edf \u0111\u00e2u?"
24
+ - "T\u00f4i c\u1ea7n qu\u1ea3n l\u00fd nh\u00e2n vi\u00ean th\u00ec truy c\u1eadp \u0111\u01b0\u1eddng n\u00e0o?"
25
+
26
+ N\u1ebfu S\u1ebfp h\u1ecfi v\u1ec1 c\u00e1c \u0111\u1ed1i t\u01b0\u1ee3ng c\u1ed1t l\u00f5i d\u01b0\u1edbi \u0111\u00e2y, B\u1eaeT BU\u1ed8C truy\u1ec1n ch\u00ednh x\u00e1c M\u00c3 CODE v\u00e0o tham s\u1ed1 'ma_code':
27
+ ${bangTuDienDanhMuc("ma_code")}
28
+ (KHI V\u00c0 CH\u1ec8 KHI \u0111\u1ed1i t\u01b0\u1ee3ng S\u1ebfp h\u1ecfi KH\u00d4NG C\u00d3 trong danh s\u00e1ch tr\u00ean, b\u1ea1n m\u1edbi \u0111\u01b0\u1ee3c d\u00f9ng tham s\u1ed1 'query' \u0111\u1ec3 t\u00ecm ki\u1ebfm t\u01b0\u01a1ng \u0111\u1ed1i).
29
+
30
+ \u26a1 Khi 'ma_code' \u0111\u01b0\u1ee3c truy\u1ec1n v\u00e0 kh\u1edbp \u0111\u00fang m\u1ed9t m\u00e0n h\u00ecnh \u0111i\u1ec1u h\u01b0\u1edbng, h\u1ec7 th\u1ed1ng d\u00f9ng TR\u1ef0C TI\u1ebeP \u0111\u1ec3 d\u1ef1ng \u0111\u01b0\u1eddng d\u1eabn \u2014 KH\u00d4NG d\u00f2 t\u00ecm, nhanh v\u00e0 ch\u00ednh x\u00e1c h\u01a1n truy\u1ec1n qua 'query'. M\u1ed9t v\u00e0i m\u00e3 trong danh s\u00e1ch (data_socai, data_sokho) l\u00e0 d\u1eef li\u1ec7u n\u1ec1n cho nhi\u1ec1u b\u00e1o c\u00e1o, kh\u00f4ng ph\u1ea3i 1 m\u00e0n h\u00ecnh c\u1ed1 \u0111\u1ecbnh \u2014 n\u1ebfu S\u1ebfp h\u1ecfi v\u1ec1 ch\u00fang, h\u1ec7 th\u1ed1ng s\u1ebd t\u1ef1 chuy\u1ec3n sang t\u00ecm b\u00e1o c\u00e1o ph\u00f9 h\u1ee3p theo 'query'.
31
+
32
+ KH\u00d4NG S\u1eec D\u1ee4NG khi: User h\u1ecfi v\u1ec1 c\u1ea5u tr\u00fac d\u1eef li\u1ec7u, mu\u1ed1n truy v\u1ea5n / t\u1ed5ng h\u1ee3p d\u1eef li\u1ec7u,
33
+ ho\u1eb7c mu\u1ed1n ch\u1ea1y b\u00e1o c\u00e1o (d\u00f9ng exploreSystemSchemaTool / exploreReportSchemaTool / dynamicAggregationTool).`,inputSchema:z.object({ma_code:z.string().optional().describe("Lo\u1ea1i danh m\u1ee5c chu\u1ea9n (customer, account...)."),query:z.string().describe('M\u00f4 t\u1ea3 t\u00e1c v\u1ee5 ho\u1eb7c t\u00ean ch\u1ee9c n\u0103ng user mu\u1ed1n t\u00ecm \u0111\u01b0\u1eddng link. Truy\u1ec1n v\u00e0o nguy\u00ean v\u0103n c\u00e2u h\u1ecfi c\u1ee7a user \u2014 tool s\u1ebd t\u1ef1 tr\u00edch xu\u1ea5t t\u00ean ch\u1ee9c n\u0103ng c\u1ed1t l\u00f5i. V\u00ed d\u1ee5: "t\u00f4i mu\u1ed1n t\u1ea1o phi\u1ebfu chi cho kh\u00e1ch h\u00e0ng th\u00ec v\u00e0o \u0111\u00e2u"')}),
34
+ execute:async({query:$query$$,ma_code:$keywords$$})=>{Logger.warn("[navigateToFeatureTool]",JSON.stringify({query:$query$$,ma_code:$keywords$$},null,2));if($keywords$$)try{var $ListInfoModel_duong_dan$$=global.getModel("listinfo");if(!$ListInfoModel_duong_dan$$)throw Error("Model 'listinfo' kh\u00f4ng t\u1ed3n t\u1ea1i.");const $safeCode$$=escapeRegex($keywords$$);var $allResults_exactDoc$$=await $ListInfoModel_duong_dan$$.findOne({$or:[{code:{$regex:`^${$safeCode$$}$`,$options:"i"}},{api_code:{$regex:`^${$safeCode$$}$`,
35
+ $options:"i"}}]}).lean();if($allResults_exactDoc$$){const $finalCode$$=$allResults_exactDoc$$.api_code||$allResults_exactDoc$$.code,$isVoucher$$=global.controllers[$finalCode$$]?.isVoucher===!0;$ListInfoModel_duong_dan$$=$isVoucher$$?`/#/voucher/${$finalCode$$}`:`/#/list/${$finalCode$$}`;return{status:"success",extracted_keywords:[$keywords$$],tong_so_ket_qua:1,message:`\u0110\u00e3 x\u00e1c \u0111\u1ecbnh tr\u1ef1c ti\u1ebfp \u0111\u01b0\u1eddng d\u1eabn cho m\u00e3 '${$keywords$$}', kh\u00f4ng c\u1ea7n t\u00ecm ki\u1ebfm.`,
36
+ ket_qua:[{ten_chuc_nang:$allResults_exactDoc$$.title,loai:$isVoucher$$?"Ch\u1ee9ng t\u1eeb":"Danh m\u1ee5c",ma_code:$finalCode$$,duong_dan:$ListInfoModel_duong_dan$$,huong_dan:$isVoucher$$?`Truy c\u1eadp **${$ListInfoModel_duong_dan$$}** \u0111\u1ec3 nh\u1eadp li\u1ec7u v\u00e0 qu\u1ea3n l\u00fd ch\u1ee9ng t\u1eeb **${$allResults_exactDoc$$.title}**.`:`Truy c\u1eadp **${$ListInfoModel_duong_dan$$}** \u0111\u1ec3 xem v\u00e0 qu\u1ea3n l\u00fd danh m\u1ee5c **${$allResults_exactDoc$$.title}**.`}]}}Logger.warn(`[navigateToFeatureTool] ma_code '${$keywords$$}' kh\u00f4ng kh\u1edbp danh m\u1ee5c/ch\u1ee9ng t\u1eeb \u0111i\u1ec1u h\u01b0\u1edbng tr\u1ef1c ti\u1ebfp n\u00e0o \u2014 chuy\u1ec3n sang t\u00ecm theo query.`)}catch($e$$){Logger.warn(`[navigateToFeatureTool] L\u1ed7i khi tra c\u1ee9u tr\u1ef1c ti\u1ebfp ma_code '${$keywords$$}', chuy\u1ec3n sang t\u00ecm theo query:`,
37
+ $e$$.message)}$keywords$$=extractFeatureKeywords($query$$);Logger.warn("[navigateToFeatureTool] extracted keywords:",$keywords$$);try{const [$listSearchResult$$,$reportDefResult$$]=await Promise.allSettled([searchActiveListInfo({keywords:$keywords$$,include_fields_schema:!1,limit:20}),getAgentReportDefinition($query$$,$id_app$$)]);$allResults_exactDoc$$=[];if($listSearchResult$$.status==="fulfilled"){const $listDocs$$=$listSearchResult$$.value?.docs||[];for(const $doc$$ of $listDocs$$){const $finalCode$$=
38
+ $doc$$.finalCode||$doc$$.api_code||$doc$$.code,$isVoucher$$=global.controllers[$finalCode$$]?.isVoucher===!0;$allResults_exactDoc$$.push({ten_chuc_nang:$doc$$.title,loai:$isVoucher$$?"Ch\u1ee9ng t\u1eeb":"Danh m\u1ee5c",ma_code:$finalCode$$,duong_dan:$isVoucher$$?`/#/voucher/${$finalCode$$}`:`/#/list/${$finalCode$$}`,huong_dan:$isVoucher$$?`Truy c\u1eadp **/#/voucher/${$finalCode$$}** \u0111\u1ec3 nh\u1eadp li\u1ec7u v\u00e0 qu\u1ea3n l\u00fd ch\u1ee9ng t\u1eeb **${$doc$$.title}**.`:`Truy c\u1eadp **/#/list/${$finalCode$$}** \u0111\u1ec3 xem v\u00e0 qu\u1ea3n l\u00fd danh m\u1ee5c **${$doc$$.title}**.`})}}else Logger.warn("[navigateToFeatureTool] listinfo search failed:",
39
+ $listSearchResult$$.reason);if($reportDefResult$$.status==="fulfilled"){const $rd$$=$reportDefResult$$.value;if($rd$$&&!$rd$$.error)if($rd$$.status==="multiple_matches"&&Array.isArray($rd$$.suggestions))for(const $s$$ of $rd$$.suggestions){const $code$$=$s$$.code||$s$$.api_code;$allResults_exactDoc$$.push({ten_chuc_nang:$s$$.title,loai:"B\u00e1o c\u00e1o",ma_code:$code$$,duong_dan:`/#/page/report/${$code$$}`,huong_dan:`Truy c\u1eadp **/#/page/report/${$code$$}** \u0111\u1ec3 xem b\u00e1o c\u00e1o **${$s$$.title}**.`})}else if($rd$$.report_info){const $code$$=
40
+ $rd$$.report_info.code||$rd$$.report_info.api_code;$allResults_exactDoc$$.push({ten_chuc_nang:$rd$$.report_info.title,loai:"B\u00e1o c\u00e1o",ma_code:$code$$,duong_dan:`/#/page/report/${$code$$}`,huong_dan:`Truy c\u1eadp **/#/page/report/${$code$$}** \u0111\u1ec3 xem b\u00e1o c\u00e1o **${$rd$$.report_info.title}**.`})}}else Logger.warn("[navigateToFeatureTool] report search failed:",$reportDefResult$$.reason);return $allResults_exactDoc$$.length===0?{status:"not_found",extracted_keywords:$keywords$$,
41
+ message:`Kh\u00f4ng t\u00ecm th\u1ea5y ch\u1ee9c n\u0103ng n\u00e0o ph\u00f9 h\u1ee3p v\u1edbi y\u00eau c\u1ea7u: "${$query$$}". `+`T\u1eeb kh\u00f3a \u0111\u00e3 th\u1eed theo th\u1ee9 t\u1ef1: [${$keywords$$.join(" \u2192 ")}]. `+"H\u00e3y h\u1ecfi l\u1ea1i user \u0111\u1ec3 l\u00e0m r\u00f5 h\u01a1n, ho\u1eb7c th\u1eed t\u1eeb kh\u00f3a kh\u00e1c."}:{status:"success",extracted_keywords:$keywords$$,tong_so_ket_qua:$allResults_exactDoc$$.length,message:`\u0110\u00e3 t\u00ecm th\u1ea5y ${$allResults_exactDoc$$.length} ch\u1ee9c n\u0103ng li\u00ean quan \u0111\u1ebfn "${$query$$}". `+
42
+ "Tr\u00ecnh b\u00e0y link cho user, n\u1ebfu nhi\u1ec1u k\u1ebft qu\u1ea3 h\u00e3y h\u1ecfi user mu\u1ed1n v\u00e0o m\u1ee5c n\u00e0o.",ket_qua:$allResults_exactDoc$$}}catch($error$$){return console.error("[L\u1ed7i navigateToFeatureTool]:",$error$$),{status:"error",message:`L\u1ed7i khi t\u00ecm \u0111\u01b0\u1eddng d\u1eabn: ${$error$$.message}`}}}}),getFeatureStatusListTool:tool({description:'C\u00f4ng c\u1ee5 tra c\u1ee9u danh s\u00e1ch c\u00e1c tr\u1ea1ng th\u00e1i h\u1ee3p l\u1ec7 (t\u1eeb model trangthai) c\u1ee7a m\u1ed9t lo\u1ea1i ch\u1ee9ng t\u1eeb ho\u1eb7c danh m\u1ee5c trong h\u1ec7 th\u1ed1ng.\n S\u1eec D\u1ee4NG KHI: AI c\u1ea7n c\u1ea5u h\u00ecnh tr\u1ea1ng th\u00e1i cho node "switch", "data" ho\u1eb7c "event". Tool n\u00e0y gi\u00fap x\u00e1c \u0111\u1ecbnh ch\u00ednh x\u00e1c "ma_trang_thai" h\u1ec7 th\u1ed1ng quy \u0111\u1ecbnh (V\u00ed d\u1ee5: Bi\u1ebft \u0111\u01b0\u1ee3c \'H\u00f3a \u0111\u01a1n\' c\u00f3 tr\u1ea1ng th\u00e1i \'CHO_DUYET\', \'DA_DUYET\'...).',
43
+ inputSchema:z.object({feature_code:z.string().describe('M\u00e3 code ho\u1eb7c api_code c\u1ee7a ch\u1ee9c n\u0103ng c\u1ea7n tra c\u1ee9u tr\u1ea1ng th\u00e1i (V\u00ed d\u1ee5: "customer", "hd2", "pn1"). H\u1ec7 th\u1ed1ng s\u1ebd t\u1ef1 \u0111\u1ed9ng chuy\u1ec3n th\u00e0nh ch\u1eef hoa \u0111\u1ec3 qu\u00e9t.')}),execute:async({feature_code:$feature_code$$})=>{try{const $TrangThaiModel$$=global.getModel("trangthai");if(!$TrangThaiModel$$)return{status:"error",message:"Model 'trangthai' kh\u00f4ng t\u1ed3n t\u1ea1i tr\u00ean h\u1ec7 th\u1ed1ng."};
44
+ const $formattedMaCt$$=$feature_code$$.toUpperCase().trim(),$statusList$$=await $TrangThaiModel$$.find({ma_ct:$formattedMaCt$$}).select({ma_trang_thai:1,ten_trang_thai:1,ma_ct:1}).sort({ma_trang_thai:1}).lean();return $statusList$$&&$statusList$$.length!==0?{status:"success",ma_ct:$formattedMaCt$$,count:$statusList$$.length,data:$statusList$$,hint:"AI l\u01b0u \u00fd: H\u00e3y s\u1eed d\u1ee5ng tr\u01b0\u1eddng 'ma_trang_thai' (V\u00ed d\u1ee5: 'NEW', 'APPROVED') c\u1ee7a b\u1ea3n ghi ph\u00f9 h\u1ee3p \u0111\u1ec3 l\u00e0m gi\u00e1 tr\u1ecb so s\u00e1nh trong node 'switch' ho\u1eb7c g\u00e1n v\u00e0o tr\u01b0\u1eddng d\u1eef li\u1ec7u c\u1ea7n c\u1eadp nh\u1eadt trong node 'data'."}:
45
+ {status:"success",ma_ct:$formattedMaCt$$,count:0,message:`Ch\u1ee9c n\u0103ng '${$feature_code$$}' (M\u00e3 d\u1eef li\u1ec7u: ${$formattedMaCt$$}) hi\u1ec7n t\u1ea1i kh\u00f4ng thi\u1ebft l\u1eadp danh s\u00e1ch tr\u1ea1ng th\u00e1i ri\u00eang trong model trangthai.`}}catch($error$$){return console.error("[L\u1ed7i t\u1ea1i getFeatureStatusListTool]:",$error$$),{status:"error",message:$error$$.message||String($error$$)}}}}),manageScheduledTasksTool:tool({description:"C\u00f4ng c\u1ee5 QU\u1ea2N L\u00dd L\u1ecaCH TR\u00ccNH AI T\u1ef0 \u0110\u1ed8NG (G\u1ed3m 3 h\u00e0nh \u0111\u1ed9ng: T\u1ea1o m\u1edbi, Xem danh s\u00e1ch, H\u1ee7y/X\u00f3a).\n [QUY T\u1eaeC B\u1eaeT BU\u1ed8C KHI S\u1eec D\u1ee4NG]:\n - N\u1ebfu S\u1ebfp mu\u1ed1n \u0110\u1eb6T L\u1ecaCH (create): B\u1eaft bu\u1ed9c ph\u1ea3i truy\u1ec1n \u0111\u1ee7 'task_name', 'prompt_message', 'cron_expression'.\n - N\u1ebfu S\u1ebfp mu\u1ed1n X\u00d3A L\u1ecaCH (delete): B\u1eaft bu\u1ed9c ph\u1ea3i truy\u1ec1n 'task_id'. N\u1ebeU CH\u01afA BI\u1ebeT ID, B\u1ea0N PH\u1ea2I g\u1ecdi c\u00f4ng c\u1ee5 n\u00e0y v\u1edbi action=\"list\" \u0111\u1ec3 l\u1ea5y danh s\u00e1ch ID tr\u01b0\u1edbc, sau \u0111\u00f3 m\u1edbi g\u1ecdi l\u1ea1i v\u1edbi action=\"delete\".",
46
+ inputSchema:z.object({action:z.enum(["create","list","delete"]).describe('Ch\u1ec9 \u0111\u1ecbnh h\u00e0nh \u0111\u1ed9ng: "create" (T\u1ea1o m\u1edbi), "list" (Xem danh s\u00e1ch), ho\u1eb7c "delete" (H\u1ee7y/X\u00f3a).'),task_name:z.string().optional().describe('D\u00f9ng cho "create": T\u00ean ng\u1eafn g\u1ecdn c\u1ee7a l\u1ecbch tr\u00ecnh (VD: "B\u00e1o c\u00e1o doanh thu h\u00e0ng ng\u00e0y").'),prompt_message:z.string().optional().describe('D\u00f9ng cho "create": C\u00e2u l\u1ec7nh \u0111\u1ec3 AI ch\u1ea1y (VD: "B\u00e1o c\u00e1o s\u1ed1 d\u01b0 ti\u1ec1n m\u1eb7t h\u00f4m nay.").'),
47
+ cron_expression:z.string().optional().describe('D\u00f9ng cho "create": Chu\u1ed7i Cron (VD: "0 8 * * *" cho 8h s\u00e1ng).'),task_id:z.string().optional().describe('D\u00f9ng cho "delete": Chu\u1ed7i _id d\u00e0i c\u1ee7a MongoDB \u0111\u1ec3 x\u00f3a t\u00e1c v\u1ee5.')}),execute:async({action:$action$$,task_name:$task_name$$,prompt_message:$prompt_message$$,cron_expression:$cron_expression$$,task_id:$task_id$$})=>{try{const $ScheduleModel$$=global.getModel("schedule");if($action$$==="list"){const $tasks$$=
48
+ await $ScheduleModel$$.find({action:"runAIAgent","data.user_id":$user_id$$,trang_thai:{$in:["0","5"]}}).select("_id title cron_expression next_run").lean();return $tasks$$&&$tasks$$.length!==0?{status:"success",data:$tasks$$.map($t$$=>({id:$t$$._id.toString(),ten_tac_vu:$t$$.title,lich_chay_cron:$t$$.cron_expression,lan_chay_tiep_theo:$t$$.next_run})),hint:"AI B\u1eaeT BU\u1ed8C L\u00c0M THEO:\n 1. Tr\u00ecnh b\u00e0y danh s\u00e1ch b\u1eb1ng B\u1ea3ng Markdown (ID vi\u1ebft t\u1eaft 5 s\u1ed1 cu\u1ed1i, T\u00ean t\u00e1c v\u1ee5, Th\u1eddi gian ch\u1ea1y, L\u1ea7n ch\u1ea1y t\u1edbi).\n 2. \u0110\u00f3ng l\u1ea1i b\u1eb1ng c\u00e2u h\u1ecfi xem S\u1ebfp c\u00f3 mu\u1ed1n gi\u1eef nguy\u00ean hay x\u00f3a l\u1ecbch n\u00e0o kh\u00f4ng."}:
49
+ {status:"success",message:"Kh\u00f4ng c\u00f3 t\u00e1c v\u1ee5",hint:"B\u00e1o c\u00e1o S\u1ebfp l\u00e0 hi\u1ec7n ch\u01b0a c\u00e0i \u0111\u1eb7t l\u1ecbch t\u1ef1 \u0111\u1ed9ng n\u00e0o."}}if($action$$==="create"){if(!$task_name$$||!$prompt_message$$||!$cron_expression$$)return{status:"error",hint:"L\u1ed7i: B\u1ea1n ph\u1ea3i cung c\u1ea5p \u0111\u1ee7 task_name, prompt_message v\u00e0 cron_expression \u0111\u1ec3 t\u1ea1o l\u1ecbch."};await $ScheduleModel$$.every($cron_expression$$,"runAIAgent",
50
+ {id_app:$id_app$$,user_id:$user_id$$,session_id:$session_id$$,prompt_message:$prompt_message$$},{title:$task_name$$});return{status:"success",hint:`B\u00e1o c\u00e1o S\u1ebfp: "D\u1ea1 S\u1ebfp, em \u0111\u00e3 \u0111\u01b0a t\u00e1c v\u1ee5 **${$task_name$$}** v\u00e0o h\u1ec7 th\u1ed1ng. C\u1ee9 \u0111\u1ebfn gi\u1edd em s\u1ebd ph\u00e2n t\u00edch s\u1ed1 li\u1ec7u v\u00e0 g\u1eedi ngay cho S\u1ebfp \u1ea1!"`}}if($action$$==="delete"){if(!$task_id$$)return{status:"error",hint:'AI B\u1eaeT BU\u1ed8C L\u01afU \u00dd: B\u1ea1n ch\u01b0a truy\u1ec1n task_id. H\u00e3y g\u1ecdi l\u1ea1i c\u00f4ng c\u1ee5 n\u00e0y v\u1edbi action="list" \u0111\u1ec3 l\u1ea5y ID tr\u01b0\u1edbc!'};
51
+ const $task$$=await $ScheduleModel$$.findOne({_id:$task_id$$,action:"runAIAgent","data.user_id":$user_id$$});if(!$task$$)return{status:"error",hint:'B\u00e1o S\u1ebfp: "D\u1ea1 S\u1ebfp, em kh\u00f4ng t\u00ecm th\u1ea5y l\u1ecbch tr\u00ecnh n\u00e0y, c\u00f3 th\u1ec3 n\u00f3 \u0111\u00e3 b\u1ecb x\u00f3a r\u1ed3i \u1ea1."'};await $ScheduleModel$$.deleteOne({_id:$task_id$$});return{status:"success",hint:`B\u00e1o c\u00e1o S\u1ebfp: "D\u1ea1 S\u1ebfp, em \u0111\u00e3 h\u1ee7y th\u00e0nh c\u00f4ng l\u1ecbch t\u1ef1 \u0111\u1ed9ng **${$task$$.title}** r\u1ed3i \u1ea1!"`}}}catch($error$$){return{status:"error",
52
+ message:`L\u1ed7i th\u1ef1c thi l\u1ecbch tr\u00ecnh: ${$error$$.message}`}}}})}}module.exports={createSystemTools};
@@ -0,0 +1,23 @@
1
+ const {z}=require("zod"),{tool}=require("ai"),moment=require("moment");
2
+ function createTaskTools($id_app$$,$user_id$$){return{manageTaskTool:tool({description:"C\u00f4ng c\u1ee5 QU\u1ea2N L\u00dd V\u00c0 GIAO VI\u1ec6C (Task Manager).\n S\u1eec D\u1ee4NG KHI: S\u1ebfp ra l\u1ec7nh t\u1ea1o c\u00f4ng vi\u1ec7c m\u1edbi, nh\u1eafc nh\u1edf, HO\u1eb6C y\u00eau c\u1ea7u c\u1eadp nh\u1eadt/ch\u1ec9nh s\u1eeda m\u1ed9t c\u00f4ng vi\u1ec7c \u0111ang c\u00f3 (VD: \u0110\u1ed5i deadline, \u0111\u1ed5i ng\u01b0\u1eddi ph\u1ee5 tr\u00e1ch, c\u1eadp nh\u1eadt tr\u1ea1ng th\u00e1i).\n \u0110\u1eb6C BI\u1ec6T: D\u00f9ng \u0111\u1ec3 GIAO VI\u1ec6C LI\u00caN K\u1ebeT V\u1edaI OKR/KEY RESULT khi S\u1ebfp y\u00eau c\u1ea7u \"T\u1ea1o c\u00f4ng vi\u1ec7c cho m\u1ee5c ti\u00eau/KR...\".\n \n C\u00c1CH TH\u1ee8C HO\u1ea0T \u0110\u1ed8NG:\n 1. Tr\u00edch xu\u1ea5t Action: T\u1ea0O M\u1edaI (create) ho\u1eb7c C\u1eacP NH\u1eacT (update).\n 2. T\u1ef1 \u0111\u1ed9ng t\u00ecm Email nh\u00e2n vi\u00ean d\u1ef1a tr\u00ean T\u00ean.\n 3. N\u1ebfu S\u1ebfp mu\u1ed1n g\u1eafn Task v\u00e0o Key Result (OKR), h\u00e3y truy\u1ec1n 'kr_keyword'. H\u1ec7 th\u1ed1ng s\u1ebd t\u1ef1 t\u00ecm v\u00e0 map 'id_link', 'id_job'.\n 4. \u0110\u1ecbnh tuy\u1ebfn d\u1eef li\u1ec7u qua Controller \u0111\u1ec3 k\u00edch ho\u1ea1t Notifications.",inputSchema:z.object({action:z.enum(["create",
3
+ "update"]).describe("H\u00e0nh \u0111\u1ed9ng: create (T\u1ea1o vi\u1ec7c m\u1edbi) ho\u1eb7c update (C\u1eadp nh\u1eadt vi\u1ec7c c\u0169)."),document_id:z.string().optional().describe('B\u1eaeT BU\u1ed8C n\u1ebfu action l\u00e0 "update". M\u00e3 ID c\u1ee7a Task c\u1ea7n s\u1eeda.'),ten_cv:z.string().optional().describe("Ti\u00eau \u0111\u1ec1 c\u00f4ng vi\u1ec7c."),mieu_ta:z.string().optional().describe("M\u00f4 t\u1ea3 chi ti\u1ebft."),phu_trach:z.string().optional().describe("T\u00ean ho\u1eb7c Email c\u1ee7a ng\u01b0\u1eddi ch\u1ecbu tr\u00e1ch nhi\u1ec7m."),
4
+ due_date:z.string().optional().describe("H\u1ea1n ch\u00f3t (YYYY-MM-DDTHH:mm:ss)."),start_date:z.string().optional().describe("Ng\u00e0y b\u1eaft \u0111\u1ea7u."),ma_loai_cv:z.string().optional().describe("M\u00e3 lo\u1ea1i c\u00f4ng vi\u1ec7c."),priority:z.number().optional().describe("\u0110\u1ed9 \u01b0u ti\u00ean. Gi\u00e1 tr\u1ecb c\u00e0ng th\u1ea5p th\u00ec \u01b0u ti\u00ean c\u00e0ng cao."),progress:z.string().optional().describe('M\u00e3 tr\u1ea1ng th\u00e1i ti\u1ebfn \u0111\u1ed9 (VD: "0" - Ch\u01b0a l\u00e0m, "1" - \u0110ang l\u00e0m, "2" - Ki\u1ec3m tra, "3" - Ho\u00e0n th\u00e0nh).'),
5
+ kr_keyword:z.string().optional().describe('T\u1eeb kh\u00f3a t\u00ean c\u1ee7a Key Result n\u1ebfu mu\u1ed1n li\u00ean k\u1ebft c\u00f4ng vi\u1ec7c n\u00e0y v\u1edbi OKR (VD: "M\u1edf m\u1edbi 50 \u0111\u1ea1i l\u00fd").')}),execute:async({action:$action$$,document_id:$document_id$$,ten_cv:$finalLoaiCv_ten_cv$$,mieu_ta:$mieu_ta$$,phu_trach:$phu_trach$$,due_date:$due_date$$,start_date:$start_date$$,ma_loai_cv:$ma_loai_cv$$,progress:$progress$$,kr_keyword:$kr_keyword$$})=>{try{const $taskController$$=
6
+ global.controllers.TASK,$Participant$$=global.getModel("participant"),$DmLoaiTask$$=global.getModel("dmloaitask"),$KeyResult$$=global.getModel("keyresult"),$req_user_id$$=typeof $user_id$$!=="undefined"?$user_id$$:"AI_AGENT_ID";let $finalDataToProcess$$={id_app:$id_app$$};$finalLoaiCv_ten_cv$$&&($finalDataToProcess$$.ten_cv=$finalLoaiCv_ten_cv$$);$mieu_ta$$&&($finalDataToProcess$$.mieu_ta=$mieu_ta$$);$progress$$&&($finalDataToProcess$$.progress=$progress$$);if($phu_trach$$)if($phu_trach$$.includes("@"))$finalDataToProcess$$.phu_trach=
7
+ $phu_trach$$;else{const $users$$=await $Participant$$.find({id_app:$id_app$$,name:{$regex:$phu_trach$$,$options:"i"},status:!0}).lean();if($users$$.length===0)return{status:"error",message:`Kh\u00f4ng t\u00ecm th\u1ea5y nh\u00e2n vi\u00ean n\u00e0o t\u00ean '${$phu_trach$$}'.`};if($users$$.length>1){const $danhSachUser$$=$users$$.map($u$$=>`- **${$u$$.name}** (Email: ${$u$$.email})`).join("\n");return{status:"need_clarification",message:`H\u1ec7 th\u1ed1ng t\u00ecm th\u1ea5y nhi\u1ec1u ng\u01b0\u1eddi t\u00ean '${$phu_trach$$}'.\n\nH\u01af\u1edaNG D\u1eaaN AI: H\u1ecfi S\u1ebfp mu\u1ed1n giao cho ai:\n${$danhSachUser$$}`}}$finalDataToProcess$$.phu_trach=
8
+ $users$$[0].email}if($kr_keyword$$){const $foundKRs$$=await $KeyResult$$.find({id_app:$id_app$$,name:{$regex:$kr_keyword$$,$options:"i"}}).lean();if($foundKRs$$.length===0)return{status:"error",message:`Kh\u00f4ng t\u00ecm th\u1ea5y Key Result (K\u1ebft qu\u1ea3 then ch\u1ed1t) n\u00e0o kh\u1edbp v\u1edbi t\u1eeb kh\u00f3a '${$kr_keyword$$}' \u0111\u1ec3 li\u00ean k\u1ebft Task.`};if($foundKRs$$.length>1){const $danhSachKR$$=$foundKRs$$.map(($k$$,$i$$)=>`${$i$$+1}. **${$k$$.name}**`).join("\n");return{status:"need_clarification",
9
+ message:`[C\u1ea2NH B\u00c1O TR\u00d9NG L\u1eb6P]: H\u1ec7 th\u1ed1ng t\u00ecm th\u1ea5y ${$foundKRs$$.length} Key Result kh\u1edbp v\u1edbi t\u1eeb kh\u00f3a '${$kr_keyword$$}'.\n\nH\u01af\u1edaNG D\u1eaaN AI: H\u00e3y y\u00eau c\u1ea7u S\u1ebfp x\u00e1c nh\u1eadn mu\u1ed1n g\u1eafn Task n\u00e0y v\u00e0o KR n\u00e0o:\n${$danhSachKR$$}`}}const $targetKR$$=$foundKRs$$[0];$finalDataToProcess$$.id_link=$targetKR$$._id.toString();$finalDataToProcess$$.id_job=$targetKR$$.id_link;Logger.info(`[manageTaskTool] \u0110\u00e3 t\u1ef1 \u0111\u1ed9ng li\u00ean k\u1ebft Task v\u1edbi KR: ${$targetKR$$.name}`)}$start_date$$&&
10
+ ($finalDataToProcess$$.start_date=moment($start_date$$).toDate());$due_date$$&&($finalDataToProcess$$.due_date=moment($due_date$$).toDate());if($action$$==="create"){$finalDataToProcess$$.start_date||($finalDataToProcess$$.start_date=new Date);$finalDataToProcess$$.due_date||($finalDataToProcess$$.due_date=moment().set({hour:17,minute:0,second:0}).toDate());$finalDataToProcess$$.progress||($finalDataToProcess$$.progress="0");$finalLoaiCv_ten_cv$$=$ma_loai_cv$$;if(!$finalLoaiCv_ten_cv$$){const $defaultLoai$$=
11
+ await $DmLoaiTask$$.findOne({id_app:$id_app$$}).lean();$finalLoaiCv_ten_cv$$=$defaultLoai$$?$defaultLoai$$.ma_loai_cv:"CV_CHUNG"}await $DmLoaiTask$$.findOne({id_app:$id_app$$,ma_loai_cv:$finalLoaiCv_ten_cv$$}).lean()||await $DmLoaiTask$$.create({id_app:$id_app$$,ma_loai_cv:$finalLoaiCv_ten_cv$$,ten_loai_cv:$finalLoaiCv_ten_cv$$,status:!0});$finalDataToProcess$$.ma_loai_cv=$finalLoaiCv_ten_cv$$}let $resultDoc$$;if($action$$==="create")return $resultDoc$$=await $taskController$$.createData($req_user_id$$,
12
+ $finalDataToProcess$$),{status:"success",data:$resultDoc$$,hint:`D\u1ea1 em \u0111\u00e3 t\u1ea1o Task${$kr_keyword$$?" v\u00e0 li\u00ean k\u1ebft v\u00e0o OKR":""} th\u00e0nh c\u00f4ng. H\u1ec7 th\u1ed1ng \u0111ang g\u1eedi Notification nh\u1eafc vi\u1ec7c \u0111\u1ebfn nh\u00e2n s\u1ef1 \u1ea1.`};if($action$$==="update"){if(!$document_id$$)return{status:"error",message:"H\u00e0nh \u0111\u1ed9ng 'update' b\u1eaft bu\u1ed9c ph\u1ea3i truy\u1ec1n document_id."};$resultDoc$$=await $taskController$$.updateData($req_user_id$$,
13
+ $document_id$$,$finalDataToProcess$$);return{status:"success",data:$resultDoc$$,hint:"D\u1ea1 em \u0111\u00e3 c\u1eadp nh\u1eadt l\u1ea1i c\u00f4ng vi\u1ec7c th\u00e0nh c\u00f4ng theo \u00fd S\u1ebfp r\u1ed3i \u1ea1."}}}catch($error$$){return console.error("[L\u1ed7i manageTaskTool]:",$error$$),{status:"error",message:`L\u1ed7i Controller khi thao t\u00e1c d\u1eef li\u1ec7u: ${$error$$.message}`}}}}),trackTaskProgressTool:tool({description:"C\u00f4ng c\u1ee5 KI\u1ec2M TRA TI\u1ebeN \u0110\u1ed8 C\u00d4NG VI\u1ec6C (Task Tracking & Monitoring).\n S\u1eec D\u1ee4NG KHI: S\u1ebfp y\u00eau c\u1ea7u ki\u1ec3m tra t\u00ecnh h\u00ecnh c\u00f4ng vi\u1ec7c, th\u1ed1ng k\u00ea task qu\u00e1 h\u1ea1n, ho\u1eb7c xem danh s\u00e1ch vi\u1ec7c \u0111ang l\u00e0m c\u1ee7a nh\u00e2n vi\u00ean/ph\u00f2ng ban.\n \n C\u00c1CH TH\u1ee8C HO\u1ea0T \u0110\u1ed8NG:\n 1. L\u1ecdc theo Nh\u00e2n vi\u00ean ho\u1eb7c Ph\u00f2ng ban.\n 2. \u0110\u1ecdc tr\u01b0\u1eddng 'progress' (0: Ch\u01b0a th\u1ef1c hi\u1ec7n, 1: \u0110ang th\u1ef1c hi\u1ec7n...) \u0111\u1ec3 ph\u00e2n lo\u1ea1i.\n 3. T\u1ef1 \u0111\u1ed9ng so s\u00e1nh 'due_date' v\u1edbi gi\u1edd hi\u1ec7n t\u1ea1i \u0111\u1ec3 ph\u00e1t hi\u1ec7n vi\u1ec7c QU\u00c1 H\u1ea0N.",
14
+ inputSchema:z.object({phu_trach:z.string().optional().describe("T\u00ean nh\u00e2n vi\u00ean ho\u1eb7c Email. \u0110\u1ec3 tr\u1ed1ng n\u1ebfu xem to\u00e0n c\u00f4ng ty."),ten_bp:z.string().optional().describe("T\u00ean ph\u00f2ng ban. \u0110\u1ec3 tr\u1ed1ng n\u1ebfu kh\u00f4ng l\u1ecdc theo ph\u00f2ng."),trang_thai_loc:z.enum(["ALL","DONE","PENDING","OVERDUE"]).default("ALL"),tu_ngay:z.string().optional().describe("H\u1ea1n ch\u00f3t t\u1eeb ng\u00e0y (YYYY-MM-DD)."),den_ngay:z.string().optional().describe("H\u1ea1n ch\u00f3t \u0111\u1ebfn ng\u00e0y (YYYY-MM-DD).")}),
15
+ execute:async({phu_trach:$filteredTasks_phu_trach$$,ten_bp:$ten_bp$$,trang_thai_loc:$trang_thai_loc$$,tu_ngay:$tu_ngay$$,den_ngay:$den_ngay$$})=>{try{const $taskController$$=global.controllers.TASK,$Participant$$=global.getModel("participant"),$DmBp$$=global.getModel("dmbp"),$TrangThai$$=global.getModel("trangthai"),$req_user_id$$=typeof $user_id$$!=="undefined"?$user_id$$:"AI_AGENT_ID";let $hopSearchQuery$$={id_app:$id_app$$,saved:{$ne:!0}},$filterName$$="To\u00e0n c\u00f4ng ty";if($filteredTasks_phu_trach$$)if($filteredTasks_phu_trach$$.includes("@"))$hopSearchQuery$$.phu_trach=
16
+ $filteredTasks_phu_trach$$,$filterName$$=`Nh\u00e2n vi\u00ean: ${$filteredTasks_phu_trach$$}`;else{const $user$$=await $Participant$$.findOne({id_app:$id_app$$,name:{$regex:$filteredTasks_phu_trach$$,$options:"i"},status:!0}).lean();if(!$user$$)return{status:"error",message:`Kh\u00f4ng t\u00ecm th\u1ea5y nh\u00e2n vi\u00ean n\u00e0o t\u00ean '${$filteredTasks_phu_trach$$}'.`};$hopSearchQuery$$.phu_trach=$user$$.email;$filterName$$=`Nh\u00e2n vi\u00ean: ${$user$$.name}`}if($ten_bp$$){const $bp$$=await $DmBp$$.findOne({id_app:$id_app$$,
17
+ ten_bp:{$regex:$ten_bp$$,$options:"i"}}).lean();if(!$bp$$)return{status:"error",message:`Kh\u00f4ng t\u00ecm th\u1ea5y ph\u00f2ng ban n\u00e0o t\u00ean '${$ten_bp$$}'.`};$hopSearchQuery$$.id_bp=$bp$$._id.toString();$filterName$$=$filterName$$==="To\u00e0n c\u00f4ng ty"?`Ph\u00f2ng: ${$bp$$.ten_bp}`:`${$filterName$$} (Thu\u1ed9c ${$bp$$.ten_bp})`}if($tu_ngay$$||$den_ngay$$)$hopSearchQuery$$.due_date={},$tu_ngay$$&&($hopSearchQuery$$.due_date.$gte=moment($tu_ngay$$).startOf("day").toDate()),$den_ngay$$&&
18
+ ($hopSearchQuery$$.due_date.$lte=moment($den_ngay$$).endOf("day").toDate());let $tasksResult$$=await $taskController$$.findData($req_user_id$$,$hopSearchQuery$$,{limit:2E3});var $taskStatus_tasks$$=Array.isArray($tasksResult$$)?$tasksResult$$:$tasksResult$$.docs||$tasksResult$$.data||[];const $mapTrangThai$$={};(await $TrangThai$$.find({id_app:$id_app$$,ma_ct:"TASK"}).lean()).forEach($t$$=>$mapTrangThai$$[$t$$.ma_trang_thai]=$t$$.ten_trang_thai);const $now$$=new Date;let $summary$$={total:$taskStatus_tasks$$.length,
19
+ done:0,pending:0,overdue:0};$filteredTasks_phu_trach$$=[];for(let $task$$ of $taskStatus_tasks$$){$taskStatus_tasks$$="PENDING";if($task$$.progress==="3"&&$task$$.progress)$taskStatus_tasks$$="DONE",$summary$$.done++;else if($task$$.due_date&&new Date($task$$.due_date)<$now$$){$taskStatus_tasks$$="OVERDUE";$summary$$.overdue++;const $daysLate$$=moment($now$$).diff(moment($task$$.due_date),"days");$task$$.so_ngay_tre=$daysLate$$===0?"Tr\u1ec5 trong ng\u00e0y":`${$daysLate$$} ng\u00e0y`}else $taskStatus_tasks$$=
20
+ "PENDING",$summary$$.pending++;$task$$.nhan_trang_thai_ai=$taskStatus_tasks$$;$task$$.ten_trang_thai_thuc_te=$mapTrangThai$$[$task$$.progress]||`M\u00e3 ${$task$$.progress}`;$trang_thai_loc$$!=="ALL"&&$trang_thai_loc$$!==$taskStatus_tasks$$||$filteredTasks_phu_trach$$.push($task$$)}return{status:"success",target_filter:$filterName$$,summary:$summary$$,data:$filteredTasks_phu_trach$$.slice(0,50),hint:`QUY T\u1eaeC B\u00c1O C\u00c1O:
21
+ 1. M\u1edf \u0111\u1ea7u b\u1eb1ng T\u00f3m t\u1eaft: "D\u1ea1 S\u1ebfp, \u0111\u1ed1i v\u1edbi ${$filterName$$}, c\u00f3 t\u1ed5ng ${$summary$$.total} vi\u1ec7c. \u0110\u00e3 xong: ${$summary$$.done}, \u0110ang l\u00e0m: ${$summary$$.pending}, QU\u00c1 H\u1ea0N: ${$summary$$.overdue}."
22
+ 2. N\u1ebfu c\u00f3 task QU\u00c1 H\u1ea0N: B\u1eaeT BU\u1ed8C li\u1ec7t k\u00ea chi ti\u1ebft (T\u00ean vi\u1ec7c, Ph\u1ee5 tr\u00e1ch, Tr\u1ea1ng th\u00e1i hi\u1ec7n t\u1ea1i, H\u1ea1n ch\u00f3t, S\u1ed1 ng\u00e0y tr\u1ec5).
23
+ 3. H\u1eceI S\u1ebeP H\u00c0NH \u0110\u1ed8NG: "S\u1ebfp c\u00f3 mu\u1ed1n em g\u1ecdi manageTaskTool \u0111\u1ec3 t\u1ea1o l\u1ec7nh nh\u1eafc nh\u1edf kh\u1ea9n c\u1ea5p kh\u00f4ng \u1ea1?"`}}catch($error$$){return console.error("[L\u1ed7i trackTaskProgressTool]:",$error$$),{status:"error",message:`L\u1ed7i truy xu\u1ea5t: ${$error$$.message}`}}}})}}module.exports={createTaskTools};
@@ -0,0 +1,57 @@
1
+ global.__aiListInfoCache=global.__aiListInfoCache||new Map;const CACHE_TTL=9E5,numeral=require("numeral"),moment=require("moment");function escapeRegex($str$$){return String($str$$).replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}const bangTuDienDanhMuc=($ten_tham_so$$="exact_code")=>`
2
+ - D\u1eef li\u1ec7u \u0111\u1ec3 t\u1ea1o b\u00e1o c\u00e1o t\u00e0i ch\u00ednh, k\u1ebf to\u00e1n -> ${$ten_tham_so$$}: "data_socai"
3
+ - D\u1eef li\u1ec7u \u0111\u1ec3 t\u1ea1o b\u00e1o c\u00e1o li\u00ean quan \u0111\u1ebfn h\u00e0ng t\u1ed3n kho nh\u01b0 nh\u1eadp, xu\u1ea5t h\u00e0ng ho\u00e1 -> ${$ten_tham_so$$}: "data_sokho"
4
+ - Kh\u00e1ch h\u00e0ng, \u0110\u1ed1i t\u00e1c, Nh\u00e0 cung c\u1ea5p -> ${$ten_tham_so$$}: "customer"
5
+ - Nh\u00f3m kh\u00e1ch h\u00e0ng -> ${$ten_tham_so$$}: "dmnhkh"
6
+ - Nh\u00e2n vi\u00ean, Ng\u01b0\u1eddi lao \u0111\u1ed9ng -> ${$ten_tham_so$$}: "dmnv"
7
+ - B\u1ed9 ph\u1eadn -> ${$ten_tham_so$$}: "dmbp"
8
+ - K\u1ebf ho\u1ea1ch, ch\u1ec9 ti\u00eau KPI -> ${$ten_tham_so$$}: "ctds2"
9
+ - C\u00f4ng vi\u1ec7c -> ${$ten_tham_so$$}: "task"
10
+ - Ph\u1ee5 tr\u00e1ch, t\u00e0i kho\u1ea3n truy c\u1eadp h\u1ec7 th\u1ed1ng -> ${$ten_tham_so$$}: "participant"
11
+ - Danh m\u1ee5c chi ph\u00ed -> ${$ten_tham_so$$}: "dmphi"
12
+ - Danh m\u1ee5c v\u1ee5 vi\u1ec7c, d\u1ef1 \u00e1n -> ${$ten_tham_so$$}: "dmdt"
13
+ - S\u1ea3n ph\u1ea9m, V\u1eadt t\u01b0, H\u00e0ng h\u00f3a -> ${$ten_tham_so$$}: "dmvt"
14
+ - Nh\u00f3m S\u1ea3n ph\u1ea9m, V\u1eadt t\u01b0, H\u00e0ng h\u00f3a -> ${$ten_tham_so$$}: "dmnvt"
15
+ - Ng\u00e0nh h\u00e0ng -> ${$ten_tham_so$$}: "ecomproductlines"
16
+ - T\u00e0i s\u1ea3n c\u1ed1 \u0111\u1ecbnh, c\u00f4ng c\u1ee5 d\u1ee5ng c\u1ee5 -> ${$ten_tham_so$$}: "qts"
17
+ - Phi\u1ebfu \u0111\u1eb7t h\u00e0ng -> ${$ten_tham_so$$}: "dh2"
18
+ - Phi\u1ebfu b\u00e1n h\u00e0ng -> ${$ten_tham_so$$}: "hd2"
19
+ - H\u00f3a \u0111\u01a1n \u0111\u1ea7u v\u00e0o -> ${$ten_tham_so$$}: "vatvao"
20
+ - H\u00f3a \u0111\u01a1n \u0111\u1ea7u ra -> ${$ten_tham_so$$}: "vatra"
21
+ `,bangTuDienBaoCao=($ten_tham_so$$="exact_code")=>`
22
+ - C\u00e2n \u0111\u1ed1i ph\u00e1t sinh t\u00e0i kho\u1ea3n-> ${$ten_tham_so$$}: "cdpstk"
23
+ - T\u1ed5ng h\u1ee3p nh\u1eadp, xu\u1ea5t t\u1ed3n kho -> ${$ten_tham_so$$}: "thnxt"
24
+ `,getApiContext=$id_app$$=>({apis:{asyncGetData:async($token$$,$model$$,$condition$$={})=>{$condition$$.id_app=$id_app$$;return global.getModel($model$$).findOne($condition$$).lean()}},userInfo:{email:"admin",token:""}}),searchActiveListInfo=async({keywords:$keywords_words$$=[],include_fields_schema:$include_fields_schema_matchedKeyword$$=!1,limit:$finalResult_limit_processedDocs$$=15})=>{const $cacheKey$$=`listinfo_${$keywords_words$$.join("_").toLowerCase()}_${$include_fields_schema_matchedKeyword$$}_${$finalResult_limit_processedDocs$$}`;
25
+ if(global.__aiListInfoCache.has($cacheKey$$)){var $ListInfoModel_cachedData$$=global.__aiListInfoCache.get($cacheKey$$);if(Date.now()-$ListInfoModel_cachedData$$.timestamp<CACHE_TTL)return $ListInfoModel_cachedData$$.result;global.__aiListInfoCache.delete($cacheKey$$)}$ListInfoModel_cachedData$$=global.getModel("listinfo");if(!$ListInfoModel_cachedData$$)throw Error("Model 'listinfo' kh\u00f4ng t\u1ed3n t\u1ea1i.");var $endpoints_matchQuery$$=Object.keys(global.controllers||{}).map($k$$=>$k$$.toLowerCase());
26
+ $endpoints_matchQuery$$={status:!0,$and:[{code:{$not:{$regex:"(_bk|_bk1|_bk2|_dev|_tmp|_bk3|_agent)$",$options:"i"}}},{$or:[{code:{$in:$endpoints_matchQuery$$}},{api_code:{$in:$endpoints_matchQuery$$}}]}]};const $selectFields$$={code:1,title:1,search_form:1,api_code:1};$include_fields_schema_matchedKeyword$$&&($selectFields$$.fields=1);let $listDocs$$=[];$include_fields_schema_matchedKeyword$$="";if($keywords_words$$&&$keywords_words$$.length>0)for(let $kw$$ of $keywords_words$$){if($kw$$=$kw$$.trim())if($listDocs$$=
27
+ await $ListInfoModel_cachedData$$.find({...$endpoints_matchQuery$$,$or:[{code:{$regex:$kw$$,$options:"i"}},{api_code:{$regex:$kw$$,$options:"i"}},{title:{$regex:$kw$$,$options:"i"}}]}).select($selectFields$$).limit($finalResult_limit_processedDocs$$).lean(),$listDocs$$.length===0&&$kw$$.includes(" ")&&($keywords_words$$=$kw$$.split(" ").filter($w$$=>$w$$.length>1),$keywords_words$$.length>=2&&($listDocs$$=await $ListInfoModel_cachedData$$.find({...$endpoints_matchQuery$$,$and:$keywords_words$$.slice(0,
28
+ 2).map($word$$=>({title:{$regex:$word$$,$options:"i"}}))}).select($selectFields$$).limit($finalResult_limit_processedDocs$$).lean()),$listDocs$$.length===0&&$keywords_words$$.length>0&&($listDocs$$=await $ListInfoModel_cachedData$$.find({...$endpoints_matchQuery$$,title:{$regex:$keywords_words$$[0],$options:"i"}}).select($selectFields$$).limit($finalResult_limit_processedDocs$$).lean()),$listDocs$$.length===0&&($listDocs$$=await $ListInfoModel_cachedData$$.find({...$endpoints_matchQuery$$,$or:$keywords_words$$.map($word$$=>
29
+ ({title:{$regex:$word$$,$options:"i"}}))}).select($selectFields$$).limit($finalResult_limit_processedDocs$$).lean())),$listDocs$$.length>0){$include_fields_schema_matchedKeyword$$=$kw$$;break}}else $listDocs$$=await $ListInfoModel_cachedData$$.find($endpoints_matchQuery$$).select($selectFields$$).limit($finalResult_limit_processedDocs$$).lean();$finalResult_limit_processedDocs$$=$listDocs$$.map($d$$=>({...$d$$,finalCode:$d$$.api_code||$d$$.code}));$finalResult_limit_processedDocs$$={docs:JSON.parse(JSON.stringify($finalResult_limit_processedDocs$$)),
30
+ matchedKeyword:$include_fields_schema_matchedKeyword$$||"all"};global.__aiListInfoCache.set($cacheKey$$,{timestamp:Date.now(),result:$finalResult_limit_processedDocs$$});return $finalResult_limit_processedDocs$$};
31
+ async function translateDocToText($doc$$,$listInfoCode_text$$,$cache$$={},$depth$$=0,$visited$$=new Set){if($visited$$.has($listInfoCode_text$$))return"";$visited$$.add($listInfoCode_text$$);if(!$cache$$[$listInfoCode_text$$]){var $indent_info$$=await global.getModel("listinfo").findOne({code:$listInfoCode_text$$});if(!$indent_info$$)return"";$cache$$[$listInfoCode_text$$]=$indent_info$$}const $listInfo$$=$cache$$[$listInfoCode_text$$];$listInfoCode_text$$=$depth$$===0?`Th\u00f4ng tin ${$listInfo$$.title}:\n`:
32
+ "";$indent_info$$=" ".repeat($depth$$);await Promise.all(($listInfo$$.fields||[]).filter($f$$=>$f$$.header.indexOf("return ")>=0).map($field$$=>(async()=>{let $body_func$$=$field$$.header;$body_func$$=`return (async ()=>{
33
+ ${$body_func$$}
34
+ })()`;try{const $func$$=new Function("master","Moment","Numeral","API","utils","context","field","listInfo",$body_func$$),$context$$=getApiContext($doc$$.id_app);let $header$$=await $func$$({},moment,numeral,$context$$.apis,{},$context$$,$field$$,$listInfo$$);$field$$.header=$header$$}catch($e$$){console.error($e$$.message,$field$$.header,$body_func$$),$field$$.header=$field$$.name}})()));for(const $field$$ of $listInfo$$.fields){const {header:$header$$,name:$name$$,type:$type$$,form:$form$$}=
35
+ $field$$,$rawValue$$=$doc$$[$name$$];if($rawValue$$!==void 0&&$rawValue$$!==null&&$rawValue$$!=="")if($type$$.toLowerCase()==="array"&&$form$$){if(Array.isArray($rawValue$$)&&$rawValue$$.length!==0){$listInfoCode_text$$+=`${$indent_info$$}- ${$header$$}:\n`;for(var $displayValue_i$$=0;$displayValue_i$$<$rawValue$$.length;$displayValue_i$$++){var $subDoc_subText$$=$rawValue$$[$displayValue_i$$];$listInfoCode_text$$+=`${$indent_info$$} * [D\u00f2ng ${$displayValue_i$$+1}]:\n`;$subDoc_subText$$=await translateDocToText($subDoc_subText$$,
36
+ $form$$,$cache$$,$depth$$+2,new Set($visited$$));$listInfoCode_text$$+=$subDoc_subText$$}}}else{$displayValue_i$$=$rawValue$$;switch($type$$.toLowerCase()){case "datetime":case "date":$displayValue_i$$=(new Date($rawValue$$)).toLocaleDateString("vi-VN");break;case "array":$displayValue_i$$=Array.isArray($rawValue$$)?$rawValue$$.join("; "):$rawValue$$;break;case "boolean":$displayValue_i$$=$rawValue$$?"C\u00f3":"Kh\u00f4ng";break;case "currency":case "number":$displayValue_i$$=Number($rawValue$$).toLocaleString("en-US");
37
+ break;default:$displayValue_i$$=String($rawValue$$).trim()}$listInfoCode_text$$+=`${$indent_info$$}- ${$header$$}: ${$displayValue_i$$}.\n`}}return $listInfoCode_text$$}
38
+ const extractFeatureKeywords=$rawQuery$$=>{var $q_withContext$$=$rawQuery$$.trim();$q_withContext$$=$q_withContext$$.replace(/^(t\u00f4i|anh|ch\u1ecb|em|m\u00ecnh|s\u1ebfp|boss)?\s*(mu\u1ed1n|c\u1ea7n|h\u00e3y|cho\s+(?:t\u00f4i|anh|em|m\u00ecnh)|gi\u00fap\s+(?:t\u00f4i|anh|em|m\u00ecnh))?\s*/i,"");$q_withContext$$=$q_withContext$$.replace(/^(t\u1ea1o\s+m\u1edbi|t\u1ea1o|nh\u1eadp|xem|m\u1edf|tra c\u1ee9u|qu\u1ea3n l\u00fd|truy c\u1eadp|v\u00e0o|t\u00ecm|xu\u1ea5t|in|l\u1ea5y|ch\u1ea1y|ki\u1ec3m tra|duy\u1ec7t|x\u1eed l\u00fd)\s+/i,"");
39
+ $q_withContext$$=$q_withContext$$.replace(/\s*(th\u00ec)?\s*(v\u00e0o \u0111\u00e2u|\u1edf \u0111\u00e2u|link n\u00e0o|link \u0111\u1ebfn|\u0111\u01b0\u1eddng d\u1eabn|\u0111\u01b0\u1eddng link|m\u00e0n h\u00ecnh n\u00e0o|ch\u1ee9c n\u0103ng (?:n\u00e0y )?\u1edf \u0111\u00e2u|\u1edf ch\u1ed7 n\u00e0o|n\u1eb1m \u1edf \u0111\u00e2u|t\u00f4i v\u00e0o \u0111\u00e2u)\s*[?\uff1f]?\s*$/i,"").trim();$q_withContext$$=$q_withContext$$.trim();const $withoutContext$$=$q_withContext$$.replace(/\s+(cho|c\u1ee7a|theo|t\u1eeb|v\u1edbi|li\u00ean quan(?:\s+\u0111\u1ebfn?)?|d\u00e0nh cho|g\u1eafn v\u1edbi|k\u00e8m|thu\u1ed9c|giao cho)\s+.*/i,
40
+ "").trim(),$keywords$$=[];$withoutContext$$&&$withoutContext$$.toLowerCase()!==$rawQuery$$.toLowerCase()&&$keywords$$.push($withoutContext$$);$q_withContext$$&&$q_withContext$$.toLowerCase()!==$withoutContext$$.toLowerCase()&&$q_withContext$$.toLowerCase()!==$rawQuery$$.toLowerCase()&&$keywords$$.push($q_withContext$$);$keywords$$.push($rawQuery$$);return[...(new Set($keywords$$))].filter($k$$=>$k$$.length>1)};
41
+ async function findRefDocsByKeyword($RefModel$$,$stringFields$$,$keyword$$,$id_app$$){const $tryFind$$=async $orConditions_query$$=>{$orConditions_query$$={$or:$orConditions_query$$};$RefModel$$.schema.paths.id_app&&($orConditions_query$$.id_app=$id_app$$);$RefModel$$.schema.paths.id_apps&&$RefModel$$.schema.paths.id_apps.instance==="Array"&&($orConditions_query$$.$and||($orConditions_query$$.$and=[]),$orConditions_query$$.$and.push({$or:[{id_apps:$id_app$$},{id_apps:null},{"id_apps.0":{$exists:!1}}]}));
42
+ return await $RefModel$$.find($orConditions_query$$).lean()};var $docs_words$$=await $tryFind$$($stringFields$$.map($f$$=>({[$f$$]:{$regex:`^${escapeRegex($keyword$$)}$`,$options:"i"}})));if($docs_words$$.length>0)return{docs:$docs_words$$,matchedBy:"exact"};$docs_words$$=await $tryFind$$($stringFields$$.map($f$$=>({[$f$$]:{$regex:escapeRegex($keyword$$),$options:"i"}})));if($docs_words$$.length>0)return{docs:$docs_words$$,matchedBy:"contains_phrase"};$docs_words$$=String($keyword$$).split(/\s+/).filter($w$$=>
43
+ $w$$.length>1);return $docs_words$$.length>1&&($docs_words$$=await $tryFind$$($docs_words$$.flatMap($w$$=>$stringFields$$.map($f$$=>({[$f$$]:{$regex:escapeRegex($w$$),$options:"i"}})))),$docs_words$$.length>0)?{docs:$docs_words$$,matchedBy:"fuzzy_words"}:{docs:[],matchedBy:"none"}}
44
+ async function resolveRefMetaByKeyword($refMeta_values$$,$keyword$$,$docs$jscomp$1_id_app$$){var $stringFields$$=($refMeta_values$$.listinfo_code||$refMeta_values$$.ref_model).toUpperCase();const $RefModel$$=global.controllers[$stringFields$$]?.model||global.getModel($refMeta_values$$.ref_model);if(!$RefModel$$)return{error:`Kh\u00f4ng t\u00ecm th\u1ea5y model danh m\u1ee5c li\u00ean k\u1ebft '${$refMeta_values$$.ref_model}'.`};$stringFields$$=Object.keys($RefModel$$.schema.paths).filter($p$$=>$RefModel$$.schema.paths[$p$$].instance===
45
+ "String"&&!["id_app","user_created"].includes($p$$));({docs:$docs$jscomp$1_id_app$$}=await findRefDocsByKeyword($RefModel$$,$stringFields$$,$keyword$$,$docs$jscomp$1_id_app$$));if($docs$jscomp$1_id_app$$.length===0)return{error:`Kh\u00f4ng t\u00ecm th\u1ea5y '${$keyword$$}' trong danh m\u1ee5c li\u00ean k\u1ebft '${$refMeta_values$$.ref_model}'.`};const $valueField$$=$refMeta_values$$.value_field||"_id";$refMeta_values$$=$docs$jscomp$1_id_app$$.map($d$$=>$valueField$$==="_id"?$d$$._id?$d$$._id.toString():
46
+ $d$$.id:$d$$[$valueField$$]);return{values:$refMeta_values$$,count:$refMeta_values$$.length,refModel:$RefModel$$}}
47
+ async function resolveDirectRefFilter($matched_pathDef$$,$keyword$$,$id_app$$){if(!$matched_pathDef$$)return{error:"Field kh\u00f4ng t\u1ed3n t\u1ea1i trong schema."};if($matched_pathDef$$.ref&&$matched_pathDef$$.ref.ref_model)return await resolveRefMetaByKeyword($matched_pathDef$$.ref,$keyword$$,$id_app$$);if($matched_pathDef$$.options&&Array.isArray($matched_pathDef$$.options.options)){const $labelField$$=$matched_pathDef$$.options.label_field||"name",$valueField$$=$matched_pathDef$$.options.value_field||
48
+ "code";$matched_pathDef$$=$matched_pathDef$$.options.options.filter($o$$=>$o$$[$labelField$$]&&$o$$[$labelField$$].toLowerCase().includes($keyword$$.toLowerCase())||$o$$[$valueField$$]&&$o$$[$valueField$$].toLowerCase()===$keyword$$.toLowerCase());return $matched_pathDef$$.length===0?{error:`Gi\u00e1 tr\u1ecb '${$keyword$$}' kh\u00f4ng h\u1ee3p l\u1ec7.`}:{values:$matched_pathDef$$.map($o$$=>$o$$[$valueField$$]),count:$matched_pathDef$$.length}}return{error:"Field kh\u00f4ng h\u1ed7 tr\u1ee3 l\u1ecdc theo t\u1eeb kh\u00f3a (kh\u00f4ng c\u00f3 ref/options)."}}
49
+ async function resolveHopChain($hops$$,$keyword$$,$id_app$$){var $currentValues_query$$=null;for(let $i$$=0;$i$$<$hops$$.length;$i$$++){const $hop$$=$hops$$[$i$$],$stepLabel$$=`b\u01b0\u1edbc ${$i$$+1}/${$hops$$.length} ('${$hop$$.controller}.${$hop$$.field}')`,$HopCtrl$$=global.controllers[$hop$$.controller.toUpperCase()];if(!$HopCtrl$$)return{error:`Kh\u00f4ng t\u00ecm th\u1ea5y controller trung gian '${$hop$$.controller}' (${$stepLabel$$}).`};var $HopModel_hopDocs$$=$HopCtrl$$.model||global.getModel($hop$$.controller.toLowerCase());
50
+ if(!$HopModel_hopDocs$$)return{error:`Kh\u00f4ng t\u00ecm th\u1ea5y model c\u1ee7a controller trung gian '${$hop$$.controller}' (${$stepLabel$$}).`};if($HopModel_hopDocs$$.schema?.paths&&!$HopModel_hopDocs$$.schema.paths[$hop$$.field])return{error:`Tr\u01b0\u1eddng b\u1eafc c\u1ea7u '${$hop$$.field}' KH\u00d4NG T\u1ed2N T\u1ea0I trong controller '${$hop$$.controller}' \u2014 c\u00f3 th\u1ec3 t\u00ean field \u0111\u00e3 b\u1ecb \u0111o\u00e1n sai. H\u00e3y g\u1ecdi exploreSystemSchemaTool \u0111\u1ec3 x\u00e1c nh\u1eadn \u0111\u00fang t\u00ean field tr\u01b0\u1edbc khi b\u1eafc c\u1ea7u (${$stepLabel$$}).`};
51
+ let $matchCondition$$=null;if($currentValues_query$$===null){if(typeof $HopCtrl$$.getJsonSchema==="function")try{const $hopPathDef$$=(await $HopCtrl$$.getJsonSchema($id_app$$))?.[$hop$$.field];if($hopPathDef$$?.ref?.ref_model){const $resolved$$=await resolveRefMetaByKeyword($hopPathDef$$.ref,$keyword$$,$id_app$$);if($resolved$$.error)return{error:`${$resolved$$.error} (${$stepLabel$$}).`};$matchCondition$$={[$hop$$.field]:{$in:$resolved$$.values}}}}catch($e$$){typeof Logger!=="undefined"&&Logger.warn(`[refBridgeResolver] Kh\u00f4ng l\u1ea5y \u0111\u01b0\u1ee3c schema c\u1ee7a '${$hop$$.controller}', d\u00f9ng fallback regex:`,
52
+ $e$$.message)}$matchCondition$$||={[$hop$$.field]:{$regex:escapeRegex($keyword$$),$options:"i"}}}else $matchCondition$$={[$hop$$.field]:{$in:$currentValues_query$$}};$currentValues_query$$={...$matchCondition$$};$HopModel_hopDocs$$.schema.paths.id_app&&($currentValues_query$$.id_app=$id_app$$);$HopModel_hopDocs$$.schema.paths.id_apps&&$HopModel_hopDocs$$.schema.paths.id_apps.instance==="Array"&&($currentValues_query$$.$and||($currentValues_query$$.$and=[]),$currentValues_query$$.$and.push({$or:[{id_apps:$id_app$$},
53
+ {id_apps:null},{"id_apps.0":{$exists:!1}}]}));$HopModel_hopDocs$$=await $HopModel_hopDocs$$.find($currentValues_query$$).lean();if($HopModel_hopDocs$$.length===0)return{error:`Kh\u00f4ng t\u00ecm th\u1ea5y d\u1eef li\u1ec7u n\u00e0o kh\u1edbp khi b\u1eafc c\u1ea7u qua ${$stepLabel$$}.`};$currentValues_query$$=$HopModel_hopDocs$$.map($d$$=>{let $val$$=$d$$[$hop$$.extract_field];$val$$||$hop$$.extract_field!=="_id"||($val$$=$d$$.id);return $val$$?$val$$.toString():null}).filter(Boolean);if($currentValues_query$$.length===
54
+ 0)return{error:`B\u1ea3ng trung gian '${$hop$$.controller}' kh\u00f4ng c\u00f3 tr\u01b0\u1eddng '${$hop$$.extract_field}' (${$stepLabel$$}).`}}return{values:$currentValues_query$$,count:$currentValues_query$$.length}}
55
+ function normalizeHops($filter$$){return $filter$$.hops&&$filter$$.hops.length>0?$filter$$.hops:$filter$$.hop_controller&&$filter$$.hop_field&&$filter$$.hop_extract_field?[{controller:$filter$$.hop_controller,field:$filter$$.hop_field,extract_field:$filter$$.hop_extract_field}]:null}
56
+ const cleanObjectOfFunctions=$obj$$=>{if($obj$$===null||typeof $obj$$!=="object")return $obj$$;if(Array.isArray($obj$$))return $obj$$.map(cleanObjectOfFunctions);const $cleaned$$={};for(const $key$$ in $obj$$)Object.prototype.hasOwnProperty.call($obj$$,$key$$)&&typeof $obj$$[$key$$]!=="function"&&($cleaned$$[$key$$]=typeof $obj$$[$key$$]==="object"?cleanObjectOfFunctions($obj$$[$key$$]):$obj$$[$key$$]);return $cleaned$$};
57
+ module.exports={cleanObjectOfFunctions,searchActiveListInfo,extractFeatureKeywords,translateDocToText,escapeRegex,findRefDocsByKeyword,resolveRefMetaByKeyword,resolveDirectRefFilter,resolveHopChain,normalizeHops,bangTuDienDanhMuc,bangTuDienBaoCao};
package/server/app.js CHANGED
@@ -11,13 +11,13 @@ extended:!0}));$app$$.use(passport.initialize());$_port_compress_cookieParser_li
11
11
  {stream:$accessLogStream_rfs$$,skip:function($req$$,$res$$){return $res$$.statusCode<400}}));$app$$.use(function($err$$,$req$$,$res$$,$next$$){Logger.error($err$$.stack);$res$$.status(500).send("Server Error!")});Logger.info("[app] connect to mongodb",$configs$$.database.url);$configs$$.database.url||(Logger.error("[app] thi\u1ebfu \u0111\u01b0\u1eddng d\u1eabn k\u1ebft n\u1ed1i v\u1edbi database trong file config"),process.exit(1));global.mongoose.connect($configs$$.database.url,{useNewUrlParser:!0,
12
12
  useFindAndModify:!1,useUnifiedTopology:!0}).then(async()=>{if(!$options$$.lite){var $redis_transactionLifetimeLimitSeconds$$=$configs$$.transactionLifetimeLimitSeconds||600,$result_retryStrategyRedis$$=await mongoose.connection.getClient().db().admin().command({setParameter:1,transactionLifetimeLimitSeconds:$redis_transactionLifetimeLimitSeconds$$});Logger.warn("[app] T\u0103ng th\u1eddi gian ho\u1ea1t \u0111\u1ed9ng c\u1ee7a m\u1ed9t transaction l\u00ean",$redis_transactionLifetimeLimitSeconds$$,
13
13
  $result_retryStrategyRedis$$)}Logger.info("[app] Connected to Database");$redis_transactionLifetimeLimitSeconds$$=require("redis");({retryStrategyRedis:$result_retryStrategyRedis$$}=require("./libs/utils"));global.clientRedis=$redis_transactionLifetimeLimitSeconds$$.createClient({host:"127.0.0.1",port:6379,retry_strategy:$result_retryStrategyRedis$$});global.clientRedis.on("error",$err$$=>{Logger.error("Redis Client Error",$err$$);process.exit(1)});global.clientRedis.on("end",()=>{Logger.error("[app] Redis connection closed.")});
14
- global.clientRedis.on("connect",function(){Logger.info("[app] redis connected");$User$$.initClientSockets();if($options$$.lite!==!0){$options$$.createRedisCache&&require("./libs/redis-cache").set();global.getModel("schedule").start();$options$$.start_abci_handler&&global.getModel("assabcihandler").start();const {recoverBackgroundTasks:$recoverBackgroundTasks$$}=require("./libs/optimizeBookkeeping");$recoverBackgroundTasks$$().catch(console.error);require("./route")($app$$,()=>{if($options$$.createServer!==
15
- !1){var $StaticPool$$=require("sticky-session");if($configs$$.use_ssl&&$options$$.sslDir){var $cpus_report_cpus_server_sslConfig$$=require("./sslConfig");$cpus_report_cpus_server_sslConfig$$=https.createServer($cpus_report_cpus_server_sslConfig$$($options$$.sslDir),$app$$)}else $cpus_report_cpus_server_sslConfig$$=http.createServer($app$$);$cpus_report_cpus_server_sslConfig$$.timeout=6E5;$options$$.useSocket!==!1&&$User$$.initSocket($cpus_report_cpus_server_sslConfig$$);if($options$$.cluster!==!1){if(!$StaticPool$$.listen($cpus_report_cpus_server_sslConfig$$,
16
- global.port))$cpus_report_cpus_server_sslConfig$$.once("listening",function(){Logger.info("[app] server started on",global.port)});$StaticPool$$=require("cluster");$StaticPool$$.on("exit",function($worker$$,$code$$,$signal$$){Logger.error("[app] worker "+$worker$$.process.pid+" died",$code$$,$signal$$)});$StaticPool$$.on("online",function($worker$$){console.info("[app] worker "+$worker$$.process.pid+" is online")})}else $cpus_report_cpus_server_sslConfig$$.listen(global.port,()=>{Logger.info("[app] server start at "+
17
- global.port+" port")})}$cpus_report_cpus_server_sslConfig$$=os.cpus().length;$StaticPool$$=$options$$.import_cpus||($options$$.start_import_data_pool?$options$$.start_report_pool||$options$$.start_input_data_pool?1:Math.round($cpus_report_cpus_server_sslConfig$$/2):0);var $StaticPool$jscomp$0$$=$options$$.input_cpus||($options$$.start_input_data_pool?Math.max(Math.round($cpus_report_cpus_server_sslConfig$$/2),2):0);$cpus_report_cpus_server_sslConfig$$=$options$$.report_cpus||($options$$.start_import_data_pool?
18
- Math.max(Math.min($cpus_report_cpus_server_sslConfig$$-$StaticPool$jscomp$0$$-$StaticPool$$,Math.round($cpus_report_cpus_server_sslConfig$$/2))-1,2):0);const $timeout_input$$=$options$$.timeout_input||$options$$.timeout||3E5,$timeout_import$$=$options$$.timeout_import||$options$$.timeout||36E5,$timeout_report$$=$options$$.timeout_report||$options$$.timeout||3E5;if($StaticPool$jscomp$0$$){const $StaticPool$$=require("./libs/WorkerStaticPool");global.inputMainPool=new $StaticPool$$(__dirname+"/workers/inputWorker.js",
19
- $options$$.max_queue_imports||0,$StaticPool$jscomp$0$$,$timeout_input$$,$StaticPool$jscomp$0$$,"input pool");global.inputMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{Logger.info("\ud83d\udd25 [app] Crud pool ready")})}$StaticPool$$&&($StaticPool$jscomp$0$$=require("./libs/WorkerStaticPool"),global.importDataMainPool=new $StaticPool$jscomp$0$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||0,$StaticPool$$,$timeout_import$$,1,"import pool"),global.importDataMainPool.exec({load:!0,
20
- configs:JSON.stringify($configs$$)},()=>{Logger.info("[app] Import pool ready")}));$cpus_report_cpus_server_sslConfig$$&&($StaticPool$$=require("./libs/WorkerStaticPool"),global.reportMainPool=new $StaticPool$$(__dirname+"/workers/reportWorker.js",$options$$.max_queue_reports||0,$cpus_report_cpus_server_sslConfig$$,$timeout_report$$,2,"report pool"),global.reportMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{Logger.info("[app] Report pool ready")}));$callbackServer$$&&$callbackServer$$()})}else require("./route")($app$$,
14
+ global.clientRedis.on("connect",function(){Logger.info("[app] redis connected");$User$$.initClientSockets();if($options$$.lite!==!0){$options$$.createRedisCache&&require("./libs/redis-cache").set();global.getModel("schedule").start();const {recoverBackgroundTasks:$recoverBackgroundTasks$$}=require("./libs/optimizeBookkeeping");$recoverBackgroundTasks$$().catch(console.error);require("./route")($app$$,()=>{if($options$$.createServer!==!1){var $StaticPool$$=require("sticky-session");if($configs$$.use_ssl&&
15
+ $options$$.sslDir){var $cpus_report_cpus_server_sslConfig$$=require("./sslConfig");$cpus_report_cpus_server_sslConfig$$=https.createServer($cpus_report_cpus_server_sslConfig$$($options$$.sslDir),$app$$)}else $cpus_report_cpus_server_sslConfig$$=http.createServer($app$$);$cpus_report_cpus_server_sslConfig$$.timeout=6E5;$options$$.useSocket!==!1&&$User$$.initSocket($cpus_report_cpus_server_sslConfig$$);if($options$$.cluster!==!1){if(!$StaticPool$$.listen($cpus_report_cpus_server_sslConfig$$,global.port))$cpus_report_cpus_server_sslConfig$$.once("listening",
16
+ function(){Logger.info("[app] server started on",global.port)});$StaticPool$$=require("cluster");$StaticPool$$.on("exit",function($worker$$,$code$$,$signal$$){Logger.error("[app] worker "+$worker$$.process.pid+" died",$code$$,$signal$$)});$StaticPool$$.on("online",function($worker$$){console.info("[app] worker "+$worker$$.process.pid+" is online")})}else $cpus_report_cpus_server_sslConfig$$.listen(global.port,()=>{Logger.info("[app] server start at "+global.port+" port")})}$cpus_report_cpus_server_sslConfig$$=
17
+ os.cpus().length;$StaticPool$$=$options$$.import_cpus||($options$$.start_import_data_pool?$options$$.start_report_pool||$options$$.start_input_data_pool?1:Math.round($cpus_report_cpus_server_sslConfig$$/2):0);var $StaticPool$jscomp$0$$=$options$$.input_cpus||($options$$.start_input_data_pool?Math.max(Math.round($cpus_report_cpus_server_sslConfig$$/2),2):0);$cpus_report_cpus_server_sslConfig$$=$options$$.report_cpus||($options$$.start_import_data_pool?Math.max(Math.min($cpus_report_cpus_server_sslConfig$$-
18
+ $StaticPool$jscomp$0$$-$StaticPool$$,Math.round($cpus_report_cpus_server_sslConfig$$/2))-1,2):0);const $timeout_input$$=$options$$.timeout_input||$options$$.timeout||3E5,$timeout_import$$=$options$$.timeout_import||$options$$.timeout||36E5,$timeout_report$$=$options$$.timeout_report||$options$$.timeout||3E5;if($StaticPool$jscomp$0$$){const $StaticPool$$=require("./libs/WorkerStaticPool");global.inputMainPool=new $StaticPool$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||0,$StaticPool$jscomp$0$$,
19
+ $timeout_input$$,$StaticPool$jscomp$0$$,"input pool");global.inputMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{Logger.info("\ud83d\udd25 [app] Crud pool ready")})}$StaticPool$$&&($StaticPool$jscomp$0$$=require("./libs/WorkerStaticPool"),global.importDataMainPool=new $StaticPool$jscomp$0$$(__dirname+"/workers/inputWorker.js",$options$$.max_queue_imports||0,$StaticPool$$,$timeout_import$$,1,"import pool"),global.importDataMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},
20
+ ()=>{Logger.info("[app] Import pool ready")}));$cpus_report_cpus_server_sslConfig$$&&($StaticPool$$=require("./libs/WorkerStaticPool"),global.reportMainPool=new $StaticPool$$(__dirname+"/workers/reportWorker.js",$options$$.max_queue_reports||0,$cpus_report_cpus_server_sslConfig$$,$timeout_report$$,2,"report pool"),global.reportMainPool.exec({load:!0,configs:JSON.stringify($configs$$)},()=>{Logger.info("[app] Report pool ready")}));$callbackServer$$&&$callbackServer$$()})}else require("./route")($app$$,
21
21
  ()=>{$callbackServer$$&&$callbackServer$$()},!0)})}).catch($err$$=>{Logger.info("[app] Not Connected to Database ERROR! ",$err$$);process.exit(1)});return $app$$};process.on("SIGINT",async()=>{global.sharedRedisConnection&&await global.sharedRedisConnection.quit();process.exit(0)});
22
22
  process.on("uncaughtException",function($err$jscomp$3_error$$){Logger.error((new Date).toUTCString()+" uncaughtException:",$err$jscomp$3_error$$.message);Logger.error($err$jscomp$3_error$$.stack);$err$jscomp$3_error$$=`
23
23
  Error: ${$err$jscomp$3_error$$.message}