swiss-crm-activemerchant 1.0.12

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 (287) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +4033 -0
  3. data/CONTRIBUTORS +568 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +252 -0
  6. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  7. data/lib/active_merchant/billing/avs_result.rb +95 -0
  8. data/lib/active_merchant/billing/base.rb +48 -0
  9. data/lib/active_merchant/billing/check.rb +112 -0
  10. data/lib/active_merchant/billing/compatibility.rb +118 -0
  11. data/lib/active_merchant/billing/credit_card.rb +451 -0
  12. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  13. data/lib/active_merchant/billing/credit_card_methods.rb +512 -0
  14. data/lib/active_merchant/billing/cvv_result.rb +37 -0
  15. data/lib/active_merchant/billing/gateway.rb +332 -0
  16. data/lib/active_merchant/billing/gateways/adyen.rb +774 -0
  17. data/lib/active_merchant/billing/gateways/airwallex.rb +370 -0
  18. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  19. data/lib/active_merchant/billing/gateways/allied_wallet.rb +205 -0
  20. data/lib/active_merchant/billing/gateways/authorize_net.rb +1125 -0
  21. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +424 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +977 -0
  23. data/lib/active_merchant/billing/gateways/axcessms.rb +242 -0
  24. data/lib/active_merchant/billing/gateways/balanced.rb +263 -0
  25. data/lib/active_merchant/billing/gateways/bambora_apac.rb +222 -0
  26. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  27. data/lib/active_merchant/billing/gateways/banwire.rb +116 -0
  28. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +397 -0
  29. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
  30. data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
  31. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +474 -0
  32. data/lib/active_merchant/billing/gateways/beanstream.rb +238 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +57 -0
  34. data/lib/active_merchant/billing/gateways/blue_pay.rb +549 -0
  35. data/lib/active_merchant/billing/gateways/blue_snap.rb +644 -0
  36. data/lib/active_merchant/billing/gateways/bogus.rb +190 -0
  37. data/lib/active_merchant/billing/gateways/borgun.rb +272 -0
  38. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  39. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +28 -0
  40. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  41. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  42. data/lib/active_merchant/billing/gateways/braintree_blue.rb +952 -0
  43. data/lib/active_merchant/billing/gateways/braintree_orange.rb +19 -0
  44. data/lib/active_merchant/billing/gateways/bridge_pay.rb +244 -0
  45. data/lib/active_merchant/billing/gateways/cams.rb +230 -0
  46. data/lib/active_merchant/billing/gateways/card_connect.rb +338 -0
  47. data/lib/active_merchant/billing/gateways/card_save.rb +21 -0
  48. data/lib/active_merchant/billing/gateways/card_stream.rb +394 -0
  49. data/lib/active_merchant/billing/gateways/cardknox.rb +327 -0
  50. data/lib/active_merchant/billing/gateways/cardprocess.rb +256 -0
  51. data/lib/active_merchant/billing/gateways/cashnet.rb +235 -0
  52. data/lib/active_merchant/billing/gateways/cc5.rb +198 -0
  53. data/lib/active_merchant/billing/gateways/cecabank.rb +249 -0
  54. data/lib/active_merchant/billing/gateways/cenpos.rb +328 -0
  55. data/lib/active_merchant/billing/gateways/checkout.rb +212 -0
  56. data/lib/active_merchant/billing/gateways/checkout_v2.rb +587 -0
  57. data/lib/active_merchant/billing/gateways/citrus_pay.rb +21 -0
  58. data/lib/active_merchant/billing/gateways/clearhaus.rb +219 -0
  59. data/lib/active_merchant/billing/gateways/commerce_hub.rb +366 -0
  60. data/lib/active_merchant/billing/gateways/commercegate.rb +142 -0
  61. data/lib/active_merchant/billing/gateways/conekta.rb +230 -0
  62. data/lib/active_merchant/billing/gateways/creditcall.rb +272 -0
  63. data/lib/active_merchant/billing/gateways/credorax.rb +526 -0
  64. data/lib/active_merchant/billing/gateways/ct_payment.rb +269 -0
  65. data/lib/active_merchant/billing/gateways/culqi.rb +279 -0
  66. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  67. data/lib/active_merchant/billing/gateways/cyber_source.rb +1148 -0
  68. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +454 -0
  69. data/lib/active_merchant/billing/gateways/d_local.rb +343 -0
  70. data/lib/active_merchant/billing/gateways/data_cash.rb +302 -0
  71. data/lib/active_merchant/billing/gateways/decidir.rb +358 -0
  72. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  73. data/lib/active_merchant/billing/gateways/dibs.rb +199 -0
  74. data/lib/active_merchant/billing/gateways/digitzs.rb +295 -0
  75. data/lib/active_merchant/billing/gateways/ebanx.rb +346 -0
  76. data/lib/active_merchant/billing/gateways/efsnet.rb +215 -0
  77. data/lib/active_merchant/billing/gateways/elavon.rb +475 -0
  78. data/lib/active_merchant/billing/gateways/element.rb +406 -0
  79. data/lib/active_merchant/billing/gateways/epay.rb +296 -0
  80. data/lib/active_merchant/billing/gateways/evo_ca.rb +307 -0
  81. data/lib/active_merchant/billing/gateways/eway.rb +226 -0
  82. data/lib/active_merchant/billing/gateways/eway_managed.rb +289 -0
  83. data/lib/active_merchant/billing/gateways/eway_rapid.rb +578 -0
  84. data/lib/active_merchant/billing/gateways/exact.rb +219 -0
  85. data/lib/active_merchant/billing/gateways/ezic.rb +195 -0
  86. data/lib/active_merchant/billing/gateways/fat_zebra.rb +223 -0
  87. data/lib/active_merchant/billing/gateways/federated_canada.rb +158 -0
  88. data/lib/active_merchant/billing/gateways/finansbank.rb +22 -0
  89. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  90. data/lib/active_merchant/billing/gateways/first_pay.rb +182 -0
  91. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +452 -0
  92. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +505 -0
  93. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  94. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  95. data/lib/active_merchant/billing/gateways/fluidpay.rb +275 -0
  96. data/lib/active_merchant/billing/gateways/forte.rb +286 -0
  97. data/lib/active_merchant/billing/gateways/garanti.rb +256 -0
  98. data/lib/active_merchant/billing/gateways/global_collect.rb +580 -0
  99. data/lib/active_merchant/billing/gateways/global_transport.rb +193 -0
  100. data/lib/active_merchant/billing/gateways/hdfc.rb +205 -0
  101. data/lib/active_merchant/billing/gateways/hps.rb +472 -0
  102. data/lib/active_merchant/billing/gateways/iats_payments.rb +312 -0
  103. data/lib/active_merchant/billing/gateways/in_context_paypal_express.rb +15 -0
  104. data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
  105. data/lib/active_merchant/billing/gateways/instapay.rb +159 -0
  106. data/lib/active_merchant/billing/gateways/ipg.rb +420 -0
  107. data/lib/active_merchant/billing/gateways/ipp.rb +176 -0
  108. data/lib/active_merchant/billing/gateways/iridium.rb +467 -0
  109. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  110. data/lib/active_merchant/billing/gateways/iveri.rb +290 -0
  111. data/lib/active_merchant/billing/gateways/ixopay.rb +320 -0
  112. data/lib/active_merchant/billing/gateways/jetpay.rb +395 -0
  113. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +432 -0
  114. data/lib/active_merchant/billing/gateways/klarna.rb +317 -0
  115. data/lib/active_merchant/billing/gateways/komoju.rb +115 -0
  116. data/lib/active_merchant/billing/gateways/kushki.rb +297 -0
  117. data/lib/active_merchant/billing/gateways/latitude19.rb +412 -0
  118. data/lib/active_merchant/billing/gateways/linkpoint.rb +448 -0
  119. data/lib/active_merchant/billing/gateways/litle.rb +643 -0
  120. data/lib/active_merchant/billing/gateways/mastercard.rb +286 -0
  121. data/lib/active_merchant/billing/gateways/maxipago.rb +220 -0
  122. data/lib/active_merchant/billing/gateways/mercado_pago.rb +348 -0
  123. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +228 -0
  124. data/lib/active_merchant/billing/gateways/merchant_one.rb +110 -0
  125. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  126. data/lib/active_merchant/billing/gateways/merchant_ware.rb +313 -0
  127. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +284 -0
  128. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +248 -0
  129. data/lib/active_merchant/billing/gateways/mercury.rb +352 -0
  130. data/lib/active_merchant/billing/gateways/metrics_global.rb +293 -0
  131. data/lib/active_merchant/billing/gateways/micropayment.rb +182 -0
  132. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  133. data/lib/active_merchant/billing/gateways/migs.rb +329 -0
  134. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  135. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  136. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +215 -0
  137. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  138. data/lib/active_merchant/billing/gateways/monei.rb +424 -0
  139. data/lib/active_merchant/billing/gateways/moneris.rb +488 -0
  140. data/lib/active_merchant/billing/gateways/money_movers.rb +150 -0
  141. data/lib/active_merchant/billing/gateways/mundipagg.rb +366 -0
  142. data/lib/active_merchant/billing/gateways/nab_transact.rb +299 -0
  143. data/lib/active_merchant/billing/gateways/ncr_secure_pay.rb +163 -0
  144. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  145. data/lib/active_merchant/billing/gateways/netaxept.rb +180 -0
  146. data/lib/active_merchant/billing/gateways/netbanx.rb +376 -0
  147. data/lib/active_merchant/billing/gateways/netbilling.rb +229 -0
  148. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  149. data/lib/active_merchant/billing/gateways/network_merchants.rb +238 -0
  150. data/lib/active_merchant/billing/gateways/nmi.rb +396 -0
  151. data/lib/active_merchant/billing/gateways/ogone.rb +509 -0
  152. data/lib/active_merchant/billing/gateways/omise.rb +323 -0
  153. data/lib/active_merchant/billing/gateways/openpay.rb +246 -0
  154. data/lib/active_merchant/billing/gateways/opp.rb +394 -0
  155. data/lib/active_merchant/billing/gateways/optimal_payment.rb +331 -0
  156. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +45 -0
  157. data/lib/active_merchant/billing/gateways/orbital.rb +1267 -0
  158. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +206 -0
  159. data/lib/active_merchant/billing/gateways/pagarme.rb +239 -0
  160. data/lib/active_merchant/billing/gateways/pago_facil.rb +120 -0
  161. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  162. data/lib/active_merchant/billing/gateways/pay_conex.rb +245 -0
  163. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +277 -0
  164. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  165. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  166. data/lib/active_merchant/billing/gateways/pay_junction_v2.rb +206 -0
  167. data/lib/active_merchant/billing/gateways/pay_secure.rb +110 -0
  168. data/lib/active_merchant/billing/gateways/pay_trace.rb +450 -0
  169. data/lib/active_merchant/billing/gateways/paybox_direct.rb +224 -0
  170. data/lib/active_merchant/billing/gateways/payeezy.rb +513 -0
  171. data/lib/active_merchant/billing/gateways/payex.rb +409 -0
  172. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +235 -0
  173. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +42 -0
  174. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  175. data/lib/active_merchant/billing/gateways/payflow.rb +473 -0
  176. data/lib/active_merchant/billing/gateways/payflow_express.rb +220 -0
  177. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +14 -0
  178. data/lib/active_merchant/billing/gateways/payflow_uk.rb +20 -0
  179. data/lib/active_merchant/billing/gateways/payment_express.rb +373 -0
  180. data/lib/active_merchant/billing/gateways/paymentez.rb +365 -0
  181. data/lib/active_merchant/billing/gateways/paymill.rb +369 -0
  182. data/lib/active_merchant/billing/gateways/paynetworx.rb +228 -0
  183. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +718 -0
  184. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +69 -0
  185. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  186. data/lib/active_merchant/billing/gateways/paypal.rb +136 -0
  187. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  188. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  189. data/lib/active_merchant/billing/gateways/paypal_express.rb +272 -0
  190. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  191. data/lib/active_merchant/billing/gateways/paypal_standard.rb +281 -0
  192. data/lib/active_merchant/billing/gateways/paysafe.rb +420 -0
  193. data/lib/active_merchant/billing/gateways/payscout.rb +159 -0
  194. data/lib/active_merchant/billing/gateways/paystation.rb +204 -0
  195. data/lib/active_merchant/billing/gateways/payu_in.rb +249 -0
  196. data/lib/active_merchant/billing/gateways/payu_latam.rb +482 -0
  197. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  198. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  199. data/lib/active_merchant/billing/gateways/pin.rb +273 -0
  200. data/lib/active_merchant/billing/gateways/pixxels.rb +263 -0
  201. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  202. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  203. data/lib/active_merchant/billing/gateways/priority.rb +392 -0
  204. data/lib/active_merchant/billing/gateways/pro_pay.rb +325 -0
  205. data/lib/active_merchant/billing/gateways/psigate.rb +227 -0
  206. data/lib/active_merchant/billing/gateways/psl_card.rb +295 -0
  207. data/lib/active_merchant/billing/gateways/qbms.rb +302 -0
  208. data/lib/active_merchant/billing/gateways/quantum.rb +274 -0
  209. data/lib/active_merchant/billing/gateways/quickbooks.rb +377 -0
  210. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +184 -0
  211. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +297 -0
  212. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +226 -0
  213. data/lib/active_merchant/billing/gateways/quickpay.rb +24 -0
  214. data/lib/active_merchant/billing/gateways/qvalent.rb +305 -0
  215. data/lib/active_merchant/billing/gateways/rapyd.rb +319 -0
  216. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  217. data/lib/active_merchant/billing/gateways/realex.rb +400 -0
  218. data/lib/active_merchant/billing/gateways/redsys.rb +723 -0
  219. data/lib/active_merchant/billing/gateways/s5.rb +247 -0
  220. data/lib/active_merchant/billing/gateways/safe_charge.rb +298 -0
  221. data/lib/active_merchant/billing/gateways/sage.rb +446 -0
  222. data/lib/active_merchant/billing/gateways/sage_pay.rb +434 -0
  223. data/lib/active_merchant/billing/gateways/sallie_mae.rb +141 -0
  224. data/lib/active_merchant/billing/gateways/secure_net.rb +260 -0
  225. data/lib/active_merchant/billing/gateways/secure_pay.rb +191 -0
  226. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +290 -0
  227. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +103 -0
  228. data/lib/active_merchant/billing/gateways/securion_pay.rb +305 -0
  229. data/lib/active_merchant/billing/gateways/shift4.rb +345 -0
  230. data/lib/active_merchant/billing/gateways/simetrik.rb +368 -0
  231. data/lib/active_merchant/billing/gateways/skip_jack.rb +450 -0
  232. data/lib/active_merchant/billing/gateways/smart_ps.rb +274 -0
  233. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  234. data/lib/active_merchant/billing/gateways/spreedly_core.rb +354 -0
  235. data/lib/active_merchant/billing/gateways/stripe.rb +866 -0
  236. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +602 -0
  237. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +151 -0
  238. data/lib/active_merchant/billing/gateways/telr.rb +273 -0
  239. data/lib/active_merchant/billing/gateways/tns.rb +23 -0
  240. data/lib/active_merchant/billing/gateways/trans_first.rb +240 -0
  241. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +612 -0
  242. data/lib/active_merchant/billing/gateways/transact_pro.rb +222 -0
  243. data/lib/active_merchant/billing/gateways/transax.rb +21 -0
  244. data/lib/active_merchant/billing/gateways/transnational.rb +9 -0
  245. data/lib/active_merchant/billing/gateways/trexle.rb +221 -0
  246. data/lib/active_merchant/billing/gateways/trust_commerce.rb +500 -0
  247. data/lib/active_merchant/billing/gateways/usa_epay.rb +24 -0
  248. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1612 -0
  249. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +367 -0
  250. data/lib/active_merchant/billing/gateways/vanco.rb +303 -0
  251. data/lib/active_merchant/billing/gateways/verifi.rb +224 -0
  252. data/lib/active_merchant/billing/gateways/viaklix.rb +171 -0
  253. data/lib/active_merchant/billing/gateways/visanet_peru.rb +250 -0
  254. data/lib/active_merchant/billing/gateways/vpos.rb +223 -0
  255. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  256. data/lib/active_merchant/billing/gateways/wepay.rb +235 -0
  257. data/lib/active_merchant/billing/gateways/wirecard.rb +430 -0
  258. data/lib/active_merchant/billing/gateways/wompi.rb +197 -0
  259. data/lib/active_merchant/billing/gateways/world_net.rb +345 -0
  260. data/lib/active_merchant/billing/gateways/worldpay.rb +1050 -0
  261. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +208 -0
  262. data/lib/active_merchant/billing/gateways/worldpay_us.rb +221 -0
  263. data/lib/active_merchant/billing/gateways.rb +14 -0
  264. data/lib/active_merchant/billing/model.rb +30 -0
  265. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +39 -0
  266. data/lib/active_merchant/billing/payment_token.rb +21 -0
  267. data/lib/active_merchant/billing/rails.rb +3 -0
  268. data/lib/active_merchant/billing/response.rb +121 -0
  269. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  270. data/lib/active_merchant/billing.rb +16 -0
  271. data/lib/active_merchant/connection.rb +194 -0
  272. data/lib/active_merchant/country.rb +338 -0
  273. data/lib/active_merchant/empty.rb +20 -0
  274. data/lib/active_merchant/errors.rb +38 -0
  275. data/lib/active_merchant/net_http_ssl_connection.rb +11 -0
  276. data/lib/active_merchant/network_connection_retries.rb +78 -0
  277. data/lib/active_merchant/post_data.rb +26 -0
  278. data/lib/active_merchant/posts_data.rb +92 -0
  279. data/lib/active_merchant/version.rb +3 -0
  280. data/lib/active_merchant.rb +63 -0
  281. data/lib/activemerchant.rb +1 -0
  282. data/lib/certs/cacert.pem +3214 -0
  283. data/lib/support/gateway_support.rb +69 -0
  284. data/lib/support/outbound_hosts.rb +28 -0
  285. data/lib/support/ssl_verify.rb +88 -0
  286. data/lib/support/ssl_version.rb +86 -0
  287. metadata +506 -0
