mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-24 05:38:52 +00:00
@@ -9,14 +9,11 @@ module Admin
|
||||
end
|
||||
|
||||
def create
|
||||
voucher_params = permitted_resource_params.merge(enterprise: @enterprise)
|
||||
@voucher = Voucher.create(voucher_params)
|
||||
@voucher = Voucher.create(permitted_resource_params.merge(enterprise: @enterprise))
|
||||
|
||||
if @voucher.save
|
||||
redirect_to(
|
||||
"#{edit_admin_enterprise_path(@enterprise)}#vouchers_panel",
|
||||
flash: { success: flash_message_for(@voucher, :successfully_created) }
|
||||
)
|
||||
flash[:success] = flash_message_for(@voucher, :successfully_created)
|
||||
redirect_to edit_admin_enterprise_path(@enterprise, anchor: :vouchers_panel)
|
||||
else
|
||||
flash[:error] = @voucher.errors.full_messages.to_sentence
|
||||
render :new
|
||||
|
||||
@@ -14,7 +14,7 @@ module CheckoutCallbacks
|
||||
prepend_before_action :require_order_cycle
|
||||
prepend_before_action :require_distributor_chosen
|
||||
|
||||
before_action :load_order, :associate_user, :load_saved_addresses, :load_saved_credit_cards
|
||||
before_action :load_order, :associate_user, :load_saved_addresses
|
||||
before_action :load_shipping_methods, if: -> { params[:step] == "details" }
|
||||
|
||||
before_action :ensure_order_not_completed
|
||||
@@ -30,8 +30,6 @@ module CheckoutCallbacks
|
||||
@order.manual_shipping_selection = true
|
||||
@order.checkout_processing = true
|
||||
|
||||
@voucher_adjustment = @order.voucher_adjustments.first
|
||||
|
||||
redirect_to(main_app.shop_path) && return if redirect_to_shop?
|
||||
redirect_to_cart_path && return unless valid_order_line_items?
|
||||
end
|
||||
@@ -43,11 +41,6 @@ module CheckoutCallbacks
|
||||
@order.ship_address ||= finder.ship_address
|
||||
end
|
||||
|
||||
def load_saved_credit_cards
|
||||
@saved_credit_cards = spree_current_user&.credit_cards&.with_payment_profile.to_a
|
||||
@selected_card = nil
|
||||
end
|
||||
|
||||
def load_shipping_methods
|
||||
@shipping_methods = available_shipping_methods.sort { |a, b| a.name.casecmp(b.name) }
|
||||
end
|
||||
|
||||
@@ -25,12 +25,12 @@ class SplitCheckoutController < ::BaseController
|
||||
redirect_to_step_based_on_order unless params[:step]
|
||||
check_step if params[:step]
|
||||
|
||||
flash_error_when_no_shipping_method_available if available_shipping_methods.none?
|
||||
return if available_shipping_methods.any?
|
||||
|
||||
flash[:error] = I18n.t('split_checkout.errors.no_shipping_methods_available')
|
||||
end
|
||||
|
||||
def update
|
||||
return process_voucher if params[:apply_voucher].present?
|
||||
|
||||
if confirm_order || update_order
|
||||
return if performed?
|
||||
|
||||
@@ -60,27 +60,6 @@ class SplitCheckoutController < ::BaseController
|
||||
replace("#flashes", partial("shared/flashes", locals: { flashes: flash }))
|
||||
end
|
||||
|
||||
def render_voucher_section_or_redirect
|
||||
respond_to do |format|
|
||||
format.cable_ready { render_voucher_section }
|
||||
format.html { redirect_to checkout_step_path(:payment) }
|
||||
end
|
||||
end
|
||||
|
||||
# Using the power of cable_car we replace only the #voucher_section instead of reloading the page
|
||||
def render_voucher_section
|
||||
render(
|
||||
status: :ok,
|
||||
cable_ready: cable_car.replace(
|
||||
"#voucher-section",
|
||||
partial(
|
||||
"split_checkout/voucher_section",
|
||||
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def order_error_messages
|
||||
# Remove ship_address.* errors if no shipping method is not selected
|
||||
remove_ship_address_errors if no_ship_address_needed?
|
||||
@@ -125,10 +104,6 @@ class SplitCheckoutController < ::BaseController
|
||||
end
|
||||
end
|
||||
|
||||
def flash_error_when_no_shipping_method_available
|
||||
flash[:error] = I18n.t('split_checkout.errors.no_shipping_methods_available')
|
||||
end
|
||||
|
||||
def check_payments_adjustments
|
||||
@order.payments.each(&:ensure_correct_adjustment)
|
||||
end
|
||||
@@ -201,40 +176,6 @@ class SplitCheckoutController < ::BaseController
|
||||
selected_shipping_method.first.require_ship_address == false
|
||||
end
|
||||
|
||||
def process_voucher
|
||||
if add_voucher
|
||||
VoucherAdjustmentsService.calculate(@order)
|
||||
render_voucher_section_or_redirect
|
||||
elsif @order.errors.present?
|
||||
render_error
|
||||
end
|
||||
end
|
||||
|
||||
def add_voucher
|
||||
if params.dig(:order, :voucher_code).blank?
|
||||
@order.errors.add(:voucher, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
# Fetch Voucher
|
||||
voucher = Voucher.find_by(code: params[:order][:voucher_code], enterprise: @order.distributor)
|
||||
|
||||
if voucher.nil?
|
||||
@order.errors.add(:voucher, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
adjustment = voucher.create_adjustment(voucher.code, @order)
|
||||
|
||||
unless adjustment.valid?
|
||||
@order.errors.add(:voucher, I18n.t('split_checkout.errors.add_voucher_error'))
|
||||
adjustment.errors.each { |error| @order.errors.import(error) }
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def summary_step?
|
||||
params[:step] == "summary"
|
||||
end
|
||||
@@ -262,6 +203,7 @@ class SplitCheckoutController < ::BaseController
|
||||
|
||||
def validate_payment!
|
||||
return true if params.dig(:order, :payments_attributes, 0, :payment_method_id).present?
|
||||
return true if @order.zero_priced_order?
|
||||
|
||||
@order.errors.add :payment_method, I18n.t('split_checkout.errors.select_a_payment_method')
|
||||
end
|
||||
|
||||
@@ -1,32 +1,77 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class VoucherAdjustmentsController < BaseController
|
||||
include CablecarResponses
|
||||
before_action :set_order
|
||||
|
||||
def create
|
||||
if add_voucher
|
||||
VoucherAdjustmentsService.calculate(@order)
|
||||
@order.update_totals_and_states
|
||||
|
||||
update_payment_section
|
||||
elsif @order.errors.present?
|
||||
render_error
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@order = current_order
|
||||
|
||||
@order.voucher_adjustments.find_by(id: params[:id])&.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.cable_ready { render_voucher_section }
|
||||
format.html { redirect_to checkout_step_path(:payment) }
|
||||
end
|
||||
update_payment_section
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Using the power of cable_car we replace only the #voucher_section instead of reloading the page
|
||||
def render_voucher_section
|
||||
render(
|
||||
status: :ok,
|
||||
cable_ready: cable_car.replace(
|
||||
def set_order
|
||||
@order = current_order
|
||||
end
|
||||
|
||||
def add_voucher
|
||||
if voucher_params[:voucher_code].blank?
|
||||
@order.errors.add(:voucher_code, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
voucher = Voucher.find_by(code: voucher_params[:voucher_code], enterprise: @order.distributor)
|
||||
|
||||
if voucher.nil?
|
||||
@order.errors.add(:voucher_code, I18n.t('split_checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
adjustment = voucher.create_adjustment(voucher.code, @order)
|
||||
|
||||
unless adjustment.valid?
|
||||
@order.errors.add(:voucher_code, I18n.t('split_checkout.errors.add_voucher_error'))
|
||||
adjustment.errors.each { |error| @order.errors.import(error) }
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def update_payment_section
|
||||
render cable_ready: cable_car.replace(
|
||||
selector: "#checkout-payment-methods",
|
||||
html: render_to_string(partial: "split_checkout/payment", locals: { step: "payment" })
|
||||
)
|
||||
end
|
||||
|
||||
def render_error
|
||||
flash.now[:error] = @order.errors.full_messages.to_sentence
|
||||
|
||||
render status: :unprocessable_entity, cable_ready: cable_car.
|
||||
replace("#flashes", partial("shared/flashes", locals: { flashes: flash })).
|
||||
replace(
|
||||
"#voucher-section",
|
||||
partial(
|
||||
"split_checkout/voucher_section",
|
||||
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def voucher_params
|
||||
params.require(:order).permit(:voucher_code)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -120,6 +120,8 @@ module CheckoutHelper
|
||||
end
|
||||
|
||||
def payment_or_shipping_price(method, order)
|
||||
return unless method
|
||||
|
||||
price = method.compute_amount(order)
|
||||
if price.zero?
|
||||
t('checkout_method_free')
|
||||
|
||||
@@ -5,11 +5,13 @@ module Spree
|
||||
def payment_method(payment)
|
||||
# hack to allow us to retrieve the name of a "deleted" payment method
|
||||
id = payment.payment_method_id
|
||||
return if id.nil?
|
||||
|
||||
Spree::PaymentMethod.find_with_destroyed(id)
|
||||
end
|
||||
|
||||
def payment_method_name(payment)
|
||||
payment_method(payment).name
|
||||
payment_method(payment)&.name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,7 +23,7 @@ module Spree
|
||||
go_to_state :delivery
|
||||
go_to_state :payment, if: ->(order) {
|
||||
order.update_totals
|
||||
order.payment_required?
|
||||
order.payment_required? || order.zero_priced_order?
|
||||
}
|
||||
go_to_state :confirmation
|
||||
go_to_state :complete
|
||||
@@ -219,6 +219,12 @@ module Spree
|
||||
total.to_f > 0.0 && !skip_payment_for_subscription?
|
||||
end
|
||||
|
||||
# There are items present in the order, but either the items have zero price,
|
||||
# or the order's total has been modified (maybe discounted) to zero.
|
||||
def zero_priced_order?
|
||||
line_items.count.positive? && total.zero?
|
||||
end
|
||||
|
||||
# Returns the relevant zone (if any) to be used for taxation purposes.
|
||||
# Uses default tax zone unless there is a specific match
|
||||
def tax_zone
|
||||
@@ -615,6 +621,10 @@ module Spree
|
||||
raise Core::GatewayError, Spree.t(:no_pending_payments) if pending_payments.empty?
|
||||
|
||||
pending_payments.each do |payment|
|
||||
if payment.amount.zero? && zero_priced_order?
|
||||
payment.update_columns(state: "completed", captured_at: Time.zone.now)
|
||||
end
|
||||
|
||||
break if payment_total >= total
|
||||
|
||||
yield payment
|
||||
|
||||
@@ -19,8 +19,10 @@ class VoucherAdjustmentsService
|
||||
# For now we just assume it is either all tax included in price or all tax excluded from price.
|
||||
if order.additional_tax_total.positive?
|
||||
handle_tax_excluded_from_price(order, amount)
|
||||
else
|
||||
elsif order.included_tax_total.positive?
|
||||
handle_tax_included_in_price(order, amount)
|
||||
else
|
||||
adjustment.amount = amount
|
||||
end
|
||||
|
||||
# Move to closed state
|
||||
|
||||
@@ -1,155 +1,156 @@
|
||||
.medium-6
|
||||
= f.fields :bill_address, model: @order.bill_address do |bill_address|
|
||||
%div.checkout-substep
|
||||
-# YOUR DETAILS
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step1.contact_information.title")
|
||||
= form_with url: checkout_update_path(checkout_step), model: @order, method: :put, data: { remote: "true" } do |f|
|
||||
.medium-6
|
||||
= f.fields :bill_address, model: @order.bill_address do |bill_address|
|
||||
%div.checkout-substep
|
||||
-# YOUR DETAILS
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step1.contact_information.title")
|
||||
|
||||
.two-columns-inputs
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= f.label :email, t("split_checkout.step1.contact_information.email.label")
|
||||
= f.text_field :email, { placeholder: " " }
|
||||
= f.error_message_on :email
|
||||
.two-columns-inputs
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= f.label :email, t("split_checkout.step1.contact_information.email.label")
|
||||
= f.text_field :email, { placeholder: " " }
|
||||
= f.error_message_on :email
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= bill_address.label :phone, t("split_checkout.step1.contact_information.phone.label")
|
||||
= bill_address.text_field :phone, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.phone"
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= bill_address.label :phone, t("split_checkout.step1.contact_information.phone.label")
|
||||
= bill_address.text_field :phone, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.phone"
|
||||
|
||||
%div.checkout-substep
|
||||
-# BILLING ADDRESS
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step1.billing_address.title")
|
||||
%div.checkout-substep
|
||||
-# BILLING ADDRESS
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step1.billing_address.title")
|
||||
|
||||
.two-columns-inputs
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= bill_address.label :firstname, t("split_checkout.step1.billing_address.first_name.label")
|
||||
= bill_address.text_field :firstname, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.firstname"
|
||||
.two-columns-inputs
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= bill_address.label :firstname, t("split_checkout.step1.billing_address.first_name.label")
|
||||
= bill_address.text_field :firstname, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.firstname"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= bill_address.label :lastname, t("split_checkout.step1.billing_address.last_name.label")
|
||||
= bill_address.text_field :lastname, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.lastname"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= bill_address.label :address1, t("split_checkout.step1.address.address1.label")
|
||||
= bill_address.text_field :address1, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.address1"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= bill_address.label :address2, t("split_checkout.step1.address.address2.label")
|
||||
= bill_address.text_field :address2, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.address2"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= bill_address.label :city, t("split_checkout.step1.address.city.label")
|
||||
= bill_address.text_field :city, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.city"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= bill_address.label :zipcode, t("split_checkout.step1.address.zipcode.label")
|
||||
= bill_address.text_field :zipcode, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.zipcode"
|
||||
|
||||
%div{ "data-controller": "dependent-select", "data-dependent-select-options-value": countries_with_states }
|
||||
- bill_address_country = @order.bill_address.country || DefaultCountry.country
|
||||
|
||||
%div.checkout-input
|
||||
= bill_address.label :country_id, t("split_checkout.step1.address.country_id.label")
|
||||
= bill_address.select :country_id, countries, { selected: bill_address_country.id }, { "data-dependent-select-target": "source", "data-action": "dependent-select#handleSelectChange" }
|
||||
|
||||
%div.checkout-input
|
||||
= bill_address.label :state_id, t("split_checkout.step1.address.state_id.label")
|
||||
= bill_address.select :state_id, states_for_country(bill_address_country), { selected: @order.bill_address&.state_id }, { "data-dependent-select-target": "select" }
|
||||
|
||||
- if spree_current_user
|
||||
%div.checkout-input
|
||||
= f.check_box :save_bill_address
|
||||
= f.label :save_bill_address, t(:checkout_default_bill_address)
|
||||
|
||||
%div.checkout-substep{ "data-controller": "toggle shippingmethod" }
|
||||
- selected_shipping_method = @order.shipping_method&.id || params[:shipping_method_id]
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step1.shipping_info.title")
|
||||
|
||||
- display_ship_address = false
|
||||
- ship_method_description = nil
|
||||
|
||||
- selected_shipping_method ||= @shipping_methods[0].id if @shipping_methods.length == 1
|
||||
- @shipping_methods.each do |shipping_method|
|
||||
- ship_method_is_selected = shipping_method.id == selected_shipping_method.to_i
|
||||
%div.checkout-input.checkout-input-radio
|
||||
= fields_for shipping_method do |shipping_method_form|
|
||||
= shipping_method_form.radio_button :name, shipping_method.id,
|
||||
id: "shipping_method_#{shipping_method.id}",
|
||||
checked: ship_method_is_selected,
|
||||
name: "shipping_method_id",
|
||||
"data-requireAddress": shipping_method.require_ship_address,
|
||||
"data-action": "toggle#toggle shippingmethod#selectShippingMethod",
|
||||
"data-toggle-show": shipping_method.require_ship_address
|
||||
= shipping_method_form.label shipping_method.id, shipping_method.name, {for: "shipping_method_" + shipping_method.id.to_s }
|
||||
%em.fees= payment_or_shipping_price(shipping_method, @order)
|
||||
- display_ship_address = display_ship_address || (ship_method_is_selected && shipping_method.require_ship_address)
|
||||
%div.checkout-input{"data-shippingmethod-target": "shippingMethodDescription", "data-shippingmethodid": shipping_method.id , style: "display: #{ship_method_is_selected ? 'block' : 'none'}" }
|
||||
#distributor_address.panel
|
||||
- if shipping_method.description.present?
|
||||
%span #{shipping_method.description}
|
||||
%br/
|
||||
%br/
|
||||
- if @order.order_cycle.pickup_time_for(@order.distributor)
|
||||
= t :checkout_ready_for
|
||||
= @order.order_cycle.pickup_time_for(@order.distributor)
|
||||
|
||||
= f.error_message_on :shipping_method, standalone: true
|
||||
|
||||
%div.checkout-input{ "data-toggle-target": "content", style: "display: #{display_ship_address ? 'block' : 'none'}" }
|
||||
= f.check_box :ship_address_same_as_billing, { id: "ship_address_same_as_billing", name: "ship_address_same_as_billing", "data-action": "shippingmethod#showHideShippingAddress", "data-shippingmethod-target": "shippingAddressCheckbox", checked: shipping_and_billing_match?(@order) }, 1, nil
|
||||
= f.label :ship_address_same_as_billing, t(:checkout_address_same), { for: "ship_address_same_as_billing" }
|
||||
|
||||
%div{"data-shippingmethod-target": "shippingMethodAddress", style: "display: #{!display_ship_address || shipping_and_billing_match?(@order) ? 'none' : 'block'}" }
|
||||
= f.fields :ship_address, model: @order.ship_address do |ship_address|
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :address1, t("split_checkout.step1.address.address1.label")
|
||||
= ship_address.text_field :address1, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.address1"
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
|
||||
= bill_address.label :lastname, t("split_checkout.step1.billing_address.last_name.label")
|
||||
= bill_address.text_field :lastname, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.lastname"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :address2, t("split_checkout.step1.address.address2.label")
|
||||
= ship_address.text_field :address2, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.address2"
|
||||
= bill_address.label :address1, t("split_checkout.step1.address.address1.label")
|
||||
= bill_address.text_field :address1, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.address1"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :city, t("split_checkout.step1.address.city.label")
|
||||
= ship_address.text_field :city, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.city"
|
||||
= bill_address.label :address2, t("split_checkout.step1.address.address2.label")
|
||||
= bill_address.text_field :address2, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.address2"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :zipcode, t("split_checkout.step1.address.zipcode.label")
|
||||
= ship_address.text_field :zipcode, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.zipcode"
|
||||
= bill_address.label :city, t("split_checkout.step1.address.city.label")
|
||||
= bill_address.text_field :city, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.city"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= bill_address.label :zipcode, t("split_checkout.step1.address.zipcode.label")
|
||||
= bill_address.text_field :zipcode, { placeholder: " " }
|
||||
= f.error_message_on "bill_address.zipcode"
|
||||
|
||||
%div{ "data-controller": "dependent-select", "data-dependent-select-options-value": countries_with_states }
|
||||
- ship_address_country = @order.ship_address.country || DefaultCountry.country
|
||||
- bill_address_country = @order.bill_address.country || DefaultCountry.country
|
||||
|
||||
%div.checkout-input
|
||||
= ship_address.label :country_id, t("split_checkout.step1.address.country_id.label")
|
||||
= ship_address.select :country_id, countries, { selected: ship_address_country.id }, { "data-dependent-select-target": "source", "data-action": "dependent-select#handleSelectChange" }
|
||||
= bill_address.label :country_id, t("split_checkout.step1.address.country_id.label")
|
||||
= bill_address.select :country_id, countries, { selected: bill_address_country.id }, { "data-dependent-select-target": "source", "data-action": "dependent-select#handleSelectChange" }
|
||||
|
||||
%div.checkout-input
|
||||
= ship_address.label :state_id, t("split_checkout.step1.address.state_id.label")
|
||||
= ship_address.select :state_id, states_for_country(ship_address_country), { selected: @order.ship_address&.state_id }, { "data-dependent-select-target": "select" }
|
||||
= bill_address.label :state_id, t("split_checkout.step1.address.state_id.label")
|
||||
= bill_address.select :state_id, states_for_country(bill_address_country), { selected: @order.bill_address&.state_id }, { "data-dependent-select-target": "select" }
|
||||
|
||||
- if spree_current_user
|
||||
%div.checkout-input
|
||||
= f.check_box :save_bill_address
|
||||
= f.label :save_bill_address, t(:checkout_default_bill_address)
|
||||
|
||||
%div.checkout-substep{ "data-controller": "toggle shippingmethod" }
|
||||
- selected_shipping_method = @order.shipping_method&.id || params[:shipping_method_id]
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step1.shipping_info.title")
|
||||
|
||||
- display_ship_address = false
|
||||
- ship_method_description = nil
|
||||
|
||||
- selected_shipping_method ||= @shipping_methods[0].id if @shipping_methods.length == 1
|
||||
- @shipping_methods.each do |shipping_method|
|
||||
- ship_method_is_selected = shipping_method.id == selected_shipping_method.to_i
|
||||
%div.checkout-input.checkout-input-radio
|
||||
= fields_for shipping_method do |shipping_method_form|
|
||||
= shipping_method_form.radio_button :name, shipping_method.id,
|
||||
id: "shipping_method_#{shipping_method.id}",
|
||||
checked: ship_method_is_selected,
|
||||
name: "shipping_method_id",
|
||||
"data-requireAddress": shipping_method.require_ship_address,
|
||||
"data-action": "toggle#toggle shippingmethod#selectShippingMethod",
|
||||
"data-toggle-show": shipping_method.require_ship_address
|
||||
= shipping_method_form.label shipping_method.id, shipping_method.name, {for: "shipping_method_" + shipping_method.id.to_s }
|
||||
%em.fees= payment_or_shipping_price(shipping_method, @order)
|
||||
- display_ship_address = display_ship_address || (ship_method_is_selected && shipping_method.require_ship_address)
|
||||
%div.checkout-input{"data-shippingmethod-target": "shippingMethodDescription", "data-shippingmethodid": shipping_method.id , style: "display: #{ship_method_is_selected ? 'block' : 'none'}" }
|
||||
#distributor_address.panel
|
||||
- if shipping_method.description.present?
|
||||
%span #{shipping_method.description}
|
||||
%br/
|
||||
%br/
|
||||
- if @order.order_cycle.pickup_time_for(@order.distributor)
|
||||
= t :checkout_ready_for
|
||||
= @order.order_cycle.pickup_time_for(@order.distributor)
|
||||
|
||||
= f.error_message_on :shipping_method, standalone: true
|
||||
|
||||
- if spree_current_user
|
||||
%div.checkout-input{ "data-toggle-target": "content", style: "display: #{display_ship_address ? 'block' : 'none'}" }
|
||||
= f.check_box :save_ship_address
|
||||
= f.label :save_ship_address, t(:checkout_default_ship_address)
|
||||
= f.check_box :ship_address_same_as_billing, { id: "ship_address_same_as_billing", name: "ship_address_same_as_billing", "data-action": "shippingmethod#showHideShippingAddress", "data-shippingmethod-target": "shippingAddressCheckbox", checked: shipping_and_billing_match?(@order) }, 1, nil
|
||||
= f.label :ship_address_same_as_billing, t(:checkout_address_same), { for: "ship_address_same_as_billing" }
|
||||
|
||||
.div.checkout-input
|
||||
= f.label :special_instructions, t(:checkout_instructions)
|
||||
= f.text_area :special_instructions, size: "60x4"
|
||||
%div{"data-shippingmethod-target": "shippingMethodAddress", style: "display: #{!display_ship_address || shipping_and_billing_match?(@order) ? 'none' : 'block'}" }
|
||||
= f.fields :ship_address, model: @order.ship_address do |ship_address|
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :address1, t("split_checkout.step1.address.address1.label")
|
||||
= ship_address.text_field :address1, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.address1"
|
||||
|
||||
%div.checkout-submit
|
||||
= f.submit t("split_checkout.step1.submit"), class: "button primary", disabled: @terms_and_conditions_accepted == false || @platform_tos_accepted == false
|
||||
%a.button.cancel{href: main_app.cart_path}
|
||||
= t("split_checkout.step1.cancel")
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :address2, t("split_checkout.step1.address.address2.label")
|
||||
= ship_address.text_field :address2, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.address2"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :city, t("split_checkout.step1.address.city.label")
|
||||
= ship_address.text_field :city, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.city"
|
||||
|
||||
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
|
||||
= ship_address.label :zipcode, t("split_checkout.step1.address.zipcode.label")
|
||||
= ship_address.text_field :zipcode, { placeholder: " " }
|
||||
= f.error_message_on "ship_address.zipcode"
|
||||
|
||||
%div{ "data-controller": "dependent-select", "data-dependent-select-options-value": countries_with_states }
|
||||
- ship_address_country = @order.ship_address.country || DefaultCountry.country
|
||||
|
||||
%div.checkout-input
|
||||
= ship_address.label :country_id, t("split_checkout.step1.address.country_id.label")
|
||||
= ship_address.select :country_id, countries, { selected: ship_address_country.id }, { "data-dependent-select-target": "source", "data-action": "dependent-select#handleSelectChange" }
|
||||
|
||||
%div.checkout-input
|
||||
= ship_address.label :state_id, t("split_checkout.step1.address.state_id.label")
|
||||
= ship_address.select :state_id, states_for_country(ship_address_country), { selected: @order.ship_address&.state_id }, { "data-dependent-select-target": "select" }
|
||||
|
||||
- if spree_current_user
|
||||
%div.checkout-input{ "data-toggle-target": "content", style: "display: #{display_ship_address ? 'block' : 'none'}" }
|
||||
= f.check_box :save_ship_address
|
||||
= f.label :save_ship_address, t(:checkout_default_ship_address)
|
||||
|
||||
.div.checkout-input
|
||||
= f.label :special_instructions, t(:checkout_instructions)
|
||||
= f.text_area :special_instructions, size: "60x4"
|
||||
|
||||
%div.checkout-submit
|
||||
= f.submit t("split_checkout.step1.submit"), class: "button primary", disabled: @terms_and_conditions_accepted == false || @platform_tos_accepted == false
|
||||
%a.button.cancel{href: main_app.cart_path}
|
||||
= t("split_checkout.step1.cancel")
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
- content_for :injection_data do
|
||||
= inject_saved_credit_cards
|
||||
|
||||
%div.checkout-step{"class": if checkout_step?(:summary) then "checkout-summary" end}
|
||||
= form_with url: checkout_update_path(checkout_step), model: @order, method: :put,
|
||||
data: { remote: "true" } do |form|
|
||||
|
||||
= render "split_checkout/#{checkout_step}", f: form
|
||||
%div.checkout-step{ class: "#{'checkout-summary' if checkout_step?(:summary)}" }
|
||||
= render "split_checkout/#{checkout_step}"
|
||||
|
||||
@@ -1,37 +1,44 @@
|
||||
.medium-6
|
||||
%div.checkout-substep{"data-controller": "paymentmethod"}
|
||||
= render partial: "split_checkout/voucher_section", formats: [:cable_ready], locals: { order: @order, voucher_adjustment: @voucher_adjustment }
|
||||
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step2.payment_method.title")
|
||||
.medium-6#checkout-payment-methods
|
||||
- if feature?(:vouchers, spree_current_user) && @order.distributor.vouchers.present?
|
||||
%div.checkout-substep
|
||||
= render partial: "split_checkout/voucher_section", locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
|
||||
|
||||
- selected_payment_method = @order.payments&.with_state(:checkout)&.first&.payment_method_id
|
||||
- selected_payment_method ||= available_payment_methods[0].id if available_payment_methods.length == 1
|
||||
- available_payment_methods.each do |payment_method|
|
||||
%div.checkout-input.checkout-input-radio
|
||||
= f.radio_button :payment_method_id, payment_method.id,
|
||||
id: "payment_method_#{payment_method.id}",
|
||||
name: "order[payments_attributes][][payment_method_id]",
|
||||
checked: (payment_method.id == selected_payment_method),
|
||||
"data-action": "paymentmethod#selectPaymentMethod",
|
||||
"data-paymentmethod-id": "#{payment_method.id}",
|
||||
"data-paymentmethod-target": "input"
|
||||
= f.label :payment_method_id, "#{payment_method.name}", for: "payment_method_#{payment_method.id}"
|
||||
%em.fees=payment_or_shipping_price(payment_method, @order)
|
||||
= form_with url: checkout_update_path(local_assigns[:step] || checkout_step), model: @order, method: :put, data: { remote: "true" } do |f|
|
||||
%div.checkout-substep{"data-controller": "paymentmethod"}
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step2.payment_method.title")
|
||||
|
||||
.paymentmethod-container{"data-paymentmethod-id": "#{payment_method.id}", style: "display: #{payment_method.id == selected_payment_method ? "block" : "none"}"}
|
||||
- if payment_method.description && !payment_method.description.empty?
|
||||
.paymentmethod-description.panel
|
||||
#{payment_method.description}
|
||||
.paymentmethod-form
|
||||
= render partial: "split_checkout/payment/#{payment_method.method_type}", locals: { payment_method: payment_method, f: f }
|
||||
- if @order.zero_priced_order?
|
||||
%h3= t(:no_payment_required)
|
||||
= hidden_field_tag "order[payments_attributes][][amount]", 0
|
||||
- else
|
||||
- selected_payment_method = @order.payments&.with_state(:checkout)&.first&.payment_method_id
|
||||
- selected_payment_method ||= available_payment_methods[0].id if available_payment_methods.length == 1
|
||||
- available_payment_methods.each do |payment_method|
|
||||
%div.checkout-input.checkout-input-radio
|
||||
= f.radio_button :payment_method_id, payment_method.id,
|
||||
id: "payment_method_#{payment_method.id}",
|
||||
name: "order[payments_attributes][][payment_method_id]",
|
||||
checked: (payment_method.id == selected_payment_method),
|
||||
"data-action": "paymentmethod#selectPaymentMethod",
|
||||
"data-paymentmethod-id": "#{payment_method.id}",
|
||||
"data-paymentmethod-target": "input"
|
||||
= f.label :payment_method_id, "#{payment_method.name}", for: "payment_method_#{payment_method.id}"
|
||||
%em.fees=payment_or_shipping_price(payment_method, @order)
|
||||
|
||||
= f.error_message_on :payment_method, standalone: true
|
||||
|
||||
%div.checkout-substep
|
||||
= t("split_checkout.step2.explaination")
|
||||
.paymentmethod-container{"data-paymentmethod-id": "#{payment_method.id}", style: "display: #{payment_method.id == selected_payment_method ? "block" : "none"}"}
|
||||
- if payment_method.description && !payment_method.description.empty?
|
||||
.paymentmethod-description.panel
|
||||
#{payment_method.description}
|
||||
.paymentmethod-form
|
||||
= render partial: "split_checkout/payment/#{payment_method.method_type}", locals: { payment_method: payment_method, f: f }
|
||||
|
||||
%div.checkout-submit
|
||||
= f.submit t("split_checkout.step2.submit"), class: "button primary", disabled: @terms_and_conditions_accepted == false || @platform_tos_accepted == false
|
||||
%a.button.cancel{href: main_app.checkout_step_path(:details)}
|
||||
= t("split_checkout.step2.cancel")
|
||||
= f.error_message_on :payment_method, standalone: true
|
||||
|
||||
%div.checkout-substep
|
||||
= t("split_checkout.step2.explaination")
|
||||
|
||||
%div.checkout-submit
|
||||
= f.submit t("split_checkout.step2.submit"), class: "button primary", disabled: @terms_and_conditions_accepted == false || @platform_tos_accepted == false
|
||||
%a.button.cancel{href: main_app.checkout_step_path(:details)}
|
||||
= t("split_checkout.step2.cancel")
|
||||
|
||||
@@ -1,103 +1,111 @@
|
||||
.summary-main
|
||||
= render partial: "split_checkout/already_ordered" if show_bought_items? && checkout_step?(:summary)
|
||||
.checkout-substep
|
||||
.checkout-title
|
||||
= t("split_checkout.step3.delivery_details.title")
|
||||
%a.summary-edit{href: main_app.checkout_step_path(:details)}
|
||||
= t("split_checkout.step3.delivery_details.edit")
|
||||
= form_with url: checkout_update_path(checkout_step), model: @order, method: :put, data: { remote: "true" } do |f|
|
||||
.summary-main
|
||||
= render partial: "split_checkout/already_ordered" if show_bought_items? && checkout_step?(:summary)
|
||||
.checkout-substep
|
||||
.checkout-title
|
||||
= t("split_checkout.step3.delivery_details.title")
|
||||
%a.summary-edit{href: main_app.checkout_step_path(:details)}
|
||||
= t("split_checkout.step3.delivery_details.edit")
|
||||
|
||||
.summary-subtitle
|
||||
= @order.shipping_method.name
|
||||
%em.fees= payment_or_shipping_price(@order.shipping_method, @order)
|
||||
.two-columns
|
||||
%div
|
||||
.summary-subtitle
|
||||
= t("split_checkout.step3.delivery_details.address")
|
||||
%span
|
||||
= @order.bill_address.firstname
|
||||
= @order.bill_address.lastname
|
||||
%div
|
||||
= @order.bill_address.phone
|
||||
.summary-subtitle
|
||||
= @order.shipping_method.name
|
||||
%em.fees= payment_or_shipping_price(@order.shipping_method, @order)
|
||||
.two-columns
|
||||
%div
|
||||
= @order.user.email if @order.user
|
||||
%br
|
||||
%div
|
||||
= @order.bill_address.address1
|
||||
- unless @order.bill_address.address2.blank?
|
||||
.summary-subtitle
|
||||
= t("split_checkout.step3.delivery_details.address")
|
||||
%span
|
||||
= @order.bill_address.firstname
|
||||
= @order.bill_address.lastname
|
||||
%div
|
||||
= @order.bill_address.address2
|
||||
%div
|
||||
= @order.bill_address.city
|
||||
%div
|
||||
= @order.bill_address.state
|
||||
%div
|
||||
= @order.bill_address.zipcode
|
||||
%div
|
||||
= @order.bill_address.country
|
||||
- if @order.special_instructions.present?
|
||||
= @order.bill_address.phone
|
||||
%div
|
||||
= @order.user.email if @order.user
|
||||
%br
|
||||
%em
|
||||
= @order.special_instructions
|
||||
- if @order.shipping_method.description.present?
|
||||
%div
|
||||
.summary-subtitle
|
||||
= t("split_checkout.step3.delivery_details.instructions")
|
||||
%div
|
||||
= @order.shipping_method.description
|
||||
|
||||
%hr
|
||||
= @order.bill_address.address1
|
||||
- unless @order.bill_address.address2.blank?
|
||||
%div
|
||||
= @order.bill_address.address2
|
||||
%div
|
||||
= @order.bill_address.city
|
||||
%div
|
||||
= @order.bill_address.state
|
||||
%div
|
||||
= @order.bill_address.zipcode
|
||||
%div
|
||||
= @order.bill_address.country
|
||||
- if @order.special_instructions.present?
|
||||
%br
|
||||
%em
|
||||
= @order.special_instructions
|
||||
- if @order.shipping_method.description.present?
|
||||
%div
|
||||
.summary-subtitle
|
||||
= t("split_checkout.step3.delivery_details.instructions")
|
||||
%div
|
||||
= @order.shipping_method.description
|
||||
|
||||
.checkout-substep
|
||||
.checkout-title
|
||||
= t("split_checkout.step3.payment_method.title")
|
||||
%a.summary-edit{href: main_app.checkout_step_path(:payment)}
|
||||
= t("split_checkout.step3.payment_method.edit")
|
||||
.two-columns
|
||||
%div
|
||||
%hr
|
||||
|
||||
.checkout-substep
|
||||
.checkout-title
|
||||
= t("split_checkout.step3.payment_method.title")
|
||||
%a.summary-edit{href: main_app.checkout_step_path(:payment)}
|
||||
= t("split_checkout.step3.payment_method.edit")
|
||||
.two-columns
|
||||
- payment_method = last_payment_method(@order)
|
||||
= payment_method&.name
|
||||
%em.fees=payment_or_shipping_price(payment_method, @order)
|
||||
- if payment_method&.description.present?
|
||||
%div
|
||||
.summary-subtitle
|
||||
= t("split_checkout.step3.payment_method.instructions")
|
||||
- if payment_method
|
||||
= payment_method.name
|
||||
%em.fees
|
||||
= payment_or_shipping_price(payment_method, @order)
|
||||
- elsif @order.zero_priced_order?
|
||||
%h4= t(:no_payment_required)
|
||||
|
||||
- if payment_method&.description.present?
|
||||
%div
|
||||
= last_payment_method(@order)&.description
|
||||
.summary-subtitle
|
||||
= t("split_checkout.step3.payment_method.instructions")
|
||||
%div
|
||||
= payment_method&.description
|
||||
|
||||
|
||||
%div.checkout-substep
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step3.order.title")
|
||||
%a.summary-edit{href: main_app.cart_path}
|
||||
= t("split_checkout.step3.order.edit")
|
||||
|
||||
= render 'spree/orders/summary', order: @order, display_footer: false
|
||||
%div.checkout-substep
|
||||
%div.checkout-title
|
||||
= t("split_checkout.step3.order.title")
|
||||
%a.summary-edit{href: main_app.cart_path}
|
||||
= t("split_checkout.step3.order.edit")
|
||||
|
||||
= render 'spree/orders/summary', order: @order, display_footer: false
|
||||
|
||||
|
||||
.summary-right{ "data-controller": "sticky", "data-sticky-target": "container" }
|
||||
.summary-right-line.total
|
||||
.summary-right-line-label= t :order_total_price
|
||||
.summary-right-line-value#order_total= @order.display_total.to_html
|
||||
|
||||
.summary-right-line
|
||||
.summary-right-line-label= t :order_produce
|
||||
.summary-right-line-value= display_checkout_subtotal(@order)
|
||||
.summary-right{ "data-controller": "sticky", "data-sticky-target": "container" }
|
||||
.summary-right-line.total
|
||||
.summary-right-line-label= t :order_total_price
|
||||
.summary-right-line-value#order_total= @order.display_total.to_html
|
||||
|
||||
- checkout_adjustments_for(@order, exclude: [:line_item]).reverse_each do |adjustment|
|
||||
.summary-right-line
|
||||
-if adjustment.originator_type == 'Voucher'
|
||||
.summary-right-line-label.voucher= adjustment.label
|
||||
.summary-right-line-value.voucher= adjustment.display_amount.to_html
|
||||
-else
|
||||
.summary-right-line-label= adjustment.label
|
||||
.summary-right-line-value= adjustment.display_amount.to_html
|
||||
.summary-right-line-label= t :order_produce
|
||||
.summary-right-line-value= display_checkout_subtotal(@order)
|
||||
|
||||
- if @order.total_tax > 0
|
||||
.summary-right-line
|
||||
.summary-right-line-label= t :order_includes_tax
|
||||
.summary-right-line-value#tax-row= display_checkout_tax_total(@order)
|
||||
|
||||
.checkout-submit
|
||||
- if any_terms_required?(@order.distributor)
|
||||
= render partial: "terms_and_conditions", locals: { f: f }
|
||||
= f.submit t("split_checkout.step3.submit"), name: "confirm_order", class: "button primary", disabled: @terms_and_conditions_accepted == false || @platform_tos_accepted == false
|
||||
- checkout_adjustments_for(@order, exclude: [:line_item]).reverse_each do |adjustment|
|
||||
.summary-right-line
|
||||
- if adjustment.originator_type == 'Voucher'
|
||||
.summary-right-line-label.voucher
|
||||
= "#{t(:voucher)}:"
|
||||
= adjustment.label
|
||||
.summary-right-line-value.voucher= adjustment.display_amount.to_html
|
||||
- else
|
||||
.summary-right-line-label= adjustment.label
|
||||
.summary-right-line-value= adjustment.display_amount.to_html
|
||||
|
||||
- if @order.total_tax > 0
|
||||
.summary-right-line
|
||||
.summary-right-line-label= t :order_includes_tax
|
||||
.summary-right-line-value#tax-row= display_checkout_tax_total(@order)
|
||||
|
||||
.checkout-submit
|
||||
- if any_terms_required?(@order.distributor)
|
||||
= render partial: "terms_and_conditions", locals: { f: f }
|
||||
= f.submit t("split_checkout.step3.submit"), name: "confirm_order", class: "button primary", disabled: @terms_and_conditions_accepted == false || @platform_tos_accepted == false
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
%div#voucher-section
|
||||
- if order.distributor.vouchers.present?
|
||||
.checkout-title
|
||||
= t("split_checkout.step2.voucher.apply_voucher")
|
||||
.checkout-input
|
||||
.two-columns-inputs.voucher{"data-controller": "toggle-button-disabled"}
|
||||
- if voucher_adjustment.present?
|
||||
%span.button.voucher-added
|
||||
%i.ofn-i_051-check-big
|
||||
= t("split_checkout.step2.voucher.voucher", voucher_amount: voucher_adjustment.originator.display_value)
|
||||
= link_to t("split_checkout.step2.voucher.remove_code"), voucher_adjustment_path(id: voucher_adjustment.id), method: "delete", data: { confirm: t("split_checkout.step2.voucher.confirm_delete") }
|
||||
- # This might not be true, ie payment method including a fee which wouldn't be covered by voucher or tax implication raising total to be bigger than the voucher amount ?
|
||||
- if voucher_adjustment.originator.amount > order.total
|
||||
.checkout-input
|
||||
%span.formError.standalone
|
||||
= t("split_checkout.step2.voucher.warning_forfeit_remaining_amount")
|
||||
- else
|
||||
= text_field_tag "[order][voucher_code]", params.dig(:order, :voucher_code), data: { action: "input->toggle-button-disabled#inputIsChanged", }, placeholder: t("split_checkout.step2.voucher.placeholder") , class: "voucher"
|
||||
= submit_tag t("split_checkout.step2.voucher.apply"), name: "apply_voucher", disabled: true, class: "button cancel voucher", "data-disable-with": false, data: { "toggle-button-disabled-target": "button" }
|
||||
25
app/views/split_checkout/_voucher_section.html.haml
Normal file
25
app/views/split_checkout/_voucher_section.html.haml
Normal file
@@ -0,0 +1,25 @@
|
||||
%div#voucher-section
|
||||
.checkout-title
|
||||
= t("split_checkout.step2.voucher.apply_voucher")
|
||||
.checkout-input{"data-controller": "toggle-button-disabled"}
|
||||
= form_with url: voucher_adjustments_path, model: @order, method: :post, data: { remote: true } do |form|
|
||||
- if voucher_adjustment.present?
|
||||
.two-columns-inputs.voucher
|
||||
%span.button.voucher-added
|
||||
%i.ofn-i_051-check-big
|
||||
= t("split_checkout.step2.voucher.voucher", voucher_amount: voucher_adjustment.originator.display_value)
|
||||
= link_to t("split_checkout.step2.voucher.remove_code"), voucher_adjustment_path(id: voucher_adjustment.id), method: "delete", data: { confirm: t("split_checkout.step2.voucher.confirm_delete") }
|
||||
|
||||
- # This might not be true, ie payment method including a fee which wouldn't be covered by voucher or tax implication raising total to be bigger than the voucher amount ?
|
||||
- if voucher_adjustment.originator.amount > order.pre_discount_total
|
||||
.checkout-input
|
||||
%span.formError.standalone
|
||||
= t("split_checkout.step2.voucher.warning_forfeit_remaining_amount")
|
||||
- else
|
||||
.two-columns-inputs
|
||||
%div.checkout-input
|
||||
= form.text_field :voucher_code, value: params.dig(:order, :voucher_code), data: { action: "input->toggle-button-disabled#inputIsChanged" }, placeholder: t("split_checkout.step2.voucher.placeholder"), class: "voucher"
|
||||
= form.error_message_on :voucher_code
|
||||
|
||||
%div.checkout-input
|
||||
= form.submit t("split_checkout.step2.voucher.apply"), disabled: true, class: "button cancel voucher-button", "data-disable-with": false, data: { "toggle-button-disabled-target": "button" }
|
||||
@@ -1,15 +1,17 @@
|
||||
- saved_credit_cards = spree_current_user&.credit_cards&.with_payment_profile.to_a
|
||||
|
||||
%div{"data-controller": "stripe-cards", "data-paymentmethod-id": "#{payment_method.id}" }
|
||||
- if @saved_credit_cards.any?
|
||||
- if saved_credit_cards.any?
|
||||
.checkout-input
|
||||
%label
|
||||
= t('split_checkout.step2.form.stripe.use_saved_card')
|
||||
= select_tag :existing_card_id,
|
||||
options_for_select(stripe_card_options(@saved_credit_cards) + [[t('split_checkout.step2.form.stripe.create_new_card'), ""]], @selected_card),
|
||||
options_for_select(stripe_card_options(saved_credit_cards) + [[t('split_checkout.step2.form.stripe.create_new_card'), ""]], nil),
|
||||
{ "data-action": "change->stripe-cards#onSelectCard", "data-stripe-cards-target": "select" }
|
||||
|
||||
%div{"data-stripe-cards-target": "stripeelements"}
|
||||
.checkout-input
|
||||
- if @saved_credit_cards.none?
|
||||
- if saved_credit_cards.none?
|
||||
%label
|
||||
= t('split_checkout.step2.form.stripe.use_new_card')
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
%tr{class: "#{cycle('odd', 'even')}"}
|
||||
%td= pretty_time(payment.created_at)
|
||||
%td.align-center= payment.display_amount.to_html
|
||||
%td.align-center= link_to payment_method_name(payment), spree.admin_order_payment_path(@order, payment)
|
||||
%td.align-center
|
||||
- if payment.payment_method_id
|
||||
= link_to payment_method_name(payment), spree.admin_order_payment_path(@order, payment)
|
||||
%td.align-center
|
||||
%span{class: "state #{payment.state}"}= t(payment.state, scope: "spree.payment_states", default: payment.state.capitalize)
|
||||
%td.actions
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
%tr.total
|
||||
%td.text-right{:colspan => "3"}
|
||||
%strong
|
||||
- if adjustment.originator_type == "Voucher"
|
||||
= "#{t(:voucher)}:"
|
||||
= adjustment.label
|
||||
%td.text-right.total
|
||||
%span= adjustment.display_amount.to_html
|
||||
|
||||
@@ -11,11 +11,15 @@
|
||||
%strong
|
||||
= order.display_total.to_html
|
||||
.pad
|
||||
.text-big
|
||||
= t :order_payment
|
||||
%strong= last_payment_method(order)&.name
|
||||
%p.text-small.text-skinny.pre-line.word-wrap
|
||||
%em= last_payment_method(order)&.description
|
||||
- if (order_payment_method = last_payment_method(order))
|
||||
.text-big
|
||||
= t :order_payment
|
||||
%strong= order_payment_method&.name
|
||||
%p.text-small.text-skinny.pre-line.word-wrap
|
||||
%em= order_payment_method&.description
|
||||
- else
|
||||
.text-big
|
||||
= t(:no_payment_required)
|
||||
|
||||
.order-summary.text-small
|
||||
%strong
|
||||
|
||||
@@ -412,22 +412,18 @@
|
||||
justify-content: normal;
|
||||
align-items: center;
|
||||
|
||||
input {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
&.cancel {
|
||||
width: 30%;
|
||||
border-radius: 0.5em;
|
||||
padding:0;
|
||||
height: 2.5em;
|
||||
background-color: $teal-400
|
||||
}
|
||||
.voucher-button {
|
||||
&.cancel {
|
||||
width: 30%;
|
||||
border-radius: 0.35em;
|
||||
padding:0;
|
||||
height: 2.5em;
|
||||
background-color: $teal-400
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -450,6 +450,7 @@ en:
|
||||
none: None
|
||||
notes: Notes
|
||||
error: Error
|
||||
voucher: Voucher
|
||||
processing_payment: "Processing payment..."
|
||||
no_pending_payments: "No pending payments"
|
||||
invalid_payment_state: "Invalid payment state: %{state}"
|
||||
@@ -2124,6 +2125,7 @@ en:
|
||||
order_not_paid: NOT PAID
|
||||
order_total: Total order
|
||||
order_payment: "Paying via:"
|
||||
no_payment_required: "No payment required"
|
||||
order_billing_address: Billing address
|
||||
order_delivery_on: Delivery on
|
||||
order_delivery_address: Delivery address
|
||||
|
||||
@@ -112,7 +112,7 @@ Openfoodnetwork::Application.routes.draw do
|
||||
get '/:id/shop', to: 'enterprises#shop', as: 'enterprise_shop'
|
||||
get "/enterprises/:permalink", to: redirect("/") # Legacy enterprise URL
|
||||
|
||||
resources :voucher_adjustments, only: [:destroy]
|
||||
resources :voucher_adjustments, only: [:create, :destroy]
|
||||
|
||||
get 'sitemap.xml', to: 'sitemap#index', defaults: { format: 'xml' }
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ module Reporting
|
||||
|
||||
def total_by_payment_method(orders, pay_method)
|
||||
orders.map(&:payments).flatten.select { |payment|
|
||||
payment.completed? && payment.payment_method.name.to_s.include?(pay_method)
|
||||
payment.completed? && payment.payment_method&.name.to_s.include?(pay_method)
|
||||
}.sum(&:amount)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,7 +17,7 @@ module Reporting
|
||||
{
|
||||
payment_state: proc { |payments| payment_state(payments.first.order) },
|
||||
distributor: proc { |payments| payments.first.order.distributor.name },
|
||||
payment_type: proc { |payments| payments.first.payment_method.name },
|
||||
payment_type: proc { |payments| payments.first.payment_method&.name },
|
||||
total_price: proc { |payments| payments.sum(&:amount) }
|
||||
}
|
||||
end
|
||||
|
||||
@@ -212,6 +212,26 @@ describe SplitCheckoutController, type: :controller do
|
||||
end
|
||||
end
|
||||
|
||||
context "with a zero-priced order" do
|
||||
let(:params) do
|
||||
{ step: "payment", order: { payments_attributes: [{ amount: 0 }] } }
|
||||
end
|
||||
|
||||
before do
|
||||
order.line_items.first.update(price: 0)
|
||||
order.update_totals_and_states
|
||||
end
|
||||
|
||||
it "allows proceeding to confirmation" do
|
||||
put :update, params: params
|
||||
|
||||
expect(response).to redirect_to checkout_step_path(:summary)
|
||||
expect(order.reload.state).to eq "confirmation"
|
||||
expect(order.payments.count).to eq 1
|
||||
expect(order.payments.first.amount).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
context "with a saved credit card" do
|
||||
let!(:saved_card) { create(:stored_credit_card, user: user) }
|
||||
let(:checkout_params) do
|
||||
@@ -233,73 +253,6 @@ describe SplitCheckoutController, type: :controller do
|
||||
expect(order.payments.first.source.id).to eq saved_card.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "Vouchers" do
|
||||
let(:voucher) { create(:voucher, code: 'some_code', enterprise: distributor) }
|
||||
|
||||
describe "adding a voucher" do
|
||||
let(:checkout_params) do
|
||||
{
|
||||
apply_voucher: "true",
|
||||
order: {
|
||||
voucher_code: voucher.code
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "adds a voucher to the order" do
|
||||
# Set the headers to simulate a cable_ready request
|
||||
request.headers["accept"] = "text/vnd.cable-ready.json"
|
||||
|
||||
put :update, params: params
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(order.reload.voucher_adjustments.length).to eq(1)
|
||||
end
|
||||
|
||||
context "when voucher doesn't exist" do
|
||||
let(:checkout_params) do
|
||||
{
|
||||
apply_voucher: "true",
|
||||
order: {
|
||||
voucher_code: "non_voucher"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "returns 422 and an error message" do
|
||||
put :update, params: params
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(flash[:error]).to match "Voucher Not found"
|
||||
end
|
||||
end
|
||||
|
||||
context "when adding fails" do
|
||||
it "returns 422 and an error message" do
|
||||
# Create a non valid adjustment
|
||||
adjustment = build(:adjustment, label: nil)
|
||||
allow(voucher).to receive(:create_adjustment).and_return(adjustment)
|
||||
allow(Voucher).to receive(:find_by).and_return(voucher)
|
||||
|
||||
put :update, params: params
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(flash[:error]).to match(
|
||||
"There was an error while adding the voucher and Label can't be blank"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "with an html request" do
|
||||
it "redirects to the payment step" do
|
||||
put :update, params: params
|
||||
|
||||
expect(response).to redirect_to(checkout_step_path(:payment))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "summary step" do
|
||||
|
||||
@@ -50,5 +50,22 @@ module Spree
|
||||
|
||||
order.process_payments!
|
||||
end
|
||||
|
||||
context "with a zero-priced order" do
|
||||
let!(:zero_order) {
|
||||
create(:order, state: "payment", line_items: [create(:line_item, price: 0)])
|
||||
}
|
||||
let!(:zero_payment) { create(:payment, order: zero_order, amount: 0, state: "checkout") }
|
||||
let(:updater) { OrderManagement::Order::Updater.new(zero_order) }
|
||||
|
||||
it "processes payments successfully" do
|
||||
zero_order.process_payments!
|
||||
updater.update_payment_state
|
||||
|
||||
expect(zero_order.payment_state).to eq "paid"
|
||||
expect(zero_payment.reload.state).to eq "completed"
|
||||
expect(zero_payment.captured_at).to_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,55 +4,96 @@ require 'spec_helper'
|
||||
|
||||
describe VoucherAdjustmentsController, type: :request do
|
||||
let(:user) { order.user }
|
||||
let(:address) { create(:address) }
|
||||
let(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let(:order) { create( :order_with_line_items, line_items_count: 1, distributor: distributor) }
|
||||
let(:order_cycle) { create(:order_cycle, distributors: [distributor]) }
|
||||
let(:exchange) { order_cycle.exchanges.outgoing.first }
|
||||
let(:order) do
|
||||
create(
|
||||
:order_with_line_items,
|
||||
line_items_count: 1,
|
||||
distributor: distributor,
|
||||
order_cycle: order_cycle,
|
||||
bill_address: address,
|
||||
ship_address: address
|
||||
)
|
||||
end
|
||||
let(:shipping_method) { distributor.shipping_methods.first }
|
||||
let(:voucher) { create(:voucher, code: 'some_code', enterprise: distributor) }
|
||||
let!(:adjustment) { voucher.create_adjustment(voucher.code, order) }
|
||||
|
||||
before do
|
||||
# Make sure the order is created by the order user, the factory doesn't set ip properly
|
||||
order.created_by = user
|
||||
order.save!
|
||||
order.update!(created_by: user)
|
||||
|
||||
order.select_shipping_method shipping_method.id
|
||||
OrderWorkflow.new(order).advance_to_payment
|
||||
|
||||
sign_in user
|
||||
end
|
||||
|
||||
describe "DELETE voucher_adjustments/:id" do
|
||||
let(:cable_ready_header) { { accept: "text/vnd.cable-ready.json" } }
|
||||
describe "POST voucher_adjustments" do
|
||||
let(:params) { { order: { voucher_code: voucher.code } } }
|
||||
|
||||
context "with a cable ready request" do
|
||||
it "deletes the voucher adjustment" do
|
||||
delete("/voucher_adjustments/#{adjustment.id}", headers: cable_ready_header)
|
||||
it "adds a voucher to the user's current order" do
|
||||
post "/voucher_adjustments", params: params
|
||||
|
||||
expect(order.voucher_adjustments.length).to eq(0)
|
||||
end
|
||||
expect(response).to be_successful
|
||||
expect(order.reload.voucher_adjustments.length).to eq(1)
|
||||
end
|
||||
|
||||
it "render a succesful response" do
|
||||
delete("/voucher_adjustments/#{adjustment.id}", headers: cable_ready_header)
|
||||
context "when voucher doesn't exist" do
|
||||
let(:params) { { order: { voucher_code: "non_voucher" } } }
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
it "returns 422 and an error message" do
|
||||
post "/voucher_adjustments", params: params
|
||||
|
||||
context "when adjustment doesn't exits" do
|
||||
it "does nothing" do
|
||||
delete "/voucher_adjustments/-1", headers: cable_ready_header
|
||||
|
||||
expect(order.voucher_adjustments.length).to eq(1)
|
||||
end
|
||||
|
||||
it "render a succesful response" do
|
||||
delete "/voucher_adjustments/-1", headers: cable_ready_header
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
expect(response).to be_unprocessable
|
||||
expect(flash[:error]).to match "Voucher code Not found"
|
||||
end
|
||||
end
|
||||
|
||||
context "with an html request" do
|
||||
it "redirect to checkout payment step" do
|
||||
delete "/voucher_adjustments/#{adjustment.id}"
|
||||
context "when adding fails" do
|
||||
it "returns 422 and an error message" do
|
||||
# Create a non valid adjustment
|
||||
bad_adjustment = build(:adjustment, label: nil)
|
||||
allow(voucher).to receive(:create_adjustment).and_return(bad_adjustment)
|
||||
allow(Voucher).to receive(:find_by).and_return(voucher)
|
||||
|
||||
expect(response).to redirect_to(checkout_step_path(:payment))
|
||||
post "/voucher_adjustments", params: params
|
||||
|
||||
expect(response).to be_unprocessable
|
||||
expect(flash[:error]).to match(
|
||||
"There was an error while adding the voucher and Label can't be blank"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE voucher_adjustments/:id" do
|
||||
let!(:adjustment) { voucher.create_adjustment(voucher.code, order) }
|
||||
|
||||
it "deletes the voucher adjustment" do
|
||||
delete "/voucher_adjustments/#{adjustment.id}"
|
||||
|
||||
expect(order.voucher_adjustments.reload.length).to eq(0)
|
||||
end
|
||||
|
||||
it "render a success response" do
|
||||
delete "/voucher_adjustments/#{adjustment.id}"
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
context "when adjustment doesn't exits" do
|
||||
it "does nothing" do
|
||||
delete "/voucher_adjustments/-1"
|
||||
|
||||
expect(order.voucher_adjustments.reload.length).to eq(1)
|
||||
end
|
||||
|
||||
it "render a success response" do
|
||||
delete "/voucher_adjustments/-1"
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -707,6 +707,8 @@ describe "As a consumer, I want to checkout my order" do
|
||||
end
|
||||
|
||||
describe "vouchers" do
|
||||
before { Flipper.enable :vouchers }
|
||||
|
||||
context "with no voucher available" do
|
||||
before do
|
||||
visit checkout_step_path(:payment)
|
||||
@@ -769,7 +771,7 @@ describe "As a consumer, I want to checkout my order" do
|
||||
fill_in "Enter voucher code", with: "non_code"
|
||||
click_button("Apply")
|
||||
|
||||
expect(page).to have_content("Voucher Not found")
|
||||
expect(page).to have_content("Voucher code Not found")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -786,9 +788,10 @@ describe "As a consumer, I want to checkout my order" do
|
||||
click_on "Remove code"
|
||||
end
|
||||
|
||||
within '.voucher' do
|
||||
within '#voucher-section' do
|
||||
expect(page).to have_button("Apply", disabled: true)
|
||||
end
|
||||
|
||||
expect(order.voucher_adjustments.length).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -106,6 +106,8 @@ describe "As a consumer, I want to see adjustment breakdown" do
|
||||
end
|
||||
|
||||
context "when using a voucher" do
|
||||
before { Flipper.enable :vouchers }
|
||||
|
||||
let!(:voucher) do
|
||||
create(:voucher, code: 'some_code', enterprise: distributor, amount: 10)
|
||||
end
|
||||
|
||||
@@ -63,6 +63,7 @@ describe "As a consumer, I want to see adjustment breakdown" do
|
||||
before do
|
||||
# assures tax is charged in dependence of shipping address
|
||||
Spree::Config.set(tax_using_ship_address: true)
|
||||
Flipper.enable :vouchers
|
||||
end
|
||||
|
||||
describe "a not-included tax" do
|
||||
@@ -115,7 +116,7 @@ describe "As a consumer, I want to see adjustment breakdown" do
|
||||
expect(page).to have_selector('#tax-row', text: with_currency(1.30))
|
||||
end
|
||||
|
||||
pending "when using a voucher" do
|
||||
context "when using a voucher" do
|
||||
let!(:voucher) do
|
||||
create(:voucher, code: 'some_code', enterprise: distributor, amount: 10)
|
||||
end
|
||||
@@ -126,9 +127,11 @@ describe "As a consumer, I want to see adjustment breakdown" do
|
||||
choose "Delivery"
|
||||
|
||||
click_button "Next - Payment method"
|
||||
|
||||
# add Voucher
|
||||
fill_in "Enter voucher code", with: voucher.code
|
||||
click_button("Apply")
|
||||
expect(page).to have_selector ".voucher-added"
|
||||
|
||||
click_on "Next - Order summary"
|
||||
click_on "Complete order"
|
||||
|
||||
Reference in New Issue
Block a user