Skip to content

Commit

Permalink
Merge pull request #312 from gms-electronics/subscription_api_fix_for…
Browse files Browse the repository at this point in the history
…_subscribable_product

Subscription api fix for subscribable product
  • Loading branch information
kennyadsl authored Jan 16, 2025
2 parents f78e322 + 188fe8e commit e76903d
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 41 deletions.
7 changes: 7 additions & 0 deletions app/models/solidus_subscriptions/line_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,12 @@ class LineItem < ApplicationRecord
validates :subscribable_id, presence: true
validates :quantity, numericality: { greater_than: 0 }
validates :interval_length, numericality: { greater_than: 0 }, unless: -> { subscription }
validate :ensure_subscribable_valid

def ensure_subscribable_valid
return unless subscribable && subscribable.subscribable != true

errors.add(:subscribable, :cannot_subscribe)
end
end
end
3 changes: 1 addition & 2 deletions app/models/solidus_subscriptions/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,11 @@ def emit_events_for_update
end

def self.ransackable_attributes(_auth_object = nil)
%w[actionable_date created_at end_date state updated_at user_id]
%w[actionable_date created_at end_date state updated_at user_id]
end

def self.ransackable_associations(_auth_object = nil)
%w[events user]
end

end
end
4 changes: 4 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,7 @@ en:
not_active: "cannot pause/resume a subscription which is not active"
state:
cannot_skip: cannot skip a subscription which is canceled or inactive
solidus_subscriptions/line_item:
attributes:
subscribable:
cannot_subscribe: "The requested item cannot be subscribed"
2 changes: 2 additions & 0 deletions db/migrate/20210323165714_update_promotion_rule_names.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class UpdatePromotionRuleNames < ActiveRecord::Migration[5.2]
}.freeze

def change
return unless Object.const_defined?("Spree::Promotion")

reversible do |dir|
dir.up do
TYPE_RENAMES.each do |old_type, new_type|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def copy_starter_frontend_files
RUBY
end

inject_into_file 'app/views/cart_line_items/_product_variants.html.erb',
" \"data-subscribable\" => variant.subscribable,\n",
before: " \"data-price\" => variant.price_for_options(current_pricing_options)&.money&.to_html\n"
end

def add_migrations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module CreateSubscription
include SolidusSubscriptions::SubscriptionLineItemBuilder

included do
after_action :handle_subscription_line_items, only: :create, if: ->{ params[:subscription_line_item] }
after_action :handle_subscription_line_items, only: :create, if: :valid_subscription_line_item_params?
end

private
Expand All @@ -14,4 +14,9 @@ def handle_subscription_line_items
line_item = @current_order.line_items.find_by(variant_id: params[:variant_id])
create_subscription_line_item(line_item)
end

def valid_subscription_line_item_params?
subscription_params = params[:subscription_line_item]
%i[subscribable_id quantity interval_length].all? { |key| subscription_params[key].present? }
end
end
Original file line number Diff line number Diff line change
@@ -1,39 +1,52 @@
<% if @product.subscribable %>
<%= content_tag :h3, t('.subscription_fields') %>
<%= fields_for :'subscription_line_item', SolidusSubscriptions::LineItem.new do |ff| %>
<div>
<%= ff.label :quantity, t('.quantity') %>
<%= ff.number_field :quantity %>
<%= ff.label :quantity, t('.quantity_suffix') %>
</div>

<div>
<%= ff.label :interval_length, t('.interval_length') %>
<%= ff.number_field :interval_length %>

<%= ff.collection_radio_buttons :interval_units, SolidusSubscriptions::LineItem.interval_units.to_a, :first, :first %>
</div>

<%= ff.hidden_field :subscribable_id %>
<div class="subscription-form">
<% if @product.subscribable %>
<%= content_tag :h3, t('.subscription_fields') %>
<%= fields_for :'subscription_line_item', SolidusSubscriptions::LineItem.new do |ff| %>
<div>
<%= ff.label :quantity, t('.quantity') %>
<%= ff.number_field :quantity %>
<%= ff.label :quantity, t('.quantity_suffix') %>
</div>

