gm-mcp 1.1.2 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -69,8 +69,10 @@ exports.server.tool("statistic_salary_x3_in_range", "Get statistic salary x3 wit
69
69
  sendMessageToLark: (0, env_1.getEnv)().SEND_MESSAGE_TO_LARK,
70
70
  });
71
71
  }));
72
- exports.server.tool("debt_collection_by_month", "The company's debt collection rate by month", {
73
- month: zod_1.default.string({ description: "Month to get data, month must be represented with format MM/yyyy" }),
72
+ exports.server.tool("debt_collection_by_month", "The company's debt collection information by month", {
73
+ month: zod_1.default.string({
74
+ description: "Month to get data,if year is not provided, please use current year (in Vietnam timezone) instead of, month must be represented with format MM/yyyy",
75
+ }),
74
76
  company_name: zod_1.default.string({ description: "Company name to get data" }),
75
77
  }, (args) => __awaiter(void 0, void 0, void 0, function* () {
76
78
  const { month, company_name } = args;
@@ -1,5 +1,15 @@
1
1
  import { LarkRecord } from "./types/lark.type";
2
- export declare function fetchReportRecords(p: {
2
+ export declare function fetchLarkBaseRecords(p: {
3
3
  view_id: string;
4
4
  field_names: string[];
5
- }): Promise<LarkRecord[]>;
5
+ app_token: string;
6
+ table_id: string;
7
+ page_size: number;
8
+ page_token?: string;
9
+ }): Promise<{
10
+ items: LarkRecord[];
11
+ page_token: string;
12
+ has_more: boolean;
13
+ total: number;
14
+ }>;
15
+ export declare function fetchDebtCollectionRecords(page_token?: string): Promise<LarkRecord[]>;
@@ -12,22 +12,48 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.fetchReportRecords = fetchReportRecords;
15
+ exports.fetchLarkBaseRecords = fetchLarkBaseRecords;
16
+ exports.fetchDebtCollectionRecords = fetchDebtCollectionRecords;
16
17
  const axios_1 = __importDefault(require("axios"));
17
18
  const lark_service_1 = require("./lark.service");
18
- function fetchReportRecords(p) {
19
+ const report_columns_1 = require("./constants/report-columns");
20
+ // Must replace by env config later
21
+ const DEBT_COLLECTION_VIEW_ID = "vewI23hNnx";
22
+ const DEBT_COLLECTION_TABLE_ID = "tblQGKjGd8MnK5qs";
23
+ const DEBT_COLLECTION_APP_TOKEN = "V5akbIXqfaBvXqs8twfl6rALgLd";
24
+ function fetchLarkBaseRecords(p) {
19
25
  return __awaiter(this, void 0, void 0, function* () {
20
26
  const access_token = yield (0, lark_service_1.getLarkTenantAccessToken)();
27
+ const { view_id, table_id, app_token, field_names, page_size, page_token } = p;
21
28
  const appToken = "V5akbIXqfaBvXqs8twfl6rALgLd";
22
29
  const tableId = "tblQGKjGd8MnK5qs";
23
- const url = `https://open.larksuite.com/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records/search`;
30
+ const url = `https://open.larksuite.com/open-apis/bitable/v1/apps/${app_token}/tables/${table_id}/records/search`;
24
31
  return axios_1.default
25
- .post(url, p, {
26
- params: { page_size: 500 },
32
+ .post(url, { view_id, field_names }, {
33
+ params: { page_size, page_token },
27
34
  headers: {
28
35
  Authorization: "Bearer " + access_token,
29
36
  },
30
37
  })
31
- .then((res) => res.data.data.items);
38
+ .then((res) => res.data.data);
39
+ });
40
+ }
41
+ function fetchDebtCollectionRecords(page_token) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const fieldNames = report_columns_1.REPORT_COLUMS.map((item) => item.field_name);
44
+ const { has_more, items, page_token: nextPageToken, total, } = yield fetchLarkBaseRecords({
45
+ view_id: DEBT_COLLECTION_VIEW_ID,
46
+ field_names: fieldNames,
47
+ app_token: DEBT_COLLECTION_APP_TOKEN,
48
+ table_id: DEBT_COLLECTION_TABLE_ID,
49
+ page_size: 500,
50
+ page_token: page_token,
51
+ });
52
+ console.log(total);
53
+ if (!has_more) {
54
+ return items;
55
+ }
56
+ const result = [...items];
57
+ return result.concat(yield fetchDebtCollectionRecords(nextPageToken));
32
58
  });
33
59
  }
package/dist/test.js CHANGED
@@ -14,9 +14,11 @@ const lark_tool_1 = require("./tools/lark-tool");
14
14
  function setupTest() {
15
15
  return __awaiter(this, void 0, void 0, function* () {
16
16
  (0, env_1.ensureEnvVariables)();
17
- const compnay = "BGG";
18
- const month = "12/2025";
19
- const res = yield (0, lark_tool_1.debtCollectionRateTool)({ sendMessageToLark: false, companyName: compnay, monthDate: month });
17
+ // const r = await fetchDebtCollectionRecords();
18
+ // console.log(r.length);
19
+ // const compnay = "BGG";
20
+ // const month = "12/2025";
21
+ const res = yield (0, lark_tool_1.debtCollectionRateTool)({ sendMessageToLark: true, companyName: 'SHYANG', monthDate: '07/2025' });
20
22
  console.log(res);
21
23
  // const fieldNames = REPORT_COLUMS.map((item) => item.field_name);
22
24
  // try {
@@ -18,8 +18,13 @@ const lark_service_1 = require("../services/lark.service");
18
18
  const companyKey = "CÔNG TY";
19
19
  const preiodKey = "KỲ LƯƠNG";
20
20
  const debtCollectionRateKey = "TỈ LỆ THU NỢ";
21
+ const debReductionMonthKey = "THÁNG CẮT NỢ";
22
+ const productKey = "Loại Sản phẩm";
23
+ const monthReductionDebtKey = "THÁNG CẮT NỢ";
24
+ const statusKey = "TRẠNG THÁI";
21
25
  function debtCollectionRateTool(options) {
22
26
  return __awaiter(this, void 0, void 0, function* () {
27
+ var _c, _d;
23
28
  const { sendMessageToLark, companyName, monthDate } = options;
24
29
  const monthParts = (0, helpers_1.extractMonth)(monthDate);
25
30
  if (monthParts === null) {
@@ -28,28 +33,39 @@ function debtCollectionRateTool(options) {
28
33
  const { month, year } = monthParts;
29
34
  const fieldNames = report_columns_1.REPORT_COLUMS.map((item) => item.field_name);
30
35
  try {
31
- const records = yield (0, lark_base_service_1.fetchReportRecords)({ view_id: "vewI23hNnx", field_names: fieldNames });
36
+ const records = yield (0, lark_base_service_1.fetchDebtCollectionRecords)();
32
37
  // console.log(records);
33
38
  // Find by name first
34
- const companyNames = records.map((item) => (item.fields["CÔNG TY"] || ""));
39
+ const companyNames = records.map((item) => (item.fields[companyKey] || ""));
35
40
  // console.log(companyNames);
36
41
  // const searchTems = "DENKO";
37
42
  // const monthTerm = "12";
38
43
  const foundName = (0, search_like_1.searchLike)(companyName, companyNames)[0];
39
- const companiesMatchName = records.filter((item) => item.fields["CÔNG TY"] === foundName);
44
+ const companiesMatchName = records.filter((item) => item.fields[companyKey] === foundName);
40
45
  // console.log(companiesMatchName);
41
- // Find by pay period
46
+ // Find by debt reduction month, search fully match
47
+ const foundMonths = companiesMatchName.filter((item) => compareReductionDebtMonth(item.fields[debReductionMonthKey], month.toString()));
42
48
  const foundMonth = (0, search_like_1.searchLike)(month.toString(), companiesMatchName.map((item) => item.fields["KỲ LƯƠNG"]))[0];
43
- console.log(foundMonth);
49
+ console.log(foundMonths);
44
50
  const finalCompnay = companiesMatchName.find((item) => item.fields["KỲ LƯƠNG"] === foundMonth);
51
+ // console.log(finalCompnay);
52
+ const messages = [];
53
+ for (const item of foundMonths) {
54
+ messages.push([
55
+ `Sản phẩm: ${item.fields[productKey] || "N/A"}`,
56
+ `Kỳ lương: ${(item === null || item === void 0 ? void 0 : item.fields[preiodKey]) || "N/A"}`,
57
+ `Tr.thái cắt nợ: ${((_d = (_c = item === null || item === void 0 ? void 0 : item.fields[statusKey]) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.text) || "N/A"}`,
58
+ `Tháng cắt nợ: ${item.fields[monthReductionDebtKey] || "N/A"}`,
59
+ `Tỷ lệ thu nợ: ${typeof item.fields[debtCollectionRateKey] === "undefined"
60
+ ? "N/A"
61
+ : round(Number(item.fields[debtCollectionRateKey])) + "%"}`,
62
+ ].join("<br>"));
63
+ }
64
+ // return {} as any;
45
65
  if (sendMessageToLark) {
46
66
  yield (0, lark_service_1.sendReportOpsGroup)({
47
- title: "Tỉ lệ thu nợ",
48
- message_content: [
49
- `Công ty: ${(finalCompnay === null || finalCompnay === void 0 ? void 0 : finalCompnay.fields[companyKey]) || "N/A"}`,
50
- `Kỳ lương: ${(finalCompnay === null || finalCompnay === void 0 ? void 0 : finalCompnay.fields[preiodKey]) || "N/A"}`,
51
- `Tỷ lệ thu nợ: ${Number(finalCompnay === null || finalCompnay === void 0 ? void 0 : finalCompnay.fields[debtCollectionRateKey]) * 100}%`,
52
- ].join("<hr>"),
67
+ title: `Tỉ lệ thu nợ - ${foundName}`,
68
+ message_content: messages.join("<hr>"),
53
69
  });
54
70
  }
55
71
  return { content: [{ type: "text", text: JSON.stringify(finalCompnay) }] };
@@ -60,3 +76,11 @@ function debtCollectionRateTool(options) {
60
76
  }
61
77
  });
62
78
  }
79
+ function compareReductionDebtMonth(a, b) {
80
+ const _a = a.toLowerCase().trim().replace("tháng", "");
81
+ const _b = b.toLowerCase().trim().replace("tháng", "");
82
+ return parseInt(_a, 10) === parseInt(_b, 10);
83
+ }
84
+ function round(x) {
85
+ return Math.round(x * 10000) / 100;
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gm-mcp",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "Mcp server for Gm",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/index.ts CHANGED
@@ -91,9 +91,12 @@ server.tool(
91
91
 
92
92
  server.tool(
93
93
  "debt_collection_by_month",
94
- "The company's debt collection rate by month",
94
+ "The company's debt collection information by month",
95
95
  {
96
- month: z.string({ description: "Month to get data, month must be represented with format MM/yyyy" }),
96
+ month: z.string({
97
+ description:
98
+ "Month to get data,if year is not provided, please use current year (in Vietnam timezone) instead of, month must be represented with format MM/yyyy",
99
+ }),
97
100
  company_name: z.string({ description: "Company name to get data" }),
98
101
  },
99
102
  async (args) => {
@@ -1,18 +1,60 @@
1
1
  import axios from "axios";
2
2
  import { LarkRecord } from "./types/lark.type";
3
3
  import { getLarkTenantAccessToken } from "./lark.service";
4
+ import { REPORT_COLUMS } from "./constants/report-columns";
4
5
 
5
- export async function fetchReportRecords(p: { view_id: string; field_names: string[] }) {
6
+ // Must replace by env config later
7
+ const DEBT_COLLECTION_VIEW_ID = "vewI23hNnx";
8
+ const DEBT_COLLECTION_TABLE_ID = "tblQGKjGd8MnK5qs";
9
+ const DEBT_COLLECTION_APP_TOKEN = "V5akbIXqfaBvXqs8twfl6rALgLd";
10
+
11
+ export async function fetchLarkBaseRecords(p: {
12
+ view_id: string;
13
+ field_names: string[];
14
+ app_token: string;
15
+ table_id: string;
16
+ page_size: number;
17
+ page_token?: string;
18
+ }) {
6
19
  const access_token = await getLarkTenantAccessToken();
20
+ const { view_id, table_id, app_token, field_names, page_size, page_token } = p;
7
21
  const appToken = "V5akbIXqfaBvXqs8twfl6rALgLd";
8
22
  const tableId = "tblQGKjGd8MnK5qs";
9
- const url = `https://open.larksuite.com/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records/search`;
23
+ const url = `https://open.larksuite.com/open-apis/bitable/v1/apps/${app_token}/tables/${table_id}/records/search`;
10
24
  return axios
11
- .post<{ data: { items: LarkRecord[] } }>(url, p, {
12
- params: { page_size: 500 },
13
- headers: {
14
- Authorization: "Bearer " + access_token,
15
- },
16
- })
17
- .then((res) => res.data.data.items);
25
+ .post<{ data: { items: LarkRecord[]; page_token: string; has_more: boolean; total: number } }>(
26
+ url,
27
+ { view_id, field_names },
28
+ {
29
+ params: { page_size, page_token },
30
+ headers: {
31
+ Authorization: "Bearer " + access_token,
32
+ },
33
+ }
34
+ )
35
+ .then((res) => res.data.data);
36
+ }
37
+
38
+ export async function fetchDebtCollectionRecords(page_token?: string): Promise<LarkRecord[]> {
39
+ const fieldNames = REPORT_COLUMS.map((item) => item.field_name);
40
+ const {
41
+ has_more,
42
+ items,
43
+ page_token: nextPageToken,
44
+ total,
45
+ } = await fetchLarkBaseRecords({
46
+ view_id: DEBT_COLLECTION_VIEW_ID,
47
+ field_names: fieldNames,
48
+ app_token: DEBT_COLLECTION_APP_TOKEN,
49
+ table_id: DEBT_COLLECTION_TABLE_ID,
50
+ page_size: 500,
51
+ page_token: page_token,
52
+ });
53
+ console.log(total);
54
+
55
+ if (!has_more) {
56
+ return items;
57
+ }
58
+ const result: LarkRecord[] = [...items];
59
+ return result.concat(await fetchDebtCollectionRecords(nextPageToken));
18
60
  }
package/src/test.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ensureEnvVariables, getEnv } from "./env";
2
2
  import { searchLike } from "./helpers/search-like";
3
3
  import { REPORT_COLUMS } from "./services/constants/report-columns";
4
- import { fetchReportRecords } from "./services/lark-base.service";
4
+ import { fetchDebtCollectionRecords, fetchLarkBaseRecords } from "./services/lark-base.service";
5
5
  import { sendLarkTextMessage, sendMessageToX3Group } from "./services/lark.service";
6
6
  import {
7
7
  statisticX3RangeTool,
@@ -14,9 +14,13 @@ import { debtCollectionRateTool } from "./tools/lark-tool";
14
14
 
15
15
  async function setupTest() {
16
16
  ensureEnvVariables();
17
- const compnay = "BGG";
18
- const month = "12/2025";
19
- const res = await debtCollectionRateTool({ sendMessageToLark: false, companyName: compnay, monthDate: month });
17
+
18
+ // const r = await fetchDebtCollectionRecords();
19
+ // console.log(r.length);
20
+
21
+ // const compnay = "BGG";
22
+ // const month = "12/2025";
23
+ const res = await debtCollectionRateTool({ sendMessageToLark: true, companyName: 'SHYANG', monthDate: '07/2025' });
20
24
  console.log(res);
21
25
 
22
26
  // const fieldNames = REPORT_COLUMS.map((item) => item.field_name);
@@ -2,12 +2,16 @@ import { CallToolResult } from "@modelcontextprotocol/sdk/types";
2
2
  import { extractMonth } from "../helpers";
3
3
  import { searchLike } from "../helpers/search-like";
4
4
  import { REPORT_COLUMS } from "../services/constants/report-columns";
5
- import { fetchReportRecords } from "../services/lark-base.service";
5
+ import { fetchDebtCollectionRecords, fetchLarkBaseRecords } from "../services/lark-base.service";
6
6
  import { sendReportOpsGroup } from "../services/lark.service";
7
7
 
8
8
  const companyKey = "CÔNG TY";
9
9
  const preiodKey = "KỲ LƯƠNG";
10
10
  const debtCollectionRateKey = "TỈ LỆ THU NỢ";
11
+ const debReductionMonthKey = "THÁNG CẮT NỢ";
12
+ const productKey = "Loại Sản phẩm";
13
+ const monthReductionDebtKey = "THÁNG CẮT NỢ";
14
+ const statusKey = "TRẠNG THÁI";
11
15
 
12
16
  export async function debtCollectionRateTool(options: {
13
17
  sendMessageToLark: boolean;
@@ -22,34 +26,53 @@ export async function debtCollectionRateTool(options: {
22
26
  const { month, year } = monthParts;
23
27
  const fieldNames = REPORT_COLUMS.map((item) => item.field_name);
24
28
  try {
25
- const records = await fetchReportRecords({ view_id: "vewI23hNnx", field_names: fieldNames });
29
+ const records = await fetchDebtCollectionRecords();
26
30
  // console.log(records);
27
31
 
28
32
  // Find by name first
29
- const companyNames = records.map((item) => (item.fields["CÔNG TY"] || "") as string);
33
+ const companyNames = records.map((item) => (item.fields[companyKey] || "") as string);
30
34
  // console.log(companyNames);
31
35
  // const searchTems = "DENKO";
32
36
  // const monthTerm = "12";
33
37
  const foundName = searchLike(companyName, companyNames)[0];
34
- const companiesMatchName = records.filter((item) => item.fields["CÔNG TY"] === foundName);
38
+ const companiesMatchName = records.filter((item) => item.fields[companyKey] === foundName);
35
39
  // console.log(companiesMatchName);
36
40
 
37
- // Find by pay period
41
+ // Find by debt reduction month, search fully match
42
+ const foundMonths = companiesMatchName.filter((item) =>
43
+ compareReductionDebtMonth(item.fields[debReductionMonthKey], month.toString())
44
+ );
38
45
  const foundMonth = searchLike(
39
46
  month.toString(),
40
47
  companiesMatchName.map((item) => item.fields["KỲ LƯƠNG"])
41
48
  )[0];
42
- console.log(foundMonth);
49
+ console.log(foundMonths);
43
50
  const finalCompnay = companiesMatchName.find((item) => item.fields["KỲ LƯƠNG"] === foundMonth);
51
+ // console.log(finalCompnay);
52
+
53
+ const messages: string[] = [];
54
+ for (const item of foundMonths) {
55
+ messages.push(
56
+ [
57
+ `Sản phẩm: ${item.fields[productKey] || "N/A"}`,
58
+ `Kỳ lương: ${item?.fields[preiodKey] || "N/A"}`,
59
+ `Tr.thái cắt nợ: ${item?.fields[statusKey]?.[0]?.text || "N/A"}`,
60
+ `Tháng cắt nợ: ${item.fields[monthReductionDebtKey] || "N/A"}`,
61
+ `Tỷ lệ thu nợ: ${
62
+ typeof item.fields[debtCollectionRateKey] === "undefined"
63
+ ? "N/A"
64
+ : round(Number(item.fields[debtCollectionRateKey])) + "%"
65
+ }`,
66
+ ].join("<br>")
67
+ );
68
+ }
69
+
70
+ // return {} as any;
44
71
 
45
72
  if (sendMessageToLark) {
46
73
  await sendReportOpsGroup({
47
- title: "Tỉ lệ thu nợ",
48
- message_content: [
49
- `Công ty: ${finalCompnay?.fields[companyKey] || "N/A"}`,
50
- `Kỳ lương: ${finalCompnay?.fields[preiodKey] || "N/A"}`,
51
- `Tỷ lệ thu nợ: ${Number(finalCompnay?.fields[debtCollectionRateKey]) * 100}%`,
52
- ].join("<hr>"),
74
+ title: `Tỉ lệ thu nợ - ${foundName}`,
75
+ message_content: messages.join("<hr>"),
53
76
  });
54
77
  }
55
78
  return { content: [{ type: "text", text: JSON.stringify(finalCompnay) }] };
@@ -58,3 +81,13 @@ export async function debtCollectionRateTool(options: {
58
81
  return { content: [{ type: "text", text: JSON.stringify(e) }] };
59
82
  }
60
83
  }
84
+
85
+ function compareReductionDebtMonth(a: string, b: string) {
86
+ const _a = a.toLowerCase().trim().replace("tháng", "");
87
+ const _b = b.toLowerCase().trim().replace("tháng", "");
88
+ return parseInt(_a, 10) === parseInt(_b, 10);
89
+ }
90
+
91
+ function round(x: number) {
92
+ return Math.round(x * 10000) / 100;
93
+ }