@targlobal/mission-control 1.5.7 → 1.5.8
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/index.js +95 -361
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +117 -407
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -506,7 +506,7 @@ const showDashboard = async () => {
|
|
|
506
506
|
console.log(chalk.cyan('┌─────────────────────────────┐'));
|
|
507
507
|
console.log(chalk.cyan('│') + ` ${chalk.bgCyan.black('TASKS')} ${chalk.bold.white(String(stats.my_tasks).padStart(3))} ${chalk.bgRed.white('CRIT')} ${chalk.bold.red(String(stats.critical_count).padStart(2))} ${chalk.bgYellow.black('OVR')} ${chalk.bold.yellow(String(stats.overdue_tasks).padStart(2))} ` + chalk.cyan('│'));
|
|
508
508
|
console.log(chalk.cyan('├─────────────────────────────┤'));
|
|
509
|
-
console.log(chalk.cyan('│') + ` ${chalk.cyan('[1]')}Tasks ${chalk.cyan('[2]')}New ${chalk.cyan('[3]')}Pay ${chalk.cyan('[4]')}Urg ${chalk.cyan('[5]')}
|
|
509
|
+
console.log(chalk.cyan('│') + ` ${chalk.cyan('[1]')}Tasks ${chalk.cyan('[2]')}New ${chalk.cyan('[3]')}Pay ${chalk.cyan('[4]')}Urg ${chalk.cyan('[5]')}Smart ` + chalk.cyan('│'));
|
|
510
510
|
console.log(chalk.cyan('└─────────────────────────────┘'));
|
|
511
511
|
console.log('');
|
|
512
512
|
|
|
@@ -528,7 +528,7 @@ const showDashboard = async () => {
|
|
|
528
528
|
console.log(chalk.cyan('║') + ' ' + chalk.cyan('║'));
|
|
529
529
|
console.log(chalk.cyan('╠══════════════════════════════════════════════════════════════════════╣'));
|
|
530
530
|
console.log(chalk.cyan('║') + chalk.dim(' Quick Actions: ') + chalk.cyan('║'));
|
|
531
|
-
console.log(chalk.cyan('║') + ` ${chalk.cyan('[1]')} My Tasks ${chalk.cyan('[2]')} New Task ${chalk.cyan('[3]')} Payouts ${chalk.cyan('[4]')} Urgent ${chalk.cyan('[5]')}
|
|
531
|
+
console.log(chalk.cyan('║') + ` ${chalk.cyan('[1]')} My Tasks ${chalk.cyan('[2]')} New Task ${chalk.cyan('[3]')} Payouts ${chalk.cyan('[4]')} Urgent ${chalk.cyan('[5]')} Smart ` + chalk.cyan('║'));
|
|
532
532
|
console.log(chalk.cyan('║') + ' ' + chalk.cyan('║'));
|
|
533
533
|
console.log(chalk.cyan('╚══════════════════════════════════════════════════════════════════════╝'));
|
|
534
534
|
console.log('');
|
|
@@ -549,78 +549,24 @@ const showDashboard = async () => {
|
|
|
549
549
|
}
|
|
550
550
|
};
|
|
551
551
|
|
|
552
|
-
const
|
|
553
|
-
setTitle('Smart
|
|
554
|
-
const spinner = ora('Loading
|
|
552
|
+
const runSuperSmartDirect = async () => {
|
|
553
|
+
setTitle('Super Smart');
|
|
554
|
+
const spinner = ora('Loading all pending payouts...').start();
|
|
555
555
|
|
|
556
556
|
try {
|
|
557
|
-
// Fetch
|
|
558
|
-
const [
|
|
559
|
-
api.getPayoutMetrics(),
|
|
557
|
+
// Fetch all pending payouts in parallel across all plans
|
|
558
|
+
const [payoutsRes, tarPayRes] = await Promise.all([
|
|
560
559
|
api.listPayouts({ status: 'pending', limit: 500 }),
|
|
561
560
|
api.getTarPayPayouts({ status: 'pending_review', limit: 500 }),
|
|
562
561
|
]);
|
|
563
562
|
|
|
564
|
-
const metrics: PayoutMetrics = metricsRes.data;
|
|
565
563
|
const payouts: Payout[] = payoutsRes.data || [];
|
|
566
564
|
const tarPayPayouts: TarPayPayout[] = tarPayRes.results || [];
|
|
567
565
|
|
|
568
566
|
spinner.stop();
|
|
569
567
|
|
|
570
|
-
//
|
|
571
|
-
|
|
572
|
-
payouts.forEach((p) => {
|
|
573
|
-
byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
|
|
574
|
-
});
|
|
575
|
-
// Add TarPay payouts
|
|
576
|
-
tarPayPayouts.forEach((p) => {
|
|
577
|
-
byPlan[p.plan] = (byPlan[p.plan] || 0) + 1;
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
const totalCount = payouts.length + tarPayPayouts.length;
|
|
581
|
-
const planSummary = Object.entries(byPlan)
|
|
582
|
-
.map(([plan, count]) => `${(PLAN_ICONS[plan] || '📋')} ${plan.toUpperCase()} ${count}`)
|
|
583
|
-
.join(' ');
|
|
584
|
-
|
|
585
|
-
// Show overview
|
|
586
|
-
console.log('');
|
|
587
|
-
console.log(chalk.cyan('╔═══ SMART QUEUE ═══╗'));
|
|
588
|
-
console.log(chalk.cyan('║') + ` Pending: ${chalk.bold.yellow(String(totalCount))} payouts (${chalk.green('$' + metrics.pending_amount.toLocaleString())})` );
|
|
589
|
-
console.log(chalk.cyan('║') + ` ${planSummary}`);
|
|
590
|
-
console.log(chalk.cyan('╚═══════════════════╝'));
|
|
591
|
-
console.log('');
|
|
592
|
-
|
|
593
|
-
if (totalCount === 0) {
|
|
594
|
-
console.log(chalk.green(' ✓ No pending payouts\n'));
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// Step 1: Select plan (with back option)
|
|
599
|
-
const planChoices = [
|
|
600
|
-
{ name: chalk.dim('← Back'), value: '__back__' },
|
|
601
|
-
...Object.entries(byPlan).map(([plan, count]) => ({
|
|
602
|
-
name: `${PLAN_ICONS[plan] || '📋'} ${plan.charAt(0).toUpperCase() + plan.slice(1)} (${count})`,
|
|
603
|
-
value: plan,
|
|
604
|
-
})),
|
|
605
|
-
{ name: '📋 All Plans', value: '__all__' },
|
|
606
|
-
];
|
|
607
|
-
|
|
608
|
-
const { selectedPlan } = await inquirer.prompt([
|
|
609
|
-
{
|
|
610
|
-
type: 'list',
|
|
611
|
-
name: 'selectedPlan',
|
|
612
|
-
message: 'Select plan:',
|
|
613
|
-
choices: planChoices,
|
|
614
|
-
},
|
|
615
|
-
]);
|
|
616
|
-
|
|
617
|
-
if (selectedPlan === '__back__') return;
|
|
618
|
-
|
|
619
|
-
const isTarPayPlan = selectedPlan === 'christmas';
|
|
620
|
-
const planFilter = selectedPlan === '__all__' ? undefined : selectedPlan;
|
|
621
|
-
|
|
622
|
-
// Unified payout items
|
|
623
|
-
interface SmartPayoutItem {
|
|
568
|
+
// Unified payout item with plan + source tracking
|
|
569
|
+
interface SuperSmartItem {
|
|
624
570
|
id: number;
|
|
625
571
|
user_email: string;
|
|
626
572
|
crypto: string;
|
|
@@ -628,63 +574,66 @@ const runSmartQueueDirect = async () => {
|
|
|
628
574
|
remaining_amount: number;
|
|
629
575
|
has_partial_payments: boolean;
|
|
630
576
|
paid_percentage: number;
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
.
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
.
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
if (smartItems.length === 0) {
|
|
662
|
-
console.log(chalk.green('\n ✓ No pending payouts for this plan\n'));
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
577
|
+
plan: string;
|
|
578
|
+
source: 'regular' | 'tarpay';
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Build unified list from both sources
|
|
582
|
+
const allItems: SuperSmartItem[] = [
|
|
583
|
+
...payouts.map((p) => ({
|
|
584
|
+
id: p.id,
|
|
585
|
+
user_email: p.user_email,
|
|
586
|
+
crypto: p.crypto_type,
|
|
587
|
+
amount: p.amount,
|
|
588
|
+
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
|
|
589
|
+
has_partial_payments: p.has_partial_payments || false,
|
|
590
|
+
paid_percentage: p.paid_percentage || 0,
|
|
591
|
+
plan: p.plan,
|
|
592
|
+
source: 'regular' as const,
|
|
593
|
+
})),
|
|
594
|
+
...tarPayPayouts.map((p) => ({
|
|
595
|
+
id: p.id,
|
|
596
|
+
user_email: p.user_email,
|
|
597
|
+
crypto: p.currency,
|
|
598
|
+
amount: parseFloat(p.amount),
|
|
599
|
+
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
|
|
600
|
+
has_partial_payments: p.has_partial_payments || false,
|
|
601
|
+
paid_percentage: p.paid_percentage || 0,
|
|
602
|
+
plan: p.plan,
|
|
603
|
+
source: 'tarpay' as const,
|
|
604
|
+
})),
|
|
605
|
+
];
|
|
665
606
|
|
|
666
|
-
// Group by currency
|
|
667
|
-
const byCurrency: Record<string,
|
|
668
|
-
|
|
607
|
+
// Group by currency across ALL plans
|
|
608
|
+
const byCurrency: Record<string, SuperSmartItem[]> = {};
|
|
609
|
+
allItems.forEach((p) => {
|
|
669
610
|
if (!byCurrency[p.crypto]) byCurrency[p.crypto] = [];
|
|
670
611
|
byCurrency[p.crypto].push(p);
|
|
671
612
|
});
|
|
672
613
|
|
|
673
|
-
const
|
|
674
|
-
const
|
|
675
|
-
const
|
|
614
|
+
const totalCount = allItems.length;
|
|
615
|
+
const totalAmount = allItems.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
616
|
+
const currencySummary = Object.entries(byCurrency)
|
|
617
|
+
.map(([crypto, items]) => `${chalk.bold(crypto)} ${items.length}`)
|
|
618
|
+
.join(' ');
|
|
676
619
|
|
|
677
|
-
|
|
678
|
-
console.log(
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
});
|
|
620
|
+
// Show overview
|
|
621
|
+
console.log('');
|
|
622
|
+
console.log(chalk.cyan('╔═══ SUPER SMART ═══╗'));
|
|
623
|
+
console.log(chalk.cyan('║') + ` Pending: ${chalk.bold.yellow(String(totalCount))} payouts (${chalk.green('$' + Math.round(totalAmount).toLocaleString())})`);
|
|
624
|
+
console.log(chalk.cyan('║') + ` ${currencySummary}`);
|
|
625
|
+
console.log(chalk.cyan('╚════════════════════╝'));
|
|
684
626
|
console.log('');
|
|
685
627
|
|
|
686
|
-
|
|
628
|
+
if (totalCount === 0) {
|
|
629
|
+
console.log(chalk.green(' ✓ No pending payouts\n'));
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Step 1: Select currency (with back option)
|
|
634
|
+
const currencies = Object.keys(byCurrency);
|
|
687
635
|
let selectedCurrency: string;
|
|
636
|
+
|
|
688
637
|
if (currencies.length === 1) {
|
|
689
638
|
selectedCurrency = currencies[0];
|
|
690
639
|
} else {
|
|
@@ -701,7 +650,7 @@ const runSmartQueueDirect = async () => {
|
|
|
701
650
|
{
|
|
702
651
|
type: 'list',
|
|
703
652
|
name: 'currency',
|
|
704
|
-
message: '
|
|
653
|
+
message: 'Select currency:',
|
|
705
654
|
choices: currencyChoices,
|
|
706
655
|
},
|
|
707
656
|
]);
|
|
@@ -711,9 +660,26 @@ const runSmartQueueDirect = async () => {
|
|
|
711
660
|
}
|
|
712
661
|
|
|
713
662
|
const currencyItems = byCurrency[selectedCurrency];
|
|
663
|
+
|
|
664
|
+
// Show plan breakdown for selected currency
|
|
665
|
+
const byPlan: Record<string, SuperSmartItem[]> = {};
|
|
666
|
+
currencyItems.forEach((p) => {
|
|
667
|
+
if (!byPlan[p.plan]) byPlan[p.plan] = [];
|
|
668
|
+
byPlan[p.plan].push(p);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
console.log(`\n ${chalk.bold(selectedCurrency)} - ${currencyItems.length} payouts:`);
|
|
672
|
+
Object.entries(byPlan).forEach(([plan, items]) => {
|
|
673
|
+
const planTotal = items.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
674
|
+
const icon = PLAN_ICONS[plan] || '📋';
|
|
675
|
+
const color = PLAN_COLORS[plan] || chalk.white;
|
|
676
|
+
console.log(` ${icon} ${color(plan.toUpperCase().padEnd(12))} ${String(items.length).padStart(2)} │ ${chalk.green(formatAmount(planTotal, selectedCurrency))}`);
|
|
677
|
+
});
|
|
678
|
+
console.log('');
|
|
679
|
+
|
|
714
680
|
const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
715
681
|
|
|
716
|
-
// Step
|
|
682
|
+
// Step 2: Ask available amount (with back)
|
|
717
683
|
const { availableAmount } = await inquirer.prompt([
|
|
718
684
|
{
|
|
719
685
|
type: 'input',
|
|
@@ -734,7 +700,19 @@ const runSmartQueueDirect = async () => {
|
|
|
734
700
|
const smartPercentage = Math.min((available / totalPending) * 100, 100);
|
|
735
701
|
const roundedPct = Math.round(smartPercentage * 100) / 100;
|
|
736
702
|
|
|
737
|
-
//
|
|
703
|
+
// Plan abbreviations for preview
|
|
704
|
+
const PLAN_ABBREV: Record<string, string> = {
|
|
705
|
+
hermes: 'HRM',
|
|
706
|
+
alpha: 'ALP',
|
|
707
|
+
mematic: 'MEM',
|
|
708
|
+
validator_v2: 'V2',
|
|
709
|
+
booster: 'BST',
|
|
710
|
+
dumpster: 'DMP',
|
|
711
|
+
christmas: 'XMS',
|
|
712
|
+
recovery: 'RCV',
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// Show preview with plan labels
|
|
738
716
|
console.log('\n' + chalk.cyan(` Processing ${chalk.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
|
|
739
717
|
console.log(chalk.dim(' ─────────────────────────────'));
|
|
740
718
|
|
|
@@ -742,14 +720,16 @@ const runSmartQueueDirect = async () => {
|
|
|
742
720
|
currencyItems.forEach((p) => {
|
|
743
721
|
const willPay = p.remaining_amount * (smartPercentage / 100);
|
|
744
722
|
previewTotal += willPay;
|
|
745
|
-
const email = p.user_email.length >
|
|
746
|
-
|
|
723
|
+
const email = p.user_email.length > 20 ? p.user_email.substring(0, 18) + '..' : p.user_email;
|
|
724
|
+
const abbrev = PLAN_ABBREV[p.plan] || p.plan.substring(0, 3).toUpperCase();
|
|
725
|
+
const planColor = PLAN_COLORS[p.plan] || chalk.white;
|
|
726
|
+
console.log(` ${chalk.dim('#' + p.id)} ${planColor('[' + abbrev + ']')} ${email.padEnd(20)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(14)} → pays ${chalk.green(formatAmount(willPay, selectedCurrency))}`);
|
|
747
727
|
});
|
|
748
728
|
|
|
749
729
|
console.log(chalk.dim(' ─────────────────────────────'));
|
|
750
730
|
console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(previewTotal, selectedCurrency))}\n`));
|
|
751
731
|
|
|
752
|
-
// Step
|
|
732
|
+
// Step 3: Confirm
|
|
753
733
|
const { confirmSmart } = await inquirer.prompt([
|
|
754
734
|
{
|
|
755
735
|
type: 'confirm',
|
|
@@ -760,11 +740,15 @@ const runSmartQueueDirect = async () => {
|
|
|
760
740
|
]);
|
|
761
741
|
|
|
762
742
|
if (confirmSmart) {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
743
|
+
// Split by source for correct API calls
|
|
744
|
+
const regularIds = currencyItems.filter((p) => p.source === 'regular').map((p) => p.id);
|
|
745
|
+
const tarPayIds = currencyItems.filter((p) => p.source === 'tarpay').map((p) => p.id);
|
|
746
|
+
|
|
747
|
+
if (regularIds.length > 0) {
|
|
748
|
+
await processPayoutsWithProgress(regularIds, 'partial', roundedPct);
|
|
749
|
+
}
|
|
750
|
+
if (tarPayIds.length > 0) {
|
|
751
|
+
await processChristmasPayoutsWithProgress(tarPayIds, 'partial', roundedPct);
|
|
768
752
|
}
|
|
769
753
|
} else {
|
|
770
754
|
console.log(chalk.dim('\n Cancelled\n'));
|
|
@@ -821,8 +805,8 @@ const runInteractiveShell = async () => {
|
|
|
821
805
|
} else if (cmd === '4') {
|
|
822
806
|
setTitle('Urgent');
|
|
823
807
|
await showUrgentCmd();
|
|
824
|
-
} else if (cmd === '5' || cmd === 'queue' || cmd === 'sq') {
|
|
825
|
-
await
|
|
808
|
+
} else if (cmd === '5' || cmd === 'queue' || cmd === 'sq' || cmd === 'super' || cmd === 'ss') {
|
|
809
|
+
await runSuperSmartDirect();
|
|
826
810
|
await showDashboard();
|
|
827
811
|
} else {
|
|
828
812
|
// Regular commands
|
|
@@ -1908,114 +1892,11 @@ const runChristmasPayoutsShell = async () => {
|
|
|
1908
1892
|
}
|
|
1909
1893
|
break;
|
|
1910
1894
|
case 'smart':
|
|
1911
|
-
case 'sp':
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
const xmasData = await api.getTarPayPayouts({
|
|
1916
|
-
plan: 'christmas',
|
|
1917
|
-
status: 'pending_review',
|
|
1918
|
-
limit: 500,
|
|
1919
|
-
});
|
|
1920
|
-
const xmasPayouts: TarPayPayout[] = xmasData.results || [];
|
|
1921
|
-
xmasSmartSpinner.stop();
|
|
1922
|
-
|
|
1923
|
-
if (xmasPayouts.length === 0) {
|
|
1924
|
-
console.log(chalk.green('\n ✓ No pending Christmas payouts\n'));
|
|
1925
|
-
break;
|
|
1926
|
-
}
|
|
1927
|
-
|
|
1928
|
-
// Group by currency
|
|
1929
|
-
const xmasByCurrency: Record<string, TarPayPayout[]> = {};
|
|
1930
|
-
xmasPayouts.forEach((p) => {
|
|
1931
|
-
if (!xmasByCurrency[p.currency]) xmasByCurrency[p.currency] = [];
|
|
1932
|
-
xmasByCurrency[p.currency].push(p);
|
|
1933
|
-
});
|
|
1934
|
-
|
|
1935
|
-
const xmasCurrencies = Object.keys(xmasByCurrency);
|
|
1936
|
-
console.log('\n' + chalk.red(` 🎄 CHRISTMAS - Pending Payouts`));
|
|
1937
|
-
console.log(chalk.dim(' ─────────────────────────────'));
|
|
1938
|
-
xmasCurrencies.forEach((crypto) => {
|
|
1939
|
-
const items = xmasByCurrency[crypto];
|
|
1940
|
-
const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
|
|
1941
|
-
console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
|
|
1942
|
-
});
|
|
1943
|
-
console.log('');
|
|
1944
|
-
|
|
1945
|
-
let xmasCurrency: string;
|
|
1946
|
-
if (xmasCurrencies.length === 1) {
|
|
1947
|
-
xmasCurrency = xmasCurrencies[0];
|
|
1948
|
-
} else {
|
|
1949
|
-
const { currency } = await inquirer.prompt([
|
|
1950
|
-
{
|
|
1951
|
-
type: 'list',
|
|
1952
|
-
name: 'currency',
|
|
1953
|
-
message: 'Which currency to process?',
|
|
1954
|
-
choices: xmasCurrencies.map((c) => {
|
|
1955
|
-
const items = xmasByCurrency[c];
|
|
1956
|
-
const total = items.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
|
|
1957
|
-
return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
|
|
1958
|
-
}),
|
|
1959
|
-
},
|
|
1960
|
-
]);
|
|
1961
|
-
xmasCurrency = currency;
|
|
1962
|
-
}
|
|
1963
|
-
|
|
1964
|
-
const xmasCurrencyPayouts = xmasByCurrency[xmasCurrency];
|
|
1965
|
-
const xmasTotalPending = xmasCurrencyPayouts.reduce((sum, p) => sum + (p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount)), 0);
|
|
1966
|
-
|
|
1967
|
-
const { xmasAvailable } = await inquirer.prompt([
|
|
1968
|
-
{
|
|
1969
|
-
type: 'input',
|
|
1970
|
-
name: 'xmasAvailable',
|
|
1971
|
-
message: `How much ${xmasCurrency} do you have available? (total pending: ${formatAmount(xmasTotalPending, xmasCurrency)})`,
|
|
1972
|
-
validate: (input: string) => {
|
|
1973
|
-
const num = parseFloat(input);
|
|
1974
|
-
if (isNaN(num) || num <= 0) return 'Please enter a positive number';
|
|
1975
|
-
return true;
|
|
1976
|
-
},
|
|
1977
|
-
},
|
|
1978
|
-
]);
|
|
1979
|
-
|
|
1980
|
-
const xmasAvailNum = parseFloat(xmasAvailable);
|
|
1981
|
-
const xmasPct = Math.min((xmasAvailNum / xmasTotalPending) * 100, 100);
|
|
1982
|
-
const xmasRoundedPct = Math.round(xmasPct * 100) / 100;
|
|
1983
|
-
|
|
1984
|
-
console.log('\n' + chalk.cyan(` Processing ${chalk.bold(xmasRoundedPct + '%')} of ${xmasCurrencyPayouts.length} ${xmasCurrency} payouts (${formatAmount(xmasAvailNum, xmasCurrency)} / ${formatAmount(xmasTotalPending, xmasCurrency)})`));
|
|
1985
|
-
console.log(chalk.dim(' ─────────────────────────────'));
|
|
1986
|
-
|
|
1987
|
-
let xmasPreviewTotal = 0;
|
|
1988
|
-
xmasCurrencyPayouts.forEach((p) => {
|
|
1989
|
-
const displayAmt = p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount);
|
|
1990
|
-
const willPay = displayAmt * (xmasPct / 100);
|
|
1991
|
-
xmasPreviewTotal += willPay;
|
|
1992
|
-
const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
|
|
1993
|
-
console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(displayAmt, xmasCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, xmasCurrency))}`);
|
|
1994
|
-
});
|
|
1995
|
-
|
|
1996
|
-
console.log(chalk.dim(' ─────────────────────────────'));
|
|
1997
|
-
console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(xmasPreviewTotal, xmasCurrency))}\n`));
|
|
1998
|
-
|
|
1999
|
-
const { confirmXmasSmart } = await inquirer.prompt([
|
|
2000
|
-
{
|
|
2001
|
-
type: 'confirm',
|
|
2002
|
-
name: 'confirmXmasSmart',
|
|
2003
|
-
message: chalk.yellow(`⚠️ Pay ${xmasRoundedPct}% of ${xmasCurrencyPayouts.length} payout(s)?`),
|
|
2004
|
-
default: false,
|
|
2005
|
-
},
|
|
2006
|
-
]);
|
|
2007
|
-
|
|
2008
|
-
if (confirmXmasSmart) {
|
|
2009
|
-
const xmasSmartIds = xmasCurrencyPayouts.map((p) => p.id);
|
|
2010
|
-
await processChristmasPayoutsWithProgress(xmasSmartIds, 'partial', xmasRoundedPct);
|
|
2011
|
-
} else {
|
|
2012
|
-
console.log(chalk.dim('\n Cancelled\n'));
|
|
2013
|
-
}
|
|
2014
|
-
} catch (e: any) {
|
|
2015
|
-
xmasSmartSpinner.fail(chalk.red('Failed to load Christmas payouts'));
|
|
2016
|
-
}
|
|
1895
|
+
case 'sp':
|
|
1896
|
+
case 'super':
|
|
1897
|
+
case 'ss':
|
|
1898
|
+
await runSuperSmartDirect();
|
|
2017
1899
|
break;
|
|
2018
|
-
}
|
|
2019
1900
|
case 'help':
|
|
2020
1901
|
case '?':
|
|
2021
1902
|
console.log(chalk.red('\n 🎄 Christmas Payout Commands:'));
|
|
@@ -2028,7 +1909,7 @@ const runChristmasPayoutsShell = async () => {
|
|
|
2028
1909
|
console.log(' select, s Interactive selection mode');
|
|
2029
1910
|
console.log(' approve, a Select & approve payouts');
|
|
2030
1911
|
console.log(chalk.cyan(' partial, p Select & pay partial %'));
|
|
2031
|
-
console.log(chalk.cyan(' smart, sp
|
|
1912
|
+
console.log(chalk.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
|
|
2032
1913
|
console.log(' reject Select & reject payouts');
|
|
2033
1914
|
console.log(' back, q Return to main payouts');
|
|
2034
1915
|
console.log(chalk.dim('\n Note: Payouts > $50 need approval, < $50 auto-sent'));
|
|
@@ -2218,180 +2099,9 @@ const runPayoutsShell = async () => {
|
|
|
2218
2099
|
break;
|
|
2219
2100
|
case 'smart':
|
|
2220
2101
|
case 'sp':
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
type: 'list',
|
|
2225
|
-
name: 'smartPlan',
|
|
2226
|
-
message: 'Select plan:',
|
|
2227
|
-
choices: [
|
|
2228
|
-
{ name: `${PLAN_ICONS.hermes || '⚡'} Hermes`, value: 'hermes' },
|
|
2229
|
-
{ name: `${PLAN_ICONS.alpha || '🔷'} Alpha`, value: 'alpha' },
|
|
2230
|
-
{ name: `${PLAN_ICONS.mematic || '💎'} Mematic`, value: 'mematic' },
|
|
2231
|
-
{ name: `${PLAN_ICONS.validator_v2 || '🔐'} Validator V2`, value: 'validator_v2' },
|
|
2232
|
-
{ name: `${PLAN_ICONS.booster || '🚀'} Booster`, value: 'booster' },
|
|
2233
|
-
{ name: `${PLAN_ICONS.christmas || '🎄'} Christmas`, value: 'christmas' },
|
|
2234
|
-
{ name: '🔄 Recovery', value: 'recovery' },
|
|
2235
|
-
{ name: '📋 All Plans', value: undefined },
|
|
2236
|
-
],
|
|
2237
|
-
},
|
|
2238
|
-
]);
|
|
2239
|
-
|
|
2240
|
-
const isTarPayPlan = smartPlan === 'christmas';
|
|
2241
|
-
const smartSpinner = ora('Loading pending payouts...').start();
|
|
2242
|
-
try {
|
|
2243
|
-
// Unified payout items with common shape
|
|
2244
|
-
interface SmartPayoutItem {
|
|
2245
|
-
id: number;
|
|
2246
|
-
user_email: string;
|
|
2247
|
-
crypto: string;
|
|
2248
|
-
amount: number;
|
|
2249
|
-
remaining_amount: number;
|
|
2250
|
-
has_partial_payments: boolean;
|
|
2251
|
-
paid_percentage: number;
|
|
2252
|
-
}
|
|
2253
|
-
|
|
2254
|
-
let smartItems: SmartPayoutItem[] = [];
|
|
2255
|
-
|
|
2256
|
-
if (isTarPayPlan) {
|
|
2257
|
-
// TarPay payouts (Christmas, etc.)
|
|
2258
|
-
const tarData = await api.getTarPayPayouts({
|
|
2259
|
-
plan: smartPlan,
|
|
2260
|
-
status: 'pending_review',
|
|
2261
|
-
limit: 500,
|
|
2262
|
-
});
|
|
2263
|
-
const tarPayouts: TarPayPayout[] = tarData.results || [];
|
|
2264
|
-
smartItems = tarPayouts.map((p) => ({
|
|
2265
|
-
id: p.id,
|
|
2266
|
-
user_email: p.user_email,
|
|
2267
|
-
crypto: p.currency,
|
|
2268
|
-
amount: parseFloat(p.amount),
|
|
2269
|
-
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : parseFloat(p.amount),
|
|
2270
|
-
has_partial_payments: p.has_partial_payments || false,
|
|
2271
|
-
paid_percentage: p.paid_percentage || 0,
|
|
2272
|
-
}));
|
|
2273
|
-
} else {
|
|
2274
|
-
// Regular payouts
|
|
2275
|
-
const smartParams: any = { status: 'pending', limit: 500 };
|
|
2276
|
-
if (smartPlan) smartParams.plan = smartPlan;
|
|
2277
|
-
const smartData = await api.listPayouts(smartParams);
|
|
2278
|
-
const smartPayouts: Payout[] = smartData.data || [];
|
|
2279
|
-
smartItems = smartPayouts.map((p) => ({
|
|
2280
|
-
id: p.id,
|
|
2281
|
-
user_email: p.user_email,
|
|
2282
|
-
crypto: p.crypto_type,
|
|
2283
|
-
amount: p.amount,
|
|
2284
|
-
remaining_amount: p.remaining_amount !== undefined ? p.remaining_amount : p.amount,
|
|
2285
|
-
has_partial_payments: p.has_partial_payments || false,
|
|
2286
|
-
paid_percentage: p.paid_percentage || 0,
|
|
2287
|
-
}));
|
|
2288
|
-
}
|
|
2289
|
-
smartSpinner.stop();
|
|
2290
|
-
|
|
2291
|
-
if (smartItems.length === 0) {
|
|
2292
|
-
console.log(chalk.green('\n ✓ No pending payouts found\n'));
|
|
2293
|
-
break;
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
|
-
// Group by crypto
|
|
2297
|
-
const byCurrency: Record<string, SmartPayoutItem[]> = {};
|
|
2298
|
-
smartItems.forEach((p) => {
|
|
2299
|
-
if (!byCurrency[p.crypto]) byCurrency[p.crypto] = [];
|
|
2300
|
-
byCurrency[p.crypto].push(p);
|
|
2301
|
-
});
|
|
2302
|
-
|
|
2303
|
-
const currencies = Object.keys(byCurrency);
|
|
2304
|
-
const planLabel = smartPlan ? smartPlan.toUpperCase() : 'ALL PLANS';
|
|
2305
|
-
const planColor = smartPlan ? (PLAN_COLORS[smartPlan] || chalk.white) : chalk.white;
|
|
2306
|
-
|
|
2307
|
-
console.log('\n' + planColor(` 📋 ${planLabel} - Pending Payouts`));
|
|
2308
|
-
console.log(chalk.dim(' ─────────────────────────────'));
|
|
2309
|
-
currencies.forEach((crypto) => {
|
|
2310
|
-
const items = byCurrency[crypto];
|
|
2311
|
-
const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
2312
|
-
console.log(` ${chalk.bold(crypto.padEnd(5))}: ${String(items.length).padStart(3)} payouts │ Total: ${chalk.green(formatAmount(total, crypto))}`);
|
|
2313
|
-
});
|
|
2314
|
-
console.log('');
|
|
2315
|
-
|
|
2316
|
-
// Select currency
|
|
2317
|
-
let selectedCurrency: string;
|
|
2318
|
-
if (currencies.length === 1) {
|
|
2319
|
-
selectedCurrency = currencies[0];
|
|
2320
|
-
} else {
|
|
2321
|
-
const { currency } = await inquirer.prompt([
|
|
2322
|
-
{
|
|
2323
|
-
type: 'list',
|
|
2324
|
-
name: 'currency',
|
|
2325
|
-
message: 'Which currency to process?',
|
|
2326
|
-
choices: currencies.map((c) => {
|
|
2327
|
-
const items = byCurrency[c];
|
|
2328
|
-
const total = items.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
2329
|
-
return { name: `${c} (${items.length} payouts, ${formatAmount(total, c)})`, value: c };
|
|
2330
|
-
}),
|
|
2331
|
-
},
|
|
2332
|
-
]);
|
|
2333
|
-
selectedCurrency = currency;
|
|
2334
|
-
}
|
|
2335
|
-
|
|
2336
|
-
const currencyItems = byCurrency[selectedCurrency];
|
|
2337
|
-
const totalPending = currencyItems.reduce((sum, p) => sum + p.remaining_amount, 0);
|
|
2338
|
-
|
|
2339
|
-
// Ask available amount
|
|
2340
|
-
const { availableAmount } = await inquirer.prompt([
|
|
2341
|
-
{
|
|
2342
|
-
type: 'input',
|
|
2343
|
-
name: 'availableAmount',
|
|
2344
|
-
message: `How much ${selectedCurrency} do you have available? (total pending: ${formatAmount(totalPending, selectedCurrency)})`,
|
|
2345
|
-
validate: (input: string) => {
|
|
2346
|
-
const num = parseFloat(input);
|
|
2347
|
-
if (isNaN(num) || num <= 0) return 'Please enter a positive number';
|
|
2348
|
-
return true;
|
|
2349
|
-
},
|
|
2350
|
-
},
|
|
2351
|
-
]);
|
|
2352
|
-
|
|
2353
|
-
const available = parseFloat(availableAmount);
|
|
2354
|
-
const smartPercentage = Math.min((available / totalPending) * 100, 100);
|
|
2355
|
-
const roundedPct = Math.round(smartPercentage * 100) / 100;
|
|
2356
|
-
|
|
2357
|
-
// Show breakdown
|
|
2358
|
-
console.log('\n' + chalk.cyan(` Processing ${chalk.bold(roundedPct + '%')} of ${currencyItems.length} ${selectedCurrency} payouts (${formatAmount(available, selectedCurrency)} / ${formatAmount(totalPending, selectedCurrency)})`));
|
|
2359
|
-
console.log(chalk.dim(' ─────────────────────────────'));
|
|
2360
|
-
|
|
2361
|
-
let previewTotal = 0;
|
|
2362
|
-
currencyItems.forEach((p) => {
|
|
2363
|
-
const willPay = p.remaining_amount * (smartPercentage / 100);
|
|
2364
|
-
previewTotal += willPay;
|
|
2365
|
-
const email = p.user_email.length > 22 ? p.user_email.substring(0, 20) + '..' : p.user_email;
|
|
2366
|
-
console.log(` ${chalk.dim('#' + p.id)} ${email.padEnd(22)} ${formatAmount(p.remaining_amount, selectedCurrency).padStart(16)} → pays ${chalk.green(formatAmount(willPay, selectedCurrency))}`);
|
|
2367
|
-
});
|
|
2368
|
-
|
|
2369
|
-
console.log(chalk.dim(' ─────────────────────────────'));
|
|
2370
|
-
console.log(chalk.bold(` Total to send: ${chalk.green(formatAmount(previewTotal, selectedCurrency))}\n`));
|
|
2371
|
-
|
|
2372
|
-
// Confirm
|
|
2373
|
-
const { confirmSmart } = await inquirer.prompt([
|
|
2374
|
-
{
|
|
2375
|
-
type: 'confirm',
|
|
2376
|
-
name: 'confirmSmart',
|
|
2377
|
-
message: chalk.yellow(`⚠️ Pay ${roundedPct}% of ${currencyItems.length} payout(s)?`),
|
|
2378
|
-
default: false,
|
|
2379
|
-
},
|
|
2380
|
-
]);
|
|
2381
|
-
|
|
2382
|
-
if (confirmSmart) {
|
|
2383
|
-
const smartIds = currencyItems.map((p) => p.id);
|
|
2384
|
-
if (isTarPayPlan) {
|
|
2385
|
-
await processChristmasPayoutsWithProgress(smartIds, 'partial', roundedPct);
|
|
2386
|
-
} else {
|
|
2387
|
-
await processPayoutsWithProgress(smartIds, 'partial', roundedPct);
|
|
2388
|
-
}
|
|
2389
|
-
} else {
|
|
2390
|
-
console.log(chalk.dim('\n Cancelled\n'));
|
|
2391
|
-
}
|
|
2392
|
-
} catch (e: any) {
|
|
2393
|
-
smartSpinner.fail(chalk.red('Failed to load payouts'));
|
|
2394
|
-
}
|
|
2102
|
+
case 'super':
|
|
2103
|
+
case 'ss':
|
|
2104
|
+
await runSuperSmartDirect();
|
|
2395
2105
|
break;
|
|
2396
2106
|
case 'hermes':
|
|
2397
2107
|
case 'alpha':
|
|
@@ -2481,7 +2191,7 @@ const runPayoutsShell = async () => {
|
|
|
2481
2191
|
console.log(' select [plan] Interactive payout selection');
|
|
2482
2192
|
console.log(' approve [ids] Approve payouts (interactive if no IDs)');
|
|
2483
2193
|
console.log(chalk.cyan(' partial, p Pay partial % (repayment mode)'));
|
|
2484
|
-
console.log(chalk.cyan(' smart, sp
|
|
2194
|
+
console.log(chalk.cyan(' smart, sp, ss Super Smart: pay by currency across all plans'));
|
|
2485
2195
|
console.log(chalk.yellow(' all Approve ALL pending payouts'));
|
|
2486
2196
|
console.log(' cancel [ids] Cancel payouts (interactive if no IDs)');
|
|
2487
2197
|
console.log(' process Process payouts by plan (interactive)');
|