كيفية دمج Canonical

تعرّف على كيفية إتاحة برنامج التشغيل Canonical PSS لربط مزود خدمة دفع بـ B2CORE من خلال تنفيذ عقد API قياسي للإيداعات، بما في ذلك الإعداد من جانب B2CORE، وwebhooks، والاستعلام الدوري، ودورة حياة حالة الإيداع.

يتيح لك برنامج التشغيل Canonical ربط مزود خدمة دفع (PSP) من اختيارك بـ B2CORE عبر PSS، حتى عندما لا يوفر B2CORE بعد برنامج تشغيل مخصصًا لهذا المزود.

لماذا تستخدم برنامج التشغيل Canonical

تعتمد معظم أنظمة الدفع في B2CORE على برنامج تشغيل مخصص مُنشأ خصيصًا لمزود واحد. يتبع برنامج التشغيل Canonical نهجًا مختلفًا: إذ يحدد عقد API واحدًا وقياسيًا — وهو Canonical Deposit API — يمكن لأي مزود تنفيذه. ثم يتولى B2CORE المصادقة، وتدفق بدء الإيداع، والاستعلام الدوري، وwebhooks، ودورة حياة الحالة بطريقة موحدة، بغض النظر عن المزود الذي يقف خلف العقد.

يكون برنامج التشغيل Canonical مفيدًا عندما تريد:

  • ربط PSP مفضل أو داخلي لا يملك برنامج تشغيل مخصصًا في B2CORE، دون انتظار تطوير مخصص.
  • تقليل الوقت اللازم للوصول إلى السوق من خلال جعل مزودك ينفذ عقدًا موثقًا ومستقرًا واحدًا بدلًا من تكامل مخصص.
  • الاحتفاظ بالتحكم الكامل في جانب المزود، بينما يدير B2CORE سير عمل الإيداع من جانبه.

يدعم برنامج التشغيل Canonical حاليًا تدفقات الإيداع. لتقديم الإيداعات من خلال مزودك، يجب على المزود تنفيذ Canonical Deposit API الموضح في مواصفات OpenAPI أدناه واتباع المتطلبات السلوكية في هذه الصفحة.

مواصفات OpenAPI

يتم تعريف Canonical Deposit API في مواصفات OpenAPI التالية، التي تغطي المصادقة، ومخططات الطلبات والاستجابات، ونقاط النهاية، ورموز الحالة. نزّلها لمراجعة العقد الكامل الذي يجب على مزودك تنفيذه:

canonical-deposit-api.yaml

يصف الجزء المتبقي من هذه الصفحة المتطلبات السلوكية، والإعداد من جانب B2CORE، وقرارات التصميم التي لا يمكن للمواصفات التعبير عنها. اقرأ كليهما معًا للحصول على صورة كاملة عن التكامل.

بيانات اعتماد برنامج تشغيل B2CORE

يتم إعداد هذه الحقول من جانب B2CORE (المكتب الخلفي) واستخدامها للمصادقة مع API الخاص بـ PSP. راجع مواصفات OpenAPI للحصول على التفاصيل الكاملة لإنشاء رمز JWT والتحقق منه.

الحقلالوصف
عنوان URL الأساسي لـ APIعنوان URL الأساسي عبر HTTPS لـ API الخاص بـ PSP.
معرّف التطبيقمعرّف التاجر الفريد. يُستخدم باعتباره مطالبة sub في JWT.
سر التطبيقالمفتاح السري لتوقيع HMAC-SHA256. مُرمّز بصيغة Base64 URL، بطول 32 بايت (43 حرفًا). لا يُرسل أبدًا في الطلبات — ويُستخدم فقط لتوقيع الرموز.

حقول إعداد برنامج تشغيل B2CORE

يتم إعداد هذه الحقول من جانب B2CORE (المكتب الخلفي) وتتحكم في سلوك برنامج التشغيل. وهي ليست جزءًا من API الموجه إلى PSP.

المعلمات العامة (globalParam1, globalParam2, globalParam3)

ثلاثة حقول نصية على مستوى الإعداد تُرسل مع كل طلب تمت مصادقته إلى PSP.

  • بالنسبة إلى نقاط النهاية POST، يتم تضمينها في جسم طلب JSON.
  • بالنسبة إلى نقاط النهاية GET، يتم تضمينها كمعلمات استعلام.

