@hostlink/hostlink-cli 1.0.3 → 1.0.5
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/bundle.js +1050 -28
- package/index.js +8 -0
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -31530,22 +31530,42 @@ var require_clients = __commonJS({
|
|
|
31530
31530
|
}
|
|
31531
31531
|
var CLIENT_FIELDS = `
|
|
31532
31532
|
client_id
|
|
31533
|
+
client_no
|
|
31533
31534
|
client_name
|
|
31534
31535
|
client_email
|
|
31535
31536
|
client_phone
|
|
31536
31537
|
client_city
|
|
31537
31538
|
status
|
|
31538
31539
|
join_date
|
|
31540
|
+
bill_title
|
|
31541
|
+
bill_first_name
|
|
31542
|
+
bill_last_name
|
|
31543
|
+
bill_department
|
|
31544
|
+
bill_name
|
|
31545
|
+
bill_addr1
|
|
31546
|
+
bill_addr2
|
|
31547
|
+
bill_addr3
|
|
31548
|
+
bill_city
|
|
31549
|
+
bill_phone
|
|
31550
|
+
bill_fax
|
|
31551
|
+
bill_email
|
|
31539
31552
|
`;
|
|
31540
31553
|
function register(program2) {
|
|
31541
31554
|
const clients2 = program2.command("clients").description("Manage clients");
|
|
31542
|
-
clients2.command("list").description("List clients").option("-l, --limit <n>", "Max number of clients to return", "50").option("-o, --offset <n>", "Number of clients to skip", "0").option("-s, --search <name>", "Filter by client name").option("--json", "Output as JSON").action(async (options) => {
|
|
31555
|
+
clients2.command("list").description("List clients").option("-l, --limit <n>", "Max number of clients to return", "50").option("-o, --offset <n>", "Number of clients to skip", "0").option("-s, --search <name>", "Filter by client name").option("--sort <field>", "Sort by field: client_no, client_no:desc, client_name, client_name:desc, join_date, join_date:desc", "client_no").option("--json", "Output as JSON").action(async (options) => {
|
|
31543
31556
|
const client = getClient();
|
|
31544
|
-
const
|
|
31557
|
+
const VALID_SORTS = ["client_no", "client_no:desc", "client_name", "client_name:desc", "join_date", "join_date:desc"];
|
|
31558
|
+
if (!VALID_SORTS.includes(options.sort)) {
|
|
31559
|
+
console.error(`Invalid sort value. Must be one of: ${VALID_SORTS.join(", ")}`);
|
|
31560
|
+
process.exit(1);
|
|
31561
|
+
}
|
|
31562
|
+
const args = [];
|
|
31563
|
+
if (options.search) args.push(`filters: { client_name: { contains: ${JSON.stringify(options.search)} } }`);
|
|
31564
|
+
args.push(`sort: ${JSON.stringify(options.sort)}`);
|
|
31545
31565
|
const pagination = `limit: ${parseInt(options.limit)}, offset: ${parseInt(options.offset)}`;
|
|
31546
31566
|
const query = gql`
|
|
31547
31567
|
query {
|
|
31548
|
-
listClient${
|
|
31568
|
+
listClient(${args.join(", ")}) {
|
|
31549
31569
|
meta { total }
|
|
31550
31570
|
data(${pagination}) {
|
|
31551
31571
|
${CLIENT_FIELDS}
|
|
@@ -31563,7 +31583,7 @@ var require_clients = __commonJS({
|
|
|
31563
31583
|
console.log("No clients found.");
|
|
31564
31584
|
} else {
|
|
31565
31585
|
list.forEach(
|
|
31566
|
-
(c) => console.log(`[${c.client_id}] ${c.client_name} | ${c.client_email ?? "-"} | ${c.client_phone ?? "-"} | ${c.status ?? "-"}`)
|
|
31586
|
+
(c) => console.log(`[${c.client_id}] ${c.client_no ? `#${c.client_no} ` : ""}${c.client_name} | ${c.client_email ?? "-"} | ${c.client_phone ?? "-"} | ${c.status ?? "-"}`)
|
|
31567
31587
|
);
|
|
31568
31588
|
console.log(`
|
|
31569
31589
|
Total: ${total}`);
|
|
@@ -31723,7 +31743,7 @@ var require_domains = __commonJS({
|
|
|
31723
31743
|
const client = getClient();
|
|
31724
31744
|
const filterParts = [];
|
|
31725
31745
|
if (options.client) filterParts.push(`client_id: ${parseInt(options.client)}`);
|
|
31726
|
-
if (options.search) filterParts.push(`domain_name: ${JSON.stringify(options.search)}`);
|
|
31746
|
+
if (options.search) filterParts.push(`domain_name: { contains: ${JSON.stringify(options.search)} }`);
|
|
31727
31747
|
const filters = filterParts.length ? `filters: { ${filterParts.join(", ")} }` : "";
|
|
31728
31748
|
const pagination = `limit: ${parseInt(options.limit)}, offset: ${parseInt(options.offset)}`;
|
|
31729
31749
|
const query = gql`
|
|
@@ -31732,6 +31752,7 @@ var require_domains = __commonJS({
|
|
|
31732
31752
|
meta { total }
|
|
31733
31753
|
data(${pagination}) {
|
|
31734
31754
|
domain_id
|
|
31755
|
+
domain_no
|
|
31735
31756
|
domain_name
|
|
31736
31757
|
client_id
|
|
31737
31758
|
expiry_date
|
|
@@ -31753,7 +31774,7 @@ var require_domains = __commonJS({
|
|
|
31753
31774
|
console.log("No domains found.");
|
|
31754
31775
|
} else {
|
|
31755
31776
|
list.forEach(
|
|
31756
|
-
(d) => console.log(`[${d.domain_id}] ${d.domain_name} | client:${d.client_id} | expires:${d.expiry_date ?? "-"} | ${d.registrar ?? "-"} | ${d.status ?? "-"}`)
|
|
31777
|
+
(d) => console.log(`[${d.domain_id}] ${d.domain_no ? `#${d.domain_no} ` : ""}${d.domain_name} | client:${d.client_id} | expires:${d.expiry_date ?? "-"} | ${d.registrar ?? "-"} | ${d.status ?? "-"}`)
|
|
31757
31778
|
);
|
|
31758
31779
|
console.log(`
|
|
31759
31780
|
Total: ${total}`);
|
|
@@ -31860,7 +31881,7 @@ Total: ${total}`);
|
|
|
31860
31881
|
process.exit(1);
|
|
31861
31882
|
}
|
|
31862
31883
|
});
|
|
31863
|
-
domains2.command("update <id>").description("Update a domain by ID").option("--domain-name <value>", "Domain name").option("--client-id <id>", "Client ID").option("--expiry-date <date>", "Expiry date").option("--creation-date <date>", "Creation date").option("--registrar <value>", "Registrar").option("--primary-dns <value>", "Primary DNS").option("--secondary-dns <value>", "Secondary DNS").option("--domain-user-id <value>", "Domain user ID").option("--domain-password <value>", "Domain password").option("--domain-type <n>", "Domain type").option("--remark <value>", "Remark").option("--server-id <n>", "Server ID").
|
|
31884
|
+
domains2.command("update <id>").description("Update a domain by ID").option("--domain-name <value>", "Domain name").option("--client-id <id>", "Client ID").option("--expiry-date <date>", "Expiry date").option("--creation-date <date>", "Creation date").option("--registrar <value>", "Registrar").option("--primary-dns <value>", "Primary DNS").option("--secondary-dns <value>", "Secondary DNS").option("--domain-user-id <value>", "Domain user ID").option("--domain-password <value>", "Domain password").option("--domain-type <n>", "Domain type").option("--remark <value>", "Remark").option("--server-id <n>", "Server ID").action(async (id, options) => {
|
|
31864
31885
|
const client = getClient();
|
|
31865
31886
|
const fieldMap = {
|
|
31866
31887
|
domainName: ["domain_name", (v) => JSON.stringify(v)],
|
|
@@ -31874,8 +31895,7 @@ Total: ${total}`);
|
|
|
31874
31895
|
domainPassword: ["domain_password", (v) => JSON.stringify(v)],
|
|
31875
31896
|
domainType: ["domain_type", (v) => parseInt(v)],
|
|
31876
31897
|
remark: ["remark", (v) => JSON.stringify(v)],
|
|
31877
|
-
serverId: ["server_id", (v) => parseInt(v)]
|
|
31878
|
-
status: ["status", (v) => parseInt(v)]
|
|
31898
|
+
serverId: ["server_id", (v) => parseInt(v)]
|
|
31879
31899
|
};
|
|
31880
31900
|
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
31881
31901
|
if (fields.length === 0) {
|
|
@@ -31927,6 +31947,190 @@ Total: ${total}`);
|
|
|
31927
31947
|
}
|
|
31928
31948
|
});
|
|
31929
31949
|
|
|
31950
|
+
// src/domain-passwords/index.js
|
|
31951
|
+
var require_domain_passwords = __commonJS({
|
|
31952
|
+
"src/domain-passwords/index.js"(exports2, module2) {
|
|
31953
|
+
var { GraphQLClient, gql } = require_main();
|
|
31954
|
+
var Conf2 = require_source();
|
|
31955
|
+
var config2 = new Conf2({ projectName: "hostlink-cli" });
|
|
31956
|
+
var ENDPOINT = "https://isapi.hostlink.com.hk/";
|
|
31957
|
+
function getClient() {
|
|
31958
|
+
const token = config2.get("token");
|
|
31959
|
+
if (!token) {
|
|
31960
|
+
console.error("No token found. Run `hostlink set-token <token>` first.");
|
|
31961
|
+
process.exit(1);
|
|
31962
|
+
}
|
|
31963
|
+
return new GraphQLClient(ENDPOINT, {
|
|
31964
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
31965
|
+
});
|
|
31966
|
+
}
|
|
31967
|
+
var DOMAIN_PASSWORD_FIELDS = `
|
|
31968
|
+
domainpassword_id
|
|
31969
|
+
domain_id
|
|
31970
|
+
name
|
|
31971
|
+
username
|
|
31972
|
+
password
|
|
31973
|
+
host
|
|
31974
|
+
port
|
|
31975
|
+
remark
|
|
31976
|
+
`;
|
|
31977
|
+
function register(program2) {
|
|
31978
|
+
const dp = program2.command("domain-passwords").description("Manage domain passwords");
|
|
31979
|
+
dp.command("list <domain_id>").description("List passwords for a domain").option("--json", "Output as JSON").action(async (domain_id, options) => {
|
|
31980
|
+
const client = getClient();
|
|
31981
|
+
const query = gql`
|
|
31982
|
+
query {
|
|
31983
|
+
listDomainPassword(filters: { domain_id: ${parseInt(domain_id)} }) {
|
|
31984
|
+
data {
|
|
31985
|
+
${DOMAIN_PASSWORD_FIELDS}
|
|
31986
|
+
}
|
|
31987
|
+
}
|
|
31988
|
+
}
|
|
31989
|
+
`;
|
|
31990
|
+
try {
|
|
31991
|
+
const data = await client.request(query);
|
|
31992
|
+
const list = data?.listDomainPassword?.data ?? [];
|
|
31993
|
+
if (options.json) {
|
|
31994
|
+
console.log(JSON.stringify(list, null, 2));
|
|
31995
|
+
} else if (list.length === 0) {
|
|
31996
|
+
console.log("No domain passwords found.");
|
|
31997
|
+
} else {
|
|
31998
|
+
list.forEach(
|
|
31999
|
+
(p) => console.log(`[${p.domainpassword_id}] ${p.name ?? "-"} | ${p.username ?? "-"} | ${p.host ?? "-"}${p.port ? `:${p.port}` : ""}${p.remark ? ` | ${p.remark}` : ""}`)
|
|
32000
|
+
);
|
|
32001
|
+
console.log(`
|
|
32002
|
+
Total: ${list.length}`);
|
|
32003
|
+
}
|
|
32004
|
+
} catch (err) {
|
|
32005
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
32006
|
+
console.error(`Failed to fetch domain passwords: ${message}`);
|
|
32007
|
+
process.exit(1);
|
|
32008
|
+
}
|
|
32009
|
+
});
|
|
32010
|
+
dp.command("get <id>").description("Get a domain password by ID").option("--json", "Output as JSON").action(async (id, options) => {
|
|
32011
|
+
const client = getClient();
|
|
32012
|
+
const query = gql`
|
|
32013
|
+
query {
|
|
32014
|
+
listDomainPassword(filters: { domainpassword_id: ${parseInt(id)} }) {
|
|
32015
|
+
data {
|
|
32016
|
+
${DOMAIN_PASSWORD_FIELDS}
|
|
32017
|
+
}
|
|
32018
|
+
}
|
|
32019
|
+
}
|
|
32020
|
+
`;
|
|
32021
|
+
try {
|
|
32022
|
+
const data = await client.request(query);
|
|
32023
|
+
const list = data?.listDomainPassword?.data ?? [];
|
|
32024
|
+
if (list.length === 0) {
|
|
32025
|
+
console.error(`Domain password [${id}] not found.`);
|
|
32026
|
+
process.exit(1);
|
|
32027
|
+
}
|
|
32028
|
+
const p = list[0];
|
|
32029
|
+
if (options.json) {
|
|
32030
|
+
console.log(JSON.stringify(p, null, 2));
|
|
32031
|
+
} else {
|
|
32032
|
+
console.log(`ID: ${p.domainpassword_id}`);
|
|
32033
|
+
console.log(`Domain ID:${p.domain_id}`);
|
|
32034
|
+
console.log(`Name: ${p.name ?? "-"}`);
|
|
32035
|
+
console.log(`Username: ${p.username ?? "-"}`);
|
|
32036
|
+
console.log(`Password: ${p.password ?? "-"}`);
|
|
32037
|
+
console.log(`Host: ${p.host ?? "-"}`);
|
|
32038
|
+
console.log(`Port: ${p.port ?? "-"}`);
|
|
32039
|
+
if (p.remark) console.log(`Remark: ${p.remark}`);
|
|
32040
|
+
}
|
|
32041
|
+
} catch (err) {
|
|
32042
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
32043
|
+
console.error(`Failed to fetch domain password: ${message}`);
|
|
32044
|
+
process.exit(1);
|
|
32045
|
+
}
|
|
32046
|
+
});
|
|
32047
|
+
dp.command("add").description("Add a password to a domain").requiredOption("-d, --domain-id <id>", "Domain ID").requiredOption("--name <value>", "Name / label").option("--username <value>", "Username").option("--password <value>", "Password").option("--host <value>", "Host").option("--port <n>", "Port").option("--remark <value>", "Remark").action(async (options) => {
|
|
32048
|
+
const client = getClient();
|
|
32049
|
+
const fieldMap = {
|
|
32050
|
+
domainId: ["domain_id", (v) => parseInt(v)],
|
|
32051
|
+
name: ["name", (v) => JSON.stringify(v)],
|
|
32052
|
+
username: ["username", (v) => JSON.stringify(v)],
|
|
32053
|
+
password: ["password", (v) => JSON.stringify(v)],
|
|
32054
|
+
host: ["host", (v) => JSON.stringify(v)],
|
|
32055
|
+
port: ["port", (v) => parseInt(v)],
|
|
32056
|
+
remark: ["remark", (v) => JSON.stringify(v)]
|
|
32057
|
+
};
|
|
32058
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
32059
|
+
const mutation = gql`
|
|
32060
|
+
mutation {
|
|
32061
|
+
addDomainPassword(data: { ${fields.join(", ")} })
|
|
32062
|
+
}
|
|
32063
|
+
`;
|
|
32064
|
+
try {
|
|
32065
|
+
const data = await client.request(mutation);
|
|
32066
|
+
const newId = data?.addDomainPassword;
|
|
32067
|
+
console.log(`Created domain password [${newId}].`);
|
|
32068
|
+
} catch (err) {
|
|
32069
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
32070
|
+
console.error(`Failed to add domain password: ${message}`);
|
|
32071
|
+
process.exit(1);
|
|
32072
|
+
}
|
|
32073
|
+
});
|
|
32074
|
+
dp.command("update <id>").description("Update a domain password by ID").option("--name <value>", "Name / label").option("--username <value>", "Username").option("--password <value>", "Password").option("--host <value>", "Host").option("--port <n>", "Port").option("--remark <value>", "Remark").action(async (id, options) => {
|
|
32075
|
+
const client = getClient();
|
|
32076
|
+
const fieldMap = {
|
|
32077
|
+
name: ["name", (v) => JSON.stringify(v)],
|
|
32078
|
+
username: ["username", (v) => JSON.stringify(v)],
|
|
32079
|
+
password: ["password", (v) => JSON.stringify(v)],
|
|
32080
|
+
host: ["host", (v) => JSON.stringify(v)],
|
|
32081
|
+
port: ["port", (v) => parseInt(v)],
|
|
32082
|
+
remark: ["remark", (v) => JSON.stringify(v)]
|
|
32083
|
+
};
|
|
32084
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
32085
|
+
if (fields.length === 0) {
|
|
32086
|
+
console.error("No fields to update. Provide at least one option.");
|
|
32087
|
+
process.exit(1);
|
|
32088
|
+
}
|
|
32089
|
+
const mutation = gql`
|
|
32090
|
+
mutation {
|
|
32091
|
+
updateDomainPassword(id: ${parseInt(id)}, data: { ${fields.join(", ")} })
|
|
32092
|
+
}
|
|
32093
|
+
`;
|
|
32094
|
+
try {
|
|
32095
|
+
const data = await client.request(mutation);
|
|
32096
|
+
if (data?.updateDomainPassword) {
|
|
32097
|
+
console.log(`Updated domain password [${id}].`);
|
|
32098
|
+
} else {
|
|
32099
|
+
console.error("Update failed.");
|
|
32100
|
+
process.exit(1);
|
|
32101
|
+
}
|
|
32102
|
+
} catch (err) {
|
|
32103
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
32104
|
+
console.error(`Failed to update domain password: ${message}`);
|
|
32105
|
+
process.exit(1);
|
|
32106
|
+
}
|
|
32107
|
+
});
|
|
32108
|
+
dp.command("delete <id>").description("Delete a domain password by ID").action(async (id) => {
|
|
32109
|
+
const client = getClient();
|
|
32110
|
+
const mutation = gql`
|
|
32111
|
+
mutation {
|
|
32112
|
+
deleteDomainPassword(id: ${parseInt(id)})
|
|
32113
|
+
}
|
|
32114
|
+
`;
|
|
32115
|
+
try {
|
|
32116
|
+
const data = await client.request(mutation);
|
|
32117
|
+
if (data?.deleteDomainPassword) {
|
|
32118
|
+
console.log(`Deleted domain password [${id}].`);
|
|
32119
|
+
} else {
|
|
32120
|
+
console.error("Delete failed.");
|
|
32121
|
+
process.exit(1);
|
|
32122
|
+
}
|
|
32123
|
+
} catch (err) {
|
|
32124
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
32125
|
+
console.error(`Failed to delete domain password: ${message}`);
|
|
32126
|
+
process.exit(1);
|
|
32127
|
+
}
|
|
32128
|
+
});
|
|
32129
|
+
}
|
|
32130
|
+
module2.exports = { register };
|
|
32131
|
+
}
|
|
32132
|
+
});
|
|
32133
|
+
|
|
31930
32134
|
// src/quotations/index.js
|
|
31931
32135
|
var require_quotations = __commonJS({
|
|
31932
32136
|
"src/quotations/index.js"(exports2, module2) {
|
|
@@ -65282,29 +65486,15 @@ var require_leave = __commonJS({
|
|
|
65282
65486
|
}
|
|
65283
65487
|
const submitData = await promptLeaveRequest();
|
|
65284
65488
|
const mutation = gql`
|
|
65285
|
-
mutation AddLeave($data:
|
|
65286
|
-
addStaffLeaveRequest(data: $data)
|
|
65287
|
-
leave_request_id
|
|
65288
|
-
type
|
|
65289
|
-
from_date
|
|
65290
|
-
to_date
|
|
65291
|
-
status
|
|
65292
|
-
remark
|
|
65293
|
-
}
|
|
65489
|
+
mutation AddLeave($data: CreateStaffLeaveInput!) {
|
|
65490
|
+
addStaffLeaveRequest(data: $data)
|
|
65294
65491
|
}
|
|
65295
65492
|
`;
|
|
65296
65493
|
try {
|
|
65297
65494
|
const result = await client.request(mutation, { data: submitData });
|
|
65298
|
-
const
|
|
65495
|
+
const leaveRequestId = result?.addStaffLeaveRequest;
|
|
65299
65496
|
console.log("\n\u2705 Leave request submitted successfully!");
|
|
65300
|
-
|
|
65301
|
-
console.log(` ID: ${req.leave_request_id}`);
|
|
65302
|
-
console.log(` Type: ${LEAVE_TYPE_LABELS[req.type] ?? req.type}`);
|
|
65303
|
-
console.log(` From: ${req.from_date}`);
|
|
65304
|
-
if (req.to_date) console.log(` To: ${req.to_date}`);
|
|
65305
|
-
console.log(` Status: ${req.status}`);
|
|
65306
|
-
if (req.remark) console.log(` Remark: ${req.remark}`);
|
|
65307
|
-
}
|
|
65497
|
+
console.log(` ID: ${leaveRequestId}`);
|
|
65308
65498
|
} catch (err) {
|
|
65309
65499
|
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65310
65500
|
console.error(`
|
|
@@ -65358,12 +65548,836 @@ var require_leave = __commonJS({
|
|
|
65358
65548
|
}
|
|
65359
65549
|
});
|
|
65360
65550
|
|
|
65551
|
+
// src/invoices/index.js
|
|
65552
|
+
var require_invoices = __commonJS({
|
|
65553
|
+
"src/invoices/index.js"(exports2, module2) {
|
|
65554
|
+
var { GraphQLClient, gql } = require_main();
|
|
65555
|
+
var Conf2 = require_source();
|
|
65556
|
+
var config2 = new Conf2({ projectName: "hostlink-cli" });
|
|
65557
|
+
var ENDPOINT = "https://isapi.hostlink.com.hk/";
|
|
65558
|
+
function getClient() {
|
|
65559
|
+
const token = config2.get("token");
|
|
65560
|
+
if (!token) {
|
|
65561
|
+
console.error("No token found. Run `hostlink set-token <token>` first.");
|
|
65562
|
+
process.exit(1);
|
|
65563
|
+
}
|
|
65564
|
+
return new GraphQLClient(ENDPOINT, {
|
|
65565
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
65566
|
+
});
|
|
65567
|
+
}
|
|
65568
|
+
function register(program2) {
|
|
65569
|
+
const invoices2 = program2.command("invoices").description("Manage invoices");
|
|
65570
|
+
invoices2.command("list").description("List invoices").option("-c, --client <id>", "Filter by client ID").option("-s, --search <text>", "Filter by client name (contains)").option("--status <value>", "Filter by status").option("-l, --limit <n>", "Max number of invoices to return", "50").option("-o, --offset <n>", "Number of invoices to skip", "0").option("--json", "Output as JSON").action(async (options) => {
|
|
65571
|
+
const client = getClient();
|
|
65572
|
+
const filterParts = [];
|
|
65573
|
+
if (options.client) filterParts.push(`client_id: ${parseInt(options.client)}`);
|
|
65574
|
+
if (options.search) filterParts.push(`client_name: { contains: ${JSON.stringify(options.search)} }`);
|
|
65575
|
+
if (options.status) filterParts.push(`status: ${JSON.stringify(options.status)}`);
|
|
65576
|
+
const filters = filterParts.length ? `filters: { ${filterParts.join(", ")} }` : "";
|
|
65577
|
+
const pagination = `limit: ${parseInt(options.limit)}, offset: ${parseInt(options.offset)}`;
|
|
65578
|
+
const query = gql`
|
|
65579
|
+
query {
|
|
65580
|
+
listInvoice${filters ? `(${filters})` : ""} {
|
|
65581
|
+
meta { total }
|
|
65582
|
+
data(${pagination}) {
|
|
65583
|
+
invoice_id
|
|
65584
|
+
invoice_no
|
|
65585
|
+
invoice_date
|
|
65586
|
+
due_date
|
|
65587
|
+
client_id
|
|
65588
|
+
client_name
|
|
65589
|
+
status
|
|
65590
|
+
total
|
|
65591
|
+
paidTotal
|
|
65592
|
+
}
|
|
65593
|
+
}
|
|
65594
|
+
}
|
|
65595
|
+
`;
|
|
65596
|
+
try {
|
|
65597
|
+
const data = await client.request(query);
|
|
65598
|
+
const list = data?.listInvoice?.data ?? [];
|
|
65599
|
+
const total = data?.listInvoice?.meta?.total ?? list.length;
|
|
65600
|
+
if (options.json) {
|
|
65601
|
+
console.log(JSON.stringify({ total, data: list }, null, 2));
|
|
65602
|
+
} else if (list.length === 0) {
|
|
65603
|
+
console.log("No invoices found.");
|
|
65604
|
+
} else {
|
|
65605
|
+
list.forEach(
|
|
65606
|
+
(inv) => console.log(`[${inv.invoice_id}] #${inv.invoice_no ?? "-"} | ${inv.client_name ?? "-"} | ${inv.invoice_date ?? "-"} | due:${inv.due_date ?? "-"} | ${inv.status ?? "-"} | $${inv.total ?? 0} | paid:$${inv.paidTotal ?? 0}`)
|
|
65607
|
+
);
|
|
65608
|
+
console.log(`
|
|
65609
|
+
Total: ${total}`);
|
|
65610
|
+
}
|
|
65611
|
+
} catch (err) {
|
|
65612
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65613
|
+
console.error(`Failed to fetch invoices: ${message}`);
|
|
65614
|
+
process.exit(1);
|
|
65615
|
+
}
|
|
65616
|
+
});
|
|
65617
|
+
invoices2.command("get <id>").description("Get an invoice by ID").option("--json", "Output as JSON").action(async (id, options) => {
|
|
65618
|
+
const client = getClient();
|
|
65619
|
+
const query = gql`
|
|
65620
|
+
query {
|
|
65621
|
+
listInvoice(filters: { invoice_id: ${parseInt(id)} }) {
|
|
65622
|
+
data {
|
|
65623
|
+
invoice_id
|
|
65624
|
+
invoice_no
|
|
65625
|
+
invoice_date
|
|
65626
|
+
due_date
|
|
65627
|
+
client_id
|
|
65628
|
+
client_name
|
|
65629
|
+
attn
|
|
65630
|
+
phone
|
|
65631
|
+
email
|
|
65632
|
+
fax
|
|
65633
|
+
addr1
|
|
65634
|
+
addr2
|
|
65635
|
+
addr3
|
|
65636
|
+
city
|
|
65637
|
+
status
|
|
65638
|
+
total
|
|
65639
|
+
paidTotal
|
|
65640
|
+
invoice_remark
|
|
65641
|
+
invoice_type
|
|
65642
|
+
invoice_send_via
|
|
65643
|
+
void_date
|
|
65644
|
+
items {
|
|
65645
|
+
paymentperiod_id
|
|
65646
|
+
description
|
|
65647
|
+
unit_price
|
|
65648
|
+
qty
|
|
65649
|
+
discount
|
|
65650
|
+
total
|
|
65651
|
+
remark
|
|
65652
|
+
period_from
|
|
65653
|
+
period_to
|
|
65654
|
+
}
|
|
65655
|
+
}
|
|
65656
|
+
}
|
|
65657
|
+
}
|
|
65658
|
+
`;
|
|
65659
|
+
try {
|
|
65660
|
+
const data = await client.request(query);
|
|
65661
|
+
const list = data?.listInvoice?.data ?? [];
|
|
65662
|
+
if (list.length === 0) {
|
|
65663
|
+
console.error(`Invoice [${id}] not found.`);
|
|
65664
|
+
process.exit(1);
|
|
65665
|
+
}
|
|
65666
|
+
const inv = list[0];
|
|
65667
|
+
if (options.json) {
|
|
65668
|
+
console.log(JSON.stringify(inv, null, 2));
|
|
65669
|
+
} else {
|
|
65670
|
+
console.log(`ID: ${inv.invoice_id}`);
|
|
65671
|
+
console.log(`No: ${inv.invoice_no ?? "-"}`);
|
|
65672
|
+
console.log(`Client ID: ${inv.client_id}`);
|
|
65673
|
+
console.log(`Client: ${inv.client_name ?? "-"}`);
|
|
65674
|
+
console.log(`Attn: ${inv.attn ?? "-"}`);
|
|
65675
|
+
console.log(`Email: ${inv.email ?? "-"}`);
|
|
65676
|
+
console.log(`Phone: ${inv.phone ?? "-"}`);
|
|
65677
|
+
console.log(`Address: ${[inv.addr1, inv.addr2, inv.addr3, inv.city].filter(Boolean).join(", ") || "-"}`);
|
|
65678
|
+
console.log(`Date: ${inv.invoice_date ?? "-"}`);
|
|
65679
|
+
console.log(`Due Date: ${inv.due_date ?? "-"}`);
|
|
65680
|
+
console.log(`Status: ${inv.status ?? "-"}`);
|
|
65681
|
+
console.log(`Total: $${inv.total ?? 0}`);
|
|
65682
|
+
console.log(`Paid: $${inv.paidTotal ?? 0}`);
|
|
65683
|
+
if (inv.void_date) console.log(`Void Date: ${inv.void_date}`);
|
|
65684
|
+
if (inv.invoice_remark) console.log(`Remark: ${inv.invoice_remark}`);
|
|
65685
|
+
if (inv.items?.length) {
|
|
65686
|
+
console.log("\n--- Items ---");
|
|
65687
|
+
inv.items.forEach((item, i) => {
|
|
65688
|
+
console.log(` [${i + 1}] ${item.description ?? "-"} | qty:${item.qty ?? 1} x $${item.unit_price ?? 0} | total:$${item.total ?? 0}${item.remark ? ` | ${item.remark}` : ""}`);
|
|
65689
|
+
});
|
|
65690
|
+
}
|
|
65691
|
+
}
|
|
65692
|
+
} catch (err) {
|
|
65693
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65694
|
+
console.error(`Failed to fetch invoice: ${message}`);
|
|
65695
|
+
process.exit(1);
|
|
65696
|
+
}
|
|
65697
|
+
});
|
|
65698
|
+
invoices2.command("add").description("Add a new invoice").requiredOption("-c, --client-id <id>", "Client ID").option("--client-name <value>", "Client name").option("--invoice-date <date>", "Invoice date (YYYY-MM-DD)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--attn <value>", "Attention (recipient name)").option("--email <value>", "Email").option("--phone <value>", "Phone").option("--addr1 <value>", "Address line 1").option("--addr2 <value>", "Address line 2").option("--addr3 <value>", "Address line 3").option("--city <value>", "City").option("--invoice-remark <value>", "Remark").option("--invoice-type <n>", "Invoice type").option("--invoice-send-via <n>", "Send via (int)").option("--quotation-ids <value>", "Linked quotation IDs").action(async (options) => {
|
|
65699
|
+
const client = getClient();
|
|
65700
|
+
const fieldMap = {
|
|
65701
|
+
clientId: ["client_id", (v) => parseInt(v)],
|
|
65702
|
+
clientName: ["client_name", (v) => JSON.stringify(v)],
|
|
65703
|
+
invoiceDate: ["invoice_date", (v) => JSON.stringify(v)],
|
|
65704
|
+
dueDate: ["due_date", (v) => JSON.stringify(v)],
|
|
65705
|
+
attn: ["attn", (v) => JSON.stringify(v)],
|
|
65706
|
+
email: ["email", (v) => JSON.stringify(v)],
|
|
65707
|
+
phone: ["phone", (v) => JSON.stringify(v)],
|
|
65708
|
+
addr1: ["addr1", (v) => JSON.stringify(v)],
|
|
65709
|
+
addr2: ["addr2", (v) => JSON.stringify(v)],
|
|
65710
|
+
addr3: ["addr3", (v) => JSON.stringify(v)],
|
|
65711
|
+
city: ["city", (v) => JSON.stringify(v)],
|
|
65712
|
+
invoiceRemark: ["invoice_remark", (v) => JSON.stringify(v)],
|
|
65713
|
+
invoiceType: ["invoice_type", (v) => parseInt(v)],
|
|
65714
|
+
invoiceSendVia: ["invoice_send_via", (v) => parseInt(v)],
|
|
65715
|
+
quotationIds: ["quotation_ids", (v) => JSON.stringify(v)]
|
|
65716
|
+
};
|
|
65717
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
65718
|
+
const mutation = gql`
|
|
65719
|
+
mutation {
|
|
65720
|
+
addInvoice(data: { ${fields.join(", ")} })
|
|
65721
|
+
}
|
|
65722
|
+
`;
|
|
65723
|
+
try {
|
|
65724
|
+
const data = await client.request(mutation);
|
|
65725
|
+
const newId = data?.addInvoice;
|
|
65726
|
+
console.log(`Created invoice [${newId}].`);
|
|
65727
|
+
} catch (err) {
|
|
65728
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65729
|
+
console.error(`Failed to add invoice: ${message}`);
|
|
65730
|
+
process.exit(1);
|
|
65731
|
+
}
|
|
65732
|
+
});
|
|
65733
|
+
invoices2.command("update <id>").description("Update an invoice by ID").option("--client-id <id>", "Client ID").option("--client-name <value>", "Client name").option("--invoice-date <date>", "Invoice date (YYYY-MM-DD)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--attn <value>", "Attention (recipient name)").option("--email <value>", "Email").option("--phone <value>", "Phone").option("--addr1 <value>", "Address line 1").option("--addr2 <value>", "Address line 2").option("--addr3 <value>", "Address line 3").option("--city <value>", "City").option("--invoice-remark <value>", "Remark").option("--invoice-type <n>", "Invoice type").option("--invoice-send-via <n>", "Send via (int)").option("--void-date <date>", "Void date (YYYY-MM-DD)").action(async (id, options) => {
|
|
65734
|
+
const client = getClient();
|
|
65735
|
+
const fieldMap = {
|
|
65736
|
+
clientId: ["client_id", (v) => parseInt(v)],
|
|
65737
|
+
clientName: ["client_name", (v) => JSON.stringify(v)],
|
|
65738
|
+
invoiceDate: ["invoice_date", (v) => JSON.stringify(v)],
|
|
65739
|
+
dueDate: ["due_date", (v) => JSON.stringify(v)],
|
|
65740
|
+
attn: ["attn", (v) => JSON.stringify(v)],
|
|
65741
|
+
email: ["email", (v) => JSON.stringify(v)],
|
|
65742
|
+
phone: ["phone", (v) => JSON.stringify(v)],
|
|
65743
|
+
addr1: ["addr1", (v) => JSON.stringify(v)],
|
|
65744
|
+
addr2: ["addr2", (v) => JSON.stringify(v)],
|
|
65745
|
+
addr3: ["addr3", (v) => JSON.stringify(v)],
|
|
65746
|
+
city: ["city", (v) => JSON.stringify(v)],
|
|
65747
|
+
invoiceRemark: ["invoice_remark", (v) => JSON.stringify(v)],
|
|
65748
|
+
invoiceType: ["invoice_type", (v) => parseInt(v)],
|
|
65749
|
+
invoiceSendVia: ["invoice_send_via", (v) => parseInt(v)],
|
|
65750
|
+
voidDate: ["void_date", (v) => JSON.stringify(v)]
|
|
65751
|
+
};
|
|
65752
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
65753
|
+
if (fields.length === 0) {
|
|
65754
|
+
console.error("No fields to update. Provide at least one option.");
|
|
65755
|
+
process.exit(1);
|
|
65756
|
+
}
|
|
65757
|
+
const mutation = gql`
|
|
65758
|
+
mutation {
|
|
65759
|
+
updateInvoice(id: ${parseInt(id)}, data: { ${fields.join(", ")} })
|
|
65760
|
+
}
|
|
65761
|
+
`;
|
|
65762
|
+
try {
|
|
65763
|
+
const data = await client.request(mutation);
|
|
65764
|
+
if (data?.updateInvoice) {
|
|
65765
|
+
console.log(`Updated invoice [${id}].`);
|
|
65766
|
+
} else {
|
|
65767
|
+
console.error("Update failed.");
|
|
65768
|
+
process.exit(1);
|
|
65769
|
+
}
|
|
65770
|
+
} catch (err) {
|
|
65771
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65772
|
+
console.error(`Failed to update invoice: ${message}`);
|
|
65773
|
+
process.exit(1);
|
|
65774
|
+
}
|
|
65775
|
+
});
|
|
65776
|
+
invoices2.command("delete <id>").description("Delete an invoice by ID").action(async (id) => {
|
|
65777
|
+
const client = getClient();
|
|
65778
|
+
const mutation = gql`
|
|
65779
|
+
mutation {
|
|
65780
|
+
deleteInvoice(id: ${parseInt(id)})
|
|
65781
|
+
}
|
|
65782
|
+
`;
|
|
65783
|
+
try {
|
|
65784
|
+
const data = await client.request(mutation);
|
|
65785
|
+
if (data?.deleteInvoice) {
|
|
65786
|
+
console.log(`Deleted invoice [${id}].`);
|
|
65787
|
+
} else {
|
|
65788
|
+
console.error("Delete failed.");
|
|
65789
|
+
process.exit(1);
|
|
65790
|
+
}
|
|
65791
|
+
} catch (err) {
|
|
65792
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65793
|
+
console.error(`Failed to delete invoice: ${message}`);
|
|
65794
|
+
process.exit(1);
|
|
65795
|
+
}
|
|
65796
|
+
});
|
|
65797
|
+
invoices2.command("pdf <id>").description("Get the PDF download link for an invoice").option("-s, --save [filename]", "Download and save PDF to local file").action(async (id, options) => {
|
|
65798
|
+
const client = getClient();
|
|
65799
|
+
const query = gql`
|
|
65800
|
+
query {
|
|
65801
|
+
listInvoice(filters: { invoice_id: ${parseInt(id)} }) {
|
|
65802
|
+
data {
|
|
65803
|
+
invoice_id
|
|
65804
|
+
invoice_no
|
|
65805
|
+
pdfLink
|
|
65806
|
+
downloadUrl
|
|
65807
|
+
}
|
|
65808
|
+
}
|
|
65809
|
+
}
|
|
65810
|
+
`;
|
|
65811
|
+
try {
|
|
65812
|
+
const data = await client.request(query);
|
|
65813
|
+
const list = data?.listInvoice?.data ?? [];
|
|
65814
|
+
if (list.length === 0) {
|
|
65815
|
+
console.error(`Invoice [${id}] not found.`);
|
|
65816
|
+
process.exit(1);
|
|
65817
|
+
}
|
|
65818
|
+
const inv = list[0];
|
|
65819
|
+
const link = inv.pdfLink || inv.downloadUrl;
|
|
65820
|
+
if (!link) {
|
|
65821
|
+
console.error("No PDF link available for this invoice.");
|
|
65822
|
+
process.exit(1);
|
|
65823
|
+
}
|
|
65824
|
+
if (options.save !== void 0) {
|
|
65825
|
+
const https = require("https");
|
|
65826
|
+
const http = require("http");
|
|
65827
|
+
const fs = require("fs");
|
|
65828
|
+
const path = require("path");
|
|
65829
|
+
const filename = typeof options.save === "string" ? options.save : `invoice-${inv.invoice_no ?? id}.pdf`;
|
|
65830
|
+
const filepath = path.resolve(filename);
|
|
65831
|
+
const protocol = link.startsWith("https") ? https : http;
|
|
65832
|
+
const token = config2.get("token");
|
|
65833
|
+
const urlObj = new URL(link);
|
|
65834
|
+
const reqOptions = {
|
|
65835
|
+
hostname: urlObj.hostname,
|
|
65836
|
+
path: urlObj.pathname + urlObj.search,
|
|
65837
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
65838
|
+
};
|
|
65839
|
+
console.log(`Downloading to: ${filepath}`);
|
|
65840
|
+
const file = fs.createWriteStream(filepath);
|
|
65841
|
+
protocol.get(reqOptions, (res) => {
|
|
65842
|
+
if (res.statusCode !== 200) {
|
|
65843
|
+
console.error(`Download failed: HTTP ${res.statusCode}`);
|
|
65844
|
+
fs.unlinkSync(filepath);
|
|
65845
|
+
process.exit(1);
|
|
65846
|
+
}
|
|
65847
|
+
res.pipe(file);
|
|
65848
|
+
file.on("finish", () => {
|
|
65849
|
+
file.close();
|
|
65850
|
+
console.log(`Saved: ${filepath}`);
|
|
65851
|
+
});
|
|
65852
|
+
}).on("error", (err) => {
|
|
65853
|
+
fs.unlinkSync(filepath);
|
|
65854
|
+
console.error(`Download error: ${err.message}`);
|
|
65855
|
+
process.exit(1);
|
|
65856
|
+
});
|
|
65857
|
+
} else {
|
|
65858
|
+
console.log(`Invoice: [${inv.invoice_id}] #${inv.invoice_no ?? ""}`);
|
|
65859
|
+
console.log(`PDF Link: ${link}`);
|
|
65860
|
+
}
|
|
65861
|
+
} catch (err) {
|
|
65862
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65863
|
+
console.error(`Failed to fetch PDF link: ${message}`);
|
|
65864
|
+
process.exit(1);
|
|
65865
|
+
}
|
|
65866
|
+
});
|
|
65867
|
+
}
|
|
65868
|
+
module2.exports = { register };
|
|
65869
|
+
}
|
|
65870
|
+
});
|
|
65871
|
+
|
|
65872
|
+
// src/invoice-items/index.js
|
|
65873
|
+
var require_invoice_items = __commonJS({
|
|
65874
|
+
"src/invoice-items/index.js"(exports2, module2) {
|
|
65875
|
+
var { GraphQLClient, gql } = require_main();
|
|
65876
|
+
var Conf2 = require_source();
|
|
65877
|
+
var config2 = new Conf2({ projectName: "hostlink-cli" });
|
|
65878
|
+
var ENDPOINT = "https://isapi.hostlink.com.hk/";
|
|
65879
|
+
function getClient() {
|
|
65880
|
+
const token = config2.get("token");
|
|
65881
|
+
if (!token) {
|
|
65882
|
+
console.error("No token found. Run `hostlink set-token <token>` first.");
|
|
65883
|
+
process.exit(1);
|
|
65884
|
+
}
|
|
65885
|
+
return new GraphQLClient(ENDPOINT, {
|
|
65886
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
65887
|
+
});
|
|
65888
|
+
}
|
|
65889
|
+
function register(program2) {
|
|
65890
|
+
const items = program2.command("invoice-items").description("Manage invoice items (PaymentPeriod)");
|
|
65891
|
+
items.command("list <invoice_id>").description("List items of an invoice").option("--json", "Output as JSON").action(async (invoice_id, options) => {
|
|
65892
|
+
const client = getClient();
|
|
65893
|
+
const query = gql`
|
|
65894
|
+
query {
|
|
65895
|
+
listPaymentPeriod(filters: { invoice_id: ${parseInt(invoice_id)} }) {
|
|
65896
|
+
data {
|
|
65897
|
+
paymentperiod_id
|
|
65898
|
+
invoice_id
|
|
65899
|
+
sequence
|
|
65900
|
+
description
|
|
65901
|
+
unit_price
|
|
65902
|
+
qty
|
|
65903
|
+
free_month
|
|
65904
|
+
discount
|
|
65905
|
+
subtotal
|
|
65906
|
+
total
|
|
65907
|
+
remark
|
|
65908
|
+
period_from
|
|
65909
|
+
period_to
|
|
65910
|
+
clientservice_id
|
|
65911
|
+
}
|
|
65912
|
+
}
|
|
65913
|
+
}
|
|
65914
|
+
`;
|
|
65915
|
+
try {
|
|
65916
|
+
const data = await client.request(query);
|
|
65917
|
+
const list = data?.listPaymentPeriod?.data ?? [];
|
|
65918
|
+
if (options.json) {
|
|
65919
|
+
console.log(JSON.stringify(list, null, 2));
|
|
65920
|
+
} else if (list.length === 0) {
|
|
65921
|
+
console.log("No items found.");
|
|
65922
|
+
} else {
|
|
65923
|
+
list.forEach(
|
|
65924
|
+
(i) => console.log(`[${i.paymentperiod_id}] #${i.sequence ?? "-"} ${i.description ?? "-"} | qty:${i.qty ?? "-"} x $${i.unit_price ?? 0} | discount:${i.discount ?? 0}% | total:$${i.total ?? 0}${i.remark ? ` | ${i.remark}` : ""}`)
|
|
65925
|
+
);
|
|
65926
|
+
console.log(`
|
|
65927
|
+
Total items: ${list.length}`);
|
|
65928
|
+
}
|
|
65929
|
+
} catch (err) {
|
|
65930
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65931
|
+
console.error(`Failed to fetch invoice items: ${message}`);
|
|
65932
|
+
process.exit(1);
|
|
65933
|
+
}
|
|
65934
|
+
});
|
|
65935
|
+
items.command("get <id>").description("Get an invoice item by ID").option("--json", "Output as JSON").action(async (id, options) => {
|
|
65936
|
+
const client = getClient();
|
|
65937
|
+
const query = gql`
|
|
65938
|
+
query {
|
|
65939
|
+
listPaymentPeriod(filters: { paymentperiod_id: ${parseInt(id)} }) {
|
|
65940
|
+
data {
|
|
65941
|
+
paymentperiod_id
|
|
65942
|
+
invoice_id
|
|
65943
|
+
sequence
|
|
65944
|
+
description
|
|
65945
|
+
unit_price
|
|
65946
|
+
qty
|
|
65947
|
+
unit_month
|
|
65948
|
+
free_month
|
|
65949
|
+
discount
|
|
65950
|
+
subtotal
|
|
65951
|
+
total
|
|
65952
|
+
remark
|
|
65953
|
+
period_from
|
|
65954
|
+
period_to
|
|
65955
|
+
clientservice_id
|
|
65956
|
+
quotation_id
|
|
65957
|
+
}
|
|
65958
|
+
}
|
|
65959
|
+
}
|
|
65960
|
+
`;
|
|
65961
|
+
try {
|
|
65962
|
+
const data = await client.request(query);
|
|
65963
|
+
const list = data?.listPaymentPeriod?.data ?? [];
|
|
65964
|
+
if (list.length === 0) {
|
|
65965
|
+
console.error(`Invoice item [${id}] not found.`);
|
|
65966
|
+
process.exit(1);
|
|
65967
|
+
}
|
|
65968
|
+
const i = list[0];
|
|
65969
|
+
if (options.json) {
|
|
65970
|
+
console.log(JSON.stringify(i, null, 2));
|
|
65971
|
+
} else {
|
|
65972
|
+
console.log(`ID: ${i.paymentperiod_id}`);
|
|
65973
|
+
console.log(`Invoice ID: ${i.invoice_id}`);
|
|
65974
|
+
console.log(`Sequence: ${i.sequence ?? "-"}`);
|
|
65975
|
+
console.log(`Description: ${i.description ?? "-"}`);
|
|
65976
|
+
console.log(`Unit Price: $${i.unit_price ?? 0}`);
|
|
65977
|
+
console.log(`Qty: ${i.qty ?? "-"}`);
|
|
65978
|
+
console.log(`Unit Month: ${i.unit_month ?? 1}`);
|
|
65979
|
+
console.log(`Free Month: ${i.free_month ?? 0}`);
|
|
65980
|
+
console.log(`Discount: ${i.discount ?? 0}%`);
|
|
65981
|
+
console.log(`Subtotal: $${i.subtotal ?? 0}`);
|
|
65982
|
+
console.log(`Total: $${i.total ?? 0}`);
|
|
65983
|
+
console.log(`Period: ${i.period_from ?? "-"} \u2192 ${i.period_to ?? "-"}`);
|
|
65984
|
+
if (i.remark) console.log(`Remark: ${i.remark}`);
|
|
65985
|
+
if (i.clientservice_id) console.log(`Client Svc ID: ${i.clientservice_id}`);
|
|
65986
|
+
if (i.quotation_id) console.log(`Quotation ID: ${i.quotation_id}`);
|
|
65987
|
+
}
|
|
65988
|
+
} catch (err) {
|
|
65989
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
65990
|
+
console.error(`Failed to fetch invoice item: ${message}`);
|
|
65991
|
+
process.exit(1);
|
|
65992
|
+
}
|
|
65993
|
+
});
|
|
65994
|
+
items.command("add").description("Add a new item to an invoice").requiredOption("-i, --invoice-id <id>", "Invoice ID").option("--unit-price <n>", "Unit price").option("--qty <n>", "Quantity").option("--unit-month <n>", "Number of months", "1").option("--free-month <n>", "Free months").option("--discount <n>", "Discount percentage").option("--subtotal <n>", "Subtotal (override)").option("--remark <value>", "Remark").option("--sequence <n>", "Display sequence order").option("--period-from <date>", "Service period start (YYYY-MM-DD)").option("--period-to <date>", "Service period end (YYYY-MM-DD)").option("--clientservice-id <n>", "Client service ID").option("--quotation-id <n>", "Linked quotation ID").action(async (options) => {
|
|
65995
|
+
const client = getClient();
|
|
65996
|
+
const fieldMap = {
|
|
65997
|
+
invoiceId: ["invoice_id", (v) => parseInt(v)],
|
|
65998
|
+
unitPrice: ["unit_price", (v) => parseFloat(v)],
|
|
65999
|
+
qty: ["qty", (v) => parseFloat(v)],
|
|
66000
|
+
unitMonth: ["unit_month", (v) => parseInt(v)],
|
|
66001
|
+
freeMonth: ["free_month", (v) => parseInt(v)],
|
|
66002
|
+
discount: ["discount", (v) => parseFloat(v)],
|
|
66003
|
+
subtotal: ["subtotal", (v) => parseFloat(v)],
|
|
66004
|
+
remark: ["remark", (v) => JSON.stringify(v)],
|
|
66005
|
+
sequence: ["sequence", (v) => parseInt(v)],
|
|
66006
|
+
periodFrom: ["period_from", (v) => JSON.stringify(v)],
|
|
66007
|
+
periodTo: ["period_to", (v) => JSON.stringify(v)],
|
|
66008
|
+
clientserviceId: ["clientservice_id", (v) => parseInt(v)],
|
|
66009
|
+
quotationId: ["quotation_id", (v) => parseInt(v)]
|
|
66010
|
+
};
|
|
66011
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
66012
|
+
const mutation = gql`
|
|
66013
|
+
mutation {
|
|
66014
|
+
addPaymentPeriod(data: { ${fields.join(", ")} })
|
|
66015
|
+
}
|
|
66016
|
+
`;
|
|
66017
|
+
try {
|
|
66018
|
+
const data = await client.request(mutation);
|
|
66019
|
+
const newId = data?.addPaymentPeriod;
|
|
66020
|
+
console.log(`Created invoice item [${newId}].`);
|
|
66021
|
+
} catch (err) {
|
|
66022
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66023
|
+
console.error(`Failed to add invoice item: ${message}`);
|
|
66024
|
+
process.exit(1);
|
|
66025
|
+
}
|
|
66026
|
+
});
|
|
66027
|
+
items.command("update <id>").description("Update an invoice item by ID").option("--invoice-id <id>", "Invoice ID").option("--unit-price <n>", "Unit price").option("--qty <n>", "Quantity").option("--unit-month <n>", "Number of months").option("--free-month <n>", "Free months").option("--discount <n>", "Discount percentage").option("--subtotal <n>", "Subtotal (override)").option("--remark <value>", "Remark").option("--sequence <n>", "Display sequence order").option("--period-from <date>", "Service period start (YYYY-MM-DD)").option("--period-to <date>", "Service period end (YYYY-MM-DD)").option("--clientservice-id <n>", "Client service ID").option("--quotation-id <n>", "Linked quotation ID").action(async (id, options) => {
|
|
66028
|
+
const client = getClient();
|
|
66029
|
+
const fieldMap = {
|
|
66030
|
+
invoiceId: ["invoice_id", (v) => parseInt(v)],
|
|
66031
|
+
unitPrice: ["unit_price", (v) => parseFloat(v)],
|
|
66032
|
+
qty: ["qty", (v) => parseFloat(v)],
|
|
66033
|
+
unitMonth: ["unit_month", (v) => parseInt(v)],
|
|
66034
|
+
freeMonth: ["free_month", (v) => parseInt(v)],
|
|
66035
|
+
discount: ["discount", (v) => parseFloat(v)],
|
|
66036
|
+
subtotal: ["subtotal", (v) => parseFloat(v)],
|
|
66037
|
+
remark: ["remark", (v) => JSON.stringify(v)],
|
|
66038
|
+
sequence: ["sequence", (v) => parseInt(v)],
|
|
66039
|
+
periodFrom: ["period_from", (v) => JSON.stringify(v)],
|
|
66040
|
+
periodTo: ["period_to", (v) => JSON.stringify(v)],
|
|
66041
|
+
clientserviceId: ["clientservice_id", (v) => parseInt(v)],
|
|
66042
|
+
quotationId: ["quotation_id", (v) => parseInt(v)]
|
|
66043
|
+
};
|
|
66044
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
66045
|
+
if (fields.length === 0) {
|
|
66046
|
+
console.error("No fields to update. Provide at least one option.");
|
|
66047
|
+
process.exit(1);
|
|
66048
|
+
}
|
|
66049
|
+
const mutation = gql`
|
|
66050
|
+
mutation {
|
|
66051
|
+
updatePaymentPeriod(id: ${parseInt(id)}, data: { ${fields.join(", ")} })
|
|
66052
|
+
}
|
|
66053
|
+
`;
|
|
66054
|
+
try {
|
|
66055
|
+
const data = await client.request(mutation);
|
|
66056
|
+
if (data?.updatePaymentPeriod) {
|
|
66057
|
+
console.log(`Updated invoice item [${id}].`);
|
|
66058
|
+
} else {
|
|
66059
|
+
console.error("Update failed.");
|
|
66060
|
+
process.exit(1);
|
|
66061
|
+
}
|
|
66062
|
+
} catch (err) {
|
|
66063
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66064
|
+
console.error(`Failed to update invoice item: ${message}`);
|
|
66065
|
+
process.exit(1);
|
|
66066
|
+
}
|
|
66067
|
+
});
|
|
66068
|
+
items.command("delete <id>").description("Delete an invoice item by ID").action(async (id) => {
|
|
66069
|
+
const client = getClient();
|
|
66070
|
+
const mutation = gql`
|
|
66071
|
+
mutation {
|
|
66072
|
+
deletePaymentPeriod(id: ${parseInt(id)})
|
|
66073
|
+
}
|
|
66074
|
+
`;
|
|
66075
|
+
try {
|
|
66076
|
+
const data = await client.request(mutation);
|
|
66077
|
+
if (data?.deletePaymentPeriod) {
|
|
66078
|
+
console.log(`Deleted invoice item [${id}].`);
|
|
66079
|
+
} else {
|
|
66080
|
+
console.error("Delete failed.");
|
|
66081
|
+
process.exit(1);
|
|
66082
|
+
}
|
|
66083
|
+
} catch (err) {
|
|
66084
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66085
|
+
console.error(`Failed to delete invoice item: ${message}`);
|
|
66086
|
+
process.exit(1);
|
|
66087
|
+
}
|
|
66088
|
+
});
|
|
66089
|
+
}
|
|
66090
|
+
module2.exports = { register };
|
|
66091
|
+
}
|
|
66092
|
+
});
|
|
66093
|
+
|
|
66094
|
+
// src/client-services/index.js
|
|
66095
|
+
var require_client_services = __commonJS({
|
|
66096
|
+
"src/client-services/index.js"(exports2, module2) {
|
|
66097
|
+
var { GraphQLClient, gql } = require_main();
|
|
66098
|
+
var Conf2 = require_source();
|
|
66099
|
+
var config2 = new Conf2({ projectName: "hostlink-cli" });
|
|
66100
|
+
var ENDPOINT = "https://isapi.hostlink.com.hk/";
|
|
66101
|
+
function getClient() {
|
|
66102
|
+
const token = config2.get("token");
|
|
66103
|
+
if (!token) {
|
|
66104
|
+
console.error("No token found. Run `hostlink set-token <token>` first.");
|
|
66105
|
+
process.exit(1);
|
|
66106
|
+
}
|
|
66107
|
+
return new GraphQLClient(ENDPOINT, {
|
|
66108
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
66109
|
+
});
|
|
66110
|
+
}
|
|
66111
|
+
function register(program2) {
|
|
66112
|
+
const cs = program2.command("client-services").description("Manage client services");
|
|
66113
|
+
cs.command("list").description("List client services").option("-c, --client <id>", "Filter by client ID").option("-s, --search <text>", "Filter by name (contains)").option("--service <id>", "Filter by service ID").option("-l, --limit <n>", "Max records to return", "50").option("-o, --offset <n>", "Records to skip", "0").option("--json", "Output as JSON").action(async (options) => {
|
|
66114
|
+
const client = getClient();
|
|
66115
|
+
const filterParts = [];
|
|
66116
|
+
if (options.client) filterParts.push(`client_id: ${parseInt(options.client)}`);
|
|
66117
|
+
if (options.service) filterParts.push(`service_id: ${parseInt(options.service)}`);
|
|
66118
|
+
if (options.search) filterParts.push(`name: { contains: ${JSON.stringify(options.search)} }`);
|
|
66119
|
+
const filters = filterParts.length ? `filters: { ${filterParts.join(", ")} }` : "";
|
|
66120
|
+
const pagination = `limit: ${parseInt(options.limit)}, offset: ${parseInt(options.offset)}`;
|
|
66121
|
+
const query = gql`
|
|
66122
|
+
query {
|
|
66123
|
+
listClientService${filters ? `(${filters})` : ""} {
|
|
66124
|
+
meta { total }
|
|
66125
|
+
data(${pagination}) {
|
|
66126
|
+
clientservice_id
|
|
66127
|
+
client_id
|
|
66128
|
+
name
|
|
66129
|
+
title
|
|
66130
|
+
unit_price
|
|
66131
|
+
unit_month
|
|
66132
|
+
unit_quantity
|
|
66133
|
+
discount
|
|
66134
|
+
join_date
|
|
66135
|
+
end_date
|
|
66136
|
+
paidPeriodTo
|
|
66137
|
+
paymentPeriodTo
|
|
66138
|
+
no_invoice
|
|
66139
|
+
clientservice_type
|
|
66140
|
+
}
|
|
66141
|
+
}
|
|
66142
|
+
}
|
|
66143
|
+
`;
|
|
66144
|
+
try {
|
|
66145
|
+
const data = await client.request(query);
|
|
66146
|
+
const list = data?.listClientService?.data ?? [];
|
|
66147
|
+
const total = data?.listClientService?.meta?.total ?? list.length;
|
|
66148
|
+
if (options.json) {
|
|
66149
|
+
console.log(JSON.stringify({ total, data: list }, null, 2));
|
|
66150
|
+
} else if (list.length === 0) {
|
|
66151
|
+
console.log("No client services found.");
|
|
66152
|
+
} else {
|
|
66153
|
+
list.forEach(
|
|
66154
|
+
(s) => console.log(`[${s.clientservice_id}] ${s.name ?? s.title ?? "-"} | client:${s.client_id} | $${s.unit_price ?? 0}/${s.unit_month ?? 1}mo | joined:${s.join_date ?? "-"} | paid to:${s.paidPeriodTo ?? "-"}${s.no_invoice ? " [no-invoice]" : ""}`)
|
|
66155
|
+
);
|
|
66156
|
+
console.log(`
|
|
66157
|
+
Total: ${total}`);
|
|
66158
|
+
}
|
|
66159
|
+
} catch (err) {
|
|
66160
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66161
|
+
console.error(`Failed to fetch client services: ${message}`);
|
|
66162
|
+
process.exit(1);
|
|
66163
|
+
}
|
|
66164
|
+
});
|
|
66165
|
+
cs.command("get <id>").description("Get a client service by ID").option("--json", "Output as JSON").action(async (id, options) => {
|
|
66166
|
+
const client = getClient();
|
|
66167
|
+
const query = gql`
|
|
66168
|
+
query {
|
|
66169
|
+
listClientService(filters: { clientservice_id: ${parseInt(id)} }) {
|
|
66170
|
+
data {
|
|
66171
|
+
clientservice_id
|
|
66172
|
+
client_id
|
|
66173
|
+
service_id
|
|
66174
|
+
domain_id
|
|
66175
|
+
quotation_id
|
|
66176
|
+
name
|
|
66177
|
+
title
|
|
66178
|
+
join_date
|
|
66179
|
+
end_date
|
|
66180
|
+
unit_price
|
|
66181
|
+
unit_month
|
|
66182
|
+
unit_quantity
|
|
66183
|
+
discount
|
|
66184
|
+
remark
|
|
66185
|
+
clientservice_type
|
|
66186
|
+
no_invoice
|
|
66187
|
+
renew_day
|
|
66188
|
+
termination_date
|
|
66189
|
+
termination_no
|
|
66190
|
+
termination_reason
|
|
66191
|
+
expect_termination_date
|
|
66192
|
+
paidPeriodTo
|
|
66193
|
+
paymentPeriodTo
|
|
66194
|
+
revenue
|
|
66195
|
+
lastPaymentPeriod {
|
|
66196
|
+
paymentperiod_id
|
|
66197
|
+
period_from
|
|
66198
|
+
period_to
|
|
66199
|
+
total
|
|
66200
|
+
}
|
|
66201
|
+
lastInvoice {
|
|
66202
|
+
invoice_id
|
|
66203
|
+
invoice_no
|
|
66204
|
+
invoice_date
|
|
66205
|
+
status
|
|
66206
|
+
total
|
|
66207
|
+
}
|
|
66208
|
+
}
|
|
66209
|
+
}
|
|
66210
|
+
}
|
|
66211
|
+
`;
|
|
66212
|
+
try {
|
|
66213
|
+
const data = await client.request(query);
|
|
66214
|
+
const list = data?.listClientService?.data ?? [];
|
|
66215
|
+
if (list.length === 0) {
|
|
66216
|
+
console.error(`Client service [${id}] not found.`);
|
|
66217
|
+
process.exit(1);
|
|
66218
|
+
}
|
|
66219
|
+
const s = list[0];
|
|
66220
|
+
if (options.json) {
|
|
66221
|
+
console.log(JSON.stringify(s, null, 2));
|
|
66222
|
+
} else {
|
|
66223
|
+
console.log(`ID: ${s.clientservice_id}`);
|
|
66224
|
+
console.log(`Client ID: ${s.client_id}`);
|
|
66225
|
+
console.log(`Service ID: ${s.service_id ?? "-"}`);
|
|
66226
|
+
console.log(`Domain ID: ${s.domain_id ?? "-"}`);
|
|
66227
|
+
console.log(`Quotation ID: ${s.quotation_id ?? "-"}`);
|
|
66228
|
+
console.log(`Name: ${s.name ?? "-"}`);
|
|
66229
|
+
console.log(`Title: ${s.title ?? "-"}`);
|
|
66230
|
+
console.log(`Join Date: ${s.join_date ?? "-"}`);
|
|
66231
|
+
console.log(`End Date: ${s.end_date ?? "-"}`);
|
|
66232
|
+
console.log(`Unit Price: $${s.unit_price ?? 0}`);
|
|
66233
|
+
console.log(`Unit Month: ${s.unit_month ?? 1}`);
|
|
66234
|
+
console.log(`Unit Quantity: ${s.unit_quantity ?? 1}`);
|
|
66235
|
+
console.log(`Discount: ${s.discount ?? 0}%`);
|
|
66236
|
+
console.log(`Renew Day: ${s.renew_day ?? "-"}`);
|
|
66237
|
+
console.log(`Type: ${s.clientservice_type ?? "-"}`);
|
|
66238
|
+
console.log(`No Invoice: ${s.no_invoice ? "Yes" : "No"}`);
|
|
66239
|
+
console.log(`Paid Period To: ${s.paidPeriodTo ?? "-"}`);
|
|
66240
|
+
console.log(`Payment Period To: ${s.paymentPeriodTo ?? "-"}`);
|
|
66241
|
+
console.log(`Revenue: $${s.revenue ?? 0}`);
|
|
66242
|
+
if (s.remark) console.log(`Remark: ${s.remark}`);
|
|
66243
|
+
if (s.termination_date) {
|
|
66244
|
+
console.log(`Termination Date: ${s.termination_date}`);
|
|
66245
|
+
console.log(`Termination Reason: ${s.termination_reason ?? "-"}`);
|
|
66246
|
+
}
|
|
66247
|
+
if (s.lastInvoice) {
|
|
66248
|
+
const inv = s.lastInvoice;
|
|
66249
|
+
console.log(`
|
|
66250
|
+
Last Invoice: [${inv.invoice_id}] #${inv.invoice_no ?? "-"} | ${inv.invoice_date ?? "-"} | ${inv.status ?? "-"} | $${inv.total ?? 0}`);
|
|
66251
|
+
}
|
|
66252
|
+
if (s.lastPaymentPeriod) {
|
|
66253
|
+
const pp = s.lastPaymentPeriod;
|
|
66254
|
+
console.log(`Last Payment Period: [${pp.paymentperiod_id}] ${pp.period_from ?? "-"} \u2192 ${pp.period_to ?? "-"} | $${pp.total ?? 0}`);
|
|
66255
|
+
}
|
|
66256
|
+
}
|
|
66257
|
+
} catch (err) {
|
|
66258
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66259
|
+
console.error(`Failed to fetch client service: ${message}`);
|
|
66260
|
+
process.exit(1);
|
|
66261
|
+
}
|
|
66262
|
+
});
|
|
66263
|
+
cs.command("add").description("Add a new client service").requiredOption("-c, --client-id <id>", "Client ID").option("--service-id <n>", "Service ID").option("--domain-id <n>", "Domain ID").option("--quotation-id <n>", "Linked quotation ID").option("--quotationitem-id <n>", "Linked quotation item ID").option("--name <value>", "Service name").option("--title <value>", "Display title").option("--join-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--unit-price <n>", "Unit price").option("--unit-month <n>", "Billing cycle in months").option("--unit-quantity <n>", "Quantity").option("--discount <n>", "Discount percentage").option("--remark <value>", "Remark").option("--clientservice-type <n>", "Service type (int)").option("--renew-day <n>", "Renewal day").option("--no-invoice", "Exclude from invoicing").option("--server-id <n>", "Server ID").action(async (options) => {
|
|
66264
|
+
const client = getClient();
|
|
66265
|
+
const fieldMap = {
|
|
66266
|
+
clientId: ["client_id", (v) => parseInt(v)],
|
|
66267
|
+
serviceId: ["service_id", (v) => parseInt(v)],
|
|
66268
|
+
domainId: ["domain_id", (v) => parseInt(v)],
|
|
66269
|
+
quotationId: ["quotation_id", (v) => parseInt(v)],
|
|
66270
|
+
quotationitemId: ["quotationitem_id", (v) => parseInt(v)],
|
|
66271
|
+
name: ["name", (v) => JSON.stringify(v)],
|
|
66272
|
+
title: ["title", (v) => JSON.stringify(v)],
|
|
66273
|
+
joinDate: ["join_date", (v) => JSON.stringify(v)],
|
|
66274
|
+
endDate: ["end_date", (v) => JSON.stringify(v)],
|
|
66275
|
+
unitPrice: ["unit_price", (v) => parseFloat(v)],
|
|
66276
|
+
unitMonth: ["unit_month", (v) => parseInt(v)],
|
|
66277
|
+
unitQuantity: ["unit_quantity", (v) => parseFloat(v)],
|
|
66278
|
+
discount: ["discount", (v) => parseFloat(v)],
|
|
66279
|
+
remark: ["remark", (v) => JSON.stringify(v)],
|
|
66280
|
+
clientserviceType: ["clientservice_type", (v) => parseInt(v)],
|
|
66281
|
+
renewDay: ["renew_day", (v) => parseInt(v)],
|
|
66282
|
+
serverId: ["server_id", (v) => parseInt(v)]
|
|
66283
|
+
};
|
|
66284
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
66285
|
+
if (options.noInvoice) fields.push("no_invoice: true");
|
|
66286
|
+
const mutation = gql`
|
|
66287
|
+
mutation {
|
|
66288
|
+
addClientService(data: { ${fields.join(", ")} })
|
|
66289
|
+
}
|
|
66290
|
+
`;
|
|
66291
|
+
try {
|
|
66292
|
+
const data = await client.request(mutation);
|
|
66293
|
+
const newId = data?.addClientService;
|
|
66294
|
+
console.log(`Created client service [${newId}].`);
|
|
66295
|
+
} catch (err) {
|
|
66296
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66297
|
+
console.error(`Failed to add client service: ${message}`);
|
|
66298
|
+
process.exit(1);
|
|
66299
|
+
}
|
|
66300
|
+
});
|
|
66301
|
+
cs.command("update <id>").description("Update a client service by ID").option("--client-id <id>", "Client ID").option("--service-id <n>", "Service ID").option("--domain-id <n>", "Domain ID").option("--quotation-id <n>", "Linked quotation ID").option("--name <value>", "Service name").option("--title <value>", "Display title").option("--join-date <date>", "Start date (YYYY-MM-DD)").option("--end-date <date>", "End date (YYYY-MM-DD)").option("--unit-price <n>", "Unit price").option("--unit-month <n>", "Billing cycle in months").option("--unit-quantity <n>", "Quantity").option("--discount <n>", "Discount percentage").option("--remark <value>", "Remark").option("--clientservice-type <n>", "Service type (int)").option("--renew-day <n>", "Renewal day").option("--termination-date <date>", "Termination date (YYYY-MM-DD)").option("--termination-no <n>", "Termination number").option("--termination-reason <value>", "Termination reason").option("--expect-termination-date <date>", "Expected termination date (YYYY-MM-DD)").option("--no-invoice", "Exclude from invoicing").action(async (id, options) => {
|
|
66302
|
+
const client = getClient();
|
|
66303
|
+
const fieldMap = {
|
|
66304
|
+
clientId: ["client_id", (v) => parseInt(v)],
|
|
66305
|
+
serviceId: ["service_id", (v) => parseInt(v)],
|
|
66306
|
+
domainId: ["domain_id", (v) => parseInt(v)],
|
|
66307
|
+
quotationId: ["quotation_id", (v) => parseInt(v)],
|
|
66308
|
+
name: ["name", (v) => JSON.stringify(v)],
|
|
66309
|
+
title: ["title", (v) => JSON.stringify(v)],
|
|
66310
|
+
joinDate: ["join_date", (v) => JSON.stringify(v)],
|
|
66311
|
+
endDate: ["end_date", (v) => JSON.stringify(v)],
|
|
66312
|
+
unitPrice: ["unit_price", (v) => parseFloat(v)],
|
|
66313
|
+
unitMonth: ["unit_month", (v) => parseInt(v)],
|
|
66314
|
+
unitQuantity: ["unit_quantity", (v) => parseFloat(v)],
|
|
66315
|
+
discount: ["discount", (v) => parseFloat(v)],
|
|
66316
|
+
remark: ["remark", (v) => JSON.stringify(v)],
|
|
66317
|
+
clientserviceType: ["clientservice_type", (v) => parseInt(v)],
|
|
66318
|
+
renewDay: ["renew_day", (v) => parseInt(v)],
|
|
66319
|
+
terminationDate: ["termination_date", (v) => JSON.stringify(v)],
|
|
66320
|
+
terminationNo: ["termination_no", (v) => parseInt(v)],
|
|
66321
|
+
terminationReason: ["termination_reason", (v) => JSON.stringify(v)],
|
|
66322
|
+
expectTerminationDate: ["expect_termination_date", (v) => JSON.stringify(v)]
|
|
66323
|
+
};
|
|
66324
|
+
const fields = Object.entries(fieldMap).filter(([optKey]) => options[optKey] != null).map(([optKey, [gqlKey, transform]]) => `${gqlKey}: ${transform(options[optKey])}`);
|
|
66325
|
+
if (options.noInvoice) fields.push("no_invoice: true");
|
|
66326
|
+
if (fields.length === 0) {
|
|
66327
|
+
console.error("No fields to update. Provide at least one option.");
|
|
66328
|
+
process.exit(1);
|
|
66329
|
+
}
|
|
66330
|
+
const mutation = gql`
|
|
66331
|
+
mutation {
|
|
66332
|
+
updateClientService(id: ${parseInt(id)}, data: { ${fields.join(", ")} })
|
|
66333
|
+
}
|
|
66334
|
+
`;
|
|
66335
|
+
try {
|
|
66336
|
+
const data = await client.request(mutation);
|
|
66337
|
+
if (data?.updateClientService) {
|
|
66338
|
+
console.log(`Updated client service [${id}].`);
|
|
66339
|
+
} else {
|
|
66340
|
+
console.error("Update failed.");
|
|
66341
|
+
process.exit(1);
|
|
66342
|
+
}
|
|
66343
|
+
} catch (err) {
|
|
66344
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66345
|
+
console.error(`Failed to update client service: ${message}`);
|
|
66346
|
+
process.exit(1);
|
|
66347
|
+
}
|
|
66348
|
+
});
|
|
66349
|
+
cs.command("delete <id>").description("Delete a client service by ID").action(async (id) => {
|
|
66350
|
+
const client = getClient();
|
|
66351
|
+
const mutation = gql`
|
|
66352
|
+
mutation {
|
|
66353
|
+
deleteClientService(id: ${parseInt(id)})
|
|
66354
|
+
}
|
|
66355
|
+
`;
|
|
66356
|
+
try {
|
|
66357
|
+
const data = await client.request(mutation);
|
|
66358
|
+
if (data?.deleteClientService) {
|
|
66359
|
+
console.log(`Deleted client service [${id}].`);
|
|
66360
|
+
} else {
|
|
66361
|
+
console.error("Delete failed.");
|
|
66362
|
+
process.exit(1);
|
|
66363
|
+
}
|
|
66364
|
+
} catch (err) {
|
|
66365
|
+
const message = err?.response?.errors?.[0]?.message ?? err.message;
|
|
66366
|
+
console.error(`Failed to delete client service: ${message}`);
|
|
66367
|
+
process.exit(1);
|
|
66368
|
+
}
|
|
66369
|
+
});
|
|
66370
|
+
}
|
|
66371
|
+
module2.exports = { register };
|
|
66372
|
+
}
|
|
66373
|
+
});
|
|
66374
|
+
|
|
65361
66375
|
// package.json
|
|
65362
66376
|
var require_package = __commonJS({
|
|
65363
66377
|
"package.json"(exports2, module2) {
|
|
65364
66378
|
module2.exports = {
|
|
65365
66379
|
name: "@hostlink/hostlink-cli",
|
|
65366
|
-
version: "1.0.
|
|
66380
|
+
version: "1.0.5",
|
|
65367
66381
|
description: "CLI tool for the HostLink platform",
|
|
65368
66382
|
main: "index.js",
|
|
65369
66383
|
bin: {
|
|
@@ -65408,10 +66422,14 @@ var { Command } = require_commander();
|
|
|
65408
66422
|
var Conf = require_source();
|
|
65409
66423
|
var clients = require_clients();
|
|
65410
66424
|
var domains = require_domains();
|
|
66425
|
+
var domainPasswords = require_domain_passwords();
|
|
65411
66426
|
var quotations = require_quotations();
|
|
65412
66427
|
var quotationItems = require_quotation_items();
|
|
65413
66428
|
var me = require_me();
|
|
65414
66429
|
var leave = require_leave();
|
|
66430
|
+
var invoices = require_invoices();
|
|
66431
|
+
var invoiceItems = require_invoice_items();
|
|
66432
|
+
var clientServices = require_client_services();
|
|
65415
66433
|
var config = new Conf({ projectName: "hostlink-cli" });
|
|
65416
66434
|
var program = new Command();
|
|
65417
66435
|
program.name("hostlink").description("HostLink CLI").version(require_package().version);
|
|
@@ -65422,9 +66440,13 @@ program.command("set-token <token>").description("Save your access token").actio
|
|
|
65422
66440
|
me.register(program);
|
|
65423
66441
|
clients.register(program);
|
|
65424
66442
|
domains.register(program);
|
|
66443
|
+
domainPasswords.register(program);
|
|
65425
66444
|
quotations.register(program);
|
|
65426
66445
|
quotationItems.register(program);
|
|
65427
66446
|
leave.register(program);
|
|
66447
|
+
invoices.register(program);
|
|
66448
|
+
invoiceItems.register(program);
|
|
66449
|
+
clientServices.register(program);
|
|
65428
66450
|
program.parse(process.argv);
|
|
65429
66451
|
/*! Bundled license information:
|
|
65430
66452
|
|
package/index.js
CHANGED
|
@@ -4,10 +4,14 @@ const { Command } = require('commander');
|
|
|
4
4
|
const Conf = require('conf');
|
|
5
5
|
const clients = require('./src/clients');
|
|
6
6
|
const domains = require('./src/domains');
|
|
7
|
+
const domainPasswords = require('./src/domain-passwords');
|
|
7
8
|
const quotations = require('./src/quotations');
|
|
8
9
|
const quotationItems = require('./src/quotation-items');
|
|
9
10
|
const me = require('./src/me');
|
|
10
11
|
const leave = require('./src/leave');
|
|
12
|
+
const invoices = require('./src/invoices');
|
|
13
|
+
const invoiceItems = require('./src/invoice-items');
|
|
14
|
+
const clientServices = require('./src/client-services');
|
|
11
15
|
|
|
12
16
|
const config = new Conf({ projectName: 'hostlink-cli' });
|
|
13
17
|
|
|
@@ -29,8 +33,12 @@ program
|
|
|
29
33
|
me.register(program);
|
|
30
34
|
clients.register(program);
|
|
31
35
|
domains.register(program);
|
|
36
|
+
domainPasswords.register(program);
|
|
32
37
|
quotations.register(program);
|
|
33
38
|
quotationItems.register(program);
|
|
34
39
|
leave.register(program);
|
|
40
|
+
invoices.register(program);
|
|
41
|
+
invoiceItems.register(program);
|
|
42
|
+
clientServices.register(program);
|
|
35
43
|
|
|
36
44
|
program.parse(process.argv);
|