From 6cee9cdf80a583abe789c10edc2b6674e3ca152c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Lucas?= Date: Sun, 9 Mar 2025 20:13:18 -0300 Subject: [PATCH 1/2] PHPAY-64: wip(assas-subscription): creating subscription with asaas gateway --- .husky/pre-commit | 2 +- .vscode/settings.json | 122 +++++++++--------- examples/asaas/subscriptions.php | 60 +++++++++ phpstan.neon | 3 +- src/Contracts/GatewayInterface.php | 7 + src/Gateways/Asaas/AsaasGateway.php | 6 + .../Asaas/Interface/AsaasGatewayInterface.php | 8 ++ .../Interface/SubscriptionInterface.php | 38 ++++++ .../StoreSubscriptionAsaasRequest.php | 62 +++++++++ .../Resources/Subscription/Subscription.php | 108 ++++++++++++++++ src/Gateways/Efi/EfiGateway.php | 5 + src/PHPay.php | 25 ++-- tests/PHPayTest.php | 2 - 13 files changed, 372 insertions(+), 76 deletions(-) create mode 100644 examples/asaas/subscriptions.php create mode 100644 src/Gateways/Asaas/Resources/Subscription/Interface/SubscriptionInterface.php create mode 100644 src/Gateways/Asaas/Resources/Subscription/Requests/StoreSubscriptionAsaasRequest.php create mode 100644 src/Gateways/Asaas/Resources/Subscription/Subscription.php diff --git a/.husky/pre-commit b/.husky/pre-commit index 41a28b8..b1eb4f1 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -8,7 +8,7 @@ fi php examples/helper/termwind-cli.php success "Pint Ok!" -phpstan=$(vendor/bin/phpstan analyse --level=9 2>&1) +phpstan=$(vendor/bin/phpstan analyse --level=7 2>&1) if [ $? -ne 0 ]; then php examples/helper/termwind-cli.php error "PHPStan tests failed." "$phpstan" diff --git a/.vscode/settings.json b/.vscode/settings.json index 0add341..fb72ae9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,62 +1,62 @@ { - "cSpell.enabled": false, - "editor.lineHeight": 1.9, - "editor.fontFamily": "JetBrains Mono", - // "editor.fontFamily": "Dank Mono", - // "editor.codeLensFontFamily": "Operator Mono", - "editor.fontLigatures": true, - "editor.formatOnSave": true, - "php-cs-fixer.onsave": true, - "php-cs-fixer.executablePath": "${extensionPath}/php-cs-fixer.phar", - "cSpell.userWords": [ - "Assertable", - "autoload", - "Bootstrapper", - "bootstrappers", - "Codeigniter", - "Dispatchable", - "flashdata", - "intelephense", - "junstyle", - "Laravel", - "Livewire", - "onsave", - "phar", - "phpstan", - "Queueable", - "Stancl", - "timesheet", - "userdata" - ], - "php-cs-fixer.lastDownload": 1693233566761, - "terminal.integrated.cursorStyle": "underline", - "terminal.integrated.defaultProfile.windows": "Git Bash", - "terminal.integrated.fontFamily": "Hack Nerd Font Mono", - "terminal.integrated.lineHeight": 1.2, - "editor.accessibilitySupport": "off", - "terminal.integrated.copyOnSelection": true, - "terminal.integrated.sendKeybindingsToShell": true, - "redhat.telemetry.enabled": true, - "editor.minimap.enabled": false, - "editor.tabSize": 4, - "editor.insertSpaces": true, - "editor.detectIndentation": false, - "github.copilot.enable": { - "*": true, - "plaintext": true, - "markdown": false, - "scminput": false - }, - "editor.inlineSuggest.enabled": true, - "explorer.confirmDragAndDrop": false, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "files.associations": { - "*.js": "javascriptreact" - }, - "window.zoomLevel": 1, - "editor.fontVariations": false, - "phpunit.phpunit": "vendor/bin/pest", - "jira-plugin.workingProject": "", -} \ No newline at end of file + "cSpell.enabled": false, + "editor.lineHeight": 2.4, + // "editor.fontFamily": "JetBrains Mono", + // "editor.fontFamily": "Dank Mono", + // "editor.codeLensFontFamily": "Operator Mono", + "editor.fontLigatures": true, + "editor.formatOnSave": true, + "php-cs-fixer.onsave": true, + "php-cs-fixer.executablePath": "${extensionPath}/php-cs-fixer.phar", + "cSpell.userWords": [ + "Assertable", + "autoload", + "Bootstrapper", + "bootstrappers", + "Codeigniter", + "Dispatchable", + "flashdata", + "intelephense", + "junstyle", + "Laravel", + "Livewire", + "onsave", + "phar", + "phpstan", + "Queueable", + "Stancl", + "timesheet", + "userdata" + ], + "php-cs-fixer.lastDownload": 1693233566761, + "terminal.integrated.cursorStyle": "underline", + "terminal.integrated.defaultProfile.windows": "Git Bash", + "terminal.integrated.fontFamily": "Hack Nerd Font Mono", + "terminal.integrated.lineHeight": 1.2, + "editor.accessibilitySupport": "off", + "terminal.integrated.copyOnSelection": true, + "terminal.integrated.sendKeybindingsToShell": true, + "redhat.telemetry.enabled": true, + "editor.minimap.enabled": false, + "editor.tabSize": 4, + "editor.insertSpaces": true, + "editor.detectIndentation": false, + "github.copilot.enable": { + "*": true, + "plaintext": true, + "markdown": false, + "scminput": false + }, + "editor.inlineSuggest.enabled": true, + "explorer.confirmDragAndDrop": false, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "files.associations": { + "*.js": "javascriptreact" + }, + "window.zoomLevel": 1, + "editor.fontVariations": false, + "phpunit.phpunit": "vendor/bin/pest", + "jira-plugin.workingProject": "" +} diff --git a/examples/asaas/subscriptions.php b/examples/asaas/subscriptions.php new file mode 100644 index 0000000..6abbf39 --- /dev/null +++ b/examples/asaas/subscriptions.php @@ -0,0 +1,60 @@ + NAME, + 'cpfCnpj' => CPF_CNPJ, +]; + +$subscriptionId = 'sub_e3knxyfo6ffgb6kg'; + +/** + * @var Subscription $phpay + */ +$phpay = PHPay::gateway(new AsaasGateway(TOKEN_ASAAS_SANDBOX))->subscription(); + +/* subscription store */ +$phpay->setCustomer($customer) + ->create([ + 'billingType' => 'BOLETO', + 'value' => 100, + 'nextDueDate' => '2025-04-09', + 'discount' => [ + 'value' => 10, + 'dueDateLimitDays' => 5, + 'type' => 'FIXED', /* PERCENTAGE */ + ], + 'interest' => [ + 'value' => 2, + ], + 'fine' => [ + 'value' => 1, + 'type' => 'FIXED', /* PERCENTAGE */ + ], + 'cycle' => 'MONTHLY', + 'description' => 'Teste de assinatura', + 'maxPayments' => 12, + 'externalReference' => '123456', + // 'split' => [ + // [ + // 'walletId' => 'rec_123456', + // 'fixedValue' => 50, + // 'percentageValue' => 50, + // 'externalReference' => '123456', + // 'description' => 'Teste de divisão', + // ], + // ], + // 'callback' => [ + // 'successUrl' => 'https://example.com/success', + // 'autoRedirect' => true, + // ] + ]); + +print_r($subscriptionCreated); diff --git a/phpstan.neon b/phpstan.neon index 5db244d..3c1f4dd 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,3 @@ parameters: paths: - - src - - tests \ No newline at end of file + - src \ No newline at end of file diff --git a/src/Contracts/GatewayInterface.php b/src/Contracts/GatewayInterface.php index 425c56d..ea4b424 100644 --- a/src/Contracts/GatewayInterface.php +++ b/src/Contracts/GatewayInterface.php @@ -34,4 +34,11 @@ public function webhook(array $webhook = []): object; * @return object */ public function pix(array $pix = []): object; + + /** + * get resource subscription from gateway. + * + * @return object + */ + public function subscription(): object; } diff --git a/src/Gateways/Asaas/AsaasGateway.php b/src/Gateways/Asaas/AsaasGateway.php index cd17db5..e22367d 100644 --- a/src/Gateways/Asaas/AsaasGateway.php +++ b/src/Gateways/Asaas/AsaasGateway.php @@ -7,6 +7,7 @@ use PHPay\Asaas\Resources\Charge\Charge; use PHPay\Asaas\Resources\Customer\Customer; use PHPay\Asaas\Resources\Pix\Pix; +use PHPay\Asaas\Resources\Subscription\Subscription; use PHPay\Asaas\Resources\Webhook\Webhook; class AsaasGateway implements AsaasGatewayInterface @@ -79,4 +80,9 @@ public function pix(array $pix = []): Pix { return new Pix($this->token, $this->sandbox); } + + public function subscription(): Subscription + { + return new Subscription($this->token, $this->sandbox); + } } diff --git a/src/Gateways/Asaas/Interface/AsaasGatewayInterface.php b/src/Gateways/Asaas/Interface/AsaasGatewayInterface.php index 626c3e2..f7dbc1a 100644 --- a/src/Gateways/Asaas/Interface/AsaasGatewayInterface.php +++ b/src/Gateways/Asaas/Interface/AsaasGatewayInterface.php @@ -5,6 +5,7 @@ use PHPay\Asaas\Resources\Charge\Charge; use PHPay\Asaas\Resources\Customer\Customer; use PHPay\Asaas\Resources\Pix\Pix; +use PHPay\Asaas\Resources\Subscription\Subscription; use PHPay\Asaas\Resources\Webhook\Webhook; use PHPay\Contracts\GatewayInterface; @@ -25,6 +26,13 @@ public function customer(array $customer = []): Customer; */ public function charge(): Charge; + /** + * get resource subscription from gateway. + * + * @return Subscription + */ + public function subscription(): Subscription; + /** * get resource webhook from gateway. * diff --git a/src/Gateways/Asaas/Resources/Subscription/Interface/SubscriptionInterface.php b/src/Gateways/Asaas/Resources/Subscription/Interface/SubscriptionInterface.php new file mode 100644 index 0000000..32d10f7 --- /dev/null +++ b/src/Gateways/Asaas/Resources/Subscription/Interface/SubscriptionInterface.php @@ -0,0 +1,38 @@ + $customer + * @return Subscription + */ + public function setCustomer(array $customer): Subscription; + + /** + * create subscription + * + * @param array $subscription + * @return array + */ + public function create(array $subscription): array; + + // public function findAll(); + // public function find(string $subscriptionId); + // public function update(string $subscriptionId, array $subscription); + // public function destroy(string $subscriptionId); + // public function findCharges(string $subscriptionId); + // public function generateCarnet(string $subscriptionId); + // public function nfeSettings(string $subscriptionId, array $nfeSettings); + // public function findNfeSettings(string $subscriptionId); + // public function updateNfeSettings(string $subscriptionId, array $nfeSettings); + // public function destroyNfeSettings(string $subscriptionId); + // public function findNfes(string $subscriptionId); +} diff --git a/src/Gateways/Asaas/Resources/Subscription/Requests/StoreSubscriptionAsaasRequest.php b/src/Gateways/Asaas/Resources/Subscription/Requests/StoreSubscriptionAsaasRequest.php new file mode 100644 index 0000000..34a503e --- /dev/null +++ b/src/Gateways/Asaas/Resources/Subscription/Requests/StoreSubscriptionAsaasRequest.php @@ -0,0 +1,62 @@ + $charge + * @return void + */ + public static function validate(array $charge): void + { + if (!isset($charge['customer']) && !is_string($charge['customer'])) { + /** @phpstan-ignore property.notFound */ + throw new \InvalidArgumentException(self::messages()->charge->customer, 400); + } + + if (!isset($charge['billingType'])) { + /** @phpstan-ignore property.notFound */ + throw new \InvalidArgumentException(self::messages()->charge->billingType, 400); + } + + if (!BillingTypeEnum::tryFrom($charge['billingType'])) { + /** @phpstan-ignore property.notFound */ + throw new \InvalidArgumentException(self::messages()->charge->billingType, 400); + } + + if (!isset($charge['value']) && !is_numeric($charge['value'])) { + /** @phpstan-ignore property.notFound */ + throw new \InvalidArgumentException(self::messages()->charge->value, 400); + } + + if (!isset($charge['nextDueDate']) && !is_string($charge['nextDueDate'])) { + /** @phpstan-ignore property.notFound */ + throw new \InvalidArgumentException(self::messages()->charge->nextDueDate, 400); + } + } + + /** + * messages for validation + * + * @return object + */ + public static function messages(): object + { + return (object) [ + 'customer' => (object) [ + 'id' => 'Asaas: O identificador do customer é obrigatório.', + ], + 'charge' => (object) [ + 'customer' => 'Asaas: O campo customer é obrigatório e deve ser do tipo string.', + 'billingType' => 'Asaas: O campo billingType é obrigatório, e tem como disponível as seguintes opções: UNDEFINED, BOLETO, CREDIT_CARD, PIX', + 'value' => 'Asaas: O campo value é obrigatório e deve ser do tipo numérico.', + 'nextDueDate' => 'Asaas: O campo nextDueDate é obrigatório e deve ser do tipo string.', + ], + ]; + } +} diff --git a/src/Gateways/Asaas/Resources/Subscription/Subscription.php b/src/Gateways/Asaas/Resources/Subscription/Subscription.php new file mode 100644 index 0000000..b1b7e7e --- /dev/null +++ b/src/Gateways/Asaas/Resources/Subscription/Subscription.php @@ -0,0 +1,108 @@ +client = $this->clientAsaasBoot(); + } + + /** + * set customer + * + * @param array $customer + * @return Subscription + */ + public function setCustomer(array $customer): Subscription + { + $customer = (new Customer( + $this->token, + $customer, + $this->sandbox + ))->create(); + + $this->customerId = $customer['id']; + + return $this; + } + + public function create(array $subscription): array + { + $subscription['customer'] = $this->customerId; + + StoreSubscriptionAsaasRequest::validate($subscription); + + return $this->post('subscriptions', $subscription); + } + + // public function findAll() + // { + // throw new \Exception('Method not implemented'); + // } + + // public function find(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function update(string $subscriptionId, array $subscription) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function destroy(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function findCharges(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function generateCarnet(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function nfeSettings(string $subscriptionId, array $nfeSettings) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function findNfeSettings(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function updateNfeSettings(string $subscriptionId, array $nfeSettings) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function destroyNfeSettings(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } + + // public function findNfes(string $subscriptionId) + // { + // throw new \Exception('Method not implemented'); + // } +} diff --git a/src/Gateways/Efi/EfiGateway.php b/src/Gateways/Efi/EfiGateway.php index e62ab9d..5a72652 100644 --- a/src/Gateways/Efi/EfiGateway.php +++ b/src/Gateways/Efi/EfiGateway.php @@ -116,4 +116,9 @@ public function pix(array $pix = []): object { throw new Exception('Not implemented'); } + + public function subscription(): object + { + throw new Exception('Not implemented'); + } } diff --git a/src/PHPay.php b/src/PHPay.php index 3e7f111..02dd972 100644 --- a/src/PHPay.php +++ b/src/PHPay.php @@ -2,7 +2,6 @@ namespace PHPay; -use Efi\Interface\EfiGatewayInterface; use PHPay\Contracts\GatewayInterface; class PHPay implements GatewayInterface @@ -19,18 +18,14 @@ public function __construct( } /** - * ATTENTION!!! ONLY EFÍ GATEWAY + * instance of PHPay. * - * @return array + * @param GatewayInterface $gateway + * @return PHPay */ - protected function getToken(): array + public static function gateway(GatewayInterface $gateway): PHPay { - /** - * @var EfiGatewayInterface $gateway - */ - $gateway = $this->gateway; - - return $gateway->getToken(); + return new PHPay($gateway); } /** @@ -75,4 +70,14 @@ public function pix(array $pix = []): object { return $this->gateway->pix($pix); } + + /** + * get resource subscription from gateway. + * + * @return object + */ + public function subscription(): object + { + return $this->gateway->subscription(); + } } diff --git a/tests/PHPayTest.php b/tests/PHPayTest.php index c2c36ed..7c47f72 100644 --- a/tests/PHPayTest.php +++ b/tests/PHPayTest.php @@ -1,7 +1,5 @@ Date: Sun, 9 Mar 2025 20:21:28 -0300 Subject: [PATCH 2/2] PHPAY-64: doc(asaas-subscription): adding create a new subscription example on readme --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 829a643..cd38bfa 100644 --- a/README.md +++ b/README.md @@ -112,11 +112,29 @@ $phpay->undoConfirmReceipt($chargeId); ``` +### Assinaturas + +```php +/** + * @var Subscription $phpay + */ +$phpay = PHPay::gateway(new AsaasGateway(TOKEN_ASAAS_SANDBOX))->subscription(); + +/** + * create a new subscription + */ +$phpay->setCustomer($customer)->create([ + 'billingType' => 'BOLETO', + 'value' => 100, + 'nextDueDate' => '2025-04-09', +]); +``` + ## 📝 Roadmap - Definições de Arquitetura ✅ - Domínios ✅ -- Documentação 🕑 +- Documentação ✍️ - Site 🕛 - Gateways ✍️ @@ -125,6 +143,7 @@ $phpay->undoConfirmReceipt($chargeId); - Cobranças ✅ - Clientes ✅ - Webhook ✅ + - Assinaturas ✍️ - Pix 🕥 - Efí. @@ -133,6 +152,7 @@ $phpay->undoConfirmReceipt($chargeId); - Cobranças ✅ - Clientes 🕥 - Webhook 🕥 + - Assinaturas ✍️ - Pix 🕥 - Lançamento v1.0.0 🚀