🌐 اقرأ هذا المقال بلغة أخرى: English · Español · Deutsch · Français · العربية · Bahasa Melayu · 简体中文 · 日本語
تعتمد معظم الوكالات الصغيرة والمستقلين إحدى طريقتين للفوترة. الأولى جدول بيانات وقالب Word يصدّره أحدهم يدوياً إلى PDF. والثانية خدمة فوترة مستضافة تُدفع عنها رسوم شهرية عن كل مستخدم، إلى الأبد. الطريقة الأولى تنهار بمجرد أن يعمل عليها شخصان. والثانية تعمل جيداً حتى تضيف زميلاً، أو عملة ثانية، أو عميلاً يحتاج إلى شيء لم يُصمَّم المنتج أصلاً من أجله.
واجهنا المشكلتين معاً، فبنينا إضافة فواتير ووردبريس خاصة بنا: ArtinTech Invoice Manager. تعمل الإضافة كتطبيق بملء الشاشة داخل موقع ووردبريس. تُنشئ فواتير احترافية مع تصدير PDF بنقرة واحدة، وتحتفظ بسجل للعملاء وأرصدتهم، وتتابع المدفوعات بعملات متعددة، وتضم لوحة إدارة لإدارة المستخدمين. الإضافة تعمل حالياً على هذا الموقع، وهي الأداة التي نصدر بها فواتير عملائنا اليوم.
هذا المقال هو السجل الكامل للبناء. يشرح ما تفعله الإضافة، وكيف بُنيت ولماذا، ونموذج الأمان، والأخطاء التي اكتشفناها قبل أن يكتشفها عملاؤنا، وما تطلّبه تجهيز الشيفرة لدليل إضافات WordPress.org. وإن كنت تقرر بين بناء أداة فوترة مخصصة أو استخدام أداة جاهزة، فالأقسام الأخيرة مكتوبة لك.

لماذا بنينا إضافة فواتير ووردبريس خاصة بنا
بناء برنامج يمكنك استئجاره خطأ في أغلب الأحيان، لذا من المهم أن نوضح بدقة لماذا لم يكن كذلك هنا. كانت العوامل الحاسمة عملية، لا عقائدية.
- يجب أن تبقى البيانات لدى الشركة. الفواتير وعناوين العملاء وسجل المدفوعات هي السجل المالي لأي شركة. الاحتفاظ بها في قاعدة بيانات ووردبريس نفسها التي ننسخها احتياطياً ونتحكم بها أبسط من الاعتماد على زر التصدير لدى طرف ثالث يوم نحتاج إليه.
- التسعير لكل مستخدم يعمل ضدك مع النمو. الأداة المستضافة الرخيصة لشخص واحد تصبح بنداً حقيقياً في الميزانية عندما يحتاج فريق صغير وبعض المتعاونين إلى حسابات خاصة بهم. أما الإضافة فتكلفتها واحدة، سواء استخدمها شخص واحد أو عشرون.
- عدة أصحاب حسابات مستقلين في تثبيت واحد. احتجنا أن يملك كل شخص فواتيره وعملاءه وشعاره وبياناته البنكية وترقيمه الخاص، معزولاً تماماً عن الآخرين، على موقع واحد.
- فواتيرنا دولية. نصدر فواتير لعملاء في الخارج، بأكثر من عملة. احتجنا إلى إجماليات لكل عملة لا تُحوَّل خلسة، وإلى فواتير تطبع البيانات البنكية للتحويلات الدولية.
- أردنا أن نستطيع تعديلها. عندما احتجنا إلى زر "تحديد كمدفوعة" أو مفتاح لإخفاء شعار العميل، أردنا تنفيذه في نفس اليوم، لا انتظاره في خطة تطوير مورّد ما.
لا يعني أيٌّ من هذا أن برامج الفوترة المستضافة سيئة. إنها مجرد مقايضة مختلفة، ومن المفيد رؤية الخيارين جنباً إلى جنب.
| خدمة فوترة مستضافة | إضافة فواتير ووردبريس مستضافة ذاتياً | |
|---|---|---|
| مكان البيانات | خوادم المورّد | قاعدة بيانات ووردبريس الخاصة بك |
| التكلفة مع نمو الفريق | ترتفع عادةً مع كل مستخدم | ثابتة مهما كان عدد المستخدمين |
| جهد الإعداد | دقائق | التثبيت، والتفعيل، وإنشاء صفحة التطبيق |
| التخصيص | ما تسمح به شاشة الإعدادات | كل ما تستطيع الشيفرة فعله |
| الصيانة | يتولاها المورّد | مسؤوليتك، كأي إضافة أخرى |
| التكاملات | غالباً كتالوج كبير من الموصلات الجاهزة | تُبنى حسب الحاجة وفق منظومتك الخاصة |
إن بدا لك العمود الأيسر قائمة من الأعباء، فالأداة المستضافة على الأرجح خيار أفضل لك. وإن بدا قائمة بأمور تفعلها لموقعك أصلاً، فالإضافة تبدأ في أن تكون منطقية.
كيف تعمل: من التثبيت إلى فاتورة مدفوعة
قبل التفاصيل، إليك سير العمل كاملاً من البداية إلى النهاية: ما يفعله المسؤول مرة واحدة، وما يفعله صاحب الحساب في كل مرة يصدر فيها فاتورة لعميل. تسع خطوات، كل منها معروضة على الواجهة الحقيقية.
الخطوة 1: ثبّت الإضافة وأنشئ صفحة التطبيق
- ارفع الإضافة من Plugins → Add New → Upload Plugin ثم فعّلها.
- افتح قائمة Invoice Manager الجديدة في لوحة wp-admin.
- انقر Create app page.
ينشر هذا صفحة على الرابط /invoice-manager/، وتصبح تلك الصفحة هي التطبيق. لا يتغير أي شيء آخر في الموقع، ويمكن للمسؤولين استخدام التطبيق فوراً.
الخطوة 2: سجّل الدخول، أو اسمح للآخرين بالتسجيل
تعرض صفحة التطبيق شاشة تسجيل دخول خاصة بها لكل من لم يسجّل دخوله. يسجّل المستخدمون الدخول باسم المستخدم أو البريد الإلكتروني المعتاد في ووردبريس، مع رابطَي "Remember me" و"Forgot password".

إذا فعّلت التسجيل العام، يظهر رابط Create one أسفل نموذج الدخول ويفتح شاشة التسجيل. ومع تفعيل موافقة المسؤول، يبقى الحساب الجديد معلّقاً حتى يوافق عليه أحد المسؤولين.

الخطوة 3: أدخل بيانات نشاطك التجاري مرة واحدة
يبدأ كل صاحب حساب من صفحة My settings:
- ارفع شعاراً، ثم اختر بين فرد أو شركة.
- أدخل عنوانك وبيانات الاتصال والرقم الضريبي.
- اختر العملة الافتراضية ومدة السداد.
- الصق بياناتك البنكية.
- حدّد بادئة الفواتير ورقم البداية، وأضف نسب الضريبة الخاصة بك.
كل ما تدخله هنا يُملأ تلقائياً في الفواتير الجديدة، فتكتبه مرة واحدة فقط.

الخطوة 4: أضف عملاءك
من Clients → Add Client، احفظ كل عميل مرة واحدة: الشعار، واسم الشركة وجهة الاتصال، والبريد الإلكتروني، والهاتف، والعنوان، والرقم الضريبي. يمكن البحث في سجل العملاء، وتعرض كل بطاقة عدد فواتير العميل والمبلغ الذي ما زال مستحقاً عليه.

الخطوة 5: أنشئ الفاتورة
انقر New invoice. ستجد الرقم والتواريخ والعملة والشروط وبياناتك مملوءة مسبقاً.
- اختر العميل.
- أضف بنود الفاتورة مع الكمية والسعر والضريبة.
- طبّق خصماً إن احتجت، وأضف حقولاً مخصصة مثل رقم أمر الشراء.
- اختر ما إذا كان شعارك وشعار العميل سيظهران على هذه الفاتورة.
- انقر Save.
تُعاد حساب الإجماليات فور الكتابة.

الخطوة 6: عاين الفاتورة ونزّل ملف PDF
يعرض زر Preview الفاتورة تماماً كما سيستلمها العميل. ويحفظ زر Download PDF ملفاً بمقاس A4 يمكنك إرساله بالبريد الإلكتروني، أو رفعه إلى بوابة العميل، أو طباعته.
تتوفر ثلاثة قوالب، تُختار لكل فاتورة من قائمة القوالب في المحرر:
- Blank: تخطيط نظيف وبسيط.
- Modern: شريط ملوّن في رأس الفاتورة.
- Classic: خط كلاسيكي مذيّل (Serif) مع خطوط فاصلة.

الخطوة 7: سجّل الدفعة
عند وصول المبلغ، انقر Mark paid في صف الفاتورة، أو أيقونة $ لتسجيل دفعة جزئية مع تاريخها وطريقتها ومرجع لها. تتغير الحالة تلقائياً:
- Partially paid (مدفوعة جزئياً) بعد أي دفعة جزئية.
- Paid (مدفوعة) عندما يصل الرصيد إلى صفر.
- Overdue (متأخرة) إذا مرّ تاريخ الاستحقاق قبل سداد الفاتورة بالكامل.

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

الخطوة 9: أدِر المستخدمين
يفتح المسؤولون، وكل من يحمل دور Invoice Manager Admin، القسم Admin panel → Users. ومن هناك يمكنهم:
- الموافقة على طلبات التسجيل المعلّقة، مع إرسال بريد إلكتروني تلقائي للمستخدم.
- تعليق الحسابات أو إعادة تفعيلها.
- إضافة مستخدمين مباشرة، ويتلقى المستخدم الجديد بريداً لتعيين كلمة المرور.
- تغيير الأدوار وحذف الحسابات.

