Nordlet

← الأساسيات / حزم تطوير البرمجيات (SDK)

استيراد الحسابات المصرفية والمدفوعات

كشوفات camt.053، ملفات CSV من Stripe، تسويات مدفوعات مزودي خدمات الدفع (PSP)، وتدفقات JSON المخصصة.

تصل جميع العمليات المستوردة بصفتها معاملات مصرفية في حساب مصرفي (bank/accounts/create). تحمي المعاملات معرف externalId، مما يجعله آمناً لإعادة استيراد نفس الملف - حيث يتم تخطي الصفوف التي يتطابق فيها الزوج (bankAccountId, externalId) مسبقاً والإبلاغ عنها في عداد التخطي (skipped). تبدأ المعاملات المستوردة بالحالة new (جديدة) ولا يتم ترحيلها إلى دفتر الأستاذ (ledger) إلا عند مطابقتها (bank/transactions/match، مع استخدام bank/transactions/suggest-matches لاقتراح المرشحين للمطابقة).

يعرض تطبيق الويب نفس عمليات الاستيراد ضمن البنك ← استيراد ملف (تحميل الملفات، وتحديد القوالب).

يمكن التراجع عن المطابقة الخاطئة باستخدام bank/transactions/unmatch (خيار إلغاء المطابقة في البنك ← المعاملات). لا يتم تعديل أو حذف القيود المرحلة إطلاقاً: فالدفعة المطابقة لفاتورة، أو السطر الذي مرحله قالب الاستيراد إلى حساب ما، يتلقى معاملة يومية عكسية (reversing journal transaction) تتضمن كل قيد في الجانب المعاكس، ومؤرخة بتاريخ date (الافتراضي: اليوم، ولا يجوز أن يسبق تاريخ الترحيل الأصلي أبداً). يعود المبلغ المدفوع للفاتورة وحالة الدفع إلى الوراء بمقدار قيمة ذلك السطر المصرفي. أما السطر المرتبط بتسوية مقدم خدمة الدفع، فيتم إلغاء ربطه فقط لأن قيد التسوية ينتمي إلى دفعة التسوية (batch). يعود السطر إلى الحالة new ويمكن مطابقتها مرة أخرى. يجب أن يقع تاريخ العكس (reversal date) ضمن فترة محاسبية مفتوحة.

قوالب الاستيراد

يحدد قالب الاستيراد مصدراً للبيانات، ويسرد الحقول التي يوفرها المصدر، ويربط الحقول المالية بحسابات دفتر الأستاذ. تتم إدارة القوالب ضمن البنك ← قوالب الاستيراد وعبر نقاط النهاية bank/import-templates/create|update|delete|get|list.

