refactor(Sbp)

This commit is contained in:
Anatoliy Poloz
2026-03-17 12:26:30 +03:00
parent e2adc8d530
commit b7b2a8fd61
25 changed files with 244 additions and 197 deletions

View File

@@ -13,11 +13,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <SECTION name="module_imports" intent="Import DTO and Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request requires the `ActivateCashQrRequestData` DTO for its JSON body and utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\CashLink\ActivateCashQrRequestData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -25,7 +26,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for activating a CashLink QR Code, a key management operation in SBP payment systems.">
class ActivateCashQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Activating a resource is an action that changes the system state, so POST is the correct verb.">
@@ -56,9 +57,9 @@ class ActivateCashQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Fields from the DTO are mapped, including conditional parameters for order number, payment purpose, QR TTL, and notification URLs.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'ActivateCashQRc',
'TermNo' => $this->data->TermNo,
'qrcId' => $this->data->qrcId,
@@ -67,22 +68,22 @@ class ActivateCashQrRequest extends Request implements HasBody
];
if ($this->data->OrderNumber !== null) {
$body['OrderNumber'] = $this->data->OrderNumber;
$bodyArray['OrderNumber'] = $this->data->OrderNumber;
}
if ($this->data->paymentPurpose !== null) {
$body['paymentPurpose'] = $this->data->paymentPurpose;
$bodyArray['paymentPurpose'] = $this->data->paymentPurpose;
}
if ($this->data->qrTtl !== null) {
$body['qrTtl'] = $this->data->qrTtl;
$bodyArray['qrTtl'] = $this->data->qrTtl;
}
if ($this->data->redirectUrl !== null) {
$body['redirectUrl'] = $this->data->redirectUrl;
$bodyArray['redirectUrl'] = $this->data->redirectUrl;
}
if ($this->data->notificationUrl !== null) {
$body['queryData'] = ['notificationUrl' => $this->data->notificationUrl];
$bodyArray['queryData'] = ['notificationUrl' => $this->data->notificationUrl];
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,20 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to change the account for a CashLink QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for modifying a CashLink QR Code, which is a key management operation.">
class ChangeAccountForCashQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Modifying a resource via an action is correctly represented by a POST request in the SBP API context.">
@@ -53,7 +53,7 @@ class ChangeAccountForCashQrRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Return the raw JSON response as an array.">
// <BELIEF_STATE "For this specific request, the response is currently returned as a raw array. A dedicated DTO could be created if a structured object is required.">
public function createDtoFromResponse(\Saloon\Http\Response $response): array
public function createDtoFromResponse(Response $response): array
{
return $response->json();
}
@@ -61,9 +61,9 @@ class ChangeAccountForCashQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Fields are conditionally added based on constructor parameters, ensuring the payload precisely matches the API specification.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'ChangeAccForCashQRc',
'TermNo' => $this->TermNo,
'qrcId' => $this->qrcId,
@@ -71,16 +71,16 @@ class ChangeAccountForCashQrRequest extends Request implements HasBody
];
if ($this->NewTermNo !== null) {
$body['NewTermNo'] = $this->NewTermNo;
$bodyArray['NewTermNo'] = $this->NewTermNo;
}
if ($this->NewMerchantId !== null) {
$body['NewMerchantId'] = $this->NewMerchantId;
$bodyArray['NewMerchantId'] = $this->NewMerchantId;
}
if ($this->redirectUrl !== null) {
$body['redirectUrl'] = $this->redirectUrl;
$bodyArray['redirectUrl'] = $this->redirectUrl;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,20 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to change the terminal number for a CashLink QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for modifying a CashLink QR Code, specifically its associated terminal, which is a key management operation.">
class ChangeTermNoForCashQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Modifying a resource via an action is correctly represented by a POST request in the SBP API context.">
@@ -49,7 +49,7 @@ class ChangeTermNoForCashQrRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Return the raw JSON response as an array.">
// <BELIEF_STATE "For this specific request, the response is currently returned as a raw array. A dedicated DTO could be created if a structured object is required.">
public function createDtoFromResponse(\Saloon\Http\Response $response): array
public function createDtoFromResponse(Response $response): array
{
return $response->json();
}
@@ -57,13 +57,15 @@ class ChangeTermNoForCashQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo` and `qrcId` are included in the body to identify the target.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'ChangeTermNoForCashQRc',
'TermNo' => $this->TermNo,
'qrcId' => $this->qrcId,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,20 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to delete a CashLink QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for deleting a CashLink QR Code, which is a critical management operation.">
class DeleteCashQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Deleting a resource via an action is correctly represented by a POST request in the SBP API context.">
@@ -49,7 +49,7 @@ class DeleteCashQrRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Return the raw JSON response as an array.">
// <BELIEF_STATE "For this specific request, the response is currently returned as a raw array. A dedicated DTO could be created if a structured object is required.">
public function createDtoFromResponse(\Saloon\Http\Response $response): array
public function createDtoFromResponse(Response $response): array
{
return $response->json();
}
@@ -57,13 +57,15 @@ class DeleteCashQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo` and `qrcId` are included in the body to identify the target.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'DelCashQRc',
'TermNo' => $this->TermNo,
'qrcId' => $this->qrcId,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,20 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to get the history of a CashLink QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for querying the history of a CashLink QR Code, which is useful for auditing and reconciliation.">
class GetCashQrHistoryRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP history requests are often performed via POST requests with a JSON body.">
@@ -51,7 +51,7 @@ class GetCashQrHistoryRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Return the raw JSON response as an array.">
// <BELIEF_STATE "For this specific request, the response is currently returned as a raw array. A dedicated DTO could be created if a structured object is required.">
public function createDtoFromResponse(\Saloon\Http\Response $response): array
public function createDtoFromResponse(Response $response): array
{
return $response->json();
}
@@ -59,15 +59,17 @@ class GetCashQrHistoryRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. All constructor properties are directly mapped to the request body to identify the QR Code and the date range.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'GetCashQrcId',
'TermNo' => $this->TermNo,
'qrcId' => $this->qrcId,
'dateFrom' => $this->dateFrom,
'dateTo' => $this->dateTo,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,20 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to get the status of a CashLink QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for querying the status of a CashLink QR Code, which is crucial for tracking payment flows.">
class GetCashQrStatusRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP status checks are often performed via POST requests with a JSON body.">
@@ -49,7 +49,7 @@ class GetCashQrStatusRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Return the raw JSON response as an array.">
// <BELIEF_STATE "For this specific request, the response is currently returned as a raw array. A dedicated DTO could be created if a structured object is required.">
public function createDtoFromResponse(\Saloon\Http\Response $response): array
public function createDtoFromResponse(Response $response): array
{
return $response->json();
}
@@ -57,13 +57,15 @@ class GetCashQrStatusRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo` and `qrcId` identify the target.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'GetCashQRCstatus',
'TermNo' => $this->TermNo,
'qrcId' => $this->qrcId,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -14,11 +14,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\CashLink;
// <BELIEF_STATE "This POST request requires specific DTOs for its JSON body and its response, along with Saloon's body-handling traits.">
use Apoloz\AlfaBank\Sbp\Data\CashLink\RegCashQrRequestData;
use Apoloz\AlfaBank\Sbp\Data\CashLink\RegCashQrResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -26,7 +27,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for generating a CashLink QR Code, a key feature in SBP payment systems.">
class RegCashQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Creating a new QR Code resource or initiating a generation action is correctly represented by a POST request.">
@@ -57,30 +58,30 @@ class RegCashQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Fields from the DTO are mapped, including conditional parameters for media type, dimensions, redirect URL, and QR Code ID.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'RegCashQRc',
'TermNo' => $this->data->TermNo,
];
if ($this->data->mediaType !== null) {
$body['mediaType'] = $this->data->mediaType;
$bodyArray['mediaType'] = $this->data->mediaType;
}
if ($this->data->width !== null) {
$body['width'] = $this->data->width;
$bodyArray['width'] = $this->data->width;
}
if ($this->data->height !== null) {
$body['height'] = $this->data->height;
$bodyArray['height'] = $this->data->height;
}
if ($this->data->redirectUrl !== null) {
$body['redirectUrl'] = $this->data->redirectUrl;
$bodyArray['redirectUrl'] = $this->data->redirectUrl;
}
if ($this->data->qrcId !== null) {
$body['qrcId'] = $this->data->qrcId;
$bodyArray['qrcId'] = $this->data->qrcId;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -18,7 +18,6 @@ use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
// </SECTION>
@@ -26,7 +25,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for modifying a Digital Ruble CashLink QR Code, which is a key management operation.">
class ChangeAccForCashUniQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Modifying a resource via an action is correctly represented by a POST request in the SBP API context.">
@@ -57,42 +56,42 @@ class ChangeAccForCashUniQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Fields from the DTO are mapped, including conditional parameters for the new account, merchant, redirect URL, etc.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'ChangeAccForCashUniQr',
'TermNo' => $this->data->TermNo,
];
if ($this->data->messageID !== null) {
$body['messageID'] = $this->data->messageID;
$bodyArray['messageID'] = $this->data->messageID;
}
if ($this->data->qrcId !== null) {
$body['qrcId'] = $this->data->qrcId;
$bodyArray['qrcId'] = $this->data->qrcId;
}
if ($this->data->account !== null) {
$body['account'] = $this->data->account;
$bodyArray['account'] = $this->data->account;
}
if ($this->data->accountDR !== null) {
$body['accountDR'] = $this->data->accountDR;
$bodyArray['accountDR'] = $this->data->accountDR;
}
if ($this->data->NewTermNo !== null) {
$body['NewTermNo'] = $this->data->NewTermNo;
$bodyArray['NewTermNo'] = $this->data->NewTermNo;
}
if ($this->data->NewMerchantId !== null) {
$body['NewMerchantId'] = $this->data->NewMerchantId;
$bodyArray['NewMerchantId'] = $this->data->NewMerchantId;
}
if ($this->data->redirectUrl !== null) {
$body['redirectUrl'] = $this->data->redirectUrl;
$bodyArray['redirectUrl'] = $this->data->redirectUrl;
}
if ($this->data->paymentPageUrl !== null) {
$body['paymentPageUrl'] = $this->data->paymentPageUrl;
$bodyArray['paymentPageUrl'] = $this->data->paymentPageUrl;
}
if ($this->data->fraudScore !== null) {
$body['fraudScore'] = $this->data->fraudScore;
$bodyArray['fraudScore'] = $this->data->fraudScore;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -18,7 +18,6 @@ use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
// </SECTION>
@@ -26,7 +25,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for generating a Digital Ruble CashLink QR Code, a key feature in the SBP Digital Ruble operations.">
class CreateCashUniQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Creating a new QR Code resource or initiating a generation action is correctly represented by a POST request.">
@@ -57,40 +56,40 @@ class CreateCashUniQrRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Fields from the DTO are mapped, including conditional and nested `queryData` for notification URLs.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'ReqCashUniQr',
'TermNo' => $this->data->TermNo,
];
if ($this->data->messageID !== null) {
$body['messageID'] = $this->data->messageID;
$bodyArray['messageID'] = $this->data->messageID;
}
if ($this->data->redirectUrl !== null) {
$body['redirectUrl'] = $this->data->redirectUrl;
$bodyArray['redirectUrl'] = $this->data->redirectUrl;
}
if ($this->data->paymentPageUrl !== null) {
$body['paymentPageUrl'] = $this->data->paymentPageUrl;
$bodyArray['paymentPageUrl'] = $this->data->paymentPageUrl;
}
if ($this->data->mediaType !== null) {
$body['mediaType'] = $this->data->mediaType;
$bodyArray['mediaType'] = $this->data->mediaType;
}
if ($this->data->width !== null) {
$body['width'] = $this->data->width;
$bodyArray['width'] = $this->data->width;
}
if ($this->data->height !== null) {
$body['height'] = $this->data->height;
$bodyArray['height'] = $this->data->height;
}
if ($this->data->qrcId !== null) {
$body['qrcId'] = $this->data->qrcId;
$bodyArray['qrcId'] = $this->data->qrcId;
}
if ($this->data->notificationUrl !== null) {
$body['queryData'] = ['notificationUrl' => $this->data->notificationUrl];
$bodyArray['queryData'] = ['notificationUrl' => $this->data->notificationUrl];
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -18,7 +18,6 @@ use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
// </SECTION>
@@ -26,7 +25,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for querying the status of a Digital Ruble CashLink QR Code, which is crucial for tracking payment flows.">
class GetCashUniQrStatusRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP status checks are often performed via POST requests with a JSON body.">
@@ -57,9 +56,9 @@ class GetCashUniQrStatusRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo`, `uniQrId`, and `paramsId` identify the target. Optional fields like `messageID` and `payrrn` provide additional context.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'GetCashUniQrStatus',
'TermNo' => $this->data->TermNo,
'uniQrId' => $this->data->uniQrId,
@@ -67,13 +66,13 @@ class GetCashUniQrStatusRequest extends Request implements HasBody
];
if ($this->data->messageID !== null) {
$body['messageID'] = $this->data->messageID;
$bodyArray['messageID'] = $this->data->messageID;
}
if ($this->data->payrrn !== null) {
$body['payrrn'] = $this->data->payrrn;
$bodyArray['payrrn'] = $this->data->payrrn;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -6,15 +6,16 @@ namespace Apoloz\AlfaBank\Sbp\Requests\DigitalRuble;
use Apoloz\AlfaBank\Sbp\Data\DigitalRuble\CreateUniQrRequestData;
use Apoloz\AlfaBank\Sbp\Data\DigitalRuble\UniQrResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
class CreateUniQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
protected Method $method = Method::POST;
@@ -32,40 +33,40 @@ class CreateUniQrRequest extends Request implements HasBody
return UniQrResponseData::from($response->json());
}
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'ReqUniQr',
'TermNo' => $this->data->TermNo,
'uniQrType' => $this->data->uniQrType,
];
if ($this->data->amount !== null) {
$body['amount'] = $this->data->amount;
$bodyArray['amount'] = $this->data->amount;
}
if ($this->data->paymentPurpose !== null) {
$body['paymentPurpose'] = $this->data->paymentPurpose;
$bodyArray['paymentPurpose'] = $this->data->paymentPurpose;
}
if ($this->data->redirectUrl !== null) {
$body['redirectUrl'] = $this->data->redirectUrl;
$bodyArray['redirectUrl'] = $this->data->redirectUrl;
}
if ($this->data->paymentPageUrl !== null) {
$body['paymentPageUrl'] = $this->data->paymentPageUrl;
$bodyArray['paymentPageUrl'] = $this->data->paymentPageUrl;
}
if ($this->data->mediaType !== null) {
$body['mediaType'] = $this->data->mediaType;
$bodyArray['mediaType'] = $this->data->mediaType;
}
if ($this->data->width !== null) {
$body['width'] = $this->data->width;
$bodyArray['width'] = $this->data->width;
}
if ($this->data->height !== null) {
$body['height'] = $this->data->height;
$bodyArray['height'] = $this->data->height;
}
if ($this->data->qrTtl !== null) {
$body['qrTtl'] = $this->data->qrTtl;
$bodyArray['qrTtl'] = $this->data->qrTtl;
}
if ($this->data->messageID !== null) {
$body['messageID'] = $this->data->messageID;
$bodyArray['messageID'] = $this->data->messageID;
}
$queryData = [];
@@ -83,9 +84,9 @@ class CreateUniQrRequest extends Request implements HasBody
}
if (! empty($queryData)) {
$body['queryData'] = $queryData;
$bodyArray['queryData'] = $queryData;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
}

