├── .gitignore ├── src ├── Interfaces │ └── RecurringPaymentInterface.php ├── resources │ └── views │ │ ├── loader.blade.php │ │ ├── failurl.blade.php │ │ ├── okurl.blade.php │ │ ├── error.blade.php │ │ └── index.blade.php ├── Http │ ├── Requests │ │ └── HandleRecurringPaymentRequest.php │ └── Controllers │ │ ├── RecurringPaymentController.php │ │ └── CasysController.php ├── config │ └── casys.php ├── routes │ └── casys.php ├── CasysServiceProvider.php └── Service │ ├── RecurringPayment.php │ └── Casys.php ├── phpstan.neon ├── rector.php ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── composer.json ├── tests └── Feature │ └── CasysTest.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | .idea 3 | vendor 4 | composer.lock -------------------------------------------------------------------------------- /src/Interfaces/RecurringPaymentInterface.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | public function sendPayment(string $merchantID, string $rpRef, string $rpRefID, int $amount, string $password): array; 11 | } -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - vendor/larastan/larastan/extension.neon 3 | - vendor/nesbot/carbon/extension.neon 4 | 5 | parameters: 6 | 7 | paths: 8 | - src/ 9 | - config/ 10 | # Level 10 is the highest level 11 | level: 10 12 | 13 | ignoreErrors: 14 | - '#Called ''env'' outside of the config directory which returns null when the config is cached, use ''config''.#' 15 | -------------------------------------------------------------------------------- /rector.php: -------------------------------------------------------------------------------- 1 | withPaths([ 9 | __DIR__ . '/src', 10 | __DIR__ . '/tests', 11 | ]) 12 | // uncomment to reach your current PHP version 13 | // ->withPhpSets() 14 | ->withTypeCoverageLevel(50) 15 | ->withDeadCodeLevel(51) 16 | ->withCodeQualityLevel(72); 17 | -------------------------------------------------------------------------------- /src/resources/views/loader.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 20 | 21 | 22 | Please wait... 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/Http/Requests/HandleRecurringPaymentRequest.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function rules(): array 15 | { 16 | return [ 17 | 'merchant_id' => 'required|string', 18 | 'rp_ref' => 'required|string', 19 | 'rp_ref_id' => 'required|string', 20 | 'amount' => 'required|numeric', 21 | 'password' => 'required|string', 22 | ]; 23 | } 24 | 25 | /** 26 | * Authorize the request. 27 | */ 28 | public function authorize(): bool 29 | { 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config/casys.php: -------------------------------------------------------------------------------- 1 | env('PAY_TO_MERCHANT'), 13 | 'MerchantName' => env('MERCHANT_NAME'), 14 | 'AmountCurrency' => env('AMOUNT_CURRENCY', 'MKD'), 15 | 'PaymentOKURL' => env('PAYMENT_OK_URL', 'paymentOKURL'), 16 | 'PaymentFailURL' => env('PAYMENT_FAIL_URL', 'paymentFailURL'), 17 | 'Password' => env('CASYS_TOKEN', 'TEST_PASS'), 18 | 'RecurrentPaymentWsdl' => env('RECURRING_PAYMENT_WSDL', 'https://www.cpay.com.mk/Recurring/RecurringPaymentsWS.wsdl'), 19 | 20 | ]; 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /src/resources/views/failurl.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
9 |
Unsuccessful transaction
10 |
11 |

12 | 13 |

14 |

Unsuccessful transaction

15 |
16 |
17 |
18 |
19 |
20 |
21 | 26 | @endsection 27 | -------------------------------------------------------------------------------- /src/resources/views/okurl.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @section('content') 3 |
4 |
5 |
6 |
7 |
8 |
Successful transaction
9 |
10 |

11 | 12 |

13 |

Successful transaction

14 |
15 |
16 |
17 |
18 |
19 | 24 |
25 | @endsection 26 | -------------------------------------------------------------------------------- /src/resources/views/error.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | @section('content') 3 |
4 |
5 |
6 |
7 |
8 |
Error
9 |
10 |

11 | 12 |
Payment error
13 |

