Enterprise الإصدار
الفوترة — مرجع متعمّق
لمحة سريعة
قسم بعنوان «لمحة سريعة»هذه الصفحة هي المرجع المتعمّق لسطح الفوترة في NextPDF Enterprise. يتألف هذا السطح من طبقتين. يُعرّف نموذج الفوترة في NextPDF\Enterprise\Billing طبقاتِ الخطط والحصص وسياسات التجاوز وتنبيهات الاستخدام المُزال منها التكرار. أمّا ركيزة الفرض في NextPDF\Enterprise\Billing\Substrate فتضع هذا النموذج على مسار الطلب الحيّ، مُغلقةً عند الفشل وآمنةً في التزامن. نقاط الدخول هي PlanRegistry وQuotaManager وOverageCalculator وBillingAlertService وQuotaEnforcementGuard. للاطّلاع على الدليل على مستوى سير العمل، راجع صفحة قدرة الفوترة.
التوفّر والترخيص
قسم بعنوان «التوفّر والترخيص»تُشحن هذه القدرة ضمن NextPDF Enterprise (nextpdf/enterprise) وتُفعَّل بمظروف ترخيص من طبقة Enterprise. لا يُحمِّل أيّ نشرٍ يفتقر إلى ذلك الاستحقاق أصنافَ هذه القدرة. قارن بين الإصدارات واحصل على ترخيص.
الفوترة قدرةٌ أساسية في Enterprise بلا رايةٍ مستقلّة لكل ميزة؛ فهي متاحة بمجرّد تثبيت حزمة Enterprise إلى جانب حزمة Core. لا يملك NextPDF Core (Apache-2.0) ولا NextPDF Pro أيّ نموذجٍ للخطط أو الحصص أو التجاوز؛ ولا يوجد لهذا السطح مكافئٌ في طبقةٍ أدنى. تخضع مشمولات الخطط والحصص والشروط التجارية لاتفاقية الترخيص، لا لفرضٍ في زمن التشغيل؛ وهذا المرجع ليس رأياً قانونياً أو تعاقدياً.
سطح واجهة البرمجة العامة
قسم بعنوان «سطح واجهة البرمجة العامة»تقع جميع الرموز ضمن NextPDF\Enterprise\Billing. أمّا الصفوف المُعلَّمة بـ substrate فتقع ضمن NextPDF\Enterprise\Billing\Substrate. وTenantContext هو نوع المستأجر المُصادَق عليه من NextPDF\Enterprise\SaaS.
| الرمز | المعاملات | السلوك الافتراضي | القيمة المُعادة | يرمي أو يفشل بـ | ملاحظات |
|---|---|---|---|---|---|
SaaSPlan (enum) | — | طبقات خطط مسنودة بسلاسل نصية: standard وadvanced وhigh_control | — | لا يرمي | تُعيد label() الاسم المعروض |
PlanDefinition::__construct | SaaSPlan $plan، float $includedCuQuota، list<CapabilityCode> $capabilities، non-empty-string $priceTier، bool $intelligencePackIncluded، bool $privacyPackIncluded | كائن قيمة خطة غير قابل للتغيير؛ يخزّن المدخلات كما هي | نسخة جديدة | لا يرمي | final readonly؛ خصائص عامة مُرقّاة |
PlanDefinition::includesCapability | CapabilityCode $capability | فحص عضوية بهوية صارمة | bool | لا يرمي | — |
PlanRegistry::__construct | list<PlanDefinition> $definitions | يفهرس التعريفات حسب الطبقة؛ ويفوز آخر تعريف لكل طبقة | سِجِلّ جديد | لا يرمي | لأغراض الاختبار ومجموعات الخطط ذات العلامة البيضاء |
PlanRegistry::get | SaaSPlan $plan | بحث قانوني عن الخطة | PlanDefinition | InvalidArgumentException عندما تكون الخطة غير مُسجّلة | — |
PlanRegistry::has | SaaSPlan $plan | فحص التسجيل | bool | لا يرمي | — |
PlanRegistry::defaultRegistry (static) | — | الإعدادات الافتراضية للإنتاج: Standard بـ 1,000 CU؛ وAdvanced بـ 5,000 CU إضافةً إلى Intelligence Pack؛ وHigh Control بـ 20,000 CU إضافةً إلى Intelligence Pack وPrivacy Pack | PlanRegistry | لا يرمي | استخدمها ما لم تستلزم الشروط التعاقدية تعريفات مخصّصة |
OveragePolicy (enum) | — | hard_stop وsoft_stop وbudget_alert | — | لا يرمي | تُطابق httpStatusCode() القيم 402 / 429 / 200؛ وisBlocking() صحيحة للإيقاف الصارم واللين فقط |
QuotaManager::__construct | PlanRegistry $planRegistry، OveragePolicy $overagePolicy | يربط السِّجِلّ بسياسة واحدة | نسخة جديدة | لا يرمي | — |
QuotaManager::checkQuota | TenantContext $tenant، SaaSPlan $plan، float $currentCu | يعود بصمت عند الحصة أو دونها، أو في ظل سياسة غير حاجبة | void | QuotaExceededException عند التجاوز الصارم في ظل سياسة حاجبة؛ وInvalidArgumentException من السِّجِلّ عند خطة غير مُسجّلة | resetsAt = أول يوم من الشهر التالي، منتصف الليل بتوقيت UTC |
QuotaManager::remainingQuota | SaaSPlan $plan، float $currentCu | قراءة صِرفة؛ لا تحجب أبداً | float | InvalidArgumentException من السِّجِلّ | سالبة عند التجاوز |
QuotaManager::usagePercentage | SaaSPlan $plan، float $currentCu | قراءة صِرفة؛ لا تحجب أبداً | float | InvalidArgumentException من السِّجِلّ | 0.0 عندما تكون الحصة المشمولة غير موجبة؛ وأعلى من 1.0 عند التجاوز |
OverageCalculator::calculate | PlanDefinition $plan، float $currentCu | يحسب لقطة تجاوز غير قابلة للتغيير | OverageResult | لا يرمي | final readonly، بلا حالة |
OverageResult | includedCu، usedCu، overageCu، usageRatio، isOverage | نتيجة حساب غير قابلة للتغيير | — | لا يرمي | overageCu = max(0, used - included)؛ وisOverage يتطلّب تجاوزاً صارماً |
BillingAlertType (enum) | — | quota_warning_80 وquota_warning_100 وbudget_exceeded وmonthly_cap_reached | — | لا يرمي | threshold() بالقيم 0.8 / 1.0 / 1.0 / 1.0؛ وseverity() بالقيم warning / critical / critical / critical |
BillingAlertService::__construct | AlertStateRepositoryInterface $alertState | يربط مخزن إزالة التكرار | نسخة جديدة | لا يرمي | — |
BillingAlertService::evaluate | TenantContext $tenant، SaaSPlan $plan، PlanDefinition $planDef، float $currentCu | يُطلق التنبيهات التي لم تُطلَق بعد بترتيب تصاعدي للعتبة ويسجّلها | list<BillingAlertType> | InvalidArgumentException عند عدم تطابق الخطة/التعريف | مفتاح إزالة التكرار: المستأجر، والنوع، وفترة YYYY-MM بتوقيت UTC |
BillingAlertService::clearAlerts | TenantContext $tenant | يمسح حالة الإطلاق للمستأجر للفترة الحالية بتوقيت UTC | void | تنتشر الإخفاقات المُعرَّفة في المستودع | يعيد تسليح التنبيهات ضمن الفترة نفسها |
AlertStateRepositoryInterface | hasAlertFired()، markAlertFired()، clearForPeriod() | عقد استمرارية دائم لإزالة تكرار التنبيهات | حسب كل دالة | مُعرَّف حسب التنفيذ | المُشغِّل يملك الديمومة عبر النسخ المتماثلة |
InMemoryAlertStateRepository | — | حالة إطلاق مسنودة بمصفوفة | حسب الواجهة | لا يرمي | لدورات حياة الطلب الواحد والاختبارات فقط |
QuotaExceededException | currentCu وlimitCu وresetsAt وtenantId وisSaaS للقراءة فقط | رفض حصة واعٍ بوضع النشر | — | هو الكائن القابل للرمي | httpStatusCode() بالقيمة 402 لـ SaaS / 403 للنشر المحلي؛ وspecCode() بالقيمة SPEC-BILLING-003 / SPEC-LIC-001؛ وتُنتج toErrorEnvelope() جسم خطأ مُهيكلاً |
DeploymentMode (enum) | — | saas وself_hosted_oss وlocal_development | — | لا يرمي | Substrate. enforcesQuota() صحيحة لـ Saas فقط؛ والانسحاب صريح دائماً |
QuotaEnforcementGuard::__construct | DeploymentMode، PlanResolverInterface، QuotaManager، UsageCounterStoreInterface | يُجمّع بوابة الحصة الحيّة | نسخة جديدة | لا يرمي | Substrate. final readonly |
QuotaEnforcementGuard::enforce | ?TenantContext $tenant، non-empty-string $featureKey، float $amount = 1.0 | بوابة حصة مُغلقة عند الفشل مع حجز ذرّي | QuotaDecision (النتائج المسموح بها فقط) | راجع تصنيف الرفض أدناه | Substrate. رَكِّبها بعد مصادقة المستأجر، وقبل المعالج القابل للفوترة |
PlanResolverInterface::resolve | TenantContext $tenant | يحلّ المستأجر إلى خطته وسياساته لكل ميزة | ResolvedPlan | NoPlanForTenantException | Substrate. اعتماد خطة افتراضية احتياطية للمستأجرين غير المعروفين عيبٌ برمجي |
RegistryPlanResolver | array<non-empty-string, ResolvedPlan> $plansByTenant | مُحلّل مسنود بخريطة | ResolvedPlan | NoPlanForTenantException للمستأجرين غير المُخطَّطين | Substrate. مُغلق عند الفشل بحكم البناء |
ResolvedPlan::policyFor | non-empty-string $featureKey | بحث عن السياسة في الخطة المُحلَّلة | ?QuotaPolicy | لا يرمي | Substrate. تعني null ميزة غير معروفة؛ وترفضها البوابة |
QuotaPolicy | non-empty-string $featureKey، float $limit، OveragePolicy $overagePolicy | حدّ لكل ميزة وسياسة عند الخرق | — | لا يرمي | Substrate. UNLIMITED = -1.0؛ والحدّ 0.0 يعني سماحاً صِفرياً، لا لامحدوداً؛ isUnlimited()، isBlocking() |
QuotaDecision | دوال ساكنة bypassed() وunlimited() وconsumed() | كائن قيمة لنتيجة مسموح بها | QuotaDecision | لا يرمي | Substrate. isAllowed() صحيحة دائماً؛ وكل رفضٍ يرمي بدلاً من ذلك |
UsageCounter | لقطة صف: المستأجر، والميزة، وحدود الفترة، used، limit، updatedAt | صف استخدام غير قابل للتغيير | — | لا يرمي | Substrate. قد تكون remaining() سالبة؛ وwouldExceed() صارمة |
UsageCounterStoreInterface::get | المستأجر، والميزة، وحدود الفترة، float $limit | يقرأ صف الاستخدام، مُنشئاً إياه بـ used = 0 عند غيابه | UsageCounter | UsageStoreUnavailableException | Substrate. لا يُعيد أبداً قيمة زائفة عند فشل الواجهة الخلفية |
UsageCounterStoreInterface::tryConsume | المستأجر، والميزة، وحدود الفترة، float $amount، float $limit | حجز ذرّي بالمقارنة والتعيين ضمن الحدّ | ?UsageCounter (null عندما يخرق الحجز الحدّ) | UsageStoreUnavailableException | Substrate. يجب أن يكون عملية ذرّية واحدة ضدّ المخزن الداعم |
InMemoryUsageCounterStore | — | تنفيذ مرجعي داخل العملية لعقد المخزن | حسب الواجهة | حسب الواجهة | Substrate. عملية واحدة فقط؛ يوثّق ثابت الذرّية |
QuotaEnforcementException (abstract) | — | النوع الأساس لكل رفضٍ في الركيزة | — | هو عائلة الكائنات القابلة للرمي | Substrate. يُصرّح كل نوع فرعي بـ httpStatusCode() |
public function checkQuota(TenantContext $tenant, SaaSPlan $plan, float $currentCu): voidpublic function evaluate( TenantContext $tenant, SaaSPlan $plan, PlanDefinition $planDef, float $currentCu,): arraypublic function enforce(?TenantContext $tenant, string $featureKey, float $amount = 1.0): QuotaDecisionpublic function tryConsume( string $tenantId, string $featureKey, DateTimeImmutable $periodStart, DateTimeImmutable $periodEnd, float $amount, float $limit,): ?UsageCounter;تصنيف الرفض في QuotaEnforcementGuard::enforce
| الاستثناء | حالة HTTP | يُرفع عند |
|---|---|---|
MissingTenantContextException | 401 | وضع SaaS بلا سياق مستأجر مُصادَق عليه |
NoPlanForTenantException | 402 | لا يجد المُحلّل خطة مُسنَدة إلى المستأجر |
UnknownFeatureException | 402 | لا تُعرّف الخطة المُحلَّلة أيّ سياسة لمفتاح الميزة |
UsageStoreUnavailableException | 503 | تعذُّر قراءة مخزن الاستخدام أو تحديثه ذرّياً؛ ويُرفع أيضاً عند $amount غير موجب |
QuotaExceededException | 402 (SaaS) / 403 (النشر المحلي) | تجاوز حصة سياسة حاجبة، أو استهلاك حجزٍ متزامن لآخر متّسع |
عقد السلوك
قسم بعنوان «عقد السلوك»- يشحن السِّجِلّ الافتراضي ثلاث طبقات (Standard / Advanced / High Control) بحصص CU ومجموعات قدرات متزايدة. ويفشل طلب خطة غير مُسجّلة بـ
InvalidArgumentExceptionصريح. - لا ترفع
QuotaManager::checkQuota()إلا عند تحقّق الشرطين معاً: السياسة حاجبة، والاستخدام الحالي أعلى بصرامة من الحصة المشمولة. ولا ترفع سياسة تنبيه الميزانية أبداً؛ ويُبلَّغ عن التجاوز عبر التنبيهات. remainingQuota()وusagePercentage()قراءتان صِرفتان ولا تحجبان أبداً. وتصبح الحصة المتبقية سالبة عند التجاوز؛ وتتجاوز نسبة الاستخدام1.0عند التجاوز.- تُقيَّم التنبيهات بترتيب تصاعدي للعتبة: تحذير 80%، وتحذير 100% (حَرِج)، ثم تجاوز-الميزانية (حَرِج). ويُشترَط في تجاوز-الميزانية تجاوزٌ صارم؛ والاستخدام عند 100% بالضبط يُطلق تحذير 100%، لا تجاوز-الميزانية.
- يُطلَق كل نوع تنبيه مرّة واحدة على الأكثر لكل مستأجر لكل فترة فوترة. وتُسجَّل حالة الإطلاق عبر
AlertStateRepositoryInterface، ومن ثمّ فإن إزالة التكرار دائمة بقدر ديمومة التنفيذ المُختار. - يتضمّن مفتاح إزالة التكرار فترة
YYYY-MMبتوقيت UTC. لذا يعيد شهرٌ تقويمي جديد تسليح كل نوع تنبيه تلقائياً؛ ولا يلزم أيّ استدعاء مسحٍ لإعادة التسليح عند التدوير. وتمسحclearAlerts()الفترة الحالية، فتعيد تسليح التنبيهات في منتصف الفترة، مثلاً بعد ترقية خطة. - يرفض حارس عدم-تطابق-الخطة في
evaluate()أيّ استدعاءٍ تختلف فيه الخطة المُقدَّمة عن تعريف الخطة، حمايةً من تعريفٍ من طبقةٍ مختلفة عن خطة المستأجر. - تُرسى جميع حسابات الفترة على توقيت UTC. ولحظة إعادة تعيين تجاوز الحصة هي أول يوم من الشهر التقويمي التالي عند منتصف الليل بتوقيت UTC؛ وينبغي لاستجابة الإيقاف اللين الإعلان عنها بوصفها أفق إعادة المحاولة.
QuotaEnforcementGuardمُغلق عند الفشل في وضع SaaS. فالمستأجر المفقود، والخطة المفقودة، والميزة غير المعروفة، وانقطاع المخزن، وخرق الحصة تُرفض جميعها؛ ولا شيء يمرّ إلى سماحٍ ضمني. ولا تنسحب النشرات غير الـ SaaS إلا ببناء الحارس بوضعDeploymentModeغير الـ SaaS.- تحجز السياسات الحاجبة الاستخدام عبر
UsageCounterStoreInterface::tryConsume، وهي مقارنة-وتعيين ذرّية. ولا تستطيع الطلبات المتزامنة مجتمعةً دفع الاستخدام فوق الحدّ؛ ويتلقّى خاسر السباقQuotaExceededExceptionحتى وإن نجح الفحص المسبق. - في ظل سياسة تنبيه الميزانية، يسجّل الحارس الاستهلاك بأفضل جهد ولا يرفض أبداً؛ ويظلّ الحجز الذي يتجاوز السقف اللين يسجّل الصف عند الحدّ.
QuotaExceededExceptionواعٍ بوضع النشر: تُطابَق رفوض SaaS بـ HTTP 402 برمز المواصفةSPEC-BILLING-003وتُعلَّم قابلة لإعادة المحاولة؛ وتُطابَق رفوض النشر المحلي بـ HTTP 403 بـSPEC-LIC-001.- لا تُصدر المكتبة استجابات HTTP بنفسها. ورموز الحالة المُصرَّح بها هي العقد لطبقة الحافة، التي تُطابق رفضاً مرميّاً باستجابة ويجب ألّا تستدعي المعالج القابل للفوترة.
الحالات الحدّية وأنماط الفشل
قسم بعنوان «الحالات الحدّية وأنماط الفشل»- حصة مشمولة غير موجبة. تُنتج
usagePercentage()وevaluate()وOverageCalculator::calculate()جميعها نسبة استخدام0.0بدلاً من القسمة على صفر. ومن ثمّ لا تُطلَق تنبيهات العتبة من النسبة وحدها أبداً. - تنبيه الميزانية مع تجاوزٍ كبير. يُعيد المدير والحارس كلاهما نتائج مسموحاً بها. لا تعامل غياب الاستثناء دليلاً على البقاء ضمن الحصة؛ راجع
OverageResultأو تدفّق التنبيهات. - عند الحدّ تماماً. تنجح
checkQuota()عندcurrentCu == includedCuQuota. ويتطلّبBudgetExceededتجاوزاً صارماً. وUsageCounter::wouldExceed()صارمة أيضاً. MonthlyCapReached. يُصرّح التعداد بنوع التنبيه الرابع هذا، لكنBillingAlertService::evaluate()لا تُصدره أبداً؛ فقائمة مرشّحيها تغطي التنبيهات الثلاثة للعتبة فقط. وهو محجوز لمُصدِرات تتبّع السقف خارج هذه الوحدة.- تعريفات طبقة مكرّرة. يفهرس
PlanRegistryحسب قيمة الطبقة؛ ويستبدل آخر تعريف لطبقةٍ ما سابقيه بصمت. ابنِ السِّجِلّات من قائمة مُزال منها التكرار. - السماح الصِفري مقابل اللامحدود. حدّ
QuotaPolicyبقيمة0.0يعني أن كل استهلاك في الفترة تجاوز. ولا يُعطّل القياسَ إلا الحارس السالبUNLIMITED؛ وisUnlimited()لا تحجب أبداً. - مقدار حجز غير موجب. ترفض
enforce()أيّ$amountغير موجب بالإغلاق عند الفشل عبرUsageStoreUnavailableException(503). وهذا عيبٌ في المُستدعِي، لا انقطاعٌ في المخزن. - انقطاع المخزن. يظهر أيّ فشلٍ في القراءة أو الحجز بوصفه
UsageStoreUnavailableExceptionويرفض. ولا يسمح الحارس أبداً بعملٍ غير مقيسٍ بينما القياس معطّل. - التنفيذات في الذاكرة.
InMemoryAlertStateRepositoryوInMemoryUsageCounterStoreصحيحان ضمن عملية PHP واحدة فقط. ويجب على النشرات متعدّدة النسخ توفير تنفيذاتٍ مسنودة بمخزن بيانات ذي ذرّية حقيقية؛ فالمخزن الذي يقرأ ثم يكتب عيبٌ يسمح بتجاوز الحصة تحت الحِمل. - وضع FIPS. لا تُجري الفوترة أيّ عمليات تعمية خاصة بها ولا سلوكاً خاصاً بـ FIPS. ويجب أن تنشأ هوية المستأجر التي تستهلكها من سياقٍ مُصادَق عليه يُوثَّق وضعه في FIPS مع سطح SaaS.
المطابقة
قسم بعنوان «المطابقة»| الادعاء | المعيار | البند |
|---|---|---|
| رمز الحالة 402 محجوز للاستخدام المستقبلي؛ ولا يحمل دلالات طلب معيارية خاصة به. | RFC 9110 | §15.5.3 |
| يشير 429 إلى أن العميل أرسل طلبات أكثر من اللازم في مدة زمنية معيّنة («تحديد المعدّل»). | RFC 6585 | §4 |
| يشير Retry-After إلى المدة التي ينبغي لوكيل المستخدم انتظارها قبل تقديم طلب متابعة. | RFC 9110 | §10.2.3 |
جميع البنود مُعاد صياغتها؛ ولا يستنسخ NextPDF النص المعياري. لا يقدّم NextPDF أيّ ادعاء مطابقة أو اعتماد لبروتوكول HTTP بشأن هذا السطح. إن مطابقة 402 / 429 / 200 التي تُصرّح بها OveragePolicy::httpStatusCode() ورموز الرفض 401 / 402 / 503 لدى الحارس هي عُرفٌ للمنتج متوائم مع البنود أعلاه: يحجز RFC 9110 الرمز 402، ومن ثمّ فإن استخدامه هنا لرفض الدفع هو العُرف الصناعي الشائع، لا دلالة مُعرّفة من IETF. وأفق إعادة المحاولة للإيقاف اللين (resetsAt) هو القيمة التي ينبغي لطبقة الحافة إظهارها بوصفها إرشاد Retry-After. أمّا إصدار استجابات HTTP الفعلية والترويسات وسلوك التخزين المؤقت فهو مسؤولية التطبيق المُضيف.
ملاحظات التطوير
قسم بعنوان «ملاحظات التطوير»- ركّب النموذج من
PlanRegistry::defaultRegistry()وسياسةOveragePolicyواحدة وQuotaManager؛ وأضفBillingAlertServiceمع تنفيذ دائم لـAlertStateRepositoryInterfaceللتنبيه. - رَكِّب
QuotaEnforcementGuardفي مسار الطلب بعد مصادقة المستأجر وقبل المعالج القابل للفوترة. التقطQuotaEnforcementExceptionوQuotaExceededExceptionالخاص بالفوترة عند الحافة وطابِقhttpStatusCode()بالاستجابة. - تعريفات الخطط في هذه الوحدة هي المصدر الوحيد للحقيقة في الفوترة؛ لا تُبقِ تعريف فوترة موازياً في مكانٍ آخر من نشرك.
- تجعل التنفيذات في الذاكرة السطح كله قابلاً لاختبار الوحدة دون إدخال/إخراج. الاختبارات الحدّية المُوصى بها: الاستخدام عند الحصة تماماً، ووحدة واحدة فوقها، وعتبات النسبة عند 0.8 و1.0، وحارس عدم-تطابق-الخطة، وسباق CAS (حجزان ضدّ آخر وحدة متّسع)، ورفض انقطاع المخزن.
- تحمل أصناف النموذج الأساسية
@since 2.2.0؛ وتحمل الركيزة@since 2.3.0. وخطّ الحزمة الحالي هو 3.1.0. - يملك المُشغِّل تنفيذات مستودع حالة التنبيه ومخزن الاستخدام، وديمومتها عبر النسخ المتماثلة، وأيّ إعادة تسليح للتنبيهات في منتصف الفترة عبر
clearAlerts().
حدود النشر
قسم بعنوان «حدود النشر»توثّق هذه الصفحة السلوك القابل للملاحظة خارجياً وسطح واجهة البرمجة العامة المدعوم فقط. أمّا مسارات فضاء الأسماء الداخلية، وأصناف المساعدة، وجداول الآليات، وأسماء ملفات كتيّب التشغيل، وبادئات التذاكر فخارج النطاق.