mohamed-saad/laravel-payment-gateways 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

mohamed-saad/laravel-payment-gateways

Composer 安装命令:

composer require mohamed-saad/laravel-payment-gateways

包简介

Unified Laravel interface for Paymob, MyFatoorah, Tabby and Tamara payment gateways.

README 文档

README

Laravel package for using multiple payment gateways from one clean API.

Supported gateways:

  • Paymob
  • MyFatoorah
  • Tabby
  • Tamara

The package gives you:

  • One fluent checkout builder: Payment::via('gateway')->...->createCheckout()
  • A facade for every gateway: Paymob, MyFatoorah, Tabby, Tamara
  • Unified response DTOs for checkout, status, refunds, and webhooks
  • One webhook route for all gateways: POST /payment-webhooks/{gateway}
  • Publishable config and migration stubs

Installation

1. Install With Composer

From your Laravel project root:

composer require mohamed-saad/laravel-payment-gateways

Laravel auto-discovery registers the service provider and facades automatically. After installation, you can use the package anywhere in your Laravel app through the facades:

use MohamedSaad\PaymentGateways\Facades\Payment;
use MohamedSaad\PaymentGateways\Facades\Paymob;
use MohamedSaad\PaymentGateways\Facades\MyFatoorah;
use MohamedSaad\PaymentGateways\Facades\Tabby;
use MohamedSaad\PaymentGateways\Facades\Tamara;

2. Publish Config And Migration

php artisan vendor:publish --tag=payment-gateways-config
php artisan vendor:publish --tag=payment-gateways-migrations
php artisan migrate

3. Add Environment Keys

PAYMENT_GATEWAY_DEFAULT=paymob
PAYMENT_GATEWAY_WEBHOOK_PATH=payment-webhooks

PAYMOB_BASE_URL=https://accept.paymob.com
PAYMOB_SECRET_KEY=
PAYMOB_PUBLIC_KEY=
PAYMOB_PAYMENT_METHODS=card
PAYMOB_HMAC_SECRET=

MYFATOORAH_API_KEY=
MYFATOORAH_COUNTRY=SA
MYFATOORAH_TEST_MODE=true
MYFATOORAH_NOTIFICATION_OPTION=LNK

TABBY_SECRET_KEY=
TABBY_PUBLIC_KEY=
TABBY_MERCHANT_CODE=
TABBY_BASE_URL=https://api.tabby.ai

TAMARA_API_TOKEN=
TAMARA_NOTIFICATION_TOKEN=
TAMARA_BASE_URL=https://api-sandbox.tamara.co

Paymob base URLs by country:

# Egypt
PAYMOB_BASE_URL=https://accept.paymob.com

# Oman
PAYMOB_BASE_URL=https://oman.paymob.com

# Saudi Arabia
PAYMOB_BASE_URL=https://ksa.paymob.com

# UAE
PAYMOB_BASE_URL=https://uae.paymob.com

Use https://api.tabby.sa for Tabby KSA production. Use Tamara production URL when your Tamara account is live.

Basic Usage

Use the generic facade when the gateway is dynamic:

use MohamedSaad\PaymentGateways\Facades\Payment;

$checkout = Payment::via('tabby')
    ->amount(150)
    ->currency('SAR')
    ->customer([
        'name' => 'Mona Lisa',
        'email' => 'customer@email.com',
        'phone' => '566027755',
    ])
    ->items([
        [
            'name' => 'Lego City 8601',
            'quantity' => 1,
            'unit_amount' => 150,
            'category' => 'Toys',
        ],
    ])
    ->callback(
        route('payment.success'),
        route('payment.cancel'),
        route('payment.failure')
    )
    ->orderReference('ORDER-1001')
    ->createCheckout();

return redirect($checkout->url);

Or use the direct gateway facade:

use MohamedSaad\PaymentGateways\Facades\Tamara;

$checkout = Tamara::amount(300)
    ->currency('SAR')
    ->customer($user)
    ->items($items)
    ->callback(route('payment.success'), route('payment.cancel'), route('payment.failure'))
    ->orderReference($order->id)
    ->createCheckout();

Gateway Examples

Paymob

Paymob flow: create an intention, receive a client_secret, then redirect to Paymob Unified Checkout.

use MohamedSaad\PaymentGateways\Facades\Paymob;

$checkout = Paymob::amount(500)
    ->currency('EGP')
    ->customer([
        'name' => 'Ahmed Ali',
        'email' => 'ahmed@example.com',
        'phone' => '01000000000',
    ])
    ->callback(
        route('payment.success'),
        route('payment.cancel'),
        route('payment.failure')
    )
    ->items([
        [
            'name' => 'Order items',
            'quantity' => 1,
            'unit_amount' => 500,
        ],
    ])
    ->orderReference('PAYMOB-ORDER-1001')
    ->meta([
        'payment_methods' => ['card'], // or integration IDs like [1256]
        'notification_url' => 'https://your-domain.com/payment-webhooks/paymob',
        'billing_data' => [
            'city' => 'Cairo',
            'country' => 'EG',
            'street' => 'NA',
        ],
    ])
    ->createCheckout();

