mayar 0.1.9 → 1.0.1
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 +133 -47
- package/package.json +10 -2
- package/src/api.js +2 -1
- package/src/cli.js +122 -31
- package/src/commands/balance.js +1 -1
- package/src/commands/bundling.js +36 -0
- package/src/commands/credit.js +72 -0
- package/src/commands/customer.js +5 -7
- package/src/commands/discount.js +52 -0
- package/src/commands/installment.js +44 -0
- package/src/commands/invoice.js +53 -25
- package/src/commands/login.js +74 -0
- package/src/commands/membership.js +92 -0
- package/src/commands/payment-link.js +23 -0
- package/src/commands/payment.js +30 -14
- package/src/commands/product.js +97 -18
- package/src/commands/qrcode.js +35 -5
- package/src/commands/review.js +90 -18
- package/src/commands/saas.js +18 -0
- package/src/commands/software.js +17 -0
- package/src/commands/transaction.js +39 -12
- package/src/commands/webhook.js +46 -13
- package/src/config.js +18 -1
- package/src/util.js +28 -1
package/src/commands/customer.js
CHANGED
|
@@ -8,9 +8,7 @@ async function run({ apiKey, flags, positional }) {
|
|
|
8
8
|
const [sub, ...rest] = positional;
|
|
9
9
|
switch (sub) {
|
|
10
10
|
case 'list': {
|
|
11
|
-
const res = await api.request('GET', '/hl/
|
|
12
|
-
apiKey, query: { page: flags.page, pageSize: flags.pageSize },
|
|
13
|
-
});
|
|
11
|
+
const res = await api.request('GET', '/hl/v2/customers', { apiKey });
|
|
14
12
|
checkResp(res);
|
|
15
13
|
if (flags.json) return ui.jsonOut(res.body);
|
|
16
14
|
const data = (res.body && res.body.data) || [];
|
|
@@ -23,19 +21,19 @@ async function run({ apiKey, flags, positional }) {
|
|
|
23
21
|
case 'create': {
|
|
24
22
|
const body = readData(flags.data);
|
|
25
23
|
if (!body) throw new Error('mayar customer create requires --data \'{"name":"...","email":"...","mobile":"..."}\'');
|
|
26
|
-
const res = await api.request('POST', '/hl/
|
|
24
|
+
const res = await api.request('POST', '/hl/v2/customers/create', { apiKey, body });
|
|
27
25
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
28
26
|
}
|
|
29
27
|
case 'search': {
|
|
30
28
|
if (!rest[0]) throw new Error('Usage: mayar customer search <email>');
|
|
31
|
-
const res = await api.request('GET', '/hl/
|
|
29
|
+
const res = await api.request('GET', '/hl/v2/customers/detail', {
|
|
32
30
|
apiKey, query: { email: rest[0] },
|
|
33
31
|
});
|
|
34
32
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
35
33
|
}
|
|
36
34
|
case 'update': {
|
|
37
35
|
if (rest.length < 2) throw new Error('Usage: mayar customer update <fromEmail> <toEmail>');
|
|
38
|
-
const res = await api.request('POST', '/hl/
|
|
36
|
+
const res = await api.request('POST', '/hl/v2/customers/update', {
|
|
39
37
|
apiKey, body: { fromEmail: rest[0], toEmail: rest[1] },
|
|
40
38
|
});
|
|
41
39
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
@@ -43,7 +41,7 @@ async function run({ apiKey, flags, positional }) {
|
|
|
43
41
|
case 'magic-link':
|
|
44
42
|
case 'magiclink': {
|
|
45
43
|
if (!rest[0]) throw new Error('Usage: mayar customer magic-link <email>');
|
|
46
|
-
const res = await api.request('POST', '/hl/
|
|
44
|
+
const res = await api.request('POST', '/hl/v2/customers/portal-login', {
|
|
47
45
|
apiKey, body: { email: rest[0] },
|
|
48
46
|
});
|
|
49
47
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const api = require('../api');
|
|
2
|
+
const ui = require('../ui');
|
|
3
|
+
const { checkResp, readData } = require('../util');
|
|
4
|
+
|
|
5
|
+
const USAGE = 'Usage: mayar discount <create|get|validate|check>';
|
|
6
|
+
|
|
7
|
+
async function run({ apiKey, flags, positional }) {
|
|
8
|
+
const [sub, ...rest] = positional;
|
|
9
|
+
switch (sub) {
|
|
10
|
+
case 'create': {
|
|
11
|
+
const body = readData(flags.data);
|
|
12
|
+
if (!body) throw new Error('mayar discount create requires --data <json|@file>');
|
|
13
|
+
const res = await api.request('POST', '/hl/v2/coupons/create', { apiKey, body });
|
|
14
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
15
|
+
}
|
|
16
|
+
case 'get':
|
|
17
|
+
case 'detail': {
|
|
18
|
+
if (!rest[0]) throw new Error('Usage: mayar discount get <id>');
|
|
19
|
+
const res = await api.request('GET', `/hl/v2/coupons/${encodeURIComponent(rest[0])}`, { apiKey });
|
|
20
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
21
|
+
}
|
|
22
|
+
case 'validate': {
|
|
23
|
+
if (!rest[0] || !rest[1]) throw new Error('Usage: mayar discount validate <couponCode> <paymentLinkId>');
|
|
24
|
+
const res = await api.request('POST', '/hl/v2/coupons/validate', {
|
|
25
|
+
apiKey, body: { couponCode: rest[0], paymentLinkId: rest[1] },
|
|
26
|
+
});
|
|
27
|
+
checkResp(res);
|
|
28
|
+
if (flags.json) return ui.jsonOut(res.body);
|
|
29
|
+
const d = (res.body && res.body.data) || {};
|
|
30
|
+
const c = d.coupon || {};
|
|
31
|
+
const valid = d.valid ? ui.green('✓ valid') : ui.red('✗ invalid');
|
|
32
|
+
process.stdout.write(`${ui.bold('Result:')} ${valid}\n`);
|
|
33
|
+
if (c.code) process.stdout.write(`${ui.bold('Code:')} ${c.code}\n`);
|
|
34
|
+
if (c.discountType) process.stdout.write(`${ui.bold('Discount type:')} ${c.discountType}\n`);
|
|
35
|
+
if (c.discountValue != null) process.stdout.write(`${ui.bold('Discount:')} ${c.discountValue}${c.discountType === 'percentage' ? '%' : ''}\n`);
|
|
36
|
+
if (c.minimumPurchase != null) process.stdout.write(`${ui.bold('Min. purchase:')} ${c.minimumPurchase}\n`);
|
|
37
|
+
if (c.eligibleCustomerType) process.stdout.write(`${ui.bold('Eligible:')} ${c.eligibleCustomerType}\n`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
case 'check': {
|
|
41
|
+
if (!rest[0]) throw new Error('Usage: mayar discount check <couponCode>');
|
|
42
|
+
const res = await api.request('POST', '/hl/v2/coupons/check', {
|
|
43
|
+
apiKey, body: { couponCode: rest[0] },
|
|
44
|
+
});
|
|
45
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
46
|
+
}
|
|
47
|
+
default:
|
|
48
|
+
throw new Error(USAGE);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = { run };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const api = require('../api');
|
|
2
|
+
const ui = require('../ui');
|
|
3
|
+
const { checkResp, readData, pagination, cursorFooter } = require('../util');
|
|
4
|
+
|
|
5
|
+
const USAGE = 'Usage: mayar installment <list|get|create>';
|
|
6
|
+
|
|
7
|
+
async function run({ apiKey, flags, positional }) {
|
|
8
|
+
const [sub, ...rest] = positional;
|
|
9
|
+
switch (sub) {
|
|
10
|
+
case undefined:
|
|
11
|
+
case 'list': {
|
|
12
|
+
const res = await api.request('GET', '/hl/v2/installments', {
|
|
13
|
+
apiKey, query: pagination(flags, { status: flags.status, customerId: flags.customerId }),
|
|
14
|
+
});
|
|
15
|
+
checkResp(res);
|
|
16
|
+
if (flags.json) return ui.jsonOut(res.body);
|
|
17
|
+
const data = (res.body && res.body.data) || [];
|
|
18
|
+
const rows = data.map((i) => ({
|
|
19
|
+
id: i.id, name: i.name, email: i.email,
|
|
20
|
+
amount: i.amount, tenure: (i.installment && i.installment.tenure) || '',
|
|
21
|
+
status: i.status,
|
|
22
|
+
}));
|
|
23
|
+
ui.table(rows, ['id', 'name', 'email', 'amount', 'tenure', 'status']);
|
|
24
|
+
cursorFooter(res.body, data.length);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
case 'get':
|
|
28
|
+
case 'detail': {
|
|
29
|
+
if (!rest[0]) throw new Error('Usage: mayar installment get <id>');
|
|
30
|
+
const res = await api.request('GET', `/hl/v2/installments/${encodeURIComponent(rest[0])}`, { apiKey });
|
|
31
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
32
|
+
}
|
|
33
|
+
case 'create': {
|
|
34
|
+
const body = readData(flags.data);
|
|
35
|
+
if (!body) throw new Error('mayar installment create requires --data <json|@file>');
|
|
36
|
+
const res = await api.request('POST', '/hl/v2/installments/create', { apiKey, body });
|
|
37
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
38
|
+
}
|
|
39
|
+
default:
|
|
40
|
+
throw new Error(USAGE);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { run };
|
package/src/commands/invoice.js
CHANGED
|
@@ -1,50 +1,78 @@
|
|
|
1
1
|
const api = require('../api');
|
|
2
2
|
const ui = require('../ui');
|
|
3
|
-
const { checkResp, readData } = require('../util');
|
|
3
|
+
const { checkResp, readData, pagination, cursorFooter } = require('../util');
|
|
4
4
|
|
|
5
|
-
const USAGE = 'Usage: mayar invoice <list|get|close|reopen|create>';
|
|
5
|
+
const USAGE = 'Usage: mayar invoice <list|get|close|reopen|status|edit|filter|create>';
|
|
6
|
+
const STATUS_ACTIONS = ['open', 'close', 'active', 'closed', 'unlisted'];
|
|
7
|
+
|
|
8
|
+
function renderList(body) {
|
|
9
|
+
const data = (body && body.data) || [];
|
|
10
|
+
const rows = data.map((i) => ({
|
|
11
|
+
id: i.id,
|
|
12
|
+
customer: (i.customer && (i.customer.name || i.customer.email)) || '',
|
|
13
|
+
amount: i.amount,
|
|
14
|
+
status: i.status,
|
|
15
|
+
createdAt: typeof i.createdAt === 'number' ? new Date(i.createdAt).toISOString() : (i.createdAt || ''),
|
|
16
|
+
}));
|
|
17
|
+
ui.table(rows, ['id', 'customer', 'amount', 'status', 'createdAt']);
|
|
18
|
+
cursorFooter(body, data.length);
|
|
19
|
+
}
|
|
6
20
|
|
|
7
21
|
async function run({ apiKey, flags, positional }) {
|
|
8
22
|
const [sub, ...rest] = positional;
|
|
9
23
|
switch (sub) {
|
|
10
24
|
case 'list': {
|
|
11
|
-
const res = await api.request('GET', '/hl/
|
|
12
|
-
apiKey,
|
|
25
|
+
const res = await api.request('GET', '/hl/v2/invoices', {
|
|
26
|
+
apiKey,
|
|
27
|
+
query: pagination(flags, { status: flags.status, search: flags.search }),
|
|
28
|
+
});
|
|
29
|
+
checkResp(res);
|
|
30
|
+
if (flags.json) return ui.jsonOut(res.body);
|
|
31
|
+
renderList(res.body); return;
|
|
32
|
+
}
|
|
33
|
+
case 'filter': {
|
|
34
|
+
if (!flags.email) throw new Error('mayar invoice filter requires --email <email>');
|
|
35
|
+
const res = await api.request('GET', '/hl/v2/invoices/filter', {
|
|
36
|
+
apiKey,
|
|
37
|
+
query: pagination(flags, { email: flags.email, status: flags.status, search: flags.search }),
|
|
13
38
|
});
|
|
14
39
|
checkResp(res);
|
|
15
40
|
if (flags.json) return ui.jsonOut(res.body);
|
|
16
|
-
|
|
17
|
-
const rows = data.map((i) => ({
|
|
18
|
-
id: i.id,
|
|
19
|
-
customer: (i.customer && (i.customer.name || i.customer.email)) || '',
|
|
20
|
-
amount: i.amount,
|
|
21
|
-
status: i.status,
|
|
22
|
-
createdAt: i.createdAt,
|
|
23
|
-
}));
|
|
24
|
-
ui.table(rows, ['id', 'customer', 'amount', 'status', 'createdAt']);
|
|
25
|
-
const m = res.body || {};
|
|
26
|
-
process.stdout.write(ui.dim(`page ${m.page ?? '?'} / ${m.pageCount ?? '?'} · total ${m.total ?? data.length}`) + '\n');
|
|
27
|
-
return;
|
|
41
|
+
renderList(res.body); return;
|
|
28
42
|
}
|
|
29
43
|
case 'get': {
|
|
30
44
|
if (!rest[0]) throw new Error('Usage: mayar invoice get <id>');
|
|
31
|
-
const res = await api.request('GET', `/hl/
|
|
45
|
+
const res = await api.request('GET', `/hl/v2/invoices/${encodeURIComponent(rest[0])}`, { apiKey });
|
|
32
46
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
33
47
|
}
|
|
34
|
-
case 'close':
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
case 'close':
|
|
49
|
+
case 'reopen': {
|
|
50
|
+
if (!rest[0]) throw new Error(`Usage: mayar invoice ${sub} <id>`);
|
|
51
|
+
const action = sub === 'reopen' ? 'open' : 'close';
|
|
52
|
+
// v2 consolidates status changes under a single action endpoint.
|
|
53
|
+
const res = await api.request('POST', `/hl/v2/invoices/${encodeURIComponent(rest[0])}/${action}`, { apiKey });
|
|
37
54
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
38
55
|
}
|
|
39
|
-
case '
|
|
40
|
-
if (!rest[0]) throw new Error(
|
|
41
|
-
|
|
56
|
+
case 'status': {
|
|
57
|
+
if (!rest[0] || !rest[1]) throw new Error(`Usage: mayar invoice status <id> <${STATUS_ACTIONS.join('|')}>`);
|
|
58
|
+
if (!STATUS_ACTIONS.includes(rest[1])) {
|
|
59
|
+
throw new Error(`Invalid action "${rest[1]}". Must be one of: ${STATUS_ACTIONS.join(', ')}`);
|
|
60
|
+
}
|
|
61
|
+
const res = await api.request('POST', `/hl/v2/invoices/${encodeURIComponent(rest[0])}/${rest[1]}`, { apiKey });
|
|
62
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
63
|
+
}
|
|
64
|
+
case 'edit': {
|
|
65
|
+
if (!rest[0]) throw new Error('Usage: mayar invoice edit <id> --data <json|@file>');
|
|
66
|
+
const body = readData(flags.data);
|
|
67
|
+
if (!body) throw new Error('mayar invoice edit requires --data <json|@file>');
|
|
68
|
+
body.id = body.id || rest[0];
|
|
69
|
+
const res = await api.request('POST', `/hl/v2/invoices/${encodeURIComponent(rest[0])}/update`, { apiKey, body });
|
|
42
70
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
43
71
|
}
|
|
44
72
|
case 'create': {
|
|
45
73
|
const body = readData(flags.data);
|
|
46
|
-
if (!body) throw new Error('mayar invoice create requires --data <json|@file
|
|
47
|
-
const res = await api.request('POST', '/hl/
|
|
74
|
+
if (!body) throw new Error('mayar invoice create requires --data <json|@file>');
|
|
75
|
+
const res = await api.request('POST', '/hl/v2/invoices/create', { apiKey, body });
|
|
48
76
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
49
77
|
}
|
|
50
78
|
default:
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const { MayarAuth } = require('@mayaross/auth');
|
|
2
|
+
const config = require('../config');
|
|
3
|
+
const ui = require('../ui');
|
|
4
|
+
|
|
5
|
+
// Decode the payload of a JWT without verifying its signature.
|
|
6
|
+
function decodeJwt(token) {
|
|
7
|
+
const parts = String(token || '').split('.');
|
|
8
|
+
if (parts.length !== 3) return null;
|
|
9
|
+
try {
|
|
10
|
+
const padded = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
|
11
|
+
const pad = padded.length % 4 === 0 ? '' : '='.repeat(4 - (padded.length % 4));
|
|
12
|
+
return JSON.parse(Buffer.from(padded + pad, 'base64').toString('utf8'));
|
|
13
|
+
} catch (_) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function run({ flags }) {
|
|
19
|
+
const authUrl = config.authBaseUrl();
|
|
20
|
+
const auth = new MayarAuth(authUrl);
|
|
21
|
+
|
|
22
|
+
if (!flags.json) {
|
|
23
|
+
ui.printBanner();
|
|
24
|
+
process.stdout.write(`${ui.bold('Sign in to Mayar')}\n`);
|
|
25
|
+
process.stdout.write(`${ui.dim('Auth server:')} ${authUrl}\n\n`);
|
|
26
|
+
process.stdout.write('Opening your browser to complete Google sign-in…\n');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const token = await auth.login({
|
|
30
|
+
openBrowser: !flags['no-browser'],
|
|
31
|
+
onUrl: ({ url }) => {
|
|
32
|
+
if (flags.json) return;
|
|
33
|
+
if (flags['no-browser']) {
|
|
34
|
+
process.stdout.write('\nOpen this URL in your browser to sign in:\n');
|
|
35
|
+
} else {
|
|
36
|
+
process.stdout.write('\nIf your browser did not open automatically, visit:\n');
|
|
37
|
+
}
|
|
38
|
+
process.stdout.write(ui.cyan(url) + '\n\n');
|
|
39
|
+
process.stdout.write(ui.dim('Waiting for you to finish signing in…') + '\n');
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// The SDK returns "authToken,refreshToken".
|
|
44
|
+
const [authToken, refreshToken] = String(token).split(',');
|
|
45
|
+
const claims = decodeJwt(authToken) || {};
|
|
46
|
+
const email = claims.sub || claims.email || null;
|
|
47
|
+
const name = claims.name || null;
|
|
48
|
+
const expiresAt = claims.exp ? new Date(claims.exp * 1000).toISOString() : null;
|
|
49
|
+
|
|
50
|
+
const existing = config.load() || {};
|
|
51
|
+
config.save({
|
|
52
|
+
...existing,
|
|
53
|
+
auth: {
|
|
54
|
+
authToken,
|
|
55
|
+
refreshToken: refreshToken || null,
|
|
56
|
+
email,
|
|
57
|
+
name,
|
|
58
|
+
expiresAt,
|
|
59
|
+
authUrl,
|
|
60
|
+
savedAt: new Date().toISOString(),
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (flags.json) {
|
|
65
|
+
ui.jsonOut({ ok: true, email, name, expiresAt, authUrl });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
process.stdout.write('\n' + ui.green(`✓ Signed in${name ? ` as ${name}` : ''}${email ? ` (${email})` : ''}`) + '\n');
|
|
70
|
+
if (expiresAt) process.stdout.write(`${ui.bold('Token expires:')} ${expiresAt}\n`);
|
|
71
|
+
process.stdout.write(ui.dim(`Credentials saved to ${config.file}`) + '\n');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = { run };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const api = require('../api');
|
|
2
|
+
const ui = require('../ui');
|
|
3
|
+
const { checkResp, readData, pagination, cursorFooter } = require('../util');
|
|
4
|
+
|
|
5
|
+
const USAGE = 'Usage: mayar membership <members|tiers|register|get|update|cancel|create-invoice>';
|
|
6
|
+
|
|
7
|
+
async function run({ apiKey, flags, positional }) {
|
|
8
|
+
const [sub, ...rest] = positional;
|
|
9
|
+
switch (sub) {
|
|
10
|
+
case 'members': {
|
|
11
|
+
if (!flags.productId) throw new Error('mayar membership members requires --productId <id>');
|
|
12
|
+
const res = await api.request('GET', '/hl/v2/memberships/members', {
|
|
13
|
+
apiKey, query: pagination(flags, { productId: flags.productId }),
|
|
14
|
+
});
|
|
15
|
+
checkResp(res);
|
|
16
|
+
if (flags.json) return ui.jsonOut(res.body);
|
|
17
|
+
const data = (res.body && res.body.data) || [];
|
|
18
|
+
const rows = data.map((m) => ({
|
|
19
|
+
id: m.id,
|
|
20
|
+
customer: (m.customer && (m.customer.name || m.customer.email)) || '',
|
|
21
|
+
tier: (m.membershipTier && m.membershipTier.name) || m.membershipTierId || '',
|
|
22
|
+
period: m.membershipMonthlyPeriod ?? '',
|
|
23
|
+
status: m.status || '',
|
|
24
|
+
}));
|
|
25
|
+
ui.table(rows, ['id', 'customer', 'tier', 'period', 'status']);
|
|
26
|
+
cursorFooter(res.body, data.length);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
case 'tiers': {
|
|
30
|
+
if (!flags.productId) throw new Error('mayar membership tiers requires --productId <id>');
|
|
31
|
+
const res = await api.request('GET', '/hl/v2/memberships/tiers', {
|
|
32
|
+
apiKey, query: pagination(flags, { productId: flags.productId }),
|
|
33
|
+
});
|
|
34
|
+
checkResp(res);
|
|
35
|
+
if (flags.json) return ui.jsonOut(res.body);
|
|
36
|
+
const data = (res.body && res.body.data) || [];
|
|
37
|
+
const rows = data.map((t) => ({
|
|
38
|
+
id: t.id, name: t.name, amount: t.amount, status: t.status,
|
|
39
|
+
}));
|
|
40
|
+
ui.table(rows, ['id', 'name', 'amount', 'status']);
|
|
41
|
+
cursorFooter(res.body, data.length);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
case 'register': {
|
|
45
|
+
const body = readData(flags.data);
|
|
46
|
+
if (!body) throw new Error('mayar membership register requires --data <json|@file>');
|
|
47
|
+
const res = await api.request('POST', '/hl/v2/memberships/members/create', { apiKey, body });
|
|
48
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
49
|
+
}
|
|
50
|
+
case 'get':
|
|
51
|
+
case 'detail': {
|
|
52
|
+
if (!rest[0]) throw new Error('Usage: mayar membership get <memberId> --productId <id>');
|
|
53
|
+
if (!flags.productId) throw new Error('mayar membership get requires --productId <id>');
|
|
54
|
+
const res = await api.request('GET', `/hl/v2/memberships/members/${encodeURIComponent(rest[0])}`, {
|
|
55
|
+
apiKey, query: { productId: flags.productId },
|
|
56
|
+
});
|
|
57
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
58
|
+
}
|
|
59
|
+
case 'update': {
|
|
60
|
+
if (!rest[0]) throw new Error('Usage: mayar membership update <memberId> --productId <id> [--data <json|@file>]');
|
|
61
|
+
if (!flags.productId) throw new Error('mayar membership update requires --productId <id>');
|
|
62
|
+
const body = readData(flags.data) || {};
|
|
63
|
+
body.productId = body.productId || flags.productId;
|
|
64
|
+
const res = await api.request('POST', `/hl/v2/memberships/members/${encodeURIComponent(rest[0])}/update`, {
|
|
65
|
+
apiKey, body,
|
|
66
|
+
});
|
|
67
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
68
|
+
}
|
|
69
|
+
case 'cancel': {
|
|
70
|
+
if (!rest[0]) throw new Error('Usage: mayar membership cancel <memberId> --productId <id>');
|
|
71
|
+
if (!flags.productId) throw new Error('mayar membership cancel requires --productId <id>');
|
|
72
|
+
const res = await api.request('POST', `/hl/v2/memberships/members/${encodeURIComponent(rest[0])}/cancel`, {
|
|
73
|
+
apiKey, body: { productId: flags.productId },
|
|
74
|
+
});
|
|
75
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
76
|
+
}
|
|
77
|
+
case 'create-invoice':
|
|
78
|
+
case 'createinvoice':
|
|
79
|
+
case 'invoice': {
|
|
80
|
+
if (!rest[0]) throw new Error('Usage: mayar membership create-invoice <memberId> --productId <id>');
|
|
81
|
+
if (!flags.productId) throw new Error('mayar membership create-invoice requires --productId <id>');
|
|
82
|
+
const res = await api.request('POST', `/hl/v2/memberships/members/${encodeURIComponent(rest[0])}/invoice/create`, {
|
|
83
|
+
apiKey, body: { productId: flags.productId },
|
|
84
|
+
});
|
|
85
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
86
|
+
}
|
|
87
|
+
default:
|
|
88
|
+
throw new Error(USAGE);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = { run };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const api = require('../api');
|
|
2
|
+
const ui = require('../ui');
|
|
3
|
+
const { checkResp, readData } = require('../util');
|
|
4
|
+
|
|
5
|
+
const USAGE = 'Usage: mayar payment-link edit <id> --data <json|@file>';
|
|
6
|
+
|
|
7
|
+
// Companion to `mayar product edit --type payment-link` — surfaces the alternate
|
|
8
|
+
// v2 route at /hl/v2/payment-links/{id}/update, which the docs confirm shares a
|
|
9
|
+
// handler with /hl/v2/products/payment-link/{id}/update.
|
|
10
|
+
async function run({ apiKey, flags, positional }) {
|
|
11
|
+
const [sub, ...rest] = positional;
|
|
12
|
+
if (sub !== 'edit') throw new Error(USAGE);
|
|
13
|
+
if (!rest[0]) throw new Error(USAGE);
|
|
14
|
+
const body = readData(flags.data);
|
|
15
|
+
if (!body) throw new Error('mayar payment-link edit requires --data <json|@file>');
|
|
16
|
+
body.id = body.id || rest[0];
|
|
17
|
+
const res = await api.request('POST', `/hl/v2/payment-links/${encodeURIComponent(rest[0])}/update`, {
|
|
18
|
+
apiKey, body,
|
|
19
|
+
});
|
|
20
|
+
checkResp(res); ui.jsonOut(res.body);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = { run };
|
package/src/commands/payment.js
CHANGED
|
@@ -1,44 +1,60 @@
|
|
|
1
1
|
const api = require('../api');
|
|
2
2
|
const ui = require('../ui');
|
|
3
|
-
const { checkResp, readData } = require('../util');
|
|
3
|
+
const { checkResp, readData, pagination, cursorFooter } = require('../util');
|
|
4
4
|
|
|
5
|
-
const USAGE = 'Usage: mayar payment <list|get|close|reopen|create>';
|
|
5
|
+
const USAGE = 'Usage: mayar payment <list|get|close|reopen|status|edit|create>';
|
|
6
|
+
const STATUS_ACTIONS = ['open', 'close', 'active', 'closed', 'unlisted'];
|
|
6
7
|
|
|
7
8
|
async function run({ apiKey, flags, positional }) {
|
|
8
9
|
const [sub, ...rest] = positional;
|
|
9
10
|
switch (sub) {
|
|
10
11
|
case 'list': {
|
|
11
|
-
const res = await api.request('GET', '/hl/
|
|
12
|
-
apiKey, query:
|
|
12
|
+
const res = await api.request('GET', '/hl/v2/payments', {
|
|
13
|
+
apiKey, query: pagination(flags, { status: flags.status }),
|
|
13
14
|
});
|
|
14
15
|
checkResp(res);
|
|
15
16
|
if (flags.json) return ui.jsonOut(res.body);
|
|
16
17
|
const data = (res.body && res.body.data) || [];
|
|
17
18
|
const rows = data.map((p) => ({
|
|
18
|
-
id: p.id, name: p.name, amount: p.amount, status: p.status,
|
|
19
|
+
id: p.id, name: p.name, amount: p.amount, status: p.status,
|
|
20
|
+
createdAt: typeof p.createdAt === 'number' ? new Date(p.createdAt).toISOString() : (p.createdAt || ''),
|
|
19
21
|
}));
|
|
20
22
|
ui.table(rows, ['id', 'name', 'amount', 'status', 'createdAt']);
|
|
23
|
+
cursorFooter(res.body, data.length);
|
|
21
24
|
return;
|
|
22
25
|
}
|
|
23
26
|
case 'get': {
|
|
24
27
|
if (!rest[0]) throw new Error('Usage: mayar payment get <id>');
|
|
25
|
-
const res = await api.request('GET', `/hl/
|
|
28
|
+
const res = await api.request('GET', `/hl/v2/payments/${encodeURIComponent(rest[0])}`, { apiKey });
|
|
26
29
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
27
30
|
}
|
|
28
|
-
case 'close':
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
case 'close':
|
|
32
|
+
case 'reopen': {
|
|
33
|
+
if (!rest[0]) throw new Error(`Usage: mayar payment ${sub} <id>`);
|
|
34
|
+
const action = sub === 'reopen' ? 'open' : 'close';
|
|
35
|
+
const res = await api.request('POST', `/hl/v2/payments/${encodeURIComponent(rest[0])}/${action}`, { apiKey });
|
|
31
36
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
32
37
|
}
|
|
33
|
-
case '
|
|
34
|
-
if (!rest[0]) throw new Error(
|
|
35
|
-
|
|
38
|
+
case 'status': {
|
|
39
|
+
if (!rest[0] || !rest[1]) throw new Error(`Usage: mayar payment status <id> <${STATUS_ACTIONS.join('|')}>`);
|
|
40
|
+
if (!STATUS_ACTIONS.includes(rest[1])) {
|
|
41
|
+
throw new Error(`Invalid action "${rest[1]}". Must be one of: ${STATUS_ACTIONS.join(', ')}`);
|
|
42
|
+
}
|
|
43
|
+
const res = await api.request('POST', `/hl/v2/payments/${encodeURIComponent(rest[0])}/${rest[1]}`, { apiKey });
|
|
44
|
+
checkResp(res); ui.jsonOut(res.body); return;
|
|
45
|
+
}
|
|
46
|
+
case 'edit': {
|
|
47
|
+
if (!rest[0]) throw new Error('Usage: mayar payment edit <id> --data <json|@file>');
|
|
48
|
+
const body = readData(flags.data);
|
|
49
|
+
if (!body) throw new Error('mayar payment edit requires --data <json|@file>');
|
|
50
|
+
body.id = body.id || rest[0];
|
|
51
|
+
const res = await api.request('POST', `/hl/v2/payments/${encodeURIComponent(rest[0])}/update`, { apiKey, body });
|
|
36
52
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
37
53
|
}
|
|
38
54
|
case 'create': {
|
|
39
55
|
const body = readData(flags.data);
|
|
40
|
-
if (!body) throw new Error('mayar payment create requires --data <json|@file
|
|
41
|
-
const res = await api.request('POST', '/hl/
|
|
56
|
+
if (!body) throw new Error('mayar payment create requires --data <json|@file>');
|
|
57
|
+
const res = await api.request('POST', '/hl/v2/payments/create', { apiKey, body });
|
|
42
58
|
checkResp(res); ui.jsonOut(res.body); return;
|
|
43
59
|
}
|
|
44
60
|
default:
|