Passed
Pull Request — master (#65)
by Rafael
05:24
created

PaymentsController   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Test Coverage

Coverage 31.76%

Importance

Changes 0
Metric Value
eloc 80
dl 0
loc 198
ccs 27
cts 85
cp 0.3176
rs 10
c 0
b 0
f 0
wmc 25

8 Methods

Rating   Name   Duplication   Size   Complexity  
B sendWebhookResponseEmail() 0 34 6
A handleChargeFailed() 0 9 2
A handleChargePending() 0 8 2
A handleCustomerSubscriptionUpdated() 0 8 2
A updateSubscriptionPaymentStatus() 0 33 5
A handleWebhook() 0 19 4
A handleChargeSucceeded() 0 9 2
A handleCustomerSubscriptionTrialwillend() 0 8 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gewaer\Api\Controllers;
6
7
use Phalcon\Cashier\Traits\StripeWebhookHandlersTrait;
8
use Phalcon\Http\Response;
9
use Gewaer\Models\Users;
10
use Gewaer\Models\EmailTemplates;
11
use Gewaer\Models\Subscription;
12
use Gewaer\Models\CompaniesSettings;
13
use Phalcon\Di;
14
use Exception;
15
16
/**
17
 * Class PaymentsController
18
 *
19
 * Class to handle payment webhook from our cashier library
20
 *
21
 * @package Gewaer\Api\Controllers
22
 * @property Log $log
23
 *
24
 */
25
class PaymentsController extends BaseController
26
{
27
    /**
28
     * Stripe Webhook Handlers
29
     */
30
    use StripeWebhookHandlersTrait;
31
32
    /**
33
     * Handle stripe webhoook calls
34
     *
35
     * @return Response
36
     */
37 4
    public function handleWebhook(): Response
38
    {
39
        //we cant processs if we dont find the stripe header
40 4
        if (!$this->request->hasHeader('Stripe-Signature')) {
41
            throw new Exception('Route not found for this call');
42
        }
43 4
        $request = $this->request->getPost();
44 4
        if (empty($request)) {
45
            $request = $this->request->getJsonRawBody(true);
46
        }
47 4
        $type = str_replace('.', '', ucwords(str_replace('_', '', $request['type']), '.'));
48 4
        $method = 'handle' . $type;
49 4
        $payloadContent = json_encode($request);
50 4
        $this->log->info("Webhook Handler Method: {$method} \n");
51 4
        $this->log->info("Payload: {$payloadContent} \n");
52 4
        if (method_exists($this, $method)) {
53 4
            return $this->{$method}($request, $method);
54
        } else {
55
            return $this->response(['Missing Method to Handled']);
56
        }
57
    }
58
59
    /**
60
     * Handle customer subscription updated.
61
     *
62
     * @param  array $payload
63
     * @return Response
64
     */
65
    protected function handleCustomerSubscriptionUpdated(array $payload, string $method): Response
66
    {
67
        $user = Users::findFirstByStripeId($payload['data']['object']['customer']);
68
        if ($user) {
69
            //We need to send a mail to the user
70
            $this->sendWebhookResponseEmail($user, $payload, $method);
71
        }
72
        return $this->response(['Webhook Handled']);
73
    }
74
75
    /**
76
     * Handle customer subscription free trial ending.
77
     *
78
     * @param  array $payload
79
     * @return Response
80
     */
81 1
    protected function handleCustomerSubscriptionTrialwillend(array $payload, string $method): Response
82
    {
83 1
        $user = Users::findFirstByStripeId($payload['data']['object']['customer']);
84 1
        if ($user) {
85
            //We need to send a mail to the user
86
            $this->sendWebhookResponseEmail($user, $payload, $method);
87
        }
88 1
        return $this->response(['Webhook Handled']);
89
    }
90
91
    /**
92
     * Handle sucessfull payment
93
     *
94
     * @param array $payload
95
     * @return Response
96
     */
97 1
    protected function handleChargeSucceeded(array $payload, string $method): Response
98
    {
99 1
        $user = Users::findFirstByStripeId($payload['data']['object']['customer']);
100 1
        if ($user) {
101
            //Update current subscription's paid column to true and store date of payment
102
            $this->response($this->updateSubscriptionPaymentStatus($user, $payload));
1 ignored issue
show
Bug introduced by
Are you sure the usage of $this->updateSubscriptio...Status($user, $payload) targeting Gewaer\Api\Controllers\P...criptionPaymentStatus() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
103
            $this->sendWebhookResponseEmail($user, $payload, $method);
104
        }
105 1
        return $this->response(['Webhook Handled']);
106
    }
107
108
    /**
109
     * Handle bad payment
110
     *
111
     * @param array $payload
112
     * @return Response
113
     */
114 1
    protected function handleChargeFailed(array $payload, string $method) : Response
115
    {
116 1
        $user = Users::findFirstByStripeId($payload['data']['object']['customer']);
117 1
        if ($user) {
118
            //We need to send a mail to the user
119
            $this->response($this->updateSubscriptionPaymentStatus($user, $payload));
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->updateSubscriptio...Status($user, $payload) targeting Gewaer\Api\Controllers\P...criptionPaymentStatus() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
120
            $this->sendWebhookResponseEmail($user, $payload, $method);
121
        }
122 1
        return $this->response(['Webhook Handled']);
123
    }
124
125
    /**
126
     * Handle pending payments
127
     *
128
     * @param array $payload
129
     * @return Response
130
     */
131 1
    protected function handleChargePending(array $payload, string $method) : Response
132
    {
133 1
        $user = Users::findFirstByStripeId($payload['data']['object']['customer']);
134 1
        if ($user) {
135
            //We need to send a mail to the user
136
            $this->sendWebhookResponseEmail($user, $payload, $method);
137
        }
138 1
        return $this->response(['Webhook Handled']);
139
    }
140
141
    /**
142
     * Send webhook related emails to user
143
     * @param Users $user
144
     * @param array $payload
145
     * @param string $method
146
     * @return void
147
     */
148
    protected function sendWebhookResponseEmail(Users $user, array $payload, string $method): void
149
    {
150
        switch ($method) {
151
            case 'handleCustomerSubscriptionTrialwillend':
152
                $templateName = 'users-trial-end';
153
                break;
154
            case 'handleCustomerSubscriptionUpdated':
155
                $templateName = 'users-subscription-updated';
156
                break;
157
158
            case 'handleChargeSucceeded':
159
                $templateName = 'users-charge-success';
160
                break;
161
162
            case 'handleChargeFailed':
163
                $templateName = 'users-charge-failed';
164
                break;
165
166
            case 'handleChargePending':
167
                $templateName = 'users-charge-pending';
168
                break;
169
170
            default:
171
                break;
172
        }
173
174
        //Search for actual template by templateName
175
        $emailTemplate = EmailTemplates::getByName($templateName);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $templateName does not seem to be defined for all execution paths leading up to this point.
Loading history...
176
177
        Di::getDefault()->getMail()
178
            ->to($user->email)
179
            ->subject('Canvas Payments and Subscriptions')
180
            ->content($emailTemplate->template)
181
            ->sendNow();
182
    }
183
184
    /**
185
     * Updates subscription payment status depending on charge event
186
     * @param $user
187
     * @param $payload
188
     * @return void
189
     */
190
    public function updateSubscriptionPaymentStatus(Users $user, array $payload)
191
    {
192
        $chargeDate = date('Y-m-d H:i:s', $payload['data']['object']['created']);
193
194
        //Fetch current user subscription
195
        $subscription = Subscription::findFirst([
196
                'conditions' => 'user_id = ?0 and companies_id = ?1 and apps_id = ?2 and is_active = 1 and is_deleted = 0',
197
                'bind' => [$user->id, $user->default_company, $this->app->getId()]
0 ignored issues
show
Bug Best Practice introduced by
The property app does not exist on Gewaer\Api\Controllers\PaymentsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
198
            ]);
199
200
        if (is_object($subscription)) {
201
            $subscription->paid = $payload['data']['object']['paid'] ? 1 : 0;
202
            $subscription->charge_date = $chargeDate;
203
204
            if ($subscription->paid) {
205
                $subscription->is_freetrial = 0;
206
                $subscription->trial_ends_days = 0;
207
            }
208
209
            if ($subscription->update()) {
210
                //Update companies setting
211
                $paidSetting = CompaniesSettings::findFirst([
212
                    'conditions' => "companies_id = ?0 and name = 'paid' and is_deleted = 0",
213
                    'bind' => [$user->default_company]
214
                ]);
215
216
                $paidSetting->value = (string)$subscription->paid;
217
                $paidSetting->update();
218
            }
219
            $this->log->info("User with id: {$user->id} charged status was {$payload['data']['object']['paid']} \n");
220
        }
221
222
        $this->log->error("Subscription not found\n");
223
    }
224
}
225