TrustBill
دليل التكاملأكتوبر 2026
شعار OracleOracle NetSuite

Oracle NetSuite · دليل التكامل

ربط Oracle NetSuite بالفوترة الإلكترونية للهيئة الاتحادية للضرائب عبر تراست بل

هذا الدليل موجّه لمسؤول NetSuite لديك أو مطوّره أو شريك التنفيذ. يقارن بين الطرق الثلاث لربط NetSuite بشبكة الفوترة الإلكترونية في الإمارات عبر تراست بل، ويوضح بدقة ما يجب إعداده داخل NetSuite، ومن يتولى كل مهمة، حتى لا يظهر أي مفاجآت أثناء اختبار القبول.

0. المصطلحات المستخدمة في الدليل

1. نظرة عامة: ما الذي تقدمه تراست بل لـ NetSuite

Oracle NetSuite منتج سحابي فقط. يحتسب ضريبة القيمة المضافة ويصدر الفواتير، لكنه لا ينتج مستندات PINT-AE ولا يستطيع تسليمها إلى الهيئة عبر شبكة Peppol. تقع تراست بل بين NetSuite والهيئة: تستلم فواتير المبيعات وإشعارات الدائنة، وتتحقق منها وفق قواعد الهيئة، وتحوّلها إلى PINT-AE، وترسلها عبر مزوّد خدمة معتمد، ثم تعيد إليك معرّف FTA UUID والحالة.

  • لا حاجة إلى تثبيت SuiteApp في مسار CSV، ولا في مسار السكربت أيضًا، فالسكربتات تعمل داخل حسابك أنت.
  • ترقيم الفواتير وسير العمل والقوالب لديك تبقى كما هي.
  • النطاق هو مستندات الذمم المدينة فقط: فواتير المبيعات وإشعارات الدائنة. الذمم الدائنة والأستاذ العام والرواتب والمخزون خارج النطاق.
  • تستخدم الخيارات الثلاثة التحقق نفسه من تراست بل ومزوّد الخدمة المعتمد نفسه. الفرق فقط في طريقة الإطلاق وإعادة الحالة، لذلك يمكنك البدء ببساطة ثم الارتقاء لاحقًا.
المتاح اليوم: الخياران A و B يعملان الآن. أما الخيار C، وهو موصّل تراست بل الأصلي الذي يسحب البيانات من NetSuite، فيُحدَّد نطاقه لكل عميل عند الطلب. لا نصفه بأنه متاح عمومًا.

2. خيارات الربط الثلاثة

لست متأكدًا أي خيار يناسبك؟ أجب عن استبيان NetSuite القصير وسنرد بتوصية وجدول زمني وسعر. أسعار جميع تكاملات الأنظمة منشورة في صفحة أسعار تكامل الأنظمة.

3. الخيار A: تصدير Saved Search ورفع جماعي

  1. تأكد من أن لكل عميل في الإمارات رقمًا ضريبيًا من 15 رقمًا مخزّنًا في حقل بسجل العميل (انظر قسم تعيين الحقول).
  2. أنشئ Saved Search من نوع Transaction. المعايير: النوع هو Invoice أو Credit Memo، وPosting يساوي true، ونطاق تاريخ تتحكم فيه.
  3. أضف أعمدة النتائج المذكورة أدناه.
  4. صدّر إلى CSV أو Excel، أو اجعل البحث يُرسل إلى بريدك وفق جدول.
  5. ارفع الملف عبر الرفع الجماعي في تراست بل. عيّن الأعمدة مرة واحدة وستتذكر تراست بل التعيين.
  6. راجع نتائج التحقق. صحّح أي صف مرفوض داخل NetSuite وليس في الملف المصدَّر، ليبقى الاثنان متطابقين.
  • Document Number وDate وDue Date ونوع المستند (Invoice أو Credit Memo).
  • اسم العميل والحقل الذي يحمل الرقم الضريبي للعميل.
  • العملة وسعر الصرف.
  • وصف البند، والكمية، والسعر (غير شامل الضريبة).
  • رمز الضريبة ومبلغ الضريبة والمبلغ الإجمالي لكل بند.
  • Created From لإشعارات الدائنة: رقم الفاتورة الأصلية.
