bnpl-partners / factoring004
即时购买后付款API SDK
Requires
- php: >=7.4
- ext-json: *
- guzzlehttp/guzzle: >=6.0
- myclabs/php-enum: ^1.8
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/log: >=1.1
- psr/simple-cache: >=1.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- rector/rector: ^0.12.16
- vimeo/psalm: ^4.15
README
需求
- PHP >=5.6
- JSON扩展
- PSR-17, PSR-18实现(可选,仅限PHP >=7.x)
版本兼容性
安装
composer require bnpl-partners/factoring004
身份验证
创建 BnplPartners\Factoring004\OAuth\OAuthTokenManager
实例。
use BnplPartners\Factoring004\OAuth\OAuthTokenManager; $tokenManager = new OAuthTokenManager('https://dev.bnpl.kz/api/users/api/v1', 'username', 'password');
生成访问令牌
$token = $tokenManager->getAccessToken(); $accessToken = $token->getAccess();
刷新访问令牌
$newToken = $tokenManager->refreshToken($oldToken->getRefresh());
缓存访问令牌
use BnplPartners\Factoring004\OAuth\CacheOAuthTokenManager; use BnplPartners\Factoring004\OAuth\OAuthTokenManager; $cache = ... // PSR-16 Cache $tokenManager = new OAuthTokenManager('https://dev.bnpl.kz/api/users/v1', 'username', 'password'); $cacheTokenManager = new CacheOAuthTokenManager($tokenManager, $cache, 'cache key'); $token = $cacheTokenManager->getAccessToken(); $accessToken = $token->getAccess();
缓存令牌刷新策略
有两种策略来刷新缓存令牌。
始终检索
这是默认行为。在这种情况下,任何过期的令牌都将刷新。如果您需要刷新令牌而不是检索,您必须调用 CacheOAuthTokenManager::refreshToken()
方法。
use BnplPartners\Factoring004\OAuth\CacheOAuthTokenManager; use BnplPartners\Factoring004\OAuth\OAuthTokenRefreshPolicy; $cacheTokenManager = new CacheOAuthTokenManager($tokenManager, $cache, 'cache key', OAuthTokenRefreshPolicy::ALWAYS_RETRIEVE()); $token = $cacheTokenManager->getAccessToken(); $accessToken = $token->getAccess();
始终刷新
过期的令牌始终会刷新。您不需要通过 CacheOAuthTokenManager::refreshToken()
方法手动刷新它。
use BnplPartners\Factoring004\OAuth\CacheOAuthTokenManager; use BnplPartners\Factoring004\OAuth\OAuthTokenRefreshPolicy; $cacheTokenManager = new CacheOAuthTokenManager($tokenManager, $cache, 'cache key', OAuthTokenRefreshPolicy::ALWAYS_REFRESH()); $token = $cacheTokenManager->getAccessToken(); $accessToken = $token->getAccess();
清除缓存令牌
如果您需要清除缓存,您将手动清除缓存。
$cacheTokenManager->clearCache();
如果您遇到身份验证错误,您将手动清除缓存。
use BnplPartners\Factoring004\Exception\AuthenticationException; use BnplPartners\Factoring004\OAuth\CacheOAuthTokenManager; use BnplPartners\Factoring004\Order\OrderManager; $cacheTokenManager = new CacheOAuthTokenManager($tokenManager, $cache, 'cache key'); $orderManager = OrderManager::create('https://dev.bnpl.kz/api', new BearerTokenAuth($cacheTokenManager->getAccessToken()->getAccess())); try { $orderManager->preApp(...); } catch (AuthenticationException $e) { $cacheTokenManager->clearCache(); }
用法
我们建议使用类 BnplPartners\Factoring004\Order\OrderManager
调用我们的端点。
创建实例
use BnplPartners\Factoring004\Order\OrderManager; use BnplPartners\Factoring004\Auth\BearerTokenAuth; require_once __DIR__ . '/vendor/autoload.php'; $manager = OrderManager::create('https://dev.bnpl.kz/api', new BearerTokenAuth('Access Token'));
PreApp端点
$response = $manager->preApp([ 'partnerData' => [ 'partnerName' => 'test', 'partnerCode' => 'test', 'pointCode' => 'test', ], 'billNumber' => '1', 'billAmount' => 6000, 'itemsQuantity' => 1, 'successRedirect' => 'http://your-store.com/success', 'postLink' => 'http://your-store.com/internal', 'items' => [ [ 'itemId' => '1', 'itemName' => 'test', 'itemQuantity' => 1, 'itemPrice' => 6000, 'itemSum' => 6000, ], ], ]); var_dump($response->getRedirectLink());
交付端点
发送OTP
$response = $manager->delivery($merchantId, $orderId, $amount)->sendOtp(); var_dump($response->getMessage());
检查OTP
$response = $manager->delivery($merchantId, $orderId, $amount)->checkOtp($otp); var_dump($response->getMessage());
无OTP
$response = $manager->delivery($merchantId, $orderId, $amount)->confirmWithoutOtp(); var_dump($response->getMessage());
完整退货端点
发送OTP
$response = $manager->fullRefund($merchantId, $orderId)->sendOtp(); var_dump($response->getMessage());
检查OTP
$response = $manager->fullRefund($merchantId, $orderId)->checkOtp($otp); var_dump($response->getMessage());
无OTP
$response = $manager->fullRefund($merchantId, $orderId)->confirmWithoutOtp(); var_dump($response->getMessage());
部分退货端点
发送OTP
$response = $manager->partialRefund($merchantId, $orderId, $amount)->sendOtp(); var_dump($response->getMessage());
检查OTP
$response = $manager->partialRefund($merchantId, $orderId, $amount)->checkOtp($otp); var_dump($response->getMessage());
无OTP
$response = $manager->partialRefund($merchantId, $orderId, $amount)->confirmWithoutOtp(); var_dump($response->getMessage());
取消端点
$response = $manager->cancel($merchantId, $orderId); var_dump($response->getMessage());
错误处理
所有方法都可以抛出 BnplPartners\Factoring004\Exception\PackageException
实例。
use BnplPartners\Factoring004\Exception\PackageException; try { $response = $manager->delivery($merchantId, $orderId, $amount)->sendOtp(); } catch (PackageException $e) { var_dump($e); }
高级用法
这些类是低级API,在章节中描述。
创建api实例
use BnplPartners\Factoring004\Api; use BnplPartners\Factoring004\Auth\BearerTokenAuth; require_once __DIR__ . '/vendor/autoload.php'; $api = Api::create('https://dev.bnpl.kz/api', new BearerTokenAuth('Access Token'));
PreApp端点
创建预应用
use BnplPartners\Factoring004\PreApp\Item; use BnplPartners\Factoring004\PreApp\PreAppMessage; use BnplPartners\Factoring004\PreApp\PartnerData; $message = new PreAppMessage( new PartnerData('test', 'test', 'test'), '1', 6000, 1, 'http://your-store.com/success', 'http://your-store.com/internal', [new Item('1', 'test', 1, 6000, 6000)], ); // Or $message = PreAppMessage::createFromArray([ 'partnerData' => [ 'partnerName' => 'test', 'partnerCode' => 'test', 'pointCode' => 'test', ], 'billNumber' => '1', 'billAmount' => 6000, 'itemsQuantity' => 1, 'successRedirect' => 'http://your-store.com/success', 'postLink' => 'http://your-store.com/internal', 'items' => [ [ 'itemId' => '1', 'itemName' => 'test', 'itemQuantity' => 1, 'itemPrice' => 6000, 'itemSum' => 6000, ], ], ]); //Send request and receive response $response = $api->preApps->preApp($message); var_dump($response->getStatus(), $response->getPreAppId(), $response->getRedirectLink()); var_dump($response->toArray(), json_encode($response));
获取预应用状态
通过预应用ID获取状态
$status = $api->preApps->getStatus($preappID)->getStatus();
通过订单ID获取状态
$status = $api->bill->getStatus($orderID)->getStatus();
交付端点
发送OTP
use BnplPartners\Factoring004\Otp\SendOtp; $sendOtp = new SendOtp('1', '1', 6000); // or $sendOtp = SendOtp::createFromArray(['merchantId' => '1', 'merchantOrderId' => '1', 'amount' => 6000]); // send request and receive response $response = $api->otp->sendOtp($sendOtp); var_dump($response->getMsg()); var_dump($response->toArray(), json_encode($response));
检查OTP
use BnplPartners\Factoring004\Otp\CheckOtp; $checkOtp = new CheckOtp('1', '1', '1111', 6000); // or $checkOtp = CheckOtp::createFromArray(['merchantId' => '1', 'merchantOrderId' => '1', 'otp' => '1111', 'amount' => 6000]); // send request and receive response $response = $api->otp->checkOtp($checkOtp); var_dump($response->getMsg()); var_dump($response->toArray(), json_encode($response));
无OTP
use BnplPartners\Factoring004\ChangeStatus\DeliveryOrder; use BnplPartners\Factoring004\ChangeStatus\DeliveryStatus; use BnplPartners\Factoring004\ChangeStatus\ErrorResponse; use BnplPartners\Factoring004\ChangeStatus\MerchantsOrders; use BnplPartners\Factoring004\ChangeStatus\SuccessResponse; $orders = new MerchantsOrders('1', [new DeliveryOrder('1', DeliveryStatus::DELIVERY(), 6000)]); // or $orders = MerchantsOrders::createFromArray([ 'merchantId' => '1', 'orders' => [ ['orderId' => '1', 'status' => 'delivered', 'amount' => 6000], ], ]); // send request and receive response $response = $api->changeStatus->changeStatusJson($orders); var_dump(array_map(fn(SuccessResponse $response) => $response->getMsg(), $response->getSuccessfulResponses())); var_dump(array_map(fn(ErrorResponse $response) => $response->getMessage(), $response->getErrorResponses())); var_dump($response->toArray(), json_encode($response));
退款端点
发送OTP退货
use BnplPartners\Factoring004\Otp\SendOtpReturn; $sendOtpReturn = new SendOtpReturn(6000, '1', '1'); // or $sendOtpReturn = SendOtpReturn::createFromArray(['amountAr' => 6000, 'merchantId' => '1', 'merchantOrderId' => '1']); // send request and receive response $response = $api->otp->sendOtpReturn($sendOtpReturn); var_dump($response->getMsg()); var_dump($response->toArray(), json_encode($response));
检查OTP退货
use BnplPartners\Factoring004\Otp\CheckOtpReturn; $checkOtpReturn = new CheckOtpReturn(6000, '1', '1', '1111'); // or $checkOtpReturn = CheckOtp::createFromArray(['amountAr' => 6000, 'merchantId' => '1', 'merchantOrderId' => '1', 'otp' => '1111']); // send request and receive response $response = $api->otp->checkOtpReturn($checkOtpReturn); var_dump($response->getMsg()); var_dump($response->toArray(), json_encode($response));
无OTP
use BnplPartners\Factoring004\ChangeStatus\ErrorResponse; use BnplPartners\Factoring004\ChangeStatus\MerchantsOrders; use BnplPartners\Factoring004\ChangeStatus\ReturnOrder; use BnplPartners\Factoring004\ChangeStatus\ReturnStatus; use BnplPartners\Factoring004\ChangeStatus\SuccessResponse; $orders = new MerchantsOrders('1', [new ReturnOrder('1', ReturnStatus::RETURN(), 6000)]); // or $orders = MerchantsOrders::createFromArray([ 'merchantId' => '1', 'orders' => [ ['orderId' => '1', 'status' => 'return', 'amount' => 6000], ], ]); // send request and receive response $response = $api->changeStatus->changeStatusJson($orders); var_dump(array_map(fn(SuccessResponse $response) => $response->getMsg(), $response->getSuccessfulResponses())); var_dump(array_map(fn(ErrorResponse $response) => $response->getMessage(), $response->getErrorResponses())); var_dump($response->toArray(), json_encode($response));
取消
use BnplPartners\Factoring004\ChangeStatus\ErrorResponse; use BnplPartners\Factoring004\ChangeStatus\MerchantsOrders; use BnplPartners\Factoring004\ChangeStatus\CancelOrder; use BnplPartners\Factoring004\ChangeStatus\CancelStatus; use BnplPartners\Factoring004\ChangeStatus\SuccessResponse; $orders = new MerchantsOrders('1', [new CancelOrder('1', CancelStatus::CANCEL())]); // or $orders = MerchantsOrders::createFromArray([ 'merchantId' => '1', 'orders' => [ ['orderId' => '1', 'status' => 'canceled'], ], ]); // send request and receive response $response = $api->changeStatus->changeStatusJson($orders); var_dump(array_map(fn(SuccessResponse $response) => $response->getMsg(), $response->getSuccessfulResponses())); var_dump(array_map(fn(ErrorResponse $response) => $response->getMessage(), $response->getErrorResponses())); var_dump($response->toArray(), json_encode($response));
错误处理
无论API返回什么错误,客户端都会抛出 BnplPartners\Factoring004\Exception\ApiException
实例。
use BnplPartners\Factoring004\Exception\ApiException; use BnplPartners\Factoring004\Exception\AuthenticationException; use BnplPartners\Factoring004\Exception\EndpointUnavailableException; use BnplPartners\Factoring004\Exception\ErrorResponseException; use BnplPartners\Factoring004\Exception\NetworkException; use BnplPartners\Factoring004\Exception\PackageException; use BnplPartners\Factoring004\Exception\TransportException; use BnplPartners\Factoring004\Exception\UnexpectedResponseException; use BnplPartners\Factoring004\Exception\ValidationException; try { $api->preApps->preApp($message); } catch (AuthenticationException $e) { // authentication errors, token invalid, token expired, etc var_dump($e->getCode(), $e->getMessage(), $e->getDescription()); } catch (EndpointUnavailableException $e) { // to catch all internal server errors 500, 503, etc var_dump($e->getResponse()); } catch (ErrorResponseException $e) { // to catch all client errors 400, 405, etc var_dump($e->getErrorResponse()); } catch (UnexpectedResponseException $e) { // to catch all responses with unexpected schema var_dump($e->getResponse()); } catch (ValidationException $e) { // endpoint validation error $details = $e->getResponse()->getDetails(); var_dump($details[0]->getError(), $details[0]->getField()); } catch (ApiException $e) { // to catch all api layer exceptions } catch (NetworkException $e) { // network issues, connection refused, etc } catch (TransportException $e) { // to catch all transport layer exceptions } catch (PackageException $e) { // to catch all the package exceptions }
异常层次结构
PackageException
ApiException
AuthenticationException
ValidationException
ErrorResponseException
UnexpectedResponseException
EndpointUnavailableException
TransportException
NetworkException
DataSerializationException
定制
PSR HTTP客户端
首先安装任何PSR-17和PSR-18包。请参阅PSR-17包 和 PSR-18包。
例如,我们安装了流行的Guzzle HTTP客户端。自版本7起,它已经实现了PSR-17和PSR-18。
composer require guzzlehttp/guzzle
对于Guzzle 6,您可以使用 GuzzleTransport
或 PsrTransport
与额外的PSR-17和PSR-18适配器。请参阅下面。
安装Guzzle 6的PSR-17和PSR-18适配器。
composer require http-interop/http-factory-guzzle mjelamanov/psr18-guzzle
传输层
传输是HTTP客户端的抽象层。
对于Guzzle 6和7
use BnplPartners\Factoring004\Transport\GuzzleTransport; require_once __DIR__ . '/vendor/autoload.php'; $transport = new GuzzleTransport(new GuzzleHttp\Client());
对于PSR-17和PSR-18客户端。
use BnplPartners\Factoring004\Transport\PsrTransport; require_once __DIR__ . '/vendor/autoload.php'; $transport = new PsrTransport( new GuzzleHttp\Psr7\HttpFactory(), new GuzzleHttp\Psr7\HttpFactory(), new GuzzleHttp\Psr7\HttpFactory(), new GuzzleHttp\Client(), );
对于具有PSR-17和PSR-18适配器的Guzzle 6客户端。
use BnplPartners\Factoring004\Transport\PsrTransport; require_once __DIR__ . '/vendor/autoload.php'; $transport = new PsrTransport( new Http\Factory\Guzzle\RequestFactory(), new Http\Factory\Guzzle\StreamFactory(), new Http\Factory\Guzzle\UriFactory(), new Mjelamanov\GuzzlePsr18\Client(new GuzzleHttp\Client()), );
对于其他PSR-17和PSR-18客户端。
use BnplPartners\Factoring004\Transport\PsrTransport; require_once __DIR__ . '/vendor/autoload.php'; $transport = new PsrTransport( new RequestFactory(), // PSR-17 instance new StreamFactory(), // PSR-17 instance new UriFactory(), // PSR-17 instance new Client() // PSR-18 instance );
您可以创建自己的传输。只需实现 BnplPartners\Factoring004\Transport\TransportInterface
。
发送请求
$response = $transport->post('/bnpl/v3/preapp', ['partnerData' => [...]], ['Content-Type' => 'application/json']); var_dump($response->getStatusCode()); // HTTP response status code var_dump($response->getHeaders()); // HTTP response headers var_dump($response->getBody()); // parsed HTTP response body
资源
每个资源是一组分组端点。
use BnplPartners\Factoring004\Auth\BearerTokenAuth; use BnplPartners\Factoring004\Otp\OtpResource; use BnplPartners\Factoring004\PreApp\PreAppResource; require_once __DIR__ . '/vendor/autoload.php'; ... $preApp = new PreAppResource($transport, 'https://dev.bnpl.kz/api', new BearerTokenAuth('Access Token')); $response = $preApp->preApp(...); $otp = new OtpResource($transport, 'https://dev.bnpl.kz/api', new BearerTokenAuth('Access Token')); $response = $otp->sendOtp(...);
测试
./vendor/bin/phpunit