@@ -0,0 +1,297 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class KushkiGateway < Gateway
4
+ self.display_name = 'Kushki'
5
+ self.homepage_url = 'https://www.kushkipagos.com'
6
+
7
+ self.test_url = 'https://api-uat.kushkipagos.com/'
8
+ self.live_url = 'https://api.kushkipagos.com/'
9
+
10
+ self.supported_countries = %w[CL CO EC MX PE]
11
+ self.default_currency = 'USD'
12
+ self.money_format = :dollars
13
+ self.supported_cardtypes = %i[visa master american_express discover diners_club alia]
14
+
15
+ def initialize(options = {})
16
+ requires!(options, :public_merchant_id, :private_merchant_id)
17
+ super
18
+ end
19
+
20
+ def purchase(amount, payment_method, options = {})
21
+ MultiResponse.run() do |r|
22
+ r.process { tokenize(amount, payment_method, options) }
23
+ r.process { charge(amount, r.authorization, options) }
24
+ end
25
+ end
26
+
27
+ def authorize(amount, payment_method, options = {})
28
+ MultiResponse.run() do |r|
29
+ r.process { tokenize(amount, payment_method, options) }
30
+ r.process { preauthorize(amount, r.authorization, options) }
31
+ end
32
+ end
33
+
34
+ def capture(amount, authorization, options = {})
35
+ action = 'capture'
36
+
37
+ post = {}
38
+ post[:ticketNumber] = authorization
39
+ add_invoice(action, post, amount, options)
40
+ add_full_response(post, options)
41
+
42
+ commit(action, post)
43
+ end
44
+
45
+ def refund(amount, authorization, options = {})
46
+ action = 'refund'
47
+
48
+ post = {}
49
+ post[:ticketNumber] = authorization
50
+ add_full_response(post, options)
51
+
52
+ commit(action, post)
53
+ end
54
+
55
+ def void(authorization, options = {})
56
+ action = 'void'
57
+
58
+ post = {}
59
+ post[:ticketNumber] = authorization
60
+ add_full_response(post, options)
61
+
62
+ commit(action, post)
63
+ end
64
+
65
+ def supports_scrubbing?
66
+ true
67
+ end
68
+
69
+ def scrub(transcript)
70
+ transcript.
71
+ gsub(%r((Private-Merchant-Id: )\d+), '\1[FILTERED]').
72
+ gsub(%r((\"card\\\":{\\\"number\\\":\\\")\d+), '\1[FILTERED]').
73
+ gsub(%r((\"cvv\\\":\\\")\d+), '\1[FILTERED]')
74
+ end
75
+
76
+ private
77
+
78
+ def tokenize(amount, payment_method, options)
79
+ action = 'tokenize'
80
+
81
+ post = {}
82
+ add_invoice(action, post, amount, options)
83
+ add_payment_method(post, payment_method, options)
84
+ add_full_response(post, options)
85
+ add_metadata(post, options)
86
+ add_months(post, options)
87
+ add_deferred(post, options)
88
+
89
+ commit(action, post)
90
+ end
91
+
92
+ def charge(amount, authorization, options)
93
+ action = 'charge'
94
+
95
+ post = {}
96
+ add_reference(post, authorization, options)
97
+ add_invoice(action, post, amount, options)
98
+ add_contact_details(post, options[:contact_details]) if options[:contact_details]
99
+ add_full_response(post, options)
100
+ add_metadata(post, options)
101
+ add_months(post, options)
102
+ add_deferred(post, options)
103
+
104
+ commit(action, post)
105
+ end
106
+
107
+ def preauthorize(amount, authorization, options)
108
+ action = 'preAuthorization'
109
+
110
+ post = {}
111
+ add_reference(post, authorization, options)
112
+ add_invoice(action, post, amount, options)
113
+ add_full_response(post, options)
114
+ add_metadata(post, options)
115
+ add_months(post, options)
116
+ add_deferred(post, options)
117
+
118
+ commit(action, post)
119
+ end
120
+
121
+ def add_invoice(action, post, money, options)
122
+ if action == 'tokenize'
123
+ post[:totalAmount] = amount(money).to_f
124
+ post[:currency] = options[:currency] || currency(money)
125
+ post[:isDeferred] = false
126
+ else
127
+ sum = {}
128
+ sum[:currency] = options[:currency] || currency(money)
129
+ add_amount_defaults(sum, money, options)
130
+ add_amount_by_country(sum, options)
131
+ post[:amount] = sum
132
+ end
133
+ end
134
+
135
+ def add_amount_defaults(sum, money, options)
136
+ sum[:subtotalIva] = amount(money).to_f
137
+ sum[:iva] = 0
138
+ sum[:subtotalIva0] = 0
139
+
140
+ sum[:ice] = 0 if sum[:currency] != 'COP'
141
+ end
142
+
143
+ def add_amount_by_country(sum, options)
144
+ if amount = options[:amount]
145
+ sum[:subtotalIva] = amount[:subtotal_iva].to_f if amount[:subtotal_iva]
146
+ sum[:iva] = amount[:iva].to_f if amount[:iva]
147
+ sum[:subtotalIva0] = amount[:subtotal_iva_0].to_f if amount[:subtotal_iva_0]
148
+ sum[:ice] = amount[:ice].to_f if amount[:ice]
149
+ if (extra_taxes = amount[:extra_taxes])
150
+ sum[:extraTaxes] ||= Hash.new
151
+ sum[:extraTaxes][:propina] = extra_taxes[:propina].to_f if extra_taxes[:propina]
152
+ sum[:extraTaxes][:tasaAeroportuaria] = extra_taxes[:tasa_aeroportuaria].to_f if extra_taxes[:tasa_aeroportuaria]
153
+ sum[:extraTaxes][:agenciaDeViaje] = extra_taxes[:agencia_de_viaje].to_f if extra_taxes[:agencia_de_viaje]
154
+ sum[:extraTaxes][:iac] = extra_taxes[:iac].to_f if extra_taxes[:iac]
155
+ end
156
+ end
157
+ end
158
+
159
+ def add_payment_method(post, payment_method, options)
160
+ card = {}
161
+ card[:number] = payment_method.number
162
+ card[:cvv] = payment_method.verification_value
163
+ card[:expiryMonth] = format(payment_method.month, :two_digits)
164
+ card[:expiryYear] = format(payment_method.year, :two_digits)
165
+ card[:name] = payment_method.name
166
+ post[:card] = card
167
+ end
168
+
169
+ def add_reference(post, authorization, options)
170
+ post[:token] = authorization
171
+ end
172
+
173
+ def add_contact_details(post, contact_details_options)
174
+ contact_details = {}
175
+ contact_details[:documentType] = contact_details_options[:document_type] if contact_details_options[:document_type]
176
+ contact_details[:documentNumber] = contact_details_options[:document_number] if contact_details_options[:document_number]
177
+ contact_details[:email] = contact_details_options[:email] if contact_details_options[:email]
178
+ contact_details[:firstName] = contact_details_options[:first_name] if contact_details_options[:first_name]
179
+ contact_details[:lastName] = contact_details_options[:last_name] if contact_details_options[:last_name]
180
+ contact_details[:secondLastName] = contact_details_options[:second_last_name] if contact_details_options[:second_last_name]
181
+ contact_details[:phoneNumber] = contact_details_options[:phone_number] if contact_details_options[:phone_number]
182
+ post[:contactDetails] = contact_details
183
+ end
184
+
185
+ def add_full_response(post, options)
186
+ post[:fullResponse] = options[:full_response].to_s.casecmp('true').zero? if options[:full_response]
187
+ end
188
+
189
+ def add_metadata(post, options)
190
+ post[:metadata] = options[:metadata] if options[:metadata]
191
+ end
192
+
193
+ def add_months(post, options)
194
+ post[:months] = options[:months] if options[:months]
195
+ end
196
+
197
+ def add_deferred(post, options)
198
+ return unless options[:deferred_grace_months] && options[:deferred_credit_type] && options[:deferred_months]
199
+
200
+ post[:deferred] = {
201
+ graceMonths: options[:deferred_grace_months],
202
+ creditType: options[:deferred_credit_type],
203
+ months: options[:deferred_months]
204
+ }
205
+ end
206
+
207
+ ENDPOINT = {
208
+ 'tokenize' => 'tokens',
209
+ 'charge' => 'charges',
210
+ 'void' => 'charges',
211
+ 'refund' => 'refund',
212
+ 'preAuthorization' => 'preAuthorization',
213
+ 'capture' => 'capture'
214
+ }
215
+
216
+ def commit(action, params)
217
+ response =
218
+ begin
219
+ parse(ssl_invoke(action, params))
220
+ rescue ResponseError => e
221
+ parse(e.response.body)
222
+ end
223
+
224
+ success = success_from(response)
225
+
226
+ Response.new(
227
+ success,
228
+ message_from(success, response),
229
+ response,
230
+ authorization: success ? authorization_from(response) : nil,
231
+ error_code: success ? nil : error_from(response),
232
+ test: test?
233
+ )
234
+ end
235
+
236
+ def ssl_invoke(action, params)
237
+ if %w[void refund].include?(action)
238
+ ssl_request(:delete, url(action, params), nil, headers(action))
239
+ else
240
+ ssl_post(url(action, params), post_data(params), headers(action))
241
+ end
242
+ end
243
+
244
+ def headers(action)
245
+ hfields = {}
246
+ hfields['Public-Merchant-Id'] = @options[:public_merchant_id] if action == 'tokenize'
247
+ hfields['Private-Merchant-Id'] = @options[:private_merchant_id] unless action == 'tokenize'
248
+ hfields['Content-Type'] = 'application/json'
249
+ hfields
250
+ end
251
+
252
+ def post_data(params)
253
+ params.to_json
254
+ end
255
+
256
+ def url(action, params)
257
+ base_url = test? ? test_url : live_url
258
+
259
+ if %w[void refund].include?(action)
260
+ base_url + 'v1/' + ENDPOINT[action] + '/' + params[:ticketNumber].to_s
261
+ else
262
+ base_url + 'card/v1/' + ENDPOINT[action]
263
+ end
264
+ end
265
+
266
+ def parse(body)
267
+ JSON.parse(body)
268
+ rescue JSON::ParserError
269
+ message = 'Invalid JSON response received from KushkiGateway. Please contact KushkiGateway if you continue to receive this message.'
270
+ message += " (The raw response returned by the API was #{body.inspect})"
271
+ {
272
+ 'message' => message
273
+ }
274
+ end
275
+
276
+ def success_from(response)
277
+ return true if response['token'] || response['ticketNumber'] || response['code'] == 'K000'
278
+ end
279
+
280
+ def message_from(succeeded, response)
281
+ if succeeded
282
+ 'Succeeded'
283
+ else
284
+ response['message']
285
+ end
286
+ end
287
+
288
+ def authorization_from(response)
289
+ response['token'] || response['ticketNumber']
290
+ end
291
+
292
+ def error_from(response)
293
+ response['code']
294
+ end
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,412 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class Latitude19Gateway < Gateway
4
+ self.display_name = 'Latitude19 Gateway'
5
+ self.homepage_url = 'http://www.l19tech.com'
6
+
7
+ self.live_url = 'https://gateway.l19tech.com/payments/'
8
+ self.test_url = 'https://gateway-sb.l19tech.com/payments/'
9
+
10
+ self.supported_countries = %w[US CA]
11
+ self.default_currency = 'USD'
12
+ self.money_format = :dollars
13
+ self.supported_cardtypes = %i[visa master american_express discover diners_club jcb]
14
+
15
+ RESPONSE_CODE_MAPPING = {
16
+ '100' => 'Approved',
17
+ '101' => 'Local duplicate detected',
18
+ '102' => 'Accepted local capture with no match',
19
+ '103' => 'Auth succeeded but capture failed',
20
+ '104' => 'Auth succeeded but failed to save info',
21
+ '200' => STANDARD_ERROR_CODE[:card_declined],
22
+ '300' => 'Processor reject',
23
+ '301' => 'Local reject on user/password',
24
+ '302' => 'Local reject',
25
+ '303' => 'Processor unknown response',
26
+ '304' => 'Error parsing processor response',
27
+ '305' => 'Processor auth succeeded but settle failed',
28
+ '306' => 'Processor auth succeeded settle status unknown',
29
+ '307' => 'Processor settle status unknown',
30
+ '308' => 'Processor duplicate',
31
+ '400' => 'Not submitted',
32
+ '401' => 'Terminated before request submitted',
33
+ '402' => 'Local server busy',
34
+ '500' => 'Submitted not returned',
35
+ '501' => 'Terminated before response returned',
36
+ '502' => 'Processor returned timeout status',
37
+ '600' => 'Failed local capture with no match',
38
+ '601' => 'Failed local capture',
39
+ '700' => 'Failed local void (not in capture file)',
40
+ '701' => 'Failed local void',
41
+ '800' => 'Failed local refund (not authorized)',
42
+ '801' => 'Failed local refund'
43
+ }
44
+
45
+ BRAND_MAP = {
46
+ 'master' => 'MC',
47
+ 'visa' => 'VI',
48
+ 'american_express' => 'AX',
49
+ 'discover' => 'DS',
50
+ 'diners_club' => 'DC',
51
+ 'jcb' => 'JC'
52
+ }
53
+
54
+ def initialize(options = {})
55
+ requires!(options, :account_number, :configuration_id, :secret)
56
+ super
57
+ end
58
+
59
+ def purchase(amount, payment_method, options = {})
60
+ if payment_method.is_a?(String)
61
+ auth_or_sale('sale', payment_method, amount, nil, options)
62
+ else
63
+ MultiResponse.run() do |r|
64
+ r.process { get_session(options) }
65
+ r.process { get_token(r.authorization, payment_method, options) }
66
+ r.process { auth_or_sale('sale', r.authorization, amount, payment_method, options) }
67
+ end
68
+ end
69
+ end
70
+
71
+ def authorize(amount, payment_method, options = {})
72
+ if payment_method.is_a?(String)
73
+ auth_or_sale('auth', payment_method, amount, nil, options)
74
+ else
75
+ MultiResponse.run() do |r|
76
+ r.process { get_session(options) }
77
+ r.process { get_token(r.authorization, payment_method, options) }
78
+ r.process { auth_or_sale('auth', r.authorization, amount, payment_method, options) }
79
+ end
80
+ end
81
+ end
82
+
83
+ def capture(amount, authorization, options = {})
84
+ post = {}
85
+ post[:method] = 'deposit'
86
+ add_request_id(post)
87
+
88
+ params = {}
89
+
90
+ _, params[:pgwTID] = split_authorization(authorization)
91
+
92
+ add_invoice(params, amount, options)
93
+ add_credentials(params, post[:method])
94
+
95
+ post[:params] = [params]
96
+ commit('v1/', post)
97
+ end
98
+
99
+ def void(authorization, options = {})
100
+ method, pgwTID = split_authorization(authorization)
101
+ case method
102
+ when 'auth'
103
+ reverse_or_void('reversal', pgwTID, options)
104
+ when 'deposit', 'sale'
105
+ reverse_or_void('void', pgwTID, options)
106
+ else
107
+ message = 'Unsupported operation: successful Purchase, Authorize and unsettled Capture transactions can only be voided.'
108
+ return Response.new(false, message)
109
+ end
110
+ end
111
+
112
+ def credit(amount, payment_method, options = {})
113
+ if payment_method.is_a?(String)
114
+ refundWithCard(payment_method, amount, nil, options)
115
+ else
116
+ MultiResponse.run() do |r|
117
+ r.process { get_session(options) }
118
+ r.process { get_token(r.authorization, payment_method, options) }
119
+ r.process { refundWithCard(r.authorization, amount, payment_method, options) }
120
+ end
121
+ end
122
+ end
123
+
124
+ def verify(payment_method, options = {}, action = nil)
125
+ if payment_method.is_a?(String)
126
+ verifyOnly(action, payment_method, nil, options)
127
+ else
128
+ MultiResponse.run() do |r|
129
+ r.process { get_session(options) }
130
+ r.process { get_token(r.authorization, payment_method, options) }
131
+ r.process { verifyOnly(action, r.authorization, payment_method, options) }
132
+ end
133
+ end
134
+ end
135
+
136
+ def store(payment_method, options = {})
137
+ verify(payment_method, options, 'store')
138
+ end
139
+
140
+ def supports_scrubbing?
141
+ true
142
+ end
143
+
144
+ def scrub(transcript)
145
+ transcript.
146
+ gsub(%r((\"cardNumber\\\":\\\")\d+), '\1[FILTERED]').
147
+ gsub(%r((\"cvv\\\":\\\")\d+), '\1[FILTERED]')
148
+ end
149
+
150
+ private
151
+
152
+ def add_request_id(post)
153
+ post[:id] = SecureRandom.hex(16)
154
+ end
155
+
156
+ def add_timestamp
157
+ Time.now.getutc.strftime('%Y%m%d%H%M%S')
158
+ end
159
+
160
+ def add_hmac(params, method)
161
+ if method == 'getSession'
162
+ hmac_message = params[:pgwAccountNumber] + '|' + params[:pgwConfigurationId] + '|' + params[:requestTimeStamp] + '|' + method
163
+ else
164
+ hmac_message = params[:pgwAccountNumber] + '|' + params[:pgwConfigurationId] + '|' + (params[:orderNumber] || '') + '|' + method + '|' + (params[:amount] || '') + '|' + (params[:sessionToken] || '') + '|' + (params[:accountToken] || '')
165
+ end
166
+
167
+ OpenSSL::HMAC.hexdigest('sha512', @options[:secret], hmac_message)
168
+ end
169
+
170
+ def add_credentials(params, method)
171
+ params[:pgwAccountNumber] = @options[:account_number]
172
+ params[:pgwConfigurationId] = @options[:configuration_id]
173
+
174
+ params[:requestTimeStamp] = add_timestamp() if method == 'getSession'
175
+
176
+ params[:pgwHMAC] = add_hmac(params, method)
177
+ end
178
+
179
+ def add_invoice(params, money, options)
180
+ params[:amount] = amount(money)
181
+ params[:orderNumber] = options[:order_id]
182
+ params[:transactionClass] = options[:transaction_class] || 'eCommerce'
183
+ end
184
+
185
+ def add_payment_method(params, credit_card)
186
+ params[:cardExp] = format(credit_card.month, :two_digits).to_s + '/' + format(credit_card.year, :two_digits).to_s
187
+ params[:cardType] = BRAND_MAP[credit_card.brand.to_s]
188
+ params[:cvv] = credit_card.verification_value
189
+ params[:firstName] = credit_card.first_name
190
+ params[:lastName] = credit_card.last_name
191
+ end
192
+
193
+ def add_customer_data(params, options)
194
+ if (billing_address = options[:billing_address] || options[:address])
195
+ params[:address1] = billing_address[:address1]
196
+ params[:address2] = billing_address[:address2]
197
+ params[:city] = billing_address[:city]
198
+ params[:stateProvince] = billing_address[:state]
199
+ params[:zipPostalCode] = billing_address[:zip]
200
+ params[:countryCode] = billing_address[:country]
201
+ end
202
+ end
203
+
204
+ def get_session(options = {})
205
+ post = {}
206
+ post[:method] = 'getSession'
207
+ add_request_id(post)
208
+
209
+ params = {}
210
+ add_credentials(params, post[:method])
211
+
212
+ post[:params] = [params]
213
+ commit('session', post)
214
+ end
215
+
216
+ def get_token(authorization, payment_method, options = {})
217
+ post = {}
218
+ post[:method] = 'tokenize'
219
+ add_request_id(post)
220
+
221
+ params = {}
222
+ _, params[:sessionId] = split_authorization(authorization)
223
+ params[:cardNumber] = payment_method.number
224
+
225
+ post[:params] = [params]
226
+ commit('token', post)
227
+ end
228
+
229
+ def auth_or_sale(method, authorization, amount, credit_card, options = {})
230
+ post = {}
231
+ post[:method] = method
232
+ add_request_id(post)
233
+
234
+ params = {}
235
+ if credit_card
236
+ _, params[:sessionToken] = split_authorization(authorization)
237
+ add_payment_method(params, credit_card)
238
+ add_customer_data(params, options)
239
+ else
240
+ _, params[:accountToken] = split_authorization(authorization)
241
+ end
242
+ add_invoice(params, amount, options)
243
+ add_credentials(params, post[:method])
244
+
245
+ post[:params] = [params]
246
+ commit('v1/', post)
247
+ end
248
+
249
+ def verifyOnly(action, authorization, credit_card, options = {})
250
+ post = {}
251
+ post[:method] = 'verifyOnly'
252
+ add_request_id(post)
253
+
254
+ params = {}
255
+ if credit_card
256
+ _, params[:sessionToken] = split_authorization(authorization)
257
+ add_payment_method(params, credit_card)
258
+ add_customer_data(params, options)
259
+ else
260
+ _, params[:accountToken] = split_authorization(authorization)
261
+ end
262
+ params[:requestAccountToken] = '1' if action == 'store'
263
+ add_invoice(params, 0, options)
264
+ add_credentials(params, post[:method])
265
+
266
+ post[:params] = [params]
267
+ commit('v1/', post)
268
+ end
269
+
270
+ def refundWithCard(authorization, amount, credit_card, options = {})
271
+ post = {}
272
+ post[:method] = 'refundWithCard'
273
+ add_request_id(post)
274
+
275
+ params = {}
276
+ if credit_card
277
+ _, params[:sessionToken] = split_authorization(authorization)
278
+ add_payment_method(params, credit_card)
279
+ else
280
+ _, params[:accountToken] = split_authorization(authorization)
281
+ end
282
+ add_invoice(params, amount, options)
283
+ add_credentials(params, post[:method])
284
+
285
+ post[:params] = [params]
286
+ commit('v1/', post)
287
+ end
288
+
289
+ def reverse_or_void(method, pgwTID, options = {})
290
+ post = {}
291
+ post[:method] = method
292
+ add_request_id(post)
293
+
294
+ params = {}
295
+ params[:orderNumber] = options[:order_id]
296
+ params[:pgwTID] = pgwTID
297
+ add_credentials(params, post[:method])
298
+
299
+ post[:params] = [params]
300
+ commit('v1/', post)
301
+ end
302
+
303
+ def commit(endpoint, post)
304
+ raw_response = ssl_post(url() + endpoint, post_data(post), headers)
305
+ response = parse(raw_response)
306
+ rescue ResponseError => e
307
+ raw_response = e.response.body
308
+ response_error(raw_response)
309
+ rescue JSON::ParserError
310
+ unparsable_response(raw_response)
311
+ else
312
+ success = success_from(response)
313
+ Response.new(
314
+ success,
315
+ message_from(response),
316
+ response,
317
+ authorization: success ? authorization_from(response, post[:method]) : nil,
318
+ avs_result: success ? avs_from(response) : nil,
319
+ cvv_result: success ? cvv_from(response) : nil,
320
+ error_code: success ? nil : error_from(response),
321
+ test: test?
322
+ )
323
+ end
324
+
325
+ def headers
326
+ {
327
+ 'Content-Type' => 'application/json'
328
+ }
329
+ end
330
+
331
+ def post_data(params)
332
+ params.to_json
333
+ end
334
+
335
+ def url
336
+ test? ? test_url : live_url
337
+ end
338
+
339
+ def parse(body)
340
+ JSON.parse(body)
341
+ end
342
+
343
+ def success_from(response)
344
+ return false if response['result'].nil? || response['error']
345
+
346
+ if response['result'].key?('pgwResponseCode')
347
+ response['error'].nil? && response['result']['lastActionSucceeded'] == 1 && response['result']['pgwResponseCode'] == '100'
348
+ else
349
+ response['error'].nil? && response['result']['lastActionSucceeded'] == 1
350
+ end
351
+ end
352
+
353
+ def message_from(response)
354
+ return response['error'] if response['error']
355
+ return 'Failed' unless response.key?('result')
356
+
357
+ if response['result'].key?('pgwResponseCode')
358
+ RESPONSE_CODE_MAPPING[response['result']['pgwResponseCode']] || response['result']['responseText']
359
+ else
360
+ response['result']['lastActionSucceeded'] == 1 ? 'Succeeded' : 'Failed'
361
+ end
362
+ end
363
+
364
+ def error_from(response)
365
+ return response['error'] if response['error']
366
+ return 'Failed' unless response.key?('result')
367
+
368
+ return response['result']['pgwResponseCode'] || response['result']['processor']['responseCode'] || 'Failed'
369
+ end
370
+
371
+ def authorization_from(response, method)
372
+ method + '|' + (
373
+ response['result']['sessionId'] ||
374
+ response['result']['sessionToken'] ||
375
+ response['result']['pgwTID'] ||
376
+ response['result']['accountToken']
377
+ )
378
+ end
379
+
380
+ def split_authorization(authorization)
381
+ authorization.split('|')
382
+ end
383
+
384
+ def avs_from(response)
385
+ response['result'].key?('avsResponse') ? AVSResult.new(code: response['result']['avsResponse']) : nil
386
+ end
387
+
388
+ def cvv_from(response)
389
+ response['result'].key?('cvvResponse') ? CVVResult.new(response['result']['cvvResponse']) : nil
390
+ end
391
+
392
+ def response_error(raw_response)
393
+ response = parse(raw_response)
394
+ rescue JSON::ParserError
395
+ unparsable_response(raw_response)
396
+ else
397
+ return Response.new(
398
+ false,
399
+ message_from(response),
400
+ response,
401
+ test: test?
402
+ )
403
+ end
404
+
405
+ def unparsable_response(raw_response)
406
+ message = 'Invalid JSON response received from Latitude19Gateway. Please contact Latitude19Gateway if you continue to receive this message.'
407
+ message += " (The raw response returned by the API was #{raw_response.inspect})"
408
+ return Response.new(false, message)
409
+ end
410
+ end
411
+ end
412
+ end