الانتقال إلى المحتوى الرئيسي

Documentation Index

Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt

Use this file to discover all available pages before exploring further.

نظرة عامة

الخطوة الأولى في دمج شحنات الهاتف المحمول هي جلب قائمة الخطط المتاحة من API. تشمل الخطط جميع مشغلي الشبكات (Mobilis، Djezzy، Ooredoo، Pixx) مع خيارات المبالغ الديناميكية والثابتة.
الخطط مستقرة ونادراً ما تتغير. احفظها في قاعدة بياناتك لتقليل استدعاءات API وتحسين الأداء.

مرجع API

اطلع على توثيق API الكامل لـ endpoint GET /v3/mobile/plans

فهم أنواع الخطط

الخطط الديناميكية

تتيح الخطط الديناميكية مبالغ متغيرة ضمن نطاق min/max:
{
  "code": "PREPAID_DJEZZY",
  "name": "Djezzy Prepaid",
  "operator": "Djezzy",
  "cost": 0.98,
  "isEnabled": true,
  "min_amount": 50,
  "max_amount": 5000
}
حالات الاستخدام:
  • شحن الخطوط المدفوعة مسبقاً (رصيد)
  • دفع فواتير الخطوط المؤجلة (facture)
  • رصيد المكالمات الدولية

الخطط الثابتة

الخطط الثابتة لها مبالغ محددة مسبقاً:
{
  "code": "PIXX_500",
  "name": "Pixx 500 DA",
  "operator": "Pixx",
  "cost": 0.97,
  "isEnabled": true,
  "amount": 500
}
حالات الاستخدام:
  • العروض الترويجية الخاصة
  • باقات الإنترنت
  • تفعيل الخدمات

خطط GetMenu

خطط خاصة تسترجع العروض المتاحة لرقم هاتف محدد:
{
  "code": "GETMENU_Mobilis",
  "name": "Mobilis GetMenu",
  "operator": "Mobilis",
  "cost": 0.98,
  "isEnabled": true,
  "min_amount": 50,
  "max_amount": 5000
}
تُعيد: مصفوفة suggested_offers تحتوي على جميع الخطط المتاحة لذلك الرقم تحديداً.

جلب الخطط من API

طلب أساسي

curl https://api.oneclickdz.com/v3/mobile/plans \
  -H "X-Access-Token: YOUR_API_KEY"

بنية الاستجابة

{
  "success": true,
  "data": {
    "dynamicPlans": [
      {
        "code": "PREPAID_MOBILIS",
        "name": "📱 PREPAID | عادي",
        "operator": "Mobilis",
        "cost": 0.96,
        "isEnabled": true,
        "min_amount": 40,
        "max_amount": 3999
      },
      {
        "code": "GROS_MOBILIS",
        "name": "📱 GROS MOBILIS | جملة",
        "operator": "GMobilis",
        "isEnabled": true,
        "min_amount": 5000,
        "max_amount": 300000
      }
    ],
    "fixedPlans": [
      {
        "code": "MIX500_MOBILIS",
        "name": "📱🌐 AUTO | MIX 500",
        "operator": "Mobilis",
        "isEnabled": true,
        "cost": 0.96,
        "amount": 500
      },
      {
        "code": "MIX1000_OOREDOO",
        "name": "📱🌐 AUTO | MIX 1000",
        "operator": "Ooredoo",
        "isEnabled": true,
        "cost": 0.99,
        "amount": 1000
      }
    ]
  },
  "meta": {
    "timestamp": "2025-10-29T00:35:59.220Z"
  }
}

فهم حقل Cost

يمثل حقل cost معامل سعر الجملة الخاص بك:
مثال: cost = 0.98لشحن بقيمة 1000 دج:
  • القيمة الاسمية: 1000 دج (ما يستلمه المستخدم)
  • تكلفتك: 1000 × 0.98 = 980 دج (ما تدفعه)
  • هامش ربحك: 1000 - 980 = 20 دج (2%)

تخزين الخطط في قاعدة البيانات

بما أن الخطط نادراً ما تتغير، احفظها محلياً مع أسعارك الخاصة:

مخطط قاعدة البيانات