تمثل هذه قيمًا خاصة بـ PSP، مثل معرّف التاجر أو القناة أو معرّف المشروع. تعتمد الدلالات الدقيقة على تنفيذ PSP. يملؤها مسؤول B2CORE أثناء إعداد التكوين.

الحقول المطلوبة (للقراءة فقط)

النوع: تحديد متعدد

يحدد حقول معلومات المستخدم التي تُعرض في نموذج الدفع بوصفها للقراءة فقط (غير قابلة للتحرير).

يجب أن تكون الحقول المحددة مُعدة ومحفوظة مسبقًا في ملف B2CORE الشخصي للمستخدم. إذا كان أي حقل محدد مفقودًا من الملف الشخصي، يفشل إنشاء نموذج الدفع بخطأ حقول مفقودة — ولا يمكن للمستخدم المتابعة حتى يتم ملء البيانات في ملفه الشخصي في B2CORE.

تحدد الحقول المحددة، إلى جانب الحقول من الحقول المطلوبة (القابلة للتحرير)، بيانات المستخدم التي يتم ملؤها بشكل فعلي في كائن startDepositUserInfo المرسل إلى PSP في طلب POST /api/v1/deposits. تُخفى الحقول غير المحددة في أي من القائمتين في النموذج وقد تُرسل كقيم فارغة.

الحقول المطلوبة (القابلة للتحرير)

النوع: تحديد متعدد

يحدد حقول معلومات المستخدم التي تُعرض في نموذج الدفع بوصفها قابلة للتحرير. يمكن للمستخدم ملء هذه الحقول أو تعديلها مباشرةً في نموذج الدفع. بخلاف الحقول المطلوبة (للقراءة فقط)، لا يوجد شرط بأن تكون هذه الحقول مُعدة مسبقًا في ملف B2CORE الشخصي للمستخدم.

قاعدة الأولوية: إذا تم تحديد حقل في كل من الحقول المطلوبة (للقراءة فقط) والحقول المطلوبة (القابلة للتحرير)، فسيُعرض بوصفه للقراءة فقط. يكون إعداد القراءة فقط ذا الأولوية دائمًا.

سلوك البريد الإلكتروني: يُعرض البريد الإلكتروني دائمًا في نموذج الدفع ويُرسل دائمًا في startDepositUserInfo، بغض النظر عما إذا كان محددًا في أي من القائمتين. يتحكم الإعداد فقط في كيفية عرضه:

تحديد البريد الإلكتروني فيالسلوك
لا توجد أي قائمةيُعرض كحقل قابل للتحرير
الحقول المطلوبة (القابلة للتحرير)يُعرض كحقل قابل للتحرير
الحقول المطلوبة (للقراءة فقط)يُعرض كحقل للقراءة فقط (القيمة من ملف B2CORE الشخصي)
كلتا القائمتينيُعرض كحقل للقراءة فقط (تكون القراءة فقط ذات الأولوية)

الموعد النهائي الافتراضي للمزامنة

النوع: تحديد
الافتراضي: 4h

الحد الأقصى للمدة بعد إنشاء الإيداع التي يقوم خلالها B2CORE بالاستعلام الدوري عن حالة الإيداع. بعد هذا الموعد النهائي:

  • StatusSyncInProgress → يُنقل الإيداع إلى unexpected.
  • StatusSyncUnexpected → يُنقل الإيداع إلى unexpected.

تتطلب حالة unexpected تحقيقًا يدويًا من المسؤول عبر LifecycleService.

آمن للفشل عند البدء

النوع: منطقي (مُضمّن حاليًا بقيمة yes، ولا يوجد خيار)

يحدد ما إذا كان من الآمن وضع علامة failed (نهائية) على إيداع عندما يواجه طلب البدء خطأً غير متوقع.

  • yes — إذا أعاد PSP خطأً أثناء بدء الإيداع، وكان B2CORE واثقًا من أن الإيداع لم يُنشأ من جانب PSP (على سبيل المثال، لم يتلقَّ B2CORE عنوان URL لإعادة التوجيه مطلقًا)، يمكن نقل الإيداع بأمان إلى failed. لم يخسر العميل أي أموال.
  • no — حتى عند حدوث خطأ، يُنقل الإيداع إلى in_progress مع معرّف خارجي غير متحقق منه ويجري الاستعلام عنه، لأن PSP قد يكون أنشأ الإيداع رغم الخطأ.