يجب أن يشير إشعار الدائنة إلى فاتورته الأصلية. أنشئ إشعارات الدائنة من الفاتورة نفسها (Actions ثم Credit) ليمتلئ حقل Created From، لا كسجلات مستقلة.

4. الخيار B: الإرسال من NetSuite إلى Partner API في تراست بل

يرسل NetSuite، أو منصة التكامل لديك، كل فاتورة معتمدة إلى تراست بل. تتحقق تراست بل منها وترسلها، ثم تتصل بك لتعيد النتيجة.

NetSuite invoice approved
      |
      v
Script or iPaaS flow --- POST /v1/partner/invoices ---> TrustBill Partner API
      ^                                                      |
      |                                          validate, PINT-AE, ASP, FTA
      |                                                      |
      +------- signed webhook: invoice.status_changed <------+
              (FTA UUID + status written to the invoice)
  1. أنشئ حقولًا مخصصة على مستوى رأس المعاملة في الفاتورة وإشعار الدائنة: حالة FTA، ومعرّف FTA UUID، وسبب الرفض (مثل custbody_tb_fta_status وcustbody_tb_fta_uuid وcustbody_tb_reject_reason).
  2. تأكد من تعبئة حقل الرقم الضريبي للعميل ورقم التسجيل الضريبي لكل شركة تابعة.
  3. تصدر لك تراست بل زوج مفاتيح تجريبيًا وسرًّا خاصًا بكل كيان قانوني. احفظها في NetSuite API Secrets، وليس في شيفرة السكربت أو معاملاته.
  4. ابنِ مسار الإرسال: التقط الفواتير المعتمدة التي لم تُرسل بعد، وعيّن حقولها (انظر جداول التعيين)، وأرسلها بطلب POST مع Idempotency-Key.
  5. ابنِ مسار الاستقبال: استقبل الإشعار الموقّع، وتحقق من التوقيع، واكتب UUID والحالة في الفاتورة.
  6. نفّذ اختبار القبول في البيئة التجريبية، ثم انتقل إلى بيانات الاعتماد الفعلية.

هيكل مبدئي لسكربت الإرسال (SuiteScript 2.1). هو رسم توضيحي للشكل العام وليس شيفرة جاهزة للإنتاج:

/**
 * @NApiVersion 2.1
 * @NScriptType ScheduledScript
 */
define(['N/https', 'N/search'], (https, search) => {
  const execute = () => {
    // 1. Find approved invoices where custbody_tb_fta_status is empty.
    // 2. For each one, build the payload (see the field mapping table).
    // 3. POST it. Use the invoice internal ID as the Idempotency-Key.
    const response = https.post({
      url: 'https://api.trustbill.ae/v1/partner/invoices',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': '<from NetSuite API Secrets>',
        'X-API-Secret': '<from NetSuite API Secrets>',
        'x-erp-partner-secret': '<per legal entity>',
        'Idempotency-Key': 'netsuite-inv-' + invoiceInternalId
      },
      body: JSON.stringify(payload)
    });
    // 4. 202 = queued. Keep the invoice marked "sent" so it is not re-sent.
  };
  return { execute };
});
فضّل سكربت Scheduled أو Map/Reduce على استدعاء خارجي مباشر من سكربت User Event. يجب ألا يمنع أي انقطاع أو بطء في الطرف الآخر أحدًا من حفظ فاتورة في NetSuite.

5. المصادقة

تستخدم Partner API طبقتين. بيانات اعتماد الشريك تثبت أن المتصل مُدمِج معروف، والسرّ الخاص بالكيان يثبت أن هذا الإرسال يخص الكيان القانوني المذكور في الفاتورة. تحتاج جميع عمليات الكتابة إلى الطبقتين معًا.

يُقارن الرقم الضريبي للبائع في الطلب بالكيان الذي يحدده x-erp-partner-secret. أي عدم تطابق يُرفض بالرمز 403 trn_mismatch قبل أي معالجة. في حسابات OneWorld يحميك هذا من سكربت يختار شركة تابعة خاطئة.

في الموصّل الأصلي (الخيار C) ينعكس الاتجاه: تنشئ دور تكامل بأقل الصلاحيات في NetSuite وبيانات اعتماد OAuth 2.0 أو بالرمز المميّز، ونطلب منك مشاركتها أثناء جلسة عن بُعد آمنة. لا ترسل كلمات المرور أو الرموز بالبريد الإلكتروني أو عبر نموذج على الويب أبدًا.

