Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pay Laravel Package

yansongda/pay

A popular PHP payment library for Laravel and other frameworks, integrating Alipay and WeChat Pay with a clean API. Supports common payment flows, refunds, queries, callbacks/notifications, and flexible configuration for multi-app and sandbox use.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require yansongda/pay:~3.7.0

Target Laravel projects by using yansongda/laravel-pay instead.

  1. Basic Configuration: Define gateway configurations in a service provider or config file (e.g., config/pay.php):

    return [
        'alipay' => [
            'default' => [
                'app_id' => env('ALIPAY_APP_ID'),
                'app_secret_cert' => env('ALIPAY_APP_SECRET_CERT'),
                'app_public_cert_path' => storage_path('certs/alipay/appCertPublicKey.crt'),
                'alipay_public_cert_path' => storage_path('certs/alipay/alipayCertPublicKey_RSA2.crt'),
                'alipay_root_cert_path' => storage_path('certs/alipay/alipayRootCert.crt'),
                'notify_url' => route('alipay.notify'),
            ],
        ],
        'logger' => [
            'enable' => env('PAY_LOG_ENABLE', false),
            'file' => storage_path('logs/pay.log'),
            'level' => env('PAY_LOG_LEVEL', 'debug'),
        ],
    ];
    
  2. First Use Case: Trigger a payment in a controller:

    use Yansongda\Pay\Pay;
    
    public function pay()
    {
        Pay::config(config('pay')); // Load configs
        $result = Pay::alipay()->web([
            'out_trade_no' => 'order_' . time(),
            'total_amount' => '10.00',
            'subject' => 'Test Payment',
        ]);
        return redirect($result->getRedirectUrl());
    }
    
  3. Callback Handling:

    public function notify()
    {
        Pay::config(config('pay'));
        try {
            $data = Pay::alipay()->callback(); // Auto-verifies signature
            // Process order: $data->out_trade_no, $data->total_amount
            return Pay::alipay()->success();
        } catch (\Throwable $e) {
            return Pay::alipay()->fail();
        }
    }
    

Implementation Patterns

1. Gateway-Specific Workflows

Alipay (Web/APP/Scan)

// Web payment
$pay = Pay::alipay()->web([
    'out_trade_no' => 'order_' . time(),
    'total_amount' => '10.00',
    'subject' => 'Product Purchase',
    'body' => 'Description',
    'timeout_express' => '30m', // Optional
]);

// Scan payment (QR code)
$pay = Pay::alipay()->scan([
    'out_trade_no' => 'order_' . time(),
    'auth_code' => $request->input('auth_code'), // From QR scan
    'total_amount' => '10.00',
]);

WeChat (Mini Program/JSAPI)

// Mini Program payment
$pay = Pay::wechat()->mini([
    'out_trade_no' => 'order_' . time(),
    'description' => 'Mini Program Purchase',
    'amount' => ['total' => 1000], // Amount in cents
    'payer' => ['openid' => $openid],
]);

// JSAPI (H5) payment
$pay = Pay::wechat()->jsapi([
    'out_trade_no' => 'order_' . time(),
    'body' => 'H5 Purchase',
    'total_fee' => 1000,
]);

Unified Query/Refund

// Query order status
$status = Pay::alipay()->query(['out_trade_no' => 'order_123']);

// Refund
$refund = Pay::wechat()->refund([
    'out_refund_no' => 'refund_' . time(),
    'out_trade_no' => 'order_123',
    'refund_amount' => 500, // Partial refund
]);

2. Multi-Tenant & Dynamic Configs

// Override configs per tenant (e.g., in middleware)
Pay::config([
    'alipay' => [
        'tenant1' => [
            'app_id' => 'tenant1_app_id',
            // ...
        ],
        'tenant2' => [
            'app_id' => 'tenant2_app_id',
            // ...
        ],
    ],
]);

// Use tenant-specific configs
Pay::alipay('tenant1')->web([...]);

3. Event-Driven Extensions

Listen to payment events (PSR-14) in EventServiceProvider:

protected $listen = [
    \Yansongda\Pay\Event\AlipayEvent::ALIPAY_NOTIFY => [
        \App\Listeners\HandleAlipayNotify::class,
    ],
    \Yansongda\Pay\Event\WechatEvent::WECHAT_NOTIFY => [
        \App\Listeners\HandleWechatNotify::class,
    ],
];

4. Custom Provider Integration

Extend for unsupported gateways (e.g., PayPal):

// Register in a service provider
Pay::extend('paypal', function () {
    return new \Yansongda\Pay\Plugin\PaypalPlugin();
});

// Usage
Pay::paypal()->create([
    'intent' => 'sale',
    'payer' => ['payment_method' => 'paypal'],
    'transactions' => [[
        'amount' => ['total' => '10.00'],
        'description' => 'Test',
    ]],
]);

5. Asynchronous Processing

Use queues for callback handling:

// Dispatch callback processing
dispatch(new HandleAlipayNotify($data));

// Listener
public function handle(HandleAlipayNotify $event) {
    $data = $event->data;
    // Process order update, send notifications, etc.
}

6. Logging & Debugging

Enable logging in config/pay.php:

'logger' => [
    'enable' => true,
    'file' => storage_path('logs/pay.log'),
    'level' => 'debug', // 'info' for production
],

View logs via Laravel’s log:read command.


7. Webhook Validation

For PayPal/Stripe webhooks:

public function handleWebhook()
{
    $request = request();
    $data = Pay::paypal()->webhook($request); // Auto-verifies signature
    // Process webhook event
}

Gotchas and Tips

1. Common Pitfalls

Issue Solution
Signature verification fails Ensure notify_url matches exactly (case-sensitive). Check cert paths and permissions.
Timeout errors Increase http.timeout in config (default: 5s). Use async processing for heavy callbacks.
Multi-tenant conflicts Explicitly specify tenant: Pay::alipay('tenant1')->web([...]).
WeChat cert errors Use wechat_public_cert_path in config. For PHP-FPM, set wechat_public_cert_path to an array of certs.
Refund failures Verify out_refund_no is unique and out_trade_no exists.

2. Debugging Tips

  • Enable debug logs:
    Pay::config(['logger' => ['level' => 'debug']]);
    
  • Inspect raw requests:
    $raw = Pay::alipay()->getLastRequest(); // For Alipay
    $raw = Pay::wechat()->getLastRequest(); // For WeChat
    
  • Test in sandbox mode:
    'mode' => Pay::MODE_SANDBOX, // For Alipay/WeChat
    

3. Configuration Quirks

  • Certificates:
    • Store certs in storage/app/certs/ and set proper permissions (chmod 644).
    • For WeChat, use an array of cert paths if multiple are provided:
      'wechat_public_cert_path' => [
          'CERT_ID_1' => 'path/to/cert1.pem',
          'CERT_ID_2' => 'path/to/cert2.pem',
      ],
      
  • Amount Units:
    • Alipay: Amount in CNY (e.g., 10.00).
    • WeChat: Amount in fen (e.g., 1000 for ¥10.00).
  • Notify URLs:
    • Must be HTTPS and publicly accessible.
    • Test locally with tools like ngrok.

4. Extension Points

Custom Plugins

Override default behavior by creating a plugin:

namespace App\Plugins;

use Yansongda\
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
graham-campbell/flysystem
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
directorytree/opensearch-client
directorytree/opensearch-adapter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin