not-manage 0.2.0 → 0.2.2
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/README.md +77 -27
- package/package.json +7 -4
- package/src/cli-options.js +278 -10
- package/src/cli.js +8 -51
- package/src/clio-api.js +33 -4
- package/src/commands-activities.js +11 -119
- package/src/commands-practice-areas.js +13 -66
- package/src/redaction-policy.js +98 -3
- package/src/redaction.js +5 -1
- package/src/resource-display.js +100 -0
- package/src/resource-handlers.js +81 -0
- package/src/resource-metadata.js +1639 -2
- package/src/resource-query-builder.js +80 -0
- package/src/resource-utils.js +48 -0
- package/src/commands-billable-clients.js +0 -105
- package/src/commands-billable-matters.js +0 -106
- package/src/commands-bills.js +0 -192
- package/src/commands-contacts.js +0 -121
- package/src/commands-matters.js +0 -156
- package/src/commands-tasks.js +0 -155
- package/src/commands-users.js +0 -134
- package/src/postinstall.js +0 -140
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const { compactQuery, parseLimit } = require("./resource-utils");
|
|
2
|
+
|
|
3
|
+
function toSnakeCase(name) {
|
|
4
|
+
return String(name).replace(/-/g, "_");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function deriveQueryKey(propertyName, optionDef) {
|
|
8
|
+
if (!optionDef || optionDef.query === false || optionDef.positional !== undefined) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (optionDef.query) {
|
|
13
|
+
return optionDef.query;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (propertyName === "all") {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return optionDef.option ? toSnakeCase(optionDef.option) : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readQueryValue(propertyName, optionDef, options, resourceMetadata, config) {
|
|
24
|
+
if (propertyName === "fields") {
|
|
25
|
+
return options.fields || resourceMetadata.defaultFields?.list;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (propertyName === "limit") {
|
|
29
|
+
return parseLimit(options.limit, config.limitMax);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const value = options[propertyName];
|
|
33
|
+
if (value === undefined || value === null || value === "") {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (optionDef.kind === "flag") {
|
|
38
|
+
return value ? true : undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (optionDef.kind === "boolean") {
|
|
42
|
+
return Boolean(value);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function buildListQueryFromResource(resourceMetadata, options = {}, config = {}) {
|
|
49
|
+
const schema = resourceMetadata?.optionSchema?.list || {};
|
|
50
|
+
const query = {};
|
|
51
|
+
|
|
52
|
+
Object.entries(schema).forEach(([propertyName, optionDef]) => {
|
|
53
|
+
const queryKey = deriveQueryKey(propertyName, optionDef);
|
|
54
|
+
if (!queryKey) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
query[queryKey] = readQueryValue(
|
|
59
|
+
propertyName,
|
|
60
|
+
optionDef,
|
|
61
|
+
options,
|
|
62
|
+
resourceMetadata,
|
|
63
|
+
config
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const withExtra =
|
|
68
|
+
typeof config.transform === "function"
|
|
69
|
+
? config.transform(compactQuery({ ...query }), options)
|
|
70
|
+
: query;
|
|
71
|
+
|
|
72
|
+
return compactQuery({
|
|
73
|
+
...(withExtra || {}),
|
|
74
|
+
...(config.extraQuery || {}),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
buildListQueryFromResource,
|
|
80
|
+
};
|
package/src/resource-utils.js
CHANGED
|
@@ -65,6 +65,50 @@ function readMatterLabel(matter) {
|
|
|
65
65
|
return matter.display_number || matter.number || matter.description || String(matter.id || "-");
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
function readStatus(status) {
|
|
69
|
+
if (!status) {
|
|
70
|
+
return "-";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (typeof status === "string") {
|
|
74
|
+
return status;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return status.name || status.value || status.state || "-";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function readHours(activity) {
|
|
81
|
+
const quantityInHours = Number(activity?.quantity_in_hours);
|
|
82
|
+
if (Number.isFinite(quantityInHours)) {
|
|
83
|
+
return quantityInHours.toFixed(2);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const quantity = Number(activity?.quantity);
|
|
87
|
+
if (Number.isFinite(quantity)) {
|
|
88
|
+
return (quantity / 3600).toFixed(2);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return "-";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readRoleList(user) {
|
|
95
|
+
const roles = Array.isArray(user?.roles) ? user.roles : [];
|
|
96
|
+
if (roles.length === 0) {
|
|
97
|
+
return "-";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return roles.join(", ");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function readFirstMatterLabel(record) {
|
|
104
|
+
const matters = Array.isArray(record?.matters) ? record.matters : [];
|
|
105
|
+
if (matters.length === 0) {
|
|
106
|
+
return "-";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return readMatterLabel(matters[0]);
|
|
110
|
+
}
|
|
111
|
+
|
|
68
112
|
function formatBoolean(value) {
|
|
69
113
|
if (value === undefined || value === null) {
|
|
70
114
|
return "-";
|
|
@@ -136,6 +180,10 @@ module.exports = {
|
|
|
136
180
|
parseLimit,
|
|
137
181
|
printKeyValueRows,
|
|
138
182
|
readContactName,
|
|
183
|
+
readFirstMatterLabel,
|
|
184
|
+
readHours,
|
|
139
185
|
readMatterLabel,
|
|
186
|
+
readRoleList,
|
|
187
|
+
readStatus,
|
|
140
188
|
readUserName,
|
|
141
189
|
};
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
clip,
|
|
3
|
-
compactQuery,
|
|
4
|
-
formatMoney,
|
|
5
|
-
parseLimit,
|
|
6
|
-
printKeyValueRows,
|
|
7
|
-
} = require("./resource-utils");
|
|
8
|
-
const { createListCommand } = require("./resource-command-runner");
|
|
9
|
-
const { getResourceMetadata } = require("./resource-metadata");
|
|
10
|
-
|
|
11
|
-
const BILLABLE_CLIENT_RESOURCE = getResourceMetadata("billable-clients");
|
|
12
|
-
|
|
13
|
-
function buildBillableClientQuery(options) {
|
|
14
|
-
return compactQuery({
|
|
15
|
-
client_id: options.clientId || undefined,
|
|
16
|
-
end_date: options.endDate || undefined,
|
|
17
|
-
fields: options.fields || BILLABLE_CLIENT_RESOURCE.defaultFields.list,
|
|
18
|
-
limit: parseLimit(options.limit, 25),
|
|
19
|
-
matter_id: options.matterId || undefined,
|
|
20
|
-
originating_attorney_id: options.originatingAttorneyId || undefined,
|
|
21
|
-
page_token: options.pageToken || undefined,
|
|
22
|
-
query: options.query || undefined,
|
|
23
|
-
responsible_attorney_id: options.responsibleAttorneyId || undefined,
|
|
24
|
-
start_date: options.startDate || undefined,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function formatBillableClientRow(record) {
|
|
29
|
-
return {
|
|
30
|
-
amount: formatMoney(record.unbilled_amount),
|
|
31
|
-
hours:
|
|
32
|
-
record.unbilled_hours === undefined || record.unbilled_hours === null
|
|
33
|
-
? "-"
|
|
34
|
-
: Number(record.unbilled_hours).toFixed(2),
|
|
35
|
-
id: String(record.id || "-"),
|
|
36
|
-
matters: String(record.billable_matters_count ?? "-"),
|
|
37
|
-
name: String(record.name || "-"),
|
|
38
|
-
trust: formatMoney(record.amount_in_trust),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function printBillableClientList(rows, options) {
|
|
43
|
-
if (rows.length === 0) {
|
|
44
|
-
console.log("No billable clients found for the selected filters.");
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const visibleRows = rows.slice(0, 50);
|
|
49
|
-
console.log("ID NAME HOURS AMOUNT TRUST MATTERS");
|
|
50
|
-
console.log("-------- ---------------------------- ----- ---------- ---------- -------");
|
|
51
|
-
|
|
52
|
-
visibleRows.forEach((row) => {
|
|
53
|
-
const line = [
|
|
54
|
-
clip(row.id, 8).padEnd(8, " "),
|
|
55
|
-
clip(row.name, 28).padEnd(28, " "),
|
|
56
|
-
clip(row.hours, 5).padEnd(5, " "),
|
|
57
|
-
clip(row.amount, 10).padEnd(10, " "),
|
|
58
|
-
clip(row.trust, 10).padEnd(10, " "),
|
|
59
|
-
clip(row.matters, 7),
|
|
60
|
-
].join(" ");
|
|
61
|
-
|
|
62
|
-
console.log(line);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (rows.length > visibleRows.length) {
|
|
66
|
-
console.log(`Showing ${visibleRows.length} of ${rows.length} billable clients. Use --json for full output.`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!options.all && options.nextPageUrl) {
|
|
70
|
-
console.log("");
|
|
71
|
-
console.log("More results are available.");
|
|
72
|
-
console.log("Run again with `--all` or pass `--page-token` from `--json` output.");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function printBillableClient(record) {
|
|
77
|
-
printKeyValueRows([
|
|
78
|
-
["ID", record.id],
|
|
79
|
-
["Name", record.name],
|
|
80
|
-
["Unbilled Hours", record.unbilled_hours],
|
|
81
|
-
["Unbilled Amount", formatMoney(record.unbilled_amount)],
|
|
82
|
-
["Amount In Trust", formatMoney(record.amount_in_trust)],
|
|
83
|
-
["Billable Matters", record.billable_matters_count],
|
|
84
|
-
]);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const billableClientsList = createListCommand({
|
|
88
|
-
apiPath: BILLABLE_CLIENT_RESOURCE.apiPath,
|
|
89
|
-
buildQuery: buildBillableClientQuery,
|
|
90
|
-
formatRow: formatBillableClientRow,
|
|
91
|
-
pluralLabel: BILLABLE_CLIENT_RESOURCE.summaryLabels.plural,
|
|
92
|
-
printList: printBillableClientList,
|
|
93
|
-
redactionResourceType: BILLABLE_CLIENT_RESOURCE.redaction.resourceType,
|
|
94
|
-
singularLabel: BILLABLE_CLIENT_RESOURCE.summaryLabels.singular,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
module.exports = {
|
|
98
|
-
billableClientsList,
|
|
99
|
-
__private: {
|
|
100
|
-
buildBillableClientQuery,
|
|
101
|
-
formatBillableClientRow,
|
|
102
|
-
printBillableClient,
|
|
103
|
-
printBillableClientList,
|
|
104
|
-
},
|
|
105
|
-
};
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
clip,
|
|
3
|
-
compactQuery,
|
|
4
|
-
formatMoney,
|
|
5
|
-
parseLimit,
|
|
6
|
-
printKeyValueRows,
|
|
7
|
-
readContactName,
|
|
8
|
-
} = require("./resource-utils");
|
|
9
|
-
const { createListCommand } = require("./resource-command-runner");
|
|
10
|
-
const { getResourceMetadata } = require("./resource-metadata");
|
|
11
|
-
|
|
12
|
-
const BILLABLE_MATTER_RESOURCE = getResourceMetadata("billable-matters");
|
|
13
|
-
|
|
14
|
-
function buildBillableMatterQuery(options) {
|
|
15
|
-
return compactQuery({
|
|
16
|
-
client_id: options.clientId || undefined,
|
|
17
|
-
end_date: options.endDate || undefined,
|
|
18
|
-
fields: options.fields || BILLABLE_MATTER_RESOURCE.defaultFields.list,
|
|
19
|
-
limit: parseLimit(options.limit, 1000),
|
|
20
|
-
matter_id: options.matterId || undefined,
|
|
21
|
-
originating_attorney_id: options.originatingAttorneyId || undefined,
|
|
22
|
-
page_token: options.pageToken || undefined,
|
|
23
|
-
query: options.query || undefined,
|
|
24
|
-
responsible_attorney_id: options.responsibleAttorneyId || undefined,
|
|
25
|
-
start_date: options.startDate || undefined,
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function formatBillableMatterRow(record) {
|
|
30
|
-
return {
|
|
31
|
-
amount: formatMoney(record.unbilled_amount),
|
|
32
|
-
client: readContactName(record.client),
|
|
33
|
-
hours:
|
|
34
|
-
record.unbilled_hours === undefined || record.unbilled_hours === null
|
|
35
|
-
? "-"
|
|
36
|
-
: Number(record.unbilled_hours).toFixed(2),
|
|
37
|
-
id: String(record.id || "-"),
|
|
38
|
-
matter: String(record.display_number || "-"),
|
|
39
|
-
trust: formatMoney(record.amount_in_trust),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function printBillableMatterList(rows, options) {
|
|
44
|
-
if (rows.length === 0) {
|
|
45
|
-
console.log("No billable matters found for the selected filters.");
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const visibleRows = rows.slice(0, 50);
|
|
50
|
-
console.log("ID MATTER CLIENT HOURS AMOUNT TRUST");
|
|
51
|
-
console.log("-------- --------------------- -------------------- ----- ---------- ----------");
|
|
52
|
-
|
|
53
|
-
visibleRows.forEach((row) => {
|
|
54
|
-
const line = [
|
|
55
|
-
clip(row.id, 8).padEnd(8, " "),
|
|
56
|
-
clip(row.matter, 21).padEnd(21, " "),
|
|
57
|
-
clip(row.client, 20).padEnd(20, " "),
|
|
58
|
-
clip(row.hours, 5).padEnd(5, " "),
|
|
59
|
-
clip(row.amount, 10).padEnd(10, " "),
|
|
60
|
-
clip(row.trust, 10),
|
|
61
|
-
].join(" ");
|
|
62
|
-
|
|
63
|
-
console.log(line);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (rows.length > visibleRows.length) {
|
|
67
|
-
console.log(`Showing ${visibleRows.length} of ${rows.length} billable matters. Use --json for full output.`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (!options.all && options.nextPageUrl) {
|
|
71
|
-
console.log("");
|
|
72
|
-
console.log("More results are available.");
|
|
73
|
-
console.log("Run again with `--all` or pass `--page-token` from `--json` output.");
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function printBillableMatter(record) {
|
|
78
|
-
printKeyValueRows([
|
|
79
|
-
["ID", record.id],
|
|
80
|
-
["Matter", record.display_number],
|
|
81
|
-
["Client", readContactName(record.client)],
|
|
82
|
-
["Unbilled Hours", record.unbilled_hours],
|
|
83
|
-
["Unbilled Amount", formatMoney(record.unbilled_amount)],
|
|
84
|
-
["Amount In Trust", formatMoney(record.amount_in_trust)],
|
|
85
|
-
]);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const billableMattersList = createListCommand({
|
|
89
|
-
apiPath: BILLABLE_MATTER_RESOURCE.apiPath,
|
|
90
|
-
buildQuery: buildBillableMatterQuery,
|
|
91
|
-
formatRow: formatBillableMatterRow,
|
|
92
|
-
pluralLabel: BILLABLE_MATTER_RESOURCE.summaryLabels.plural,
|
|
93
|
-
printList: printBillableMatterList,
|
|
94
|
-
redactionResourceType: BILLABLE_MATTER_RESOURCE.redaction.resourceType,
|
|
95
|
-
singularLabel: BILLABLE_MATTER_RESOURCE.summaryLabels.singular,
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
module.exports = {
|
|
99
|
-
billableMattersList,
|
|
100
|
-
__private: {
|
|
101
|
-
buildBillableMatterQuery,
|
|
102
|
-
formatBillableMatterRow,
|
|
103
|
-
printBillableMatter,
|
|
104
|
-
printBillableMatterList,
|
|
105
|
-
},
|
|
106
|
-
};
|
package/src/commands-bills.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
clip,
|
|
3
|
-
compactQuery,
|
|
4
|
-
formatMoney,
|
|
5
|
-
parseLimit,
|
|
6
|
-
printKeyValueRows,
|
|
7
|
-
readContactName,
|
|
8
|
-
readMatterLabel,
|
|
9
|
-
} = require("./resource-utils");
|
|
10
|
-
const { createGetCommand, createListCommand } = require("./resource-command-runner");
|
|
11
|
-
const { getResourceMetadata } = require("./resource-metadata");
|
|
12
|
-
|
|
13
|
-
const BILL_RESOURCE = getResourceMetadata("bills");
|
|
14
|
-
const VALID_BILL_STATUSES = new Set(["all", "overdue"]);
|
|
15
|
-
|
|
16
|
-
function normalizeBillStatusFilters(options = {}) {
|
|
17
|
-
const state =
|
|
18
|
-
typeof options.state === "string"
|
|
19
|
-
? options.state.trim() || undefined
|
|
20
|
-
: options.state || undefined;
|
|
21
|
-
|
|
22
|
-
if (options.status === undefined || options.status === null || options.status === "") {
|
|
23
|
-
return { state, status: undefined };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (typeof options.status !== "string") {
|
|
27
|
-
throw new Error(
|
|
28
|
-
"Invalid value for --status on bills/invoices. Use `all`, `overdue`, or `unpaid`."
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const status = options.status.trim().toLowerCase();
|
|
33
|
-
|
|
34
|
-
if (!status) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
"Invalid value for --status on bills/invoices. Use `all`, `overdue`, or `unpaid`."
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (status === "unpaid") {
|
|
41
|
-
if (state && state !== "awaiting_payment") {
|
|
42
|
-
throw new Error(
|
|
43
|
-
"`--status unpaid` conflicts with `--state`. Use `--state awaiting_payment` or remove one of the filters."
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
state: state || "awaiting_payment",
|
|
49
|
-
status: undefined,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!VALID_BILL_STATUSES.has(status)) {
|
|
54
|
-
throw new Error(
|
|
55
|
-
"Invalid value for --status on bills/invoices. Use `all`, `overdue`, or `unpaid`."
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return { state, status };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function buildBillQuery(options) {
|
|
63
|
-
const filters = normalizeBillStatusFilters(options);
|
|
64
|
-
|
|
65
|
-
return compactQuery({
|
|
66
|
-
client_id: options.clientId || undefined,
|
|
67
|
-
created_since: options.createdSince || undefined,
|
|
68
|
-
due_after: options.dueAfter || undefined,
|
|
69
|
-
due_before: options.dueBefore || undefined,
|
|
70
|
-
fields: options.fields || BILL_RESOURCE.defaultFields.list,
|
|
71
|
-
issued_after: options.issuedAfter || undefined,
|
|
72
|
-
issued_before: options.issuedBefore || undefined,
|
|
73
|
-
limit: parseLimit(options.limit),
|
|
74
|
-
matter_id: options.matterId || undefined,
|
|
75
|
-
order: options.order || undefined,
|
|
76
|
-
overdue_only: options.overdueOnly ? true : undefined,
|
|
77
|
-
page_token: options.pageToken || undefined,
|
|
78
|
-
query: options.query || undefined,
|
|
79
|
-
state: filters.state,
|
|
80
|
-
status: filters.status,
|
|
81
|
-
type: options.type || undefined,
|
|
82
|
-
updated_since: options.updatedSince || undefined,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function readFirstMatterLabel(bill) {
|
|
87
|
-
const matters = Array.isArray(bill.matters) ? bill.matters : [];
|
|
88
|
-
if (matters.length === 0) {
|
|
89
|
-
return "-";
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return readMatterLabel(matters[0]);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function formatBillRow(bill) {
|
|
96
|
-
return {
|
|
97
|
-
id: String(bill.id || "-"),
|
|
98
|
-
number: String(bill.number || "-"),
|
|
99
|
-
state: String(bill.state || "-"),
|
|
100
|
-
client: readContactName(bill.client),
|
|
101
|
-
dueAt: String(bill.due_at || "-"),
|
|
102
|
-
balance: formatMoney(bill.balance),
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function printBillList(rows, options) {
|
|
107
|
-
if (rows.length === 0) {
|
|
108
|
-
console.log("No bills found for the selected filters.");
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const visibleRows = rows.slice(0, 50);
|
|
113
|
-
console.log("ID BILL STATE CLIENT DUE BALANCE");
|
|
114
|
-
console.log("-------- -------------- ------------ ---------------------------- ------------ ----------");
|
|
115
|
-
|
|
116
|
-
visibleRows.forEach((row) => {
|
|
117
|
-
const line = [
|
|
118
|
-
clip(row.id, 8).padEnd(8, " "),
|
|
119
|
-
clip(row.number, 14).padEnd(14, " "),
|
|
120
|
-
clip(row.state, 12).padEnd(12, " "),
|
|
121
|
-
clip(row.client, 28).padEnd(28, " "),
|
|
122
|
-
clip(row.dueAt, 12).padEnd(12, " "),
|
|
123
|
-
clip(row.balance, 10),
|
|
124
|
-
].join(" ");
|
|
125
|
-
|
|
126
|
-
console.log(line);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
if (rows.length > visibleRows.length) {
|
|
130
|
-
console.log(`Showing ${visibleRows.length} of ${rows.length} bills. Use --json for full output.`);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (!options.all && options.nextPageUrl) {
|
|
134
|
-
console.log("");
|
|
135
|
-
console.log("More results are available.");
|
|
136
|
-
console.log("Run again with `--all` or pass `--page-token` from `--json` output.");
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function printBill(bill) {
|
|
141
|
-
printKeyValueRows([
|
|
142
|
-
["ID", bill.id],
|
|
143
|
-
["Number", bill.number],
|
|
144
|
-
["State", bill.state],
|
|
145
|
-
["Type", bill.type],
|
|
146
|
-
["Kind", bill.kind],
|
|
147
|
-
["Client", readContactName(bill.client)],
|
|
148
|
-
["Matter", readFirstMatterLabel(bill)],
|
|
149
|
-
["Issued", bill.issued_at],
|
|
150
|
-
["Due", bill.due_at],
|
|
151
|
-
["Total", formatMoney(bill.total)],
|
|
152
|
-
["Balance", formatMoney(bill.balance)],
|
|
153
|
-
["Paid", formatMoney(bill.paid)],
|
|
154
|
-
["Paid At", bill.paid_at],
|
|
155
|
-
["Pending", formatMoney(bill.pending)],
|
|
156
|
-
["Due Amount", formatMoney(bill.due)],
|
|
157
|
-
["Subject", bill.subject],
|
|
158
|
-
["Memo", bill.memo],
|
|
159
|
-
["Created", bill.created_at],
|
|
160
|
-
["Updated", bill.updated_at],
|
|
161
|
-
]);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const billsList = createListCommand({
|
|
165
|
-
apiPath: BILL_RESOURCE.apiPath,
|
|
166
|
-
buildQuery: buildBillQuery,
|
|
167
|
-
formatRow: formatBillRow,
|
|
168
|
-
pluralLabel: BILL_RESOURCE.summaryLabels.plural,
|
|
169
|
-
printList: printBillList,
|
|
170
|
-
redactionResourceType: BILL_RESOURCE.redaction.resourceType,
|
|
171
|
-
singularLabel: BILL_RESOURCE.summaryLabels.singular,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
const billsGet = createGetCommand({
|
|
175
|
-
apiPath: BILL_RESOURCE.apiPath,
|
|
176
|
-
defaultFields: BILL_RESOURCE.defaultFields.get,
|
|
177
|
-
printItem: printBill,
|
|
178
|
-
redactionResourceType: BILL_RESOURCE.redaction.resourceType,
|
|
179
|
-
usage: "Usage: not-manage bills get <id> [--fields ...] [--json]",
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
module.exports = {
|
|
183
|
-
billsGet,
|
|
184
|
-
billsList,
|
|
185
|
-
__private: {
|
|
186
|
-
buildBillQuery,
|
|
187
|
-
formatBillRow,
|
|
188
|
-
normalizeBillStatusFilters,
|
|
189
|
-
printBill,
|
|
190
|
-
printBillList,
|
|
191
|
-
},
|
|
192
|
-
};
|
package/src/commands-contacts.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
clip,
|
|
3
|
-
compactQuery,
|
|
4
|
-
formatBoolean,
|
|
5
|
-
parseLimit,
|
|
6
|
-
printKeyValueRows,
|
|
7
|
-
readContactName,
|
|
8
|
-
} = require("./resource-utils");
|
|
9
|
-
const { createGetCommand, createListCommand } = require("./resource-command-runner");
|
|
10
|
-
const { getResourceMetadata } = require("./resource-metadata");
|
|
11
|
-
|
|
12
|
-
const CONTACT_RESOURCE = getResourceMetadata("contacts");
|
|
13
|
-
|
|
14
|
-
function buildContactQuery(options) {
|
|
15
|
-
return compactQuery({
|
|
16
|
-
client_only: options.clientOnly ? true : undefined,
|
|
17
|
-
clio_connect_only: options.clioConnectOnly ? true : undefined,
|
|
18
|
-
created_since: options.createdSince || undefined,
|
|
19
|
-
email_only: options.emailOnly ? true : undefined,
|
|
20
|
-
fields: options.fields || CONTACT_RESOURCE.defaultFields.list,
|
|
21
|
-
initial: options.initial || undefined,
|
|
22
|
-
limit: parseLimit(options.limit),
|
|
23
|
-
order: options.order || undefined,
|
|
24
|
-
page_token: options.pageToken || undefined,
|
|
25
|
-
query: options.query || undefined,
|
|
26
|
-
type: options.type || undefined,
|
|
27
|
-
updated_since: options.updatedSince || undefined,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function formatContactRow(contact) {
|
|
32
|
-
return {
|
|
33
|
-
id: String(contact.id || "-"),
|
|
34
|
-
name: readContactName(contact),
|
|
35
|
-
type: String(contact.type || "-"),
|
|
36
|
-
client: formatBoolean(contact.is_client),
|
|
37
|
-
email: String(contact.primary_email_address || "-"),
|
|
38
|
-
phone: String(contact.primary_phone_number || "-"),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function printContactList(rows, options) {
|
|
43
|
-
if (rows.length === 0) {
|
|
44
|
-
console.log("No contacts found for the selected filters.");
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const visibleRows = rows.slice(0, 50);
|
|
49
|
-
console.log("ID NAME TYPE CLIENT EMAIL PHONE");
|
|
50
|
-
console.log("-------- ---------------------------- ------------ ------ ---------------------------- ------------------");
|
|
51
|
-
|
|
52
|
-
visibleRows.forEach((row) => {
|
|
53
|
-
const line = [
|
|
54
|
-
clip(row.id, 8).padEnd(8, " "),
|
|
55
|
-
clip(row.name, 28).padEnd(28, " "),
|
|
56
|
-
clip(row.type, 12).padEnd(12, " "),
|
|
57
|
-
clip(row.client, 6).padEnd(6, " "),
|
|
58
|
-
clip(row.email, 28).padEnd(28, " "),
|
|
59
|
-
clip(row.phone, 18),
|
|
60
|
-
].join(" ");
|
|
61
|
-
|
|
62
|
-
console.log(line);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (rows.length > visibleRows.length) {
|
|
66
|
-
console.log(`Showing ${visibleRows.length} of ${rows.length} contacts. Use --json for full output.`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!options.all && options.nextPageUrl) {
|
|
70
|
-
console.log("");
|
|
71
|
-
console.log("More results are available.");
|
|
72
|
-
console.log("Run again with `--all` or pass `--page-token` from `--json` output.");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function printContact(contact) {
|
|
77
|
-
printKeyValueRows([
|
|
78
|
-
["ID", contact.id],
|
|
79
|
-
["Name", readContactName(contact)],
|
|
80
|
-
["Type", contact.type],
|
|
81
|
-
["Client", formatBoolean(contact.is_client)],
|
|
82
|
-
["Primary Email", contact.primary_email_address],
|
|
83
|
-
["Secondary Email", contact.secondary_email_address],
|
|
84
|
-
["Primary Phone", contact.primary_phone_number],
|
|
85
|
-
["Secondary Phone", contact.secondary_phone_number],
|
|
86
|
-
["Clio Connect Email", contact.clio_connect_email],
|
|
87
|
-
["Title", contact.title],
|
|
88
|
-
["Prefix", contact.prefix],
|
|
89
|
-
["Created", contact.created_at],
|
|
90
|
-
["Updated", contact.updated_at],
|
|
91
|
-
]);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const contactsList = createListCommand({
|
|
95
|
-
apiPath: CONTACT_RESOURCE.apiPath,
|
|
96
|
-
buildQuery: buildContactQuery,
|
|
97
|
-
formatRow: formatContactRow,
|
|
98
|
-
pluralLabel: CONTACT_RESOURCE.summaryLabels.plural,
|
|
99
|
-
printList: printContactList,
|
|
100
|
-
redactionResourceType: CONTACT_RESOURCE.redaction.resourceType,
|
|
101
|
-
singularLabel: CONTACT_RESOURCE.summaryLabels.singular,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
const contactsGet = createGetCommand({
|
|
105
|
-
apiPath: CONTACT_RESOURCE.apiPath,
|
|
106
|
-
defaultFields: CONTACT_RESOURCE.defaultFields.get,
|
|
107
|
-
printItem: printContact,
|
|
108
|
-
redactionResourceType: CONTACT_RESOURCE.redaction.resourceType,
|
|
109
|
-
usage: "Usage: not-manage contacts get <id> [--fields ...] [--json]",
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
module.exports = {
|
|
113
|
-
contactsGet,
|
|
114
|
-
contactsList,
|
|
115
|
-
__private: {
|
|
116
|
-
buildContactQuery,
|
|
117
|
-
formatContactRow,
|
|
118
|
-
printContact,
|
|
119
|
-
printContactList,
|
|
120
|
-
},
|
|
121
|
-
};
|