pay 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pay might be problematic. Click here for more details.
- checksums.yaml +4 -4
 - data/README.md +168 -14
 - data/Rakefile +15 -17
 - data/app/controllers/pay/payments_controller.rb +3 -0
 - data/app/controllers/pay/webhooks/paddle_controller.rb +36 -0
 - data/app/mailers/pay/user_mailer.rb +2 -2
 - data/app/models/pay/application_record.rb +6 -1
 - data/app/models/pay/charge.rb +7 -0
 - data/app/models/pay/subscription.rb +24 -3
 - data/app/views/pay/payments/show.html.erb +1 -1
 - data/config/routes.rb +1 -0
 - data/db/migrate/20170205020145_create_pay_subscriptions.rb +2 -1
 - data/db/migrate/20170727235816_create_pay_charges.rb +1 -0
 - data/db/migrate/20200603134434_add_data_to_pay_models.rb +17 -0
 - data/lib/generators/active_record/pay_generator.rb +1 -1
 - data/lib/generators/pay/orm_helpers.rb +1 -2
 - data/lib/pay.rb +11 -2
 - data/lib/pay/billable.rb +7 -2
 - data/lib/pay/braintree.rb +1 -1
 - data/lib/pay/braintree/billable.rb +18 -4
 - data/lib/pay/braintree/charge.rb +4 -0
 - data/lib/pay/braintree/subscription.rb +6 -0
 - data/lib/pay/engine.rb +7 -0
 - data/lib/pay/paddle.rb +38 -0
 - data/lib/pay/paddle/billable.rb +66 -0
 - data/lib/pay/paddle/charge.rb +39 -0
 - data/lib/pay/paddle/subscription.rb +59 -0
 - data/lib/pay/paddle/webhooks.rb +1 -0
 - data/lib/pay/paddle/webhooks/signature_verifier.rb +115 -0
 - data/lib/pay/paddle/webhooks/subscription_cancelled.rb +18 -0
 - data/lib/pay/paddle/webhooks/subscription_created.rb +59 -0
 - data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +21 -0
 - data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +64 -0
 - data/lib/pay/paddle/webhooks/subscription_updated.rb +34 -0
 - data/lib/pay/stripe.rb +1 -0
 - data/lib/pay/stripe/billable.rb +14 -5
 - data/lib/pay/stripe/charge.rb +4 -0
 - data/lib/pay/stripe/subscription.rb +7 -1
 - data/lib/pay/stripe/webhooks/charge_succeeded.rb +7 -7
 - data/lib/pay/stripe/webhooks/payment_action_required.rb +7 -8
 - data/lib/pay/stripe/webhooks/subscription_created.rb +1 -1
 - data/lib/pay/version.rb +1 -1
 - metadata +63 -8
 
| 
         @@ -1,5 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Pay
         
     | 
| 
       2 
     | 
    
         
            -
              class ApplicationRecord <  
     | 
| 
      
 2 
     | 
    
         
            +
              class ApplicationRecord < Pay.model_parent_class.constantize
         
     | 
| 
       3 
3 
     | 
    
         
             
                self.abstract_class = true
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def self.json_column?(name)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  return unless connected? && table_exists?
         
     | 
| 
      
 7 
     | 
    
         
            +
                  [:json, :jsonb].include?(attribute_types[name].type)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
       4 
9 
     | 
    
         
             
              end
         
     | 
| 
       5 
10 
     | 
    
         
             
            end
         
     | 
    
        data/app/models/pay/charge.rb
    CHANGED
    
    | 
         @@ -2,6 +2,9 @@ module Pay 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class Charge < ApplicationRecord
         
     | 
| 
       3 
3 
     | 
    
         
             
                self.table_name = Pay.chargeable_table
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
                # Only serialize for non-json columns
         
     | 
| 
      
 6 
     | 
    
         
            +
                serialize :data unless json_column?("data")
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
       5 