ماذا تفعل الإضافة: جولة في الميزات
يعرض سير العمل السابق المسار الرئيسي، وتغطي هذه الجولة بقية ما تستطيع الإضافة فعله. كل شيء يعمل داخل صفحة واحدة من الموقع، بواجهة مصممة لتبدو كتطبيق مستقل لا كشاشة من شاشات ووردبريس.
لوحة الفواتير
تجيب الشاشة الرئيسية عن السؤال الذي يفتح لأجله كل صاحب عمل أداة الفوترة: من يدين لنا بماذا؟ تظهر في الأعلى أربعة أرقام: إجمالي الفواتير، والمحصّل، والمستحق، والمتأخر. يُحسب كل رقم منها لكل عملة على حدة، مع مفتاح للتبديل عندما يصدر صاحب الحساب فواتير بأكثر من عملة. وتحتها أحدث أربع فواتير على شكل بطاقات، ثم القائمة الكاملة.
يمكن البحث في القائمة برقم الفاتورة أو اسم العميل، وتصفيتها حسب العميل والحالة ونوع المستند والفترة الزمنية، وترتيبها حسب أي عمود. ومن كل صف يمكنك تسجيل دفعة، أو تحديد الفاتورة كمدفوعة، أو تنزيل ملف PDF، أو نسخها، أو حذفها، دون فتحها.
محرر الفواتير
صُمم المحرر على هيئة المستند النهائي، فما تكتبه يظهر في موضعه الفعلي. وتضم اللوحة الجانبية الإجراءات.
- أربعة أنواع من المستندات: فاتورة (Invoice)، وعرض سعر (Quote)، وفاتورة مبدئية (Proforma)، وإشعار دائن (Credit Note).
- ترقيم تلقائي ببادئة خاصة بكل مستخدم، مثل AT2623. يمكن تعديل الرقم، ويُرفض أي رقم مكرر.
- تاريخا الإصدار والاستحقاق. يُملأ تاريخ الاستحقاق من مدة السداد الافتراضية لكل شخص.
- بنود الفاتورة مع الكمية وسعر الوحدة والوصف ونسبة ضريبة تُختار من قائمة النسب الخاصة بالمستخدم.
- خصم على مستوى الفاتورة، وحقول مخصصة مثل رقم أمر الشراء، ومعلومات إضافية عن الشركة، ووصف حر.
- بيانات العميل، تُختار من سجل العملاء أو تُكتب لمرة واحدة، مع خيار حفظ عميل جديد فوراً.
- اختيار العملة لكل فاتورة، ونص الشروط المملوء مسبقاً من الإعدادات.
تتحدث الإجماليات أثناء الكتابة. وإذا حاولت المغادرة مع تغييرات غير محفوظة، يسألك التطبيق قبل تجاهلها. هذا التفصيل الصغير أهم في أداة الفوترة منه في أي مكان آخر تقريباً.
المدفوعات والحالات وزر "تحديد كمدفوعة"
لا أحد يحدد حالة الفاتورة يدوياً. تُشتق الحالة من المدفوعات المسجلة عليها، فلا يمكن أن تتعارض مع الأموال الفعلية.
| المدفوعات المسجلة | الحالة المعروضة |
|---|---|
| لا توجد | Unpaid (غير مدفوعة) |
| أقل من الإجمالي | Partially paid (مدفوعة جزئياً) |
| تساوي الإجمالي أو تزيد | Paid (مدفوعة) |
| غير مسددة بالكامل وتجاوزت تاريخ الاستحقاق | Overdue (متأخرة) |
| نوع المستند عرض سعر | Quote (لا يُحتسب إيراداً أبداً) |
لكل دفعة تاريخ ومبلغ وطريقة وملاحظة اختيارية، فتُسجَّل الدفعات الجزئية والنقص الناتج عن رسوم التحويل بدقة. وللحالة الأكثر شيوعاً، أي أن العميل دفع ببساطة، يوجد زر Mark as paid بنقرة واحدة. يسجل الزر دفعة واحدة بقيمة الرصيد المتبقي بتاريخ اليوم.
تصدير PDF والقوالب
يمكن معاينة كل فاتورة وتنزيلها كملف PDF بمقاس A4 بأحد ثلاثة قوالب: تخطيط Blank نظيف، وتخطيط Modern بشريط رأس ملوّن، وتخطيط Classic بخط مذيّل وخطوط فاصلة.
يتضمن ملف PDF:
- شعار المرسل وشعار العميل، ويمكن إيقاف كل منهما لفاتورة بعينها.
- العنوانين كليهما.
- البنود والخصم والضريبة والإجمالي.
- أي مدفوعات مستلمة، والرصيد المستحق، والبيانات البنكية، والشروط.
سجل العملاء
يُحفظ العملاء مرة واحدة ويُعاد استخدامهم. لكل عميل شعار، واسم الشركة وجهة الاتصال، وعنوان، ورقم ضريبي، وملاحظات.
تعرض قائمة العملاء المبلغ المستحق على كل عميل، وتعرض صفحة كل عميل:
- إجماليات الفواتير والمحصّل والمستحق لكل عملة.
- سجل فواتيره الكامل.
- زراً يبدأ فاتورة جديدة ببيانات العميل مملوءة مسبقاً.
إعدادات شخصية لكل صاحب حساب
لكل مستخدم ما يخصه من:
- الشعار، واختيار الهوية كفرد أو شركة.
- العنوان ورقم الهاتف مع رمز الاتصال الدولي.
- رقم التسجيل الضريبي والموقع الإلكتروني.
- العملة الافتراضية ومدة السداد بالأيام.
- البيانات البنكية، وبادئة رقم الفاتورة، والرقم التالي.
- نص الشروط الافتراضي وقائمة بنسب الضريبة المسمّاة.
وهكذا يستطيع شخصان على الموقع نفسه إصدار فواتير تبدو صادرة عن نشاطين تجاريين مختلفين، لأنها كذلك فعلاً.
التسجيل والموافقات ولوحة الإدارة
للتطبيق شاشات تسجيل دخول وتسجيل خاصة به في الواجهة الأمامية، فلا يحتاج أصحاب الحسابات إلى رؤية wp-admin إطلاقاً. التسجيل العام اختياري. وعند تفعيله، يمكن اشتراط موافقة المسؤول قبل استخدام الحسابات الجديدة، ويتلقى المسؤول بريداً عن كل تسجيل.
داخل التطبيق، يحصل المسؤولون على Admin panel من أربعة أقسام:
- Overview: أعداد الحسابات وحجم الفواتير عبر جميع المستخدمين.
- Users: الموافقة على الحسابات وتعليقها وإعادة تفعيلها وإضافتها وحذفها، وتغيير الأدوار.
- Sign-up settings: إعدادات التسجيل.
- Messages: الرسائل المرسلة من نموذج "Contact us" داخل التطبيق.

