refactor(payment): migrate SDK to yansongda pay
This commit is contained in:
@@ -22,15 +22,17 @@ export const gatewaySchema = {
|
|||||||
payment_codepay_enabled: false,
|
payment_codepay_enabled: false,
|
||||||
payment_stripe_enabled: false,
|
payment_stripe_enabled: false,
|
||||||
wechat_merchantid: '',
|
wechat_merchantid: '',
|
||||||
wechat_jsapi: '',
|
wechat_appid: '',
|
||||||
wechat_appsecret: '',
|
wechat_payment_type: 'native',
|
||||||
|
wechat_api_v3_key: '',
|
||||||
|
wechat_private_key_path: '',
|
||||||
wechat_cert_path: '',
|
wechat_cert_path: '',
|
||||||
wechat_key_path: '',
|
|
||||||
alipay_appid: '',
|
alipay_appid: '',
|
||||||
alipay_privatekey: '',
|
alipay_privatekey: '',
|
||||||
alipay_publickey: '',
|
alipay_payment_type: 'page',
|
||||||
alipay_return_url: '',
|
alipay_app_public_cert_path: '',
|
||||||
alipay_notify_url: '',
|
alipay_public_cert_path: '',
|
||||||
|
alipay_root_cert_path: '',
|
||||||
paypal_client_id: '',
|
paypal_client_id: '',
|
||||||
paypal_client_secret: '',
|
paypal_client_secret: '',
|
||||||
paypal_currency: 'USD',
|
paypal_currency: 'USD',
|
||||||
@@ -94,10 +96,14 @@ export const gatewaySchema = {
|
|||||||
dependsOn: { key: 'payment_wechat_enabled', value: true },
|
dependsOn: { key: 'payment_wechat_enabled', value: true },
|
||||||
fields: [
|
fields: [
|
||||||
{ key: 'wechat_merchantid', label: '商户号', type: 'input', default: '' },
|
{ key: 'wechat_merchantid', label: '商户号', type: 'input', default: '' },
|
||||||
{ key: 'wechat_jsapi', label: 'JSAPI密钥', type: 'input', default: '' },
|
{ key: 'wechat_appid', label: 'AppID', type: 'input', default: '' },
|
||||||
{ key: 'wechat_appsecret', label: 'AppSecret', type: 'input', default: '' },
|
{ key: 'wechat_payment_type', label: '支付方式', type: 'select', default: 'native', options: [
|
||||||
{ key: 'wechat_cert_path', label: '证书路径', type: 'input', default: '', help: '退款等接口需要,绝对路径。' },
|
{ label: '扫码支付(Native)', value: 'native' },
|
||||||
{ key: 'wechat_key_path', label: '密钥路径', type: 'input', default: '' },
|
{ label: 'H5支付', value: 'h5' },
|
||||||
|
] },
|
||||||
|
{ key: 'wechat_api_v3_key', label: 'APIv3密钥', type: 'input', default: '', help: '微信商户平台设置的 APIv3 密钥(32位)。' },
|
||||||
|
{ key: 'wechat_private_key_path', label: '商户私钥路径', type: 'input', default: '', help: 'apiclient_key.pem 绝对路径,用于签名。' },
|
||||||
|
{ key: 'wechat_cert_path', label: '商户API证书路径', type: 'input', default: '', help: 'apiclient_cert.pem 绝对路径。' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -111,9 +117,14 @@ export const gatewaySchema = {
|
|||||||
fields: [
|
fields: [
|
||||||
{ key: 'alipay_appid', label: 'AppID', type: 'input', default: '' },
|
{ key: 'alipay_appid', label: 'AppID', type: 'input', default: '' },
|
||||||
{ key: 'alipay_privatekey', label: '应用私钥', type: 'textarea', rows: 3, default: '' },
|
{ key: 'alipay_privatekey', label: '应用私钥', type: 'textarea', rows: 3, default: '' },
|
||||||
{ key: 'alipay_publickey', label: '支付宝公钥', type: 'textarea', rows: 3, default: '' },
|
{ key: 'alipay_payment_type', label: '支付方式', type: 'select', default: 'page', options: [
|
||||||
{ key: 'alipay_return_url', label: '同步回调地址', type: 'input', default: '' },
|
{ label: '电脑网站支付(web)', value: 'page' },
|
||||||
{ key: 'alipay_notify_url', label: '异步回调地址', type: 'input', default: '' },
|
{ label: '手机网站支付(wap)', value: 'wap' },
|
||||||
|
] },
|
||||||
|
{ key: 'alipay_app_public_cert_path', label: '应用公钥证书路径', type: 'input', default: '', help: 'appCertPublicKey.crt 绝对路径。' },
|
||||||
|
{ key: 'alipay_public_cert_path', label: '支付宝公钥证书路径', type: 'input', default: '', help: 'alipayCertPublicKey_RSA2.crt 绝对路径。' },
|
||||||
|
{ key: 'alipay_root_cert_path', label: '支付宝根证书路径', type: 'input', default: '', help: 'alipayRootCert.crt 绝对路径。' },
|
||||||
|
{ key: 'alipay_notify_help', label: '回调地址说明', type: 'notice', alertType: 'info', alertContent: '异步通知 / 同步返回已固定为 /wp-json/aksrt/v1/payment/alipay/{notify|return},无需在此填写。' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.4",
|
"php": ">=7.4",
|
||||||
"stripe/stripe-php": "^16.1",
|
"stripe/stripe-php": "^16.1",
|
||||||
"yurunsoft/pay-sdk": "~3.0",
|
"yansongda/pay": "^3.7",
|
||||||
"yurunsoft/yurun-oauth-login": "~3.0"
|
"yurunsoft/yurun-oauth-login": "~3.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
|||||||
Generated
+713
-18
@@ -4,8 +4,337 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "8f8c952e2744521268680c9c6f7ad76a",
|
"content-hash": "fe1258c91a142e623f464f5ddaef58f9",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "guzzlehttp/psr7",
|
||||||
|
"version": "2.13.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/guzzle/psr7.git",
|
||||||
|
"reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dad89620b7a6edb60c15858442eb2e408b45d8f4",
|
||||||
|
"reference": "dad89620b7a6edb60c15858442eb2e408b45d8f4",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"psr/http-factory": "^1.0",
|
||||||
|
"psr/http-message": "^1.1 || ^2.0",
|
||||||
|
"ralouphie/getallheaders": "^3.0",
|
||||||
|
"symfony/deprecation-contracts": "^2.5 || ^3.0",
|
||||||
|
"symfony/polyfill-php80": "^1.25"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"psr/http-factory-implementation": "1.0",
|
||||||
|
"psr/http-message-implementation": "1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
|
"http-interop/http-factory-tests": "1.1.0",
|
||||||
|
"jshttp/mime-db": "1.54.0.1",
|
||||||
|
"phpunit/phpunit": "^8.5.52 || ^9.6.34"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"bamarni-bin": {
|
||||||
|
"bin-links": true,
|
||||||
|
"forward-command": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"GuzzleHttp\\Psr7\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "George Mponos",
|
||||||
|
"email": "gmponos@gmail.com",
|
||||||
|
"homepage": "https://github.com/gmponos"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tobias Nyholm",
|
||||||
|
"email": "tobias.nyholm@gmail.com",
|
||||||
|
"homepage": "https://github.com/Nyholm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Márk Sági-Kazár",
|
||||||
|
"email": "mark.sagikazar@gmail.com",
|
||||||
|
"homepage": "https://github.com/sagikazarmark"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tobias Schultze",
|
||||||
|
"email": "webmaster@tubo-world.de",
|
||||||
|
"homepage": "https://github.com/Tobion"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Márk Sági-Kazár",
|
||||||
|
"email": "mark.sagikazar@gmail.com",
|
||||||
|
"homepage": "https://sagikazarmark.hu"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PSR-7 message implementation that also provides common utility methods",
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"message",
|
||||||
|
"psr-7",
|
||||||
|
"request",
|
||||||
|
"response",
|
||||||
|
"stream",
|
||||||
|
"uri",
|
||||||
|
"url"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
|
"source": "https://github.com/guzzle/psr7/tree/2.13.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/GrahamCampbell",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/Nyholm",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-07-16T22:23:49+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/container",
|
||||||
|
"version": "2.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/container.git",
|
||||||
|
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
||||||
|
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.4.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Container\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||||
|
"homepage": "https://github.com/php-fig/container",
|
||||||
|
"keywords": [
|
||||||
|
"PSR-11",
|
||||||
|
"container",
|
||||||
|
"container-interface",
|
||||||
|
"container-interop",
|
||||||
|
"psr"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-fig/container/issues",
|
||||||
|
"source": "https://github.com/php-fig/container/tree/2.0.2"
|
||||||
|
},
|
||||||
|
"time": "2021-11-05T16:47:00+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/event-dispatcher",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/event-dispatcher.git",
|
||||||
|
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
|
||||||
|
"reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\EventDispatcher\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "http://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Standard interfaces for event handling.",
|
||||||
|
"keywords": [
|
||||||
|
"events",
|
||||||
|
"psr",
|
||||||
|
"psr-14"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/php-fig/event-dispatcher/issues",
|
||||||
|
"source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
|
||||||
|
},
|
||||||
|
"time": "2019-01-08T18:20:26+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/http-client",
|
||||||
|
"version": "1.0.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/http-client.git",
|
||||||
|
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||||
|
"reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.0 || ^8.0",
|
||||||
|
"psr/http-message": "^1.0 || ^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Http\\Client\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common interface for HTTP clients",
|
||||||
|
"homepage": "https://github.com/php-fig/http-client",
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"http-client",
|
||||||
|
"psr",
|
||||||
|
"psr-18"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/http-client"
|
||||||
|
},
|
||||||
|
"time": "2023-09-23T14:17:50+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/http-factory",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/http-factory.git",
|
||||||
|
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||||
|
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1",
|
||||||
|
"psr/http-message": "^1.0 || ^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Http\\Message\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
|
||||||
|
"keywords": [
|
||||||
|
"factory",
|
||||||
|
"http",
|
||||||
|
"message",
|
||||||
|
"psr",
|
||||||
|
"psr-17",
|
||||||
|
"psr-7",
|
||||||
|
"request",
|
||||||
|
"response"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/http-factory"
|
||||||
|
},
|
||||||
|
"time": "2024-04-15T12:06:14+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/http-message",
|
"name": "psr/http-message",
|
||||||
"version": "2.0",
|
"version": "2.0",
|
||||||
@@ -109,6 +438,50 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-09-11T13:17:53+00:00"
|
"time": "2024-09-11T13:17:53+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "ralouphie/getallheaders",
|
||||||
|
"version": "3.0.3",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ralouphie/getallheaders.git",
|
||||||
|
"reference": "120b605dfeb996808c31b6477290a714d356e822"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
|
||||||
|
"reference": "120b605dfeb996808c31b6477290a714d356e822",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.6"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php-coveralls/php-coveralls": "^2.1",
|
||||||
|
"phpunit/phpunit": "^5 || ^6.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/getallheaders.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ralph Khattar",
|
||||||
|
"email": "ralph.khattar@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A polyfill for getallheaders.",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/ralouphie/getallheaders/issues",
|
||||||
|
"source": "https://github.com/ralouphie/getallheaders/tree/develop"
|
||||||
|
},
|
||||||
|
"time": "2019-03-08T08:55:37+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "stripe/stripe-php",
|
"name": "stripe/stripe-php",
|
||||||
"version": "v16.6.0",
|
"version": "v16.6.0",
|
||||||
@@ -169,45 +542,367 @@
|
|||||||
"time": "2025-02-24T22:35:29+00:00"
|
"time": "2025-02-24T22:35:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "yurunsoft/pay-sdk",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v3.1.7",
|
"version": "v3.7.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Yurunsoft/PaySDK.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "e146a056f3aa1b68f64bbc5e261bf137b7723307"
|
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Yurunsoft/PaySDK/zipball/e146a056f3aa1b68f64bbc5e261bf137b7723307",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d",
|
||||||
"reference": "e146a056f3aa1b68f64bbc5e261bf137b7723307",
|
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.5",
|
"php": ">=8.1"
|
||||||
"yurunsoft/yurun-http": "~4.0|~5.0"
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/contracts",
|
||||||
|
"name": "symfony/contracts"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"function.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-06-05T06:23:12+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php80",
|
||||||
|
"version": "v1.37.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||||
|
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
|
||||||
|
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"thanks": {
|
||||||
|
"url": "https://github.com/symfony/polyfill",
|
||||||
|
"name": "symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php80\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ion Bazan",
|
||||||
|
"email": "ion.bazan@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-04-10T16:19:22+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "yansongda/artful",
|
||||||
|
"version": "v1.1.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/yansongda/artful.git",
|
||||||
|
"reference": "6fb48671fe99c3008566481b16771edcf82ecd0e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/yansongda/artful/zipball/6fb48671fe99c3008566481b16771edcf82ecd0e",
|
||||||
|
"reference": "6fb48671fe99c3008566481b16771edcf82ecd0e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"guzzlehttp/psr7": "^2.6",
|
||||||
|
"php": ">=8.0",
|
||||||
|
"psr/container": "^1.1 || ^2.0",
|
||||||
|
"psr/event-dispatcher": "^1.0",
|
||||||
|
"psr/http-client": "^1.0",
|
||||||
|
"psr/http-message": "^1.1 || ^2.0",
|
||||||
|
"psr/log": "^1.1 || ^2.0 || ^3.0",
|
||||||
|
"yansongda/supports": "~4.0.10"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"friendsofphp/php-cs-fixer": "2.18.3"
|
"friendsofphp/php-cs-fixer": "^3.44",
|
||||||
|
"guzzlehttp/guzzle": "^7.0",
|
||||||
|
"hyperf/pimple": "^2.2",
|
||||||
|
"mockery/mockery": "^1.4",
|
||||||
|
"monolog/monolog": "^2.2",
|
||||||
|
"phpstan/phpstan": "^1.0.0 || ^2.0.0",
|
||||||
|
"phpunit/phpunit": "^9.0",
|
||||||
|
"symfony/event-dispatcher": "^5.2.0",
|
||||||
|
"symfony/http-foundation": "^5.2.0",
|
||||||
|
"symfony/psr-http-message-bridge": "^2.1",
|
||||||
|
"symfony/var-dumper": "^5.1"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"hyperf/pimple": "其它/无框架下使用 SDK,请安装,任选其一",
|
||||||
|
"illuminate/container": "其它/无框架下使用 SDK,请安装,任选其一"
|
||||||
},
|
},
|
||||||
"bin": [
|
|
||||||
"src/Weixin/Tool/CertificateDownloader.php"
|
|
||||||
],
|
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/Functions.php"
|
||||||
|
],
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"Yurun\\PaySDK\\": "src/"
|
"Yansongda\\Artful\\": "src"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
"license": [
|
"license": [
|
||||||
"MIT"
|
"MIT"
|
||||||
],
|
],
|
||||||
"description": "PHP 集成支付 SDK ,集成了支付宝、微信支付的支付接口和其它相关接口的操作。",
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "yansongda",
|
||||||
|
"email": "me@yansongda.cn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Artful 是一个简单易用的 API 请求框架 PHP Api RequesT Framwork U Like。",
|
||||||
|
"keywords": [
|
||||||
|
"api",
|
||||||
|
"artful",
|
||||||
|
"framework",
|
||||||
|
"request"
|
||||||
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/Yurunsoft/PaySDK/issues",
|
"homepage": "https://artful.yansongda.cn",
|
||||||
"source": "https://github.com/Yurunsoft/PaySDK/tree/v3.1.7"
|
"issues": "https://github.com/yansongda/artful/issues",
|
||||||
|
"source": "https://github.com/yansongda/artful"
|
||||||
},
|
},
|
||||||
"time": "2024-09-02T06:00:28+00:00"
|
"time": "2026-04-15T06:37:37+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "yansongda/pay",
|
||||||
|
"version": "v3.7.20",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/yansongda/pay.git",
|
||||||
|
"reference": "26987ebf789f1e7f0a85febb640986ab4289fd7f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/yansongda/pay/zipball/26987ebf789f1e7f0a85febb640986ab4289fd7f",
|
||||||
|
"reference": "26987ebf789f1e7f0a85febb640986ab4289fd7f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-bcmath": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"php": ">=8.0",
|
||||||
|
"yansongda/artful": "~1.1.3",
|
||||||
|
"yansongda/supports": "~4.0.10"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"hyperf/framework": "<3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.44",
|
||||||
|
"guzzlehttp/guzzle": "^7.0",
|
||||||
|
"hyperf/pimple": "^2.2",
|
||||||
|
"jetbrains/phpstorm-attributes": "^1.1",
|
||||||
|
"mockery/mockery": "^1.4",
|
||||||
|
"monolog/monolog": "^2.2",
|
||||||
|
"phpstan/phpstan": "^1.0.0 || ^2.0.0",
|
||||||
|
"phpunit/phpunit": "^9.0",
|
||||||
|
"symfony/event-dispatcher": "^5.2.0",
|
||||||
|
"symfony/http-foundation": "^5.2.0",
|
||||||
|
"symfony/psr-http-message-bridge": "^2.1",
|
||||||
|
"symfony/var-dumper": "^5.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/Functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Yansongda\\Pay\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "yansongda",
|
||||||
|
"email": "me@yansongda.cn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "可能是我用过的最优雅的 Alipay 和 WeChat 的支付 SDK 扩展包了",
|
||||||
|
"keywords": [
|
||||||
|
"alipay",
|
||||||
|
"pay",
|
||||||
|
"wechat"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"homepage": "https://pay.yansongda.cn",
|
||||||
|
"issues": "https://github.com/yansongda/pay/issues",
|
||||||
|
"source": "https://github.com/yansongda/pay"
|
||||||
|
},
|
||||||
|
"time": "2026-03-23T07:33:29+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "yansongda/supports",
|
||||||
|
"version": "v4.0.12",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/yansongda/supports.git",
|
||||||
|
"reference": "308de376d20cb1cd4f959644793e0582ccd1ef6d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/yansongda/supports/zipball/308de376d20cb1cd4f959644793e0582ccd1ef6d",
|
||||||
|
"reference": "308de376d20cb1cd4f959644793e0582ccd1ef6d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.0",
|
||||||
|
"mockery/mockery": "^1.4",
|
||||||
|
"phpstan/phpstan": "^1.1.0",
|
||||||
|
"phpunit/phpunit": "^9.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"monolog/monolog": "Use logger",
|
||||||
|
"symfony/console": "Use stdout logger"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/Functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Yansongda\\Supports\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "yansongda",
|
||||||
|
"email": "me@yansongda.cn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "common components",
|
||||||
|
"keywords": [
|
||||||
|
"array",
|
||||||
|
"collection",
|
||||||
|
"config",
|
||||||
|
"support"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/yansongda/supports/issues",
|
||||||
|
"source": "https://github.com/yansongda/supports"
|
||||||
|
},
|
||||||
|
"time": "2025-01-08T08:55:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "yurunsoft/yurun-http",
|
"name": "yurunsoft/yurun-http",
|
||||||
|
|||||||
@@ -247,17 +247,26 @@ class SchemaPayment {
|
|||||||
// Field-level dependsOn kept for contract audit / non-SPA consumers.
|
// Field-level dependsOn kept for contract audit / non-SPA consumers.
|
||||||
['key' => 'wechat', 'title' => '微信支付配置', 'collapsible' => true, 'expandWhen' => 'payment_wechat_enabled', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true], 'fields' => [
|
['key' => 'wechat', 'title' => '微信支付配置', 'collapsible' => true, 'expandWhen' => 'payment_wechat_enabled', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true], 'fields' => [
|
||||||
['key' => 'wechat_merchantid', 'label' => '商户号', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
['key' => 'wechat_merchantid', 'label' => '商户号', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
||||||
['key' => 'wechat_jsapi', 'label' => 'JSAPI密钥', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
['key' => 'wechat_appid', 'label' => 'AppID', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
||||||
['key' => 'wechat_appsecret', 'label' => 'AppSecret', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
['key' => 'wechat_payment_type', 'label' => '支付方式', 'type' => 'select', 'default' => 'native', 'options' => [
|
||||||
['key' => 'wechat_cert_path', 'label' => '证书路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
['value' => 'native', 'label' => '扫码支付(Native)'],
|
||||||
['key' => 'wechat_key_path', 'label' => '密钥路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
['value' => 'h5', 'label' => 'H5支付'],
|
||||||
|
], 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
||||||
|
['key' => 'wechat_api_v3_key', 'label' => 'APIv3密钥', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
||||||
|
['key' => 'wechat_private_key_path', 'label' => '商户私钥路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
||||||
|
['key' => 'wechat_cert_path', 'label' => '商户API证书路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_wechat_enabled', 'value' => true]],
|
||||||
]],
|
]],
|
||||||
['key' => 'alipay', 'title' => '支付宝配置', 'collapsible' => true, 'expandWhen' => 'payment_alipay_enabled', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true], 'fields' => [
|
['key' => 'alipay', 'title' => '支付宝配置', 'collapsible' => true, 'expandWhen' => 'payment_alipay_enabled', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true], 'fields' => [
|
||||||
['key' => 'alipay_appid', 'label' => 'AppID', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
['key' => 'alipay_appid', 'label' => 'AppID', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
['key' => 'alipay_privatekey', 'label' => '应用私钥', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
['key' => 'alipay_privatekey', 'label' => '应用私钥', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
['key' => 'alipay_publickey', 'label' => '支付宝公钥', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
['key' => 'alipay_payment_type', 'label' => '支付方式', 'type' => 'select', 'default' => 'page', 'options' => [
|
||||||
['key' => 'alipay_return_url', 'label' => '同步回调地址', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
['value' => 'page', 'label' => '电脑网站支付(web)'],
|
||||||
['key' => 'alipay_notify_url', 'label' => '异步回调地址', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
['value' => 'wap', 'label' => '手机网站支付(wap)'],
|
||||||
|
], 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
|
['key' => 'alipay_app_public_cert_path', 'label' => '应用公钥证书路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
|
['key' => 'alipay_public_cert_path', 'label' => '支付宝公钥证书路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
|
['key' => 'alipay_root_cert_path', 'label' => '支付宝根证书路径', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
|
['key' => 'alipay_notify_help', 'label' => '回调地址说明', 'type' => 'notice', 'alertType' => 'info', 'alertContent' => '异步通知 / 同步返回已固定为 /wp-json/aksrt/v1/payment/alipay/{notify|return},无需在此填写。', 'dependsOn' => ['key' => 'payment_alipay_enabled', 'value' => true]],
|
||||||
]],
|
]],
|
||||||
['key' => 'paypal', 'title' => 'PayPal配置', 'collapsible' => true, 'expandWhen' => 'payment_paypal_enabled', 'dependsOn' => ['key' => 'payment_paypal_enabled', 'value' => true], 'fields' => [
|
['key' => 'paypal', 'title' => 'PayPal配置', 'collapsible' => true, 'expandWhen' => 'payment_paypal_enabled', 'dependsOn' => ['key' => 'payment_paypal_enabled', 'value' => true], 'fields' => [
|
||||||
['key' => 'paypal_client_id', 'label' => 'Client ID', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_paypal_enabled', 'value' => true]],
|
['key' => 'paypal_client_id', 'label' => 'Client ID', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'payment_paypal_enabled', 'value' => true]],
|
||||||
|
|||||||
@@ -328,6 +328,10 @@ class AfterSale {
|
|||||||
$update['resolved_at'] = current_time('mysql');
|
$update['resolved_at'] = current_time('mysql');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($new_status === self::STATUS_COMPLETED && !$this->complete_refund($record)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$updated = (bool) $wpdb->update($this->table(), $update, ['id' => $id]);
|
$updated = (bool) $wpdb->update($this->table(), $update, ['id' => $id]);
|
||||||
if ($updated) {
|
if ($updated) {
|
||||||
$note = $operator_note !== '' ? $operator_note : sprintf(__('售后状态更新为:%s', 'aksrt'), $this->get_status_label($new_status));
|
$note = $operator_note !== '' ? $operator_note : sprintf(__('售后状态更新为:%s', 'aksrt'), $this->get_status_label($new_status));
|
||||||
@@ -565,6 +569,74 @@ class AfterSale {
|
|||||||
do_action('aksrt_shop_refund_executed', $order_number, $user_id, $refund_amount, $payment_method);
|
do_action('aksrt_shop_refund_executed', $order_number, $user_id, $refund_amount, $payment_method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an online-channel refund before completing the after-sale ticket.
|
||||||
|
*/
|
||||||
|
private function complete_refund(array $record): bool {
|
||||||
|
$type = (string) ($record['type'] ?? '');
|
||||||
|
if (!in_array($type, [self::TYPE_REFUND, self::TYPE_REFUND_RETURN, self::TYPE_INSURED_PRICE], true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!class_exists('AKSRT\\Payment\\OrderRepository')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$order_number = sanitize_text_field((string) ($record['order_number'] ?? ''));
|
||||||
|
$order = OrderRepository::get_instance()->get($order_number);
|
||||||
|
if (!$order) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment_method = (string) ($order['payment_method'] ?? 'balance');
|
||||||
|
if (!in_array($payment_method, ['wechatpay', 'alipay'], true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$refund_amount = (float) ($record['amount'] ?? 0);
|
||||||
|
if ($refund_amount <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request_id = sprintf(
|
||||||
|
'AS_%d_%s',
|
||||||
|
(int) ($record['id'] ?? 0),
|
||||||
|
substr(hash('sha256', $order_number), 0, 16)
|
||||||
|
);
|
||||||
|
return $this->refund_via_gateway($payment_method, $order_number, $refund_amount, $request_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function refund_via_gateway(string $payment_method, string $order_number, float $refund_amount, string $request_id): bool {
|
||||||
|
$gateway = Gateway::get_instance()->get_gateway($payment_method);
|
||||||
|
if (!$gateway || !method_exists($gateway, 'refund')) {
|
||||||
|
$this->log_refund_error($order_number, $payment_method, 'gateway unavailable');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $gateway->refund($order_number, $refund_amount, $request_id);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->log_refund_error($order_number, $payment_method, $e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($result['success'])) {
|
||||||
|
$this->log_refund_error($order_number, $payment_method, (string) ($result['message'] ?? 'unknown error'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function log_refund_error(string $order_number, string $payment_method, string $message): void {
|
||||||
|
error_log(sprintf(
|
||||||
|
'[AKSRT AfterSale] gateway refund failed order=%s gateway=%s: %s',
|
||||||
|
$order_number,
|
||||||
|
$payment_method,
|
||||||
|
$message
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
private function sync_order_status(array $record, string $new_status, string $note = ''): void {
|
private function sync_order_status(array $record, string $new_status, string $note = ''): void {
|
||||||
if (!class_exists('AKSRT\\Payment\\OrderRepository') || !class_exists('AKSRT\\Payment\\Order')) {
|
if (!class_exists('AKSRT\\Payment\\OrderRepository') || !class_exists('AKSRT\\Payment\\Order')) {
|
||||||
return;
|
return;
|
||||||
@@ -807,13 +879,20 @@ class AfterSale {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$wpdb->update($this->table(), [
|
if (!$this->complete_refund($record)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$updated = (bool) $wpdb->update($this->table(), [
|
||||||
'status' => self::STATUS_COMPLETED,
|
'status' => self::STATUS_COMPLETED,
|
||||||
'operator_id' => $operator_id,
|
'operator_id' => $operator_id,
|
||||||
'operator_note' => sanitize_textarea_field($note),
|
'operator_note' => sanitize_textarea_field($note),
|
||||||
'updated_at' => current_time('mysql'),
|
'updated_at' => current_time('mysql'),
|
||||||
'resolved_at' => current_time('mysql'),
|
'resolved_at' => current_time('mysql'),
|
||||||
], ['id' => $ticket_id]);
|
], ['id' => $ticket_id]);
|
||||||
|
if (!$updated) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
update_post_meta($ticket_id, '_aksrt_as_progress', self::PROGRESS_DONE);
|
update_post_meta($ticket_id, '_aksrt_as_progress', self::PROGRESS_DONE);
|
||||||
$this->sync_order_status($record, self::STATUS_COMPLETED, $note ?: __('售后已完成', 'aksrt'));
|
$this->sync_order_status($record, self::STATUS_COMPLETED, $note ?: __('售后已完成', 'aksrt'));
|
||||||
|
|||||||
@@ -114,27 +114,29 @@ class Gateway {
|
|||||||
return new \WP_REST_Response('gateway not found', 404);
|
return new \WP_REST_Response('gateway not found', 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$verify = $gateway->verify_callback($request);
|
$verify = $gateway->verify_callback($request);
|
||||||
$verified = !empty($verify['success']);
|
$verified = !empty($verify['success']);
|
||||||
$paid = $verified && ($verify['status'] ?? '') === 'paid';
|
$paid = $verified && ($verify['status'] ?? '') === 'paid';
|
||||||
|
$processed = $verified;
|
||||||
|
|
||||||
if ($paid) {
|
if ($paid) {
|
||||||
$this->complete_order($gateway_id, $verify);
|
// Only ACK paid notifications after the order was actually synchronized.
|
||||||
|
$processed = $this->complete_order($gateway_id, $verify);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 网关各自要求的 ACK 格式
|
// 网关各自要求的 ACK 格式
|
||||||
if ($gateway_id === 'wechatpay' && method_exists($gateway, 'output_callback_response')) {
|
if ($gateway_id === 'wechatpay' && method_exists($gateway, 'output_callback_response')) {
|
||||||
$gateway->output_callback_response(['success' => $verified]); // exit
|
$gateway->output_callback_response(['success' => $processed]); // exit
|
||||||
}
|
}
|
||||||
if ($gateway_id === 'alipay') {
|
if ($gateway_id === 'alipay') {
|
||||||
// 支付宝异步通知要求返回纯文本 success,否则会重复通知
|
// 支付宝异步通知要求返回纯文本 success,否则会重复通知
|
||||||
header('Content-Type: text/plain; charset=utf-8');
|
header('Content-Type: text/plain; charset=utf-8');
|
||||||
echo $verified ? 'success' : 'fail';
|
echo $processed ? 'success' : 'fail';
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stripe / PayPal webhook:200 表示已接收;验签失败返回 400 触发重试
|
// Stripe / PayPal webhook:200 表示已接收;处理失败返回 400 触发重试
|
||||||
return new \WP_REST_Response(['received' => $verified], $verified ? 200 : 400);
|
return new \WP_REST_Response(['received' => $processed], $processed ? 200 : 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,6 +158,20 @@ class Gateway {
|
|||||||
$order_number = $order_number ?: sanitize_text_field((string) ($verify['order_number'] ?? ''));
|
$order_number = $order_number ?: sanitize_text_field((string) ($verify['order_number'] ?? ''));
|
||||||
if (($verify['status'] ?? '') === 'paid' && $this->complete_order($gateway_id, $verify)) {
|
if (($verify['status'] ?? '') === 'paid' && $this->complete_order($gateway_id, $verify)) {
|
||||||
$status = 'success';
|
$status = 'success';
|
||||||
|
} elseif ($order_number !== '') {
|
||||||
|
// Alipay synchronous returns generally omit trade_status; query after signature verification.
|
||||||
|
$query = $gateway->query_status($order_number);
|
||||||
|
if (!empty($query['success']) && ($query['status'] ?? '') === 'paid') {
|
||||||
|
$done = $this->complete_order($gateway_id, [
|
||||||
|
'order_number' => $order_number,
|
||||||
|
'amount' => 0,
|
||||||
|
'transaction_id' => $query['transaction_id'] ?? '',
|
||||||
|
'status' => 'paid',
|
||||||
|
]);
|
||||||
|
if ($done) {
|
||||||
|
$status = 'success';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($gateway_id === 'paypal' && method_exists($gateway, 'capture_order')) {
|
} elseif ($gateway_id === 'paypal' && method_exists($gateway, 'capture_order')) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
|
* Alipay gateway via yansongda/pay (cert mode).
|
||||||
|
*
|
||||||
* @package AKSRT
|
* @package AKSRT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -7,188 +9,206 @@ namespace AKSRT\Payment\Gateways;
|
|||||||
|
|
||||||
defined('ABSPATH') || exit;
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
use Yansongda\Pay\Pay;
|
||||||
|
|
||||||
class AlipayGateway implements \AKSRT\Payment\GatewayInterface {
|
class AlipayGateway implements \AKSRT\Payment\GatewayInterface {
|
||||||
|
|
||||||
public function get_id(): string {
|
public function get_id(): string {
|
||||||
return 'alipay';
|
return 'alipay';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_name(): string {
|
public function get_name(): string {
|
||||||
return __('支付宝', 'aksrt');
|
return __('支付宝', 'aksrt');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function is_configured(): bool {
|
public function is_configured(): bool {
|
||||||
if (class_exists('\AKSRT\Settings\PaymentRuntime')
|
if (class_exists('\AKSRT\Settings\PaymentRuntime')
|
||||||
&& !\AKSRT\Settings\PaymentRuntime::is_gateway_enabled('alipay')) {
|
&& !\AKSRT\Settings\PaymentRuntime::is_gateway_enabled('alipay')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$config = $this->get_config();
|
$c = $this->get_config();
|
||||||
return !empty($config['app_id']) && !empty($config['private_key']) && !empty($config['alipay_public_key']);
|
return $c['app_id'] !== ''
|
||||||
}
|
&& $c['private_key'] !== ''
|
||||||
|
&& $c['app_public_cert'] !== ''
|
||||||
|
&& $c['alipay_public_cert'] !== ''
|
||||||
|
&& $c['alipay_root_cert'] !== '';
|
||||||
|
}
|
||||||
|
|
||||||
public function create_payment(array $order): array {
|
public function create_payment(array $order): array {
|
||||||
if (!$this->is_configured()) {
|
if (!$this->is_configured()) {
|
||||||
return ['success' => false, 'message' => __('支付宝未配置', 'aksrt')];
|
return ['success' => false, 'message' => __('支付宝未配置', 'aksrt')];
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->get_config();
|
$order_number = (string) ($order['order_number'] ?? '');
|
||||||
$order_number = $order['order_number'] ?? '';
|
$amount = (float) ($order['amount'] ?? 0);
|
||||||
$amount = (float) ($order['amount'] ?? 0);
|
$subject = (string) ($order['subject'] ?? __('订单支付', 'aksrt'));
|
||||||
$subject = $order['subject'] ?? __('订单支付', 'aksrt');
|
$payment_type = $this->get_config()['payment_type'];
|
||||||
$payment_type = $config['payment_type'] ?? 'page'; // page / wap
|
|
||||||
|
|
||||||
try {
|
if ($order_number === '' || $amount <= 0) {
|
||||||
$sdk = $this->create_sdk($config);
|
return ['success' => false, 'message' => __('订单参数无效', 'aksrt')];
|
||||||
|
}
|
||||||
|
|
||||||
if ($payment_type === 'wap') {
|
try {
|
||||||
// 手机网站支付
|
YansongdaPayFactory::boot_alipay();
|
||||||
$request = new \Yurun\PaySDK\AlipayApp\Wap\Params\Pay\Request;
|
|
||||||
$request->notify_url = home_url('/wp-json/aksrt/v1/payment/alipay/notify');
|
|
||||||
$request->return_url = home_url('/wp-json/aksrt/v1/payment/alipay/return');
|
|
||||||
$request->businessParams->out_trade_no = $order_number;
|
|
||||||
$request->businessParams->total_amount = number_format($amount, 2, '.', '');
|
|
||||||
$request->businessParams->subject = $subject;
|
|
||||||
} else {
|
|
||||||
// 电脑网站支付
|
|
||||||
$request = new \Yurun\PaySDK\AlipayApp\Page\Params\Pay\Request;
|
|
||||||
$request->notify_url = home_url('/wp-json/aksrt/v1/payment/alipay/notify');
|
|
||||||
$request->return_url = home_url('/wp-json/aksrt/v1/payment/alipay/return');
|
|
||||||
$request->businessParams->out_trade_no = $order_number;
|
|
||||||
$request->businessParams->total_amount = number_format($amount, 2, '.', '');
|
|
||||||
$request->businessParams->subject = $subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建支付跳转 URL(prepareExecute 已将查询参数追加到 $url)
|
$payload = [
|
||||||
$sdk->prepareExecute($request, $url, $data);
|
'out_trade_no' => $order_number,
|
||||||
$payment_url = $url;
|
'total_amount' => number_format($amount, 2, '.', ''),
|
||||||
|
'subject' => mb_substr($subject, 0, 256),
|
||||||
|
];
|
||||||
|
|
||||||
return [
|
$result = $payment_type === 'wap'
|
||||||
'success' => true,
|
? Pay::alipay()->wap($payload)
|
||||||
'payment_url' => $payment_url,
|
: Pay::alipay()->web($payload);
|
||||||
'payment_data' => ['order_number' => $order_number],
|
|
||||||
'message' => __('支付宝支付链接已生成', 'aksrt'),
|
|
||||||
];
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function verify_callback(\WP_REST_Request $request): array {
|
$payment_url = YansongdaPayFactory::extract_payment_url($result);
|
||||||
$config = $this->get_config();
|
$html = YansongdaPayFactory::extract_html_body($result);
|
||||||
|
|
||||||
try {
|
// Prefer Location / action URL; if only auto-submit HTML, expose as payment_data for frontend.
|
||||||
$sdk = $this->create_sdk($config);
|
if ($payment_url === '' && $html !== '' && preg_match('#action=[\'"]([^\'"]+)[\'"]#i', $html, $m)) {
|
||||||
$params = $request->get_params();
|
$payment_url = html_entity_decode($m[1], ENT_QUOTES);
|
||||||
|
}
|
||||||
|
|
||||||
if ($sdk->verifyCallback($params)) {
|
if ($payment_url === '' && $html === '') {
|
||||||
$trade_status = $params['trade_status'] ?? '';
|
return ['success' => false, 'message' => __('支付宝支付链接生成失败', 'aksrt')];
|
||||||
return [
|
}
|
||||||
'success' => true,
|
|
||||||
'order_number' => $params['out_trade_no'] ?? '',
|
|
||||||
'amount' => (float) ($params['total_amount'] ?? 0),
|
|
||||||
'transaction_id' => $params['trade_no'] ?? '',
|
|
||||||
'status' => in_array($trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED']) ? 'paid' : 'pending',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['success' => false, 'message' => __('支付宝回调验证失败', 'aksrt')];
|
return [
|
||||||
} catch (\Exception $e) {
|
'success' => true,
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
'payment_url' => $payment_url,
|
||||||
}
|
'payment_data' => array_filter([
|
||||||
}
|
'order_number' => $order_number,
|
||||||
|
'html' => $html !== '' ? $html : null,
|
||||||
|
]),
|
||||||
|
'message' => __('支付宝支付链接已生成', 'aksrt'),
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function query_status(string $order_number): array {
|
public function verify_callback(\WP_REST_Request $request): array {
|
||||||
if (!$this->is_configured()) {
|
try {
|
||||||
return ['success' => false, 'message' => __('支付宝未配置', 'aksrt')];
|
YansongdaPayFactory::boot_alipay();
|
||||||
}
|
|
||||||
|
|
||||||
$config = $this->get_config();
|
// Use the unsanitized form/query payload; route params must not enter the signature base.
|
||||||
|
$callback_input = strtoupper($request->get_method()) === 'POST'
|
||||||
|
? $request->get_body_params()
|
||||||
|
: $request->get_query_params();
|
||||||
|
if (!is_array($callback_input)) {
|
||||||
|
$callback_input = [];
|
||||||
|
}
|
||||||
|
unset($callback_input['gateway']);
|
||||||
|
|
||||||
try {
|
$data_obj = Pay::alipay()->callback($callback_input);
|
||||||
$sdk = $this->create_sdk($config);
|
$data = YansongdaPayFactory::to_array($data_obj);
|
||||||
|
|
||||||
$request = new \Yurun\PaySDK\AlipayApp\Params\Query\Request;
|
$trade_status = (string) ($data['trade_status'] ?? '');
|
||||||
$request->businessParams->out_trade_no = $order_number;
|
$paid = in_array($trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'], true);
|
||||||
|
|
||||||
$result = $sdk->execute($request);
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'order_number' => (string) ($data['out_trade_no'] ?? ''),
|
||||||
|
'amount' => (float) ($data['total_amount'] ?? 0),
|
||||||
|
'transaction_id' => (string) ($data['trade_no'] ?? ''),
|
||||||
|
'status' => $paid ? 'paid' : 'pending',
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($sdk->checkResult()) {
|
/**
|
||||||
$trade_status = $result['trade_status'] ?? '';
|
* Alipay async notify expects plain text success/fail (Gateway also handles this).
|
||||||
$status = 'pending';
|
*/
|
||||||
if (in_array($trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
|
public function output_callback_response(array $result): void {
|
||||||
$status = 'paid';
|
try {
|
||||||
} elseif ($trade_status === 'TRADE_CLOSED') {
|
if (!empty($result['success'])) {
|
||||||
$status = 'cancelled';
|
YansongdaPayFactory::boot_alipay();
|
||||||
}
|
YansongdaPayFactory::emit_response(Pay::alipay()->success(), 'success');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
header('Content-Type: text/plain; charset=utf-8');
|
||||||
|
echo 'fail';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
public function query_status(string $order_number): array {
|
||||||
'success' => true,
|
if (!$this->is_configured()) {
|
||||||
'status' => $status,
|
return ['success' => false, 'message' => __('支付宝未配置', 'aksrt')];
|
||||||
'transaction_id' => $result['trade_no'] ?? '',
|
}
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['success' => false, 'message' => $sdk->getError() ?: __('查询失败', 'aksrt')];
|
try {
|
||||||
} catch (\Exception $e) {
|
YansongdaPayFactory::boot_alipay();
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
$result = Pay::alipay()->query([
|
||||||
}
|
'out_trade_no' => $order_number,
|
||||||
}
|
]);
|
||||||
|
$data = YansongdaPayFactory::to_array($result);
|
||||||
|
|
||||||
public function refund(string $order_number, float $amount): array {
|
$trade_status = (string) ($data['trade_status'] ?? '');
|
||||||
if (!$this->is_configured()) {
|
$status = 'pending';
|
||||||
return ['success' => false, 'message' => __('支付宝未配置', 'aksrt')];
|
if (in_array($trade_status, ['TRADE_SUCCESS', 'TRADE_FINISHED'], true)) {
|
||||||
}
|
$status = 'paid';
|
||||||
|
} elseif ($trade_status === 'TRADE_CLOSED') {
|
||||||
|
$status = 'cancelled';
|
||||||
|
}
|
||||||
|
|
||||||
$config = $this->get_config();
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'status' => $status,
|
||||||
|
'transaction_id' => (string) ($data['trade_no'] ?? ''),
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
public function refund(string $order_number, float $amount, string $request_id = ''): array {
|
||||||
$sdk = $this->create_sdk($config);
|
if (!$this->is_configured()) {
|
||||||
|
return ['success' => false, 'message' => __('支付宝未配置', 'aksrt')];
|
||||||
|
}
|
||||||
|
|
||||||
$request = new \Yurun\PaySDK\AlipayApp\Params\Refund\Request;
|
try {
|
||||||
$request->businessParams->out_trade_no = $order_number;
|
YansongdaPayFactory::boot_alipay();
|
||||||
$request->businessParams->refund_amount = number_format($amount, 2, '.', '');
|
$refund_request_id = sanitize_key($request_id !== '' ? $request_id : $order_number . '_refund');
|
||||||
$request->businessParams->refund_reason = __('用户申请退款', 'aksrt');
|
$result = Pay::alipay()->refund([
|
||||||
$request->businessParams->out_request_no = $order_number . '_refund_' . time();
|
'out_trade_no' => $order_number,
|
||||||
|
'refund_amount' => number_format($amount, 2, '.', ''),
|
||||||
|
'refund_reason' => __('用户申请退款', 'aksrt'),
|
||||||
|
'out_request_no' => $refund_request_id,
|
||||||
|
]);
|
||||||
|
$data = YansongdaPayFactory::to_array($result);
|
||||||
|
|
||||||
$result = $sdk->execute($request);
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'refund_id' => (string) ($data['trade_no'] ?? $data['out_trade_no'] ?? ''),
|
||||||
|
'message' => __('退款成功', 'aksrt'),
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($sdk->checkResult()) {
|
/**
|
||||||
return [
|
* @return array{app_id:string,private_key:string,app_public_cert:string,alipay_public_cert:string,alipay_root_cert:string,payment_type:string}
|
||||||
'success' => true,
|
*/
|
||||||
'refund_id' => $result['trade_no'] ?? '',
|
private function get_config(): array {
|
||||||
'message' => __('退款成功', 'aksrt'),
|
$all = class_exists('\AKSRT\Settings\Settings')
|
||||||
];
|
? \AKSRT\Settings\Settings::get_all()
|
||||||
}
|
: [];
|
||||||
|
$type = sanitize_key((string) ($all['alipay_payment_type'] ?? 'page'));
|
||||||
return ['success' => false, 'message' => $sdk->getError() ?: __('退款失败', 'aksrt')];
|
if (!in_array($type, ['page', 'wap'], true)) {
|
||||||
} catch (\Exception $e) {
|
$type = 'page';
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
}
|
||||||
}
|
return [
|
||||||
}
|
'app_id' => (string) ($all['alipay_appid'] ?? ''),
|
||||||
|
'private_key' => (string) ($all['alipay_privatekey'] ?? ''),
|
||||||
private function get_config(): array {
|
'app_public_cert' => (string) ($all['alipay_app_public_cert_path'] ?? ''),
|
||||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
'alipay_public_cert' => (string) ($all['alipay_public_cert_path'] ?? ''),
|
||||||
return [];
|
'alipay_root_cert' => (string) ($all['alipay_root_cert_path'] ?? ''),
|
||||||
}
|
'payment_type' => $type,
|
||||||
$all = \AKSRT\Settings\Settings::get_all();
|
];
|
||||||
return [
|
}
|
||||||
'app_id' => (string) ($all['alipay_appid'] ?? ''),
|
|
||||||
'private_key' => (string) ($all['alipay_privatekey'] ?? ''),
|
|
||||||
'alipay_public_key' => (string) ($all['alipay_publickey'] ?? ''),
|
|
||||||
'return_url' => (string) ($all['alipay_return_url'] ?? ''),
|
|
||||||
'notify_url' => (string) ($all['alipay_notify_url'] ?? ''),
|
|
||||||
'payment_type' => (string) ($all['alipay_payment_type'] ?? 'page'),
|
|
||||||
'sign_type' => (string) ($all['alipay_sign_type'] ?? 'RSA2'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function create_sdk(array $config): \Yurun\PaySDK\AlipayApp\SDK {
|
|
||||||
$params = new \Yurun\PaySDK\AlipayApp\Params\PublicParams;
|
|
||||||
$params->appID = $config['app_id'] ?? '';
|
|
||||||
$params->appPrivateKey = $config['private_key'] ?? '';
|
|
||||||
$params->appPublicKey = $config['alipay_public_key'] ?? '';
|
|
||||||
$params->sign_type = $config['sign_type'] ?? 'RSA2';
|
|
||||||
|
|
||||||
return new \Yurun\PaySDK\AlipayApp\SDK($params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
|
* WeChat Pay gateway via yansongda/pay (API v3).
|
||||||
|
*
|
||||||
* @package AKSRT
|
* @package AKSRT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -7,236 +9,283 @@ namespace AKSRT\Payment\Gateways;
|
|||||||
|
|
||||||
defined('ABSPATH') || exit;
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
use Yansongda\Pay\Pay;
|
||||||
|
|
||||||
class WechatPayGateway implements \AKSRT\Payment\GatewayInterface {
|
class WechatPayGateway implements \AKSRT\Payment\GatewayInterface {
|
||||||
|
|
||||||
public function get_id(): string {
|
public function get_id(): string {
|
||||||
return 'wechatpay';
|
return 'wechatpay';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_name(): string {
|
public function get_name(): string {
|
||||||
return __('微信支付', 'aksrt');
|
return __('微信支付', 'aksrt');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function is_configured(): bool {
|
public function is_configured(): bool {
|
||||||
if (class_exists('\AKSRT\Settings\PaymentRuntime')
|
if (class_exists('\AKSRT\Settings\PaymentRuntime')
|
||||||
&& !\AKSRT\Settings\PaymentRuntime::is_gateway_enabled('wechatpay')) {
|
&& !\AKSRT\Settings\PaymentRuntime::is_gateway_enabled('wechatpay')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$config = $this->get_config();
|
$c = $this->get_config();
|
||||||
return !empty($config['mch_id']) && !empty($config['key']);
|
return $c['mch_id'] !== ''
|
||||||
}
|
&& $c['appid'] !== ''
|
||||||
|
&& $c['api_v3_key'] !== ''
|
||||||
|
&& $c['private_key'] !== ''
|
||||||
|
&& $c['cert_path'] !== '';
|
||||||
|
}
|
||||||
|
|
||||||
public function create_payment(array $order): array {
|
public function create_payment(array $order): array {
|
||||||
if (!$this->is_configured()) {
|
if (!$this->is_configured()) {
|
||||||
return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')];
|
return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')];
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->get_config();
|
$order_number = (string) ($order['order_number'] ?? '');
|
||||||
$order_number = $order['order_number'] ?? '';
|
$amount = (float) ($order['amount'] ?? 0);
|
||||||
$amount = (float) ($order['amount'] ?? 0);
|
$subject = (string) ($order['subject'] ?? __('订单支付', 'aksrt'));
|
||||||
$subject = $order['subject'] ?? __('订单支付', 'aksrt');
|
$payment_type = $this->get_config()['payment_type'];
|
||||||
$payment_type = $config['payment_type'] ?? 'native'; // native / jsapi / h5
|
$total_fen = (int) round($amount * 100);
|
||||||
|
|
||||||
try {
|
if ($order_number === '' || $total_fen <= 0) {
|
||||||
$sdk = $this->create_sdk($config);
|
return ['success' => false, 'message' => __('订单参数无效', 'aksrt')];
|
||||||
$total_fee = (int) ($amount * 100); // 转为分
|
}
|
||||||
|
|
||||||
switch ($payment_type) {
|
try {
|
||||||
case 'jsapi':
|
YansongdaPayFactory::boot_wechat();
|
||||||
$request = new \Yurun\PaySDK\Weixin\JSAPI\Params\Pay\Request;
|
|
||||||
$request->openid = $order['openid'] ?? '';
|
|
||||||
break;
|
|
||||||
case 'h5':
|
|
||||||
$request = new \Yurun\PaySDK\Weixin\H5\Params\Pay\Request;
|
|
||||||
break;
|
|
||||||
case 'native':
|
|
||||||
default:
|
|
||||||
$request = new \Yurun\PaySDK\Weixin\Native\Params\Pay\Request;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->body = $subject;
|
$payload = [
|
||||||
$request->out_trade_no = $order_number;
|
'out_trade_no' => $order_number,
|
||||||
$request->total_fee = $total_fee;
|
'description' => mb_substr($subject, 0, 127),
|
||||||
$request->fee_type = 'CNY';
|
'amount' => [
|
||||||
$request->notify_url = home_url('/wp-json/aksrt/v1/payment/wechatpay/notify');
|
'total' => $total_fen,
|
||||||
$request->spbill_create_ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
|
'currency' => 'CNY',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
$result = $sdk->execute($request);
|
switch ($payment_type) {
|
||||||
|
case 'h5':
|
||||||
|
$payload['scene_info'] = [
|
||||||
|
'payer_client_ip' => (string) ($_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
|
||||||
|
'h5_info' => ['type' => 'Wap'],
|
||||||
|
];
|
||||||
|
$result = Pay::wechat()->h5($payload);
|
||||||
|
break;
|
||||||
|
case 'native':
|
||||||
|
default:
|
||||||
|
$result = Pay::wechat()->scan($payload);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($sdk->checkResult()) {
|
$data = YansongdaPayFactory::to_array($result);
|
||||||
$result_data = [
|
$payment_data = array_merge($data, ['order_number' => $order_number]);
|
||||||
'success' => true,
|
|
||||||
'payment_data' => array_merge($result, ['order_number' => $order_number]),
|
|
||||||
'message' => __('微信支付订单已创建', 'aksrt'),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($payment_type === 'native' && !empty($result['code_url'])) {
|
$result_data = [
|
||||||
$result_data['payment_url'] = $result['code_url'];
|
'success' => true,
|
||||||
} elseif ($payment_type === 'h5' && !empty($result['h5_url'])) {
|
'payment_data' => $payment_data,
|
||||||
$result_data['payment_url'] = $result['h5_url'];
|
'message' => __('微信支付订单已创建', 'aksrt'),
|
||||||
}
|
];
|
||||||
|
|
||||||
return $result_data;
|
if ($payment_type === 'native' && !empty($data['code_url'])) {
|
||||||
}
|
$result_data['payment_url'] = (string) $data['code_url'];
|
||||||
|
} elseif ($payment_type === 'h5' && !empty($data['h5_url'])) {
|
||||||
|
$result_data['payment_url'] = (string) $data['h5_url'];
|
||||||
|
}
|
||||||
|
|
||||||
return ['success' => false, 'message' => $sdk->getError() ?: __('微信支付创建失败', 'aksrt')];
|
return $result_data;
|
||||||
} catch (\Exception $e) {
|
} catch (\Throwable $e) {
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function verify_callback(\WP_REST_Request $request): array {
|
public function verify_callback(\WP_REST_Request $request): array {
|
||||||
$config = $this->get_config();
|
try {
|
||||||
|
YansongdaPayFactory::boot_wechat();
|
||||||
|
|
||||||
try {
|
// Pass raw body + headers so callback works under WP REST (php://input may be drained).
|
||||||
$sdk = $this->create_sdk($config);
|
$raw = $request->get_body();
|
||||||
|
$headers = [
|
||||||
|
'Content-Type' => (string) ($request->get_header('content-type') ?: 'application/json'),
|
||||||
|
'Wechatpay-Serial' => (string) $request->get_header('wechatpay-serial'),
|
||||||
|
'Wechatpay-Timestamp' => (string) $request->get_header('wechatpay-timestamp'),
|
||||||
|
'Wechatpay-Nonce' => (string) $request->get_header('wechatpay-nonce'),
|
||||||
|
'Wechatpay-Signature' => (string) $request->get_header('wechatpay-signature'),
|
||||||
|
];
|
||||||
|
$callback = Pay::wechat()->callback([
|
||||||
|
'body' => $raw !== '' ? $raw : file_get_contents('php://input'),
|
||||||
|
'headers' => $headers,
|
||||||
|
]);
|
||||||
|
|
||||||
// 读取原始请求体
|
$data = YansongdaPayFactory::to_array($callback);
|
||||||
$xml = file_get_contents('php://input');
|
// Decrypted resource is nested under resource (array) after CallbackPlugin.
|
||||||
$data = \Yurun\PaySDK\Lib\XML::fromString($xml);
|
$resource = [];
|
||||||
|
if (isset($data['resource']) && is_array($data['resource'])) {
|
||||||
|
$resource = $data['resource'];
|
||||||
|
// ciphertext decrypt may leave plaintext fields at resource root or under ciphertext key.
|
||||||
|
if (isset($resource['ciphertext']) && is_array($resource['ciphertext'])) {
|
||||||
|
$resource = $resource['ciphertext'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($sdk->verifyCallback($data)) {
|
$order_number = (string) ($resource['out_trade_no'] ?? $data['out_trade_no'] ?? '');
|
||||||
return [
|
$transaction_id = (string) ($resource['transaction_id'] ?? $data['transaction_id'] ?? '');
|
||||||
'success' => true,
|
$trade_state = (string) ($resource['trade_state'] ?? $data['trade_state'] ?? '');
|
||||||
'order_number' => $data['out_trade_no'] ?? '',
|
$event_type = (string) ($data['event_type'] ?? '');
|
||||||
'amount' => (($data['total_fee'] ?? 0) / 100),
|
|
||||||
'transaction_id' => $data['transaction_id'] ?? '',
|
|
||||||
'status' => ($data['result_code'] ?? '') === 'SUCCESS' ? 'paid' : 'pending',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['success' => false, 'message' => __('微信支付回调签名验证失败', 'aksrt')];
|
$total_fen = (int) YansongdaPayFactory::dig($resource, 'amount.total', 0);
|
||||||
} catch (\Exception $e) {
|
if ($total_fen <= 0) {
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
$total_fen = (int) YansongdaPayFactory::dig($data, 'amount.total', 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$paid = ($trade_state === 'SUCCESS') || ($event_type === 'TRANSACTION.SUCCESS');
|
||||||
* 输出微信支付回调响应
|
|
||||||
*/
|
|
||||||
public function output_callback_response(array $result): void {
|
|
||||||
if ($result['success'] ?? false) {
|
|
||||||
echo '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
|
|
||||||
} else {
|
|
||||||
echo '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[' . ($result['message'] ?? 'FAIL') . ']]></return_msg></xml>';
|
|
||||||
}
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function query_status(string $order_number): array {
|
// When event is pay success, resource has trade_state SUCCESS.
|
||||||
if (!$this->is_configured()) {
|
if ($event_type !== '' && $event_type !== 'TRANSACTION.SUCCESS' && $trade_state !== 'SUCCESS') {
|
||||||
return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')];
|
$paid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->get_config();
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'order_number' => $order_number,
|
||||||
|
'amount' => $total_fen > 0 ? ($total_fen / 100) : 0.0,
|
||||||
|
'transaction_id' => $transaction_id,
|
||||||
|
'status' => $paid ? 'paid' : 'pending',
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
/**
|
||||||
$sdk = $this->create_sdk($config);
|
* Output WeChat v3 notify ACK (JSON).
|
||||||
|
*/
|
||||||
|
public function output_callback_response(array $result): void {
|
||||||
|
try {
|
||||||
|
YansongdaPayFactory::boot_wechat();
|
||||||
|
if (!empty($result['success'])) {
|
||||||
|
YansongdaPayFactory::emit_response(Pay::wechat()->success(), '{"code":"SUCCESS","message":"成功"}');
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
// fall through to fail body
|
||||||
|
}
|
||||||
|
|
||||||
$request = new \Yurun\PaySDK\Weixin\OrderQuery\Request;
|
if (!headers_sent()) {
|
||||||
$request->out_trade_no = $order_number;
|
http_response_code(500);
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
}
|
||||||
|
echo wp_json_encode([
|
||||||
|
'code' => 'FAIL',
|
||||||
|
'message' => (string) ($result['message'] ?? 'FAIL'),
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$result = $sdk->execute($request);
|
public function query_status(string $order_number): array {
|
||||||
|
if (!$this->is_configured()) {
|
||||||
|
return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')];
|
||||||
|
}
|
||||||
|
|
||||||
if ($sdk->checkResult()) {
|
try {
|
||||||
$trade_state = $result['trade_state'] ?? '';
|
YansongdaPayFactory::boot_wechat();
|
||||||
$status = 'pending';
|
$action = $this->query_action();
|
||||||
if ($trade_state === 'SUCCESS') {
|
$result = Pay::wechat()->query([
|
||||||
$status = 'paid';
|
'out_trade_no' => $order_number,
|
||||||
} elseif (in_array($trade_state, ['CLOSED', 'REVOKED'])) {
|
'_action' => $action,
|
||||||
$status = 'cancelled';
|
]);
|
||||||
} elseif ($trade_state === 'REFUND') {
|
$data = YansongdaPayFactory::to_array($result);
|
||||||
$status = 'refunded';
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
$trade_state = (string) ($data['trade_state'] ?? '');
|
||||||
'success' => true,
|
$status = 'pending';
|
||||||
'status' => $status,
|
if ($trade_state === 'SUCCESS') {
|
||||||
'transaction_id' => $result['transaction_id'] ?? '',
|
$status = 'paid';
|
||||||
];
|
} elseif (in_array($trade_state, ['CLOSED', 'REVOKED'], true)) {
|
||||||
}
|
$status = 'cancelled';
|
||||||
|
} elseif ($trade_state === 'REFUND') {
|
||||||
|
$status = 'refunded';
|
||||||
|
}
|
||||||
|
|
||||||
return ['success' => false, 'message' => $sdk->getError() ?: __('查询失败', 'aksrt')];
|
return [
|
||||||
} catch (\Exception $e) {
|
'success' => true,
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
'status' => $status,
|
||||||
}
|
'transaction_id' => (string) ($data['transaction_id'] ?? ''),
|
||||||
}
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function refund(string $order_number, float $amount): array {
|
public function refund(string $order_number, float $amount, string $request_id = ''): array {
|
||||||
if (!$this->is_configured()) {
|
if (!$this->is_configured()) {
|
||||||
return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')];
|
return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')];
|
||||||
}
|
}
|
||||||
|
|
||||||
$config = $this->get_config();
|
try {
|
||||||
|
YansongdaPayFactory::boot_wechat();
|
||||||
|
$action = $this->query_action();
|
||||||
|
|
||||||
try {
|
$query = Pay::wechat()->query([
|
||||||
$sdk = $this->create_sdk($config);
|
'out_trade_no' => $order_number,
|
||||||
|
'_action' => $action,
|
||||||
|
]);
|
||||||
|
$q = YansongdaPayFactory::to_array($query);
|
||||||
|
$total_fen = (int) YansongdaPayFactory::dig($q, 'amount.total', 0);
|
||||||
|
$refund_fen = (int) round($amount * 100);
|
||||||
|
if ($total_fen <= 0) {
|
||||||
|
$total_fen = $refund_fen;
|
||||||
|
}
|
||||||
|
if ($refund_fen <= 0) {
|
||||||
|
return ['success' => false, 'message' => __('退款金额无效', 'aksrt')];
|
||||||
|
}
|
||||||
|
|
||||||
// 先查询订单获取 transaction_id
|
$refund_request_id = sanitize_key($request_id !== '' ? $request_id : 'REF_' . $order_number);
|
||||||
$query = new \Yurun\PaySDK\Weixin\OrderQuery\Request;
|
$result = Pay::wechat()->refund([
|
||||||
$query->out_trade_no = $order_number;
|
'_action' => 'refund_' . $action,
|
||||||
$query_result = $sdk->execute($query);
|
'out_trade_no' => $order_number,
|
||||||
|
'out_refund_no' => $refund_request_id,
|
||||||
|
'reason' => __('用户申请退款', 'aksrt'),
|
||||||
|
'amount' => [
|
||||||
|
'refund' => $refund_fen,
|
||||||
|
'total' => $total_fen,
|
||||||
|
'currency' => 'CNY',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$data = YansongdaPayFactory::to_array($result);
|
||||||
|
|
||||||
if (!$sdk->checkResult() || empty($query_result['transaction_id'])) {
|
return [
|
||||||
return ['success' => false, 'message' => __('未找到支付记录', 'aksrt')];
|
'success' => true,
|
||||||
}
|
'refund_id' => (string) ($data['refund_id'] ?? $data['out_refund_no'] ?? ''),
|
||||||
|
'message' => __('退款成功', 'aksrt'),
|
||||||
|
];
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return ['success' => false, 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$refund_fee = (int) ($amount * 100);
|
/**
|
||||||
|
* @return array{mch_id:string,appid:string,api_v3_key:string,private_key:string,cert_path:string,payment_type:string}
|
||||||
|
*/
|
||||||
|
private function get_config(): array {
|
||||||
|
$all = class_exists('\AKSRT\Settings\Settings')
|
||||||
|
? \AKSRT\Settings\Settings::get_all()
|
||||||
|
: [];
|
||||||
|
$type = sanitize_key((string) ($all['wechat_payment_type'] ?? 'native'));
|
||||||
|
if (!in_array($type, ['native', 'h5'], true)) {
|
||||||
|
$type = 'native';
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'mch_id' => (string) ($all['wechat_merchantid'] ?? ''),
|
||||||
|
'appid' => (string) ($all['wechat_appid'] ?? ''),
|
||||||
|
'api_v3_key' => (string) ($all['wechat_api_v3_key'] ?? ''),
|
||||||
|
'private_key' => (string) ($all['wechat_private_key_path'] ?? ''),
|
||||||
|
'cert_path' => (string) ($all['wechat_cert_path'] ?? ''),
|
||||||
|
'payment_type' => $type,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
$request = new \Yurun\PaySDK\Weixin\Refund\Request;
|
private function query_action(): string {
|
||||||
$request->out_trade_no = $order_number;
|
$map = [
|
||||||
$request->out_refund_no = 'REF_' . $order_number . '_' . time();
|
'native' => 'native',
|
||||||
$request->total_fee = (int) ($query_result['total_fee'] ?? $refund_fee);
|
'h5' => 'h5',
|
||||||
$request->refund_fee = $refund_fee;
|
];
|
||||||
$request->refund_desc = __('用户申请退款', 'aksrt');
|
$type = $this->get_config()['payment_type'];
|
||||||
|
return $map[$type] ?? 'native';
|
||||||
$result = $sdk->execute($request);
|
}
|
||||||
|
|
||||||
if ($sdk->checkResult()) {
|
|
||||||
return [
|
|
||||||
'success' => true,
|
|
||||||
'refund_id' => $result['refund_id'] ?? '',
|
|
||||||
'message' => __('退款成功', 'aksrt'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['success' => false, 'message' => $sdk->getError() ?: __('退款失败', 'aksrt')];
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return ['success' => false, 'message' => $e->getMessage()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_config(): array {
|
|
||||||
if (!class_exists('\AKSRT\Settings\Settings')) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
$all = \AKSRT\Settings\Settings::get_all();
|
|
||||||
return [
|
|
||||||
'mch_id' => (string) ($all['wechat_merchantid'] ?? ''),
|
|
||||||
'key' => (string) ($all['wechat_jsapi'] ?? ''),
|
|
||||||
'appid' => (string) ($all['wechat_appid'] ?? ''),
|
|
||||||
'appsecret' => (string) ($all['wechat_appsecret'] ?? ''),
|
|
||||||
'cert_path' => (string) ($all['wechat_cert_path'] ?? ''),
|
|
||||||
'key_path' => (string) ($all['wechat_key_path'] ?? ''),
|
|
||||||
'payment_type' => (string) ($all['wechat_payment_type'] ?? 'native'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function create_sdk(array $config): \Yurun\PaySDK\Weixin\SDK {
|
|
||||||
$params = new \Yurun\PaySDK\Weixin\Params\PublicParams;
|
|
||||||
$params->appID = $config['appid'] ?? '';
|
|
||||||
$params->mch_id = $config['mch_id'] ?? '';
|
|
||||||
$params->key = $config['key'] ?? '';
|
|
||||||
$params->sign_type = $config['sign_type'] ?? 'HMAC-SHA256';
|
|
||||||
|
|
||||||
if (!empty($config['cert_path'])) {
|
|
||||||
$params->certPath = $config['cert_path'];
|
|
||||||
}
|
|
||||||
if (!empty($config['key_path'])) {
|
|
||||||
$params->keyPath = $config['key_path'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new \Yurun\PaySDK\Weixin\SDK($params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,275 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Shared yansongda/pay config bootstrap for WeChat / Alipay gateways.
|
||||||
|
*
|
||||||
|
* @package AKSRT
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace AKSRT\Payment\Gateways;
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
use Yansongda\Pay\Pay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds Pay::config() payloads from aksrt_settings and boots the SDK.
|
||||||
|
*/
|
||||||
|
class YansongdaPayFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boot Pay with a partial channel config (wechat and/or alipay).
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $channels Keys: wechat?, alipay?
|
||||||
|
*/
|
||||||
|
public static function boot(array $channels): void {
|
||||||
|
$config = [
|
||||||
|
'logger' => self::logger_config(),
|
||||||
|
'http' => [
|
||||||
|
'timeout' => 10.0,
|
||||||
|
'connect_timeout' => 5.0,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!empty($channels['wechat']) && is_array($channels['wechat'])) {
|
||||||
|
$config['wechat'] = [
|
||||||
|
'default' => $channels['wechat'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!empty($channels['alipay']) && is_array($channels['alipay'])) {
|
||||||
|
$config['alipay'] = [
|
||||||
|
'default' => $channels['alipay'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-config is safe; Pay caches tenant config per process.
|
||||||
|
Pay::config($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WeChat Pay API v3 merchant config.
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public static function wechat_from_settings(): array {
|
||||||
|
$all = self::settings();
|
||||||
|
$notify = home_url('/wp-json/aksrt/v1/payment/wechatpay/notify');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'mch_id' => (string) ($all['wechat_merchantid'] ?? ''),
|
||||||
|
'mch_secret_key' => (string) ($all['wechat_api_v3_key'] ?? ''),
|
||||||
|
'mch_secret_cert' => (string) ($all['wechat_private_key_path'] ?? ''),
|
||||||
|
'mch_public_cert_path' => (string) ($all['wechat_cert_path'] ?? ''),
|
||||||
|
'mp_app_id' => (string) ($all['wechat_appid'] ?? ''),
|
||||||
|
'notify_url' => $notify,
|
||||||
|
'mode' => Pay::MODE_NORMAL,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alipay cert-mode config (yansongda/pay 3.x requires cert paths for SN + verify).
|
||||||
|
*
|
||||||
|
* app_secret_cert may be PEM string or file path.
|
||||||
|
* Cert path fields accept absolute file paths (or PEM content via get_public_cert).
|
||||||
|
*
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public static function alipay_from_settings(): array {
|
||||||
|
$all = self::settings();
|
||||||
|
$notify = home_url('/wp-json/aksrt/v1/payment/alipay/notify');
|
||||||
|
$return = home_url('/wp-json/aksrt/v1/payment/alipay/return');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'app_id' => (string) ($all['alipay_appid'] ?? ''),
|
||||||
|
'app_secret_cert' => (string) ($all['alipay_privatekey'] ?? ''),
|
||||||
|
'app_public_cert_path' => (string) ($all['alipay_app_public_cert_path'] ?? ''),
|
||||||
|
'alipay_public_cert_path' => (string) ($all['alipay_public_cert_path'] ?? ''),
|
||||||
|
'alipay_root_cert_path' => (string) ($all['alipay_root_cert_path'] ?? ''),
|
||||||
|
'return_url' => $return,
|
||||||
|
'notify_url' => $notify,
|
||||||
|
'mode' => Pay::MODE_NORMAL,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function boot_wechat(): void {
|
||||||
|
self::boot(['wechat' => self::wechat_from_settings()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function boot_alipay(): void {
|
||||||
|
self::boot(['alipay' => self::alipay_from_settings()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Collection / ArrayAccess / array to plain array.
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
public static function to_array($data): array {
|
||||||
|
if (is_array($data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
if ($data instanceof \Yansongda\Supports\Collection) {
|
||||||
|
return $data->all();
|
||||||
|
}
|
||||||
|
if ($data instanceof \ArrayAccess) {
|
||||||
|
$out = [];
|
||||||
|
foreach ($data as $k => $v) {
|
||||||
|
$out[$k] = is_array($v) || $v instanceof \ArrayAccess || $v instanceof \Yansongda\Supports\Collection
|
||||||
|
? self::to_array($v)
|
||||||
|
: $v;
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
if (is_object($data) && method_exists($data, 'toArray')) {
|
||||||
|
$arr = $data->toArray();
|
||||||
|
return is_array($arr) ? $arr : [];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nested value from array using dot path.
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $data
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function dig(array $data, string $path, $default = null) {
|
||||||
|
$cur = $data;
|
||||||
|
foreach (explode('.', $path) as $seg) {
|
||||||
|
if (!is_array($cur) || !array_key_exists($seg, $cur)) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
$cur = $cur[$seg];
|
||||||
|
}
|
||||||
|
return $cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a redirect / payment URL from alipay web/wap response.
|
||||||
|
*
|
||||||
|
* @param mixed $result
|
||||||
|
*/
|
||||||
|
public static function extract_payment_url($result): string {
|
||||||
|
if (is_string($result) && $result !== '') {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
if ($result instanceof \Psr\Http\Message\ResponseInterface) {
|
||||||
|
$loc = $result->getHeaderLine('Location');
|
||||||
|
if ($loc !== '') {
|
||||||
|
return $loc;
|
||||||
|
}
|
||||||
|
$body = (string) $result->getBody();
|
||||||
|
if (preg_match('#action=[\'"]([^\'"]+)[\'"]#i', $body, $m)) {
|
||||||
|
return html_entity_decode($m[1], ENT_QUOTES);
|
||||||
|
}
|
||||||
|
if (preg_match('#https?://[^\s"\'<>]+#', $body, $m)) {
|
||||||
|
return $m[0];
|
||||||
|
}
|
||||||
|
// Auto-submit HTML form: callers may open as document; store empty payment_url and put HTML in payment_data.
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (is_object($result)) {
|
||||||
|
if (method_exists($result, 'getTargetUrl')) {
|
||||||
|
$url = (string) $result->getTargetUrl();
|
||||||
|
if ($url !== '') {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (method_exists($result, '__toString')) {
|
||||||
|
$s = (string) $result;
|
||||||
|
if (strpos($s, 'http') === 0) {
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$arr = self::to_array($result);
|
||||||
|
foreach (['payment_url', 'h5_url', 'code_url', 'mweb_url'] as $k) {
|
||||||
|
if (!empty($arr[$k]) && is_string($arr[$k])) {
|
||||||
|
return $arr[$k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML body from alipay Response (form auto-submit) when no Location header.
|
||||||
|
*
|
||||||
|
* @param mixed $result
|
||||||
|
*/
|
||||||
|
public static function extract_html_body($result): string {
|
||||||
|
if ($result instanceof \Psr\Http\Message\ResponseInterface) {
|
||||||
|
if ($result->getHeaderLine('Location') !== '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return (string) $result->getBody();
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit SDK success()/fail() ResponseInterface (or string) and exit.
|
||||||
|
*
|
||||||
|
* @param mixed $response
|
||||||
|
*/
|
||||||
|
public static function emit_response($response, string $fallback_body = 'success'): void {
|
||||||
|
if ($response instanceof \Psr\Http\Message\ResponseInterface) {
|
||||||
|
$status = $response->getStatusCode();
|
||||||
|
if ($status > 0 && !headers_sent()) {
|
||||||
|
http_response_code($status);
|
||||||
|
}
|
||||||
|
foreach ($response->getHeaders() as $name => $values) {
|
||||||
|
if (strtolower((string) $name) === 'transfer-encoding') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($values as $value) {
|
||||||
|
header($name . ': ' . $value, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$body = (string) $response->getBody();
|
||||||
|
echo $body !== '' ? $body : $fallback_body;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (is_string($response) && $response !== '') {
|
||||||
|
echo $response;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
echo $fallback_body;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
private static function settings(): array {
|
||||||
|
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||||
|
return \AKSRT\Settings\Settings::get_all();
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string,mixed>
|
||||||
|
*/
|
||||||
|
private static function logger_config(): array {
|
||||||
|
$enabled = defined('WP_DEBUG') && WP_DEBUG;
|
||||||
|
$file = '';
|
||||||
|
if ($enabled && function_exists('wp_upload_dir')) {
|
||||||
|
$uploads = wp_upload_dir();
|
||||||
|
if (empty($uploads['error']) && !empty($uploads['basedir'])) {
|
||||||
|
$dir = trailingslashit((string) $uploads['basedir']) . 'aksrt-pay';
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
wp_mkdir_p($dir);
|
||||||
|
}
|
||||||
|
$file = trailingslashit($dir) . 'pay.log';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'enable' => $enabled && $file !== '',
|
||||||
|
'file' => $file,
|
||||||
|
'level' => 'info',
|
||||||
|
'type' => 'single',
|
||||||
|
'max_file' => 30,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -336,10 +336,6 @@ class PaymentRuntime {
|
|||||||
'pid' => sanitize_text_field((string) ($settings['epay_pid'] ?? '')),
|
'pid' => sanitize_text_field((string) ($settings['epay_pid'] ?? '')),
|
||||||
'key' => sanitize_text_field((string) ($settings['epay_key'] ?? '')),
|
'key' => sanitize_text_field((string) ($settings['epay_key'] ?? '')),
|
||||||
],
|
],
|
||||||
'alipay_extra' => [
|
|
||||||
'return_url' => esc_url_raw((string) ($settings['alipay_return_url'] ?? '')),
|
|
||||||
'notify_url' => esc_url_raw((string) ($settings['alipay_notify_url'] ?? '')),
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user