react-native-iap 14.3.4 → 14.3.5-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +8 -0
- package/lib/index.js +36 -0
- package/lib/module/hooks/useIAP.js +6 -4
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +14 -12
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +0 -58
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/type-bridge.js +44 -33
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/specs/RnIap.nitro.d.ts +7 -0
- package/lib/specs/RnIap.nitro.js +1 -0
- package/lib/typescript/src/hooks/useIAP.d.ts +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +18 -58
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/package.json +1 -1
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/src/hooks/useIAP.ts +8 -4
- package/src/index.ts +15 -12
- package/src/types.ts +36 -59
- package/src/utils/type-bridge.ts +54 -44
package/src/types.ts
CHANGED
|
@@ -131,11 +131,12 @@ export interface FetchProductsResult {
|
|
|
131
131
|
subscriptions?: ProductSubscription[] | null;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
export type IapEvent =
|
|
135
|
+
| 'promoted-product-ios'
|
|
136
|
+
| 'purchase-error'
|
|
137
|
+
| 'purchase-updated';
|
|
138
|
+
|
|
139
|
+
export type IapPlatform = 'android' | 'ios';
|
|
139
140
|
|
|
140
141
|
export interface Mutation {
|
|
141
142
|
/** Acknowledge a non-consumable purchase or subscription */
|
|
@@ -199,17 +200,11 @@ export interface MutationValidateReceiptArgs {
|
|
|
199
200
|
options: ReceiptValidationProps;
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
export
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export enum Platform {
|
|
210
|
-
Android = 'ANDROID',
|
|
211
|
-
Ios = 'IOS',
|
|
212
|
-
}
|
|
203
|
+
export type PaymentModeIOS =
|
|
204
|
+
| 'empty'
|
|
205
|
+
| 'free-trial'
|
|
206
|
+
| 'pay-as-you-go'
|
|
207
|
+
| 'pay-up-front';
|
|
213
208
|
|
|
214
209
|
export interface PricingPhaseAndroid {
|
|
215
210
|
billingCycleCount: number;
|
|
@@ -235,7 +230,7 @@ export interface ProductAndroid extends ProductCommon {
|
|
|
235
230
|
id: string;
|
|
236
231
|
nameAndroid: string;
|
|
237
232
|
oneTimePurchaseOfferDetailsAndroid?: ProductAndroidOneTimePurchaseOfferDetail | null;
|
|
238
|
-
platform:
|
|
233
|
+
platform: IapPlatform;
|
|
239
234
|
price?: number | null;
|
|
240
235
|
subscriptionOfferDetailsAndroid?:
|
|
241
236
|
| ProductSubscriptionAndroidOfferDetails[]
|
|
@@ -257,7 +252,7 @@ export interface ProductCommon {
|
|
|
257
252
|
displayName?: string | null;
|
|
258
253
|
displayPrice: string;
|
|
259
254
|
id: string;
|
|
260
|
-
platform:
|
|
255
|
+
platform: IapPlatform;
|
|
261
256
|
price?: number | null;
|
|
262
257
|
title: string;
|
|
263
258
|
type: ProductType;
|
|
@@ -273,7 +268,7 @@ export interface ProductIOS extends ProductCommon {
|
|
|
273
268
|
id: string;
|
|
274
269
|
isFamilyShareableIOS: boolean;
|
|
275
270
|
jsonRepresentationIOS: string;
|
|
276
|
-
platform:
|
|
271
|
+
platform: IapPlatform;
|
|
277
272
|
price?: number | null;
|
|
278
273
|
subscriptionInfoIOS?: SubscriptionInfoIOS | null;
|
|
279
274
|
title: string;
|
|
@@ -281,11 +276,7 @@ export interface ProductIOS extends ProductCommon {
|
|
|
281
276
|
typeIOS: ProductTypeIOS;
|
|
282
277
|
}
|
|
283
278
|
|
|
284
|
-
export
|
|
285
|
-
All = 'ALL',
|
|
286
|
-
InApp = 'IN_APP',
|
|
287
|
-
Subs = 'SUBS',
|
|
288
|
-
}
|
|
279
|
+
export type ProductQueryType = 'all' | 'in-app' | 'subs';
|
|
289
280
|
|
|
290
281
|
export interface ProductRequest {
|
|
291
282
|
skus: string[];
|
|
@@ -305,7 +296,7 @@ export interface ProductSubscriptionAndroid extends ProductCommon {
|
|
|
305
296
|
id: string;
|
|
306
297
|
nameAndroid: string;
|
|
307
298
|
oneTimePurchaseOfferDetailsAndroid?: ProductAndroidOneTimePurchaseOfferDetail | null;
|
|
308
|
-
platform:
|
|
299
|
+
platform: IapPlatform;
|
|
309
300
|
price?: number | null;
|
|
310
301
|
subscriptionOfferDetailsAndroid: ProductSubscriptionAndroidOfferDetails[];
|
|
311
302
|
title: string;
|
|
@@ -336,7 +327,7 @@ export interface ProductSubscriptionIOS extends ProductCommon {
|
|
|
336
327
|
introductoryPriceSubscriptionPeriodIOS?: SubscriptionPeriodIOS | null;
|
|
337
328
|
isFamilyShareableIOS: boolean;
|
|
338
329
|
jsonRepresentationIOS: string;
|
|
339
|
-
platform:
|
|
330
|
+
platform: IapPlatform;
|
|
340
331
|
price?: number | null;
|
|
341
332
|
subscriptionInfoIOS?: SubscriptionInfoIOS | null;
|
|
342
333
|
subscriptionPeriodNumberIOS?: string | null;
|
|
@@ -346,17 +337,13 @@ export interface ProductSubscriptionIOS extends ProductCommon {
|
|
|
346
337
|
typeIOS: ProductTypeIOS;
|
|
347
338
|
}
|
|
348
339
|
|
|
349
|
-
export
|
|
350
|
-
InApp = 'IN_APP',
|
|
351
|
-
Subs = 'SUBS',
|
|
352
|
-
}
|
|
340
|
+
export type ProductType = 'in-app' | 'subs';
|
|
353
341
|
|
|
354
|
-
export
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
342
|
+
export type ProductTypeIOS =
|
|
343
|
+
| 'auto-renewable-subscription'
|
|
344
|
+
| 'consumable'
|
|
345
|
+
| 'non-consumable'
|
|
346
|
+
| 'non-renewing-subscription';
|
|
360
347
|
|
|
361
348
|
export type Purchase = PurchaseAndroid | PurchaseIOS;
|
|
362
349
|
|
|
@@ -371,7 +358,7 @@ export interface PurchaseAndroid extends PurchaseCommon {
|
|
|
371
358
|
obfuscatedAccountIdAndroid?: string | null;
|
|
372
359
|
obfuscatedProfileIdAndroid?: string | null;
|
|
373
360
|
packageNameAndroid?: string | null;
|
|
374
|
-
platform:
|
|
361
|
+
platform: IapPlatform;
|
|
375
362
|
productId: string;
|
|
376
363
|
purchaseState: PurchaseState;
|
|
377
364
|
purchaseToken?: string | null;
|
|
@@ -384,7 +371,7 @@ export interface PurchaseCommon {
|
|
|
384
371
|
id: string;
|
|
385
372
|
ids?: string[] | null;
|
|
386
373
|
isAutoRenewing: boolean;
|
|
387
|
-
platform:
|
|
374
|
+
platform: IapPlatform;
|
|
388
375
|
productId: string;
|
|
389
376
|
purchaseState: PurchaseState;
|
|
390
377
|
/** Unified purchase token (iOS JWS, Android purchaseToken) */
|
|
@@ -415,7 +402,7 @@ export interface PurchaseIOS extends PurchaseCommon {
|
|
|
415
402
|
originalTransactionDateIOS?: number | null;
|
|
416
403
|
originalTransactionIdentifierIOS?: string | null;
|
|
417
404
|
ownershipTypeIOS?: string | null;
|
|
418
|
-
platform:
|
|
405
|
+
platform: IapPlatform;
|
|
419
406
|
productId: string;
|
|
420
407
|
purchaseState: PurchaseState;
|
|
421
408
|
purchaseToken?: string | null;
|
|
@@ -436,7 +423,7 @@ export interface PurchaseInput {
|
|
|
436
423
|
id: string;
|
|
437
424
|
ids?: string[] | null;
|
|
438
425
|
isAutoRenewing: boolean;
|
|
439
|
-
platform:
|
|
426
|
+
platform: IapPlatform;
|
|
440
427
|
productId: string;
|
|
441
428
|
purchaseState: PurchaseState;
|
|
442
429
|
purchaseToken?: string | null;
|
|
@@ -466,14 +453,13 @@ export interface PurchaseParams {
|
|
|
466
453
|
type?: ProductQueryType | null;
|
|
467
454
|
}
|
|
468
455
|
|
|
469
|
-
export
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
456
|
+
export type PurchaseState =
|
|
457
|
+
| 'deferred'
|
|
458
|
+
| 'failed'
|
|
459
|
+
| 'pending'
|
|
460
|
+
| 'purchased'
|
|
461
|
+
| 'restored'
|
|
462
|
+
| 'unknown';
|
|
477
463
|
|
|
478
464
|
export interface Query {
|
|
479
465
|
/** Get current StoreKit 2 entitlements (iOS 15+) */
|
|
@@ -710,18 +696,9 @@ export interface SubscriptionOfferIOS {
|
|
|
710
696
|
type: SubscriptionOfferTypeIOS;
|
|
711
697
|
}
|
|
712
698
|
|
|
713
|
-
export
|
|
714
|
-
Introductory = 'INTRODUCTORY',
|
|
715
|
-
Promotional = 'PROMOTIONAL',
|
|
716
|
-
}
|
|
699
|
+
export type SubscriptionOfferTypeIOS = 'introductory' | 'promotional';
|
|
717
700
|
|
|
718
|
-
export
|
|
719
|
-
Day = 'DAY',
|
|
720
|
-
Empty = 'EMPTY',
|
|
721
|
-
Month = 'MONTH',
|
|
722
|
-
Week = 'WEEK',
|
|
723
|
-
Year = 'YEAR',
|
|
724
|
-
}
|
|
701
|
+
export type SubscriptionPeriodIOS = 'day' | 'empty' | 'month' | 'week' | 'year';
|
|
725
702
|
|
|
726
703
|
export interface SubscriptionPeriodValueIOS {
|
|
727
704
|
unit: SubscriptionPeriodIOS;
|
package/src/utils/type-bridge.ts
CHANGED
|
@@ -10,8 +10,8 @@ import type {
|
|
|
10
10
|
NitroPurchase,
|
|
11
11
|
NitroSubscriptionStatus,
|
|
12
12
|
} from '../specs/RnIap.nitro';
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import type {
|
|
14
|
+
IapPlatform,
|
|
15
15
|
PaymentModeIOS,
|
|
16
16
|
ProductType,
|
|
17
17
|
ProductTypeIOS,
|
|
@@ -25,51 +25,61 @@ import type {
|
|
|
25
25
|
SubscriptionStatusIOS,
|
|
26
26
|
} from '../types';
|
|
27
27
|
|
|
28
|
-
const PLATFORM_IOS = 'ios';
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
28
|
+
const PLATFORM_IOS: IapPlatform = 'ios';
|
|
29
|
+
const PLATFORM_ANDROID: IapPlatform = 'android';
|
|
30
|
+
const PRODUCT_TYPE_SUBS: ProductType = 'subs';
|
|
31
|
+
const PRODUCT_TYPE_IN_APP: ProductType = 'in-app';
|
|
32
|
+
const PURCHASE_STATE_DEFERRED: PurchaseState = 'deferred';
|
|
33
|
+
const PURCHASE_STATE_FAILED: PurchaseState = 'failed';
|
|
34
|
+
const PURCHASE_STATE_PENDING: PurchaseState = 'pending';
|
|
35
|
+
const PURCHASE_STATE_PURCHASED: PurchaseState = 'purchased';
|
|
36
|
+
const PURCHASE_STATE_RESTORED: PurchaseState = 'restored';
|
|
37
|
+
const PURCHASE_STATE_UNKNOWN: PurchaseState = 'unknown';
|
|
38
|
+
const PAYMENT_MODE_EMPTY: PaymentModeIOS = 'empty';
|
|
39
|
+
const PAYMENT_MODE_FREE_TRIAL: PaymentModeIOS = 'free-trial';
|
|
40
|
+
const PAYMENT_MODE_PAY_AS_YOU_GO: PaymentModeIOS = 'pay-as-you-go';
|
|
41
|
+
const PAYMENT_MODE_PAY_UP_FRONT: PaymentModeIOS = 'pay-up-front';
|
|
42
|
+
const SUBSCRIPTION_PERIOD_DAY: SubscriptionPeriodIOS = 'day';
|
|
43
|
+
const SUBSCRIPTION_PERIOD_WEEK: SubscriptionPeriodIOS = 'week';
|
|
44
|
+
const SUBSCRIPTION_PERIOD_MONTH: SubscriptionPeriodIOS = 'month';
|
|
45
|
+
const SUBSCRIPTION_PERIOD_YEAR: SubscriptionPeriodIOS = 'year';
|
|
46
|
+
const SUBSCRIPTION_PERIOD_EMPTY: SubscriptionPeriodIOS = 'empty';
|
|
35
47
|
const DEFAULT_JSON_REPR = '{}';
|
|
36
48
|
|
|
37
49
|
type Nullable<T> = T | null | undefined;
|
|
38
50
|
|
|
39
51
|
function normalizePlatform(value?: Nullable<string>): IapPlatform {
|
|
40
|
-
return value?.toLowerCase() === PLATFORM_IOS
|
|
41
|
-
? IapPlatform.Ios
|
|
42
|
-
: IapPlatform.Android;
|
|
52
|
+
return value?.toLowerCase() === PLATFORM_IOS ? PLATFORM_IOS : PLATFORM_ANDROID;
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
function normalizeProductType(value?: Nullable<string>): ProductType {
|
|
46
56
|
return value?.toLowerCase() === PRODUCT_TYPE_SUBS
|
|
47
|
-
?
|
|
48
|
-
:
|
|
57
|
+
? PRODUCT_TYPE_SUBS
|
|
58
|
+
: PRODUCT_TYPE_IN_APP;
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
function normalizeProductTypeIOS(value?: Nullable<string>): ProductTypeIOS {
|
|
52
62
|
switch ((value ?? '').toLowerCase()) {
|
|
53
63
|
case 'consumable':
|
|
54
|
-
return
|
|
64
|
+
return 'consumable';
|
|
55
65
|
case 'nonconsumable':
|
|
56
66
|
case 'non_consumable':
|
|
57
67
|
case 'non-consumable':
|
|
58
|
-
return
|
|
68
|
+
return 'non-consumable';
|
|
59
69
|
case 'autorenewablesubscription':
|
|
60
70
|
case 'auto_renewable_subscription':
|
|
61
71
|
case 'autorenewable':
|
|
62
|
-
return
|
|
72
|
+
return 'auto-renewable-subscription';
|
|
63
73
|
case 'nonrenewingsubscription':
|
|
64
74
|
case 'non_renewing_subscription':
|
|
65
|
-
return
|
|
75
|
+
return 'non-renewing-subscription';
|
|
66
76
|
default:
|
|
67
77
|
if (value) {
|
|
68
78
|
console.warn(
|
|
69
79
|
`[react-native-iap] Unknown iOS product type "${value}", defaulting to NonConsumable.`,
|
|
70
80
|
);
|
|
71
81
|
}
|
|
72
|
-
return
|
|
82
|
+
return 'non-consumable';
|
|
73
83
|
}
|
|
74
84
|
}
|
|
75
85
|
|
|
@@ -77,15 +87,15 @@ function normalizePaymentMode(value?: Nullable<string>): PaymentModeIOS | null {
|
|
|
77
87
|
switch ((value ?? '').toUpperCase()) {
|
|
78
88
|
case 'FREE_TRIAL':
|
|
79
89
|
case 'FREETRIAL':
|
|
80
|
-
return
|
|
90
|
+
return PAYMENT_MODE_FREE_TRIAL;
|
|
81
91
|
case 'PAY_AS_YOU_GO':
|
|
82
92
|
case 'PAYASYOUGO':
|
|
83
|
-
return
|
|
93
|
+
return PAYMENT_MODE_PAY_AS_YOU_GO;
|
|
84
94
|
case 'PAY_UP_FRONT':
|
|
85
95
|
case 'PAYUPFRONT':
|
|
86
|
-
return
|
|
96
|
+
return PAYMENT_MODE_PAY_UP_FRONT;
|
|
87
97
|
default:
|
|
88
|
-
return
|
|
98
|
+
return PAYMENT_MODE_EMPTY;
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
101
|
|
|
@@ -94,15 +104,15 @@ function normalizeSubscriptionPeriod(
|
|
|
94
104
|
): SubscriptionPeriodIOS | null {
|
|
95
105
|
switch ((value ?? '').toUpperCase()) {
|
|
96
106
|
case 'DAY':
|
|
97
|
-
return
|
|
107
|
+
return SUBSCRIPTION_PERIOD_DAY;
|
|
98
108
|
case 'WEEK':
|
|
99
|
-
return
|
|
109
|
+
return SUBSCRIPTION_PERIOD_WEEK;
|
|
100
110
|
case 'MONTH':
|
|
101
|
-
return
|
|
111
|
+
return SUBSCRIPTION_PERIOD_MONTH;
|
|
102
112
|
case 'YEAR':
|
|
103
|
-
return
|
|
113
|
+
return SUBSCRIPTION_PERIOD_YEAR;
|
|
104
114
|
default:
|
|
105
|
-
return
|
|
115
|
+
return SUBSCRIPTION_PERIOD_EMPTY;
|
|
106
116
|
}
|
|
107
117
|
}
|
|
108
118
|
|
|
@@ -110,32 +120,32 @@ function normalizePurchaseState(state: unknown): PurchaseState {
|
|
|
110
120
|
if (typeof state === 'string') {
|
|
111
121
|
switch (state.toLowerCase()) {
|
|
112
122
|
case PURCHASE_STATE_PURCHASED:
|
|
113
|
-
return
|
|
123
|
+
return PURCHASE_STATE_PURCHASED;
|
|
114
124
|
case PURCHASE_STATE_PENDING:
|
|
115
|
-
return
|
|
125
|
+
return PURCHASE_STATE_PENDING;
|
|
116
126
|
case PURCHASE_STATE_FAILED:
|
|
117
|
-
return
|
|
127
|
+
return PURCHASE_STATE_FAILED;
|
|
118
128
|
case PURCHASE_STATE_RESTORED:
|
|
119
|
-
return
|
|
129
|
+
return PURCHASE_STATE_RESTORED;
|
|
120
130
|
case PURCHASE_STATE_DEFERRED:
|
|
121
|
-
return
|
|
131
|
+
return PURCHASE_STATE_DEFERRED;
|
|
122
132
|
default:
|
|
123
|
-
return
|
|
133
|
+
return PURCHASE_STATE_UNKNOWN;
|
|
124
134
|
}
|
|
125
135
|
}
|
|
126
136
|
|
|
127
137
|
if (typeof state === 'number') {
|
|
128
138
|
switch (state) {
|
|
129
139
|
case 1:
|
|
130
|
-
return
|
|
140
|
+
return PURCHASE_STATE_PURCHASED;
|
|
131
141
|
case 2:
|
|
132
|
-
return
|
|
142
|
+
return PURCHASE_STATE_PENDING;
|
|
133
143
|
default:
|
|
134
|
-
return
|
|
144
|
+
return PURCHASE_STATE_UNKNOWN;
|
|
135
145
|
}
|
|
136
146
|
}
|
|
137
147
|
|
|
138
|
-
return
|
|
148
|
+
return PURCHASE_STATE_UNKNOWN;
|
|
139
149
|
}
|
|
140
150
|
|
|
141
151
|
function toNullableString(value: unknown): string | null {
|
|
@@ -192,7 +202,7 @@ export function convertNitroProductToProduct(
|
|
|
192
202
|
platform,
|
|
193
203
|
};
|
|
194
204
|
|
|
195
|
-
if (platform ===
|
|
205
|
+
if (platform === PLATFORM_IOS) {
|
|
196
206
|
const iosProduct: any = {
|
|
197
207
|
...base,
|
|
198
208
|
displayNameIOS: nitroProduct.displayName ?? nitroProduct.title,
|
|
@@ -241,7 +251,7 @@ export function convertNitroProductToProduct(
|
|
|
241
251
|
),
|
|
242
252
|
};
|
|
243
253
|
|
|
244
|
-
if (type ===
|
|
254
|
+
if (type === PRODUCT_TYPE_SUBS) {
|
|
245
255
|
if (!Array.isArray(androidProduct.subscriptionOfferDetailsAndroid)) {
|
|
246
256
|
androidProduct.subscriptionOfferDetailsAndroid = [];
|
|
247
257
|
}
|
|
@@ -256,7 +266,7 @@ export function convertNitroProductToProduct(
|
|
|
256
266
|
export function convertProductToProductSubscription(
|
|
257
267
|
product: Product,
|
|
258
268
|
): ProductSubscription {
|
|
259
|
-
if (product.type !==
|
|
269
|
+
if (product.type !== PRODUCT_TYPE_SUBS) {
|
|
260
270
|
console.warn(
|
|
261
271
|
'Converting non-subscription product to ProductSubscription:',
|
|
262
272
|
product.id,
|
|
@@ -265,7 +275,7 @@ export function convertProductToProductSubscription(
|
|
|
265
275
|
|
|
266
276
|
const output: any = {...(product as any)};
|
|
267
277
|
|
|
268
|
-
if (output.platform ===
|
|
278
|
+
if (output.platform === PLATFORM_ANDROID) {
|
|
269
279
|
if (!Array.isArray(output.subscriptionOfferDetailsAndroid)) {
|
|
270
280
|
output.subscriptionOfferDetailsAndroid = [];
|
|
271
281
|
}
|
|
@@ -296,7 +306,7 @@ export function convertNitroPurchaseToPurchase(
|
|
|
296
306
|
};
|
|
297
307
|
|
|
298
308
|
if (
|
|
299
|
-
purchase.purchaseState ===
|
|
309
|
+
purchase.purchaseState === PURCHASE_STATE_UNKNOWN &&
|
|
300
310
|
nitroPurchase.purchaseStateAndroid != null
|
|
301
311
|
) {
|
|
302
312
|
purchase.purchaseState = normalizePurchaseState(
|
|
@@ -304,7 +314,7 @@ export function convertNitroPurchaseToPurchase(
|
|
|
304
314
|
);
|
|
305
315
|
}
|
|
306
316
|
|
|
307
|
-
if (platform ===
|
|
317
|
+
if (platform === PLATFORM_IOS) {
|
|
308
318
|
const iosPurchase: any = purchase;
|
|
309
319
|
iosPurchase.quantityIOS = toNullableNumber(nitroPurchase.quantityIOS);
|
|
310
320
|
iosPurchase.originalTransactionDateIOS = toNullableNumber(
|