• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MerginMaps / input / 6422038473

05 Oct 2023 04:51PM UTC coverage: 62.265% (+0.4%) from 61.9%
6422038473

push

github

web-flow
Remove subscription pages for iOS and call-to-actions (#2835)

* remove subscription pages for ios and call-to-actions

* bring back button to account page to get to the dashboard

* merge url params

7681 of 12336 relevant lines covered (62.26%)

105.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

68.54
/app/purchasing.cpp
1
/***************************************************************************
2
 *                                                                         *
3
 *   This program is free software; you can redistribute it and/or modify  *
4
 *   it under the terms of the GNU General Public License as published by  *
5
 *   the Free Software Foundation; either version 2 of the License, or     *
6
 *   (at your option) any later version.                                   *
7
 *                                                                         *
8
 ***************************************************************************/
9

10
#include  <QDebug>
11
#include <QNetworkReply>
12
#include <QUrlQuery>
13

14
#include "purchasing.h"
15
#include "merginapi.h"
16
#include "inpututils.h"
17
#include "merginuserinfo.h"
18
#include "merginsubscriptioninfo.h"
19
#include "coreutils.h"
20

21
#if defined (APPLE_PURCHASING)
22
#include "ios/iospurchasing.h"
23
#endif
24
#if defined (INPUT_TEST)
25
#include "test/testingpurchasingbackend.h"
26
#endif
27

28
void PurchasingPlan::clear()
×
29
{
30
  mAlias = QString();
×
31
  mId = QString();
×
32
  mPeriod = QString();
×
33
  mPrice = QString();
×
34
  mStorage = QString();
×
35
}
×
36

37
QString PurchasingPlan::alias() const
×
38
{
39
  return mAlias;
×
40
}
41

42
void PurchasingPlan::setAlias( const QString &alias )
×
43
{
44
  mAlias = alias;
×
45
  emit planChanged();
×
46
}
×
47

48
QString PurchasingPlan::id() const
56✔
49
{
50
  return mId;
56✔
51
}
52

53
void PurchasingPlan::setId( const QString &billingProductId )
×
54
{
55
  mId = billingProductId;
×
56
  emit planChanged();
×
57
}
×
58

59
QString PurchasingPlan::period() const
×
60
{
61
  return mPeriod;
×
62
}
63

64
void PurchasingPlan::setPeriod( const QString &billingPeriod )
×
65
{
66
  mPeriod = billingPeriod;
×
67
  emit planChanged();
×
68
}
×
69

70
QString PurchasingPlan::price() const
×
71
{
72
  return mPrice;
×
73
}
74

75
void PurchasingPlan::setPrice( const QString &billingPrice )
×
76
{
77
  mPrice = billingPrice;
×
78
  emit planChanged();
×
79
}
×
80

81
bool PurchasingPlan::isIndividualPlan() const
16✔
82
{
83
  return !mIsProfessional;
16✔
84
}
85

86
bool PurchasingPlan::isProfessionalPlan() const
8✔
87
{
88
  return mIsProfessional;
8✔
89
}
90

91
QString PurchasingPlan::storage() const
×
92
{
93
  return mStorage;
×
94
}
95

96
void PurchasingPlan::setStorage( const QString &storage )
×
97
{
98
  mStorage = storage;
×
99
  emit planChanged();
×
100
}
×
101

102
Purchasing *PurchasingPlan::purchasing() const
21✔
103
{
104
  return mPurchasing;
21✔
105
}
106

107
void PurchasingPlan::setPurchasing( Purchasing *purchasing )
8✔
108
{
109
  mPurchasing = purchasing;
8✔
110
}
8✔
111

112
void PurchasingPlan::setFromJson( QJsonObject docObj )
8✔
113
{
114
  mAlias = docObj.value( QStringLiteral( "alias" ) ).toString();
8✔
115
  mId = docObj.value( QStringLiteral( "billing_product_id" ) ).toString();
8✔
116
  const QString billingPeriod = docObj.value( QStringLiteral( "billing_period" ) ).toString();
16✔
117
  bool isMonthly = billingPeriod.contains( "month", Qt::CaseInsensitive );
8✔
118
  if ( isMonthly )
8✔
119
  {
120
    mPeriod = tr( "Monthly subscription" );
8✔
121
  }
122
  else
123
  {
124
    mPeriod = tr( "Annual subscription" );
×
125
  }
126
  const QString billingPrice = docObj.value( QStringLiteral( "billing_price" ) ).toString();
16✔
127
  if ( isMonthly )
8✔
128
  {
129
    mPrice = billingPrice + "/" + tr( "month" );
8✔
130
  }
131
  else
132
  {
133
    mPrice = billingPrice + "/" + tr( "year" );
×
134
  }
135

136
  double bytes = docObj.value( QStringLiteral( "storage" ) ).toDouble();
8✔
137
  mStorage = InputUtils::bytesToHumanSize( bytes );
8✔
138

139
  mIsProfessional = ( bytes > 1024.0 * 1024.0 * 1024.0 * 5 ); // storage > 5GB
8✔
140

141
  emit planChanged();
8✔
142
}
8✔
143

144
/* ********************************************************************************************************/
145
/* ********************************************************************************************************/
146
/* ********************************************************************************************************/
147

148

149
PurchasingTransaction::PurchasingTransaction( PurchasingTransaction::TransactionType type, QSharedPointer<PurchasingPlan> plan )
7✔
150
  : mPlan( plan )
7✔
151
  , mType( type )
7✔
152
{
153
}
7✔
154

155
void PurchasingTransaction::verificationFinished()
7✔
156
{
157
  Q_ASSERT( mPlan );
7✔
158
  Q_ASSERT( mPlan->purchasing() );
7✔
159
  MerginApi *api = mPlan->purchasing()->merginApi();
7✔
160

161
  QNetworkReply *r = qobject_cast<QNetworkReply *>( sender() );
7✔
162
  Q_ASSERT( r );
7✔
163

164
  if ( r->error() == QNetworkReply::NoError )
7✔
165
  {
166
    CoreUtils::log( "purchase successful", QStringLiteral( "Payment success" ) );
7✔
167
    mPlan->purchasing()->onTransactionVerificationSucceeded( this );
7✔
168
  }
169
  else
170
  {
171
    QString serverMsg = api->extractServerErrorMsg( r->readAll() );
×
172
    QString message = QStringLiteral( "Network API error: %1(): %2. %3" ).arg( QStringLiteral( "purchase" ), r->errorString(), serverMsg );
×
173
    emit api->networkErrorOccurred( serverMsg, QStringLiteral( "Mergin API error: purchase" ) );
×
174
    CoreUtils::log( "purchase", QStringLiteral( "FAILED - %1" ).arg( message ) );
×
175
    mPlan->purchasing()->onTransactionVerificationFailed( this );
×
176
  }
×
177
  r->deleteLater();
7✔
178
}
7✔
179

180
PurchasingTransaction::TransactionType PurchasingTransaction::type() const
7✔
181
{
182
  return mType;
7✔
183
}
184

185
PurchasingPlan *PurchasingTransaction::plan() const
×
186
{
187
  return mPlan.get();
×
188
}
189

190
/* ********************************************************************************************************/
191
/* ********************************************************************************************************/
192
/* ********************************************************************************************************/
193

194
Purchasing::Purchasing( MerginApi *merginApi, QObject *parent )
18✔
195
  : QObject( parent )
196
  , mMerginApi( merginApi )
18✔
197
{
198
  setDefaultUrls();
18✔
199
  createBackend();
18✔
200

201
  connect( mMerginApi, &MerginApi::apiRootChanged, this, &Purchasing::onMerginServerChanged );
18✔
202
  connect( mMerginApi, &MerginApi::apiSupportsSubscriptionsChanged, this, &Purchasing::onMerginServerStatusChanged );
18✔
203
  connect( mMerginApi, &MerginApi::apiVersionStatusChanged, this, &Purchasing::onMerginServerStatusChanged );
18✔
204
  connect( mMerginApi->subscriptionInfo(), &MerginSubscriptionInfo::planProviderChanged, this, &Purchasing::evaluateHasInAppPurchases );
18✔
205
  connect( mMerginApi->subscriptionInfo(), &MerginSubscriptionInfo::planProductIdChanged, this, &Purchasing::onMerginPlanProductIdChanged );
18✔
206

207
  connect( this, &Purchasing::hasInAppPurchasesChanged, this, &Purchasing::onHasInAppPurchasesChanged );
18✔
208
}
18✔
209

210
void Purchasing::createBackend()
19✔
211
{
212
  mBackend.reset();
19✔
213
#if defined( PURCHASING )
214
#if defined (APPLE_PURCHASING)
215
  mBackend.reset( new IosPurchasingBackend );
216
#elif defined (INPUT_TEST)
217
  mBackend.reset( new TestingPurchasingBackend( mMerginApi ) );
19✔
218
#endif
219
#endif
220

221
  if ( mBackend )
19✔
222
  {
223
    mBackend->setPurchasing( this );
19✔
224
    mBackend->init();
19✔
225

226
    connect( mBackend.get(), &PurchasingBackend::planRegistrationSucceeded, this, &Purchasing::onPlanRegistrationSucceeded );
19✔
227
    connect( mBackend.get(), &PurchasingBackend::planRegistrationFailed, this, &Purchasing::onPlanRegistrationFailed );
19✔
228

229
    connect( mBackend.get(), &PurchasingBackend::transactionCreationSucceeded, this, &Purchasing::onTransactionCreationSucceeded );
19✔
230
    connect( mBackend.get(), &PurchasingBackend::transactionCreationFailed, this, &Purchasing::onTransactionCreationFailed );
19✔
231
  }
232
}
19✔
233

234
void Purchasing::evaluateHasInAppPurchases()
21✔
235
{
236
  bool hasInApp =
237
    mMerginApi->apiSupportsSubscriptions() &&
21✔
238
    mMerginApi->apiVersionStatus() == MerginApiStatus::OK &&
37✔
239
    bool( mBackend ) &&
58✔
240
    mBackend->userCanMakePayments();
16✔
241

242
  bool hasCompatiblePlanType = true;
21✔
243
  if ( mMerginApi->subscriptionInfo()->ownsActiveSubscription() )
21✔
244
  {
245
    hasCompatiblePlanType =
6✔
246
      bool( mBackend ) &&
12✔
247
      mBackend->provider() == mMerginApi->subscriptionInfo()->planProvider();
6✔
248
  }
249
  setHasInAppPurchases( hasInApp && hasCompatiblePlanType );
21✔
250
}
21✔
251

252
void Purchasing::onHasInAppPurchasesChanged()
13✔
253
{
254
  bool hasManageCapability = false;
13✔
255
  QString subscriptionManageUrl = mMerginApi->apiRoot() + "subscription";
13✔
256
  QString subscriptionBillingUrl = mMerginApi->apiRoot() + "billing";
13✔
257

258
  if ( hasInAppPurchases() )
13✔
259
  {
260
    hasManageCapability = mBackend->hasManageSubscriptionCapability();
13✔
261
    subscriptionManageUrl = mBackend->subscriptionManageUrl();
13✔
262
    subscriptionBillingUrl = mBackend->subscriptionBillingUrl();
13✔
263
  }
264

265
  setHasManageSubscriptionCapability( hasManageCapability );
13✔
266
  setSubscriptionManageUrl( subscriptionManageUrl );
13✔
267
  setSubscriptionBillingUrl( subscriptionBillingUrl );
13✔
268
}
13✔
269

270
bool Purchasing::hasInAppPurchases() const
20✔
271
{
272
  return mHasInAppPurchases;
20✔
273
}
274

275
bool Purchasing::hasManageSubscriptionCapability() const
×
276
{
277
  return mHasManageSubscriptionCapability;
×
278
}
279

280
QString Purchasing::subscriptionManageUrl()
×
281
{
282
  return mSubscriptionManageUrl;
×
283
}
284

285
QString Purchasing::subscriptionBillingUrl()
×
286
{
287
  return mSubscriptionBillingUrl;
×
288
}
289

290
void Purchasing::onMerginServerChanged()
1✔
291
{
292
  qDebug() << "Mergin Server Url changed reseting purchasing";
1✔
293
  clean();
1✔
294
}
1✔
295

296
void Purchasing::purchase( const QString &planId )
7✔
297
{
298
  if ( transactionPending() )
7✔
299
  {
300
    qDebug() << "unable to initiate purchase, there is a transaction pending";
×
301
    return;
×
302
  }
303

304
  if ( hasInAppPurchases() )
7✔
305
  {
306
    if ( mPlansWithPendingRegistration.contains( planId ) )
7✔
307
    {
308
      qDebug() << "unable to initiate purchase, plan " << planId << " is not yet registered";
×
309
    }
310

311
    if ( !mRegisteredPlans.contains( planId ) )
7✔
312
    {
313
      qDebug() << "unable to initiate purchase, unable to find plan " << planId;
×
314
    }
315

316
    setTransactionCreationRequested( true );
7✔
317
    return mBackend->createTransaction( mRegisteredPlans.value( planId ) );
7✔
318
  }
319
  else
320
  {
321
    qDebug() << "unable to initiate purchase, purchase api not ready";
×
322
  }
323
}
324

325
void Purchasing::restore()
×
326
{
327
  if ( transactionPending() )
×
328
  {
329
    qDebug() << "unable to initiate restore, there is a transaction pending";
×
330
    return;
×
331
  }
332

333
  if ( hasInAppPurchases() )
×
334
  {
335
    setTransactionCreationRequested( true );
×
336
    return mBackend->restore( );
×
337
  }
338
  else
339
  {
340
    qDebug() << "unable to initiate restore, purchase api not ready";
×
341
  }
342
}
343

344
void Purchasing::onMerginPlanProductIdChanged()
10✔
345
{
346
  if ( !mBackend )
10✔
347
    return;
3✔
348

349
  QString planId = mMerginApi->subscriptionInfo()->planProductId();
10✔
350
  if ( planId.isEmpty() )
10✔
351
    return;
3✔
352

353
  if ( mBackend->provider() != mMerginApi->subscriptionInfo()->planProvider() )
7✔
354
    return;
×
355

356
  QString price = mBackend->getLocalizedPrice( mMerginApi->subscriptionInfo()->planProductId() );
7✔
357
  mMerginApi->subscriptionInfo()->setLocalizedPrice( price );
7✔
358
}
10✔
359

360
void Purchasing::onMerginServerStatusChanged()
10✔
361
{
362
  qDebug() << "Mergin Server status changed, fetching purchasing plan";
10✔
363
  if ( mBackend && mPlansWithPendingRegistration.empty() && mRegisteredPlans.empty() )
10✔
364
  {
365
    fetchPurchasingPlans();
10✔
366
  }
367
  evaluateHasInAppPurchases();
10✔
368
}
10✔
369

370
void Purchasing::fetchPurchasingPlans( )
10✔
371
{
372
  if ( !mMerginApi->apiSupportsSubscriptions() ) return;
15✔
373
  if ( mMerginApi->apiVersionStatus() != MerginApiStatus::OK ) return;
10✔
374

375
  QUrl url( mMerginApi->apiRoot() + QStringLiteral( "/v1/plan" ) );
10✔
376
  QUrlQuery query;
5✔
377
  query.addQueryItem( "billing_service", MerginSubscriptionType::toString( mBackend->provider() ) );
5✔
378
  url.setQuery( query );
5✔
379
  QNetworkRequest request = mMerginApi->getDefaultRequest( false );
5✔
380
  request.setUrl( url );
5✔
381
  QNetworkReply *reply = mMerginApi->mManager.get( request );
5✔
382
  connect( reply, &QNetworkReply::finished, this, &Purchasing::onFetchPurchasingPlansFinished );
5✔
383
  CoreUtils::log( "request plan", QStringLiteral( "Requesting purchasing plans for provider %1" ).arg( MerginSubscriptionType::toString( mBackend->provider() ) ) );
5✔
384
}
5✔
385

386
void Purchasing::onFetchPurchasingPlansFinished()
5✔
387
{
388
  QNetworkReply *r = qobject_cast<QNetworkReply *>( sender() );
5✔
389
  Q_ASSERT( r );
5✔
390
  QString serverMsg;
5✔
391
  if ( r->error() == QNetworkReply::NoError )
5✔
392
  {
393
    CoreUtils::log( "fetch plans", QStringLiteral( "Success" ) );
5✔
394
    QByteArray data = r->readAll();
5✔
395
    const QJsonDocument doc = QJsonDocument::fromJson( data );
5✔
396
    if ( doc.isArray() )
5✔
397
    {
398
      const QJsonArray vArray = doc.array();
5✔
399
      for ( auto it = vArray.constBegin(); it != vArray.constEnd(); ++it )
13✔
400
      {
401
        const QJsonObject obj = it->toObject();
8✔
402
        QSharedPointer<PurchasingPlan> plan = mBackend->createPlan();
8✔
403
        plan->setFromJson( obj );
8✔
404
        plan->setPurchasing( this );
8✔
405
        if ( mPlansWithPendingRegistration.contains( plan->id() ) )
8✔
406
        {
407
          qDebug() << "Plan " << plan->id() << " registration already pending";
×
408
        }
409
        else if ( mRegisteredPlans.contains( plan->id() ) )
8✔
410
        {
411
          qDebug() << "Plan " << plan->id() << " already registered";
×
412
        }
413
        else
414
        {
415
          qDebug() << "Plan " << plan->id() << " requested registration";
8✔
416
          mPlansWithPendingRegistration.insert( plan->id(), plan );
8✔
417
          mBackend->registerPlan( plan );
8✔
418
        }
419
      }
8✔
420
    }
5✔
421
  }
5✔
422
  else
423
  {
424
    serverMsg = mMerginApi->extractServerErrorMsg( r->readAll() );
×
425
    CoreUtils::log( "fetch plans", QStringLiteral( "FAILED - %1. %2" ).arg( r->errorString(), serverMsg ) );
×
426
  }
427
  r->deleteLater();
5✔
428
}
5✔
429

430
void Purchasing::clean()
1✔
431
{
432
  createBackend();
1✔
433
  mRegisteredPlans.clear();
1✔
434
  mPlansWithPendingRegistration.clear();
1✔
435
  mTransactionsWithPendingVerification.clear();
1✔
436
  mTransactionCreationRequested = false;
1✔
437
  mIndividualPlanId.clear();
1✔
438
  mProfessionalPlanId.clear();
1✔
439
  setDefaultUrls();
1✔
440
  setHasInAppPurchases( false );
1✔
441

442
  emit individualPlanChanged();
1✔
443
  emit professionalPlanChanged();
1✔
444
  emit transactionPendingChanged();
1✔
445
}
1✔
446

447
void Purchasing::onPlanRegistrationFailed( const QString &id )
×
448
{
449
  qDebug() << "Failed to register plan " + id;
×
450
  if ( mPlansWithPendingRegistration.contains( id ) )
×
451
    mPlansWithPendingRegistration.remove( id );
×
452

453
  if ( mPlansWithPendingRegistration.empty() && mRegisteredPlans.empty() )
×
454
  {
455
    CoreUtils::log( "Plan Registration", QStringLiteral( "Failed to register any plans" ) );
×
456
  }
457
}
×
458

459
void Purchasing::onPlanRegistrationSucceeded( const QString &id )
8✔
460
{
461
  if ( mPlansWithPendingRegistration.contains( id ) )
8✔
462
  {
463
    QSharedPointer<PurchasingPlan> plan = mPlansWithPendingRegistration.take( id );
8✔
464
    if ( mRegisteredPlans.contains( plan->id() ) )
8✔
465
    {
466
      qDebug() << "Plan " << id << " is already in registered plans.";
×
467
    }
468
    else
469
    {
470
      qDebug() << "Plan " + id + " registered";
8✔
471
      mRegisteredPlans.insert( id, plan );
8✔
472
      if ( plan->isProfessionalPlan() )
8✔
473
      {
474
        qDebug() << "Plan " + id + " is professional plan";
4✔
475
        setProfessionalPlanId( plan->id() );
4✔
476
      }
477
      if ( plan->isIndividualPlan() )
8✔
478
      {
479
        qDebug() << "Plan " + id + " is individual plan";
4✔
480
        setIndividualPlanId( plan->id() );
4✔
481
      }
482
    }
483
  }
8✔
484
  else
485
  {
486
    qDebug() << "Plan " + id + " registered OK, but failed to find in pending registrations";
×
487
  }
488
  emit hasInAppPurchasesChanged();
8✔
489
}
8✔
490

491
void Purchasing::onTransactionCreationSucceeded( QSharedPointer<PurchasingTransaction> transaction )
7✔
492
{
493
  setTransactionCreationRequested( false );
7✔
494

495
  if ( !mMerginApi->validateAuth() || mMerginApi->apiVersionStatus() != MerginApiStatus::OK )
7✔
496
  {
497
    return;
×
498
  }
499

500
  mTransactionsWithPendingVerification.push_back( transaction );
7✔
501

502
  QNetworkRequest request = mMerginApi->getDefaultRequest();
7✔
503
  QUrl url( mMerginApi->apiRoot() + QStringLiteral( "v1/subscription/process-transaction" ) );
14✔
504
  request.setUrl( url );
7✔
505
  request.setHeader( QNetworkRequest::ContentTypeHeader, QVariant( "application/json" ) );
7✔
506
  QJsonDocument jsonDoc;
7✔
507
  QJsonObject jsonObject;
7✔
508
  jsonObject.insert( QStringLiteral( "type" ), MerginSubscriptionType::toString( transaction->provider() ) );
14✔
509
  jsonObject.insert( QStringLiteral( "receipt-data" ), transaction->receipt() );
14✔
510
  jsonObject.insert( QStringLiteral( "api_key" ), mMerginApi->getApiKey( mMerginApi->apiRoot() ) );
14✔
511

512
  if ( mMerginApi->serverType() == MerginServerType::SAAS )
7✔
513
  {
514
    jsonObject.insert( QStringLiteral( "workspace" ), mMerginApi->userInfo()->activeWorkspaceId() );
14✔
515
  }
516

517
  jsonDoc.setObject( jsonObject );
7✔
518
  QByteArray json = jsonDoc.toJson( QJsonDocument::Compact );
7✔
519
  QNetworkReply *reply = mMerginApi->mManager.post( request, json );
7✔
520
  connect( reply, &QNetworkReply::finished, transaction.get(), &PurchasingTransaction::verificationFinished );
7✔
521
  CoreUtils::log( "process transaction", QStringLiteral( "Requesting processing of in-app transaction: " ) + url.toString() );
14✔
522
}
7✔
523

524
void Purchasing::onTransactionCreationFailed()
×
525
{
526
  notify( tr( "Failed to process payment details.%1Subscription is not purchased." ).arg( "<br/>" ) );
×
527
  setTransactionCreationRequested( false );
×
528
}
×
529

530
void Purchasing::onTransactionVerificationSucceeded( PurchasingTransaction *transaction )
7✔
531
{
532
  Q_ASSERT( transaction );
7✔
533
  if ( transaction->type() == PurchasingTransaction::RestoreTransaction )
7✔
534
    notify( tr( "Successfully restored your subscription" ) );
×
535
  else
536
    notify( tr( "Successfully purchased subscription" ) );
7✔
537

538
  removePendingTransaction( transaction );
7✔
539
  mMerginApi->getServiceInfo();
7✔
540
}
7✔
541

542
void Purchasing::onTransactionVerificationFailed( PurchasingTransaction *transaction )
×
543
{
544
  Q_ASSERT( transaction );
×
545
  if ( transaction->type() == PurchasingTransaction::RestoreTransaction )
×
546
    notify( tr( "Unable to restore your subscription" ) );
×
547
  else
548
    notify( tr( "Failed to purchase subscription" ) );
×
549

550
  removePendingTransaction( transaction );
×
551
}
×
552

553
void Purchasing::notify( const QString &msg )
7✔
554
{
555
  mMerginApi->notify( msg );
7✔
556
}
7✔
557

558

559
MerginApi *Purchasing::merginApi() const
7✔
560
{
561
  return mMerginApi;
7✔
562
}
563

564
int Purchasing::registeredPlansCount() const
×
565
{
566
  return mRegisteredPlans.count();
×
567
}
568

569
void Purchasing::removePendingTransaction( PurchasingTransaction *transaction )
7✔
570
{
571
  transaction->finalizeTransaction();
7✔
572

573
  int index = -1;
7✔
574
  for ( int i = 0; i < mTransactionsWithPendingVerification.count(); ++i )
7✔
575
  {
576
    if ( mTransactionsWithPendingVerification.at( i ).get() == transaction )
7✔
577
    {
578
      index = i;
7✔
579
      break;
7✔
580
    }
581
  }
582
  if ( index >= 0 )
7✔
583
  {
584
    mTransactionsWithPendingVerification.removeAt( index );
7✔
585
  }
586

587
  emit transactionPendingChanged();
7✔
588
}
7✔
589

590

591
bool Purchasing::transactionPending() const
9✔
592
{
593
  return !mTransactionsWithPendingVerification.empty() || mTransactionCreationRequested;
9✔
594
}
595

596
PurchasingPlan *Purchasing::individualPlan() const
×
597
{
598
  static PurchasingPlan sEmptyPlan;
×
599

600
  QSharedPointer<PurchasingPlan> plan = registeredPlan( mIndividualPlanId );
×
601
  if ( plan )
×
602
  {
603
    return plan.get();
×
604
  }
605
  else
606
  {
607
    return &sEmptyPlan;
×
608
  }
609
}
×
610

611
PurchasingPlan *Purchasing::professionalPlan() const
×
612
{
613
  static PurchasingPlan sEmptyPlan;
×
614

615
  QSharedPointer<PurchasingPlan> plan = registeredPlan( mProfessionalPlanId );
×
616
  if ( plan )
×
617
  {
618
    return plan.get();
×
619
  }
620
  else
621
  {
622
    return &sEmptyPlan;
×
623
  }
624
}
×
625

626
QSharedPointer<PurchasingPlan> Purchasing::registeredPlan( const QString &id ) const
×
627
{
628
  if ( id.isEmpty() )
×
629
    return nullptr;
×
630

631
  if ( mRegisteredPlans.contains( id ) )
×
632
    return mRegisteredPlans.value( id );
×
633

634
  return nullptr;
×
635
}
636

637
QSharedPointer<PurchasingPlan> Purchasing::pendingPlan( const QString &id ) const
×
638
{
639
  if ( id.isEmpty() )
×
640
    return nullptr;
×
641

642
  if ( mPlansWithPendingRegistration.contains( id ) )
×
643
    return mPlansWithPendingRegistration.value( id );
×
644

645
  return nullptr;
×
646
}
647

648
void Purchasing::setSubscriptionBillingUrl( const QString &subscriptionBillingUrl )
13✔
649
{
650
  if ( mSubscriptionBillingUrl != subscriptionBillingUrl )
13✔
651
  {
652
    mSubscriptionBillingUrl = subscriptionBillingUrl;
×
653
    emit subscriptionBillingUrlChanged();
×
654
  }
655
}
13✔
656

657
void Purchasing::setDefaultUrls()
19✔
658
{
659
  mSubscriptionManageUrl = mMerginApi->apiRoot() + "subscription";
19✔
660
  emit subscriptionManageUrlChanged();
19✔
661
  mSubscriptionBillingUrl = mMerginApi->apiRoot() + "billing";
19✔
662
  emit subscriptionBillingUrlChanged();
19✔
663
}
19✔
664

665
void Purchasing::setSubscriptionManageUrl( const QString &subscriptionManageUrl )
13✔
666
{
667
  if ( mSubscriptionManageUrl != subscriptionManageUrl )
13✔
668
  {
669
    mSubscriptionManageUrl = subscriptionManageUrl;
×
670
    emit subscriptionManageUrlChanged();
×
671
  }
672
}
13✔
673

674
void Purchasing::setHasManageSubscriptionCapability( bool hasManageSubscriptionCapability )
13✔
675
{
676
  if ( mHasManageSubscriptionCapability != hasManageSubscriptionCapability )
13✔
677
  {
678
    mHasManageSubscriptionCapability = hasManageSubscriptionCapability;
5✔
679
    emit hasManageSubscriptionCapabilityChanged();
5✔
680
  }
681
}
13✔
682

683
void Purchasing::setHasInAppPurchases( bool hasInAppPurchases )
22✔
684
{
685
  if ( mHasInAppPurchases != hasInAppPurchases )
22✔
686
  {
687
    mHasInAppPurchases = hasInAppPurchases;
5✔
688
    emit hasInAppPurchasesChanged();
5✔
689
  }
690
}
22✔
691

692
void Purchasing::setTransactionCreationRequested( bool transactionCreationRequested )
14✔
693
{
694
  if ( mTransactionCreationRequested != transactionCreationRequested )
14✔
695
  {
696
    mTransactionCreationRequested = transactionCreationRequested;
14✔
697
    emit transactionPendingChanged();
14✔
698
  }
699
}
14✔
700

701
void Purchasing::setIndividualPlanId( const QString &planId )
4✔
702
{
703
  if ( mIndividualPlanId != planId )
4✔
704
  {
705
    mIndividualPlanId = planId;
4✔
706
    emit individualPlanChanged();
4✔
707
  }
708
}
4✔
709

710
void Purchasing::setProfessionalPlanId( const QString &planId )
4✔
711
{
712
  if ( mProfessionalPlanId != planId )
4✔
713
  {
714
    mProfessionalPlanId = planId;
4✔
715
    emit professionalPlanChanged();
4✔
716
  }
717
}
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc