Skip to content

Commit

Permalink
Close #1037 Add Quantity to Customer and Add Query or Create Variant …
Browse files Browse the repository at this point in the history
…in Subscription
  • Loading branch information
Regene27 committed Mar 7, 2024
1 parent c3d7525 commit ce0dd33
Show file tree
Hide file tree
Showing 16 changed files with 340 additions and 26 deletions.
32 changes: 27 additions & 5 deletions app/controllers/spree/billing/subscriptions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
module Spree
module Billing
class SubscriptionsController < Spree::Billing::BaseController
before_action :load_customer
before_action :load_subscription, if: -> { member_action? }
before_action :load_variant, only: :create

helper_method :customer

def create
@subscription = @variant.subscriptions.build(subscription_params.merge(variant_id: @variant.id))

if @subscription.save
flash[:success] = flash_message_for(@subscription, :successfully_created)
else
flash[:error] = flash_message_for(@subscription, :not_created)
end

redirect_to billing_customer_subscriptions_url(customer)
end

protected

Expand All @@ -13,14 +27,14 @@ def collection
@collection = @search.result.page(page).per(per_page)
end

def load_customer
customer
end

def load_subscription
@subscription = @object
end

def load_variant
@variant = SpreeCmCommissioner::VariantChecker.new(variant_params, current_vendor).find_or_create_variant
end

def customer
@customer ||= SpreeCmCommissioner::Customer.find(params[:customer_id])
end
Expand All @@ -39,6 +53,14 @@ def object_name
def collection_url(options = {})
billing_customer_subscriptions_url(options)
end

def variant_params
params.require(:variant).permit(:product_id, :sku, :price, option_value_ids: [])
end

def subscription_params
params.require(:spree_cm_commissioner_subscription).permit(:start_date, :customer_id, :status, :variant_id)
end
end
end
end
10 changes: 10 additions & 0 deletions app/controllers/spree/billing/variants_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ class VariantsController < Spree::Billing::BaseController
belongs_to 'spree/product', find_by: :slug
before_action :load_data

def new
if request.xhr?
@variant = @product.variants.build

render :show, layout: false
else
redirect_to new_billing_product_variant_url(@product)
end
end

def collection
return @collection if @collection.present?

Expand Down
3 changes: 3 additions & 0 deletions app/models/spree_cm_commissioner/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Subscription < SpreeCmCommissioner::Base

belongs_to :variant, class_name: 'Spree::Variant'
belongs_to :customer, class_name: 'SpreeCmCommissioner::Customer'
belongs_to :product, class_name: 'Spree::Product'

has_many :orders, -> { order(:created_at) }, class_name: 'Spree::Order', dependent: :nullify
has_many :line_items, through: :orders, class_name: 'Spree::LineItem'
Expand All @@ -23,6 +24,8 @@ class Subscription < SpreeCmCommissioner::Base
after_create :create_order
after_commit :update_customer_active_subscriptions_count

accepts_nested_attributes_for :variant

def create_order
SpreeCmCommissioner::SubscribedOrderCreator.call(subscription: self)
end
Expand Down
2 changes: 2 additions & 0 deletions app/models/spree_cm_commissioner/variant_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ def self.prepended(base)
base.validate :validate_option_types

base.scope :subscribable, -> { active.joins(:product).where(product: { subscribable: true, status: :active }) }

base.has_many :subscriptions, class_name: 'SpreeCmCommissioner::Subscription', dependent: :destroy
end

def selected_option_value_ids
Expand Down
29 changes: 29 additions & 0 deletions app/services/spree_cm_commissioner/sku_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module SpreeCmCommissioner
class SkuGenerator
def initialize(product, variant_params)
@product = product
@variant_params = variant_params
end

def generate_sku
return if @variant_params.nil? || @variant_params.blank?

option_values = @variant_params[:option_value_ids].map { |id| Spree::OptionValue.find(id) }
sku_parts = [product.name]

option_values.each do |option_value|
sku_parts << "#{option_value.option_type.name}-#{option_value.name}"
end

sku_parts << "price-#{@variant_params[:price]}"

sku_parts.join('-').gsub(' ', '-').downcase
end

private

def product
@product ||= Spree::Product.find(@variant_params[:product_id])
end
end
end
32 changes: 32 additions & 0 deletions app/services/spree_cm_commissioner/variant_checker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module SpreeCmCommissioner
class VariantChecker
attr_reader :variant

def initialize(variant_params, current_vendor)
@product = Spree::Product.find_by(id: variant_params[:product_id])
@variant_params = variant_params
@current_vendor = current_vendor
end

