From e93f1d4f3482963191ab1ef6fbb3635ccc66522b Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 16 May 2026 00:15:38 +0300 Subject: [PATCH] feat: implement annual subscription model across backend quota system and flutter UI --- app/Middleware/QuotaMiddleware.php | 10 ++-- app/middleware/QuotaMiddleware.php | 10 ++-- .../subscription/views/subscription_view.dart | 2 +- update_annual_plans.sql | 46 +++++++++++++++++++ update_plans.php | 6 +++ 5 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 update_annual_plans.sql create mode 100644 update_plans.php diff --git a/app/Middleware/QuotaMiddleware.php b/app/Middleware/QuotaMiddleware.php index a983ba4..68b8bd0 100644 --- a/app/Middleware/QuotaMiddleware.php +++ b/app/Middleware/QuotaMiddleware.php @@ -57,10 +57,10 @@ final class QuotaMiddleware json_error('اشتراكك متأخر الدفع. يرجى تسوية المبلغ المستحق للمتابعة.', 403); } - // Auto-reset monthly counter if billing period has ended + // Auto-reset period counter if billing period has ended if (!empty($sub['current_period_end']) && strtotime($sub['current_period_end']) < time()) { $newStart = date('Y-m-d H:i:s'); - $newEnd = date('Y-m-d H:i:s', strtotime('+30 days')); + $newEnd = date('Y-m-d H:i:s', strtotime('+1 year')); // Changed to annual $resetStmt = $db->prepare(" UPDATE subscriptions @@ -76,15 +76,15 @@ final class QuotaMiddleware $sub['current_period_start'] = $newStart; $sub['current_period_end'] = $newEnd; - error_log("QuotaMiddleware: Auto-reset monthly counter for tenant {$tenantId}"); + error_log("QuotaMiddleware: Auto-reset annual counter for tenant {$tenantId}"); } // Check invoice quota $used = (int)$sub['invoices_used_this_month']; - $limit = (int)$sub['max_invoices_per_month']; + $limit = (int)$sub['max_invoices_per_month']; // Keeping the DB column name the same for compatibility if ($used >= $limit) { - json_error('لقد وصلت للحد الأقصى من الفواتير المسموحة هذا الشهر (' . $limit . ' فاتورة). يرجى ترقية باقتك.', 429, [ + json_error('لقد وصلت للحد الأقصى من الفواتير المسموحة في باقتك الحالية (' . $limit . ' فاتورة). يرجى ترقية باقتك للاستمرار.', 429, [ 'quota_type' => 'invoices', 'used' => $used, 'limit' => $limit, diff --git a/app/middleware/QuotaMiddleware.php b/app/middleware/QuotaMiddleware.php index a983ba4..68b8bd0 100644 --- a/app/middleware/QuotaMiddleware.php +++ b/app/middleware/QuotaMiddleware.php @@ -57,10 +57,10 @@ final class QuotaMiddleware json_error('اشتراكك متأخر الدفع. يرجى تسوية المبلغ المستحق للمتابعة.', 403); } - // Auto-reset monthly counter if billing period has ended + // Auto-reset period counter if billing period has ended if (!empty($sub['current_period_end']) && strtotime($sub['current_period_end']) < time()) { $newStart = date('Y-m-d H:i:s'); - $newEnd = date('Y-m-d H:i:s', strtotime('+30 days')); + $newEnd = date('Y-m-d H:i:s', strtotime('+1 year')); // Changed to annual $resetStmt = $db->prepare(" UPDATE subscriptions @@ -76,15 +76,15 @@ final class QuotaMiddleware $sub['current_period_start'] = $newStart; $sub['current_period_end'] = $newEnd; - error_log("QuotaMiddleware: Auto-reset monthly counter for tenant {$tenantId}"); + error_log("QuotaMiddleware: Auto-reset annual counter for tenant {$tenantId}"); } // Check invoice quota $used = (int)$sub['invoices_used_this_month']; - $limit = (int)$sub['max_invoices_per_month']; + $limit = (int)$sub['max_invoices_per_month']; // Keeping the DB column name the same for compatibility if ($used >= $limit) { - json_error('لقد وصلت للحد الأقصى من الفواتير المسموحة هذا الشهر (' . $limit . ' فاتورة). يرجى ترقية باقتك.', 429, [ + json_error('لقد وصلت للحد الأقصى من الفواتير المسموحة في باقتك الحالية (' . $limit . ' فاتورة). يرجى ترقية باقتك للاستمرار.', 429, [ 'quota_type' => 'invoices', 'used' => $used, 'limit' => $limit, diff --git a/musadaq-app/lib/features/subscription/views/subscription_view.dart b/musadaq-app/lib/features/subscription/views/subscription_view.dart index 5cc4b15..127b61b 100644 --- a/musadaq-app/lib/features/subscription/views/subscription_view.dart +++ b/musadaq-app/lib/features/subscription/views/subscription_view.dart @@ -302,7 +302,7 @@ class SubscriptionView extends StatelessWidget { children: [ _buildPlanStat(Icons.business, '${plan['max_companies'] ?? 0} شركات'), const SizedBox(width: 8), - _buildPlanStat(Icons.receipt_long, '${plan['max_invoices_month'] ?? 0} فاتورة/شهر'), + _buildPlanStat(Icons.receipt_long, '${plan['max_invoices_month'] ?? 0} فاتورة/سنة'), const SizedBox(width: 8), _buildPlanStat(Icons.people, '${plan['max_users'] ?? 0} مستخدمين'), ], diff --git a/update_annual_plans.sql b/update_annual_plans.sql new file mode 100644 index 0000000..04d89c8 --- /dev/null +++ b/update_annual_plans.sql @@ -0,0 +1,46 @@ +-- 1. Update existing plans to annual quotas and pricing +-- We'll assume the basic plan ID is 'basic' and pro is 'pro'. If they are different, they will need adjusting. + +-- Basic Plan (Annual) +UPDATE subscription_plans +SET + name_ar = 'الباقة الأساسية (سنوي)', + name_en = 'Basic Plan (Annual)', + price = 120.00, + max_invoices_per_month = 12000, + max_companies = 1, + max_users = 1 +WHERE id = 'basic'; + +-- Pro Plan (Annual) +UPDATE subscription_plans +SET + name_ar = 'الباقة الاحترافية (سنوي)', + name_en = 'Pro Plan (Annual)', + price = 250.00, + max_invoices_per_month = 50000, + max_companies = 9999, -- unlimited + max_users = 5 +WHERE id = 'pro'; + +-- Free Trial Plan +UPDATE subscription_plans +SET + name_ar = 'التجربة المجانية', + name_en = 'Free Trial', + price = 0.00, + max_invoices_per_month = 15, + max_companies = 1, + max_users = 1 +WHERE id = 'free'; + +-- 2. Update existing active subscriptions to match the new annual quota limits so no one gets blocked +UPDATE subscriptions s +JOIN subscription_plans sp ON s.plan_id = sp.id +SET + s.max_invoices_per_month = sp.max_invoices_per_month, + s.max_companies = sp.max_companies, + s.max_users = sp.max_users, + -- Adjust the period end to +1 year if it's currently set to a month (for paid plans only) + s.current_period_end = IF(s.plan_id != 'free', DATE_ADD(s.current_period_start, INTERVAL 1 YEAR), s.current_period_end); + diff --git a/update_plans.php b/update_plans.php new file mode 100644 index 0000000..26c2cca --- /dev/null +++ b/update_plans.php @@ -0,0 +1,6 @@ +query("SELECT * FROM subscription_plans")->fetchAll(); +print_r($plans);