حاليًا، القيمة دائمًا yes. الحالة المعتادة: من دون عنوان URL لإعادة التوجيه، لا يمكن للعميل إكمال صفحة الدفع الخاصة بـ PSP، لذلك لا يمكن أن ينجح الإيداع.

انتظار webhook قبل الاستعلام الدوري

النوع: منطقي (مُضمّن حاليًا بقيمة yes، ولا يوجد خيار)

يتحكم في ما إذا كان B2CORE ينتظر إشعار webhook قبل أن يبدأ الاستعلام الدوري عن GET /api/v1/deposits/{externalID}.

القيمةالسلوك
yesبعد بدء الإيداع، ينتظر B2CORE لمدة تصل إلى 5 دقائق وصول webhook قبل أن يبدأ الاستعلام الدوري. إذا لم يصل webhook خلال 5 دقائق، يتابع B2CORE الاستعلام الدوري القياسي.
noيبدأ B2CORE الاستعلام الدوري فورًا وفقًا لجدول التراجع القياسي.

المنطق: ترسل العديد من أنظمة PSP إشعار webhook بسرعة عند تغير حالة الإيداع. يقلل انتظار webhook قبل الاستعلام الدوري من عدد استدعاءات API غير الضرورية، مما يساعد على البقاء ضمن حدود المعدل. تضمن المهلة البالغة 5 دقائق استمرار التقدم حتى إذا تأخر webhook أو فُقد.

تدفق اختبار الإعداد

عندما ينقر مسؤول على Test Configuration في B2CORE:

1. B2CORE generates a one-time JWT signed with appSecret
2. B2CORE → POST /api/v1/configuration/test (with Bearer JWT + globalParams)
3. If response status = "available" → test result: "available"
4. If response status = "failed" → test result: "failed" (with error from PSP)
5. If unexpected error (5xx, timeout, and similar) → test result: "unexpected"

طريقة اختبار الإعداد هي الطريقة الوحيدة التي يُتوقع فيها أن تعيد أي مشكلة في بيانات الاعتماد ليس 401 Unauthorized، بل 200 OK مع جسم استجابة.

يتم عرض code وdescription لمسؤول B2CORE، لذا أعد بيانات واضحة وغير حساسة.

تصميم نظام Webhook

قناتا webhook

يدعم B2CORE قناتين لـ webhook لكل إيداع:

القناةالتسجيلالوصف
تلقائيةعبر notificationURL في طلب POST /api/v1/depositsنشطة دائمًا. ينشئ B2CORE عنوان URL ويمرره إلى PSP.
قابلة لإعداد المسؤوليحددها المسؤول في المكتب الخلفي لـ B2COREاختيارية. يمكن للمسؤول إعداد عنوان URL منفصل لـ webhook يرسل PSP الإشعارات إليه (على سبيل المثال، يتم تسجيله في لوحة تحكم PSP).

تتدفق كلتا القناتين إلى معالج webhook نفسه في B2CORE → مخزن driver_transit → مسار تحسين المستعلم.

Webhook كتحسين للاستعلام الدوري

ليس webhook مصدر الحقيقة. بل هو تحسين يقلل طلبات الاستعلام الدوري غير الضرورية.

PSP → B2CORE webhook handler → driver_transit (key-value store) → poller

آلية العمل:

  1. عند وصول webhook، يخزن B2CORE علامة في driver_transit مرتبطة بـ externalID.
  2. يتحقق المستعلم من driver_transit قبل إجراء استدعاء API:
    • إذا وُجدت علامة webhook لـ externalID، يستدعي B2CORE فورًا GET /api/v1/deposits/{externalID}.
    • إذا لم توجد علامة ومرت أقل من 5 دقائق، ينتظر B2CORE (راجع انتظار webhook قبل الاستعلام الدوري).
    • إذا لم توجد علامة ومرت أكثر من 5 دقائق، يتابع B2CORE الاستعلام الدوري القياسي.
  3. عندما يصل الإيداع إلى حالة نهائية (نجاح أو فشل)، يُحذف إدخال driver_transit.

حمولة webhook

حمولة webhook بسيطة (راجع callback الخاص بـ webhook ضمن POST /api/v1/deposits في مواصفات OpenAPI):

