spree_core 2.0.3 → 2.0.4

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/logo/spree_50.png +0 -0
  3. data/app/assets/images/noimage/large.png +0 -0
  4. data/app/assets/images/noimage/mini.png +0 -0
  5. data/app/assets/images/noimage/product.png +0 -0
  6. data/app/assets/images/noimage/small.png +0 -0
  7. data/app/controllers/spree/base_controller.rb +3 -0
  8. data/app/helpers/spree/base_helper.rb +15 -11
  9. data/app/models/spree/adjustment.rb +5 -0
  10. data/app/models/spree/app_configuration.rb +3 -3
  11. data/app/models/spree/calculator/default_tax.rb +2 -2
  12. data/app/models/spree/calculator/percent_per_item.rb +9 -5
  13. data/app/models/spree/calculator.rb +1 -1
  14. data/app/models/spree/credit_card.rb +25 -0
  15. data/app/models/spree/line_item.rb +9 -0
  16. data/app/models/spree/new_adjustment.rb +4 -0
  17. data/app/models/spree/order/checkout.rb +4 -5
  18. data/app/models/spree/order.rb +52 -25
  19. data/app/models/spree/order_contents.rb +8 -7
  20. data/app/models/spree/order_inventory.rb +13 -13
  21. data/app/models/spree/order_populator.rb +4 -14
  22. data/app/models/spree/order_updater.rb +1 -1
  23. data/app/models/spree/payment/processing.rb +5 -0
  24. data/app/models/spree/payment.rb +12 -1
  25. data/app/models/spree/payment_method.rb +1 -4
  26. data/app/models/spree/product.rb +44 -17
  27. data/app/models/spree/promotion/actions/create_adjustment.rb +1 -1
  28. data/app/models/spree/promotion/actions/create_line_items.rb +32 -2
  29. data/app/models/spree/promotion.rb +2 -1
  30. data/app/models/spree/shipment.rb +5 -5
  31. data/app/models/spree/shipping_adjustment.rb +4 -0
  32. data/app/models/spree/shipping_method.rb +6 -0
  33. data/app/models/spree/shipping_rate.rb +1 -0
  34. data/app/models/spree/stock/availability_validator.rb +5 -3
  35. data/app/models/spree/stock/coordinator.rb +16 -4
  36. data/app/models/spree/stock/estimator.rb +16 -6
  37. data/app/models/spree/stock/packer.rb +2 -1
  38. data/app/models/spree/stock_location.rb +16 -6
  39. data/app/models/spree/tax_category.rb +1 -7
  40. data/app/models/spree/tax_rate.rb +1 -0
  41. data/app/models/spree/variant.rb +16 -3
  42. data/app/models/spree/zone.rb +1 -1
  43. data/config/initializers/user_class_extensions.rb +1 -1
  44. data/config/locales/en.yml +15 -1
  45. data/db/migrate/20130228210442_create_shipping_method_zone.rb +6 -1
  46. data/db/migrate/20130306181701_add_address_fields_to_stock_location.rb +4 -1
  47. data/db/migrate/20130515180736_add_backorderable_default_to_spree_stock_location.rb +5 -0
  48. data/db/migrate/20130516151222_add_propage_all_variants_to_spree_stock_location.rb +5 -0
  49. data/db/migrate/20130626232741_add_cvv_result_code_and_cvv_result_message_to_spree_payments.rb +6 -0
  50. data/db/migrate/20130628021056_add_unique_index_to_permalink_on_spree_products.rb +5 -0
  51. data/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb +7 -0
  52. data/db/migrate/20130708052307_add_deleted_at_to_spree_tax_rates.rb +5 -0
  53. data/db/migrate/20130711200933_remove_lock_version_from_inventory_units.rb +6 -0
  54. data/db/migrate/20130718042445_add_cost_price_to_line_item.rb +5 -0
  55. data/db/migrate/20130718233855_set_backorderable_to_default_to_false.rb +6 -0
  56. data/db/migrate/20130725031716_add_created_by_id_to_spree_orders.rb +5 -0
  57. data/db/migrate/20130729214043_index_completed_at_on_spree_orders.rb +5 -0
  58. data/db/migrate/20130802014537_add_tax_category_id_to_spree_line_items.rb +5 -0
  59. data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +9 -0
  60. data/db/migrate/20130805043440_create_spree_new_adjustments.rb +8 -0
  61. data/lib/generators/spree/dummy/templates/rails/database.yml +8 -7
  62. data/lib/generators/spree/install/install_generator.rb +1 -1
  63. data/lib/spree/core/calculated_adjustments.rb +12 -1
  64. data/lib/spree/core/controller_helpers/order.rb +5 -3
  65. data/lib/spree/core/controller_helpers/search.rb +14 -0
  66. data/lib/spree/core/permalinks.rb +13 -13
  67. data/lib/spree/core/s3_support.rb +1 -1
  68. data/lib/spree/core/version.rb +1 -1
  69. data/lib/spree/core.rb +7 -5
  70. data/lib/spree/i18n/base.rb +17 -0
  71. data/lib/spree/i18n/initializer.rb +1 -0
  72. data/lib/spree/i18n.rb +28 -7
  73. data/lib/spree/money.rb +2 -0
  74. data/lib/spree/testing_support/authorization_helpers.rb +6 -15
  75. data/lib/spree/testing_support/capybara_ext.rb +20 -11
  76. data/lib/spree/testing_support/common_rake.rb +13 -0
  77. data/lib/spree/testing_support/factories/country_factory.rb +1 -1
  78. data/lib/spree/testing_support/factories/order_factory.rb +0 -2
  79. data/lib/spree/testing_support/factories/payment_method_factory.rb +1 -1
  80. data/lib/spree/testing_support/factories/product_factory.rb +8 -18
  81. data/lib/spree/testing_support/factories/return_authorization_factory.rb +4 -0
  82. data/lib/spree/testing_support/factories/shipment_factory.rb +1 -1
  83. data/lib/spree/testing_support/factories/stock_item_factory.rb +2 -1
  84. data/lib/spree/testing_support/factories/stock_location_factory.rb +5 -2
  85. data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
  86. data/lib/spree/testing_support/order_walkthrough.rb +14 -1
  87. data/vendor/assets/javascripts/jquery.validate/localization/messages_et.js +23 -0
  88. data/vendor/assets/javascripts/jquery.validate/localization/messages_eu.js +25 -0
  89. data/vendor/assets/javascripts/jquery.validate/localization/messages_hr.js +25 -0
  90. data/vendor/assets/javascripts/jquery.validate/localization/messages_ka.js +25 -0
  91. data/vendor/assets/javascripts/jquery.validate/localization/messages_ko.js +25 -0
  92. data/vendor/assets/javascripts/jquery.validate/localization/messages_my.js +25 -0
  93. data/vendor/assets/javascripts/jquery.validate/localization/messages_pt_BR.js +26 -0
  94. data/vendor/assets/javascripts/jquery.validate/localization/messages_pt_PT.js +26 -0
  95. data/vendor/assets/javascripts/jquery.validate/localization/messages_sl.js +25 -0
  96. data/vendor/assets/javascripts/jquery.validate/localization/messages_sv.js +23 -0
  97. data/vendor/assets/javascripts/jquery.validate/localization/messages_uk.js +25 -0
  98. data/vendor/assets/javascripts/jquery.validate/localization/messages_zh.js +25 -0
  99. data/vendor/assets/javascripts/jquery.validate/localization/messages_zh_TW.js +26 -0
  100. metadata +118 -67
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed8c2bb0d1d4f097b6846f78ba702a63d4db3b3f
4
- data.tar.gz: daa9817909d9e8867c3ab1df1d9f975f5118afdd
3
+ metadata.gz: b435838b2a77628006e2e2885f5dbe2039958630
4
+ data.tar.gz: 1df2bcec2ac50c9d4716017752eb8c56ab2f9960
5
5
  SHA512:
6
- metadata.gz: c79a195b6bc5781a8e1ea6551eb7adbf21f94c1ebf641e86db28407355bbbddeba7e133e972971e43dcebbf593822fa015a60ea53d9b6f24ea402bc264853737
7
- data.tar.gz: 19d02ac7c62b7b1e70a2c585a6bdae432ccf9c2d1bf5678459882506f2bc5e9962f459b34aff64f8aeb8968ef7b3274c1f9871be482de13b93dd1da0482a7553
6
+ metadata.gz: 1154f9c96163b14b0f85379e73718b6e5a95a6b60688399df8b724e109880d1e21deb4dbd77d44ae8dd29fe1cd98bd563d74c6ce191ac89eff57424dba437602
7
+ data.tar.gz: 5d008b1beae9dc20bf209bcc59063debee39ae36c6426569f970af0aad14b64287b61f9bed6454190e694ce96cb9b145be04b15066bc8abc80da9fb3c91c21fe
Binary file
Binary file
Binary file
Binary file
@@ -5,6 +5,9 @@ class Spree::BaseController < ApplicationController
5
5
  include Spree::Core::ControllerHelpers::RespondWith
6
6
  include Spree::Core::ControllerHelpers::SSL
7
7
  include Spree::Core::ControllerHelpers::Common
