الفرق بين المراجعتين لصفحة: «Laravel/billing»

من موسوعة حسوب
ط نقل رؤيا-بنعطية صفحة Laravel/Cashier إلى Laravel/billing
لا ملخص تعديل
 
(12 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:Laravel Cashier}}</noinclude>
== مقدمة ==
== مقدمة ==
يقدم Laravel Cashier واجهة قويّة لاشتراكات خدمات الفواتير Stripe و Braintree، وهي تعالج تقريبًا كل شيفرات boilerplate الخاصة باشتراك الفواتير التي تخشى من كتابتها، وبالإضافة إلى إدارة الاشتراكات الأساسية، يستطيع Cashier التعامل مع القسائم (coupons)، ومبادلة الاشتراكات وكميّات الاشتراكات وفترات السماح بالإلغاء وحتى إنشاء ملفات PDF للفواتير.
يقدم Laravel Cashier واجهة قويّة لاشتراكات خدمات الفواتير Stripe و Braintree، وهي تعالج تقريبًا كل شيفرات boilerplate الخاصة باشتراك الفواتير التي تخشى من كتابتها، وبالإضافة إلى إدارة الاشتراكات الأساسية، يستطيع Cashier التعامل مع القسائم (coupons)، ومبادلة الاشتراكات وكميّات الاشتراكات وفترات السماح بالإلغاء وحتى إنشاء ملفات PDF للفواتير.
سطر 15: سطر 16:


==== تهجير قواعد البيانات ====
==== تهجير قواعد البيانات ====
قبل استخدام Cashier، سنحتاج أيضًا إلى إعداد قاعدة البيانات، وذلك عن طريق إضافة عدة أعمدة إلى جدول users وإنشاء جدول subscriptions جديد لاحتواء جميع اشتراكات عملائنا:<syntaxhighlight lang="php">
قبل استخدام Cashier، سنحتاج أيضًا إلى إعداد قاعدة البيانات، وذلك عن طريق إضافة عدة أعمدة إلى جدول <code>users</code> وإنشاء جدول <code>subscriptions</code> جديد لاحتواء جميع اشتراكات عملائنا:<syntaxhighlight lang="php">
Schema::table('users', function ($table) {
Schema::table('users', function ($table) {
     $table->string('stripe_id')->nullable();
     $table->string('stripe_id')->nullable();
سطر 36: سطر 37:
</syntaxhighlight>
</syntaxhighlight>


بمجرّد إنشاء التهجيرات، شغّل أمر <code>Artisan migrate</code>.
بمجرّد إنشاء التهجيرات، شغّل أمر <code>migrate</code> Artisan.


=== نموذج Billable ===
=== نموذج Billable ===
بعد ذلك، أضف سمة Billable إلى تعريف نموذجك، توفّر هذه السمة طرقًا مختلفة تسمح لك بتنفيذ مهام الفوترة الشائعة، كإنشاء الاشتراكات وتطبيق القسائم وتحديث بيانات بطاقة الائتمان:<syntaxhighlight lang="php3">
بعد ذلك، أضف سمة <code>Billable</code> إلى تعريف نموذجك، توفّر هذه السمة طرقًا مختلفة تسمح لك بتنفيذ مهام الفوترة الشائعة، كإنشاء الاشتراكات وتطبيق القسائم وتحديث بيانات بطاقة الائتمان:<syntaxhighlight lang="php3">
use Laravel\Cashier\Billable;
use Laravel\Cashier\Billable;


سطر 49: سطر 50:


==== مفاتيح الواجهة البرمجيّة API ====
==== مفاتيح الواجهة البرمجيّة API ====
ختامًا، يجب عليك ضبط مفتاح Stripe في ملف الضبط services.php، ويمكنك استرداد مفاتيح  Stripe API من لوحة تحكم Stripe:<syntaxhighlight lang="php">
ختامًا، يجب عليك ضبط مفتاح Stripe في ملف الضبط <code>services.php</code>، ويمكنك استرداد مفاتيح  Stripe API من لوحة تحكم Stripe:<syntaxhighlight lang="php">
'stripe' => [
'stripe' => [
     'model'  => App\User::class,
     'model'  => App\User::class,
سطر 61: سطر 62:


==== تحذيرات Braintree ====
==== تحذيرات Braintree ====
تعمل تطبيقات Stripe و Braintree بنفس الطريقة في عدة عمليات، فكلاهما يوفران فوترة الاشتراك ببطاقات الائتمان لكن يدعم Braintree بايبال أيضًا، ومع ذلك، يفتقر Braintree إلى بعض المميزات المدعومة من Stripe، ويجب عليك مراعاة ما يلي عند اتخاذ قرار استخدام Stripe أو Braintree:
تعمل تطبيقات Stripe و Braintree بنفس الطريقة في عدة عمليات، فكلاهما يوفران فوترة الاشتراك ببطاقات الائتمان لكن يدعم Paypal Braintree أيضًا، ومع ذلك، يفتقر Braintree إلى بعض المميزات المدعومة من Stripe، ويجب عليك مراعاة ما يلي عند اتخاذ قرار استخدام Stripe أو Braintree:
* يدعم Braintree Paypal على عكس Stripe.
* يدعم Paypal Braintree على عكس Stripe.


* لا يدعم Braintree توابع الزيادة والنقصان على الاشتراكات، وهذه حدود Braintree وليست حدود Cashier.
* لا يدعم Braintree توابع الزيادة والنقصان على الاشتراكات، وهذه حدود Braintree وليست حدود Cashier.
سطر 84: سطر 85:


==== تهجير قواعد البيانات ====
==== تهجير قواعد البيانات ====
قبل استخدام Cashier، سنحتاج إلى إعداد قاعدة البيانات، وذلك عن طريق إضافة عدة أعمدة إلى جدول users و إنشاء جدول subscriptions جديد لاحتواء جميع اشتراكات عملائنا:<syntaxhighlight lang="php">
قبل استخدام Cashier، سنحتاج إلى إعداد قاعدة البيانات، وذلك عن طريق إضافة عدة أعمدة إلى جدول <code>users</code> و إنشاء جدول <code>subscriptions</code> جديد لاحتواء جميع اشتراكات عملائنا:<syntaxhighlight lang="php">
Schema::table('users', function ($table) {
Schema::table('users', function ($table) {
     $table->string('braintree_id')->nullable();
     $table->string('braintree_id')->nullable();
سطر 106: سطر 107:
</syntaxhighlight>
</syntaxhighlight>


بمجرّد إنشاء التهجيرات، شغّل أمر Artisan migrate.
بمجرّد إنشاء التهجيرات، شغّل أمر <code>migrate</code> Artisan.


==== نموذج Billable ====
==== نموذج <code>Billable</code> ====
بعد ذلك، أضف سمة <code>Billable</code> إلى تعريف نموذجك:<syntaxhighlight lang="php">
بعد ذلك، أضف سمة <code>Billable</code> إلى تعريف نموذجك:<syntaxhighlight lang="php">
use Laravel\Cashier\Billable;
use Laravel\Cashier\Billable;
سطر 120: سطر 121:


=== مفاتيح الواجهة البرمجيّة API ===
=== مفاتيح الواجهة البرمجيّة API ===
ختامًا، يجب عليك ضبط الخيارات التاليّة في ملف الضبط services.php:<syntaxhighlight lang="php">
ختامًا، يجب عليك ضبط الخيارات التاليّة في ملف الضبط <code>services.php</code>:<syntaxhighlight lang="php">
'braintree' => [
'braintree' => [
     'model'  => App\User::class,
     'model'  => App\User::class,
سطر 159: سطر 160:
يجب أن يكون المعامل الأول الممرّر إلى تابع newSubscription هو اسم الاشتراك، إذا كان تطبيقك يوفّر نوع واحد من الاشتراكات، يمكنك تسميته main أو primary، وأما المعامل الثاني فهو تحديد خطة Stripe أو Braintree التي يشترك فيها المستخدم، ويجب أن تتوافق هذه القيمة مع معرّف Stripe أو Braintree.
يجب أن يكون المعامل الأول الممرّر إلى تابع newSubscription هو اسم الاشتراك، إذا كان تطبيقك يوفّر نوع واحد من الاشتراكات، يمكنك تسميته main أو primary، وأما المعامل الثاني فهو تحديد خطة Stripe أو Braintree التي يشترك فيها المستخدم، ويجب أن تتوافق هذه القيمة مع معرّف Stripe أو Braintree.


سيبدأ تابع create، والذي يقبل بطاقة ائتمان أو رمز مصدر Stripe، الاشتراك بالإضافة إلى تحديث قاعدة بياناتك بمعرّف العميل ومعلومات الفوترة ذات الصلة.
سيبدأ التابع <code>create</code>، والذي يقبل بطاقة ائتمان أو رمز مصدر Stripe، الاشتراك بالإضافة إلى تحديث قاعدة بياناتك بمعرّف العميل ومعلومات الفوترة ذات الصلة.


==== بيانات المستخدم إضافيّة ====
==== بيانات المستخدم إضافيّة ====
إذا كنت ترغب في تحديد تفاصيل إضافيّة للعميل، فيمكنك القيام بذلك عن طريق تمريرها كمعامل ثاني إلى التابع create:<syntaxhighlight lang="php">
إذا كنت ترغب في تحديد تفاصيل إضافيّة للعميل، فيمكنك القيام بذلك عن طريق تمريرها كمعامل ثاني إلى التابع <code>create</code>:<syntaxhighlight lang="php">
$user->newSubscription('main', 'monthly')->create($stripeToken, [
$user->newSubscription('main', 'monthly')->create($stripeToken, [
     'email' => $email,
     'email' => $email,
سطر 180: سطر 181:


=== التحقق من حالة الاشتراك ===
=== التحقق من حالة الاشتراك ===
بمجرد اشتراك المستخدم بتطبيقك، يمكنك التحقق بسهولة من حالة الاشتراك باستخدام مجموعة متنوعة من التوابع المناسبة، فتابع subscribed يرجع true إذا كان للمستخدم اشتراك نشط، وحتى إذا كان الاشتراك حاليًا ضمن الفترة التجريبيّة:<syntaxhighlight lang="php">
بمجرد اشتراك المستخدم بتطبيقك، يمكنك التحقق بسهولة من حالة الاشتراك باستخدام مجموعة متنوعة من التوابع المناسبة، فالتابع <code>subscribed</code> يرجع <code>true</code> إذا كان للمستخدم اشتراك نشط، وحتى إذا كان الاشتراك حاليًا ضمن الفترة التجريبيّة:<syntaxhighlight lang="php">
if ($user->subscribed('main')) {
if ($user->subscribed('main')) {
   //
   //
سطر 212: سطر 213:


==== حالة الاشتراك الملغى ====
==== حالة الاشتراك الملغى ====
لتحديد ما إذا كان المستخدم مشتركًا نشيطًا سابقًا ولكنه ألغى اشتراكه، يمكنك استخدام تابع cancelled:<syntaxhighlight lang="php">
لتحديد ما إذا كان المستخدم مشتركًا نشيطًا سابقًا ولكنه ألغى اشتراكه، يمكنك استخدام تابع <code>cancelled</code>:<syntaxhighlight lang="php">
if ($user->subscription('main')->cancelled()) {
if ($user->subscription('main')->cancelled()) {
   //
   //
سطر 218: سطر 219:
</syntaxhighlight>
</syntaxhighlight>


يمكنك أيضًا تحديد ما إذا كان المستخدم قد ألغى اشتراكه ولكنه لا يزال في فترة "السماح" حتى انتهاء صلاحيّة اشتراكه بالكامل، فعلى سبيل المثال، إذا الغى المستخدم اشتراكه في الخامس من شهر آذار/مارس والذي من المقرر في الأصل أن تنتهي صلاحيته في 10 من آذار/مارس، فسيكون المستخدم في فترة "السماح" حتى 10 من آذار/مارس، ولاحظ أن تابع subscribed سيرجع true في هذه الحالة:<syntaxhighlight lang="php">
يمكنك أيضًا تحديد ما إذا كان المستخدم قد ألغى اشتراكه ولكنه لا يزال في فترة "السماح" حتى انتهاء صلاحيّة اشتراكه بالكامل، فعلى سبيل المثال، إذا الغى المستخدم اشتراكه في الخامس من شهر آذار/مارس والذي من المقرر في الأصل أن تنتهي صلاحيته في 10 من آذار/مارس، فسيكون المستخدم في فترة "السماح" حتى 10 من آذار/مارس، ولاحظ أن التابع <code>subscribed</code> سيرجع <code>true</code> في هذه الحالة:<syntaxhighlight lang="php">
if ($user->subscription('main')->onGracePeriod()) {
if ($user->subscription('main')->onGracePeriod()) {
   //
   //
سطر 225: سطر 226:


=== تغيير الخطط ===
=== تغيير الخطط ===
قد يرغب المستخدم بعد اشتراك في تطبيقك في تغييره إلى خطة اشتراك جديدة، ولاستبدال اشتراك جديد باشتراك المستخدم الحالي، مرّر معرّف الخطة إلى تابع <code>swap</code>:<syntaxhighlight lang="php">
قد يرغب المستخدم بعد اشتراك في تطبيقك في تغييره إلى خطة اشتراك جديدة، ولاستبدال اشتراك جديد باشتراك المستخدم الحالي، مرّر معرّف الخطة إلى التابع <code>swap</code>:<syntaxhighlight lang="php">
$user = App\User::find(1);
$user = App\User::find(1);


سطر 278: سطر 279:


=== إلغاء الاشتراكات ===
=== إلغاء الاشتراكات ===
لإلغاء اشتراك، استدع التابع cancel على اشتراك المستخدم:<syntaxhighlight lang="php">
لإلغاء اشتراك، استدع التابع <code>cancel</code> على اشتراك المستخدم:<syntaxhighlight lang="php">
$user->subscription('main')->cancel();
$user->subscription('main')->cancel();
</syntaxhighlight>
</syntaxhighlight>


عند إلغاء الاشتراك، سيعيّن Cashier بشكل تلقائي عمود ends_at في قاعدة بياناتك، وسيُستخدم هذا العمود لمعرفة متى يجب على التابع subscribed إرجاع القيمة false، فعلى سبيل المثال، إذا ألغى عميل اشتراكه في الأول من مارس،ولم يكن من المقرر أن ينتهي الاشتراك حتى الخامس من مارس، فسيبقى التابع subscribed يرجع true حتى تاريخ 5 مارس.
عند إلغاء الاشتراك، سيعيّن Cashier بشكل تلقائي عمود <code>ends_at</code> في قاعدة بياناتك، وسيُستخدم هذا العمود لمعرفة متى يجب على التابع <code>subscribed</code> إرجاع القيمة <code>false</code>، فعلى سبيل المثال، إذا ألغى عميل اشتراكه في الأول من مارس،ولم يكن من المقرر أن ينتهي الاشتراك حتى الخامس من مارس، فسيبقى التابع <code>subscribed</code> يرجع <code>true</code> حتى تاريخ 5 مارس.


يمكنك تحديد ما إذا كان المستخدم قد ألغى اشتراكه ولكن لا يزال في فترة "السماح" عن طريق استخدام التابع <code>onGracePeriod</code>:<syntaxhighlight lang="php">
يمكنك تحديد ما إذا كان المستخدم قد ألغى اشتراكه ولكن لا يزال في فترة "السماح" عن طريق استخدام التابع <code>onGracePeriod</code>:<syntaxhighlight lang="php">
سطر 290: سطر 291:
</syntaxhighlight>
</syntaxhighlight>


إذا رغبت في إنهاء الاشتراك فورًا، فاستدع التابع cancelNow على اشتراك المستخدم:<syntaxhighlight lang="php">
إذا رغبت في إنهاء الاشتراك فورًا، فاستدع التابع <code>cancelNow</code> على اشتراك المستخدم:<syntaxhighlight lang="php">
$user->subscription('main')->cancelNow();
$user->subscription('main')->cancelNow();
</syntaxhighlight>
</syntaxhighlight>


=== استئناف الاشتراكات ===
=== استئناف الاشتراكات ===
إذا ألغى مستخدم اشتراكه ويرغب في استئنافه استخدم التابع resume، ويجب على المستخدم أن يظل في فترة السماح لاستئناف اشتراكه:<syntaxhighlight lang="php">
إذا ألغى مستخدم اشتراكه ويرغب في استئنافه استخدم التابع <code>resume</code>، ويجب على المستخدم أن يظل في فترة السماح لاستئناف اشتراكه:<syntaxhighlight lang="php">
$user->subscription('main')->resume();
$user->subscription('main')->resume();
</syntaxhighlight>
</syntaxhighlight>
سطر 309: سطر 310:


=== مع واجهة بطاقة الائتمان ===
=== مع واجهة بطاقة الائتمان ===
إذا كنت ترغب في توفير فترات تجريبيّة لعملائك مع الاستمرار في جمع معلومات طريقة الدفع، يجب عليك استخدام التابع trialDays عند إنشائك للاشتراك:<syntaxhighlight lang="php">
إذا كنت ترغب في توفير فترات تجريبيّة لعملائك مع الاستمرار في جمع معلومات طريقة الدفع، يجب عليك استخدام التابع <code>trialDays</code> عند إنشائك للاشتراك:<syntaxhighlight lang="php">
$user = User::find(1);
$user = User::find(1);


سطر 321: سطر 322:
تنبيه: إذا لم يلغي العميل اشتراكه قبل انتهاء الفترة التجريبيّة فسُتفرض الرسوم فور انتهاء الفترة التجريبيّة، لذلك يجب عليك التأكد من إبلاغ المستخدمين بتاريخ انتهاء الفترة التجريبيّة.
تنبيه: إذا لم يلغي العميل اشتراكه قبل انتهاء الفترة التجريبيّة فسُتفرض الرسوم فور انتهاء الفترة التجريبيّة، لذلك يجب عليك التأكد من إبلاغ المستخدمين بتاريخ انتهاء الفترة التجريبيّة.


يتيح لك التابع trialUntil توفير نسخة DateTime لتحديد موعد انتهاء الفترة التجريبيّة:<syntaxhighlight lang="php">
يتيح لك التابع <code>trialUntil</code> توفير نسخة <code>DateTime</code> لتحديد موعد انتهاء الفترة التجريبيّة:<syntaxhighlight lang="php">
use Carbon\Carbon;
use Carbon\Carbon;


سطر 329: سطر 330:
</syntaxhighlight>
</syntaxhighlight>


يمكنك معرفة ما إذا كان المستخدم في فترته التجريبيّة أو لا إما باستخدام التابع onTrial على نسخة المستخدم أو باستخدام التابع onTrial على نسخة الاشتراك، فالمثالان التاليان متطابقان:<syntaxhighlight lang="php">
يمكنك معرفة ما إذا كان المستخدم في فترته التجريبيّة أو لا إما باستخدام التابع <code>onTrial</code> على نسخة المستخدم أو باستخدام التابع <code>onTrial</code> على نسخة الاشتراك، فالمثالان التاليان متطابقان:<syntaxhighlight lang="php">
if ($user->onTrial('main')) {
if ($user->onTrial('main')) {
   //
   //
سطر 339: سطر 340:
</syntaxhighlight>
</syntaxhighlight>


==== بدون واجهة بطاقة الائتمان ====
=== بدون واجهة بطاقة الائتمان ===
إذا كنت ترغب في تقديم فترات تجريبيّة دون جمع معلومات عن طريقة دفع المستخدم، يمكنك تعيين عمود trial_ends_at في سجل المستخدم بناءً على تاريخ انتهاء الإصدار التجريبي المطلوب، ويتم ذلك عادةً أثناء تسجيل المستخدم:<syntaxhighlight lang="php">
إذا كنت ترغب في تقديم فترات تجريبيّة دون جمع معلومات عن طريقة دفع المستخدم، يمكنك تعيين عمود <code>trial_ends_at</code> في سجل المستخدم بناءً على تاريخ انتهاء الإصدار التجريبي المطلوب، ويتم ذلك عادةً أثناء تسجيل المستخدم:<syntaxhighlight lang="php">
$user = User::create([
$user = User::create([
   // Populate other user properties...
   // ملأ بقية خصائص المستخدم
     'trial_ends_at' => now()->addDays(10),
     'trial_ends_at' => now()->addDays(10),
]);
]);
</syntaxhighlight>
</syntaxhighlight>


تنبيه: تأكد من إضافة تاريخ لـ trial_ends_at لتعريف النموذج.
تنبيه: تأكد من إضافة تاريخ لـ <code>trial_ends_at</code> لتعريف النموذج.


يشير Cashier إلى نوع الفترة التجريبيّة على أنها "تجربة عامة"، نظرًا لأنه غير مرتبط بأي اشتراك حالي، وسيُرجع التابع <code>onTrial</code> في نسخة <code>User</code> القيمة <code>true</code> إذا لم يتجاوز التاريخ الحالي قيمة <code>trial_ends_at</code>:<syntaxhighlight lang="php">
يشير Cashier إلى نوع الفترة التجريبيّة على أنها "تجربة عامة"، نظرًا لأنه غير مرتبط بأي اشتراك حالي، وسيُرجع التابع <code>onTrial</code> في نسخة <code>User</code> القيمة <code>true</code> إذا لم يتجاوز التاريخ الحالي قيمة <code>trial_ends_at</code>:<syntaxhighlight lang="php">
if ($user->onTrial()) {
if ($user->onTrial()) {
   // User is within their trial period...
   // المستخدم في الفترة التجريبية
}
}
</syntaxhighlight>
</syntaxhighlight>
سطر 357: سطر 358:
يمكنك أيضًا استخدام التابع <code>onGenericTrial</code> إذا أردت معرفة على وجه التحديد أن المستخدم ضمن فترة النسخة التجريبيّة العامة ولم ينشئ اشتراكًا فعليًّا بعد:<syntaxhighlight lang="php">
يمكنك أيضًا استخدام التابع <code>onGenericTrial</code> إذا أردت معرفة على وجه التحديد أن المستخدم ضمن فترة النسخة التجريبيّة العامة ولم ينشئ اشتراكًا فعليًّا بعد:<syntaxhighlight lang="php">
if ($user->onGenericTrial()) {
if ($user->onGenericTrial()) {
   // User is within their "generic" trial period...
   // المستخدم في الفترة التجريبية العامة
}
}
</syntaxhighlight>
</syntaxhighlight>
سطر 367: سطر 368:
</syntaxhighlight>
</syntaxhighlight>


== معالجة خطّافي الويب في Stripe ‏ Stripe Webhooks ==
== معالجة خطاطيف الويب في Stripe ‏ ==
يمكن لكل من Stripe وBraintree إعلام تطبيقك بمجموعة من الأحداث عبر خطاطف الويب (webhooks)، ولمعالجة خطّافي الويب في Stripe، يجب عليك تعريف المسار الذي يشير إلى وحدة تحكم  خطّاف الويب الخاص بـ Cashier، وستُعالج وحدة التحكم هذه جميع طلبات خطّاف الويب الواردة وترسلها إلى تابع وحدة التحكم المناسب:<syntaxhighlight lang="php">
يمكن لكل من Stripe وBraintree إعلام تطبيقك بمجموعة من الأحداث عبر خطاطيف الويب (webhooks)، ولمعالجة خطاطيف الويب في Stripe، يجب عليك تعريف المسار الذي يشير إلى وحدة تحكم  خطّاف الويب الخاص بـ Cashier، وستُعالج وحدة التحكم هذه جميع طلبات خطّاف الويب الواردة وترسلها إلى تابع وحدة التحكم المناسب:<syntaxhighlight lang="php">
Route::post(
Route::post(
     'stripe/webhook',
     'stripe/webhook',
سطر 380: سطر 381:
بشكل افتراضي، ستتعامل وحدة التحكم تلقائيًا مع إلغاء الاشتراكات التي تحتوي على عدد كبير من محاولات الحصول على الرسوم الفاشلة (كما هو محدد بواسطة إعدادات Stripe)، ومع ذلك، كما سنكتشف قريبًا، يمكننا توسيع وحدة التحكم للتعامل مع أي حدث خطاف ويب ترغب به.
بشكل افتراضي، ستتعامل وحدة التحكم تلقائيًا مع إلغاء الاشتراكات التي تحتوي على عدد كبير من محاولات الحصول على الرسوم الفاشلة (كما هو محدد بواسطة إعدادات Stripe)، ومع ذلك، كما سنكتشف قريبًا، يمكننا توسيع وحدة التحكم للتعامل مع أي حدث خطاف ويب ترغب به.


=== خطافو الويب وحماية CSRF ===
=== خطاطيف الويب وحماية CSRF ===
نظرًا لأن خطّافي ويب Stripe تحتاج إلى تجاوز حماية CSRF الخاصة بإطار Laravel، تأكد من وضع عنوان URI كاستثناء في البرمجيّة الوسيطة  VerifyCsrfToken الخاصة بك أو ضع المسار خارج مجموعة البرمجيّة الوسيطة web:<syntaxhighlight lang="php">
نظرًا لأن خطاطيف ويب Stripe تحتاج إلى تجاوز [[Laravel/csrf|حماية CSRF]] الخاصة بإطار Laravel، تأكد من وضع عنوان URI كاستثناء في البرمجيّة الوسيطة  <code>VerifyCsrfToken</code> الخاصة بك أو ضع المسار خارج مجموعة البرمجيّة الوسيطة web:<syntaxhighlight lang="php">
protected $except = [
protected $except = [
     'stripe/*',
     'stripe/*',
سطر 387: سطر 388:
</syntaxhighlight>
</syntaxhighlight>


=== تعريف معالجات أحداث خطّافي الويب ===
=== تعريف معالجات أحداث خطاطيف الويب ===
سيتعامل Cashier بشكل تلقائي بإلغاء الاشتراك عند فشل شحن المبلغ، لكن إذا كان لديك أحداث خطّافي ويب Stripe ترغب في معالجتها، فوسّع وحدة التحكم خطّاف الويب ويجب أن تكون أسماء التوابع متطابقة مع اتفاقيّة Cashier المتوقعة، والتي تنصّ على أنه يجب أن تبدأ بالكلمة handle وتستخدم حالة سِنَام الجمل (camelCase) لاسم خطّاف الويب الذي ترغب في معالجته. فعلى سبيل المثال، إذا كنت ترغب في معالجة خطاف الويب الخاص بالخطاف invoice.payment_succeeded فيجب عليك إضافة التابع handleInvoicePaymentSucceeded إلى وحدة التحكم:<syntaxhighlight lang="php">
سيتعامل Cashier بشكل تلقائي بإلغاء الاشتراك عند فشل شحن المبلغ، لكن إذا كان لديك أحداث خطاطيف ويب Stripe ترغب في معالجتها، فوسّع وحدة التحكم خطّاف الويب ويجب أن تكون أسماء التوابع متطابقة مع اتفاقيّة Cashier المتوقعة، والتي تنصّ على أنه يجب أن تبدأ بالكلمة handle وتستخدم حالة سِنَام الجمل (camelCase) لاسم خطّاف الويب الذي ترغب في معالجته. فعلى سبيل المثال، إذا كنت ترغب في معالجة خطاف الويب الخاص بالخطاف <code>invoice.payment_succeeded</code> فيجب عليك إضافة التابع <code>handleInvoicePaymentSucceeded</code> إلى وحدة التحكم:<syntaxhighlight lang="php">
<?php
<?php


سطر 398: سطر 399:
{
{
     /**
     /**
     * التعامل مع خطّافي الويب.
     * التعامل مع خطاطيف الويب.
     *
     *
     * @param  مصفوفة  $payload
     * @param  مصفوفة  $payload
سطر 405: سطر 406:
     public function handleInvoicePaymentSucceeded($payload)
     public function handleInvoicePaymentSucceeded($payload)
     {
     {
       // Handle The Event
       // معالجة الحدث
     }
     }
}
}
سطر 417: سطر 418:
</syntaxhighlight>
</syntaxhighlight>


==== اشتراكات فاشلة ====
=== اشتراكات فاشلة ===
ماذا لو انتهت صلاحيّة بطاقة ائتمان العميل؟ لا تقلق! يحتوي Cashier على وحدة تحكم خطاف ويب يمكنها إلغاء اشتراك العميل بسهولة.
ماذا لو انتهت صلاحيّة بطاقة ائتمان العميل؟ لا تقلق! يحتوي Cashier على وحدة تحكم خطاف ويب يمكنها إلغاء اشتراك العميل بسهولة.


سطر 429: سطر 430:
وهذا كل شيء، ستُلتقط المدفوعات الفاشلة وتُعالج عن طريق وحدة التحكم، وستلغي وحدة التحكم اشتراك العميل عندما يعلن Stripe فشل الاشتراك (عادةً بعد ثلاث محاولات دفع فاشلة).
وهذا كل شيء، ستُلتقط المدفوعات الفاشلة وتُعالج عن طريق وحدة التحكم، وستلغي وحدة التحكم اشتراك العميل عندما يعلن Stripe فشل الاشتراك (عادةً بعد ثلاث محاولات دفع فاشلة).


معالجة خطّافي الويب في Braintree
== معالجة خطاطيف الويب في Braintree ==
 
يمكن لكل من Stripe وBraintree إعلام تطبيقك بمجموعة من الأحداث عبر خطاطيف الويب، ولمعالجة خطاطيف ويب Braintree، يجب عليك تعريف المسار الذي يشير إلى وحدة تحكم خطّاف الويب الخاص بـ Cashier، وستعالج وحدة التحكم هذه جميع طلبات خطّاف الويب الواردة وترسلها إلى تابع وحدة التحكم المناسب:<syntaxhighlight lang="php">
يمكن لكل من Stripe وBraintree إعلام تطبيقك بمجموعة من الأحداث عبر خطّافي الويب، ولمعالجة خطّافي ويب Braintree، يجب عليك تعريف المسار الذي يشير إلى وحدة تحكم خطّاف الويب الخاص بـ Cashier، وستعالج وحدة التحكم هذه جميع طلبات خطّاف الويب الواردة وترسلها إلى تابع وحدة التحكم المناسب:<syntaxhighlight lang="php">
Route::post(
Route::post(
     'braintree/webhook',
     'braintree/webhook',
سطر 443: سطر 443:


=== خطاطيف الويب وحماية CSRF ===
=== خطاطيف الويب وحماية CSRF ===
نظرًا لأن Braintree webhooks تحتاج إلى تجاوز حماية CSRF الخاصة بإطار Laravel، فتأكد من وضع URI كاستثناء في وسيطة VerifyCsrfToken الخاصة بك أو ضع مسار خارج مجموعة وسيطة web:<syntaxhighlight lang="php">
نظرًا لأن خطاطيف ويب Braintree تحتاج إلى تجاوز [[Laravel/csrf|حماية CSRF]] الخاصة بإطار [[Laravel]]، فتأكد من وضع URI كاستثناء في وسيطة <code>VerifyCsrfToken</code> الخاصة بك أو ضع مسار خارج مجموعة وسيطة web:<syntaxhighlight lang="php">
protected $except = [
protected $except = [
     'braintree/*',
     'braintree/*',
سطر 449: سطر 449:
</syntaxhighlight>
</syntaxhighlight>


=== تعريف معالجات أحداث خطّافي الويب ===
=== تعريف معالجات أحداث خطاطيف الويب ===
سيتعامل Cashier بشكل تلقائي بإلغاء الاشتراك عند فشل شحن المبلغ، لكن إذا كان لديك أحداث Braintree خطّاف ويب ترغب في معالجتها، فوسّع وحدة التحكم خطّاف الويب ويجب أن تكون أسماء التوابع متطابقة مع اتفاقيّة Cashier المتوقعة، والتي تنصّ على أنه يجب أن تبدأ بالكلمة handle وتستخدم حالة سِنَام الجمل (camelCase) لاسم خطّاف الويب الذي ترغب في معالجته. فعلى سبيل المثال، إذا كنت ترغب في التعامل مع خطّاف الويب <code>dispute_opened</code> فيجب عليك إضافة التابع <code>handleDisputeOpened</code> إلى وحدة التحكم:<syntaxhighlight lang="php">
سيتعامل Cashier بشكل تلقائي بإلغاء الاشتراك عند فشل شحن المبلغ، لكن إذا كان لديك أحداث Braintree خطّاف ويب ترغب في معالجتها، فوسّع وحدة التحكم خطّاف الويب ويجب أن تكون أسماء التوابع متطابقة مع اتفاقيّة Cashier المتوقعة، والتي تنصّ على أنه يجب أن تبدأ بالكلمة handle وتستخدم حالة سِنَام الجمل (camelCase) لاسم خطّاف الويب الذي ترغب في معالجته. فعلى سبيل المثال، إذا كنت ترغب في التعامل مع خطّاف الويب <code>dispute_opened</code> فيجب عليك إضافة التابع <code>handleDisputeOpened</code> إلى وحدة التحكم:<syntaxhighlight lang="php">
<?php
<?php
سطر 488: سطر 488:


=== رسم بسيط ===
=== رسم بسيط ===
تنبيه: عند استخدام Stripe، سيقبل التابع charge المقدار الذي ترغب في خصمه في أدنى مقام للعملة المستخدمة في طلب اشتراكك، ومع ذلك، عند استخدام Braintree، يجب عليك تمرير المبلغ الكامل بالدولار إلى التابع charge:
تنبيه: عند استخدام Stripe، سيقبل التابع <code>charge</code> المقدار الذي ترغب في خصمه في أدنى مقام للعملة المستخدمة في طلب اشتراكك، ومع ذلك، عند استخدام Braintree، يجب عليك تمرير المبلغ الكامل بالدولار إلى التابع <code>charge</code>:


إذا كنت ترغب في إجراء دفعة واحدة لبطاقة ائتمان أحد العملاء المشتركين، فيمكنك استخدام التابع charge على نسخة نموذج billable.<syntaxhighlight lang="php">
إذا كنت ترغب في إجراء دفعة واحدة لبطاقة ائتمان أحد العملاء المشتركين، فيمكنك استخدام التابع <code>charge</code> على نسخة نموذج <code>Billable</code>.<syntaxhighlight lang="php">
// Stripe Accepts Charges In Cents...
// centsتقبل الدفعات بال Stripe
$user->charge(100);
$user->charge(100);


// Braintree Accepts Charges In Dollars...
//Dollarsتقبل الدفعات بال Braitree
$user->charge(1);
$user->charge(1);
</syntaxhighlight>
</syntaxhighlight>


يقبل التابع charge مصفوفة كمعامل ثاني مما يسمح لك بتمرير أي خيارات ترغب في تضمينها لرسوم إنشاء Stripe / Braintree، راجع توثيقات Stripe أو Braintree المتعلقة بالخيارات المتاحة لك عند إنشاء الرسوم:<syntaxhighlight lang="php">
يقبل التابع <code>charge</code> مصفوفة كمعامل ثاني مما يسمح لك بتمرير أي خيارات ترغب في تضمينها لرسوم إنشاء Stripe / Braintree، راجع توثيقات Stripe أو Braintree المتعلقة بالخيارات المتاحة لك عند إنشاء الرسوم:<syntaxhighlight lang="php">
$user->charge(100, [
$user->charge(100, [
     'custom_option' => $value,
     'custom_option' => $value,
سطر 504: سطر 504:
</syntaxhighlight>
</syntaxhighlight>


سيرمي التابع charge استثناء إذا فشلت عمليّة الشحن، وإذا نجحت، فستعاد إجابة Stripe أو Braintree كاملة من التابع:<syntaxhighlight lang="php">
سيرمي التابع <code>charge</code> استثناء إذا فشلت عمليّة الشحن، وإذا نجحت، فستعاد إجابة Stripe أو Braintree كاملة من التابع:<syntaxhighlight lang="php">
try {
try {
     $response = $user->charge(100);
     $response = $user->charge(100);
سطر 513: سطر 513:


=== الشحن مع الفاتورة ===
=== الشحن مع الفاتورة ===
قد تحتاج في بعض الأحيان إلى تحصيل رسوم لمرة واحدة ولكن ترغب أيضًا في إنشاء فاتورة لتحصيل الرسوم حتى تتمكن من تقديم إيصال بصيغة PDF إلى عميلك، يسمح لك التابع invoiceFor بذلك. فعلى سبيل المثال، لنفرض على العميل رسوم 5.00$ لمرة واحدة:<syntaxhighlight lang="php">
قد تحتاج في بعض الأحيان إلى تحصيل رسوم لمرة واحدة ولكن ترغب أيضًا في إنشاء فاتورة لتحصيل الرسوم حتى تتمكن من تقديم إيصال بصيغة PDF إلى عميلك، يسمح لك التابع <code>invoiceFor</code> بذلك. فعلى سبيل المثال، لنفرض على العميل رسوم 5.00$ لمرة واحدة:<syntaxhighlight lang="php">
// Stripe Accepts Charges In Cents...
// centsتقبل الدفعات بال Stripe


$user->invoiceFor('One Time Fee', 500);
$user->invoiceFor('One Time Fee', 500);


// Braintree Accepts Charges In Dollars...
// dollarsتقبل الدفعات بال Braitree


$user->invoiceFor('One Time Fee', 5);
$user->invoiceFor('One Time Fee', 5);
سطر 536: سطر 536:
</syntaxhighlight>
</syntaxhighlight>


سينشئ التابع <code>invoiceFor</code> فاتورة Stripe والتي ستعيد محاولات الفوترة الفاشلة، وإذا كنت لا ترغب في إنشاء فاتورة لإعادة المحاولة مع العمليات الفاشلة، ستحتاج إلى إغلاقها باستخدام الواجهة Stripe البرمجيّة بعد أول عمليّة تحصيل رسوم فاشلة.
سينشئ التابع <code>invoiceFor</code> فاتورة Stripe والتي ستعيد محاولات الفوترة الفاشلة، وإذا كنت لا ترغب في إنشاء فاتورة لإعادة المحاولة مع العمليات الفاشلة، ستحتاج إلى إغلاقها باستخدام واجهة Stripe البرمجية بعد أول عمليّة تحصيل رسوم فاشلة.


== الفواتير ==
== الفواتير ==
سطر 542: سطر 542:
$invoices = $user->invoices();
$invoices = $user->invoices();


// تضمين الفواتير المعلّقة في النتائج...
// تضمين الفواتير المعلّقة في النتائج
$invoices = $user->invoicesIncludingPending();
$invoices = $user->invoicesIncludingPending();


سطر 573: سطر 573:
== مصادر ==
== مصادر ==
* [https://laravel.com/docs/5.6/billing صفحة Laravel Cashier في توثيق Laravel الرسمي].
* [https://laravel.com/docs/5.6/billing صفحة Laravel Cashier في توثيق Laravel الرسمي].
[[تصنيف:Laravel|{{SUBPAGENAME}}]]
[[تصنيف:Laravel Official Packages|{{SUBPAGENAME}}]]

المراجعة الحالية بتاريخ 14:11، 23 أكتوبر 2018

مقدمة

يقدم Laravel Cashier واجهة قويّة لاشتراكات خدمات الفواتير Stripe و Braintree، وهي تعالج تقريبًا كل شيفرات boilerplate الخاصة باشتراك الفواتير التي تخشى من كتابتها، وبالإضافة إلى إدارة الاشتراكات الأساسية، يستطيع Cashier التعامل مع القسائم (coupons)، ومبادلة الاشتراكات وكميّات الاشتراكات وفترات السماح بالإلغاء وحتى إنشاء ملفات PDF للفواتير.

تنبيه: إذا كنت تضع رسوم لمرة واحدةً فقط ولا توفّر الاشتراكات، فيجب عليك أن لا تستخدم Cashier، وبدلًا من ذلك، يجب عليك استخدام حزمة برمجيات التطوير (SDK) الخاصة بـ Braintree و Stripe مباشرةً.

الضبط

Stripe

Composer

أولًا، أضف حزمة Cashier الخاصة بخدمة Stripe إلى اعتماديّاتك:

composer require "laravel/cashier":"~7.0"

تهجير قواعد البيانات

قبل استخدام Cashier، سنحتاج أيضًا إلى إعداد قاعدة البيانات، وذلك عن طريق إضافة عدة أعمدة إلى جدول users وإنشاء جدول subscriptions جديد لاحتواء جميع اشتراكات عملائنا:

Schema::table('users', function ($table) {
    $table->string('stripe_id')->nullable();
    $table->string('card_brand')->nullable();
    $table->string('card_last_four')->nullable();
    $table->timestamp('trial_ends_at')->nullable();
});

Schema::create('subscriptions', function ($table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->string('name');
    $table->string('stripe_id');
    $table->string('stripe_plan');
    $table->integer('quantity');
    $table->timestamp('trial_ends_at')->nullable();
    $table->timestamp('ends_at')->nullable();
    $table->timestamps();
});

بمجرّد إنشاء التهجيرات، شغّل أمر migrate Artisan.

نموذج Billable

بعد ذلك، أضف سمة Billable إلى تعريف نموذجك، توفّر هذه السمة طرقًا مختلفة تسمح لك بتنفيذ مهام الفوترة الشائعة، كإنشاء الاشتراكات وتطبيق القسائم وتحديث بيانات بطاقة الائتمان:

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
}

مفاتيح الواجهة البرمجيّة API

ختامًا، يجب عليك ضبط مفتاح Stripe في ملف الضبط services.php، ويمكنك استرداد مفاتيح  Stripe API من لوحة تحكم Stripe:

'stripe' => [
    'model'  => App\User::class,
    'key' => env('STRIPE_KEY'),
    'secret' => env('STRIPE_SECRET'),
],

Braintree

تحذيرات Braintree

تعمل تطبيقات Stripe و Braintree بنفس الطريقة في عدة عمليات، فكلاهما يوفران فوترة الاشتراك ببطاقات الائتمان لكن يدعم Paypal Braintree أيضًا، ومع ذلك، يفتقر Braintree إلى بعض المميزات المدعومة من Stripe، ويجب عليك مراعاة ما يلي عند اتخاذ قرار استخدام Stripe أو Braintree:

  • يدعم Paypal Braintree على عكس Stripe.
  • لا يدعم Braintree توابع الزيادة والنقصان على الاشتراكات، وهذه حدود Braintree وليست حدود Cashier.
  • لا يدعم Braintree الخصومات القائمة على النسبة المئويّة، وهذه حدود Braintree وليست حدود Cashier.

Composer

أضف أولًا حزمة Cashier الخاصة بخدمة Braintree إلى اعتماديّاتك:

composer require "laravel/cashier-braintree":"~2.0"

مقدم الخدمة

بعد ذلك، سجّل مقدّم الخدمة Laravel\Cashier\CashierServiceProvider في ملف الضبط config/app.php :

Laravel\Cashier\CashierServiceProvider::class

قسيمة خطة الائتمان

قبل استخدام Cashier مع Braintree، ستحتاج إلى تعريف قسيمة plan-credit في لوحة تحكم Braintree، وسيُستخدم هذا الخصم لتجزئة الاشتراكات التي تتغيّر من الفوترة السنويّة إلى الشهريّة أو من الشهريّة إلى السنويّة.

يمكن أن يكون مقدار الخصم الذي تريد تكوينه في لوحة تحكم Braintree أي قيمة تريدها، حيث سيعيد Cashier تعريف المبلغ المحدد بالمبلغ المخصص الخاص بنا في كل مرة نطبّق فيها القسيمة، وهذه القسيمة مطلوبة لأن Braintree لا يدعم الاشتراكات التناسبية عبر ترددات الاشتراك.

تهجير قواعد البيانات

قبل استخدام Cashier، سنحتاج إلى إعداد قاعدة البيانات، وذلك عن طريق إضافة عدة أعمدة إلى جدول users و إنشاء جدول subscriptions جديد لاحتواء جميع اشتراكات عملائنا:

Schema::table('users', function ($table) {
    $table->string('braintree_id')->nullable();
    $table->string('paypal_email')->nullable();
    $table->string('card_brand')->nullable();
    $table->string('card_last_four')->nullable();
    $table->timestamp('trial_ends_at')->nullable();
});

Schema::create('subscriptions', function ($table) {
    $table->increments('id');
    $table->unsignedInteger('user_id');
    $table->string('name');
    $table->string('braintree_id');
    $table->string('braintree_plan');
    $table->integer('quantity');
    $table->timestamp('trial_ends_at')->nullable();
    $table->timestamp('ends_at')->nullable();
    $table->timestamps();
});

بمجرّد إنشاء التهجيرات، شغّل أمر migrate Artisan.

نموذج Billable

بعد ذلك، أضف سمة Billable إلى تعريف نموذجك:

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
}

مفاتيح الواجهة البرمجيّة API

ختامًا، يجب عليك ضبط الخيارات التاليّة في ملف الضبط services.php:

'braintree' => [
    'model'  => App\User::class,
    'environment' => env('BRAINTREE_ENV'),
    'merchant_id' => env('BRAINTREE_MERCHANT_ID'),
    'public_key' => env('BRAINTREE_PUBLIC_KEY'),
    'private_key' => env('BRAINTREE_PRIVATE_KEY'),
],

ثم يجب عليك إضافة استدعاءات حزمة برمجيات التطوير Braintree SDK التالية إلى تابع boot الخاص بموفّر الخدمة AppServiceProvider:

\Braintree_Configuration::environment(config('services.braintree.environment'));
\Braintree_Configuration::merchantId(config('services.braintree.merchant_id'));
\Braintree_Configuration::publicKey(config('services.braintree.public_key'));
\Braintree_Configuration::privateKey(config('services.braintree.private_key'));

ضبط العملة

العملة الافتراضية لـ Cashier هي الدولار الأمريكي (USD)، ويمكنك تغيير العملة الافتراضيّة باستدعاء تابع Cashier::useCurrency من داخل تابع boot من أحد موفرّي الخدمة.

يقبل تابع useCurrency سلستين نصيتيّن كمعاملات: العملة ورمز العملة:

use Laravel\Cashier\Cashier;

Cashier::useCurrency('eur', '€');

الاشتراكات

إنشاء الاشتراكات

لإنشاء اشتراك، استردّ نسخة من نموذج billable والتي ستكون عادةً نسخة من App\User، وبمجرد استرداد نسخة النموذج، يمكنك استخدام تابع newSubscription لإنشاء اشتراك النموذج:

$user = User::find(1);

$user->newSubscription('main', 'premium')->create($stripeToken);

يجب أن يكون المعامل الأول الممرّر إلى تابع newSubscription هو اسم الاشتراك، إذا كان تطبيقك يوفّر نوع واحد من الاشتراكات، يمكنك تسميته main أو primary، وأما المعامل الثاني فهو تحديد خطة Stripe أو Braintree التي يشترك فيها المستخدم، ويجب أن تتوافق هذه القيمة مع معرّف Stripe أو Braintree.

سيبدأ التابع create، والذي يقبل بطاقة ائتمان أو رمز مصدر Stripe، الاشتراك بالإضافة إلى تحديث قاعدة بياناتك بمعرّف العميل ومعلومات الفوترة ذات الصلة.

بيانات المستخدم إضافيّة

إذا كنت ترغب في تحديد تفاصيل إضافيّة للعميل، فيمكنك القيام بذلك عن طريق تمريرها كمعامل ثاني إلى التابع create:

$user->newSubscription('main', 'monthly')->create($stripeToken, [
    'email' => $email,
]);

لمعرفة المزيد حول الحقول الإضافية المدعومة بواسطة Stripe أو Braintree، راجع توثيق Stripe حول إنشاء العميل أو توثيق Braintree المشابهة.

القسائم

إذا رغبت في تطبيق قسيمة عند إنشاء الاشتراك، فيمكنك استخدام تابع withCoupon:

$user->newSubscription('main', 'monthly')
     ->withCoupon('code')
     ->create($stripeToken);

التحقق من حالة الاشتراك

بمجرد اشتراك المستخدم بتطبيقك، يمكنك التحقق بسهولة من حالة الاشتراك باستخدام مجموعة متنوعة من التوابع المناسبة، فالتابع subscribed يرجع true إذا كان للمستخدم اشتراك نشط، وحتى إذا كان الاشتراك حاليًا ضمن الفترة التجريبيّة:

if ($user->subscribed('main')) {
   //
}

إن التابع subscribed هو مرشح رائع لبرمجيّة وسيطة للمسار، فهو يسمح لك بترشيح الوصول إلى المسارات ووحدات التحكم بناءًا على حالة اشتراك المستخدم:

public function handle($request, Closure $next)
{
    if ($request->user() && ! $request->user()->subscribed('main')) {
       // This user is not a paying customer...
        return redirect('billing');
    }

    return $next($request);
}

إذا أردت تحديد ما إذا كان المستخدم ما يزال ضمن الفترة التجريبيّة، فيمكنك استخدام التابع onTrial، ويمكنك استخدام هذا التابع لعرض تحذير للمستخدم بأنه ما يزال في الفترة التجريبيّة الخاصة به:

if ($user->subscription('main')->onTrial()) {
   //
}

يمكن استخدام التابع subscribedToPlan لتحديد ما إذا كان المستخدم مشتركًا بخطة معينة بناءً على معرّف الخطة في Stripe / Braintree، وفي هذا المثال، سنحدد ما إذا كان الاشتراك main للمستخدم مفعّل للخطة الشهريّة:

if ($user->subscribedToPlan('monthly', 'main')) {
   //
}

حالة الاشتراك الملغى

لتحديد ما إذا كان المستخدم مشتركًا نشيطًا سابقًا ولكنه ألغى اشتراكه، يمكنك استخدام تابع cancelled:

if ($user->subscription('main')->cancelled()) {
   //
}

يمكنك أيضًا تحديد ما إذا كان المستخدم قد ألغى اشتراكه ولكنه لا يزال في فترة "السماح" حتى انتهاء صلاحيّة اشتراكه بالكامل، فعلى سبيل المثال، إذا الغى المستخدم اشتراكه في الخامس من شهر آذار/مارس والذي من المقرر في الأصل أن تنتهي صلاحيته في 10 من آذار/مارس، فسيكون المستخدم في فترة "السماح" حتى 10 من آذار/مارس، ولاحظ أن التابع subscribed سيرجع true في هذه الحالة:

if ($user->subscription('main')->onGracePeriod()) {
   //
}

تغيير الخطط

قد يرغب المستخدم بعد اشتراك في تطبيقك في تغييره إلى خطة اشتراك جديدة، ولاستبدال اشتراك جديد باشتراك المستخدم الحالي، مرّر معرّف الخطة إلى التابع swap:

$user = App\User::find(1);

$user->subscription('main')->swap('provider-plan-id');

إذا كان المستخدم قيد الإصدار التجريبي، فسيُحتفظ بالفترة التجريبيّة أيضًا وإذا كان هنالك كميّة للاشتراك، فسيُحتفظ بتلك الكميّة quantity أيضًا.

إذا أردت مبادلة الخطط وإلغاء أي فترة تجريبيّة للمستخدم قيد التشغيل حاليًا، فيمكنك استخدام التابع skipTrial:

$user->subscription('main')
        ->skipTrial()
        ->swap('provider-plan-id');

كميّة الاشتراك

تنبيه: كميّة الاشتراك مدعومة فقط من نسخة Stripe من Cashier، فلا يملك Braintree خاصيّة تتوافق مع "كميّة" Stripe.

تتأثر في بعض الأحيان الاشتراكات بالكميّة، فعلى سبيل المثال، إذا كان يتقاضى تطبيقك 10 دولارات شهريًا للمستخدم على الحساب، فلزيادة أو نقصان كميّة الاشتراك بسهولة، يمكنك استخدام التوابع incrementQuantity وdecrementQuantity:

$user = User::find(1);

$user->subscription('main')->incrementQuantity();

// Add five to the subscription's current quantity...
$user->subscription('main')->incrementQuantity(5);

$user->subscription('main')->decrementQuantity();

// Subtract five to the subscription's current quantity...
$user->subscription('main')->decrementQuantity(5);

يمكنك بدلًا من ذلك تعيين كميّة محددة باستخدام التابع updateQuantity:

$user->subscription('main')->updateQuantity(10);

يمكنك استخدام التابع noProrate لتحديث كميّة الاشتراك دون تقييم الرسوم:

$user->subscription('main')->noProrate()->updateQuantity(10);

للمزيد من المعلومات حول كميّات الاشتراك، راجع توثيق Stripe.

رسوم الاشتراك

لتحديد نسبة الرسوم للمستخدم على الاشتراك، طبّق التابع taxPercentage على نموذج billable الخاص بك، وأرجع قيمة رقميّة بين 0 و 100، مع عدم وجود أكثر من منزلتين عشريتين.

public function taxPercentage() {
    return 20;
}

يمكّنك التابع taxPercentage من تطبيق معدّل الرسوم على أساسيات نموذج بنموذج model-by-model، والذي قد يكون مفيدًا لقاعدة المستخدمين التي تغطي الكثير من البلدان ومعدلات الرسوم.

تنبيه: لا يطبّق التابع taxPercentage على رسوم الاشتراك فقط، فإذا استخدمت Cashier لتحصيل رسوم دفعة واحدة، فستحتاج إلى تعديد معدل الرسوم يدويًا في ذلك الوقت.

إلغاء الاشتراكات

لإلغاء اشتراك، استدع التابع cancel على اشتراك المستخدم:

$user->subscription('main')->cancel();

عند إلغاء الاشتراك، سيعيّن Cashier بشكل تلقائي عمود ends_at في قاعدة بياناتك، وسيُستخدم هذا العمود لمعرفة متى يجب على التابع subscribed إرجاع القيمة false، فعلى سبيل المثال، إذا ألغى عميل اشتراكه في الأول من مارس،ولم يكن من المقرر أن ينتهي الاشتراك حتى الخامس من مارس، فسيبقى التابع subscribed يرجع true حتى تاريخ 5 مارس.

يمكنك تحديد ما إذا كان المستخدم قد ألغى اشتراكه ولكن لا يزال في فترة "السماح" عن طريق استخدام التابع onGracePeriod:

if ($user->subscription('main')->onGracePeriod()) {
   //
}

إذا رغبت في إنهاء الاشتراك فورًا، فاستدع التابع cancelNow على اشتراك المستخدم:

$user->subscription('main')->cancelNow();

استئناف الاشتراكات

إذا ألغى مستخدم اشتراكه ويرغب في استئنافه استخدم التابع resume، ويجب على المستخدم أن يظل في فترة السماح لاستئناف اشتراكه:

$user->subscription('main')->resume();

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

تحديث بطاقات الائتمان

يمكن استخدام التابع updateCard لتحديث معلومات بطاقة ائتمان العميل، ويقبل هذا التابع رمز Stripe وسيعيّن بطاقة الائتمان الجديدة المصدر الافتراضي للفوترة:

$user->updateCard($stripeToken);

الفترات التجريبيّة للاشتراكات

مع واجهة بطاقة الائتمان

إذا كنت ترغب في توفير فترات تجريبيّة لعملائك مع الاستمرار في جمع معلومات طريقة الدفع، يجب عليك استخدام التابع trialDays عند إنشائك للاشتراك:

$user = User::find(1);

$user->newSubscription('main', 'monthly')
            ->trialDays(10)
            ->create($stripeToken);

سيحدد هذا التابع تاريخ انتهاء الفترة التجريبيّة في سجل الاشتراك داخل قاعدة البيانات، بالإضافة إلى إرشاد Stripe أو Braintree إلى عدم البدء في إعداد فواتير للعميل إلى ما بعد هذا التاريخ.

تنبيه: إذا لم يلغي العميل اشتراكه قبل انتهاء الفترة التجريبيّة فسُتفرض الرسوم فور انتهاء الفترة التجريبيّة، لذلك يجب عليك التأكد من إبلاغ المستخدمين بتاريخ انتهاء الفترة التجريبيّة.

يتيح لك التابع trialUntil توفير نسخة DateTime لتحديد موعد انتهاء الفترة التجريبيّة:

use Carbon\Carbon;

$user->newSubscription('main', 'monthly')
            ->trialUntil(Carbon::now()->addDays(10))
            ->create($stripeToken);

يمكنك معرفة ما إذا كان المستخدم في فترته التجريبيّة أو لا إما باستخدام التابع onTrial على نسخة المستخدم أو باستخدام التابع onTrial على نسخة الاشتراك، فالمثالان التاليان متطابقان:

if ($user->onTrial('main')) {
   //
}

if ($user->subscription('main')->onTrial()) {
   //
}

بدون واجهة بطاقة الائتمان

إذا كنت ترغب في تقديم فترات تجريبيّة دون جمع معلومات عن طريقة دفع المستخدم، يمكنك تعيين عمود trial_ends_at في سجل المستخدم بناءً على تاريخ انتهاء الإصدار التجريبي المطلوب، ويتم ذلك عادةً أثناء تسجيل المستخدم:

$user = User::create([
   // ملأ بقية خصائص المستخدم
    'trial_ends_at' => now()->addDays(10),
]);

تنبيه: تأكد من إضافة تاريخ لـ trial_ends_at لتعريف النموذج.

يشير Cashier إلى نوع الفترة التجريبيّة على أنها "تجربة عامة"، نظرًا لأنه غير مرتبط بأي اشتراك حالي، وسيُرجع التابع onTrial في نسخة User القيمة true إذا لم يتجاوز التاريخ الحالي قيمة trial_ends_at:

if ($user->onTrial()) {
   // المستخدم في الفترة التجريبية
}

يمكنك أيضًا استخدام التابع onGenericTrial إذا أردت معرفة على وجه التحديد أن المستخدم ضمن فترة النسخة التجريبيّة العامة ولم ينشئ اشتراكًا فعليًّا بعد:

if ($user->onGenericTrial()) {
   //  المستخدم في الفترة التجريبية العامة
}

بمجرّد استعدادك لإنشاء اشتراك فعلي للمستخدم، يمكنك استخدام التابع newSubscription كالمعتاد:

$user = User::find(1);

$user->newSubscription('main', 'monthly')->create($stripeToken);

معالجة خطاطيف الويب في Stripe ‏

يمكن لكل من Stripe وBraintree إعلام تطبيقك بمجموعة من الأحداث عبر خطاطيف الويب (webhooks)، ولمعالجة خطاطيف الويب في Stripe، يجب عليك تعريف المسار الذي يشير إلى وحدة تحكم  خطّاف الويب الخاص بـ Cashier، وستُعالج وحدة التحكم هذه جميع طلبات خطّاف الويب الواردة وترسلها إلى تابع وحدة التحكم المناسب:

Route::post(
    'stripe/webhook',
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);

تنبيه: بمجرّد تسجيل الطريق الخاص بك، تأكد من تكوين عنوان خطاف ويب webhook URL في إعدادات لوحة تحكم Stripe.

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

خطاطيف الويب وحماية CSRF

نظرًا لأن خطاطيف ويب Stripe تحتاج إلى تجاوز حماية CSRF الخاصة بإطار Laravel، تأكد من وضع عنوان URI كاستثناء في البرمجيّة الوسيطة  VerifyCsrfToken الخاصة بك أو ضع المسار خارج مجموعة البرمجيّة الوسيطة web:

protected $except = [
    'stripe/*',
];

تعريف معالجات أحداث خطاطيف الويب

سيتعامل Cashier بشكل تلقائي بإلغاء الاشتراك عند فشل شحن المبلغ، لكن إذا كان لديك أحداث خطاطيف ويب Stripe ترغب في معالجتها، فوسّع وحدة التحكم خطّاف الويب ويجب أن تكون أسماء التوابع متطابقة مع اتفاقيّة Cashier المتوقعة، والتي تنصّ على أنه يجب أن تبدأ بالكلمة handle وتستخدم حالة سِنَام الجمل (camelCase) لاسم خطّاف الويب الذي ترغب في معالجته. فعلى سبيل المثال، إذا كنت ترغب في معالجة خطاف الويب الخاص بالخطاف invoice.payment_succeeded فيجب عليك إضافة التابع handleInvoicePaymentSucceeded إلى وحدة التحكم:

<?php

namespace App\Http\Controllers;

use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;

class WebhookController extends CashierController
{
    /**
     * التعامل مع خطاطيف الويب.
     *
     * @param  مصفوفة  $payload
     * @return Response
     */
    public function handleInvoicePaymentSucceeded($payload)
    {
       // معالجة الحدث
    }
}

بعد ذلك، حدد المسار إلى وحدة التحكم Cashier داخل ملف routes/web.php:

Route::post(
    'stripe/webhook',
    '\App\Http\Controllers\WebhookController@handleWebhook'
);

اشتراكات فاشلة

ماذا لو انتهت صلاحيّة بطاقة ائتمان العميل؟ لا تقلق! يحتوي Cashier على وحدة تحكم خطاف ويب يمكنها إلغاء اشتراك العميل بسهولة.

وكما ذُكِر أعلاه، كل ما عليك القيام به هو توجيه المسار إلى وحدة التحكم:

Route::post(
    'stripe/webhook',
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);

وهذا كل شيء، ستُلتقط المدفوعات الفاشلة وتُعالج عن طريق وحدة التحكم، وستلغي وحدة التحكم اشتراك العميل عندما يعلن Stripe فشل الاشتراك (عادةً بعد ثلاث محاولات دفع فاشلة).

معالجة خطاطيف الويب في Braintree

يمكن لكل من Stripe وBraintree إعلام تطبيقك بمجموعة من الأحداث عبر خطاطيف الويب، ولمعالجة خطاطيف ويب Braintree، يجب عليك تعريف المسار الذي يشير إلى وحدة تحكم خطّاف الويب الخاص بـ Cashier، وستعالج وحدة التحكم هذه جميع طلبات خطّاف الويب الواردة وترسلها إلى تابع وحدة التحكم المناسب:

Route::post(
    'braintree/webhook',
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);

تنبيه: بمجرّد تسجيل المسار الخاص بك، تأكد من إنشاء عنوان خطاف ويب webhook URL في إعدادات لوحة تحكم Braintree.

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

خطاطيف الويب وحماية CSRF

نظرًا لأن خطاطيف ويب Braintree تحتاج إلى تجاوز حماية CSRF الخاصة بإطار Laravel، فتأكد من وضع URI كاستثناء في وسيطة VerifyCsrfToken الخاصة بك أو ضع مسار خارج مجموعة وسيطة web:

protected $except = [
    'braintree/*',
];

تعريف معالجات أحداث خطاطيف الويب

سيتعامل Cashier بشكل تلقائي بإلغاء الاشتراك عند فشل شحن المبلغ، لكن إذا كان لديك أحداث Braintree خطّاف ويب ترغب في معالجتها، فوسّع وحدة التحكم خطّاف الويب ويجب أن تكون أسماء التوابع متطابقة مع اتفاقيّة Cashier المتوقعة، والتي تنصّ على أنه يجب أن تبدأ بالكلمة handle وتستخدم حالة سِنَام الجمل (camelCase) لاسم خطّاف الويب الذي ترغب في معالجته. فعلى سبيل المثال، إذا كنت ترغب في التعامل مع خطّاف الويب dispute_opened فيجب عليك إضافة التابع handleDisputeOpened إلى وحدة التحكم:

<?php

namespace App\Http\Controllers;

use Braintree\WebhookNotification;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;

class WebhookController extends CashierController
{
    /**
     * التعامل مع خطّافي  Braintree.
     *
     * @param  WebhookNotification  $webhook
     * @return Response
     */
    public function handleDisputeOpened(WebhookNotification $notification)
    {
       // Handle The Event
    }
}

اشتراكات فاشلة

ماذا لو انتهت صلاحيّة بطاقة ائتمان العميل؟ لا تقلق! يحتوي Cashier على وحدة التحكم خطّاف الويب الذي يمكنه إلغاء اشتراك العميل بسهول.

وكما ذكر أعلاه، كل ما عليك القيام به هو توجيه المسار إلى وحدة التحكم:

Route::post(
    'braintree/webhook',
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);

وهذا كل شيء، ستُلتقط المدفوعات الفاشلة وتُعالج عن طريق وحدة التحكم، وستلغى وحدة التحكم اشتراك العميل عندما يعرّف Braintree بفشل الاشتراك (عادةً بعد ثلاث محاولات دفع فاشلة). لا تنس أنك بحاجة إلى إعداد عنوان خطّاف الويب webhook URI في إعدادات لوحة تحكم Braintree الخاصة بك.

رسوم واحدة

رسم بسيط

تنبيه: عند استخدام Stripe، سيقبل التابع charge المقدار الذي ترغب في خصمه في أدنى مقام للعملة المستخدمة في طلب اشتراكك، ومع ذلك، عند استخدام Braintree، يجب عليك تمرير المبلغ الكامل بالدولار إلى التابع charge:

إذا كنت ترغب في إجراء دفعة واحدة لبطاقة ائتمان أحد العملاء المشتركين، فيمكنك استخدام التابع charge على نسخة نموذج Billable.

// centsتقبل الدفعات بال Stripe
$user->charge(100);

//Dollarsتقبل الدفعات بال Braitree
$user->charge(1);

يقبل التابع charge مصفوفة كمعامل ثاني مما يسمح لك بتمرير أي خيارات ترغب في تضمينها لرسوم إنشاء Stripe / Braintree، راجع توثيقات Stripe أو Braintree المتعلقة بالخيارات المتاحة لك عند إنشاء الرسوم:

$user->charge(100, [
    'custom_option' => $value,
]);

سيرمي التابع charge استثناء إذا فشلت عمليّة الشحن، وإذا نجحت، فستعاد إجابة Stripe أو Braintree كاملة من التابع:

try {
    $response = $user->charge(100);
} catch (Exception $e) {
   //
}

الشحن مع الفاتورة

قد تحتاج في بعض الأحيان إلى تحصيل رسوم لمرة واحدة ولكن ترغب أيضًا في إنشاء فاتورة لتحصيل الرسوم حتى تتمكن من تقديم إيصال بصيغة PDF إلى عميلك، يسمح لك التابع invoiceFor بذلك. فعلى سبيل المثال، لنفرض على العميل رسوم 5.00$ لمرة واحدة:

//  centsتقبل الدفعات بال Stripe

$user->invoiceFor('One Time Fee', 500);

//  dollarsتقبل الدفعات بال Braitree

$user->invoiceFor('One Time Fee', 5);

ستفرض الفاتورة على الفور على بطاقة ائتمان المستخدم، يقبل التابع invoiceFor مصفوفة كمعامل ثالث، مما يسمح لك بتمرير أي خيارات ترغب في تمريرها إلى Stripe أو Braintree عند إنشاء الرسم:

$user->invoiceFor('One Time Fee', 500, [
    'custom-option' => $value,
]);

إذا كنت تستخدم Braintree كموفّر للفوترة، يجب عليك تضمين خيار description عند استدعاء التابع invoiceFor:

$user->invoiceFor('One Time Fee', 500, [
    'description' => 'your invoice description here',
]);

سينشئ التابع invoiceFor فاتورة Stripe والتي ستعيد محاولات الفوترة الفاشلة، وإذا كنت لا ترغب في إنشاء فاتورة لإعادة المحاولة مع العمليات الفاشلة، ستحتاج إلى إغلاقها باستخدام واجهة Stripe البرمجية بعد أول عمليّة تحصيل رسوم فاشلة.

الفواتير

يمكنك استرداد مصفوفة من فواتير نموذج billable بسهولة باستخدام التابع invoices:

$invoices = $user->invoices();

// تضمين الفواتير المعلّقة في النتائج
$invoices = $user->invoicesIncludingPending();

عند إدراج الفواتير الخاصة بالعميل، يجوز لك استخدام التوابع المساعدة لعرض معلومات الفاتورة ذات الصلة، فعلى سبيل المثال، قد ترغب في سرد كل فاتورة في جدول مما يسمح للمستخدم تنزيل أي منها بسهولة:

<table>
    @foreach ($invoices as $invoice)
        <tr>
            <td>{{ $invoice->date()->toFormattedDateString() }}</td>
            <td>{{ $invoice->total() }}</td>
            <td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
        </tr>
    @endforeach
</table>

توليد فواتير PDF

من خلال المسار أو وحدة التحكم، استخدم التابع downloadInvoice لإنشاء PDF قابل للتحميل من الفاتورة، سينشئ هذا التابع استجابة HTTP المناسبة تلقائيًا لإرسال ملف التنزيل إلى المتصفح:

use Illuminate\Http\Request;

Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) {
    return $request->user()->downloadInvoice($invoiceId, [
        'vendor'  => 'Your Company',
        'product' => 'Your Product',
    ]);
});

مصادر