6. حمولة الطلب: ما الذي يرسله NetSuite

فاتورة مبيعات في حدها الأدنى. المخطط الكامل، بما فيه إشعارات الدائنة والمدينة، منشور على https://api.trustbill.ae/v1/partner/openapi.json.

POST /v1/partner/invoices HTTP/1.1
Host: api.trustbill.ae
Content-Type: application/json
X-API-Key: tbp_live_...
X-API-Secret: tbs_live_...
x-erp-partner-secret: ers_live_...
Idempotency-Key: netsuite-inv-48213

{
  "documentType": "tax_invoice",
  "externalRef": "INV-2026-00042",
  "issueDate": "2026-10-31",
  "dueDate": "2026-11-30",
  "currency": "AED",
  "seller": { "trn": "100123456700003", "legalName": "Acme Trading L.L.C" },
  "buyer":  { "trn": "100987654300003", "legalName": "Beta Distribution F.Z.E" },
  "lines": [
    { "description": "Industrial pump, model X9", "quantity": 2,
      "unitPrice": 1500.00, "taxCategory": "S", "taxRate": 5 }
  ],
  "totals": { "netAmount": 3000.00, "taxAmount": 150.00, "grossAmount": 3150.00 },
  "indicators": { "freeZone": false, "reverseCharge": false, "export": false }
}

يعيد الطلب الناجح الرمز 202 Accepted مع معرّف الفاتورة في تراست بل وstatus: "queued". الإشعار الموقّع هو القناة المعتمدة للنتيجة النهائية من الهيئة.

7. تعيين حقول NetSuite

اعتمد هذا الجدول معيار قبول للتعيين. معرّفات الحقول المعروضة هي حقول NetSuite القياسية؛ أما الحقول التي تبدأ بـ custentity_ أو custbody_ فهي أمثلة، لأن كل حساب يسمّي حقوله المخصصة بطريقته.

8. تعيين الرموز الضريبية

سواء استخدمت SuiteTax أو الرموز الضريبية التقليدية، يجب أن يقابل كل رمز تطبّقه على بند مبيعات إماراتي فئة ضريبية واحدة في PINT-AE. تختلف أسماء الرموز من حساب إلى آخر، لكن المنطق واحد.

الرمز الضريبي غير المعيَّن هو السبب الأكثر شيوعًا لفشل أول فاتورة. اتفق على التعيين مع مستشارك الضريبي قبل اختبار القبول، وأدخله مرة واحدة في إعدادات تراست بل ثم تعيين الضرائب.

9. OneWorld والشركات التابعة وتعدد الأرقام الضريبية

10. إشعارات الحالة المرتدة إلى NetSuite

عندما تصل الفاتورة إلى حالة نهائية، ترسل تراست بل حدثًا واحدًا هو invoice.status_changed إلى العنوان الذي سجّلته. الإشعارات موقّعة وتُعاد محاولة إرسالها عند الفشل.

POST /your-endpoint HTTP/1.1
Content-Type: application/json
X-Webhook-Timestamp: 1761900000
X-Webhook-Signature: t=1761900000,v1=4e9c3d...hex...

{
  "event": "invoice.status_changed",
  "payload": {
    "invoiceId": "inv_01HZ...",
    "externalRef": "INV-2026-00042",
    "status": "delivered",
    "ftaUuid": "f1b8c7e2-9d4a-4b11-9c38-7c7a3a9c0e8b"
  }
}
  1. اقرأ X-Webhook-Timestamp واستخرج v1 من X-Webhook-Signature.
  2. ارفض الطلب إذا تجاوز فارق الطابع الزمني عن الوقت الحالي 300 ثانية.
  3. احسب HMAC-SHA256 للنص timestamp.raw_body باستخدام سرّ الإشعارات وقارنه بزمن ثابت.
  4. بعد ذلك فقط حلّل الجسم واكتب ftaUuid وstatus في الحقول المخصصة للفاتورة.