def find_or_create_variant
find_variant_by_sku || create_variant
end

private

def find_variant_by_sku
@variant = @product.variants.where(sku: variant_sku).first
end

def create_variant
variant_creator = SpreeCmCommissioner::VariantCreator.new(@product, @variant_params, @current_vendor)
variant_creator.create_variant
@variant = variant_creator.variant
end

def variant_sku
sku_generator = SpreeCmCommissioner::SkuGenerator.new(@product, @variant_params)
sku_generator.generate_sku
end
end
end
37 changes: 37 additions & 0 deletions app/services/spree_cm_commissioner/variant_creator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module SpreeCmCommissioner
class VariantCreator
attr_reader :variant

def initialize(product, variant_params, current_vendor)
@product = product
@variant_params = variant_params
@current_vendor = current_vendor
end

def create_variant
@variant = @product.variants.build
generate_sku
set_variant_attributes
@variant.save
@variant
end

private

def generate_sku
sku_generator = SpreeCmCommissioner::SkuGenerator.new(@product, @variant_params)
@variant.sku = sku_generator.generate_sku
end

def set_variant_attributes
@variant.option_value_ids = @variant_params[:option_value_ids]
@variant.price = @variant_params[:price]
stock_item = @variant.stock_items.build(stock_location_id: stock_location, count_on_hand: 1, backorderable: false)
stock_item.save
end

def stock_location
@stock_location ||= Spree::StockLocation.find_by!(vendor_id: @current_vendor.id).id
end
end
end
6 changes: 3 additions & 3 deletions app/views/spree/billing/shared/_subscription_tabs.html.erb
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
<% content_for :page_title do %>
<%= page_header_back_button spree.billing_customer_subscriptions_path(@customer) %>
<%= page_header_back_button spree.billing_customer_subscriptions_path(customer) %>
<%= @subscription.variant.sku %>
<% end %>
<% content_for :page_tabs do %>
<li class="nav-item">
<%= link_to_with_icon 'tag.svg',
Spree.t(:edit),
spree.edit_billing_customer_subscription_path(@customer, @subscription),
spree.edit_billing_customer_subscription_path(customer, @subscription),
class: "nav-link #{'active' if current == :account}" %>
</li>
<% end %>
<% content_for :page_tabs do %>
<li class="nav-item">
<%= link_to_with_icon 'cart.svg',
Spree.t(:orders),
spree.billing_orders_path(customer_id: @customer.id, subscription_id: @subscription.id),
spree.billing_orders_path(customer_id: customer.id, subscription_id: @subscription.id),
class: "nav-link #{'active' if current == :order}" %>
</li>
<% end %>
104 changes: 86 additions & 18 deletions app/views/spree/billing/subscriptions/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,22 +1,90 @@
<div data-hook="admin_user_form_fields" class="row">
<div class="col-12 col-md-6">
<%= f.hidden_field :customer_id, value: @customer.id %>
<%= f.field_container :variant_id do %>
<%= f.label :variant, Spree.t(:variant) %>
<%= f.collection_select(:variant_id, @customer.subscribable_variants, :id, :display_variant, { include_blank: false }, { class: 'select2' ,disabled: @subscription.persisted?}) %>
<%= f.error_message_on :product_id %>
<% end %>
<%= f.field_container :start_date do %>
<%= f.label :start_date, Spree.t(:start_date) %>
<%= f.date_field :start_date, class: 'form-control', disabled: @subscription.persisted? %>
<%= f.error_message_on :start_date %>
<% end %>
<% if @subscription.id.present? %>
<%= f.field_container :status do %>
<%= f.label :status, Spree.t(:status) %>
<%= f.select :status, SpreeCmCommissioner::Subscription.statuses.keys, {}, class: 'select2' %>
<%= f.error_message_on :status %>
<div class="col-12">
<%= f.hidden_field :customer_id, value: customer.id %>

<div class="col-12">
<% if @subscription.persisted? %>
<%= f.field_container :product do %>
<%= f.label :product, Spree.t(:product) %>
<%= f.text_field :product, value: f.object.variant.product.name, class: 'form-control', disabled: true %>
<%= f.error_message_on :product %>
<% end %>
<% else %>
<%= f.field_container :product do %>
<%= f.label :product, Spree:t(:product) %>
<%= f.select :product, options_for_select(Spree::Product.joins(:taxons)
.where(spree_taxons: { id: customer.taxon_id })
.map{ |product| [product.name, product.sku] }),
{ include_blank: true },
{ class: "select2-clear" } %>
<%= f.error_message_on :product %>
<% end %>
<% end %>
<% end %>
</div>