8 
     | 
    
         
             
                # Associations
         
     | 
| 
       6 
9 
     | 
    
         
             
                belongs_to :owner, polymorphic: true
         
     | 
| 
       7 
10 
     | 
    
         | 
| 
         @@ -39,5 +42,9 @@ module Pay 
     | 
|
| 
       39 
42 
     | 
    
         
             
                def paypal?
         
     | 
| 
       40 
43 
     | 
    
         
             
                  braintree? && card_type == "PayPal"
         
     | 
| 
       41 
44 
     | 
    
         
             
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def paddle?
         
     | 
| 
      
 47 
     | 
    
         
            +
                  processor == "paddle"
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
       42 
49 
     | 
    
         
             
              end
         
     | 
| 
       43 
50 
     | 
    
         
             
            end
         
     | 
| 
         @@ -2,7 +2,10 @@ module Pay 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class Subscription < ApplicationRecord
         
     | 
| 
       3 
3 
     | 
    
         
             
                self.table_name = Pay.subscription_table
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
                STATUSES = %w[incomplete incomplete_expired trialing active past_due canceled unpaid]
         
     | 
| 
      
 5 
     | 
    
         
            +
                STATUSES = %w[incomplete incomplete_expired trialing active past_due canceled unpaid paused]
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                # Only serialize for non-json columns
         
     | 
| 
      
 8 
     | 
    
         
            +
                serialize :data unless json_column?("data")
         
     | 
| 
       6 
9 
     | 
    
         | 
| 
       7 
10 
     | 
    
         
             
                # Associations
         
     | 
| 
       8 
11 
     | 
    
         
             
                belongs_to :owner, polymorphic: true
         
     | 
| 
         @@ -66,6 +69,15 @@ module Pay 
     | 
|
| 
       66 
69 
     | 
    
         
             
                  past_due? || incomplete?
         
     | 
| 
       67 
70 
     | 
    
         
             
                end
         
     | 
| 
       68 
71 
     | 
    
         | 
| 
      
 72 
     | 
    
         
            +
                def paused?
         
     | 
| 
      
 73 
     | 
    
         
            +
                  status == "paused"
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def pause
         
     | 
| 
      
 77 
     | 
    
         
            +
                  return unless paddle?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  send("#{processor}_pause")
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
       69 
81 
     | 
    
         
             
                def cancel
         
     | 
| 
       70 
82 
     | 
    
         
             
                  send("#{processor}_cancel")
         
     | 
| 
       71 
83 
     | 
    
         
             
                end
         
     | 
| 
         @@ -76,8 +88,17 @@ module Pay 
     | 
|
| 
       76 
88 
     | 
    
         | 
| 
       77 
89 
     | 
    
         
             
                def resume
         
     | 
| 
       78 
90 
     | 
    
         
             
                  unless on_grace_period?
         
     | 
| 
       79 
     | 
    
         
            -
                     
     | 
| 
       80 
     | 
    
         
            -
                       
     | 
| 
      
 91 
     | 
    
         
            +
                    unless paddle?
         
     | 
| 
      
 92 
     | 
    
         
            +
                      raise StandardError,
         
     | 
| 
      
 93 
     | 
    
         
            +
                        "You can only resume subscriptions within their grace period."
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  unless paused?
         
     | 
| 
      
 98 
     | 
    
         
            +
                    if paddle?
         
     | 
| 
      
 99 
     | 
    
         
            +
                      raise StandardError,
         
     | 
| 
      
 100 
     | 
    
         
            +
                        "You can only resume paused subscriptions."
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
       81 
102 
     | 
    
         
             
                  end
         
     | 
| 
       82 
103 
     | 
    
         | 
| 
       83 
104 
     | 
    
         
             
                  send("#{processor}_resume")
         
     | 
| 
         @@ -51,7 +51,7 @@ 
     | 
|
| 
       51 
51 
     | 
    
         
             
                    </div>
         
     | 
