payify 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f957956057b109f043ac54f598c6adcde5787fb3f779f7c99a263bbca92e012a
4
- data.tar.gz: 2e69a4de3e352cd038d342acd577e01295d66b37336c36ef9cb3a60bb90a0e06
3
+ metadata.gz: f5cf7eb6359e3f095e4eaade8ed118042a3eb933588240ee0a34d3af0947e8a5
4
+ data.tar.gz: e9ee5e294c8a45a24304d47c15c1f8886601cf6f04c480e03ee503226abd5137
5
5
  SHA512:
6
- metadata.gz: 79c566e04f04a47b0dad3c43b91f6f2225d3ab527cf146c17de91d9024adc351a311223f4b6a1f4a3eb63819d7790aaa92978883a5f0023917e6eea750a2b83c
7
- data.tar.gz: c2285524f52429511146472b86fb66bb7df5eabd36a8897babeb503158ba87e56babd4fe7fb1ceed2febc2674d49f70edad0a0521299c3adf43df822e3a1a3ab
6
+ metadata.gz: bb091698b89e880398366b24a12006dfbddb44bf7311da2257557a1f953fbfcae1221af550ef41f7e78afa7fc3dfaa0a8305c7ce9835023fc44252f65996320d
7
+ data.tar.gz: b2c5728bdf7222d5fa00a58ad4e585114c5ffb0ca91a726d27e3088de40f59c21fd9463a31516cc8ebc108f9de499e50d1b81c032af2bc023f992a492c33bb61
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: payify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Lopez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-20 00:00:00.000000000 Z
11
+ date: 2023-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dotenv-rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.8.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.8.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: money
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '6.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '6.16'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: rails
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +52,20 @@ dependencies:
24
52
  - - "~>"
25
53
  - !ruby/object:Gem::Version
26
54
  version: '7.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: stripe
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 8.5.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 8.5.0
27
69
  description: Payify is a Ruby gem that simplifies payment integration into Ruby on
28
70
  Rails projects.
29
71
  email:
@@ -31,34 +73,7 @@ email:
31
73
  executables: []
32
74
  extensions: []
33
75
  extra_rdoc_files: []
34
- files:
35
- - README.md
36
- - app/assets/config/payify_manifest.js
37
- - app/assets/images/payify/screenshot.png
38
- - app/assets/images/payify/vat.png
39
- - app/assets/stylesheets/payify/application.css
40
- - app/controllers/payify/payments_controller.rb
41
- - app/helpers/payify/application_helper.rb
42
- - app/jobs/payify/application_job.rb
43
- - app/mailers/payify/application_mailer.rb
44
- - app/models/concerns/payify/has_payment_concern.rb
45
- - app/models/concerns/payify/stripe_payment_concern.rb
46
- - app/models/payify/application_record.rb
47
- - app/models/payify/payment.rb
48
- - app/serializers/payify/payment_serializer.rb
49
- - app/views/payify/application.html.erb
50
- - app/views/payify/payments/_form.html.erb
51
- - app/views/payify/payments/complete.html.erb
52
- - app/views/payify/payments/new.html.erb
53
- - config/locales/payify.en.yml
54
- - config/routes.rb
55
- - db/migrate/20230611124944_create_payment.rb
56
- - db/migrate/20230617052430_add_stripe_payment_intent_id.rb
57
- - lib/payify.rb
58
- - lib/payify/engine.rb
59
- - lib/payify/version.rb
60
- - lib/stripe/client.rb
61
- - lib/tasks/payify_tasks.rake
76
+ files: []
62
77
  homepage: https://github.com/andrewdsilva/payify
63
78
  licenses:
64
79
  - MIT
