moneytree-rails 0.1.0 → 0.1.5

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +63 -30
  4. data/Rakefile +30 -4
  5. data/app/assets/config/moneytree_manifest.js +1 -0
  6. data/app/assets/stylesheets/moneytree/application.css +15 -0
  7. data/app/controllers/moneytree/application_controller.rb +9 -0
  8. data/app/controllers/moneytree/oauth/square_controller.rb +14 -0
  9. data/app/controllers/moneytree/oauth/stripe_controller.rb +44 -0
  10. data/app/controllers/moneytree/webhooks/square_controller.rb +9 -0
  11. data/app/controllers/moneytree/webhooks/stripe_controller.rb +67 -0
  12. data/app/jobs/moneytree/application_job.rb +4 -0
  13. data/app/mailers/moneytree/application_mailer.rb +6 -0
  14. data/app/models/moneytree/application_record.rb +5 -0
  15. data/app/models/moneytree/payment.rb +23 -0
  16. data/app/models/moneytree/payment_gateway.rb +47 -0
  17. data/app/models/moneytree/refund.rb +46 -0
  18. data/app/models/moneytree/transaction.rb +30 -0
  19. data/app/views/layouts/moneytree/application.html.erb +15 -0
  20. data/config/routes.rb +8 -0
  21. data/db/migrate/20200914151648_create_moneytree_payment_gateways.rb +11 -0
  22. data/db/migrate/20201008161617_create_moneytree_transactions.rb +18 -0
  23. data/lib/moneytree-rails.rb +1 -0
  24. data/lib/moneytree.rb +16 -16
  25. data/lib/moneytree/account.rb +4 -34
  26. data/lib/moneytree/engine.rb +5 -0
  27. data/lib/moneytree/order.rb +15 -0
  28. data/lib/moneytree/payment_provider/base.rb +5 -2
  29. data/lib/moneytree/payment_provider/stripe.rb +80 -0
  30. data/lib/moneytree/transaction_response.rb +15 -0
  31. data/lib/moneytree/version.rb +1 -1
  32. data/lib/tasks/moneytree_tasks.rake +4 -0
  33. metadata +45 -33
  34. data/.github/workflows/ruby.yml +0 -33
  35. data/.gitignore +0 -12
  36. data/.rspec +0 -3
  37. data/.travis.yml +0 -6
  38. data/CHANGELOG.md +0 -7
  39. data/CODE_OF_CONDUCT.md +0 -74
  40. data/Gemfile +0 -15
  41. data/Gemfile.lock +0 -248
  42. data/Guardfile +0 -70
  43. data/LICENSE.txt +0 -21
  44. data/app/controllers/moneytree/oauth_controller.rb +0 -18
  45. data/bin/console +0 -14
  46. data/bin/setup +0 -8
  47. data/config.ru +0 -9
  48. data/lib/generators/moneytree/activerecord_generator.rb +0 -41
  49. data/lib/generators/moneytree/base_generator.rb +0 -13
  50. data/lib/generators/moneytree/install_generator.rb +0 -43
  51. data/lib/generators/moneytree/templates/active_record_event_model.rb.tt +0 -10
  52. data/lib/generators/moneytree/templates/active_record_migration.rb.tt +0 -62
  53. data/lib/generators/moneytree/templates/active_record_visit_model.rb.tt +0 -6
  54. data/lib/generators/moneytree/templates/base_store_initializer.rb.tt +0 -20
  55. data/lib/generators/moneytree/templates/moneytree_initializer.rb.tt +0 -15
  56. data/lib/moneytree/transaction.rb +0 -9
  57. data/moneytree.gemspec +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac0effde5b67728b209c237fcd5eb32f1bfaf682396d6dd65b3bbef29614c880
4
- data.tar.gz: 48b468a83dfd1a2099a04c3d137538d90444be660e281cbcf9fbb502469b28e7
3
+ metadata.gz: 2006000e7eb666a0edd1d8e035330c00804f41460dcca1a7e73d75f855dcd254
4
+ data.tar.gz: 1a36220066504521f1d9d4b477d9eeca1fb5ddd7dce1abc37daefe0a4412001f
5
5
  SHA512:
6
- metadata.gz: f07412f98d4783a4e6b64316c1fe10300e0c47f6f008a9479b8df592e23a01c2d72697de61b53d5d495e504a64bdfdb79529bddc71af205ff1fa968a3742b420
7
- data.tar.gz: c04082cfb750538aa4ae3f9500c2d3b9fcae56ad546a81e326ae5994e7045c781ff4ac408b99b71492fef642dccd60d2c5ac851f17b55b957ed04ca780fb30d3
6
+ metadata.gz: 72fbbd0d1f6dd0e144e6d72a412aa7313487afa0d92c2bbb5213925a4d3e4eaebdcb1369a64060183d7b073de41823f97d1f978f8751151c82799a8565324530
7
+ data.tar.gz: 296df5c1b71b78acd51639d49caca1964bf8260c156ddc7ea68aa648dcf47a6fe8e1e0b9887e1cf20236365a8436dd9b76f45c7e1a5f18fdb74d537a3944d8bf
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Kieran Klaassen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,16 +1,9 @@
1
1
  # 🚧 WORK IN PROGRESS 🚧
2
2
 
3
- - [ ] OAuth
4
- - [ ] Cards
5
- - [ ] Customers
6
- - [ ] Payments
7
- - [ ] Refunds
8
- - [ ] Notifications
9
-
10
3
  # Moneytree 💵 🌴
11
4
 