8
+ include Spree::Core::ControllerHelpers::Search
8
9
 
9
10
  respond_to :html
10
11
  end
12
+
13
+ require 'spree/i18n/initializer'
@@ -165,13 +165,6 @@ module Spree
165
165
  end
166
166
  end
167
167
 
168
- def t(*args)
169
- puts "WARNING: Spree's translations are now scoped to a 'spree' namespace. Please use the Spree.t helper."
170
- puts "Called from: #{caller[0]}"
171
- I18n.t(*args)
172
- end
173
-
174
-
175
168
  private
176
169
 
177
170
  # Returns style of image or nil
@@ -182,15 +175,26 @@ module Spree
182
175
  end
183
176
  end
184
177
 
178
+ def create_product_image_tag(image, product, options, style)
179
+ options.reverse_merge! alt: image.alt.blank? ? product.name : image.alt
180
+ image_tag image.attachment.url(style), options
181
+ end
182
+
185
183
  def define_image_method(style)
186
184
  self.class.send :define_method, "#{style}_image" do |product, *options|
187
185
  options = options.first || {}
188
186
  if product.images.empty?
189
- image_tag "noimage/#{style}.png", options
187
+ if !product.is_a?(Spree::Variant) && !product.variant_images.empty?
188
+ create_product_image_tag(product.variant_images.first, product, options, style)
189
+ else
190
+ if product.is_a?(Variant) && !product.product.variant_images.empty?
191
+ create_product_image_tag(product.product.variant_images.first, product, options, style)
192
+ else
193
+ image_tag "noimage/#{style}.png", options
194
+ end
195
+ end
190
196
  else
191
- image = product.images.first
192
- options.reverse_merge! alt: image.alt.blank? ? product.name : image.alt
193
- image_tag image.attachment.url(style), options
197
+ create_product_image_tag(product.images.first, product, options, style)
194
198
  end
195
199
  end
196
200
  end
@@ -58,6 +58,7 @@ module Spree
58
58
  scope :charge, -> { where('amount >= 0') }
59
59
  scope :credit, -> { where('amount < 0') }
60
60
  scope :promotion, -> { where(originator_type: 'Spree::PromotionAction') }
61
+ scope :return_authorization, -> { where(source_type: "Spree::ReturnAuthorization") }
61
62
 
62
63
  # Update the boolean _eligible_ attribute which determines which adjustments
63
64
  # count towards the order's adjustment_total.
@@ -82,6 +83,10 @@ module Spree
82
83
  # record from db for the association
83
84
  def update!
84
85
  return if immutable?
86
+ # Fix for #3381
87
+ # If we attempt to call 'source' before the reload, then source is currently
88
+ # the order object. After calling a reload, the source is the Shipment.
89
+ reload
85
90
  originator.update_adjustment(self, source) if originator.present?
86
91
  set_eligibility
87
92
  end
@@ -22,7 +22,7 @@ module Spree
22
22
 
23
23
  # Alphabetized to more easily lookup particular preferences
24
24
  preference :address_requires_state, :boolean, default: true # should state/state_name be required
25
- preference :admin_interface_logo, :string, default: 'admin/bg/spree_50.png'
25
+ preference :admin_interface_logo, :string, default: 'logo/spree_50.png'
26
26
  preference :admin_products_per_page, :integer, default: 10
27
27
  preference :allow_backorder_shipping, :boolean, default: false # should only be true if you don't need to track inventory
28
28
  preference :allow_checkout_on_gateway_error, :boolean, default: false
@@ -51,7 +51,7 @@ module Spree
51
51
  preference :hide_cents, :boolean, default: false
52
52
  preference :last_check_for_spree_alerts, :string, default: nil
53
53
  preference :layout, :string, default: 'spree/layouts/spree_application'
54
- preference :logo, :string, default: 'admin/bg/spree_50.png'
54
+ preference :logo, :string, default: 'logo/spree_50.png'
55
55
  preference :max_level_in_taxons_menu, :integer, default: 1 # maximum nesting level in taxons menu
56
56
  preference :orders_per_page, :integer, default: 15
57
57
  preference :prices_inc_tax, :boolean, default: false
@@ -68,7 +68,7 @@ module Spree
68
68
  preference :site_name, :string, default: 'Spree Demo Site'