data/README.md DELETED
@@ -1,164 +0,0 @@
1
- # Payify
2
-
3
- PayifyRails is a Ruby gem that simplifies payment integration into Ruby on Rails projects. It allows to easily add payment functionality to your models. For example, by applying the HasPaymentConcern to a reservation model, you can manage the payment process for reservations seamlessly.
4
-
5
- ![Screenshot](./app/assets/images/payify/screenshot.png)
6
-
7
- ## Installation
8
-
9
- To install the gem add it into a Gemfile (Bundler):
10
-
11
- ```ruby
12
- gem 'payify', '~> 0.1.0'
13
- ```
14
-
15
- And then execute:
16
-
17
- ```
18
- bundle install
19
- ```
20
-
21
- ## Features ✅
22
-
23
- - Includes a Payment model
24
- - Provides concerns to easily add a payment system to your model
25
- - Enables payment with Stripe
26
- - Offers a payment form to integrate into your application
27
- - Allows payment status to be checked via an api route
28
- - Allows configuration of payment (currency, VAT)
29
- - Provides a user interface for payment processing
30
- - Enables management of payment status (pending, paid)
31
-
32
- ## Configuration
33
-
34
- For now, Payify uses Stripe as the payment gateway. You can configure the currency using an initializer.
35
-
36
- ```ruby
37
- # initializers/payify.rb
38
- Payify.setup do |config|
39
- config.currency = "usd"
40
- config.default_tax_rates_id = "eur"
41
- end
42
- ```
43
-
44
- To handle VAT or different tax rates on your payments, you need to create tax rates on Stripe and define the default_tax_rates_id or, alternatively, define the tax_rates_id method on your payment-related models. Leave it empty if you don't manage any taxes.
45
-
46
- You can set your Stripe API credentials using environment variables. (Secret key, Publishable key)
47
-
48
- ```ruby
49
- # .env
50
- STRIPE_API_KEY="..."
51
- STRIPE_PUBLISHABLE_KEY="..."
52
- ```
53
-
54
- ## Usage
55
-
56
- To enable payment functionality for a model, simply include the HasPayment concern:
57
-
58
- ```ruby
59
- class Reservation < ApplicationRecord
60
- include Payify::HasPaymentConcern
61
-
62
- def amount_to_pay
63
- self.price
64
- end
65
-
66
- # Optional : Override the default tax rates id
67
- def tax_rates_id
68
- 'txr_1234567890'
69
- end
70
- end
71
- ```
72
-
73
- When you want to request a payment for a model on which you added the concern, you just need to call the create_payment method.
74
-
75
- ```ruby
76
- reservation_1.create_payment
77
- ```
78
-
79
- Then you can find the id of the new pending payment with payment.id.
80
-
81
- ```ruby
82
- reservation_1.payment.id
83
- ```
84
-
85
- Now you just have to redirect the user to `/payments/:id/new` or include the payment form in your page.
86
-
87
- ```ruby
88
- # reservation/show.html.erb
89
- <%= render "payify/payments/form", payment: @payment %>
90
- ```
91
-
92
- After completing the payment process, the user will be redirected to:
93
-
94
- ```
95
- /payments/:id/complete
96
- ```
97
-
98
- The application will then verify the payment status with Stripe. You can do it manually calling the following method:
99
-
100
- ```ruby
101
- @payment.stripe_confirm_payment
102
- ```
103
-
104
- If the payment has been successfully processed, a confirmation message will be displayed to the user. The payment method `paid?` will return `true`.
105
-
106
- To customize the page that displays the payment status, you can create the following file:
107
-
108
- ```ruby
109
- # views/payify/payments/complete.html.erb
110
-
111
- <% if @payment.paid? %>
112
- <div class="alert alert-success" role="alert">
113
- <%= I18n.t("payments.complete.paid") %>
114
- </div>
115
- <% else %>
116
- <div class="alert alert-danger" role="alert">
117
- <%= I18n.t("payments.complete.pending") %>
118
- </div>
119
- <% end %>
120
- ```
121
-
122
- ## API
123
-
124
- If you prefer using the Payify API, after creating the payment object, you can initialize a new Stripe payment by making a request to: `/payments/:id/new.json`
125
-
126
- This request will return a JSON response containing the `stripe_payment_intent_id` and `stripe_client_secret` required to process a payment using Stripe.
127
-
128
- After making the payment, you can make a request to the following endpoint to update the payment status and retrieve its current state:
129
-
130
- ```
131
- /payments/:id/complete.json
132
- ```
133
-
134
- ## Status
135
-
136
- You can access the payment status using `@payment.status`. The possible statuses are:
137
-
138
- - `pending`: The payment is still being processed.
139
- - `paid`: The payment has been successfully completed.
140
- - `failed`: The payment has failed.
141
-
142
- ## Tests
143
-
144
- To run the tests, execute `rspec` command.
145
-
146
- You can test the payment process in your web browser by following these steps:
147
-
148
- 1. Navigate to the `test/dummy` directory.
149
- 2. Run the following commands:
150
- - `rails db:create`
151
- - `rails db:migrate`
152
- - `rails db:seed`
153
- - `rails s`
154
- 3. Open your browser and go to: [http://localhost:3000/](http://localhost:3000/).
155
-
156
- Each time you run the seed command, your test database will be reset with a reservation that has a payment with an ID of 1. This allows you to test the payment process at the following address: [http://localhost:3000/payments/1/new](http://localhost:3000/payments/1/new).
157
-
158
- ## Contributing
159
-
160
- Bug reports and pull requests are welcome on GitHub at https://github.com/andrewdsilva/payify.
161
-
162
- ## License
163
-
164
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1 +0,0 @@
1
- //= link_directory ../stylesheets/payify .css
Binary file
@@ -1,15 +0,0 @@
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
- */
@@ -1,29 +0,0 @@
1
- module Payify
2
- class PaymentsController < ActionController::Base
3
- before_action :set_object, only: %i[new complete]
4
-
5
- def new
6
- @payment.stripe_init_intent
7
-
8
- respond_to do |format|
9
- format.html
10
- format.json { render json: @payment }
11
- end
12
- end
13
-
14
- def complete
15
- @payment.stripe_confirm_payment unless @payment.paid?
16
-
17
- respond_to do |format|
18
- format.html
19
- format.json { render json: @payment }
20
- end
21
- end
22
-
23
- private
24
-
25
- def set_object
26
- @payment = Payment.find(params[:id])
27
- end
28
- end
29
- end
@@ -1,4 +0,0 @@
1
- module Payify
2
- module ApplicationHelper
3
- end
4
- end
@@ -1,4 +0,0 @@
1
- module Payify
2
- class ApplicationJob < ActiveJob::Base
3
- end
4
- end
@@ -1,6 +0,0 @@
1
- module Payify
2
- class ApplicationMailer < ActionMailer::Base
3
- default from: "from@example.com"
4
- layout "mailer"
5
- end
6
- end
@@ -1,28 +0,0 @@
1
- module Payify
2
- module HasPaymentConcern
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- has_one :payment, as: :model, dependent: :destroy, class_name: "Payify::Payment"
7
- end
8
-
9
- def create_payment
10
- build_payment(amount: amount_to_pay)
11
-
12
- payment.save
13
- payment
14
- end
15
-
16
- def cancel_payment
17
- payment.destroy if payment.present?
18
- end
19
-
20
- def amount_to_pay
21
- raise NotImplementedError, "The 'amount_to_pay' method must be implemented in the including model."
22
- end
23
-
24
- def tax_rates_id
25
- nil
26
- end
27
- end
28
- end
@@ -1,33 +0,0 @@
1
- require "stripe/client"
2
-
3
- module Payify
4
- module StripePaymentConcern
5
- extend ActiveSupport::Concern
6
-
7
- def stripe_client
8
- @stripe_client ||= Stripe::Client.new
9
- end
10
-
11
- def stripe_init_intent
12
- return unless stripe_payment_inent_id.nil? && !paid?
13
-
14
- intent = stripe_client.create_payment_intent(amount, tax_id)
15
-
16
- update_attribute(:stripe_payment_inent_id, intent.id)
17
- update_attribute(:stripe_client_secret, intent.client_secret)
18
- end
19
-
20
- def stripe_confirm_payment
21
- intent = stripe_client.find_intent(stripe_payment_inent_id)
22
-
23
- return unless intent["status"] == "succeeded"
24
-
25
- update_attribute(:paid_at, Time.now)
26
- update_attribute(:status, Payify::Payment.statuses[:paid])
27
- end
28
-
29
- def tax_id
30
- model&.tax_rates_id || Payify.default_tax_rates_id
31
- end
32
- end
33
- end
@@ -1,5 +0,0 @@
1
- module Payify
2
- class ApplicationRecord < ActiveRecord::Base
3
- self.abstract_class = true
4
- end
5
- end
@@ -1,35 +0,0 @@
1
- module Payify
2
- class Payment < ApplicationRecord
3
- include ::Payify::StripePaymentConcern
4
-
5
- enum status: { pending: 0, paid: 1, failed: 2 }
6
- enum payment_method: { stripe: 0 }
7
-
8
- belongs_to :model, polymorphic: true, optional: true
9
-
10
- validates :amount, presence: true, numericality: { greater_than_or_equal_to: 0 }
11
- validates :status, presence: true
12
-
13
- before_destroy :cannot_destroy_if_paid
14
-
15
- def make_payment(transaction_id)
16
- self.transaction_id = transaction_id
17
- self.paid_at = Time.current
18
- self.status = :paid
19
- end
20
-
21
- def can_destroy?
22
- !paid?
23
- end
24
-
25
- def paid?
26
- paid_at.present?
27
- end
28
-
29
- private
30
-
31
- def cannot_destroy_if_paid
32
- raise ActiveRecord::RecordNotDestroyed if paid?
33
- end
34
- end
35
- end
@@ -1,10 +0,0 @@
1
- module Payify
2
- class PaymentSerializer < ActiveModel::Serializer
3
- attributes :id, :amount, :status, :payment_method, :transaction_id, :paid_at
4
-
5
- attributes :stripe_payment_inent_id, :stripe_client_secret
6
-
7
- attribute(:paid) { object.paid? }
8
- attribute(:can_destroy) { object.can_destroy? }
9
- end
10
- end
@@ -1,15 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Payify</title>
5
- <%= csrf_meta_tags %>
6
- <%= csp_meta_tag %>
7
-
8
- <%= stylesheet_link_tag "payify/application", media: "all" %>
9
- </head>
10
- <body>
11
-
12
- <%= yield %>
13
-
14
- </body>
15
- </html>
@@ -1,46 +0,0 @@
1
- <script src="https://js.stripe.com/v3/"></script>
2
-
3
- <%= form_with(id: "payment-form", url: payify.complete_payment_path, method: "post") do |form| %>
4
- <div id="payment-element">
5
- </div>
6
-
7
- <div id="error-message">
8
- </div>
9
-
10
- <%= form.submit I18n.t("payments.submit"), id: "submit", class: "btn btn-primary w-100 mt-4" %>
11
- <% end %>
12
-
13
- <script>
14
- const stripe = Stripe("<%= Payify.stripe_publishable_key %>");
15
-
16
- const options = {
17
- clientSecret: "<%= payment.stripe_client_secret %>",
18
- };
19
-
20
- const elements = stripe.elements(options);
21
-
22
- const paymentElement = elements.create("payment");
23
- paymentElement.mount("#payment-element");
24
-
25
- const form = document.getElementById("payment-form");
26
-
27
- form.addEventListener("submit", async (event) => {
28
- event.preventDefault();
29
-
30
- const {error} = await stripe.confirmPayment({
31
- elements,
32
- confirmParams: {
33
- return_url: "<%= request.base_url %>/payify/payments/<%= payment.id %>/complete",
34
- },
35
- });
36
-
37
- if (error) {
38
- const messageContainer = document.querySelector("#error-message");
39
- messageContainer.textContent = error.message;
40
- } else {
41
- // Your customer will be redirected to your `return_url`. For some payment
42
- // methods like iDEAL, your customer will be redirected to an intermediate
43
- // site first to authorize the payment, then redirected to the `return_url`.
44
- }
45
- });
46
- </script>
@@ -1,26 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
-
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
8
-
9
- <title>Payment</title>
10
- </head>
11
- <body>
12
-
13
- <div class="container py-5 my-5" style="max-width: 500px;">
14
- <% if @payment.paid? %>
15
- <div class="alert alert-success" role="alert">
16
- <%= I18n.t("payments.complete.paid") %>
17
- </div>
18
- <% else %>
19
- <div class="alert alert-danger" role="alert">
20
- <%= I18n.t("payments.complete.pending") %>
21
- </div>
22
- <% end %>
23
- </div>
24
-
25
- </body>
26
- </html>
@@ -1,24 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
-
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
8
-
9
- <title>Payment</title>
10
- </head>
11
- <body>
12
-
13
- <div class="container py-5 my-5" style="max-width: 500px;">
14
- <% if @payment.paid? %>
15
- <div class="alert alert-info" role="alert">
16
- <%= I18n.t("payments.already_paid") %>
17
- </div>
18
- <% else %>
19
- <%= render "form", payment: @payment %>
20
- <% end %>
21
- </div>
22
-
23
- </body>
24
- </html>
@@ -1,7 +0,0 @@
1
- en:
2
- payments:
3
- submit: Submit
4
- already_paid: Payment has already been completed.
5
- complete:
6
- pending: Payment pending.
7
- paid: Successful payment!
data/config/routes.rb DELETED
@@ -1,8 +0,0 @@
1
- ::Payify::Engine.routes.draw do
2
- resources :payments do
3
- member do
4
- get "new"
5
- get "complete", as: "complete"
6
- end
7
- end
8
- end
@@ -1,15 +0,0 @@
1
- class CreatePayment < ActiveRecord::Migration[7.0]
2
- def change
3
- create_table :payify_payments do |t|
4
- t.decimal :amount, precision: 10, scale: 2, null: false
5
- t.integer :status, default: 0, null: false
6
- t.integer :payment_method
7
- t.string :transaction_id
8
- t.datetime :paid_at
9
- t.string :model_type
10
- t.integer :model_id
11
-
12
- t.timestamps
13
- end
14
- end
15
- end
@@ -1,6 +0,0 @@
1
- class AddStripePaymentIntentId < ActiveRecord::Migration[7.0]
2
- def change
3
- add_column :payify_payments, :stripe_payment_inent_id, :string
4
- add_column :payify_payments, :stripe_client_secret, :string
5
- end
6
- end
data/lib/payify/engine.rb DELETED
@@ -1,5 +0,0 @@
1
- module Payify
2
- class Engine < ::Rails::Engine
3
- isolate_namespace Payify
4
- end
5
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Payify
4
- VERSION = "0.1.1"
5
- end
data/lib/payify.rb DELETED
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "payify/version"
4
- require "payify/engine"
5
- require "dotenv/load"
6
-
7
- module Payify
8
- class Error < StandardError; end
9
-
10
- mattr_accessor :currency
11
- @@currency = "usd"
12
-
13
- mattr_accessor :default_tax_rates_id
14
- @@default_tax_rates_id = nil
15
-
16
- mattr_accessor :stripe_api_key
17
- @@stripe_api_key = ENV["STRIPE_API_KEY"]
18
-
19
- mattr_accessor :stripe_publishable_key
20
- @@stripe_publishable_key = ENV["STRIPE_PUBLISHABLE_KEY"]
21
-
22
- def self.setup
23
- yield self
24
- end
25
- end
data/lib/stripe/client.rb DELETED
@@ -1,31 +0,0 @@
1
- module Stripe
2
- class Client
3
- def initialize
4
- stripe
5
-
6
- Stripe.api_key = Payify.stripe_api_key
7
- end
8
-
9
- def stripe
10
- @stripe ||= Stripe::StripeClient.new
11
- end
12
-
13
- def create_payment_intent(amount, tax_id = nil, object_invoice = "")
14
- infos = {
15
- amount: (amount * 100).to_i,
16
- currency: Payify.currency,
17
- description: object_invoice,
18
- setup_future_usage: "off_session",
19
- metadata: {
20
- "tax_id": tax_id
21
- }
22
- }
23
-
24
- Stripe::PaymentIntent.create(infos)
25
- end
26
-
27
- def find_intent(payment_intent_id)
28
- Stripe::PaymentIntent.retrieve(payment_intent_id)
29
- end
30
- end
31
- end
@@ -1,4 +0,0 @@
1
- # desc "Explaining what the task does"
2
- # task :payify do
3
- # # Task goes here
4
- # end