Skip to content

Commit

Permalink
FIT: Allowing more pix key types
Browse files Browse the repository at this point in the history
  • Loading branch information
kayon-ariel committed Oct 9, 2024
1 parent 946c97a commit 15bf164
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 12 deletions.
50 changes: 46 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ A PHP library for generating QR codes for PIX payments, including optional trans

- [Installation](#installation)
- [Usage](#usage)
- [Methods](#methods)
- [StaticPix::generatePix](#staticpixgeneratepixkey-idtx--amount-000-description--)
- [StaticPix::formatField](#staticpixformatfieldid-value)
- [StaticPix::calculateCRC16](#staticpixcalculatecrc16data)
- [Accepted Key Types](#accepted-key-types)
- [Example Usage](#example-usage)

## Installation

Expand Down Expand Up @@ -51,3 +49,47 @@ $pixCode = StaticPix::generatePix('your-pix-key', 'Transaction-ID', 100.00, 'Pay
echo $pixCode;
```

## Accepted Key Types

In the `PixPhp` library, the following types of keys are accepted for generating PIX codes:

1. **CPF (Cadastro de Pessoas Físicas)**
- **Format:** `123.456.789-09`
- **Description:** A Brazilian individual taxpayer identification number. The library accepts CPF numbers with or without formatting.

2. **CNPJ (Cadastro Nacional da Pessoa Jurídica)**
- **Format:** `12.345.678/0001-95`
- **Description:** A Brazilian business taxpayer identification number. The library accepts CNPJ numbers with or without formatting.

3. **Email**
- **Format:** `example@test.com`
- **Description:** A valid email address. The library accepts well-formed email addresses as PIX keys.

4. **Phone**
- **Format:** `+55 11 91234-5678`
- **Description:** A Brazilian phone number including the country code. The library accepts phone numbers with various formatting styles, including spaces and dashes, while retaining the `+55` prefix.

5. **Random Key**
- **Format:** `617ef6be-e18e-427f-919b-6e43bae33400`
- **Description:** The Pix random key is a 32-character alphanumeric code, randomly generated by the Central Bank to be linked to a single account.

## Example Usage

You can pass any of the accepted key types to the `generatePix` method:

```php
// Using CPF
$pixCodeCpf = StaticPix::generatePix("123.456.789-09", "ID123", 100.00);

// Using CNPJ
$pixCodeCnpj = StaticPix::generatePix("12.345.678/0001-95", "ID456", 250.50);

// Using Email
$pixCodeEmail = StaticPix::generatePix("example@test.com", "ID789", 50.00);

// Using Phone
$pixCodePhone = StaticPix::generatePix("+55 11 91234-5678", "ID101", 75.00);

// Using Random Key
$pixCodeRandom = StaticPix::generatePix("617ef6be-e18e-427f-919b-6e43bae33400", "ID102", 30.00);
```
61 changes: 61 additions & 0 deletions src/PixKey.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace PixPhp;

class PixKey
{
public static function validateKey($key)
{
// Trim spaces and special characters
$key = trim($key);

// Check if the key is a CPF
if (preg_match('/^\d{3}\.\d{3}\.\d{3}-\d{2}$/', $key)) {
return 'CPF';
}

// Check if the key is a CNPJ
if (preg_match('/^\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}$/', $key)) {
return 'CNPJ';
}

// Check if the key is an email
if (filter_var($key, FILTER_VALIDATE_EMAIL)) {
return 'EMAIL';
}

// Check if the key is a phone number
if (preg_match('/^\+55 \d{2} \d{5}-\d{4}$/', $key)) {
return 'PHONE';
}

// Check if the key is a random key
if (preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $key)) {
return 'RANDOM';
}

// If the key does not match any known format
throw new \InvalidArgumentException('Invalid PIX key.');
}

public static function formatKey($key)
{
$type = self::validateKey($key);

// Format the key according to its type
switch ($type) {
case 'CPF':
return preg_replace('/[^\d]/', '', $key);
case 'CNPJ':
return preg_replace('/[^\d]/', '', $key);
case 'EMAIL':
return strtolower(trim($key));
case 'PHONE':
return preg_replace('/[^+\d]/', '', $key);
case 'RANDOM':
return trim($key);
default:
throw new \InvalidArgumentException('Invalid PIX key.');
}
}
}
2 changes: 1 addition & 1 deletion src/StaticPix.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static function calculateCRC16($data)
public static function generatePix($key, $idTx = '', $amount = 0.00, $description = '')
{
$result = "000201";
$result .= self::formatField("26", "0014br.gov.bcb.pix" . self::formatField("01", $key));
$result .= self::formatField("26", "0014br.gov.bcb.pix" . self::formatField("01", PixKey::formatKey($key)));
$result .= "52040000"; // Fixed code
$result .= "5303986"; // Currency (Real)
if ($amount > 0) {
Expand Down
42 changes: 42 additions & 0 deletions tests/PixKeyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

use PHPUnit\Framework\TestCase;
use PixPhp\PixKey;

class PixKeyTest extends TestCase
{
public function testValidCpf()
{
$cpf = '123.456.789-09';
$this->assertEquals('CPF', PixKey::validateKey($cpf));
$this->assertEquals('12345678909', PixKey::formatKey($cpf));
}

public function testValidCnpj()
{
$cnpj = '12.345.678/0001-95';
$this->assertEquals('CNPJ', PixKey::validateKey($cnpj));
$this->assertEquals('12345678000195', PixKey::formatKey($cnpj));
}

public function testValidEmail()
{
$email = 'example@test.com';
$this->assertEquals('EMAIL', PixKey::validateKey($email));
$this->assertEquals('example@test.com', PixKey::formatKey($email));
}

public function testValidPhone()
{
$phone = '+55 11 91234-5678';
$this->assertEquals('PHONE', PixKey::validateKey($phone));
$this->assertEquals('+5511912345678', PixKey::formatKey($phone));
}

public function testInvalidKey()
{
$this->expectException(InvalidArgumentException::class);
$invalidKey = 'invalid_key';
PixKey::validateKey($invalidKey);
}
}
66 changes: 59 additions & 7 deletions tests/StaticPixTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ public function testFormatField()

public function testCalculateCRC16()
{
$data = "00020126330014br.gov.bcb.pix0111chave-teste5204000053039865406100.005802BR5901N6001C62090505ID1236304";
$data = "00020126580014br.gov.bcb.pix0136617ef6be-e18e-427f-919b-6e43bae3340052040000530398654041.005802BR5901N6001C6205050116304";
$crc = StaticPix::calculateCRC16($data);
$this->assertEquals("9F03", $crc);
$this->assertEquals("2BD6", $crc);
}

public function testGeneratePixWithoutDescription()
{
$pixCode = StaticPix::generatePix("chave-teste", "ID123", 100.00);
$this->assertStringContainsString("0014br.gov.bcb.pix0111chave-teste", $pixCode);
$pixCode = StaticPix::generatePix("617ef6be-e18e-427f-919b-6e43bae33400", "ID123", 100.00);
$this->assertStringContainsString("0014br.gov.bcb.pix0136617ef6be-e18e-427f-919b-6e43bae33400", $pixCode);
$this->assertStringContainsString("52040000", $pixCode); // Fixed code
$this->assertStringContainsString("5303986", $pixCode); // Currency (Real)
$this->assertStringContainsString("5406100.00", $pixCode); // Amount
Expand All @@ -40,8 +40,8 @@ public function testGeneratePixWithoutDescription()

public function testGeneratePixWithDescription()
{
$pixCode = StaticPix::generatePix("chave-teste", "ID123", 100.00, "Pagamento de teste");
$this->assertStringContainsString("0014br.gov.bcb.pix0111chave-teste", $pixCode);
$pixCode = StaticPix::generatePix("617ef6be-e18e-427f-919b-6e43bae33400", "ID123", 100.00, "Pagamento de teste");
$this->assertStringContainsString("0014br.gov.bcb.pix0136617ef6be-e18e-427f-919b-6e43bae33400", $pixCode);
$this->assertStringContainsString("52040000", $pixCode); // Fixed code
$this->assertStringContainsString("5303986", $pixCode); // Currency (Real)
$this->assertStringContainsString("5406100.00", $pixCode); // Amount
Expand All @@ -58,7 +58,59 @@ public function testGeneratePixWithDescription()

public function testGeneratePixWithZeroAmount()
{
$pixCode = StaticPix::generatePix("chave-teste", "ID123", 0.00);
$pixCode = StaticPix::generatePix("617ef6be-e18e-427f-919b-6e43bae33400", "ID123", 0.00);
$this->assertStringNotContainsString("54", $pixCode); // Amount should not be included for 0.00
}

public function testGeneratePixWithCpf()
{
$pixKey = '123.456.789-09'; // Example CPF
$pixCode = StaticPix::generatePix($pixKey, "ID123", 100.00);

$this->assertStringContainsString("0014br.gov.bcb.pix011112345678909", $pixCode); // Formatted CPF
$this->assertStringContainsString("5406100.00", $pixCode); // Amount

// Calculates CRC16 for code without part 6304
$pixCodeWithoutCRC = substr($pixCode, 0, -4); // Remove the CRC part and its size
$this->assertStringEndsWith("6304" . StaticPix::calculateCRC16($pixCodeWithoutCRC), $pixCode); // CRC16
}

public function testGeneratePixWithCnpj()
{
$pixKey = '12.345.678/0001-95'; // Example CNPJ
$pixCode = StaticPix::generatePix($pixKey, "ID456", 250.50);

$this->assertStringContainsString("0014br.gov.bcb.pix011412345678000195", $pixCode); // Formatted CNPJ
$this->assertStringContainsString("5406250.50", $pixCode); // Amount

// Calculates CRC16 for code without part 6304
$pixCodeWithoutCRC = substr($pixCode, 0, -4); // Remove the CRC part and its size
$this->assertStringEndsWith("6304" . StaticPix::calculateCRC16($pixCodeWithoutCRC), $pixCode); // CRC16
}

public function testGeneratePixWithEmail()
{
$pixKey = 'example@test.com'; // Example Email
$pixCode = StaticPix::generatePix($pixKey, "ID789", 250.50);

$this->assertStringContainsString("0014br.gov.bcb.pix0116example@test.com", $pixCode); // Formatted Email
$this->assertStringContainsString("5406250.50", $pixCode); // Amount

// Calculates CRC16 for code without part 6304
$pixCodeWithoutCRC = substr($pixCode, 0, -4); // Remove the CRC part and its size
$this->assertStringEndsWith("6304" . StaticPix::calculateCRC16($pixCodeWithoutCRC), $pixCode); // CRC16
}

public function testGeneratePixWithPhone()
{
$pixKey = '+55 11 91234-5678'; // Example Phone
$pixCode = StaticPix::generatePix($pixKey, "ID789", 250.50);

$this->assertStringContainsString("0014br.gov.bcb.pix0114+5511912345678", $pixCode); // Formatted Email
$this->assertStringContainsString("5406250.50", $pixCode); // Amount

// Calculates CRC16 for code without part 6304
$pixCodeWithoutCRC = substr($pixCode, 0, -4); // Remove the CRC part and its size
$this->assertStringEndsWith("6304" . StaticPix::calculateCRC16($pixCodeWithoutCRC), $pixCode); // CRC16
}
}

0 comments on commit 15bf164

Please sign in to comment.