CREATE TABLE mobile_plans (
    id SERIAL PRIMARY KEY,
    code VARCHAR(100) UNIQUE NOT NULL,
    name VARCHAR(255) NOT NULL,
    operator VARCHAR(50) NOT NULL,
    type VARCHAR(20) NOT NULL, -- 'dynamic' or 'fixed'
    
    -- Cost info
    wholesale_cost DECIMAL(5,4) NOT NULL,
    sell_price_multiplier DECIMAL(5,4) NOT NULL,
    
    -- Amount limits
    min_amount INTEGER,
    max_amount INTEGER,
    fixed_amount INTEGER,
    
    -- Status
    is_enabled BOOLEAN DEFAULT true,
    is_visible BOOLEAN DEFAULT true,
    
    -- Metadata
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_mobile_plans_operator ON mobile_plans(operator);
CREATE INDEX idx_mobile_plans_enabled ON mobile_plans(is_enabled);
CREATE INDEX idx_mobile_plans_code ON mobile_plans(code);

دالة المزامنة

const db = require('./database');

async function syncMobilePlans() {
  try {
    console.log('🔄 Syncing mobile plans...');
    
    // Fetch plans from API
    const plans = await fetchMobilePlans();
    
    // Calculate your pricing
    const PROFIT_MARGIN = 0.05; // 5% profit
    
    for (const plan of plans) {
      const isFixed = !!plan.amount;
      
      const planData = {
        code: plan.code,
        name: plan.name,
        operator: plan.operator,
        type: isFixed ? 'fixed' : 'dynamic',
        wholesaleCost: plan.cost,
        sellPriceMultiplier: plan.cost * (1 + PROFIT_MARGIN),
        minAmount: plan.min_amount || null,
        maxAmount: plan.max_amount || null,
        fixedAmount: plan.amount || null,
        isEnabled: plan.isEnabled,
        lastSyncedAt: new Date()
      };
      
      // Upsert (insert or update)
      await db.mobilePlans.upsert({
        where: { code: plan.code },
        update: planData,
        create: planData
      });
    }
    
    console.log(`✅ Successfully synced ${plans.length} plans`);
    
    // Log statistics
    const stats = {
      total: plans.length,
      dynamic: plans.filter(p => !p.amount).length,
      fixed: plans.filter(p => p.amount).length,
      enabled: plans.filter(p => p.isEnabled).length
    };
    
    console.log('📊 Plan statistics:', stats);
    
    return stats;
  } catch (error) {
    console.error('❌ Failed to sync plans:', error);
    throw error;
  }
}

// Run sync on startup
syncMobilePlans();

// Schedule daily sync at midnight
const cron = require('node-cron');
cron.schedule('0 0 * * *', () => {
  console.log('⏰ Running scheduled plan sync...');
  syncMobilePlans();
});

عرض الخطط للمستخدمين

عند طلب المستخدمين للخطط، قدّمها من قاعدة بياناتك مع أسعارك الخاصة:
async function getUserPlans(filters = {}) {
  const { operator, type, enabled = true } = filters;
  
  const query = { isEnabled: enabled, isVisible: true };
  
  if (operator) query.operator = operator;
  if (type) query.type = type;
  
  const plans = await db.mobilePlans.findMany({
    where: query,
    orderBy: [
      { operator: 'asc' },
      { fixedAmount: 'asc' },
      { name: 'asc' }
    ]
  });
  
  // Transform for user display (remove wholesale cost!)
  return plans.map(plan => ({
    code: plan.code,
    name: plan.name,
    operator: plan.operator,
    type: plan.type,
    minAmount: plan.minAmount,
    maxAmount: plan.maxAmount,
    amount: plan.fixedAmount,
    // Don't expose wholesale cost!
    // Only expose what user needs
  }));
}

// API endpoint
app.get('/api/mobile/plans', async (req, res) => {
  try {
    const { operator } = req.query;
    const plans = await getUserPlans({ operator });
    res.json({ success: true, data: { plans } });
  } catch (error) {
    res.status(500).json({ 
      success: false, 
      error: error.message 
    });
  }
});

تصفية الخطط

حسب المشغل

const mobilisPlans = await getUserPlans({ operator: 'Mobilis' });
const djezzyPlans = await getUserPlans({ operator: 'Djezzy' });
const ooredooPlans = await getUserPlans({ operator: 'Ooredoo' });

حسب رقم الهاتف

function getOperatorFromPhone(phone) {
  const prefixMap = {
    '065': ['Mobilis'],
    '066': ['Mobilis', 'Ooredoo'],
    '067': ['Mobilis'],
    '077': ['Djezzy', 'Mobilis'],
    '078': ['Djezzy'],
    '055': ['Ooredoo', 'Djezzy', 'Mobilis'],
    '056': ['Ooredoo'],
    '068': ['Pixx']
  };
  
  const prefix = phone.substring(0, 3);
  return prefixMap[prefix] || [];
}

async function getPlansForPhone(phone) {
  const operators = getOperatorFromPhone(phone);
  
  if (operators.length === 0) {
    throw new Error('Invalid phone number prefix');
  }
  
  const plans = await db.mobilePlans.findMany({
    where: {
      operator: { in: operators },
      isEnabled: true,
      isVisible: true
    }
  });
  
  return plans;
}

أفضل الممارسات

احرص دائماً على تخزين الخطط في قاعدة بياناتك. الخطط نادراً ما تتغير، والتخزين المؤقت يحسّن الأداء بشكل ملحوظ.
لا تكشف أبداً عن حقل cost للمستخدمين النهائيين. اعرض فقط أسعار التجزئة الخاصة بك.
أنشئ مهمة cron يومية لمزامنة الخطط. هذا يضمن حصولك على أحدث العروض والتوافر.
تحقق دائماً من isEnabled قبل عرض الخطط. الخطط المعطلة قد تكون غير متاحة مؤقتاً بسبب مشاكل المشغل.
احسب سعر البيع بإضافة هامش ربح معقول (عادةً 3-10%) إلى تكلفة الجملة.
أنشئ فهارس على الحقول التي يُستعلم عنها بتكرار (operator، code، isEnabled) للبحث السريع.

الخطوات التالية

الخطوة 2: التحقق من الصحة

تعلّم كيفية التحقق من أرقام الهاتف ومدخلات المستخدم

مرجع API الخطط

توثيق API الكامل لـ GET /v3/mobile/plans

API رصيد الحساب

تعلّم كيفية التحقق من رصيد حسابك

دليل التسعير

فهم تسعير API وهيكل التكاليف

صيغة الاستجابة

تعرّف على هياكل استجابة API

مرجع النماذج

اطلع على جميع نماذج البيانات والمخططات