| 
       52 
52 
     | 
    
         
             
                  <% end %>
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
                  <%= link_to t("back"),  
     | 
| 
      
 54 
     | 
    
         
            +
                  <%= link_to t("back"), @redirect_to, class: "inline-block w-full px-4 py-3 bg-gray-200 hover:bg-gray-300 text-center text-gray-700 rounded-lg" %>
         
     | 
| 
       55 
55 
     | 
    
         
             
                </div>
         
     | 
| 
       56 
56 
     | 
    
         | 
| 
       57 
57 
     | 
    
         
             
                <p class="text-center text-gray-500 text-sm">
         
     | 
    
        data/config/routes.rb
    CHANGED
    
    
| 
         @@ -1,7 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            class CreatePaySubscriptions < ActiveRecord::Migration[4.2]
         
     | 
| 
       2 
2 
     | 
    
         
             
              def change
         
     | 
| 
       3 
3 
     | 
    
         
             
                create_table :pay_subscriptions do |t|
         
     | 
| 
       4 
     | 
    
         
            -
                   
     | 
| 
      
 4 
     | 
    
         
            +
                  # Some Billable objects use string as ID, add `type: :string` if needed
         
     | 
| 
      
 5 
     | 
    
         
            +
                  t.references :owner, polymorphic: true
         
     | 
| 
       5 
6 
     | 
    
         
             
                  t.string :name, null: false
         
     | 
| 
       6 
7 
     | 
    
         
             
                  t.string :processor, null: false
         
     | 
| 
       7 
8 
     | 
    
         
             
                  t.string :processor_id, null: false
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            class CreatePayCharges < ActiveRecord::Migration[4.2]
         
     | 
| 
       2 
2 
     | 
    
         
             
              def change
         
     | 
| 
       3 
3 
     | 
    
         
             
                create_table :pay_charges do |t|
         
     | 
| 
      
 4 
     | 
    
         
            +
                  # Some Billable objects use string as ID, add `type: :string` if needed
         
     | 
| 
       4 
5 
     | 
    
         
             
                  t.references :owner, polymorphic: true
         
     | 
| 
       5 
6 
     | 
    
         
             
                  t.string :processor, null: false
         
     | 
| 
       6 
7 
     | 
    
         
             
                  t.string :processor_id, null: false
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class AddDataToPayModels < ActiveRecord::Migration[4.2]
         
     | 
| 
      
 2 
     | 
    
         
            +
              def change
         
     | 
| 
      
 3 
     | 
    
         
            +
                add_column :pay_subscriptions, :data, data_column_type
         
     | 
| 
      
 4 
     | 
    
         
            +
                add_column :pay_charges, :data, data_column_type
         
     | 
| 
      
 5 
     | 
    
         
            +
              end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def data_column_type
         
     | 
| 
      
 8 
     | 
    
         
            +
                case ActiveRecord::Base.configurations.default_hash.dig("adapter")
         
     | 
| 
      
 9 
     | 
    
         
            +
                when "mysql2"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :json
         
     | 
| 
      
 11 
     | 
    
         
            +
                when "postgresql"
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :jsonb
         
     | 
| 
      
 13 
     | 
    
         
            +
                else
         
     | 
| 
      
 14 
     | 
    
         
            +
                  :text
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -26,7 +26,7 @@ module ActiveRecord 
     | 
|
| 
       26 
26 
     | 
    
         
             
                    end
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
                    indent_depth = class_path.size - 1
         
     | 
| 
       29 
     | 
    
         
            -
                    content = content.split("\n").map { |line| "  " * indent_depth + line } 
     | 
| 
      
 29 
     | 
    
         
            +
                    content = content.split("\n").map { |line| "  " * indent_depth + line }.join("\n") << "\n"
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                    inject_into_class(model_path, class_path.last, content) if model_exists?
         
     | 
| 
       32 