البنية: كيف يجب أن تخزّن إضافة فواتير ووردبريس بياناتها
تتحدد معظم جودة الإضافة على المدى الطويل ببنية بياناتها، لأنها الجزء الوحيد الذي يصعب تغييره بعد وجود فواتير حقيقية. اتخذنا أربعة قرارات مبكراً، وصمدت الأربعة كلها.
أنواع منشورات مخصصة، لا جداول مخصصة
الفواتير والعملاء ورسائل التواصل كلها أنواع منشورات مخصصة (Custom Post Types) خاصة. كل سجل يملكه مستخدم ووردبريس الذي أنشأه، وتُحفظ البيانات المنظمة في حقل واحد من بيانات المنشور الوصفية (post meta). أما الإعدادات الشخصية فتُحفظ في بيانات المستخدم الوصفية (user meta)، وخيارات الإضافة العامة عبر Options API.
كانت الجداول المخصصة في قاعدة البيانات ستكون أسرع قليلاً عند الأحجام الضخمة جداً. في المقابل، تمنحنا أنواع المنشورات الكثير مجاناً:
- تشمل النسخ الاحتياطية وعمليات النقل المعتادة في ووردبريس هذه البيانات تلقائياً.
- أدوات التصدير تفهمها أصلاً.
- ذاكرة التخزين المؤقت للكائنات (object cache) تعمل دون شيفرة إضافية.
- حذف مستخدم يمكن أن يحذف سجلاته معه دون سطر واحد من شيفرة التنظيف.
نادراً ما تحتوي أداة فوترة لنشاط تجاري على أكثر من بضعة آلاف من الفواتير لكل شخص. وعند هذا الحجم، يكون النهج الأصلي في ووردبريس هو الصحيح.
سُجّلت أنواع المنشورات على أنها خاصة تماماً: غير عامة، ولا يمكن الاستعلام عنها، ومستبعدة من البحث، ومخفية عن REST API وخرائط الموقع. لا يمكن لفاتورة أن تتسرب عن طريق الخطأ إلى نتائج البحث في القالب أو إلى خريطة موقع إضافة SEO.
اللقطات الثابتة: لماذا تنسخ الفاتورة بيانات المرسل والعميل
الفاتورة سجل قانوني للحظة زمنية محددة. إذا انتقل مكتبك العام المقبل، فيجب أن تبقى فواتير العام الماضي تحمل عنوان العام الماضي. لذلك عند إنشاء فاتورة، تنسخ الإضافة بيانات المرسل إليها، وتفعل الشيء نفسه مع بيانات العميل.
تغيير إعداداتك أو عنوان عميل لا يعيد كتابة التاريخ أبداً. وعندما تريد فعلاً أن تأخذ مسودة قديمة البيانات الجديدة، يوفر المحرر إجراءً صريحاً هو "Use my latest settings" بدلاً من فعل ذلك بصمت.
تحتفظ الفاتورة أيضاً برابط إلى سجل العميل، وهو ما تُبنى عليه أرصدة كل عميل. عند حذف عميل، يُزال الرابط وتبقى اللقطة. تظل الفاتورة مقروءة بشكل صحيح، وتتوقف فقط عن الاحتساب لعميل لم يعد موجوداً.
الحالة تُحسب ولا تُخزَّن
حالة "متأخرة" تعتمد على تاريخ اليوم، فتخزينها يجعلها خاطئة بحلول الغد. تخزّن الإضافة الحقائق: البنود والخصم والمدفوعات وتاريخ الاستحقاق، وتحسب الحالة في كل مرة تُقرأ فيها الفاتورة. حقل الحالة المخزّن من أكثر أسباب مشكلة "لوحة المعلومات تقول مدفوعة والبنك يقول غير ذلك" شيوعاً في برامج الأعمال.
حسابات مالية يعتمدها المحاسب
- الخصم يُطبَّق قبل الضريبة. خصم 10% يقلل المجموع الفرعي والضريبة المحتسبة عليه معاً، وهذا ما تتوقعه معظم الأنظمة الضريبية.
- الضريبة لكل بند. لكل بند نسبته الخاصة، فيمكن لفاتورة واحدة أن تجمع أعمالاً خاضعة للضريبة وأخرى معفاة.
- الإشعارات الدائنة تُحتسب بالسالب في كل الإجماليات، وعروض الأسعار لا تُحتسب إطلاقاً.
- العملات لا تُحوَّل أبداً. تُحفظ الإجماليات لكل عملة على حدة. التحويل الصامت بسعر صرف ما ينتج أرقاماً لا تطابق الفاتورة ولا البنك.
- تُعاد حساب الإجماليات على الخادم من البنود عند حفظ الفاتورة. حسابات المتصفح للعرض فقط، ولا يمكن لطلب مُتلاعَب به أن يخزّن إجمالياً غير صحيح.
واجهة REST API مع التحقق من الملكية في كل طلب
تتواصل الواجهة الأمامية مع ووردبريس عبر مساحة أسماء REST مخصصة. يمر كل مسار عبر فحص الصلاحيات نفسه. يجب أن يصدر الطلب عن مستخدم مسجّل الدخول يملك صلاحية الإضافة الخاصة وحالة حساب نشطة، وأن يحمل رمز nonce صالحاً من ووردبريس.
إضافة إلى ذلك، يتحقق كل طلب يشير إلى فاتورة أو عميل من أن السجل يخص المستخدم الحالي. وإن لم يكن كذلك، تجيب الواجهة بـ غير موجود (not found) لا ممنوع (forbidden). التمييز مقصود: "ممنوع" يؤكد وجود سجل بذلك المعرّف، أما "غير موجود" فلا يكشف شيئاً. ونختبر هذا صراحة، بطلب فاتورة حساب ما أثناء تسجيل الدخول بحساب آخر.
كل حقل وارد يُنقّى ويُقيَّد طوله:
- يجب أن تطابق التواريخ صيغة صارمة.
- يجب أن تتكون العملات من ثلاثة أحرف.
- يجب أن تأتي أنواع المستندات والقوالب من قائمة ثابتة.
- لا تُقبل الشعارات إلا كصور مرفوعة مسبقاً إلى مكتبة وسائط الموقع نفسه.
تُفك الصور المرفوعة ويُتحقق من أنها ملفات PNG أو JPEG أو GIF أو WebP حقيقية قبل وصولها إلى مكتبة الوسائط. وتُرفض صور SVG لأن ملف SVG قد يحمل شيفرة برمجية.
وفّر علينا تفصيل عملي واحد تذاكر دعم مستقبلية. بعض الاستضافات المشتركة وقواعد جدران الحماية تحظر طلبات HTTP من نوع PUT وDELETE تماماً. لذلك يرسل التطبيق كل عملية كتابة كطلب POST مع ترويسة تجاوز الطريقة (method override) القياسية في ووردبريس، والتي تدعمها REST API أصلاً. تبقى المسارات متوافقة مع REST، وتنجح الطلبات حتى على الاستضافات المقيِّدة.
الحسابات والأدوار والموافقات
تضيف الإضافة دورين ونموذج صلاحيات واحداً، ولا تمس أدوار ووردبريس الأصلية إلا لمنح المسؤولين حق الوصول.
| الدور | يستخدم التطبيق | يدير أصحاب الحسابات | يدير مسؤولي الفواتير والأدوار |
|---|---|---|---|
| Administrator (المسؤول) | نعم | نعم | نعم |
| Invoice Manager Admin | نعم | نعم | لا |
| Invoice Account Holder | نعم | لا | لا |
وُجد الدور الأوسط حتى يستطيع مدير المكتب الموافقة على المستخدمين ودعمهم دون منحه مفاتيح الموقع بالكامل. لا يمكن أبداً تعليق المسؤولين أو حذفهم من داخل التطبيق، ولا يستطيع أحد حذف حسابه بنفسه هناك. فهذه بالضبط الأخطاء التي تحبس الناس خارج مواقعهم.
التسجيل العام معطّل حتى يفعّله أحد المسؤولين. وعند تفعيله، يُحمى النموذج بأربع طرق:
- رمز nonce.
- حقل مخفي (honeypot) تملؤه الروبوتات ولا يملؤه البشر.
- حد أقصى قدره خمس عمليات تسجيل لكل عنوان شبكة في الساعة.
- حد أدنى لطول كلمة المرور.
عند تفعيل الموافقة، يستطيع الحساب الجديد تسجيل الدخول لكنه لا يرى سوى شاشة "بانتظار الموافقة" حتى يوافق عليه أحد المسؤولين، ويُرسل إليه بريد في تلك اللحظة. وتعليق مستخدم يُخرجه فوراً من كل أجهزته، بإنهاء جلسات ووردبريس الخاصة به، بدلاً من انتظار انتهاء صلاحية ملف تعريف الارتباط.
تطبيق بملء الشاشة لا يستطيع القالب إفساده
يجب أن يبدو تطبيق الفوترة ويعمل بالطريقة نفسها على كل موقع يُثبَّت عليه. أنماط أزرار القالب، أو إعادة ضبط الأنماط في منشئ الصفحات، أو محسّن السكربتات في إضافة التخزين المؤقت، كلها قادرة على إفساد واجهة على هيئة تطبيق بطرق خفية. لذلك تتولى الإضافة عرض صفحتها بالكامل.
عندما يفتح الزائر صفحة التطبيق، تقدّم الإضافة قالبها البسيط الخاص بدلاً من قالب الموقع. يطبع هذا القالب ملف الأنماط والسكربتات الخاصة بالإضافة فقط، عبر دوال ووردبريس القياسية للأنماط والسكربتات، ولا شيء من القالب أو الإضافات الأخرى. كما تطلب الصفحة من أنظمة التخزين المؤقت عدم تخزينها، ومن محركات البحث عدم فهرستها، فهي تطبيق وليست محتوى.
الواجهة نفسها مكتوبة بوحدات JavaScript عادية، دون أي إطار عمل، ومجمّعة في ملف واحد مقروء. يعتمد التنقل على مسارات hash، فالتبديل بين الفواتير والعملاء والإعدادات لا يعيد تحميل الصفحة، ويظل زر الرجوع في المتصفح يعمل. والخط المستخدم، DM Sans، مضمّن مع الإضافة بدلاً من تحميله من خدمة خطوط، فلا يرسل التطبيق أي طلبات إلى خوادم أطراف ثالثة.
صُمم التخطيط للهواتف منذ البداية. على الشاشات الصغيرة:
- يتحول الشريط الجانبي إلى قائمة منزلقة.
- تتحول جداول البيانات إلى بطاقات متراصة، مع تسمية لكل قيمة.
- يُعاد ترتيب محرر الفواتير في عمود واحد.
كثيراً ما تُراجع الفواتير من الهاتف، عندما يقول العميل إنه دفع.