69
69
  preference :site_url, :string, default: 'demo.spreecommerce.com'
70
70
  preference :tax_using_ship_address, :boolean, default: true
71
- preference :track_inventory_levels, :boolean, default: true # will not track on_hand values for variants /products
71
+ preference :track_inventory_levels, :boolean, default: true # Determines whether to track on_hand values for variants / products.
72
72
 
73
73
  # Preferences related to image settings
74
74
  preference :attachment_default_url, :string, default: '/spree/products/:id/:style/:basename.:extension'
@@ -24,7 +24,7 @@ module Spree
24
24
 
25
25
  def compute_order(order)
26
26
  matched_line_items = order.line_items.select do |line_item|
27
- line_item.product.tax_category == rate.tax_category
27
+ line_item.tax_category == rate.tax_category
28
28
  end
29
29
 
30
30
  line_items_total = matched_line_items.sum(&:total)
@@ -32,7 +32,7 @@ module Spree
32
32
  end
33
33
 
34
34
  def compute_line_item(line_item)
35
- if line_item.product.tax_category == rate.tax_category
35
+ if line_item.tax_category == rate.tax_category
36
36
  if rate.included_in_price
37
37
  deduced_total_by_rate(line_item.total, rate)
38
38
  else
@@ -1,10 +1,10 @@
1
1
  module Spree
2
2
 
3
3
  # A calculator for promotions that calculates a percent-off discount
4
- # for all matching products in an order. This should not be used as a
4
+ # for all matching products in an order. This should not be used as a
5
5
  # shipping calculator since it would be the same thing as a flat percent
6
6
  # off the entire order.
7
-
7
+
8
8
  class Calculator::PercentPerItem < Calculator
9
9
  preference :percent, :decimal, :default => 0
10
10
 
@@ -23,10 +23,14 @@ module Spree
23
23
 
24
24
  private
25
25
 
26
- # Returns all products that match the promotion's rule.
26
+ # Returns all products that match this calculator, but only if the calculator
27
+ # is attached to a promotion. If attached to a ShippingMethod, nil is returned.
28
+ # Copied from per_item.rb
27
29
  def matching_products
28
- @matching_products ||= if compute_on_promotion?
29
- self.calculable.promotion.rules.map(&:products).flatten
30
+ if compute_on_promotion?
31
+ self.calculable.promotion.rules.map do |rule|
32
+ rule.respond_to?(:products) ? rule.products : []
33
+ end.flatten
30
34
  end
31
35
  end
32
36
 
@@ -21,7 +21,7 @@ module Spree
21
21
 
22
22
  # Returns all calculators applicable for kind of work
23
23
  def self.calculators
24
- Rails.application.config.spree.calculators.all
24
+ Rails.application.config.spree.calculators
25
25
  end
26
26
 
27
27
  def to_s
@@ -10,6 +10,7 @@ module Spree
10
10
  validates :month, :year, numericality: { only_integer: true }
11
11
  validates :number, presence: true, unless: :has_payment_profile?, on: :create
12
12
  validates :verification_value, presence: true, unless: :has_payment_profile?, on: :create
13
+ validate :expiry_not_in_the_past
13
14
 
14
15
  attr_accessible :first_name, :last_name, :number, :verification_value, :year,
15
16
  :month, :gateway_customer_profile_id, :gateway_payment_profile_id
@@ -30,6 +31,19 @@ module Spree
30
31
  end
31
32
  end
32
33
 
34
+ # Some payment gateways, such as USA EPay, only support an ActiveMerchant::Billing::CreditCard
35
+ # object, rather than an object *like* that. So we need to convert it.
36
+ def to_active_merchant
37
+ ActiveMerchant::Billing::CreditCard.new(
38
+ :number => number,
39
+ :month => month,
40
+ :year => year,
41
+ :verification_value => verification_value,
42
+ :first_name => first_name,
43
+ :last_name => last_name
44
+ )
45
+ end
46
+
33
47
  # sets self.cc_type while we still have the card number
34
48
  def set_card_type
35
49
  self.cc_type ||= CardDetector.brand?(number)
@@ -87,5 +101,16 @@ module Spree
87
101
  return 'visa' if Rails.env.development?
88
102
  cc_type
89
103
  end
104
+
105
+ private
106
+
107
+ def expiry_not_in_the_past
108
+ if year && month
109
+ time = "#{year}-#{month}-1".to_time
110
+ if time < Time.zone.now.beginning_of_month
111
+ errors.add(:base, :card_expired)
112
+ end
113
+ end
114
+ end
90
115
  end