return redirect($checkout->url);

Important Paymob values:

$checkout->checkoutId;    // Paymob intention id
$checkout->referenceCode; // Paymob order id / intention_order_id
$checkout->url;           // Unified Checkout URL
$checkout->raw;           // Full Paymob intention response, including client_secret

Paymob callbacks are sent to notification_url. Add this URL in the intention payload or in your dashboard:

https://your-domain.com/payment-webhooks/paymob

For old Paymob transaction inquiry/refund endpoints, also set the legacy API key:

PAYMOB_API_KEY=

MyFatoorah

MyFatoorah flow: send payment, redirect customer to invoice URL, then verify invoice status.

use MohamedSaad\PaymentGateways\Facades\MyFatoorah;

$checkout = MyFatoorah::amount(250)
    ->currency('SAR')
    ->customer([
        'name' => 'Mona Lisa',
        'email' => 'mona@example.com',
        'phone' => '0500000000',
    ])
    ->callback(
        route('payment.success'),
        route('payment.cancel'),
        route('payment.failure')
    )
    ->items([
        [
            'name' => 'Order items',
            'quantity' => 1,
            'unit_amount' => 250,
        ],
    ])
    ->orderReference('MYFATOORAH-ORDER-1001')
    ->meta([
        'notification_option' => 'LNK',
        'language' => 'en',
        'webhook_url' => 'https://your-domain.com/payment-webhooks/myfatoorah',
    ])
    ->createCheckout();

return redirect($checkout->url);

Verify payment:

$status = MyFatoorah::verifyPayment($invoiceId);

Refund:

$refund = MyFatoorah::refund($paymentId, 50);

Callback URL:

https://your-domain.com/payment-webhooks/myfatoorah

Tabby

Tabby checkout endpoint:

POST https://api.tabby.ai/api/v2/checkout

Example:

use MohamedSaad\PaymentGateways\Facades\Tabby;

$checkout = Tabby::amount(100)
    ->currency('AED')
    ->customer([
        'name' => 'John Doe',
        'email' => 'jsmith@example.com',
        'phone' => '500000001',
    ])
    ->items([
        [
            'title' => 'Name of the product',
            'quantity' => 1,
            'unit_price' => '100.00',
            'category' => 'Clothes',
            'reference_id' => 'SKU123',
            'description' => 'Description of the product',
            'image_url' => 'https://example.com/image.jpg',
            'product_url' => 'https://example.com/product',
            'brand' => 'Brand Name',
            'is_refundable' => true,
        ],
    ])
    ->callback(
        'https://your-store/success',
        'https://your-store/cancel',
        'https://your-store/failure'
    )
    ->orderReference('TABBY-ORDER-1001')
    ->meta([
        'lang' => 'en',
        'buyer_dob' => '2000-01-20',
        'shipping_address' => [
            'city' => 'Dubai',
            'address' => 'Dubai',
            'zip' => '1111',
        ],
        'buyer_history' => [
            'registered_since' => now()->subYear()->toIso8601String(),
            'loyalty_level' => 2,
        ],
        'order_history' => [],
    ])
    ->createCheckout();

return redirect($checkout->url);

Important Tabby values:

$checkout->checkoutId;    // Tabby session id
$checkout->referenceCode; // Tabby payment id, save this
$checkout->url;           // Redirect URL

Verify, capture, and refund:

$status = Tabby::verifyPayment($paymentId);
$captured = Tabby::capture($paymentId, 100);
$refund = Tabby::refund($paymentId, 50);

Register Tabby webhook:

Tabby::registerWebhook(
    'https://your-domain.com/payment-webhooks/tabby',
    [
        'title' => 'X-Webhook-Token',
        'value' => 'your-random-webhook-token',
    ]
);

Tabby registers webhooks per merchant_code and per environment. A test secret key registers test webhooks, and a live secret key registers production webhooks.

More details: Tabby README

Tamara

Tamara checkout endpoint:

POST https://{environment}.tamara.co/checkout

Sandbox example:

POST https://api-sandbox.tamara.co/checkout

Example:

use MohamedSaad\PaymentGateways\Facades\Tamara;

