Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a step to the Spree checkout process

I'm trying to add an extra step to my Spree 1.2 store which will allow a customer to create a subscription. I've inserted the step, and rendered the correct view, but when the user clicks 'save and continue' the next step is rendered, but nothing is actually saved.

I understand that I need to add a state_callback, but I'm not sure how to do this and the Spree documentation is very lacking around this (presumably because it's quite new)

At present I've got the following in my extension:

models/spree/order_decorator.rb

Spree::Order.class_eval do
  belongs_to :subscription

  accepts_nested_attributes_for :subscription

  # This doesn't appear to be called
  Spree::Order.state_machine.after_transition :from => :subscription,
                                              :do => :valid_subs?

  checkout_flow do
    go_to_state :address
    go_to_state :subscription
    go_to_state :payment, :if => lambda { |order| order.payment_required? }
    go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
    go_to_state :complete
    remove_transition :from => :delivery, :to => :confirm
  end
end

Not entirely sure that accepts_nested_attributes is necessary, but my dev approach for this has been trial and error so far, so it ended up staying there.

In models/subscription.rb

class Subscription < ActiveRecord::Base

  attr_accessible :start_date, :frequency

  belongs_to :user 
  has_many :orders
  has_many :products

  validates :start_date, :frequency, :presence => true

  def schedule
    ...code that returns a list of dates rendered on FE...
  end

  private #----

  ... some methods used in schedule ...

  def valid_subs?
    binding.pry # never called
  end

  def after_subscription
    binding.pry # never called either...
  end
end

views/spree/checkout/_subscription.html.erb

<h1><%= t(:"subscription.title") %></h1>

<div class="columns alpha six" data-hook="subscription_calendar_fieldset_wrapper">
  <fieldset id="subscription_calendar" data-hook>
    <%= form.fields_for :subscription_picker do |subscription_picker| %>
      <legend><%= t(:"subscription.first_delivery") %></legend>
      <%= render :partial => 'subscription/picker' %>
    <% end %>
  </fieldset>
</div>

<div class="columns omega six" data-hook="subscription_dates_fieldset_wrapper">
  <fieldset id="subscription_dates" data-hook>
    <legend align="center"><%= t(:"subscription.next_deliveries") %></legend>
    <div class='dates'></div>
  </fieldset>
</div>

<div class="form-buttons" data-hook="buttons" style='clear:both;'>
  <%= submit_tag t(:save_and_continue), :class => 'continue button primary' %>
</div>

views/subscription/_picker.html.erb

<div class='row'>
  <label for="subscription_frequency">Occurs every:</label>
  <% frequency_options = [["2 Weeks", 14], ["3 Weeks", 21], ["Month", 30], ["2 Months", 60], ["3 Months", 90]] %>
  <%= select(:subscription, :frequency, options_for_select(frequency_options, 30), {}) %>
</div>
<div id="start-date-picker" class="calendar"></div>
<%= hidden_field(:subscription, :start_date, {value: (DateTime.now + 14).to_date.iso8601}) %>

... JS that creates the calendar ...

On clicking 'save and continue' I see the following params sent:

{
                  "utf8" => "✓",
               "_method" => "put",
    "authenticity_token" => "...BLAH...",
          "subscription" => {
         "frequency" => "30",
        "start_date" => "2012-11-17"
    },
                "commit" => "Save and Continue",
            "controller" => "spree/checkout",
                "action" => "update",
                 "state" => "subscription"
}
like image 864
purpletonic Avatar asked Nov 04 '12 16:11

purpletonic


1 Answers

You have two problems. Your callback isn't firing because the call to checkout_flow erases the current state machine and replaces it. Move this code to after your call to checkout_flow:

Spree::Order.state_machine.after_transition :from => :subscription,
                                          :do => :valid_subs?

Second, your subscription information isn't saving because the parameters need to be passed as part of the order. The params should appear nested like this:

"order" => {    
    "subscription" => {
        "frequency" => "30",
        "start_date" => "2012-11-17"
    }
}

You can do that by attaching your call to select and hidden_field to the appropriate form 'subscription_picker':

<%= subscription_picker.select(:frequency, options_for_select(frequency_options, 30), {}) %>

and

<%= subscription_picker.hidden_field(:start_date, {value: (DateTime.now + 14).to_date.iso8601}) %>

You should probably pass the form object to your partial as an explicit parameter for style and understandability.

Cheers.

like image 72
user2041636 Avatar answered Oct 20 '22 09:10

user2041636