View File

@@ -12,20 +12,21 @@ namespace Apoloz\AlfaBank\Sbp\Requests\DigitalRuble;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\DigitalRuble\GetUniQrStatusResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to get the status of Universal QR Codes.">
// <BELIEF_STATE "This class encapsulates the logic for querying the status of multiple Uni QR Codes, which is part of managing digital ruble transactions.">
class GetUniQrStatusRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP status checks are often performed via POST requests with a JSON body.">
@@ -49,21 +50,23 @@ class GetUniQrStatusRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `GetUniQrStatusResponseData` DTO provides a type-safe and structured object for the status of Universal QR Codes.">
public function createDtoFromResponse(\Saloon\Http\Response $response): \Apoloz\AlfaBank\Sbp\Data\DigitalRuble\GetUniQrStatusResponseData
public function createDtoFromResponse(Response $response): GetUniQrStatusResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\DigitalRuble\GetUniQrStatusResponseData::from($response->json());
return GetUniQrStatusResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo` and `uniQrIds` are included in the body to identify the targets.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'GetUniQrStatus',
'TermNo' => $this->TermNo,
'uniQrIds' => $this->uniQrIds,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -13,20 +13,21 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Management;
// <SECTION name="module_imports" intent="Import DTO and Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request requires the `BlockQrRequestData` DTO for its JSON body and utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\Management\BlockQrRequestData;
use Apoloz\AlfaBank\Sbp\Data\Management\SbpManagementResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to block a QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for blocking an SBP QR Code, which is a critical management operation.">
class BlockQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Blocking a resource is an action that changes the system state, so POST is the correct verb.">
@@ -49,20 +50,22 @@ class BlockQrRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `SbpManagementResponseData` DTO provides a structured object for the result of the block operation.">
public function createDtoFromResponse(\Saloon\Http\Response $response): \Apoloz\AlfaBank\Sbp\Data\Management\SbpManagementResponseData
public function createDtoFromResponse(Response $response): SbpManagementResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\Management\SbpManagementResponseData::from($response->json());
return SbpManagementResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Using the DTO's `toArray` method ensures the payload is correctly structured.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'BlockQRcId'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,21 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Management;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\Management\GetBlockedQrListResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to get a list of blocked QR Codes.">
// <BELIEF_STATE "This class encapsulates the logic for querying blocked QR Codes, which is part of managing payment terminals.">
class GetBlockedQrListRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP list requests are often performed via POST requests with a JSON body.">
@@ -48,20 +49,22 @@ class GetBlockedQrListRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `GetBlockedQrListResponseData` DTO provides a type-safe object for the list of blocked QR Codes.">
public function createDtoFromResponse(\Saloon\Http\Response $response): \Apoloz\AlfaBank\Sbp\Data\Management\GetBlockedQrListResponseData
public function createDtoFromResponse(Response $response): GetBlockedQrListResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\Management\GetBlockedQrListResponseData::from($response->json());
return GetBlockedQrListResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo` is included in the body to identify the terminal.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'GetBlockedQRcIdList',
'TermNo' => $this->TermNo,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -13,20 +13,21 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Management;
// <SECTION name="module_imports" intent="Import DTO and Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request requires the `BlockQrRequestData` DTO for its JSON body and utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\Management\BlockQrRequestData;
use Apoloz\AlfaBank\Sbp\Data\Management\SbpManagementResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to unblock a QR Code.">
// <BELIEF_STATE "This class encapsulates the logic for unblocking an SBP QR Code, which is a critical management operation.">
class UnblockQrRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Unblocking a resource is an action that changes the system state, so POST is the correct verb.">
@@ -49,20 +50,22 @@ class UnblockQrRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `SbpManagementResponseData` DTO provides a structured object for the result of the unblock operation.">
public function createDtoFromResponse(\Saloon\Http\Response $response): \Apoloz\AlfaBank\Sbp\Data\Management\SbpManagementResponseData
public function createDtoFromResponse(Response $response): SbpManagementResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\Management\SbpManagementResponseData::from($response->json());
return SbpManagementResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Using the DTO's `toArray` method ensures the payload is correctly structured.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'UnblockQRcId'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -13,11 +13,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Registry;
// <SECTION name="module_imports" intent="Import DTO and Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request requires the `GetBankListResponseData` DTO for its response and utilizes `HasBody` and `HasJsonBody` for proper payload serialization.">
use Apoloz\AlfaBank\Sbp\Data\Registry\GetBankListResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -25,7 +26,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for querying the list of SBP participating banks, which is essential for routing payments.">
class GetBankListRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP list requests are often performed via POST requests with a JSON body.">
@@ -57,20 +58,20 @@ class GetBankListRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Optional fields are conditionally added to the body.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'GetBankList',
];
if ($this->messageID !== null) {
$body['messageID'] = $this->messageID;
$bodyArray['messageID'] = $this->messageID;
}
if ($this->BankMemberIdFilter !== null) {
$body['BankMemberIdFilter'] = $this->BankMemberIdFilter;
$bodyArray['BankMemberIdFilter'] = $this->BankMemberIdFilter;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -14,11 +14,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Reversal;
// <BELIEF_STATE "This POST request requires specific DTOs for its JSON body and its response, along with Saloon's body-handling traits.">
use Apoloz\AlfaBank\Sbp\Data\Reversal\GetQrcReversalDataRequestData;
use Apoloz\AlfaBank\Sbp\Data\Reversal\GetQrcReversalDataResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -26,7 +27,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for querying detailed SBP reversal information, which is crucial for auditing and reconciliation.">
class GetQrcReversalDataRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP data requests are often performed via POST requests with a JSON body.">
@@ -57,12 +58,14 @@ class GetQrcReversalDataRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Other fields from the DTO are conditionally added, ensuring the payload precisely matches the API specification.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'GetQRCreversalData'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -5,15 +5,16 @@ declare(strict_types=1);
namespace Apoloz\AlfaBank\Sbp\Requests\Reversal;
use Apoloz\AlfaBank\Sbp\Data\Reversal\ReversalHistoryResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
class GetQrcReversalHistoryRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
protected Method $method = Method::POST;
@@ -32,12 +33,14 @@ class GetQrcReversalHistoryRequest extends Request implements HasBody
return ReversalHistoryResponseData::from($response->json());
}
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'GetQRCreversalHistory',
'TermNo' => $this->TermNo,
'payrrn' => $this->payrrn,
];
return CmsSigner::canonicalize($bodyArray);
}
}

