@surelycrm/cli 1.0.0 → 1.2.0

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 CHANGED
@@ -45,12 +45,14 @@ Configuration is stored in `~/.surecli/config.json`.
45
45
  |---------|-------------|
46
46
  | `sure-cli config` | Show stored configuration |
47
47
  | `sure-cli create-customer` | Create a new customer |
48
- | `sure-cli get-customer --id {guid}` | Get a customer by GUID |
49
- | `sure-cli get-customer-by-reference --reference {ref}` | Get a customer by reference number |
48
+ | `sure-cli get-customer --id {guid}` | Get a customer by GUID, email, or reference |
50
49
  | `sure-cli update-customer --id {guid}` | Update an existing customer |
51
50
  | `sure-cli change-status --customer-id {guid} --status-id {guid}` | Change a customer's status |
52
51
  | `sure-cli start-workflow --customer-id {guid} --workflow-name {name}` | Start a workflow for a customer |
53
52
  | `sure-cli get-customers-by-age --age {age} --comparison {comparison}` | Filter customers by age |
53
+ | `sure-cli get-support-tickets --new` | Get new/open support tickets |
54
+ | `sure-cli get-support-tickets --recently-replied --hours {hours}` | Get recently replied support tickets |
55
+ | `sure-cli reply-to-ticket --id {guid} --message {message}` | Reply to a support ticket |
54
56
 
55
57
  Use `--help` on any command for details.
56
58
 
@@ -61,6 +63,7 @@ JSON templates for complex payloads are in the `templates/` directory:
61
63
  - `customer.json` — customer create/update payload
62
64
  - `status-change.json` — status change payload
63
65
  - `workflow-start.json` — workflow start payload
66
+ - `support-reply.json` — support ticket reply payload
64
67
 
65
68
  ## Documentation
66
69
 
package/bin/sure-cli.js CHANGED
@@ -7,7 +7,7 @@ const { loadConfig, saveConfig, requireConfig } = require('../lib/config');
7
7
  const { request, handleResponse } = require('../lib/api');
8
8
 
9
9
  const program = new Command();
10
- program.name('sure-cli').description('CLI wrapper for the SurelyCrm API').version('1.0.0');
10
+ program.name('sure-cli').description('CLI wrapper for the SurelyCrm API').version('1.1.0');
11
11
 
12
12
  const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
13
13
 
@@ -107,23 +107,33 @@ program
107
107
 
108
108
  program
109
109
  .command('get-customer')
110
- .description('Get a customer by GUID')
111
- .requiredOption('--id <guid>', 'Customer GUID')
110
+ .description('Get a customer by GUID, email address, or reference number')
111
+ .option('--id <guid>', 'Customer GUID')
112
+ .option('--email <email>', 'Customer email address')
113
+ .option('--reference <reference>', 'Customer reference number')
112
114
  .action(run(async (options) => {
113
115
  const config = requireConfig();
114
- const id = getRequiredOption(options, 'id');
115
- const response = await request(config.baseUrl, config.apiKey, 'GET', `Api/customer/${id}`);
116
- handleResponse(response);
117
- }));
118
116
 
119
- program
120
- .command('get-customer-by-reference')
121
- .description('Get a customer by reference number')
122
- .requiredOption('--reference <reference>', 'Customer reference number')
123
- .action(run(async (options) => {
124
- const config = requireConfig();
125
- const reference = getRequiredOption(options, 'reference');
126
- const response = await request(config.baseUrl, config.apiKey, 'GET', `Api/customer/reference/${encodeURIComponent(reference)}`);
117
+ const provided = [options.id, options.email, options.reference].filter(Boolean);
118
+ if (provided.length === 0) {
119
+ console.error('One of --id, --email, or --reference is required');
120
+ process.exit(1);
121
+ }
122
+ if (provided.length > 1) {
123
+ console.error('Only one of --id, --email, or --reference can be provided');
124
+ process.exit(1);
125
+ }
126
+
127
+ let path;
128
+ if (options.id) {
129
+ path = `Api/customer/${options.id}`;
130
+ } else if (options.email) {
131
+ path = `Api/customer/byEmail/${encodeURIComponent(options.email)}`;
132
+ } else {
133
+ path = `Api/customer/reference/${encodeURIComponent(options.reference)}`;
134
+ }
135
+
136
+ const response = await request(config.baseUrl, config.apiKey, 'GET', path);
127
137
  handleResponse(response);
128
138
  }));
129
139
 
@@ -199,4 +209,76 @@ program
199
209
  handleResponse(response);
200
210
  }));
201
211
 
212
+ program
213
+ .command('get-support-tickets')
214
+ .description('Get support tickets')
215
+ .option('--new', 'Get new/open support tickets')
216
+ .option('--recently-replied', 'Get support tickets with replies in the recent period')
217
+ .option('--hours <hours>', 'Number of hours to look back for recently replied tickets', '24')
218
+ .option('--page <page>', 'Page number', '1')
219
+ .option('--page-size <pageSize>', 'Page size', '25')
220
+ .action(run(async (options) => {
221
+ const config = requireConfig();
222
+
223
+ if (!options.new && !options.recentlyReplied) {
224
+ console.error('Either --new or --recently-replied is required');
225
+ process.exit(1);
226
+ }
227
+
228
+ if (options.new && options.recentlyReplied) {
229
+ console.error('Cannot use both --new and --recently-replied at the same time');
230
+ process.exit(1);
231
+ }
232
+
233
+ const params = new URLSearchParams();
234
+ if (options.new) {
235
+ params.append('newTickets', 'true');
236
+ } else if (options.recentlyReplied) {
237
+ params.append('recentlyReplied', 'true');
238
+ params.append('hours', options.hours);
239
+ }
240
+ params.append('page', options.page);
241
+ params.append('pageSize', options.pageSize);
242
+
243
+ const response = await request(config.baseUrl, config.apiKey, 'GET', `Api/support/tickets?${params.toString()}`);
244
+ handleResponse(response);
245
+ }));
246
+
247
+ program
248
+ .command('reply-to-ticket')
249
+ .description('Reply to a support ticket')
250
+ .requiredOption('--id <guid>', 'Support ticket GUID')
251
+ .option('--message <message>', 'Reply message text')
252
+ .option('--template <file>', 'Path to a JSON reply template')
253
+ .option('--data <json>', 'Inline JSON reply payload')
254
+ .option('--internal', 'Mark the reply as internal-only', false)
255
+ .option('--close', 'Close the ticket after replying', false)
256
+ .action(run(async (options) => {
257
+ const config = requireConfig();
258
+ const id = getRequiredOption(options, 'id');
259
+
260
+ let body = parseDataInput(options);
261
+ if (!body) {
262
+ body = loadTemplate('support-reply');
263
+ }
264
+
265
+ if (options.message) {
266
+ body.message = options.message;
267
+ }
268
+ if (options.internal) {
269
+ body.isInternal = true;
270
+ }
271
+ if (options.close) {
272
+ body.closeAfterReply = true;
273
+ }
274
+
275
+ if (!body.message) {
276
+ console.error('A message is required. Use --message, --template, or --data.');
277
+ process.exit(1);
278
+ }
279
+
280
+ const response = await request(config.baseUrl, config.apiKey, 'POST', `Api/support/tickets/${id}/reply`, body);
281
+ handleResponse(response);
282
+ }));
283
+
202
284
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@surelycrm/cli",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "CLI wrapper for the SurelyCrm API",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,5 @@
1
+ {
2
+ "message": "",
3
+ "isInternal": false,
4
+ "closeAfterReply": false
5
+ }