├── LICENSE.md ├── README.md ├── composer.json ├── config └── paymaya-sdk.php ├── phpstan.neon ├── phpunit.xml └── src ├── Commands ├── Customization │ ├── DeleteCustomizationCommand.php │ ├── RegisterCustomizationCommand.php │ └── RetrieveCustomizationCommand.php └── Webhook │ └── Checkout │ ├── RegisterWebHookCommand.php │ └── RetrieveWebhookCommand.php ├── Facades ├── CheckoutFacade.php ├── ClientFacade.php ├── CustomizationFacade.php ├── PaymayaFacade.php └── WebhookFacade.php ├── LaravelPaymaya.php └── LaravelPaymayaServiceProvider.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) lloricode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the 7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Paymaya SDK for Laravel 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/lloricode/laravel-paymaya-sdk.svg?style=flat-square)](https://packagist.org/packages/lloricode/laravel-paymaya-sdk) 4 | [![Tests](https://github.com/lloricode/laravel-paymaya-sdk/actions/workflows/run-tests.yml/badge.svg)](https://github.com/lloricode/laravel-paymaya-sdk/actions/workflows/run-tests.yml) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/lloricode/laravel-paymaya-sdk.svg?style=flat-square)](https://packagist.org/packages/lloricode/laravel-paymaya-sdk) 6 | [![codecov](https://codecov.io/gh/lloricode/laravel-paymaya-sdk/branch/main/graph/badge.svg?token=JXRH9XB4BL)](https://codecov.io/gh/lloricode/laravel-paymaya-sdk) 7 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/donate?hosted_button_id=V8PYXUNG6QP44) 8 | 9 | 10 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/D1D71HJZD) 11 | 12 | Paymaya SDK for laravel, it uses [lloricode/paymaya-sdk-php](https://github.com/lloricode/paymaya-sdk-php). 13 | 14 | - [Installation](#installation) 15 | - [Usage](#usage) 16 | - [Checkout](#checkout) 17 | - [Webhooks](#webhook) 18 | - [Testing with Guzzle Mock](#testing-with-guzzle-mock) 19 | 20 | ## Installation 21 | 22 | You can install the package via composer: 23 | 24 | ```bash 25 | composer require lloricode/laravel-paymaya-sdk 26 | ``` 27 | 28 | You can publish the config file with: 29 | 30 | ```bash 31 | php artisan vendor:publish --provider="Lloricode\LaravelPaymaya\LaravelPaymayaServiceProvider" --tag="laravel-paymaya-sdk-config" 32 | ``` 33 | 34 | This is the contents of the published config file: 35 | 36 | ```php 37 | env('PAYMAYA_MODE', PaymayaClient::ENVIRONMENT_SANDBOX), 44 | 'keys' => [ 45 | 'public' => env('PAYMAYA_PUBLIC_KEY'), 46 | 'secret' => env('PAYMAYA_SECRET_KEY'), 47 | ], 48 | 49 | /** 50 | * 51 | * Webhooks 52 | * 53 | */ 54 | 'webhooks' => [ 55 | Webhook::CHECKOUT_SUCCESS => 'api/payment-callback/paymaya/success', 56 | Webhook::CHECKOUT_FAILURE => 'api/payment-callback/paymaya/failure', 57 | Webhook::CHECKOUT_DROPOUT => 'api/payment-callback/paymaya/dropout', 58 | 59 | // Webhook::PAYMENT_SUCCESS => 'api/test/success', 60 | // Webhook::PAYMENT_EXPIRED => 'api/test/expired', 61 | // Webhook::PAYMENT_FAILED => 'api/test/failed', 62 | ], 63 | 64 | 'checkout' => [ 65 | 'customization' => [ 66 | 'logoUrl' => 'https://image1.png', 67 | 'iconUrl' => 'https://image2.png', 68 | 'appleTouchIconUrl' => 'https://image3.png', 69 | 'customTitle' => 'test paymaya sandbox title', 70 | 'colorScheme' => '#e01c44', 71 | 'redirectTimer'=> 3, 72 | ], 73 | ], 74 | ]; 75 | ``` 76 | 77 | ## Usage 78 | 79 | You can copy the sample to test it. 80 | 81 | ### Checkout 82 | 83 | https://developers.paymaya.com/blog/entry/paymaya-checkout-api-overview 84 | 85 | ``` php 86 | use Carbon\Carbon; 87 | use Lloricode\Paymaya\Request\Checkout\Amount\AmountDetail; 88 | use Lloricode\Paymaya\Request\Checkout\Amount\Amount; 89 | use Lloricode\Paymaya\Request\Checkout\Buyer\BillingAddress; 90 | use Lloricode\Paymaya\Request\Checkout\Buyer\Buyer; 91 | use Lloricode\Paymaya\Request\Checkout\Buyer\Contact; 92 | use Lloricode\Paymaya\Request\Checkout\Buyer\ShippingAddress; 93 | use Lloricode\Paymaya\Request\Checkout\Checkout; 94 | use Lloricode\Paymaya\Request\Checkout\Item; 95 | use Lloricode\Paymaya\Request\Checkout\MetaData; 96 | use Lloricode\Paymaya\Request\Checkout\RedirectUrl; 97 | use Lloricode\Paymaya\Request\Checkout\TotalAmount; 98 | use PaymayaSDK; 99 | 100 | $checkout = (new Checkout()) 101 | ->setTotalAmount( 102 | (new TotalAmount()) 103 | ->setValue(100) 104 | ->setDetails( 105 | (new AmountDetail()) 106 | ->setSubtotal(100) 107 | ) 108 | ) 109 | ->setBuyer( 110 | (new Buyer()) 111 | ->setFirstName('John') 112 | ->setMiddleName('Paul') 113 | ->setLastName('Doe') 114 | ->setBirthday(Carbon::parse('1995-10-24')) 115 | ->setCustomerSince(Carbon::parse('1995-10-24')) 116 | ->setGender('M') 117 | ->setContact( 118 | (new Contact()) 119 | ->setPhone('+639181008888') 120 | ->setEmail('merchant@merchantsite.com') 121 | ) 122 | ->setShippingAddress( 123 | (new ShippingAddress()) 124 | ->setFirstName('John') 125 | ->setMiddleName('Paul') 126 | ->setLastName('Doe') 127 | ->setPhone('+639181008888') 128 | ->setEmail('merchant@merchantsite.com') 129 | ->setLine1('6F Launchpad') 130 | ->setLine2('Reliance Street') 131 | ->setCity('Mandaluyong City') 132 | ->setState('Metro Manila') 133 | ->setZipCode('1552') 134 | ->setCountryCode('PH') 135 | ->setShippingType('ST') 136 | ) 137 | ->setBillingAddress( 138 | (new BillingAddress()) 139 | ->setLine1('6F Launchpad') 140 | ->setLine2('Reliance Street') 141 | ->setCity('Mandaluyong City') 142 | ->setState('Metro Manila') 143 | ->setZipCode('1552') 144 | ->setCountryCode('PH') 145 | ) 146 | ) 147 | ->addItem( 148 | (new Item()) 149 | ->setName('Canvas Slip Ons') 150 | ->setQuantity(1) 151 | ->setCode('CVG-096732') 152 | ->setDescription('Shoes') 153 | ->setAmount( 154 | (new Amount()) 155 | ->setValue(100) 156 | ->setDetails( 157 | (new AmountDetail()) 158 | ->setDiscount(0) 159 | ->setServiceCharge(0) 160 | ->setShippingFee(0) 161 | ->setTax(0) 162 | ->setSubtotal(100) 163 | ) 164 | ) 165 | ->setTotalAmount( 166 | (new Amount()) 167 | ->setValue(100) 168 | ->setDetails( 169 | (new AmountDetail()) 170 | ->setDiscount(0) 171 | ->setServiceCharge(0) 172 | ->setShippingFee(0) 173 | ->setTax(0) 174 | ->setSubtotal(100) 175 | ) 176 | ) 177 | ) 178 | ->setRedirectUrl( 179 | (new RedirectUrl()) 180 | ->setSuccess('https://www.merchantsite.com/success') 181 | ->setFailure('https://www.merchantsite.com/failure') 182 | ->setCancel('https://www.merchantsite.com/cancel') 183 | )->setRequestReferenceNumber('1551191039') 184 | ->setMetadata( 185 | (new MetaData()) 186 | ->setSMI('smi') 187 | ->setSMN('smn') 188 | ->setMCI('mci') 189 | ->setMPC('mpc') 190 | ->setMCO('mco') 191 | ->setMST('mst') 192 | ); 193 | 194 | $checkoutResponse = PaymayaSDK::checkout()->execute($checkout); 195 | 196 | echo 'id: '.$checkoutResponse->checkoutId."\n"; 197 | echo 'url: '.$checkoutResponse->redirectUrl."\n"; 198 | ``` 199 | 200 | ### Webhook 201 | 202 | ``` 203 | # see config `paymaya-sdk.webhooks` array to set your webhooks, 204 | # then run this to register webhooks. 205 | 206 | php artisan paymaya-sdk:webhook:register 207 | 208 | 209 | # retrieve webhooks 210 | 211 | php artisan paymaya-sdk:webhook:retrieve 212 | 213 | 214 | # retrieve output 215 | 216 | +--------+------------------+------------------------------+---------------------+---------------------+ 217 | | id | name | callbackUrl | createdAt | updatedAt | 218 | +--------+------------------+------------------------------+---------------------+---------------------+ 219 | | | CHECKOUT_SUCCESS | http://localhost/api/success | 2021-02-05 17:40:40 | 2021-02-05 17:40:40 | 220 | | | CHECKOUT_FAILURE | http://localhost/api/failed | 2021-02-05 17:40:45 | 2021-02-05 17:40:45 | 221 | | | CHECKOUT_DROPOUT | http://localhost/api/dropout | 2021-02-05 17:40:45 | 2021-02-05 17:40:45 | 222 | +--------+------------------+------------------------------+---------------------+---------------------+ 223 | 224 | ``` 225 | 226 | ### Testing with Guzzle Mock 227 | 228 | Add this to your Base Test Case 229 | 230 | ```php 231 | use GuzzleHttp\Handler\MockHandler; 232 | use GuzzleHttp\HandlerStack; 233 | use GuzzleHttp\Psr7\Response; 234 | use PaymayaSDK; 235 | 236 | protected function fakePaymaya(array $mockResponse, &$history = []) 237 | { 238 | $mock = []; 239 | 240 | foreach ($mockResponse as $value) { 241 | $mock[] = new Response( 242 | $value['status'] ?? 200, 243 | $value['headers'] ?? [], 244 | json_encode($value['body'] ?? []), 245 | ); 246 | } 247 | 248 | PaymayaSDK::client()->setHandlerStack( 249 | HandlerStack::create(new MockHandler($mock)), 250 | $history 251 | ); 252 | } 253 | ``` 254 | 255 | Sample usage of mock 256 | 257 | ```php 258 | 259 | /** 260 | * @test 261 | */ 262 | public function success_checkout() 263 | { 264 | $paymayaID = 'test-paymaya-generated-id'; 265 | $paymayaRedirectUrl = 'http://test-paymaya/redirect-url'; 266 | 267 | $this->fakePaymaya( 268 | [ 269 | [ 270 | 'body' => [ 271 | 'checkoutId' => $paymayaID, 272 | 'redirectUrl' => $paymayaRedirectUrl, 273 | ], 274 | ], 275 | ] 276 | ); 277 | 278 | // you test 279 | 280 | 281 | ``` 282 | 283 | 284 | ## Testing 285 | 286 | ```bash 287 | composer test 288 | ``` 289 | 290 | ## Changelog 291 | 292 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 293 | 294 | ## Contributing 295 | 296 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 297 | 298 | ## Security Vulnerabilities 299 | 300 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 301 | 302 | ## Credits 303 | 304 | - [Lloric Mayuga Garcia](https://github.com/lloricode) 305 | - [All Contributors](../../contributors) 306 | 307 | ## License 308 | 309 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 310 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lloricode/laravel-paymaya-sdk", 3 | "description": "SDK for Paymaya using Laravel", 4 | "keywords": [ 5 | "lloricode", 6 | "paymaya", 7 | "sdk", 8 | "laravel", 9 | "php" 10 | ], 11 | "homepage": "https://github.com/lloricode/laravel-paymaya-sdk", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Lloric Mayuga Garcia", 16 | "email": "lloricode@gmail.com", 17 | "role": "Developer", 18 | "homepage": "https://lloricode.com" 19 | } 20 | ], 21 | "require": { 22 | "php": "^8.2", 23 | "ext-json": "*", 24 | "illuminate/contracts": "^11.0|^12.0", 25 | "lloricode/paymaya-sdk-php": "^2.0.0", 26 | "spatie/laravel-package-tools": "^1.16.2" 27 | }, 28 | "require-dev": { 29 | "composer-runtime-api": "^2.2.2", 30 | "laravel/pint": "^1.14", 31 | "orchestra/testbench": "^9.0|^10.0", 32 | "pestphp/pest": "^3.7.4", 33 | "pestphp/pest-plugin-laravel": "^3.1.0", 34 | "phpstan/extension-installer": "^1.3.1", 35 | "phpstan/phpstan": "^2.1", 36 | "phpstan/phpstan-deprecation-rules": "^2.0.1", 37 | "phpstan/phpstan-phpunit": "^2.0.4", 38 | "rector/rector": "^2.0.9", 39 | "spatie/laravel-ray": "^1.35.1", 40 | "ticketswap/phpstan-error-formatter": "^1.1" 41 | }, 42 | "autoload": { 43 | "psr-4": { 44 | "Lloricode\\LaravelPaymaya\\": "src" 45 | } 46 | }, 47 | "autoload-dev": { 48 | "psr-4": { 49 | "Lloricode\\LaravelPaymaya\\Tests\\": "tests" 50 | } 51 | }, 52 | "scripts": { 53 | "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", 54 | "analyse": "vendor/bin/phpstan analyse", 55 | "test": "vendor/bin/pest -p", 56 | "test-coverage": "vendor/bin/pest --coverage", 57 | "format": "vendor/bin/pint", 58 | "refactor": "vendor/bin/rector process", 59 | "refactor-dry-run": "vendor/bin/rector process --dry-run" 60 | }, 61 | "config": { 62 | "sort-packages": true, 63 | "allow-plugins": { 64 | "pestphp/pest-plugin": true, 65 | "phpstan/extension-installer": true 66 | } 67 | }, 68 | "extra": { 69 | "laravel": { 70 | "providers": [ 71 | "Lloricode\\LaravelPaymaya\\LaravelPaymayaServiceProvider" 72 | ], 73 | "aliases": { 74 | "PaymayaSDKCheckoutClient": "Lloricode\\LaravelPaymaya\\Facades\\CheckoutFacade", 75 | "PaymayaSDKClient": "Lloricode\\LaravelPaymaya\\Facades\\ClientFacade", 76 | "PaymayaSDKCustomizationClient": "Lloricode\\LaravelPaymaya\\Facades\\CustomizationFacade", 77 | "PaymayaSDK": "Lloricode\\LaravelPaymaya\\Facades\\PaymayaFacade", 78 | "PaymayaSDKWebhhokClient": "Lloricode\\LaravelPaymaya\\Facades\\WebhookFacade" 79 | } 80 | } 81 | }, 82 | "minimum-stability": "dev", 83 | "prefer-stable": true, 84 | "funding": [ 85 | { 86 | "type": "github", 87 | "url": "https://github.com/lloricde" 88 | } 89 | ], 90 | "support": { 91 | "issues": "https://github.com/lloricode/laravel-paymaya-sdk/issues", 92 | "source": "https://github.com/lloricode/laravel-paymaya-sdk" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /config/paymaya-sdk.php: -------------------------------------------------------------------------------- 1 | env('PAYMAYA_MODE', PaymayaClient::ENVIRONMENT_SANDBOX), 14 | 'keys' => [ 15 | 'public' => env('PAYMAYA_PUBLIC_KEY'), 16 | 'secret' => env('PAYMAYA_SECRET_KEY'), 17 | ], 18 | 19 | 'timeout' => 3, 20 | 21 | /** 22 | * Webhooks 23 | */ 24 | 'webhooks' => [ 25 | Webhook::CHECKOUT_SUCCESS => 'api/payment-callback/paymaya/success', 26 | Webhook::CHECKOUT_FAILURE => 'api/payment-callback/paymaya/failure', 27 | Webhook::CHECKOUT_DROPOUT => 'api/payment-callback/paymaya/dropout', 28 | 29 | // Webhook::PAYMENT_SUCCESS => 'api/test/success', 30 | // Webhook::PAYMENT_EXPIRED => 'api/test/expired', 31 | // Webhook::PAYMENT_FAILED => 'api/test/failed', 32 | ], 33 | 34 | 'checkout' => [ 35 | 'customization' => [ 36 | 'logoUrl' => 'https://image1.png', 37 | 'iconUrl' => 'https://image2.png', 38 | 'appleTouchIconUrl' => 'https://image3.png', 39 | 'customTitle' => 'test paymaya sandbox title', 40 | 'colorScheme' => '#e01c44', 41 | 'redirectTimer' => 3, 42 | ], 43 | ], 44 | ]; 45 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: max 3 | paths: 4 | - src 5 | tmpDir: build/phpstan 6 | 7 | ignoreErrors: 8 | - identifier: missingType.iterableValue 9 | 10 | errorFormat: ticketswap 11 | editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' 12 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | tests 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ./src 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/Commands/Customization/DeleteCustomizationCommand.php: -------------------------------------------------------------------------------- 1 | delete(); 20 | 21 | $this->info('Done deleting customization'); 22 | 23 | return self::SUCCESS; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Commands/Customization/RegisterCustomizationCommand.php: -------------------------------------------------------------------------------- 1 | register(new Customization(...config()->array('paymaya-sdk.checkout.customization'))); 25 | 26 | $this->info('Done registering customization'); 27 | } catch (ClientException $exception) { 28 | $response = (array) json_decode((string) $exception->getResponse()->getBody(), true); 29 | 30 | if (($response['message'] ?? null) === 'Missing/invalid parameters.') { 31 | $this->error('Missing/invalid parameters.'); 32 | /** @phpstan-ignore-next-line */ 33 | $this->comment(json_encode($response['parameters'] ?? [], JSON_PRETTY_PRINT)); 34 | } 35 | 36 | return self::FAILURE; 37 | } 38 | 39 | return self::SUCCESS; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Commands/Customization/RetrieveCustomizationCommand.php: -------------------------------------------------------------------------------- 1 | retrieve()->toArray(); 20 | 21 | $rows = []; 22 | 23 | foreach ($data as $field => $value) { 24 | $rows[] = [$field, is_bool($value) ? ($value ? 'true' : 'false') : $value]; 25 | } 26 | 27 | $this->table(['Field', 'Value'], $rows); 28 | 29 | return self::SUCCESS; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Commands/Webhook/Checkout/RegisterWebHookCommand.php: -------------------------------------------------------------------------------- 1 | deleteAll(); 21 | 22 | foreach (config()->array('paymaya-sdk.webhooks') as $name => $url) { 23 | PaymayaFacade::webhook() 24 | ->register( 25 | (new Webhook) 26 | ->setName($name) 27 | /** @phpstan-ignore-next-line */ 28 | ->setCallbackUrl(url($url)) 29 | ); 30 | } 31 | 32 | $this->info('Done registering webhooks'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Commands/Webhook/Checkout/RetrieveWebhookCommand.php: -------------------------------------------------------------------------------- 1 | table(['id', 'name', 'callbackUrl', 'createdAt', 'updatedAt'], $this->retrieveWebhooks()); 20 | } 21 | 22 | /** @throws \GuzzleHttp\Exception\GuzzleException*/ 23 | public function retrieveWebhooks(): array 24 | { 25 | $return = []; 26 | 27 | foreach (PaymayaFacade::webhook()->retrieve() as $webhookResponse) { 28 | $return[] = [ 29 | 'id' => $webhookResponse->id, 30 | 'name' => $webhookResponse->name, 31 | 'callbackUrl' => $webhookResponse->callbackUrl, 32 | 'createdAt' => $webhookResponse->createdAt, 33 | 'updatedAt' => $webhookResponse->updatedAt, 34 | ]; 35 | } 36 | 37 | return $return; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Facades/CheckoutFacade.php: -------------------------------------------------------------------------------- 1 | name('laravel-paymaya-sdk') 22 | ->hasConfigFile() 23 | ->hasCommands( 24 | [ 25 | RetrieveWebhookCommand::class, 26 | RegisterWebHookCommand::class, 27 | RegisterCustomizationCommand::class, 28 | RetrieveCustomizationCommand::class, 29 | DeleteCustomizationCommand::class, 30 | ] 31 | ); 32 | } 33 | 34 | /** @return void */ 35 | public function packageRegistered() 36 | { 37 | $this->app->singleton( 38 | PaymayaClient::class, 39 | fn () => (new PaymayaClient( 40 | config()->string('paymaya-sdk.keys.secret'), 41 | config()->string('paymaya-sdk.keys.public'), 42 | config()->string('paymaya-sdk.mode'), 43 | )) 44 | ->setTimeout(config()->integer('paymaya-sdk.timeout', 3)) 45 | ); 46 | } 47 | } 48 | --------------------------------------------------------------------------------