@targlobal/mission-control 1.5.7 → 1.5.9
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 +1 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +7 -0
- package/dist/api.js.map +1 -1
- package/dist/index.js +157 -373
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +8 -0
- package/src/index.ts +175 -419
package/dist/index.js
CHANGED
|
@@ -503,7 +503,7 @@ const showDashboard = async () => {
|
|
|
503
503
|
console.log(chalk_1.default.cyan('┌─────────────────────────────┐'));
|
|
504
504
|
console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.bgCyan.black('TASKS')} ${chalk_1.default.bold.white(String(stats.my_tasks).padStart(3))} ${chalk_1.default.bgRed.white('CRIT')} ${chalk_1.default.bold.red(String(stats.critical_count).padStart(2))} ${chalk_1.default.bgYellow.black('OVR')} ${chalk_1.default.bold.yellow(String(stats.overdue_tasks).padStart(2))} ` + chalk_1.default.cyan('│'));
|
|
505
505
|
console.log(chalk_1.default.cyan('├─────────────────────────────┤'));
|
|
506
|
-
console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.cyan('[1]')}Tasks ${chalk_1.default.cyan('[2]')}New ${chalk_1.default.cyan('[3]')}Pay ${chalk_1.default.cyan('[4]')}Urg ${chalk_1.default.cyan('[5]')}
|
|
506
|
+
console.log(chalk_1.default.cyan('│') + ` ${chalk_1.default.cyan('[1]')}Tasks ${chalk_1.default.cyan('[2]')}New ${chalk_1.default.cyan('[3]')}Pay ${chalk_1.default.cyan('[4]')}Urg ${chalk_1.default.cyan('[5]')}Smart ` + chalk_1.default.cyan('│'));
|
|
507
507
|
console.log(chalk_1.default.cyan('└─────────────────────────────┘'));
|
|
508
508
|
console.log('');
|
|
509
509
|
// Show urgent count only in compact mode
|
|
@@ -525,7 +525,7 @@ const showDashboard = async () => {
|
|
|
525
525
|
console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
|
|
526
526
|
console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════════════╣'));
|
|
527
527
|
console.log(chalk_1.default.cyan('║') + chalk_1.default.dim(' Quick Actions: ') + chalk_1.default.cyan('║'));
|
|
528
|
-
console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.cyan('[1]')} My Tasks ${chalk_1.default.cyan('[2]')} New Task ${chalk_1.default.cyan('[3]')} Payouts ${chalk_1.default.cyan('[4]')} Urgent ${chalk_1.default.cyan('[5]')}
|
|
528
|
+
console.log(chalk_1.default.cyan('║') + ` ${chalk_1.default.cyan('[1]')} My Tasks ${chalk_1.default.cyan('[2]')} New Task ${chalk_1.default.cyan('[3]')} Payouts ${chalk_1.default.cyan('[4]')} Urgent ${chalk_1.default.cyan('[5]')} Smart ` + chalk_1.default.cyan('║'));
|
|
529
529
|
console.log(chalk_1.default.cyan('║') + ' ' + chalk_1.default.cyan('║'));
|
|
530
530
|
console.log(chalk_1.default.cyan('╚══════════════════════════════════════════════════════════════════════╝'));
|
|
531
531
|
console.log('');
|
|
@@ -545,115 +545,68 @@ const showDashboard = async () => {
|
|
|
545
545
|
// Silently fail - show basic prompt
|
|
546
546
|
}
|
|
547
547
|
};
|
|
548
|
-
const
|
|
549
|
-
setTitle('Smart
|
|
550
|
-
const spinner = (0, ora_1.default)('Loading
|
|
548
|
+
const runSuperSmartDirect = async () => {
|
|
549
|
+
setTitle('Super Smart');
|
|
550
|
+
const spinner = (0, ora_1.default)('Loading all pending payouts...').start();
|
|
551
551
|
try {
|
|
552
|
-
// Fetch
|
|
553
|
-
const [
|
|
554
|
-
api_1.api.getPayoutMetrics(),
|
|
552
|
+
// Fetch all pending payouts in parallel across all plans
|
|
553
|
+
const [payoutsRes, tarPayRes] = await Promise.all([
|
|
555
554
|
api_1.api.listPayouts({ status: 'pending', limit: 500 }),
|
|
556
555
|
api_1.api.getTarPayPayouts({ status: 'pending_review', limit: 500 }),
|
|
557
556
|
]);
|
|
558
|
-
const metrics = metricsRes.data;
|
|
559
557
|
const payouts = payoutsRes.data || [];
|
|
560
558
|
const tarPayPayouts = tarPayRes.results || [];
|
|
561
559
|
spinner.stop();
|
|
562
|
-
// Build
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
|
|
566
|
-
});
|
|
567
|
-
// Add TarPay payouts
|
|
568
|
-
tarPayPayouts.forEach((p) => {
|
|
569
|
-
byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
|
|
570
|
-
});
|
|
571
|
-
const totalCount = payouts.length + tarPayPayouts.length;
|
|
572
|
-
const planSummary = Object.entries(byPlan)
|
|
573
|
-
.map(([plan, count]) => `${(PLAN_ICONS[plan] || '📋')} ${plan.toUpperCase()} ${count}`)
|
|
574
|
-
.join(' ');
|
|
575
|
-
// Show overview
|
|
576
|
-
console.log('');
|
|
577
|
-
console.log(chalk_1.default.cyan('╔═══ SMART QUEUE ═══╗'));
|
|
578
|
-
console.log(chalk_1.default.cyan('║') + ` Pending: ${chalk_1.default.bold.yellow(String(totalCount))} payouts (${chalk_1.default.green('$' + metrics.pending_amount.toLocaleString())})`);
|
|
579
|
-
console.log(chalk_1.default.cyan('║') + ` ${planSummary}`);
|
|
580
|
-
console.log(chalk_1.default.cyan('╚═══════════════════╝'));
|
|
581
|
-
console.log('');
|
|
582
|
-
if (totalCount === 0) {
|
|
583
|
-
console.log(chalk_1.default.green(' ✓ No pending payouts\n'));
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
// Step 1: Select plan (with back option)
|
|
587
|
-
const planChoices = [
|
|
588
|
-
{ name: chalk_1.default.dim('← Back'), value: '__back__' },
|
|
589
|
-
...Object.entries(byPlan).map(([plan, count]) => ({
|
|
590
|
-
name: `${PLAN_ICONS[plan] || '📋'} ${plan.charAt(0).toUpperCase() + plan.slice(1)} (${count})`,
|
|
591
|
-
value: plan,
|
|
592
|
-
})),
|
|
593
|
-
{ name: '📋 All Plans', value: '__all__' },
|
|
594
|
-
];
|
|
595
|
-
const { selectedPlan } = await inquirer_1.default.prompt([
|
|
596
|
-
{
|
|
597
|
-
type: 'list',
|
|
598
|
-
name: 'selectedPlan',
|
|
599
|
-
message: 'Select plan:',
|
|
600
|
-
choices: planChoices,
|
|
601
|
-
},
|
|
602
|
-
]);
|
|
603
|
-
if (selectedPlan === '__back__')
|
|
604
|
-
return;
|
|
605
|
-
const isTarPayPlan = selectedPlan === 'christmas';
|
|
606
|
-
const planFilter = selectedPlan === '__all__' ? undefined : selectedPlan;
|
|
607
|
-
let smartItems = [];
|
|
608
|
-
if (isTarPayPlan) {
|
|
609
|
-
smartItems = tarPayPayouts
|
|
610
|
-
.filter((p) => !planFilter || p.plan === planFilter)
|
|
611
|
-
.map((p) => ({
|
|
560
|
+
// Build unified list from both sources
|
|
561
|
+
const allItems = [
|
|
562
|
+
...payouts.map((p) => ({
|
|
612
563
|
id: p.id,
|
|
613
564
|
user_email: p.user_email,
|
|
614
|
-
crypto: p.
|
|
615
|
-
amount:
|
|
616
|
-
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount :
|
|
565
|
+
crypto: p.crypto_type,
|
|
566
|
+
amount: p.amount,
|
|
567
|
+
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
|
|
617
568
|
has_partial_payments: p.has_partial_payments || false,
|
|
618
569
|
paid_percentage: p.paid_percentage || 0,
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
.filter((p) => !planFilter || p.plan === planFilter)
|
|
624
|
-
.map((p) => ({
|
|
570
|
+
plan: p.plan,
|
|
571
|
+
source: 'regular',
|
|
572
|
+
})),
|
|
573
|
+
...tarPayPayouts.map((p) => ({
|
|
625
574
|
id: p.id,
|
|
626
575
|
user_email: p.user_email,
|
|
627
|
-
crypto: p.
|
|
628
|
-
amount: p.amount,
|
|
629
|
-
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
|
|
576
|
+
crypto: p.currency,
|
|
577
|
+
amount: parseFloat(p.amount),
|
|
578
|
+
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
|
|
630
579
|
has_partial_payments: p.has_partial_payments || false,
|
|
631
580
|
paid_percentage: p.paid_percentage || 0,
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
// Group by currency
|
|
581
|
+
plan: p.plan,
|
|
582
|
+
source: 'tarpay',
|
|
583
|
+
})),
|
|
584
|
+
];
|
|
585
|
+
// Group by currency across ALL plans
|
|
639
586
|
const byCurrency = {};
|
|
640
|
-
|
|
587
|
+
allItems.forEach((p) => {
|
|
641
588
|
if (!byCurrency[p.crypto])
|
|
642
589
|
byCurrency[p.crypto] = [];
|
|
643
590
|
byCurrency[p.crypto].push(p);
|
|
644
591
|
});
|
|
645
|
-
const
|
|
646
|
-
const
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
});
|
|
592
|
+
const totalCount = allItems.length;
|
|
593
|
+
const totalAmount = allItems.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
594
|
+
const currencySummary = Object.entries(byCurrency)
|
|
595
|
+
.map(([crypto, items]) => `${chalk_1.default.bold(crypto)} ${items.length}`)
|
|
596
|
+
.join(' ');
|
|
597
|
+
// Show overview
|
|
598
|
+
console.log('');
|
|
599
|
+
console.log(chalk_1.default.cyan('╔═══ SUPER SMART ═══╗'));
|
|
600
|
+
console.log(chalk_1.default.cyan('║') + ` Pending: ${chalk_1.default.bold.yellow(String(totalCount))} payouts (${chalk_1.default.green('$' + Math.round(totalAmount).toLocaleString())})`);
|
|
601
|
+
console.log(chalk_1.default.cyan('║') + ` ${currencySummary}`);
|
|
602
|
+
console.log(chalk_1.default.cyan('╚════════════════════╝'));
|
|
655
603
|
console.log('');
|
|
656
|
-
|
|
604
|
+
if (totalCount === 0) {
|
|
605
|
+
console.log(chalk_1.default.green(' ✓ No pending payouts\n'));
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
// Step 1: Select currency (with back option)
|
|
609
|
+
const currencies = Object.keys(byCurrency);
|
|
657
610
|
let selectedCurrency;
|
|
658
611
|
if (currencies.length === 1) {
|
|
659
612
|
selectedCurrency = currencies[0];
|
|
@@ -671,7 +624,7 @@ const runSmartQueueDirect = async () => {
|
|
|
671
624
|
{
|
|
672
625
|
type: 'list',
|
|
673
626
|
name: 'currency',
|
|
674
|
-
message: '
|
|
627
|
+
message: 'Select currency:',
|
|
675
628
|
choices: currencyChoices,
|
|
676
629
|
},
|
|
677
630
|
]);
|
|
@@ -680,8 +633,23 @@ const runSmartQueueDirect = async () => {
|
|
|
680
633
|
selectedCurrency = currency;
|
|
681
634
|
}
|
|
682
635
|
const currencyItems = byCurrency[selectedCurrency];
|
|
636
|
+
// Show plan breakdown for selected currency
|
|
637
|
+
const byPlan = {};
|
|
638
|
+
currencyItems.forEach((p) => {
|
|
639
|
+
if (!byPlan[p.plan])
|
|
640
|
+
byPlan[p.plan] = [];
|
|
641
|
+
byPlan[p.plan].push(p);
|
|
642
|
+
});
|
|
643
|
+
console.log(`\n ${chalk_1.default.bold(selectedCurrency)} - ${currencyItems.length} payouts:`);
|
|
644
|
+
Object.entries(byPlan).forEach(([plan, items]) => {
|
|
645
|
+
const planTotal = items.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
646
|
+
const icon = PLAN_ICONS[plan] || '📋';
|
|
647
|
+
const color = PLAN_COLORS[plan] || chalk_1.default.white;
|
|
648
|
+
console.log(` ${icon} ${color(plan.toUpperCase().padEnd(12))} ${String(items.length).padStart(2)} │ ${chalk_1.default.green(formatAmount(planTotal, selectedCurrency))}`);
|
|
649
|
+
});
|
|
650
|
+
console.log('');
|
|
683
651
|
const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
684
|
-
// Step
|
|
652
|
+
// Step 2: Ask available amount (with back)
|
|
685
653
|
const { availableAmount } = await inquirer_1.default.prompt([
|
|
686
654
|
{
|
|
687
655
|
type: 'input',
|
|
@@ -700,36 +668,94 @@ const runSmartQueueDirect = async () => {
|
|
|
700
668
|
if (availableAmount.toLowerCase() === 'back' || availableAmount.toLowerCase() === 'q')
|
|
701
669
|
return;
|
|
702
670
|
const available = parseFloat(availableAmount);
|
|
703
|
-
const
|
|
704
|
-
|
|
671
|
+
const equalShare = available / currencyItems.length;
|
|
672
|
+
// Plan abbreviations for preview
|
|
673
|
+
const PLAN_ABBREV = {
|
|
674
|
+
hermes: 'HRM',
|
|
675
|
+
alpha: 'ALP',
|
|
676
|
+
mematic: 'MEM',
|
|
677
|
+
validator_v2: 'V2',
|
|
678
|
+
booster: 'BST',
|
|
679
|
+
dumpster: 'DMP',
|
|
680
|
+
christmas: 'XMS',
|
|
681
|
+
recovery: 'RCV',
|
|
682
|
+
};
|
|
683
|
+
// Smart equal distribution preview (mirrors backend logic)
|
|
684
|
+
// Capped users get only their remaining, surplus redistributed
|
|
685
|
+
let previewTotal = 0;
|
|
686
|
+
const allocations = [];
|
|
687
|
+
let pool = available;
|
|
688
|
+
let unallocated = [...currencyItems];
|
|
689
|
+
while (unallocated.length > 0 && pool > 0.001) {
|
|
690
|
+
const share = pool / unallocated.length;
|
|
691
|
+
const capped = [];
|
|
692
|
+
const uncapped = [];
|
|
693
|
+
for (const p of unallocated) {
|
|
694
|
+
const existing = allocations.find((a) => a.item.id === p.id);
|
|
695
|
+
const alreadyAllocated = existing ? existing.willPay : 0;
|
|
696
|
+
const remaining = p.remaining_amount - alreadyAllocated;
|
|
697
|
+
if (remaining <= share) {
|
|
698
|
+
capped.push(p);
|
|
699
|
+
const amt = remaining;
|
|
700
|
+
if (existing)
|
|
701
|
+
existing.willPay += amt;
|
|
702
|
+
else
|
|
703
|
+
allocations.push({ item: p, willPay: amt });
|
|
704
|
+
pool -= amt;
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
uncapped.push(p);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (capped.length === 0) {
|
|
711
|
+
// No one capped, give everyone the equal share
|
|
712
|
+
for (const p of uncapped) {
|
|
713
|
+
const existing = allocations.find((a) => a.item.id === p.id);
|
|
714
|
+
if (existing)
|
|
715
|
+
existing.willPay += share;
|
|
716
|
+
else
|
|
717
|
+
allocations.push({ item: p, willPay: share });
|
|
718
|
+
pool -= share;
|
|
719
|
+
}
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
unallocated = uncapped;
|
|
723
|
+
}
|
|
705
724
|
// Show preview
|
|
706
|
-
console.log('\n' + chalk_1.default.cyan(`
|
|
725
|
+
console.log('\n' + chalk_1.default.cyan(` Equal distribution: ${chalk_1.default.bold(formatAmount(available, selectedCurrency))} across ${currencyItems.length} ${selectedCurrency} payouts`));
|
|
707
726
|
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
|
|
727
|
+
for (const alloc of allocations) {
|
|
728
|
+
previewTotal += alloc.willPay;
|
|
729
|
+
const p = alloc.item;
|
|
730
|
+
const email = p.user_email.length > 20 ? p.user_email.substring(0, 18) + '..' : p.user_email;
|
|
731
|
+
const abbrev = PLAN_ABBREV[p.plan] || p.plan.substring(0, 3).toUpperCase();
|
|
732
|
+
const planColor = PLAN_COLORS[p.plan] || chalk_1.default.white;
|
|
733
|
+
const capped = alloc.willPay < equalShare - 0.01 ? chalk_1.default.dim(' (capped)') : '';
|
|
734
|
+
console.log(` ${chalk_1.default.dim('#' + p.id)} ${planColor('[' + abbrev + ']')} ${email.padEnd(20)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(14)} → pays ${chalk_1.default.green(formatAmount(alloc.willPay, selectedCurrency))}${capped}`);
|
|
735
|
+
}
|
|
715
736
|
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
716
737
|
console.log(chalk_1.default.bold(` Total to send: ${chalk_1.default.green(formatAmount(previewTotal, selectedCurrency))}\n`));
|
|
717
|
-
// Step
|
|
738
|
+
// Step 3: Confirm
|
|
718
739
|
const { confirmSmart } = await inquirer_1.default.prompt([
|
|
719
740
|
{
|
|
720
741
|
type: 'confirm',
|
|
721
742
|
name: 'confirmSmart',
|
|
722
|
-
message: chalk_1.default.yellow(`⚠️
|
|
743
|
+
message: chalk_1.default.yellow(`⚠️ Equal distribute ${formatAmount(available, selectedCurrency)} across ${currencyItems.length} payout(s)?`),
|
|
723
744
|
default: false,
|
|
724
745
|
},
|
|
725
746
|
]);
|
|
726
747
|
if (confirmSmart) {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
748
|
+
// Split by source for correct API calls
|
|
749
|
+
const regularIds = currencyItems.filter((p) => p.source === 'regular').map((p) => p.id);
|
|
750
|
+
const tarPayIds = currencyItems.filter((p) => p.source === 'tarpay').map((p) => p.id);
|
|
751
|
+
if (regularIds.length > 0) {
|
|
752
|
+
await processPayoutsWithProgress(regularIds, 'equal', available);
|
|
730
753
|
}
|
|
731
|
-
|
|
732
|
-
|
|
754
|
+
if (tarPayIds.length > 0) {
|
|
755
|
+
// TarPay still uses percentage-based for now (christmas payouts)
|
|
756
|
+
const smartPercentage = Math.min((available / totalPending) * 100, 100);
|
|
757
|
+
const roundedPct = Math.round(smartPercentage * 100) / 100;
|
|
758
|
+
await processChristmasPayoutsWithProgress(tarPayIds, 'partial', roundedPct);
|
|
733
759
|
}
|
|
734
760
|
}
|
|
735
761
|
else {
|
|
@@ -785,8 +811,8 @@ const runInteractiveShell = async () => {
|
|
|
785
811
|
setTitle('Urgent');
|
|
786
812
|
await showUrgentCmd();
|
|
787
813
|
}
|
|
788
|
-
else if (cmd === '5' || cmd === 'queue' || cmd === 'sq') {
|
|
789
|
-
await
|
|
814
|
+
else if (cmd === '5' || cmd === 'queue' || cmd === 'sq' || cmd === 'super' || cmd === 'ss') {
|
|
815
|
+
await runSuperSmartDirect();
|
|
790
816
|
await showDashboard();
|
|
791
817
|
}
|
|
792
818
|
else {
|
|
@@ -1350,8 +1376,8 @@ const selectPayoutsInteractive = async (plan) => {
|
|
|
1350
1376
|
return [];
|
|
1351
1377
|
}
|
|
1352
1378
|
};
|
|
1353
|
-
const processPayoutsWithProgress = async (ids, action,
|
|
1354
|
-
const actionLabel = action === 'partial' ? `PARTIAL ${
|
|
1379
|
+
const processPayoutsWithProgress = async (ids, action, percentageOrAmount) => {
|
|
1380
|
+
const actionLabel = action === 'partial' ? `PARTIAL ${percentageOrAmount}%` : action === 'equal' ? `EQUAL DIST $${percentageOrAmount}` : action.toUpperCase();
|
|
1355
1381
|
console.log('\n' + chalk_1.default.cyan('╔══════════════════════════════════════════════════════════════╗'));
|
|
1356
1382
|
console.log(chalk_1.default.cyan('║') + chalk_1.default.bold.white(` 🔄 ${actionLabel} - ${ids.length} PAYOUT(S)... `.substring(0, 60)) + chalk_1.default.cyan('║'));
|
|
1357
1383
|
console.log(chalk_1.default.cyan('╠══════════════════════════════════════════════════════════════╣'));
|
|
@@ -1375,7 +1401,10 @@ const processPayoutsWithProgress = async (ids, action, percentage) => {
|
|
|
1375
1401
|
result = await api_1.api.batchApprovePayouts(ids);
|
|
1376
1402
|
}
|
|
1377
1403
|
else if (action === 'partial') {
|
|
1378
|
-
result = await api_1.api.batchPartialPayouts(ids,
|
|
1404
|
+
result = await api_1.api.batchPartialPayouts(ids, percentageOrAmount);
|
|
1405
|
+
}
|
|
1406
|
+
else if (action === 'equal') {
|
|
1407
|
+
result = await api_1.api.batchEqualPartialPayouts(ids, percentageOrAmount);
|
|
1379
1408
|
}
|
|
1380
1409
|
else {
|
|
1381
1410
|
result = await api_1.api.batchCancelPayouts(ids);
|
|
@@ -1393,7 +1422,11 @@ const processPayoutsWithProgress = async (ids, action, percentage) => {
|
|
|
1393
1422
|
}
|
|
1394
1423
|
else if (action === 'partial') {
|
|
1395
1424
|
icon = '%';
|
|
1396
|
-
verb = `PARTIAL ${
|
|
1425
|
+
verb = `PARTIAL ${percentageOrAmount}% SENT`;
|
|
1426
|
+
}
|
|
1427
|
+
else if (action === 'equal') {
|
|
1428
|
+
icon = '⚖';
|
|
1429
|
+
verb = 'EQUAL DISTRIBUTION SENT';
|
|
1397
1430
|
}
|
|
1398
1431
|
else {
|
|
1399
1432
|
icon = '↩';
|
|
@@ -1807,107 +1840,11 @@ const runChristmasPayoutsShell = async () => {
|
|
|
1807
1840
|
}
|
|
1808
1841
|
break;
|
|
1809
1842
|
case 'smart':
|
|
1810
|
-
case 'sp':
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
const xmasData = await api_1.api.getTarPayPayouts({
|
|
1815
|
-
plan: 'christmas',
|
|
1816
|
-
status: 'pending_review',
|
|
1817
|
-
limit: 500,
|
|
1818
|
-
});
|
|
1819
|
-
const xmasPayouts = xmasData.results || [];
|
|
1820
|
-
xmasSmartSpinner.stop();
|
|
1821
|
-
if (xmasPayouts.length === 0) {
|
|
1822
|
-
console.log(chalk_1.default.green('\n ✓ No pending Christmas payouts\n'));
|
|
1823
|
-
break;
|
|
1824
|
-
}
|
|
1825
|
-
// Group by currency
|
|
1826
|
-
const xmasByCurrency = {};
|
|
1827
|
-
xmasPayouts.forEach((p) => {
|
|
1828
|
-
if (!xmasByCurrency[p.currency])
|
|
1829
|
-
xmasByCurrency[p.currency] = [];
|
|
1830
|
-
xmasByCurrency[p.currency].push(p);
|
|
1831
|
-
});
|
|
1832
|
-
const xmasCurrencies = Object.keys(xmasByCurrency);
|
|
1833
|
-
console.log('\n' + chalk_1.default.red(` 🎄 CHRISTMAS - Pending Payouts`));
|
|
1834
|
-
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
1835
|
-
xmasCurrencies.forEach((crypto) => {
|
|
1836
|
-
const items = xmasByCurrency[crypto];
|
|
1837
|
-
const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
|
|
1838
|
-
console.log(` ${chalk_1.default.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk_1.default.green(formatAmount(total, crypto))}`);
|
|
1839
|
-
});
|
|
1840
|
-
console.log('');
|
|
1841
|
-
let xmasCurrency;
|
|
1842
|
-
if (xmasCurrencies.length === 1) {
|
|
1843
|
-
xmasCurrency = xmasCurrencies[0];
|
|
1844
|
-
}
|
|
1845
|
-
else {
|
|
1846
|
-
const { currency } = await inquirer_1.default.prompt([
|
|
1847
|
-
{
|
|
1848
|
-
type: 'list',
|
|
1849
|
-
name: 'currency',
|
|
1850
|
-
message: 'Which currency to process?',
|
|
1851
|
-
choices: xmasCurrencies.map((c) => {
|
|
1852
|
-
const items = xmasByCurrency[c];
|
|
1853
|
-
const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
|
|
1854
|
-
return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
|
|
1855
|
-
}),
|
|
1856
|
-
},
|
|
1857
|
-
]);
|
|
1858
|
-
xmasCurrency = currency;
|
|
1859
|
-
}
|
|
1860
|
-
const xmasCurrencyPayouts = xmasByCurrency[xmasCurrency];
|
|
1861
|
-
const xmasTotalPending = xmasCurrencyPayouts.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
|
|
1862
|
-
const { xmasAvailable } = await inquirer_1.default.prompt([
|
|
1863
|
-
{
|
|
1864
|
-
type: 'input',
|
|
1865
|
-
name: 'xmasAvailable',
|
|
1866
|
-
message: `How much ${xmasCurrency} do you have available? (total pending: ${formatAmount(xmasTotalPending, xmasCurrency)})`,
|
|
1867
|
-
validate: (input) => {
|
|
1868
|
-
const num = parseFloat(input);
|
|
1869
|
-
if (isNaN(num) || num <= 0)
|
|
1870
|
-
return 'Please enter a positive number';
|
|
1871
|
-
return true;
|
|
1872
|
-
},
|
|
1873
|
-
},
|
|
1874
|
-
]);
|
|
1875
|
-
const xmasAvailNum = parseFloat(xmasAvailable);
|
|
1876
|
-
const xmasPct = Math.min((xmasAvailNum / xmasTotalPending) * 100, 100);
|
|
1877
|
-
const xmasRoundedPct = Math.round(xmasPct * 100) / 100;
|
|
1878
|
-
console.log('\n' + chalk_1.default.cyan(` Processing ${chalk_1.default.bold(xmasRoundedPct + '%')} of ${xmasCurrencyPayouts.length} ${xmasCurrency} payouts (${formatAmount(xmasAvailNum, xmasCurrency)} / ${formatAmount(xmasTotalPending, xmasCurrency)})`));
|
|
1879
|
-
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
1880
|
-
let xmasPreviewTotal = 0;
|
|
1881
|
-
xmasCurrencyPayouts.forEach((p) => {
|
|
1882
|
-
const displayAmt = p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount);
|
|
1883
|
-
const willPay = displayAmt * (xmasPct / 100);
|
|
1884
|
-
xmasPreviewTotal += willPay;
|
|
1885
|
-
const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
|
|
1886
|
-
console.log(` ${chalk_1.default.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(displayAmt, xmasCurrency).padStart(16)} → pays ${chalk_1.default.green(formatAmount(willPay, xmasCurrency))}`);
|
|
1887
|
-
});
|
|
1888
|
-
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
1889
|
-
console.log(chalk_1.default.bold(` Total to send: ${chalk_1.default.green(formatAmount(xmasPreviewTotal, xmasCurrency))}\n`));
|
|
1890
|
-
const { confirmXmasSmart } = await inquirer_1.default.prompt([
|
|
1891
|
-
{
|
|
1892
|
-
type: 'confirm',
|
|
1893
|
-
name: 'confirmXmasSmart',
|
|
1894
|
-
message: chalk_1.default.yellow(`⚠️ Pay ${xmasRoundedPct}% of ${xmasCurrencyPayouts.length} payout(s)?`),
|
|
1895
|
-
default: false,
|
|
1896
|
-
},
|
|
1897
|
-
]);
|
|
1898
|
-
if (confirmXmasSmart) {
|
|
1899
|
-
const xmasSmartIds = xmasCurrencyPayouts.map((p) => p.id);
|
|
1900
|
-
await processChristmasPayoutsWithProgress(xmasSmartIds, 'partial', xmasRoundedPct);
|
|
1901
|
-
}
|
|
1902
|
-
else {
|
|
1903
|
-
console.log(chalk_1.default.dim('\n Cancelled\n'));
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
catch (e) {
|
|
1907
|
-
xmasSmartSpinner.fail(chalk_1.default.red('Failed to load Christmas payouts'));
|
|
1908
|
-
}
|
|
1843
|
+
case 'sp':
|
|
1844
|
+
case 'super':
|
|
1845
|
+
case 'ss':
|
|
1846
|
+
await runSuperSmartDirect();
|
|
1909
1847
|
break;
|
|
1910
|
-
}
|
|
1911
1848
|
case 'help':
|
|
1912
1849
|
case '?':
|
|
1913
1850
|
console.log(chalk_1.default.red('\n 🎄 Christmas Payout Commands:'));
|
|
@@ -1920,7 +1857,7 @@ const runChristmasPayoutsShell = async () => {
|
|
|
1920
1857
|
console.log(' select, s Interactive selection mode');
|
|
1921
1858
|
console.log(' approve, a Select & approve payouts');
|
|
1922
1859
|
console.log(chalk_1.default.cyan(' partial, p Select & pay partial %'));
|
|
1923
|
-
console.log(chalk_1.default.cyan(' smart, sp
|
|
1860
|
+
console.log(chalk_1.default.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
|
|
1924
1861
|
console.log(' reject Select & reject payouts');
|
|
1925
1862
|
console.log(' back, q Return to main payouts');
|
|
1926
1863
|
console.log(chalk_1.default.dim('\n Note: Payouts > $50 need approval, < $50 auto-sent'));
|
|
@@ -2106,162 +2043,9 @@ const runPayoutsShell = async () => {
|
|
|
2106
2043
|
break;
|
|
2107
2044
|
case 'smart':
|
|
2108
2045
|
case 'sp':
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
type: 'list',
|
|
2113
|
-
name: 'smartPlan',
|
|
2114
|
-
message: 'Select plan:',
|
|
2115
|
-
choices: [
|
|
2116
|
-
{ name: `${PLAN_ICONS.hermes || '⚡'} Hermes`, value: 'hermes' },
|
|
2117
|
-
{ name: `${PLAN_ICONS.alpha || '🔷'} Alpha`, value: 'alpha' },
|
|
2118
|
-
{ name: `${PLAN_ICONS.mematic || '💎'} Mematic`, value: 'mematic' },
|
|
2119
|
-
{ name: `${PLAN_ICONS.validator_v2 || '🔐'} Validator V2`, value: 'validator_v2' },
|
|
2120
|
-
{ name: `${PLAN_ICONS.booster || '🚀'} Booster`, value: 'booster' },
|
|
2121
|
-
{ name: `${PLAN_ICONS.christmas || '🎄'} Christmas`, value: 'christmas' },
|
|
2122
|
-
{ name: '🔄 Recovery', value: 'recovery' },
|
|
2123
|
-
{ name: '📋 All Plans', value: undefined },
|
|
2124
|
-
],
|
|
2125
|
-
},
|
|
2126
|
-
]);
|
|
2127
|
-
const isTarPayPlan = smartPlan === 'christmas';
|
|
2128
|
-
const smartSpinner = (0, ora_1.default)('Loading pending payouts...').start();
|
|
2129
|
-
try {
|
|
2130
|
-
let smartItems = [];
|
|
2131
|
-
if (isTarPayPlan) {
|
|
2132
|
-
// TarPay payouts (Christmas, etc.)
|
|
2133
|
-
const tarData = await api_1.api.getTarPayPayouts({
|
|
2134
|
-
plan: smartPlan,
|
|
2135
|
-
status: 'pending_review',
|
|
2136
|
-
limit: 500,
|
|
2137
|
-
});
|
|
2138
|
-
const tarPayouts = tarData.results || [];
|
|
2139
|
-
smartItems = tarPayouts.map((p) => ({
|
|
2140
|
-
id: p.id,
|
|
2141
|
-
user_email: p.user_email,
|
|
2142
|
-
crypto: p.currency,
|
|
2143
|
-
amount: parseFloat(p.amount),
|
|
2144
|
-
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
|
|
2145
|
-
has_partial_payments: p.has_partial_payments || false,
|
|
2146
|
-
paid_percentage: p.paid_percentage || 0,
|
|
2147
|
-
}));
|
|
2148
|
-
}
|
|
2149
|
-
else {
|
|
2150
|
-
// Regular payouts
|
|
2151
|
-
const smartParams = { status: 'pending', limit: 500 };
|
|
2152
|
-
if (smartPlan)
|
|
2153
|
-
smartParams.plan = smartPlan;
|
|
2154
|
-
const smartData = await api_1.api.listPayouts(smartParams);
|
|
2155
|
-
const smartPayouts = smartData.data || [];
|
|
2156
|
-
smartItems = smartPayouts.map((p) => ({
|
|
2157
|
-
id: p.id,
|
|
2158
|
-
user_email: p.user_email,
|
|
2159
|
-
crypto: p.crypto_type,
|
|
2160
|
-
amount: p.amount,
|
|
2161
|
-
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
|
|
2162
|
-
has_partial_payments: p.has_partial_payments || false,
|
|
2163
|
-
paid_percentage: p.paid_percentage || 0,
|
|
2164
|
-
}));
|
|
2165
|
-
}
|
|
2166
|
-
smartSpinner.stop();
|
|
2167
|
-
if (smartItems.length === 0) {
|
|
2168
|
-
console.log(chalk_1.default.green('\n ✓ No pending payouts found\n'));
|
|
2169
|
-
break;
|
|
2170
|
-
}
|
|
2171
|
-
// Group by crypto
|
|
2172
|
-
const byCurrency = {};
|
|
2173
|
-
smartItems.forEach((p) => {
|
|
2174
|
-
if (!byCurrency[p.crypto])
|
|
2175
|
-
byCurrency[p.crypto] = [];
|
|
2176
|
-
byCurrency[p.crypto].push(p);
|
|
2177
|
-
});
|
|
2178
|
-
const currencies = Object.keys(byCurrency);
|
|
2179
|
-
const planLabel = smartPlan ? smartPlan.toUpperCase() : 'ALL PLANS';
|
|
2180
|
-
const planColor = smartPlan ? (PLAN_COLORS[smartPlan] || chalk_1.default.white) : chalk_1.default.white;
|
|
2181
|
-
console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
|
|
2182
|
-
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
2183
|
-
currencies.forEach((crypto) => {
|
|
2184
|
-
const items = byCurrency[crypto];
|
|
2185
|
-
const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
2186
|
-
console.log(` ${chalk_1.default.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk_1.default.green(formatAmount(total, crypto))}`);
|
|
2187
|
-
});
|
|
2188
|
-
console.log('');
|
|
2189
|
-
// Select currency
|
|
2190
|
-
let selectedCurrency;
|
|
2191
|
-
if (currencies.length === 1) {
|
|
2192
|
-
selectedCurrency = currencies[0];
|
|
2193
|
-
}
|
|
2194
|
-
else {
|
|
2195
|
-
const { currency } = await inquirer_1.default.prompt([
|
|
2196
|
-
{
|
|
2197
|
-
type: 'list',
|
|
2198
|
-
name: 'currency',
|
|
2199
|
-
message: 'Which currency to process?',
|
|
2200
|
-
choices: currencies.map((c) => {
|
|
2201
|
-
const items = byCurrency[c];
|
|
2202
|
-
const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
2203
|
-
return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
|
|
2204
|
-
}),
|
|
2205
|
-
},
|
|
2206
|
-
]);
|
|
2207
|
-
selectedCurrency = currency;
|
|
2208
|
-
}
|
|
2209
|
-
const currencyItems = byCurrency[selectedCurrency];
|
|
2210
|
-
const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
2211
|
-
// Ask available amount
|
|
2212
|
-
const { availableAmount } = await inquirer_1.default.prompt([
|
|
2213
|
-
{
|
|
2214
|
-
type: 'input',
|
|
2215
|
-
name: 'availableAmount',
|
|
2216
|
-
message: `How much ${selectedCurrency} do you have available? (total pending: ${formatAmount(totalPending, selectedCurrency)})`,
|
|
2217
|
-
validate: (input) => {
|
|
2218
|
-
const num = parseFloat(input);
|
|
2219
|
-
if (isNaN(num) || num <= 0)
|
|
2220
|
-
return 'Please enter a positive number';
|
|
2221
|
-
return true;
|
|
2222
|
-
},
|
|
2223
|
-
},
|
|
2224
|
-
]);
|
|
2225
|
-
const available = parseFloat(availableAmount);
|
|
2226
|
-
const smartPercentage = Math.min((available / totalPending) * 100, 100);
|
|
2227
|
-
const roundedPct = Math.round(smartPercentage * 100) / 100;
|
|
2228
|
-
// Show breakdown
|
|
2229
|
-
console.log('\n' + chalk_1.default.cyan(` Processing ${chalk_1.default.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
|
|
2230
|
-
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
2231
|
-
let previewTotal = 0;
|
|
2232
|
-
currencyItems.forEach((p) => {
|
|
2233
|
-
const willPay = p.remaining_amount * (smartPercentage / 100);
|
|
2234
|
-
previewTotal += willPay;
|
|
2235
|
-
const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
|
|
2236
|
-
console.log(` ${chalk_1.default.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk_1.default.green(formatAmount(willPay, selectedCurrency))}`);
|
|
2237
|
-
});
|
|
2238
|
-
console.log(chalk_1.default.dim(' ─────────────────────────────'));
|
|
2239
|
-
console.log(chalk_1.default.bold(` Total to send: ${chalk_1.default.green(formatAmount(previewTotal, selectedCurrency))}\n`));
|
|
2240
|
-
// Confirm
|
|
2241
|
-
const { confirmSmart } = await inquirer_1.default.prompt([
|
|
2242
|
-
{
|
|
2243
|
-
type: 'confirm',
|
|
2244
|
-
name: 'confirmSmart',
|
|
2245
|
-
message: chalk_1.default.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
|
|
2246
|
-
default: false,
|
|
2247
|
-
},
|
|
2248
|
-
]);
|
|
2249
|
-
if (confirmSmart) {
|
|
2250
|
-
const smartIds = currencyItems.map((p) => p.id);
|
|
2251
|
-
if (isTarPayPlan) {
|
|
2252
|
-
await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
|
|
2253
|
-
}
|
|
2254
|
-
else {
|
|
2255
|
-
await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
else {
|
|
2259
|
-
console.log(chalk_1.default.dim('\n Cancelled\n'));
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2262
|
-
catch (e) {
|
|
2263
|
-
smartSpinner.fail(chalk_1.default.red('Failed to load payouts'));
|
|
2264
|
-
}
|
|
2046
|
+
case 'super':
|
|
2047
|
+
case 'ss':
|
|
2048
|
+
await runSuperSmartDirect();
|
|
2265
2049
|
break;
|
|
2266
2050
|
case 'hermes':
|
|
2267
2051
|
case 'alpha':
|
|
@@ -2349,7 +2133,7 @@ const runPayoutsShell = async () => {
|
|
|
2349
2133
|
console.log(' select [plan] Interactive payout selection');
|
|
2350
2134
|
console.log(' approve [ids] Approve payouts (interactive if no IDs)');
|
|
2351
2135
|
console.log(chalk_1.default.cyan(' partial, p Pay partial % (repayment mode)'));
|
|
2352
|
-
console.log(chalk_1.default.cyan(' smart, sp
|
|
2136
|
+
console.log(chalk_1.default.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
|
|
2353
2137
|
console.log(chalk_1.default.yellow(' all Approve ALL pending payouts'));
|
|
2354
2138
|
console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
|
|
2355
2139
|
console.log(' process Process payouts by plan (interactive)');
|