<div class="col-12">
<% if @subscription.persisted? %>
<%= f.field_container :variant do %>
<%= f.label :variant, Spree.t(:variant) %>
<%= f.text_field :variant, value: f.object.variant.sku, class: 'form-control', disabled: true %>
<%= f.error_message_on :product %>
<% end %>
<% else %>
<div id="option-types-form-container">
</div>
<% end %>
</div>

<div class="col-12">
<%= f.field_container :start_date do %>
<%= f.label :start_date, Spree.t(:start_date) %>
<%= f.date_field :start_date, class: 'form-control', disabled: @subscription.persisted? %>
<%= f.error_message_on :start_date %>
<% end %>
</div>

<div class="col-12">
<% if @subscription.id.present? %>
<%= f.field_container :status do %>
<%= f.label :status, Spree.t(:status) %>
<%= f.select :status, SpreeCmCommissioner::Subscription.statuses.keys, {}, class: 'select2' %>
<%= f.error_message_on :status %>
<% end %>
<% end %>
</div>
</div>
</div>

<script>
$(document).ready(function () {
const productSelector = "#spree_cm_commissioner_subscription_product";
const variantIdSelector = "#spree_cm_commissioner_subscription_variant_id";
const optionTypesFormDiv = "#option-types-form-container";

$(productSelector).on("change", function () {
removeOptionTypesForm();
appendOptionTypesForm();
});

function appendOptionTypesForm() {
var productSku = $(productSelector).val();

$.ajax({
url: '/en/billing/products/' + productSku + '/variants/new',
type: 'GET',
dataType: 'html',
success: function (response) {
console.log('Success fetching form:', response);
$(optionTypesFormDiv).append(response);
},
error: function (error) {
console.error('Error fetching form:', error);
}
});
}

function removeOptionTypesForm() {
$(optionTypesFormDiv).empty();
}
});
</script>
33 changes: 33 additions & 0 deletions app/views/spree/billing/variants/show.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<%= fields_for @variant do |f| %>
<div class="card mb-3">
<div class="card-header">
<h5 class="mb-0"><%= Spree.t(:variant) %></h5>
</div>
<%= f.hidden_field :product_id, value: @product.id %>

<div class="row">
<div data-hook="billing_variant_form_fields" class="col-6 p-4">
<div data-hook="variants">
<div class="form-group " data-hook="price">
<%= f.label :price, Spree.t(:price) %>
<%= f.text_field :price, placeholder: I18n.t('spree.billing.subscription_price_placeholder', currency: @variant.currency), value: number_to_currency(@variant.price, unit: ''), class: 'form-control' %>
</div>
</div>
</div>
<div data-hook="billing_varaint_option_types_field" class="col-6 p-4">
<% @product.option_types.each do |option_type| %>
<div class="form-group" data-hook="presentation">
<%= label :new_variant, option_type.presentation %>
<% if option_type.name == 'color' %>
<%= f.collection_select 'option_value_ids', option_type.option_values, :id, :name,
{ include_blank: true }, { name: 'variant[option_value_ids][]', class: 'select2-clear form-control', id: "option_value_ids-#{option_type.id}" } %>
<% else %>
<%= f.collection_select 'option_value_ids', option_type.option_values, :id, :presentation,
{ include_blank: true }, { name: 'variant[option_value_ids][]', class: 'select2-clear form-control', id: "option_value_ids-#{option_type.id}" } %>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
<% end %>
1 change: 1 addition & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ en:
overdue: "Overdue"
failed: "Failed"
unknown: "Unknown"
subscription_price_placeholder: "Subscription Price In %{currency}"
upsupported_payment: "Unsupported event"
exceeded_available_quantity_on_date:
zero: "Rooms are not available on %{date}"
Expand Down
1 change: 1 addition & 0 deletions config/locales/km.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ km:
overdue: "ហួសថ្ងៃបង់"
failed: "បរាជ័យ"
unknown: "មិនស្គាល់"
subscription_price_placeholder: "តម្លៃជា​​​ %{currency}"
upsupported_payment: "មិនស្គាល់ការបង់ប្រាក់"
selected_item_not_available_on_date: "Selected item not available on %{date}"
auto_apply: "ដាក់ប្រើដោយស្វ័យប្រវត្តិ"
Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@
resources :homepage_section_relatable_options
end

namespace :billing do
resources :variants, only: %i[index show]
end

namespace :storefront do
resource :cart, controller: :cart, only: %i[show create destroy] do
patch :restart_checkout_flow
Expand Down
Loading

0 comments on commit ce0dd33

Please sign in to comment.