32 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/pay.rb
    CHANGED
    
    | 
         @@ -12,6 +12,9 @@ module Pay 
     | 
|
| 
       12 
12 
     | 
    
         
             
              @@billable_class = "User"
         
     | 
| 
       13 
13 
     | 
    
         
             
              @@billable_table = @@billable_class.tableize
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
              mattr_accessor :model_parent_class
         
     | 
| 
      
 16 
     | 
    
         
            +
              @@model_parent_class = "ApplicationRecord"
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       15 
18 
     | 
    
         
             
              mattr_accessor :chargeable_class
         
     | 
| 
       16 
19 
     | 
    
         
             
              mattr_accessor :chargeable_table
         
     | 
| 
       17 
20 
     | 
    
         
             
              @@chargeable_class = "Pay::Charge"
         
     | 
| 
         @@ -105,11 +108,17 @@ module Pay 
     | 
|
| 
       105 
108 
     | 
    
         
             
              class BraintreeError < Error
         
     | 
| 
       106 
109 
     | 
    
         
             
                attr_reader :result
         
     | 
| 
       107 
110 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
                def initialize(result)
         
     | 
| 
      
 111 
     | 
    
         
            +
                def initialize(result = nil)
         
     | 
| 
       109 
112 
     | 
    
         
             
                  @result = result
         
     | 
| 
       110 
113 
     | 
    
         
             
                end
         
     | 
| 
       111 
114 
     | 
    
         
             
              end
         
     | 
| 
       112 
115 
     | 
    
         | 
| 
      
 116 
     | 
    
         
            +
              class BraintreeAuthorizationError < BraintreeError
         
     | 
| 
      
 117 
     | 
    
         
            +
                def message
         
     | 
| 
      
 118 
     | 
    
         
            +
                  "Either the data you submitted is malformed and does not match the API or the API key you used may not be authorized to perform this action."
         
     | 
| 
      
 119 
     | 
    
         
            +
                end
         
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       113 
122 
     | 
    
         
             
              class InvalidPaymentMethod < Error
         
     | 
| 
       114 
123 
     | 
    
         
             
                attr_reader :payment
         
     | 
| 
       115 
124 
     | 
    
         | 
| 
         @@ -118,7 +127,7 @@ module Pay 
     | 
|
| 
       118 
127 
     | 
    
         
             
                end
         
     | 
| 
       119 
128 
     | 
    
         | 
| 
       120 
129 
     | 
    
         
             
                def message
         
     | 
| 
       121 
     | 
    
         
            -
                  "This payment attempt failed  
     | 
| 
      
 130 
     | 
    
         
            +
                  "This payment attempt failed because of an invalid payment method."
         
     | 
| 
       122 
131 
     | 
    
         
             
                end
         
     | 
| 
       123 
132 
     | 
    
         
             
              end
         
     | 
| 
       124 
133 
     | 
    
         | 
    
        data/lib/pay/billable.rb
    CHANGED
    
    | 
         @@ -19,9 +19,10 @@ module Pay 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  include Pay::Billable::SyncEmail
         
     | 
| 
       20 
20 
     | 
    
         
             
                  include Pay::Stripe::Billable if defined? ::Stripe
         
     | 
| 
       21 
21 
     | 
    
         
             
                  include Pay::Braintree::Billable if defined? ::Braintree
         
     | 
| 
      
 22 
     | 
    
         
            +
                  include Pay::Paddle::Billable if defined? ::PaddlePay
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
                  has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner
         
     | 
| 
       24 
     | 
    
         
            -
                  has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner
         
     | 
| 
      
 24 
     | 
    
         
            +
                  has_many :charges, class_name: Pay.chargeable_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
         
     | 
| 
      
 25 
     | 
    
         
            +
                  has_many :subscriptions, class_name: Pay.subscription_class, foreign_key: :owner_id, inverse_of: :owner, as: :owner
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
                  attribute :plan, :string
         
     | 
| 
       27 