$checkout = Tamara::amount(300)
    ->currency('SAR')
    ->customer([
        'name' => 'Mona Lisa',
        'email' => 'customer@email.com',
        'phone' => '566027755',
    ])
    ->items([
        [
            'name' => 'Lego City 8601',
            'type' => 'Digital',
            'reference_id' => '123',
            'sku' => 'SA-12436',
            'quantity' => 1,
            'unit_amount' => 490,
            'discount_amount' => ['amount' => 100, 'currency' => 'SAR'],
            'tax_amount' => ['amount' => 10, 'currency' => 'SAR'],
            'item_url' => 'https://item-url.com/1234',
            'image_url' => 'https://image-url.com/1234',
        ],
    ])
    ->callback(
        'http://example.com/#/success',
        'http://example.com/#/cancel',
        'http://example.com/#/fail'
    )
    ->orderReference('abd12331-a123-1234-4567-fbde34ae')
    ->meta([
        'order_number' => 'A123125',
        'shipping_amount' => ['amount' => 1, 'currency' => 'SAR'],
        'tax_amount' => ['amount' => 1, 'currency' => 'SAR'],
        'discount' => [
            'amount' => ['amount' => 0, 'currency' => 'SAR'],
        ],
        'country_code' => 'SA',
        'description' => 'Enter order description here.',
        'billing_address' => [
            'city' => 'Riyadh',
            'country_code' => 'SA',
            'first_name' => 'Mona',
            'last_name' => 'Lisa',
            'line1' => '3764 Al Urubah Rd',
            'line2' => 'string',
            'phone_number' => '532298658',
            'region' => 'As Sulimaniyah',
        ],
        'shipping_address' => [
            'city' => 'Riyadh',
            'country_code' => 'SA',
            'first_name' => 'Mona',
            'last_name' => 'Lisa',
            'line1' => '3764 Al Urubah Rd',
            'line2' => 'string',
            'phone_number' => '532298658',
            'region' => 'As Sulimaniyah',
        ],
        'platform' => 'Laravel',
        'is_mobile' => false,
        'locale' => 'ar_SA',
        'risk_assessment' => [
            'customer_age' => 21,
            'customer_dob' => '01-12-2000',
            'customer_gender' => 'Female',
            'customer_nationality' => 'SA',
            'is_premium_customer' => false,
            'is_existing_customer' => false,
            'is_guest_user' => false,
        ],
        'additional_data' => [
            'delivery_method' => 'Home Delivery',
            'pickup_store' => 'Store A',
            'store_code' => 'Branch A',
        ],
    ])
    ->createCheckout();

return redirect($checkout->url);

Important Tamara values:

$checkout->checkoutId;    // Tamara checkout_id
$checkout->referenceCode; // Tamara order_id
$checkout->url;           // Redirect URL

Verify, authorise, and refund:

$status = Tamara::verifyPayment($orderId);
$authorised = Tamara::authorise($orderId);
$refund = Tamara::refund($orderId, 50);

Register Tamara webhook:

Tamara::registerWebhook([
    'type' => 'order',
    'events' => [
        'order_approved',
        'order_authorised',
        'order_canceled',
        'order_updated',
        'order_captured',
        'order_refunded',
    ],
    'url' => 'https://your-domain.com/payment-webhooks/tamara',
    'headers' => [
        'authorization' => 'your-webhook-authorization-token',
    ],
]);

You can also add the webhook URL manually in the Tamara dashboard:

https://your-domain.com/payment-webhooks/tamara

More details: Tamara README

Webhooks

The package registers one route:

POST /payment-webhooks/{gateway}

Examples:

POST /payment-webhooks/paymob
POST /payment-webhooks/myfatoorah
POST /payment-webhooks/tabby
POST /payment-webhooks/tamara

Listen for payment status changes:

use Illuminate\Support\Facades\Event;
use MohamedSaad\PaymentGateways\Events\PaymentStatusChanged;

Event::listen(PaymentStatusChanged::class, function (PaymentStatusChanged $event) {
    $event->result->gateway;
    $event->result->transactionId;
    $event->result->status;
    $event->result->signatureValid;
});

Response DTOs

Checkout returns CheckoutResponseDTO:

$checkout->gateway;
$checkout->checkoutId;
$checkout->url;
$checkout->referenceCode;
$checkout->raw;

Payment status returns PaymentStatusDTO:

$status->gateway;
$status->transactionId;
$status->status;
$status->amount;
$status->currency;
$status->raw;

Refund returns RefundResponseDTO:

$refund->gateway;
$refund->refundId;
$refund->amount;
$refund->successful;
$refund->raw;

Notes

  • BNPL gateways need item, customer, address, and history data for scoring.
  • Tabby usually needs capture after authorization: Tabby::capture($paymentId, $amount).
  • Tamara usually needs authorise before settlement: Tamara::authorise($orderId).
  • Always save the gateway checkout/payment/order IDs returned in $checkout->raw.
  • Test all gateways with sandbox credentials before production.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-07-14

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固