في NetSuite يمكنك استقبال الإشعار في Suitelet متاح من الخارج (وتتحقق من HMAC بوحدة N/crypto)، أو تتركه لمنصة التكامل لديك لتستقبله وتحدّث الفاتورة عبر REST. تتبع إعادة المحاولة الجدول: 30 ثانية، ثم دقيقتان، ثم 10 دقائق، ثم 30 دقيقة، ثم ساعة، ثم 3 ساعات. الأخطاء مستندات مشكلة وفق RFC 7807: تعامل مع قيمة type الثابتة وليس مع رمز HTTP وحده.

11. قائمة اختبار القبول والإطلاق

  • في البيئة التجريبية، الرقم الضريبي التجريبي المحجوز 100000000000000 يقبل دائمًا ويُطلق إشعارًا حقيقيًا، بينما 100000000000666 يرفض دائمًا.
  • تأكد من عمل التحقق من توقيع الإشعار قبل الإطلاق.
  • انتقل إلى بيانات الاعتماد الفعلية، ثم ارفع حجم الإرسال تدريجيًا خلال أول يومين.

12. من يتولى ماذا

الأسئلة الشائعة

هل Oracle NetSuite سحابي أم محلي؟

NetSuite سحابي فقط (SaaS). المنتجات المحلية من Oracle هي E-Business Suite وJD Edwards وتُربط بطرق مختلفة. أما Oracle Fusion Cloud ERP فهو سحابي أيضًا لكنه منتج مستقل وأكبر وله دليله الخاص.

هل لدى تراست بل موصّل أصلي لـ NetSuite؟

ليس كمنتج متاح عمومًا اليوم. يمكنك الربط الآن بالخيار A (تصدير ورفع) أو الخيار B (إرسال عبر سكربت أو منصة تكامل). أما الموصّل الأصلي الذي يسحب من NetSuite فيُحدَّد نطاقه لكل عميل عند الطلب.

هل أحتاج إلى تثبيت SuiteApp؟

لا. الخيار A لا يتطلب تثبيت أي شيء. أما الخيار B فيستخدم سكربتات أو مسارات تعمل في حسابك أنت ويطبّقها مسؤولك أو شريك NetSuite لديك.

أين يُخزَّن الرقم الضريبي للعميل في NetSuite؟

إما في حقل التسجيل الضريبي في سجل العميل أو في حقل مخصص أنشأه فريقك. يجب أن يكون 15 رقمًا. يسأل الاستبيان عن مكان حفظه لنتمكن من تعيينه.

نستخدم OneWorld مع عدة شركات تابعة. هل هذه مشكلة؟

لا. تصبح كل شركة تابعة تحمل رقمًا ضريبيًا إماراتيًا كيانًا قانونيًا مستقلًا في تراست بل بسرّها الخاص. يختار مسارك السرّ الصحيح بحسب الشركة التابعة.

هل يدعم NetSuite الفوترة الإلكترونية في الإمارات أصلًا؟

يحتسب NetSuite ضريبة القيمة المضافة ويصدر الفواتير. أما تسليم فواتير PINT-AE إلى شبكة الهيئة عبر مزوّد خدمة معتمد فخطوة منفصلة، وهي ما تقوم به تراست بل. قد تصدر Oracle تحديثات توطين، لذلك اسأل شريك NetSuite عمّا هو مثبّت في حسابك.

ماذا يحدث عند رفض فاتورة؟

يعيد الإشعار الحالة rejected مع السبب، ويمكنك كتابته في حقل بالفاتورة. صحّح السبب في NetSuite وأعد الإرسال، أو أصدر إشعار دائنة حيث تتطلب القواعد ذلك.

كم يستغرق التنفيذ وكم التكلفة؟

يمكن بدء الخيار A في اليوم نفسه. يستغرق الخيار B عادةً من أسبوع إلى أسبوعين من وقت مطوّر NetSuite. يُحدَّد نطاق الخيار C بعد الاستبيان. الأسعار منشورة في صفحة أسعار تكامل الأنظمة.

هل هو آمن؟

تستخدم الطلبات HTTPS مع زوج مفاتيح وسرّ خاص بكل كيان. والإشعارات موقّعة بـ HMAC مع نافذة لمنع إعادة الإرسال. في NetSuite نطلب فقط دور تكامل بأقل الصلاحيات، ولا نطلب كلمات المرور عبر النموذج أبدًا.

أدلة ذات صلة