28 
     | 
    
         
             
                  attribute :quantity, :integer
         
     | 
| 
         @@ -118,6 +119,10 @@ module Pay 
     | 
|
| 
       118 
119 
     | 
    
         
             
                  braintree? && card_type == "PayPal"
         
     | 
| 
       119 
120 
     | 
    
         
             
                end
         
     | 
| 
       120 
121 
     | 
    
         | 
| 
      
 122 
     | 
    
         
            +
                def paddle?
         
     | 
| 
      
 123 
     | 
    
         
            +
                  processor == "paddle"
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
       121 
126 
     | 
    
         
             
                def has_incomplete_payment?(name: "default")
         
     | 
| 
       122 
127 
     | 
    
         
             
                  subscription(name: name)&.has_incomplete_payment?
         
     | 
| 
       123 
128 
     | 
    
         
             
                end
         
     | 
    
        data/lib/pay/braintree.rb
    CHANGED
    
    | 
         @@ -19,7 +19,7 @@ module Pay 
     | 
|
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
                  Pay.charge_model.include Pay::Braintree::Charge
         
     | 
| 
       21 
21 
     | 
    
         
             
                  Pay.subscription_model.include Pay::Braintree::Subscription
         
     | 
| 
       22 
     | 
    
         
            -
                  Pay.billable_models.each { |model| model.include Pay:: 
     | 
| 
      
 22 
     | 
    
         
            +
                  Pay.billable_models.each { |model| model.include Pay::Braintree::Billable }
         
     | 
| 
       23 
23 
     | 
    
         
             
                end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                def public_key
         
     | 
| 
         @@ -1,6 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Pay
         
     | 
| 
       2 
2 
     | 
    
         
             
              module Braintree
         
     | 
| 
       3 
3 
     | 
    
         
             
                module Billable
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    scope :braintree, -> { where(processor: :braintree) }
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
       4 
10 
     | 
    
         
             
                  # Handles Billable#customer
         
     | 
| 
       5 
11 
     | 
    
         
             
                  #
         
     | 
| 
       6 
12 
     | 
    
         
             
                  # Returns Braintree::Customer
         
     | 
| 
         @@ -24,6 +30,8 @@ module Pay 
     | 
|
| 
       24 
30 
     | 
    
         | 
| 
       25 
31 
     | 
    
         
             
                      result.customer
         
     | 
| 
       26 
32 
     | 
    
         
             
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  rescue ::Braintree::AuthorizationError
         
     | 
| 
      
 34 
     | 
    
         
            +
                    raise BraintreeAuthorizationError
         
     | 
| 
       27 
35 
     | 
    
         
             
                  rescue ::Braintree::BraintreeError => e
         
     | 
| 
       28 
36 
     | 
    
         
             
                    raise BraintreeError, e.message
         
     | 
| 
       29 
37 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -33,7 +41,7 @@ module Pay 
     | 
|
| 
       33 
41 
     | 
    
         
             
                  # Returns a Pay::Charge
         
     | 
| 
       34 
42 
     | 
    
         
             
                  def create_braintree_charge(amount, options = {})
         
     | 
| 
       35 
43 
     | 
    
         
             
                    args = {
         
     | 
| 
       36 
     | 
    
         
            -
                      amount: amount / 100.0,
         
     | 
| 
      
 44 
     | 
    
         
            +
                      amount: amount.to_i / 100.0,
         
     | 
| 
       37 
45 
     | 
    
         
             
                      customer_id: customer.id,
         
     | 
| 
       38 
46 
     | 
    
         
             
                      options: {submit_for_settlement: true}
         
     | 
| 
       39 
47 
     | 
    
         
             
                    }.merge(options)
         
     | 
| 
         @@ -42,6 +50,8 @@ module Pay 
     | 
|
| 
       42 
50 
     | 
    
         
             
                    raise BraintreeError.new(result), result.message unless result.success?
         
     | 
| 
       43 
51 
     | 
    
         | 
| 
       44 
52 
     | 
    
         
             
                    save_braintree_transaction(result.transaction)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  rescue ::Braintree::AuthorizationError
         
     | 
| 
      
 54 
     | 
    
         
            +
                    raise BraintreeAuthorizationError
         
     | 
| 
       45 
55 
     | 
    
         
             
                  rescue ::Braintree::BraintreeError => e
         
     | 
| 
       46 
56 
     | 
    
         
             
                    raise BraintreeError, e.message
         
     | 
| 
       47 
57 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -67,6 +77,8 @@ module Pay 
     | 
|
| 
       67 
77 
     | 
    
         
             
                    raise BraintreeError.new(result), result.message unless result.success?
         
     | 
| 
       68 
78 
     | 
    
         | 
| 
       69 
79 
     | 
    
         
             
                    create_subscription(result.subscription, "braintree", name, plan, status: :active)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  rescue ::Braintree::AuthorizationError
         
     | 
| 
      
 81 
     | 
    
         
            +
                    raise BraintreeAuthorizationError
         
     | 
| 
       70 
82 
     | 
    
         
             
                  rescue ::Braintree::BraintreeError => e
         
     | 
| 
       71 
83 
     | 
    
         
             
                    raise BraintreeError, e.message
         
     | 
| 
       72 
84 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -88,6 +100,8 @@ module Pay 
     | 
|
| 
       88 
100 
     | 
    
         
             
                    update_braintree_card_on_file result.payment_method
         
     | 
| 
       89 
101 
     | 
    
         
             
                    update_subscriptions_to_payment_method(result.payment_method.token)
         
     | 
| 
       90 
102 
     | 
    
         
             
                    true
         
     | 
| 
      
 103 
     | 
    
         
            +
                  rescue ::Braintree::AuthorizationError
         
     | 
| 
      
 104 
     | 
    
         
            +
                    raise BraintreeAuthorizationError
         
     | 
| 
       91 
105 
     | 
    
         
             
                  rescue ::Braintree::BraintreeError => e
         
     | 
| 
       92 
106 
     | 
    
         
             
                    raise BraintreeError, e.message
         
     | 
| 
       93 
107 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -103,11 +117,11 @@ module Pay 
     | 
|
| 
       103 
117 
     | 
    
         
             
                  def braintree_trial_end_date(subscription)
         
     | 
| 
       104 
118 
     | 
    
         
             
                    return unless subscription.trial_period
         
     | 
| 
       105 
119 
     | 
    
         
             
                    # Braintree returns dates without time zones, so we'll assume they're UTC
         
     | 
| 
       106 
     | 
    
         
            -
                     
     | 
| 
      
 120 
     | 
    
         
            +
                    subscription.first_billing_date.end_of_day
         
     | 
| 
       107 
121 
     | 
    
         
             
                  end
         
     | 
| 
       108 
122 
     | 
    
         | 
| 
       109 
123 
     | 
    
         
             
                  def update_subscriptions_to_payment_method(token)
         
     | 
| 
       110 
     | 
    
         
            -
                    subscriptions.each do |subscription|
         
     | 
| 
      
 124 
     | 
    
         
            +
                    subscriptions.braintree.each do |subscription|
         
     | 
| 
       111 
125 
     | 
    
         
             
                      if subscription.active?
         
     | 
| 
       112 
126 
     | 
    
         
             
                        gateway.subscription.update(subscription.processor_id, {payment_method_token: token})
         
     | 
| 
       113 
127 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -167,7 +181,7 @@ module Pay 
     | 
|
| 
       167 
181 
     | 
    
         | 
| 
       168 
182 
     | 
    
         
             
                  def card_details_for_braintree_transaction(transaction)
         
     | 
| 
       169 
183 
     | 
    
         
             
                    case transaction.payment_instrument_type
         
     | 
| 
       170 
     | 
    
         
            -
                    when "credit_card", "samsung_pay_card", "masterpass_card", " 
     | 
| 
      
 184 
     | 
    
         
            +
                    when "credit_card", "samsung_pay_card", "masterpass_card", "visa_checkout_card"
         
     | 
| 
       171 
185 
     | 
    
         
             
                      payment_method = transaction.send("#{transaction.payment_instrument_type}_details")
         
     | 
| 
       172 
186 
     | 
    
         
             
                      {
         
     | 
| 
       173 
187 
     | 
    
         
             
                        card_type: payment_method.card_type,
         
     | 
    
        data/lib/pay/braintree/charge.rb
    CHANGED
    
    
    
        data/lib/pay/engine.rb
    CHANGED
    
    | 
         @@ -11,6 +11,11 @@ begin 
     | 
|
| 
       11 
11 
     | 
    
         
             
              require "stripe_event"
         
     | 
| 
       12 
12 
     | 
    
         
             
            rescue LoadError
         
     | 
| 
       13 
13 
     | 
    
         
             
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            begin
         
     | 
| 
      
 16 
     | 
    
         
            +
              require "paddle_pay"
         
     | 
| 
      
 17 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
       14 
19 
     | 
    
         
             
            # rubocop:enable Lint/HandleExceptions
         
     | 
| 
       15 
20 
     | 
    
         | 
| 
       16 
21 
     | 
    
         
             
            module Pay
         
     | 
| 
         @@ -21,6 +26,7 @@ module Pay 
     | 
|
| 
       21 
26 
     | 
    
         
             
                  # Include processor backends
         
     | 
| 
       22 
27 
     | 
    
         
             
                  require "pay/stripe" if defined? ::Stripe
         
     | 
| 
       23 
28 
     | 
    
         
             
                  require "pay/braintree" if defined? ::Braintree
         
     | 
| 
      
 29 
     | 
    
         
            +
                  require "pay/paddle" if defined? ::PaddlePay
         
     | 
| 
       24 
30 
     | 
    
         | 
| 
       25 
31 
     | 
    
         
             
                  if Pay.automount_routes
         
     | 
| 
       26 
32 
     | 
    
         
             
                    app.routes.append do
         
     | 
| 
         @@ -32,6 +38,7 @@ module Pay 
     | 
|
| 
       32 
38 
     | 
    
         
             
                config.to_prepare do
         
     | 
| 
       33 
39 
     | 
    
         
             
                  Pay::Stripe.setup if defined? ::Stripe
         
     | 
| 
       34 
40 
     | 
    
         
             
                  Pay::Braintree.setup if defined? ::Braintree
         
     | 
| 
      
 41 
     | 
    
         
            +
                  Pay::Paddle.setup if defined? ::PaddlePay
         
     | 
| 
       35 
42 
     | 
    
         | 
| 
       36 
43 
     | 
    
         
             
                  Pay.charge_model.include Pay::Receipts if defined? ::Receipts::Receipt
         
     | 
| 
       37 
44 
     | 
    
         
             
                end
         
     | 
    
        data/lib/pay/paddle.rb
    ADDED
    
    | 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "pay/env"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "pay/paddle/billable"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "pay/paddle/charge"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "pay/paddle/subscription"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "pay/paddle/webhooks"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Pay
         
     | 
| 
      
 8 
     | 
    
         
            +
              module Paddle
         
     | 
| 
      
 9 
     | 
    
         
            +
                include Env
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                extend self
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def setup
         
     | 
| 
      
 14 
     | 
    
         
            +
                  ::PaddlePay.config.vendor_id = vendor_id
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ::PaddlePay.config.vendor_auth_code = vendor_auth_code
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  Pay.charge_model.include Pay::Paddle::Charge
         
     | 
| 
      
 18 
     | 
    
         
            +
                  Pay.subscription_model.include Pay::Paddle::Subscription
         
     | 
| 
      
 19 
     | 
    
         
            +
                  Pay.billable_models.each { |model| model.include Pay::Paddle::Billable }
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def vendor_id
         
     | 
| 
      
 23 
     | 
    
         
            +
                  find_value_by_name(:paddle, :vendor_id)
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def vendor_auth_code
         
     | 
| 
      
 27 
     | 
    
         
            +
                  find_value_by_name(:paddle, :vendor_auth_code)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def public_key_base64
         
     | 
| 
      
 31 
     | 
    
         
            +
                  find_value_by_name(:paddle, :public_key_base64)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def passthrough(owner:, **options)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  options.merge(owner_sgid: owner.to_sgid.to_s).to_json
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Pay
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Paddle
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Billable
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 7 
     | 
    
         
            +
                    scope :paddle, -> { where(processor: :paddle) }
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def paddle_customer
         
     | 
| 
      
 11 
     | 
    
         
            +
                    # pass
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def create_paddle_charge(amount, options = {})
         
     | 
| 
      
 15 
     | 
    
         
            +
                    return unless subscription.processor_id
         
     | 
| 
      
 16 
     | 
    
         
            +
                    raise Pay::Error, "A charge_name is required to create a one-time charge" if options[:charge_name].nil?
         
     | 
| 
      
 17 
     | 
    
         
            +
                    response = PaddlePay::Subscription::Charge.create(subscription.processor_id, amount.to_f / 100, options[:charge_name], options)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    charge = charges.find_or_initialize_by(
         
     | 
| 
      
 19 
     | 
    
         
            +
                      processor: :paddle,
         
     | 
| 
      
 20 
     | 
    
         
            +
                      processor_id: response[:invoice_id]
         
     | 
| 
      
 21 
     | 
    
         
            +
                    )
         
     | 
| 
      
 22 
     | 
    
         
            +
                    charge.update(
         
     | 
| 
      
 23 
     | 
    
         
            +
                      amount: Integer(response[:amount].to_f * 100),
         
     | 
| 
      
 24 
     | 
    
         
            +
                      card_type: subscription.processor_subscription.payment_information[:payment_method],
         
     | 
| 
      
 25 
     | 
    
         
            +
                      paddle_receipt_url: response[:receipt_url],
         
     | 
| 
      
 26 
     | 
    
         
            +
                      created_at: DateTime.parse(response[:payment_date])
         
     | 
| 
      
 27 
     | 
    
         
            +
                    )
         
     | 
| 
      
 28 
     | 
    
         
            +
                    charge
         
     | 
| 
      
 29 
     | 
    
         
            +
                  rescue ::PaddlePay::PaddlePayError => e
         
     | 
| 
      
 30 
     | 
    
         
            +
                    raise Error, e.message
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def create_paddle_subscription(name, plan, options = {})
         
     | 
| 
      
 34 
     | 
    
         
            +
                    # pass
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def update_paddle_card(token)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    # pass
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def update_paddle_email!
         
     | 
| 
      
 42 
     | 
    
         
            +
                    # pass
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def paddle_trial_end_date(subscription)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return unless subscription.state == "trialing"
         
     | 
| 
      
 47 
     | 
    
         
            +
                    DateTime.parse(subscription.next_payment[:date]).end_of_day
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  def paddle_subscription(subscription_id, options = {})
         
     | 
| 
      
 51 
     | 
    
         
            +
                    hash = PaddlePay::Subscription::User.list({subscription_id: subscription_id}, options).try(:first)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    OpenStruct.new(hash)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  rescue ::PaddlePay::PaddlePayError => e
         
     | 
| 
      
 54 
     | 
    
         
            +
                    raise Error, e.message
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def paddle_invoice!(options = {})
         
     | 
| 
      
 58 
     | 
    
         
            +
                    # pass
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  def paddle_upcoming_invoice
         
     | 
| 
      
 62 
     | 
    
         
            +
                    # pass
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     |