doku / doku-php-library
处理API SNAP的库
1.0.2
2024-09-25 04:23 UTC
Requires
- php: >=8.1
- firebase/php-jwt: ^6.10
- paragonie/sodium_compat: ^2.0
Requires (Dev)
- phpunit/phpunit: ^11.3@dev
README
本指南演示了如何在PHP项目中集成和使用Doku Snap SDK以执行各种支付操作。
目录
Doku Snap SDK集成指南
目录
安装
使用Composer安装Doku Snap SDK
composer require doku/doku-php-library
配置
在使用Doku Snap SDK之前,您需要使用您的凭据对其进行初始化
use Doku\Snap\Snap; $privateKey = "YOUR_PRIVATE_KEY"; $publicKey = "YOUR_PUBLIC_KEY"; $clientId = "YOUR_CLIENT_ID"; $secretKey = "YOUR_SECRET_KEY"; $isProduction = false; // Set to true for production environment $issuer = "YOUR_ISSUER"; // Optional $authCode = "YOUR_AUTH_CODE"; // Optional $snap = new Snap($privateKey, $publicKey, $clientId, $issuer, $isProduction, $secretKey, $authCode);
使用
初始化
始终从初始化Snap对象开始
$snap = new Snap($privateKey, $publicKey, $clientId, $issuer, $isProduction, $secretKey, $authCode);
令牌管理
获取当前令牌
$currentToken = $snap->getCurrentTokenB2B(); echo "Current Token: " . $currentToken . PHP_EOL;
生成新令牌
$newTokenResponse = $snap->getB2BToken($privateKey, $clientId, $isProduction); echo "New Token: " . $newTokenResponse->accessToken . PHP_EOL;
虚拟账户操作
创建虚拟账户
use Doku\Snap\Models\VA\Request\CreateVaRequestDto; use Doku\Snap\Models\TotalAmount\TotalAmount; use Doku\Snap\Models\VA\AdditionalInfo\CreateVaRequestAdditionalInfo; use Doku\Snap\Models\VA\VirtualAccountConfig\CreateVaVirtualAccountConfig; $createVaRequestDto = new CreateVaRequestDto( "8129014", // partner "17223992157", // customerno "812901417223992157", // customerNo "T_" . time(), // virtualAccountName "test.example." . time() . "@test.com", // virtualAccountEmail "621722399214895", // virtualAccountPhone "INV_CIMB_" . time(), // trxId new TotalAmount("12500.00", "IDR"), // totalAmount new CreateVaRequestAdditionalInfo("VIRTUAL_ACCOUNT_BANK_CIMB", new CreateVaVirtualAccountConfig(true)), // additionalInfo 'C', // virtualAccountTrxType "2024-08-31T09:54:04+07:00" // expiredDate ); $result = $snap->createVa($createVaRequestDto); echo json_encode($result, JSON_PRETTY_PRINT);
更新虚拟账户
use Doku\Snap\Models\VA\Request\UpdateVaRequestDto; use Doku\Snap\Models\VA\AdditionalInfo\UpdateVaRequestAdditionalInfo; use Doku\Snap\Models\VA\VirtualAccountConfig\UpdateVaVirtualAccountConfig; $updateVaRequestDto = new UpdateVaRequestDto( "8129014", // partnerServiceId "17223992155", // customerNo "812901417223992155", // virtualAccountNo "T_" . time(), // virtualAccountName "test.example." . time() . "@test.com", // virtualAccountEmail "00000062798", // virtualAccountPhone "INV_CIMB_" . time(), // trxId new TotalAmount("14000.00", "IDR"), // totalAmount new UpdateVaRequestAdditionalInfo("VIRTUAL_ACCOUNT_BANK_CIMB", new UpdateVaVirtualAccountConfig("ACTIVE", "10000.00", "15000.00")), // additionalInfo "O", // virtualAccountTrxType "2024-08-02T15:54:04+07:00" // expiredDate ); $result = $snap->updateVa($updateVaRequestDto); echo json_encode($result, JSON_PRETTY_PRINT);
删除虚拟账户
use Doku\Snap\Models\VA\Request\DeleteVaRequestDto; use Doku\Snap\Models\VA\AdditionalInfo\DeleteVaRequestAdditionalInfo; $deleteVaRequestDto = new DeleteVaRequestDto( "8129014", // partnerServiceId "17223992155", // customerNo "812901417223992155", // virtualAccountNo "INV_CIMB_" . time(), // trxId new DeleteVaRequestAdditionalInfo("VIRTUAL_ACCOUNT_BANK_CIMB") // additionalInfo ); $result = $snap->deletePaymentCode($deleteVaRequestDto); echo json_encode($result, JSON_PRETTY_PRINT);
检查虚拟账户状态
use Doku\Snap\Models\VA\Request\CheckStatusVaRequestDto; $checkStatusVaRequestDto = new CheckStatusVaRequestDto( "8129014", // partnerServiceId "17223992155", // customerNo "812901417223992155", // virtualAccountNo null, null, null ); $result = $snap->checkStatusVa($checkStatusVaRequestDto); echo json_encode($result, JSON_PRETTY_PRINT);
直接扣款操作
账户绑定
use Doku\Snap\Models\AccountBinding\AccountBindingRequestDto; use Doku\Snap\Models\AccountBinding\AccountBindingAdditionalInfoRequestDto; $additionalInfo = new AccountBindingAdditionalInfoRequestDto( "Mandiri", // channel "CUST123", // custIdMerchant "John Doe", // customerName "john.doe@example.com", // email "1234567890", // idCard "Indonesia", // country "123 Main St, Jakarta", // address "19900101", // dateOfBirth "https://success.example.com", // successRegistrationUrl "https://fail.example.com", // failedRegistrationUrl "iPhone 12", // deviceModel "iOS", // osType "CH001" // channelId ); $accountBindingRequestDto = new AccountBindingRequestDto( "6281234567890", // phoneNo $additionalInfo ); $result = $snap->doAccountBinding($accountBindingRequestDto, $privateKey, $clientId, $secretKey, $isProduction); echo json_encode($result, JSON_PRETTY_PRINT);
账户解绑
use Doku\Snap\Models\AccountUnbinding\AccountUnbindingRequestDto; use Doku\Snap\Models\AccountUnbinding\AccountUnbindingAdditionalInfoRequestDto; $additionalInfo = new AccountUnbindingAdditionalInfoRequestDto("Mandiri"); $accountUnbindingRequestDto = new AccountUnbindingRequestDto( "tokenB2b2c123", // tokenId (tokenB2b2c) $additionalInfo ); $result = $snap->doAccountUnbinding($accountUnbindingRequestDto, $privateKey, $clientId, $secretKey, $isProduction); echo json_encode($result, JSON_PRETTY_PRINT);
支付跳跃应用
use Doku\Snap\Models\PaymentJumpApp\PaymentJumpAppRequestDto; use Doku\Snap\Models\PaymentJumpApp\PaymentJumpAppAdditionalInfoRequestDto; use Doku\Snap\Models\PaymentJumpApp\UrlParamDto; $timestamp = time(); $totalAmount = new TotalAmount("50000.00", "IDR"); $additionalInfo = new PaymentJumpAppAdditionalInfoRequestDto( "Mandiri", // channel "Payment for Order #123", // remarks "merchantId" ); $urlParam = new UrlParamDto("url", "type", "no"); $paymentJumpAppRequestDto = new PaymentJumpAppRequestDto( "ORDER_" . $timestamp, // partnerReferenceNo date('Y-m-d H:i:s', strtotime('+1 day')), // validUpTo (24 hours from now) "12", // pointOfInitiation $urlParam, $totalAmount, $additionalInfo ); $deviceId = "DEVICE_ID_123"; $result = $snap->doPaymentJumpApp($paymentJumpAppRequestDto, $deviceId, $privateKey, $clientId, $secretKey, $isProduction); echo json_encode($result, JSON_PRETTY_PRINT);
卡片操作
卡片注册
use Doku\Snap\Models\CardRegistration\CardRegistrationRequestDto; use Doku\Snap\Models\CardRegistration\CardRegistrationAdditionalInfoRequestDto; $additionalInfo = new CardRegistrationAdditionalInfoRequestDto( 'Mandiri', 'John Doe', 'john@example.com', '1234567890', 'ID', '123 Main St', '19900101', 'http://success.url', 'http://failed.url' ); $cardRegistrationRequestDto = new CardRegistrationRequestDto( 'encrypted_card_data', 'cust123', '081234567890', $additionalInfo ); $deviceId = "DEVICE_ID_123"; $response = $snap->doCardRegistration( $cardRegistrationRequestDto, $deviceId, $privateKey, $clientId, $secretKey, $isProduction ); echo json_encode($response, JSON_PRETTY_PRINT);
卡片解绑
use Doku\Snap\Models\AccountUnbinding\AccountUnbindingRequestDto; use Doku\Snap\Models\AccountUnbinding\AccountUnbindingAdditionalInfoRequestDto; $additionalInfo = new AccountUnbindingAdditionalInfoRequestDto("Mandiri"); $cardUnbindingRequestDto = new AccountUnbindingRequestDto( "tokenB2b2c123", // tokenId (tokenB2b2c) $additionalInfo ); $result = $snap->doCardUnbinding($cardUnbindingRequestDto, $privateKey, $clientId, $secretKey, $isProduction); echo json_encode($result, JSON_PRETTY_PRINT);
其他操作
检查交易状态
use Doku\Snap\Models\CheckStatus\CheckStatusRequestDto; use Doku\Snap\Models\CheckStatus\CheckStatusAdditionalInfoRequestDto; $checkStatusRequestDto = new CheckStatusRequestDto( "originalPartnerRefNo123", // originalPartnerReferenceNo "originalRefNo456", // originalReferenceNo "originalExtId789", // originalExternalId "SERVICE_CODE_001", // serviceCode "2023-08-29T12:00:00+07:00", // transactionDate new TotalAmount(100000, "IDR"),// totalAmount "MERCHANT_001", // merchantId "SUBMERCHANT_001", // subMerchantId "STORE_001", // externalStoreId new CheckStatusAdditionalInfoRequestDto("DEVICE_001", "DIRECT_DEBIT_MANDIRI") // additionalInfo ); $authCode = "exampleAuthCode456"; $response = $snap->doCheckStatus( $checkStatusRequestDto, $authCode, $privateKey, $clientId, $secretKey, $isProduction ); echo json_encode($response, JSON_PRETTY_PRINT);
退款
use Doku\Snap\Models\Refund\RefundRequestDto; use Doku\Snap\Models\Refund\RefundAdditionalInfoRequestDto; $additionalInfo = new RefundAdditionalInfoRequestDto("WEB"); $refundAmount = new TotalAmount("100.00", "USD"); $refundRequest = new RefundRequestDto( $additionalInfo, "ORIG123", "EXT456", $refundAmount, "Customer request", "REF789" ); $authCode = "exampleAuthCode456"; $result = $snap->doRefund($refundRequest, $authCode, $privateKey, $clientId, $secretKey, $isProduction); echo json_encode($result, JSON_PRETTY_PRINT);
余额查询
use Doku\Snap\Models\BalanceInquiry\BalanceInquiryRequestDto; use Doku\Snap\Models\BalanceInquiry\BalanceInquiryAdditionalInfoRequestDto; $additionalInfo = new BalanceInquiryAdditionalInfoRequestDto("DIRECT_DEBIT_MANDIRI"); $balanceInquiryRequestDto = new BalanceInquiryRequestDto($additionalInfo); $authCode = "exampleAuthCode123"; $result = $snap->doBalanceInquiry($balanceInquiryRequestDto, $authCode); echo "Response Code: " . $result->responseCode . PHP_EOL; echo "Response Message: " . $result->responseMessage . PHP_EOL; echo "Account Infos: " . PHP_EOL; foreach ($result->accountInfos as $accountInfo) { echo " Balance Type: " . $accountInfo->balanceType . PHP_EOL; echo " Amount: " . $accountInfo->amount->value . " " . $accountInfo->amount->currency . PHP_EOL; echo " Flat Amount: " . $accountInfo->flatAmount->value . " " . $accountInfo->flatAmount->currency . PHP_EOL; echo " Hold Amount: " . $accountInfo->holdAmount->value . " " . $accountInfo->holdAmount->currency . PHP_EOL; echo "---" . PHP_EOL; }
错误处理
SDK为各种错误条件抛出异常。始终将您的API调用包裹在try-catch块中
try { $result = $snap->createVa($createVaRequestDto); // Process successful result } catch (Exception $e) { echo "Error: " . $e->getMessage() . PHP_EOL; // Handle the error appropriately }
高级使用
处理令牌请求
在控制器中处理令牌请求(例如,在CodeIgniter中)
public function tokenRequest() { try { $xSignature = $this->request->getHeaderLine('X-SIGNATURE'); $xTimestamp = $this->request->getHeaderLine('X-TIMESTAMP'); $xClientKey = $this->request->getHeaderLine('X-CLIENT-KEY'); $jsonBody = $this->request->getJSON(true); // Validate headers and body if (empty($xSignature) || empty($xTimestamp) || empty($xClientKey)) { return $this->failUnauthorized('Missing required headers'); } if (!isset($jsonBody['grantType']) || $jsonBody['grantType'] !== 'client_credentials') { return $this->failValidationError('Invalid or missing grantType in request body'); } $isSignatureValid = $this->snap->validateSignature($xSignature, $xTimestamp, $this->privateKey, $xClientKey); $notificationTokenDTO = $this->snap->generateTokenB2BResponse($isSignatureValid); $responseBody = $notificationTokenDTO->generateJSONBody(); $headers = $notificationTokenDTO->generateJSONHeader(); // Set response headers foreach (json_decode($headers) as $name => $value) { $this->response->setHeader($name, $value); } return $this->respond(json_decode($responseBody), 200); } catch (\Exception $e) { return $this->fail(['error' => $e->getMessage()], 500); } }
处理支付通知
处理支付通知
use Doku\Snap\Models\RequestHeader\RequestHeaderDTO; use Doku\Snap\Models\Notification\PaymentNotificationRequestBodyDTO; use Doku\Snap\Models\TotalAmount\TotalAmount; use Doku\Snap\Models\Notification\PaymentNotificationRequestAdditionalInfo; public function paymentNotification() { $jsonBody = $this->request->getJSON(true); $xRequestId = time() * 1000; $requestHeaderDTO = new RequestHeaderDTO( $this->request->getHeaderLine('X-TIMESTAMP'), $this->request->getHeaderLine('X-SIGNATURE'), $this->request->getHeaderLine('X-CLIENT-KEY'), $xRequestId, "channel_id", $this->request->getHeaderLine('Authorization') ); $paidAmount = new TotalAmount( $jsonBody['paidAmount']['value'] ?? null, $jsonBody['paidAmount']['currency'] ?? null ); $additionalInfo = new PaymentNotificationRequestAdditionalInfo( $jsonBody['additionalInfo']['channel'] ?? null, $jsonBody['additionalInfo']['senderName'] ?? null, $jsonBody['additionalInfo']['sourceAccountNo'] ?? null, $jsonBody['additionalInfo']['sourceBankCode'] ?? null, $jsonBody['additionalInfo']['sourceBankName'] ?? null ); $paymentNotificationRequestBodyDTO = new PaymentNotificationRequestBodyDTO( $jsonBody['partnerServiceId'] ?? '', $jsonBody['customerNo'] ?? '', $jsonBody['virtualAccountNo'] ?? '', $jsonBody['virtualAccountName'] ?? '', $jsonBody['virtualAccountEmail'] ?? '', $jsonBody['trxId'] ?? '', $jsonBody['paymentRequestId'] ?? '', $paidAmount, $jsonBody['virtualAccountPhone'] ?? '', $additionalInfo, $jsonBody['trxDateTime'] ?? $jsonBody['expiredDate'] ?? '', $jsonBody['virtualAccountTrxType'] ?? '' ); $responseDTO = $this->snap->validateTokenAndGenerateNotificationResponse($requestHeaderDTO, $paymentNotificationRequestBodyDTO); $headers = $responseDTO->generateJSONHeader(); $responseBody = $responseDTO->generateJSONBody(); foreach (json_decode($headers) as $name => $value) { $this->response->setHeader($name, $value); } return $this->respond(json_decode($responseBody)); }
处理直接查询
处理直接查询
public function inquiry() { $authorization = $this->request->getHeaderLine('Authorization'); $isValid = $this->snap->validateTokenB2B($authorization); if ($isValid) { $requestBody = $this->request->getJSON(true); $inquiryRequestId = $requestBody['inquiryRequestId']; $header = $this->snap->generateRequestHeader(); $body = [ "responseCode" => "2002400", "responseMessage" => "Successful", "virtualAccountData" => [ "partnerServiceId" => "12362", "customerNo" => "60000000000000000001", "virtualAccountNo" => "1236260000000000000000001", "virtualAccountName" => "Customer Name", "virtualAccountEmail" => "customer.email@mail.com", "virtualAccountPhone" => "081293912081", "totalAmount" => [ "value" => "11500.00", "currency" => "IDR" ], "virtualAccountTrxType" => "C", "expiredDate" => "2023-01-01T10:55:00+07:00", "additionalInfo" => [ "channel" => "VIRTUAL_ACCOUNT_BRI", "trxId" => "INV-001" ], "inquiryStatus" => "00", "inquiryReason" => [ "english" => "Success", "indonesia" => "Sukses" ], "inquiryRequestId" => $inquiryRequestId, ] ]; foreach ($this->request->getHeaders() as $name => $value) { $this->response->setHeader($name, $value); } return $this->respond($body); } else { return $this->failUnauthorized('Invalid token'); } }
处理直接扣款的支付通知
处理直接扣款的支付通知
use Doku\Snap\Models\NotifyPayment\NotifyPaymentDirectDebitRequestDto; use Doku\Snap\Models\TotalAmount\TotalAmount; use Doku\Snap\Models\NotifyPayment\PaymentNotificationAdditionalInfoRequestDto; use Doku\Snap\Models\VA\AdditionalInfo\Origin; use Doku\Snap\Models\Payment\LineItemsDto; public function handleDirectDebitNotification() { $requestBody = $this->request->getJSON(true); $xSignature = $this->request->getHeaderLine('X-SIGNATURE'); $xTimestamp = $this->request->getHeaderLine('X-TIMESTAMP'); $amount = new TotalAmount($requestBody['amount']['value'], $requestBody['amount']['currency']); $lineItems = array_map(function ($item) { return new LineItemsDto($item['name'], $item['price'], $item['quantity']); }, $requestBody['additionalInfo']['lineItems']); $additionalInfo = new PaymentNotificationAdditionalInfoRequestDto( $requestBody['additionalInfo']['channelId'], $requestBody['additionalInfo']['acquirerId'], $requestBody['additionalInfo']['custIdMerchant'], $requestBody['additionalInfo']['accountType'], $lineItems, new Origin() ); $notifyPaymentRequest = new NotifyPaymentDirectDebitRequestDto( $requestBody['originalPartnerReferenceNo'], $requestBody['originalReferenceNo'], $requestBody['originalExternalId'], $requestBody['latestTransactionStatus'], $requestBody['transactionStatusDesc'], $amount, $additionalInfo ); $response = $this->snap->handleDirectDebitNotification($notifyPaymentRequest, $xSignature, $xTimestamp); return $this->respond($response); }
控制器最佳实践
- 验证输入:在处理之前始终验证和清理输入数据。
- 使用try-catch:将您的SDK调用包裹在try-catch块中,以优雅地处理异常。
- 记录错误:记录任何错误或异常以进行调试。
- 设置适当的头信息:确保您在响应中设置了正确的头信息。
- 处理令牌过期:实现逻辑以在令牌过期时刷新令牌。
- 保护敏感数据:永远不要记录或公开敏感数据,如令牌或个人信息。
遵循这些模式和最佳实践,您可以将Doku Snap SDK有效地集成到CodeIgniter或类似的MVC框架应用中。