solidus_paypal_braintree 0.4.0 → 1.0.0

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.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +40 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +18 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +68 -0
  8. data/CHANGELOG.md +258 -0
  9. data/Gemfile +43 -0
  10. data/LICENSE +2 -2
  11. data/README.md +77 -23
  12. data/Rakefile +4 -25
  13. data/app/assets/javascripts/solidus_paypal_braintree/checkout.js +32 -3
  14. data/app/assets/javascripts/solidus_paypal_braintree/client.js +23 -4
  15. data/app/assets/javascripts/solidus_paypal_braintree/constants.js +19 -0
  16. data/app/assets/javascripts/solidus_paypal_braintree/frontend.js +1 -0
  17. data/app/assets/javascripts/solidus_paypal_braintree/hosted_form.js +15 -5
  18. data/app/assets/javascripts/solidus_paypal_braintree/paypal_button.js +47 -20
  19. data/app/assets/javascripts/solidus_paypal_braintree/paypal_messaging.js +22 -0
  20. data/app/decorators/controllers/solidus_paypal_braintree/admin_payments_controller_decorator.rb +11 -0
  21. data/app/decorators/controllers/solidus_paypal_braintree/checkout_controller_decorator.rb +11 -0
  22. data/app/decorators/controllers/solidus_paypal_braintree/client_tokens_controller.rb +41 -0
  23. data/app/decorators/controllers/solidus_paypal_braintree/orders_controller_decorator.rb +11 -0
  24. data/app/decorators/models/solidus_paypal_braintree/spree/store_decorator.rb +20 -0
  25. data/app/decorators/models/solidus_paypal_braintree/spree/user_decorator.rb +13 -0
  26. data/app/helpers/solidus_paypal_braintree/braintree_admin_helper.rb +23 -0
  27. data/app/helpers/solidus_paypal_braintree/braintree_checkout_helper.rb +46 -0
  28. data/app/models/application_record.rb +2 -0
  29. data/app/models/solidus_paypal_braintree/address.rb +30 -0
  30. data/app/models/solidus_paypal_braintree/configuration.rb +26 -3
  31. data/app/models/solidus_paypal_braintree/customer.rb +7 -3
  32. data/app/models/solidus_paypal_braintree/gateway.rb +52 -20
  33. data/app/models/solidus_paypal_braintree/response.rb +3 -2
  34. data/app/models/solidus_paypal_braintree/source.rb +21 -7
  35. data/app/models/solidus_paypal_braintree/transaction.rb +2 -0
  36. data/app/models/solidus_paypal_braintree/transaction_address.rb +30 -12
  37. data/app/models/solidus_paypal_braintree/transaction_import.rb +13 -9
  38. data/app/views/spree/api/payments/source_views/_paypal_braintree.json.jbuilder +3 -0
  39. data/app/views/spree/checkout/existing_payment/_paypal_braintree.html.erb +10 -0
  40. data/app/views/spree/shared/_apple_pay_button.html.erb +2 -2
  41. data/app/views/spree/shared/_braintree_errors.html.erb +11 -17
  42. data/app/views/spree/shared/_braintree_hosted_fields.html.erb +24 -9
  43. data/app/views/spree/shared/_paypal_braintree_head_scripts.html.erb +9 -6
  44. data/app/views/spree/shared/_paypal_cart_button.html.erb +16 -2
  45. data/app/views/spree/shared/_paypal_messaging.html.erb +13 -0
  46. data/bin/console +17 -0
  47. data/bin/rails +15 -0
  48. data/bin/setup +8 -0
  49. data/config/locales/en.yml +10 -0
  50. data/config/locales/it.yml +51 -8
  51. data/config/routes.rb +2 -0
  52. data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +3 -1
  53. data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +5 -7
  54. data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +3 -1
  55. data/db/migrate/20190705115327_add_paypal_button_preferences_to_braintree_configurations.rb +5 -0
  56. data/db/migrate/20190911141712_add_3d_secure_to_braintree_configuration.rb +5 -0
  57. data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +20 -5
  58. data/lib/controllers/frontend/solidus_paypal_braintree/checkouts_controller.rb +25 -21
  59. data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +55 -51
  60. data/lib/generators/solidus_paypal_braintree/install/install_generator.rb +7 -5
  61. data/lib/solidus_paypal_braintree.rb +4 -0
  62. data/lib/solidus_paypal_braintree/country_mapper.rb +4 -2
  63. data/lib/solidus_paypal_braintree/engine.rb +11 -11
  64. data/lib/solidus_paypal_braintree/factories.rb +8 -4
  65. data/lib/solidus_paypal_braintree/request_protection.rb +3 -0
  66. data/lib/solidus_paypal_braintree/version.rb +3 -1
  67. data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +30 -5
  68. data/lib/views/backend/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
  69. data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +2 -2
  70. data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_paypal_braintree.html.erb +2 -2
  71. data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +4 -2
  72. data/lib/views/frontend/spree/shared/_paypal_checkout_button.html.erb +30 -0
  73. data/solidus_paypal_braintree.gemspec +42 -0
  74. data/spec/controllers/solidus_paypal_braintree/checkouts_controller_spec.rb +99 -0
  75. data/spec/controllers/solidus_paypal_braintree/client_tokens_controller_spec.rb +55 -0
  76. data/spec/controllers/solidus_paypal_braintree/configurations_controller_spec.rb +73 -0
  77. data/spec/controllers/solidus_paypal_braintree/transactions_controller_spec.rb +183 -0
  78. data/spec/features/backend/configuration_spec.rb +23 -0
  79. data/spec/features/backend/new_payment_spec.rb +137 -0
  80. data/spec/features/frontend/braintree_credit_card_checkout_spec.rb +187 -0
  81. data/spec/features/frontend/paypal_checkout_spec.rb +166 -0
  82. data/spec/fixtures/cassettes/admin/invalid_credit_card.yml +63 -0
  83. data/spec/fixtures/cassettes/admin/resubmit_credit_card.yml +352 -0
  84. data/spec/fixtures/cassettes/admin/valid_credit_card.yml +412 -0
  85. data/spec/fixtures/cassettes/braintree/create_profile.yml +71 -0
  86. data/spec/fixtures/cassettes/braintree/generate_token.yml +63 -0
  87. data/spec/fixtures/cassettes/braintree/token.yml +63 -0
  88. data/spec/fixtures/cassettes/checkout/invalid_credit_card.yml +63 -0
  89. data/spec/fixtures/cassettes/checkout/resubmit_credit_card.yml +216 -0
  90. data/spec/fixtures/cassettes/checkout/update.yml +71 -0
  91. data/spec/fixtures/cassettes/checkout/valid_credit_card.yml +156 -0
  92. data/spec/fixtures/cassettes/gateway/authorize.yml +86 -0
  93. data/spec/fixtures/cassettes/gateway/authorize/credit_card/address.yml +86 -0
  94. data/spec/fixtures/cassettes/gateway/authorize/merchant_account/EUR.yml +154 -0
  95. data/spec/fixtures/cassettes/gateway/authorize/paypal/EUR.yml +90 -0
  96. data/spec/fixtures/cassettes/gateway/authorize/paypal/address.yml +90 -0
  97. data/spec/fixtures/cassettes/gateway/authorized_transaction.yml +73 -0
  98. data/spec/fixtures/cassettes/gateway/cancel/missing.yml +63 -0
  99. data/spec/fixtures/cassettes/gateway/cancel/refunds.yml +272 -0
  100. data/spec/fixtures/cassettes/gateway/cancel/void.yml +201 -0
  101. data/spec/fixtures/cassettes/gateway/capture.yml +141 -0
  102. data/spec/fixtures/cassettes/gateway/complete.yml +157 -0
  103. data/spec/fixtures/cassettes/gateway/credit.yml +208 -0
  104. data/spec/fixtures/cassettes/gateway/purchase.yml +87 -0
  105. data/spec/fixtures/cassettes/gateway/settled_transaction.yml +140 -0
  106. data/spec/fixtures/cassettes/gateway/void.yml +137 -0
  107. data/spec/fixtures/cassettes/source/card_type.yml +267 -0
  108. data/spec/fixtures/cassettes/source/last4.yml +267 -0
  109. data/spec/fixtures/cassettes/transaction/import/valid.yml +71 -0
  110. data/spec/fixtures/cassettes/transaction/import/valid/capture.yml +224 -0
  111. data/spec/fixtures/views/spree/orders/edit.html.erb +50 -0
  112. data/spec/helpers/solidus_paypal_braintree/braintree_admin_helper_spec.rb +17 -0
  113. data/spec/models/solidus_paypal_braintree/address_spec.rb +51 -0
  114. data/spec/models/solidus_paypal_braintree/avs_result_spec.rb +317 -0
  115. data/spec/models/solidus_paypal_braintree/gateway_spec.rb +692 -0
  116. data/spec/models/solidus_paypal_braintree/response_spec.rb +280 -0
  117. data/spec/models/solidus_paypal_braintree/source_spec.rb +360 -0
  118. data/spec/models/solidus_paypal_braintree/transaction_address_spec.rb +253 -0
  119. data/spec/models/solidus_paypal_braintree/transaction_import_spec.rb +283 -0
  120. data/spec/models/solidus_paypal_braintree/transaction_spec.rb +85 -0
  121. data/spec/models/spree/store_spec.rb +14 -0
  122. data/spec/requests/spree/api/orders_controller_spec.rb +36 -0
  123. data/spec/spec_helper.rb +26 -0
  124. data/spec/support/capybara.rb +7 -0
  125. data/spec/support/factories.rb +2 -0
  126. data/spec/support/gateway_helpers.rb +29 -0
  127. data/spec/support/order_ready_for_payment.rb +37 -0
  128. data/spec/support/vcr.rb +42 -0
  129. data/spec/support/views.rb +1 -0
  130. metadata +182 -194
  131. data/app/controllers/solidus_paypal_braintree/client_tokens_controller.rb +0 -22
  132. data/app/helpers/braintree_admin_helper.rb +0 -18
  133. data/app/models/spree/store_decorator.rb +0 -11
  134. data/app/views/spree/shared/_paypal_checkout_button.html.erb +0 -27
  135. data/config/initializers/braintree.rb +0 -1
