gm-mcp 2.0.6 → 2.0.8
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 +2 -2
- package/dist/services/gimo.service.d.ts +18 -3
- package/dist/services/gimo.service.js +66 -8
- package/dist/services/types/pay-period.d.ts +11 -0
- package/dist/services/types/status-change.d.ts +10 -0
- package/dist/services/types/status-change.js +2 -0
- package/dist/tools/eligibility-tools.d.ts +7 -0
- package/dist/tools/eligibility-tools.js +168 -0
- package/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/services/gimo.service.ts +68 -9
- package/src/services/types/pay-period.ts +12 -0
- package/src/services/types/status-change.ts +11 -0
- package/src/tools/{accessible-tools.ts → eligibility-tools.ts} +52 -16
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ const tools_1 = require("./tools");
|
|
|
20
20
|
const zod_1 = __importDefault(require("zod"));
|
|
21
21
|
const env_1 = require("./env");
|
|
22
22
|
const lark_tool_1 = require("./tools/lark-tool");
|
|
23
|
-
const
|
|
23
|
+
const eligibility_tools_1 = require("./tools/eligibility-tools");
|
|
24
24
|
exports.server = new mcp_js_1.McpServer({
|
|
25
25
|
name: "mcp-server",
|
|
26
26
|
version: "1.0.0",
|
|
@@ -85,7 +85,7 @@ exports.server.tool("check_eligibility", "Check customer's eligibility for salar
|
|
|
85
85
|
phone_number: zod_1.default.string({ description: "Customer's phone number" }),
|
|
86
86
|
}, (args) => __awaiter(void 0, void 0, void 0, function* () {
|
|
87
87
|
const { phone_number } = args;
|
|
88
|
-
return (0,
|
|
88
|
+
return (0, eligibility_tools_1.elgibilityTool)(phone_number);
|
|
89
89
|
}));
|
|
90
90
|
function bootstap() {
|
|
91
91
|
(0, env_1.ensureEnvVariables)();
|
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import { Gimo } from "./types";
|
|
2
|
-
import { PayPeriod } from "./types/pay-period";
|
|
2
|
+
import { PayPeriod, PayperiodInfo } from "./types/pay-period";
|
|
3
3
|
import { TimeSheet } from "./types/time-keeper";
|
|
4
|
+
import { CustomerEwaStatusChangeLogs } from "./types/status-change";
|
|
4
5
|
export declare function getAccessToken(): Promise<string>;
|
|
5
|
-
export declare function findCustomerEWAByPhonenumber(phoneNumber: string
|
|
6
|
+
export declare function findCustomerEWAByPhonenumber(phoneNumber: string, options?: {
|
|
7
|
+
accessToken?: string;
|
|
8
|
+
}): Promise<Gimo.CustomerEWA | null>;
|
|
6
9
|
export declare function getPayPeriods(params: {
|
|
7
10
|
orgId: number;
|
|
8
11
|
parnterId: number;
|
|
12
|
+
}, options?: {
|
|
13
|
+
accessToken?: string;
|
|
9
14
|
}): Promise<PayPeriod[]>;
|
|
10
15
|
export declare function getTimeSheets(params: {
|
|
11
16
|
payPeriodId: number;
|
|
12
17
|
employeeId: number;
|
|
18
|
+
}, options?: {
|
|
19
|
+
accessToken?: string;
|
|
13
20
|
}): Promise<TimeSheet[]>;
|
|
14
|
-
export declare function getEmployeeByCustomerId(customerId: number
|
|
21
|
+
export declare function getEmployeeByCustomerId(customerId: number, options?: {
|
|
22
|
+
accessToken?: string;
|
|
23
|
+
}): Promise<Gimo.EmployeeInfo>;
|
|
15
24
|
export declare function findCustomerEWAById(id: number): Promise<Gimo.CustomerEWA>;
|
|
25
|
+
export declare function getCustomerStatusChange(ewaCustomerId: number, options?: {
|
|
26
|
+
accessToken?: string;
|
|
27
|
+
}): Promise<CustomerEwaStatusChangeLogs[]>;
|
|
28
|
+
export declare function getCurrentPayperiodInfo(payPeriodId: number, options?: {
|
|
29
|
+
accessToken?: string;
|
|
30
|
+
}): Promise<PayperiodInfo>;
|
|
@@ -18,6 +18,8 @@ exports.getPayPeriods = getPayPeriods;
|
|
|
18
18
|
exports.getTimeSheets = getTimeSheets;
|
|
19
19
|
exports.getEmployeeByCustomerId = getEmployeeByCustomerId;
|
|
20
20
|
exports.findCustomerEWAById = findCustomerEWAById;
|
|
21
|
+
exports.getCustomerStatusChange = getCustomerStatusChange;
|
|
22
|
+
exports.getCurrentPayperiodInfo = getCurrentPayperiodInfo;
|
|
21
23
|
const axios_1 = __importDefault(require("axios"));
|
|
22
24
|
const env_1 = require("../env");
|
|
23
25
|
function getAccessToken() {
|
|
@@ -31,10 +33,15 @@ function getAccessToken() {
|
|
|
31
33
|
.then((res) => res.data.access_token);
|
|
32
34
|
});
|
|
33
35
|
}
|
|
34
|
-
function findCustomerEWAByPhonenumber(phoneNumber) {
|
|
36
|
+
function findCustomerEWAByPhonenumber(phoneNumber, options) {
|
|
35
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
const { accessToken } = options || {};
|
|
39
|
+
let access_token = accessToken;
|
|
40
|
+
if (!access_token) {
|
|
41
|
+
access_token = yield getAccessToken();
|
|
42
|
+
}
|
|
36
43
|
const customerApiUrl = `${(0, env_1.getEnv)().DASH_URL}/api/v1/admin/customers/ewa/pagination`;
|
|
37
|
-
const access_token =
|
|
44
|
+
// const access_token = await getAccessToken();
|
|
38
45
|
// Find inlist
|
|
39
46
|
const customers = yield axios_1.default
|
|
40
47
|
.get(customerApiUrl, {
|
|
@@ -53,11 +60,16 @@ function findCustomerEWAByPhonenumber(phoneNumber) {
|
|
|
53
60
|
return findCustomerEWAById(foundedCustomer.customer_id);
|
|
54
61
|
});
|
|
55
62
|
}
|
|
56
|
-
function getPayPeriods(params) {
|
|
63
|
+
function getPayPeriods(params, options) {
|
|
57
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
65
|
const { orgId, parnterId } = params;
|
|
66
|
+
const { accessToken } = options || {};
|
|
67
|
+
let access_token = accessToken;
|
|
68
|
+
if (!access_token) {
|
|
69
|
+
access_token = yield getAccessToken();
|
|
70
|
+
}
|
|
59
71
|
const url = `${(0, env_1.getEnv)().DASH_URL}/api/v1/admin/partners/${parnterId}/pay-periods`;
|
|
60
|
-
const access_token =
|
|
72
|
+
// const access_token = await getAccessToken();
|
|
61
73
|
const customer = yield axios_1.default
|
|
62
74
|
.get(url, {
|
|
63
75
|
headers: {
|
|
@@ -73,11 +85,15 @@ function getPayPeriods(params) {
|
|
|
73
85
|
return customer || null;
|
|
74
86
|
});
|
|
75
87
|
}
|
|
76
|
-
function getTimeSheets(params) {
|
|
88
|
+
function getTimeSheets(params, options) {
|
|
77
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
78
90
|
const { payPeriodId, employeeId } = params;
|
|
91
|
+
const { accessToken } = options || {};
|
|
92
|
+
let access_token = accessToken;
|
|
93
|
+
if (!access_token) {
|
|
94
|
+
access_token = yield getAccessToken();
|
|
95
|
+
}
|
|
79
96
|
const url = `${(0, env_1.getEnv)().DASH_URL}/api/v2/admin/time-sheets/by-period`;
|
|
80
|
-
const access_token = yield getAccessToken();
|
|
81
97
|
const customer = yield axios_1.default
|
|
82
98
|
.get(url, {
|
|
83
99
|
headers: {
|
|
@@ -93,10 +109,14 @@ function getTimeSheets(params) {
|
|
|
93
109
|
return customer || null;
|
|
94
110
|
});
|
|
95
111
|
}
|
|
96
|
-
function getEmployeeByCustomerId(customerId) {
|
|
112
|
+
function getEmployeeByCustomerId(customerId, options) {
|
|
97
113
|
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
const { accessToken } = options || {};
|
|
115
|
+
let access_token = accessToken;
|
|
116
|
+
if (!access_token) {
|
|
117
|
+
access_token = yield getAccessToken();
|
|
118
|
+
}
|
|
98
119
|
const url = `${(0, env_1.getEnv)().DASH_URL}/api/v1/admin/customers/${customerId}/employee-info`;
|
|
99
|
-
const access_token = yield getAccessToken();
|
|
100
120
|
const customer = yield axios_1.default
|
|
101
121
|
.get(url, {
|
|
102
122
|
headers: {
|
|
@@ -124,3 +144,41 @@ function findCustomerEWAById(id) {
|
|
|
124
144
|
return customer || null;
|
|
125
145
|
});
|
|
126
146
|
}
|
|
147
|
+
function getCustomerStatusChange(ewaCustomerId, options) {
|
|
148
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
const { accessToken } = options || {};
|
|
150
|
+
let access_token = accessToken;
|
|
151
|
+
if (!access_token) {
|
|
152
|
+
access_token = yield getAccessToken();
|
|
153
|
+
}
|
|
154
|
+
const url = `${(0, env_1.getEnv)().DASH_URL}/api/v1/admin/customers/ewa/${ewaCustomerId}/status/changes`;
|
|
155
|
+
const res = yield axios_1.default
|
|
156
|
+
.get(url, {
|
|
157
|
+
headers: {
|
|
158
|
+
Authorization: "Bearer " + access_token,
|
|
159
|
+
},
|
|
160
|
+
})
|
|
161
|
+
.then((res) => res.data);
|
|
162
|
+
// Select first customer
|
|
163
|
+
return res;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function getCurrentPayperiodInfo(payPeriodId, options) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
const { accessToken } = options || {};
|
|
169
|
+
let access_token = accessToken;
|
|
170
|
+
if (!access_token) {
|
|
171
|
+
access_token = yield getAccessToken();
|
|
172
|
+
}
|
|
173
|
+
const url = `${(0, env_1.getEnv)().DASH_URL}/api/v1/admin/employees/${payPeriodId}/current-pay-period-info`;
|
|
174
|
+
const res = yield axios_1.default
|
|
175
|
+
.get(url, {
|
|
176
|
+
headers: {
|
|
177
|
+
Authorization: "Bearer " + access_token,
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
.then((res) => res.data);
|
|
181
|
+
// Select first customer
|
|
182
|
+
return res;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
@@ -39,3 +39,14 @@ export interface Config {
|
|
|
39
39
|
version_number: number;
|
|
40
40
|
previous_config_id: any;
|
|
41
41
|
}
|
|
42
|
+
export interface PayperiodInfo {
|
|
43
|
+
month: number;
|
|
44
|
+
year: number;
|
|
45
|
+
worked_days: number;
|
|
46
|
+
standard_work_days: number;
|
|
47
|
+
work_days: number;
|
|
48
|
+
earned_amount: number;
|
|
49
|
+
advanced_amount: number;
|
|
50
|
+
accessible_amount: number;
|
|
51
|
+
has_income_from_attendance: boolean;
|
|
52
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types";
|
|
2
|
+
export declare const DEBT_COLLECTION_TYPE: {
|
|
3
|
+
readonly PARTNER_IN_CHARGE: "PARTNER_IN_CHARGE";
|
|
4
|
+
readonly DIRECT_FROM_CUSTOMER_ACCOUNT: "DIRECT_FROM_CUSTOMER_ACCOUNT";
|
|
5
|
+
};
|
|
6
|
+
export declare const EMPLOYEE_STATUS_MAPS: Record<string, any>;
|
|
7
|
+
export declare function elgibilityTool(phoneNumber: string): Promise<CallToolResult>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.EMPLOYEE_STATUS_MAPS = exports.DEBT_COLLECTION_TYPE = void 0;
|
|
13
|
+
exports.elgibilityTool = elgibilityTool;
|
|
14
|
+
const gimo_service_1 = require("../services/gimo.service");
|
|
15
|
+
const FIELD_LABELS = {
|
|
16
|
+
ewa_status: "Trạng thái EWA",
|
|
17
|
+
dda: "Trạng thái DDA",
|
|
18
|
+
seniority: "Thâm niên làm việc",
|
|
19
|
+
working_status: "Trạng thái làm việc",
|
|
20
|
+
longest_overdue_bill: "Số ngày quá hạn thanh toán dài nhất",
|
|
21
|
+
outstanding_balance: "Số dư nợ",
|
|
22
|
+
parnter_contract_expirity: "Hạn hợp đồng đối tác",
|
|
23
|
+
time_sheet: "Dữ liệu chấm công",
|
|
24
|
+
product_type: "Loại sản phẩm",
|
|
25
|
+
opreation_note: "Ghi chú vận hành",
|
|
26
|
+
};
|
|
27
|
+
const PRODUCT_TYPE = {
|
|
28
|
+
EWA_01: "EWA_01",
|
|
29
|
+
EWA_02: "EWA_02",
|
|
30
|
+
EWA_03: "EWA_03",
|
|
31
|
+
EWA_04: "EWA_04",
|
|
32
|
+
};
|
|
33
|
+
const PARTNER_ONBOARD_METHOD = {
|
|
34
|
+
/// truyen thong
|
|
35
|
+
TRADITIONAL: "TRADITIONAL",
|
|
36
|
+
/// cong doan
|
|
37
|
+
UNION: "UNION",
|
|
38
|
+
/// chung minh thu nhap
|
|
39
|
+
EARNING_PROVE: "EARNING_PROVE",
|
|
40
|
+
};
|
|
41
|
+
exports.DEBT_COLLECTION_TYPE = {
|
|
42
|
+
PARTNER_IN_CHARGE: "PARTNER_IN_CHARGE",
|
|
43
|
+
DIRECT_FROM_CUSTOMER_ACCOUNT: "DIRECT_FROM_CUSTOMER_ACCOUNT",
|
|
44
|
+
};
|
|
45
|
+
function getProductType(options) {
|
|
46
|
+
const { partner_onboard_method, debt_collection_type } = options;
|
|
47
|
+
if (debt_collection_type === exports.DEBT_COLLECTION_TYPE.PARTNER_IN_CHARGE) {
|
|
48
|
+
return PRODUCT_TYPE.EWA_01;
|
|
49
|
+
}
|
|
50
|
+
if (debt_collection_type === exports.DEBT_COLLECTION_TYPE.DIRECT_FROM_CUSTOMER_ACCOUNT) {
|
|
51
|
+
if (partner_onboard_method === PARTNER_ONBOARD_METHOD.EARNING_PROVE) {
|
|
52
|
+
return PRODUCT_TYPE.EWA_03;
|
|
53
|
+
}
|
|
54
|
+
if (partner_onboard_method === PARTNER_ONBOARD_METHOD.UNION) {
|
|
55
|
+
return PRODUCT_TYPE.EWA_02;
|
|
56
|
+
}
|
|
57
|
+
// if (partner_onboard_method === PARTNER_ONBOARD_METHOD.TRADITIONAL) {
|
|
58
|
+
// return PRODUCT_TYPE.EWA_02;
|
|
59
|
+
// }
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
exports.EMPLOYEE_STATUS_MAPS = {
|
|
64
|
+
ACTIVE: "Đang làm việc",
|
|
65
|
+
SUSPEND__WAITING_TO_APPROVE: "Chờ công đoàn phê duyệt",
|
|
66
|
+
SUSPEND__MATERNITY_LEAVE: "Nhân sự nghỉ thai sản",
|
|
67
|
+
SUSPEND__UNPAID_LEAVE: "Nhân sự nghỉ không lương",
|
|
68
|
+
SUSPEND__RE_UPLOAD_ACCOUNT_STATEMENT: "Chờ cập nhật chứng minh thu nhập",
|
|
69
|
+
SUSPEND__WAITING_APPRAISALS_ACCOUNT_STATEMENT: "Chờ phê duyệt chứng minh thu nhập",
|
|
70
|
+
SUSPEND__DEFAULT: "Tạm nghỉ",
|
|
71
|
+
INACTIVE: "Nghỉ việc",
|
|
72
|
+
};
|
|
73
|
+
const CUSTOMER_EWA_STATUSP_MAPS = {
|
|
74
|
+
ACTIVE: "Hoạt động",
|
|
75
|
+
DEACTIVATE: "Tạm ngưng",
|
|
76
|
+
};
|
|
77
|
+
const BASE_REQUIRED_CRITERIA = {
|
|
78
|
+
ewa_status: "ACTIVE",
|
|
79
|
+
seniority: ">= 0.3 year",
|
|
80
|
+
working_status: exports.EMPLOYEE_STATUS_MAPS.ACTIVE,
|
|
81
|
+
longest_overdue_bill: "<=10 days",
|
|
82
|
+
outstanding_balance: "0",
|
|
83
|
+
parnter_contract_expirity: "Not yet expired",
|
|
84
|
+
time_sheet: "The data exists",
|
|
85
|
+
available_balance: ">0",
|
|
86
|
+
};
|
|
87
|
+
const EWA_02_CRITERIA = Object.assign(Object.assign({}, BASE_REQUIRED_CRITERIA), { dda: "REGISTERED" });
|
|
88
|
+
const EWA_03_CRITERIA = Object.assign(Object.assign({}, BASE_REQUIRED_CRITERIA), { dda: "REGISTERED" });
|
|
89
|
+
const formatter = (record) => {
|
|
90
|
+
return Object.keys(record)
|
|
91
|
+
.map((key) => `${key}: ${record[key]}`)
|
|
92
|
+
.join(",");
|
|
93
|
+
};
|
|
94
|
+
function elgibilityTool(phoneNumber) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
try {
|
|
98
|
+
const accessToken = yield (0, gimo_service_1.getAccessToken)();
|
|
99
|
+
const customer = yield (0, gimo_service_1.findCustomerEWAByPhonenumber)(phoneNumber, { accessToken });
|
|
100
|
+
if (!customer) {
|
|
101
|
+
throw "Customer not found";
|
|
102
|
+
}
|
|
103
|
+
const { employee, partner } = yield (0, gimo_service_1.getEmployeeByCustomerId)(customer.customer_id, { accessToken });
|
|
104
|
+
let periods = [];
|
|
105
|
+
let timeSheets = [];
|
|
106
|
+
let ewaDeactiveReason = "";
|
|
107
|
+
let currentPayperiodInfo = null;
|
|
108
|
+
if (employee) {
|
|
109
|
+
const payPeriods = yield (0, gimo_service_1.getPayPeriods)({ orgId: employee === null || employee === void 0 ? void 0 : employee.organization_id, parnterId: employee.partner_id }, { accessToken });
|
|
110
|
+
if (payPeriods === null || payPeriods === void 0 ? void 0 : payPeriods.length) {
|
|
111
|
+
periods = payPeriods;
|
|
112
|
+
timeSheets = yield (0, gimo_service_1.getTimeSheets)({ payPeriodId: payPeriods[0].id, employeeId: employee.id }, { accessToken });
|
|
113
|
+
currentPayperiodInfo = yield (0, gimo_service_1.getCurrentPayperiodInfo)(payPeriods[0].id, { accessToken });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (customer.ewa_status === "DEACTIVATE") {
|
|
117
|
+
ewaDeactiveReason =
|
|
118
|
+
((_b = (_a = (yield (0, gimo_service_1.getCustomerStatusChange)(customer.customer_id, { accessToken }))) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.log_description) || "";
|
|
119
|
+
}
|
|
120
|
+
const { debt_collection, onboard_method } = partner || {};
|
|
121
|
+
const productType = getProductType({
|
|
122
|
+
debt_collection_type: debt_collection || "",
|
|
123
|
+
partner_onboard_method: onboard_method || "",
|
|
124
|
+
});
|
|
125
|
+
const currentInformation = {
|
|
126
|
+
ewa_status: customer === null || customer === void 0 ? void 0 : customer.ewa_status,
|
|
127
|
+
dda: customer === null || customer === void 0 ? void 0 : customer.dda_status,
|
|
128
|
+
seniority: employee === null || employee === void 0 ? void 0 : employee.seniority,
|
|
129
|
+
working_status: exports.EMPLOYEE_STATUS_MAPS[(employee === null || employee === void 0 ? void 0 : employee.status) || "ACTIVE"],
|
|
130
|
+
product_type: productType,
|
|
131
|
+
time_sheet: (timeSheets === null || timeSheets === void 0 ? void 0 : timeSheets.length) ? "The data exists" : "The data does't exists",
|
|
132
|
+
longest_overdue_bill: customer.ewa_longest_over_due_day,
|
|
133
|
+
opreation_note: employee === null || employee === void 0 ? void 0 : employee.reason,
|
|
134
|
+
available_balance: currentPayperiodInfo === null || currentPayperiodInfo === void 0 ? void 0 : currentPayperiodInfo.accessible_amount,
|
|
135
|
+
};
|
|
136
|
+
const getRequriedCriteria = (productType) => {
|
|
137
|
+
if (productType === PRODUCT_TYPE.EWA_01) {
|
|
138
|
+
return BASE_REQUIRED_CRITERIA;
|
|
139
|
+
}
|
|
140
|
+
if (productType === PRODUCT_TYPE.EWA_02) {
|
|
141
|
+
return EWA_02_CRITERIA;
|
|
142
|
+
}
|
|
143
|
+
if (productType === PRODUCT_TYPE.EWA_03) {
|
|
144
|
+
return EWA_03_CRITERIA;
|
|
145
|
+
}
|
|
146
|
+
return BASE_REQUIRED_CRITERIA;
|
|
147
|
+
};
|
|
148
|
+
const requiredCriteria = getRequriedCriteria(productType);
|
|
149
|
+
const reasons = [ewaDeactiveReason];
|
|
150
|
+
const result = `
|
|
151
|
+
Customer ${customer.customer_full_name}, partner name ${customer.partner_name} has these information: ${formatter(currentInformation)}
|
|
152
|
+
Eligibility Criteria for Salary Advance: ${formatter(requiredCriteria)}
|
|
153
|
+
Reasons: ${reasons.filter(Boolean).join("")}
|
|
154
|
+
`;
|
|
155
|
+
return { content: [{ type: "text", text: result }] };
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
return {
|
|
159
|
+
content: [
|
|
160
|
+
{
|
|
161
|
+
type: "text",
|
|
162
|
+
text: "Oh no,có rồi, thử lại nhé " + error,
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import z from "zod";
|
|
14
14
|
import { ensureEnvVariables, getEnv } from "./env";
|
|
15
15
|
import { debtCollectionRateTool } from "./tools/lark-tool";
|
|
16
|
-
import {
|
|
16
|
+
import { elgibilityTool } from "./tools/eligibility-tools";
|
|
17
17
|
|
|
18
18
|
export const server = new McpServer(
|
|
19
19
|
{
|
|
@@ -115,7 +115,7 @@ server.tool(
|
|
|
115
115
|
},
|
|
116
116
|
async (args) => {
|
|
117
117
|
const { phone_number } = args;
|
|
118
|
-
return
|
|
118
|
+
return elgibilityTool(phone_number);
|
|
119
119
|
}
|
|
120
120
|
);
|
|
121
121
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { Gimo } from "./types";
|
|
3
3
|
import { getEnv } from "../env";
|
|
4
|
-
import { PayPeriod } from "./types/pay-period";
|
|
4
|
+
import { PayPeriod, PayperiodInfo } from "./types/pay-period";
|
|
5
5
|
import { TimeSheet } from "./types/time-keeper";
|
|
6
|
+
import { CustomerEwaStatusChangeLogs } from "./types/status-change";
|
|
6
7
|
|
|
7
8
|
export async function getAccessToken() {
|
|
8
9
|
const url = `${getEnv().DASH_URL}/api/v1/auth/admin/login`;
|
|
@@ -14,9 +15,15 @@ export async function getAccessToken() {
|
|
|
14
15
|
.then((res) => res.data.access_token);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export async function findCustomerEWAByPhonenumber(phoneNumber: string) {
|
|
18
|
+
export async function findCustomerEWAByPhonenumber(phoneNumber: string, options?: { accessToken?: string }) {
|
|
19
|
+
const { accessToken } = options || {};
|
|
20
|
+
let access_token = accessToken;
|
|
21
|
+
if (!access_token) {
|
|
22
|
+
access_token = await getAccessToken();
|
|
23
|
+
}
|
|
18
24
|
const customerApiUrl = `${getEnv().DASH_URL}/api/v1/admin/customers/ewa/pagination`;
|
|
19
|
-
|
|
25
|
+
|
|
26
|
+
// const access_token = await getAccessToken();
|
|
20
27
|
// Find inlist
|
|
21
28
|
const customers = await axios
|
|
22
29
|
.get<{ content: Gimo.CustomerEWA[] }>(customerApiUrl, {
|
|
@@ -35,10 +42,15 @@ export async function findCustomerEWAByPhonenumber(phoneNumber: string) {
|
|
|
35
42
|
return findCustomerEWAById(foundedCustomer.customer_id);
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
export async function getPayPeriods(params: { orgId: number; parnterId: number }) {
|
|
45
|
+
export async function getPayPeriods(params: { orgId: number; parnterId: number }, options?: { accessToken?: string }) {
|
|
39
46
|
const { orgId, parnterId } = params;
|
|
47
|
+
const { accessToken } = options || {};
|
|
48
|
+
let access_token = accessToken;
|
|
49
|
+
if (!access_token) {
|
|
50
|
+
access_token = await getAccessToken();
|
|
51
|
+
}
|
|
40
52
|
const url = `${getEnv().DASH_URL}/api/v1/admin/partners/${parnterId}/pay-periods`;
|
|
41
|
-
const access_token = await getAccessToken();
|
|
53
|
+
// const access_token = await getAccessToken();
|
|
42
54
|
const customer = await axios
|
|
43
55
|
.get<PayPeriod[]>(url, {
|
|
44
56
|
headers: {
|
|
@@ -54,10 +66,17 @@ export async function getPayPeriods(params: { orgId: number; parnterId: number }
|
|
|
54
66
|
return customer || null;
|
|
55
67
|
}
|
|
56
68
|
|
|
57
|
-
export async function getTimeSheets(
|
|
69
|
+
export async function getTimeSheets(
|
|
70
|
+
params: { payPeriodId: number; employeeId: number },
|
|
71
|
+
options?: { accessToken?: string },
|
|
72
|
+
) {
|
|
58
73
|
const { payPeriodId, employeeId } = params;
|
|
74
|
+
const { accessToken } = options || {};
|
|
75
|
+
let access_token = accessToken;
|
|
76
|
+
if (!access_token) {
|
|
77
|
+
access_token = await getAccessToken();
|
|
78
|
+
}
|
|
59
79
|
const url = `${getEnv().DASH_URL}/api/v2/admin/time-sheets/by-period`;
|
|
60
|
-
const access_token = await getAccessToken();
|
|
61
80
|
const customer = await axios
|
|
62
81
|
.get<TimeSheet[]>(url, {
|
|
63
82
|
headers: {
|
|
@@ -73,9 +92,13 @@ export async function getTimeSheets(params: { payPeriodId: number; employeeId: n
|
|
|
73
92
|
return customer || null;
|
|
74
93
|
}
|
|
75
94
|
|
|
76
|
-
export async function getEmployeeByCustomerId(customerId: number) {
|
|
95
|
+
export async function getEmployeeByCustomerId(customerId: number, options?: { accessToken?: string }) {
|
|
96
|
+
const { accessToken } = options || {};
|
|
97
|
+
let access_token = accessToken;
|
|
98
|
+
if (!access_token) {
|
|
99
|
+
access_token = await getAccessToken();
|
|
100
|
+
}
|
|
77
101
|
const url = `${getEnv().DASH_URL}/api/v1/admin/customers/${customerId}/employee-info`;
|
|
78
|
-
const access_token = await getAccessToken();
|
|
79
102
|
const customer = await axios
|
|
80
103
|
.get<Gimo.EmployeeInfo>(url, {
|
|
81
104
|
headers: {
|
|
@@ -101,3 +124,39 @@ export async function findCustomerEWAById(id: number) {
|
|
|
101
124
|
// Select first customer
|
|
102
125
|
return customer || null;
|
|
103
126
|
}
|
|
127
|
+
|
|
128
|
+
export async function getCustomerStatusChange(ewaCustomerId: number, options?: { accessToken?: string }) {
|
|
129
|
+
const { accessToken } = options || {};
|
|
130
|
+
let access_token = accessToken;
|
|
131
|
+
if (!access_token) {
|
|
132
|
+
access_token = await getAccessToken();
|
|
133
|
+
}
|
|
134
|
+
const url = `${getEnv().DASH_URL}/api/v1/admin/customers/ewa/${ewaCustomerId}/status/changes`;
|
|
135
|
+
const res = await axios
|
|
136
|
+
.get<CustomerEwaStatusChangeLogs[]>(url, {
|
|
137
|
+
headers: {
|
|
138
|
+
Authorization: "Bearer " + access_token,
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
.then((res) => res.data);
|
|
142
|
+
// Select first customer
|
|
143
|
+
return res;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function getCurrentPayperiodInfo(payPeriodId: number, options?: { accessToken?: string }) {
|
|
147
|
+
const { accessToken } = options || {};
|
|
148
|
+
let access_token = accessToken;
|
|
149
|
+
if (!access_token) {
|
|
150
|
+
access_token = await getAccessToken();
|
|
151
|
+
}
|
|
152
|
+
const url = `${getEnv().DASH_URL}/api/v1/admin/employees/${payPeriodId}/current-pay-period-info`;
|
|
153
|
+
const res = await axios
|
|
154
|
+
.get<PayperiodInfo>(url, {
|
|
155
|
+
headers: {
|
|
156
|
+
Authorization: "Bearer " + access_token,
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
.then((res) => res.data);
|
|
160
|
+
// Select first customer
|
|
161
|
+
return res;
|
|
162
|
+
}
|
|
@@ -40,3 +40,15 @@ export interface Config {
|
|
|
40
40
|
version_number: number;
|
|
41
41
|
previous_config_id: any;
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
export interface PayperiodInfo {
|
|
45
|
+
month: number;
|
|
46
|
+
year: number;
|
|
47
|
+
worked_days: number;
|
|
48
|
+
standard_work_days: number;
|
|
49
|
+
work_days: number;
|
|
50
|
+
earned_amount: number;
|
|
51
|
+
advanced_amount: number;
|
|
52
|
+
accessible_amount: number;
|
|
53
|
+
has_income_from_attendance: boolean;
|
|
54
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CustomerEwaStatusChangeLogs {
|
|
2
|
+
log_created_at: string;
|
|
3
|
+
log_description?: string;
|
|
4
|
+
log_ewa_status?: "DEACTIVATE" | "ACTIVE";
|
|
5
|
+
log_id: string;
|
|
6
|
+
log_type?: string;
|
|
7
|
+
log_user_id?: string;
|
|
8
|
+
log_username?: string;
|
|
9
|
+
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { CallToolResult } from "@modelcontextprotocol/sdk/types";
|
|
2
2
|
import {
|
|
3
3
|
findCustomerEWAByPhonenumber,
|
|
4
|
+
getAccessToken,
|
|
5
|
+
getCurrentPayperiodInfo,
|
|
6
|
+
getCustomerStatusChange,
|
|
4
7
|
getEmployeeByCustomerId,
|
|
5
8
|
getPayPeriods,
|
|
6
9
|
getTimeSheets,
|
|
7
10
|
} from "../services/gimo.service";
|
|
8
|
-
import { PayPeriod } from "../services/types/pay-period";
|
|
11
|
+
import { PayPeriod, PayperiodInfo } from "../services/types/pay-period";
|
|
9
12
|
import { TimeSheet } from "../services/types/time-keeper";
|
|
10
13
|
|
|
14
|
+
const FIELD_LABELS: Record<string, string> = {
|
|
15
|
+
ewa_status: "Trạng thái EWA",
|
|
16
|
+
dda: "Trạng thái DDA",
|
|
17
|
+
seniority: "Thâm niên làm việc",
|
|
18
|
+
working_status: "Trạng thái làm việc",
|
|
19
|
+
longest_overdue_bill: "Số ngày quá hạn thanh toán dài nhất",
|
|
20
|
+
outstanding_balance: "Số dư nợ",
|
|
21
|
+
parnter_contract_expirity: "Hạn hợp đồng đối tác",
|
|
22
|
+
time_sheet: "Dữ liệu chấm công",
|
|
23
|
+
product_type: "Loại sản phẩm",
|
|
24
|
+
opreation_note: "Ghi chú vận hành",
|
|
25
|
+
};
|
|
26
|
+
|
|
11
27
|
const PRODUCT_TYPE = {
|
|
12
28
|
EWA_01: "EWA_01",
|
|
13
29
|
EWA_02: "EWA_02",
|
|
@@ -59,6 +75,11 @@ export const EMPLOYEE_STATUS_MAPS: Record<string, any> = {
|
|
|
59
75
|
INACTIVE: "Nghỉ việc",
|
|
60
76
|
};
|
|
61
77
|
|
|
78
|
+
const CUSTOMER_EWA_STATUSP_MAPS = {
|
|
79
|
+
ACTIVE: "Hoạt động",
|
|
80
|
+
DEACTIVATE: "Tạm ngưng",
|
|
81
|
+
};
|
|
82
|
+
|
|
62
83
|
const BASE_REQUIRED_CRITERIA = {
|
|
63
84
|
ewa_status: "ACTIVE",
|
|
64
85
|
seniority: ">= 0.3 year",
|
|
@@ -67,6 +88,7 @@ const BASE_REQUIRED_CRITERIA = {
|
|
|
67
88
|
outstanding_balance: "0",
|
|
68
89
|
parnter_contract_expirity: "Not yet expired",
|
|
69
90
|
time_sheet: "The data exists",
|
|
91
|
+
available_balance: ">0",
|
|
70
92
|
};
|
|
71
93
|
|
|
72
94
|
const EWA_02_CRITERIA = {
|
|
@@ -79,26 +101,39 @@ const EWA_03_CRITERIA = {
|
|
|
79
101
|
dda: "REGISTERED",
|
|
80
102
|
};
|
|
81
103
|
|
|
82
|
-
const formatter = (record:Record<string,any>) => {
|
|
83
|
-
return Object.keys(record)
|
|
84
|
-
}
|
|
104
|
+
const formatter = (record: Record<string, any>) => {
|
|
105
|
+
return Object.keys(record)
|
|
106
|
+
.map((key) => `${key}: ${record[key]}`)
|
|
107
|
+
.join(",");
|
|
108
|
+
};
|
|
85
109
|
|
|
86
|
-
export async function
|
|
110
|
+
export async function elgibilityTool(phoneNumber: string): Promise<CallToolResult> {
|
|
87
111
|
try {
|
|
88
|
-
const
|
|
112
|
+
const accessToken = await getAccessToken();
|
|
113
|
+
const customer = await findCustomerEWAByPhonenumber(phoneNumber, { accessToken });
|
|
89
114
|
if (!customer) {
|
|
90
115
|
throw "Customer not found";
|
|
91
116
|
}
|
|
92
|
-
const { employee, partner } = await getEmployeeByCustomerId(customer.customer_id);
|
|
117
|
+
const { employee, partner } = await getEmployeeByCustomerId(customer.customer_id, { accessToken });
|
|
93
118
|
let periods: PayPeriod[] = [];
|
|
94
119
|
let timeSheets: TimeSheet[] = [];
|
|
120
|
+
let ewaDeactiveReason = "";
|
|
121
|
+
let currentPayperiodInfo: PayperiodInfo | null = null;
|
|
95
122
|
if (employee) {
|
|
96
|
-
const payPeriods = await getPayPeriods(
|
|
123
|
+
const payPeriods = await getPayPeriods(
|
|
124
|
+
{ orgId: employee?.organization_id, parnterId: employee.partner_id },
|
|
125
|
+
{ accessToken },
|
|
126
|
+
);
|
|
97
127
|
if (payPeriods?.length) {
|
|
98
128
|
periods = payPeriods;
|
|
99
|
-
timeSheets = await getTimeSheets({ payPeriodId: payPeriods[0].id, employeeId: employee.id });
|
|
129
|
+
timeSheets = await getTimeSheets({ payPeriodId: payPeriods[0].id, employeeId: employee.id }, { accessToken });
|
|
130
|
+
currentPayperiodInfo = await getCurrentPayperiodInfo(payPeriods[0].id, { accessToken });
|
|
100
131
|
}
|
|
101
132
|
}
|
|
133
|
+
if (customer.ewa_status === "DEACTIVATE") {
|
|
134
|
+
ewaDeactiveReason =
|
|
135
|
+
(await getCustomerStatusChange(customer.customer_id, { accessToken }))?.[0]?.log_description || "";
|
|
136
|
+
}
|
|
102
137
|
const { debt_collection, onboard_method } = partner || {};
|
|
103
138
|
|
|
104
139
|
const productType = getProductType({
|
|
@@ -113,6 +148,9 @@ export async function accessibleTool(phoneNumber: string): Promise<CallToolResul
|
|
|
113
148
|
working_status: EMPLOYEE_STATUS_MAPS[employee?.status || "ACTIVE"],
|
|
114
149
|
product_type: productType,
|
|
115
150
|
time_sheet: timeSheets?.length ? "The data exists" : "The data does't exists",
|
|
151
|
+
longest_overdue_bill: customer.ewa_longest_over_due_day,
|
|
152
|
+
opreation_note: employee?.reason,
|
|
153
|
+
available_balance: currentPayperiodInfo?.accessible_amount,
|
|
116
154
|
};
|
|
117
155
|
|
|
118
156
|
const getRequriedCriteria = (productType: keyof typeof PRODUCT_TYPE | null) => {
|
|
@@ -130,15 +168,13 @@ export async function accessibleTool(phoneNumber: string): Promise<CallToolResul
|
|
|
130
168
|
|
|
131
169
|
const requiredCriteria: Record<string, any> = getRequriedCriteria(productType);
|
|
132
170
|
|
|
133
|
-
const
|
|
134
|
-
current_information: currentInformation,
|
|
135
|
-
valid_information: requiredCriteria,
|
|
136
|
-
};
|
|
171
|
+
const reasons = [ewaDeactiveReason];
|
|
137
172
|
|
|
138
173
|
const result = `
|
|
139
|
-
Customer ${customer.customer_full_name}, partner name ${customer.partner_name} has these
|
|
140
|
-
Eligibility Criteria for Salary
|
|
141
|
-
|
|
174
|
+
Customer ${customer.customer_full_name}, partner name ${customer.partner_name} has these information: ${formatter(currentInformation)}
|
|
175
|
+
Eligibility Criteria for Salary Advance: ${formatter(requiredCriteria)}
|
|
176
|
+
Reasons: ${reasons.filter(Boolean).join("")}
|
|
177
|
+
`;
|
|
142
178
|
|
|
143
179
|
return { content: [{ type: "text", text: result }] };
|
|
144
180
|
} catch (error) {
|