Skip to content

Commit

Permalink
Merge pull request #81 from friendlycart/allow-updating-goodie-quantity
Browse files Browse the repository at this point in the history
Allow changing quantity for automatic line items
  • Loading branch information
tvdeyen authored Nov 10, 2023
2 parents a28ca37 + 7a1aaa6 commit ef0952d
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,24 @@
module SolidusFriendlyPromotions
module LineItemDecorator
def self.prepended(base)
base.attr_accessor :quantity_setter
base.belongs_to :managed_by_order_action, class_name: "SolidusFriendlyPromotions::PromotionAction", optional: true
base.validate :validate_managed_quantity_same, on: :update
base.after_save :reset_quantity_setter
end

private

def validate_managed_quantity_same
if managed_by_order_action && quantity_changed?
if managed_by_order_action && quantity_changed? && quantity_setter != managed_by_order_action
errors.add(:quantity, :cannot_be_changed_for_automated_items)
end
end

def reset_quantity_setter
@quantity_setter = nil
end

Spree::LineItem.prepend self
Spree::LineItem.prepend SolidusFriendlyPromotions::DiscountableAmount
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ class CreateDiscountedItem < PromotionAction
include OrderLevelAction
preference :variant_id, :integer
preference :quantity, :integer, default: 1
preference :necessary_quantity, :integer, default: 1

def perform(order)
line_item = find_item(order) || create_item(order)
set_quantity(line_item, determine_item_quantity(order))
line_item.current_discounts << discount(line_item)
end

Expand All @@ -24,7 +26,20 @@ def find_item(order)
end

def create_item(order)
order.line_items.create!(quantity: preferred_quantity, variant: variant, managed_by_order_action: self)
order.line_items.create!(quantity: determine_item_quantity(order), variant: variant, managed_by_order_action: self)
end

def determine_item_quantity(order)
applicable_line_items = promotion.applicable_line_items(order)
# Integer division will floor automatically, which is what we want here:
# 1 Item, 2 needed: 1 * 1 / 2 => 0
# 5 items, 2 preferred, 2 needed: 5 / 2 * 2 => 4
applicable_line_items.sum(&:quantity) / preferred_necessary_quantity * preferred_quantity
end

def set_quantity(line_item, quantity)
line_item.quantity_setter = self
line_item.quantity = quantity
end

def variant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<%= form.label :preferred_quantity %>
<%= form.number_field :preferred_quantity, class: "fullwidth" %>
</div>
<div class="field">
<%= form.label :preferred_necessary_quantity %>
<%= form.number_field :preferred_necessary_quantity, class: "fullwidth" %>
</div>
<% end %>

<%= render(
Expand Down
4 changes: 3 additions & 1 deletion promotions/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ en:
solidus_friendly_promotions/actions/adjust_shipment:
description: Creates a promotion credit on matching shipments
solidus_friendly_promotions/actions/create_discounted_item:
description: Creates a discounted item
description: Creates a discounted item with the quantity the applicable line items.
preferred_quantity: Quantity per applicable line item quantity
preferred_necessary_quantity: Number of items needed for a discounted item
solidus_friendly_promotions/rules/first_order:
description: Must be the customer's first order
solidus_friendly_promotions/rules/first_repeat_purchase_since:
Expand Down
16 changes: 16 additions & 0 deletions promotions/spec/models/promotion/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
let(:goodie) { create(:variant, price: 4) }
let(:action) { SolidusFriendlyPromotions::Actions::CreateDiscountedItem.new(preferred_variant_id: goodie.id, calculator: hundred_percent) }
let(:hundred_percent) { SolidusFriendlyPromotions::Calculators::Percent.new(preferred_percent: 100) }
let(:rule) { SolidusFriendlyPromotions::Rules::Product.new(products: [shirt], preferred_line_item_applicable: true) }

it "creates a new discounted line item" do
expect(order.adjustments).to be_empty
Expand All @@ -48,6 +49,21 @@
expect(order.line_items.flat_map(&:adjustments).length).to eq(1)
end

context "when a second base item is added" do
before do
order.contents.add(shirt.master)
end

it "creates a new discounted line item" do
expect(order.adjustments).to be_empty
expect(order.line_items.count).to eq(3)
expect(order.total).to eq(59.97)
expect(order.item_total).to eq(67.97)
expect(order.item_total_before_tax).to eq(59.97)
expect(order.line_items.flat_map(&:adjustments).length).to eq(1)
end
end

context "when the goodie becomes unavailable" do
before do
order.contents.remove(shirt.master)
Expand Down

0 comments on commit ef0952d

Please sign in to comment.