{
  "externalID": "550e8400-e29b-41d4-a716-446655440000",
  "status": "success"
}

تحتوي الحمولة على الحقول التالية:

  • externalID — يطابق UUID من طلب POST /api/v1/deposits.
  • status — إحدى القيم "success" أو "failed" أو "unprocessable".

يجب إرسال webhook فقط عندما ينتقل الإيداع إلى حالة نهائية.

تدفق بدء الإيداع

طلب البدء

يبدأ B2CORE إيداعًا باستدعاء POST /api/v1/deposits.

يتضمن الطلب حقل returnURL — وهو عنوان URL لصفحة واجهة B2CORE الأمامية لإعادة توجيه المستخدم إليها بعد التفاعل مع صفحة PSP. هذا ليس webhook — بل هو إعادة توجيه للمتصفح فقط.

لجميع التفاصيل الأخرى، راجع مواصفات OpenAPI.

تعيين نتيجة البدء

تُعيّن استجابة PSP إلى إجراء في B2CORE كما يلي:

استجابة PSPإجراء B2CORE
يعيد PSP عنوان URL لإعادة التوجيهالانتقال إلى in_progress
2xx مع مخالفة للمواصفات (على سبيل المثال، عدم وجود عنوان URL لإعادة التوجيه)الانتقال إلى failed
HTTP 4xx / 5xx / انتهاء المهلة / خطأ في الشبكةالانتقال إلى failed

تؤدي جميع سيناريوهات الفشل إلى failed (وليس unexpected) لأن آمن للفشل عند البدء هو yes (راجع آمن للفشل عند البدء): من دون عنوان URL صالح لإعادة التوجيه، لا يمكن للمستخدم النهائي التفاعل مع صفحة الدفع الخاصة بـ PSP، لذلك لا يمكن فقدان أي أموال.

تدفق إعادة التوجيه

عند بدء ناجح، يتلقى B2CORE عنوان URL لإعادة التوجيه ويرسل المستخدم النهائي إلى صفحة الدفع الخاصة بـ PSP:

sequenceDiagram
    participant B as B2CORE
    participant P as PSP
    participant U as End user

    B->>P: POST /api/v1/deposits
    P-->>B: 200 OK<br/>action.type: "redirect"<br/>action.redirect.url: "..."
    B->>U: Redirect end user to PSP payment page
    U->>P: Open PSP payment page
    U->>P: Complete payment
    P-->>U: Redirect to returnURL
    U->>B: Land on B2CORE "in progress" page
  • يعيد returnURL المستخدم إلى صفحة واجهة أمامية في B2CORE تشير إلى أن الإيداع قيد المعالجة.
  • بعد البدء، يبدأ B2CORE تدفق الاستعلام الدوري وwebhook (راجع الاستعلام الدوري ومزامنة الحالة).
  • حاليًا، "redirect" هو نوع الإجراء الوحيد المدعوم.

الاستعلام الدوري ومزامنة الحالة

جدول التراجع للاستعلام الدوري

يستخدم B2CORE تراجعًا تدريجيًا للاستعلام الدوري عن GET /api/v1/deposits/{externalID}:

الوقت منذ بدء الإيداعفترة الاستعلام
0–15 دقيقةكل دقيقة واحدة
15–60 دقيقةكل 3 دقائق
1–3 ساعاتكل 5 دقائق
3–5 ساعاتكل 10 دقائق
5+ ساعاتكل 15 دقيقة

معالجة الموعد النهائي

الموعد النهائي الافتراضي: 4 ساعات بعد إنشاء الإيداع (قابل للإعداد، راجع الموعد النهائي الافتراضي للمزامنة).

عند تجاوز الموعد النهائي، تتم معالجة الحالات الوسيطة كما يلي:

نتيجة الاستعلام الأخيرةإجراء B2CORE
inProgressالانتقال إلى unexpected
خطأ في الشبكة، أو 5xx، أو خطأ في التحليل، وما شابهالانتقال إلى unexpected

توقف حالة unexpected الاستعلام الدوري التلقائي وتتطلب إجراءً يدويًا من المسؤول عبر LifecycleService في B2CORE.

منطق انتظار webhook

عندما تكون قيمة انتظار webhook قبل الاستعلام الدوري هي yes (القيمة الافتراضية الحالية، راجع انتظار webhook قبل الاستعلام الدوري):