View File

@@ -14,11 +14,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Reversal;
// <BELIEF_STATE "This POST request requires specific DTOs for its JSON body and its response, along with Saloon's body-handling traits.">
use Apoloz\AlfaBank\Sbp\Data\Reversal\GetQrcReversalStatusRequestData;
use Apoloz\AlfaBank\Sbp\Data\Reversal\GetQrcReversalStatusResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -26,7 +27,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for querying the status of an SBP reversal, which is a critical operation in payment systems.">
class GetQrcReversalStatusRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP status checks are often performed via POST requests with a JSON body.">
@@ -57,12 +58,14 @@ class GetQrcReversalStatusRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Other fields from the DTO are conditionally added, ensuring the payload precisely matches the API specification.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'GetQRCreversalStatus'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -14,11 +14,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Reversal;
// <BELIEF_STATE "This POST request requires specific DTOs for its JSON body and its response, along with Saloon's body-handling traits.">
use Apoloz\AlfaBank\Sbp\Data\Reversal\QrcReversalRequestData;
use Apoloz\AlfaBank\Sbp\Data\Reversal\QrcReversalResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -26,7 +27,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for initiating an SBP reversal, which is a critical operation in payment systems.">
class QrcReversalRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Initiating a new transaction or action that changes the system state (like a reversal) is correctly represented by a POST request.">
@@ -57,12 +58,14 @@ class QrcReversalRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Other fields from the DTO are conditionally added, ensuring the payload precisely matches the API specification.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'QRCreversal'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -14,11 +14,12 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Status;
// <BELIEF_STATE "This POST request requires specific DTOs for its JSON body and its response, along with Saloon's body-handling traits.">
use Apoloz\AlfaBank\Sbp\Data\Status\GetQrcStatusRequestData;
use Apoloz\AlfaBank\Sbp\Data\Status\GetQrcStatusResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -26,7 +27,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for querying the status of an SBP QR Code, which is crucial for tracking payment flows.">
class GetQrcStatusRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP status checks are often performed via POST requests with a JSON body.">
@@ -57,12 +58,14 @@ class GetQrcStatusRequest extends Request implements HasBody
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. The `TermNo` is mandatory, and `qrcId`, `payrrn`, and `messageID` are optional filters to pinpoint the transaction.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'GetQRCstatus'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,20 +12,21 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Subscription;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\Subscription\GetQrSubStatusResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasStringBody;
// <BELIEF_STATE "The `Response` object is fully qualified in `createDtoFromResponse` as it is not explicitly imported with a `use` statement at the top. This is acceptable but less explicit.">
// use Saloon\Http\Response; // Explicit import would be cleaner
// </SECTION>
// <SECTION name="class_definition" intent="Define the request to get the status of a QR Code subscription.">
// <BELIEF_STATE "This class encapsulates the logic for querying the status of an SBP subscription, which is crucial for managing recurring payments.">
class GetQrSubStatusRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Even though it retrieves data, SBP status checks are often performed via POST requests with a JSON body.">
@@ -50,27 +51,27 @@ class GetQrSubStatusRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `GetQrSubStatusResponseData` DTO provides a structured object for the status of the subscription.">
public function createDtoFromResponse(\Saloon\Http\Response $response): \Apoloz\AlfaBank\Sbp\Data\Subscription\GetQrSubStatusResponseData
public function createDtoFromResponse(Response $response): GetQrSubStatusResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\Subscription\GetQrSubStatusResponseData::from($response->json());
return GetQrSubStatusResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Other fields are conditionally added, ensuring the payload precisely matches the API specification.">
protected function defaultBody(): array
protected function defaultBody(): string
{
$body = [
$bodyArray = [
'command' => 'GetQRCSubStatus',
'TermNo' => $this->TermNo,
'qrcId' => $this->qrcId,
];
if ($this->RQperiod !== null) {
$body['RQperiod'] = $this->RQperiod;
$bodyArray['RQperiod'] = $this->RQperiod;
}
return $body;
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -12,11 +12,13 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Subscription;
// <SECTION name="module_imports" intent="Import Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\Subscription\QrcSubPayPetitionResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -24,7 +26,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for initiating a payment through an SBP subscription, which is a key part of recurring payment flows.">
class QrcSubPayPetitionRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Initiating a payment action that changes the system state is correctly represented by a POST request.">
@@ -50,23 +52,25 @@ class QrcSubPayPetitionRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `QrcSubPayPetitionResponseData` DTO provides a structured object for the result of the payment petition.">
public function createDtoFromResponse(Response $response): \Apoloz\AlfaBank\Sbp\Data\Subscription\QrcSubPayPetitionResponseData
public function createDtoFromResponse(Response $response): QrcSubPayPetitionResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\Subscription\QrcSubPayPetitionResponseData::from($response->json());
return QrcSubPayPetitionResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. All constructor properties are directly mapped to the request body.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return [
$bodyArray = [
'command' => 'QRCSubPayPetition',
'TermNo' => $this->TermNo,
'subscriptionToken' => $this->subscriptionToken,
'SenderMemberId' => $this->SenderMemberId,
'qrcId' => $this->qrcId,
];
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -13,11 +13,13 @@ namespace Apoloz\AlfaBank\Sbp\Requests\Subscription;
// <SECTION name="module_imports" intent="Import DTO and Saloon components for a JSON body request.">
// <BELIEF_STATE "This POST request requires the `RegQrSubRequestData` DTO for its JSON body and utilizes `HasBody` and `HasJsonBody` for proper payload serialization. It currently returns a raw array response.">
use Apoloz\AlfaBank\Sbp\Data\Subscription\RegQrSubRequestData;
use Apoloz\AlfaBank\Sbp\Data\Subscription\RegQrSubResponseData;
use Apoloz\AlfaBank\Utils\CmsSigner;
use Saloon\Contracts\Body\HasBody;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Body\HasStringBody;
// </SECTION>
@@ -25,7 +27,7 @@ use Saloon\Traits\Body\HasJsonBody;
// <BELIEF_STATE "This class encapsulates the logic for initiating an SBP subscription, which is crucial for recurring payment models.">
class RegQrSubRequest extends Request implements HasBody
{
use HasJsonBody;
use HasStringBody;
// <SECTION name="http_method" intent="Declare the HTTP verb.">
// <BELIEF_STATE "Registering a new resource or initiating an action that changes the system state is correctly represented by a POST request.">
@@ -48,20 +50,22 @@ class RegQrSubRequest extends Request implements HasBody
// <SECTION name="response_caster" intent="Map the JSON response to a DTO.">
// <BELIEF_STATE "Casting the response to a `RegQrSubResponseData` DTO provides a structured object for the result of the subscription registration.">
public function createDtoFromResponse(Response $response): \Apoloz\AlfaBank\Sbp\Data\Subscription\RegQrSubResponseData
public function createDtoFromResponse(Response $response): RegQrSubResponseData
{
return \Apoloz\AlfaBank\Sbp\Data\Subscription\RegQrSubResponseData::from($response->json());
return RegQrSubResponseData::from($response->json());
}
// </SECTION>
// <SECTION name="body_builder" intent="Construct the JSON body for the request.">
// <BELIEF_STATE "The `command` field specifies the operation to the SBP API. Using the DTO's `toArray` method ensures the payload is correctly structured.">
protected function defaultBody(): array
protected function defaultBody(): string
{
return array_merge(
$bodyArray = array_merge(
['command' => 'RegQRcSub'],
$this->data->toArray()
);
return CmsSigner::canonicalize($bodyArray);
}
// </SECTION>
}

View File

@@ -55,15 +55,17 @@ class OpenSslCmsSigner implements SignerInterface
@unlink($inFile);
@unlink($outFile);
// Извлекаем Base64 тело подписи согласно примеру из документации Альфы
$parts = explode("\n\n", $signedData, 2);
if (isset($parts[1])) {
$signature = trim($parts[1]);
// Удаляем возможные PEM-завершители и переносы строк
$signature = str_replace(["-----BEGIN PKCS7-----", "-----END PKCS7-----", "\n", "\r", " "], '', $signature);
return $signature;
// Надежно извлекаем только Base64 блок подписи из S/MIME или PEM структуры
$parts = explode("\n\n", $signedData);
foreach ($parts as $part) {
// Очищаем часть от пробелов и переносов
$cleaned = str_replace(["\n", "\r", ' '], '', $part);
// Ищем блок, который выглядит как длинный Base64 (больше 128 символов) и не содержит S/MIME заголовков
if (preg_match('/^[a-zA-Z0-9\/+]+=*$/', $cleaned) && strlen($cleaned) > 128) {
return $cleaned;
}
}
throw new SignerException("Failed to extract signature body from CMS container.");
throw new SignerException("Failed to extract signature body from CMS container. Output: " . substr($signedData, 0, 100));
}
}