91
116
  end
@@ -3,11 +3,13 @@ module Spree
3
3
  before_validation :adjust_quantity
4
4
  belongs_to :order, class_name: "Spree::Order"
5
5
  belongs_to :variant, class_name: "Spree::Variant"
6
+ belongs_to :tax_category, class_name: "Spree::TaxCategory"
6
7
 
7
8
  has_one :product, through: :variant
8
9
  has_many :adjustments, as: :adjustable, dependent: :destroy
9
10
 
10
11
  before_validation :copy_price
12
+ before_validation :copy_tax_category
11
13
 
12
14
  validates :variant, presence: true
13
15
  validates :quantity, numericality: {
@@ -30,10 +32,17 @@ module Spree
30
32
  def copy_price
31
33
  if variant
32
34
  self.price = variant.price if price.nil?
35
+ self.cost_price = variant.cost_price if cost_price.nil?
33
36
  self.currency = variant.currency if currency.nil?
34
37
  end
35
38
  end
36
39
 
40
+ def copy_tax_category
41
+ if variant
42
+ self.tax_category = variant.product.tax_category
43
+ end
44
+ end
45
+
37
46
  def increment_quantity
38
47
  ActiveSupport::Deprecation.warn("[SPREE] Spree::LineItem#increment_quantity will be deprecated in Spree 2.1, please use quantity.increment! instead.")
39
48
  self.quantity.increment!
@@ -0,0 +1,4 @@
1
+ module Spree
2
+ class NewAdjustment < ActiveRecord::Base
3
+ end
4
+ end
@@ -63,15 +63,14 @@ module Spree
63
63
  transition :to => :awaiting_return
64
64
  end
65
65
 
66
+
66
67
  before_transition :to => :complete do |order|
67
- begin
68
- order.process_payments! if order.payment_required?
69
- rescue Spree::Core::GatewayError
70
- !!Spree::Config[:allow_checkout_on_gateway_error]
71
- end
68
+ order.process_payments! if order.payment_required?
72
69
  end
70
+ before_transition :from => :cart, :do => :ensure_line_items_present
73
71
 
74
72
  before_transition :to => :delivery, :do => :create_proposed_shipments
73
+ before_transition :to => :delivery, :do => :ensure_available_shipping_rates
75
74
 
76
75
  after_transition :to => :complete, :do => :finalize!
77
76
  after_transition :to => :delivery, :do => :create_tax_charge!
@@ -20,9 +20,7 @@ module Spree
20
20
  order.payment_required?
21
21
  }
22
22
  go_to_state :confirm, if: ->(order) { order.confirmation_required? }
23
- go_to_state :complete, if: ->(order) {
24
- (order.payment_required? && order.has_unprocessed_payments?) || !order.payment_required?
25
- }
23
+ go_to_state :complete
26
24
  remove_transition from: :delivery, to: :confirm
27
25
  end
28
26
 
@@ -30,16 +28,17 @@ module Spree
30
28
 
31
29
  attr_accessible :line_items, :bill_address_attributes, :ship_address_attributes,
32
30
  :payments_attributes, :ship_address, :bill_address, :currency,
33
- :payments_attributes, :line_items_attributes, :number, :email,
34
- :use_billing, :special_instructions, :shipments_attributes,
35
- :coupon_code
31
+ :line_items_attributes, :number, :email, :use_billing,
32
+ :special_instructions, :shipments_attributes, :coupon_code
36
33
 
37
34
  attr_reader :coupon_code
38
35
 
39
36
  if Spree.user_class
40
37
  belongs_to :user, class_name: Spree.user_class.to_s
38
+ belongs_to :created_by, class_name: Spree.user_class.to_s
41
39
  else
42
40
  belongs_to :user
41
+ belongs_to :created_by
43
42
  end
44
43
 
45
44
  belongs_to :bill_address, foreign_key: :bill_address_id, class_name: 'Spree::Address'
@@ -49,17 +48,21 @@ module Spree
49
48
  alias_attribute :shipping_address, :ship_address
50
49
 
51
50
  has_many :state_changes, as: :stateful
52
- has_many :line_items, dependent: :destroy, order: 'created_at ASC'
53
- has_many :payments, dependent: :destroy
51
+ has_many :line_items, dependent: :destroy, order: "#{Spree::LineItem.table_name}.created_at ASC"
52
+ has_many :payments, dependent: :destroy, :class_name => "Spree::Payment"
54
53
 
