bodega 0.3.0 → 0.4.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.
Files changed (39) hide show
  1. data/.rspec +3 -0
  2. data/Gemfile +10 -6
  3. data/Gemfile.lock +50 -19
  4. data/VERSION +1 -1
  5. data/app/controllers/bodega/orders_controller.rb +21 -30
  6. data/app/helpers/bodega/application_helper.rb +1 -0
  7. data/app/helpers/bodega/cart_helper.rb +9 -25
  8. data/app/models/bodega/order.rb +113 -11
  9. data/app/models/bodega/order_product.rb +20 -26
  10. data/app/models/bodega/product.rb +9 -12
  11. data/app/views/bodega/orders/_cart.html.erb +26 -0
  12. data/app/views/bodega/orders/_cart_row.html.erb +24 -0
  13. data/app/views/bodega/orders/_shipping_row.html.erb +13 -0
  14. data/app/views/bodega/orders/edit.html.erb +1 -0
  15. data/app/views/bodega/orders/new.html.erb +2 -38
  16. data/bodega.gemspec +30 -12
  17. data/config/locales/en.yml +13 -0
  18. data/config/routes.rb +9 -9
  19. data/db/migrate/20121111170337_create_bodega_orders.rb +12 -0
  20. data/lib/bodega/engine.rb +0 -1
  21. data/lib/bodega/optional.rb +12 -0
  22. data/lib/bodega/payment_method/base.rb +5 -13
  23. data/lib/bodega/payment_method/paypal.rb +12 -4
  24. data/lib/bodega/payment_method.rb +0 -4
  25. data/lib/bodega/shipping_method/base.rb +71 -0
  26. data/lib/bodega/shipping_method/ups.rb +18 -0
  27. data/lib/bodega/shipping_method.rb +5 -0
  28. data/lib/bodega.rb +19 -1
  29. data/spec/lib/bodega/payment_method/base_spec.rb +12 -0
  30. data/spec/lib/bodega/shipping_method/base_spec.rb +12 -0
  31. data/spec/lib/bodega_spec.rb +18 -0
  32. data/spec/models/order_product_spec.rb +72 -0
  33. data/spec/models/order_spec.rb +93 -0
  34. data/spec/models/product_spec.rb +78 -0
  35. data/spec/spec_helper.rb +25 -0
  36. data/spec/support/active_record.rb +43 -0
  37. data/spec/support/rails.rb +7 -0
  38. data/spec/support/vcr.rb +0 -0
  39. metadata +36 -18
@@ -1,41 +1,5 @@
1
- <% if current_products.empty? -%>
1
+ <% if current_order.empty? -%>
2
2
  <h3><%= t 'bodega.empty_cart' %></h3>
3
3
  <% else -%>
4
- <%= form_for(current_order, url: root_path) do |form| %>
5
- <table id="bodega-cart">
6
- <thead>
7
- <tr><th class="product-name" colspan="2"><%= t 'bodega.product' %></th><th class="price"><%= t 'bodega.price' %></th><th class="total" colspan="2"><%= t 'bodega.total' %></th></tr>
8
- </thead>
9
- <tbody>
10
- <% current_order.order_products.each do |order_product| -%>
11
- <tr>
12
- <td class="quantity-field">
13
- <%= number_field_tag 'products[][quantity]', order_product.quantity, class: 'quantity', max: order_product.product.max_for_sale, min: 1 %>
14
- </td>
15
- <td class="product-name">
16
- <%= order_product.name %>
17
- <%= hidden_field_tag 'products[][type]', order_product.product_type %>
18
- <%= hidden_field_tag 'products[][id]', order_product.product_id %>
19
- </td>
20
- <td class="price">
21
- <%= humanized_money_with_symbol order_product.price %>
22
- </td>
23
- <td class="subtotal">
24
- <%= humanized_money_with_symbol order_product.subtotal %>
25
- </td>
26
- <td class="remove">
27
- <%= link_to t('bodega.remove'), bodega.remove_path(product_id: order_product.identifier) %>
28
- </td>
29
- </tr>
30
- <% end -%>
31
- <tr>
32
- <td colspan="3"></td>
33
- <td><%= humanized_money_with_symbol current_order.subtotal %></td>
34
- <td></td>
35
- </tr>
36
- </tbody>
37
- </table>
38
- <%= button_tag t('bodega.update_cart'), id: 'bodega-update', name: :update, value: 1 %>
39
- <%= button_tag t('bodega.checkout'), id: 'bodega-checkout', name: :checkout, value: 1 %>
40
- <% end =%>
4
+ <%= render :partial => 'cart' %>
41
5
  <% end -%>
data/bodega.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "bodega"
8
- s.version = "0.3.0"
8
+ s.version = "0.3.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Flip Sasser"]
12
- s.date = "2013-01-07"
12
+ s.date = "2013-02-04"
13
13
  s.description = "Bodega adds checkout logic to any model in your app!"
14
14
  s.email = "flip@x451.com"
15
15
  s.extra_rdoc_files = [
@@ -33,6 +33,10 @@ Gem::Specification.new do |s|
33
33
  "app/models/bodega/order.rb",
34
34
  "app/models/bodega/order_product.rb",
35
35
  "app/models/bodega/product.rb",
36
+ "app/views/bodega/orders/_cart.html.erb",
37
+ "app/views/bodega/orders/_cart_row.html.erb",
38
+ "app/views/bodega/orders/_shipping_row.html.erb",
39
+ "app/views/bodega/orders/edit.html.erb",
36
40
  "app/views/bodega/orders/new.html.erb",
37
41
  "app/views/bodega/orders/show.html.erb",
38
42
  "bodega.gemspec",
@@ -42,9 +46,13 @@ Gem::Specification.new do |s|
42
46
  "db/migrate/20121111170420_create_bodega_order_products.rb",
43
47
  "lib/bodega.rb",
44
48
  "lib/bodega/engine.rb",
49
+ "lib/bodega/optional.rb",
45
50
  "lib/bodega/payment_method.rb",
46
51
  "lib/bodega/payment_method/base.rb",
47
52
  "lib/bodega/payment_method/paypal.rb",
53
+ "lib/bodega/shipping_method.rb",
54
+ "lib/bodega/shipping_method/base.rb",
55
+ "lib/bodega/shipping_method/ups.rb",
48
56
  "lib/bodega/version.rb",
49
57
  "lib/generators/bodega/install/install_generator.rb",
50
58
  "lib/generators/bodega/product/USAGE",
@@ -55,7 +63,17 @@ Gem::Specification.new do |s|
55
63
  "lib/generators/bodega/productize/productize_generator.rb",
56
64
  "lib/generators/bodega/productize/templates/migration.rb",
57
65
  "lib/tasks/bodega_tasks.rake",
58
- "script/rails"
66
+ "script/rails",
67
+ "spec/lib/bodega/payment_method/base_spec.rb",
68
+ "spec/lib/bodega/shipping_method/base_spec.rb",
69
+ "spec/lib/bodega_spec.rb",
70
+ "spec/models/order_product_spec.rb",
71
+ "spec/models/order_spec.rb",
72
+ "spec/models/product_spec.rb",
73
+ "spec/spec_helper.rb",
74
+ "spec/support/active_record.rb",
75
+ "spec/support/rails.rb",
76
+ "spec/support/vcr.rb"
59
77
  ]
60
78
  s.homepage = "http://github.com/flipsasser/bodega"
61
79
  s.licenses = ["MIT"]
@@ -67,24 +85,24 @@ Gem::Specification.new do |s|
67
85
  s.specification_version = 3
68
86
 
69
87
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
70
- s.add_runtime_dependency(%q<configurator2>, [">= 0.1.2"])
88
+ s.add_runtime_dependency(%q<activerecord>, [">= 3.2.11"])
89
+ s.add_runtime_dependency(%q<configurator2>, [">= 0.1.3"])
71
90
  s.add_runtime_dependency(%q<i18n>, [">= 0"])
91
+ s.add_runtime_dependency(%q<maintain>, [">= 0"])
72
92
  s.add_runtime_dependency(%q<money-rails>, [">= 0"])
73
- s.add_development_dependency(%q<jeweler>, ["= 1.8.4"])
74
- s.add_development_dependency(%q<pry>, [">= 0"])
75
93
  else
76
- s.add_dependency(%q<configurator2>, [">= 0.1.2"])
94
+ s.add_dependency(%q<activerecord>, [">= 3.2.11"])
95
+ s.add_dependency(%q<configurator2>, [">= 0.1.3"])
77
96
  s.add_dependency(%q<i18n>, [">= 0"])
97
+ s.add_dependency(%q<maintain>, [">= 0"])
78
98
  s.add_dependency(%q<money-rails>, [">= 0"])
79
- s.add_dependency(%q<jeweler>, ["= 1.8.4"])
80
- s.add_dependency(%q<pry>, [">= 0"])
81
99
  end
82
100
  else
83
- s.add_dependency(%q<configurator2>, [">= 0.1.2"])
101
+ s.add_dependency(%q<activerecord>, [">= 3.2.11"])
102
+ s.add_dependency(%q<configurator2>, [">= 0.1.3"])
84
103
  s.add_dependency(%q<i18n>, [">= 0"])
104
+ s.add_dependency(%q<maintain>, [">= 0"])
85
105
  s.add_dependency(%q<money-rails>, [">= 0"])
86
- s.add_dependency(%q<jeweler>, ["= 1.8.4"])
87
- s.add_dependency(%q<pry>, [">= 0"])
88
106
  end
89
107
  end
90
108
 
@@ -1,3 +1,16 @@
1
1
  en:
2
2
  bodega:
3
+ total: "Total"
4
+ grand_total: "Grand total:"
5
+ check_out: "Check Out"
6
+ update_cart: "Update Cart"
3
7
  empty_cart: "Your cart is currently empty."
8
+ sold_out: "Sorry, this product is sold out."
9
+ one_in_stock: "There is only one in stock!"
10
+ x_in_stock: "There are only x in stock!"
11
+ street_1: "123 Main Street"
12
+ street_2: "Apartment #1B"
13
+ city: "City"
14
+ postal_code: "Zip"
15
+ order_processed: "Your order has been processed! Thank you!"
16
+ order_failed: "There was a problem processing this order. Your account has not been charged."
data/config/routes.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  Bodega::Engine.routes.draw do
2
2
  # Building orders
3
- get '', as: :root, to: 'orders#new'
4
- post '', to: 'orders#create'
3
+ get '', as: :new_order, to: 'orders#new'
4
+ resource :order, only: :create, path: '' do
5
+ # Add products to an order
6
+ post :add, as: :add_to, to: 'orders#add'
7
+ get 'remove/:product_id', as: :remove_from, constraints: {product_id: /.+\.\d+/}, to: 'orders#remove'
5
8
 
6
- # Add products to an order
7
- post :add, to: 'orders#add'
8
- get 'remove/:product_id', as: :remove, constraints: {product_id: /.+\.\d+/}, to: 'orders#remove'
9
-
10
- # Processing orders
11
- get :complete, to: 'orders#complete'
12
- post :complete, to: 'orders#complete'
9
+ # Processing orders
10
+ get :complete, to: 'orders#complete'
11
+ post :complete, to: 'orders#complete'
12
+ end
13
13
 
14
14
  # Existing orders
15
15
  get ':id', as: :order, to: 'orders#show'
@@ -4,8 +4,20 @@ class CreateBodegaOrders < ActiveRecord::Migration
4
4
  def change
5
5
  create_table :bodega_orders do |t|
6
6
  t.belongs_to :customer, polymorphic: true
7
+ t.integer :status
7
8
  t.string :identifier, limit: 20
8
9
  t.string :payment_id
10
+ t.string :shipping_rate_code
11
+ t.string :shipping_rate_name, limit: 50
12
+ t.text :shipping_rates
13
+ t.string :tracking_number
14
+ t.string :street_1, limit: 60
15
+ t.string :street_2, limit: 60
16
+ t.string :city, limit: 60
17
+ t.string :state, limit: 3
18
+ t.string :postal_code, limit: 11
19
+ t.string :country, limit: 3
20
+ t.money :shipping
9
21
  t.money :tax
10
22
  t.money :total
11
23
  t.timestamps
data/lib/bodega/engine.rb CHANGED
@@ -4,7 +4,6 @@ module Bodega
4
4
 
5
5
  initializer "bodega.hookses" do
6
6
  ActiveSupport.on_load :action_controller do
7
- #helper 'bodega/application'
8
7
  helper 'bodega/cart'
9
8
  include Bodega::CartHelper
10
9
  end
@@ -0,0 +1,12 @@
1
+ module Bodega
2
+ module Optional
3
+ def options(*new_options)
4
+ option_namespace = self.name.split('::').pop.underscore
5
+ Bodega.class_eval do
6
+ option option_namespace do
7
+ options(*new_options.flatten)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,16 +1,9 @@
1
+ require 'bodega/optional'
2
+
1
3
  module Bodega
2
4
  module PaymentMethod
3
5
  class Base
4
- class << self
5
- def options(*new_options)
6
- option_namespace = self.name.split('::').pop.underscore
7
- Bodega.class_eval do
8
- option option_namespace do
9
- options(*new_options.flatten)
10
- end
11
- end
12
- end
13
- end
6
+ extend Bodega::Optional
14
7
 
15
8
  attr_accessor :options, :order
16
9
 
@@ -18,13 +11,12 @@ module Bodega
18
11
  raise "Implement #{self.class.name}#checkout_url"
19
12
  end
20
13
 
21
- def complete!
14
+ def complete!(options = {})
22
15
  raise "Implement #{self.class.name}#complete!"
23
16
  end
24
17
 
25
- def initialize(order, options)
18
+ def initialize(order)
26
19
  self.order = order
27
- self.options = options
28
20
  end
29
21
  end
30
22
  end
@@ -10,13 +10,12 @@ module Bodega
10
10
  response.redirect_uri
11
11
  end
12
12
 
13
- def complete!
13
+ def complete!(options = {})
14
14
  response = client.checkout!(
15
15
  options[:token],
16
16
  options[:PayerID],
17
17
  request
18
18
  )
19
- require 'pry'; binding.pry
20
19
  response.payment_info.last.transaction_id
21
20
  end
22
21
 
@@ -32,8 +31,17 @@ module Bodega
32
31
 
33
32
  def request
34
33
  @request ||= ::Paypal::Payment::Request.new(
35
- amount: order.subtotal.to_f,
36
- description: order.order_products.map(&:quantity_and_name).to_sentence
34
+ amount: order.total.to_f,
35
+ description: order.order_products.map(&:quantity_and_name).to_sentence,
36
+ items: order.order_products.map {|order_product|
37
+ {
38
+ name: order_product.name,
39
+ amount: order_product.price.to_f,
40
+ quantity: order_product.quantity
41
+ }
42
+ },
43
+ shipping_amount: order.shipping.to_f,
44
+ tax_amount: order.tax.to_f
37
45
  )
38
46
  end
39
47
  end
@@ -2,9 +2,5 @@ module Bodega
2
2
  module PaymentMethod
3
3
  autoload :Paypal, 'bodega/payment_method/paypal'
4
4
  autoload :Plinq, 'bodega/payment_method/plinq'
5
-
6
- def payment_method
7
- @payment_method ||= "Bodega::PaymentMethod::#{Bodega.config.payment_method.to_s.classify}".constantize.new(current_order, params)
8
- end
9
5
  end
10
6
  end
@@ -0,0 +1,71 @@
1
+ require 'bodega/optional'
2
+
3
+ module Bodega
4
+ module ShippingMethod
5
+ class Base
6
+ extend Bodega::Optional
7
+ include ActiveMerchant::Shipping if defined?(ActiveMerchant)
8
+
9
+ attr_accessor :order
10
+
11
+ def initialize(order)
12
+ self.order = order
13
+ end
14
+
15
+ def rates
16
+ return {} unless packages.any?
17
+ @rates ||= {}.tap do |rates|
18
+ response = client.find_rates(origin, destination, packages)
19
+ response.rates.sort_by(&:price).each do |rate|
20
+ rates[rate.service_code] = {
21
+ name: rate.service_name,
22
+ price: rate.price
23
+ }
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+ def client
30
+ raise "Implement #{self.class}#client to return an instance of an ActiveMerchant::Shipping method"
31
+ end
32
+
33
+ def destination
34
+ @destination ||= location_for(order)
35
+ end
36
+
37
+ def location_for(location_object)
38
+ Location.new(
39
+ city: location_object.city,
40
+ state: location_object.state,
41
+ zip: location_object.postal_code,
42
+ country: location_object.country
43
+ )
44
+ end
45
+
46
+ def origin
47
+ @origin ||= location_for(Bodega.config.shipping.origin)
48
+ end
49
+
50
+ def packages
51
+ @packages ||= [].tap do |packages|
52
+ order.products.each do |product|
53
+ packages.push(package_for(product)) if shippable?(product)
54
+ end
55
+ end
56
+ end
57
+
58
+ def package_for(product)
59
+ Package.new(
60
+ product.weight,
61
+ product.dimensions,
62
+ units: Bodega.config.shipping.units
63
+ )
64
+ end
65
+
66
+ def shippable?(product)
67
+ product.respond_to?(:weight) && product.respond_to?(:dimensions)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,18 @@
1
+ require 'bodega/shipping_method/base'
2
+
3
+ module Bodega
4
+ module ShippingMethod
5
+ class UPS < Base
6
+ options :login, :password, :api_key
7
+
8
+ protected
9
+ def client
10
+ @client ||= ActiveMerchant::Shipping::UPS.new(
11
+ login: Bodega.config.ups.login,
12
+ password: Bodega.config.ups.password,
13
+ key: Bodega.config.ups.api_key
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module Bodega
2
+ module ShippingMethod
3
+ autoload :UPS, 'bodega/shipping_method/ups'
4
+ end
5
+ end
data/lib/bodega.rb CHANGED
@@ -1,13 +1,16 @@
1
- require 'bodega/engine'
1
+ require 'bodega/engine' if defined?(Rails)
2
2
  require 'configurator'
3
3
  require 'i18n'
4
4
  require 'money-rails'
5
5
 
6
6
  module Bodega
7
7
  autoload :PaymentMethod, 'bodega/payment_method'
8
+ autoload :ShippingMethod, 'bodega/shipping_method'
8
9
 
9
10
  extend Configurator
10
11
  option :customer_method, :current_user
12
+ option :max_quantity, 1000
13
+
11
14
  # Auto-detect payment method. If a user has the Paypal gem installed,
12
15
  # it'll use that. If a user has the Plinq gem installed, it'll use that.
13
16
  # Otherwise, it'll be all, "HEY I NEED A PAYMENT METHOD" when checkout
@@ -16,6 +19,21 @@ module Bodega
16
19
  defined?(::Plinq) ? :plinq : defined?(::Paypal) ? :paypal : raise("No payment method detected. Please set one using `Bodega.config.payment_method=`")
17
20
  }
18
21
 
22
+ # Defaults to no shipping. Change to :fedex, :ups, or :usps and add
23
+ # `gem "active_shipping"` to gain access to various shipping calculations
24
+ # in the checkout process.
25
+ option :shipping_method, nil
26
+ option :shipping do
27
+ origin do
28
+ city nil
29
+ state nil
30
+ postal_code nil
31
+ country nil
32
+ end
33
+ states []
34
+ units :metric
35
+ end
36
+
19
37
  # Auto-detect test mode. Defaults to true if running in development or test
20
38
  # mode.
21
39
  option :test_mode, lambda { Rails.env.development? || Rails.env.test? }
@@ -0,0 +1,12 @@
1
+ require 'bodega'
2
+ require 'bodega/payment_method/base'
3
+ require 'active_support/core_ext/string/inflections'
4
+
5
+ describe Bodega::PaymentMethod::Base do
6
+ describe ".options" do
7
+ it "defines options on the Bodega configuration instance" do
8
+ described_class.options(:a, :b, :z)
9
+ Bodega.config.base.should_not be_nil
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'bodega'
2
+ require 'bodega/shipping_method/base'
3
+ require 'active_support/core_ext/string/inflections'
4
+
5
+ describe Bodega::PaymentMethod::Base do
6
+ describe ".options" do
7
+ it "defines options on the Bodega configuration instance" do
8
+ described_class.options(:a, :b, :z)
9
+ Bodega.config.base.should_not be_nil
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bodega do
4
+ describe ".config" do
5
+ describe "#payment_method" do
6
+ it "auto-detects Paypal" do
7
+ class Paypal; end
8
+ Bodega.config.payment_method.should == :paypal
9
+ end
10
+ end
11
+
12
+ describe "test_mode" do
13
+ it "auto-detects test mode" do
14
+ Bodega.config.test_mode.should be_true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'bodega/order_product'
3
+
4
+ describe Bodega::OrderProduct do
5
+ let(:product) { TestProduct.create!(product_attrs) }
6
+ let(:product_attrs) { {price: 49.95} }
7
+ let(:order_product) { described_class.new(product: product, quantity: 1) }
8
+
9
+ describe "#identifier" do
10
+ it "returns a friendly identifier" do
11
+ order_product.identifier.should == "TestProduct.1"
12
+ end
13
+ end
14
+
15
+ describe "#name" do
16
+ it "defaults to a human-readable name" do
17
+ order_product.name.should == "Test Product #1"
18
+ end
19
+
20
+ it "delegates to the product" do
21
+ def product.name
22
+ "Ohai"
23
+ end
24
+ order_product.name.should == "Ohai"
25
+ end
26
+ end
27
+
28
+ describe "#quantity_and_name" do
29
+ it "returns the quantity and the name" do
30
+ order_product.quantity_and_name.should == "1 x Test Product #1"
31
+ end
32
+ end
33
+
34
+ describe "#subtotal" do
35
+ it "returns the subtotal for the product quantity" do
36
+ product.stub(:price) { 25.0 }
37
+ order_product.quantity = 2
38
+ order_product.subtotal.should == 50.0
39
+ end
40
+ end
41
+
42
+ describe "for stock-kept products" do
43
+ let(:product_attrs) { {price: 49.95, keep_stock: true, number_in_stock: 1} }
44
+
45
+ it "can't be saved if the product is out-of-stock" do
46
+ product.stub(:in_stock?) { false }
47
+ product.save!
48
+ order_product.save
49
+ order_product.errors[:quantity].first.should == "Sorry, this product is sold out."
50
+ end
51
+
52
+ it "notifies me if my quantity is higher than the number left" do
53
+ order_product.quantity = 2
54
+ order_product.save
55
+ order_product.errors[:quantity].first.should == "There is only one in stock!"
56
+ end
57
+
58
+ it "can't be saved if the quantity is too high" do
59
+ product.stub(:number_in_stock) { 2 }
60
+ order_product.quantity = 3
61
+ order_product.save
62
+ order_product.errors[:quantity].first.should == "There are only 2 in stock!"
63
+ end
64
+
65
+ it "reduces Product#number_in_stock when #update_stock is called" do
66
+ order_product.stub(:order) { OpenStruct.new }
67
+ order_product.save!
68
+ order_product.update_stock
69
+ product.reload.number_in_stock.should == 0
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+ require 'bodega/order'
3
+ require 'bodega/order_product'
4
+ require 'bodega/product'
5
+
6
+ describe Bodega::Order do
7
+ before do
8
+ TestProduct.send :include, Bodega::Product
9
+ end
10
+
11
+ let!(:product_1) { TestProduct.create!(price: 30) }
12
+ let!(:product_2) { TestProduct.create!(price: 25) }
13
+ let(:order) { Bodega::Order.new }
14
+
15
+ describe "#payment_method" do
16
+ require 'bodega'
17
+ require 'bodega/payment_method'
18
+ class Paypal; end
19
+
20
+ it "returns an instance of Bodega::PaymentMethod::Base" do
21
+ order.payment_method.should be_instance_of(Bodega::PaymentMethod::Paypal)
22
+ end
23
+
24
+ it "returns an instance of Bodega::PaymentMethod::Base with a reference to the order" do
25
+ order.payment_method.order.should == order
26
+ end
27
+ end
28
+
29
+ describe "#shipping_method" do
30
+ require 'bodega'
31
+ require 'bodega/shipping_method'
32
+
33
+ before do
34
+ Bodega.config { shipping_method :ups }
35
+ module ActiveMerchant; module Shipping; class UPS; end; end; end
36
+ end
37
+
38
+ it "returns an instance of Bodega::ShippingMethod::Base" do
39
+ order.shipping_method.should be_instance_of(Bodega::ShippingMethod::UPS)
40
+ end
41
+ end
42
+
43
+ describe "#subtotal" do
44
+ let(:cart) do
45
+ {
46
+ "TestProduct.1" => {
47
+ product_type: "TestProduct",
48
+ product_id: "1",
49
+ quantity: "1"
50
+ },
51
+ "TestProduct.2" => {
52
+ product_type: "TestProduct",
53
+ product_id: "2",
54
+ quantity: "2"
55
+ }
56
+ }
57
+ end
58
+
59
+ it "adds up the #order_products subtotals" do
60
+ cart.each do |identifier, item|
61
+ order.update_product(item)
62
+ end
63
+ order.save!
64
+ order.subtotal.should == 80
65
+ end
66
+ end
67
+
68
+ describe "cart management" do
69
+ before { order.save! }
70
+
71
+ it "defaults to quantity 1 when none given" do
72
+ order.update_product(product_type: "TestProduct", product_id: 1)
73
+ order.send(:order_product, "TestProduct.1").quantity.should == 1
74
+ end
75
+
76
+ it "accepts new quantities" do
77
+ order.update_product(product_type: "TestProduct", product_id: 1, quantity: 10)
78
+ order.send(:order_product, "TestProduct.1").quantity.should == 10
79
+ end
80
+
81
+ it "updates old quantities when no new quantity is given" do
82
+ order.update_product(product_type: "TestProduct", product_id: 1, quantity: 10)
83
+ order.update_product(product_type: "TestProduct", product_id: 1)
84
+ order.send(:order_product, "TestProduct.1").quantity.should == 11
85
+ end
86
+
87
+ it "removes products when told to" do
88
+ order.update_product(product_type: "TestProduct", product_id: 1, quantity: 10)
89
+ order.update_product(product_type: "TestProduct", product_id: 1, quantity: 30, remove: "1")
90
+ order.send(:order_product, "TestProduct.1").should be_nil
91
+ end
92
+ end
93
+ end