mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Compare commits
43 Commits
v1.8.8-tra
...
v1.8.10-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c72d17dc83 | ||
|
|
78ffdec693 | ||
|
|
49c19a1d6a | ||
|
|
e854eb0426 | ||
|
|
4a9c17cb28 | ||
|
|
0d1547f439 | ||
|
|
fa5ed529cb | ||
|
|
accb3076e9 | ||
|
|
a4e4e1ec68 | ||
|
|
4809237ecc | ||
|
|
81877fedb6 | ||
|
|
1f2c6f2a85 | ||
|
|
4fe5e60967 | ||
|
|
f4eb9cb790 | ||
|
|
775f9b3ada | ||
|
|
188b33921c | ||
|
|
20c033317f | ||
|
|
e7a5d063ac | ||
|
|
1fda781d7e | ||
|
|
45fc801a08 | ||
|
|
21337a5b50 | ||
|
|
c83ad2ecc4 | ||
|
|
80d8d18eb2 | ||
|
|
903d1afb53 | ||
|
|
cd55d2e2ff | ||
|
|
05cf8c4351 | ||
|
|
b04d815408 | ||
|
|
7b370a2eb6 | ||
|
|
5808b601b8 | ||
|
|
fdcd3dc3e3 | ||
|
|
c4bd085393 | ||
|
|
0e91d01412 | ||
|
|
fcb9e9fa56 | ||
|
|
3591354cb1 | ||
|
|
b38eab11eb | ||
|
|
c43dea60b7 | ||
|
|
268bea25d0 | ||
|
|
e94ae20b31 | ||
|
|
a94961c0a7 | ||
|
|
0d5fde919b | ||
|
|
429ef4e2ba | ||
|
|
e8999d23e1 | ||
|
|
209c9242d9 |
@@ -643,9 +643,8 @@ GEM
|
||||
whenever (0.9.2)
|
||||
activesupport (>= 2.3.4)
|
||||
chronic (>= 0.6.3)
|
||||
wicked_pdf (0.11.0)
|
||||
rails
|
||||
wkhtmltopdf-binary (0.9.9.3)
|
||||
wicked_pdf (1.1.0)
|
||||
wkhtmltopdf-binary (0.12.3.1)
|
||||
xml-simple (1.1.4)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
@@ -98,6 +98,14 @@ The site is configured to use
|
||||
startup time while Rails loads. See the Zeus github page for
|
||||
usage instructions.
|
||||
|
||||
Once [npm dependencies are
|
||||
installed](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Karma), AngularJS tests can be run with:
|
||||
|
||||
./script/karma run
|
||||
|
||||
If you want karma to automatically rerun the tests on file modification, use:
|
||||
|
||||
./script/karma start
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -12,7 +12,10 @@ angular.module('admin.orderCycles')
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
|
||||
@@ -13,7 +13,10 @@ angular.module('admin.orderCycles')
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
|
||||
@@ -8,7 +8,10 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.init = (enterprises) ->
|
||||
enterprise = enterprises[Object.keys(enterprises)[0]]
|
||||
|
||||
@@ -10,7 +10,10 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
$scope.init()
|
||||
|
||||
$scope.$watch 'order_cycle_form.$dirty', (newValue) ->
|
||||
StatusMessage.display 'notice', 'You have unsaved changes' if newValue
|
||||
StatusMessage.display 'notice', t("admin.unsaved_changes") if newValue
|
||||
|
||||
$scope.$watch 'order_cycle_form.$valid', (isValid) ->
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.products", ["admin.utils"])
|
||||
angular.module("admin.products", ["textAngular", "admin.utils"])
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("admin.utils").directive "textangularStrip", () ->
|
||||
restrict: 'CA'
|
||||
link: (scope, element, attrs) ->
|
||||
scope.stripFormatting = ($html) ->
|
||||
return String($html).replace(/<[^>]+>/gm, '')
|
||||
@@ -11,6 +11,14 @@ angular.module("admin.utils").factory "StatusMessage", ($timeout) ->
|
||||
text: ""
|
||||
style: {}
|
||||
|
||||
invalidMessage: ""
|
||||
|
||||
setValidation: (isValid) ->
|
||||
if isValid
|
||||
StatusMessage.invalidMessage = ''
|
||||
else
|
||||
StatusMessage.invalidMessage = t("admin.form_invalid")
|
||||
|
||||
active: ->
|
||||
@statusMessage.text != ''
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#save-bar.animate-show{ ng: { show: 'dirty || persist || StatusMessage.active()' } }
|
||||
.container
|
||||
.eight.columns.alpha
|
||||
%h5#status-message{ ng: { style: 'StatusMessage.statusMessage.style' } }
|
||||
%h5#status-message{ ng: { show: "StatusMessage.invalidMessage == ''", style: 'StatusMessage.statusMessage.style' } }
|
||||
{{ StatusMessage.statusMessage.text || " " }}
|
||||
%h5#status-message{ ng: { show: "StatusMessage.invalidMessage !== ''" }, style: 'color: #da5354' }
|
||||
{{ StatusMessage.invalidMessage || " " }}
|
||||
.eight.columns.omega.text-right{ ng: { transclude: true } }
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
%p.modal-header {{'contact' | t}}
|
||||
%p{"ng-if" => "::enterprise.phone", "ng-bind" => "::enterprise.phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "::enterprise.email_address"}
|
||||
%p{"ng-if" => "::enterprise.email_address"}
|
||||
%a{"ng-href" => "{{::enterprise.email_address | stripUrl}}", target: "_blank", mailto: true}
|
||||
%span.email{"ng-bind" => "::enterprise.email_address | stripUrl"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.website"}
|
||||
%p{"ng-if" => "enterprise.website"}
|
||||
%a{"ng-href" => "http://{{::enterprise.website | stripUrl}}", target: "_blank", "ng-bind" => "::enterprise.website | stripUrl"}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
.filter-shopfront.property-selectors.inline-block
|
||||
%filter-selector{ 'selector-set' => "productPropertySelectors", objects: "[product] | propertiesWithValuesOf" }
|
||||
|
||||
%div{"ng-if" => "product.description"}
|
||||
%div{"ng-if" => "product.description_html"}
|
||||
%hr
|
||||
%p.text-small{"ng-bind" => "::product.description"}
|
||||
%p.text-small{"ng-bind-html" => "::product.description_html"}
|
||||
%hr
|
||||
|
||||
.columns.small-12.large-6
|
||||
|
||||
@@ -74,6 +74,9 @@ form.order_cycle {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
}
|
||||
.icon-question-sign {
|
||||
font-size: 18px;
|
||||
}
|
||||
table.exchanges {
|
||||
tr td.active {
|
||||
width: 20px;
|
||||
@@ -113,6 +116,14 @@ form.order_cycle {
|
||||
margin-right: 2em;
|
||||
}
|
||||
}
|
||||
.collection-details {
|
||||
input {
|
||||
width: 90%
|
||||
}
|
||||
span {
|
||||
font-size: 1rem
|
||||
}
|
||||
}
|
||||
}
|
||||
.coordinator-fees {
|
||||
margin-top: 1em;
|
||||
@@ -200,6 +211,13 @@ table#listing_enterprise_groups {
|
||||
|
||||
// textAngular wysiwyg
|
||||
text-angular {
|
||||
.ta-toolbar {
|
||||
border: 1px solid #cdd9e4;
|
||||
padding: 0.4em;
|
||||
margin-bottom: -1px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 0.25em 0.25em 0 0;
|
||||
}
|
||||
.ta-scroll-window > .ta-bind {
|
||||
max-height: 400px;
|
||||
min-height: 100px;
|
||||
@@ -210,12 +228,18 @@ text-angular {
|
||||
}
|
||||
.ta-scroll-window.form-control {
|
||||
min-height: 100px;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.btn-group {
|
||||
display: inline;
|
||||
margin-right: 8px;
|
||||
button {
|
||||
padding: 5px 10px;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
button.active:not(:hover) {
|
||||
box-shadow: 0 0 0.7em rgba(0,0,0,0.3) inset;
|
||||
background-color: #4583bf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ class BaseController < ApplicationController
|
||||
private
|
||||
|
||||
def set_order_cycles
|
||||
unless @distributor.ready_for_checkout?
|
||||
@order_cycles = OrderCycle.where('false')
|
||||
return
|
||||
end
|
||||
|
||||
@order_cycles = OrderCycle.with_distributor(@distributor).active
|
||||
.order(@distributor.preferred_shopfront_order_cycle_order)
|
||||
|
||||
|
||||
@@ -54,12 +54,9 @@ module CheckoutHelper
|
||||
end
|
||||
|
||||
def display_adjustment_tax_rates(adjustment)
|
||||
tax_rate = (adjustment.included_tax / (adjustment.amount - adjustment.included_tax)).round(2)
|
||||
if tax_rate == 0 || tax_rate.infinite?
|
||||
""
|
||||
else
|
||||
number_to_percentage(tax_rate * 100, :precision => 1)
|
||||
end
|
||||
tax_rates = adjustment.tax_rates
|
||||
return "" if adjustment.amount == adjustment.included_tax
|
||||
tax_rates.map { |tr| number_to_percentage(tr.amount * 100, :precision => 1) }.join(", ")
|
||||
end
|
||||
|
||||
def display_adjustment_amount(adjustment)
|
||||
|
||||
@@ -175,7 +175,7 @@ class AbilityDecorator
|
||||
def add_order_management_abilities(user)
|
||||
# Enterprise User can only access orders that they are a distributor for
|
||||
can [:index, :create], Spree::Order
|
||||
can [:read, :update, :fire, :resend, :invoice, :print], Spree::Order do |order|
|
||||
can [:read, :update, :fire, :resend, :invoice, :print, :print_ticket], Spree::Order do |order|
|
||||
# We allow editing orders with a nil distributor as this state occurs
|
||||
# during the order creation process from the admin backend
|
||||
order.distributor.nil? || user.enterprises.include?(order.distributor) || order.order_cycle.andand.coordinated_by?(user)
|
||||
|
||||
@@ -34,10 +34,30 @@ module Spree
|
||||
included_tax > 0
|
||||
end
|
||||
|
||||
def display_included_tax
|
||||
Spree::Money.new(included_tax, { :currency => currency })
|
||||
def tax_rates
|
||||
case originator
|
||||
when Spree::TaxRate
|
||||
[originator]
|
||||
when EnterpriseFee
|
||||
case source
|
||||
when Spree::LineItem
|
||||
tax_category = originator.inherits_tax_category? ? source.product.tax_category : originator.tax_category
|
||||
return tax_category ? tax_category.tax_rates.match(source.order) : []
|
||||
when Spree::Order
|
||||
return originator.tax_category ? originator.tax_category.tax_rates.match(source) : []
|
||||
end
|
||||
else
|
||||
[find_closest_tax_rate_from_included_tax]
|
||||
end
|
||||
end
|
||||
|
||||
def find_closest_tax_rate_from_included_tax
|
||||
approximation = (included_tax / (amount - included_tax))
|
||||
return nil if approximation.infinite? or approximation.zero?
|
||||
Spree::TaxRate.order("ABS(amount - #{approximation})").first
|
||||
end
|
||||
|
||||
|
||||
def self.without_callbacks
|
||||
skip_callback :save, :after, :update_adjustable
|
||||
skip_callback :destroy, :after, :update_adjustable
|
||||
|
||||
@@ -6,7 +6,6 @@ Spree::AppConfiguration.class_eval do
|
||||
|
||||
# Terms of Service Preferences
|
||||
preference :enterprises_require_tos, :boolean, default: false
|
||||
preference :enterprise_tos_link, :string, default: "/Terms-of-service.pdf"
|
||||
|
||||
# Tax Preferences
|
||||
preference :products_require_tax_category, :boolean, default: false
|
||||
|
||||
@@ -234,12 +234,12 @@ Spree::Order.class_eval do
|
||||
|
||||
def tax_adjustment_totals
|
||||
tax_adjustments.each_with_object(Hash.new) do |adjustment, hash|
|
||||
if adjustment.originator_type == "Spree::TaxRate"
|
||||
tax_rate = adjustment.originator.amount
|
||||
else
|
||||
tax_rate = (adjustment.included_tax / (adjustment.amount - adjustment.included_tax)).round(2)
|
||||
end
|
||||
hash.update({tax_rate => adjustment.included_tax}) { |_tax_rate, amount1, amount2| amount1 + amount2 }
|
||||
tax_rates = adjustment.tax_rates
|
||||
tax_rates_hash = Hash[tax_rates.collect do |tax_rate|
|
||||
tax_amount = tax_rates.one? ? adjustment.included_tax : tax_rate.compute_tax(adjustment.amount)
|
||||
[tax_rate.amount, tax_amount]
|
||||
end]
|
||||
hash.update(tax_rates_hash) { |_tax_rate, amount1, amount2| amount1 + amount2 }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
%fieldset.enterprise_toc.no-border-bottom
|
||||
%legend{:align => "center"}= t(:enterprise_terms_of_service)
|
||||
- [:enterprise_tos_link, :enterprises_require_tos].each do |pref|
|
||||
- type = Spree::Config.preference_type(pref)
|
||||
.field
|
||||
= label_tag(pref, t(pref) + ': ') + tag(:br) if type != :boolean
|
||||
= preference_field_tag(pref, Spree::Config[pref], :type => type)
|
||||
= label_tag(pref, t(pref)) + tag(:br) if type == :boolean
|
||||
|
||||
.field
|
||||
= preference_field_tag(:enterprises_require_tos, Spree::Config[:enterprises_require_tos], :type => Spree::Config.preference_type(:enterprises_require_tos))
|
||||
= label_tag(:enterprises_require_tos, t(:enterprises_require_tos)) + tag(:br)
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
%table.index
|
||||
%thead
|
||||
%tr{"data-hook" => "producer_properties_header"}
|
||||
%th= t(:inherited_property)
|
||||
%th= t(:value)
|
||||
%th= t('admin.products.properties.inherited_property')
|
||||
%th= t('admin.description')
|
||||
%th.actions
|
||||
%tbody#producer_properties{"data-hook" => ""}
|
||||
- @product.supplier.producer_properties.each do |producer_property|
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/ replace "tr[data-hook='product_properties_header']"
|
||||
%tr{"data-hook" => "product_properties_header"}
|
||||
%th= t('admin.products.properties.property_name')
|
||||
%th= t('admin.description')
|
||||
%th.actions
|
||||
@@ -0,0 +1,3 @@
|
||||
/ 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)
|
||||
@@ -0,0 +1,2 @@
|
||||
add_to_attributes 'fieldset.no-border-top'
|
||||
attributes 'ng-app' => 'admin.products'
|
||||
@@ -72,7 +72,7 @@
|
||||
= f.field_container :description do
|
||||
= f.label :product_description, t(:product_description)
|
||||
%br/
|
||||
= f.text_area :description, class: 'fullwidth', rows: 3
|
||||
%text-angular{'id' => 'product_description', 'name' => 'product[description]', 'class' => 'text-angular', 'textangular-strip' => true, 'ta-paste' => "stripFormatting($html)", 'ta-toolbar' => "[['bold','italics','clear']]"}
|
||||
= f.error_message_on :description
|
||||
.four.columns.omega{ style: "text-align: center" }
|
||||
%fieldset.no-border-bottom{ id: "image" }
|
||||
|
||||
@@ -37,7 +37,7 @@ class Api::CachedProductSerializer < ActiveModel::Serializer
|
||||
include ActionView::Helpers::SanitizeHelper
|
||||
|
||||
attributes :id, :name, :permalink
|
||||
attributes :on_demand, :group_buy, :notes, :description
|
||||
attributes :on_demand, :group_buy, :notes, :description, :description_html
|
||||
attributes :properties_with_values
|
||||
|
||||
has_many :variants, serializer: Api::VariantSerializer
|
||||
@@ -49,10 +49,17 @@ class Api::CachedProductSerializer < ActiveModel::Serializer
|
||||
has_many :images, serializer: Api::ImageSerializer
|
||||
has_one :supplier, serializer: Api::IdSerializer
|
||||
|
||||
#return an unformatted descripton
|
||||
def description
|
||||
strip_tags object.description
|
||||
end
|
||||
|
||||
#return a sanitized html description
|
||||
def description_html
|
||||
d = sanitize(object.description, options = {tags: "p, b, strong, em, i"})
|
||||
d.to_s.html_safe
|
||||
end
|
||||
|
||||
def properties_with_values
|
||||
object.properties_including_inherited
|
||||
end
|
||||
|
||||
@@ -9,14 +9,16 @@
|
||||
selected
|
||||
- if type == 'supplier'
|
||||
%td.receival-details
|
||||
= text_field_tag 'order_cycle_incoming_exchange_{{ $index }}_receival_instructions', '', 'id' => 'order_cycle_incoming_exchange_{{ $index }}_receival_instructions', 'placeholder' => 'Receival instructions', 'ng-model' => 'exchange.receival_instructions'
|
||||
= text_field_tag 'order_cycle_incoming_exchange_{{ $index }}_receival_instructions', '', 'id' => 'order_cycle_incoming_exchange_{{ $index }}_receival_instructions', 'placeholder' => t('.receival_instructions_placeholder'), 'ng-model' => 'exchange.receival_instructions'
|
||||
- if type == 'distributor'
|
||||
%td.tags.panel-toggle.text-center{ name: "tags", ng: { if: 'enterprises[exchange.enterprise_id].managed || order_cycle.viewing_as_coordinator' } }
|
||||
{{ exchange.tags.length }}
|
||||
%td.collection-details
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', 'placeholder' => 'Ready for (ie. Date / Time)', 'ng-model' => 'exchange.pickup_time', 'ng-disabled' => '!enterprises[exchange.enterprise_id].managed && !order_cycle.viewing_as_coordinator'
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_time', 'required' => 'required', 'placeholder' => t('.pickup_time_placeholder'), 'ng-model' => 'exchange.pickup_time', 'ng-disabled' => '!enterprises[exchange.enterprise_id].managed && !order_cycle.viewing_as_coordinator', 'maxlength' => 35
|
||||
%span.icon-question-sign{'ofn-with-tip' => t('admin.order_cycles.edit.pickup_time_tip')}
|
||||
%br/
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_instructions', 'placeholder' => 'Pick-up instructions', 'ng-model' => 'exchange.pickup_instructions', 'ng-disabled' => '!enterprises[exchange.enterprise_id].managed && !order_cycle.viewing_as_coordinator'
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_{{ $index }}_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_{{ $index }}_pickup_instructions', 'placeholder' => t('.pickup_instructions_placeholder'), 'ng-model' => 'exchange.pickup_instructions', 'ng-disabled' => '!enterprises[exchange.enterprise_id].managed && !order_cycle.viewing_as_coordinator'
|
||||
%span.icon-question-sign{'ofn-with-tip' => t('admin.order_cycles.edit.pickup_instructions_tip')}
|
||||
%td.fees
|
||||
%ol{ ng: { show: 'enterprises[exchange.enterprise_id].managed || order_cycle.viewing_as_coordinator' } }
|
||||
%li{'ng-repeat' => 'enterprise_fee in exchange.enterprise_fees'}
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
.alpha.two.columns
|
||||
= label_tag t('.ready_for')
|
||||
.six.columns
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'placeholder' => t('.ready_for_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_time', 'size' => 30
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'required' => 'required', 'placeholder' => t('.ready_for_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_time', 'size' => 30, 'maxlength' => 35
|
||||
%span.icon-question-sign{'ofn-with-tip' => t('admin.order_cycles.edit.pickup_time_tip')}
|
||||
.two.columns
|
||||
= label_tag t('.customer_instructions')
|
||||
.six.columns.omega
|
||||
= text_field_tag 'order_cycle_outgoing_exchange_0_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_instructions', 'placeholder' => t('.customer_instructions_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_instructions', 'size' => 30
|
||||
%span.icon-question-sign{'ofn-with-tip' => t('admin.order_cycles.edit.pickup_instructions_tip')}
|
||||
|
||||
= label_tag t('.products')
|
||||
%table.exchanges
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f|
|
||||
|
||||
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
|
||||
%input.red{ type: "button", value: t(:update), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty" } }
|
||||
%input.red{ type: "button", value: t('.update_and_close'), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty" } }
|
||||
%input.red{ type: "button", value: t(:update), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input.red{ type: "button", value: t('.update_and_close'), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input{ type: "button", ng: { value: "order_cycle_form.$dirty ? 'Cancel' : 'Close'", click: "cancel('#{main_app.admin_order_cycles_path}')" } }
|
||||
|
||||
- if order_cycles_simple_form
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f|
|
||||
|
||||
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
|
||||
%input.red{ type: "button", value: t(:create), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty" } }
|
||||
%input.red{ type: "button", value: t(:create), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
|
||||
%input{ type: "button", ng: { value: "order_cycle_form.$dirty ? 'Cancel' : 'Close'", click: "cancel('#{main_app.admin_order_cycles_path}')" } }
|
||||
|
||||
- if order_cycles_simple_form
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
%table.index.sortable{"data-hook" => "", "data-sortable-link" => main_app.update_positions_admin_enterprise_producer_properties_url(@enterprise)}
|
||||
%thead
|
||||
%tr{"data-hook" => "producer_properties_header"}
|
||||
%th{colspan: "2"}= t('.property')
|
||||
%th= t('.value')
|
||||
%th{colspan: "2"}= t('admin.products.properties.property_name')
|
||||
%th= t('admin.description')
|
||||
%th.actions
|
||||
%tbody#producer_properties{"data-hook" => ""}
|
||||
= f.fields_for :producer_properties do |pp_form|
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
= inject_enterprise_attributes
|
||||
|
||||
- steps = %w{about contact details finished images introduction}
|
||||
- steps += %w{limit_reached logo promo social steps type}
|
||||
- steps += %w{logo promo social steps type}
|
||||
- steps.each do |step|
|
||||
= render partial: "registration/steps/#{step}"
|
||||
= render "modal"
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
= render partial: "registration/steps/limit_reached"
|
||||
|
||||
/ Directive which loads the modal
|
||||
%div{ "ofn-registration-limit-modal" => true }
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
.small-12.columns{'ng-hide' => '!tos_required' }
|
||||
%p.tos-message
|
||||
#{t(:enterprise_tos_message)}
|
||||
%a{href: "#{Spree::Config.enterprise_tos_link}", target: "_blank" } #{t(:enterprise_tos_link_text)}
|
||||
%a{href: ContentConfig.footer_tos_url, target: "_blank" } #{t(:enterprise_tos_link_text)}
|
||||
%p.tos-checkbox
|
||||
%input{ type: 'checkbox', name: 'accept_terms', id: 'accept_terms', ng: { model: "tos_accepted" } }
|
||||
%label{for: "accept_terms"} #{t(:enterprise_tos_agree)}
|
||||
|
||||
@@ -105,6 +105,7 @@ module Openfoodnetwork
|
||||
config.assets.precompile += ['mail/all.css']
|
||||
config.assets.precompile += ['search/all.css', 'search/*.js']
|
||||
config.assets.precompile += ['shared/*']
|
||||
config.assets.precompile += ['qz/*']
|
||||
|
||||
config.active_support.escape_html_entities_in_json = true
|
||||
end
|
||||
|
||||
@@ -35,6 +35,7 @@ Openfoodnetwork::Application.configure do
|
||||
|
||||
# Tests assume English text on the site.
|
||||
config.i18n.default_locale = "en"
|
||||
I18n.locale = config.i18n.locale = config.i18n.default_locale
|
||||
|
||||
# Use SQL instead of Active Record's schema dumper when creating the test database.
|
||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||
|
||||
@@ -70,6 +70,8 @@ en-GB:
|
||||
clear_all: Clear All
|
||||
start_date: "Start Date"
|
||||
end_date: "End Date"
|
||||
unsaved_changes: "You have unsaved changes"
|
||||
form_invalid: "Form contains missing or invalid fields"
|
||||
columns: Columns
|
||||
actions: Actions
|
||||
viewing: "Viewing: %{current_view_name}"
|
||||
@@ -198,7 +200,9 @@ en-GB:
|
||||
variants_without_unit_value: "WARNING: Some variants do not have a unit value"
|
||||
order_cycles:
|
||||
edit:
|
||||
choose_products_from: "Choose Products From:"
|
||||
choose_products_from: 'Choose Products From:'
|
||||
pickup_time_tip: When orders from this OC will be ready for the customer
|
||||
pickup_instructions_tip: These instructions are shown to customers after they complete an order
|
||||
enterprise:
|
||||
select_outgoing_oc_products_from: Select outgoing OC products from
|
||||
enterprises:
|
||||
|
||||
@@ -105,10 +105,13 @@ en:
|
||||
clear_all: Clear All
|
||||
start_date: "Start Date"
|
||||
end_date: "End Date"
|
||||
unsaved_changes: "You have unsaved changes"
|
||||
form_invalid: "Form contains missing or invalid fields"
|
||||
|
||||
columns: Columns
|
||||
actions: Actions
|
||||
viewing: "Viewing: %{current_view_name}"
|
||||
description: Description
|
||||
|
||||
whats_this: What's this?
|
||||
|
||||
@@ -223,6 +226,9 @@ en:
|
||||
inherits_properties?: Inherits Properties?
|
||||
available_on: Available On
|
||||
av_on: "Av. On"
|
||||
properties:
|
||||
property_name: Property Name
|
||||
inherited_property: Inherited Property
|
||||
variants:
|
||||
to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order."
|
||||
|
||||
@@ -271,10 +277,6 @@ en:
|
||||
order_error: "Some errors must be resolved before you can update orders.\nAny fields with red borders contain errors."
|
||||
variants_without_unit_value: "WARNING: Some variants do not have a unit value"
|
||||
|
||||
order_cycles:
|
||||
edit:
|
||||
choose_products_from: "Choose Products From:"
|
||||
|
||||
enterprise:
|
||||
select_outgoing_oc_products_from: Select outgoing OC products from
|
||||
|
||||
@@ -463,6 +465,16 @@ en:
|
||||
next_step: Next step
|
||||
choose_starting_point: 'Choose your starting point:'
|
||||
order_cycles:
|
||||
edit:
|
||||
advanced_settings: Advanced Settings
|
||||
update_and_close: Update and Close
|
||||
choose_products_from: 'Choose Products From:'
|
||||
pickup_time_tip: When orders from this OC will be ready for the customer
|
||||
pickup_instructions_tip: These instructions are shown to customers after they complete an order
|
||||
exchange_form:
|
||||
pickup_instructions_placeholder: "Pick-up instructions"
|
||||
pickup_time_placeholder: "Ready for (ie. Date / Time)"
|
||||
receival_instructions_placeholder: "Receival instructions"
|
||||
advanced_settings:
|
||||
title: Advanced Settings
|
||||
choose_product_tip: You can opt to restrict all available products (both incoming and outgoing), to only those in %{inventory}'s inventory.
|
||||
@@ -481,7 +493,7 @@ en:
|
||||
distributor: Distributor
|
||||
products: Products
|
||||
tags: Tags
|
||||
delivery_detaisl: Pickup / Delivery details
|
||||
delivery_details: Pickup / Delivery details
|
||||
debug_info: Debug information
|
||||
name_and_timing_form:
|
||||
name: Name
|
||||
@@ -499,13 +511,7 @@ en:
|
||||
customer_instructions_placeholder: Pick-up or delivery notes
|
||||
products: Products
|
||||
fees: Fees
|
||||
edit:
|
||||
advanced_settings: Advanced Settings
|
||||
update_and_close: Update and Close
|
||||
producer_properties:
|
||||
form:
|
||||
property: Property
|
||||
value: Value
|
||||
index:
|
||||
title: Producer Properties
|
||||
shared:
|
||||
|
||||
@@ -32,21 +32,11 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def adjustment_tax(adjustable, adjustment)
|
||||
tax_rates = rates_for(adjustable)
|
||||
tax_rates = adjustment.tax_rates
|
||||
|
||||
tax_rates.select(&:included_in_price).sum do |rate|
|
||||
rate.compute_tax adjustment.amount
|
||||
end
|
||||
end
|
||||
|
||||
def rates_for(adjustable)
|
||||
case adjustable
|
||||
when Spree::LineItem
|
||||
tax_category = enterprise_fee.inherits_tax_category? ? adjustable.product.tax_category : enterprise_fee.tax_category
|
||||
return tax_category ? tax_category.tax_rates.match(adjustable.order) : []
|
||||
when Spree::Order
|
||||
return enterprise_fee.tax_category ? enterprise_fee.tax_category.tax_rates.match(adjustable) : []
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module OpenFoodNetwork
|
||||
class EnterpriseInjectionData
|
||||
def active_distributors
|
||||
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
|
||||
@active_distributors ||= Enterprise.distributors_with_active_order_cycles.ready_for_checkout
|
||||
end
|
||||
|
||||
def earliest_closing_times
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
namespace :karma do
|
||||
task :start => :environment do
|
||||
task :start => :environment do |task|
|
||||
continue_only_in_test_env task
|
||||
with_tmp_config :start
|
||||
end
|
||||
|
||||
task :run => :environment do
|
||||
task :run => :environment do |task|
|
||||
continue_only_in_test_env task
|
||||
with_tmp_config :start, "--single-run"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def continue_only_in_test_env task
|
||||
if Rails.env != 'test'
|
||||
raise "Task must be called in test environment:\n bundle exec rake #{task.name} RAILS_ENV=test"
|
||||
end
|
||||
end
|
||||
|
||||
def with_tmp_config(command, args = nil)
|
||||
Tempfile.open('karma_unit.js', Rails.root.join('tmp') ) do |f|
|
||||
f.write unit_js(application_spec_files << i18n_file)
|
||||
|
||||
@@ -14,4 +14,4 @@ echo "--- Bundling"
|
||||
bundle install
|
||||
|
||||
echo "--- Running tests"
|
||||
bundle exec rake karma:run
|
||||
./script/karma run
|
||||
|
||||
13
script/karma
Executable file
13
script/karma
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
task="$1"
|
||||
|
||||
if [ "$task" = "run" ] || [ "$task" = "start" ]; then
|
||||
exec bundle exec rake "karma:$task" RAILS_ENV=test
|
||||
else
|
||||
echo "Usage:"
|
||||
echo " $0 run # to run the tests once"
|
||||
echo " $0 start # to run the tests on every file modification"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ShopController do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let!(:pm) { create(:payment_method) }
|
||||
let!(:sm) { create(:shipping_method) }
|
||||
let(:distributor) { create(:distributor_enterprise, payment_methods: [pm], shipping_methods: [sm]) }
|
||||
|
||||
it "redirects to the home page if no distributor is selected" do
|
||||
spree_get :show
|
||||
|
||||
@@ -6,7 +6,7 @@ describe ShopsController do
|
||||
let!(:invisible_distributor) { create(:distributor_enterprise, visible: false) }
|
||||
|
||||
before do
|
||||
Enterprise.stub(:distributors_with_active_order_cycles) { [distributor] }
|
||||
Enterprise.stub_chain("distributors_with_active_order_cycles.ready_for_checkout") { [distributor] }
|
||||
end
|
||||
|
||||
# Exclusion from actual rendered view handled in features/consumer/home
|
||||
|
||||
@@ -350,6 +350,8 @@ feature %q{
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'New instructions 0'
|
||||
fill_in 'order_cycle_outgoing_exchange_1_pickup_time', with: 'New time 1'
|
||||
fill_in 'order_cycle_outgoing_exchange_1_pickup_instructions', with: 'New instructions 1'
|
||||
fill_in 'order_cycle_outgoing_exchange_2_pickup_time', with: 'New time 2'
|
||||
fill_in 'order_cycle_outgoing_exchange_2_pickup_instructions', with: 'New instructions 2'
|
||||
|
||||
page.find("table.exchanges tr.distributor-#{distributor.id} td.tags").click
|
||||
within ".exchange-tags" do
|
||||
@@ -616,6 +618,11 @@ feature %q{
|
||||
select 'Permitted distributor', from: 'new_distributor_id'
|
||||
click_button 'Add distributor'
|
||||
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'pickup time'
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'pickup instructions'
|
||||
fill_in 'order_cycle_outgoing_exchange_1_pickup_time', with: 'pickup time 2'
|
||||
fill_in 'order_cycle_outgoing_exchange_1_pickup_instructions', with: 'pickup instructions'
|
||||
|
||||
# Should only have suppliers / distributors listed which the user is managing or
|
||||
# has E2E permission to add products to order cycles
|
||||
page.should_not have_select 'new_supplier_id', with_options: [supplier_unmanaged.name]
|
||||
|
||||
@@ -35,7 +35,7 @@ feature %q{
|
||||
fill_in 'product_on_hand', with: 5
|
||||
select 'Test Tax Category', from: 'product_tax_category_id'
|
||||
select 'Test Shipping Category', from: 'product_shipping_category_id'
|
||||
fill_in 'product_description', with: "A description..."
|
||||
page.find("input[name='product\[description\]']", visible: false).set('A description...')
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
@@ -75,7 +75,8 @@ feature %q{
|
||||
check 'product_on_demand'
|
||||
select 'Test Tax Category', from: 'product_tax_category_id'
|
||||
select 'Test Shipping Category', from: 'product_shipping_category_id'
|
||||
fill_in 'product_description', with: "In demand, and on_demand! The hottest cakes in town."
|
||||
#fill_in 'product_description', with: "In demand, and on_demand! The hottest cakes in town."
|
||||
page.first("input[name='product\[description\]']", visible: false).set('In demand, and on_demand! The hottest cakes in town.')
|
||||
|
||||
click_button 'Create'
|
||||
|
||||
|
||||
@@ -98,6 +98,23 @@ feature "Registration", js: true do
|
||||
expect(e.instagram).to eq "@InStAgRaM"
|
||||
end
|
||||
|
||||
context "when the user has no more remaining enterprises" do
|
||||
before do
|
||||
user.update_attributes(enterprise_limit: 0)
|
||||
end
|
||||
|
||||
it "displays the limit reached page" do
|
||||
visit registration_path
|
||||
|
||||
expect(page).to have_selector "dd", text: "Login"
|
||||
switch_to_login_tab
|
||||
|
||||
# Enter Login details
|
||||
fill_in "Email", with: user.email
|
||||
fill_in "Password", with: user.password
|
||||
click_login_and_ensure_content I18n.t('limit_reached_headline')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Terms of Service agreement" do
|
||||
|
||||
60
spec/features/consumer/shopping/products_spec.rb
Normal file
60
spec/features/consumer/shopping/products_spec.rb
Normal file
@@ -0,0 +1,60 @@
|
||||
require 'spec_helper'
|
||||
|
||||
feature "As a consumer I want to view products", js: true do
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
include ShopWorkflow
|
||||
include UIComponentHelper
|
||||
|
||||
describe "Viewing a product" do
|
||||
let(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let(:supplier) { create(:supplier_enterprise) }
|
||||
let(:oc1) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), orders_close_at: 2.days.from_now) }
|
||||
let(:product) { create(:simple_product, supplier: supplier) }
|
||||
let(:variant) { product.variants.first }
|
||||
let(:order) { create(:order, distributor: distributor) }
|
||||
let(:exchange1) { oc1.exchanges.to_enterprises(distributor).outgoing.first }
|
||||
|
||||
before do
|
||||
set_order order
|
||||
end
|
||||
|
||||
describe "viewing HTML product descriptions" do
|
||||
before do
|
||||
exchange1.update_attribute :pickup_time, "monday"
|
||||
add_variant_to_order_cycle(exchange1, variant)
|
||||
end
|
||||
|
||||
it "shows HTML product description" do
|
||||
product.description = "<p><b>Formatted</b> product description.</p>"
|
||||
product.save!
|
||||
|
||||
visit shop_path
|
||||
select "monday", :from => "order_cycle_id"
|
||||
|
||||
open_product_modal product
|
||||
modal_should_be_open_for product
|
||||
|
||||
within(".reveal-modal") do
|
||||
html.should include("<p><b>Formatted</b> product description.</p>")
|
||||
end
|
||||
end
|
||||
|
||||
it "does not show unsecure HTML" do
|
||||
product.description = "<script>alert('Dangerous!');</script><p>Safe</p>"
|
||||
product.save!
|
||||
|
||||
visit shop_path
|
||||
select "monday", :from => "order_cycle_id"
|
||||
|
||||
open_product_modal product
|
||||
modal_should_be_open_for product
|
||||
|
||||
within(".reveal-modal") do
|
||||
html.should include("<p>Safe</p>")
|
||||
html.should_not include("<script>alert('Dangerous!');</script>")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6,8 +6,8 @@ feature 'Shops', js: true do
|
||||
|
||||
let!(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let!(:invisible_distributor) { create(:distributor_enterprise, visible: false) }
|
||||
let(:d1) { create(:distributor_enterprise) }
|
||||
let(:d2) { create(:distributor_enterprise) }
|
||||
let!(:d1) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let!(:d2) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise)) }
|
||||
let!(:producer) { create(:supplier_enterprise) }
|
||||
let!(:er) { create(:enterprise_relationship, parent: distributor, child: producer) }
|
||||
@@ -57,6 +57,20 @@ feature 'Shops', js: true do
|
||||
end
|
||||
end
|
||||
|
||||
describe "showing available hubs" do
|
||||
let!(:hub) { create(:distributor_enterprise, with_payment_and_shipping: false) }
|
||||
let!(:order_cycle) { create(:simple_order_cycle, distributors: [hub], coordinator: hub) }
|
||||
let!(:producer) { create(:supplier_enterprise) }
|
||||
let!(:er) { create(:enterprise_relationship, parent: hub, child: producer) }
|
||||
|
||||
it "does not show hubs that are not ready for checkout" do
|
||||
visit shops_path
|
||||
|
||||
Enterprise.ready_for_checkout.should_not include hub
|
||||
page.should_not have_content hub.name
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering by product property" do
|
||||
let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) }
|
||||
let!(:p1) { create(:simple_product, supplier: producer) }
|
||||
@@ -92,7 +106,7 @@ feature 'Shops', js: true do
|
||||
describe "taxon badges" do
|
||||
let!(:closed_oc) { create(:closed_order_cycle, distributors: [shop], variants: [p_closed.variants.first]) }
|
||||
let!(:p_closed) { create(:simple_product, taxons: [taxon_closed]) }
|
||||
let(:shop) { create(:distributor_enterprise) }
|
||||
let(:shop) { create(:distributor_enterprise, with_payment_and_shipping: true) }
|
||||
let(:taxon_closed) { create(:taxon, name: 'Closed') }
|
||||
|
||||
describe "open shops" do
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe Adjustment do
|
||||
it "has metadata" do
|
||||
@@ -279,6 +281,21 @@ module Spree
|
||||
adjustment.included_tax.should == 10.00
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting the corresponding tax rate" do
|
||||
let!(:adjustment_with_tax) { create(:adjustment, amount: 50, included_tax: 10) }
|
||||
let!(:adjustment_without_tax) { create(:adjustment, amount: 50, included_tax: 0) }
|
||||
let!(:tax_rate) { create(:tax_rate, calculator: Spree::Calculator::DefaultTax.new, amount: 0.25) }
|
||||
let!(:other_tax_rate) { create(:tax_rate, calculator: Spree::Calculator::DefaultTax.new, amount: 0.3) }
|
||||
|
||||
it "returns nil if there is no included tax" do
|
||||
adjustment_without_tax.find_closest_tax_rate_from_included_tax.should == nil
|
||||
end
|
||||
|
||||
it "returns the most accurate tax rate" do
|
||||
adjustment_with_tax.find_closest_tax_rate_from_included_tax.should == tax_rate
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -276,6 +276,50 @@ describe Spree::Order do
|
||||
end
|
||||
end
|
||||
|
||||
describe "getting a hash of all taxes" do
|
||||
let(:zone) { create(:zone_with_member) }
|
||||
let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) }
|
||||
|
||||
let(:tax_rate10) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.1, zone: zone) }
|
||||
let(:tax_rate15) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.15, zone: zone) }
|
||||
let(:tax_rate20) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.2, zone: zone) }
|
||||
let(:tax_category10) { create(:tax_category, tax_rates: [tax_rate10]) }
|
||||
let(:tax_category15) { create(:tax_category, tax_rates: [tax_rate15]) }
|
||||
let(:tax_category20) { create(:tax_category, tax_rates: [tax_rate20]) }
|
||||
|
||||
let(:variant) { create(:variant, product: create(:product, tax_category: tax_category10)) }
|
||||
let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 46.0)) }
|
||||
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category20, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 48.0)) }
|
||||
|
||||
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: [enterprise_fee], distributors: [coordinator], variants: [variant]) }
|
||||
let!(:order) { create(:order, shipping_method: shipping_method, bill_address: create(:address), order_cycle: order_cycle, distributor: coordinator) }
|
||||
let!(:line_item) { create(:line_item, order: order, variant: variant, price: 44.0) }
|
||||
|
||||
before do
|
||||
Spree::Config.shipment_inc_vat = true
|
||||
Spree::Config.shipping_tax_rate = tax_rate15.amount
|
||||
order.create_shipment!
|
||||
Spree::TaxRate.adjust(order)
|
||||
order.reload.update_distribution_charge!
|
||||
end
|
||||
|
||||
it "returns a hash with all 3 taxes" do
|
||||
order.tax_adjustment_totals.size.should == 3
|
||||
end
|
||||
|
||||
it "contains tax on line_item" do
|
||||
order.tax_adjustment_totals[tax_rate10.amount].should == 4.0
|
||||
end
|
||||
|
||||
it "contains tax on shipping_fee" do
|
||||
order.tax_adjustment_totals[tax_rate15.amount].should == 6.0
|
||||
end
|
||||
|
||||
it "contains tax on enterprise_fee" do
|
||||
order.tax_adjustment_totals[tax_rate20.amount].should == 8.0
|
||||
end
|
||||
end
|
||||
|
||||
describe "setting the distributor" do
|
||||
it "sets the distributor when no order cycle is set" do
|
||||
d = create(:distributor_enterprise)
|
||||
|
||||
Reference in New Issue
Block a user