55
- has_many :shipments, dependent: :destroy do
54
+ has_many :shipments, dependent: :destroy, :class_name => "Shipment" do
56
55
  def states
57
56
  pluck(:state).uniq
58
57
  end
59
58
  end
60
59
 
61
60
  has_many :return_authorizations, dependent: :destroy
62
- has_many :adjustments, as: :adjustable, dependent: :destroy, order: 'created_at ASC'
61
+ has_many :adjustments,
62
+ as: :adjustable,
63
+ dependent: :destroy,
64
+ order: "#{Spree::Adjustment.table_name}.created_at ASC",
65
+ inverse_of: :source
63
66
 
64
67
  accepts_nested_attributes_for :line_items
65
68
  accepts_nested_attributes_for :bill_address
@@ -175,13 +178,6 @@ module Spree
175
178
  payments.map(&:payment_method).compact.any?(&:payment_profiles_supported?)
176
179
  end
177
180
 
178
- # Used by the checkout state machine to check for unprocessed payments
179
- # The Order should be unable to proceed to complete if there are unprocessed
180
- # payments and there is payment required.
181
- def has_unprocessed_payments?
182
- payments.with_state('checkout').reload.exists?
183
- end
184
-
185
181
  # Indicates the number of items in the order
186
182
  def item_count
187
183
  line_items.inject(0) { |sum, li| sum + li.quantity }
@@ -406,7 +402,7 @@ module Spree
406
402
 
407
403
  # Helper methods for checkout steps
408
404
  def paid?
409
- payment_state == 'paid'
405
+ payment_state == 'paid' || payment_state == 'credit_owed'
410
406
  end
411
407
 
412
408
  def available_payment_methods
@@ -417,8 +413,23 @@ module Spree
417
413
  payments.select(&:checkout?)
418
414
  end
419
415
 
416
+ # processes any pending payments and must return a boolean as it's
417
+ # return value is used by the checkout state_machine to determine
418
+ # success or failure of the 'complete' event for the order
419
+ #
420
+ # Returns:
421
+ # - true if all pending_payments processed successfully
422
+ # - true if a payment failed, ie. raised a GatewayError
423
+ # which gets rescued and converted to TRUE when
424
+ # :allow_checkout_gateway_error is set to true
425
+ # - false if a payment failed, ie. raised a GatewayError
426
+ # which gets rescued and converted to FALSE when
427
+ # :allow_checkout_on_gateway_error is set to false
428
+ #
420
429
  def process_payments!
421
- begin
430
+ if pending_payments.empty?
431
+ raise Core::GatewayError.new Spree.t(:no_pending_payments)
432
+ else
422
433
  pending_payments.each do |payment|
423
434
  break if payment_total >= total
424
435
 
@@ -428,9 +439,10 @@ module Spree
428
439
  self.payment_total += payment.amount
429
440
  end
430
441
  end
431
- rescue Core::GatewayError
432
- !!Spree::Config[:allow_checkout_on_gateway_error]
433
442
  end
443
+ rescue Core::GatewayError => e
444
+ result = !!Spree::Config[:allow_checkout_on_gateway_error]
445
+ errors.add(:base, e.message) and return result
434
446
  end
435
447
 
436
448
  def billing_firstname
@@ -504,10 +516,13 @@ module Spree
504
516
  end
505
517
 
506
518
  # Tells us if there if the specified promotion is already associated with the order
507
- # regardless of whether or not its currently eligible. Useful because generally
508
- # you would only want a promotion to apply to order no more than once.
509
- def promotion_credit_exists?(promotion)
510
- !! adjustments.promotion.reload.detect { |credit| credit.originator.promotion.id == promotion.id }
519
+ # regardless of whether or not its currently eligible. Useful because generally
520
+ # you would only want a promotion action to apply to order no more than once.
521
+ #
522
+ # Receives an adjustment +originator+ (here a PromotionAction object) and tells
523
+ # if the order has adjustments from that already
524
+ def promotion_credit_exists?(originator)
525
+ !! adjustments.promotion.reload.detect { |credit| credit.originator.id == originator.id }
511
526
  end
512
527
 
513
528
  def promo_total
@@ -540,6 +555,12 @@ module Spree
540
555
  return true unless new_record? or state == 'cart'
541
556
  end
542
557
 
558
+ def ensure_line_items_present
559
+ unless line_items.present?
560
+ errors.add(:base, Spree.t(:there_are_no_items_for_this_order)) and return false
561
+ end
562
+ end
563
+
543
564
  def has_available_shipment
544
565
  return unless has_step?("delivery")
545
566
  return unless address?
@@ -547,6 +568,12 @@ module Spree
547
568
  # errors.add(:base, :no_shipping_methods_available) if available_shipping_methods.empty?
548
569
  end
549
570
 
571
+ def ensure_available_shipping_rates
572
+ if shipments.empty? || shipments.any? { |shipment| shipment.shipping_rates.blank? }
573
+ errors.add(:base, Spree.t(:items_cannot_be_shipped)) and return false
574
+ end
575
+ end
576
+
550
577
  def has_available_payment
551
578
  return unless delivery?
552
579
  # errors.add(:base, :no_payment_methods_available) if available_payment_methods.empty?
@@ -6,21 +6,22 @@ module Spree
6
6
  @order = order
7
7
  end
8
8
 
9
+ # Get current line item for variant if exists
10
+ # Add variant qty to line_item
9
11
  def add(variant, quantity, currency=nil, shipment=nil)
10
- #get current line item for variant if exists
11
12
  line_item = order.find_line_item_by_variant(variant)
12
-
13
- #add variant qty to line_item
14
13
  add_to_line_item(line_item, variant, quantity, currency, shipment)
15
14
  end
16
15
 
16
+ # Get current line item for variant
17
+ # Remove variant qty from line_item
17
18
  def remove(variant, quantity, shipment=nil)
18
- #get current line item for variant
19
19
  line_item = order.find_line_item_by_variant(variant)
20
20
 
21
- #TODO raise exception if line_item is nil
21
+ unless line_item
22
+ raise ActiveRecord::RecordNotFound, "Line item not found for variant #{variant.sku}"
23
+ end
22
24
 
23
- #remove variant qty from line_item
24
25
  remove_from_line_item(line_item, variant, quantity, shipment)
25
26
  end
26
27
 
@@ -29,7 +30,7 @@ module Spree
29
30
  def add_to_line_item(line_item, variant, quantity, currency=nil, shipment=nil)
30
31
  if line_item
31
32
  line_item.target_shipment = shipment
32
- line_item.quantity += quantity
33
+ line_item.quantity += quantity.to_i
33
34
  line_item.currency = currency unless currency.nil?
34
35
  line_item.save
35
36
  else
@@ -6,10 +6,13 @@ module Spree
6
6
  @order = order
7
7
  end
8
8
 
9
- # Only verify inventory for completed orders
10
- # as carts have inventory assigned via create_proposed_shipment methh
9
+ # Only verify inventory for completed orders (as orders in frontend checkout
10
+ # have inventory assigned via +order.create_proposed_shipment+) or when
11
+ # shipment is explicitly passed
11
12
  #
12
- # or when shipment is explicitly passed
13
+ # In case shipment is passed the stock location should only unstock or
14
+ # restock items if the order is completed. That is so because stock items
15
+ # are always unstocked when the order is completed through +shipment.finalize+
13
16
  def verify(line_item, shipment = nil)
14
17
  if order.completed? || shipment.present?
15
18
 
@@ -51,7 +54,6 @@ module Spree
51
54
  #
52
55
  # first unshipped that already includes this variant
53
56
  # first unshipped that's leaving from a stock_location that stocks this variant
54
- #
55
57
  def determine_target_shipment(variant)
56
58
  shipment = order.shipments.detect do |shipment|
57
59
  (shipment.ready? || shipment.pending?) && shipment.include?(variant)
@@ -63,7 +65,6 @@ module Spree
63
65
  end
64
66
 
65
67
  def add_to_shipment(shipment, variant, quantity)
66
- #create inventory_units
67
68
  on_hand, back_order = shipment.stock_location.fill_status(variant, quantity)
68
69
 
69
70
  on_hand.times do
@@ -76,11 +77,11 @@ module Spree
76
77
  state: 'backordered'}, without_protection: true)
77
78
  end
78
79
 
79
-
80
80
  # adding to this shipment, and removing from stock_location
81
- shipment.stock_location.unstock variant, quantity, shipment
81
+ if order.completed?
82
+ shipment.stock_location.unstock(variant, quantity, shipment)
83
+ end
82
84
 
83
- # return quantity added
84
85
  quantity
85
86
  end
86
87
 
@@ -99,14 +100,13 @@ module Spree
99
100
  removed_quantity += 1
100
101
  end
101
102
 
102
- if shipment.inventory_units.count == 0
103
- shipment.destroy
104
- end
103
+ shipment.destroy if shipment.inventory_units.count == 0
105
104
 