إنشاء فواتير PDF داخل المتصفح
إنشاء ملفات PDF على الخادم بلغة PHP يعني عادةً مكتبات ثقيلة، وخطوطاً على الخادم، وحدوداً للذاكرة، ونتائج مختلفة كثيراً من استضافة إلى أخرى. لذلك ننشئ ملف PDF في متصفح المستخدم بدلاً من ذلك:
- تُعرض الفاتورة كمستند HTML بمقاس A4.
- يُحوَّل هذا المستند إلى صورة.
- توضع الصورة في ملف PDF باستخدام مكتبة html2pdf.js مفتوحة المصدر.
لهذا ثلاث فوائد:
- يبدو ملف PDF مطابقاً تماماً للمعاينة على الشاشة، لأنه هو المعاينة نفسها.
- يعمل على أي استضافة.
- لا تُرسل أي بيانات فواتير إلى أي مكان لتحويلها.
المقايضة أن النص في ملف PDF صورة وليس نصاً قابلاً للتحديد. وبالنسبة لفواتير تُقرأ وتُطبع وتُحفظ، هذا ثمن مقبول مقابل نتيجة متطابقة في كل مكان.
الأخطاء التي اكتشفناها قبل أن يكتشفها عملاؤنا
وصل كل واحد من هذه الأخطاء إلى شاشة حقيقية. ويستحق كل منها الوصف، لأنه يمثل فئة من الأخطاء تظهر في مشاريع أخرى أيضاً.
الصفحة الثانية الفارغة بسبب نصف بكسل
كانت الفواتير المكونة من صفحة واحدة تُنزَّل كملفات PDF من صفحتين، والصفحة الثانية فارغة. السبب: كان للمستند على الشاشة حد أدنى للارتفاع قدره 1123 بكسل ليبدو في المعاينة كورقة كاملة، بينما ارتفاع A4 عند 96 DPI هو 1122.5 بكسل. كان تجاوز نصف البكسل هذا كافياً لتبدأ مكتبة PDF صفحة جديدة.
يزيل الإصلاح الحد الأدنى للارتفاع أثناء التصدير فقط، فتبقى المعاينة شبيهة بالورق. وتأكدنا منه بعدّ صفحات ملف PDF الناتج: صفحتان قبل الإصلاح، وصفحة واحدة بعده. أما فاتورة من 45 بنداً فما زالت تمتد بشكل صحيح إلى صفحة ثانية فيها محتوى.
رابط تسجيل الخروج الذي هرّب نفسه
تُرجع دالة رابط تسجيل الخروج في ووردبريس رابطاً مهرّباً مسبقاً لـ HTML، تُكتب فيه علامات & على هيئة &. هذا صحيح داخل سمة HTML وخاطئ داخل JavaScript، حيث أفسدت العلامة المهرّبة رمز الأمان وعملية الخروج. يفك الإصلاح ترميز الرابط مرة واحدة قبل تمريره إلى التطبيق. إنه خطأ صغير، لكنه نموذجي لما يحدث عند الحدود بين قوالب PHP ولغة JavaScript.
شعارات العملاء التي لم تصل إلى الفاتورة
كان شعار العميل يُرفع ويُحفظ بشكل صحيح، لكنه لم يظهر أبداً في الفواتير. ببساطة لم تكن اللقطة المنسوخة في كل فاتورة تتضمنه. كان للإصلاح شقان:
- الفواتير الجديدة تتضمن الشعار الآن في اللقطة.
- الفواتير المحفوظة سابقاً تستخدم الشعار الحالي للعميل المرتبط عند قراءتها، دون إعادة كتابة البيانات المخزنة.
إبقاء البيانات المخزنة دون مساس عند إصلاح مشكلة في العرض عادة تستحق التمسك بها.
بطاقة في لوحة المعلومات تخالف الجدول
بعد تحديد فاتورة كمدفوعة من القائمة، كان صف الجدول يتحول إلى الأخضر، لكن بطاقة "أحدث الفواتير" فوقه تظل تقول Unpaid حتى إعادة تحميل الصفحة. فقد عرضان للبيانات نفسها تزامنهما. الآن، أي إجراء يغير فاتورة يعيد رسم الشاشة كلها من بيانات جديدة، فتتفق كل الأرقام على الصفحة دائماً.
المحاذاة بعد إضافة الشعار
عندما وُضع شعار العميل فوق عنوانه، بدأت كتلة "To" أدنى من كتلة "From"، وبدت الفاتورة غير متوازنة. أصلح ذلك نقلُ الشعار إلى يمين العنوان: تبدأ الكتلتان على السطر نفسه، ويصطف الشعار مع رقم الفاتورة فوقه. ثم منحنا عمود العميل عرضاً أكبر قليلاً ليبقى عنوان شارع سويسري نموذجي على سطر واحد. الدرس: اختبر تخطيطات الفواتير ببيانات عملاء حقيقية، لأن الأسماء التجريبية تكون دائماً قصيرة على نحو مريح.
التجهيز لدليل إضافات WordPress.org
الشيفرة التي تعمل على موقعك والشيفرة التي تجتاز مراجعة WordPress.org ليستا الشيء نفسه. للدليل قواعد محددة، وقد غيّرنا عدداً من الأمور للالتزام بها قبل التقديم.
- لا اتصالات بخوادم خارجية. كان الخط يُحمَّل في البداية من خدمة خطوط، ما يرسل عنوان IP لكل زائر إلى طرف ثالث. أصبح الآن مضمّناً مع الإضافة بموجب رخصة الخطوط المفتوحة الخاصة به.
- السكربتات والأنماط تمر عبر دوال ووردبريس نفسها. استُبدلت وسوم script وlink المكتوبة يدوياً بأصول مسجّلة ذات إصدارات. وتُرفق إعدادات التشغيل عبر آلية السكربت المضمّن القياسية.
- شيفرة مصدرية مقروءة. لا يقبل الدليل شيفرة مصغّرة دون مصدرها. لذلك تُشحن حزمة التطبيق غير مصغّرة، مع الوحدات الأصلية، ويشرح ملف readme كيفية إعادة بنائها.
- ذكر رخص الأطراف الثالثة. مكتبة PDF والخط مذكوران في ملف readme مع رخصهما وروابط مصادرهما، وملفات الرخص مرفقة بالإضافة.
- لا تستدعي الإضافة خطافات النواة (core hooks). كانت نسخة مبكرة تستدعي إجراء تسجيل الدخول الخاص بووردبريس بعد التسجيل، وأصبحت الآن تسجّل الدخول عبر شيفرتها الخاصة.
- إلغاء التثبيت بموافقة صريحة. حذف الإضافة لا يزيل شيئاً ما لم يطلب المسؤول صراحة حذف البيانات. فالفواتير سجلات تجارية، وفقدانها بنقرة خاطئة غير مقبول.
- ملف readme كامل يتضمن وصفاً قصيراً وخطوات التثبيت وأسئلة شائعة وقسماً للخصوصية وسجلاً للتغييرات. وبُنيت الشيفرة بحيث تستطيع أداة Plugin Check الرسمية مراجعتها بسلاسة.
لم تجعل أي من هذه القواعد الإضافة أسوأ، بل جعلها عدد منها أفضل. فتضمين الخط مثلاً أزال سؤالاً يتعلق بالخصوصية من أساسه.
هل تبني إضافة فواتير ووردبريس مخصصة أم تستخدم إضافة جاهزة؟
بصراحة، معظم الشركات لا ينبغي أن تطلب أداة فوترة مخصصة. إذا كان شخص واحد يرسل بضع فواتير شهرياً بعملة واحدة، فسيخدمه منتج جاهز جيداً وبتكلفة أقل من أي بناء مخصص. يصبح البناء المخصص الخيار الأفضل عندما يصدق عدد من الأمور التالية:
- يحتاج عدة أشخاص إلى فوترة منفصلة ومعزولة على نظام واحد، وبدأ التسعير لكل مستخدم يرهق الميزانية.
- يجب أن ترتبط الفوترة بشيء خاص بنشاطك، مثل نظام حجوزات، أو أداة لمتابعة المشاريع، أو نظام ERP، أو بوابة عملاء.
- تصدر فواتير بعدة عملات وتحتاج إلى إجماليات لا تُحوَّل من خلف ظهرك.
- تحتاج فواتيرك إلى قواعد لا تدعمها الأدوات الجاهزة، مثل خطوات موافقة مخصصة، أو أنواع مستندات، أو أنظمة ترقيم.
- تريد أن تبقى البيانات المالية في بنية تحتية تملكها وتنسخها احتياطياً وتتحكم بها.
إذا انطبق أمر واحد فقط من هذه، فابحث أكثر في المنتجات الجاهزة أولاً. وإذا انطبقت ثلاثة أو أكثر، فإن إضافة مركّزة مثل هذه تكلف عادةً على مدى عامين أو ثلاثة أقل من الاشتراكات والحلول الالتفافية التي تحل محلها، وتفعل تماماً ما تحتاج إليه.
وأياً كان اختيارك، قيّم أي أداة فوترة بالمعايير التي تناولها هذا المقال:
- هل تحتفظ بسجل ثابت لكل فاتورة، بحيث لا تعيد التغييرات اللاحقة على بياناتك أو بيانات العميل كتابة الفواتير القديمة؟
- هل تحسب الحالة من المدفوعات بدلاً من تخزينها؟
- هل تفصل بين العملات؟
- هل تعزل المستخدمين عن بعضهم؟
- هل يمكنك استخراج بياناتك؟
الأسئلة الشائعة
هل يمكن لإضافة فواتير ووردبريس أن تخدم أكثر من مستخدم؟
نعم، إذا صُممت لذلك. في ArtinTech Invoice Manager، تعود كل فاتورة وكل عميل إلى صاحب الحساب الذي أنشأهما، وتتحقق الواجهة البرمجية من الملكية في كل طلب. لكل مستخدم إعداداته وشعاره وترقيمه وبياناته البنكية، ولا يستطيع رؤية بيانات أي شخص آخر.
هل ترسل الإضافة بيانات الفواتير إلى أي خدمة خارجية؟
لا. كل شيء محفوظ في قاعدة بيانات ووردبريس الخاصة بالموقع. تُنشأ ملفات PDF في متصفح المستخدم، والخط مضمّن مع الإضافة. الرسائل الصادرة الوحيدة هي رسائل البريد العادية في ووردبريس، مثل إشعارات التسجيل والموافقة.
هل يمكنها إصدار فواتير بعملات مختلفة؟
نعم. لكل فاتورة عملتها، وتعرض لوحة المعلومات وصفحات العملاء الإجماليات لكل عملة على حدة. لا يُحوَّل أي شيء، فتطابق الأرقام دائماً الفواتير التي أرسلتها فعلاً.
هل تعمل مع القالب أو منشئ الصفحات لديّ؟
نعم. تُعرض صفحة التطبيق بقالب الإضافة وأصولها الخاصة، فلا يستطيع القالب أو Elementor أو أي منشئ صفحات آخر تغيير شكلها أو سلوكها. ولا يتأثر باقي موقعك إطلاقاً.
هل الإضافة متاحة على WordPress.org؟
جهّزناها لدليل إضافات WordPress.org، وستُدرج هناك بعد اجتيازها المراجعة. وحتى ذلك الحين، إن رغبت في استخدامها أو في نسخة مكيّفة مع سير عملك، تواصل معنا.
هل يمكنكم بناء نسخة مخصصة لنشاطي التجاري؟
نعم. تخطيطات الفواتير المخصصة، وأنواع المستندات الإضافية، والتكامل مع نظام حجوزات أو نظام مشاريع، وبوابات العملاء، ومسارات الموافقة، كلها امتدادات منطقية للأساس نفسه. اطّلع على خدمة تطوير إضافات ووردبريس لمعرفة كيف نحدد نطاق هذا العمل.
بناء أدوات ووردبريس كهذه جزء أساسي من عملنا. بعضها إصلاحات صغيرة، مثل خطأ 403 المرتبط بالتخزين المؤقت الذي تتبعناه إلى مدة صلاحية رمز nonce. وبعضها تطبيقات كاملة مثل هذا، ننجزها ضمن خدمات تطوير ووردبريس وتطوير أنظمة CMS وERP المخصصة. إن كنت تفاضل بين أدوات الفوترة، أو تتعامل مع أي برنامج آخر تضطر شركتك للالتفاف حوله باستمرار، فلنتحدث. سنقدم لك تقييماً صريحاً، حتى لو كانت الإجابة أن منتجاً جاهزاً يكفي.