Files
zemailnator/app/Filament/Widgets/RevenueMetrics.php
idevakk 27ac13948c feat: implement comprehensive multi-provider payment processing system
- Add unified payment provider architecture with contract-based design
  - Implement 6 payment providers: Stripe, Lemon Squeezy, Polar, Oxapay, Crypto, Activation Keys
  - Create subscription management with lifecycle handling (create, cancel, pause, resume, update)
  - Add coupon system with usage tracking and trial extensions
  - Build Filament admin resources for payment providers, subscriptions, coupons, and trials
  - Implement payment orchestration service with provider registry and configuration management
  - Add comprehensive payment logging and webhook handling for all providers
  - Create customer analytics dashboard with revenue, churn, and lifetime value metrics
  - Add subscription migration service for provider switching
  - Include extensive test coverage for all payment functionality
2025-11-19 09:37:00 -08:00

124 lines
3.7 KiB
PHP

<?php
namespace App\Filament\Widgets;
use App\Models\Subscription;
use Filament\Widgets\ChartWidget;
use Illuminate\Support\Facades\DB;
class RevenueMetrics extends ChartWidget
{
protected static ?int $sort = 1;
protected int|string|array $columnSpan = 'full';
public function getHeading(): string
{
return 'Revenue Trends';
}
protected function getData(): array
{
$monthlyRevenue = $this->getMonthlyRevenueTrend();
$mrrByProvider = $this->getMRRByProvider();
return [
'datasets' => [
[
'label' => 'Monthly Revenue',
'data' => array_values($monthlyRevenue),
'borderColor' => 'rgba(34, 197, 94, 1)',
'backgroundColor' => 'rgba(34, 197, 94, 0.1)',
'fill' => true,
'tension' => 0.4,
],
[
'label' => 'MRR by Provider',
'data' => array_values($mrrByProvider),
'borderColor' => 'rgba(59, 130, 246, 1)',
'backgroundColor' => 'rgba(59, 130, 246, 0.1)',
'fill' => true,
'tension' => 0.4,
],
],
'labels' => array_keys($monthlyRevenue),
];
}
protected function getType(): string
{
return 'line';
}
protected function getOptions(): array
{
return [
'responsive' => true,
'interaction' => [
'intersect' => false,
'mode' => 'index',
],
'plugins' => [
'legend' => [
'position' => 'top',
],
'tooltip' => [
'callbacks' => [
'label' => 'function(context) {
let label = context.dataset.label || "";
if (label) {
label += ": ";
}
if (context.parsed.y !== null) {
label += "$" + context.parsed.y.toFixed(2);
}
return label;
}',
],
],
],
'scales' => [
'y' => [
'beginAtZero' => true,
'ticks' => [
'callback' => 'function(value) {
return "$" + value;
}',
],
],
],
];
}
private function getMonthlyRevenueTrend(): array
{
return Subscription::query()
->select(
DB::raw("strftime('%Y-%m', subscriptions.created_at) as month"),
DB::raw('SUM(plans.price) as revenue')
)
->join('plans', 'subscriptions.plan_id', '=', 'plans.id')
->where('subscriptions.status', 'active')
->where('subscriptions.created_at', '>=', now()->subMonths(12))
->groupBy('month')
->orderBy('month')
->pluck('revenue', 'month')
->toArray();
}
private function getMRRByProvider(): array
{
return Subscription::query()
->select(
'provider',
DB::raw('SUM(plans.price) as mrr')
)
->join('plans', 'subscriptions.plan_id', '=', 'plans.id')
->where('subscriptions.status', 'active')
->groupBy('provider')
->orderBy('mrr', 'desc')
->pluck('mrr', 'provider')
->toArray();
}
}