diff --git a/.github/workflows/laravel.yml b/.github/workflows/laravel.yml index 7b9a658..163e3b8 100644 --- a/.github/workflows/laravel.yml +++ b/.github/workflows/laravel.yml @@ -4,7 +4,7 @@ on: push: branches: [ main ] pull_request: - branches: [ main ] + branches: [ main, develop ] jobs: laravel-tests: diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..c850289 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @adeildo-jr diff --git a/src/Celcoin.php b/src/Celcoin.php index c64f429..0b75798 100644 --- a/src/Celcoin.php +++ b/src/Celcoin.php @@ -13,6 +13,7 @@ use WeDevBr\Celcoin\Clients\CelcoinDDAUser; use WeDevBr\Celcoin\Clients\CelcoinDDAWebhooks; use WeDevBr\Celcoin\Clients\CelcoinElectronicTransactions; +use WeDevBr\Celcoin\Clients\CelcoinKyc; use WeDevBr\Celcoin\Clients\CelcoinPIXCOB; use WeDevBr\Celcoin\Clients\CelcoinPIXCOBV; use WeDevBr\Celcoin\Clients\CelcoinPIXDICT; @@ -29,6 +30,7 @@ /** * Class Celcoin + * * @package WeDevBr\Celcoin */ class Celcoin @@ -218,7 +220,7 @@ public static function clientPIXDynamic(?string $mtlsPassphrase = null): Celcoin * @param string|null $mtlsPassphrase * @return CelcoinPIXPayment */ - public static function clientPIXPayment(?string $mtlsPassphrase): CelcoinPIXPayment + public static function clientPIXPayment(?string $mtlsPassphrase = null): CelcoinPIXPayment { return new CelcoinPIXPayment($mtlsPassphrase); } @@ -227,7 +229,7 @@ public static function clientPIXPayment(?string $mtlsPassphrase): CelcoinPIXPaym * @param string|null $mtlsPassphrase * @return CelcoinPIXReceivement */ - public static function clientPIXReceivement(?string $mtlsPassphrase): CelcoinPIXReceivement + public static function clientPIXReceivement(?string $mtlsPassphrase = null): CelcoinPIXReceivement { return new CelcoinPIXReceivement($mtlsPassphrase); } @@ -236,7 +238,7 @@ public static function clientPIXReceivement(?string $mtlsPassphrase): CelcoinPIX * @param string|null $mtlsPassphrase * @return CelcoinPIXReverse */ - public static function clientPIXReverse(?string $mtlsPassphrase): CelcoinPIXReverse + public static function clientPIXReverse(?string $mtlsPassphrase = null): CelcoinPIXReverse { return new CelcoinPIXReverse($mtlsPassphrase); } @@ -245,8 +247,17 @@ public static function clientPIXReverse(?string $mtlsPassphrase): CelcoinPIXReve * @param string|null $mtlsPassphrase * @return CelcoinPixWebhooks */ - public static function clientPixWebhooks(?string $mtlsPassphrase): CelcoinPixWebhooks + public static function clientPixWebhooks(?string $mtlsPassphrase = null): CelcoinPixWebhooks { return new CelcoinPixWebhooks($mtlsPassphrase); } + + /** + * @param string|null $mtlsPassphrase + * @return CelcoinKyc + */ + public static function clientKyc(?string $mtlsPassphrase = null): CelcoinKyc + { + return new CelcoinKyc($mtlsPassphrase); + } } diff --git a/src/Clients/CelcoinKyc.php b/src/Clients/CelcoinKyc.php new file mode 100644 index 0000000..9daa5c3 --- /dev/null +++ b/src/Clients/CelcoinKyc.php @@ -0,0 +1,27 @@ +toArray(), CreateKycRule::rules()); + + return $this->post( + self::CREATE_KYC_ENDPOINT, + $body + ); + } +} diff --git a/src/Common/CelcoinBaseApi.php b/src/Common/CelcoinBaseApi.php index 44364b5..da1a62e 100644 --- a/src/Common/CelcoinBaseApi.php +++ b/src/Common/CelcoinBaseApi.php @@ -4,6 +4,7 @@ use Illuminate\Http\Client\PendingRequest; use Illuminate\Http\Client\RequestException; +use Illuminate\Http\File; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; use WeDevBr\Celcoin\Auth\Auth; @@ -85,19 +86,25 @@ protected function get(string $endpoint, array|string|null $query = null, $respo /** * @throws RequestException */ - protected function post(string $endpoint, array $body = null) + protected function post(string $endpoint, array $body = []) { $token = $this->getToken() ?? Auth::login()->getToken(); $request = Http::withToken($token) ->withHeaders([ 'accept' => 'application/json', - 'content-type' => 'application/json', + 'content-type' => 'application/json' ]); if ($this->mtlsCert && $this->mtlsKey && $this->mtlsPassphrase) { $request = $this->setRequestMtls($request); } + foreach ($body as $field => $document) { + if ($document instanceof File) { + $request->attach($field, $document->getContent(), $document->getFileName()); + } + } + return $request->post($this->getFinalUrl($endpoint), $body) ->throw() ->json(); @@ -109,7 +116,8 @@ protected function post(string $endpoint, array $body = null) protected function put( string $endpoint, ?array $body = null, - ): mixed { + ): mixed + { $token = $this->getToken() ?? Auth::login()->getToken(); $request = Http::withToken($token) ->withHeaders([ @@ -133,7 +141,8 @@ protected function patch( string $endpoint, ?array $body = null, bool $asJson = false - ): mixed { + ): mixed + { $body_format = $asJson ? 'json' : 'form_params'; $token = $this->getToken() ?? Auth::login()->getToken(); $request = Http::withToken($token) diff --git a/src/Enums/KycDocumentEnum.php b/src/Enums/KycDocumentEnum.php new file mode 100644 index 0000000..b10f585 --- /dev/null +++ b/src/Enums/KycDocumentEnum.php @@ -0,0 +1,15 @@ + ['boolean'], 'duedate' => ['required', 'date'], 'amount' => ['required', 'decimal:0,2'], - 'key' => ['sometimes', 'nullable'], + 'key' => ['required'], 'debtor' => ['required', 'array'], 'debtor.name' => ['required'], 'debtor.document' => ['required', 'numeric'], diff --git a/src/Rules/BAAS/RegisterPixKey.php b/src/Rules/BAAS/RegisterPixKey.php index 0b8c9da..8402071 100644 --- a/src/Rules/BAAS/RegisterPixKey.php +++ b/src/Rules/BAAS/RegisterPixKey.php @@ -12,7 +12,7 @@ public static function rules() { return [ "account" => ['required', 'string'], - "keyType" => ['required', Rule::in([PixKeyTypeEnum::EVP->value])], + "keyType" => ['required', Rule::enum(PixKeyTypeEnum::class)], "key" => ['required_unless:keyType,EVP', 'string'], ]; } diff --git a/src/Rules/KYC/CreateKycRule.php b/src/Rules/KYC/CreateKycRule.php new file mode 100644 index 0000000..e7214d2 --- /dev/null +++ b/src/Rules/KYC/CreateKycRule.php @@ -0,0 +1,20 @@ + ['required', 'digits:11,14'], + 'filetype' => ['required', Rule::enum(KycDocumentEnum::class)], + 'front' => ['required', 'file'], + 'verse' => ['sometimes', 'file'], + 'cnpj' => ['sometimes', 'same:documentnumber', 'digits:11,14'], + ]; + } +} diff --git a/src/Types/BillPayments/BillData.php b/src/Types/BillPayments/BillData.php index 454e523..0cc7de7 100644 --- a/src/Types/BillPayments/BillData.php +++ b/src/Types/BillPayments/BillData.php @@ -6,10 +6,10 @@ class BillData extends Data { - public int $value; - public int $originalValue; - public int $valueWithDiscount; - public int $valueWithAdditional; + public float $value; + public float $originalValue; + public float $valueWithDiscount; + public float $valueWithAdditional; public function __construct(array $data = []) { diff --git a/src/Types/KYC/CreateKyc.php b/src/Types/KYC/CreateKyc.php new file mode 100644 index 0000000..4da454d --- /dev/null +++ b/src/Types/KYC/CreateKyc.php @@ -0,0 +1,42 @@ +front->file; + } + + if ($array['verse']) { + $array['verse'] = $this->verse->file; + } + + return $array; + } +} diff --git a/src/Types/KYC/KycDocument.php b/src/Types/KYC/KycDocument.php new file mode 100644 index 0000000..7d5062b --- /dev/null +++ b/src/Types/KYC/KycDocument.php @@ -0,0 +1,31 @@ +getContent(); + $data['fileName'] = $file->getFilename(); + $data['file'] = $file; + parent::__construct($data); + } + + public function getContents(): string + { + return $this->contents; + } + + public function getFileName(): string + { + return $this->fileName; + } +} diff --git a/tests/Feature/CelcoinClientInstancesTest.php b/tests/Feature/CelcoinClientInstancesTest.php index e5b4502..8cea02b 100644 --- a/tests/Feature/CelcoinClientInstancesTest.php +++ b/tests/Feature/CelcoinClientInstancesTest.php @@ -14,6 +14,7 @@ use WeDevBr\Celcoin\Clients\CelcoinDDAUser; use WeDevBr\Celcoin\Clients\CelcoinDDAWebhooks; use WeDevBr\Celcoin\Clients\CelcoinElectronicTransactions; +use WeDevBr\Celcoin\Clients\CelcoinKyc; use WeDevBr\Celcoin\Clients\CelcoinPIXCOB; use WeDevBr\Celcoin\Clients\CelcoinPIXCOBV; use WeDevBr\Celcoin\Clients\CelcoinPIXDICT; @@ -147,4 +148,10 @@ public function testSuccessCreateInstancePIXDynamic() $instance = Celcoin::clientPIXDynamic(); $this->assertInstanceOf(CelcoinPIXDynamic::class, $instance); } + + public function testSuccessCreateInstanceKyc() + { + $instance = Celcoin::clientKyc(); + $this->assertInstanceOf(CelcoinKyc::class, $instance); + } } diff --git a/tests/GlobalStubs.php b/tests/GlobalStubs.php index ccc343d..d16390b 100644 --- a/tests/GlobalStubs.php +++ b/tests/GlobalStubs.php @@ -22,4 +22,4 @@ final static public function loginResponse(): PromiseInterface Response::HTTP_OK, ); } -} \ No newline at end of file +} diff --git a/tests/Integration/KYC/CelcoinSendKycTest.php b/tests/Integration/KYC/CelcoinSendKycTest.php new file mode 100644 index 0000000..4ae0c6f --- /dev/null +++ b/tests/Integration/KYC/CelcoinSendKycTest.php @@ -0,0 +1,137 @@ +front = UploadedFile::fake()->image('front.jpg'); + $this->verse = UploadedFile::fake()->image('verse.jpg'); + } + + public function testSendKycSuccessful() + { + Http::fake([ + config('celcoin.login_url') => GlobalStubs::loginResponse(), + sprintf( + '%s%s', + config('celcoin.api_url'), + CelcoinKyc::CREATE_KYC_ENDPOINT + ) => static::successResponse(), + ]); + $kyc = new CelcoinKyc(); + $body = static::getKycBody(); + $response = $kyc->createKyc(new CreateKyc($body)); + $this->assertEquals(200, $response['status']); + } + + public function testSendKycValidationRules() + { + Http::fake([ + config('celcoin.login_url') => GlobalStubs::loginResponse(), + ]); + + $kyc = new CelcoinKyc(); + $body = static::getKycBody(); + unset($body['front']); + $this->expectException(ValidationException::class); + $kyc->createKyc(new CreateKyc($body)); + } + + public function testSendKycFailedRequest() + { + Http::fake([ + config('celcoin.login_url') => GlobalStubs::loginResponse(), + sprintf( + '%s%s', + config('celcoin.api_url'), + CelcoinKyc::CREATE_KYC_ENDPOINT + ) => static::internalErrorResponse(), + ]); + $body = static::getKycBody(); + $this->expectException(RequestException::class); + $this->expectExceptionCode(500); + try { + $kyc = new CelcoinKyc(); + $kyc->createKyc(new CreateKyc($body)); + } catch (RequestException $e) { + $response = $e->response->json(); + $this->assertEquals(0, $response['errorCode']); + throw $e; + } + } + + public function getKycBody( + string $nifNumber = null, + KycDocumentEnum $fileType = null, + string $fileFront = null, + string $cnpj = null, + bool $addVerse = true + ): array + { + $file = $this->front; + + $body = [ + 'documentnumber' => $nifNumber ?? "11122233344", + 'filetype' => $fileType ?? KycDocumentEnum::CONTRATO_SOCIAL, + 'front' => $fileFront ?? $this->getFile($file->path()), + ]; + + if (strlen($body['documentnumber']) === 14 && empty($cnpj)) { + $body['cnpj'] = $body['documentnumber']; + } + + if ($addVerse) { + $verse = $this->verse; + $body['verse'] = $this->getFile($verse->path()); + } + + return $body; + } + + public static function successResponse(): PromiseInterface + { + return Http::response([ + 'status' => 200, + 'message' => "Arquivo enviado com sucesso", + ]); + } + + public static function notFoundResponse(): PromiseInterface + { + return Http::response([ + 'errorCode' => 404, + 'errorMessage' => 'BackgroundCheck nao encontrado!', + ], 404); + } + + public static function internalErrorResponse(): PromiseInterface + { + return Http::response([ + 'errorCode' => 0, + 'errorMessage' => 'string', + ], 500); + } + + public function getFile(string $path = null): KycDocument + { + return new KycDocument(new File($path)); + } +}