op_cart 0.4.0 → 0.4.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 +4 -4
- data/app/controllers/op_cart/orders_controller.rb +1 -1
- data/app/models/op_cart/order.rb +16 -2
- data/app/models/op_cart/subscription.rb +66 -0
- data/db/migrate/20150205220423_create_op_cart_subscriptions.rb +19 -0
- data/db/seeds.rb +19 -7
- data/lib/op_cart/version.rb +1 -1
- data/test/dummy/log/development.log +59 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 695ceaa47d75df3df79ef2d8049909b2cd605662
|
4
|
+
data.tar.gz: edfc90597c37f748372219b032568a26d17012c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9f7d545228109490cb3a503023943b4ae6a5dcf196eca748609af70a633fb4c229251570e7b723a9fea78f1eb369c713ac0c31cdf51b98f78eb89e094bba267
|
7
|
+
data.tar.gz: 88aa09d43bea2327481b99d933ac087a8093c2e857a22e0b0bf2bb6a253df0208565d43ac1958a6c556e320212230df1e35856c22f7a2383d343a824293a9a6a
|
data/app/models/op_cart/order.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module OpCart
|
2
2
|
class Order < ActiveRecord::Base
|
3
3
|
has_many :line_items
|
4
|
+
has_many :subscriptions
|
4
5
|
belongs_to :shipping_address
|
5
6
|
belongs_to :user
|
6
7
|
|
@@ -19,6 +20,7 @@ module OpCart
|
|
19
20
|
before_validation :set_total
|
20
21
|
before_validation -> { self.status = :pending }, unless: :status?
|
21
22
|
before_save :charge_customer, if: -> { self.status == 'pending' }
|
23
|
+
before_create :create_subscriptions
|
22
24
|
|
23
25
|
private
|
24
26
|
|
@@ -40,10 +42,9 @@ module OpCart
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def charge_customer
|
43
|
-
customer = Customer.find_or_create_by user: user
|
44
45
|
if processor_token.present?
|
45
46
|
customer.update_card processor_token
|
46
|
-
processor_token = nil
|
47
|
+
self.processor_token = nil
|
47
48
|
end
|
48
49
|
|
49
50
|
self.processor_response = Stripe::Charge.create(
|
@@ -53,6 +54,7 @@ module OpCart
|
|
53
54
|
).to_hash
|
54
55
|
self.status = :paid if processor_response['captured']
|
55
56
|
rescue Stripe::InvalidRequestError, Stripe::CardError => e
|
57
|
+
self.processor_token = nil
|
56
58
|
if e.try(:code) == 'card_declined'
|
57
59
|
self.status = :payment_declined
|
58
60
|
end
|
@@ -68,5 +70,17 @@ module OpCart
|
|
68
70
|
self.errors.add :card_error, (message || e.message)
|
69
71
|
false
|
70
72
|
end
|
73
|
+
|
74
|
+
def create_subscriptions
|
75
|
+
line_items.each do |li|
|
76
|
+
if li.sellable.is_a? Plan
|
77
|
+
subscriptions.new customer: customer, plan: li.sellable, quantity: li.quantity
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def customer
|
83
|
+
@customer ||= Customer.find_or_create_by user: user
|
84
|
+
end
|
71
85
|
end
|
72
86
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module OpCart
|
2
|
+
class Subscription < ActiveRecord::Base
|
3
|
+
belongs_to :plan
|
4
|
+
belongs_to :order
|
5
|
+
belongs_to :customer
|
6
|
+
|
7
|
+
before_validation -> { self.status = :pending }, unless: :status?
|
8
|
+
before_validation -> { self.quantity = 1 }, unless: :quantity?
|
9
|
+
before_validation :create_subscription, on: :create
|
10
|
+
before_validation :update_subscription, on: :update
|
11
|
+
|
12
|
+
validates :processor_token, uniqueness: true, presence: true
|
13
|
+
validates :status, presence: true
|
14
|
+
validates :quantity, numericality: { only_integer: true, greater_than: 0 }
|
15
|
+
validates :started_at, presence: true
|
16
|
+
validates :plan, :order, :customer, presence: true
|
17
|
+
|
18
|
+
def processor_object
|
19
|
+
@processor_object ||= customer.processor_object.subscriptions.retrieve processor_token
|
20
|
+
rescue Stripe::InvalidRequestError => e
|
21
|
+
raise e unless e.message.include? 'does not have subscription'
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_subscription
|
27
|
+
subscriptions_attributes = { plan: plan.processor_token, quantity: quantity }
|
28
|
+
subscriptions_attributes[:trial_end] = trial_ended_at.to_i if trial_ended_at
|
29
|
+
update_local_object customer.processor_object.subscriptions.create(subscriptions_attributes)
|
30
|
+
rescue Stripe::InvalidRequestError => e
|
31
|
+
if e.param
|
32
|
+
self.errors.add e.param, e.message
|
33
|
+
else
|
34
|
+
self.errors.add :base, e.message
|
35
|
+
end
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_subscription
|
40
|
+
subscriptions_attributes = {}
|
41
|
+
subscriptions_attributes[:quantity] = quantity if quantity_changed?
|
42
|
+
subscriptions_attributes[:trial_end] = trial_ended_at.to_i if trial_ended_at_changed?
|
43
|
+
subscriptions_attributes[:plan] = plan.processor_token if plan_id_changed?
|
44
|
+
update_local_object customer.processor_object.subscriptions.create(subscriptions_attributes)
|
45
|
+
rescue Stripe::InvalidRequestError => e
|
46
|
+
if e.param
|
47
|
+
self.errors.add e.param, e.message
|
48
|
+
else
|
49
|
+
self.errors.add :base, e.message
|
50
|
+
end
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def update_local_object subscription=processor_object
|
55
|
+
self.processor_token = subscription.id
|
56
|
+
self.status = subscription.status
|
57
|
+
self.quantity = subscription.quantity
|
58
|
+
self.started_at = Time.at subscription.start
|
59
|
+
self.canceled_at = Time.at subscription.canceled_at if subscription.canceled_at
|
60
|
+
self.ended_at = Time.at subscription.ended_at if subscription.ended_at
|
61
|
+
self.trial_started_at = Time.at subscription.trial_start if subscription.trial_start
|
62
|
+
self.trial_ended_at = Time.at subscription.trial_end if subscription.trial_end
|
63
|
+
self.plan = Plan.find_by! processor_token: subscription.plan.id
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateOpCartSubscriptions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :op_cart_subscriptions do |t|
|
4
|
+
t.string :processor_token
|
5
|
+
t.string :status
|
6
|
+
t.integer :quantity
|
7
|
+
t.datetime :started_at
|
8
|
+
t.datetime :canceled_at
|
9
|
+
t.datetime :ended_at
|
10
|
+
t.datetime :trial_started_at
|
11
|
+
t.datetime :trial_ended_at
|
12
|
+
t.references :plan, index: true
|
13
|
+
t.references :order, index: true
|
14
|
+
t.references :customer, index: true
|
15
|
+
|
16
|
+
t.timestamps null: false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/db/seeds.rb
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
shipping_address1_attrs = {
|
2
|
+
full_name: User.first.name,
|
3
|
+
street: '123 N 4th',
|
4
|
+
locality: 'New York',
|
5
|
+
region: 'New York',
|
6
|
+
postal_code: '12345',
|
7
|
+
user: User.first,
|
8
|
+
}
|
9
|
+
shipping_address1 = OpCart::ShippingAddress.where(street: shipping_address1_attrs[:street]).first_or_create! shipping_address1_attrs
|
10
|
+
|
1
11
|
product1_attrs = {
|
2
12
|
name: 'Device 3000',
|
3
13
|
description: 'The original Device 3000',
|
@@ -7,8 +17,7 @@ product1_attrs = {
|
|
7
17
|
charge_taxes: true,
|
8
18
|
user: User.first,
|
9
19
|
}
|
10
|
-
|
11
|
-
product1 = OpCart::Product.where(sku: product1_attrs[:sku]).first_or_create product1_attrs
|
20
|
+
product1 = OpCart::Product.where(sku: product1_attrs[:sku]).first_or_create! product1_attrs
|
12
21
|
|
13
22
|
product2_attrs = {
|
14
23
|
name: 'Device 9000',
|
@@ -19,8 +28,7 @@ product2_attrs = {
|
|
19
28
|
charge_taxes: true,
|
20
29
|
user: User.first,
|
21
30
|
}
|
22
|
-
|
23
|
-
product2 = OpCart::Product.where(sku: product2_attrs[:sku]).first_or_create product2_attrs
|
31
|
+
product2 = OpCart::Product.where(sku: product2_attrs[:sku]).first_or_create! product2_attrs
|
24
32
|
|
25
33
|
rand_plan_no = rand 10**9
|
26
34
|
plan1_attrs = {
|
@@ -35,8 +43,7 @@ plan1_attrs = {
|
|
35
43
|
allow_purchases: true,
|
36
44
|
user: User.first,
|
37
45
|
}
|
38
|
-
|
39
|
-
plan1 = OpCart::Plan.where(name: plan1_attrs[:name]).first_or_create plan1_attrs
|
46
|
+
plan1 = OpCart::Plan.where(name: plan1_attrs[:name]).first_or_create! plan1_attrs
|
40
47
|
|
41
48
|
plan_addon1_attrs = {
|
42
49
|
recurring: false,
|
@@ -44,5 +51,10 @@ plan_addon1_attrs = {
|
|
44
51
|
plan: plan1,
|
45
52
|
user: User.first,
|
46
53
|
}
|
54
|
+
plan_addon1 = OpCart::PlanAddon.first_or_create! plan_addon1_attrs
|
47
55
|
|
48
|
-
|
56
|
+
token1 = Stripe::Token.create card: { number: '4'+'1'*15, exp_month: 1, exp_year: 2031, cvc: 123 }
|
57
|
+
order1 = OpCart::Order.first || OpCart::Order.new(user: User.first, shipping_address: shipping_address1, processor_token: token1.id)
|
58
|
+
order1.line_items << OpCart::LineItem.new(sellable: plan1, quantity: 1)
|
59
|
+
order1.line_items << OpCart::LineItem.new(sellable: plan_addon1.product, quantity: 1)
|
60
|
+
order1.save!
|
data/lib/op_cart/version.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
[1m[36m (22.3ms)[0m [1mCREATE TABLE "schema_migrations" ("version" character varying NOT NULL) [0m
|
2
|
+
[1m[35m (2.1ms)[0m CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
|
3
|
+
[1m[36mActiveRecord::SchemaMigration Load (0.4ms)[0m [1mSELECT "schema_migrations".* FROM "schema_migrations"[0m
|
4
|
+
Migrating to CreateOpCartProducts (20140829191646)
|
5
|
+
[1m[35m (0.3ms)[0m BEGIN
|
6
|
+
[1m[36m (30.8ms)[0m [1mCREATE TABLE "op_cart_products" ("id" serial primary key, "name" character varying NOT NULL, "description" text NOT NULL, "sku" character varying, "image_url" character varying, "price" integer NOT NULL, "allow_purchases" boolean DEFAULT 'f', "charge_taxes" boolean DEFAULT 'f', "user_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) [0m
|
7
|
+
[1m[35m (1.4ms)[0m CREATE INDEX "index_op_cart_products_on_user_id" ON "op_cart_products" ("user_id")
|
8
|
+
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO "schema_migrations" ("version") VALUES ($1)[0m [["version", "20140829191646"]]
|
9
|
+
[1m[35m (7.3ms)[0m COMMIT
|
10
|
+
Migrating to CreateOpCartOrders (20140829200318)
|
11
|
+
[1m[36m (10.9ms)[0m [1mBEGIN[0m
|
12
|
+
[1m[35m (5.5ms)[0m CREATE TABLE "op_cart_orders" ("id" serial primary key, "total" integer NOT NULL, "tax_amount" integer DEFAULT 0, "status" character varying NOT NULL, "processor_response" json NOT NULL, "shipping_address_id" integer NOT NULL, "user_id" integer NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
|
13
|
+
[1m[36m (1.5ms)[0m [1mCREATE INDEX "index_op_cart_orders_on_shipping_address_id" ON "op_cart_orders" ("shipping_address_id")[0m
|
14
|
+
[1m[35m (1.4ms)[0m CREATE INDEX "index_op_cart_orders_on_user_id" ON "op_cart_orders" ("user_id")
|
15
|
+
[1m[36mSQL (0.3ms)[0m [1mINSERT INTO "schema_migrations" ("version") VALUES ($1)[0m [["version", "20140829200318"]]
|
16
|
+
[1m[35m (0.5ms)[0m COMMIT
|
17
|
+
Migrating to CreateOpCartLineItems (20140829201756)
|
18
|
+
[1m[36m (0.3ms)[0m [1mBEGIN[0m
|
19
|
+
[1m[35mSQL (26.9ms)[0m CREATE EXTENSION IF NOT EXISTS "hstore"
|
20
|
+
[1m[36m (4.8ms)[0m [1mCREATE TABLE "op_cart_line_items" ("id" serial primary key, "unit_price" integer NOT NULL, "quantity" integer NOT NULL, "sellable_snapshot" hstore NOT NULL, "sellable_id" integer NOT NULL, "sellable_type" character varying NOT NULL, "order_id" integer NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) [0m
|
21
|
+
[1m[35m (1.4ms)[0m CREATE INDEX "index_op_cart_line_items_on_sellable_type_and_sellable_id" ON "op_cart_line_items" ("sellable_type", "sellable_id")
|
22
|
+
[1m[36m (1.1ms)[0m [1mCREATE INDEX "index_op_cart_line_items_on_order_id" ON "op_cart_line_items" ("order_id")[0m
|
23
|
+
[1m[35mSQL (0.3ms)[0m INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20140829201756"]]
|
24
|
+
[1m[36m (1.7ms)[0m [1mCOMMIT[0m
|
25
|
+
Migrating to CreateOpCartShippingAddresses (20150125000000)
|
26
|
+
[1m[35m (0.4ms)[0m BEGIN
|
27
|
+
[1m[36m (4.2ms)[0m [1mCREATE TABLE "op_cart_shipping_addresses" ("id" serial primary key, "full_name" character varying NOT NULL, "street" character varying NOT NULL, "street_2" character varying, "locality" character varying NOT NULL, "region" character varying NOT NULL, "postal_code" character varying NOT NULL, "user_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) [0m
|
28
|
+
[1m[35m (1.2ms)[0m CREATE INDEX "index_op_cart_shipping_addresses_on_user_id" ON "op_cart_shipping_addresses" ("user_id")
|
29
|
+
[1m[36mSQL (0.2ms)[0m [1mINSERT INTO "schema_migrations" ("version") VALUES ($1)[0m [["version", "20150125000000"]]
|
30
|
+
[1m[35m (0.4ms)[0m COMMIT
|
31
|
+
Migrating to CreateOpCartCustomers (20150131000000)
|
32
|
+
[1m[36m (0.3ms)[0m [1mBEGIN[0m
|
33
|
+
[1m[35m (5.3ms)[0m CREATE TABLE "op_cart_customers" ("id" serial primary key, "processor_token" character varying, "delinquent" boolean DEFAULT 'f', "default_card_id" integer, "user_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
|
34
|
+
[1m[36m (0.8ms)[0m [1mCREATE INDEX "index_op_cart_customers_on_default_card_id" ON "op_cart_customers" ("default_card_id")[0m
|
35
|
+
[1m[35m (1.1ms)[0m CREATE INDEX "index_op_cart_customers_on_user_id" ON "op_cart_customers" ("user_id")
|
36
|
+
[1m[36mSQL (0.2ms)[0m [1mINSERT INTO "schema_migrations" ("version") VALUES ($1)[0m [["version", "20150131000000"]]
|
37
|
+
[1m[35m (0.3ms)[0m COMMIT
|
38
|
+
Migrating to CreateOpCartCards (20150131000001)
|
39
|
+
[1m[36m (0.3ms)[0m [1mBEGIN[0m
|
40
|
+
[1m[35m (5.1ms)[0m CREATE TABLE "op_cart_cards" ("id" serial primary key, "processor_token" character varying, "fingerprint" character varying, "last4" character varying, "brand" character varying, "exp_month" character varying, "exp_year" character varying, "customer_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
|
41
|
+
[1m[36m (1.0ms)[0m [1mCREATE INDEX "index_op_cart_cards_on_processor_token" ON "op_cart_cards" ("processor_token")[0m
|
42
|
+
[1m[35m (1.2ms)[0m CREATE INDEX "index_op_cart_cards_on_fingerprint" ON "op_cart_cards" ("fingerprint")
|
43
|
+
[1m[36m (1.5ms)[0m [1mCREATE INDEX "index_op_cart_cards_on_customer_id" ON "op_cart_cards" ("customer_id")[0m
|
44
|
+
[1m[35mSQL (0.2ms)[0m INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20150131000001"]]
|
45
|
+
[1m[36m (0.5ms)[0m [1mCOMMIT[0m
|
46
|
+
Migrating to CreateOpCartPlans (20150201033629)
|
47
|
+
[1m[35m (0.4ms)[0m BEGIN
|
48
|
+
[1m[36m (6.2ms)[0m [1mCREATE TABLE "op_cart_plans" ("id" serial primary key, "processor_token" character varying, "name" character varying NOT NULL, "description" character varying, "image_url" character varying, "price" integer, "interval_count" integer, "interval" character varying, "trial_period_days" integer, "allow_purchases" boolean DEFAULT 'f', "user_id" integer, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) [0m
|
49
|
+
[1m[35m (1.3ms)[0m CREATE INDEX "index_op_cart_plans_on_user_id" ON "op_cart_plans" ("user_id")
|
50
|
+
[1m[36m (7.5ms)[0m [1mALTER TABLE "op_cart_plans" ADD CONSTRAINT "fk_rails_f7712cb323"
|
51
|
+
FOREIGN KEY ("user_id")
|
52
|
+
REFERENCES "users" ("id")
|
53
|
+
[0m
|
54
|
+
PG::UndefinedTable: ERROR: relation "users" does not exist
|
55
|
+
: ALTER TABLE "op_cart_plans" ADD CONSTRAINT "fk_rails_f7712cb323"
|
56
|
+
FOREIGN KEY ("user_id")
|
57
|
+
REFERENCES "users" ("id")
|
58
|
+
|
59
|
+
[1m[35m (0.2ms)[0m ROLLBACK
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: op_cart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Boehs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -87,6 +87,7 @@ files:
|
|
87
87
|
- app/models/op_cart/plan_addon.rb
|
88
88
|
- app/models/op_cart/product.rb
|
89
89
|
- app/models/op_cart/shipping_address.rb
|
90
|
+
- app/models/op_cart/subscription.rb
|
90
91
|
- config/initializers/stripe.rb
|
91
92
|
- config/locales/op_cart.en.yml
|
92
93
|
- config/routes.rb
|
@@ -98,6 +99,7 @@ files:
|
|
98
99
|
- db/migrate/20150131000001_create_op_cart_cards.rb
|
99
100
|
- db/migrate/20150201033629_create_op_cart_plans.rb
|
100
101
|
- db/migrate/20150203043805_create_op_cart_plan_addons.rb
|
102
|
+
- db/migrate/20150205220423_create_op_cart_subscriptions.rb
|
101
103
|
- db/seeds.rb
|
102
104
|
- lib/op_cart.rb
|
103
105
|
- lib/op_cart/engine.rb
|
@@ -133,6 +135,7 @@ files:
|
|
133
135
|
- test/dummy/config/locales/en.yml
|
134
136
|
- test/dummy/config/routes.rb
|
135
137
|
- test/dummy/config/secrets.yml
|
138
|
+
- test/dummy/log/development.log
|
136
139
|
- test/dummy/log/test.log
|
137
140
|
- test/dummy/public/404.html
|
138
141
|
- test/dummy/public/422.html
|
@@ -199,6 +202,7 @@ test_files:
|
|
199
202
|
- test/dummy/config/routes.rb
|
200
203
|
- test/dummy/config/secrets.yml
|
201
204
|
- test/dummy/config.ru
|
205
|
+
- test/dummy/log/development.log
|
202
206
|
- test/dummy/log/test.log
|
203
207
|
- test/dummy/public/404.html
|
204
208
|
- test/dummy/public/422.html
|