Merge pull request #3164 from luisramos0/2-0-stable-dec-3rd

[Spree Upgrade] Merging master into 2-0-stable (first run in Dec2018)
This commit is contained in:
Maikel
2018-12-04 13:38:02 +11:00
committed by GitHub
59 changed files with 494 additions and 197 deletions

View File

@@ -186,6 +186,9 @@ Lint/AssignmentInCondition:
Metrics/AbcSize:
Max: 15
Metrics/BlockLength:
ExcludedMethods: ["describe", "context"]
Metrics/BlockNesting:
Max: 3

View File

@@ -154,4 +154,6 @@ group :development do
# While we don't require this gem directly, no dependents forced the upgrade to a version
# greater than 1.0.9, so we just required the latest available version here.
gem 'eventmachine', '>= 1.2.3'
gem 'rack-mini-profiler', '< 1.0.0'
end

View File

@@ -578,6 +578,8 @@ GEM
rack (1.4.7)
rack-cache (1.8.0)
rack (>= 0.4)
rack-mini-profiler (0.10.7)
rack (>= 1.2.0)
rack-rewrite (1.5.1)
rack-ssl (1.3.4)
rack
@@ -683,7 +685,7 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
skylight (1.6.1)
skylight (1.7.1)
activesupport (>= 3.0.0)
spinjs-rails (1.3)
rails (>= 3.1)
@@ -716,7 +718,7 @@ GEM
unicorn (5.4.1)
kgio (~> 2.6)
raindrops (~> 0.7)
unicorn-rails (1.1.0)
unicorn-rails (2.2.1)
rack
unicorn
uuidtools (2.1.5)
@@ -809,6 +811,7 @@ DEPENDENCIES
poltergeist (>= 1.16.0)
pry-byebug (>= 3.4.3)
rabl
rack-mini-profiler (< 1.0.0)
rack-rewrite
rack-ssl
rails (~> 3.2.22)

View File

@@ -1,7 +1,7 @@
angular.module('admin.enterpriseFees').directive 'spreeDeleteResource', ->
(scope, element, attrs) ->
if scope.enterprise_fee.id
url = '/admin/enterprise_fees/' + scope.enterprise_fee.id
url = '/api/enterprise_fees/' + scope.enterprise_fee.id
html = '<a href="' + url + '" class="delete-resource icon_link icon-trash no-text" data-action="remove" data-confirm="' + t('are_you_sure') + '" url="' + url + '"></a>'
#var html = '<a href="'+url+'" class="delete-resource" data-confirm="Are you sure?"><img alt="Delete" src="/assets/admin/icons/delete.png" /> Delete</a>';
element.append html

View File

@@ -1,25 +1,22 @@
Darkswarm.controller "AccordionCtrl", ($scope, localStorageService, $timeout, $document, CurrentHub) ->
key = "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"
value = if localStorageService.get(key) then {} else { details: true, billing: false, shipping: false, payment: false }
localStorageService.bind $scope, "accordion", value, key
$scope.accordionSections = ["details", "billing", "shipping", "payment"]
# Scrolling is confused by our position:fixed top bar - add an offset to scroll
# to the correct location, plus 5px buffer
offset_height = $("nav.top-bar").height() + 5
$scope.accordion = { details: true, billing: true, shipping: true, payment: true }
$scope.show = (section)->
$scope.show = (section) ->
$scope.accordion[section] = true
# If we call scrollTo() directly after show(), when one of the accordions above the
# scroll location is closed by show(), scrollTo() will scroll to the old location of
# the element. Putting this in a 50 ms timeout is enough delay for the DOM to
# have updated.
$timeout ->
$document.scrollTo($("##{section}"), offset_height, 500)
, 50
$scope.scrollTo = (section) ->
# Scrolling is confused by our position:fixed top bar - add an offset to scroll
# to the correct location, plus 5px buffer
offset_height = $("nav.top-bar").height() + 5
$document.scrollTo($("##{section}"), offset_height, 400)
$scope.$on 'purchaseFormInvalid', (event, form) ->
# Scroll to first invalid section
for section in $scope.accordionSections
if not form[section].$valid
$scope.show section
$timeout ->
$scope.scrollTo(section)
, 50
break

View File

@@ -5,7 +5,7 @@ Darkswarm.controller "BillingCtrl", ($scope, $timeout) ->
$scope.summary = ->
[$scope.order.bill_address.address1,
$scope.order.bill_address.city,
$scope.order.bill_address.city,
$scope.order.bill_address.zipcode]
$timeout $scope.onTimeout
$timeout $scope.onTimeout

View File

