1# frozen_string_literal: true
  2
  3require "test_helper"
  4require "credit_card_sale"
  5require "customer"
  6require "transaction"
  7require "ostruct"
  8
  9CreditCardSale::BRAINTREE = Minitest::Mock.new
 10CreditCardSale::REDIS = Minitest::Mock.new
 11TrustLevelRepo::REDIS = Minitest::Mock.new
 12TrustLevelRepo::DB = Minitest::Mock.new
 13CustomerFinancials::REDIS = Minitest::Mock.new
 14
 15class CreditCardSaleTest < Minitest::Test
 16	FAKE_BRAINTREE_TRANSACTION =
 17		OpenStruct.new(
 18			customer_details: OpenStruct.new(id: "customer"),
 19			id: "transaction",
 20			created_at: Time.at(0),
 21			amount: 12
 22		)
 23
 24	def test_sale_fails
 25		CreditCardSale::REDIS.expect(
 26			:exists,
 27			EMPromise.resolve(0),
 28			["jmp_customer_credit_card_lock-test"]
 29		)
 30		TrustLevelRepo::REDIS.expect(
 31			:get,
 32			EMPromise.resolve("Customer"),
 33			["jmp_customer_trust_level-test"]
 34		)
 35		TrustLevelRepo::DB.expect(
 36			:query_one,
 37			EMPromise.resolve({}),
 38			[String, "test"], default: {}
 39		)
 40		CustomerFinancials::REDIS.expect(
 41			:get,
 42			EMPromise.resolve("1"),
 43			["jmp_pay_decline-test"]
 44		)
 45		CustomerFinancials::REDIS.expect(
 46			:incr,
 47			EMPromise.resolve(nil),
 48			["jmp_pay_decline-test"]
 49		)
 50		CustomerFinancials::REDIS.expect(
 51			:expire,
 52			EMPromise.resolve(nil),
 53			["jmp_pay_decline-test", 60 * 60 * 24]
 54		)
 55		braintree_transaction = Minitest::Mock.new
 56		CreditCardSale::BRAINTREE.expect(:transaction, braintree_transaction)
 57		braintree_transaction.expect(
 58			:sale,
 59			EMPromise.resolve(
 60				OpenStruct.new(success?: false, message: "declined")
 61			),
 62			amount: 99,
 63			merchant_account_id: "merchant_usd",
 64			options: { submit_for_settlement: true },
 65			payment_method_token: "token"
 66		)
 67		assert_raises(BraintreeFailure) do
 68			CreditCardSale.new(
 69				customer(plan_name: "test_usd"),
 70				amount: 99,
 71				payment_method: OpenStruct.new(token: "token")
 72			).sale.sync
 73		end
 74		assert_mock CustomerFinancials::REDIS
 75		assert_mock CreditCardSale::REDIS
 76		assert_mock TrustLevelRepo::REDIS
 77		assert_mock TrustLevelRepo::DB
 78	end
 79	em :test_sale_fails
 80
 81	def test_sale_locked
 82		CreditCardSale::REDIS.expect(
 83			:exists,
 84			EMPromise.resolve(1),
 85			["jmp_customer_credit_card_lock-test"]
 86		)
 87		TrustLevelRepo::REDIS.expect(
 88			:get,
 89			EMPromise.resolve("Customer"),
 90			["jmp_customer_trust_level-test"]
 91		)
 92		TrustLevelRepo::DB.expect(
 93			:query_one,
 94			EMPromise.resolve({}),
 95			[String, "test"], default: {}
 96		)
 97		CustomerFinancials::REDIS.expect(
 98			:get,
 99			EMPromise.resolve("0"),
100			["jmp_pay_decline-test"]
101		)
102		assert_raises("locked") do
103			CreditCardSale.new(
104				customer(plan_name: "test_usd"),
105				amount: 123,
106				payment_method: OpenStruct.new(token: "token")
107			).sale.sync
108		end
109		assert_mock CustomerFinancials::REDIS
110		assert_mock CreditCardSale::REDIS
111		assert_mock TrustLevelRepo::REDIS
112		assert_mock TrustLevelRepo::DB
113	end
114	em :test_sale_locked
115
116	def test_sale_amount_too_high
117		CreditCardSale::REDIS.expect(
118			:exists,
119			EMPromise.resolve(0),
120			["jmp_customer_credit_card_lock-test"]
121		)
122		TrustLevelRepo::REDIS.expect(
123			:get,
124			EMPromise.resolve("Customer"),
125			["jmp_customer_trust_level-test"]
126		)
127		TrustLevelRepo::DB.expect(
128			:query_one,
129			EMPromise.resolve({}),
130			[String, "test"], default: {}
131		)
132		CustomerFinancials::REDIS.expect(
133			:get,
134			EMPromise.resolve("0"),
135			["jmp_pay_decline-test"]
136		)
137
138		assert_raises(AmountTooHighError) do
139			CreditCardSale.new(
140				customer(plan_name: "test_usd"),
141				amount: 131,
142				payment_method: OpenStruct.new(token: "token")
143			).sale.sync
144		end
145
146		assert_mock CustomerFinancials::REDIS
147		assert_mock CreditCardSale::REDIS
148		assert_mock TrustLevelRepo::REDIS
149		assert_mock TrustLevelRepo::DB
150	end
151	em :test_sale_amount_too_high
152
153	def test_sale_too_many_declines
154		CreditCardSale::REDIS.expect(
155			:exists,
156			EMPromise.resolve(0),
157			["jmp_customer_credit_card_lock-test"]
158		)
159		TrustLevelRepo::REDIS.expect(
160			:get,
161			EMPromise.resolve("Customer"),
162			["jmp_customer_trust_level-test"]
163		)
164		TrustLevelRepo::DB.expect(
165			:query_one,
166			EMPromise.resolve({}),
167			[String, "test"], default: {}
168		)
169		CustomerFinancials::REDIS.expect(
170			:get,
171			EMPromise.resolve("3"),
172			["jmp_pay_decline-test"]
173		)
174
175		assert_raises(DeclinedError) do
176			CreditCardSale.new(
177				customer(plan_name: "test_usd"),
178				amount: 50,
179				payment_method: OpenStruct.new(token: "token")
180			).sale.sync
181		end
182
183		assert_mock CustomerFinancials::REDIS
184		assert_mock CreditCardSale::REDIS
185		assert_mock TrustLevelRepo::REDIS
186		assert_mock TrustLevelRepo::DB
187	end
188	em :test_sale_too_many_declines
189
190	def test_sale
191		req = stub_request(
192			:post,
193			"https://api.churnbuster.io/v1/successful_payments"
194		).with(
195			body: {
196				customer: {
197					source: "braintree",
198					source_id: "test",
199					email: "test@smtp.cheogram.com",
200					properties: {}
201				},
202				payment: {
203					source: "braintree",
204					source_id: "transaction",
205					amount_in_cents: 9900,
206					currency: "USD"
207				}
208			}.to_json
209		).to_return(status: 200, body: "", headers: {})
210
211		CreditCardSale::REDIS.expect(
212			:exists,
213			EMPromise.resolve(0),
214			["jmp_customer_credit_card_lock-test"]
215		)
216		TrustLevelRepo::REDIS.expect(
217			:get,
218			EMPromise.resolve("Customer"),
219			["jmp_customer_trust_level-test"]
220		)
221		TrustLevelRepo::DB.expect(
222			:query_one,
223			EMPromise.resolve({}),
224			[String, "test"], default: {}
225		)
226		CustomerFinancials::REDIS.expect(
227			:get,
228			EMPromise.resolve("1"),
229			["jmp_pay_decline-test"]
230		)
231		braintree_transaction = Minitest::Mock.new
232		CreditCardSale::BRAINTREE.expect(:transaction, braintree_transaction)
233		braintree_transaction.expect(
234			:sale,
235			EMPromise.resolve(
236				OpenStruct.new(
237					success?: true,
238					transaction: FAKE_BRAINTREE_TRANSACTION
239				)
240			),
241			amount: 99,
242			payment_method_token: "token",
243			merchant_account_id: "merchant_usd",
244			options: { submit_for_settlement: true }
245		)
246		CreditCardSale::REDIS.expect(
247			:setex,
248			EMPromise.resolve(1),
249			["jmp_customer_credit_card_lock-test", 86400, "1"]
250		)
251		result = CreditCardSale.new(
252			customer(plan_name: "test_usd"),
253			amount: 99,
254			payment_method: OpenStruct.new(token: "token")
255		).sale.sync
256		assert_equal FAKE_BRAINTREE_TRANSACTION, result
257		assert_mock CustomerFinancials::REDIS
258		assert_mock CreditCardSale::REDIS
259		assert_mock TrustLevelRepo::REDIS
260		assert_mock TrustLevelRepo::DB
261		assert_requested req
262	end
263	em :test_sale
264
265	def test_builder
266		expected = Transaction.new(
267			customer_id: "customer",
268			transaction_id: "transaction",
269			created_at: Time.at(0),
270			settled_after: Time.at(7776000),
271			amount: 12,
272			note: "Credit card payment"
273		)
274
275		assert_equal(
276			expected,
277			CreditCardSale::BraintreeTransaction.build(FAKE_BRAINTREE_TRANSACTION)
278		)
279	end
280
281	def test_create
282		req = stub_request(
283			:post,
284			"https://api.churnbuster.io/v1/successful_payments"
285		).with(
286			body: {
287				customer: {
288					source: "braintree",
289					source_id: "test",
290					email: "test@smtp.cheogram.com",
291					properties: {}
292				},
293				payment: {
294					source: "braintree",
295					source_id: "transaction",
296					amount_in_cents: 9900,
297					currency: "USD"
298				}
299			}.to_json
300		).to_return(status: 200, body: "", headers: {})
301
302		CreditCardSale::REDIS.expect(
303			:exists,
304			EMPromise.resolve(0),
305			["jmp_customer_credit_card_lock-test"]
306		)
307		TrustLevelRepo::REDIS.expect(
308			:get,
309			EMPromise.resolve("Customer"),
310			["jmp_customer_trust_level-test"]
311		)
312		TrustLevelRepo::DB.expect(
313			:query_one,
314			EMPromise.resolve({}),
315			[String, "test"], default: {}
316		)
317		CustomerFinancials::REDIS.expect(
318			:get,
319			EMPromise.resolve("1"),
320			["jmp_pay_decline-test"]
321		)
322		braintree_transaction = Minitest::Mock.new
323		CreditCardSale::BRAINTREE.expect(:transaction, braintree_transaction)
324		response = EMPromise.resolve(
325			OpenStruct.new(
326				success?: true,
327				transaction: FAKE_BRAINTREE_TRANSACTION
328			)
329		)
330		braintree_transaction.expect(
331			:sale,
332			response,
333			amount: 99,
334			payment_method_token: "token",
335			merchant_account_id: "merchant_usd",
336			options: { submit_for_settlement: true }
337		)
338		CreditCardSale::REDIS.expect(
339			:setex,
340			EMPromise.resolve(1),
341			["jmp_customer_credit_card_lock-test", 86400, "1"]
342		)
343
344		transaction = PromiseMock.new
345		transaction.expect(:insert, EMPromise.resolve(nil))
346
347		transaction_class = Minitest::Mock.new
348		transaction_class.expect(
349			:new,
350			transaction,
351			customer_id: "customer",
352			transaction_id: "transaction",
353			created_at: Time.at(0),
354			settled_after: Time.at(7776000),
355			amount: 12,
356			note: "Credit card payment"
357		)
358
359		result = CreditCardSale.create(
360			customer(plan_name: "test_usd"),
361			amount: 99,
362			payment_method: OpenStruct.new(token: "token"),
363			transaction_class: transaction_class
364		).sync
365
366		assert_equal transaction.object_id, result.object_id
367		assert_mock transaction_class
368		assert_mock transaction
369		assert_mock CustomerFinancials::REDIS
370		assert_mock CreditCardSale::REDIS
371		assert_mock TrustLevelRepo::REDIS
372		assert_mock TrustLevelRepo::DB
373		assert_requested req
374	end
375	em :test_create
376end