Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 187
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
InstancyServiceV2
0.00% covered (danger)
0.00%
0 / 187
0.00% covered (danger)
0.00%
0 / 10
1806
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 createInstancyUser
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
132
 updateMembership
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
132
 userMembershipDetails
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getUserDetailsByEmailForAllSites
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 validateUser
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 authenticateUser
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 generateSessionID
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 callInstancyApi
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 hasError
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Http\Services;
4
5use App\Exceptions\ExpectedException;
6use App\Http\Models\Admin\Company;
7use App\Http\Models\Admin\CompanyGroup;
8use App\Http\Models\Auth\User;
9use Carbon\Carbon;
10use Illuminate\Support\Facades\Http;
11use Illuminate\Support\Str;
12
13class InstancyServiceV2
14{
15    private $astrKey;
16
17    private $url;
18
19    private $sso_url;
20
21    private $siteGroupId;
22
23    private $action;
24
25    private $uniquePassword;
26
27    public function __construct()
28    {
29        $this->url = 'https://ondemand-admin.vengreso.com/InstancyService.asmx';
30        $this->sso_url = 'https://ondemand-master-admin.vengreso.com/InstancyService.asmx';
31        $this->astrKey = '22A9838A-2196-47ED-8126-4321B7A07EF1';
32        $this->siteGroupId = '388';
33        $this->uniquePassword = '17$5I$jaFq@';
34
35        if (! isProduction() && ! isLocalProduction()) {
36            $this->url = 'https://ondemand-admin.instancy.net/instancyservice.asmx';
37            $this->sso_url = 'https://ondemand-master-admin.instancy.net/InstancyService.asmx';
38            $this->astrKey = 'A58ABE98-1B0D-41FC-9805-0F34D6B99E80';
39        }
40    }
41
42    /**
43     * Create Instancy User
44     *
45     *
46     * @return mixed
47     */
48    public function createInstancyUser(string $email, string $groupId): array
49    {
50        $user = User::whereEmail($email)->first();
51        if (! $user) {
52            return ['Error' => 'User not found'];
53        }
54        $First_Name = str_replace("'", ' ', $user->first_name);
55        $Last_Name = str_replace("'", ' ', $user->last_name);
56        $this->action = 'CreateUser';
57
58        $parentId = $this->siteGroupId;
59
60        if ($groupId) {
61            $parentId = $groupId;
62        }
63
64        // Get the users subscription data.
65        // We are assuming that all the users have subscription records
66        // since this is only for pro users.
67        $subscription = $user->subscription('main');
68
69        if (! $subscription) {
70            throw new ExpectedException("The user with email $email needs to have an active subscription");
71        }
72
73        $end_date = Carbon::parse($subscription->ends_at)->toDateString();
74        $start_date = $subscription->created_at->toDateString();
75
76        if ($subscription->stripe_status == 'trialing') {
77            $end_date = Carbon::parse($subscription->trial_ends_at)->toDateString();
78        }
79
80        $MembershipType = 'Annual';
81        $MembershipDurationID = 30; // Sales pro yearly
82
83        if ($subscription->plan && $subscription->plan->identifier == 'sales-pro-monthly') {
84            $MembershipType = 'Non-Annual';
85            $MembershipDurationID = 32; // Sales pro yearly
86        }
87
88        $instancyEmail = $email;
89
90        if (! isProduction() && ! isLocalProduction()) {
91            $instancyEmail = 'staging.'.$email;
92        }
93
94        $xml = "<?xml version='1.0' encoding='iso-8859-1'?>
95        <InstancyWrapper>
96            <Request SiteID='$this->siteGroupId'>
97                <UserDetails>
98                    <GroupID><![CDATA[$parentId]]></GroupID>
99                    <First_Name><![CDATA[$First_Name]]></First_Name>
100                    <Gender><![CDATA[1]]></Gender>
101                    <Last_Name><![CDATA[$Last_Name]]></Last_Name>
102                    <User_name><![CDATA[$instancyEmail]]></User_name>
103                    <Email><![CDATA[$instancyEmail]]></Email>
104                    <Password><![CDATA[FlyMSGWelcome#2024]]></Password>
105                    <Mobile_Number><![CDATA[0000000000]]></Mobile_Number>
106                    <Job_title>User</Job_title>
107                    <Company_Name>Vengreso</Company_Name>
108                    <MembershipDurationID>$MembershipDurationID</MembershipDurationID>
109                    <PaymentType><![CDATA[Credit Card]]></PaymentType>
110                </UserDetails>
111            </Request>
112        </InstancyWrapper>";
113
114        $response = $this->callInstancyApi($xml);
115        $response = parseInstancyXml($response);
116
117        $response = parseInstancyXml($response['value']);
118        $response_status = $response['Response'][0]['@attributes']['Result'];
119
120        if ($response_status == 'Success') {
121            // Update the user profile with the instancy ID
122            $instancy_id = $response['UserDetails'][0]['UserID'][0]['value'];
123            $user->instancy_id = $instancy_id;
124            $user->save();
125
126            $response['FlyMSGUser'] = [
127                'InstancyID' => $instancy_id,
128                'Email' => $email,
129            ];
130        } else {
131            $result = $this->getUserDetailsByEmailForAllSites($email);
132            $result_status = $result['Response'][0]['@attributes']['Result'];
133            if ($result_status == 'Success') {
134                // Get the user id and save it to the DB user profile
135                $instancy_id = $result['UserDetails'][0]['UserID'][0]['value'];
136                $response['FlyMSGUser'] = [
137                    'InstancyID' => $instancy_id,
138                    'Email' => $email,
139                ];
140            }
141        }
142
143        return $response;
144    }
145
146    /**
147     * Update Membership on instancy.
148     * Used mostly to update the users membership expiry date.
149     * If a param $date is passed, it will be used as the new expiry date.
150     *
151     * @param  string  $email
152     * @param  string  $date  of expiry
153     */
154    public function updateMembership($email, $date = null): array
155    {
156        $user = User::withTrashed()->whereEmail($email)->first();
157        $group = CompanyGroup::find($user->company_group_id);
158        $company = Company::find($user->company_id);
159
160        $groupId = false;
161        if ($group) {
162            $groupId = $group->instancy_id;
163        } elseif ($company) {
164            $groupId = $company->instancy_id;
165        }
166
167        if (! $user) {
168            return ['Error' => 'User not found'];
169        }
170
171        $instancy_id = $user->instancy_id;
172        if (! $instancy_id) {
173            $result = $this->getUserDetailsByEmailForAllSites($email);
174            $result_status = $result['Response'][0]['@attributes']['Result'];
175            if ($result_status == 'Success') {
176                // Get the user id and save it to the DB user profile
177                $instancy_id = $result['UserDetails'][0]['UserID'][0]['value'];
178                $user->instancy_id = $instancy_id;
179                $user->save();
180            } else {
181                $this->createInstancyUser($email, $groupId);
182                $result = $this->getUserDetailsByEmailForAllSites($email);
183                $result_status = $result['Response'][0]['@attributes']['Result'];
184                if ($result_status == 'Success') {
185                    // Get the user id and save it to the DB user profile
186                    $instancy_id = $result['UserDetails'][0]['UserID'][0]['value'];
187                    $user->instancy_id = $instancy_id;
188                    $user->save();
189                }
190            }
191        }
192
193        // Get the users subscription data.
194        // We are assuming that all the users have subscription records
195        // since this is only for pro users.
196        $subscription = $user->subscription('main');
197
198        $end_date = Carbon::parse($subscription->ends_at)->toDateString();
199        $start_date = $subscription->created_at->toDateString();
200
201        if ($subscription->stripe_status == 'trialing') {
202            $end_date = Carbon::parse($subscription->trial_ends_at)->toDateString();
203        }
204
205        if ($subscription->stripe_status != 'active' && $subscription->stripe_status != 'trialing') {
206            // If not active, expire it by setting the expiry date to a day before
207            // today.
208            $end_date = Carbon::now()->toDateString();
209        }
210
211        $this->action = 'UpdateMemebrship';
212        $siteID = $this->siteGroupId;
213        $end_date = $date ?? $end_date;
214
215        $DurationName = 'One Year';
216        $MembershipType = 'Annual';
217        $MembershipDurationID = 30; // Sales pro yearly
218
219        if ($subscription->plan?->identifier == 'sales-pro-monthly') {
220            $DurationName = 'One Month';
221            $MembershipType = 'Non-Annual';
222            $MembershipDurationID = 32; // Sales pro yearly
223        }
224
225        $xml = "<?xml version='1.0' encoding='iso-8859-1'?>
226        <InstancyWrapper>
227            <Request SiteID='$siteID'>
228                <UpdateMemebrship>
229                    <MembershipID>40</MembershipID>
230                    <UserID>$instancy_id</UserID>
231                    <ExpiryDate>$end_date</ExpiryDate>
232                    <StartDate>$start_date</StartDate>
233                    <DurationName>$DurationName</DurationName>
234                    <MembershipDurationID>$MembershipDurationID</MembershipDurationID>
235                    <RecurringProfileID></RecurringProfileID>
236                    <Paymentmode>Exempted</Paymentmode>
237                    <Notes></Notes>
238                    <Amount>0</Amount>
239                </UpdateMemebrship>
240            </Request>
241        </InstancyWrapper>";
242        $response = $this->callInstancyApi($xml);
243        $response = parseInstancyXml($response);
244        $response = parseInstancyXml($response['value']);
245        $response['FlyMSGUser'] = [
246            'InstancyID' => $instancy_id,
247            'Email' => $email,
248        ];
249
250        return $response;
251    }
252
253    /**
254     * function to get the user membership details
255     */
256    public function userMembershipDetails($data): array
257    {
258        return $this->getUserDetailsByEmailForAllSites($data['email']);
259    }
260
261    /**
262     * Get Membership Details by Email
263     * Use this to get the details about the user and the membership
264     * but mostly to get the USER ID to backfill the missing
265     * ones on flymsg DB.
266     *
267     * @param  string  $email
268     * @return array $response
269     */
270    public function getUserDetailsByEmailForAllSites($email): array
271    {
272        $user = User::whereEmail($email)->first();
273        if (! $user) {
274            return ['Error' => 'User not found'];
275        }
276
277        $instancy_id = $user->instancy_id;
278
279        $instancyEmail = $email;
280
281        if (! isProduction() && ! isLocalProduction()) {
282            $instancyEmail = 'staging.'.$email;
283        }
284
285        $this->action = 'GetUserInfoByEmailForAllSites';
286        $siteID = $this->siteGroupId;
287        $xml = "<?xml version='1.0' encoding='iso-8859-1'?><InstancyWrapper><Request SiteID='$siteID'/><UserDetails><email><![CDATA[$instancyEmail]]></email></UserDetails></InstancyWrapper>";
288        $response = $this->callInstancyApi($xml);
289        $response = parseInstancyXml($response);
290        $response = parseInstancyXml($response['value']);
291        $response['FlyMSGUser'] = [
292            'InstancyID' => $instancy_id,
293            'Email' => $email,
294        ];
295
296        return $response;
297    }
298
299    public function validateUser(string $email): bool
300    {
301        $response = $this->getUserDetailsByEmailForAllSites($email);
302
303        return $this->hasError($response);
304    }
305
306    public function authenticateUser(string $email)
307    {
308        $response = $this->generateSessionID($email);
309
310        if ($this->hasError($response)) {
311            if (
312                $response['Response'][0]['@attributes']['ResultDescription'] != 'User Membership Expired' &&
313                $response['Response'][0]['@attributes']['ResultDescription'] != 'Account Deactivated'
314            ) {
315                // Attempt to create the user and authenticate again
316                // this preserves the old api.
317
318                $user = User::firstWhere('email', $email);
319                $group = CompanyGroup::find($user->company_group_id);
320                $company = Company::find($user->company_id);
321
322                $groupId = false;
323                if ($company) {
324                    $groupId = $company->instancy_id;
325                } elseif ($group) {
326                    $groupId = $group->instancy_id;
327                }
328
329                $this->createInstancyUser($email, $groupId);
330                $response = $this->authenticateUser($email);
331
332                // Handle authentication error
333                return $response; // Or throw an exception
334            }
335        }
336
337        return $response;
338    }
339
340    private function generateSessionID($email)
341    {
342        $api = $this->sso_url.'/AuthenticateUser';
343        $siteID = $this->siteGroupId;
344
345        $instancyEmail = $email;
346
347        if (! isProduction() && ! isLocalProduction()) {
348            $instancyEmail = 'staging.'.$email;
349        }
350
351        $data = "<?xml version='1.0' encoding='iso-8859-1'?><InstancyWrapper><Request SiteID='$siteID'><UserDetails><UserID><![CDATA[-1]]></UserID><Email><![CDATA[$instancyEmail]]></Email><Password><![CDATA[$this->uniquePassword]]></Password></UserDetails></Request></InstancyWrapper>";
352        $response = Http::withHeaders([
353            'Cookie' => 'ASP.NET_SessionId=fuhbkztcn41q4vteeipt5jmr',
354            'Accept-Encoding' => '',
355        ])->asForm()
356            ->post($api, [
357                'astrKey' => $this->astrKey,
358                'astrXML' => $data,
359            ]);
360
361        $email = urlencode($email);
362
363        $response = parseInstancyXml($response->body());
364        $response = parseInstancyXml($response['value']);
365
366        return $response;
367    }
368
369    private function callInstancyApi($xml)
370    {
371        $url = $this->url.'/'.$this->action;
372        $response = Http::withHeaders([
373            'Accept-Encoding' => '',
374            'Content-Type' => 'application/x-www-form-urlencoded',
375        ])->asForm()
376            ->post($url, [
377                'astrKey' => $this->astrKey,
378                'astrXML' => $xml,
379            ])->body();
380
381        return $response;
382    }
383
384    public function hasError($response)
385    {
386        return Str::contains(json_encode($response), ['Invalid User ID', 'Invalid Client ID', 'There is no row', 'Error']);
387    }
388}