POST /v1/bank/import-templates/create
{
  "name": "Stripe payments export",
  "type": "stripe",
  "fields": [
    { "name": "id" },
    { "name": "Created date (UTC)" },
    { "name": "Amount" },
    { "name": "Fee", "accountCode": "6800" },
    { "name": "Amount Refunded" }
  ],
  "metaFields": ["order_id"]
}
  • القيمة type هي أحد الأنواع التالية: stripe أو iso20022 أو bank_connection أو revolut.
  • يحتوي كل حقل على name (اسم) وaccountCode (رمز حساب) اختياري. الحقول المالية وحدها هي التي تقبل تعيين حساب: حقول Stripe مثل Amount وFee وAmount Refunded؛ وحقل camt.053 مثل Ntry/Amt؛ وتدفق البيانات المصرفي مثل transaction_amount.amount. يجب أن يكون الحساب موجوداً في شجرة الحسابات (يمكن إنشاؤه عبر ledger/accounts/create).
  • يمكن تخطي حقل fields؛ وفي هذه الحالة يتم الرجوع تلقائياً إلى قائمة الحقول القياسية لهذا النوع: أسماء الأعمدة في ملف المدفوعات ← التصدير من Stripe (باستثناء أعمدة Card … الـ 19 التي يتركها النموذج غير محددة أيضاً بشكل افتراضي)، أو عناصر camt.053 التي يحملها كل كشف (Stmt/Id، Stmt/Acct/Id/IBAN، Stmt/Bal/…، Ntry/Amt، Ntry/CdtDbtInd، Ntry/Sts، Ntry/BookgDt)، أو السمات التي يعيدها تدفق الخدمات المصرفية المفتوحة PSD2 لكل معاملة. يمكنك إضافة أو حذف إدخالات لتتناسب مع ملفك: يقرأ المستورد أيضاً عناصر camt.053 الاختيارية وهي Ntry/ValDt، Ntry/NtryRef، Ntry/AcctSvcrRef، Ntry/AddtlNtryInf، TxDtls/Refs/EndToEndId، TxDtls/Refs/TxId، TxDtls/RltdPties/Dbtr/Nm، TxDtls/RltdPties/DbtrAcct/Id/IBAN، TxDtls/RltdPties/Cdtr/Nm، TxDtls/RltdPties/CdtrAcct/Id/IBAN، TxDtls/RmtInf/Ustrd، وTxDtls/AddtlTxInf.
  • يمكن لحقل البريد الإلكتروني للعميل في Stripe (Customer Email) أن يحمل القيمة "createPartner": true. في هذه الحالة، ينشئ الاستيراد عميلاً (شريكاً من نوع فرد، مصنفاً كعميل) لكل بريد إلكتروني في الملف لا يملكه أي شريك حالي، مستخدماً وصف العميل Customer Description كاسم له (أو البريد الإلكتروني في حال كان الوصف فارغاً) وأعمدة عنوان البطاقة Card Address … كعنوان في حال تضمن الملف ذلك. تتم مطابقة الشركاء الحاليين بواسطة البريد الإلكتروني مع تجاهل حالة الأحرف (case-insensitively). يعيد الرد العدد الإجمالي في customersCreated.
  • تسرد حقول metaFields (خاصة بـ Stripe فقط) مفاتيح البيانات الوصفية (metadata) التي تحملها مدفوعاتك. تصدر Stripe كل مفتاح كعمود بصيغة <key> (metadata)؛ وهذه القائمة حرة الشكل ويمكن أن تكون طويلة.
  • حقل invoiceItemId (خاص بـ Stripe فقط، اختياري) هو عنصر من كتالوج الصنف. عند تعيينه، تشير كل فاتورة وسطر إشعار دائن ينشئه الاستيراد إلى هذا الصنف (ترحيله، ومعدل ضريبة القيمة المضافة الخاص به عندما يكون حقل invoiceVatRatePercent فارغاً)؛ بينما يستمر جلب نص السطر من المعاملة نفسها.
  • يحدد حقل companyMetaField (خاص بـ Stripe فقط) أحد تلك المفاتيح ليكون بمثابة مؤشر للشركات. عندما يحمل الشحن قيمة true أو 1 أو yes أو company أو business أو b2b في هذا العمود، فإن العميل المنشأ له يُعامل كشريك من نوع شركة بدلاً من فرد.
  • يحدد حقل invoiceMetaField (خاص بـ Stripe فقط) أحد تلك المفاتيح، وليكن مثلاً رقم الطلب، بينما يحدد حقل invoiceVatRatePercent معدل ضريبة القيمة المضافة للفواتير المنشأة منه. عند الاستيراد، يتم تجميع كل صف دفع واسترداد بناءً على قيمة هذا المفتاح:
    • القيمة التي تتطابق مع فاتورة مبيعات موجودة - أي أمر مبيعات يكون مرجعه الخارجي externalRef مساوياً لتلك القيمة عبر (ecommerce/orders/create، لأي قناة) أو فاتورة يكون رقمها الكامل fullNumber مساوياً لتلك القيمة - تقوم بربط المجموعة بتلك الفاتورة؛
    • القيمة التي ليس لها فاتورة تنشئ فاتورة جديدة: الشريك يُستمد من Customer Email (يتم إنشاؤه عند عدم وجوده، تماماً كما هو الحال في createPartner)، مع سطر واحد لكل عملية دفع (باستخدام ملخص عناصر الدفع Checkout Line Item Summary أو الوصف Description كنص، ومبلغ الدفع كجعر شامل للضريبة بالنسبة المئوية في invoiceVatRatePercent)، وتاريخ الإصدار = تاريخ الدفع الأول، ومعالجة ضريبة القيمة المضافة تُستمد من الشركة وبلد البطاقة. يتم إصدار الفاتورة وترحيلها دفعة واحدة، ويتم تسجيل أمر مبيعات بقناة stripe وتلك القيمة كمرجع خارجي externalRef لكي تقوم عمليات الاستيراد اللاحقة بالربط بدلاً من الإنشاء؛
    • بعد ذلك، تتم مطابقة كل عملية دفع في المجموعة مع الفاتورة كعملية تحصيل (مع ترحيل التحصيل)؛ وكل عملية استرداد تنشئ إشعاراً داحناً صادراً مقابل الفاتورة بالمبلغ المسترد وتطابق الاسترداد معها.
  • تعود الأعداد في الاستجابة تحت مسميات invoicesCreated وinvoicesLinked وcreditNotesCreated وpaymentsMatched؛ أما المجموعات التي تعذر معالجتها (مثل غياب البريد الإلكتروني للعميل، أو اختلاف العملات، أو فاتورة مرتبطة لا تزال في حالة مسودة أو مدفوعة بالكامل مسبقاً) فيتم إدراجها في warnings (التحذيرات) وتُترك كمعاملات مصرفية بالحالة new. احذر من تعيين الحقل Amount لحساب في دفتر الأستاذ في نفس القالب: فالدفعات المطابقة لفاتورة لا تُرحل مرة أخرى، بينما الدفعات غير المطابقة سيتم ترحيلها.
  • أسماء القوالب فريدة لكل شركة.
  • تحمل قوالب camt.053 والاتصالات المصرفية نفس الخيارات، مقروءة من الكشف بدلاً من أعمدة Stripe:
    • إنشاء الشركاء المفقودين (Create missing partners): يؤدي تفعيل createPartner في صف اسم المدين (TxDtls/RltdPties/Dbtr/Nm، أو تدفق البيانات debtor.name) إلى إنشاء عميل لكل دافع مجهول للأموال الواردة؛ وفي صف اسم الدائن (TxDtls/RltdPties/Cdtr/Nm، أو تدفق البيانات creditor.name) إلى إنشاء مورد لكل مستلم مجهول للأموال الصادرة. يتم التعرف على الشركاء بواسطة رقم الحساب المصرفي الدولي IBAN (المخزن في partner_bank_accounts)، ثم بواسطة الاسم المطابق تماماً؛ ويُعتبر الشريك الجديد شركة إذا حمل الاسم شكلاً قانونياً (مثل UAB، MB، SIA، GmbH، Ltd، …)، وإلا فيُعتبر فرداً. تعود الأعداد في الاستجابة على هيئة customersCreated (استيراد الملفات) أو partnersCreated (مزامنة تدفق البيانات).
    • ربط الفواتير عن طريق المرجع (Link invoices by reference): عندما يتم تعيين invoiceMetaField إلى صف الحوالة أو المرجع (TxDtls/RmtInf/Ustrd، TxDtls/RmtInf/Strd/CdtrRefInf/Ref، TxDtls/Refs/EndToEndId؛ أو تدفق البيانات remittance_information، reference_number)، فإن ذلك يطابق كل سطر مصرفي جديد يحتوي مرجعه أو وصفه على رقم فاتورة مبيعات صادرة مفتوحة (أموال واردة) أو فاتورة شراء مسجلة (أموال صادرة)، ويقوم بترحيل الدفعة. عندما يكون رقم الIBAN الخاص بالدافع مخزناً لدى شريك ما، أو عندما يساوي اسم الدافع اسم شريك أو رمزه، يجب أن ينتمي الفاتورة لذلك الشريك. لا يتم ربط الدفعة الواردة من دافع مجهول إلا عندما تساوي الرصيد المتبقي للفاتورة ويحمل رقم الفاتورة بادئة سلسلته، بحيث لا يُتخذ الرقم المجرد مثل المبلغ كمرجع أبداً. لا يتم ربط الدفعة التي تتجاوز الرصيد المتبقي إطلاقاً. تبقى السطور التي تفشل في هذه الفحوصات في حالة "جديدة" للمطابقة اليدوية ويتم إدراجها في التحذيرات. وعند تفعيل advanceInvoices: true، فإن الدفعة الواردة غير المطابقة من شريك معروف تنشئ فاتورة دفع مقدم صادرة (من نوع advance) للمبلغ بالمعدل المئوي invoiceVatRatePercent أو معدل invoiceItemId وتطابق الدفعة معها؛ ويجب أن يكون الشريك معروفاً، لذا يجب تفعيل صف المدين أيضاً.
    • قواعد الترحيل حسب رمز المعاملة المصرفية (Posting rules by transaction code): بالإضافة إلى Ntry/Amt / transaction_amount.amount، تحتوي قائمة الحقول على صفوف قواعد مثل Ntry/BkTxCd=CHRG، =INTR، =TAXE، وNtry/CdtDbtInd=DBIT، =CRDT (تدفق البيانات: bank_transaction_code=…، credit_debit_indicator=…). يُرحل السطر إلى حساب القاعدة الأولى التي تتطابق معه: عائلة رمز المعاملة المصرفية أولاً، ثم اتجاهها، ثم صف المبلغ العادي. لا يتم التحقق من صفوف القواعد ضد الملف.
    • شريك الرسوم المصرفية (Bank charges partner): يؤدي تفعيل createPartner في صف القاعدة …=CHRG إلى إنشاء مورد يُسمى باسم البنك (كشف Stmt/Acct/Svcr/FinInstnId/Nm، أو بنك الاتصال، أو اسم الحساب المصرفي في دفتر الأستاذ) ويقيد كل رسوم مع ذلك الشريك.
    • يتم اختيار قوالب الاتصال المصرفي لكل حساب تدفق عبر bank/feeds/accounts/configure (قسم البنك ← الاتصالات في التطبيق)، والذي يحدد أيضاً جدول المزامنة syncSchedule (manual، daily، weekly، monthly): حيث تقوم واجهة برمجة التطبيقات بمزامنة الحسابات ذات الجدول الزمني تلقائياً بمجرد انقضاء فترتها. تُطبق القوالب عند كل عملية مزامنة bank/feeds/sync؛ وتبلغ استجابة المزامنة بعد ذلك عن الأعداد التالية: posted، وpartnersCreated، وinvoicesLinked، وinvoicesCreated، وpaymentsMatched، وwarnings.

