yansongda/laravel-pay
yansongda/laravel-pay 是 Laravel/Lumen 的聚合支付扩展,基于 yansongda/pay,支持支付宝、微信、抖音支付、江苏银行(e融支付)等。提供 Facade 调用与统一配置,快速创建订单、发起网页/公众号/小程序等支付。
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require yansongda/laravel-pay:~3.7.0
Publish Config:
php artisan vendor:publish --provider="Yansongda\LaravelPay\PayServiceProvider" --tag=laravel-pay
(For Lumen, manually copy config and register the provider.)
Configure .env:
Add your gateway credentials (e.g., ALIPAY_APP_ID, WECHAT_APP_ID) under the PAY_* section in .env.
First Use Case: Generate a Alipay Web Pay link:
use Yansongda\LaravelPay\Facades\Pay;
$order = [
'out_trade_no' => time(),
'total_amount' => '1.00',
'subject' => 'Order #' . time(),
];
return Pay::alipay()->web($order);
(Shortcut: Pay::web($order) also works.)
Pay::alipay()->web($order);
Pay::alipay()->app($order);
refund().
Pay::alipay()->refund(['out_trade_no' => $orderId, 'refund_amount' => '0.50']);
mp() for WeChat Mini Programs.
Pay::wechat()->mp($order);
Pay::wechat()->native($order);
Pay::wechat()->jsapi($order);
$gateway = request()->input('gateway') === 'alipay' ? 'alipay' : 'wechat';
Pay::$gateway()->web($order);
Generate Unique out_trade_no:
Use Laravel’s Str::uuid() or time() + random() to avoid collisions.
$order['out_trade_no'] = Str::uuid()->toString();
Store Orders in DB:
Save $order to orders table before processing, then reference it in callbacks.
$order = Order::create([...]);
Pay::alipay()->web($order->toArray());
Async Notifications: Use Laravel Queues to handle async webhook notifications:
Pay::alipay()->web($order)->setNotifyUrl(route('pay.notify'))->execute();
Notify URL:
Configure in .env (e.g., ALIPAY_NOTIFY_URL) and handle notifications in a controller:
public function handleNotify(Request $request)
{
$result = Pay::alipay()->verifyNotify($request->all());
if ($result->success()) {
// Update order status, etc.
}
return $result->success() ? 'success' : 'fail';
}
Verify Signatures: Always verify signatures in notifications to prevent fraud:
$result = Pay::alipay()->verifyNotify($data);
Sandbox Mode:
Enable in config (sandbox => true) and use test credentials from gateways (e.g., Alipay’s sandbox app ID).
'alipay' => [
'sandbox' => env('PAY_ALIPAY_SANDBOX', true),
'app_id' => env('PAY_ALIPAY_APP_ID', '202100****'),
],
Mock Responses:
Use Pay::alipay()->mock() to simulate successful/failure responses during testing:
$mock = Pay::alipay()->mock()->web($order);
Missing .env Keys:
Ensure all required keys (e.g., ALIPAY_APP_ID, WECHAT_MCH_ID) are set in .env. The package won’t throw errors if they’re missing—it’ll fail silently during execution.
Fix: Validate config in a service provider’s boot() method:
if (empty(config('pay.alipay.app_id'))) {
throw new \RuntimeException('Alipay app_id not configured.');
}
Sandbox vs. Production:
Forgetting to switch between sandbox and production modes can lead to failed payments. Always double-check:
'alipay' => [
'sandbox' => env('APP_ENV') === 'local', // Toggle based on environment
],
time() as out_trade_no, collisions may occur.
Fix: Use UUIDs or a database sequence:
$order['out_trade_no'] = (string) Str::orderedUuid();
Signature Mismatches: If notifications fail verification, check:
ALIPAY_APP_PRIVATE_KEY and ALIPAY_APP_PUBLIC_KEY are correct.Pay::alipay()->verifyNotify() to debug.Logging Notifications: Log raw notification data for debugging:
\Log::debug('Alipay Notify', $request->all());
Subject/Body Limits:
subject and body must be ≤ 128 characters. Truncate long descriptions:
$order['subject'] = Str::limit($subject, 128);
Currency:
Defaults to CNY. Explicitly set if needed:
$order['currency'] = 'USD';
OpenID Requirements:
For mp() and jsapi, openid is mandatory. Fetch it via WeChat’s OAuth:
$openid = session('wechat_openid'); // Store during OAuth flow
$order['openid'] = $openid;
Total Fee:
Must be an integer (e.g., 100 for ¥1.00). Convert floats:
$order['total_fee'] = (int) ($amount * 100);
valid_time (in seconds) must be ≥ 60 and ≤ 7200 (2 hours). Default to 3600 (1 hour):
$order['valid_time'] = 3600;
Yansongda\Pay\Gateway:
namespace App\Pay;
use Yansongda\Pay\Gateway;
class CustomGateway extends Gateway
{
protected $code = 'custom';
protected $name = 'Custom Pay';
public function pay(array $data)
{
// Custom logic
return $this->response()->success($data);
}
}
config/pay.php:
'gateways' => [
'custom' => [
'driver' => \App\Pay\CustomGateway::class,
],
],
Pay::extend('alipay', function () {
return new \App\Pay\CustomAlipayResponse();
});
Caching Config:
Avoid loading config files repeatedly by caching the Pay facade’s config:
$config = config('pay');
Pay::setConfig($config); // Cache config if modified rarely
Batch Refunds: For multiple refunds, use batch processing:
How can I help you explore Laravel packages today?