Mollie   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 49
dl 0
loc 139
rs 10
c 1
b 0
f 0
wmc 18

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
C updatePayment() 0 63 14
A getPaymentUrl() 0 36 3
1
<?php
2
3
namespace App\PaymentProvider;
4
5
use App\Purchase;
6
use App\Exceptions\PaymentProviderException;
7
use App\Mail\TicketsPaid;
8
use Illuminate\Support\Facades\Log;
9
use Illuminate\Support\Facades\Mail;
10
use Mollie\Api\MollieApiClient;
11
12
/**
13
 * Class to process requests to Mollie
14
 * 
15
 * Find docs @ https://github.com/mollie/mollie-api-php
16
 */
17
class Mollie
18
{
19
    /**
20
     * API-Object; initialized by constructor
21
     */
22
    protected $apiClient;
23
24
    /**
25
     * 
26
     * @param string $configKey Configuration key for this exact project
27
     * @return void
28
     */
29
    public function __construct($configKey)
30
    {
31
        $this->apiClient = new MollieApiClient();
32
        $this->apiClient->setApiKey($configKey);
33
    }
34
35
    /**
36
     * Generates for a given Purchase a payment request at Mollie and
37
     * returns a payment url where the customer can pay the purchase
38
     * 
39
     * For more details on the payment-create-process take a look at
40
     * https://github.com/mollie/mollie-api-php/blob/master/examples/payments/create-payment.php
41
     * 
42
     * @param Purchase $purchase the customer's purchase
43
     * @return string PaymentUrl to Mollie for the given purchase
44
     */
45
    public function getPaymentUrl(Purchase $purchase)
46
    {
47
        // Format the purchase's total to have 2 decimals being seperated by a dot and without
48
        // a thousand-seperator. Format = 123456.78
49
        $amountFormatted = number_format($purchase->total(), 2, '.', '');
50
51
        $firstEvent = $purchase->events()->pop();
52
53
        try {
54
            $payment = $this->apiClient->payments->create([
55
                'amount' => [
56
                    'currency' => 'EUR',
57
                    'value'    => $amountFormatted
58
                ],
59
                'locale' => config('paymentprovider.locale'),
60
                'description' => $firstEvent->project->name . ' | ' . $firstEvent->second_name,
61
                'redirectUrl' => route('ticket.purchase', $purchase),
62
                'webhookUrl'  => route('ts.payment.mollie.webhook'),
63
                'metadata' => [
64
                    'purchase_id' => $purchase->id
65
                ]
66
            ]);
67
            
68
            // Store the payment-reference from Mollie to the associated purchase
69
            $purchase->payment_id = $payment->id;
70
            $purchase->save();
71
72
        } catch( \Mollie\Api\Exceptions\ApiException $e ) {
73
            throw new PaymentProviderException( $e );
74
        }
75
76
        // Set a reference to the customer, depending if a user object exists
77
        $customerReference = $purchase->customer ? $purchase->customer->id : $purchase->customer_name;
78
        Log::info('[Purchase#' . $purchase->id . '] Created Payment#' . $payment->id . ' @Mollie and sending customer#' . $customerReference . ' to payment provider');
79
        
80
        return $payment->getCheckoutUrl();
81
    }
82
83
    /**
84
     * This function gets called by the mollie webhook
85
     * 
86
     * For more details on the payment-create-process take a look at
87
     * https://github.com/mollie/mollie-api-php/blob/master/examples/payments/webhook.php
88
     * 
89
     * @param string $paymentId 
90
     * @return void 
91
     * @throws PaymentProviderException 
92
     */
93
    public function updatePayment(string $paymentId)
94
    {
95
        try {
96
            // Retrieve the payment's current state and its associated purchase
97
            $payment = $this->apiClient->payments->get($paymentId);
98
            $purchaseId = $payment->metadata->purchase_id;
99
            $purchase = Purchase::find($purchaseId);
100
101
            if( !$purchase ) {
102
                throw new PaymentProviderException('Payment-Id "' . $paymentId . '" has no matching purchase!');
103
            }
104
105
            if( $payment->isPaid() && !$payment->hasRefunds() && !$payment->hasChargebacks() ) {
106
                /*
107
                * The payment is paid and isn't refunded or charged back.
108
                */
109
                // Only send an email with the tickets on the change of state to "paid"
110
                if($purchase->state != 'paid') {
111
                    Log::info('[Purchase#' . $purchase->id . '] Sending Ticket-Mail.');
112
                    Mail::to($purchase->customer)->send(new TicketsPaid($purchase));
113
                }
114
            } elseif( $payment->isOpen() ) {
115
                /*
116
                * The payment is open.
117
                */
118
            } elseif( $payment->isPending() ) {
119
                /*
120
                * The payment is pending.
121
                */
122
            } elseif( $payment->isFailed() ) {
123
                /*
124
                * The payment has failed.
125
                */
126
                $purchase->deleteWithAllData();
127
            } elseif( $payment->isExpired() ) {
128
                /*
129
                * The payment is expired.
130
                */
131
                $purchase->deleteWithAllData();
132
            } elseif( $payment->isCanceled() ) {
133
                /*
134
                * The payment has been canceled.
135
                */
136
                $purchase->deleteWithAllData();
137
            } elseif( $payment->hasRefunds() ) {
138
                /*
139
                * The payment has been (partially) refunded.
140
                * The status of the payment is still "paid"
141
                */
142
            } elseif( $payment->hasChargebacks() ) {
143
                /*
144
                * The payment has been (partially) charged back.
145
                * The status of the payment is still "paid"
146
                */
147
            }
148
149
            // Update the purchase's state
150
            $purchase->state = $payment->status;
151
            $purchase->state_updated = new \DateTime();
152
            $purchase->save();
153
154
        } catch (\Mollie\Api\Exceptions\ApiException $e) {
155
            throw new PaymentProviderException( $e );
156
        }
157
    }
158
159
}
160