# Payment providers

You can add your own payment provider by providing an implementation of a PaymentProvider class.

# Implement a PaymentProvider

To implement a PaymentProvider simply extend the abstract OFFLINE\Mall\Classes\Payments\PaymentProvider class and implement all missing methods.

You can place your custom PaymentProvider inside the classes directory of your plugin:

plugins/yourname/yourplugin/classes/ExampleProvider.php

# PaymentResult

The process method receives an instance of a PaymentResult. You can call one of the three methods success, redirect and fail on it. This will automatically log the payment attempt and update the order.

Check out the payment providers that are shipped with the plugin (opens new window) for more information on how to use these methods.

# Example implementation

<?php
namespace YourName\YourPlugin\Classes;

use OFFLINE\Mall\Models\PaymentGatewaySettings;
use OFFLINE\Mall\Classes\Payments\PaymentResult;

class ExampleProvider extends \OFFLINE\Mall\Classes\Payments\PaymentProvider
{
   /**
    * The order that is being paid.
    *
    * @var \OFFLINE\Mall\Models\Order
    */
   public $order;
   /**
    * Data that is needed for the payment.
    * Card numbers, tokens, etc. 
    *
    * @var array
    */
   public $data;

   /**
    * Return the display name of your payment provider.
    *
    * @return string
    */
   public function name(): string
   {
       return 'Example provider';
   }

   /**
    * Return a unique identifier for this payment provider.
    *
    * @return string
    */
   public function identifier(): string
   {
       return 'example-provider';
   }

   /**
    * Validate the given input data for this payment.
    *
    * @return bool
    * @throws \October\Rain\Exception\ValidationException
    */
   public function validate(): bool
   {
       $rules = [
           'card_number' => 'required|size:16',
       ];

       $validation = \Validator::make($this->data, $rules);
       if ($validation->fails()) {
           throw new \October\Rain\Exception\ValidationException($validation);
       }

       return true;
   }
   
   /**
    * Return any custom backend settings fields.
    * 
    * These fields will be rendered in the backend
    * settings page of your provider. 
    *
    * @return array
    */
   public function settings(): array
   {
       return [
           'api_key'     => [
               'label'   => 'API-Key',
               'comment' => 'The API Key for the payment service',
               'span'    => 'left',
               'type'    => 'text',
           ],
       ];
   }
   
   /**
    * Setting keys returned from this method are stored encrypted.
    *
    * Use this to store API tokens and other secret data
    * that is needed for this PaymentProvider to work.
    *
    * @return array
    */
   public function encryptedSettings(): array
   {
       return ['api_key'];
   }

   /**
    * Process the payment.
    *
    * @param PaymentResult $result
    *
    * @return PaymentResult
    */
   public function process(PaymentResult $result): PaymentResult
   {
       $gateway = AnyPaymentService::create();
       $gateway->setApiKey(decrypt(PaymentGatewaySettings::get('api_key')));
       
       $response = null;
       try {
           $response = $gateway->purchase([
               'amount'    => $this->order->total_in_currency,
               'currency'  => $this->order->currency['code'],
               'token'     => $this->data['token'],
               'returnUrl' => $this->returnUrl(),
               'cancelUrl' => $this->cancelUrl(),
           ])->send();
       } catch (\Throwable $e) {
           // Something bad happened! Log the payment as failed.
           // There is no response data available so we pass an empty array.
           return $result->fail([], $e);
       }
       
       // Get the payment data from your gateway. 
       $data = (array)$response->getData();
       
       if ( ! $response->isSuccessful()) {
           // The response failed. Pass any payment data and the
           // response itself to the fail method to log this payment attempt.
           return $result->fail($data, $response);
       }
       
       // The payment was successful! You may update the order here.
       // You don't have to save it since the success method will take
       // care of it.
       //
       // $this->order->card_holder_name = $data['card_holder_name'];
       
       // Log the payment as successful.
       return $result->success($data, $response);
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

# Register a PaymentProvider

To register a PaymentProvider with oc-mall simply call the registerProvider method from your own plugin's boot method.

<?php
namespace YourName\YourPlugin;

use YourName\YourPlugin\Classes\ExampleProvider;
use OFFLINE\Mall\Classes\Payments\PaymentGateway;
use System\Classes\PluginBase;

// Your Plugin.php
class Plugin extends PluginBase {

    public function boot()
    {
        $gateway = $this->app->get(PaymentGateway::class);
        $gateway->registerProvider(new ExampleProvider());
    }
    
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17