12
5
  [![Actions Status](https://github.com/kieranklaassen/moneytree/workflows/build/badge.svg)](https://github.com/kieranklaassen/moneytree/actions)
13
- [![Gem Version](https://badge.fury.io/rb/moneytree.svg)](https://badge.fury.io/rb/moneytree)
6
+ [![Gem Version](https://badge.fury.io/rb/moneytree-rails.svg)](https://badge.fury.io/rb/moneytree-rails)
14
7
 
15
8
  🔥 A powerful, simple, and extendable payment engine for rails, centered around transactional payments. 💵 🌴
16
9
 
@@ -19,16 +12,16 @@ functionality with almost no work on your end:
19
12
 
20
13
  - 💵💶💷💴 Multi-currency
21
14
  - 🔑 OAuth to link your PSP account
22
- - 👩‍💻PSP account creation, (with commission)
15
+ - 👩‍💻 PSP account creation, (with commission)
23
16
  - ⚙️ Webhooks
24
- - 💳 PCI compliance with Javascript libraries
25
- - 🧲 Platform fees
17
+ - 💳 ~~PCI compliance with Javascript libraries~~ comming soon
18
+ - 🧲 Platform fees a.k.a. Market Places
26
19
 
27
20
  Currently we support the following PSP's:
28
21
 
29
- - Square
22
+ - ~~Square~~ comming soon
30
23
  - Stripe
31
- - Braintree
24
+ - ~~Braintree~~ comming soon
32
25
 
33
26
  But if you want to add more PSP's, we make it easy to do so. Read our
34
27
  [Contributing](https://github.com/kieranklaassen/moneytree#contributing) section to learn more.
@@ -48,33 +41,69 @@ rails app:template LOCATION='https://railsbytes.com/script/Xg8sOv'
48
41
  Add the latest version of Moneytree to your gem Gemfile by running:
49
42
 
50
43
  ```bash
51
- $ bundle add moneytree
44
+ $ bundle add moneytree-rails
52
45
  $ bundle install
53
- $ bundle exec moneytree init
46
+ $ rails g moneytree:install:migrations
47
+ $ rails g db:migrate
54
48
  ```
55
49
 
56
- Or your can use environment variables:
57
-
58
- FIXME: add
59
-
60
50
  ## Configuration
61
51
 
52
+ ### Initializer
53
+
62
54
  Do you need to make some changes to how Moneytree is used? You can create an initializer
63
55
  `config/initializers/moneytree.rb`
64
56
 
65
57
  ```ruby
66
58
  Moneytree.setup do |config|
67
- config.enabled_psps = [:square, :stripe, :braintree]
68
- config.account_class = 'Account'
69
- config.order_class = 'Order'
70
- config.transaction_class = 'Transaction'
71
-
72
- config.square_credentials = {
73
- app_id: ENV['SQUARE_APP_ID'],
74
- app_secret: ENV['SQUARE_APP_SECRET'],
75
- environment: Rails.env.production? : 'production' : 'sandbox',
76
- oauth_domain: Rails.env.production? ? 'https://connect.squareup.com' : 'https://connect.squareupsandbox.com'
59
+ config.current_account = :current_merchant
60
+ config.stripe_credentials = {
61
+ api_key: ENV['STRIPE_API_KEY'],
62
+ client_id: ENV['STRIPE_CLIENT_ID']
77
63
  }
64
+ config.oauth_redirect = '/welcome_back'
65
+ config.refund_application_fee = true # false by default
66
+ end
67
+ ```
68
+
69
+ ### Routes
70
+
71
+ Add to your routes and authenticate if needed to make sure only admins can integrate with OAuth.
72
+
73
+ ```ruby
74
+ authenticate :user, ->(u) { u.admin? } do
75
+ mount Moneytree::Engine => '/moneytree'
76
+ end
77
+ ```
78
+
79
+ ### Models
80
+
81
+ Include account concern into your models and make sure the following attributes work:
82
+
83
+ ```ruby
84
+ class Merchant < ApplicationRecord
85
+ include Moneytree::Account
86
+
87
+ def email
88
+ owner.email
89
+ end
90
+
91
+ def currency_code
92
+ currency.code
93
+ end
94
+
95
+ def website
96
+ 'https://www.boomtown.com'
97
+ end
98
+ end
99
+ ```
100
+
101
+ And add `Moneytree::Order` concern to the model that will be the parent for all the transactions. In most cases this
102
+ will be an order. This model will keep a balance and you can add multiple payments and refunds to it.
103
+
104
+ ```ruby
105
+ class Order < ApplicationRecord
106
+ include Moneytree::Order
78
107
  end
79
108
  ```
80
109
 
@@ -88,6 +117,10 @@ transaction attached for the payment. You can name these models however you want
88
117
 
89
118
  ### The API
90
119
 
120
+ #### Moneytree::PaymentGateway
121
+
122
+ ##### #method here
123
+
91
124
  ## Development
92
125
 
93
126
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can
@@ -105,7 +138,7 @@ intended to be a safe, welcoming space for collaboration, and contributors are e
105
138
 
106
139
  ## License
107
140
 
108
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
141
+ The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
109
142
 
110
143
  ## Code of Conduct
111
144
 
data/Rakefile CHANGED
@@ -1,6 +1,32 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
3
6
 
4
- RSpec::Core::RakeTask.new(:spec)
7
+ require 'rdoc/task'
5
8
 
6
- task :default => :spec
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Moneytree'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/moneytree .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,9 @@
1
+ module Moneytree
2
+ class ApplicationController < ::ApplicationController
3
+ protect_from_forgery with: :exception
4
+
5
+ # def current_account
6
+ # send(Moneytree.current_account)
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module Moneytree
2
+ module Oauth
3
+ class SquareController < ApplicationController
4
+ def new
5
+ redirect_to current_account.oauth_link
6
+ end
7
+
8
+ def callback
9
+ current_account.oauth_callback(params)
10
+ render text: 'Boom'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,44 @@
1
+ module Moneytree
2
+ module Oauth
3
+ class StripeController < ApplicationController
4
+ def new
5
+ redirect_to stripe_oauth_url
6
+ end
7
+
8
+ def callback
9
+ # TODO: Remove this module prefix once we figure out how to properly autoload this.
10
+ payment_gateway = Moneytree::PaymentGateway.create!(psp: 'stripe', account: current_account)
11
+ payment_gateway.oauth_callback(payment_gateway_params)
12
+ redirect_to Moneytree.oauth_redirect, notice: 'Connected to Stripe'
13
+ end
14
+
15
+ private
16
+
17
+ def payment_gateway_params
18
+ params.permit :scope, :code
19
+ end
20
+
21
+ def stripe_oauth_url
22
+ # https://stripe.com/docs/connect/oauth-reference
23
+ # https://stripe.com/docs/connect/oauth-reference#get-authorize
24
+ URI::HTTPS.build(
25
+ host: 'connect.stripe.com',
26
+ path: '/oauth/authorize',
27
+ query: {
28
+ response_type: :code,
29
+ client_id: Moneytree.stripe_credentials[:client_id],
30
+ scope: PaymentProvider::Stripe::PERMISSION,
31
+ redirect_uri: oauth_stripe_callback_url,
32
+ 'stripe_user[email]': current_account.email,
33
+ 'stripe_user[url]': current_account.website,
34
+ 'stripe_user[currency]': current_account.currency_code
35
+ }.to_query
36
+ ).to_s
37
+ end
38
+
39
+ def current_account
40
+ send(Moneytree.current_account)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ module Moneytree
2
+ module Webhooks
3
+ class SquareController < ApplicationController
4
+ def create
5
+ # Do some callback magic here
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,67 @@
1
+ module Moneytree
2
+ module Webhooks
3
+ class StripeController < ApplicationController
4
+ skip_before_action :verify_authenticity_token
5
+
6
+ def create
7
+ case webhook_params.type
8
+ when 'charge.succeeded'
9
+ process_charge!
10
+ when 'charge.refunded'
11
+ process_refund!
12
+ else
13
+ puts "Unhandled event type: #{webhook_params.type}"
14
+ end
15
+
16
+ head :ok
17
+ end
18
+
19
+ private
20
+
21
+ def webhook_params
22
+ @webhook_params ||=
23
+ ::Stripe::Event.construct_from(
24
+ JSON.parse(request.body.read, symbolize_names: true)
25
+ )
26
+ end
27
+
28
+ def process_charge!
29
+ return if transaction.completed?
30
+
31
+ transaction.process_response(
32
+ TransactionResponse.new(:success, '', { charge_id: stripe_object.id })
33
+ )
34
+
35
+ if Moneytree.order_status_trigger_method
36
+ transaction.order.send(Moneytree.order_status_trigger_method, transaction)
37
+ end
38
+ end
39
+
40
+ def process_refund!
41
+ stripe_object.refunds.data.each do |stripe_refund_object|
42
+ # TODO: Create refund transaction in db for PSP-initiated refunds
43
+ next if stripe_refund_object.metadata[:moneytree_transaction_id].blank?
44
+
45
+ refund = transaction.refunds.find(stripe_refund_object.metadata[:moneytree_transaction_id])
46
+
47
+ next if refund.completed?
48
+
49
+ refund.process_response(
50
+ TransactionResponse.new(:success, '')
51
+ )
52
+ if Moneytree.order_status_trigger_method
53
+ transaction.order.send(Moneytree.order_status_trigger_method, transaction)
54
+ end
55
+ end
56
+ end
57
+
58
+ def transaction
59
+ @transaction ||= Transaction.find(stripe_object.metadata[:moneytree_transaction_id])
60
+ end
61
+
62
+ def stripe_object
63
+ @stripe_object ||= webhook_params.data.object
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,4 @@
1
+ module Moneytree
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Moneytree
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Moneytree
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module Moneytree
2
+ class Payment < Transaction
3
+ has_many :refunds, class_name: 'Refund'
4
+
5
+ validates_absence_of :payment_id
6
+
7
+ validates_numericality_of :amount, greater_than: 0
8
+ validates_numericality_of :app_fee_amount, greater_than_or_equal_to: 0
9
+
10
+ private
11
+
12
+ def execute_transaction(metadata: {})
13
+ process_response(
14
+ payment_gateway.charge(
15
+ amount,
16
+ details,
17
+ app_fee_amount: app_fee_amount,
18
+ metadata: metadata.merge(moneytree_transaction_id: id)
19
+ )
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ module Moneytree
2
+ class PaymentGateway < ApplicationRecord
3
+ belongs_to :account, polymorphic: true
4
+
5
+ enum psp: Moneytree::PSPS
6
+ serialize :psp_credentials
7
+ # encrypts :psp_credentials
8
+ # FIXME: enable https://github.com/ankane/lockbox
9
+ delegate :oauth_link, :scope_correct?, :charge, :refund, to: :payment_provider
10
+
11
+ # has_many :orders
12
+ # has_many :transactions
13
+ # has_many :customers
14
+ # has_many :cards
15
+
16
+ def oauth_callback(params)
17
+ update! psp_credentials: payment_provider.get_access_token(params)
18
+ end
19
+
20
+ def psp_connected?
21
+ psp.present? && psp_credentials.present?
22
+ end
23
+
24
+ def needs_oauth?
25
+ !psp_connected? || !scope_correct?
26
+ end
27
+
28
+ def scope_correct?
29
+ psp_credentials[:scope] == payment_provider.scope
30
+ end
31
+
32
+ private
33
+
34
+ def payment_provider
35
+ @payment_provider ||=
36
+ case psp
37
+ when 'stripe'
38
+ # TODO: see if we only need to pass credentials
39
+ Moneytree::PaymentProvider::Stripe.new(self)
40
+ # when 'square'
41
+ # Moneytree::PaymentProvider::Square.new(self)
42
+ else
43
+ raise 'BOOM'
44
+ end
45
+ end
46
+ end
47
+ end