مرر templateId إلى bank/statements/import بدلاً من format: حيث يحدد نوع القالب المحلل المطلوب، ويجب أن يحتوي الملف على كل حقل مدرج في القالب - أي ملف يفتقر لأي منها يتم رفضه بالرمز HTTP 422 مع ذكر أسماء الأعمدة أو العناصر المفقودة. لا يُشترط وجود حقول البيانات الوصفية. تصف قوالب الاتصال المصرفي تدفق PSD2 المباشر ولا يمكن استخدامها لاستيراد الملفات.

يقرأ قالب ISO 20022 أيضاً ملفات MT940: الملف الذي يبدأ بـ {1: أو :20: (أو يتم إرساله مع القيمة "format": "mt940") يتم تحليله كملف MT940 وتُطبق قواعد مطابقة المراجع والترحيل الخاصة بالقالب على سطوره. يتم تخطي التحقق من العناصر في ملفات MT940، ولا تُطبق قواعد Ntry/BkTxCd=… أبداً على سطور MT940 نظراً لعدم احتواء ملفات MT940 على رموز معاملات مصرفية خاصة بمعيار ISO 20022؛ وعوضاً عن ذلك، استخدم قواعد Ntry/CdtDbtInd=….

يحمل الحساب المصرفي عملة واحدة. يُرفض الكشف الوارد بعملة أخرى بالرمز HTTP 422 (في ملف camt.053 الذي يحتوي على كشوفات بعمولات متعددة لنفس الـ IBAN، يتم استيراد الكشف المتوافق مع عملة الحساب فقط)، وكذلك الحال بالنسبة للسطر المرسل إلى نقاط النهاية bank/transactions/import بعملة تخالف عملة الحساب.

تُرحل كل حركة ناتجة عن حقل يحتوي على accountCode وقت الاستيراد كمعاملة يومية واحدة: فالأموال الواردة تجعل حساب البنك في دفتر الأستاذ مديناً والحساب المعين دائناً؛ والأموال الصادرة تجعل الحساب المعين مديناً وحساب البنك في دفتر الأستاذ دائناً. يتم تحويل المبالغ إلى العملة الأساسية في تاريخ الحركة. تصبح المعاملة المصرفية بعد ذلك "مطابقة" (matched) لتلك المعاملة اليومية (بحيث يكون matchedDocumentType = journal_transaction) ولم تعد مطروحة للمطابقة مع الفواتير. تبلغ الاستجابة عن العدد في posted. أما الحركات الناتجة عن الحقول غير المعينة فتبقى في حالة new وتتم مطابقتها مع الفواتير كالسابق - على سبيل المثال، قم بتعيين الحقل Fee لحساب مصروفات رسوم مزود خدمة الدفع واترك حقل Amount بدون تعيين لكي تظل الدفعات مطابقة لفواتير المبيعات.

POST /v1/bank/statements/import
{
  "bankAccountId": "…",
  "templateId": "…",
  "content": "id,Created date (UTC),Amount,…"
}

معيار ISO 20022 camt.053 (فتح الخدمات المصرفية عبر XML)

تتيح لك البنوك اللتوانية (Swedbank، SEB، Luminor، Šiaulių bankas، …) تنزيل كشوفات الحسابات بصيغة ISO 20022 camt.053 XML من خدماتها المصرفية عبر الإنترنت - وعادة ما يكون ذلك تحت خيار تصدير/تنزيل الكشوفات، بالصيغة "ISO XML" أو "camt.053". يتم إرجاع نفس التنسيق بواسطة واجهات برمجة تطبيقات معلومات الحساب PSD2.

POST /v1/bank/statements/import
{
  "bankAccountId": "…",
  "format": "camt053",
  "content": "<?xml version=\"1.0\"…>…"
}
  • قد يحتوي الملف على عدة كشوفات؛ يجب أن يتطابق رقم الـ IBAN لكل كشف مع الـ IBAN الخاص بالحساب المصرفي (الكشوفات التي لا تحتوي على IBAN، أو الحسابات التي لا تملك واحداً، يتم قبولها كما هي).
  • تتحول مراجع القيود (AcctSvcrRef/NtryRef، مع العودة إلى استخدام تجزئة المحتوى كبديل) إلى معرف externalId.
  • تعكس الاستجابة البيانات الوصفية لكل كشف: معرف الكشف، والفترة، والأرصدة الافتتاحية/الختامية، وعدد المعاملات.
  • يتم استخراج اسم الطرف المقابل، ورقم الـ IBAN، وغرض الدفع لكل إدخال لأغراض المطابقة.

تُصدر المدفوعات في الاتجاه المعاكس بصيغة pain.001 عبر bank/payments/export.

ملفات Revolut Business CSV

قم بتنزيل كشف المعاملات الخاص بحساب Revolut Business بصيغة CSV واستورده باستخدام القالب المدمج Revolut Business (القيمة templateId: "builtin-revolut"). تمتلك كل شركة هذا القالب دون الحاجة لإنشائه: يقوم أمر bank/import-templates/list-builtin بإدراجه، وbank/import-templates/get بإرجاعه، بينما يرفض أمرا bank/import-templates/update وbank/import-templates/delete التعامل معه مرجعين الرمز HTTP 400. يظهر هذا القالب في التطبيق أولاً ضمن البنك ← قوالب الاستيراد؛ وعند فتحه تظهر إعداداته، ويؤدي حفظه إلى إنشاء قالب شركة خاص بك يمكنك تعديله.

POST /v1/bank/statements/import
{
  "bankAccountId": "…",
  "templateId": "builtin-revolut",
  "content": "Date started (UTC),Date completed (UTC),ID,Type,State,…"
}
  • يتم استيراد الصفوف التي تكون فيها حالة State مساوية لـ COMPLETED فقط. أما الصفوف الأخرى (مثل PENDOUNG أو PENDING) فيتم استبعادها وعدها في التحذيرات warnings؛ ليتم استيرادها لاحقاً عند استيراد ملف تصبح فيه مكتملة.
  • يتحول كل صف إلى معاملة مصرفية بالتاريخ المستمد من Date completed (UTC)، والمبلغ من Total amount، والعملة من Payment currency، ومعرف ID كـ externalId، وDescription كالوصف.
  • الطرف المقابل للأموال الصادرة هو Beneficiary name وBeneficiary IBAN؛ وفي حالة المدفوعات بالبطاقة بدون مستفيد، يكون التاجر هو الوارد في حقل Description. بينما الطرف المقابل للأموال الواردة هو Sender name وSender account.
  • يتم تجميع الصفوف حسب الحساب والعملة. يجب أن يتطابق رقم الحساب الدولي International account number مع الـ IBAN الخاص بالحساب المصرفي، ويتم استيراد الصفوف التي تحمل عملة الحساب المصرفي فقط.
  • يتحقق المستورد لكل صف من أن رصيد الصف السابق مضافاً إليه Total amount يساوي الحقل Balance، ويقوم بإدراج أي صف لا يحقق ذلك في التحذيرات warnings.
  • يجب أن يحتوي الملف على الأعمدة التالية: Date completed (UTC)، وID، وType، وState، وDescription، وPayment currency، وTotal amount، وReference، وSender name، وBeneficiary name.

عند كل عملية استيراد، يقوم القالب المدمج بما يلي:

  • إنشاء عميل لكل مرسل مجهول للأموال الواردة، ومورد لكل مستفيد مجهول أو تاجر بطاقات للأموال الصادرة، تماماً كما هو موضح في قسم إنشاء الشركاء المفقودين أعلاه؛

  • مطابقة كل صف يحتوي مرجعه Reference أو وصفه Description على رقم فاتورة مبيعات أو شراء مفتوحة، وترحيل الدفعة وفقاً لضوابط قسم ربط الفواتير عن طريق المرجع أعلاه؛

  • ترحيل الصفوف التي لم تطابقها أي فاتورة بناءً على نوعها Type، إلى حساب قاعدة الترحيل المناسبة:

    Type قاعدة الترحيل (Posting rule) الحساب الافتراضي شجرة الحسابات الرومانية عملية الترحيل
    FEE bank.fees 6800 627 جعل حساب القاعدة مديناً، وحساب البنك في دفتر الأستاذ دائناً؛ والشريك: مورد مسجى باسم الحساب المصرفي
    CARD_PAYMENT bank.cardPayments 6209 628 جعل حساب القاعدة مديناً، وحساب البنك في دفتر الأستاذ دائناً، بدون ضريبة قِيمة مضافة
    TOPUP bank.topUps 3010 1012 جعل حساب البنك في دفتر الأستاذ مديناً، وحساب القاعدة دائناً

    تبقى صفوف الأنواع الأخرى، مثل TRANSFER، بحالة new للمطابقة.

يمكنك تغيير الحسابات باستخدام ledger/posting-rules/update؛ وسوف يست استخدم القالب المدمج الحسابات الجديدة بدءاً من الاستيراد التالي. لا يمكن إيقاف تشغيل قاعدة الترحيل: لاستيراد مدفوعات البطاقات أو عمليات الشحن دون ترحيلها، أنشئ قالب شركة من نوع revolut بدون صفوف النوع Type=CARD_PAYMENT أو Type=TOPUP واستخدمه في الاستيراد. عملية دفع البطاقة المرحلة بهذه الطريقة لا تتم مطابقتها مع فاتورة المورد إذا تم تسجيل تلك الفاتورة لاحقاً؛ لذا قم بترحيل أحد الإجراءين فقط وليس كلييهما.

يستخدم قالب الشركة من نوع revolut نفس الأعمدة ويمكنه ترحيل الصفوف حسب النوع باستخدام صفوف القواعد Type=FEE وType=CARD_PAYMENT وType=TRANSFER وType=TOPUP. أما الاستيراد باستخدام الخيار "format": "revolut-csv" بدون تحديد قالب فيقوم باستيراد الصفوف دون أي من هذه الخطوات.

ملفات Stripe CSV

قم بالتصدير من لوحة تحكم Stripe - حيث يعمل أي من التقرير التاليين:

  • التقارير ← الرصيد ← التغيير المفصل للرصيد من النشاط (Reports → Balance → Itemized balance change from activity) (موصى به): الأعمدة هي balance_transaction_id, created_utc, currency, gross, fee, net, reporting_category, description.
  • المدفوعات ← التصدير (Payments → Export): الأعمدة هي id, Created (UTC), Amount, Fee, Currency, Description, Customer Description.
POST /v1/bank/statements/import
{
  "bankAccountId": "…",
  "format": "stripe-csv",
  "content": "balance_transaction_id,created_utc,currency,gross,fee,net,…"
}

أنشئ حساباً مصرفياً مخصصاً لـ Stripe (مثلاً باسم "Stripe"، وحساب الأستاذ العام 2710 أو حساباً فرعياً خاصاً به) - حيث يتصرف رصيد Stripe تماماً مثل الحساب المصرفي: تتدفق الشحنات للداخل، وتُخصم الرسوم، وتعمل المدفوعات على تحويل الرصيد إلى حسابك المصرفي الحقيقي.

سلوك الاستيراد:

  • تتحول كل معاملة رصيد إلى معاملة مصرفية واحدة للمبلغ الإجمالي (gross) (حيث externalId = معرف معاملة الرصيد).
  • تتحول الرسوم (fee) غير الصفرية إلى معاملة ثانية بعلامة معاكسة (بحيث externalId = <id>:fee، والطرف المقابل هو "Stripe") - لكي يمكن مطابقة/ترحيل الرسوم كمصروفات بشكل منفصل عن الإيرادات. أما الرسوم المُستردة على عمليات الاسترداد فتأتي كمبالغ موجبة.
  • تُستورد صفوف عمليات الدفع (Payout) كمعاملات سالبة منفردة؛ قم بمطابقتها مقابل المعاملة الواردة المقابلة في كشف حسابك المصرفي الحقيقي.
  • تُتخطي الصفوف ذات المبلغ الصفري؛ ويُستمد التاريخ من الحقل created_utc (بتوقيت UTC).
  • تُتخطي صفوف تصدير المدفوعات التي لم تحرك أموالاً: أي الحالات التي يكون فيها Captured = false (عمليات التفويض/الالتقاط المؤجل) والحالات Status التي تكون Failed (فاشلة) أو Canceled (ملغاة).
  • يتحول المبلغ المسترد (Amount Refunded) غير الصفر إلى معاملة ثالثة سالبة (حيث externalId = <id>:refund) مؤرخة بتاريخ Refunded date (UTC) - لكي لا تضيع المبالغ المستردة الجزئية والكاملة المضمنة في صفوف المدفوعات.

تسوية تسوية مزودي خدمات الدفع (تقارير مدفوعات Stripe)

لتقسيم المدفوعات الإجمالية (lump-sum payout) إلى طلباتها الأساسية، ومبالغ الاسترداد، والرسوم، والمبالغ المستردة القسرية (chargebacks)، استخدم نقاط نهاية التسويات بدلاً من استيراد الكشوفات البسيطة. يتم قبول نوعين من تصديرات Stripe (ويتم اكتشافهما تلقائياً):

  • التقارير ← المدفوعات ← تسوية المدفوعات، مفصلة (Reports → Payouts → Payout reconciliation, itemized) (أنواع التقارير payout_reconciliation.itemized.* أو payout_reconciliation.by_id.itemized.*) - دقيقة، صف واحد لكل معاملة رصيد؛ وهي المفضلة في الحسابات الحية.
  • المدفوعات ← التصدير (المفصلة) (Payments → Export (unified payments)) - تصدير على مستوى الشحنة؛ يعمل في وضع الاختبار/البيئة التجريبية (sandbox) حيث لا تتوفر تسوية المدفوعات. يتم تجميع الشحنات الملتقطة بواسطة معرف الدفع في عمود Transfer؛ بينما يتم تخطي الصفوف غير الملتقطة/الفاشلة (skippedNotSettled)؛ ويتحول Amount Refunded غير الصفر إلى سطر استرداد اصطناعي في دفعة دفع الشحنة - وهو تقريب، نظراً لأن الاسترداد قد يكون قد استقر حقاً في دفعة لاحقة. تأتي مراجع المطابقة من معرف الشحنة، وPaymentIntent ID، وInvoice Number، وClient Reference ID، وكل عمود بصيغة … (metadata) (مثل رقم الطلب في البيانات الوصفية).

يمكن لملف CSV واحد أن يمتد ليشمل العديد من المدفوعات. تقوم Stripe بتنزيل التقرير المفصل ملفاً واحداً لكل قسم (…_charge_…، …_refund_…، …_fee_…)؛ قم باستيرادها جميعاً - فالصفوف الخاصة بدفعة تم استيرادها مسبقاً تندمج في الدفعة الحالية (ويتم الإبلاغ عنها في العداد updated) طالما لم يتم ترحيلها بعد، ويتم إعادة حساب إجماليات الدفعة.

POST /v1/bank/settlements/import
{
  "bankAccountId": "…",
  "provider": "stripe",
  "content": "balance_transaction_id,created_utc,…,reporting_category,…,automatic_payout_id,…"
}

سلوك الاستيراد:

  • يتم تجميع الصفوف حسب automatic_payout_id في دفعات تسوية (settlement batches) - دفعة واحدة لكل عملية دفع، مع إجماليات الإجمالي/الرسوم/الصافي (مجموع حقل net للصفوف = المبلغ الذي يدخل حسابك المصرفي). يتم تخطي إعادة استيراد الدفعة (العداد skipped). أما الصفوف التي لم تُسند بعد إلى دفعة وصفوف payout نفسها فيتم تخطيها وعدها بشكل منفصل.
  • يتم مطابقة كل صف شحنة/استرداد/نزاع تلقائياً مع فاتورة مبيعات باستخدام العناصر التالية بالترتيب: المرجع الخارجي لأمر التجارة الإلكترونية externalRef (أي قيمة من order_id، أو payment_intent_id، أو source_id، أو charge_id، أو أي عمود بصيغة *_metadata[...])، أو رقم الفاتورة الكامل fullNumber الذي يظهر في تلك الأعمدة، وفي حالات الاسترداد والنزاعات - معرف الشحنة charge_id لشحنة تمت مطابقتها مسبقاً (من نفس الملف أو عمليات الاستيراد السابقة).
  • المراجعة تتم عبر bank/settlements/list / bank/settlements/get؛ وإصلاح البقايا المتبقية يتم عبر bank/settlements/match { lineId, invoiceId } (أو استخدام invoiceId: null لإلغاء المطابقة).

يؤدي تنفيذ طلب POST /v1/bank/settlements/post { id, date?, commissionPercent? } إلى ترحيل الدفعة بأكملها كمعاملة يومية متوازنة واحدة وتسوية الفواتير المطابقة (تحديث paidAmount/paymentStatus، وإطلاق إشعارات الويب sale_invoice.paid):

  • جعل حساب الأستاذ العام للبنك مديناً بصافي الدفعة؛ وجعل رسوم مزود خدمة الدفع (settlements.fees، الافتراضي 6800) مدينَة للرسوم المقتطعة وصفوف الرسوم.
  • جعل الحسابات المدينة (accounts receivable) دائنة لكل شحنة مطابقة؛ وتعمل عمليات الاسترداد والنزاعات على عكس ذلك. يُحدد تطبيق المبلغ بحد أقصى يعادل الرصيد المتبقي لكل فاتورة - فأي زيادة تستقر في حساب التعليق مع إصدار تحذير.
  • الشحنات غير المطابقة: عند تعيين commissionPercent يتم تقسيمها إلى إيرادات عمولة (settlements.commissionRevenue، الافتراضي 5001) والتزام تجاه البائع (settlements.sellerPayable، الافتراضي 4499) - وهو تدفق السوق الذي تنتمي فيه الأموال المحصلة في الغالب إلى البائعين. وبدون ذلك، يتم ركنها في حساب settlements.suspense (الافتراضي 4440، الدفعات المقدمة المستلمة).
  • ترحيل صفوف platform_earning (رسوم تطبيق Stripe Connect) إلى إيرادات العمولة؛ وتعمل صفوف transfer (المدفوعات للبائعين المتصلين) على تخفيض الالتزام تجاه البائع.
  • جميع الحسابات الأربعة قابلة للتجاوز لكل شركة عبر قواعد الترحيل (ledger/posting-rules).
  • السطر الذي تم استيراد شحنته أو رسومه أو استرداده مسبقاً إلى حساب مصرفي آخر من تصدير مدفوعات Stripe (bank/statements/import) لا يتم تقييده على الرسوم أو الحسابات المدينة أو حساب التعليق. بدلاً من ذلك، يُقيد صافي مبلغه net في حساب الأستاذ العام لذلك الحساب المصرفي، لكي تتم تصفية الحساب المصرفي لـ Stripe دفعة بعد دفعة. يمثل summary.clearedAmount إجمالي المبلغ المحول بهذه الطريقة؛ والسطر الذي يختلف مبلغه عما يحتفظ به ذلك الحساب يتم ذكره بالاسم في التحذيرات warnings. وإذا لم يبق شيء للتقييد، تُرحل الدفعة مع جعل journalTransactionId بالقيمة فارغة (null).

تعيد نقاط النهاية bank/settlements/list و/get لكل دفعة القيم التالية: clearedNet، وclearingDifference (خطوط الدفع ناقص المبالغ التي يحتفظ بها الحساب المصرفي الآخر لها؛ وتكون صفراً عندما تتطابق)، وclearingOpenCount (الخطوط التي بها فرق أو حركة غير مرحلة)؛ بينما تعيد نقطة النهاية /get نفس القيم لكل سطر تحت أسماء clearingBankAccountId، وclearingBooked، وclearingDifference، وclearingUnposted. يتم مقارنة خطوط الاسترداد للشحنة الواحدة معاً، نظراً لأن تصدير المدفوعات لا يحتوي إلا على إجمالي المبلغ المسترد. تصدير مدفوعات Stripe الذي يتم استيراده بعد ترحيل دفعته يتخطى حركات تلك الدفعة ويذكرها بالاسم في التحذيرات warnings.

تتم فوترة ضريبة القيمة المضافة على العمولة نفسها بشكل منفصل (عبر إصدار فاتورة عمولة للبائع)؛ فالتقسيم يخصص النقد المحصل فقط.

المدفوعات بعملة أخرى

تُكتب قيود اليومية دائماً بالعملة الأساسية للشركة، ولكن الدفع بعملة مختلفة يتم ترحيله تلقائياً - دون الحاجة لأي إدخال يدوي:

  • يتم تحويل الدفعة بالعر سعر الصرف لتاريخ الترحيل (date، مع الرجوع لتاريخ الدفعة، ثم تاريخ اليوم). سعر الصرف هو سعر الشركة الخاص لتلك العملة (reference/exchange-rates/set) عندما يكون حديثاً على الأقل مثل السعر الرسمي، وإلا فيتم استخدام أحدث سعر صرف رسمي في أو قبل هذا التاريخ. وفي حال عدم وجود سعر صرف في أو قبل التاريخ، يفشل الطلب مع الرمز 422 ويشير إلى reference/exchange-rates/sync.
  • يتم تحويل كل حساب بسعر صرف تلك الدفعة باستثناء الحسابات المدينة (accounts receivable)، والتي يتم إبراء ذمتها بسعر الصرف fxRate الذي صدرت به كل فاتورة. يُرحل الفارق بين السعرين إلى حساب bank.fxGain (الافتراضي 5803) أو bank.fxLoss (الافتراضي 6803) كفارق صرف محقق، لكي يظل قيد اليومية متوازناً.
  • يعيد الملخص في الاستجابة summary قيمة سعر الصرف المستخدم fxRate وفارق الصرف الناتج exchangeDifference، وتحتفظ الدفعة بسعر الصرف الذي رُحلت به. الفاتورة المطابقة التي تختلف عملتها عن عملة الدفعة لا تتم تسويتها: بل يذهب مبلغها إلى حساب التعليق مع إصدار تحذير.
  • يبقى حد استيراد واحد قائماً: تُرفض الدفعة المفردة التي تختلط صفوفها بعدة عملات بالرمز 422، وكذلك الحال بالنسبة لإعادة الاستيراد التي تختلف عملتها عن الدفعة المخزنة مسبقاً لتلك الدفعة.

التدفقات اليدوية / المخصصة

يمكن دفع أي شيء آخر كبيانات JSON عادية:

POST /v1/bank/transactions/import
{
  "bankAccountId": "…",
  "transactions": [
    { "date": "2026-07-01", "amount": "-25.00", "currency": "EUR",
      "counterpartyName": "…", "description": "…", "externalId": "unique-ref-1" }
  ]
}

احرص على توفير معرف externalId مستقر لكل معاملة للحفاظ على خاصية التكرار الآمن (idempotent) لعمليات إعادة الاستيراد.