dolla 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 51bfe8941859c9004339b4853d215b833a102e21
4
+ data.tar.gz: de83ca1306e3f444dd2f913cf2afb8dce47b161c
5
+ SHA512:
6
+ metadata.gz: 98fee4c69a05caba1410d17e86ad32948e457675717cd8cc7aa18bec3077d197220c9b67977fe2a6b63f07b76edbd5baf7b6f90cad1d44e90acf197a0e522ef3
7
+ data.tar.gz: 36bfcfde3d6ec3891d1f07aedffba0281536b2ac61e07338baca6e6c9a6edbfe33283f99a0fa0fb50afe920ccc2c8d09d541010ea9213ce574c040f9d2b202ed
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ Gemfile.lock
14
+ .env.development
15
+ .rem
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler -v 1.16.1
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at sanchez.dav90@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in dolla.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 David Sanchez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Dolla
2
+
3
+ Dolla is a payment gateway module developed by AMCO.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'dolla'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dolla
20
+
21
+ ## Usage
22
+
23
+ After install, run `rake dolla:install` command to create an initializer file, adding the config variables to modify in your application `config/initializers/dolla.rb`:
24
+
25
+ ```ruby
26
+ Dolla.configure do |config|
27
+ config.business_unit = 'BUSINESS_UNIT'
28
+ config.payment_gateway_code = 'PAYMENT_GATEWAY_CODE'
29
+ config.cancel_gateway_code = 'CANCEL_GATEWAY_CODE'
30
+ config.currency = 'CURRENCY'
31
+ config.client_id = 'CLIENT_ID'
32
+ config.admin_email = 'ADMIN_EMAIL'
33
+ config.transaction_type = 'TRANSACTION_TYPE'
34
+ config.platform = 'PLATFORM'
35
+ config.payment = 'PAYMENT'
36
+ config.cancellation = 'CANCELLATION'
37
+ config.rijndael_key = 'RIJNDAEL_KEY'
38
+ config.hmac_key = 'HMAC_KEY'
39
+ end
40
+ ```
41
+
42
+ ## Development
43
+
44
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
45
+
46
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
47
+
48
+ ## Contributing
49
+
50
+ Bug reports and pull requests are welcome on GitHub at https://github.com/amco/dolla. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
51
+
52
+ ## License
53
+
54
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
55
+
56
+ ## Code of Conduct
57
+
58
+ Everyone interacting in the Dolla project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/dolla/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.pattern = "test/**/*_test.rb"
8
+ end
9
+
10
+ desc "Run tests"
11
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dolla"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/dolla.gemspec ADDED
@@ -0,0 +1,35 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "dolla/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dolla"
8
+ spec.version = Dolla::VERSION
9
+ spec.authors = ["Enrique Vidal", "David Sanchez", "Carlos Muniz"]
10
+ spec.email = ["enrique@cloverinteractive.com", "sanchez.dav90@gmail.com", "mumo.crls@gmail.com"]
11
+
12
+ spec.summary = %q{Dolla module for payment gateways.}
13
+ spec.description = %q{Dolla is a gem that provide payments methods for bank gateways.}
14
+ spec.homepage = "https://github.com/amco/dolla."
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.16"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest", "~> 5.1"
27
+ spec.add_development_dependency "factory_bot"
28
+ spec.add_development_dependency "timecop"
29
+ spec.add_runtime_dependency "activerecord"
30
+ spec.add_dependency 'symbolize'
31
+ spec.add_dependency 'rails'
32
+ spec.add_dependency 'ruby-hmac'
33
+ spec.add_dependency 'crypt19-rb'
34
+ spec.add_dependency 'savon', "~> 0.9.14"
35
+ end
data/lib/dolla.rb ADDED
@@ -0,0 +1,38 @@
1
+ require "dolla/configuration"
2
+ require "dolla/version"
3
+ require "savon"
4
+
5
+ module Dolla
6
+ class << self
7
+ attr_accessor :configuration
8
+ end
9
+
10
+ def self.configuration
11
+ @configuration ||= Configuration.new
12
+ end
13
+
14
+ def self.reset
15
+ @configuration = Configuration.new
16
+ end
17
+
18
+ def self.configure
19
+ yield(configuration)
20
+ end
21
+
22
+ autoload :CardNumberPrefix, 'dolla/card_number_prefix'
23
+ autoload :PaymentStub, 'dolla/payment_stub'
24
+ autoload :Gateway, 'dolla/gateway'
25
+ autoload :ReferenceNumber, 'dolla/reference_number'
26
+ autoload :Options, 'dolla/options'
27
+ autoload :EndPoints, 'dolla/end_points'
28
+ autoload :Amount, 'dolla/payment_slip/amount'
29
+ autoload :DueDate, 'dolla/payment_slip/due_date'
30
+ autoload :Terms, 'dolla/terms'
31
+ autoload :EncryptionTools, 'dolla/encryption_tools'
32
+ autoload :RequestBuilder, 'dolla/request_builder'
33
+ autoload :CardType, 'dolla/card_type'
34
+
35
+ module CardPrefix
36
+ autoload :Amex, 'dolla/card_prefix/amex'
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ module Dolla
2
+ class CardNumberPrefix
3
+ attr_accessor :prefix, :bank
4
+
5
+ def initialize(args = {})
6
+ @prefix = args[:prefix]
7
+ @bank = args[:bank]
8
+ end
9
+
10
+ def self.is_amex
11
+ prefixes = ::Dolla::CardPrefix::Amex::PREFIXES
12
+
13
+ prefixes.map do |prefix|
14
+ new(prefix: prefix, bank: :amex)
15
+ end
16
+ end
17
+
18
+ def self.card_number_is_amex? number
19
+ number.to_s.match /^(34|37)/
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ module Dolla
2
+ module CardPrefix
3
+ class Amex
4
+ PREFIXES = %w{
5
+ 370700 370701 370702 370703 370704 370705 370706 370707 370708
6
+ 370709 370710 370711 370712 370713 370714 370715 370716 370717
7
+ 370718 370719 370720 370721 370722 370723 370724 370725 370726
8
+ 370727 370728 370729 370730 370731 370732 370733 370734 370735
9
+ 370736 370737 370738 370739 370740 370741 370742 370743 370744
10
+ 370745 370746 370747 370748 370749 370750 370751 370752 370753
11
+ 370754 370755 370756 370757 370758 370759 370760 370761 370762
12
+ 370763 370764 370765 370766 370767 370768 370769 370770 370771
13
+ 370772 370773 370774 370775 370776 370777 370778 370779 370780
14
+ 370781 370782 370783 370784 370785 370786 370787 370788 370789
15
+ 370790 370791 370792 370793 370794 370795 370796 370797 370798
16
+ 370799 376620 376621 376622 376623 376624 376625 376626 376627
17
+ 376628 376629 376660 376661 376662 376663 376664 376665 376666
18
+ 376667 376668 376669 376670 376671 376672 376673 376674 376675
19
+ 376676 376677 376678 376679 376680 376681 376689 376700 376701
20
+ 376702 376703 376704 376705 376706 376707 376708 376709 376716
21
+ 376717 376718 377650 377651 377652 377653 377654 377655 377656
22
+ 377657 377658 377659}
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,23 @@
1
+ module Dolla
2
+ class CardType
3
+ PREFIXES = {
4
+ 1 => [ 4 ], #Bank code for VISA
5
+ 2 => [ *51..55 ], #Bank code for MC
6
+ 3 => [ 34, 37 ], #Bank code for AMEX
7
+ }
8
+
9
+ attr_accessor :name, :bank_code
10
+
11
+ def initialize(args = {})
12
+ @name = args[:name]
13
+ @bank_code = args[:bank_code]
14
+ end
15
+
16
+ def self.card_code_for_number number
17
+ codes = self.all.map do |card_type|
18
+ PREFIXES[ card_type.bank_code ].map { |prefix| card_type if number =~ /\A#{ prefix }/ }
19
+ end.flatten.compact.uniq.last
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ module Dolla
2
+ class Configuration
3
+ attr_accessor :business_unit, :payment_gateway_code, :cancel_gateway_code, :currency,
4
+ :client_id, :admin_email, :transaction_type, :platform, :payment, :cancellation,
5
+ :rijndael_key, :hmac_key
6
+
7
+ def initialize
8
+ @business_unit = nil
9
+ @payment_gateway_code = nil
10
+ @cancel_gateway_code = nil
11
+ @currency = nil
12
+ @client_id = nil
13
+ @admin_email = nil
14
+ @transaction_type = nil
15
+ @platform = nil
16
+ @payment = nil
17
+ @cancellation = nil
18
+ @rijndael_key = nil
19
+ @hmac_key = nil
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ require 'hmac-sha1'
2
+ require 'crypt/rijndael'
3
+
4
+ module Dolla
5
+ module EncryptionTools
6
+ def build_digest *ary
7
+ sha1 = HMAC::SHA1.new Dolla.configuration.hmac_key
8
+ sha1 << ary.join
9
+
10
+ sha1.to_s
11
+ end
12
+
13
+ def padding(key)
14
+ final_key = "\0" * 16
15
+ key.length.times { |i| final_key[i%16] ^= key[i] }
16
+
17
+ final_key
18
+ end
19
+
20
+ def rijndael_encrypt( value )
21
+ rijndael = Crypt::Rijndael.new Dolla.configuration.rijndael_key, 128
22
+ Base64.encode64( rijndael.encrypt_block( padding value ) ).strip
23
+ end
24
+
25
+ def decimal_format value
26
+ sprintf "%0.2f", value
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module Dolla
2
+ module EndPoints
3
+
4
+ XML_NAMESPACE = {
5
+ default: 'http://webservice.interred.adquira.com.mx',
6
+ amex: 'http://adquira.com.mx/amex/schemas',
7
+ }
8
+
9
+ PRODUCTION_URL = {
10
+ default: 'https://www.multipagos.com.mx/ProcesaPagosOLW/services/ProcesadorPagos',
11
+ amex: 'https://www.multipagos.com.mx/AmexWS/services/insPagoAmex.wsdl',
12
+ }
13
+
14
+ TESTING_URL = {
15
+ default: 'https://www.egbs5.com.mx/ProcesaPagosOLW/services/ProcesadorPagos?WSDL',
16
+ amex: 'https://www.egbs5.com.mx/AmexWS/services/insPagoAmex.wsdl',
17
+ }
18
+
19
+ WSDL_ADDRESS = Rails.env.production? ? PRODUCTION_URL : TESTING_URL
20
+
21
+ def get_wsdl_address key = nil
22
+ key ? WSDL_ADDRESS[key] : WSDL_ADDRESS[:default]
23
+ end
24
+
25
+ def get_xml_namespace key = nil
26
+ key ? XML_NAMESPACE[key] : XML_NAMESPACE[:default]
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,176 @@
1
+ module Dolla
2
+ module Gateway
3
+ include Options
4
+ include EndPoints
5
+ include Terms
6
+ include EncryptionTools
7
+
8
+ ACTIONS = {
9
+ default: {
10
+ cancel_purchase: :reverso_tdc_interred,
11
+ process_purchase: :procesa_compra_o_l,
12
+ },
13
+
14
+ amex: {
15
+ process_purchase: :ins_pago_amex_request
16
+ }
17
+ }.freeze
18
+
19
+ delegate :request, to: :payments_gateway
20
+
21
+ attr_accessor :payment_id, :code, :amount, :cvv, :card_number, :card_expiration,
22
+ :cardholder, :phone_number, :name, :last_name, :address, :zip_code,
23
+ :email, :card_type_bank_code, :user_agent, :server_address, :bank_account_terms
24
+
25
+ def pay!
26
+ request soap_action(:process_purchase), xmlns: xml_namespace do
27
+ soap.element_form_default = :qualified
28
+ soap.body = build_payment_body.to_hash
29
+ end
30
+ end
31
+
32
+ def reference valid_timeframe = 1.week
33
+ due_date = valid_timeframe.from_now
34
+ ReferenceNumber.new( due_date: due_date, amount: amount, payment_id: payment_id )
35
+ end
36
+
37
+ def payments_gateway
38
+ @client ||= ::Savon::Client.new do
39
+ wsdl.endpoint = wsdl_address
40
+ wsdl.namespace = xml_namespace
41
+ end
42
+ end
43
+
44
+ def wsdl_address
45
+ amex? ? get_wsdl_address(:amex) : get_wsdl_address
46
+ end
47
+
48
+ def xml_namespace
49
+ amex? ? get_xml_namespace(:amex) : get_xml_namespace
50
+ end
51
+
52
+ def soap_action key
53
+ actions = amex? ? ACTIONS[:amex] : ACTIONS[:default]
54
+ actions[key]
55
+ end
56
+
57
+ def amex?
58
+ CardNumberPrefix.card_number_is_amex? card_number
59
+ end
60
+
61
+ def card_number= value
62
+ @card_number = value.to_s.gsub /\D/, ''
63
+ end
64
+
65
+ def full_name
66
+ [name, last_name].join(' ')
67
+ end
68
+
69
+ def decimal_amount
70
+ decimal_format( amount )
71
+ end
72
+
73
+ def build_payment_body
74
+ amex? ? build_amex_payment_body : build_default_payment_body
75
+ end
76
+
77
+ def build_default_payment_body
78
+ body = default_body_fields
79
+
80
+ body.set_option :card_type, card_type_bank_code
81
+ body.set_option :transaction_type, Dolla.configuration.transaction_type
82
+ body.set_option :track, ''
83
+ body.set_option :admin_email, Dolla.configuration.admin_email
84
+ body.set_option :transaction, Dolla.configuration.payment
85
+ body.set_option :afiliation, ''
86
+ body.set_option :platform, Dolla.configuration.platform
87
+
88
+ %i/card_sequence interred_sequence signature_flag promissory_code promissory_transaction/.each do |opt|
89
+ body.set_option opt, ''
90
+ end
91
+
92
+ body.set_option(:order!, body.keys) # Unfortunately order matters...
93
+ end
94
+
95
+ def build_amex_payment_body
96
+ body = default_body_fields
97
+
98
+ body.set_option :typed_card, amex_typed_card
99
+ body.set_option :avs_validation, amex_avs_validation
100
+ body.set_option :slid_card, nil
101
+ body.set_option :card_chip, nil
102
+
103
+ body.set_option :order!, body.keys
104
+ end
105
+
106
+ def amex_avs_validation
107
+ opt = ActiveSupport::OrderedHash.new
108
+
109
+ opt[ get_option(:name) ] = name
110
+ opt[ get_option(:surnames) ] = last_name
111
+ opt[ get_option(:zip_code) ] = zip_code
112
+ opt[ get_option(:address) ] = address
113
+ opt[ get_option(:shipping) ] = nil
114
+
115
+ opt
116
+ end
117
+
118
+ def amex_typed_card
119
+ opt = ActiveSupport::OrderedHash.new
120
+
121
+ opt['operationEnvironment'] = 0 # more static values that we don't know what they are
122
+ opt['cardHolderPresent'] = 'S'
123
+ opt['cardPresent'] = false
124
+
125
+ opt[ get_option(:online_purchase) ] = ActiveSupport::OrderedHash.new
126
+
127
+ opt[ get_option(:online_purchase) ]['browser'] = user_agent[0..49]
128
+ opt[ get_option(:online_purchase) ]['shipping'] = '05' # plz don't ask me what this means, multipagos just said to set it to this
129
+ opt[ get_option(:online_purchase) ]['productId'] = '0' * 6 # just a placeholder until we get the asset system right
130
+ opt[ get_option(:online_purchase) ][ get_option(:client_ip) ] = server_address
131
+ opt
132
+ end
133
+
134
+ def default_body_fields
135
+ encrypted = encrypted_customer_info
136
+
137
+ if amex?
138
+ cardholder = :full_name
139
+ currency = :amex_currency
140
+ terms = bank_account_terms > 1 ? bank_account_terms : ''
141
+ end
142
+
143
+ cardholder ||= :cardholder
144
+ currency ||= :currency
145
+
146
+ body = RequestBuilder.new
147
+
148
+ body.set_option :payment_id, payment_id
149
+ body.set_option :payment_code, code
150
+ body.set_option :business_unit, Dolla.configuration.business_unit
151
+ body.set_option :service_type, Dolla.configuration.payment_gateway_code
152
+ body.set_option currency, Dolla.configuration.currency
153
+ body.set_option :total, decimal_amount
154
+ body.set_option cardholder, full_name
155
+ body.set_option :card_number, encrypted[:cc]
156
+ body.set_option :card_expiration, encrypted[:cc_exp]
157
+ body.set_option :cvv, encrypted[:cc_cvv]
158
+ body.set_option :digest, encrypted[:hmac]
159
+ body.set_option :client_email, email
160
+ body.set_option :client_phone, phone_number
161
+ body.set_option :client_id, Dolla.configuration.client_id
162
+ body.set_option :payment_plan, payment_plan
163
+ body.set_option :terms, (amex? ? terms : bank_account_terms)
164
+ end
165
+
166
+ def encrypted_customer_info
167
+ {
168
+ hmac: build_digest( payment_id, code, decimal_amount, cvv ),
169
+ cc: rijndael_encrypt( card_number ),
170
+ cc_exp: rijndael_encrypt( card_expiration.strftime( '%y%m' ) ),
171
+ cc_cvv: rijndael_encrypt( cvv.to_s ),
172
+ }
173
+ end
174
+
175
+ end
176
+ end
@@ -0,0 +1,58 @@
1
+ module Dolla
2
+ module Options
3
+
4
+ OPTS = {
5
+ payment_id: 's_transm',
6
+ payment_code: 'c_referencia',
7
+ business_unit: 'val_1',
8
+ service_type: 't_servicio',
9
+ currency: 't_cur',
10
+ total: 't_importe',
11
+ cardholder: 'tarjetabiente', # No, this is not a typo that's how it's spelled in their documentation and WSDL
12
+ card_number: 'val_3',
13
+ card_expiration: 'val_4',
14
+ cvv: 'val_5',
15
+ digest: 'val_6', # 160-bit HMAC SHA-1 (payment_id + payment_reference + total + cvv).
16
+ client_email: 'val_11',
17
+ client_phone: 'val_12',
18
+ client_id: 'clave_entidad',
19
+ card_type: 'val_16', # 1 visa, 2 mastercard, 3 Amex
20
+ transaction_type: 'val_17', # 0 typed, 1 slided
21
+ track: 'val_18', # Only if transaction_type is 1
22
+ payment_plan: 'val_19',
23
+ terms: 'val_20',
24
+ admin_email: 'email_admin',
25
+ transaction: 'accion',
26
+ afiliation: 'nu_afiliacion',
27
+ platform: 'nu_plataforma',
28
+ card_sequence: 'TAG5F34',
29
+ interred_sequence: 'TAGSEMV',
30
+ signature_flag: 'sFlag',
31
+ promissory_code: 'TAG9F26',
32
+ promissory_transaction: 'TAG9F27',
33
+ authorization: 'cd_autorizacion',
34
+
35
+ # From this point it's all AMEX specific the reason behind why this isn't under an :amex key
36
+ # is because 1) order matters, 2) we have 3 levels of nesting in all AMEX requests
37
+
38
+ avs_validation: 'validacionAVS',
39
+ typed_card: 'tarjetaDigitada',
40
+ slid_card: 'tarjetaDeslizada',
41
+ card_chip: 'tarjetaChip',
42
+ online_purchase: 'compraRemotaCliente',
43
+ name: 'nombreTitular',
44
+ surnames: 'apellidosTitular',
45
+ full_name: 'titular',
46
+ zip_code: 'codigoPostal',
47
+ address: 'direccion',
48
+ shipping: 'datosEnvio',
49
+ client_ip: 'ipCliente',
50
+ amex_currency: 'c_cur',
51
+ }.freeze
52
+
53
+ def get_option key
54
+ OPTS[key]
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ module Dolla
2
+ module PaymentSlip
3
+ class Amount
4
+ attr_reader :value
5
+
6
+ delegate :length, to: :value
7
+
8
+ def initialize number
9
+ @value = format_amount number
10
+ end
11
+
12
+ def hash
13
+ filler_string = "".ljust( length, "731" ).reverse
14
+ (0..length-1).inject(0) do |sum, position|
15
+ sum + value[ position, 1 ].to_i * filler_string[ position, 1 ].to_i
16
+ end % 10
17
+ end
18
+
19
+ private
20
+
21
+ def format_amount number
22
+ "%d" % ( number * 100 ).round
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ module Dolla
2
+ module PaymentSlip
3
+ class DueDate
4
+ extend Forwardable
5
+
6
+ PAYSLIP_EPOCH_YEAR = 2014
7
+ PAYSLIP_YEAR_MUTATOR = 372
8
+
9
+ PAYSLIP_MONTH_MUTATOR = 31
10
+
11
+ def_delegators :@due_date, :year, :month, :day
12
+
13
+ def initialize due_date
14
+ @due_date = due_date
15
+ end
16
+
17
+ # TODO: hack temporal
18
+ def hash
19
+ h = mutate_year(year) + mutate_month(month) + mutate_day(day)
20
+ h.to_s.rjust(4, "0")
21
+ end
22
+
23
+ private
24
+
25
+ def mutate_year year
26
+ ( year - PAYSLIP_EPOCH_YEAR ) * PAYSLIP_YEAR_MUTATOR
27
+ end
28
+
29
+ def mutate_month month
30
+ ( month - 1 ) * PAYSLIP_MONTH_MUTATOR
31
+ end
32
+
33
+ def mutate_day day
34
+ day - 1
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,43 @@
1
+ module Dolla
2
+ class PaymentStub
3
+ include Dolla::Gateway
4
+
5
+ attr_reader :attributes
6
+
7
+ def initialize opts = {}
8
+ @attributes = {
9
+ payment_id: 100,
10
+ code: 'ABCDE',
11
+ amount: "1.10",
12
+ cvv: "123",
13
+ card_number: "4111111111111111",
14
+ card_expiration: 1.year.from_now,
15
+ name: "Doroteo",
16
+ last_name: 'Arango',
17
+ address: '1911 Columbos',
18
+ email: 'villa@losdorados.com',
19
+ phone_number: '6661231234',
20
+ zip_code: "22000",
21
+ user_agent: 'Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405',
22
+ server_address: '127.0.0.1',
23
+ }.merge!( opts )
24
+
25
+ attributes.each do |prop, value|
26
+ send("#{prop}=", value)
27
+ end
28
+ end
29
+
30
+ def bank_account_terms
31
+ 1
32
+ end
33
+
34
+ def card_type
35
+ @card_type ||= FactoryBot.build(:visa_card)
36
+ end
37
+
38
+ def card_type_bank_code
39
+ card_type.bank_code
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails'
2
+
3
+ module Dolla
4
+ class Railtie < Rails::Railtie
5
+ railtie_name :dolla
6
+
7
+ rake_tasks do
8
+ load File.join File.dirname(__FILE__), 'tasks/prefixes.rake'
9
+ end
10
+ end
11
+ end
12
+
13
+
@@ -0,0 +1,59 @@
1
+ module Dolla
2
+ class ReferenceNumber
3
+
4
+ attr_reader :request, :id, :due_date, :amount
5
+
6
+ REFERENCE_NUMBER_FORMAT = { initial: '%07d%s%d%d', final: '%s-%02d' }.freeze
7
+ BANK_FILLER = %w/11 13 17 19 23/.freeze
8
+
9
+ delegate :length, to: :ref
10
+
11
+ def initialize(payment_id:, due_date:, amount:)
12
+ @id = payment_id
13
+ @due_date = due_date
14
+ @amount = amount
15
+ end
16
+
17
+ def number
18
+ final_reference_number_format % [ref, ref_hash]
19
+ end
20
+
21
+ private
22
+
23
+ def ref
24
+ initial_reference_number_format % [id, hash_date, hash_amount, 2]
25
+ end
26
+
27
+ def ref_hash
28
+ numbers_container = []
29
+
30
+ BANK_FILLER.cycle do |filler|
31
+ numbers_container << filler
32
+ break if numbers_container.length >= length
33
+ end
34
+
35
+ numbers_container.reverse!
36
+
37
+ (0..length-1).inject(0) do |sum, position|
38
+ sum += (ref[ position, 1 ].to_i * numbers_container[ position ].to_i)
39
+ end % 97 + 1
40
+ end
41
+
42
+ def hash_date
43
+ PaymentSlip::DueDate.new( due_date ).hash
44
+ end
45
+
46
+ def hash_amount
47
+ PaymentSlip::Amount.new( amount ).hash
48
+ end
49
+
50
+ def initial_reference_number_format
51
+ REFERENCE_NUMBER_FORMAT[:initial]
52
+ end
53
+
54
+ def final_reference_number_format
55
+ REFERENCE_NUMBER_FORMAT[:final]
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ module Dolla
2
+ class RequestBuilder
3
+ extend Forwardable
4
+ include Options
5
+
6
+ def_delegators :@hash, :[], :[]=, :keys
7
+
8
+ def initialize
9
+ @hash = ActiveSupport::OrderedHash.new
10
+ end
11
+
12
+ def set_option key, value
13
+ option_key = (key == :order!)? key : get_option( key )
14
+ @hash[ option_key ] = value
15
+ self
16
+ end
17
+
18
+ def to_hash
19
+ @hash
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module Dolla
2
+ module Terms
3
+ BANK_FINANCED = 1
4
+ NOT_FINANCED = 0
5
+
6
+ #TODO: when implementing montlhy payments will require
7
+ #to have logic for set if financing is available
8
+ def payment_plan
9
+ bank_account_terms > 1 ? BANK_FINANCED : NOT_FINANCED
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Dolla
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ module Dolla
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ def copy_initializer
7
+ template "dolla_initializer.rb", "config/initializers/dolla.rb"
8
+
9
+ puts "Install complete! Please make sure to set following ENV variables!"
10
+ puts "ENV['BUSINESS_UNIT'] = <number>"
11
+ puts "ENV['PAYMENT_GATEWAY_CODE'] = <number>"
12
+ puts "ENV['CANCEL_GATEWAY_CODE'] = <number>"
13
+ puts "ENV['CURRENCY'] = <number>"
14
+ puts "ENV['CLIENT_ID'] = <number>"
15
+ puts "ENV['ADMIN_EMAIL'] = <string>"
16
+ puts "ENV['TRANSACTION_TYPE'] = <number>"
17
+ puts "ENV['PLATFORM'] = <number>"
18
+ puts "ENV['PAYMENT'] = <string>"
19
+ puts "ENV['CANCELLATION'] = <string>"
20
+ puts "ENV['RIJNDAEL_KEY'] = <string>"
21
+ puts "ENV['HMAC_KEY'] = <string>"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ Dolla.configure do |config|
2
+ config.business_unit = 'BUSINESS_UNIT'
3
+ config.payment_gateway_code = 'PAYMENT_GATEWAY_CODE'
4
+ config.cancel_gateway_code = 'CANCEL_GATEWAY_CODE'
5
+ config.currency = 'CURRENCY'
6
+ config.client_id = 'CLIENT_ID'
7
+ config.admin_email = 'ADMIN_EMAIL'
8
+ config.transaction_type = 'TRANSACTION_TYPE'
9
+ config.platform = 'PLATFORM'
10
+ config.payment = 'PAYMENT'
11
+ config.cancellation = 'CANCELLATION'
12
+ config.rijndael_key = 'RIJNDAEL_KEY'
13
+ config.hmac_key = 'HMAC_KEY'
14
+ end
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dolla
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Enrique Vidal
8
+ - David Sanchez
9
+ - Carlos Muniz
10
+ autorequire:
11
+ bindir: exe
12
+ cert_chain: []
13
+ date: 2018-01-19 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bundler
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.16'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1.16'
29
+ - !ruby/object:Gem::Dependency
30
+ name: rake
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '10.0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '10.0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: minitest
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '5.1'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '5.1'
57
+ - !ruby/object:Gem::Dependency
58
+ name: factory_bot
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: timecop
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ - !ruby/object:Gem::Dependency
86
+ name: activerecord
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :runtime
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ - !ruby/object:Gem::Dependency
100
+ name: symbolize
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ type: :runtime
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ - !ruby/object:Gem::Dependency
114
+ name: rails
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :runtime
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: ruby-hmac
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ - !ruby/object:Gem::Dependency
142
+ name: crypt19-rb
143
+ requirement: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ type: :runtime
149
+ prerelease: false
150
+ version_requirements: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ - !ruby/object:Gem::Dependency
156
+ name: savon
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - "~>"
160
+ - !ruby/object:Gem::Version
161
+ version: 0.9.14
162
+ type: :runtime
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: 0.9.14
169
+ description: Dolla is a gem that provide payments methods for bank gateways.
170
+ email:
171
+ - enrique@cloverinteractive.com
172
+ - sanchez.dav90@gmail.com
173
+ - mumo.crls@gmail.com
174
+ executables: []
175
+ extensions: []
176
+ extra_rdoc_files: []
177
+ files:
178
+ - ".gitignore"
179
+ - ".travis.yml"
180
+ - CODE_OF_CONDUCT.md
181
+ - Gemfile
182
+ - LICENSE.txt
183
+ - README.md
184
+ - Rakefile
185
+ - bin/console
186
+ - bin/setup
187
+ - dolla.gemspec
188
+ - lib/dolla.rb
189
+ - lib/dolla/card_number_prefix.rb
190
+ - lib/dolla/card_prefix/amex.rb
191
+ - lib/dolla/card_type.rb
192
+ - lib/dolla/configuration.rb
193
+ - lib/dolla/encryption_tools.rb
194
+ - lib/dolla/end_points.rb
195
+ - lib/dolla/gateway.rb
196
+ - lib/dolla/options.rb
197
+ - lib/dolla/payment_slip/amount.rb
198
+ - lib/dolla/payment_slip/due_date.rb
199
+ - lib/dolla/payment_stub.rb
200
+ - lib/dolla/railtie.rb
201
+ - lib/dolla/reference_number.rb
202
+ - lib/dolla/request_builder.rb
203
+ - lib/dolla/terms.rb
204
+ - lib/dolla/version.rb
205
+ - lib/generators/install_generator.rb
206
+ - lib/generators/templates/dolla_initializer.rb
207
+ homepage: https://github.com/amco/dolla.
208
+ licenses:
209
+ - MIT
210
+ metadata: {}
211
+ post_install_message:
212
+ rdoc_options: []
213
+ require_paths:
214
+ - lib
215
+ required_ruby_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ required_rubygems_version: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ">="
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ requirements: []
226
+ rubyforge_project:
227
+ rubygems_version: 2.6.13
228
+ signing_key:
229
+ specification_version: 4
230
+ summary: Dolla module for payment gateways.
231
+ test_files: []