@targlobal/mission-control 1.3.3 → 1.4.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/dist/api.d.ts +34 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +25 -0
- package/dist/api.js.map +1 -1
- package/dist/index.js +478 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +57 -0
- package/src/index.ts +503 -50
package/src/index.ts
CHANGED
|
@@ -6,10 +6,10 @@ import ora from 'ora';
|
|
|
6
6
|
import Table from 'cli-table3';
|
|
7
7
|
import inquirer from 'inquirer';
|
|
8
8
|
import { getConfig, setConfig, isAuthenticated, clearConfig, setUser, getUser } from './config';
|
|
9
|
-
import { api, Task, Board, Payout, PayoutMetrics, resetApiClient } from './api';
|
|
9
|
+
import { api, Task, Board, Payout, PayoutMetrics, TarPayPayout, resetApiClient } from './api';
|
|
10
10
|
import { execSync, spawn } from 'child_process';
|
|
11
11
|
|
|
12
|
-
const VERSION = '1.
|
|
12
|
+
const VERSION = '1.4.0';
|
|
13
13
|
const program = new Command();
|
|
14
14
|
|
|
15
15
|
// Set terminal title
|
|
@@ -709,6 +709,7 @@ const PLAN_COLORS: Record<string, (s: string) => string> = {
|
|
|
709
709
|
validator_v2: chalk.blue,
|
|
710
710
|
booster: chalk.green,
|
|
711
711
|
dumpster: chalk.gray,
|
|
712
|
+
christmas: chalk.red,
|
|
712
713
|
};
|
|
713
714
|
|
|
714
715
|
const PLAN_ICONS: Record<string, string> = {
|
|
@@ -718,6 +719,46 @@ const PLAN_ICONS: Record<string, string> = {
|
|
|
718
719
|
validator_v2: '🔐',
|
|
719
720
|
booster: '🚀',
|
|
720
721
|
dumpster: '🗑️',
|
|
722
|
+
christmas: '🎄',
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
// Helper to get percentage (preset or custom input)
|
|
726
|
+
const getPercentageWithCustom = async (): Promise<number | null> => {
|
|
727
|
+
const { percentage } = await inquirer.prompt([
|
|
728
|
+
{
|
|
729
|
+
type: 'list',
|
|
730
|
+
name: 'percentage',
|
|
731
|
+
message: 'Select percentage of remaining amount to pay:',
|
|
732
|
+
choices: [
|
|
733
|
+
{ name: '10%', value: 10 },
|
|
734
|
+
{ name: '25%', value: 25 },
|
|
735
|
+
{ name: '50%', value: 50 },
|
|
736
|
+
{ name: '75%', value: 75 },
|
|
737
|
+
{ name: '100% (Full)', value: 100 },
|
|
738
|
+
{ name: chalk.cyan('Custom...'), value: -1 },
|
|
739
|
+
],
|
|
740
|
+
},
|
|
741
|
+
]);
|
|
742
|
+
|
|
743
|
+
if (percentage === -1) {
|
|
744
|
+
const { customPct } = await inquirer.prompt([
|
|
745
|
+
{
|
|
746
|
+
type: 'input',
|
|
747
|
+
name: 'customPct',
|
|
748
|
+
message: 'Enter custom percentage (1-100):',
|
|
749
|
+
validate: (input: string) => {
|
|
750
|
+
const num = parseFloat(input);
|
|
751
|
+
if (isNaN(num) || num < 1 || num > 100) {
|
|
752
|
+
return 'Please enter a number between 1 and 100';
|
|
753
|
+
}
|
|
754
|
+
return true;
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
]);
|
|
758
|
+
return parseFloat(customPct);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return percentage;
|
|
721
762
|
};
|
|
722
763
|
|
|
723
764
|
const formatAmount = (amount: number, crypto?: string): string => {
|
|
@@ -1232,6 +1273,434 @@ const processPayoutsWithProgress = async (ids: number[], action: 'approve' | 'ca
|
|
|
1232
1273
|
}
|
|
1233
1274
|
};
|
|
1234
1275
|
|
|
1276
|
+
// ==================== CHRISTMAS/TARPAY PAYOUT FUNCTIONS ====================
|
|
1277
|
+
|
|
1278
|
+
const listChristmasPayoutsCmd = async (options: { status?: string; page?: number }) => {
|
|
1279
|
+
const spinner = ora('Loading Christmas payouts...').start();
|
|
1280
|
+
const compact = isCompact();
|
|
1281
|
+
|
|
1282
|
+
try {
|
|
1283
|
+
const data = await api.getTarPayPayouts({
|
|
1284
|
+
plan: 'christmas',
|
|
1285
|
+
status: options.status || 'pending_review',
|
|
1286
|
+
limit: compact ? 10 : 20,
|
|
1287
|
+
offset: ((options.page || 1) - 1) * (compact ? 10 : 20),
|
|
1288
|
+
});
|
|
1289
|
+
const payouts: TarPayPayout[] = data.results || [];
|
|
1290
|
+
spinner.stop();
|
|
1291
|
+
|
|
1292
|
+
if (payouts.length === 0) {
|
|
1293
|
+
console.log(chalk.dim('\n No Christmas payouts found\n'));
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// Info banner about $50 threshold
|
|
1298
|
+
console.log('');
|
|
1299
|
+
console.log(chalk.red('🎄 CHRISTMAS PAYOUTS') + chalk.dim(' (TarPay)'));
|
|
1300
|
+
console.log(chalk.dim(' Payouts > $50 require manual approval. < $50 are auto-sent.'));
|
|
1301
|
+
console.log('');
|
|
1302
|
+
|
|
1303
|
+
if (compact) {
|
|
1304
|
+
payouts.forEach((p) => {
|
|
1305
|
+
const isPartial = p.has_partial_payments && (p.paid_percentage || 0) > 0;
|
|
1306
|
+
const statusIcon = p.status === 'completed' ? chalk.green('✓') :
|
|
1307
|
+
p.status === 'failed' ? chalk.red('✗') :
|
|
1308
|
+
isPartial ? chalk.cyan('%') : chalk.yellow('●');
|
|
1309
|
+
const email = p.user_email.length > 12 ? p.user_email.substring(0, 10) + '..' : p.user_email;
|
|
1310
|
+
const displayAmt = isPartial ? (p.remaining_amount || parseFloat(p.amount)) : parseFloat(p.amount);
|
|
1311
|
+
const amountStr = isPartial ? `${displayAmt.toFixed(2)}(${Math.round(p.paid_percentage || 0)}%)` : displayAmt.toFixed(2);
|
|
1312
|
+
console.log(` ${statusIcon} ${chalk.dim('#' + p.id)} ${chalk.red('xmas')} ${email} ${chalk.green(amountStr)} ${p.currency}`);
|
|
1313
|
+
});
|
|
1314
|
+
console.log(chalk.dim(`\n ${data.count} total\n`));
|
|
1315
|
+
} else {
|
|
1316
|
+
const table = new Table({
|
|
1317
|
+
head: [
|
|
1318
|
+
chalk.cyan('ID'),
|
|
1319
|
+
chalk.cyan('User'),
|
|
1320
|
+
chalk.cyan('Remaining'),
|
|
1321
|
+
chalk.cyan('Crypto'),
|
|
1322
|
+
chalk.cyan('Progress'),
|
|
1323
|
+
chalk.cyan('Status'),
|
|
1324
|
+
],
|
|
1325
|
+
style: { head: [], border: [] },
|
|
1326
|
+
colWidths: [8, 24, 14, 10, 12, 14],
|
|
1327
|
+
});
|
|
1328
|
+
|
|
1329
|
+
payouts.forEach((p) => {
|
|
1330
|
+
const isPartial = p.has_partial_payments && (p.paid_percentage || 0) > 0;
|
|
1331
|
+
const paidPct = p.paid_percentage || 0;
|
|
1332
|
+
const displayAmount = isPartial ? (p.remaining_amount || parseFloat(p.amount)) : parseFloat(p.amount);
|
|
1333
|
+
|
|
1334
|
+
let statusIcon;
|
|
1335
|
+
if (p.status === 'completed') {
|
|
1336
|
+
statusIcon = chalk.green('✓ Done');
|
|
1337
|
+
} else if (p.status === 'failed') {
|
|
1338
|
+
statusIcon = chalk.red('✗ Failed');
|
|
1339
|
+
} else if (isPartial) {
|
|
1340
|
+
statusIcon = chalk.cyan(`% ${Math.round(paidPct)}%`);
|
|
1341
|
+
} else if (p.status === 'pending_review') {
|
|
1342
|
+
statusIcon = chalk.yellow('● Review');
|
|
1343
|
+
} else {
|
|
1344
|
+
statusIcon = chalk.blue('~ ' + p.status);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// Progress bar for partial payments
|
|
1348
|
+
let progressStr = '-';
|
|
1349
|
+
if (isPartial) {
|
|
1350
|
+
const filled = Math.round(paidPct / 10);
|
|
1351
|
+
const empty = 10 - filled;
|
|
1352
|
+
progressStr = chalk.green('█'.repeat(filled)) + chalk.dim('░'.repeat(empty));
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
table.push([
|
|
1356
|
+
chalk.dim(String(p.id)),
|
|
1357
|
+
p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email,
|
|
1358
|
+
chalk.green('$' + displayAmount.toFixed(2)),
|
|
1359
|
+
p.currency,
|
|
1360
|
+
progressStr,
|
|
1361
|
+
statusIcon,
|
|
1362
|
+
]);
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1365
|
+
console.log(table.toString());
|
|
1366
|
+
console.log(chalk.dim(`\n ${data.count} total\n`));
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
} catch (error: any) {
|
|
1370
|
+
spinner.fail(chalk.red('Failed to load Christmas payouts'));
|
|
1371
|
+
console.log(chalk.dim(` ${error.response?.data?.detail || error.message}\n`));
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
const selectChristmasPayoutsInteractive = async (status?: string): Promise<number[]> => {
|
|
1376
|
+
const spinner = ora('Loading Christmas payouts...').start();
|
|
1377
|
+
|
|
1378
|
+
try {
|
|
1379
|
+
const data = await api.getTarPayPayouts({
|
|
1380
|
+
plan: 'christmas',
|
|
1381
|
+
status: status || 'pending_review',
|
|
1382
|
+
limit: 100,
|
|
1383
|
+
});
|
|
1384
|
+
const payouts: TarPayPayout[] = data.results || [];
|
|
1385
|
+
spinner.stop();
|
|
1386
|
+
|
|
1387
|
+
if (payouts.length === 0) {
|
|
1388
|
+
console.log(chalk.dim('\n No Christmas payouts found\n'));
|
|
1389
|
+
return [];
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
const choices = payouts.map((p) => {
|
|
1393
|
+
const isPartial = p.has_partial_payments && (p.paid_percentage || 0) > 0;
|
|
1394
|
+
const displayAmount = isPartial ? (p.remaining_amount || parseFloat(p.amount)) : parseFloat(p.amount);
|
|
1395
|
+
const progressStr = isPartial ? chalk.cyan(` (${Math.round(p.paid_percentage || 0)}% paid)`) : '';
|
|
1396
|
+
return {
|
|
1397
|
+
name: `${chalk.red('🎄')} ${chalk.dim('#' + p.id)} ${p.user_email.substring(0, 25).padEnd(25)} ${chalk.green('$' + displayAmount.toFixed(2).padStart(10))} ${chalk.dim(p.currency)}${progressStr}`,
|
|
1398
|
+
value: p.id,
|
|
1399
|
+
short: `#${p.id}`,
|
|
1400
|
+
};
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
const { selected } = await inquirer.prompt([
|
|
1404
|
+
{
|
|
1405
|
+
type: 'checkbox',
|
|
1406
|
+
name: 'selected',
|
|
1407
|
+
message: 'Select Christmas payouts to process:',
|
|
1408
|
+
choices,
|
|
1409
|
+
pageSize: 15,
|
|
1410
|
+
loop: false,
|
|
1411
|
+
},
|
|
1412
|
+
]);
|
|
1413
|
+
|
|
1414
|
+
return selected;
|
|
1415
|
+
} catch (error: any) {
|
|
1416
|
+
spinner.fail(chalk.red('Failed to load Christmas payouts'));
|
|
1417
|
+
return [];
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1421
|
+
const processChristmasPayoutsWithProgress = async (ids: number[], action: 'approve' | 'reject' | 'partial', percentage?: number) => {
|
|
1422
|
+
const actionLabel = action === 'partial' ? `PARTIAL ${percentage}%` : action.toUpperCase();
|
|
1423
|
+
console.log('\n' + chalk.red('╔══════════════════════════════════════════════════════════════╗'));
|
|
1424
|
+
console.log(chalk.red('║') + chalk.bold.white(` 🎄 CHRISTMAS ${actionLabel} - ${ids.length} PAYOUT(S)... `.substring(0, 60)) + chalk.red('║'));
|
|
1425
|
+
console.log(chalk.red('╠══════════════════════════════════════════════════════════════╣'));
|
|
1426
|
+
|
|
1427
|
+
const startTime = Date.now();
|
|
1428
|
+
|
|
1429
|
+
// Show progress
|
|
1430
|
+
let processed = 0;
|
|
1431
|
+
const progressBar = (current: number, total: number) => {
|
|
1432
|
+
const percent = Math.round((current / total) * 100);
|
|
1433
|
+
const filled = Math.round(percent / 2);
|
|
1434
|
+
const empty = 50 - filled;
|
|
1435
|
+
return chalk.green('█'.repeat(filled)) + chalk.dim('░'.repeat(empty)) + ` ${percent}%`;
|
|
1436
|
+
};
|
|
1437
|
+
|
|
1438
|
+
const progressInterval = setInterval(() => {
|
|
1439
|
+
processed = Math.min(processed + Math.random() * 10, 90);
|
|
1440
|
+
process.stdout.write(`\r${chalk.red('║')} ${progressBar(processed, 100)} ${chalk.red('║')}`);
|
|
1441
|
+
}, 200);
|
|
1442
|
+
|
|
1443
|
+
try {
|
|
1444
|
+
let result: any;
|
|
1445
|
+
let successCount = 0;
|
|
1446
|
+
let failedCount = 0;
|
|
1447
|
+
const errors: string[] = [];
|
|
1448
|
+
|
|
1449
|
+
if (action === 'partial') {
|
|
1450
|
+
result = await api.batchTarPayPartialPayouts(ids, percentage!);
|
|
1451
|
+
successCount = result.success_count || 0;
|
|
1452
|
+
failedCount = result.failed_count || 0;
|
|
1453
|
+
} else {
|
|
1454
|
+
// Process approve/reject one by one
|
|
1455
|
+
for (const id of ids) {
|
|
1456
|
+
try {
|
|
1457
|
+
if (action === 'approve') {
|
|
1458
|
+
await api.approveTarPayPayout(id);
|
|
1459
|
+
} else {
|
|
1460
|
+
await api.rejectTarPayPayout(id);
|
|
1461
|
+
}
|
|
1462
|
+
successCount++;
|
|
1463
|
+
} catch (e: any) {
|
|
1464
|
+
failedCount++;
|
|
1465
|
+
errors.push(`#${id}: ${e.response?.data?.detail || e.message}`);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
result = { success: true, success_count: successCount, failed_count: failedCount, errors };
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
clearInterval(progressInterval);
|
|
1472
|
+
processed = 100;
|
|
1473
|
+
process.stdout.write(`\r${chalk.red('║')} ${progressBar(100, 100)} ${chalk.red('║')}\n`);
|
|
1474
|
+
|
|
1475
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
1476
|
+
console.log(chalk.red('╠══════════════════════════════════════════════════════════════╣'));
|
|
1477
|
+
|
|
1478
|
+
let icon, verb;
|
|
1479
|
+
if (action === 'approve') {
|
|
1480
|
+
icon = '✓'; verb = 'APPROVED';
|
|
1481
|
+
} else if (action === 'partial') {
|
|
1482
|
+
icon = '%'; verb = `PARTIAL ${percentage}% SENT`;
|
|
1483
|
+
} else {
|
|
1484
|
+
icon = '↩'; verb = 'REJECTED';
|
|
1485
|
+
}
|
|
1486
|
+
console.log(chalk.red('║') + chalk.green(` ${icon} ${verb} `.substring(0, 60)) + chalk.red('║'));
|
|
1487
|
+
console.log(chalk.red('║') + ` Successful: ${chalk.bold.green(String(successCount).padEnd(5))} Failed: ${chalk.bold.red(String(failedCount).padEnd(5))} Time: ${chalk.dim(elapsed + 's')}`.padEnd(62) + chalk.red('║'));
|
|
1488
|
+
|
|
1489
|
+
console.log(chalk.red('╚══════════════════════════════════════════════════════════════╝\n'));
|
|
1490
|
+
|
|
1491
|
+
// Show errors if any
|
|
1492
|
+
const errList = result.errors || errors;
|
|
1493
|
+
if (errList.length > 0) {
|
|
1494
|
+
console.log(chalk.red(' Errors:'));
|
|
1495
|
+
errList.slice(0, 5).forEach((err: any) => {
|
|
1496
|
+
const errMsg = typeof err === 'string' ? err : `Payout ${err.payout_id}: ${err.error}`;
|
|
1497
|
+
console.log(chalk.dim(` - ${errMsg}`));
|
|
1498
|
+
});
|
|
1499
|
+
if (errList.length > 5) {
|
|
1500
|
+
console.log(chalk.dim(` ... and ${errList.length - 5} more errors`));
|
|
1501
|
+
}
|
|
1502
|
+
console.log('');
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
return result;
|
|
1506
|
+
} catch (error: any) {
|
|
1507
|
+
clearInterval(progressInterval);
|
|
1508
|
+
console.log(chalk.red('║') + chalk.red(' ✗ ERROR: ' + (error.response?.data?.detail || error.message).substring(0, 50).padEnd(52)) + chalk.red('║'));
|
|
1509
|
+
console.log(chalk.red('╚══════════════════════════════════════════════════════════════╝\n'));
|
|
1510
|
+
return { success: false };
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
|
|
1514
|
+
const runChristmasPayoutsShell = async () => {
|
|
1515
|
+
setTitle('Christmas Payouts');
|
|
1516
|
+
|
|
1517
|
+
// Show initial list
|
|
1518
|
+
await listChristmasPayoutsCmd({ status: 'pending_review' });
|
|
1519
|
+
|
|
1520
|
+
const runLoop = async () => {
|
|
1521
|
+
const { command } = await inquirer.prompt([
|
|
1522
|
+
{
|
|
1523
|
+
type: 'input',
|
|
1524
|
+
name: 'command',
|
|
1525
|
+
message: chalk.red('christmas') + chalk.cyan(' > '),
|
|
1526
|
+
prefix: '',
|
|
1527
|
+
},
|
|
1528
|
+
]);
|
|
1529
|
+
|
|
1530
|
+
const parts = command.trim().split(/\s+/);
|
|
1531
|
+
const cmd = parts[0]?.toLowerCase();
|
|
1532
|
+
|
|
1533
|
+
if (cmd === 'back' || cmd === 'exit' || cmd === 'q') {
|
|
1534
|
+
setTitle('Payouts');
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
if (cmd === '') {
|
|
1539
|
+
return runLoop();
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
try {
|
|
1543
|
+
switch (cmd) {
|
|
1544
|
+
case 'refresh':
|
|
1545
|
+
case 'r':
|
|
1546
|
+
case 'list':
|
|
1547
|
+
case 'ls':
|
|
1548
|
+
await listChristmasPayoutsCmd({ status: 'pending_review' });
|
|
1549
|
+
break;
|
|
1550
|
+
case 'all':
|
|
1551
|
+
await listChristmasPayoutsCmd({});
|
|
1552
|
+
break;
|
|
1553
|
+
case 'done':
|
|
1554
|
+
case 'completed':
|
|
1555
|
+
await listChristmasPayoutsCmd({ status: 'completed' });
|
|
1556
|
+
break;
|
|
1557
|
+
case 'failed':
|
|
1558
|
+
await listChristmasPayoutsCmd({ status: 'failed' });
|
|
1559
|
+
break;
|
|
1560
|
+
case 'select':
|
|
1561
|
+
case 's':
|
|
1562
|
+
const selectedIds = await selectChristmasPayoutsInteractive('pending_review');
|
|
1563
|
+
if (selectedIds.length > 0) {
|
|
1564
|
+
const { action } = await inquirer.prompt([
|
|
1565
|
+
{
|
|
1566
|
+
type: 'list',
|
|
1567
|
+
name: 'action',
|
|
1568
|
+
message: `What do you want to do with ${selectedIds.length} selected payout(s)?`,
|
|
1569
|
+
choices: [
|
|
1570
|
+
{ name: chalk.green('✓ Approve & Send 100%'), value: 'approve' },
|
|
1571
|
+
{ name: chalk.cyan('% Pay Partial % (custom amount)'), value: 'partial' },
|
|
1572
|
+
{ name: chalk.yellow('↩ Reject'), value: 'reject' },
|
|
1573
|
+
{ name: chalk.dim('✗ Cancel'), value: 'none' },
|
|
1574
|
+
],
|
|
1575
|
+
},
|
|
1576
|
+
]);
|
|
1577
|
+
|
|
1578
|
+
if (action === 'approve') {
|
|
1579
|
+
const { confirm } = await inquirer.prompt([
|
|
1580
|
+
{
|
|
1581
|
+
type: 'confirm',
|
|
1582
|
+
name: 'confirm',
|
|
1583
|
+
message: chalk.yellow(`⚠️ Confirm: Approve ${selectedIds.length} payout(s)?`),
|
|
1584
|
+
default: false,
|
|
1585
|
+
},
|
|
1586
|
+
]);
|
|
1587
|
+
if (confirm) {
|
|
1588
|
+
await processChristmasPayoutsWithProgress(selectedIds, 'approve');
|
|
1589
|
+
}
|
|
1590
|
+
} else if (action === 'partial') {
|
|
1591
|
+
const percentage = await getPercentageWithCustom();
|
|
1592
|
+
if (percentage !== null) {
|
|
1593
|
+
const { confirm } = await inquirer.prompt([
|
|
1594
|
+
{
|
|
1595
|
+
type: 'confirm',
|
|
1596
|
+
name: 'confirm',
|
|
1597
|
+
message: chalk.yellow(`⚠️ Confirm: Pay ${percentage}% of ${selectedIds.length} payout(s)?`),
|
|
1598
|
+
default: false,
|
|
1599
|
+
},
|
|
1600
|
+
]);
|
|
1601
|
+
if (confirm) {
|
|
1602
|
+
await processChristmasPayoutsWithProgress(selectedIds, 'partial', percentage);
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
} else if (action === 'reject') {
|
|
1606
|
+
const { confirm } = await inquirer.prompt([
|
|
1607
|
+
{
|
|
1608
|
+
type: 'confirm',
|
|
1609
|
+
name: 'confirm',
|
|
1610
|
+
message: chalk.yellow(`⚠️ Confirm: Reject ${selectedIds.length} payout(s)?`),
|
|
1611
|
+
default: false,
|
|
1612
|
+
},
|
|
1613
|
+
]);
|
|
1614
|
+
if (confirm) {
|
|
1615
|
+
await processChristmasPayoutsWithProgress(selectedIds, 'reject');
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
break;
|
|
1620
|
+
case 'approve':
|
|
1621
|
+
case 'a':
|
|
1622
|
+
const approveIds = await selectChristmasPayoutsInteractive('pending_review');
|
|
1623
|
+
if (approveIds.length > 0) {
|
|
1624
|
+
const { confirm } = await inquirer.prompt([
|
|
1625
|
+
{
|
|
1626
|
+
type: 'confirm',
|
|
1627
|
+
name: 'confirm',
|
|
1628
|
+
message: chalk.yellow(`⚠️ Approve ${approveIds.length} payout(s)?`),
|
|
1629
|
+
default: false,
|
|
1630
|
+
},
|
|
1631
|
+
]);
|
|
1632
|
+
if (confirm) {
|
|
1633
|
+
await processChristmasPayoutsWithProgress(approveIds, 'approve');
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
break;
|
|
1637
|
+
case 'partial':
|
|
1638
|
+
case 'p':
|
|
1639
|
+
const partialIds = await selectChristmasPayoutsInteractive('pending_review');
|
|
1640
|
+
if (partialIds.length > 0) {
|
|
1641
|
+
const percentage = await getPercentageWithCustom();
|
|
1642
|
+
if (percentage !== null) {
|
|
1643
|
+
const { confirm } = await inquirer.prompt([
|
|
1644
|
+
{
|
|
1645
|
+
type: 'confirm',
|
|
1646
|
+
name: 'confirm',
|
|
1647
|
+
message: chalk.yellow(`⚠️ Pay ${percentage}% of ${partialIds.length} payout(s)?`),
|
|
1648
|
+
default: false,
|
|
1649
|
+
},
|
|
1650
|
+
]);
|
|
1651
|
+
if (confirm) {
|
|
1652
|
+
await processChristmasPayoutsWithProgress(partialIds, 'partial', percentage);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
break;
|
|
1657
|
+
case 'reject':
|
|
1658
|
+
const rejectIds = await selectChristmasPayoutsInteractive('pending_review');
|
|
1659
|
+
if (rejectIds.length > 0) {
|
|
1660
|
+
const { confirm } = await inquirer.prompt([
|
|
1661
|
+
{
|
|
1662
|
+
type: 'confirm',
|
|
1663
|
+
name: 'confirm',
|
|
1664
|
+
message: chalk.yellow(`⚠️ Reject ${rejectIds.length} payout(s)?`),
|
|
1665
|
+
default: false,
|
|
1666
|
+
},
|
|
1667
|
+
]);
|
|
1668
|
+
if (confirm) {
|
|
1669
|
+
await processChristmasPayoutsWithProgress(rejectIds, 'reject');
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
break;
|
|
1673
|
+
case 'help':
|
|
1674
|
+
case '?':
|
|
1675
|
+
console.log(chalk.red('\n 🎄 Christmas Payout Commands:'));
|
|
1676
|
+
console.log(chalk.dim(' ────────────────────────────────'));
|
|
1677
|
+
console.log(' refresh, r Refresh pending payouts');
|
|
1678
|
+
console.log(' list, ls List pending_review payouts');
|
|
1679
|
+
console.log(' all List all payouts (any status)');
|
|
1680
|
+
console.log(' done List completed payouts');
|
|
1681
|
+
console.log(' failed List failed payouts');
|
|
1682
|
+
console.log(' select, s Interactive selection mode');
|
|
1683
|
+
console.log(' approve, a Select & approve payouts');
|
|
1684
|
+
console.log(chalk.cyan(' partial, p Select & pay partial %'));
|
|
1685
|
+
console.log(' reject Select & reject payouts');
|
|
1686
|
+
console.log(' back, q Return to main payouts');
|
|
1687
|
+
console.log(chalk.dim('\n Note: Payouts > $50 need approval, < $50 auto-sent'));
|
|
1688
|
+
console.log('');
|
|
1689
|
+
break;
|
|
1690
|
+
default:
|
|
1691
|
+
console.log(chalk.red(` Unknown command: ${cmd}`));
|
|
1692
|
+
console.log(chalk.dim(' Type "help" for available commands\n'));
|
|
1693
|
+
}
|
|
1694
|
+
} catch (e: any) {
|
|
1695
|
+
console.log(chalk.red(` Error: ${e.message}\n`));
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
await runLoop();
|
|
1699
|
+
};
|
|
1700
|
+
|
|
1701
|
+
await runLoop();
|
|
1702
|
+
};
|
|
1703
|
+
|
|
1235
1704
|
const runPayoutsShell = async () => {
|
|
1236
1705
|
setTitle('Payouts');
|
|
1237
1706
|
await showPayoutDashboard();
|
|
@@ -1303,30 +1772,19 @@ const runPayoutsShell = async () => {
|
|
|
1303
1772
|
await processPayoutsWithProgress(selectedIds, 'approve');
|
|
1304
1773
|
}
|
|
1305
1774
|
} else if (action === 'partial') {
|
|
1306
|
-
const
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
}
|
|
1319
|
-
]);
|
|
1320
|
-
const { confirm } = await inquirer.prompt([
|
|
1321
|
-
{
|
|
1322
|
-
type: 'confirm',
|
|
1323
|
-
name: 'confirm',
|
|
1324
|
-
message: chalk.yellow(`⚠️ Confirm: Pay ${percentage}% of ${selectedIds.length} payout(s)?`),
|
|
1325
|
-
default: false,
|
|
1326
|
-
},
|
|
1327
|
-
]);
|
|
1328
|
-
if (confirm) {
|
|
1329
|
-
await processPayoutsWithProgress(selectedIds, 'partial', percentage);
|
|
1775
|
+
const percentage = await getPercentageWithCustom();
|
|
1776
|
+
if (percentage !== null) {
|
|
1777
|
+
const { confirm } = await inquirer.prompt([
|
|
1778
|
+
{
|
|
1779
|
+
type: 'confirm',
|
|
1780
|
+
name: 'confirm',
|
|
1781
|
+
message: chalk.yellow(`⚠️ Confirm: Pay ${percentage}% of ${selectedIds.length} payout(s)?`),
|
|
1782
|
+
default: false,
|
|
1783
|
+
},
|
|
1784
|
+
]);
|
|
1785
|
+
if (confirm) {
|
|
1786
|
+
await processPayoutsWithProgress(selectedIds, 'partial', percentage);
|
|
1787
|
+
}
|
|
1330
1788
|
}
|
|
1331
1789
|
} else if (action === 'cancel') {
|
|
1332
1790
|
const { confirm } = await inquirer.prompt([
|
|
@@ -1395,30 +1853,19 @@ const runPayoutsShell = async () => {
|
|
|
1395
1853
|
const partialPlan = args.find((a: string) => !a.startsWith('-') && isNaN(Number(a)));
|
|
1396
1854
|
const partialSelected = await selectPayoutsInteractive(partialPlan);
|
|
1397
1855
|
if (partialSelected.length > 0) {
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
}
|
|
1411
|
-
]);
|
|
1412
|
-
const { confirmPartial } = await inquirer.prompt([
|
|
1413
|
-
{
|
|
1414
|
-
type: 'confirm',
|
|
1415
|
-
name: 'confirmPartial',
|
|
1416
|
-
message: chalk.yellow(`⚠️ Pay ${partialPercentage}% of ${partialSelected.length} payout(s)?`),
|
|
1417
|
-
default: false,
|
|
1418
|
-
},
|
|
1419
|
-
]);
|
|
1420
|
-
if (confirmPartial) {
|
|
1421
|
-
await processPayoutsWithProgress(partialSelected, 'partial', partialPercentage);
|
|
1856
|
+
const partialPercentage = await getPercentageWithCustom();
|
|
1857
|
+
if (partialPercentage !== null) {
|
|
1858
|
+
const { confirmPartial } = await inquirer.prompt([
|
|
1859
|
+
{
|
|
1860
|
+
type: 'confirm',
|
|
1861
|
+
name: 'confirmPartial',
|
|
1862
|
+
message: chalk.yellow(`⚠️ Pay ${partialPercentage}% of ${partialSelected.length} payout(s)?`),
|
|
1863
|
+
default: false,
|
|
1864
|
+
},
|
|
1865
|
+
]);
|
|
1866
|
+
if (confirmPartial) {
|
|
1867
|
+
await processPayoutsWithProgress(partialSelected, 'partial', partialPercentage);
|
|
1868
|
+
}
|
|
1422
1869
|
}
|
|
1423
1870
|
}
|
|
1424
1871
|
break;
|
|
@@ -1429,6 +1876,11 @@ const runPayoutsShell = async () => {
|
|
|
1429
1876
|
case 'validator_v2':
|
|
1430
1877
|
await listPayoutsCmd({ plan: cmd });
|
|
1431
1878
|
break;
|
|
1879
|
+
case 'christmas':
|
|
1880
|
+
case 'xmas':
|
|
1881
|
+
// Christmas payouts subshell
|
|
1882
|
+
await runChristmasPayoutsShell();
|
|
1883
|
+
break;
|
|
1432
1884
|
case 'process':
|
|
1433
1885
|
// Process specific plan with interactive selection
|
|
1434
1886
|
const { processPlan } = await inquirer.prompt([
|
|
@@ -1509,6 +1961,7 @@ const runPayoutsShell = async () => {
|
|
|
1509
1961
|
console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
|
|
1510
1962
|
console.log(' process Process payouts by plan (interactive)');
|
|
1511
1963
|
console.log(' hermes/alpha/etc List payouts for specific plan');
|
|
1964
|
+
console.log(chalk.red(' christmas, xmas 🎄 Christmas payouts (TarPay)'));
|
|
1512
1965
|
console.log(' back, q Return to main menu');
|
|
1513
1966
|
console.log('');
|
|
1514
1967
|
break;
|