@gmisoftware/react-native-pay 0.0.13 → 0.0.14

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.
@@ -3,11 +3,13 @@ package com.margelo.nitro.pay
3
3
  import com.google.android.gms.wallet.WalletConstants
4
4
  import org.json.JSONArray
5
5
  import org.json.JSONObject
6
+ import java.util.Locale
6
7
 
7
8
  /**
8
9
  * Builder for Google Pay API request objects
9
10
  */
10
11
  object GooglePayRequestBuilder {
12
+ private val googlePayPriceLocale = Locale.US
11
13
 
12
14
  /**
13
15
  * Creates an IsReadyToPay request
@@ -138,7 +140,7 @@ object GooglePayRequestBuilder {
138
140
 
139
141
  return JSONObject().apply {
140
142
  put("totalPriceStatus", PaymentConstants.TOTAL_PRICE_STATUS_FINAL)
141
- put("totalPrice", String.format("%.2f", totalAmount))
143
+ put("totalPrice", formatPrice(totalAmount))
142
144
  put("totalPriceLabel", PaymentConstants.TOTAL_PRICE_LABEL_DEFAULT)
143
145
  put("currencyCode", request.currencyCode)
144
146
  put("countryCode", request.countryCode)
@@ -165,11 +167,15 @@ object GooglePayRequestBuilder {
165
167
  else
166
168
  PaymentConstants.PENDING_TYPE
167
169
  )
168
- put("price", String.format("%.2f", item.amount))
170
+ put("price", formatPrice(item.amount))
169
171
  })
170
172
  }
171
173
  }
172
174
  }
175
+
176
+ private fun formatPrice(amount: Double): String {
177
+ return String.format(googlePayPriceLocale, "%.2f", amount)
178
+ }
173
179
 
174
180
  /**
175
181
  * Creates allowed auth methods
@@ -30,7 +30,7 @@ private struct PaymentRequestBuilder {
30
30
  paymentRequest.merchantIdentifier = merchantIdentifier
31
31
  paymentRequest.countryCode = request.countryCode
32
32
  paymentRequest.currencyCode = request.currencyCode
33
- paymentRequest.paymentSummaryItems = buildPaymentItems(request.paymentItems)
33
+ paymentRequest.paymentSummaryItems = buildPaymentItems(for: request)
34
34
  paymentRequest.merchantCapabilities = buildMerchantCapabilities(request.merchantCapabilities)
35
35
  paymentRequest.supportedNetworks = buildSupportedNetworks(request.supportedNetworks)
36
36
 
@@ -67,8 +67,8 @@ private struct PaymentRequestBuilder {
67
67
  return nil
68
68
  }
69
69
 
70
- private static func buildPaymentItems(_ items: [PaymentItem]) -> [PKPaymentSummaryItem] {
71
- return items.map { item in
70
+ private static func buildPaymentItems(for request: PaymentRequest) -> [PKPaymentSummaryItem] {
71
+ let lineItems = request.paymentItems.map { item in
72
72
  let pkItem = PKPaymentSummaryItem(
73
73
  label: item.label,
74
74
  amount: NSDecimalNumber(decimal: Decimal(item.amount))
@@ -76,6 +76,29 @@ private struct PaymentRequestBuilder {
76
76
  pkItem.type = item.type == .final ? .final : .pending
77
77
  return pkItem
78
78
  }
79
+
80
+ guard request.paymentItems.count > 1 else {
81
+ return lineItems
82
+ }
83
+
84
+ let totalAmount = request.paymentItems.reduce(Decimal.zero) { partialResult, item in
85
+ partialResult + Decimal(item.amount)
86
+ }
87
+ let totalLabel: String
88
+ if let merchantName = request.merchantName?
89
+ .trimmingCharacters(in: CharacterSet.whitespacesAndNewlines),
90
+ !merchantName.isEmpty {
91
+ totalLabel = merchantName
92
+ } else {
93
+ totalLabel = "Total"
94
+ }
95
+ let totalItem = PKPaymentSummaryItem(
96
+ label: totalLabel,
97
+ amount: NSDecimalNumber(decimal: totalAmount)
98
+ )
99
+ totalItem.type = .final
100
+
101
+ return lineItems + [totalItem]
79
102
  }
80
103
 
81
104
  private static func buildMerchantCapabilities(_ capabilities: [String]) -> PKMerchantCapability {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmisoftware/react-native-pay",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "author": "gmi.software",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,6 +43,16 @@
43
43
  "plugins": [
44
44
  "prettier"
45
45
  ],
46
+ "overrides": [
47
+ {
48
+ "files": [
49
+ "jest.setup.js"
50
+ ],
51
+ "env": {
52
+ "jest": true
53
+ }
54
+ }
55
+ ],
46
56
  "rules": {
47
57
  "prettier/prettier": [
48
58
  "warn",
@@ -23,10 +23,7 @@ describe('usePaymentCheckout integration', () => {
23
23
  mockStartPayment.mockReset()
24
24
  })
25
25
 
26
- const renderCheckout = () =>
27
- renderHook(() =>
28
- usePaymentCheckout({})
29
- )
26
+ const renderCheckout = () => renderHook(() => usePaymentCheckout({}))
30
27
 
31
28
  it('loads payment service status on mount', async () => {
32
29
  const { result } = renderCheckout()
@@ -108,6 +105,13 @@ describe('usePaymentCheckout integration', () => {
108
105
  ])
109
106
  expect(result.current.paymentRequest.countryCode).toBe('US')
110
107
  expect(result.current.paymentRequest.currencyCode).toBe('USD')
108
+ expect(result.current.paymentRequest).not.toHaveProperty(
109
+ 'applePayMerchantIdentifier'
110
+ )
111
+ expect(result.current.paymentRequest).not.toHaveProperty('merchantName')
112
+ expect(result.current.paymentRequest).not.toHaveProperty(
113
+ 'googlePayMerchantId'
114
+ )
111
115
  })
112
116
 
113
117
  it('rejects startPayment when cart is empty', async () => {
@@ -11,7 +11,11 @@ import type {
11
11
  PayServiceStatus,
12
12
  GooglePayEnvironment,
13
13
  } from '../types'
14
- import { createPaymentItem, calculateTotal } from '../utils'
14
+ import {
15
+ createPaymentItem,
16
+ calculateTotal,
17
+ sanitizePaymentRequest,
18
+ } from '../utils'
15
19
 
16
20
  /**
17
21
  * Configuration for `usePaymentCheckout`.
@@ -207,20 +211,20 @@ export function usePaymentCheckout(
207
211
  googlePayGatewayMerchantId,
208
212
  } = config
209
213
 
210
- return {
211
- applePayMerchantIdentifier,
214
+ return sanitizePaymentRequest({
212
215
  countryCode,
213
- merchantName,
214
216
  currencyCode,
215
217
  supportedNetworks,
216
218
  merchantCapabilities,
217
219
  paymentItems:
218
220
  items.length > 0 ? items : [createPaymentItem('Total', 0, 'final')],
221
+ applePayMerchantIdentifier,
222
+ merchantName,
219
223
  googlePayMerchantId,
220
224
  googlePayEnvironment,
221
225
  googlePayGateway,
222
226
  googlePayGatewayMerchantId,
223
- }
227
+ })
224
228
  }, [config, items])
225
229
 
226
230
  // Cart operations
@@ -76,7 +76,7 @@ describe('withApplePay', () => {
76
76
  expect(result).toEqual({
77
77
  modResults: {
78
78
  'com.apple.developer.in-app-payments': ['merchant.com.test'],
79
- ReactNativePayApplePayMerchantIdentifiers: ['merchant.com.test'],
79
+ 'ReactNativePayApplePayMerchantIdentifiers': ['merchant.com.test'],
80
80
  },
81
81
  })
82
82
  })
@@ -7,6 +7,7 @@ import {
7
7
  formatNetworkName,
8
8
  isNetworkSupported,
9
9
  parseAmount,
10
+ sanitizePaymentRequest,
10
11
  } from '../paymentHelpers'
11
12
 
12
13
  describe('paymentHelpers', () => {
@@ -71,10 +72,43 @@ describe('paymentHelpers', () => {
71
72
  expect(request.supportedNetworks).toEqual(['visa'])
72
73
  expect(request.merchantCapabilities).toEqual(['EMV'])
73
74
  expect(request.merchantName).toBe('My Store')
74
- expect(request.applePayMerchantIdentifier).toBe('merchant.com.apple.override')
75
+ expect(request.applePayMerchantIdentifier).toBe(
76
+ 'merchant.com.apple.override'
77
+ )
75
78
  expect(request.googlePayMerchantId).toBe('google-pay-merchant-id')
76
79
  })
77
80
 
81
+ it('omits undefined optional fields from created payment requests', () => {
82
+ const request = createPaymentRequest({
83
+ amount: 10,
84
+ label: 'Order',
85
+ merchantName: undefined,
86
+ googlePayMerchantId: undefined,
87
+ googlePayGateway: 'stripe',
88
+ })
89
+
90
+ expect(request).not.toHaveProperty('merchantName')
91
+ expect(request).not.toHaveProperty('googlePayMerchantId')
92
+ expect(request.googlePayGateway).toBe('stripe')
93
+ })
94
+
95
+ it('sanitizes payment requests before native bridging', () => {
96
+ const request = sanitizePaymentRequest({
97
+ countryCode: 'PL',
98
+ currencyCode: 'PLN',
99
+ paymentItems: [{ label: 'Order', amount: 10, type: 'final' }],
100
+ supportedNetworks: ['visa'],
101
+ merchantCapabilities: ['3DS'],
102
+ merchantName: undefined,
103
+ googlePayGateway: 'przelewy24',
104
+ googlePayGatewayMerchantId: undefined,
105
+ } as any)
106
+
107
+ expect(request).not.toHaveProperty('merchantName')
108
+ expect(request).not.toHaveProperty('googlePayGatewayMerchantId')
109
+ expect(request.googlePayGateway).toBe('przelewy24')
110
+ })
111
+
78
112
  it('formats and parses amount values', () => {
79
113
  expect(formatAmount(29.9)).toBe('29.90')
80
114
  expect(parseAmount('29.90')).toBeCloseTo(29.9)
@@ -29,6 +29,31 @@ export const CommonNetworks = {
29
29
  DISCOVER: 'discover',
30
30
  } as const
31
31
 
32
+ const DEFAULT_SUPPORTED_NETWORKS: PaymentRequest['supportedNetworks'] = [
33
+ CommonNetworks.VISA,
34
+ CommonNetworks.MASTERCARD,
35
+ CommonNetworks.AMEX,
36
+ CommonNetworks.DISCOVER,
37
+ ]
38
+
39
+ const DEFAULT_MERCHANT_CAPABILITIES: PaymentRequest['merchantCapabilities'] = [
40
+ '3DS',
41
+ ]
42
+
43
+ function omitUndefinedProperties<T extends object>(value: T): T {
44
+ return Object.fromEntries(
45
+ Object.entries(value as Record<string, unknown>).filter(
46
+ ([, entryValue]) => entryValue !== undefined
47
+ )
48
+ ) as T
49
+ }
50
+
51
+ export function sanitizePaymentRequest(
52
+ request: PaymentRequest
53
+ ): PaymentRequest {
54
+ return omitUndefinedProperties(request)
55
+ }
56
+
32
57
  /**
33
58
  * Creates a payment item with the specified label, amount, and type.
34
59
  *
@@ -103,24 +128,19 @@ export function createPaymentRequest(
103
128
  label,
104
129
  countryCode = 'US',
105
130
  currencyCode = 'USD',
106
- supportedNetworks = [
107
- CommonNetworks.VISA,
108
- CommonNetworks.MASTERCARD,
109
- CommonNetworks.AMEX,
110
- CommonNetworks.DISCOVER,
111
- ],
112
- merchantCapabilities = ['3DS'],
131
+ supportedNetworks = DEFAULT_SUPPORTED_NETWORKS,
132
+ merchantCapabilities = DEFAULT_MERCHANT_CAPABILITIES,
113
133
  ...rest
114
134
  } = options
115
135
 
116
- return {
136
+ return sanitizePaymentRequest({
117
137
  countryCode,
118
138
  currencyCode,
119
139
  paymentItems: [createPaymentItem(label, amount, 'final')],
120
140
  supportedNetworks,
121
141
  merchantCapabilities,
122
142
  ...rest,
123
- }
143
+ } as PaymentRequest)
124
144
  }
125
145
 
126
146
  /**