106
105
  # removing this from shipment, and adding to stock_location
107
- shipment.stock_location.restock variant, removed_quantity, shipment
106
+ if order.completed?
107
+ shipment.stock_location.restock variant, removed_quantity, shipment
108
+ end
108
109
 
109
- # return quantity removed
110
110
  removed_quantity
111
111
  end
112
112
  end
@@ -46,22 +46,12 @@ module Spree
46
46
 
47
47
  variant = Spree::Variant.find(variant_id)
48
48
  if quantity > 0
49
- if check_stock_levels(variant, quantity)
50
- @order.contents.add(variant, quantity, currency)
49
+ line_item = @order.contents.add(variant, quantity, currency)
50
+ unless line_item.valid?
51
+ errors.add(:base, line_item.errors.messages.values.join(" "))
52
+ return false
51
53
  end
52
54
  end
53
55
  end
54
-
55
- def check_stock_levels(variant, quantity)
56
- display_name = %Q{#{variant.name}}
57
- display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank?
58
-
59
- if Stock::Quantifier.new(variant).can_supply? quantity
60
- true
61
- else
62
- errors.add(:base, Spree.t(:out_of_stock, :scope => :order_populator, :item => display_name.inspect))
63
- return false
64
- end
65
- end
66
56
  end
67
57
  end
@@ -131,7 +131,7 @@ module Spree
131
131
  # This promotion provides the most discount, and if two promotions
132
132
  # have the same amount, then it will pick the latest one.
133
133
  def choose_best_promotion_adjustment
134
- if best_promotion_adjustment = order.adjustments.promotion.reorder("amount ASC, created_at DESC").first
134
+ if best_promotion_adjustment = order.adjustments.promotion.eligible.reorder("amount ASC, created_at DESC").first
135
135
  other_promotions = order.adjustments.promotion.where("id NOT IN (?)", best_promotion_adjustment.id)
136
136
  other_promotions.update_all(eligible: false)
137
137
  end
@@ -154,6 +154,11 @@ module Spree
154
154
  unless response.authorization.nil?
155
155
  self.response_code = response.authorization
156
156
  self.avs_response = response.avs_result['code']
157
+
158
+ if response.cvv_result
159
+ self.cvv_response_code = response.cvv_result['code']
160
+ self.cvv_response_message = response.cvv_result['message']
161
+ end
157
162
  end
158
163
  self.send("#{success_state}!")
159
164
  else
@@ -2,12 +2,13 @@ module Spree
2
2
  class Payment < ActiveRecord::Base
3
3
  include Spree::Payment::Processing
4
4
  belongs_to :order, class_name: 'Spree::Order'
5
- belongs_to :source, polymorphic: true, validate: true
5
+ belongs_to :source, polymorphic: true
6
6
  belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
7
7
 
8
8
  has_many :offsets, class_name: "Spree::Payment", foreign_key: :source_id, conditions: "source_type = 'Spree::Payment' AND amount < 0 AND state = 'completed'"
9
9
  has_many :log_entries, as: :source
10
10
 
11
+ before_validation :validate_source
11
12
  before_save :set_unique_identifier
12
13
 
13
14
  after_save :create_payment_profile, if: :profiles_supported?
@@ -105,6 +106,16 @@ module Spree
105
106
 
106
107
  private
107
108
 
109
+ def validate_source
110
+ if source && !source.valid?
111
+ source.errors.each do |field, error|
112
+ field_name = I18n.t("activerecord.attributes.#{source.class.to_s.underscore}.#{field}")
113
+ self.errors.add(Spree.t(source.class.to_s.demodulize.underscore), "#{field_name} #{error}")
114
+ end
115
+ end
116
+ return !errors.present?
117
+ end
118
+
108
119
  def profiles_supported?
109
120
  payment_method.respond_to?(:payment_profiles_supported?) && payment_method.payment_profiles_supported?
110
121
  end
@@ -1,5 +1,6 @@
1
1
  module Spree
2
2
  class PaymentMethod < ActiveRecord::Base
3
+ acts_as_paranoid
3
4
  DISPLAY = [:both, :front_end, :back_end]
4
5
  default_scope where(deleted_at: nil)
5
6
 
@@ -39,10 +40,6 @@ module Spree
39
40
  type.demodulize.downcase
40
41
  end
41
42
 
42
- def destroy
43
- touch :deleted_at
44
- end
45
-
46
43
  def self.find_with_destroyed *args
47
44
  self.with_exclusive_scope { find(*args) }
48
45
  end