@@ -0,0 +1,71 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.sandbox.braintreegateway.com/merchants/7rdg92j7bm7fk5h3/customers
6
+ body:
7
+ encoding: UTF-8
8
+ string: |
9
+ <?xml version="1.0" encoding="UTF-8"?>
10
+ <customer>
11
+ <payment-method-nonce>fake-valid-nonce</payment-method-nonce>
12
+ </customer>
13
+ headers:
14
+ Accept-Encoding:
15
+ - gzip
16
+ Accept:
17
+ - application/xml
18
+ User-Agent:
19
+ - Braintree Ruby Gem 2.98.0
20
+ X-Apiversion:
21
+ - '5'
22
+ Content-Type:
23
+ - application/xml
24
+ Authorization:
25
+ - Basic bXdqa2t4d2NwMzJja2huZjphOTI5OGY0M2IzMGM2OTlkYjMwNzJjYzRhMDBmN2Y0OQ==
26
+ response:
27
+ status:
28
+ code: 201
29
+ message: Created
30
+ headers:
31
+ Date:
32
+ - Fri, 13 Sep 2019 14:27:57 GMT
33
+ Content-Type:
34
+ - application/xml; charset=utf-8
35
+ Transfer-Encoding:
36
+ - chunked
37
+ X-Frame-Options:
38
+ - SAMEORIGIN
39
+ X-Xss-Protection:
40
+ - 1; mode=block
41
+ X-Content-Type-Options:
42
+ - nosniff
43
+ X-Authentication:
44
+ - basic_auth
45
+ X-User:
46
+ - 3v249hqtptsg744y
47
+ Vary:
48
+ - Accept-Encoding
49
+ Content-Encoding:
50
+ - gzip
51
+ Etag:
52
+ - W/"353759854f3f20558dfdfbeff3bd4668"
53
+ Cache-Control:
54
+ - max-age=0, private, must-revalidate
55
+ X-Runtime:
56
+ - '0.384787'
57
+ X-Request-Id:
58
+ - 02-1568384876.677-92.223.152.178-13026259
59
+ Content-Security-Policy:
60
+ - frame-ancestors 'self'
61
+ X-Broxyid:
62
+ - 02-1568384876.677-92.223.152.178-13026259
63
+ Strict-Transport-Security:
64
+ - max-age=31536000; includeSubDomains
65
+ body:
66
+ encoding: ASCII-8BIT
67
+ string: !binary |-
68
+ H4sIAG2ne10AA6xWXXPaOhB9z69g/O4YAy44Y5xp506405mmD01y27x0ZGuNFWTJlWQC/fVXMv7iw5RM+saePSutV2d3CW43GR2sQUjC2dxyr4fWAFjMMWHLufX4cGfPrNvwKogLqXgGIrwaDAKCQ8+fTob+eOgHjrYMqJ1xipiytT0VeOmPXqZRNk1WXjoOnK7XsBMipLIZymDACJ1bShRgOaWLoj5PzLMcse0RDhki9AjNU86Oz0jQ5gh7hUgSdeI+AUgBtpEaqG0OcwtrU5EMrHA0dH176Nvu+MGd3IymN970OXDagDK+yPHb4tuA3f1l0e2EAMVyl9KS8ghRU8Uf46ffeOGr5++fk/uH1fj+n4/el98fvcBpOdVHYKLsGAksqzSQEGhrGe++f4doLCKUagHYCGMBUtb47ul/zeo3r7BaG/a+LrpwS+5/+IrQ+/z1badFUHmlEgCqTryHBBsFDJs6n6VRHiNKVN9VApa6Z3qcOZdKv4FuJAj9iTucBk4X6n5OwZTYlrCNaJ6iUe+HHzLHlzBZod+AxH+gniv4+7qgOuWdvVCe4fToUuuVhZOhO5rNDIc1uBG1ba4Ln4hEOrPG7jJSTrGWaV8JjOLM+CKIho9sxfgr0ye1WEvblZInNpGyQCyGLv/Y2QS+v8Bv6MGWavSttITDx28dZoPWfAwRUe2X7MzWmaCC1olHnFNAzApNBQ21dLbkQujXsXXjFNR8QOfQQ08dApuciDIfO+NMpaE7Cpwj8AR7C0jo8o2Ge/QS3WMDPsw9QVRCFdXJpJ2q8eLOi/57KvDCpXiRrp/v/Jcfrv8S//vp5etCHgzgMjgFRFWqxdaRRAeraSRDS7ALQcNUqVzeOA6SEpS8jgQizIy2pa7OK9pea/05OdpmwNTPDFTK8U/Kl9xZa51f52x5C2xNBGeGMJeI4Yhv9Nhuzm9u1GI0HRUhtmpT20NrajmYJ6E7m7mBUxm1T6ciOO30Rw00BAE50gW559pX/W59HBdx+degjW+xmiaLSMaC5OYh9zdZ26qKr4CFcZ7Hs1Xg7KzaVzDyqyjnYVQ2hK4M0atVhCjxvOnETzw/cRM8nuEPcRK7Gkgm3ixKtOB6Q5uz/8J0WwPLuC3xqkeQjb8TIXQau3Y9WZFyVHS3+x5Qzs+gmqVw8s/B4aA9Wv9vGTznV//5xX9u7V+w9C9a+WcX/pl1f+Gyv3TVX7roL17zf1zyf2UDvbsFAqejtsYAbbZyCq/+BwAA//8DAGwXsMSxDAAA
69
+ http_version:
70
+ recorded_at: Fri, 13 Sep 2019 14:27:57 GMT
71
+ recorded_with: VCR 5.0.0
@@ -0,0 +1,224 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://api.sandbox.braintreegateway.com/merchants/7rdg92j7bm7fk5h3/customers
6
+ body:
7
+ encoding: UTF-8
8
+ string: |
9
+ <?xml version="1.0" encoding="UTF-8"?>
10
+ <customer>
11
+ <payment-method-nonce>fake-valid-nonce</payment-method-nonce>
12
+ </customer>
13
+ headers:
14
+ Accept-Encoding:
15
+ - gzip
16
+ Accept:
17
+ - application/xml
18
+ User-Agent:
19
+ - Braintree Ruby Gem 2.98.0
20
+ X-Apiversion:
21
+ - '5'
22
+ Content-Type:
23
+ - application/xml
24
+ Authorization:
25
+ - Basic bXdqa2t4d2NwMzJja2huZjphOTI5OGY0M2IzMGM2OTlkYjMwNzJjYzRhMDBmN2Y0OQ==
26
+ response:
27
+ status:
28
+ code: 201
29
+ message: Created
30
+ headers:
31
+ Date:
32
+ - Fri, 13 Sep 2019 14:28:01 GMT
33
+ Content-Type:
34
+ - application/xml; charset=utf-8
35
+ Transfer-Encoding:
36
+ - chunked
37
+ X-Frame-Options:
38
+ - SAMEORIGIN
39
+ X-Xss-Protection:
40
+ - 1; mode=block
41
+ X-Content-Type-Options:
42
+ - nosniff
43
+ X-Authentication:
44
+ - basic_auth
45
+ X-User:
46
+ - 3v249hqtptsg744y
47
+ Vary:
48
+ - Accept-Encoding
49
+ Content-Encoding:
50
+ - gzip
51
+ Etag:
52
+ - W/"110ef4341df24590b6e3c609ec3ba459"
53
+ Cache-Control:
54
+ - max-age=0, private, must-revalidate
55
+ X-Runtime:
56
+ - '0.378468'
57
+ X-Request-Id:
58
+ - 02-1568384880.224-92.223.152.178-13026813
59
+ Content-Security-Policy:
60
+ - frame-ancestors 'self'
61
+ X-Broxyid:
62
+ - 02-1568384880.224-92.223.152.178-13026813
63
+ Strict-Transport-Security:
64
+ - max-age=31536000; includeSubDomains
65
+ body:
66
+ encoding: ASCII-8BIT
67
+ string: !binary |-
68
+ H4sIAHGne10AA6xWy3KjOhDd5ytc7AkPmxhSmOySqVlkc5PMJJspgRqjWEhcSTj2fP0IzMsPPE5ldu7Tp6Wmdbrb4d0mp5M1CEk4WxjOtW1MgCUcE7ZcGM9P96Zv3EVXYVJKxXMQ0dVkEhIc3cxtb+55wTS0tFWB2plkiClT23OBl4H7Po/zebryMk0aeit2SoRUJkM5TBihC0OJEgyrdlE05kl4XiC2PcIhR4QeoUXG2fEZKdocYR8QS6JO3CcAKcAmUhO1LWBhYG0qkoMRubYTmHZgOtMnZ3br+re2/RZafUAdXxb48nhHx/cBu/vropspAYrlLqUl5TGiVRVfpy+/8UOg3n5+Tx/fk4/Hp8R5fFr9Dq2e03wEJspMkMCySQMJgbZG5d337xCNxYRSLQATYSxAyhbfPb1M2jdvsFYb5r4uhnBPHn/4hjD6/O1tp0XQeKUSAKpNfIQEGwUMV3U+S6M8QZSosasELHXPjDgLLpV+A91IEAUzx56H1hAafk7JlNjWsIlokSF39MMPmdNLmKzUb0CSv1DPFfxrXdCc8qlesI96oT7DGtGl1iuLZrbj+n7FYR1eidqsroteiEQ6s84eMjJOsZbpWAkqxVXjiyAaPbMV4x9Mn9RjPW1XSp6aRMoSsQSG/GNnF/j1An+iB3tqpW+lJRw9/zdgdmjLxxAT1X/JzuydKSppm3jMOQXEjKiqYEWtnT25FPp1TN04Ja0+YHDooacNgU1BRJ2PmXOmsshxQ+sIPMHeAhK6fK69R6/RPTbgw9xTRCU0UYNM+qmaPNx78Y+XEj84FD9k67f74P3V8d3XvHDhGz8YwHVwBoiqTIttIIkB1tJIjpZgloJGmVKFvLUsJCUoeR0LRFg12pa6Oh9oe631ZxVomwNTv3JQGce/KF9ya611fl2w5R2wNRGcVYSFRAzHfKPHdnd+d6MWY9VRMWKrPrU9tKXWg3kWOb7vhFZjtD6diuB00B8t0BEEFEgX5FGXp/3d+zguk/qvQR/fYy1NlrFMBCmqh9zfZH2rKr4CFt3E7+uNXoQ7q/WVjPxf1vMwrhtCV4bo1SoilHrefBakXpA6KZ76+CZJE0cD6czz41QLbjS0O/sfTLc1sJybEq9GBNn5BxFCp7Fr15MVqUfFcLvvAfX8DJtZCif/HBwO2qP1/5nBc371n1/859b+BUv/opV/duGfWfcXLvtLV/2li/7iNf/XJf9PNtCXWyC0BmrrDNBmL6fo6g8AAAD//wMAfnRhhbEMAAA=
69
+ http_version:
70
+ recorded_at: Fri, 13 Sep 2019 14:28:01 GMT
71
+ - request:
72
+ method: post
73
+ uri: https://api.sandbox.braintreegateway.com/merchants/7rdg92j7bm7fk5h3/transactions
74
+ body:
75
+ encoding: UTF-8
76
+ string: |
77
+ <?xml version="1.0" encoding="UTF-8"?>
78
+ <transaction>
79
+ <amount>15.00</amount>
80
+ <order-id>R999999999-ABCD1234</order-id>
81
+ <channel>Solidus</channel>
82
+ <options>
83
+ <store-in-vault-on-success type="boolean">true</store-in-vault-on-success>
84
+ </options>
85
+ <payment-method-token>6bjvxz</payment-method-token>
86
+ <shipping>
87
+ <first-name>John</first-name>
88
+ <last-name>Doe</last-name>
89
+ <street-address>10 Lovely Street Northwest</street-address>
90
+ <locality>Herndon</locality>
91
+ <postal-code>21088-0255</postal-code>
92
+ <region>AL</region>
93
+ <country-code-alpha2>US</country-code-alpha2>
94
+ </shipping>
95
+ <customer-id>670575593</customer-id>
96
+ <type>sale</type>
97
+ </transaction>
98
+ headers:
99
+ Accept-Encoding:
100
+ - gzip
101
+ Accept:
102
+ - application/xml
103
+ User-Agent:
104
+ - Braintree Ruby Gem 2.98.0
105
+ X-Apiversion:
106
+ - '5'
107
+ Content-Type:
108
+ - application/xml
109
+ Authorization:
110
+ - Basic bXdqa2t4d2NwMzJja2huZjphOTI5OGY0M2IzMGM2OTlkYjMwNzJjYzRhMDBmN2Y0OQ==
111
+ response:
112
+ status:
113
+ code: 201
114
+ message: Created
115
+ headers:
116
+ Date:
117
+ - Fri, 13 Sep 2019 14:28:02 GMT
118
+ Content-Type:
119
+ - application/xml; charset=utf-8
120
+ Transfer-Encoding:
121
+ - chunked
122
+ X-Frame-Options:
123
+ - SAMEORIGIN
124
+ X-Xss-Protection:
125
+ - 1; mode=block
126
+ X-Content-Type-Options:
127
+ - nosniff
128
+ X-Authentication:
129
+ - basic_auth
130
+ X-User:
131
+ - 3v249hqtptsg744y
132
+ Vary:
133
+ - Accept-Encoding
134
+ Content-Encoding:
135
+ - gzip
136
+ Etag:
137
+ - W/"f39e2777d3b86e6d871f5bc62e96f566"
138
+ Cache-Control:
139
+ - max-age=0, private, must-revalidate
140
+ X-Runtime:
141
+ - '0.365501'
142
+ X-Request-Id:
143
+ - 01-1568384881.777-92.223.152.178-12974361
144
+ Content-Security-Policy:
145
+ - frame-ancestors 'self'
146
+ X-Broxyid:
147
+ - 01-1568384881.777-92.223.152.178-12974361
148
+ Strict-Transport-Security:
149
+ - max-age=31536000; includeSubDomains
150
+ body:
151
+ encoding: ASCII-8BIT
152
+ string: !binary |-
153
+ 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
154
+ http_version:
155
+ recorded_at: Fri, 13 Sep 2019 14:28:02 GMT
156
+ - request:
157
+ method: put
158
+ uri: https://api.sandbox.braintreegateway.com/merchants/7rdg92j7bm7fk5h3/transactions/j6z5s58d/submit_for_settlement
159
+ body:
160
+ encoding: UTF-8
161
+ string: |
162
+ <?xml version="1.0" encoding="UTF-8"?>
163
+ <transaction>
164
+ <amount>15.00</amount>
165
+ </transaction>
166
+ headers:
167
+ Accept-Encoding:
168
+ - gzip
169
+ Accept:
170
+ - application/xml
171
+ User-Agent:
172
+ - Braintree Ruby Gem 2.98.0
173
+ X-Apiversion:
174
+ - '5'
175
+ Content-Type:
176
+ - application/xml
177
+ Authorization:
178
+ - Basic bXdqa2t4d2NwMzJja2huZjphOTI5OGY0M2IzMGM2OTlkYjMwNzJjYzRhMDBmN2Y0OQ==
179
+ response:
180
+ status:
181
+ code: 200
182
+ message: OK
183
+ headers:
184
+ Date:
185
+ - Fri, 13 Sep 2019 14:28:03 GMT
186
+ Content-Type:
187
+ - application/xml; charset=utf-8
188
+ Transfer-Encoding:
189
+ - chunked
190
+ X-Frame-Options:
191
+ - SAMEORIGIN
192
+ X-Xss-Protection:
193
+ - 1; mode=block
194
+ X-Content-Type-Options:
195
+ - nosniff
196
+ X-Authentication:
197
+ - basic_auth
198
+ X-User:
199
+ - 3v249hqtptsg744y
200
+ Vary:
201
+ - Accept-Encoding
202
+ Content-Encoding:
203
+ - gzip
204
+ Etag:
205
+ - W/"77e50737669d11411f113d3437283723"
206
+ Cache-Control:
207
+ - max-age=0, private, must-revalidate
208
+ X-Runtime:
209
+ - '0.245194'
210
+ X-Request-Id:
211
+ - 01-1568384883.102-92.223.152.178-12974580
212
+ Content-Security-Policy:
213
+ - frame-ancestors 'self'
214
+ X-Broxyid:
215
+ - 01-1568384883.102-92.223.152.178-12974580
216
+ Strict-Transport-Security:
217
+ - max-age=31536000; includeSubDomains
218
+ body:
219
+ encoding: ASCII-8BIT
220
+ string: !binary |-
221
+ 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
222
+ http_version:
223
+ recorded_at: Fri, 13 Sep 2019 14:28:03 GMT
224
+ recorded_with: VCR 5.0.0
@@ -0,0 +1,50 @@
1
+ <!-- Modified cart view with PayPal button, from solidus_paypal_braintree -->
2
+
3
+ <% @body_id = 'cart' %>
4
+ <div data-hook="cart_container">
5
+ <h1><%= t('spree.shopping_cart') %></h1>
6
+
7
+ <% if @order.line_items.empty? %>
8
+
9
+ <div data-hook="empty_cart">
10
+ <p><%= t('spree.your_cart_is_empty') %></p>
11
+ <p><%= link_to t('spree.continue_shopping'), products_path, class: 'button continue' %></p>
12
+ </div>
13
+
14
+ <% else %>
15
+
16
+ <div data-hook="outside_cart_form">
17
+ <%= form_for @order, url: update_cart_path, html: {id: 'update-cart'} do |order_form| %>
18
+ <div data-hook="inside_cart_form">
19
+
20
+ <div data-hook="cart_items">
21
+ <%= render 'form', order_form: order_form %>
22
+ </div>
23
+
24
+ <div class="links columns sixteen alpha omega" data-hook="cart_buttons">
25
+ <%= order_form.text_field :coupon_code, size: 10, placeholder: t('spree.coupon_code') %>
26
+ <%= button_tag class: 'primary', id: 'update-button' do %>
27
+ <%= t('spree.update') %>
28
+ <% end %>
29
+ <%= button_tag class: 'button checkout primary', id: 'checkout-link', name: 'checkout' do %>
30
+ <%= t('spree.checkout') %>
31
+ <% end %>
32
+ </div>
33
+
34
+ </div>
35
+ <% end %>
36
+ </div>
37
+
38
+ <div id="empty-cart" data-hook>
39
+ <%= form_tag empty_cart_path, method: :put do %>
40
+ <p id="clear_cart_link" data-hook>
41
+ <%= submit_tag t('spree.empty_cart'), class: 'button gray' %>
42
+ <%= t('spree.or') %>
43
+ <%= link_to t('spree.continue_shopping'), products_path, class: 'continue button gray' %>
44
+ </p>
45
+ <% end %>
46
+ </div>
47
+
48
+ <%= render "spree/shared/paypal_cart_button" %>
49
+ <% end %>
50
+ </div>
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalBraintree::BraintreeAdminHelper do
4
+ describe '#braintree_transaction_link' do
5
+ subject { helper.braintree_transaction_link(payment) }
6
+
7
+ let(:payment_method) { create_gateway }
8
+ let(:payment) do
9
+ instance_double(Spree::Payment, payment_method: payment_method, response_code: 'abcde')
10
+ end
11
+ let(:merchant_id) { payment_method.preferences[:merchant_id] }
12
+
13
+ it 'generates a link to Braintree admin' do
14
+ expect(subject).to eq "<a title=\"Show payment on Braintree\" target=\"_blank\" rel=\"noopener\" href=\"https://sandbox.braintreegateway.com/merchants/#{merchant_id}/transactions/abcde\">abcde</a>" # rubocop:disable Layout/LineLength
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalBraintree::Address do
4
+ describe '#to_json' do
5
+ subject(:address_json) { JSON.parse(described_class.new(spree_address).to_json) }
6
+
7
+ let(:german_address) { create(:address, country_iso: 'DE', state: nil) } # Does not require states
8
+ let(:us_address) { create(:address, country_iso: 'US') } # Requires states
9
+ let(:spree_address) { us_address }
10
+
11
+ before do
12
+ create(:country, iso: 'DE', states_required: false)
13
+ create(:country, iso: 'US', states_required: true)
14
+ end
15
+
16
+ it 'has all the required keys' do
17
+ expect(address_json.keys).to contain_exactly(
18
+ 'line1',
19
+ 'line2',
20
+ 'city',
21
+ 'postalCode',
22
+ 'countryCode',
23
+ 'recipientName',
24
+ 'state',
25
+ 'phone'
26
+ )
27
+ end
28
+
29
+ context 'with a country that does not require state' do
30
+ let(:spree_address) { german_address }
31
+
32
+ it { is_expected.not_to have_key('state') }
33
+ end
34
+
35
+ context 'with states turned off globally' do
36
+ before do
37
+ allow(::Spree::Config).to receive(:address_requires_state).and_return(false)
38
+ end
39
+
40
+ context 'with a country that requires states' do
41
+ it { is_expected.not_to have_key('state') }
42
+ end
43
+
44
+ context 'with a country that does not require state' do
45
+ let(:spree_address) { german_address }
46
+
47
+ it { is_expected.not_to have_key('state') }
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,317 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe SolidusPaypalBraintree::AVSResult do
4
+ describe 'AVS response message' do
5
+ subject { described_class.build(transaction).to_hash['message'] }
6
+
7
+ context 'with avs_error_response_code' do
8
+ let(:transaction) do
9
+ instance_double('Braintree::Transaction',
10
+ avs_error_response_code: error_code,
11
+ avs_street_address_response_code: nil,
12
+ avs_postal_code_response_code: nil)
13
+ end
14
+
15
+ context 'when error code is S' do
16
+ let(:error_code) { 'S' }
17
+
18
+ it { is_expected.to eq 'U.S.-issuing bank does not support AVS.' }
19
+ end
20
+
21
+ context 'when error code is E' do
22
+ let(:error_code) { 'E' }
23
+
24
+ it { is_expected.to eq 'AVS data is invalid or AVS is not allowed for this card type.' }
25
+ end
26
+ end
27
+
28
+ context 'without avs_error_response_code' do
29
+ let(:transaction) do
30
+ instance_double('Braintree::Transaction',
31
+ avs_error_response_code: nil,
32
+ avs_street_address_response_code: codes.first,
33
+ avs_postal_code_response_code: codes.last)
34
+ end
35
+
36
+ context 'when street address result is M and postal code result is N' do
37
+ let(:codes) { %w(M N) }
38
+
39
+ it { is_expected.to eq 'Street address matches, but postal code does not match.' }
40
+
41
+ it {
42
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'M', 'postal_match' => 'N')
43
+ }
44
+ end
45
+
46
+ context 'when street address result is M and postal code result is U' do
47
+ let(:codes) { %w(M U) }
48
+
49
+ it { is_expected.to eq 'Street address matches, but postal code not verified.' }
50
+
51
+ it {
52
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'M', 'postal_match' => 'U')
53
+ }
54
+ end
55
+
56
+ context 'when street address result is M and postal code result is I' do
57
+ let(:codes) { %w(M I) }
58
+
59
+ it { is_expected.to eq 'Street address matches, but postal code not verified.' }
60
+
61
+ it {
62
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'M', 'postal_match' => 'I')
63
+ }
64
+ end
65
+
66
+ context 'when street address result is M and postal code result is A' do
67
+ let(:codes) { %w(M A) }
68
+
69
+ it { is_expected.to eq 'Street address matches, but postal code not verified.' }
70
+
71
+ it {
72
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'M', 'postal_match' => 'A')
73
+ }
74
+ end
75
+
76
+ context 'when street address result is N and postal code result is N' do
77
+ let(:codes) { %w(N N) }
78
+
79
+ it { is_expected.to eq 'Street address and postal code do not match.' }
80
+
81
+ it {
82
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'N', 'postal_match' => 'N')
83
+ }
84
+ end
85
+
86
+ context 'when street address result is N and postal code result is U' do
87
+ let(:codes) { %w(N U) }
88
+
89
+ it { is_expected.to eq 'Street address and postal code do not match.' }
90
+
91
+ it {
92
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'N', 'postal_match' => 'U')
93
+ }
94
+ end
95
+
96
+ context 'when street address result is N and postal code result is I' do
97
+ let(:codes) { %w(N I) }
98
+
99
+ it { is_expected.to eq 'Street address and postal code do not match.' }
100
+
101
+ it {
102
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'N', 'postal_match' => 'I')
103
+ }
104
+ end
105
+
106
+ context 'when street address result is N and postal code result is A' do
107
+ let(:codes) { %w(N A) }
108
+
109
+ it { is_expected.to eq 'Street address and postal code do not match.' }
110
+
111
+ it {
112
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'N', 'postal_match' => 'A')
113
+ }
114
+ end
115
+
116
+ context 'when street address result is I and postal code result is N' do
117
+ let(:codes) { %w(I N) }
118
+
119
+ it { is_expected.to eq 'Street address and postal code do not match.' }
120
+
121
+ it {
122
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'I', 'postal_match' => 'N')
123
+ }
124
+ end
125
+
126
+ context 'when street address result is A and postal code result is N' do
127
+ let(:codes) { %w(A N) }
128
+
129
+ it { is_expected.to eq 'Street address and postal code do not match.' }
130
+
131
+ it {
132
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'A', 'postal_match' => 'N')
133
+ }
134
+ end
135
+
136
+ context 'when street address result is U and postal code result is U' do
137
+ let(:codes) { %w(U U) }
138
+
139
+ it { is_expected.to eq 'Address not verified.' }
140
+
141
+ it {
142
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'U', 'postal_match' => 'U')
143
+ }
144
+ end
145
+
146
+ context 'when street address result is U and postal code result is I' do
147
+ let(:codes) { %w(U I) }
148
+
149
+ it { is_expected.to eq 'Address not verified.' }
150
+
151
+ it {
152
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'U', 'postal_match' => 'I')
153
+ }
154
+ end
155
+
156
+ context 'when street address result is U and postal code result is A' do
157
+ let(:codes) { %w(U A) }
158
+
159
+ it { is_expected.to eq 'Address not verified.' }
160
+
161
+ it {
162
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'U', 'postal_match' => 'A')
163
+ }
164
+ end
165
+
166
+ context 'when street address result is I and postal code result is U' do
167
+ let(:codes) { %w(I U) }
168
+
169
+ it { is_expected.to eq 'Address not verified.' }
170
+
171
+ it {
172
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'I', 'postal_match' => 'U')
173
+ }
174
+ end
175
+
176
+ context 'when street address result is I and postal code result is I' do
177
+ let(:codes) { %w(I I) }
178
+
179
+ it { is_expected.to eq 'Address not verified.' }
180
+
181
+ it {
182
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'I', 'postal_match' => 'I')
183
+ }
184
+ end
185
+
186
+ context 'when street address result is I and postal code result is A' do
187
+ let(:codes) { %w(I A) }
188
+
189
+ it { is_expected.to eq 'Address not verified.' }
190
+
191
+ it {
192
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'I', 'postal_match' => 'A')
193
+ }
194
+ end
195
+
196
+ context 'when street address result is A and postal code result is U' do
197
+ let(:codes) { %w(A U) }
198
+
199
+ it { is_expected.to eq 'Address not verified.' }
200
+
201
+ it {
202
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'A', 'postal_match' => 'U')
203
+ }
204
+ end
205
+
206
+ context 'when street address result is A and postal code result is I' do
207
+ let(:codes) { %w(A I) }
208
+
209
+ it { is_expected.to eq 'Address not verified.' }
210
+
211
+ it {
212
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'A', 'postal_match' => 'I')
213
+ }
214
+ end
215
+
216
+ context 'when street address result is A and postal code result is A' do
217
+ let(:codes) { %w(A A) }
218
+
219
+ it { is_expected.to eq 'Address not verified.' }
220
+
221
+ it {
222
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'A', 'postal_match' => 'A')
223
+ }
224
+ end
225
+
226
+ context 'when street address result is M and postal code result is M' do
227
+ let(:codes) { %w(M M) }
228
+
229
+ it { is_expected.to eq 'Street address and postal code match.' }
230
+
231
+ it {
232
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'M', 'postal_match' => 'M')
233
+ }
234
+ end
235
+
236
+ context 'when street address result is U and postal code result is N' do
237
+ let(:codes) { %w(U N) }
238
+
239
+ it { is_expected.to eq "Street address and postal code do not match. For American Express: Card member's name, street address and postal code do not match." } # rubocop:disable Layout/LineLength
240
+
241
+ it {
242
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'U', 'postal_match' => 'N')
243
+ }
244
+ end
245
+
246
+ context 'when street address result is U and postal code result is M' do
247
+ let(:codes) { %w(U M) }
248
+
249
+ it { is_expected.to eq 'Postal code matches, but street address not verified.' }
250
+
251
+ it {
252
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'U', 'postal_match' => 'M')
253
+ }
254
+ end
255
+
256
+ context 'when street address result is I and postal code result is M' do
257
+ let(:codes) { %w(I M) }
258
+
259
+ it { is_expected.to eq 'Postal code matches, but street address not verified.' }
260
+
261
+ it {
262
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'I', 'postal_match' => 'M')
263
+ }
264
+ end
265
+
266
+ context 'when street address result is A and postal code result is M' do
267
+ let(:codes) { %w(A M) }
268
+
269
+ it { is_expected.to eq 'Postal code matches, but street address not verified.' }
270
+
271
+ it {
272
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'A', 'postal_match' => 'M')
273
+ }
274
+ end
275
+
276
+ context 'when street address result is N and postal code result is M' do
277
+ let(:codes) { %w(N M) }
278
+
279
+ it { is_expected.to eq 'Street address does not match, but 5-digit postal code matches.' }
280
+
281
+ it {
282
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'N', 'postal_match' => 'M')
283
+ }
284
+ end
285
+
286
+ context 'when street address response code is nil' do
287
+ let(:codes) { [nil, 'M'] }
288
+
289
+ it { is_expected.to be_nil }
290
+
291
+ it {
292
+ expect(described_class.build(transaction).to_hash).to include('street_match' => nil, 'postal_match' => 'M')
293
+ }
294
+ end
295
+
296
+ context 'when postal code response code is nil' do
297
+ let(:codes) { ['M', nil] }
298
+
299
+ it { is_expected.to be_nil }
300
+
301
+ it {
302
+ expect(described_class.build(transaction).to_hash).to include('street_match' => 'M', 'postal_match' => nil)
303
+ }
304
+ end
305
+
306
+ context 'when postal code and street address response code is nil' do
307
+ let(:codes) { [nil, nil] }
308
+
309
+ it { is_expected.to be_nil }
310
+
311
+ it {
312
+ expect(described_class.build(transaction).to_hash).to include('street_match' => nil, 'postal_match' => nil)
313
+ }
314
+ end
315
+ end
316
+ end
317
+ end