spree_core 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
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