### Install and Configure Payfast Package Source: https://github.com/zfhassaan/payfast/wiki/Understanding-the-Hosted-Checkout-Process-for-Payfast copy Commands to install the package and publish the configuration file. ```bash composer require zfhassaan/payfast ``` ```bash php artisan vendor:publish --tag=payfast-config ``` -------------------------------- ### Install dependencies Source: https://github.com/zfhassaan/payfast/wiki/Contributing Install project dependencies using Composer. ```bash composer install ``` -------------------------------- ### Listen to PaymentInitiated Event Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Events-and-Listeners.md Example listener for logging payment initiation details. ```php use zfhassaan\Payfast\Events\PaymentInitiated; Event::listen(PaymentInitiated::class, function ($event) { $paymentData = $event->paymentData; $response = $event->response; // Log payment initiation Log::info('Payment initiated', [ 'order' => $paymentData['orderNumber'], 'amount' => $paymentData['transactionAmount'], ]); }); ``` -------------------------------- ### Execute Full Payment Lifecycle Example Source: https://github.com/zfhassaan/payfast/wiki/Models-and-Database Demonstrates creating, updating, and querying a payment record. ```php use zfhassaan\Payfast\Models\ProcessPayment; // Create payment $payment = ProcessPayment::create([ 'uid' => \Str::uuid(), 'orderNo' => 'ORD-12345', 'status' => ProcessPayment::STATUS_PENDING, ]); // Update status $payment->markAsValidated(); // Check status if ($payment->isValidated()) { // Payment is validated } // Find and update $payment = ProcessPayment::where('transaction_id', 'TXN123456')->first(); if ($payment) { $payment->markAsCompleted(); } ``` -------------------------------- ### Install PayFast Package Source: https://github.com/zfhassaan/payfast/wiki/Home copy Use Composer to install the package into your Laravel project. ```bash composer require zfhassaan/payfast ``` -------------------------------- ### Verify Installation Source: https://github.com/zfhassaan/payfast/wiki/Installation-Guide Use tinker or a test route to verify the facade is correctly registered and functional. ```php // In tinker or a test route php artisan tinker // Test facade use zfhassaan\Payfast\Facades\PayFast; PayFast::getToken(); ``` -------------------------------- ### Command Output Example Source: https://github.com/zfhassaan/payfast/wiki/Console-Commands Sample console output showing the processing status of individual payment records. ```text Processing 5 payment(s)... Checking payment: ORD-12345 (Status: validated) ✓ Payment ORD-12345 completed successfully Checking payment: ORD-12346 (Status: validated) ✗ Payment ORD-12346 verification failed: Transaction not found ... Processing complete! Completed: 3 Processed: 5 Failed: 2 ``` -------------------------------- ### Controller IPN Implementation Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/API-Reference.md Example of manual IPN handling within a controller. ```php // In your controller public function handleIPN(Request $request) { $ipnData = $request->all(); $response = PayFast::handleIPN($ipnData); return $response; } ``` -------------------------------- ### Load Migrations in TestCase Source: https://github.com/zfhassaan/payfast/blob/main/TESTING.md Use this in the setUp method to ensure database migrations are loaded during testing. ```php $this->loadMigrationsFrom(__DIR__ . '/../../../packages/zfhassaan/payfast/src/database/migrations'); ``` -------------------------------- ### Implement Payment Controller Source: https://github.com/zfhassaan/payfast/blob/main/PAYMENT_FLOW.md A Laravel controller example demonstrating how to initiate payments, verify OTPs, and handle transaction callbacks using the PayFast facade. ```php $request->order_number, 'transactionAmount' => $request->amount, 'customerMobileNo' => $request->mobile, 'customer_email' => $request->email, 'cardNumber' => $request->card_number, 'expiry_month' => $request->expiry_month, 'expiry_year' => $request->expiry_year, 'cvv' => $request->cvv, ]; $response = PayFast::getOTPScreen($paymentData); $result = json_decode($response->getContent(), true); if ($result['status']) { return redirect('/otp-screen')->with([ 'transaction_id' => $result['data']['transaction_id'], 'payment_id' => $result['data']['payment_id'], ]); } return back()->withErrors(['payment' => $result['message']]); } public function verifyOTP(Request $request) { $response = PayFast::verifyOTPAndStorePares( $request->transaction_id, $request->otp, $request->pares ); $result = json_decode($response->getContent(), true); if ($result['status']) { return response()->json([ 'message' => 'OTP verified. Waiting for payment confirmation...', 'pares' => $request->pares, ]); } return response()->json($result, 400); } public function handleCallback(Request $request) { $response = PayFast::completeTransactionFromPares($request->pares); $result = json_decode($response->getContent(), true); if ($result['status']) { $payment = ProcessPayment::where('data_3ds_pares', $request->pares)->first(); // Update your order // Send confirmation email // etc. return response()->json([ 'status' => 'success', 'transaction_id' => $payment->transaction_id, ]); } return response()->json($result, 400); } } ``` -------------------------------- ### Configure test environment Source: https://github.com/zfhassaan/payfast/wiki/Testing-Guide Set the necessary Payfast configuration values within the TestCase setup method. ```php config([ 'payfast.api_url' => 'https://api.payfast.test', 'payfast.merchant_id' => 'test_merchant_id', 'payfast.secured_key' => 'test_secured_key', 'payfast.mode' => 'sandbox', ]); ``` -------------------------------- ### Configuring Test Environment Source: https://github.com/zfhassaan/payfast/blob/main/TESTING.md Set package configuration values within the TestCase setup method. ```php config([ 'payfast.api_url' => 'https://api.payfast.test', 'payfast.merchant_id' => 'test_merchant_id', // ... ]); ``` -------------------------------- ### Install PHP cURL Extension Source: https://github.com/zfhassaan/payfast/wiki/Installation-Guide Commands to install the required cURL extension for different operating systems. ```bash # Ubuntu/Debian sudo apt-get install php-curl # macOS (Homebrew) brew install php-curl # Windows (XAMPP/WAMP) # Enable extension=curl in php.ini ``` -------------------------------- ### Implement Custom Console Command Source: https://github.com/zfhassaan/payfast/wiki/Console-Commands Example of a custom command class that checks payment statuses and updates records using the PayFast facade. ```php option('status') ?? 'validated'; $payments = ProcessPayment::where('status', $status) ->limit(10) ->get(); foreach ($payments as $payment) { $response = PayFast::getTransactionDetails($payment->transaction_id); $result = json_decode($response->getContent(), true); if ($result['status']) { $payment->markAsCompleted(); $this->info("Payment {$payment->orderNo} completed"); } } } } ``` -------------------------------- ### Listen to PaymentCompleted Event Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Events-and-Listeners.md Example listener for updating order status and sending confirmation emails. ```php use zfhassaan\Payfast\Events\PaymentCompleted; Event::listen(PaymentCompleted::class, function ($event) { $paymentData = $event->paymentData; $response = $event->response; // Update order status $order = Order::where('order_number', $paymentData['orderNumber'])->first(); if ($order) { $order->update(['status' => 'paid']); } // Send confirmation email Mail::to($paymentData['customer_email'])->send(new PaymentConfirmationMail($order)); }); ``` -------------------------------- ### Process Card Payment Source: https://github.com/zfhassaan/payfast/blob/main/docs/index.html Example of retrieving an authentication token and initiating a card payment request using the PayFast facade. ```php use zfhassaan\Payfast\Facades\PayFast; // Get authentication token $response = PayFast::getToken(); // Process card payment $paymentData = [ 'orderNumber' => 'ORD-12345', 'transactionAmount' => 1000.00, 'customerMobileNo' => '03001234567', 'customer_email' => 'customer@example.com', 'cardNumber' => '4111111111111111', 'expiry_month' => '12', 'expiry_year' => '2025', 'cvv' => '123', ]; $response = PayFast::getOTPScreen($paymentData); ``` -------------------------------- ### Conventional Commit Message Examples Source: https://github.com/zfhassaan/payfast/wiki/Contributing Examples of commit messages following the conventional commits specification. ```text feat: Add new payment method fix: Fix token refresh issue docs: Update installation guide test: Add tests for new feature refactor: Refactor payment service chore: Update dependencies ``` -------------------------------- ### Initiate Transaction Directly Source: https://github.com/zfhassaan/payfast/wiki/API-Reference Start a transaction directly without going through the OTP flow. ```php $response = PayFast::initiateTransaction($data); ``` ```php $data = [ 'orderNumber' => 'ORD-12345', 'transactionAmount' => 1000.00, // ... other payment data ]; ``` ```php $response = PayFast::initiateTransaction($paymentData); $result = json_decode($response, true); ``` -------------------------------- ### Listen to PaymentFailed Event Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Events-and-Listeners.md Example listener for logging errors and notifying administrators. ```php use zfhassaan\Payfast\Events\PaymentFailed; Event::listen(PaymentFailed::class, function ($event) { $paymentData = $event->paymentData; $errorCode = $event->errorCode; $errorMessage = $event->errorMessage; // Log failure Log::error('Payment failed', [ 'order' => $paymentData['orderNumber'], 'error_code' => $errorCode, 'error_message' => $errorMessage, ]); // Notify admin Mail::to(config('payfast.admin_emails'))->send(new PaymentFailureMail($paymentData, $errorMessage)); }); ``` -------------------------------- ### Listen to TokenRefreshed Event Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Events-and-Listeners.md Example listener for updating the cached authentication token. ```php use zfhassaan\Payfast\Events\TokenRefreshed; Event::listen(TokenRefreshed::class, function ($event) { $oldToken = $event->oldToken; $newToken = $event->newToken; // Update token in cache or database Cache::put('payfast_token', $newToken, 3600); }); ``` -------------------------------- ### Mocking HTTP Client Service Source: https://github.com/zfhassaan/payfast/wiki/Testing-Guide Example of mocking an HTTP client interface and binding the mock instance into the application container. ```php use zfhassaan\Payfast\Services\Contracts\HttpClientInterface; $httpClient = Mockery::mock(HttpClientInterface::class); $httpClient->shouldReceive('post') ->once() ->andReturn(['code' => '00', 'token' => 'test_token']); $this->app->instance(HttpClientInterface::class, $httpClient); ``` -------------------------------- ### Handle EasyPaisa Response Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/API-Reference.md Example of decoding the JSON response from an EasyPaisa payment request. ```php $response = PayFast::payWithEasyPaisa($paymentData); $result = json_decode($response, true); ``` -------------------------------- ### PayFast Command Usage Examples Source: https://github.com/zfhassaan/payfast/wiki/Console-Commands Various ways to invoke the check-pending-payments command using status filters, limits, and notification toggles. ```bash # Check all pending and validated payments php artisan payfast:check-pending-payments # Check specific status php artisan payfast:check-pending-payments --status=otp_verified # Limit results php artisan payfast:check-pending-payments --limit=10 # Skip email notifications php artisan payfast:check-pending-payments --no-email # Combine options php artisan payfast:check-pending-payments --status=validated --limit=20 --no-email ``` -------------------------------- ### Define PayFast Routes Source: https://github.com/zfhassaan/payfast/wiki/Getting-Started Register the necessary POST and GET routes in your Laravel web.php file to handle payment initiation, OTP verification, callbacks, and status checks. ```php Route::post('/payment/initiate', [PaymentController::class, 'initiatePayment']); Route::post('/payment/verify-otp', [PaymentController::class, 'verifyOTP']); Route::post('/payment/callback', [PaymentController::class, 'handleCallback']); Route::get('/payment/status/{transactionId}', [PaymentController::class, 'checkStatus']); ``` -------------------------------- ### Initialize PayFast Migrations Source: https://github.com/zfhassaan/payfast/blob/main/FINAL_IMPLEMENTATION.md Commands to publish and run the necessary database migrations for the package. ```bash php artisan vendor:publish --tag=payfast-migrations php artisan migrate ``` -------------------------------- ### GET /payment/status/{transactionId} Source: https://github.com/zfhassaan/payfast/wiki/Getting-Started Checks the status of a specific transaction. ```APIDOC ## GET /payment/status/{transactionId} ### Description Retrieves the status of a transaction by its ID. ### Method GET ### Endpoint /payment/status/{transactionId} ### Parameters #### Path Parameters - **transactionId** (string) - Required - The unique identifier of the transaction. ``` -------------------------------- ### Publish Configuration and Migrations Source: https://github.com/zfhassaan/payfast/wiki/Understanding-the-Direct-Checkout-Process copy Publish the necessary configuration files and database migrations for the package. ```bash php artisan vendor:publish --tag=payfast-config php artisan vendor:publish --tag=payfast-migrations php artisan migrate ``` -------------------------------- ### IPN Data Structure Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/API-Reference.md Example array structure for IPN notification data. ```php $ipnData = [ 'transaction_id' => 'TXN123456', 'order_no' => 'ORD-12345', 'status' => '00', 'amount' => '1000.00', 'currency' => 'PKR', ]; ``` -------------------------------- ### Migrate PayFast Initialization Source: https://github.com/zfhassaan/payfast/blob/main/REFACTORING_SUMMARY.md Update legacy instantiation to use the service container or facade pattern. ```php $payfast = new PayFast(); $result = $payfast->GetToken(); ``` ```php $payfast = app('payfast'); // or use facade $result = $payfast->getToken(); ``` -------------------------------- ### View Project File Structure Source: https://github.com/zfhassaan/payfast/blob/main/REFACTORING_SUMMARY.md Overview of the refactored directory layout for the PayFast package. ```text src/ ├── DTOs/ │ └── PaymentRequestDTO.php ├── Events/ │ ├── PaymentCompleted.php │ ├── PaymentFailed.php │ ├── PaymentInitiated.php │ ├── PaymentValidated.php │ └── TokenRefreshed.php ├── Listeners/ │ ├── LogPaymentActivity.php │ └── StorePaymentRecord.php ├── Repositories/ │ ├── Contracts/ │ │ └── ProcessPaymentRepositoryInterface.php │ └── ProcessPaymentRepository.php ├── Services/ │ ├── Contracts/ │ │ ├── AuthenticationServiceInterface.php │ │ ├── HttpClientInterface.php │ │ ├── PaymentServiceInterface.php │ │ └── TransactionServiceInterface.php │ ├── AuthenticationService.php │ ├── ConfigService.php │ ├── HttpClientService.php │ ├── PaymentService.php │ └── TransactionService.php ├── Helpers/ │ └── Utility.php (refactored) ├── Interfaces/ │ └── PaymentInterface.php (updated) ├── Models/ │ └── ProcessPayment.php (updated) ├── Facade/ │ └── Payfast.php (updated) ├── Provider/ │ └── PayFastServiceProvider.php (refactored) └── PayFast.php (completely refactored) ``` -------------------------------- ### Listen to PaymentValidated Event Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Events-and-Listeners.md Example listener for sending a validation notification email. ```php use zfhassaan\Payfast\Events\PaymentValidated; Event::listen(PaymentValidated::class, function ($event) { $paymentData = $event->paymentData; $response = $event->validationResponse; // Send validation notification Mail::to($paymentData['customer_email'])->send(new PaymentValidatedMail($paymentData)); }); ``` -------------------------------- ### Publish Command for Customization Source: https://github.com/zfhassaan/payfast/wiki/Console-Commands Execute this command to publish the package's console command file to the local application directory. ```bash php artisan vendor:publish --tag=payfast-command ``` -------------------------------- ### Set Up Merchant Data Source: https://github.com/zfhassaan/payfast/wiki/Understanding-the-Hosted-Checkout-Process-for-Payfast copy Retrieving merchant credentials from the configuration file. ```php $merchant_id = config('payfast.merchant_id'); $secured_key = config('payfast.secured_key'); $merchant_name = 'Your Merchant Name'; // Your registered merchant name ``` -------------------------------- ### Get Authentication Token Source: https://github.com/zfhassaan/payfast/wiki/API-Reference Retrieves the current authentication token as a string or null. ```php $token = PayFast::getAuthToken(); ``` -------------------------------- ### Configure PayFast Environment Variables Source: https://github.com/zfhassaan/payfast/blob/main/README.md Add these keys to your .env file to authenticate and configure the PayFast gateway. ```text PAYFAST_API_URL= PAYFAST_SANDBOX_URL= PAYFAST_GRANT_TYPE= PAYFAST_MERCHANT_ID= PAYFAST_MODE= PAYFAST_SECURED_KEY= PAYFAST_RETURN_URL= ``` -------------------------------- ### Using ProcessPaymentRepository Source: https://github.com/zfhassaan/payfast/wiki/Models-and-Database Demonstrates creating, finding, and updating payment records via the repository interface. ```php use zfhassaan\Payfast\Repositories\Contracts\ProcessPaymentRepositoryInterface; $repository = app(ProcessPaymentRepositoryInterface::class); // Create payment $payment = $repository->create([ 'orderNo' => 'ORD-12345', 'status' => 'validated', ]); // Find by transaction ID $payment = $repository->findByTransactionId('TXN123456'); // Find by basket ID $payment = $repository->findByBasketId('ORD-12345'); // Update payment $repository->update($payment->id, [ 'status' => 'completed', ]); ``` -------------------------------- ### Example IPN Data Structure Source: https://github.com/zfhassaan/payfast/wiki/IPN-Handling The expected format of the data payload received from PayFast. ```php [ 'transaction_id' => 'TXN123456', 'order_no' => 'ORD-12345', 'status' => '00', 'amount' => '1000.00', 'currency' => 'PKR', ] ``` -------------------------------- ### Run tests Source: https://github.com/zfhassaan/payfast/wiki/Contributing Execute the test suite using Artisan. ```bash php artisan test ``` -------------------------------- ### Run PayFast Tests Source: https://github.com/zfhassaan/payfast/blob/main/IMPLEMENTATION_COMPLETE.md Commands to execute the test suite from either the package directory or the project root. ```bash # Run tests from package directory cd packages/zfhassaan/payfast composer install ./vendor/bin/phpunit # Or from root php artisan test --filter PayFast ``` -------------------------------- ### Clone the repository Source: https://github.com/zfhassaan/payfast/wiki/Contributing Commands to clone the PayFast repository and navigate into the project directory. ```bash git clone https://github.com/zfhassaan/payfast.git cd payfast ``` -------------------------------- ### Get OTP Screen for Card Payments Source: https://github.com/zfhassaan/payfast/wiki/API-Reference Validate customer details and retrieve the OTP screen for card payments. ```php $response = PayFast::getOTPScreen($paymentData); ``` ```php $paymentData = [ 'orderNumber' => 'ORD-12345', // Required 'transactionAmount' => 1000.00, // Required 'customerMobileNo' => '03001234567', // Required 'customer_email' => 'customer@example.com', // Required 'cardNumber' => '4111111111111111', // Required 'expiry_month' => '12', // Required 'expiry_year' => '2025', // Required 'cvv' => '123', // Required ]; ``` ```json { "status": true, "data": { "token": "abc123...", "customer_validate": {...}, "transaction_id": "TXN123456", "payment_id": 1, "redirect_url": "https://..." }, "message": "OTP screen retrieved successfully", "code": "00" } ``` ```php $paymentData = [ 'orderNumber' => 'ORD-12345', 'transactionAmount' => 1000.00, 'customerMobileNo' => '03001234567', 'customer_email' => 'customer@example.com', 'cardNumber' => '4111111111111111', 'expiry_month' => '12', 'expiry_year' => '2025', 'cvv' => '123', ]; $response = PayFast::getOTPScreen($paymentData); ``` -------------------------------- ### Publish Configuration File Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Command to generate the configuration file in the config directory. ```bash php artisan vendor:publish --tag=payfast-config ``` -------------------------------- ### Importing the PayFast Facade Source: https://github.com/zfhassaan/payfast/wiki/Getting-Started Use the Facade to access PayFast functionality within your application. ```php use zfhassaan\Payfast\Facades\PayFast; ``` -------------------------------- ### Publish Package Resources Source: https://github.com/zfhassaan/payfast/blob/main/IMPLEMENTATION_COMPLETE.md Use artisan commands to publish configuration, migrations, email templates, and console commands to your application. ```bash php artisan vendor:publish --tag=payfast-config ``` ```bash php artisan vendor:publish --tag=payfast-migrations php artisan migrate ``` ```bash php artisan vendor:publish --tag=payfast-email-templates ``` ```bash php artisan vendor:publish --tag=payfast-command ``` -------------------------------- ### PSR-12 Compliant Class Structure Source: https://github.com/zfhassaan/payfast/wiki/Contributing Example of a class following PSR-12 standards, including strict types, namespace declaration, and DocBlocks. ```php */ public function myMethod(string $param): array { // Implementation } } ``` -------------------------------- ### Test PayFast Configuration Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Verify that the package is correctly configured by attempting to retrieve a token. ```php use zfhassaan\Payfast\Facades\PayFast; // This will use your configuration $response = PayFast::getToken(); if ($response->getStatusCode() === 200) { // Configuration is correct } ``` -------------------------------- ### Run Database Migrations Source: https://github.com/zfhassaan/payfast/blob/main/IMPLEMENTATION_SUMMARY.md Command to apply the new database schema changes for status tracking and payment processing. ```bash php artisan migrate ``` -------------------------------- ### PaymentInitiated Event Data and Listener Source: https://github.com/zfhassaan/payfast/wiki/Events-and-Listeners Defines the structure of the PaymentInitiated event data and demonstrates how to listen for it to log payment initiation. ```php [ 'paymentData' => [...], // Payment request data 'response' => [...], // API response ] ``` ```php use zfhassaan\Payfast\Events\PaymentInitiated; Event::listen(PaymentInitiated::class, function ($event) { $paymentData = $event->paymentData; $response = $event->response; // Log payment initiation Log::info('Payment initiated', [ 'order' => $paymentData['orderNumber'], 'amount' => $paymentData['transactionAmount'], ]); }); ``` -------------------------------- ### Initiate Payment with PayFast Source: https://github.com/zfhassaan/payfast/blob/main/IMPLEMENTATION_SUMMARY.md Initiates a payment request by passing customer and card details to the getOTPScreen method. ```php $response = PayFast::getOTPScreen([ 'orderNumber' => 'ORD-123', 'transactionAmount' => 1000, 'customerMobileNo' => '03001234567', 'customer_email' => 'customer@example.com', 'cardNumber' => '4111111111111111', 'expiry_month' => '12', 'expiry_year' => '2025', 'cvv' => '123', ]); ``` -------------------------------- ### Using ActivityLogRepository Source: https://github.com/zfhassaan/payfast/wiki/Models-and-Database Creates a new activity log entry using the repository interface. ```php use zfhassaan\Payfast\Repositories\Contracts\ActivityLogRepositoryInterface; $repository = app(ActivityLogRepositoryInterface::class); // Create log $repository->create([ 'transaction_id' => 'TXN123456', 'status' => 'completed', ]); ``` -------------------------------- ### Interact with ActivityLog Model Source: https://github.com/zfhassaan/payfast/wiki/Models-and-Database Demonstrates creating log entries and querying logs by transaction or order identifiers. ```php use zfhassaan\Payfast\Models\ActivityLog; // Create activity log ActivityLog::create([ 'user_id' => 1, 'transaction_id' => 'TXN123456', 'order_no' => 'ORD-12345', 'status' => 'completed', 'amount' => 1000.00, 'details' => json_encode(['message' => 'Payment completed']), ]); // Find by transaction ID $logs = ActivityLog::where('transaction_id', 'TXN123456')->get(); // Find by order number $logs = ActivityLog::where('order_no', 'ORD-12345')->get(); ``` -------------------------------- ### Publish PayFast test files Source: https://github.com/zfhassaan/payfast/wiki/Testing-Guide Executes the artisan command to copy test files into the local tests directory. ```bash php artisan vendor:publish --tag=payfast-tests ``` -------------------------------- ### Register PayFast Facade Alias Source: https://github.com/zfhassaan/payfast/blob/main/README.md Add the Payfast facade to your aliases array in the configuration file. ```php 'aliases' => Facade::defaultAliases()->merge([ 'Payfast' => \zfhassaan\Payfast\Facade\Payfast::class, ])->toArray(), ``` -------------------------------- ### Wallet Initiation Response Format Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/API-Reference.md Expected JSON structure returned after initiating a wallet transaction. ```json { "code": "00", "message": "Wallet transaction initiated", "transaction_id": "TXN123456" } ``` -------------------------------- ### Configure PayFast Environment Mode Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Set the PAYFAST_MODE variable to toggle between sandbox and production environments. ```env PAYFAST_MODE=sandbox ``` ```env PAYFAST_MODE=production ``` -------------------------------- ### Configuration File Structure Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide The PHP array structure used to map environment variables to package settings. ```php return [ // API Configuration 'api_url' => env('PAYFAST_API_URL', ''), 'sandbox_api_url' => env('PAYFAST_SANDBOX_URL', ''), // Authentication 'grant_type' => env('PAYFAST_GRANT_TYPE', ''), 'merchant_id' => env('PAYFAST_MERCHANT_ID', ''), 'secured_key' => env('PAYFAST_SECURED_KEY', ''), // Application Settings 'store_id' => env('PAYFAST_STORE_ID', ''), 'return_url' => env('PAYFAST_RETURN_URL', ''), 'mode' => env('PAYFAST_MODE', 'sandbox'), 'transaction_check' => env('PAYFAST_VERIFY_TRANSACTION', ''), // Email Configuration 'admin_emails' => env('PAYFAST_ADMIN_EMAILS', ''), 'email_templates' => [ 'status_notification' => 'payfast::emails.status-notification', 'payment_completion' => 'payfast::emails.payment-completion', 'admin_notification' => 'payfast::emails.admin-notification', 'payment_failure' => 'payfast::emails.payment-failure', ], 'email_subjects' => [ 'payment_completion' => env('PAYFAST_EMAIL_SUBJECT_COMPLETION', 'Payment Completed Successfully'), 'admin_notification' => env('PAYFAST_EMAIL_SUBJECT_ADMIN', 'New Payment Completed'), 'payment_failure' => env('PAYFAST_EMAIL_SUBJECT_FAILURE', 'Payment Failed'), ], ]; ``` -------------------------------- ### Monitor Application Logs Source: https://github.com/zfhassaan/payfast/wiki/Troubleshooting Use tail to monitor Laravel and PayFast specific log files in real-time. ```bash # Laravel logs tail -f storage/logs/laravel.log # PayFast specific logs tail -f storage/logs/Payfast/*.log ``` -------------------------------- ### POST /payment/initiate Source: https://github.com/zfhassaan/payfast/wiki/Getting-Started Initiates a new payment process. ```APIDOC ## POST /payment/initiate ### Description Initiates a payment transaction. ### Method POST ### Endpoint /payment/initiate ``` -------------------------------- ### Configuration File Structure Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/Configuration-Guide.md The internal structure of the config/payfast.php file, which maps environment variables to package settings. ```php return [ // API Configuration 'api_url' => env('PAYFAST_API_URL', ''), 'sandbox_api_url' => env('PAYFAST_SANDBOX_URL', ''), // Authentication 'grant_type' => env('PAYFAST_GRANT_TYPE', ''), 'merchant_id' => env('PAYFAST_MERCHANT_ID', ''), 'secured_key' => env('PAYFAST_SECURED_KEY', ''), // Application Settings 'store_id' => env('PAYFAST_STORE_ID', ''), 'return_url' => env('PAYFAST_RETURN_URL', ''), 'checkout_url' => env('PAYFAST_CHECKOUT_URL', ''), 'mode' => env('PAYFAST_MODE', 'sandbox'), 'transaction_check' => env('PAYFAST_VERIFY_TRANSACTION', ''), // Email Configuration 'admin_emails' => env('PAYFAST_ADMIN_EMAILS', ''), 'email_templates' => [ 'status_notification' => 'payfast::emails.status-notification', 'payment_completion' => 'payfast::emails.payment-completion', 'admin_notification' => 'payfast::emails.admin-notification', 'payment_failure' => 'payfast::emails.payment-failure', ], 'email_subjects' => [ 'payment_completion' => env('PAYFAST_EMAIL_SUBJECT_COMPLETION', 'Payment Completed Successfully'), 'admin_notification' => env('PAYFAST_EMAIL_SUBJECT_ADMIN', 'New Payment Completed'), 'payment_failure' => env('PAYFAST_EMAIL_SUBJECT_FAILURE', 'Payment Failed'), ], ]; ``` -------------------------------- ### Implement Payment Controller Source: https://github.com/zfhassaan/payfast/wiki/Understanding-the-Hosted-Checkout-Process-for-Payfast copy A complete controller implementation for handling hosted checkout initiation, success callbacks, and failure scenarios. ```php validate([ 'order_id' => 'required|string', 'amount' => 'required|numeric|min:0.01', 'mobile' => 'required|string', 'email' => 'required|email', ]); // Get merchant data $merchant_id = config('payfast.merchant_id'); $secured_key = config('payfast.secured_key'); $merchant_name = 'Your Merchant Name'; // Customer data $order_id = $request->order_id; $amount = $request->amount; $mobile = $request->mobile; $email = $request->email; // Get access token $tokenResponse = PayFast::getToken(); $tokenData = json_decode($tokenResponse->getContent(), true); if (!$tokenData['status'] || $tokenData['code'] !== '00') { return back()->withErrors(['payment' => 'Failed to get authentication token']); } $ACCESS_TOKEN = $tokenData['data']['token']; // Create signature $signature = md5($merchant_id . ":" . $merchant_name . ":" . $amount . ":" . $order_id); $backend_callback = "signature=" . $signature . "&order_id=" . $order_id; // Build payload $successUrl = route('payment.success'); $failUrl = route('payment.failure'); $payment_url = config('payfast.mode') === 'production' ? config('payfast.api_url') . '/checkout' : config('payfast.sandbox_api_url') . '/checkout'; $payload = [ 'MERCHANT_ID' => $merchant_id, 'MERCHANT_NAME' => $merchant_name, 'TOKEN' => $ACCESS_TOKEN, 'PROCCODE' => '00', 'TXNAMT' => $amount, 'CUSTOMER_MOBILE_NO' => $mobile, 'CUSTOMER_EMAIL_ADDRESS' => $email, 'SIGNATURE' => $signature, 'VERSION' => 'WOOCOM-APPS-PAYMENT-0.9', 'TXNDESC' => 'Products purchased from ' . $merchant_name, 'SUCCESS_URL' => urlencode($successUrl), 'FAILURE_URL' => urlencode($failUrl), 'BASKET_ID' => $order_id, 'ORDER_DATE' => date('Y-m-d H:i:s', time()), 'CHECKOUT_URL' => urlencode($backend_callback), ]; return view('payment.hosted-checkout', [ 'payment_url' => $payment_url, 'payload' => $payload, ]); } public function handleSuccess(Request $request) { // Verify signature $signature = $request->input('signature'); $order_id = $request->input('order_id'); // Verify the signature matches // Update order status // Send confirmation email // etc. return view('payment.success', [ 'order_id' => $order_id, ]); } public function handleFailure(Request $request) { // Handle payment failure // Log the failure // Notify customer // etc. return view('payment.failure'); } } ``` -------------------------------- ### Implement OTP Verification Route and Controller Source: https://github.com/zfhassaan/payfast/blob/main/PAYMENT_FLOW.md Define the route and controller logic to verify the OTP and store the 3DS pares received from PayFast. ```php // routes/web.php Route::post('/payment/verify-otp', [PaymentController::class, 'verifyOTP']); // app/Http/Controllers/PaymentController.php public function verifyOTP(Request $request) { $request->validate([ 'transaction_id' => 'required|string', 'otp' => 'required|string', 'pares' => 'required|string', // Received from PayFast 3DS ]); $response = PayFast::verifyOTPAndStorePares( $request->transaction_id, $request->otp, $request->pares ); $result = json_decode($response->getContent(), true); if ($result['status']) { // Payment updated with status: 'otp_verified' and pares stored return response()->json([ 'message' => 'OTP verified successfully', 'pares' => $request->pares, ]); } return response()->json($result, 400); } ``` -------------------------------- ### Configure Production Mode Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Configuration-Guide.md Sets the environment to production mode for processing real transactions. ```env PAYFAST_MODE=production ``` -------------------------------- ### Publish Database Migrations Source: https://github.com/zfhassaan/payfast/wiki/Installation-Guide Copies the required database migration files to the application's migration directory. ```bash php artisan vendor:publish --tag=payfast-migrations ``` -------------------------------- ### Initiate Mobile Wallet Transaction Source: https://github.com/zfhassaan/payfast/blob/main/README.md Demonstrates how to initiate a mobile wallet transaction, such as Easy Paisa, using the Payfast package. ```php /** * Mobile Wallet Account Initiate Transaction * This is demo function for Easy Paisa. * */ public function payfast(Request $request) { $payfast = new Payfast(); $response = $payfast->getToken(); if($response != null && $response->code == "00" ){ $payfast->setAuthToken($response->token); } else { abort(403, 'Error: Auth Token Not Generated.'); } $show_otp = $payfast->wallet($request->all()); return $show_otp; } ``` -------------------------------- ### Required Environment Variables Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Essential settings for API connectivity and authentication. ```env # API URLs PAYFAST_API_URL=https://api.payfast.com PAYFAST_SANDBOX_URL=https://sandbox.payfast.com # Authentication PAYFAST_GRANT_TYPE=client_credentials PAYFAST_MERCHANT_ID=your_merchant_id PAYFAST_SECURED_KEY=your_secured_key # Application Settings PAYFAST_RETURN_URL=https://yourdomain.com/payment/callback PAYFAST_MODE=sandbox ``` -------------------------------- ### Manage Credentials via Environment Variables Source: https://github.com/zfhassaan/payfast/wiki/Security-Best-Practices Avoid hardcoding sensitive credentials by utilizing configuration files that pull from environment variables. ```php // Don't hardcode credentials $merchantId = '12345'; $securedKey = 'secret_key'; ``` ```php // Use environment variables $merchantId = config('payfast.merchant_id'); $securedKey = config('payfast.secured_key'); ``` -------------------------------- ### PayFast::walletTransactionInitiate() Source: https://github.com/zfhassaan/payfast/wiki/API-Reference Initiates a wallet transaction after successful validation. ```APIDOC ## PayFast::walletTransactionInitiate($data) ### Description Initiate wallet transaction after validation. ### Parameters - **$data** (array) - Required - Transaction data array. ### Returns - **string|bool** - JSON string or boolean result. ``` -------------------------------- ### Run PayFast Test Suite Commands Source: https://github.com/zfhassaan/payfast/blob/main/TEST_SUMMARY.md Commands to execute the test suite using artisan, including filtering and coverage reporting. ```bash # Run all tests php artisan test # Run PayFast tests only php artisan test --filter PayFast # Run with coverage php artisan test --coverage # Run specific test class php artisan test tests/Unit/PayFast/Services/AuthenticationServiceTest.php ``` -------------------------------- ### Accessing Configuration via Helper Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Retrieve Payfast configuration values directly using the Laravel config helper. ```php $merchantId = config('payfast.merchant_id'); $mode = config('payfast.mode'); $apiUrl = config('payfast.api_url'); ``` -------------------------------- ### Optional Environment Variables Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Additional settings for store identification, transaction verification, and email notifications. ```env # Store Configuration PAYFAST_STORE_ID=your_store_id # Transaction Verification PAYFAST_VERIFY_TRANSACTION=https://api.payfast.com/transaction/view # Email Notifications PAYFAST_ADMIN_EMAILS=admin@example.com,admin2@example.com PAYFAST_EMAIL_SUBJECT_COMPLETION=Payment Completed Successfully PAYFAST_EMAIL_SUBJECT_ADMIN=New Payment Completed PAYFAST_EMAIL_SUBJECT_FAILURE=Payment Failed ``` -------------------------------- ### Enable Debugging Configuration Source: https://github.com/zfhassaan/payfast/wiki/Troubleshooting Update the .env file to enable debug mode and set the logging level. ```env APP_DEBUG=true LOG_LEVEL=debug ``` -------------------------------- ### PayFast::verifyOTPAndStorePares() Source: https://github.com/zfhassaan/payfast/wiki/API-Reference Verifies the OTP provided by the customer and stores the 3DS pares. ```APIDOC ## PayFast::verifyOTPAndStorePares($transactionId, $otp, $pares) ### Description Completes the OTP verification step and stores the 3DS pares for the transaction. ### Parameters - **$transactionId** (string) - Transaction ID from getOTPScreen - **$otp** (string) - OTP entered by customer - **$pares** (string) - 3DS pares from PayFast ### Returns - **JsonResponse** ``` -------------------------------- ### Configuration Validation Requirements Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide List of required configuration keys that must be present to avoid initialization exceptions. ```php // Required values - api_url or sandbox_api_url (based on mode) - merchant_id - secured_key - grant_type - return_url ``` -------------------------------- ### Migrate Payfast Service Usage Source: https://github.com/zfhassaan/payfast/blob/main/ARCHITECTURE.md Compare the deprecated legacy instantiation with the new service-based approach. ```php $payfast = new PayFast(); $payfast->GetToken(); ``` ```php $payfast = app('payfast'); $payfast->getToken(); ``` -------------------------------- ### Configure Sandbox Mode Source: https://github.com/zfhassaan/payfast/blob/main/wiki/Configuration-Guide.md Sets the environment to sandbox mode for testing purposes. ```env PAYFAST_MODE=sandbox ``` -------------------------------- ### Mocking Dependencies with Mockery Source: https://github.com/zfhassaan/payfast/blob/main/TESTING.md Use Mockery to define expectations and return values for service dependencies. ```php $mock = Mockery::mock(ServiceInterface::class); $mock->shouldReceive('method') ->once() ->andReturn(['result' => 'data']); ``` -------------------------------- ### Create a Subscription in PHP Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/Subscriptions.md Use the createSubscription method to initiate a recurring payment plan. Ensure all required customer and order details are provided in the data array. ```php use zfhassaan\Payfast\Facades\PayFast; $subscriptionData = [ 'orderNumber' => 'SUB-1001', // Unique order identifier 'transactionAmount' => 500.00, // Amount to charge per cycle 'customer_email' => 'user@example.com', 'customerMobileNo' => '03001234567', 'planId' => 'PREMIUM_MONTHLY', // Unique identifier for the plan 'frequency' => 'monthly', // Optional: daily, weekly, monthly, yearly 'iterations' => 12, // Optional: Number of recurring cycles ]; $response = PayFast::createSubscription($subscriptionData); ``` -------------------------------- ### Environment Configuration Variables Source: https://github.com/zfhassaan/payfast/wiki/Configuration-Guide Define environment-specific variables in your .env file for different deployment stages. ```env PAYFAST_MODE=sandbox PAYFAST_API_URL=https://sandbox.payfast.com PAYFAST_SANDBOX_URL=https://sandbox.payfast.com ``` ```env PAYFAST_MODE=sandbox PAYFAST_API_URL=https://staging.payfast.com PAYFAST_SANDBOX_URL=https://staging.payfast.com ``` ```env PAYFAST_MODE=production PAYFAST_API_URL=https://api.payfast.com PAYFAST_SANDBOX_URL=https://sandbox.payfast.com ``` -------------------------------- ### PayFast Package Directory Structure Source: https://github.com/zfhassaan/payfast/blob/main/FINAL_IMPLEMENTATION.md Visual representation of the package file hierarchy, including source code, database migrations, events, repositories, and configuration files. ```text packages/zfhassaan/payfast/ ├── src/ │ ├── Console/ │ │ ├── CABPayments.php # Enhanced with logging & emails │ │ └── CABPayments.php.stub # Publishable │ ├── database/ │ │ ├── migrations/ # All migrations │ │ └── factories/ # Model factories │ ├── Events/ # Payment events │ ├── Listeners/ │ │ ├── LogPaymentActivity.php # Audit logging │ │ ├── SendPaymentEmailNotifications.php # Email notifications │ │ └── StorePaymentRecord.php │ ├── Models/ │ │ ├── ProcessPayment.php │ │ ├── ActivityLog.php # NEW │ │ └── IPNLog.php # NEW │ ├── Repositories/ │ │ ├── Contracts/ # Interfaces (DIP) │ │ │ ├── ProcessPaymentRepositoryInterface.php │ │ │ ├── ActivityLogRepositoryInterface.php # NEW │ │ │ └── IPNLogRepositoryInterface.php # NEW │ │ ├── ProcessPaymentRepository.php │ │ ├── ActivityLogRepository.php # NEW │ │ └── IPNLogRepository.php # NEW │ ├── Services/ │ │ ├── Contracts/ # Interfaces (DIP) │ │ │ └── EmailNotificationServiceInterface.php # NEW │ │ └── EmailNotificationService.php # NEW │ ├── resources/ │ │ └── views/ │ │ └── emails/ # Publishable templates │ │ ├── status-notification.blade.php │ │ ├── payment-completion.blade.php │ │ ├── admin-notification.blade.php │ │ └── payment-failure.blade.php │ └── Provider/ │ └── PayFastServiceProvider.php # Updated ├── tests/ # Moved here │ ├── Unit/ │ │ └── [All unit tests] │ ├── Feature/ │ │ └── [All feature tests] │ └── TestCase.php ├── config/ │ └── config.php # Updated with email config ├── phpunit.xml # NEW └── composer.json # Updated ``` -------------------------------- ### Interact with IPNLog Model Source: https://github.com/zfhassaan/payfast/wiki/Models-and-Database Demonstrates creating IPN records and querying them based on processing status or transaction identifiers. ```php use zfhassaan\Payfast\Models\IPNLog; // Create IPN log IPNLog::create([ 'transaction_id' => 'TXN123456', 'order_no' => 'ORD-12345', 'status' => '00', 'amount' => 1000.00, 'currency' => 'PKR', 'ipn_data' => json_encode($ipnData), 'processed' => true, ]); // Find unprocessed IPNs $unprocessed = IPNLog::where('processed', false)->get(); // Find by transaction ID $log = IPNLog::where('transaction_id', 'TXN123456')->first(); ``` -------------------------------- ### Implement IPN Service in Controller Source: https://github.com/zfhassaan/payfast/blob/main/RELEASE_NOTES_v1.0.4.md Use the Payfast facade to handle incoming IPN requests within your controller. ```php // Add to your controller public function handleIPN(Request $request) { return Payfast::handleIPN($request->all()); } ``` -------------------------------- ### Publish Package Assets Source: https://github.com/zfhassaan/payfast/wiki/Installation-Guide Commands to publish optional email templates, console commands, or test suites. ```bash php artisan vendor:publish --tag=payfast-email-templates ``` ```bash php artisan vendor:publish --tag=payfast-command ``` ```bash php artisan vendor:publish --tag=payfast-tests ``` -------------------------------- ### Create unit test for service method Source: https://github.com/zfhassaan/payfast/blob/main/docs/content/Contributing.md Standard structure for unit tests using the project's base TestCase, following the Arrange-Act-Assert pattern. ```php myMethod('input'); // Assert $this->assertNotNull($result); } } ``` -------------------------------- ### Test IPN Endpoint with cURL Source: https://github.com/zfhassaan/payfast/blob/main/IPN_USAGE.md Simulate a PayFast IPN request using the command line. ```bash # Using curl curl -X POST https://yourdomain.com/payment/ipn \ -H "Content-Type: application/json" \ -d '{ "transaction_id": "TXN123456", "order_no": "ORD-12345", "status": "00", "amount": "1000.00", "currency": "PKR" }' ``` -------------------------------- ### Implement Payfast Checkout Flow Source: https://github.com/zfhassaan/payfast/blob/main/README.md Handles the initial checkout process by generating an authentication token and validating the customer. ```php use zfhassaan\Payfast\Payfast; ... ... /** * Validate Customer and get OTP Screen. * Step 1 */ public function checkout(Request $request) { $payfast = new Payfast(); $response = $payfast->getToken(); if($response != null && $response->code == "00" ){ $payfast->setAuthToken($response->token); } else { abort(403, 'Error: Auth Token Not Generated.'); } $show_otp = $payfast->customer_validate($request->all()); return $show_otp; } ``` -------------------------------- ### Set Authentication Credentials Source: https://github.com/zfhassaan/payfast/wiki/Console-Commands Define your merchant credentials in the .env file to fix authentication failures. ```env PAYFAST_MERCHANT_ID=your_merchant_id PAYFAST_SECURED_KEY=your_secured_key ```