@@ -13,11 +13,11 @@ Darkswarm.controller "DetailsCtrl", ($scope, $timeout, $http, CurrentUser, Authe
$scope.summary = ->
[$scope.fullName(),
$scope.order.email,
$scope.order.email,
$scope.order.bill_address.phone]
$scope.fullName = ->
[$scope.order.bill_address.firstname ? null,
[$scope.order.bill_address.firstname ? null,
$scope.order.bill_address.lastname ? null].join(" ").trim()
$timeout $scope.onTimeout
$timeout $scope.onTimeout

View File

@@ -2,11 +2,11 @@ window.FieldsetMixin = ($scope)->
$scope.next = (event = false)->
event.preventDefault() if event
return unless $scope.nextPanel
$scope.accordion[$scope.name] = false
$scope.show $scope.nextPanel
$scope.onTimeout = ->
if $scope[$scope.name].$valid
$scope.next()
$scope.accordion[$scope.name] = !$scope[$scope.name].$valid
$scope.valid = ->
$scope.form().$valid

View File

@@ -2,7 +2,6 @@ module Admin
class EnterpriseFeesController < ResourceController
before_filter :load_enterprise_fee_set, :only => :index
before_filter :load_data
before_filter :do_not_destroy_referenced_fees, :only => :destroy
def index
@@ -45,22 +44,6 @@ module Admin
private
def do_not_destroy_referenced_fees
product_distribution = ProductDistribution.where(:enterprise_fee_id => @object).first
if product_distribution
p = product_distribution.product
error = I18n.t(:enterprise_fees_destroy_error, id: p.id, name: p.name)
respond_with(@object) do |format|
format.html do
flash[:error] = error
redirect_to collection_url
end
format.js { render text: error, status: 403 }
end
end
end
def load_enterprise_fee_set
@enterprise_fee_set = EnterpriseFeeSet.new :collection => collection
end

View File

@@ -0,0 +1,21 @@
module Api
class EnterpriseFeesController < BaseController
respond_to :json
def destroy
authorize! :destroy, enterprise_fee
if enterprise_fee.destroy
render text: I18n.t(:successfully_removed), status: 204
else
render text: enterprise_fee.errors.full_messages.first, status: 403
end
end
private
def enterprise_fee
@enterprise_fee ||= EnterpriseFee.find_by_id params[:id]
end
end
end

View File

@@ -55,7 +55,7 @@ module EnterprisesHelper
if enterprise.sells == 'none'
enterprise.producer_profile_only ? I18n.t(:profile) : I18n.t(:supplier_only)
else
"Has Shopfront"
I18n.t(:has_shopfront)
end
end

View File

@@ -26,6 +26,7 @@ class EnterpriseFee < ActiveRecord::Base
validates_presence_of :name
before_save :ensure_valid_tax_category_settings
before_destroy :ensure_no_product_distributions
scope :for_enterprise, lambda { |enterprise| where(enterprise_id: enterprise) }
scope :for_enterprises, lambda { |enterprises| where(enterprise_id: enterprises) }
@@ -68,6 +69,15 @@ class EnterpriseFee < ActiveRecord::Base
return true
end
def ensure_no_product_distributions
dependent_distribution = ProductDistribution.where(enterprise_fee_id: self).first
return unless dependent_distribution
product = dependent_distribution.product
error = I18n.t(:enterprise_fees_destroy_error, id: product.id, name: product.name)
errors.add(:base, error)
false
end
def refresh_products_cache
OpenFoodNetwork::ProductsCache.enterprise_fee_changed self
end

View File

@@ -100,7 +100,8 @@ module ProductImport
entries[entry.line_number] = {
attributes: entry.displayable_attributes,
validates_as: entry.validates_as,
errors: entry.invalid_attributes
errors: entry.invalid_attributes,
product_validations: entry.product_validations
}
end
entries.to_json

View File

@@ -1,3 +0,0 @@
/ insert_before "[data-hook='admin_order_form_buttons']"
= render partial: 'spree/admin/orders/_form/distribution_fields'

View File

@@ -1,2 +0,0 @@
add_to_attributes "table.index, [data-hook='admin_order_form_buttons']"
attributes "ng-show" => "distributionChosen()"

View File

@@ -1,3 +0,0 @@
/ replace "code[erb-loud]:contains('button t(:update)')"
= button t(:update_and_recalculate_fees), 'icon-refresh'

View File

@@ -1,3 +0,0 @@
/ replace 'code[erb-loud]:contains(\'"(#{f.object.variant.options_text})"\')'
= "(#{f.object.full_name})"

View File

@@ -1,3 +0,0 @@
/ replace 'code[erb-loud]:contains(\'f.object.variant.display_amount\')'
= f.object.single_money

View File

@@ -1,6 +0,0 @@
/ insert_after "code[erb-loud]:contains('button_link_to t(:resend)')"
%li.links-dropdown#links-dropdown{ links: order_links(@order).to_json }
:coffee
angular.bootstrap(document.getElementById("links-dropdown"),['admin.dropdown'])

View File

@@ -1,6 +0,0 @@
/ replace "code[erb-loud]:contains(\'error_messages\')"
-# Suppress errors when manually creating a new order - needs to proceed to edit page
-# without having line items (which otherwise gives a validation error)
- unless params["suppress_error_msg"]
= render partial: "spree/shared/error_messages", :locals => { :target => @order }

View File

@@ -1,3 +0,0 @@
/ replace "[data-hook=admin_product_form_left] code[erb-loud]:contains('f.text_area :description')"
%text-angular{'id' => 'product_description', 'name' => 'product[description]', 'class' => 'text-angular', 'textangular-strip' => true, 'ta-paste' => "stripFormatting($html)", 'ta-toolbar' => "[['bold','italics','clear']]"}
= sanitize(@product.description)

View File

@@ -1,3 +0,0 @@
/ insert_after "div[class='variant_units_form']"
= render 'spree/admin/products/primary_taxon_form', f: f

View File

@@ -1,6 +0,0 @@
/ insert_before "code[erb-loud]:contains('f.field_container :price')"
= f.field_container :supplier do
= f.label :supplier, t(:spree_admin_supplier)
%br
= f.collection_select(:supplier_id, @producers, :id, :name, {:include_blank => true}, {:class => "select2"})
= f.error_message_on :supplier

View File

@@ -1,17 +0,0 @@
/ insert_top "[data-hook='admin_product_form_right']"
.variant_units_form{ 'ng-app' => 'admin.products', 'ng-controller' => 'editUnitsCtrl' }
= f.field_container :units do
= f.label :variant_unit_with_scale, t(:spree_admin_variant_unit_scale)
%select.select2.fullwidth{ id: 'product_variant_unit_with_scale', 'ng-model' => 'variant_unit_with_scale', 'ng-change' => 'setFields()', 'ng-options' => 'unit[1] as unit[0] for unit in variant_unit_options' }
%option{'value' => ''}
= f.text_field :variant_unit, {'id' => 'variant_unit', 'ng-value' => 'product.variant_unit', 'hidden' => true}
= f.text_field :variant_unit_scale, {'id' => 'variant_unit_scale', 'ng-value' => 'product.variant_unit_scale', 'hidden' => true}
.variant_unit_name{'ng-show' => 'product.variant_unit == "items"'}
= f.field_container :variant_unit_name do
= f.label :variant_unit_name, t(:spree_admin_variant_unit_name)
= f.text_field :variant_unit_name, {placeholder: t('admin.products.unit_name_placeholder')}
= f.error_message_on :variant_unit_name

View File

@@ -1,2 +0,0 @@
remove "code[erb-loud]:contains('f.label :available_on')"
closing_selector("code[erb-loud]:contains('f.text_field :available_on')")

View File

@@ -1,2 +0,0 @@
remove "code[erb-loud]:contains('f.field_container :cost_currency')"
closing_selector("code[erb-silent]:contains('end')")

View File

@@ -1,2 +0,0 @@
remove "code[erb-loud]:contains('f.field_container :cost_price')"
closing_selector("code[erb-silent]:contains('end')")

View File

@@ -1 +0,0 @@
remove "div[data-hook='admin_product_form_meta']"

View File

@@ -1 +0,0 @@
remove "div[class='twelve columns alpha omega']"

View File

@@ -1,2 +0,0 @@
/ replace "[data-hook=admin_product_form_right] code[erb-loud]:contains('f.label :price')"
= f.label :price, raw(t(:price) + content_tag(:span, ' *', :class => 'required'))

View File

@@ -1,5 +0,0 @@
/ insert_bottom "[data-hook=admin_product_form_left]"
= f.field_container :taxons do
= f.label :taxon_ids, t(:taxons)
%br
= f.hidden_field :taxon_ids, :value => @product.taxon_ids.join(',')

View File

@@ -1,2 +0,0 @@
add_to_attributes 'fieldset.no-border-top'
attributes 'ng-app' => 'admin.products'

View File

@@ -1,3 +0,0 @@
/ replace_contents "#new_product_link"
= button_link_to t(:new_product), new_object_url, {:icon => 'icon-plus', :id => 'admin_new_product' }

View File

@@ -1,3 +0,0 @@
/ replace "code[erb-loud]:contains('button_link_to t(:back_to_products_list)')"
= button_link_to t('admin.products.back_to_products_list'), admin_products_path, :icon => 'icon-arrow-left'

View File

@@ -7,3 +7,5 @@
( {{entry.attributes.display_name}} )
%p.error{ng: {repeat: "(attribute, error) in entry.errors", show: "ignore_fields.indexOf(attribute) < 0" }}
&nbsp;-&nbsp; {{error}}
%p.error{ng: {repeat: "(attribute, error) in entry.product_validations"}}
&nbsp;-&nbsp; {{error}}

View File

@@ -16,7 +16,7 @@
= render partial: "shopping_shared/details"
%accordion{"close-others" => "true"}
%accordion{"close-others" => "false"}
%checkout.row{"ng-controller" => "CheckoutCtrl"}
.small-12.medium-8.large-9.columns
- unless spree_current_user

View File

@@ -0,0 +1,17 @@
= render partial: "spree/admin/variants/autocomplete", formats: :js
#add-line-item
%fieldset
%legend{align: "center"}
= t(:add_product)
.field.eight.columns.alpha
= label_tag :add_product_name, t(:name_or_sku)
= hidden_field_tag :add_variant_id, "", class: "variant_autocomplete fullwidth"
.field.two.columns
= label_tag :add_quantity, t(:qty)
= number_field_tag :add_quantity, 1, min: 0
.actions.two.columns.omega
= link_to_with_icon 'icon-plus', t(:add), admin_order_line_items_url(@order),
method: :post,
id: 'add_line_item_to_order',
class: 'button fullwidth',
'data-update' => 'order-form-wrapper'

View File

@@ -0,0 +1,68 @@
%div
- if @line_item.try(:errors).present?
= render partial: 'spree/shared/error_messages', locals: { target: @line_item }
= form_for @order, url: admin_order_url(@order), method: :put do |f|
%fieldset.no-border-top
= f.hidden_field :number
%table.index{"ng-show" => "distributionChosen()"}
%colgroup
%col{style: "width: 49%;"}/
%col{style: "width: 14%;"}/
%col{style: "width: 10%;"}/
%col{style: "width: 14%;"}/
%col{style: "width: 8%;"}/
%thead#line-items
%tr
%th
= t(:item_description)
%th.price
= t(:price)
%th.qty
= t(:qty)
%th.total
%span
= t(:total)
%th.orders-actions.actions
%tbody
= f.fields_for :line_items do |li_form|
= render partial: 'spree/admin/orders/line_item', locals: { f: li_form }
%tbody#subtotal.no-border-top
%tr#subtotal-row
%td{colspan: "3"}
%b
= t(:subtotal)
\:
%td.total.align-center
%span
= @order.display_item_total.to_html
%td.actions
%tbody#order-charges.no-border-top
- @order.adjustments.eligible.each do |adjustment|
%tr
%td{colspan: "3"}
%strong
= adjustment.label
\:
%td.total.align-center
%span= adjustment.display_amount.to_html
%td.actions
%tbody#order-total.grand-total.no-border-top
%tr
%td{colspan: "3"}
%b
= t(:order_total)
\:
%td.total.align-center
%span#order_total
= @order.display_total.to_html
%td.actions
= render partial: 'spree/admin/orders/_form/distribution_fields'
.filter-actions.actions{"ng-show" => "distributionChosen()"}
= button t(:update_and_recalculate_fees), 'icon-refresh'
%span.or
= t(:or)
= link_to_with_icon 'button icon-arrow-left', t(:back), admin_orders_url
= javascript_tag do
= render partial: 'spree/admin/shared/update_order_state', handlers: [:js]

View File

@@ -0,0 +1,12 @@
%tr{id: "#{spree_dom_id(f.object)}", class: "#{cycle('odd', 'even')}"}
%td
= f.object.variant.product.name
= "(#{f.object.full_name})" unless f.object.variant.option_values.empty?
%td.price.align-center
= f.object.variant.display_amount
%td.qty
= f.number_field :quantity, min: 0, class: "qty"
%td.total.align-center
= f.object.single_money
%td.actions
= link_to_delete f.object, {url: admin_order_line_item_url(@order.number, f.object), no_text: true}

View File

@@ -3,6 +3,8 @@
- content_for :page_actions do
%li= event_links
%li= button_link_to t(:resend), resend_admin_order_url(@order), method: :post, icon: 'icon-email'
%li.links-dropdown#links-dropdown{ links: order_links(@order).to_json }
%li= button_link_to t(:back_to_orders_list), admin_orders_path, icon: 'icon-arrow-left'
= admin_inject_shops(module: 'admin.orders')
@@ -10,15 +12,19 @@
= render 'spree/admin/shared/order_tabs', current: 'Order Details'
%div{"data-hook" => "admin_order_edit_header"}
= render 'spree/shared/error_messages', target: @order
%div
- unless params["suppress_error_msg"]
= render partial: "spree/shared/error_messages", :locals => { :target => @order }
%div{"ng-app" => "admin.orders", "ng-controller" => "orderCtrl", "ofn-distributor-id" => @order.distributor_id, "ofn-order-cycle-id" => @order.order_cycle_id}
= render 'add_product'
%div{"data-hook" => "admin_order_edit_form"}
%div
#order-form-wrapper
= render 'form', order: @order
- content_for :head do
= javascript_tag 'var expand_variants = true;'
:coffee
angular.bootstrap(document.getElementById("links-dropdown"),['admin.dropdown'])

View File

@@ -0,0 +1,106 @@
%div{"data-hook" => "admin_product_form_fields"}
.left.eight.columns.alpha
= f.field_container :name do
= f.label :name, raw(t(:name) + content_tag(:span, ' *', :class => 'required'))
= f.text_field :name, :class => 'fullwidth title'
= f.error_message_on :name
= f.field_container :permalink do
= f.label :permalink, raw(t(:permalink) + content_tag(:span, ' *', :class => "required"))
= f.text_field :permalink, :class => 'fullwidth title'
= f.error_message_on :permalink
= f.field_container :description do
= f.label :description, t(:description)
%text-angular{'id' => 'product_description', 'name' => 'product[description]', 'class' => 'text-angular', 'textangular-strip' => true, 'ta-paste' => "stripFormatting($html)", 'ta-toolbar' => "[['bold','italics','clear']]"}
= sanitize(@product.description)
= f.error_message_on :description
= f.field_container :taxons do
= f.label :taxon_ids, t(:taxons)
%br
= f.hidden_field :taxon_ids, :value => @product.taxon_ids.join(',')
.right.four.columns.omega
.variant_units_form{ 'ng-app' => 'admin.products', 'ng-controller' => 'editUnitsCtrl' }
= f.field_container :units do
= f.label :variant_unit_with_scale, t(:spree_admin_variant_unit_scale)
%select.select2.fullwidth{ id: 'product_variant_unit_with_scale', 'ng-model' => 'variant_unit_with_scale', 'ng-change' => 'setFields()', 'ng-options' => 'unit[1] as unit[0] for unit in variant_unit_options' }
%option{'value' => ''}
= f.text_field :variant_unit, {'id' => 'variant_unit', 'ng-value' => 'product.variant_unit', 'hidden' => true}
= f.text_field :variant_unit_scale, {'id' => 'variant_unit_scale', 'ng-value' => 'product.variant_unit_scale', 'hidden' => true}
.variant_unit_name{'ng-show' => 'product.variant_unit == "items"'}
= f.field_container :variant_unit_name do
= f.label :variant_unit_name, t(:spree_admin_variant_unit_name)
= f.text_field :variant_unit_name, {placeholder: t('admin.products.unit_name_placeholder')}
= f.error_message_on :variant_unit_name
= render 'spree/admin/products/primary_taxon_form', f: f
= f.field_container :supplier do
= f.label :supplier, t(:spree_admin_supplier)
%br
= f.collection_select(:supplier_id, @producers, :id, :name, {:include_blank => true}, {:class => "select2"})
= f.error_message_on :supplier
= f.field_container :price do
= f.label :price, raw(t(:price) + content_tag(:span, ' *', :class => 'required'))
= f.text_field :price, :value => number_to_currency(@product.price, :unit => '')
= f.error_message_on :price
.clear
- unless @product.has_variants?
= f.field_container :sku do
= f.label :sku, t(:sku)
= f.text_field :sku, :size => 16
- if Spree::Config[:track_inventory_levels]
.alpha.two.columns
= f.field_container :on_hand do
= f.label :on_hand, t(:on_hand)
= f.number_field :on_hand, :min => 0
.omega.two.columns
= f.field_container :on_demand, :class => ['checkbox'] do
%label
= f.check_box :on_demand
= t(:on_demand)
.clear
%ul#shipping_specs
%li#shipping_specs_weight_field.field.alpha.two.columns
= f.label :weight, t(:weight)
= f.text_field :weight, :size => 4
%li#shipping_specs_height_field.field.omega.two.columns
= f.label :height, t(:height)
= f.text_field :height, :size => 4
%li#shipping_specs_width_field.field.alpha.two.columns
= f.label :width, t(:width)
= f.text_field :width, :size => 4
%li#shipping_specs_depth_field.field.omega.two.columns
= f.label :depth, t(:depth)
= f.text_field :depth, :size => 4
= f.field_container :shipping_categories do
= f.label :shipping_category_id, t(:shipping_categories)
= f.collection_select(:shipping_category_id, @shipping_categories, :id, :name, { :include_blank => 'None' }, { :class => 'select2' })
= f.error_message_on :shipping_category
= f.field_container :tax_category do
= f.label :tax_category_id, t(:tax_category)
= f.collection_select(:tax_category_id, @tax_categories, :id, :name, { :include_blank => 'None' }, { :class => 'select2' })
= f.error_message_on :tax_category
.clear
%div
.clear
- unless Rails.env.test?
:javascript
$('.select2-container').css({width: '20em'})

View File

@@ -0,0 +1,14 @@
- content_for :page_actions do
%li= button_link_to t('admin.products.back_to_products_list'), admin_products_path, :icon => 'icon-arrow-left'
%li#new_product_link
= button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' }
= render :partial => 'spree/admin/shared/product_sub_menu'
= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Product Details' }
= render :partial => 'spree/shared/error_messages', :locals => { :target => @product }
= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f|
%fieldset.no-border-top{'ng-app' => 'admin.products'}
= render :partial => 'form', :locals => { :f => f }
= render :partial => 'spree/admin/shared/edit_resource_links'

View File

@@ -0,0 +1,75 @@
- content_for :page_title do
= t(:order)
\#
= @order.number
- if @order.bill_address.present?
= @order.bill_address.firstname
= @order.bill_address.lastname
\-
- content_for :sidebar_title do
= t(:order_information)
- content_for :sidebar do
%header#order_tab_summary
%dl.additional-info
%dt#order_status
= t(:status)
%dd
- order_state_classes = "state #{@order.state}"
%span{ class: order_state_classes }
= t(@order.state, scope: :order_state)
%dt
= t(:total)
\:
%dd#order_total
= @order.display_total.to_html
- if @order.completed?
%dt
= t(:shipment)
\:
%dd#shipment_status
- shipment_state_classes = "state #{@order.shipment_state}"
%span{ class: shipment_state_classes }
= t(@order.shipment_state, scope: :shipment_states, default: [:missing, "none"])
%dt
= t(:payment)
\:
%dd#payment_status
- payment_state_classes = "state #{@order.payment_state}"
%span{ class: payment_state_classes }
= t(@order.payment_state, scope: :payment_states, default: [:missing, "none"])
%dt
= t(:date_completed)
\:
%dd#date_complete
= pretty_time(@order.completed_at)
%nav.menu
%ul
- order_details_classes = "active" if current == "Order Details"
%li{ class: order_details_classes }
= link_to_with_icon 'icon-edit', t(:order_details), edit_admin_order_url(@order)
- customer_details_classes = "active" if current == "Customer Details"
%li{ class: customer_details_classes }
= link_to_with_icon 'icon-user', t(:customer_details), admin_order_customer_url(@order)
- adjustments_classes = "active" if current == "Adjustments"
%li{ class: adjustments_classes }
= link_to_with_icon 'icon-cogs', t(:adjustments), admin_order_adjustments_url(@order)
- payments_classes = "active" if current == "Payments"
%li{ class: payments_classes }
= link_to_with_icon 'icon-credit-card', t(:payments), admin_order_payments_url(@order)
- shipments_classes = "active" if current == "Shipments"
%li{ class: shipments_classes }
= link_to_with_icon 'icon-road', t(:shipments), admin_order_shipments_url(@order)
- if @order.completed?
- authorizations_classes = "active" if current == "Return Authorizations"
%li{ class: authorizations_classes }
= link_to_with_icon 'icon-share-alt', t(:return_authorizations), admin_order_return_authorizations_url(@order)

View File

@@ -1,11 +1,11 @@
.row
.alpha.five.columns
= f.field_container :email do
= f.label :email, Spree.t(:email)
= f.label :email, t(".email")
= f.email_field :email, class: "fullwidth"
= error_message_on :user, :email
.field
= label_tag nil, Spree.t(:roles)
= label_tag nil, t(".roles")
%ul
- @roles.each do |role|
%li
@@ -13,14 +13,14 @@
= label_tag role.name
= hidden_field_tag "user[spree_role_ids][]", ""
= f.field_container :enterprise_limit do
= f.label :enterprise_limit, t(:enterprise_limit)
= f.label :enterprise_limit, t(".enterprise_limit")
= f.text_field :enterprise_limit, class: "fullwidth"
.omega.five.columns
= f.field_container :password do
= f.label :password, Spree.t(:password)
= f.label :password, t(".password")
= f.password_field :password, class: "fullwidth"
= f.error_message_on :password
= f.field_container :password do
= f.label :password_confirmation, Spree.t(:confirm_password)
= f.label :password_confirmation, t(".confirm_password")
= f.password_field :password_confirmation, class: "fullwidth"
= f.error_message_on :password_confirmation

View File

@@ -1,10 +1,10 @@
- content_for :page_title do
= Spree.t(:editing_user)
= t(".editing_user")
- content_for :page_actions do
%li
= button_link_to Spree.t(:back_to_users_list), spree.admin_users_path, icon: "icon-arrow-left"
= button_link_to t(".back_to_users_list"), spree.admin_users_path, icon: "icon-arrow-left"
%fieldset.alpha.ten.columns{"data-hook" => "admin_user_edit_general_settings"}
%legend= Spree.t(:general_settings)
%legend= t(".general_settings")
%div{"data-hook" => "admin_user_edit_form_header"}
= render partial: "spree/shared/error_messages", locals: { target: @user }
%div{"data-hook" => "admin_user_edit_form"}

View File

@@ -1,8 +1,8 @@
- content_for :page_title do
= Spree.t(:listing_users)
= t(".listing_users")
- content_for :page_actions do
%li
= button_link_to Spree.t(:new_user), new_object_url, icon: "icon-plus", id: "admin_new_user_link"
= button_link_to t(".new_user"), new_object_url, icon: "icon-plus", id: "admin_new_user_link"
= render "admin/shared/users_sub_menu"
@@ -13,8 +13,8 @@
%col{ style: "width: 15%" }
%thead
%tr
%th= sort_link @search,:email, Spree.t(:user), {}, {title: "users_email_title"}
%th= sort_link @search,:enterprise_limit, t(:enterprise_limit)
%th= sort_link @search,:email, t(".user"), {}, {title: "users_email_title"}
%th= sort_link @search,:enterprise_limit, t(".enterprise_limit")
%th.actions
%tbody
- @users.each do |user|
@@ -28,13 +28,13 @@
= link_to_delete user, no_text: true
= paginate @users
- content_for :sidebar_title do
= Spree.t(:search)
= t(".search")
- content_for :sidebar do
.box.align-center
= search_form_for [:admin, @search] do |f|
.field
= f.label Spree.t(:email)
= f.label t(".email")
%br
= f.text_field :email_cont, class: "fullwidth"
%div
= button Spree.t(:search), "icon-search"
= button t(".search"), "icon-search"

View File

@@ -209,7 +209,6 @@ en:
distributors: Distributors
distribution: Distribution
order_cycles: Order Cycles
enterprise_limit: Enterprise Limit
bulk_order_management: Bulk Order Management
enterprises: Enterprises
enterprise_groups: Groups
@@ -225,6 +224,7 @@ en:
admin_and_handling: Admin & Handling
profile: Profile
supplier_only: Supplier Only
has_shopfront: Has Shopfront
weight: Weight
volume: Volume
items: Items
@@ -252,6 +252,7 @@ en:
password_confirmation: Password Confirmation
reset_password_token: Reset password token
expired: has expired, please request a new one
back_to_payments_list: "Back to Payments List"
actions:
create_and_add_another: "Create and Add Another"
@@ -1941,7 +1942,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
enterprise_long_desc: "Long Description"
enterprise_long_desc_placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words."
enterprise_long_desc_length: "%{num} characters / up to 600 recommended"
enterprise_limit: Enterprise Limit
enterprise_abn: "ABN"
enterprise_abn_placeholder: "eg. 99 123 456 789"
enterprise_acn: "ACN"
@@ -2402,6 +2402,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
validation_msg_relationship_already_established: "^That relationship is already established."
validation_msg_at_least_one_hub: "^At least one hub must be selected"
validation_msg_product_category_cant_be_blank: "^Product Category cant be blank"
validation_msg_tax: "^Tax Category is required"
validation_msg_tax_category_cant_be_blank: "^Tax Category can't be blank"
validation_msg_is_associated_with_an_exising_customer: "is associated with an existing customer"
content_configuration_pricing_table: "(TODO: Pricing table)"
@@ -2769,6 +2770,23 @@ See the %{link} to find out more about %{sitename}'s features and to start using
bulk_coop_packing_sheets: 'Bulk Co-op - Packing Sheets'
bulk_coop_customer_payments: 'Bulk Co-op - Customer Payments'
users:
index:
listing_users: "Listing Users"
new_user: "New User"
user: "User"
enterprise_limit: "Enterprise Limit"
search: "Search"
email: "Email"
edit:
editing_user: "Editing User"
back_to_users_list: "Back To Users List"
general_settings: "General Settings"
form:
email: "Email"
roles: "Roles"
enterprise_limit: "Enterprise Limit"
confirm_password: "Confirm Password"
password: "Password"
email_confirmation:
confirmation_pending: "Email confirmation is pending. We've sent a confirmation email to %{address}."
variants:

View File

@@ -111,6 +111,8 @@ Openfoodnetwork::Application.routes.draw do
resources :customers, only: [:index, :update]
resources :enterprise_fees, only: [:destroy]
post '/product_images/:product_id', to: 'product_images#update_product_image'
end

View File

@@ -35,7 +35,7 @@ Openfoodnetwork::Application.routes.draw do
resources :enterprise_relationships
resources :enterprise_roles
resources :enterprise_fees do
resources :enterprise_fees, except: :destroy do
collection do
get :for_order_cycle
post :bulk_update, :as => :bulk_update

View File

@@ -0,0 +1,42 @@
# When we introduced the Customer model, we didn't associate any existing
# customers with users that have the same email address.
# Later we decided to create that association when users sign up. But we didn't
# update all the existing customers. We do that now for data consistency and to
# solve several bugs.
#
# - https://github.com/openfoodfoundation/openfoodnetwork/pull/2084
# - https://github.com/openfoodfoundation/openfoodnetwork/issues/2841
class AssociateCustomersToUsers < ActiveRecord::Migration
class Customer < ActiveRecord::Base
end
def up
save_customers
execute "UPDATE customers
SET user_id = spree_users.id
FROM spree_users
WHERE customers.email = spree_users.email
AND customers.user_id IS NULL;"
end
def down
customers = backed_up_customers
Customer.where(id: customers).update_all(user_id: nil)
end
def save_customers
customers = Customer.
joins("INNER JOIN spree_users ON customers.email = spree_users.email").
where(user_id: nil).all
File.write(backup_file, YAML.dump(customers))
end
def backed_up_customers
YAML.load(File.read(backup_file))
end
def backup_file
File.join("log", "customers_without_user_association.log")
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20181106162211) do
ActiveRecord::Schema.define(:version => 20181123012635) do
create_table "account_invoices", :force => true do |t|
t.integer "user_id", :null => false

View File

@@ -0,0 +1,34 @@
require 'spec_helper'
module Api
describe EnterpriseFeesController, type: :controller do
include AuthenticationWorkflow
let!(:unreferenced_fee) { create(:enterprise_fee) }
let!(:referenced_fee) { create(:enterprise_fee) }
let(:product) { create(:product) }
let(:distributor) { create(:distributor_enterprise) }
let!(:product_distribution) { create(:product_distribution, product: product, distributor: distributor, enterprise_fee: referenced_fee) }
let(:current_user) { create(:admin_user) }
before do
allow(controller).to receive(:spree_current_user) { current_user }
end
describe "destroy" do
it "removes the fee" do
expect { spree_delete :destroy, id: unreferenced_fee.id, format: :json }
.to change { EnterpriseFee.count }.by -1
end
context "when the fee is referenced by a product distribution" do
it "does not remove the fee" do
spree_delete :destroy, id: referenced_fee.id, format: :json
expect(response.status).to eq 403
expect(response.body).to match(/That enterprise fee cannot be deleted/)
expect(referenced_fee.reload).to eq(referenced_fee)
end
end
end
end
end

View File

@@ -90,7 +90,7 @@ describe Spree::Admin::LineItemsController, type: :controller do
it 'returns an HTML response with the order form' do
spree_put :update, params
expect(response.body).to match(/admin_order_form_fields/)
expect(response.body).to match(/edit_order/)
end
end
end

View File

@@ -16,10 +16,10 @@ feature %q{
let!(:producer_related) { create(:supplier_enterprise) }
let!(:producer_unrelated) { create(:supplier_enterprise) }
let!(:er1) { create(:enterprise_relationship, parent: producer, child: hub,
permissions_list: [:create_variant_overrides])
permissions_list: [:create_variant_overrides])
}
let!(:er2) { create(:enterprise_relationship, parent: producer_related, child: hub,
permissions_list: [:create_variant_overrides])
permissions_list: [:create_variant_overrides])
}
context "as an enterprise user" do
@@ -28,7 +28,7 @@ feature %q{
describe "selecting a hub" do
let!(:er1) { create(:enterprise_relationship, parent: hub2, child: producer_managed,
permissions_list: [:add_to_order_cycle])
permissions_list: [:add_to_order_cycle])
} # This er should not confer ability to create VOs for hub2
it "displays a list of hub choices (ie. only those managed by the user)" do
@@ -338,7 +338,7 @@ feature %q{
it "shows the overridden price" do
targetted_select2_search product.name, from: '#add_variant_id', dropdown_css: '.select2-drop'
click_link 'Add'
expect(page).to have_selector("table.index tbody[data-hook='admin_order_form_line_items'] tr") # Wait for JS
expect(page).to have_selector("table.index tbody tr") # Wait for JS
expect(page).to have_content(product.variants.first.variant_overrides.first.price)
end
end

View File

@@ -65,19 +65,18 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
let(:user) { create(:user) }
def fill_out_form
toggle_shipping
choose sm1.name
toggle_payment
choose pm1.name
toggle_details
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Email", with: "test@test.com"
fill_in "Phone", with: "0468363090"
end
toggle_billing
check "Save as default billing address"
within "#billing" do
fill_in "City", with: "Melbourne"
fill_in "Postcode", with: "3066"
@@ -86,7 +85,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
select "Victoria", from: "State"
end
toggle_shipping
check "Shipping address same as billing address?"
check "Save as default shipping address"
end
@@ -150,7 +148,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
it "checks out successfully" do
visit checkout_path
choose sm2.name
toggle_payment
choose pm1.name
expect do
@@ -193,7 +190,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
visit checkout_path
fill_out_form
toggle_payment
choose stripe_pm.name
end
@@ -229,7 +225,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
end
it "shows a breakdown of the order price" do
toggle_shipping
choose sm2.name
page.should have_selector 'orderdetails .cart-total', text: with_currency(11.23)
@@ -243,7 +238,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
end
it "shows all shipping methods in order by name" do
toggle_shipping
within '#shipping' do
expect(page).to have_selector "label", count: 4 # Three shipping methods + instructions label
labels = page.all('label').map(&:text)
@@ -255,7 +249,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
context "when shipping method requires an address" do
before do
toggle_shipping
choose sm1.name
end
it "shows ship address forms when 'same as billing address' is unchecked" do
@@ -270,7 +263,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
it "shows shipping methods allowed by the rule" do
# No rules in effect
toggle_shipping
page.should have_content "Frogs"
page.should have_content "Donkeys"
page.should have_content "Local"
@@ -316,7 +308,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
before do
visit checkout_path
checkout_as_guest
toggle_payment
end
it "shows all available payment methods" do
@@ -327,8 +318,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
describe "purchasing" do
it "takes us to the order confirmation page when we submit a complete form" do
toggle_details
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
@@ -336,8 +325,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
fill_in "Phone", with: "0468363090"
end
toggle_billing
within "#billing" do
fill_in "Address", with: "123 Your Face"
select "Australia", from: "Country"
@@ -346,15 +333,11 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
fill_in "Postcode", with: "3066"
end
toggle_shipping
within "#shipping" do
choose sm2.name
fill_in 'Any comments or special instructions?', with: "SpEcIaL NoTeS"
end
toggle_payment
within "#payment" do
choose pm1.name
end
@@ -383,18 +366,16 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
context "with basic details filled" do
before do
toggle_shipping
choose sm1.name
toggle_payment
choose pm1.name
toggle_details
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Email", with: "test@test.com"
fill_in "Phone", with: "0468363090"
end
toggle_billing
within "#billing" do
fill_in "City", with: "Melbourne"
fill_in "Postcode", with: "3066"
@@ -402,7 +383,7 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
select "Australia", from: "Country"
select "Victoria", from: "State"
end
toggle_shipping
check "Shipping address same as billing address?"
end
@@ -443,7 +424,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
expect(page).to have_selector ".transaction-fee td", text: with_currency(0.00)
expect(page).to have_selector ".total", text: with_currency(11.23)
toggle_payment
choose "#{pm2.name} (#{with_currency(5.67)})"
expect(page).to have_selector ".transaction-fee td", text: with_currency(5.67)
@@ -465,7 +445,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
let!(:pm1) { create(:payment_method, distributors: [distributor], name: "Roger rabbit", type: gateway_type) }
it "takes us to the order confirmation page when submitted with a valid credit card" do
toggle_payment
fill_in 'Card Number', with: "4111111111111111"
select 'February', from: 'secrets.card_month'
select (Date.current.year+1).to_s, from: 'secrets.card_year'
@@ -480,7 +459,6 @@ feature "As a consumer I want to check out my cart", js: true, retry: 3 do
end
it "shows the payment processing failed message when submitted with an invalid credit card" do
toggle_payment
fill_in 'Card Number', with: "9999999988887777"
select 'February', from: 'secrets.card_month'
select (Date.current.year+1).to_s, from: 'secrets.card_year'

View File

@@ -67,7 +67,6 @@ feature "Using embedded shopfront functionality", js: true do
fill_in "Phone", with: "0456789012"
end
toggle_billing
within "#billing" do
fill_in "Address", with: "123 Street"
select "Australia", from: "Country"
@@ -76,12 +75,10 @@ feature "Using embedded shopfront functionality", js: true do
fill_in "Postcode", with: "3066"
end
toggle_shipping
within "#shipping" do
find('input[type="radio"]').trigger 'click'
end
toggle_payment
within "#payment" do
find('input[type="radio"]').trigger 'click'
end

View File

@@ -173,7 +173,6 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do
fill_in "Phone", with: "0456789012"
end
toggle_billing
within "#billing" do
fill_in "Address", with: "123 Street"
select "Australia", from: "Country"
@@ -182,12 +181,10 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do
fill_in "Postcode", with: "3066"
end
toggle_shipping
within "#shipping" do
choose sm.name
end
toggle_payment
within "#payment" do
choose pm.name
end
@@ -201,5 +198,4 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do
wait_until_enabled 'li.cart a.button'
first(:link, 'Checkout now').click
end
end

View File

@@ -18,16 +18,4 @@ module CheckoutWorkflow
def toggle_details
toggle_accordion :details
end
def toggle_billing
toggle_accordion :billing
end
def toggle_shipping
toggle_accordion :shipping
end
def toggle_payment
toggle_accordion :payment
end
end

View File

@@ -13,7 +13,7 @@ module ShopWorkflow
end
def set_order(order)
ApplicationController.any_instance.stub(:session).and_return({order_id: order.id, access_token: order.token})
allow_any_instance_of(ApplicationController).to receive(:session).and_return({order_id: order.id, access_token: order.token})
end
def add_product_to_cart(order, product, quantity: 1)