PHP code example of atannex / billing

1. Go to this page and download the library: Download atannex/billing library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

atannex / billing example snippets


// An MTN number goes to MTN MoMo, an Orange number to Orange Money. Nothing else to choose.
$payment = Billing::amount(5000)->phone('677 12 34 56')->for($order)->charge();

$payment->status;          // PaymentStatus::Processing: the payer has a prompt on their phone

// A USD card payment goes to Stripe Checkout.
$payment = Billing::amount('49.90', 'USD')->method('card')->returnTo(route('orders.show', $order))->charge();

return redirect($payment->redirectUrl());

use Atannex\Billing\Facades\Billing;

$payment = Billing::amount(5000)               // major units, default currency (XAF)
    ->for($order)                              // what is paid for (morph)
    ->by($user)                                // who pays; Billable models fill name/email/phone
    ->phone('677 12 34 56')                    // any common format; drives operator routing
    ->description('Annual subscription')
    ->returnTo(route('orders.show', $order), route('cart'))   // after hosted pages
    ->idempotencyKey("order-{$order->id}")
    ->metadata(['plan' => 'annual'])
    ->charge();

match (true) {
    $payment->() => view('pay.card', ['secret' => $payment->clientSecret()]),     // Stripe intent mode
    $payment->isOpen() => view('pay.waiting', ['payment' => $payment]),                         // MTN / Orange push: approve on the phone
    $payment->succeeded() => redirect()->route('orders.show', $order),
    default => back()->withErrors($payment->failure_message),
};

use Atannex\Billing\Concerns\Billable;   // on User
use Atannex\Billing\Concerns\Payable;    // on Order, Invoice, Ticket…

$user->charge(5000)->for($order)->charge();
$user->payments()->paid()->get();

$order->pay(5000)->phone($phone)->charge();
$order->isPaid();                 // a successful payment, not fully refunded
$order->amountPaid('XAF');        // Money, net of refunds
$order->latestPayment;

$payment->money();           // Money (5000 XAF)
$payment->refundable();      // what can still be refunded
$payment->net();             // kept after refunds
$payment->status;            // PaymentStatus enum
$payment->isOpen(); $payment->isPaid(); $payment->succeeded(); $payment->failed();
$payment->failure_code;      // approval_rejected, not_enough_funds, expired, amount_mismatch, …
$payment->failure_message;   // readable: "The payer declined the payment."
$payment->events;            // the audit ledger

Payment::open()->get();  Payment::paid()->gateway('mtn_momo')->get();  Payment::status('failed')->get();

Billing::find('PAY-01J…');
Billing::refresh($payment);  // ask the provider now
Billing::cancel($payment);   // open payments only; expires the Stripe session / cancels the intent

Billing::refund($payment);                          // everything that is left
Billing::refund($payment, 2000, 'Damaged item');    // part, in major units of the payment's currency
Billing::refund($payment, Money::of('9.90', 'EUR'));

Event::listen(PaymentSucceeded::class, function (PaymentSucceeded $event) {
    $event->payment->payable?->markPaid();
});

'routing' => [
    'enabled' => true,
    'order' => ['mtn_momo', 'orange_money', 'stripe', 'flutterwave', 'paypal'],
    'failover' => false,
],

use Atannex\Billing\Facades\Billing;
use Atannex\Billing\Enums\PaymentStatus;

$fake = Billing::fake()->process();          // succeed() · fail('code', 'message') · process() · atest('id')->first();
$fake->settle($payment, PaymentStatus::Succeeded);   // the provider confirms, through the real processor
$this->assertTrue($order->fresh()->isPaid());

$fake->assertChargedTimes(1);  $fake->assertNothingCharged();  $fake->assertRefunded();

use Atannex\Billing\Gateways\AbstractGateway;

class CinetPayGateway extends AbstractGateway
{
    protected array $capabilities = [Capability::Redirect, Capability::Webhooks];

    public function initiate(Payment $payment): Snapshot { /* call the API, return a Snapshot */ }
    public function fetch(Payment $payment): Snapshot { /* map the provider's status */ }
    public function verifyWebhook(Request $request, ?Payment $payment): bool { /* … */ }
    public function parseWebhook(Request $request): WebhookEvent { /* … refresh: true */ }
}

Billing::extend('cinetpay', fn (string $name, array $config, $app) => new CinetPayGateway(
    $name, $config, $app->make(\Illuminate\Http\Client\Factory::class), $app['cache']->store(),
));
bash
composer vendor:publish --tag=billing-config
php artisan migrate
bash
php artisan billing:mtn-sandbox-user --host=your-tunnel.ngrok.app
bash
php artisan billing:gateways                  # what is configured, enabled, routed
php artisan billing:payment PAY-01J… --refresh   # one payment, its refunds and ledger
php artisan billing:reconcile [--sync] [--gateway=mtn_momo]
php artisan billing:prune [--days=90]         # old webhook calls (scheduled daily)
php artisan billing:mtn-sandbox-user [--product=disbursement] [--host=…]