From aceb7d324fc6309d1b0c9683f02c075617ae1bc0 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 16 May 2026 01:36:22 +0300 Subject: [PATCH] Update: 2026-05-16 01:36:22 --- app/Middleware/QuotaMiddleware.php | 6 ++-- app/config/plans.php | 38 +++++++++++--------- app/middleware/QuotaMiddleware.php | 6 ++-- app/modules_app/payments/create.php | 27 ++++++++++----- app/modules_app/subscriptions/plans.php | 4 ++- public/landing.php | 32 ++++++++++++----- public/shell.php | 29 +++++++++++++--- update_subscription_strategy.sql | 46 +++++++++++++++++++++++++ 8 files changed, 145 insertions(+), 43 deletions(-) create mode 100644 update_subscription_strategy.sql diff --git a/app/Middleware/QuotaMiddleware.php b/app/Middleware/QuotaMiddleware.php index 68b8bd0..5875548 100644 --- a/app/Middleware/QuotaMiddleware.php +++ b/app/Middleware/QuotaMiddleware.php @@ -31,7 +31,7 @@ final class QuotaMiddleware // Fetch subscription with plan info $stmt = $db->prepare(" - SELECT s.*, sp.name_ar as plan_name, sp.ai_features, sp.jofotara_enabled + SELECT s.*, sp.name_ar as plan_name, sp.ai_features, sp.jofotara_enabled, sp.price_monthly_jod, sp.price_annual_jod FROM subscriptions s LEFT JOIN subscription_plans sp ON s.plan_id = sp.id WHERE s.tenant_id = ? @@ -60,7 +60,9 @@ final class QuotaMiddleware // 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('+1 year')); // Changed to annual + $cycle = $sub['billing_cycle'] ?? 'annual'; + $interval = ($cycle === 'monthly') ? '+1 month' : '+1 year'; + $newEnd = date('Y-m-d H:i:s', strtotime($interval)); $resetStmt = $db->prepare(" UPDATE subscriptions diff --git a/app/config/plans.php b/app/config/plans.php index 5e3f463..f49ec76 100644 --- a/app/config/plans.php +++ b/app/config/plans.php @@ -15,6 +15,8 @@ return [ 'max_invoices_month' => 15, 'max_users' => 1, 'price_jod' => 0.00, + 'price_monthly_jod' => 0.00, + 'price_annual_jod' => 0.00, 'ai_features' => true, 'jofotara_enabled' => true, 'badge_color' => 'gray', @@ -29,43 +31,47 @@ return [ ], 'basic' => [ 'id' => 'basic', - 'name_ar' => 'الباقة الأساسية (سنوي)', - 'name_en' => 'Basic Plan (Annual)', - 'max_companies' => 1, - 'max_invoices_month' => 12000, - 'max_users' => 1, - 'price_jod' => 120.00, + 'name_ar' => 'الباقة الأساسية', + 'name_en' => 'Basic Plan', + 'max_companies' => 3, + 'max_invoices_month' => 500, + 'max_users' => 2, + 'price_jod' => 15.00, // Default legacy price + 'price_monthly_jod' => 15.00, + 'price_annual_jod' => 120.00, 'ai_features' => true, 'jofotara_enabled' => true, 'badge_color' => 'blue', - 'description_ar' => 'للمحاسبين المستقلين والشركات الصغيرة — 12,000 فاتورة سنوياً', + 'description_ar' => 'للمحاسبين المستقلين والشركات الصغيرة — 3 شركات', 'features' => [ 'استخراج الفواتير بالذكاء الاصطناعي', 'الربط المباشر مع جوفوترة', - 'شركة واحدة فقط', - '12,000 فاتورة سنوياً (سخية جداً)', - 'مستخدم واحد', + 'حتى 3 شركات (بدلاً من واحدة)', + '500 فاتورة شهرياً (سخية جداً)', + 'مستخدمين اثنين', 'دعم فني عبر الواتساب', ], ], 'pro' => [ 'id' => 'pro', - 'name_ar' => 'الباقة الاحترافية (سنوي)', - 'name_en' => 'Pro Plan (Annual)', + 'name_ar' => 'الباقة الاحترافية', + 'name_en' => 'Pro Plan', 'max_companies' => 9999, - 'max_invoices_month' => 50000, + 'max_invoices_month' => 3000, 'max_users' => 5, - 'price_jod' => 250.00, + 'price_jod' => 35.00, // Default legacy price + 'price_monthly_jod' => 35.00, + 'price_annual_jod' => 290.00, 'ai_features' => true, 'jofotara_enabled' => true, 'badge_color' => 'gold', 'is_popular' => true, - 'description_ar' => 'للمكاتب الكبيرة والموزعين — 50,000 فاتورة سنوياً', + 'description_ar' => 'للمكاتب الكبيرة والموزعين — حجم عمل ضخم', 'features' => [ 'استخراج الفواتير بالذكاء الاصطناعي', 'الربط المباشر مع جوفوترة', 'عدد شركات غير محدود', - '50,000 فاتورة سنوياً', + '3,000 فاتورة شهرياً', '5 مستخدمين', 'API كامل لتطبيق الهاتف', 'مدير حساب مخصص', diff --git a/app/middleware/QuotaMiddleware.php b/app/middleware/QuotaMiddleware.php index 68b8bd0..5875548 100644 --- a/app/middleware/QuotaMiddleware.php +++ b/app/middleware/QuotaMiddleware.php @@ -31,7 +31,7 @@ final class QuotaMiddleware // Fetch subscription with plan info $stmt = $db->prepare(" - SELECT s.*, sp.name_ar as plan_name, sp.ai_features, sp.jofotara_enabled + SELECT s.*, sp.name_ar as plan_name, sp.ai_features, sp.jofotara_enabled, sp.price_monthly_jod, sp.price_annual_jod FROM subscriptions s LEFT JOIN subscription_plans sp ON s.plan_id = sp.id WHERE s.tenant_id = ? @@ -60,7 +60,9 @@ final class QuotaMiddleware // 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('+1 year')); // Changed to annual + $cycle = $sub['billing_cycle'] ?? 'annual'; + $interval = ($cycle === 'monthly') ? '+1 month' : '+1 year'; + $newEnd = date('Y-m-d H:i:s', strtotime($interval)); $resetStmt = $db->prepare(" UPDATE subscriptions diff --git a/app/modules_app/payments/create.php b/app/modules_app/payments/create.php index 161465e..610ce8f 100644 --- a/app/modules_app/payments/create.php +++ b/app/modules_app/payments/create.php @@ -32,8 +32,13 @@ if ($errors) { $db = Database::getInstance(); $tenantId = $decoded['tenant_id']; -$userId = $decoded['user_id']; -$planId = $data['plan_id']; +$userId = $decoded['user_id']; +$planId = $data['plan_id']; +$cycle = $data['billing_cycle'] ?? 'annual'; // Default to annual + +if (!in_array($cycle, ['monthly', 'annual'])) { + json_error('دورة الفوترة غير صالحة.', 422); +} try { // 1. Get plan details @@ -45,6 +50,9 @@ try { json_error('الباقة المختارة غير صالحة أو غير نشطة.', 422); } + // Determine amount based on cycle + $amount = ($cycle === 'monthly') ? ($plan['price_monthly_jod'] ?? $plan['price_jod']) : ($plan['price_annual_jod'] ?? ($plan['price_jod'] * 10)); + // 2. Check for existing pending payment for this tenant $stmt = $db->prepare("SELECT id FROM payment_requests WHERE tenant_id = ? AND status = 'pending' LIMIT 1"); $stmt->execute([$tenantId]); @@ -68,15 +76,16 @@ try { // 6. Create payment request $paymentId = Database::generateUuid(); $stmt = $db->prepare(" - INSERT INTO payment_requests (id, tenant_id, user_id, plan_id, amount_jod, internal_reference, cliq_alias, payer_name, status, created_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'pending', NOW()) + INSERT INTO payment_requests (id, tenant_id, user_id, plan_id, billing_cycle, amount_jod, internal_reference, cliq_alias, payer_name, status, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', NOW()) "); $stmt->execute([ $paymentId, $tenantId, $userId, $planId, - $plan['price_jod'], + $cycle, + $amount, $referenceNumber, $cliqAlias, $user['name'] ?? '' @@ -88,17 +97,17 @@ try { $tenantId, $userId, $paymentId, - json_encode(['plan_id' => $planId, 'amount' => $plan['price_jod'], 'ref' => $referenceNumber]) + json_encode(['plan_id' => $planId, 'cycle' => $cycle, 'amount' => $amount, 'ref' => $referenceNumber]) ]); json_success([ 'payment_id' => $paymentId, 'reference_number' => $referenceNumber, 'cliq_alias' => $cliqAlias, - 'amount_jod' => (float)$plan['price_jod'], - 'plan_name' => $plan['name_ar'] ?? $plan['name_en'], + 'amount_jod' => (float)$amount, + 'plan_name' => ($plan['name_ar'] ?? $plan['name_en']) . " (" . ($cycle === 'monthly' ? 'شهري' : 'سنوي') . ")", 'payer_name' => $user['name'] ?? '', - 'instructions' => "قم بالتحويل عبر CliQ إلى الاسم المستعار: {$cliqAlias} بمبلغ {$plan['price_jod']} دينار أردني.", + 'instructions' => "قم بالتحويل عبر CliQ إلى الاسم المستعار: {$cliqAlias} بمبلغ {$amount} دينار أردني.", ], 'تم إنشاء طلب الدفع بنجاح'); } catch (\Throwable $e) { diff --git a/app/modules_app/subscriptions/plans.php b/app/modules_app/subscriptions/plans.php index 6301bb3..e63f47b 100644 --- a/app/modules_app/subscriptions/plans.php +++ b/app/modules_app/subscriptions/plans.php @@ -13,7 +13,7 @@ $db = Database::getInstance(); try { $stmt = $db->query(" SELECT id, name_ar, name_en, max_companies, max_invoices_month, max_users, - price_jod, ai_features, jofotara_enabled, sort_order + price_jod, price_annual_jod, price_monthly_jod, ai_features, jofotara_enabled, sort_order FROM subscription_plans WHERE is_active = 1 ORDER BY sort_order ASC @@ -36,6 +36,8 @@ try { $plan['max_invoices_month'] = (int)$plan['max_invoices_month']; $plan['max_users'] = (int)$plan['max_users']; $plan['price_jod'] = (float)$plan['price_jod']; + $plan['price_annual_jod'] = (float)$plan['price_annual_jod']; + $plan['price_monthly_jod'] = (float)$plan['price_monthly_jod']; $plan['ai_features'] = (bool)$plan['ai_features']; $plan['jofotara_enabled'] = (bool)$plan['jofotara_enabled']; } diff --git a/public/landing.php b/public/landing.php index e6fe715..b77f82b 100644 --- a/public/landing.php +++ b/public/landing.php @@ -164,11 +164,23 @@

اختر الباقة المناسبة لحجم أعمالك

لا رسوم خفية. لا عقود طويلة. ابدأ مجاناً وتدرّج حسب احتياجك.

+
+
+ دفع سنوي (توفير ✨) + دفع شهري +
+
+ + +
التجربة المجانية
-
0 دينار/سنة
+
0 دينار/شهر
للتجربة الأولية
  • شركة واحدة
  • @@ -182,13 +194,14 @@
    -
    الباقة الاحترافية (سنوي)
    -
    250 دينار/سنة
    +
    الباقة الاحترافية
    +
    290 دينار/سنة
    +
    للمكاتب الكبيرة والموزعين
    • شركات غير محدودة
    • -
    • 50,000 فاتورة سنوياً
    • +
    • 3,000 فاتورة شهرياً
    • 5 مستخدمين
    • تدقيق ذكي استباقي
    • مدير حساب مخصص
    • diff --git a/public/shell.php b/public/shell.php index 709f761..c8722e7 100644 --- a/public/shell.php +++ b/public/shell.php @@ -1951,6 +1951,22 @@

    + +
    +
    + + +
    +
    +