<div>
<%= ff.label :interval_length, t('.interval_length') %>
<%= ff.number_field :interval_length %>

<%= ff.collection_radio_buttons :interval_units, SolidusSubscriptions::LineItem.interval_units.to_a, :first, :first %>
</div>

<%= ff.hidden_field :subscribable_id %> <!-- Hidden field for subscribable_id -->
<% end %>
<% end %>
<% end %>
</div>

<script>
document.addEventListener("DOMContentLoaded", function(e) {
document.addEventListener("DOMContentLoaded", function() {
var cartForm = document.querySelector('form[action="/cart_line_items"]');

cartForm.addEventListener('submit', function(e) {
var variantInput = e.target.querySelector('[name*="variant_id"]:checked');
var subscribableInput = e.target.querySelector('[name*="subscription_line_item[subscribable_id]"]');

if (!variantInput) {
variantInput = cartForm.querySelector('[name="variant_id"]');
var variantRadioButtons = cartForm.querySelectorAll('[data-js="variant-radio"]');
var subscribableInput = cartForm.querySelector('[name*="subscription_line_item[subscribable_id]"]');
var subscriptionFields = document.querySelector('.subscription-form'); // Select the subscription form container

function handleVariantSelection(e) {
var variantRadioButton = e.target;
var isSubscribable = variantRadioButton.getAttribute('data-subscribable') === 'true';

if (isSubscribable) {
subscribableInput.value = variantRadioButton.value;
subscriptionFields.style.display = 'block';
} else {
subscriptionFields.style.display = 'none';
}
}

subscribableInput.value = variantInput.value;

return true;
variantRadioButtons.forEach(function(variantRadioButton) {
variantRadioButton.addEventListener('change', handleVariantSelection);
});

var selectedVariantRadioButton = cartForm.querySelector('[data-js="variant-radio"]:checked');
if (selectedVariantRadioButton) {
handleVariantSelection({ target: selectedVariantRadioButton });
}
});
</script>

8 changes: 5 additions & 3 deletions lib/solidus_subscriptions/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ class Engine < Rails::Engine
}
end

initializer 'solidus_subscriptions.register_promotion_rules', after: 'spree.promo.register.promotion.rules' do |app|
app.config.spree.promotions.rules << 'SolidusSubscriptions::Promotion::Rules::SubscriptionCreationOrder'
app.config.spree.promotions.rules << 'SolidusSubscriptions::Promotion::Rules::SubscriptionInstallmentOrder'
if Object.const_defined?("Spree::Promotion")
initializer 'solidus_subscriptions.register_promotion_rules', after: 'spree.promo.register.promotion.rules' do |app|
app.config.spree.promotions.rules << 'SolidusSubscriptions::Promotion::Rules::SubscriptionCreationOrder'
app.config.spree.promotions.rules << 'SolidusSubscriptions::Promotion::Rules::SubscriptionInstallmentOrder'
end
end

initializer 'solidus_subscriptions.configure_backend' do
Expand Down
2 changes: 1 addition & 1 deletion solidus_subscriptions.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'httparty', '~> 0.18'
spec.add_dependency 'i18n'
spec.add_dependency 'solidus_core', '>= 2.11', '< 5'
spec.add_dependency 'solidus_support', '~> 0.9'
spec.add_dependency 'solidus_support', '~> 0.11'
spec.add_dependency 'state_machines'

spec.add_development_dependency 'rspec-activemodel-mocks'
Expand Down
91 changes: 91 additions & 0 deletions spec/controllers/concerns/create_subscription_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
require 'spec_helper'
require_relative '../../../lib/generators/solidus_subscriptions/install/templates/app/controllers/concerns/create_subscription'

RSpec.describe CreateSubscription, type: :controller do
subject(:controller_instance) do
Class.new(ApplicationController) do
include CreateSubscription
attr_accessor :params, :current_order

def initialize(params = {})
@params = params
@current_order = nil
end
end.new
end

let(:variant) { create(:variant) }
let(:order) { create(:order) }

before do
controller_instance.current_order = order
end

describe '#subscription_line_item_params_present?' do
context 'when all required params are present' do
it 'returns true' do
controller_instance.params = {
subscription_line_item: {
subscribable_id: 1,
quantity: 2,
interval_length: 1
}
}
expect(controller_instance.send(:valid_subscription_line_item_params?)).to be true
end
end

context 'when required params are missing' do
it 'returns false' do
controller_instance.params = {
subscription_line_item: {
subscribable_id: '',
quantity: '',
interval_length: ''
}
}
expect(controller_instance.send(:valid_subscription_line_item_params?)).to be false
end
end
end

describe '#handle_subscription_line_items' do
context 'when subscription params are missing' do
it 'does not invoke handle_subscription_line_items and does not create a subscription line item' do
order.line_items.count

controller_instance.params = {
variant_id: variant.id,
subscription_line_item: {}
}

expect(controller_instance.send(:valid_subscription_line_item_params?)).to be false

expect(controller_instance).not_to receive(:handle_subscription_line_items)

expect(controller_instance).not_to receive(:create_subscription_line_item)
end
end

context 'when subscription params are present' do
it 'calls create_subscription_line_item with the correct line item' do
line_item = create(:line_item, order: order, variant: variant)

controller_instance.params = {
variant_id: variant.id,
subscription_line_item: {
subscribable_id: 1,
quantity: 2,
interval_length: 1
}
}

allow(order.line_items).to receive(:find_by).with(variant_id: variant.id).and_return(line_item)

expect(controller_instance).to receive(:create_subscription_line_item).with(line_item)

controller_instance.send(:handle_subscription_line_items)
end
end
end
end
4 changes: 2 additions & 2 deletions spec/controllers/spree/api/line_items_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
subject(:post_create) { post :create, params: params }

let(:params) { line_item_params }
let!(:variant) { create :variant }
let!(:variant) { create :variant, subscribable: true }
let!(:order) { create :order }

let(:line_item_params) do
Expand Down Expand Up @@ -70,7 +70,7 @@
let(:params) { line_item_params }

context 'when adding subscription information' do
let(:variant) { create :variant }
let(:variant) { create :variant, subscribable: true }
let(:order) { create :order }
let(:line_item) { create :line_item, order: order, variant: variant }
let(:line_item_params) do
Expand Down
2 changes: 1 addition & 1 deletion spec/controllers/spree/api/orders_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
routes { Spree::Core::Engine.routes }

let(:order) { create :order }
let(:variant) { create :variant }
let(:variant) { create :variant, subscribable: true }

describe 'patch /update' do
subject(:subscription_line_items) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
describe 'POST /orders/populate' do
subject(:populate) { post :populate, params: params }

let!(:variant) { create :variant }
let!(:variant) { create :variant, subscribable: true }
let(:params) { line_item_params }
let(:line_item_params) do
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
it 'voids the actionable date of the unfulfilled installments' do
stub_config(clear_past_installments: true)
subscription = create(:subscription)
unfulfilled_installment = create(:installment, :failed, subscription: subscription)
unfulfilled_installment = create(:installment, :failed, subscription: subscription)

described_class.perform_now(subscription)

Expand Down
22 changes: 22 additions & 0 deletions spec/models/solidus_subscriptions/line_item_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,26 @@
expect(interval.from_now).to eq Date.parse("2016-10-22")
end
end

describe "custom validation" do
context "when subscribable is not true" do
let(:subscribable) { create(:variant, subscribable: false) }
let(:line_item) { build(:subscription_line_item, subscribable: subscribable) }

it "adds an error to subscribable" do
line_item.valid?
expect(line_item.errors[:subscribable]).to include("The requested item cannot be subscribed")
end
end

context "when subscribable is true" do
let(:subscribable) { create(:variant, subscribable: true) }
let(:line_item) { build(:subscription_line_item, subscribable: subscribable) }

it "does not add an error to subscribable" do
line_item.valid?
expect(line_item.errors[:subscribable]).to be_empty
end
end
end
end

0 comments on commit e76903d

Please sign in to comment.