flowchart TD
    A["t=0min: deposit created, redirect URL returned<br/>Poller scheduled but WAITS for webhook"] --> B{Webhook received<br/>before t=5min?}
    B -- yes --> C["Immediately poll<br/>GET /api/v1/deposits/{externalID}"]
    B -- "no (t=5min elapsed)" --> D["Begin standard polling<br/>(1-minute intervals initially)"]
    C --> E[Continue with standard<br/>polling backoff]
    D --> E
    E --> F[Continue until terminal status<br/>or deadline]

تعيين نتائج الاستعلام الدوري

تُعيّن كل نتيجة استعلام من GET /api/v1/deposits/{externalID} إلى إجراء داخلي في B2CORE:

حالة استجابة PSPإجراء B2CORE
"inProgress" + لم يتم تجاوز الموعد النهائيمتابعة الاستعلام الدوري (إعادة المحاولة)
"inProgress" + تم تجاوز الموعد النهائيالانتقال إلى unexpected
"success"الانتقال إلى success، وإيقاف الاستعلام الدوري. حفظ finalAmount وfinalCurrencyCode
"failed"الانتقال إلى failed، وإيقاف الاستعلام الدوري. حفظ reason
"unprocessable"الانتقال إلى unexpected، وإيقاف الاستعلام الدوري. حفظ reason. يتطلب تحقيقًا من المسؤول
HTTP 5xx / انتهاء المهلة / خطأ في التحليلالتعامل معها باعتبارها محاولة استعلام unexpected. متابعة الاستعلام الدوري إذا لم يتم تجاوز الموعد النهائي
HTTP 404 مع X-Safe-To-Fail-After-Secondsمتابعة الاستعلام الدوري. بعد الوقت المحدد بالإضافة إلى هامش أمان (5 دقائق)، إذا بقيت النتيجة 404، الانتقال إلى failed بسبب "deposit redirect URL is expired"
HTTP 404 من دون الترويسةمتابعة الاستعلام الدوري. انتظار ظهور الإيداع من جانب PSP أو تجاوز الموعد النهائي للمزامنة

دورة حياة حالة الإيداع

يصف هذا القسم حالات إيداع B2CORE. لتعيين حالات استجابة PSP إلى حالات B2CORE، راجع تعيين نتيجة البدء وتعيين نتائج الاستعلام الدوري.

مخطط الحالة الكامل

flowchart TD
    created[created]
    post["POST /api/v1/deposits"]
    failed1[failed]
    inProgress1[in_progress]
    unexpected1[unexpected]
    poll["GET /api/v1/deposits/{externalID}<br/>(polling)"]
    retryIP["(in_progress)<br/>(retry)"]
    retryUX["(unexpected)<br/>(retry)"]
    success[success]
    failed2[failed]
    unprocessable["(unprocessable)<br/>(stop polling)"]
    inProgress2[in_progress]

    created --> post
    post --> failed1
    post --> inProgress1

    inProgress1 --> poll
    poll --> retryIP
    poll --> retryUX
    poll --> success
    poll --> failed2
    poll --> unprocessable

    retryIP --> inProgress2
    retryUX --> inProgress2
    unprocessable --> unexpected1
    unexpected1 -->|Manual recovery| inProgress2

الاسترداد من حالة unexpected

يمكن للمسؤول تنفيذ هذه الانتقالات اليدوية عبر LifecycleService:

الانتقالمتى يُستخدم
unexpectedin_progressإعادة محاولة الاستعلام الدوري (على سبيل المثال، بعد حل انقطاع PSP)
unexpectedsuccessفقط إذا كانت آخر محاولة استعلام هي unprocessable وأكد المسؤول النجاح
unexpectedfailedيؤكد المسؤول فشل الإيداع

تعريفات حالات الإيداع

يعرّف الجدول التالي كل حالة إيداع في B2CORE:

