Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 108
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ClearEmailProcessing
0.00% covered (danger)
0.00%
0 / 108
0.00% covered (danger)
0.00%
0 / 2
1190
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 handle
0.00% covered (danger)
0.00%
0 / 107
0.00% covered (danger)
0.00%
0 / 1
1122
1<?php
2
3namespace App\Console\Commands;
4
5use App\Models\TblQuotations;
6use App\Models\TblSendgridWebhook;
7use Illuminate\Console\Command;
8use Illuminate\Support\Facades\Cache;
9use Illuminate\Support\Facades\DB;
10use Illuminate\Support\Facades\Http;
11use Illuminate\Support\Facades\Log;
12
13class ClearEmailProcessing extends Command
14{
15    /**
16     * The name and signature of the console command.
17     *
18     * @var string
19     */
20    protected $signature = 'clear:email-processing';
21
22    /**
23     * The console command description.
24     *
25     * @var string
26     */
27    protected $description = 'Clear email processing';
28
29    /**
30     * Create a new command instance.
31     *
32     * @return void
33     */
34    public function __construct()
35    {
36        parent::__construct();
37    }
38
39    /**
40     * Execute the console command.
41     *
42     * @return int
43     */
44    public function handle()
45    {
46        try {
47
48            $startedAt = date('Y-m-d H:i:s');
49
50            $query = "SELECT 
51                        id,
52                        email,
53                        x_message_id,
54                        x_status
55                    FROM tbl_quotations 
56                    WHERE (x_status IS NOT NULL AND x_status != 'Completed') 
57                    AND x_message_id IS NOT NULL";
58
59            $result = DB::select($query);
60
61            $emailErrors = ['deferred', 'bounce', 'dropped', 'spamreport', 'invalid'];
62
63            if (count($result) > 0) {
64
65                $quoteIds = [];
66
67                for ($i = 0; $i < count($result); $i++) {
68                    $emails = explode(',', str_replace(' ', '', $result[$i]->email));
69                    $xMessageId = $result[$i]->x_message_id;
70                    $xOrderStatus = $result[$i]->x_status;
71
72                    $sendGrid = TblSendgridWebhook::where('x_message_id', $xMessageId)->first();
73
74                    if ($sendGrid) {
75
76                        $events = json_decode($sendGrid->json_body, true);
77                        $xStatus = 'processed';
78                        $isProcessed = 0;
79                        $isDelivered = 0;
80                        $isError = 0;
81                        $eventsUpdated = false;
82
83                        foreach ($emails as $email) {
84
85                            $emailEvents = array_filter($events, fn ($event) => strtolower($event['email']) === strtolower($email));
86
87                            $statuses = array_unique(array_column($emailEvents, 'event'));
88                            $eventCount = count($statuses);
89
90                            if ($eventCount === 1 && in_array('processed', $statuses)) {
91                                $xStatus = 'processed';
92                            }
93
94                            if ($eventCount == 2) {
95                                if (in_array('processed', $statuses) && in_array('delivered', $statuses)) {
96                                    $xStatus = 'delivered';
97                                }
98
99                                foreach ($emailErrors as $e) {
100                                    if (in_array('processed', $statuses) && in_array($e, $statuses)) {
101                                        $xStatus = $e;
102                                    }
103                                }
104                            } elseif ($eventCount > 2) {
105                                if (in_array('processed', $statuses) && in_array('delivered', $statuses)) {
106                                    $xStatus = 'delivered';
107                                }
108
109                                if ($xStatus != 'delivered') {
110                                    foreach ($emailErrors as $e) {
111                                        if (in_array('processed', $statuses) && in_array($e, $statuses)) {
112                                            $xStatus = $e;
113                                            break;
114                                        }
115                                    }
116                                }
117                            }
118
119                            if ($xStatus == 'processed') {
120                                $query = urlencode('msg_id LIKE "'.$xMessageId.'%" AND to_email IN ("'.$email.'")');
121                                $response = Http::withToken(env('SENDGRID_API_KEY'))
122                                    ->get("https://api.sendgrid.com/v3/messages?limit=10&query={$query}");
123
124                                $data = $response->json();
125
126                                if (! empty($data['messages'])) {
127                                    $xStatus = $data['messages'][0]['status'] ?? 'processed';
128
129                                    if ($xStatus == 'delivered') {
130                                        $data['messages'][0]['timestamp'] = strtotime($data['messages'][0]['last_event_time']);
131                                        unset($data['messages'][0]['last_event_time']);
132
133                                        $data['messages'][0]['email'] = $data['messages'][0]['to_email'];
134                                        unset($data['messages'][0]['to_email']);
135
136                                        $data['messages'][0]['event'] = $data['messages'][0]['status'];
137                                        unset($data['messages'][0]['status']);
138
139                                        $data['messages'][0]['click'] = $data['messages'][0]['clicks_count'];
140                                        unset($data['messages'][0]['clicks_count']);
141
142                                        $data['messages'][0]['open'] = $data['messages'][0]['opens_count'];
143                                        unset($data['messages'][0]['opens_count']);
144
145                                        array_push($events, $data['messages'][0]);
146                                        $eventsUpdated = true;
147                                    }
148                                }
149                            }
150
151                            if ($xStatus == 'processed') {
152                                $isProcessed++;
153                            } elseif ($xStatus == 'delivered') {
154                                $isDelivered++;
155                            } else {
156                                $isError++;
157                            }
158                        }
159
160                        if ($eventsUpdated) {
161                            TblSendgridWebhook::where('x_message_id', $xMessageId)->update(
162                                [
163                                    'updated_at' => date('Y-m-d H:i:s'),
164                                    'json_body' => json_encode($events),
165                                ]
166                            );
167                        }
168
169                        if (count($emails) == $isDelivered) {
170                            $xStatus = 'Completed';
171                        } elseif ($isProcessed > 0) {
172                            $xStatus = 'Processing';
173                        } elseif ($isError > 0) {
174                            if ($xStatus == 'bounce') {
175                                $xStatus = 'Error - Bounce';
176                            } else {
177                                $xStatus = 'Error';
178                            }
179                        }
180
181                        if ($xOrderStatus != $xStatus) {
182                            TblQuotations::where('id', $result[$i]->id)->update(
183                                [
184                                    'x_status' => $xStatus,
185                                ]
186                            );
187
188                            Log::channel('clear_email_processing')->info($xMessageId.': OK');
189                        }
190                    }
191                }
192
193            }
194
195            $query = "SELECT 
196                        a.x_message_id
197                    FROM 
198                        tbl_quotations a 
199                    LEFT JOIN 
200                        tbl_sendgrid_webhook b 
201                        ON a.x_message_id = b.x_message_id 
202                    WHERE 
203                        a.x_status = 'Processing'
204                        AND a.x_status IS NOT NULL
205                        AND (b.updated_at < NOW() - INTERVAL 30 DAY OR b.x_message_id IS NULL)";
206
207            $result = DB::select($query);
208
209            $idsCollection = collect($result)->pluck('x_message_id');
210
211            $idsString = $idsCollection->map(function ($id) {
212                return "'".$id."'";
213            })
214                ->implode(',');
215
216            $totalCount = $idsCollection->count();
217
218            if ($totalCount > 0) {
219                $query = "DELETE FROM tbl_sendgrid_webhook
220                            WHERE x_message_id IN ({$idsString})";
221
222                $result = DB::select($query);
223
224                $query = "UPDATE tbl_quotations 
225                            SET x_message_id = NULL, x_status = NULL 
226                            WHERE x_message_id IN ({$idsString})";
227
228                $result = DB::select($query);
229            }
230
231            TblQuotations::whereNull('x_message_id')->where('x_status', 'Processing')->update(['x_status' => null]);
232
233            Cache::flush();
234
235        } catch (\Exception $e) {
236            Log::channel('clear_email_processing')->error($e->getMessage());
237        }
238
239        return 0;
240    }
241}