14 |
15 |
16 |
17 |
18 |
19 | 24 |
25 | @endsection 26 | -------------------------------------------------------------------------------- /src/routes/casys.php: -------------------------------------------------------------------------------- 1 | name('loader'); 19 | Route::post('payment', [CasysController::class, 'getCasys'])->name('validateAndPay'); 20 | Route::post('paymentOKURL', [CasysController::class, 'success'])->name('paymentOKURL'); 21 | Route::post('paymentFailURL', [CasysController::class, 'fail'])->name('paymentFailURL'); 22 | 23 | Route::post('recurring-payment', [RecurringPaymentController::class, 'handleRecurringPayment'])->name('recurring.payment'); 24 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kalimeromk/casys-laravel", 3 | "description": "Integration of casys payment method", 4 | "require": { 5 | "php": ">=8.0", 6 | "ext-json": "*", 7 | "ext-soap": "*" 8 | }, 9 | "keywords": [ 10 | "laravel", 11 | "casys" 12 | ], 13 | "license": "MIT", 14 | "authors": [ 15 | { 16 | "name": "Zoran Shefot Bogoevski", 17 | "email": "zbogoevski@gmail.com" 18 | } 19 | ], 20 | "autoload": { 21 | "psr-4": { 22 | "Kalimero\\Casys\\": "src/", 23 | "Kalimero\\Casys\\Tests\\": "tests/" 24 | } 25 | }, 26 | "scripts": { 27 | "post-autoload-dump": [ 28 | "@php ./vendor/bin/testbench package:discover --ansi" 29 | ], 30 | "test": "vendor/bin/phpunit" 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Kalimero\\Casys\\Tests\\": "tests/" 35 | } 36 | }, 37 | "extra": { 38 | "laravel": { 39 | "providers": [ 40 | "Kalimero\\Casys\\CasysServiceProvider" 41 | ] 42 | } 43 | }, 44 | "require-dev": { 45 | "orchestra/testbench": "^5.0|^6.0|^7.0|8.0|^9.0", 46 | "phpunit/phpunit": "^8.0|^9.0|10.0|^11.0", 47 | "mockery/mockery": "^1.4|^1.5|^1.6|^1.7", 48 | "larastan/larastan": "^3.0", 49 | "rector/rector": "^2.1.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Http/Controllers/RecurringPaymentController.php: -------------------------------------------------------------------------------- 1 | recurringPayment = $recurringPayment; 17 | } 18 | 19 | /** 20 | * Handle the recurring payment request. 21 | */ 22 | public function handleRecurringPayment(HandleRecurringPaymentRequest $request): JsonResponse 23 | { 24 | $validated = $request->validated(); 25 | 26 | $merchantId = is_string($validated['merchant_id']) ? $validated['merchant_id'] : ''; 27 | $rpRef = is_string($validated['rp_ref']) ? $validated['rp_ref'] : ''; 28 | $rpRefId = is_string($validated['rp_ref_id']) ? $validated['rp_ref_id'] : ''; 29 | $amount = is_int($validated['amount']) ? $validated['amount'] : 0; 30 | $password = is_string($validated['password']) ? $validated['password'] : ''; 31 | 32 | $response = $this->recurringPayment->sendPayment( 33 | $merchantId, 34 | $rpRef, 35 | $rpRefId, 36 | $amount, 37 | $password 38 | ); 39 | 40 | return response()->json($response); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/Feature/CasysTest.php: -------------------------------------------------------------------------------- 1 | get(route('casys.index')); 16 | 17 | $response->assertStatus(200); 18 | $response->assertViewIs('casys::loader'); 19 | } 20 | 21 | public function test_it_returns_casys_data_on_getCasys(): void 22 | { 23 | $client = $this->faker->word; 24 | $amount = $this->faker->randomNumber(2); 25 | 26 | $response = $this->get(route('casys.getCasys', ['client' => $client, 'amount' => $amount])); 27 | 28 | $response->assertStatus(200); 29 | $response->assertViewIs('casys::index'); 30 | $response->assertViewHas('casys'); 31 | } 32 | 33 | public function test_it_returns_success_view_on_success(): void 34 | { 35 | $response = $this->get(route('casys.success')); 36 | 37 | $response->assertStatus(200); 38 | $response->assertViewIs('casys::okurl'); 39 | $response->assertViewHas('success', 'You transaction was successful'); 40 | } 41 | 42 | public function test_it_returns_fail_view_on_fail(): void 43 | { 44 | $response = $this->get(route('casys.fail')); 45 | 46 | $response->assertStatus(200); 47 | $response->assertViewIs('casys::failurl'); 48 | $response->assertViewHas('success', 'Your transaction failed'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/CasysServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__ . '/resources/views', 'casys'); 19 | $this->loadRoutesFrom(__DIR__ . '/routes/casys.php'); 20 | 21 | $this->publishes([ 22 | __DIR__ . '/resources/views' => resource_path('views/vendor/casys'), 23 | ]); 24 | } 25 | 26 | /** 27 | * Register the service provider. 28 | */ 29 | public function register(): void 30 | { 31 | $this->registerConfig(); 32 | 33 | $this->app->singleton(RecurringPaymentInterface::class, function (): RecurringPayment { 34 | $wsdl = config('casys.RecurrentPaymentWsdl'); 35 | 36 | // Ensure the WSDL is valid 37 | if (!is_string($wsdl) || ($wsdl === '' || $wsdl === '0')) { 38 | throw new InvalidArgumentException('The WSDL URL for the Recurrent Payment service must be a valid non-empty string.'); 39 | } 40 | 41 | $soapClient = new SoapClient($wsdl); 42 | 43 | return new RecurringPayment($soapClient); 44 | }); 45 | } 46 | 47 | /** 48 | * Register package config. 49 | */ 50 | protected function registerConfig(): void 51 | { 52 | $this->mergeConfigFrom(__DIR__ . '/config/casys.php', 'casys'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Http/Controllers/CasysController.php: -------------------------------------------------------------------------------- 1 | casys = $casys; 22 | } 23 | 24 | /** 25 | * Display the payment loader view. 26 | */ 27 | public function index(): View|Factory|Application 28 | { 29 | /** @var view-string $viewName */ 30 | $viewName = 'casys::loader'; 31 | return view($viewName); 32 | } 33 | 34 | /** 35 | * Generate and display the payment data. 36 | * 37 | * @param stdClass $client An object containing client data (name, last_name, country, email). 38 | * @param float $amount The amount to be paid. 39 | */ 40 | public function getCasys(stdClass $client, float $amount): View|Factory|Application 41 | { 42 | $casysData = $this->casys->getCasysData($client, $amount); 43 | /** @var view-string $viewName */ 44 | $viewName = 'casys::index'; 45 | return view($viewName, ['casysData' => $casysData]); 46 | } 47 | 48 | /** 49 | * Handle successful payment. 50 | */ 51 | public function success(): View|Factory|Application 52 | { 53 | /** @var view-string $viewName */ 54 | $viewName = 'casys::okurl'; 55 | return view($viewName)->with('success', 'Your transaction was successful'); 56 | } 57 | 58 | /** 59 | * Handle failed payment. 60 | */ 61 | public function fail(): View|Factory|Application 62 | { 63 | /** @var view-string $viewName */ 64 | $viewName = 'casys::failurl'; 65 | return view($viewName)->with('error', 'Your transaction failed'); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Service/RecurringPayment.php: -------------------------------------------------------------------------------- 1 | soapClient = $soapClient; 19 | } 20 | 21 | /** 22 | * Perform a recurring payment. 23 | * 24 | * @return array{success: bool, payment_reference?: string, error_description?: string} 25 | * @throws Exception 26 | */ 27 | public function sendPayment(string $merchantID, string $rpRef, string $rpRefID, int $amount, string $password): array 28 | { 29 | $params = [ 30 | 'Amount' => $amount, 31 | 'MerchantID' => $merchantID, 32 | 'RPRef' => $rpRef, 33 | 'RPRefID' => $rpRefID, 34 | 'MD5' => md5($merchantID . $rpRefID . $rpRef . $amount . $password), 35 | ]; 36 | 37 | try { 38 | $response = $this->soapClient->__soapCall('sendPayment', [$params]); 39 | 40 | if (is_object($response) && isset($response->Success)) { 41 | $paymentReference = ''; 42 | if (isset($response->CPayPaymentRef)) { 43 | $paymentReference = is_string($response->CPayPaymentRef) ? $response->CPayPaymentRef : ''; 44 | } 45 | 46 | $errorDescription = 'Unknown error'; 47 | if (isset($response->ErrorDecription)) { 48 | $errorDescription = is_string($response->ErrorDecription) ? $response->ErrorDecription : 'Unknown error'; 49 | } 50 | 51 | return $response->Success 52 | ? ['success' => true, 'payment_reference' => $paymentReference] 53 | : ['success' => false, 'error_description' => $errorDescription]; 54 | } 55 | 56 | return ['success' => false, 'error_description' => 'Invalid response format from SOAP service']; 57 | } catch (Exception $e) { 58 | return ['success' => false, 'error_description' => $e->getMessage()]; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/resources/views/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
9 |
Payment system
10 |
11 |
18 | @foreach ($casys['required'] as $key => $value) 19 | 20 | @endforeach 21 | 23 | 24 | @foreach ($casys['user'] as $key => $value) 25 | 26 | @endforeach 27 | 28 |
29 |
30 | 36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | @endsection 44 | @push('scripts') 45 | 50 | @endpush 51 | -------------------------------------------------------------------------------- /src/Service/Casys.php: -------------------------------------------------------------------------------- 1 | , user: array, checkSumHeader: string} 16 | */ 17 | public function getCasysData(stdClass $client, float $amount): array 18 | { 19 | $requiredData = [ 20 | 'AmountToPay' => (int) round($amount) > 0 ? (int) round($amount) * 100 : null, 21 | 'PayToMerchant' => config('casys.PayToMerchant'), 22 | 'MerchantName' => config('casys.MerchantName'), 23 | 'AmountCurrency' => config('casys.AmountCurrency'), 24 | 'Details1' => Str::random(12), 25 | 'Details2' => 'Price ' . round($amount) . (is_string(config('casys.AmountCurrency')) ? config('casys.AmountCurrency') : ''), 26 | 'PaymentOKURL' => config('casys.PaymentOKURL'), 27 | 'PaymentFailURL' => config('casys.PaymentFailURL'), 28 | 'OriginalAmount' => (int) round($amount), 29 | 'OriginalCurrency' => config('casys.AmountCurrency'), 30 | ]; 31 | 32 | $userData = [ 33 | 'FirstName' => $client->name, 34 | 'LastName' => $client->last_name, 35 | 'Country' => $client->country, 36 | 'Email' => $client->email, 37 | ]; 38 | 39 | $checkSumHeader = implode(',', array_merge(array_keys($requiredData), array_keys($userData))); 40 | $checkSumHeaderLengths = implode('', array_merge(array_values($requiredData), array_values($userData))); 41 | $password = config('casys.Password'); 42 | $passwordString = is_string($password) ? $password : ''; 43 | $checkSumHeaderParams = $checkSumHeaderLengths . md5($passwordString); 44 | 45 | foreach ($requiredData as $value) { 46 | $checkSumHeaderParams .= is_null($value) ? '' : (is_scalar($value) ? (string)$value : ''); 47 | } 48 | 49 | foreach ($userData as $value) { 50 | $checkSumHeaderParams .= is_null($value) ? '' : (is_scalar($value) ? (string)$value : ''); 51 | } 52 | 53 | return [ 54 | 'checkSum' => $checkSumHeaderParams, 55 | 'required' => $requiredData, 56 | 'user' => $userData, 57 | 'checkSumHeader' => $checkSumHeader . $checkSumHeaderLengths, 58 | ]; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Casys Laravel Package 3 | 4 | This is a package to integrate the Casys payment gateway into Laravel. It generates complete scaffolding for simple integration, including support for recurring payments. 5 | 6 | ## Features 7 | 1. **Views** 8 | - `resources/views/vendor/casys` 9 | 2. **Configuration** 10 | - `config/casys.php` 11 | 3. **Controllers** 12 | - `/Http/Controllers/CasysController` 13 | - `/Http/Controllers/RecurringPaymentController` 14 | 4. **Recurring Payment Support** 15 | - `/Http/Services/RecurringPayment.php` 16 | - Example integration for managing recurring payments using SOAP services. 17 | 5. **Routes** 18 | - Predefined routes for standard and recurring payments. 19 | 20 | --- 21 | 22 | ## Installation 23 | 24 | Require this package by running: 25 | 26 | ```bash 27 | composer require kalimeromk/casys-laravel 28 | ``` 29 | 30 | After installation, publish the package files: 31 | 32 | ```bash 33 | php artisan vendor:publish --provider="Kalimero\Casys\CasysServiceProvider" 34 | ``` 35 | 36 | This will publish the following files: 37 | - `config/casys.php` 38 | - `resources/views/vendor/casys` 39 | 40 | --- 41 | 42 | ## Laravel Setup 43 | 44 | Register the route file in your `RouteServiceProvider` or add the following routes to your existing route file: 45 | 46 | ### Standard Payment Routes 47 | ```php 48 | use App\Http\Controllers\CasysController; 49 | 50 | Route::get('paymentLoader', [CasysController::class, 'index'])->name('loader'); 51 | Route::post('payment', [CasysController::class, 'getCasys'])->name('validateAndPay'); 52 | Route::post('paymentOKURL', [CasysController::class, 'success'])->name('paymentOKURL'); 53 | Route::post('paymentFailURL', [CasysController::class, 'fail'])->name('paymentFailURL'); 54 | ``` 55 | 56 | ### Recurring Payment Routes 57 | ```php 58 | use KalimeroMK\Casys\Controllers\RecurringPaymentController; 59 | 60 | Route::post('/recurring-payment', [RecurringPaymentController::class, 'handleRecurringPayment'])->name('recurring.payment'); 61 | ``` 62 | 63 | For Laravel <=7, use the controller string syntax: 64 | ```php 65 | Route::get('paymentLoader', 'CasysController@index')->name('loader'); 66 | Route::post('payment', 'CasysController@getCasys')->name('validateAndPay'); 67 | Route::post('paymentOKURL', 'CasysController@success')->name('paymentOKURL'); 68 | Route::post('paymentFailURL', 'CasysController@fail')->name('paymentFailURL'); 69 | ``` 70 | 71 | --- 72 | 73 | ## How to Use 74 | 75 | ### Configuration 76 | Add your credentials to the `.env` file: 77 | ```env 78 | PAY_TO_MERCHANT=your_merchant_id 79 | MERCHANT_NAME=your_merchant_name 80 | AMOUNT_CURRENCY=MKD 81 | PAYMENT_OK_URL=your_success_url 82 | PAYMENT_FAIL_URL=your_fail_url 83 | CASYS_TOKEN=your_token 84 | ``` 85 | 86 | ### Standard Payments 87 | For standard payments, simply pass the amount and client data to the appropriate method in the `CasysController`. The views provided by the package will handle the UI. If you wish to customize the views, edit the published views in `resources/views/vendor/casys`. 88 | 89 | --- 90 | 91 | ### Recurring Payments 92 | 93 | The package includes support for recurring payments through the `RecurringPayment` class and `RecurringPaymentController`. Here’s how you can integrate it: 94 | 95 | #### **Recurring Payment Parameters** 96 | The recurring payment requires the following parameters: 97 | - **RPRef**: A string containing details about the recurring payment, formatted as: 98 | ```plaintext 99 | RPRef = RequestType,BillingCycle,MaxBCycles,BillingAmount,BillingCycleStart 100 | ``` 101 | - **RPRefID**: Unique ID returned during the initial registration of the recurring transaction. 102 | 103 | #### **Example Workflow** 104 | 1. **Initial Registration** 105 | The cardholder performs the initial transaction with the `RPRef` parameter set. The system returns an `RPRefID`, which you should store for future recurring payments. 106 | 107 | 2. **Subsequent Payments** 108 | Use the stored `RPRefID` to initiate subsequent payments without user involvement. 109 | 110 | #### **Example Request** 111 | Call the `/recurring-payment` endpoint with the following payload: 112 | ```json 113 | { 114 | "merchant_id": "YourMerchantID", 115 | "rp_ref": "R,1M,12,500000,20240101", 116 | "rp_ref_id": "UniqueRPRefID", 117 | "amount": 500000, 118 | "password": "YourMerchantPassword" 119 | } 120 | ``` 121 | 122 | #### **Example Recurring Payment Integration** 123 | You can use the `RecurringPayment` service class in your application: 124 | 125 | ```php 126 | use KalimeroMK\Casys\Services\RecurringPayment; 127 | 128 | $recurringPayment = new RecurringPayment(); 129 | 130 | $response = $recurringPayment->sendPayment( 131 | $merchantId, 132 | $rpRef, 133 | $rpRefId, 134 | $amount, 135 | $password 136 | ); 137 | 138 | if ($response['success']) { 139 | echo "Recurring payment successful! Reference: " . $response['payment_reference']; 140 | } else { 141 | echo "Recurring payment failed: " . $response['error_description']; 142 | } 143 | ``` 144 | 145 | --- 146 | 147 | ### Provided Controllers 148 | 149 | #### **CasysController** 150 | Handles the standard payment flow, including: 151 | - Loading the payment page (`paymentLoader` route). 152 | - Validating and processing payments (`payment` route). 153 | - Handling success (`paymentOKURL` route) and failure (`paymentFailURL` route) callbacks. 154 | 155 | #### **RecurringPaymentController** 156 | Handles recurring payment requests via the `/recurring-payment` route. Example integration is included for making SOAP calls to the Casys gateway. 157 | 158 | --- 159 | 160 | ## Info 161 | 162 | This package is in an alpha stage and is designed to be flexible for your specific needs. **Suggestions are welcome!** 163 | --------------------------------------------------------------------------------