الحالةالمعنى التجاري
in_progressالإيداع قيد المعالجة. يشمل جميع الحالات الوسيطة: تحويل بنكي معلّق، تحقق 3DS قيد التقدم، انتظار مراجعة يدوية من جانب PSP، تفاعل العميل مع صفحة الدفع الخاصة بـ PSP، وما شابه. هذه حالة غير نهائية — يواصل B2CORE الاستعلام الدوري.
successتلقى الوسيط أموال العميل. أكد PSP إضافة الأموال. يعكس الحقلان finalAmount وfinalCurrencyCode المبلغ والعملة الفعليين المستلمين، وقد يختلفان عن الطلب الأولي بسبب الرسوم أو التحويل.
failedلم ينجح الإيداع. لم يخسر العميل أي أموال، ولم يتلقَّ الوسيط أي أموال. أمثلة: رفض البطاقة، أو رفض التحويل البنكي، أو إلغاء المستخدم في صفحة PSP، أو انتهاء صلاحية رابط إعادة التوجيه.
unexpectedلم يمكن حل الإيداع تلقائيًا ويتطلب إجراءً يدويًا من المسؤول عبر B2CORE (راجع الاسترداد من حالة unexpected)؛ تم إيقاف الاستعلام الدوري التلقائي. تُدخل هذه الحالة عند انتهاء الموعد النهائي أثناء in_progress، أو عندما يبلغ PSP عن unprocessable.

توقيت إنشاء الإيداع

يتبع PSP أحد نمطين لإنشاء الإيداع:

النمطالسلوكتأثير الاستعلام الدوري
إنشاء فوريينشئ PSP سجل الإيداع عند POST /api/v1/deposits.يعيد GET /api/v1/deposits/{externalID} نتيجة مباشرةً بعد البدء.
إنشاء مؤجلينشئ PSP سجل الإيداع فقط بعد أن يكمل المستخدم النهائي صفحة الدفع الخاصة بـ PSP.يعيد GET /api/v1/deposits/{externalID} القيمة 404 Not Found إلى أن يكمل المستخدم الصفحة.

بالنسبة إلى الإنشاء المؤجل، يُفترض أن يعيد PSP الترويسة X-Safe-To-Fail-After-Seconds مع استجابة 404. تخبر هذه الترويسة B2CORE بالمدة التي يكون فيها رابط إعادة التوجيه صالحًا. بعد redirect_time + header_value + safety_margin، إذا ظل الإيداع 404، يضع B2CORE علامة failed عليه بسبب "deposit redirect URL is expired".

إذا كانت الترويسة غائبة، يواصل B2CORE الاستعلام الدوري إلى أن يظهر الإيداع أو يتم تجاوز الموعد النهائي للمزامنة (4 ساعات افتراضيًا)، وعندها ينتقل الإيداع إلى unexpected.

المتطلبات السلوكية

التتبع الموزع

تتضمن جميع طلبات HTTP من B2CORE إلى PSP ترويسات تتبع قياسية وفقًا لمواصفات W3C Trace Context:

  • traceparent — يحتوي على معرّف التتبع، ومعرّف الامتداد الأب، وعلامات التتبع.
  • tracestate — بيانات تتبع خاصة بالمورّد.

ينبغي على عمليات تنفيذ PSP نشر هذه الترويسات إلى خدماتها اللاحقة لضمان إمكانية المراقبة الشاملة من طرف إلى طرف.

قفل العملة في صفحة الدفع الخاصة بـ PSP

عندما تتضمن استجابة بدء الإيداع إعادة توجيه إلى صفحة دفع PSP:

  • يجب ألا تسمح صفحة PSP للمستخدم النهائي بتغيير currencyCode إلى أي عملة مماثلة أو مكافئة أو بديلة.
  • يجب أن تطابق العملة المعروضة في صفحة PSP تمامًا ما تم إرساله في طلب بدء الإيداع.
  • إذا كانت صفحة PSP تسمح باختيار العملة، فيجب أن تكون العملة محددة مسبقًا ومقفلة.

توصية بقائمة السماح لعناوين IP

رغم أن ذلك ليس مطلوبًا في مواصفات API، فإنه يوصى بشدة بأن تضبط عمليات تنفيذ PSP قائمة سماح لعناوين IP من جانبها. يوفر ذلك طبقة أمان إضافية تتجاوز مصادقة JWT، إذ يقصر الوصول إلى API على عناوين IP المعروفة الخاصة بـ B2CORE.

لإتاحة برنامج التشغيل Canonical في بيئتك، يرجى التواصل مع مدير حسابك. يرجى تحديد الكيفية الدقيقة والأغراض التي تخطط لاستخدام برنامج التشغيل Canonical من أجلها، حتى نتمكن من ترتيب الوصول وفقًا لذلك.

آخر تحديث في

في هذه الصفحة