mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge tag 'v1.8.11' into transifex
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -115,7 +115,6 @@ end
|
||||
|
||||
group :test do
|
||||
gem 'webmock'
|
||||
|
||||
# See spec/spec_helper.rb for instructions
|
||||
#gem 'perftools.rb'
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
angular.module("admin.products").controller "editUnitsCtrl", ($scope, VariantUnitManager) ->
|
||||
|
||||
$scope.product =
|
||||
variant_unit: angular.element('#variant_unit').val()
|
||||
variant_unit_scale: angular.element('#variant_unit_scale').val()
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
if $scope.product.variant_unit == 'items'
|
||||
$scope.variant_unit_with_scale = 'items'
|
||||
else
|
||||
$scope.variant_unit_with_scale = $scope.product.variant_unit + '_' + $scope.product.variant_unit_scale
|
||||
|
||||
$scope.setFields = ->
|
||||
if $scope.variant_unit_with_scale == 'items'
|
||||
variant_unit = 'items'
|
||||
variant_unit_scale = null
|
||||
else
|
||||
options = $scope.variant_unit_with_scale.split('_')
|
||||
variant_unit = options[0]
|
||||
variant_unit_scale = options[1]
|
||||
|
||||
$scope.product.variant_unit = variant_unit
|
||||
$scope.product.variant_unit_scale = variant_unit_scale
|
||||
@@ -0,0 +1,14 @@
|
||||
angular.module("admin.products").controller "variantUnitsCtrl", ($scope, VariantUnitManager, $timeout) ->
|
||||
|
||||
$scope.unitName = (scale, type) ->
|
||||
VariantUnitManager.getUnitName(scale, type)
|
||||
|
||||
$scope.scale = angular.element('#product_variant_unit_scale').val()
|
||||
|
||||
$scope.updateValue = ->
|
||||
unit_value_human = angular.element('#unit_value_human').val()
|
||||
$scope.unit_value = unit_value_human * $scope.scale
|
||||
|
||||
variant_unit_value = angular.element('#variant_unit_value').val()
|
||||
$scope.unit_value_human = variant_unit_value / $scope.scale
|
||||
$timeout -> $scope.updateValue()
|
||||
@@ -1,8 +1,8 @@
|
||||
$ ->
|
||||
if ($ 'form#update-cart').is('*')
|
||||
($ 'form#update-cart a.delete').show().one 'click', ->
|
||||
($ this).parents('.line-item').first().find('input.line_item_quantity').val 0
|
||||
($ this).parents('form').first().submit()
|
||||
if $('form#update-cart').is('*') || $('form#update-order').is('*')
|
||||
$('form#update-cart a.delete, form#update-order a.delete').show().one 'click', ->
|
||||
$(this).parents('.line-item').first().find('input.line_item_quantity').val 0
|
||||
$(this).parents('form').first().submit()
|
||||
false
|
||||
|
||||
($ 'form#update-cart').submit ->
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Darkswarm.controller "EditBoughtOrderController", ($scope, $resource, Cart) ->
|
||||
$scope.showBought = false
|
||||
|
||||
$scope.deleteLineItem = (id) ->
|
||||
params = {id: id}
|
||||
success = (response) ->
|
||||
$(".line-item-" + id).remove()
|
||||
Cart.removeFinalisedLineItem(id)
|
||||
fail = (error) ->
|
||||
console.log error
|
||||
|
||||
$resource("/line_items/:id").delete(params, success, fail)
|
||||
@@ -10,7 +10,7 @@ Darkswarm.controller "OrderCycleCtrl", ($scope, $timeout, OrderCycle) ->
|
||||
$("#order_cycle_id").trigger("openTrigger")
|
||||
|
||||
|
||||
Darkswarm.controller "OrderCycleChangeCtrl", ($scope, $timeout, OrderCycle, Products, Variants, Cart) ->
|
||||
Darkswarm.controller "OrderCycleChangeCtrl", ($scope, $timeout, OrderCycle, Products, Variants, Cart, ChangeableOrdersAlert) ->
|
||||
# Track previous order cycle id for use with revertOrderCycle()
|
||||
$scope.previous_order_cycle_id = OrderCycle.order_cycle.order_cycle_id
|
||||
$scope.$watch 'order_cycle.order_cycle_id', (newValue, oldValue)->
|
||||
@@ -30,3 +30,5 @@ Darkswarm.controller "OrderCycleChangeCtrl", ($scope, $timeout, OrderCycle, Prod
|
||||
Variants.clear()
|
||||
Cart.clear()
|
||||
Products.update()
|
||||
Cart.reloadFinalisedLineItems()
|
||||
ChangeableOrdersAlert.reload()
|
||||
|
||||
@@ -11,8 +11,7 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
'angularFileUpload',
|
||||
'angularSlideables'
|
||||
]).config ($httpProvider, $tooltipProvider, $locationProvider, $anchorScrollProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers['common']['X-Requested-With'] = 'XMLHttpRequest'
|
||||
$httpProvider.defaults.headers.common.Accept = "application/json, text/javascript, */*"
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Darkswarm.directive "changeableOrdersAlert", (ChangeableOrdersAlert) ->
|
||||
restrict: "C"
|
||||
scope: true
|
||||
link: (scope, element, attrs) ->
|
||||
scope.alert = ChangeableOrdersAlert
|
||||
@@ -0,0 +1,9 @@
|
||||
Darkswarm.directive "confirmLinkClick", ($window) ->
|
||||
restrict: 'A'
|
||||
scope:
|
||||
confirmMsg: '@confirmLinkClick'
|
||||
link: (scope, elem, attr) ->
|
||||
elem.bind 'click', (event) ->
|
||||
unless confirm(scope.confirmMsg)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
@@ -6,7 +6,11 @@ Darkswarm.directive "ofnOnHand", ->
|
||||
# In cases where this field gets its value from the HTML element rather than the model,
|
||||
# initialise the model with the HTML value.
|
||||
if scope.$eval(attr.ngModel) == undefined
|
||||
ngModel.$setViewValue elem.val()
|
||||
# Don't dirty the model when we do this
|
||||
setDirty = ngModel.$setDirty
|
||||
ngModel.$setDirty = angular.noop
|
||||
ngModel.$setViewValue(elem.val())
|
||||
ngModel.$setDirty = setDirty
|
||||
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
on_hand = parseInt(attr.ofnOnHand)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, localStorageService)->
|
||||
Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService) ->
|
||||
# Handles syncing of current cart/order state to server
|
||||
new class Cart
|
||||
dirty: false
|
||||
@@ -6,11 +6,15 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
update_enqueued: false
|
||||
order: CurrentOrder.order
|
||||
line_items: CurrentOrder.order?.line_items || []
|
||||
line_items_finalised: CurrentOrder.order?.finalised_line_items || []
|
||||
|
||||
constructor: ->
|
||||
for line_item in @line_items
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.register line_item.variant
|
||||
for line_item in @line_items_finalised
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.extend line_item.variant
|
||||
|
||||
adjust: (line_item) =>
|
||||
line_item.total_price = line_item.variant.price_with_fees * line_item.quantity
|
||||
@@ -115,3 +119,15 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
|
||||
clear: ->
|
||||
@line_items = []
|
||||
localStorageService.clearAll() # One day this will have to be moar GRANULAR
|
||||
|
||||
removeFinalisedLineItem: (id) =>
|
||||
@line_items_finalised = @line_items_finalised.filter (item) ->
|
||||
item.id != id
|
||||
|
||||
reloadFinalisedLineItems: =>
|
||||
@line_items_finalised = []
|
||||
$resource("/line_items/bought").query (items) =>
|
||||
for line_item in items
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.extend line_item.variant
|
||||
@line_items_finalised = items
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Darkswarm.factory 'ChangeableOrdersAlert', ($http) ->
|
||||
new class ChangeableOrdersAlert
|
||||
html: ''
|
||||
visible: true
|
||||
|
||||
constructor: ->
|
||||
@reload()
|
||||
|
||||
reload: ->
|
||||
$http.get('/shop/changeable_orders_alert').then (response) =>
|
||||
@html = response.data.trim()
|
||||
|
||||
close: =>
|
||||
@visible = false
|
||||
@@ -3,10 +3,12 @@ Darkswarm.factory 'Orders', (orders_by_distributor, currencyConfig, CurrentHub,
|
||||
constructor: ->
|
||||
# Populate Orders.orders from json in page.
|
||||
@orders_by_distributor = orders_by_distributor
|
||||
@changeable_orders = []
|
||||
@currency_symbol = currencyConfig.symbol
|
||||
|
||||
for distributor in @orders_by_distributor
|
||||
@updateRunningBalance(distributor.distributed_orders)
|
||||
@findChangeableOrders(distributor.distributed_orders)
|
||||
@updateRunningBalance(distributor.distributed_orders)
|
||||
|
||||
|
||||
updateRunningBalance: (orders) ->
|
||||
@@ -14,3 +16,7 @@ Darkswarm.factory 'Orders', (orders_by_distributor, currencyConfig, CurrentHub,
|
||||
balances = orders.slice(i,orders.length).map (o) -> parseFloat(o.outstanding_balance)
|
||||
running_balance = balances.reduce (a,b) -> a+b
|
||||
order.running_balance = running_balance.toFixed(2)
|
||||
|
||||
findChangeableOrders: (orders) ->
|
||||
for order in orders when order.changes_allowed
|
||||
@changeable_orders.push(order)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%div{ ng: { show: "data.length > limit" } }
|
||||
%input{ type: 'button', value: t(:show_more), ng: { click: 'limit = limit + increment' } }
|
||||
or
|
||||
%input{ type: 'button', value: t(:show_more_with_more, num: '{{ data.length - limit }}'), ng: { click: 'limit = data.length' } }
|
||||
%input{ type: 'button', value: t(:show_all_with_more, num: '{{ data.length - limit }}'), ng: { click: 'limit = data.length' } }
|
||||
|
||||
3
app/assets/stylesheets/admin/enterprises.css.scss
Normal file
3
app/assets/stylesheets/admin/enterprises.css.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
form[name="enterprise_form"] div.row.warning {
|
||||
color: #DA7F52;
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
height: 100px
|
||||
width: 100px
|
||||
margin-right: 12px
|
||||
|
||||
|
||||
location
|
||||
@include headingFont
|
||||
@media all and (max-width: 768px)
|
||||
@@ -30,7 +30,7 @@
|
||||
margin-top: 0
|
||||
@media all and (max-width: 768px)
|
||||
margin-bottom: 8px
|
||||
|
||||
|
||||
|
||||
ordercycle
|
||||
text-align: right
|
||||
@@ -47,24 +47,26 @@
|
||||
p
|
||||
max-width: 100%
|
||||
float: right
|
||||
form.custom
|
||||
form.custom
|
||||
text-align: right
|
||||
& > strong
|
||||
line-height: 2.5
|
||||
font-size: 1.29em
|
||||
padding-right: 14px
|
||||
@media all and (max-width: 768px)
|
||||
select
|
||||
select
|
||||
width: inherit
|
||||
display: inline-block
|
||||
border-width: 1px
|
||||
border-color: #999
|
||||
color: #666
|
||||
font-size: 1em
|
||||
font-size: 1em
|
||||
margin-bottom: 0
|
||||
padding: 8px 20px 8px 12px
|
||||
@media all and (max-width: 768px)
|
||||
font-size: 0.875em
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0)
|
||||
font-size: 16px
|
||||
closing
|
||||
@include headingFont
|
||||
@media all and (max-width: 768px)
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
@import "branding";
|
||||
@import "mixins";
|
||||
|
||||
.account-summary {
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
|
||||
.orders {
|
||||
@include sidepaddingSm;
|
||||
|
||||
@include panepadding;
|
||||
|
||||
padding-top: 10px;
|
||||
|
||||
h3 {
|
||||
padding-top: 2em;
|
||||
}
|
||||
margin-top: 50px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
a {
|
||||
color: $clr-brick;
|
||||
@@ -26,6 +24,12 @@
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.active_table_row {
|
||||
h3 {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
i.ofn-i_059-producer, i.ofn-i_060-producer-reversed {
|
||||
font-size: 3rem;
|
||||
display: inline-block;
|
||||
@@ -61,6 +65,7 @@
|
||||
.transaction-group {}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-radius: 0.5em 0.5em 0 0;
|
||||
|
||||
tr:nth-of-type(even) {
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
|
||||
@-webkit-keyframes slideOutUp {
|
||||
0% {
|
||||
opacity: 1;
|
||||
-webkit-transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
@@ -46,10 +48,18 @@
|
||||
|
||||
@keyframes slideOutUp {
|
||||
0% {
|
||||
opacity: 1;
|
||||
-webkit-transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateY(-20px);
|
||||
-ms-transform: translateY(-20px);
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeIn {
|
||||
|
||||
@@ -6,23 +6,25 @@
|
||||
background-color: #e1f0f5
|
||||
padding: 1em
|
||||
width: 100%
|
||||
border: none
|
||||
color: inherit
|
||||
|
||||
checkout
|
||||
display: block
|
||||
|
||||
@media all and (max-width: 640px)
|
||||
&.row .row
|
||||
@media all and (max-width: 640px)
|
||||
&.row .row
|
||||
margin-left: 0
|
||||
margin-right: 0
|
||||
|
||||
|
||||
orderdetails
|
||||
.button, table
|
||||
width: 100%
|
||||
@media all and (max-width: 640px)
|
||||
@media all and (max-width: 640px)
|
||||
form.edit_order
|
||||
border: 1px solid $disabled-bright
|
||||
margin-bottom: 2rem
|
||||
|
||||
|
||||
#details, #billing, #shipping, #payment
|
||||
border: 0
|
||||
margin: 1em 0
|
||||
@@ -34,20 +36,20 @@ checkout
|
||||
margin: 0
|
||||
padding: 0.65em
|
||||
background: #f7f7f7
|
||||
|
||||
.label
|
||||
|
||||
.label
|
||||
font-size: 1em
|
||||
padding: 0.3rem 0.35rem 0.275rem
|
||||
|
||||
// Logic to turn on & off the alerts for success against each fieldset
|
||||
|
||||
label, label.alert, label.success, &.valid label.alert, &.dirty label.success
|
||||
label, label.alert, label.success, &.valid label.alert, &.dirty label.success
|
||||
display: none
|
||||
|
||||
&.dirty label.alert
|
||||
&.dirty label.alert
|
||||
display: inline
|
||||
&.dirty.valid label.alert
|
||||
display: none
|
||||
&.dirty.valid label.alert
|
||||
display: none
|
||||
&.valid label.success
|
||||
display: inline
|
||||
|
||||
@@ -60,7 +62,7 @@ checkout
|
||||
text-align: left
|
||||
|
||||
// Logic to swap out up / down accordion icons
|
||||
//Foundation overrides
|
||||
//Foundation overrides
|
||||
dd > a
|
||||
@include csstrans
|
||||
background: $disabled-light !important
|
||||
@@ -68,7 +70,7 @@ checkout
|
||||
dd > a:hover
|
||||
background: $disabled-v-dark !important
|
||||
color: white
|
||||
|
||||
|
||||
dd
|
||||
span.accordion-up
|
||||
display: none
|
||||
@@ -79,4 +81,3 @@ checkout
|
||||
display: inline
|
||||
span.accordion-down
|
||||
display: none
|
||||
|
||||
|
||||
@@ -110,6 +110,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.alert-box.changeable-orders-alert {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.alert-box.shopfront-message {
|
||||
border: 2px solid $clr-turquoise;
|
||||
border-radius: 5px;
|
||||
|
||||
@@ -72,11 +72,35 @@
|
||||
|
||||
// Shopping cart
|
||||
#cart-detail {
|
||||
.cart-item-delete {
|
||||
a.delete {
|
||||
.cart-item-delete, .bought-item-delete {
|
||||
a {
|
||||
font-size: 1.125em;
|
||||
}
|
||||
}
|
||||
|
||||
.out-of-stock {
|
||||
color: $clr-brick;
|
||||
}
|
||||
|
||||
button, .button {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toggle-bought {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tr.bought td {
|
||||
color: $med-grey;
|
||||
|
||||
h5 {
|
||||
color: $med-grey;
|
||||
}
|
||||
|
||||
.already-confirmed {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-thumb-image {
|
||||
@@ -90,9 +114,3 @@
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
#edit-cart {
|
||||
button, .button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
48
app/controllers/line_items_controller.rb
Normal file
48
app/controllers/line_items_controller.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
class LineItemsController < BaseController
|
||||
respond_to :json
|
||||
|
||||
before_filter :load_line_item, only: :destroy
|
||||
|
||||
def bought
|
||||
respond_with bought_items, each_serializer: Api::LineItemSerializer
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :destroy, @line_item
|
||||
destroy_with_lock @line_item
|
||||
respond_with(@line_item)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_line_item
|
||||
@line_item = Spree::LineItem.find_by_id(params[:id])
|
||||
not_found unless @line_item
|
||||
end
|
||||
|
||||
# List all items the user already ordered in the current order cycle
|
||||
def bought_items
|
||||
return [] unless current_order_cycle && spree_current_user && current_distributor
|
||||
current_order_cycle.items_bought_by_user(spree_current_user, current_distributor)
|
||||
end
|
||||
|
||||
def unauthorized
|
||||
status = spree_current_user ? 403 : 401
|
||||
render nothing: true, status: status and return
|
||||
end
|
||||
|
||||
def not_found
|
||||
render nothing: true, status: 404 and return
|
||||
end
|
||||
|
||||
def destroy_with_lock(item)
|
||||
order = item.order
|
||||
order.with_lock do
|
||||
item.destroy
|
||||
order.update_shipping_fees!
|
||||
order.update_payment_fees!
|
||||
order.update_distribution_charge!
|
||||
order.create_tax_charge!
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -37,6 +37,10 @@ class ShopController < BaseController
|
||||
end
|
||||
end
|
||||
|
||||
def changeable_orders_alert
|
||||
render layout: false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def filtered_json(products_json)
|
||||
|
||||
@@ -12,6 +12,9 @@ Spree::Admin::OrdersController.class_eval do
|
||||
|
||||
before_filter :load_distribution_choices, only: [:new, :edit, :update]
|
||||
|
||||
# Ensure that the distributor is set for an order when
|
||||
before_filter :ensure_distribution, only: :new
|
||||
|
||||
# After updating an order, the fees should be updated as well
|
||||
# Currently, adding or deleting line items does not trigger updating the
|
||||
# fees! This is a quick fix for that.
|
||||
@@ -131,4 +134,16 @@ Spree::Admin::OrdersController.class_eval do
|
||||
ocs.closed +
|
||||
ocs.undated
|
||||
end
|
||||
|
||||
def ensure_distribution
|
||||
unless @order
|
||||
@order = Spree::Order.new
|
||||
@order.generate_order_number
|
||||
@order.save!
|
||||
end
|
||||
unless @order.distribution_set?
|
||||
render 'set_distribution', locals: { order: @order }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -231,7 +231,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
@report_types = REPORT_TYPES[:orders_and_fulfillment]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
@include_blank = 'All'
|
||||
@include_blank = I18n.t(:all)
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user, params
|
||||
|
||||
@@ -8,10 +8,12 @@ Spree::OrdersController.class_eval do
|
||||
prepend_before_filter :require_order_cycle, only: :edit
|
||||
prepend_before_filter :require_distributor_chosen, only: :edit
|
||||
before_filter :check_hub_ready_for_checkout, only: :edit
|
||||
before_filter :check_at_least_one_line_item, only: :update
|
||||
|
||||
include OrderCyclesHelper
|
||||
layout 'darkswarm'
|
||||
|
||||
respond_to :json
|
||||
|
||||
# Patching to redirect to shop if order is empty
|
||||
def edit
|
||||
@@ -32,7 +34,7 @@ Spree::OrdersController.class_eval do
|
||||
|
||||
def update
|
||||
@insufficient_stock_lines = []
|
||||
@order = current_order
|
||||
@order = order_to_update
|
||||
unless @order
|
||||
flash[:error] = t(:order_not_found)
|
||||
redirect_to root_path and return
|
||||
@@ -43,12 +45,19 @@ Spree::OrdersController.class_eval do
|
||||
|
||||
render :edit and return unless apply_coupon_code
|
||||
|
||||
fire_event('spree.order.contents_changed')
|
||||
if @order == current_order
|
||||
fire_event('spree.order.contents_changed')
|
||||
else
|
||||
@order.update_distribution_charge!
|
||||
end
|
||||
|
||||
respond_with(@order) do |format|
|
||||
format.html do
|
||||
if params.has_key?(:checkout)
|
||||
@order.next_transition.run_callbacks if @order.cart?
|
||||
redirect_to checkout_state_path(@order.checkout_steps.first)
|
||||
elsif @order.complete?
|
||||
redirect_to order_path(@order)
|
||||
else
|
||||
redirect_to cart_path
|
||||
end
|
||||
@@ -162,6 +171,18 @@ Spree::OrdersController.class_eval do
|
||||
@order_cycle = OrderCycle.find session[:expired_order_cycle_id]
|
||||
end
|
||||
|
||||
def cancel
|
||||
@order = Spree::Order.find_by_number!(params[:id])
|
||||
authorize! :cancel, @order
|
||||
|
||||
if @order.cancel
|
||||
flash[:success] = I18n.t(:orders_your_order_has_been_cancelled)
|
||||
else
|
||||
flash[:error] = I18n.t(:orders_could_not_cancel)
|
||||
end
|
||||
redirect_to request.referer || order_path(@order)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
@@ -202,4 +223,30 @@ Spree::OrdersController.class_eval do
|
||||
def wrap_json_infinity(n)
|
||||
n == Float::INFINITY ? 2147483647 : n
|
||||
end
|
||||
|
||||
def order_to_update
|
||||
return @order_to_update if defined? @order_to_update
|
||||
return @order_to_update = current_order unless params[:id]
|
||||
@order_to_update = changeable_order_from_number
|
||||
end
|
||||
|
||||
# If a specific order is requested, return it if it is COMPLETE and
|
||||
# changes are allowed and the user has access. Return nil if not.
|
||||
def changeable_order_from_number
|
||||
order = Spree::Order.complete.find_by_number(params[:id])
|
||||
return nil unless order.andand.changes_allowed? && can?(:update, order)
|
||||
order
|
||||
end
|
||||
|
||||
def check_at_least_one_line_item
|
||||
return unless order_to_update.andand.complete?
|
||||
|
||||
items = params[:order][:line_items_attributes]
|
||||
.andand.select{ |k,attrs| attrs["quantity"].to_i > 0 }
|
||||
|
||||
if items.empty?
|
||||
flash[:error] = I18n.t(:orders_cannot_remove_the_final_item)
|
||||
redirect_to order_path(order_to_update)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ module CheckoutHelper
|
||||
enterprise_fee_adjustments = adjustments.select { |a| a.originator_type == 'EnterpriseFee' && a.source_type != 'Spree::LineItem' }
|
||||
adjustments.reject! { |a| a.originator_type == 'EnterpriseFee' && a.source_type != 'Spree::LineItem' }
|
||||
unless exclude.include? :admin_and_handling
|
||||
adjustments << Spree::Adjustment.new(label: 'Admin & Handling', amount: enterprise_fee_adjustments.sum(&:amount))
|
||||
adjustments << Spree::Adjustment.new(label: I18n.t(:orders_form_admin), amount: enterprise_fee_adjustments.sum(&:amount))
|
||||
end
|
||||
|
||||
adjustments
|
||||
@@ -55,7 +55,6 @@ module CheckoutHelper
|
||||
|
||||
def display_adjustment_tax_rates(adjustment)
|
||||
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
|
||||
|
||||
|
||||
@@ -88,4 +88,12 @@ module EnterprisesHelper
|
||||
def remaining_trial_days(enterprise)
|
||||
distance_of_time_in_words(Time.zone.now, enterprise.shop_trial_start_date + Spree::Config[:shop_trial_length_days].days)
|
||||
end
|
||||
|
||||
def order_changes_allowed?
|
||||
current_order.andand.distributor.andand.allow_order_changes?
|
||||
end
|
||||
|
||||
def show_bought_items?
|
||||
order_changes_allowed? && current_order.finalised_line_items.present?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,5 +16,31 @@ module Spree
|
||||
def cart_count
|
||||
current_order.andand.line_items.andand.count || 0
|
||||
end
|
||||
|
||||
def changeable_orders
|
||||
# Only returns open order for the current user + shop + oc combo
|
||||
return @changeable_orders unless @changeable_orders.nil?
|
||||
return @changeable_orders = [] unless spree_current_user && current_distributor && current_order_cycle
|
||||
return @changeable_orders = [] unless current_distributor.allow_order_changes?
|
||||
@changeable_orders = Spree::Order.complete.where(
|
||||
state: 'complete',
|
||||
user_id: spree_current_user.id,
|
||||
distributor_id: current_distributor.id,
|
||||
order_cycle_id: current_order_cycle.id)
|
||||
end
|
||||
|
||||
def changeable_orders_link_path
|
||||
changeable_orders.one? ? spree.order_path(changeable_orders.first) : spree.account_path
|
||||
end
|
||||
|
||||
def shop_changeable_orders_alert_html
|
||||
return "" unless changeable_orders.any?
|
||||
t(:shop_changeable_orders_alert_html,
|
||||
count: changeable_orders.count,
|
||||
path: changeable_orders_link_path,
|
||||
order: changeable_orders.first.number,
|
||||
shop: current_distributor.name,
|
||||
oc_close: l(current_order_cycle.orders_close_at, format: "%A, %b %d, %Y @ %H:%M"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module OpenFoodNetwork
|
||||
attr_accessible :preferred_per_kg
|
||||
|
||||
def self.description
|
||||
"Weight (per kg)"
|
||||
I18n.t('spree.weight')
|
||||
end
|
||||
|
||||
def compute(object)
|
||||
|
||||
@@ -250,6 +250,13 @@ class OrderCycle < ActiveRecord::Base
|
||||
OpenFoodNetwork::ProductsCache.order_cycle_changed self
|
||||
end
|
||||
|
||||
def items_bought_by_user(user, distributor)
|
||||
# The Spree::Order.complete scope only checks for completed_at date, does not ensure state is "complete"
|
||||
orders = Spree::Order.complete.where(state: "complete", user_id: user, distributor_id: distributor, order_cycle_id: self)
|
||||
scoper = OpenFoodNetwork::ScopeVariantToHub.new(distributor)
|
||||
items = Spree::LineItem.joins(:order).merge(orders)
|
||||
items.each { |li| scoper.scope(li.variant) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ class AbilityDecorator
|
||||
# All abilites are allocated from this initialiser, currently in 5 chunks.
|
||||
# Spree also defines other abilities.
|
||||
def initialize(user)
|
||||
add_shopping_abilities user
|
||||
add_base_abilities user if is_new_user? user
|
||||
add_enterprise_management_abilities user if can_manage_enterprises? user
|
||||
add_group_management_abilities user if can_manage_groups? user
|
||||
@@ -50,6 +51,16 @@ class AbilityDecorator
|
||||
can_manage_enterprises? user
|
||||
end
|
||||
|
||||
def add_shopping_abilities(user)
|
||||
can [:destroy], Spree::LineItem do |item|
|
||||
user == item.order.user &&
|
||||
item.order.changes_allowed?
|
||||
end
|
||||
can [:cancel], Spree::Order do |order|
|
||||
order.user == user
|
||||
end
|
||||
end
|
||||
|
||||
# New users can create an enterprise, and gain other permissions from doing this.
|
||||
def add_base_abilities(user)
|
||||
can [:create], Enterprise
|
||||
@@ -184,6 +195,7 @@ class AbilityDecorator
|
||||
can [:admin , :for_line_items], Enterprise
|
||||
can [:admin, :index, :create], Spree::LineItem
|
||||
can [:destroy, :update], Spree::LineItem do |item|
|
||||
order = item.order
|
||||
user.admin? || user.enterprises.include?(order.distributor) || order.order_cycle.andand.coordinated_by?(user)
|
||||
end
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ module Spree
|
||||
included_tax > 0
|
||||
end
|
||||
|
||||
# @return [Array<Spree::TaxRate>]
|
||||
def tax_rates
|
||||
case originator
|
||||
when Spree::TaxRate
|
||||
@@ -47,14 +48,17 @@ module Spree
|
||||
return originator.tax_category ? originator.tax_category.tax_rates.match(source) : []
|
||||
end
|
||||
else
|
||||
[find_closest_tax_rate_from_included_tax]
|
||||
find_closest_tax_rates_from_included_tax
|
||||
end
|
||||
end
|
||||
|
||||
def find_closest_tax_rate_from_included_tax
|
||||
# shipping fees and adjustments created from the admin panel have
|
||||
# taxes set at creation in the included_tax field without relation
|
||||
# to the corresponding TaxRate, so we look for the closest one
|
||||
def find_closest_tax_rates_from_included_tax
|
||||
approximation = (included_tax / (amount - included_tax))
|
||||
return nil if approximation.infinite? or approximation.zero?
|
||||
Spree::TaxRate.order("ABS(amount - #{approximation})").first
|
||||
return [] if approximation.infinite? or approximation.zero?
|
||||
[Spree::TaxRate.order("ABS(amount - #{approximation})").first]
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -94,8 +94,41 @@ Spree::LineItem.class_eval do
|
||||
(final_weight_volume || 0) / quantity
|
||||
end
|
||||
|
||||
# MONKEYPATCH of Spree method
|
||||
# Enables scoping of variant to hub/shop, stock drawn down from inventory
|
||||
def update_inventory
|
||||
return true unless order.completed?
|
||||
|
||||
scoper.scope(variant) # this line added
|
||||
|
||||
if new_record?
|
||||
Spree::InventoryUnit.increase(order, variant, quantity)
|
||||
elsif old_quantity = self.changed_attributes['quantity']
|
||||
if old_quantity < quantity
|
||||
Spree::InventoryUnit.increase(order, variant, (quantity - old_quantity))
|
||||
elsif old_quantity > quantity
|
||||
Spree::InventoryUnit.decrease(order, variant, (old_quantity - quantity))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# MONKEYPATCH of Spree method
|
||||
# Enables scoping of variant to hub/shop, stock replaced to inventory
|
||||
def remove_inventory
|
||||
return true unless order.completed?
|
||||
|
||||
scoper.scope(variant) # this line added
|
||||
|
||||
Spree::InventoryUnit.decrease(order, variant, quantity)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scoper
|
||||
return @scoper unless @scoper.nil?
|
||||
@scoper = OpenFoodNetwork::ScopeVariantToHub.new(order.distributor)
|
||||
end
|
||||
|
||||
def calculate_final_weight_volume
|
||||
if final_weight_volume.present? && quantity_was > 0
|
||||
self.final_weight_volume = final_weight_volume * quantity / quantity_was
|
||||
|
||||
@@ -9,7 +9,7 @@ end
|
||||
|
||||
Spree::Order.class_eval do
|
||||
belongs_to :order_cycle
|
||||
belongs_to :distributor, :class_name => 'Enterprise'
|
||||
belongs_to :distributor, class_name: 'Enterprise'
|
||||
belongs_to :cart
|
||||
belongs_to :customer
|
||||
|
||||
@@ -21,6 +21,9 @@ Spree::Order.class_eval do
|
||||
before_validation :associate_customer, unless: :customer_id?
|
||||
before_validation :ensure_customer, unless: :customer_is_valid?
|
||||
|
||||
before_save :update_shipping_fees!, if: :complete?
|
||||
before_save :update_payment_fees!, if: :complete?
|
||||
|
||||
checkout_flow do
|
||||
go_to_state :address
|
||||
go_to_state :delivery
|
||||
@@ -39,7 +42,6 @@ Spree::Order.class_eval do
|
||||
remove_transition :from => :delivery, :to => :confirm
|
||||
end
|
||||
|
||||
|
||||
# -- Scopes
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
@@ -88,7 +90,7 @@ Spree::Order.class_eval do
|
||||
unless self.order_cycle == order_cycle
|
||||
self.order_cycle = order_cycle
|
||||
self.distributor = nil unless order_cycle.nil? || order_cycle.has_distributor?(distributor)
|
||||
self.empty!
|
||||
empty!
|
||||
save!
|
||||
end
|
||||
end
|
||||
@@ -99,7 +101,6 @@ Spree::Order.class_eval do
|
||||
current_item.andand.destroy
|
||||
end
|
||||
|
||||
|
||||
# Overridden to support max_quantity
|
||||
def add_variant(variant, quantity = 1, max_quantity = nil, currency = nil)
|
||||
line_items(:reload)
|
||||
@@ -126,7 +127,7 @@ Spree::Order.class_eval do
|
||||
current_item.currency = currency unless currency.nil?
|
||||
current_item.save
|
||||
else
|
||||
current_item = Spree::LineItem.new(:quantity => quantity, max_quantity: max_quantity)
|
||||
current_item = Spree::LineItem.new(quantity: quantity, max_quantity: max_quantity)
|
||||
current_item.variant = variant
|
||||
if currency
|
||||
current_item.currency = currency unless currency.nil?
|
||||
@@ -134,13 +135,31 @@ Spree::Order.class_eval do
|
||||
else
|
||||
current_item.price = variant.price
|
||||
end
|
||||
self.line_items << current_item
|
||||
line_items << current_item
|
||||
end
|
||||
|
||||
self.reload
|
||||
reload
|
||||
current_item
|
||||
end
|
||||
|
||||
# After changing line items of a completed order
|
||||
def update_shipping_fees!
|
||||
shipments.each do |shipment|
|
||||
next if shipment.shipped?
|
||||
update_adjustment! shipment.adjustment
|
||||
shipment.save # updates included tax
|
||||
end
|
||||
end
|
||||
|
||||
# After changing line items of a completed order
|
||||
def update_payment_fees!
|
||||
payments.each do |payment|
|
||||
next if payment.completed?
|
||||
update_adjustment! payment.adjustment
|
||||
payment.save
|
||||
end
|
||||
end
|
||||
|
||||
def cap_quantity_at_stock!
|
||||
line_items.each &:cap_quantity_at_stock!
|
||||
end
|
||||
@@ -158,6 +177,10 @@ Spree::Order.class_eval do
|
||||
save!
|
||||
end
|
||||
|
||||
def distribution_set?
|
||||
distributor && order_cycle
|
||||
end
|
||||
|
||||
def update_distribution_charge!
|
||||
with_lock do
|
||||
EnterpriseFee.clear_all_adjustments_on_order self
|
||||
@@ -195,6 +218,12 @@ Spree::Order.class_eval do
|
||||
line_items.map(&:variant)
|
||||
end
|
||||
|
||||
# Show already bought line items of this order cycle
|
||||
def finalised_line_items
|
||||
return [] unless order_cycle && user && distributor
|
||||
order_cycle.items_bought_by_user(user, distributor)
|
||||
end
|
||||
|
||||
def admin_and_handling_total
|
||||
adjustments.eligible.where("originator_type = ? AND source_type != ?", 'EnterpriseFee', 'Spree::LineItem').sum(&:amount)
|
||||
end
|
||||
@@ -205,26 +234,26 @@ Spree::Order.class_eval do
|
||||
|
||||
# Does this order have shipments that can be shipped?
|
||||
def ready_to_ship?
|
||||
self.shipments.any?{|s| s.can_ship?}
|
||||
shipments.any?(&:can_ship?)
|
||||
end
|
||||
|
||||
# Ship all pending orders
|
||||
def ship
|
||||
self.shipments.each do |s|
|
||||
shipments.each do |s|
|
||||
s.ship if s.can_ship?
|
||||
end
|
||||
end
|
||||
|
||||
def shipping_tax
|
||||
adjustments(:reload).shipping.sum &:included_tax
|
||||
adjustments(:reload).shipping.sum(&:included_tax)
|
||||
end
|
||||
|
||||
def enterprise_fee_tax
|
||||
adjustments(:reload).enterprise_fee.sum &:included_tax
|
||||
adjustments(:reload).enterprise_fee.sum(&:included_tax)
|
||||
end
|
||||
|
||||
def total_tax
|
||||
(adjustments + price_adjustments).sum &:included_tax
|
||||
(adjustments + price_adjustments).sum(&:included_tax)
|
||||
end
|
||||
|
||||
def tax_adjustments
|
||||
@@ -254,11 +283,12 @@ Spree::Order.class_eval do
|
||||
# Overrride of Spree method, that allows us to send separate confirmation emails to user and shop owners
|
||||
# And separately, to skip sending confirmation email completely for user invoice orders
|
||||
def deliver_order_confirmation_email
|
||||
unless account_invoice?
|
||||
Delayed::Job.enqueue ConfirmOrderJob.new(id)
|
||||
end
|
||||
Delayed::Job.enqueue ConfirmOrderJob.new(id) unless account_invoice?
|
||||
end
|
||||
|
||||
def changes_allowed?
|
||||
complete? && distributor.andand.allow_order_changes? && order_cycle.andand.open?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -272,9 +302,9 @@ Spree::Order.class_eval do
|
||||
self.ship_address = distributor.address.clone
|
||||
|
||||
if bill_address
|
||||
self.ship_address.firstname = bill_address.firstname
|
||||
self.ship_address.lastname = bill_address.lastname
|
||||
self.ship_address.phone = bill_address.phone
|
||||
ship_address.firstname = bill_address.firstname
|
||||
ship_address.lastname = bill_address.lastname
|
||||
ship_address.phone = bill_address.phone
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -286,11 +316,11 @@ Spree::Order.class_eval do
|
||||
end
|
||||
|
||||
def product_distribution_for(line_item)
|
||||
line_item.variant.product.product_distribution_for self.distributor
|
||||
line_item.variant.product.product_distribution_for distributor
|
||||
end
|
||||
|
||||
def require_customer?
|
||||
return true unless new_record? or state == 'cart'
|
||||
return true unless new_record? || state == 'cart'
|
||||
end
|
||||
|
||||
def customer_is_valid?
|
||||
@@ -313,4 +343,11 @@ Spree::Order.class_eval do
|
||||
self.customer = Customer.create(enterprise: distributor, email: email_for_customer, user: user, name: customer_name, bill_address: bill_address.andand.clone, ship_address: ship_address.andand.clone)
|
||||
end
|
||||
end
|
||||
|
||||
def update_adjustment!(adjustment)
|
||||
locked = adjustment.locked
|
||||
adjustment.locked = false
|
||||
adjustment.update!(self)
|
||||
adjustment.locked = locked
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,13 +37,14 @@ Spree::Taxon.class_eval do
|
||||
#
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.distributed_taxons(which_taxons=:all)
|
||||
# TODO: Why can't we merge(Spree::Product.with_order_cycles_inner) here?
|
||||
taxons = Spree::Taxon.
|
||||
joins(products: {variants_including_master: {exchanges: :order_cycle}}).
|
||||
merge(Exchange.outgoing).
|
||||
select('spree_taxons.*, exchanges.receiver_id AS enterprise_id')
|
||||
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
|
||||
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
|
||||
|
||||
taxons = taxons.merge(OrderCycle.active) if which_taxons == :current
|
||||
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
|
||||
|
||||
taxons = Spree::Taxon
|
||||
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id").joins(products: :variants_including_master)
|
||||
.joins("INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars ON spree_variants.id = ents_and_vars.variant_id")
|
||||
|
||||
taxons.inject({}) do |ts, t|
|
||||
ts[t.enterprise_id.to_i] ||= Set.new
|
||||
|
||||
@@ -19,7 +19,7 @@ class VariantOverride < ActiveRecord::Base
|
||||
|
||||
def self.indexed(hub)
|
||||
Hash[
|
||||
for_hubs(hub).map { |vo| [vo.variant, vo] }
|
||||
for_hubs(hub).preload(:variant).map { |vo| [vo.variant, vo] }
|
||||
]
|
||||
end
|
||||
|
||||
@@ -58,6 +58,14 @@ class VariantOverride < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def increment_stock!(quantity)
|
||||
if stock_overridden?
|
||||
increment! :count_on_hand, quantity
|
||||
else
|
||||
Bugsnag.notify RuntimeError.new "Attempting to decrement stock level on a VariantOverride without a count_on_hand specified."
|
||||
end
|
||||
end
|
||||
|
||||
def default_stock?
|
||||
default_stock.present?
|
||||
end
|
||||
|
||||
@@ -1,38 +1,3 @@
|
||||
/ insert_before "[data-hook='admin_order_form_buttons']"
|
||||
|
||||
%fieldset.no-border-bottom
|
||||
%legend{align: 'center'} Distribution
|
||||
|
||||
- if @order.complete?
|
||||
.alpha.six.columns
|
||||
%p
|
||||
%b Distributor:
|
||||
= f.object.distributor.andand.name || "None"
|
||||
= f.hidden_field :distributor_id
|
||||
.omega.six.columns
|
||||
%p
|
||||
%b Order cycle:
|
||||
= f.object.order_cycle.andand.name || "None"
|
||||
= f.hidden_field :order_cycle_id
|
||||
|
||||
- else
|
||||
.alpha.six.columns
|
||||
.field
|
||||
%label{for: "order_distributor_id"} Distributor
|
||||
%input.ofn-select2.fullwidth{id: "order_distributor_id",
|
||||
type: 'number',
|
||||
name: "order[distributor_id]",
|
||||
"ng-model" => 'distributor_id',
|
||||
data: "shops" }
|
||||
|
||||
.omega.six.columns
|
||||
.field
|
||||
%label{ for: "order_order_cycle_id"} Order Cycle
|
||||
%input.ofn-select2.fullwidth{id: "order_order_cycle_id",
|
||||
type: 'number',
|
||||
name: "order[order_cycle_id]",
|
||||
"ng-model" => 'order_cycle_id',
|
||||
"ng-disabled" => "!distributor_id",
|
||||
data: "orderCycles",
|
||||
text: "name_and_status",
|
||||
filter: "validOrderCycle" }
|
||||
= render partial: 'spree/admin/orders/_form/distribution_fields'
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/ replace 'code[erb-loud]:contains(\'f.object.variant.display_amount\')'
|
||||
|
||||
= f.object.single_money
|
||||
@@ -0,0 +1,6 @@
|
||||
/ 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 }
|
||||
@@ -1,16 +1,17 @@
|
||||
/ insert_top "[data-hook='admin_product_form_right']"
|
||||
|
||||
= f.field_container :variant_unit do
|
||||
= f.label :variant_unit, 'Variant unit'
|
||||
= f.select :variant_unit, product_variant_unit_options, {:include_blank => true}, {:class => "select2 fullwidth"}
|
||||
= f.error_message_on :variant_unit
|
||||
.variant_units_form{ 'ng-app' => 'admin.products', 'ng-controller' => 'editUnitsCtrl' }
|
||||
|
||||
= f.field_container :variant_unit_scale do
|
||||
= f.label :variant_unit_scale, 'Variant unit scale'
|
||||
= f.text_field :variant_unit_scale
|
||||
= f.error_message_on :variant_unit_scale
|
||||
= f.field_container :units do
|
||||
= f.label :variant_unit_with_scale, :units
|
||||
%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.field_container :variant_unit_name do
|
||||
= f.label :variant_unit_name, 'Variant unit name'
|
||||
= f.text_field :variant_unit_name
|
||||
= f.error_message_on :variant_unit_name
|
||||
= 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, 'Variant unit name'
|
||||
= f.text_field :variant_unit_name, {placeholder: t('admin.products.unit_name_placeholder')}
|
||||
= f.error_message_on :variant_unit_name
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
.three.columns.omega{ 'ng-show' => "product.variant_unit_with_scale == 'items'" }
|
||||
= f.field_container :unit_name do
|
||||
= f.label :product_variant_unit_name, t(:unit_name)
|
||||
%input.fullwidth{ id: 'product_variant_unit_name','ng-model' => 'product.variant_unit_name', :name => 'product[variant_unit_name]', :placeholder => 'eg. bunches', :type => 'text' }
|
||||
%input.fullwidth{ id: 'product_variant_unit_name','ng-model' => 'product.variant_unit_name', :name => 'product[variant_unit_name]', :placeholder => t('admin.products.unit_name_placeholder'), :type => 'text' }
|
||||
.twelve.columns.alpha
|
||||
.six.columns.alpha
|
||||
= render 'spree/admin/products/primary_taxon_form', f: f
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/ replace_contents 'tr[data-hook="order_details_line_item_row"] td.price'
|
||||
|
||||
= item.single_display_amount
|
||||
@@ -1,3 +1,3 @@
|
||||
/ insert_bottom "[data-hook='admin_product_sub_tabs']"
|
||||
|
||||
= tab :variant_overrides, label: "Inventory", url: main_app.admin_inventory_path, match_path: '/inventory'
|
||||
= tab :variant_overrides, url: main_app.admin_inventory_path, match_path: '/inventory'
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
/ insert_top "[data-hook='admin_variant_form_fields']"
|
||||
|
||||
- if product_has_variant_unit_option_type?(@product)
|
||||
.field{"data-hook" => "unit_value"}
|
||||
= f.label :unit_value, "Unit Value"
|
||||
= f.text_field :unit_value, class: "fullwidth"
|
||||
- if @product.variant_unit != 'items'
|
||||
.field{"data-hook" => "unit_value", 'ng-controller' => 'variantUnitsCtrl'}
|
||||
= f.label :unit_value, "#{t('admin.'+@product.variant_unit)} ({{unitName(#{@product.variant_unit_scale}, '#{@product.variant_unit}')}})"
|
||||
= hidden_field_tag 'product_variant_unit_scale', @product.variant_unit_scale
|
||||
= text_field_tag :unit_value_human, nil, {class: "fullwidth", 'ng-model' => 'unit_value_human', 'ng-change' => 'updateValue()'}
|
||||
= f.text_field :unit_value, {hidden: true, 'ng-value' => 'unit_value'}
|
||||
|
||||
.field{"data-hook" => "unit_description"}
|
||||
= f.label :unit_description, "Unit Description"
|
||||
= f.text_field :unit_description, class: "fullwidth"
|
||||
.field{"data-hook" => "unit_description"}
|
||||
= f.label :unit_description, "Unit Description"
|
||||
= f.text_field :unit_description, class: "fullwidth", placeholder: t('admin.products.unit_name_placeholder')
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/ replace "[data-hook='admin_variant_form_additional_fields']"
|
||||
|
||||
.right.six.columns.omega.label-block{"data-hook" => "admin_variant_form_additional_fields"}
|
||||
- if @product.variant_unit != 'weight'
|
||||
.field{"data-hook" => 'weight'}
|
||||
= f.label 'weight', t('weight')+' (kg)'
|
||||
- value = number_with_precision(@variant.weight, :precision => 2)
|
||||
= f.text_field 'weight', :value => value, :class => 'fullwidth'
|
||||
|
||||
- [:height, :width, :depth].each do |field|
|
||||
.field{"data-hook" => field}
|
||||
= f.label field, t(field)
|
||||
- value = number_with_precision(@variant.send(field), :precision => 2)
|
||||
= f.text_field field, :value => value, :class => 'fullwidth'
|
||||
@@ -4,7 +4,7 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :preferred_shopfront_message, :preferred_shopfront_closed_message, :preferred_shopfront_taxon_order, :preferred_shopfront_order_cycle_order
|
||||
attributes :preferred_product_selection_from_inventory_only
|
||||
attributes :owner, :users, :tag_groups, :default_tag_group
|
||||
attributes :require_login
|
||||
attributes :require_login, :allow_guest_orders, :allow_order_changes
|
||||
|
||||
has_one :owner, serializer: Api::Admin::UserSerializer
|
||||
has_many :users, serializer: Api::Admin::UserSerializer
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
class Api::CurrentOrderSerializer < ActiveModel::Serializer
|
||||
attributes :id, :item_total, :email, :shipping_method_id,
|
||||
:display_total, :payment_method_id
|
||||
:display_total, :payment_method_id
|
||||
|
||||
has_one :bill_address, serializer: Api::AddressSerializer
|
||||
has_one :ship_address, serializer: Api::AddressSerializer
|
||||
|
||||
has_many :line_items, serializer: Api::LineItemSerializer
|
||||
has_many :finalised_line_items, serializer: Api::LineItemSerializer
|
||||
|
||||
def payment_method_id
|
||||
object.payments.first.andand.payment_method_id
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
module Api
|
||||
class OrderSerializer < ActiveModel::Serializer
|
||||
attributes :number, :completed_at, :total, :state, :shipment_state, :payment_state, :outstanding_balance, :payments, :path
|
||||
attributes :number, :completed_at, :total, :state, :shipment_state, :payment_state
|
||||
attributes :outstanding_balance, :payments, :path, :cancel_path, :changes_allowed, :changes_allowed_until
|
||||
attributes :shop_name, :item_count
|
||||
|
||||
has_many :payments, serializer: Api::PaymentSerializer
|
||||
|
||||
def shop_name
|
||||
object.distributor.andand.name
|
||||
end
|
||||
|
||||
def item_count
|
||||
object.line_items.sum(&:quantity)
|
||||
end
|
||||
|
||||
def completed_at
|
||||
object.completed_at.blank? ? "" : I18n.l(object.completed_at, format: :long)
|
||||
object.completed_at.blank? ? "" : I18n.l(object.completed_at, format: "%b %d, %Y %H:%M")
|
||||
end
|
||||
|
||||
def changes_allowed_until
|
||||
return I18n.t(:not_allowed) unless object.changes_allowed?
|
||||
I18n.l(object.order_cycle.andand.orders_close_at, format: "%b %d, %Y %H:%M")
|
||||
end
|
||||
|
||||
def total
|
||||
@@ -25,7 +40,16 @@ module Api
|
||||
end
|
||||
|
||||
def path
|
||||
Spree::Core::Engine.routes_url_helpers.order_url(object.number, only_path: true)
|
||||
Spree::Core::Engine.routes_url_helpers.order_path(object)
|
||||
end
|
||||
|
||||
def cancel_path
|
||||
return nil unless object.changes_allowed?
|
||||
Spree::Core::Engine.routes_url_helpers.cancel_order_path(object)
|
||||
end
|
||||
|
||||
def changes_allowed
|
||||
object.changes_allowed?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
class Api::VariantSerializer < ActiveModel::Serializer
|
||||
attributes :id, :is_master, :count_on_hand, :name_to_display, :unit_to_display
|
||||
attributes :options_text, :on_demand, :price, :fees, :price_with_fees, :product_name
|
||||
attributes :tag_list
|
||||
|
||||
def price
|
||||
object.price
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
%col{ width: '62.5%' }
|
||||
%col{ width: '12.5%' }
|
||||
%thead
|
||||
%th Date
|
||||
%th= t('admin.date')
|
||||
%th= t(:description)
|
||||
%th= t(:charge)
|
||||
- if order = invoice.order
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
.filter_select.five.columns.alpha
|
||||
%label{ :for => 'quick_search', ng: {class: '{disabled: !shop_id}'} }=t('admin.quick_search')
|
||||
%br
|
||||
%input.fullwidth{ :type => "text", :id => 'quick_search', ng: { model: 'quickSearch', disabled: '!shop_id' }, :placeholder => "Search by email/code..." }
|
||||
%input.fullwidth{ :type => "text", :id => 'quick_search', ng: { model: 'quickSearch', disabled: '!shop_id' }, :placeholder => t('.search_by_email') }
|
||||
.filter_select.four.columns
|
||||
%label{ :for => 'hub_id', ng: { bind: "shop_id ? '#{t('admin.shop')}' : '#{t('admin.variant_overrides.index.select_a_shop')}'" } }
|
||||
%br
|
||||
@@ -94,6 +94,6 @@
|
||||
|
||||
-# %show-more.text-center{ data: "filteredCustomers", limit: "customerLimit", increment: "20" }
|
||||
%div.text-center{ ng: { show: "filteredCustomers.length > customerLimit" } }
|
||||
%input{ type: 'button', value: 'Show More', ng: { click: 'customerLimit = customerLimit + 20' } }
|
||||
%input{ type: 'button', value: t(:show_more), ng: { click: 'customerLimit = customerLimit + 20' } }
|
||||
or
|
||||
%input{ type: 'button', value: "Show All ({{ filteredCustomers.length - customerLimit }} More)", ng: { click: 'customerLimit = filteredCustomers.length' } }
|
||||
%input{ type: 'button', value: t(:show_all_with_more, num: '{{ filteredCustomers.length - customerLimit }}'), ng: { click: 'customerLimit = filteredCustomers.length' } }
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
= f.label :charges_sales_tax, t(:say_no), value: 'false'
|
||||
.row
|
||||
.alpha.three.columns
|
||||
= f.label :display_invoice_logo, 'Display logo in invoices'
|
||||
= f.label :display_invoice_logo, t('.display_invoice_logo')
|
||||
.omega.eight.columns
|
||||
= f.check_box :display_invoice_logo
|
||||
.row
|
||||
.alpha.three.columns
|
||||
= f.label :invoice_text, 'Add customized text at the end of invoices'
|
||||
= f.label :invoice_text, t('.invoice_text')
|
||||
.omega.eight.columns
|
||||
= f.text_area :invoice_text, style: "width: 100%; height: 100px;"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
%tr{ ng: { controller: 'shippingMethodsCtrl', init: "findShippingMethodByID(#{shipping_method.id})" } }
|
||||
%td= shipping_method.name
|
||||
%td= f.check_box :shipping_method_ids, { :multiple => true, 'ng-model' => 'ShippingMethod.selected' }, shipping_method.id, nil
|
||||
%td= link_to "Edit", edit_admin_shipping_method_path(shipping_method)
|
||||
%td= link_to t(:edit), edit_admin_shipping_method_path(shipping_method)
|
||||
%br
|
||||
.row
|
||||
.six.columns.alpha
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
.three.columns.alpha
|
||||
= f.label "enterprise_preferred_shopfront_message", t(:shopfront_message)
|
||||
= f.label "enterprise_preferred_shopfront_message", t('.shopfront_message')
|
||||
.eight.columns.omega
|
||||
%text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular',
|
||||
'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]",
|
||||
@@ -9,7 +9,7 @@
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
.three.columns.alpha
|
||||
= f.label "enterprise_preferred_shopfront_closed_message", t(:shopfront_closed_message)
|
||||
= f.label "enterprise_preferred_shopfront_closed_message", t('.shopfront_closed_message')
|
||||
.eight.columns.omega
|
||||
%text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular',
|
||||
'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]",
|
||||
@@ -17,7 +17,7 @@
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
.three.columns.alpha
|
||||
= f.label "enterprise_preferred_shopfront_taxon_order", t(:shopfront_category_ordering)
|
||||
= f.label "enterprise_preferred_shopfront_taxon_order", t('.shopfront_category_ordering')
|
||||
%br
|
||||
(top to bottom)
|
||||
.eight.columns.omega
|
||||
@@ -51,9 +51,27 @@
|
||||
%label= t '.allow_guest_orders'
|
||||
%div{'ofn-with-tip' => t('.allow_guest_orders_tip')}
|
||||
%a= t 'admin.whats_this'
|
||||
.eight.columns.omega
|
||||
.row
|
||||
.three.columns.alpha
|
||||
= f.radio_button :allow_guest_orders, true, "ng-model" => "Enterprise.allow_guest_orders", "ng-value" => "true"
|
||||
= f.label :allow_guest_orders, t('.allow_guest_orders_true'), value: :true
|
||||
.five.columns.omega
|
||||
= f.radio_button :allow_guest_orders, false, "ng-model" => "Enterprise.allow_guest_orders", "ng-value" => "false"
|
||||
= f.label :allow_guest_orders, t('.allow_guest_orders_false'), value: :false
|
||||
.row.warning{ng: {show: 'Enterprise.allow_guest_orders && Enterprise.allow_order_changes'}}
|
||||
.eight.columns.alpha.omega
|
||||
%i.icon-warning-sign
|
||||
= t '.recommend_require_login'
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
.three.columns.alpha
|
||||
%label= t '.allow_order_changes'
|
||||
%div{'ofn-with-tip' => t('.allow_order_changes_tip')}
|
||||
%a= t 'admin.whats_this'
|
||||
.three.columns
|
||||
= f.radio_button :allow_guest_orders, true
|
||||
= f.label :allow_guest_orders, t('.allow_guest_orders_true'), value: :true
|
||||
= f.radio_button :allow_order_changes, false, "ng-model" => "Enterprise.allow_order_changes", "ng-value" => "false"
|
||||
= f.label :allow_order_changes, t('.allow_order_changes_false'), value: :false
|
||||
.five.columns.omega
|
||||
= f.radio_button :allow_guest_orders, false
|
||||
= f.label :allow_guest_orders, t('.allow_guest_orders_false'), value: :false
|
||||
= f.radio_button :allow_order_changes, true, "ng-model" => "Enterprise.allow_order_changes", "ng-value" => "true"
|
||||
= f.label :allow_order_changes, t('.allow_order_changes_true'), value: :true
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
.filter_select.four.columns
|
||||
%label{ :for => 'producer_filter', ng: {class: '{disabled: !hub_id}'} }=t('admin.producer')
|
||||
%br
|
||||
%input.ofn-select2.fullwidth{ :id => 'producer_filter', type: 'number', data: 'producers', blank: "{id: 0, name: 'All'}", ng: { model: 'producerFilter', disabled: '!hub_id' } }
|
||||
%input.ofn-select2.fullwidth{ :id => 'producer_filter', type: 'number', data: 'producers', blank: "{id: 0, name: '#{t(:all)}'}", ng: { model: 'producerFilter', disabled: '!hub_id' } }
|
||||
-# .filter_select{ :class => "three columns" }
|
||||
-# %label{ :for => 'distributor_filter' }Hub
|
||||
-# %br
|
||||
|
||||
2
app/views/checkout/_already_ordered.html.haml
Normal file
2
app/views/checkout/_already_ordered.html.haml
Normal file
@@ -0,0 +1,2 @@
|
||||
%p.alert-box.info
|
||||
= t '.message_html', cart: link_to(t('.cart'), "#{cart_path}#bought-products")
|
||||
@@ -11,6 +11,7 @@
|
||||
= render "checkout/billing", f: f
|
||||
= render "checkout/shipping", f: f
|
||||
= render "checkout/payment", f: f
|
||||
= render "checkout/already_ordered", f: f if show_bought_items?
|
||||
%p
|
||||
%button.button.primary{type: :submit}
|
||||
= t :checkout_send
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
= inject_shop_enterprises
|
||||
|
||||
%shop.darkswarm
|
||||
.alert-box.changeable-orders-alert.info.animate-show{ ng: { show: "alert.visible && alert.html", cloak: true } }
|
||||
%span{ ng: { bind: { html: "alert.html" } } }
|
||||
%a.close{ ng: { click: "alert.close()" } } ×
|
||||
|
||||
- content_for :order_cycle_form do
|
||||
|
||||
%div{"ng-controller" => "OrderCycleChangeCtrl", "ng-cloak" => true}
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
.small-12.medium-6.medium-offset-3.columns.text-center
|
||||
%h2
|
||||
= t :producers_signup_cta_headline
|
||||
%p.text-big Start with a free profile, and expand when you're ready!
|
||||
%p.text-big= t('.start_free_profile')
|
||||
%a.button.transparent{href: "/register"}
|
||||
= t :producers_signup_cta_action
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
%a.button.secondary.tiny.add_to_cart{ href: cart_path, type: :submit, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" }
|
||||
= "{{ Cart.dirty ? '#{t(:cart_updating)}' : (Cart.empty() ? '#{t(:cart_empty)}' : '#{t(:cart_edit)}' ) }}"
|
||||
%a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
|
||||
= t 'checkout'
|
||||
= t '.checkout'
|
||||
%table
|
||||
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"}
|
||||
%td
|
||||
@@ -47,4 +47,25 @@
|
||||
%a.button.secondary.tiny.add_to_cart{ href: cart_path, type: :submit, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" }
|
||||
= "{{ Cart.dirty ? '#{t(:cart_updating)}' : (Cart.empty() ? '#{t(:cart_empty)}' : '#{t(:cart_edit)}' ) }}"
|
||||
%a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
|
||||
= t 'checkout'
|
||||
= t '.checkout'
|
||||
- if order_changes_allowed?
|
||||
%h5{"ng-if" => "Cart.line_items_finalised.length", style: 'margin-top: 1em'}
|
||||
= t '.already_ordered_products'
|
||||
%table
|
||||
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items_finalised",
|
||||
"id" => "cart-variant-{{ line_item.variant.id }}"}
|
||||
%td
|
||||
%small
|
||||
%strong
|
||||
{{ line_item.variant.extended_name }}
|
||||
%td.text-right
|
||||
%small
|
||||
%span.quantity {{ line_item.quantity }}
|
||||
%i.ofn-i_009-close
|
||||
%span.price {{ line_item.variant.price_with_fees | localizeCurrency }}
|
||||
|
||||
%td
|
||||
%small
|
||||
\=
|
||||
%strong
|
||||
.total-price.right {{ line_item.total_price | localizeCurrency }}
|
||||
|
||||
1
app/views/shop/changeable_orders_alert.html.haml
Normal file
1
app/views/shop/changeable_orders_alert.html.haml
Normal file
@@ -0,0 +1 @@
|
||||
= shop_changeable_orders_alert_html
|
||||
@@ -6,7 +6,7 @@
|
||||
.row.summary
|
||||
.small-10.medium-10.large-11.columns.summary-header
|
||||
%h3
|
||||
%a{"ng-click" => "triggerProductModal()"}
|
||||
%a{"ng-click" => "triggerProductModal()", href: 'javascript:void(0)'}
|
||||
%span{"ng-bind" => "::product.name"}
|
||||
%i.ofn-i_057-expand
|
||||
%small
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
- distributor = @order.andand.distributor || current_distributor
|
||||
|
||||
%navigation
|
||||
%distributor.details.row
|
||||
.small-12.medium-6.large-6.columns
|
||||
#distributor_title
|
||||
- if current_distributor.logo?
|
||||
%img.left{src: current_distributor.logo.url(:thumb)}
|
||||
- if distributor.logo?
|
||||
%img.left{src: distributor.logo.url(:thumb)}
|
||||
%h3
|
||||
= current_distributor.name
|
||||
%location= current_distributor.address.city
|
||||
= distributor.name
|
||||
%location= distributor.address.city
|
||||
/ Will this needs to be a drop-down to choose either pick-up point or delivery once shipping methods are implemented
|
||||
|
||||
.small-12.medium-6.large-6.columns
|
||||
= render partial: "shopping_shared/order_cycles"
|
||||
|
||||
= render partial: "shopping_shared/tabs"
|
||||
|
||||
= render partial: "shopping_shared/tabs" if distributor == current_distributor
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
%fieldset.no-border-bottom
|
||||
%legend{align: 'center'} Distribution
|
||||
|
||||
- if @order.complete?
|
||||
.alpha.six.columns
|
||||
%p
|
||||
%b Distributor:
|
||||
= @order.distributor.andand.name || "None"
|
||||
%input{type: "hidden", id: "order_distributor_id", value: @order.distributor.andand.id}
|
||||
.omega.six.columns
|
||||
%p
|
||||
%b Order cycle:
|
||||
= @order.order_cycle.andand.name || "None"
|
||||
%input{type: "hidden", id: "order_order_cycle_id", value: @order.order_cycle.andand.id}
|
||||
- else
|
||||
.alpha.six.columns
|
||||
.field
|
||||
%label{for: "order_distributor_id"} Distributor
|
||||
%input.ofn-select2.fullwidth{id: "order_distributor_id",
|
||||
type: 'number',
|
||||
name: "order[distributor_id]",
|
||||
"ng-model" => 'distributor_id',
|
||||
data: "shops" }
|
||||
|
||||
.omega.six.columns
|
||||
.field
|
||||
%label{ for: "order_order_cycle_id"} Order Cycle
|
||||
%input.ofn-select2.fullwidth{id: "order_order_cycle_id",
|
||||
type: 'number',
|
||||
name: "order[order_cycle_id]",
|
||||
"ng-model" => 'order_cycle_id',
|
||||
"ng-disabled" => "!distributor_id",
|
||||
data: "orderCycles",
|
||||
text: "name_and_status",
|
||||
filter: "validOrderCycle" }
|
||||
@@ -31,21 +31,21 @@
|
||||
%label{ :for => 'supplier_filter' }
|
||||
= t("admin.producer")
|
||||
%br
|
||||
%input#supplier_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'suppliers', blank: "{ id: 0, name: 'All' }", ng: { model: 'supplierFilter' } }
|
||||
%input#supplier_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'suppliers', blank: "{ id: 0, name: '#{t(:all)}' }", ng: { model: 'supplierFilter' } }
|
||||
.filter_select{ :class => "three columns" }
|
||||
%label{ :for => 'distributor_filter' }
|
||||
= t("admin.shop")
|
||||
%br
|
||||
%input#distributor_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'distributors', blank: "{ id: 0, name: 'All' }", ng: { model: 'distributorFilter' } }
|
||||
%input#distributor_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'distributors', blank: "{ id: 0, name: '#{t(:all)}' }", ng: { model: 'distributorFilter' } }
|
||||
.filter_select{ :class => "three columns" }
|
||||
%label{ :for => 'order_cycle_filter' }
|
||||
= t("admin.order_cycle")
|
||||
%br
|
||||
%input#order_cycle_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'orderCycles', blank: "{ id: 0, name: 'All' }", on: { selecting: "confirmRefresh" }, ng: { model: 'orderCycleFilter', change: 'refreshData()' } }
|
||||
%input#order_cycle_filter.ofn-select2.fullwidth{ type: 'number', 'min-search' => 5, data: 'orderCycles', blank: "{ id: 0, name: '#{t(:all)}' }", on: { selecting: "confirmRefresh" }, ng: { model: 'orderCycleFilter', change: 'refreshData()' } }
|
||||
.filter_clear{ :class => "two columns omega" }
|
||||
%label{ :for => 'clear_all_filters' }
|
||||
%br
|
||||
%input.red.fullwidth{ :type => 'button', :id => 'clear_all_filters', :value => "Clear All", 'ng-click' => "resetSelectFilters()" }
|
||||
%input.red.fullwidth{ :type => 'button', :id => 'clear_all_filters', :value => t('admin.clear_all'), 'ng-click' => "resetSelectFilters()" }
|
||||
|
||||
%hr.divider.sixteen.columns.alpha.omega{ ng: { show: 'unitsVariantSelected()' } }
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
%h6{ :class => "eight columns alpha", 'ng-hide' => 'sharedResource', style: 'text-align: center;' } {{ selectedUnitsVariant.full_name }}
|
||||
%div{ :class => "four columns omega" }
|
||||
%h6{ :class => "four columns alpha", :style => 'text-align: right;' }
|
||||
%a{ :href => '#', 'ng-click' => 'selectedUnitsVariant = {};selectedUnitsProduct = {};sharedResource=false;' } Clear
|
||||
%a{ :href => '#', 'ng-click' => 'selectedUnitsVariant = {};selectedUnitsProduct = {};sharedResource=false;' }= t('admin.clear')
|
||||
%hr
|
||||
.row
|
||||
.one.column.alpha
|
||||
|
||||
24
app/views/spree/admin/orders/set_distribution.html.haml
Normal file
24
app/views/spree/admin/orders/set_distribution.html.haml
Normal file
@@ -0,0 +1,24 @@
|
||||
- content_for :page_title do
|
||||
= t(:new)
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to t(:back_to_orders_list), spree.admin_orders_path, :icon => 'icon-arrow-left'
|
||||
|
||||
= admin_inject_shops 'admin.orders'
|
||||
= admin_inject_order_cycles
|
||||
|
||||
= render 'spree/admin/shared/order_tabs', :current => 'Order Details'
|
||||
|
||||
= csrf_meta_tags
|
||||
|
||||
%div{"data-hook" => "admin_order_new_header"}
|
||||
= render 'spree/shared/error_messages', :target => @order
|
||||
|
||||
%div{"ng-app" => "admin.orders", "ng-controller" => "ordersCtrl"}
|
||||
= form_for @order, url: admin_order_url(@order), method: :put do |f|
|
||||
= render 'spree/admin/orders/_form/distribution_fields'
|
||||
-# This param passed to stop validation error in next page due to no line items in order yet:
|
||||
= hidden_field_tag 'suppress_error_msg', "true"
|
||||
= button_tag :class => 'secondary radius expand small', :id => 'update-button' do
|
||||
%i.icon-arrow-right
|
||||
= t(:next)
|
||||
@@ -13,24 +13,24 @@
|
||||
'\x1B' + '\x74' + '\x10',
|
||||
'\x1B' + '\x61' + '\x31', // center align
|
||||
'\x1B' + '\x21' + '\x30', // em mode on
|
||||
'#{@order.distributor.name}' + '\x0A',
|
||||
'#{j(@order.distributor.name)}' + '\x0A',
|
||||
'\x1B' + '\x21' + '\x0A' + '\x1B' + '\x45' + '\x0A', // em mode off
|
||||
'\x0A',
|
||||
'#{@order.distributor.address.address_part1}' + '\x0A', // text and line break
|
||||
'#{@order.distributor.address.address_part2}' + '\x0A',
|
||||
'#{@order.distributor.email}' + '\x0A',
|
||||
'#{j(@order.distributor.address.address_part1)}' + '\x0A', // text and line break
|
||||
'#{j(@order.distributor.address.address_part2)}' + '\x0A',
|
||||
'#{j(@order.distributor.email)}' + '\x0A',
|
||||
'\x0A', // line break
|
||||
'\x1B' + '\x61' + '\x32', // right align
|
||||
'#{l Time.zone.now.to_date}' + '\x0A',
|
||||
'#{@order.number}' + '\x0A',
|
||||
'#{j(l(Time.zone.now.to_date))}' + '\x0A',
|
||||
'#{j(@order.number)}' + '\x0A',
|
||||
'\x1B' + '\x61' + '\x30', // left align
|
||||
'\x0A',
|
||||
'\x1B' + '\x4D' + '\x31', // small text
|
||||
"#{'%6s %-23s%12s%12s' %
|
||||
[t(:ticket_column_qty),
|
||||
t(:ticket_column_item),
|
||||
t(:ticket_column_unit_price),
|
||||
t(:ticket_column_total_price)]}",
|
||||
"#{'%6s %-26s%10s%10s' %
|
||||
[j(t(:ticket_column_qty)),
|
||||
j(t(:ticket_column_item)),
|
||||
j(t(:ticket_column_unit_price)),
|
||||
j(t(:ticket_column_total_price))]}",
|
||||
'\x0A',
|
||||
'\x1B' + '\x4D' + '\x30', // normal text
|
||||
'__________________________________________' + '\x0A',
|
||||
@@ -38,36 +38,34 @@
|
||||
.sort_by{ |line_item| line_item.product.name }
|
||||
.map { |line_item| '%5d %-19.19s%8.8s%8.8s' %
|
||||
[line_item.quantity,
|
||||
line_item.product.name,
|
||||
line_item.single_display_amount_with_adjustments.money.format(symbol: false),
|
||||
line_item.display_amount_with_adjustments.money.format(symbol: false)] }
|
||||
j(line_item.product.name),
|
||||
j(line_item.single_display_amount_with_adjustments.format(symbol: false, with_currency: false)),
|
||||
j(line_item.display_amount_with_adjustments.format(symbol: false, with_currency: false))] }
|
||||
.join('" + \'\x0A\' + "')}",
|
||||
'\x0A',
|
||||
"#{checkout_adjustments_for(@order, exclude: [:line_item])
|
||||
.reject{ |a| a.amount == 0 }
|
||||
.reverse.map { |adjustment| '%5s %-27.27s%8.8s' %
|
||||
["",
|
||||
raw(adjustment.label),
|
||||
display_adjustment_amount(adjustment).money.format(symbol: false)] }
|
||||
.join('" + \'\x0A\' + "')}",
|
||||
'\x0A',
|
||||
j(raw(adjustment.label)),
|
||||
j(display_adjustment_amount(adjustment).format(symbol: false, with_currency: false))] +
|
||||
'" + \'\x0A\' + "'}.join }",
|
||||
'__________________________________________' + '\x0A',
|
||||
'\x0A',
|
||||
'\x1B' + '\x45' + '\x0D', // bold on
|
||||
"#{'%31s%10s' %
|
||||
[t(:total_incl_tax),
|
||||
@order.display_total]}",
|
||||
[j(t(:total_incl_tax)),
|
||||
j(@order.display_total.format(with_currency: false))]}",
|
||||
'\x1B' + '\x45' + '\x0A', // bold off
|
||||
'\x0A',
|
||||
"#{display_checkout_taxes_hash(@order).map { |tax_rate, tax_value|
|
||||
'%31s%10s' %
|
||||
[t(:tax_total, rate: tax_rate),
|
||||
tax_value] }
|
||||
.join('" + \'\x0A\' + "')}",
|
||||
'\x0A',
|
||||
[j(t(:tax_total, rate: tax_rate)),
|
||||
j(tax_value.format(with_currency: false))] +
|
||||
'" + \'\x0A\' + "'}.join }",
|
||||
"#{'%31s%10s' %
|
||||
[t(:total_excl_tax),
|
||||
display_checkout_total_less_tax(@order)]}",
|
||||
[j(t(:total_excl_tax)),
|
||||
j(display_checkout_total_less_tax(@order).format(with_currency: false))]}",
|
||||
'\x0A',
|
||||
'\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A' + '\x0A',
|
||||
'\x1B' + '\x69', // cut paper
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
.filter_clear.three.columns.omega
|
||||
%label{ :for => 'clear_all_filters' }
|
||||
%br
|
||||
%input.fullwidth.red{ :type => 'button', :id => 'clear_all_filters', :value => "Clear Filters", 'ng-click' => "resetSelectFilters()" }
|
||||
%input.fullwidth.red{ :type => 'button', :id => 'clear_all_filters', :value => t('admin.clear_filters'), 'ng-click' => "resetSelectFilters()" }
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
%tr{ ng: { controller: "ColumnsCtrl" } }
|
||||
%th.left-actions
|
||||
%a{ 'ng-click' => 'toggleShowAllVariants()', :style => 'color: red' }
|
||||
Expand All
|
||||
= t(:expand_all)
|
||||
%th.producer{ 'ng-show' => 'columns.producer.visible' }=t('admin.producer')
|
||||
%th.sku{ 'ng-show' => 'columns.sku.visible' }=t('admin.sku')
|
||||
%th.name{ 'ng-show' => 'columns.name.visible' }=t('admin.name')
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
%input.fullwidth{ :type => 'text', id: "p{{product.id}}_category_id", 'ng-model' => 'product.category_id', 'ofn-taxon-autocomplete' => '', 'ofn-track-product' => 'category_id', 'multiple-selection' => 'false', placeholder: 'Category' }
|
||||
%td.tax_category{ 'ng-if' => 'columns.tax_category.visible' }
|
||||
%select.select2{ name: 'product_tax_category_id', 'ofn-track-product' => 'tax_category_id', ng: {model: 'product.tax_category_id', options: 'tax_category.id as tax_category.name for tax_category in tax_categories'} }
|
||||
%option{value: ''} None
|
||||
%option{value: ''}= t(:none)
|
||||
%td.inherits_properties{ 'ng-show' => 'columns.inherits_properties.visible' }
|
||||
%input{ 'ng-model' => 'product.inherits_properties', :name => 'inherits_properties', 'ofn-track-product' => 'inherits_properties', type: "checkbox" }
|
||||
%td.available_on{ 'ng-show' => 'columns.available_on.visible' }
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
%div.sixteen.columns.alpha{ 'ng-hide' => 'loading || products.length == 0', style: "margin-bottom: 10px" }
|
||||
%div.four.columns.alpha
|
||||
%input.four.columns.alpha{ :type => 'button', :value => 'Save Changes', 'ng-click' => 'submitProducts()'}
|
||||
%input.four.columns.alpha{ :type => 'button', :value => t(:save_changes), 'ng-click' => 'submitProducts()'}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.row
|
||||
.four.columns.alpha
|
||||
= label_tag nil, "Distributor: "
|
||||
= f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => 'All'}, {:class => "select2 fullwidth"})
|
||||
= f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => t(:all)}, {:class => "select2 fullwidth"})
|
||||
= label_tag nil, "Report Type: "
|
||||
%br
|
||||
= select_tag(:report_type, options_for_select([['Bulk Co-op - Totals by Supplier',:bulk_coop_supplier_report],['Bulk Co-op - Allocation',:bulk_coop_allocation],['Bulk Co-op - Packing Sheets',:bulk_coop_packing_sheets],['Bulk Co-op - Customer Payments',:bulk_coop_customer_payments]], @report_type))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.row
|
||||
.four.columns.alpha
|
||||
= label_tag nil, t(:report_distributor)
|
||||
= f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => 'All'}, {:class => "select2 fullwidth"})
|
||||
= f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => t(:all)}, {:class => "select2 fullwidth"})
|
||||
= label_tag nil, t(:report_customers_type)
|
||||
%br
|
||||
= select_tag(:report_type, options_for_select([[t(:report_tax_types),:tax_types],[t(:report_tax_rates),:tax_rates]], @report_type))
|
||||
|
||||
35
app/views/spree/orders/_bought.html.haml
Normal file
35
app/views/spree/orders/_bought.html.haml
Normal file
@@ -0,0 +1,35 @@
|
||||
%tbody{ ng: { controller: 'EditBoughtOrderController' } }
|
||||
%tr
|
||||
%td.toggle-bought{ colspan: 2, ng: { click: 'showBought=!showBought' } }
|
||||
%h5.brick
|
||||
%i{ ng: { class: "{ 'ofn-i_007-caret-right': !showBought, 'ofn-i_005-caret-down': showBought}"} }
|
||||
= t(:orders_bought_items_notice, count: @order.finalised_line_items.sum(&:quantity))
|
||||
%td.text-right{ colspan: 3 }
|
||||
%a.edit-finalised.button.radius.expand.small{ href: changeable_orders_link_path, ng: { class: "{secondary: !showBought, primary: showBought}" } }
|
||||
= t(:orders_bought_edit_button)
|
||||
%i.ofn-i_007-caret-right
|
||||
|
||||
|
||||
- @order.finalised_line_items.each do |line_item|
|
||||
- variant = line_item.variant
|
||||
%tr.bought.line-item{class: "line-item-#{line_item.id} variant-#{variant.id}", ng: { show: 'showBought'} }
|
||||
%td.cart-item-description
|
||||
|
||||
%div.item-thumb-image
|
||||
- if variant.images.length == 0
|
||||
= link_to mini_image(variant.product), variant.product
|
||||
- else
|
||||
= link_to image_tag(variant.images.first.attachment.url(:mini)), variant.product
|
||||
|
||||
= render 'spree/shared/line_item_name', line_item: line_item
|
||||
%span.already-confirmed= t(:orders_bought_already_confirmed)
|
||||
%td.text-right.cart-item-price
|
||||
= line_item.single_display_amount_with_adjustments.to_html
|
||||
%td.text-center.cart-item-quantity
|
||||
= line_item.quantity
|
||||
%td.cart-item-total.text-right
|
||||
= line_item.display_amount_with_adjustments.to_html unless line_item.quantity.nil?
|
||||
|
||||
%td.bought-item-delete.text-center
|
||||
%a{ng: {click: "deleteLineItem(#{line_item.id})"}}
|
||||
%i.ofn-i_026-trash
|
||||
@@ -20,19 +20,10 @@
|
||||
= order_form.fields_for :line_items do |item_form|
|
||||
= render :partial => 'line_item', :locals => { :variant => item_form.object.variant, :line_item => item_form.object, :item_form => item_form }
|
||||
|
||||
= render 'bought' if show_bought_items? && @order.cart?
|
||||
|
||||
%tfoot#edit-cart
|
||||
%tr
|
||||
%td{colspan:"2"}
|
||||
%td
|
||||
= button_tag :class => 'secondary radius expand small', :id => 'update-button' do
|
||||
%i.ofn-i_023-refresh
|
||||
= t(:update)
|
||||
%td
|
||||
%td#empty-cart.text-center
|
||||
%span#clear_cart_link{"data-hook" => ""}
|
||||
= link_to t(:orders_form_empty_cart), empty_cart_path, method: :put, :class => 'not-bold small'
|
||||
-#= form_tag empty_cart_path, :method => :put do
|
||||
-#= submit_tag t(:empty_cart), :class => 'button alert expand small'
|
||||
= render 'spree/orders/form/cart_actions_row' if @order.cart?
|
||||
|
||||
/ This is the fees row which we want to replace with the pop-over
|
||||
-# - unless @order.adjustments.eligible.blank?
|
||||
@@ -52,6 +43,14 @@
|
||||
%span.order-total.distribution-total= display_checkout_admin_and_handling_adjustments_total_for(@order)
|
||||
%td
|
||||
|
||||
- checkout_adjustments_for(@order, exclude: [:line_item, :admin_and_handling]).reject{ |a| a.amount == 0 }.reverse_each do |adjustment|
|
||||
%tr.order-adjustment
|
||||
%td.text-right{:colspan => "3"}
|
||||
= adjustment.label
|
||||
%td.text-right.total
|
||||
%span= adjustment.display_amount.to_html
|
||||
%td
|
||||
|
||||
%tr
|
||||
%td.text-right{colspan:"3"}
|
||||
%h5
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
= render 'spree/shared/line_item_name', line_item: line_item
|
||||
|
||||
- if @insufficient_stock_lines.include? line_item
|
||||
- if @insufficient_stock_lines.andand.include? line_item
|
||||
%span.out-of-stock
|
||||
= variant.in_stock? ? t(:insufficient_stock, :on_hand => variant.on_hand) : t(:out_of_stock)
|
||||
%br/
|
||||
@@ -35,6 +35,5 @@
|
||||
= line_item.display_amount_with_adjustments.to_html unless line_item.quantity.nil?
|
||||
|
||||
%td.cart-item-delete.text-center{"data-hook" => "cart_item_delete"}
|
||||
{{ quantity }}
|
||||
%a.delete{href: "#", id: "delete_#{dom_id(line_item)}"}
|
||||
%i.delete.ofn-i_026-trash
|
||||
|
||||
65
app/views/spree/orders/_summary.html.haml
Normal file
65
app/views/spree/orders/_summary.html.haml
Normal file
@@ -0,0 +1,65 @@
|
||||
%table#line-items{"data-hook" => "order_details"}
|
||||
%col{valign: "middle"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%thead{"data-hook" => ""}
|
||||
%tr{"data-hook" => "order_details_line_items_headers"}
|
||||
%th= t(:item)
|
||||
%th.price= t(:price)
|
||||
%th.text-center.qty= t(:qty)
|
||||
%th.text-right.total
|
||||
%span= t(:total)
|
||||
%tbody{"data-hook" => ""}
|
||||
- order.line_items.each do |item|
|
||||
%tr.line_item{"data-hook" => "order_details_line_item_row", class: "variant-#{item.variant.id}" }
|
||||
%td(data-hook = "order_item_description")
|
||||
|
||||
%div.item-thumb-image{"data-hook" => "order_item_image"}
|
||||
- if item.variant.images.length == 0
|
||||
= link_to mini_image(item.variant.product), item.variant.product
|
||||
- else
|
||||
= link_to image_tag(item.variant.images.first.attachment.url(:mini)), item.variant.product
|
||||
|
||||
|
||||
= render 'spree/shared/line_item_name', line_item: item
|
||||
|
||||
%td.text-right.price{"data-hook" => "order_item_price"}
|
||||
%span= item.single_display_amount_with_adjustments.to_html
|
||||
%td.text-center{"data-hook" => "order_item_qty"}= item.quantity
|
||||
%td.text-right.total{"data-hook" => "order_item_total"}
|
||||
%span= item.display_amount_with_adjustments.to_html
|
||||
|
||||
%tfoot
|
||||
#subtotal{"data-hook" => "order_details_subtotal"}
|
||||
%tr#subtotal-row.total
|
||||
%td.text-right{colspan: "3"}
|
||||
%strong
|
||||
= t :order_produce
|
||||
%td.text-right.total
|
||||
%span= display_checkout_subtotal(order)
|
||||
|
||||
#order-charges{"data-hook" => "order_details_adjustments"}
|
||||
- checkout_adjustments_for(order, exclude: [:line_item]).reject{ |a| a.amount == 0 }.reverse_each do |adjustment|
|
||||
%tr.total
|
||||
%td.text-right{:colspan => "3"}
|
||||
%strong
|
||||
= adjustment.label
|
||||
%td.text-right.total
|
||||
%span= adjustment.display_amount.to_html
|
||||
|
||||
#order-total{"data-hook" => "order_details_total"}
|
||||
%tr.total
|
||||
%td.text-right{colspan: "3"}
|
||||
%h5
|
||||
= t :order_total_price
|
||||
%td.text-right.total
|
||||
%h5#order_total= order.display_total.to_html
|
||||
|
||||
- if order.total_tax > 0
|
||||
#tax{"data-hook" => "order_details_tax"}
|
||||
%tr#tax-row.total
|
||||
%td.text-right{colspan: "3"}
|
||||
= t :order_includes_tax
|
||||
%td.text-right.total
|
||||
%span= display_checkout_tax_total(order)
|
||||
@@ -31,17 +31,6 @@
|
||||
.row
|
||||
= render :partial => 'form', :locals => { :order_form => order_form }
|
||||
|
||||
|
||||
.links{'data-hook' => "cart_buttons"}
|
||||
.row
|
||||
.columns.large-8{"data-hook" => ""}
|
||||
|
||||
%a.button.large.secondary{href: main_app.shop_path}
|
||||
%i.ofn-i_008-caret-left
|
||||
= t :orders_edit_continue
|
||||
.columns.large-4.text-right
|
||||
%a#checkout-link.button.large.primary{href: main_app.checkout_path}
|
||||
= t :orders_edit_checkout
|
||||
%i.ofn-i_007-caret-right
|
||||
= render "spree/orders/form/cart_links"
|
||||
|
||||
= render partial: "shared/footer"
|
||||
|
||||
10
app/views/spree/orders/form/_cart_actions_row.html.haml
Normal file
10
app/views/spree/orders/form/_cart_actions_row.html.haml
Normal file
@@ -0,0 +1,10 @@
|
||||
%tr
|
||||
%td{colspan:"2"}
|
||||
%td
|
||||
= button_tag :class => 'secondary radius expand small', :id => 'update-button' do
|
||||
%i.ofn-i_023-refresh
|
||||
= t(:update)
|
||||
%td
|
||||
%td#empty-cart.text-center
|
||||
%span#clear_cart_link{"data-hook" => ""}
|
||||
= link_to t(:orders_form_empty_cart), empty_cart_path, method: :put, :class => 'not-bold small'
|
||||
9
app/views/spree/orders/form/_cart_links.html.haml
Normal file
9
app/views/spree/orders/form/_cart_links.html.haml
Normal file
@@ -0,0 +1,9 @@
|
||||
.row.links{'data-hook' => "cart_buttons"}
|
||||
.columns.large-8{"data-hook" => ""}
|
||||
%a.button.large.secondary{href: main_app.shop_path}
|
||||
%i.ofn-i_008-caret-left
|
||||
= t :orders_edit_continue
|
||||
.columns.large-4.text-right
|
||||
%a#checkout-link.button.large.primary{href: main_app.checkout_path}
|
||||
= t :orders_edit_checkout
|
||||
%i.ofn-i_007-caret-right
|
||||
24
app/views/spree/orders/form/_update_buttons.html.haml
Normal file
24
app/views/spree/orders/form/_update_buttons.html.haml
Normal file
@@ -0,0 +1,24 @@
|
||||
.row
|
||||
.columns.small-12.medium-3
|
||||
- if current_order.andand.distributor == @order.distributor
|
||||
- if current_order.line_items.present?
|
||||
= link_to spree.cart_path, :class => "button expand" do
|
||||
%i.ofn-i_008-caret-left
|
||||
= t(:order_back_to_cart)
|
||||
- else
|
||||
= link_to main_app.shop_path, :class => "button expand" do
|
||||
%i.ofn-i_008-caret-left
|
||||
= t(:order_back_to_store)
|
||||
- else
|
||||
|
||||
- if order.changes_allowed?
|
||||
.columns.show-for-medium-up.medium-3
|
||||
.columns.small-12.medium-3
|
||||
= link_to spree.cancel_order_path(@order), method: :put, :class => "button secondary expand", "confirm-link-click" => t('orders_confirm_cancel') do
|
||||
%i.ofn-i_009-close
|
||||
= t(:cancel_order)
|
||||
.columns.small-12.medium-3
|
||||
= button_tag :class => 'button primary radius expand', :id => 'update-button', "ng-disabled" => 'update_order_form.$pristine' do
|
||||
%i.ofn-i_051-check-big
|
||||
%span{ ng: { show: 'update_order_form.$dirty' } }= t(:save_changes)
|
||||
%span{ ng: { hide: 'update_order_form.$dirty' } }= t(:order_saved)
|
||||
@@ -10,8 +10,15 @@
|
||||
.row
|
||||
.columns.large-12.text-center
|
||||
%h2
|
||||
= t :orders_show_number
|
||||
= " #" + @order.number
|
||||
= t(:orders_show_order_number, number: @order.number)
|
||||
- if @order.canceled?
|
||||
%span.brick
|
||||
= t(:orders_show_cancelled)
|
||||
%i.ofn-i_009-close
|
||||
- elsif @order.complete?
|
||||
%span.turquoise
|
||||
= t(:orders_show_confirmed)
|
||||
%i.ofn-i_051-check-big
|
||||
|
||||
#order{"data-hook" => ""}
|
||||
- if params.has_key? :checkout_complete
|
||||
@@ -19,12 +26,5 @@
|
||||
|
||||
= render 'spree/shared/order_details', order: @order
|
||||
|
||||
.row
|
||||
.columns.large-12
|
||||
= link_to t(:back_to_store), main_app.shop_path, :class => "button"
|
||||
- unless params.has_key? :checkout_complete
|
||||
- if try_spree_current_user && respond_to?(:spree_account_path)
|
||||
= link_to t(:my_account), spree_account_path, :class => "button"
|
||||
|
||||
|
||||
= render partial: "shared/footer"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
%div{:data-hook => "product_source"}
|
||||
%h6.product-section-title SUPPLIER
|
||||
%h6.product-section-title= t(:supplier)
|
||||
%table#product-source.table-display{:width => "100%"}
|
||||
%tbody
|
||||
- if @product.supplier
|
||||
@@ -7,7 +7,7 @@
|
||||
%td= link_to @product.supplier.name, [main_app, @product.supplier]
|
||||
- if false
|
||||
%br/
|
||||
%h6.product-section-title DISTRIBUTORS
|
||||
%h6.product-section-title= t(:distributors)
|
||||
%table#product-source.table-display{:width => "100%"}
|
||||
%tbody
|
||||
- order = current_order(false)
|
||||
@@ -18,11 +18,11 @@
|
||||
%td
|
||||
%b= link_to(distributor.name, [main_app, distributor])
|
||||
%td
|
||||
%b Current
|
||||
%b= t(:current)
|
||||
- elsif order.nil? || validator.can_change_to_distributor?(distributor)
|
||||
%tr.even
|
||||
%td= link_to distributor.name, [main_app, distributor]
|
||||
%td Available
|
||||
%td= t(:available)
|
||||
- else
|
||||
%tr.even
|
||||
%td= link_to distributor.name, [main_app, distributor]
|
||||
|
||||
@@ -86,68 +86,14 @@
|
||||
%br
|
||||
.row
|
||||
.columns.large-12
|
||||
%table#line-items{"data-hook" => "order_details"}
|
||||
%col{valign: "middle"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%col{halign: "center", valign: "middle", width: "5%"}/
|
||||
%thead{"data-hook" => ""}
|
||||
%tr{"data-hook" => "order_details_line_items_headers"}
|
||||
%th= t(:item)
|
||||
%th.price= t(:price)
|
||||
%th.text-center.qty= t(:qty)
|
||||
%th.text-right.total
|
||||
%span= t(:total)
|
||||
%tbody{"data-hook" => ""}
|
||||
- order.line_items.each do |item|
|
||||
%tr{"data-hook" => "order_details_line_item_row"}
|
||||
%td(data-hook = "order_item_description")
|
||||
- if order.changes_allowed?
|
||||
.alert-box.order-summary{ "ofn-inline-alert" => true, "ng-show" => "visible" }
|
||||
= t(:orders_changeable_orders_alert_html, oc_close: l(order.order_cycle.orders_close_at, format: "%b %d, %Y %H:%M"))
|
||||
%a.close{ "ng-click" => "close()" } ×
|
||||
|
||||
%div.item-thumb-image{"data-hook" => "order_item_image"}
|
||||
- if item.variant.images.length == 0
|
||||
= link_to mini_image(item.variant.product), item.variant.product
|
||||
- else
|
||||
= link_to image_tag(item.variant.images.first.attachment.url(:mini)), item.variant.product
|
||||
|
||||
|
||||
= render 'spree/shared/line_item_name', line_item: item
|
||||
|
||||
%td.text-right.price{"data-hook" => "order_item_price"}
|
||||
%span= item.single_display_amount_with_adjustments.to_html
|
||||
%td.text-center{"data-hook" => "order_item_qty"}= item.quantity
|
||||
%td.text-right.total{"data-hook" => "order_item_total"}
|
||||
%span= item.display_amount_with_adjustments.to_html
|
||||
|
||||
%tfoot
|
||||
#subtotal{"data-hook" => "order_details_subtotal"}
|
||||
%tr#subtotal-row.total
|
||||
%td.text-right{colspan: "3"}
|
||||
%strong
|
||||
= t :order_produce
|
||||
%td.text-right.total
|
||||
%span= display_checkout_subtotal(order)
|
||||
|
||||
#order-charges{"data-hook" => "order_details_adjustments"}
|
||||
- checkout_adjustments_for(order, exclude: [:line_item]).reject{ |a| a.amount == 0 }.reverse_each do |adjustment|
|
||||
%tr.total
|
||||
%td.text-right{:colspan => "3"}
|
||||
%strong
|
||||
= adjustment.label
|
||||
%td.text-right.total
|
||||
%span= adjustment.display_amount.to_html
|
||||
|
||||
#order-total{"data-hook" => "order_details_total"}
|
||||
%tr.total
|
||||
%td.text-right{colspan: "3"}
|
||||
%h5
|
||||
= t :order_total_price
|
||||
%td.text-right.total
|
||||
%h5#order_total= order.display_total.to_html
|
||||
|
||||
- if order.total_tax > 0
|
||||
#tax{"data-hook" => "order_details_tax"}
|
||||
%tr#tax-row.total
|
||||
%td.text-right{colspan: "3"}
|
||||
= t :order_includes_tax
|
||||
%td.text-right.total
|
||||
%span= display_checkout_tax_total(order)
|
||||
= form_for order, html: {id: 'update-order', name: 'update_order_form' } do |order_form|
|
||||
- if order.changes_allowed?
|
||||
= render 'spree/orders/form', order_form: order_form
|
||||
-else
|
||||
= render 'spree/orders/summary', order: order
|
||||
= render 'spree/orders/form/update_buttons', order: order
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<%= t('.welcome', email: @email) %>
|
||||
|
||||
<%= t('.text') %>
|
||||
<%= @confirmation_url %>
|
||||
23
app/views/spree/users/_open_orders.html.haml
Normal file
23
app/views/spree/users/_open_orders.html.haml
Normal file
@@ -0,0 +1,23 @@
|
||||
.row
|
||||
.small-12.columns
|
||||
%table
|
||||
%tr
|
||||
%th.order1= t('.order')
|
||||
%th.order2= t('.shop')
|
||||
%th.order3.show-for-large-up= t('.changes_allowed_until')
|
||||
%th.order4.show-for-large-up= t('.items')
|
||||
%th.order5.text-right= t('.total')
|
||||
%th.order6.text-right.show-for-large-up= t('.edit')
|
||||
%th.order7.text-right= t('.cancel')
|
||||
%tbody.transaction-group{"ng-repeat" => "order in Orders.changeable_orders", "ng-class-odd"=>"'odd'", "ng-class-even"=>"'even'"}
|
||||
%tr.order-row
|
||||
%td.order1
|
||||
%a{"ng-href" => "{{::order.path}}", "ng-bind" => "::order.number"}
|
||||
%td.order2{"ng-bind" => "::order.shop_name"}
|
||||
%td.order3.show-for-large-up{"ng-bind" => "order.changes_allowed_until"}
|
||||
%td.order4.show-for-large-up{"ng-bind" => "::order.item_count"}
|
||||
%td.order5.text-right{"ng-class" => "{'credit' : order.total < 0, 'debit' : order.total > 0, 'paid' : order.total == 0}","ng-bind" => "::order.total | localizeCurrency"}
|
||||
%td.order6.text-right.show-for-large-up.brick
|
||||
%a{"ng-href" => "{{::order.path}}" }= t('.edit')
|
||||
%td.order7.text-right
|
||||
= link_to t('.cancel'), "", method: :put, "ng-href" => "{{::order.cancel_path}}", "confirm-link-click" => t('orders_confirm_cancel')
|
||||
@@ -1,12 +1,10 @@
|
||||
.row.active_table_row.skinny-head.margin-top{"ng-click" => "toggle($event)", "ng-class" => "{'closed' : !open()}"}
|
||||
.columns.small-2
|
||||
%span.margin-top
|
||||
%img.account-logo{"logo-fallback" => true, "ng-src" => "{{distributor.logo}}"}
|
||||
.columns.small-10.medium-5
|
||||
%span.margin-top
|
||||
%strong{"ng-bind" => "::distributor.name"}
|
||||
.columns.small-8.small-offset-2.medium-3.text-right
|
||||
%span.margin-top.distributor-balance{"ng-bind" => "::distributor.balance | formatBalance", "ng-class" => "{'credit' : distributor.balance < 0, 'debit' : distributor.balance > 0, 'paid' : distributor.balance == 0}" }
|
||||
.columns.small-2.medium-2.text-right
|
||||
%span.margin-top
|
||||
%img.margin-top.account-logo{"logo-fallback" => true, "ng-src" => "{{distributor.logo}}"}
|
||||
.columns.small-5
|
||||
%h3.margin-top{"ng-bind" => "::distributor.name"}
|
||||
.columns.small-4.text-right
|
||||
%h3.margin-top.distributor-balance{"ng-bind" => "::distributor.balance | formatBalance", "ng-class" => "{'credit' : distributor.balance < 0, 'debit' : distributor.balance > 0, 'paid' : distributor.balance == 0}" }
|
||||
.columns.small-1.text-right
|
||||
%h3.margin-top
|
||||
%i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"}
|
||||
|
||||
@@ -3,22 +3,26 @@
|
||||
|
||||
.row.pad-top
|
||||
.small-12.columns.pad-top
|
||||
%h2= accurate_title
|
||||
.account-summary{"data-hook" => "account_summary"}
|
||||
= @user.email
|
||||
(#{link_to t(:edit), spree.edit_account_path})
|
||||
%h3= t(:my_orders)
|
||||
%h2
|
||||
= accurate_title
|
||||
%span.account-summary{"data-hook" => "account_summary"}
|
||||
= @user.email
|
||||
(#{link_to t(:edit), spree.edit_account_path})
|
||||
|
||||
.orders{"ng-controller" => "OrdersCtrl", "ng-cloak" => true}
|
||||
.row
|
||||
.small-12.columns
|
||||
.active_table
|
||||
%distributor.active_table_node.row.animate-repeat{"ng-if" => "Orders.orders_by_distributor.length > 0", "ng-repeat" => "(key, distributor) in Orders.orders_by_distributor",
|
||||
"ng-controller" => "DistributorNodeCtrl",
|
||||
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !distributor.active}",
|
||||
id: "{{distributor.hash}}"}
|
||||
.small-12.columns
|
||||
= render partial: "spree/users/skinny"
|
||||
= render partial: "spree/users/fat"
|
||||
.message{"ng-if" => "Orders.orders_by_distributor.length == 0", "ng-bind" => "::'you_have_no_orders_yet' | t"}
|
||||
.my-open-orders{ ng: { show: 'Orders.changeable_orders.length > 0' } }
|
||||
%h3= t(:open_orders)
|
||||
= render 'open_orders'
|
||||
|
||||
.active_table
|
||||
%h3.my-orders= t(:transaction_history)
|
||||
%distributor.active_table_node.row.animate-repeat{"ng-if" => "Orders.orders_by_distributor.length > 0", "ng-repeat" => "(key, distributor) in Orders.orders_by_distributor",
|
||||
"ng-controller" => "DistributorNodeCtrl",
|
||||
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !distributor.active}",
|
||||
id: "{{distributor.hash}}"}
|
||||
.small-12.columns
|
||||
= render partial: "spree/users/skinny"
|
||||
= render partial: "spree/users/fat"
|
||||
.message{"ng-if" => "Orders.orders_by_distributor.length == 0", "ng-bind" => "::'you_have_no_orders_yet' | t"}
|
||||
|
||||
= render partial: "shared/footer"
|
||||
|
||||
@@ -80,6 +80,21 @@ en:
|
||||
show_all: Show all
|
||||
show_all_with_more: "Show All (%{num} More)"
|
||||
cancel: Cancel
|
||||
edit: Edit
|
||||
distributors: Distributors
|
||||
order_cycles: Order Cycles
|
||||
enterprise_limit: Enterprise Limit
|
||||
bulk_order_management: Bulk Order Management
|
||||
enterprises: Enterprises
|
||||
enterprise_groups: Groups
|
||||
reports: Reports
|
||||
variant_overrides: Inventory
|
||||
more: More
|
||||
spree_products: Spree Products
|
||||
all: All
|
||||
current: Current
|
||||
available: Available
|
||||
dashboard: Dashboard
|
||||
|
||||
admin:
|
||||
# Common properties / models
|
||||
@@ -99,6 +114,9 @@ en:
|
||||
sku: SKU
|
||||
tags: Tags
|
||||
variant: Variant
|
||||
weight: Weight
|
||||
volume: Volume
|
||||
items: Items
|
||||
|
||||
# General form elements
|
||||
quick_search: Quick Search
|
||||
@@ -107,6 +125,8 @@ en:
|
||||
end_date: "End Date"
|
||||
unsaved_changes: "You have unsaved changes"
|
||||
form_invalid: "Form contains missing or invalid fields"
|
||||
clear_filters: Clear Filters
|
||||
clear: Clear
|
||||
|
||||
columns: Columns
|
||||
actions: Actions
|
||||
@@ -190,6 +210,7 @@ en:
|
||||
edit: 'Edit'
|
||||
update_address: 'Update Address'
|
||||
confirm_delete: 'Sure to delete?'
|
||||
search_by_email: "Search by email/code..."
|
||||
|
||||
cache_settings:
|
||||
show:
|
||||
@@ -218,6 +239,7 @@ en:
|
||||
new_button: New Enterprise Group
|
||||
|
||||
products:
|
||||
unit_name_placeholder: 'eg. bunches'
|
||||
bulk_edit:
|
||||
unit: Unit
|
||||
display_as: Display As
|
||||
@@ -299,6 +321,8 @@ en:
|
||||
abn_placeholder: eg. 99 123 456 789
|
||||
acn: ACN
|
||||
acn_placeholder: eg. 123 456 789
|
||||
display_invoice_logo: Display logo in invoices
|
||||
invoice_text: Add customized text at the end of invoices
|
||||
contact:
|
||||
name: Name
|
||||
name_placeholder: eg. Gustav Plum
|
||||
@@ -371,17 +395,25 @@ en:
|
||||
shopfront_requires_login_tip: "Choose whether customers must login to view the shopfront or if it's visible to everybody."
|
||||
shopfront_requires_login_false: "Public"
|
||||
shopfront_requires_login_true: "Visible to registered customers only"
|
||||
recommend_require_login: "We recommend to require users to login when orders can be changed."
|
||||
allow_guest_orders: "Guest orders"
|
||||
allow_guest_orders_tip: "Allow checkout as guest or require a registered user."
|
||||
allow_guest_orders_false: "Require login to order"
|
||||
allow_guest_orders_true: "Allow guest checkout"
|
||||
allow_order_changes: "Change orders"
|
||||
allow_order_changes_tip: "Allow customers to change their order as long the order cycle is open."
|
||||
allow_order_changes_false: "Placed orders cannot be changed / cancelled"
|
||||
allow_order_changes_true: "Customers can change / cancel orders while order cycle is open"
|
||||
shopfront_message: Shopfront Message
|
||||
shopfront_message_placeholder: >
|
||||
An optional explanation for customers detailing how your shopfront works,
|
||||
to be displayed above the product list on your shop page.
|
||||
shopfront_closed_message: Shopfront Closed Message
|
||||
shopfront_closed_message_placeholder: >
|
||||
A message which provides a more detailed explanation about why your shop is
|
||||
closed and/or when customers can expect it to open again. This is displayed
|
||||
on your shop only when you have no active order cycles (ie. shop is closed).
|
||||
shopfront_category_ordering: Shopfront Category Ordering
|
||||
open_date: Open Date
|
||||
close_date: Close Date
|
||||
social:
|
||||
@@ -523,12 +555,25 @@ en:
|
||||
invoice_style2?: Use the alternative invoice model that includes total tax breakdown per rate and tax rate info per item (not yet suitable for countries displaying prices excluding tax)
|
||||
enable_receipt_printing?: Show options for printing receipts using thermal printers in order dropdown?
|
||||
|
||||
# Frontend views
|
||||
#
|
||||
# These keys are referenced relatively like `t('.message')` in
|
||||
# app/views/checkout/_already_ordered.html.haml.
|
||||
#
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "cart"
|
||||
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
|
||||
home:
|
||||
hubs:
|
||||
show_closed_shops: "Show closed shops"
|
||||
hide_closed_shops: "Hide closed shops"
|
||||
show_on_map: "Show all on the map"
|
||||
shared:
|
||||
menu:
|
||||
cart:
|
||||
checkout: "Checkout now"
|
||||
already_ordered_products: "Already ordered in this order cycle"
|
||||
register_call:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
@@ -604,6 +649,7 @@ en:
|
||||
terms_of_service: "Terms of service"
|
||||
on_demand: On demand
|
||||
none: None
|
||||
not_allowed: Not allowed
|
||||
|
||||
label_shops: "Shops"
|
||||
label_map: "Map"
|
||||
@@ -626,7 +672,6 @@ en:
|
||||
items: "items"
|
||||
cart_headline: "Your shopping cart"
|
||||
total: "Total"
|
||||
checkout: "Checkout now"
|
||||
cart_updating: "Updating cart..."
|
||||
cart_empty: "Cart empty"
|
||||
cart_edit: "Edit your cart"
|
||||
@@ -635,15 +680,6 @@ en:
|
||||
card_securitycode: "Security Code"
|
||||
card_expiry_date: Expiry Date
|
||||
|
||||
ofn_cart_headline: "Current cart for:"
|
||||
ofn_cart_distributor: "Distributor:"
|
||||
ofn_cart_oc: "Order cycle:"
|
||||
ofn_cart_from: "From:"
|
||||
ofn_cart_to: "To:"
|
||||
ofn_cart_product: "Product:"
|
||||
ofn_cart_quantitiy: "Quantity:"
|
||||
ofn_cart_send: "Buy me"
|
||||
|
||||
ie_warning_headline: "Your browser is out of date :-("
|
||||
ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
|
||||
ie_warning_chrome: Download Chrome
|
||||
@@ -743,6 +779,7 @@ en:
|
||||
order_billing_address: Billing address
|
||||
order_delivery_on: Delivery on
|
||||
order_delivery_address: Delivery address
|
||||
order_delivery_time: Delivery time
|
||||
order_special_instructions: "Your notes:"
|
||||
order_pickup_time: Ready for collection
|
||||
order_pickup_instructions: Collection Instructions
|
||||
@@ -751,6 +788,8 @@ en:
|
||||
order_includes_tax: (includes tax)
|
||||
order_payment_paypal_successful: Your payment via PayPal has been processed successfully.
|
||||
order_hub_info: Hub Info
|
||||
order_back_to_store: Back To Store
|
||||
order_back_to_cart: Back To Cart
|
||||
|
||||
bom_tip: "Use this page to alter product quantities across multiple orders. Products may also be removed from orders entirely, if required."
|
||||
|
||||
@@ -860,6 +899,11 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
hubs_distance: Closest to
|
||||
hubs_distance_filter: "Show me shops near %{location}"
|
||||
|
||||
shop_changeable_orders_alert_html:
|
||||
one: Your order with <a href='%{path}' target='_blank'>%{shop} / %{order}</a> is open for review. You can make changes until %{oc_close}.
|
||||
other: You have <a href='%{path}' target='_blank'>%{count} orders with %{shop}</a> currently open for review. You can make changes until %{oc_close}.
|
||||
orders_changeable_orders_alert_html: This order has been confirmed, but you can make changes until <strong>%{oc_close}</strong>.
|
||||
|
||||
products_clear_all: Clear all
|
||||
products_showing: "Showing:"
|
||||
products_with: with
|
||||
@@ -1005,7 +1049,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
orders_edit_checkout: Checkout
|
||||
orders_form_empty_cart: "Empty cart"
|
||||
orders_form_subtotal: Produce subtotal
|
||||
orders_form_admin: Admin and handling
|
||||
orders_form_admin: Admin & Handling
|
||||
orders_form_total: Total
|
||||
orders_oc_expired_headline: Orders have closed for this order cycle
|
||||
orders_oc_expired_text: "Sorry, orders for this order cycle closed %{time} ago! Please contact your hub directly to see if they can accept late orders."
|
||||
@@ -1015,7 +1059,18 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
orders_oc_expired_phone: "Phone:"
|
||||
orders_show_title: Order Confirmation
|
||||
orders_show_time: Order ready on
|
||||
orders_show_number: Order confirmation
|
||||
orders_show_order_number: "Order #%{number}"
|
||||
orders_show_cancelled: Cancelled
|
||||
orders_show_confirmed: Confirmed
|
||||
orders_your_order_has_been_cancelled: "Your order has been cancelled"
|
||||
orders_could_not_cancel: "Sorry, the order could not be cancelled"
|
||||
orders_cannot_remove_the_final_item: "Cannot remove the final item from an order, please cancel the order instead."
|
||||
orders_bought_items_notice:
|
||||
one: An additional item is already confirmed for this order cycle
|
||||
other: "%{count} additional items already confirmed for this order cycle"
|
||||
orders_bought_edit_button: Edit confirmed items
|
||||
orders_bought_already_confirmed: "* already confirmed"
|
||||
orders_confirm_cancel: Are you sure you want to cancel this order?
|
||||
|
||||
products_cart_distributor_choice: "Distributor for your order:"
|
||||
products_cart_distributor_change: "Your distributor for this order will be changed to %{name} if you add this product to your cart."
|
||||
@@ -1122,6 +1177,7 @@ 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"
|
||||
@@ -1262,6 +1318,7 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
calculator_values: "Calculator values"
|
||||
flat_percent_per_item: "Flat Percent (per item)"
|
||||
new_order_cycles: "New Order Cycles"
|
||||
new_order_cycle: "New Order Cycle"
|
||||
select_a_coordinator_for_your_order_cycle: "Select a coordinator for your order cycle"
|
||||
edit_order_cycle: "Edit Order Cycle"
|
||||
roles: "Roles"
|
||||
@@ -1282,6 +1339,7 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
price: "Price"
|
||||
on_hand: "On hand"
|
||||
save_changes: "Save Changes"
|
||||
order_saved: "Order Saved"
|
||||
spree_admin_overview_enterprises_header: "My Enterprises"
|
||||
spree_admin_overview_enterprises_footer: "MANAGE MY ENTERPRISES"
|
||||
spree_admin_enterprises_hubs_name: "Name"
|
||||
@@ -1324,6 +1382,8 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
edit_profile_details: "Edit profile details"
|
||||
edit_profile_details_etc: "Change your profile description, images, etc."
|
||||
order_cycle: "Order Cycle"
|
||||
order_cycles: "Order Cycles"
|
||||
enterprises: "Enterprises"
|
||||
remove_tax: "Remove tax"
|
||||
enterprise_terms_of_service: "Enterprise Terms of Service"
|
||||
enterprises_require_tos: "Enterprises must accept Terms of Service"
|
||||
@@ -1542,6 +1602,10 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
now_out_of_stock: is now out of stock.
|
||||
only_n_remainging: "now only has %{num} remaining."
|
||||
|
||||
producers:
|
||||
signup:
|
||||
start_free_profile: "Start with a free profile, and expand when you're ready!"
|
||||
|
||||
spree:
|
||||
admin:
|
||||
products:
|
||||
@@ -1558,7 +1622,11 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
date_picker:
|
||||
format: ! '%Y-%m-%d'
|
||||
js_format: 'yy-mm-dd'
|
||||
inventory: Inventory
|
||||
zipcode: Postcode
|
||||
orders:
|
||||
bought:
|
||||
item: "Already ordered in this order cycle"
|
||||
shipment_states:
|
||||
backorder: backorder
|
||||
partial: partial
|
||||
@@ -1596,6 +1664,23 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
orders:
|
||||
invoice:
|
||||
tax_invoice: "TAX INVOICE: "
|
||||
payment_states:
|
||||
balance_due: balance due
|
||||
completed: completed
|
||||
checkout: checkout
|
||||
credit_owed: credit owed
|
||||
failed: failed
|
||||
paid: paid
|
||||
pending: pending
|
||||
processing: processing
|
||||
void: void
|
||||
invalid: invalid
|
||||
shipment_states:
|
||||
backorder: backorder
|
||||
partial: partial
|
||||
pending: pending
|
||||
ready: ready
|
||||
shipped: shipped
|
||||
user_mailer:
|
||||
reset_password_instructions:
|
||||
request_sent_text: |
|
||||
@@ -1606,3 +1691,19 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
issue_text: |
|
||||
If the above URL does not work try copying and pasting it into your browser.
|
||||
If you continue to have problems please feel free to contact us.
|
||||
weight: Weight (per kg)
|
||||
zipcode: Postcode
|
||||
users:
|
||||
show:
|
||||
open_orders: Open Orders
|
||||
transaction_history: Transaction History
|
||||
open_orders:
|
||||
order: Order
|
||||
shop: Shop
|
||||
changes_allowed_until: Changes Allowed Until
|
||||
items: Items
|
||||
total: Total
|
||||
edit: Edit
|
||||
cancel: Cancel
|
||||
closed: Closed
|
||||
until: Until
|
||||
|
||||
@@ -522,8 +522,8 @@ fr:
|
||||
date_of_transaction: "Date de la transaction :"
|
||||
ticket_column_qty: "Qté"
|
||||
ticket_column_item: "Produit"
|
||||
ticket_column_unit_price: "Prix unitaire"
|
||||
ticket_column_total_price: "Prix total"
|
||||
ticket_column_unit_price: "Px unit"
|
||||
ticket_column_total_price: "Px total"
|
||||
logo: "Logo (640x130)"
|
||||
logo_mobile: "Logo smartphone (75x26)"
|
||||
logo_mobile_svg: "Logo smartphone (SVG)"
|
||||
|
||||
@@ -28,6 +28,7 @@ Openfoodnetwork::Application.routes.draw do
|
||||
get :products
|
||||
post :order_cycle
|
||||
get :order_cycle
|
||||
get :changeable_orders_alert
|
||||
end
|
||||
|
||||
resources :producers, only: [:index] do
|
||||
@@ -42,6 +43,10 @@ Openfoodnetwork::Application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
resources :line_items, only: [:destroy] do
|
||||
get :bought, on: :collection
|
||||
end
|
||||
|
||||
resources :groups, only: [:index, :show] do
|
||||
collection do
|
||||
get :signup
|
||||
@@ -262,6 +267,7 @@ Spree::Core::Engine.routes.prepend do
|
||||
resources :orders do
|
||||
get :clear, :on => :collection
|
||||
get :order_cycle_expired, :on => :collection
|
||||
put :cancel, on: :member
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddAllowOrderChangesToEnterprise < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :enterprises, :allow_order_changes, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
||||
@@ -251,6 +251,7 @@ ActiveRecord::Schema.define(:version => 20161215230219) do
|
||||
t.boolean "allow_guest_orders", :default => true, :null => false
|
||||
t.text "invoice_text"
|
||||
t.boolean "display_invoice_logo", :default => false
|
||||
t.boolean "allow_order_changes", :default => false, :null => false
|
||||
end
|
||||
|
||||
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
|
||||
|
||||
@@ -47,6 +47,14 @@ module OpenFoodNetwork
|
||||
end
|
||||
end
|
||||
|
||||
def increment!(attribute, by=1)
|
||||
if attribute == :count_on_hand && @variant_override.andand.stock_overridden?
|
||||
@variant_override.increment_stock! by
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def sku
|
||||
@variant_override.andand.sku || super
|
||||
end
|
||||
|
||||
@@ -20,4 +20,7 @@ Spree::Money.class_eval do
|
||||
output
|
||||
end
|
||||
|
||||
def format(options={})
|
||||
@money.format(@options.merge!(options))
|
||||
end
|
||||
end
|
||||
|
||||
162
spec/controllers/line_items_controller_spec.rb
Normal file
162
spec/controllers/line_items_controller_spec.rb
Normal file
@@ -0,0 +1,162 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe LineItemsController do
|
||||
let(:user) { create(:user) }
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:order_cycle) { create(:simple_order_cycle) }
|
||||
|
||||
context "listing bought items" do
|
||||
let!(:completed_order) do
|
||||
order = create(:completed_order_with_totals, user: user, distributor: distributor, order_cycle: order_cycle)
|
||||
while !order.completed? do break unless order.next! end
|
||||
order
|
||||
end
|
||||
|
||||
before do
|
||||
controller.stub spree_current_user: user
|
||||
controller.stub current_order_cycle: order_cycle
|
||||
controller.stub current_distributor: distributor
|
||||
end
|
||||
|
||||
it "lists items bought by the user from the same shop in the same order_cycle" do
|
||||
get :bought, { format: :json }
|
||||
expect(response.status).to eq 200
|
||||
json_response = JSON.parse(response.body)
|
||||
expect(json_response.length).to eq completed_order.line_items(:reload).count
|
||||
expect(json_response[0]['id']).to eq completed_order.line_items.first.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "destroying a line item on a completed order" do
|
||||
let(:item) do
|
||||
order = create(:completed_order_with_totals)
|
||||
item = create(:line_item, order: order)
|
||||
while !order.completed? do break unless order.next! end
|
||||
item
|
||||
end
|
||||
|
||||
before { controller.stub spree_current_user: item.order.user }
|
||||
|
||||
context "without a line item id" do
|
||||
it "fails and raises an error" do
|
||||
delete :destroy
|
||||
expect(response.status).to eq 404
|
||||
end
|
||||
end
|
||||
|
||||
context "with a line item id" do
|
||||
let(:params) { { format: :json, id: item } }
|
||||
|
||||
context "where the item's order is not associated with the user" do
|
||||
it "denies deletion" do
|
||||
delete :destroy, params
|
||||
expect(response.status).to eq 403
|
||||
end
|
||||
end
|
||||
|
||||
context "where the item's order is associated with the current user" do
|
||||
before { item.order.update_attributes(user_id: user.id) }
|
||||
|
||||
context "without an order cycle" do
|
||||
it "denies deletion" do
|
||||
delete :destroy, params
|
||||
expect(response.status).to eq 403
|
||||
end
|
||||
end
|
||||
|
||||
context "with an order cycle" do
|
||||
before { item.order.update_attributes(order_cycle_id: order_cycle.id) }
|
||||
|
||||
context "without a distributor" do
|
||||
it "denies deletion" do
|
||||
delete :destroy, params
|
||||
expect(response.status).to eq 403
|
||||
end
|
||||
end
|
||||
|
||||
context "where the item's order has a distributor" do
|
||||
before { item.order.update_attributes(distributor_id: distributor.id) }
|
||||
context "where changes are not allowed" do
|
||||
it "denies deletion" do
|
||||
delete :destroy, params
|
||||
expect(response.status).to eq 403
|
||||
end
|
||||
end
|
||||
|
||||
context "where changes are allowed" do
|
||||
before { distributor.update_attributes(allow_order_changes: true) }
|
||||
|
||||
it "deletes the line item" do
|
||||
delete :destroy, params
|
||||
expect(response.status).to eq 204
|
||||
expect { item.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "where shipping and payment fees apply" do
|
||||
let(:distributor) { create(:distributor_enterprise, charges_sales_tax: true, allow_order_changes: true) }
|
||||
let(:shipping_fee) { 3 }
|
||||
let(:payment_fee) { 5 }
|
||||
let(:order) { create(:completed_order_with_fees, distributor: distributor, shipping_fee: shipping_fee, payment_fee: payment_fee) }
|
||||
|
||||
before do
|
||||
Spree::Config.shipment_inc_vat = true
|
||||
Spree::Config.shipping_tax_rate = 0.25
|
||||
end
|
||||
|
||||
it "updates the fees" do
|
||||
# Sanity check fees
|
||||
item_num = order.line_items.length
|
||||
initial_fees = item_num * (shipping_fee + payment_fee)
|
||||
expect(order.adjustment_total).to eq initial_fees
|
||||
expect(order.shipment.adjustment.included_tax).to eq 1.2
|
||||
|
||||
# Delete the item
|
||||
item = order.line_items.first
|
||||
controller.stub spree_current_user: order.user
|
||||
request = { format: :json, id: item }
|
||||
delete :destroy, request
|
||||
expect(response.status).to eq 204
|
||||
|
||||
# Check the fees again
|
||||
order.reload
|
||||
order.shipment.reload
|
||||
expect(order.adjustment_total).to eq initial_fees - shipping_fee - payment_fee
|
||||
expect(order.shipment.adjustment.amount).to eq shipping_fee
|
||||
expect(order.payment.adjustment.amount).to eq payment_fee
|
||||
expect(order.shipment.adjustment.included_tax).to eq 0.6
|
||||
end
|
||||
end
|
||||
|
||||
context "where enterprise fees apply" do
|
||||
let(:user) { create(:user) }
|
||||
let(:variant) { create(:variant) }
|
||||
let(:distributor) { create(:distributor_enterprise, allow_order_changes: true) }
|
||||
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) }
|
||||
let(:enterprise_fee) { create(:enterprise_fee, calculator: build(:calculator_per_item) ) }
|
||||
let!(:exchange) { create(:exchange, incoming: true, sender: variant.product.supplier, receiver: order_cycle.coordinator, variants: [variant], enterprise_fees: [enterprise_fee]) }
|
||||
let!(:order) do
|
||||
order = create(:completed_order_with_totals, user: user, distributor: distributor, order_cycle: order_cycle)
|
||||
order.reload.line_items.first.update_attributes(variant_id: variant.id)
|
||||
while !order.completed? do break unless order.next! end
|
||||
order.update_distribution_charge!
|
||||
order
|
||||
end
|
||||
let(:params) { { format: :json, id: order.line_items.first } }
|
||||
|
||||
it "updates the fees" do
|
||||
expect(order.reload.adjustment_total).to eq enterprise_fee.calculator.preferred_amount
|
||||
|
||||
controller.stub spree_current_user: user
|
||||
delete :destroy, params
|
||||
expect(response.status).to eq 204
|
||||
|
||||
expect(order.reload.adjustment_total).to eq 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -191,6 +191,216 @@ describe Spree::OrdersController do
|
||||
end
|
||||
end
|
||||
|
||||
describe "removing items from a completed order" do
|
||||
context "with shipping and transaction fees" do
|
||||
let(:distributor) { create(:distributor_enterprise, charges_sales_tax: true, allow_order_changes: true) }
|
||||
let(:order) { create(:completed_order_with_fees, distributor: distributor, shipping_fee: shipping_fee, payment_fee: payment_fee) }
|
||||
let(:line_item1) { order.line_items.first }
|
||||
let(:line_item2) { order.line_items.second }
|
||||
let(:shipping_fee) { 3 }
|
||||
let(:payment_fee) { 5 }
|
||||
let(:item_num) { order.line_items.length }
|
||||
let(:expected_fees) { item_num * (shipping_fee + payment_fee) }
|
||||
let(:params) { { order: { line_items_attributes: {
|
||||
"0" => {id: line_item1.id, quantity: 1},
|
||||
"1" => {id: line_item2.id, quantity: 0}
|
||||
} } } }
|
||||
|
||||
before do
|
||||
Spree::Config.shipment_inc_vat = true
|
||||
Spree::Config.shipping_tax_rate = 0.25
|
||||
|
||||
# Sanity check the fees
|
||||
expect(order.adjustments.length).to eq 2
|
||||
expect(item_num).to eq 2
|
||||
expect(order.adjustment_total).to eq expected_fees
|
||||
expect(order.shipment.adjustment.included_tax).to eq 1.2
|
||||
|
||||
allow(subject).to receive(:spree_current_user) { order.user }
|
||||
allow(subject).to receive(:order_to_update) { order }
|
||||
end
|
||||
|
||||
it "updates the fees" do
|
||||
# Setting quantity of an item to zero
|
||||
spree_post :update, params
|
||||
|
||||
# Check if fees got updated
|
||||
order.reload
|
||||
expect(order.line_items.count).to eq 1
|
||||
expect(order.adjustment_total).to eq expected_fees - shipping_fee - payment_fee
|
||||
expect(order.shipment.adjustment.included_tax).to eq 0.6
|
||||
end
|
||||
end
|
||||
|
||||
context "with enterprise fees" do
|
||||
let(:user) { create(:user) }
|
||||
let(:variant) { create(:variant) }
|
||||
let(:distributor) { create(:distributor_enterprise, allow_order_changes: true) }
|
||||
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) }
|
||||
let(:enterprise_fee) { create(:enterprise_fee, calculator: build(:calculator_per_item) ) }
|
||||
let!(:exchange) { create(:exchange, incoming: true, sender: variant.product.supplier, receiver: order_cycle.coordinator, variants: [variant], enterprise_fees: [enterprise_fee]) }
|
||||
let!(:order) do
|
||||
order = create(:completed_order_with_totals, user: user, distributor: distributor, order_cycle: order_cycle)
|
||||
order.reload.line_items.first.update_attributes(variant_id: variant.id)
|
||||
while !order.completed? do break unless order.next! end
|
||||
order.update_distribution_charge!
|
||||
order
|
||||
end
|
||||
let(:params) { { order: { line_items_attributes: {
|
||||
"0" => { id: order.line_items.first.id, quantity: 2 }
|
||||
} } } }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:spree_current_user) { order.user }
|
||||
allow(subject).to receive(:order_to_update) { order }
|
||||
end
|
||||
|
||||
it "updates the fees" do
|
||||
expect(order.reload.adjustment_total).to eq enterprise_fee.calculator.preferred_amount
|
||||
|
||||
controller.stub spree_current_user: user
|
||||
spree_post :update, params
|
||||
|
||||
expect(order.reload.adjustment_total).to eq enterprise_fee.calculator.preferred_amount * 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "removing items from a completed order" do
|
||||
let(:order) { create(:completed_order_with_totals) }
|
||||
let!(:line_item) { order.reload.line_items.first }
|
||||
let(:params) { { order: {} } }
|
||||
|
||||
before { allow(subject).to receive(:order_to_update) { order } }
|
||||
|
||||
context "when more than one item remains" do
|
||||
before do
|
||||
params[:order][:line_items_attributes] = { "0" => {quantity: "1", id: line_item.id} }
|
||||
end
|
||||
|
||||
it "removes the item" do
|
||||
spree_post :update, params
|
||||
expect(flash[:error]).to be nil
|
||||
expect(response).to redirect_to spree.order_path(order)
|
||||
expect(order.reload.line_items.count).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context "when only one item remains" do
|
||||
before do
|
||||
params[:order][:line_items_attributes] = { "0" => {quantity: "0", id: line_item.id} }
|
||||
end
|
||||
|
||||
it "does not remove the item, flash suggests cancellation" do
|
||||
spree_post :update, params
|
||||
expect(flash[:error]).to eq I18n.t(:orders_cannot_remove_the_final_item)
|
||||
expect(response).to redirect_to spree.order_path(order)
|
||||
expect(order.reload.line_items.count).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#order_to_update" do
|
||||
let!(:current_order) { double(:current_order) }
|
||||
let(:params) { { } }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:current_order) { current_order }
|
||||
allow(controller).to receive(:params) { params }
|
||||
end
|
||||
|
||||
context "when no order id is given in params" do
|
||||
it "returns the current_order" do
|
||||
expect(controller.send(:order_to_update)).to eq current_order
|
||||
end
|
||||
end
|
||||
|
||||
context "when an order_id is given in params" do
|
||||
before do
|
||||
params.merge!({id: order.number})
|
||||
end
|
||||
|
||||
context "and the order is not complete" do
|
||||
let!(:order) { create(:order) }
|
||||
|
||||
it "returns nil" do
|
||||
expect(controller.send(:order_to_update)).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
context "and the order is complete" do
|
||||
let!(:order) { create(:completed_order_with_totals) }
|
||||
|
||||
context "and the user doesn't have permisson to 'update' the order" do
|
||||
before { allow(controller).to receive(:can?).with(:update, order) { false } }
|
||||
|
||||
it "returns nil" do
|
||||
expect(controller.send(:order_to_update)).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
context "and the user has permission to 'update' the order" do
|
||||
before { allow(controller).to receive(:can?).with(:update, order) { true } }
|
||||
|
||||
context "and the order is not editable" do
|
||||
|
||||
it "returns nil" do
|
||||
expect(controller.send(:order_to_update)).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
context "and the order is editable" do
|
||||
let(:order_cycle) { create(:simple_order_cycle) }
|
||||
let(:distributor) { create(:enterprise, allow_order_changes: true) }
|
||||
|
||||
before do
|
||||
order.update_attributes(order_cycle_id: order_cycle.id, distributor_id: distributor.id)
|
||||
end
|
||||
|
||||
it "returns the order" do
|
||||
expect(controller.send(:order_to_update)).to eq order
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "cancelling an order" do
|
||||
let(:user) { create(:user) }
|
||||
let(:order) { create(:order, user: user) }
|
||||
let(:params) { { id: order.number } }
|
||||
|
||||
context "when the user does not have permission to cancel the order" do
|
||||
it "responds with unauthorized" do
|
||||
spree_put :cancel, params
|
||||
expect(response).to render_template 'shared/unauthorized'
|
||||
end
|
||||
end
|
||||
|
||||
context "when the user has permission to cancel the order" do
|
||||
before { allow(controller).to receive(:spree_current_user) { user } }
|
||||
|
||||
context "when the order is not yet complete" do
|
||||
it "responds with forbidden" do
|
||||
spree_put :cancel, params
|
||||
expect(response.status).to redirect_to spree.order_path(order)
|
||||
expect(flash[:error]).to eq I18n.t(:orders_could_not_cancel)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the order is complete" do
|
||||
let(:order) { create(:completed_order_with_totals, user: user) }
|
||||
|
||||
it "responds with success" do
|
||||
spree_put :cancel, params
|
||||
expect(response.status).to redirect_to spree.order_path(order)
|
||||
expect(flash[:success]).to eq I18n.t(:orders_your_order_has_been_cancelled)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
require 'ffaker'
|
||||
require 'spree/core/testing_support/factories'
|
||||
|
||||
# http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md
|
||||
#
|
||||
# The spree_core gem defines factories in several files. For example:
|
||||
#
|
||||
# - lib/spree/core/testing_support/factories/calculator_factory.rb
|
||||
# * calculator
|
||||
# * no_amount_calculator
|
||||
#
|
||||
# - lib/spree/core/testing_support/factories/order_factory.rb
|
||||
# * order
|
||||
# * order_with_totals
|
||||
# * order_with_inventory_unit_shipped
|
||||
# * completed_order_with_totals
|
||||
#
|
||||
FactoryGirl.define do
|
||||
factory :classification, class: Spree::Classification do
|
||||
end
|
||||
@@ -57,6 +71,14 @@ FactoryGirl.define do
|
||||
end
|
||||
end
|
||||
|
||||
factory :order_cycle_with_overrides, parent: :order_cycle do
|
||||
after (:create) do |oc|
|
||||
oc.variants.each do |variant|
|
||||
create(:variant_override, variant: variant, hub: oc.distributors.first, price: variant.price + 100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
factory :simple_order_cycle, :class => OrderCycle do
|
||||
sequence(:name) { |n| "Order Cycle #{n}" }
|
||||
|
||||
@@ -171,6 +193,10 @@ FactoryGirl.define do
|
||||
end
|
||||
|
||||
sequence(:calculator_amount)
|
||||
factory :calculator_per_item, class: Spree::Calculator::PerItem do
|
||||
preferred_amount { generate(:calculator_amount) }
|
||||
end
|
||||
|
||||
factory :enterprise_fee, :class => EnterpriseFee do
|
||||
ignore { amount nil }
|
||||
|
||||
@@ -178,7 +204,7 @@ FactoryGirl.define do
|
||||
sequence(:fee_type) { |n| EnterpriseFee::FEE_TYPES[n % EnterpriseFee::FEE_TYPES.count] }
|
||||
|
||||
enterprise { Enterprise.first || FactoryGirl.create(:supplier_enterprise) }
|
||||
calculator { Spree::Calculator::PerItem.new(preferred_amount: amount || generate(:calculator_amount)) }
|
||||
calculator { build(:calculator_per_item, preferred_amount: amount) }
|
||||
|
||||
after(:create) { |ef| ef.calculator.save! }
|
||||
end
|
||||
@@ -237,6 +263,27 @@ FactoryGirl.define do
|
||||
end
|
||||
end
|
||||
|
||||
factory :completed_order_with_fees, parent: :order_with_totals_and_distribution do
|
||||
ignore do
|
||||
shipping_fee 3
|
||||
payment_fee 5
|
||||
end
|
||||
|
||||
shipping_method do
|
||||
shipping_calculator = build(:calculator_per_item, preferred_amount: shipping_fee)
|
||||
create(:shipping_method, calculator: shipping_calculator, require_ship_address: false, distributors: [distributor])
|
||||
end
|
||||
|
||||
after(:create) do |order, evaluator|
|
||||
create(:line_item, order: order)
|
||||
order.create_shipment!
|
||||
payment_calculator = build(:calculator_per_item, preferred_amount: evaluator.payment_fee)
|
||||
payment_method = create(:payment_method, calculator: payment_calculator)
|
||||
create(:payment, order: order, amount: order.total, payment_method: payment_method, state: 'checkout')
|
||||
while !order.completed? do break unless order.next! end
|
||||
end
|
||||
end
|
||||
|
||||
factory :zone_with_member, :parent => :zone do
|
||||
default_tax true
|
||||
|
||||
|
||||
@@ -58,124 +58,263 @@ feature %q{
|
||||
end
|
||||
end
|
||||
|
||||
scenario "creating an order cycle", js: true do
|
||||
page.driver.resize(1280, 2000)
|
||||
context "with specific time" do
|
||||
let(:order_cycle_opening_time) { Time.zone.local(2040, 11, 06, 06, 00, 00) }
|
||||
let(:order_cycle_closing_time) { Time.zone.local(2040, 11, 13, 17, 00, 00) }
|
||||
|
||||
# Given coordinating, supplying and distributing enterprises with some products with variants
|
||||
coordinator = create(:distributor_enterprise, name: 'My coordinator')
|
||||
supplier = create(:supplier_enterprise, name: 'My supplier')
|
||||
product = create(:product, supplier: supplier)
|
||||
v1 = create(:variant, product: product)
|
||||
v2 = create(:variant, product: product)
|
||||
distributor = create(:distributor_enterprise, name: 'My distributor', with_payment_and_shipping: true)
|
||||
scenario "creating an order cycle", js: true do
|
||||
page.driver.resize(1280, 2000)
|
||||
|
||||
# Relationships required for interface to work
|
||||
create(:enterprise_relationship, parent: supplier, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: distributor, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: supplier, child: distributor, permissions_list: [:add_to_order_cycle])
|
||||
# Given coordinating, supplying and distributing enterprises with some products with variants
|
||||
coordinator = create(:distributor_enterprise, name: 'My coordinator')
|
||||
supplier = create(:supplier_enterprise, name: 'My supplier')
|
||||
product = create(:product, supplier: supplier)
|
||||
v1 = create(:variant, product: product)
|
||||
v2 = create(:variant, product: product)
|
||||
distributor = create(:distributor_enterprise, name: 'My distributor', with_payment_and_shipping: true)
|
||||
|
||||
# And some enterprise fees
|
||||
supplier_fee = create(:enterprise_fee, enterprise: supplier, name: 'Supplier fee')
|
||||
coordinator_fee = create(:enterprise_fee, enterprise: coordinator, name: 'Coord fee')
|
||||
distributor_fee = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee')
|
||||
# Relationships required for interface to work
|
||||
create(:enterprise_relationship, parent: supplier, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: distributor, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: supplier, child: distributor, permissions_list: [:add_to_order_cycle])
|
||||
|
||||
# When I go to the new order cycle page
|
||||
login_to_admin_section
|
||||
click_link 'Order Cycles'
|
||||
click_link 'New Order Cycle'
|
||||
# And some enterprise fees
|
||||
supplier_fee = create(:enterprise_fee, enterprise: supplier, name: 'Supplier fee')
|
||||
coordinator_fee = create(:enterprise_fee, enterprise: coordinator, name: 'Coord fee')
|
||||
distributor_fee = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee')
|
||||
|
||||
# Select a coordinator since there are two available
|
||||
select2_select 'My coordinator', from: 'coordinator_id'
|
||||
click_button "Continue >"
|
||||
# When I go to the new order cycle page
|
||||
login_to_admin_section
|
||||
click_link 'Order Cycles'
|
||||
click_link 'New Order Cycle'
|
||||
|
||||
# And I fill in the basic fields
|
||||
fill_in 'order_cycle_name', with: 'Plums & Avos'
|
||||
fill_in 'order_cycle_orders_open_at', with: '2040-11-06 06:00:00'
|
||||
fill_in 'order_cycle_orders_close_at', with: '2040-11-13 17:00:00'
|
||||
# Select a coordinator since there are two available
|
||||
select2_select 'My coordinator', from: 'coordinator_id'
|
||||
click_button "Continue >"
|
||||
|
||||
# And I add a coordinator fee
|
||||
click_button 'Add coordinator fee'
|
||||
select 'Coord fee', from: 'order_cycle_coordinator_fee_0_id'
|
||||
# And I fill in the basic fields
|
||||
fill_in 'order_cycle_name', with: 'Plums & Avos'
|
||||
fill_in 'order_cycle_orders_open_at', with: order_cycle_opening_time
|
||||
fill_in 'order_cycle_orders_close_at', with: order_cycle_closing_time
|
||||
|
||||
# I should not be able to add a blank supplier
|
||||
page.should have_select 'new_supplier_id', selected: ''
|
||||
page.should have_button 'Add supplier', disabled: true
|
||||
# And I add a coordinator fee
|
||||
click_button 'Add coordinator fee'
|
||||
select 'Coord fee', from: 'order_cycle_coordinator_fee_0_id'
|
||||
|
||||
# And I add a supplier and some products
|
||||
select 'My supplier', from: 'new_supplier_id'
|
||||
click_button 'Add supplier'
|
||||
fill_in 'order_cycle_incoming_exchange_0_receival_instructions', with: 'receival instructions'
|
||||
page.find('table.exchanges tr.supplier td.products').click
|
||||
check "order_cycle_incoming_exchange_0_variants_#{v1.id}"
|
||||
check "order_cycle_incoming_exchange_0_variants_#{v2.id}"
|
||||
# I should not be able to add a blank supplier
|
||||
page.should have_select 'new_supplier_id', selected: ''
|
||||
page.should have_button 'Add supplier', disabled: true
|
||||
|
||||
# I should not be able to re-add the supplier
|
||||
page.should_not have_select 'new_supplier_id', with_options: ['My supplier']
|
||||
page.should have_button 'Add supplier', disabled: true
|
||||
page.all("td.supplier_name").map(&:text).should == ['My supplier']
|
||||
# And I add a supplier and some products
|
||||
select 'My supplier', from: 'new_supplier_id'
|
||||
click_button 'Add supplier'
|
||||
fill_in 'order_cycle_incoming_exchange_0_receival_instructions', with: 'receival instructions'
|
||||
page.find('table.exchanges tr.supplier td.products').click
|
||||
check "order_cycle_incoming_exchange_0_variants_#{v1.id}"
|
||||
check "order_cycle_incoming_exchange_0_variants_#{v2.id}"
|
||||
|
||||
# And I add a supplier fee
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
select 'My supplier', from: 'order_cycle_incoming_exchange_0_enterprise_fees_0_enterprise_id'
|
||||
select 'Supplier fee', from: 'order_cycle_incoming_exchange_0_enterprise_fees_0_enterprise_fee_id'
|
||||
# I should not be able to re-add the supplier
|
||||
page.should_not have_select 'new_supplier_id', with_options: ['My supplier']
|
||||
page.should have_button 'Add supplier', disabled: true
|
||||
page.all("td.supplier_name").map(&:text).should == ['My supplier']
|
||||
|
||||
# And I add a distributor with the same products
|
||||
select 'My distributor', from: 'new_distributor_id'
|
||||
click_button 'Add distributor'
|
||||
# And I add a supplier fee
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
select 'My supplier', from: 'order_cycle_incoming_exchange_0_enterprise_fees_0_enterprise_id'
|
||||
select 'Supplier fee', from: 'order_cycle_incoming_exchange_0_enterprise_fees_0_enterprise_fee_id'
|
||||
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'pickup time'
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'pickup instructions'
|
||||
# And I add a distributor with the same products
|
||||
select 'My distributor', from: 'new_distributor_id'
|
||||
click_button 'Add distributor'
|
||||
|
||||
page.find('table.exchanges tr.distributor td.products').click
|
||||
check "order_cycle_outgoing_exchange_0_variants_#{v1.id}"
|
||||
check "order_cycle_outgoing_exchange_0_variants_#{v2.id}"
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'pickup time'
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'pickup instructions'
|
||||
|
||||
page.find('table.exchanges tr.distributor td.tags').click
|
||||
within ".exchange-tags" do
|
||||
find(:css, "tags-input .tags input").set "wholesale\n"
|
||||
page.find('table.exchanges tr.distributor td.products').click
|
||||
check "order_cycle_outgoing_exchange_0_variants_#{v1.id}"
|
||||
check "order_cycle_outgoing_exchange_0_variants_#{v2.id}"
|
||||
|
||||
page.find('table.exchanges tr.distributor td.tags').click
|
||||
within ".exchange-tags" do
|
||||
find(:css, "tags-input .tags input").set "wholesale\n"
|
||||
end
|
||||
|
||||
# And I add a distributor fee
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
select 'My distributor', from: 'order_cycle_outgoing_exchange_0_enterprise_fees_0_enterprise_id'
|
||||
select 'Distributor fee', from: 'order_cycle_outgoing_exchange_0_enterprise_fees_0_enterprise_fee_id'
|
||||
|
||||
# And I click Create
|
||||
click_button 'Create'
|
||||
|
||||
# Then my order cycle should have been created
|
||||
page.should have_content 'Your order cycle has been created.'
|
||||
|
||||
page.should have_selector 'a', text: 'Plums & Avos'
|
||||
page.should have_selector "input[value='#{order_cycle_opening_time}']"
|
||||
page.should have_selector "input[value='#{order_cycle_closing_time}']"
|
||||
page.should have_content 'My coordinator'
|
||||
|
||||
page.should have_selector 'td.suppliers', text: 'My supplier'
|
||||
page.should have_selector 'td.distributors', text: 'My distributor'
|
||||
|
||||
# And it should have some fees
|
||||
oc = OrderCycle.last
|
||||
oc.exchanges.incoming.first.enterprise_fees.should == [supplier_fee]
|
||||
oc.coordinator_fees.should == [coordinator_fee]
|
||||
oc.exchanges.outgoing.first.enterprise_fees.should == [distributor_fee]
|
||||
|
||||
# And it should have some variants selected
|
||||
oc.exchanges.first.variants.count.should == 2
|
||||
oc.exchanges.last.variants.count.should == 2
|
||||
|
||||
# And my receival and pickup time and instructions should have been saved
|
||||
exchange = oc.exchanges.incoming.first
|
||||
exchange.receival_instructions.should == 'receival instructions'
|
||||
|
||||
exchange = oc.exchanges.outgoing.first
|
||||
exchange.pickup_time.should == 'pickup time'
|
||||
exchange.pickup_instructions.should == 'pickup instructions'
|
||||
exchange.tag_list.should == ['wholesale']
|
||||
end
|
||||
|
||||
# And I add a distributor fee
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
select 'My distributor', from: 'order_cycle_outgoing_exchange_0_enterprise_fees_0_enterprise_id'
|
||||
select 'Distributor fee', from: 'order_cycle_outgoing_exchange_0_enterprise_fees_0_enterprise_fee_id'
|
||||
scenario "updating an order cycle", js: true do
|
||||
# Given an order cycle with all the settings
|
||||
oc = create(:order_cycle)
|
||||
initial_variants = oc.variants.sort_by &:id
|
||||
|
||||
# And I click Create
|
||||
click_button 'Create'
|
||||
# And a coordinating, supplying and distributing enterprise with some products with variants
|
||||
coordinator = oc.coordinator
|
||||
supplier = create(:supplier_enterprise, name: 'My supplier')
|
||||
distributor = create(:distributor_enterprise, name: 'My distributor', with_payment_and_shipping: true)
|
||||
product = create(:product, supplier: supplier)
|
||||
v1 = create(:variant, product: product)
|
||||
v2 = create(:variant, product: product)
|
||||
|
||||
# Then my order cycle should have been created
|
||||
page.should have_content 'Your order cycle has been created.'
|
||||
# Relationships required for interface to work
|
||||
create(:enterprise_relationship, parent: supplier, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: distributor, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: supplier, child: distributor, permissions_list: [:add_to_order_cycle])
|
||||
|
||||
page.should have_selector 'a', text: 'Plums & Avos'
|
||||
# And some enterprise fees
|
||||
supplier_fee1 = create(:enterprise_fee, enterprise: supplier, name: 'Supplier fee 1')
|
||||
supplier_fee2 = create(:enterprise_fee, enterprise: supplier, name: 'Supplier fee 2')
|
||||
coordinator_fee1 = create(:enterprise_fee, enterprise: coordinator, name: 'Coord fee 1')
|
||||
coordinator_fee2 = create(:enterprise_fee, enterprise: coordinator, name: 'Coord fee 2')
|
||||
distributor_fee1 = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee 1')
|
||||
distributor_fee2 = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee 2')
|
||||
|
||||
page.should have_selector "input[value='2040-11-06 06:00:00 +1100']"
|
||||
page.should have_selector "input[value='2040-11-13 17:00:00 +1100']"
|
||||
page.should have_content 'My coordinator'
|
||||
# When I go to its edit page
|
||||
login_to_admin_section
|
||||
click_link 'Order Cycles'
|
||||
click_link oc.name
|
||||
wait_until { page.find('#order_cycle_name').value.present? }
|
||||
|
||||
page.should have_selector 'td.suppliers', text: 'My supplier'
|
||||
page.should have_selector 'td.distributors', text: 'My distributor'
|
||||
# And I update it
|
||||
fill_in 'order_cycle_name', with: 'Plums & Avos'
|
||||
fill_in 'order_cycle_orders_open_at', with: order_cycle_opening_time
|
||||
fill_in 'order_cycle_orders_close_at', with: order_cycle_closing_time
|
||||
|
||||
# And it should have some fees
|
||||
oc = OrderCycle.last
|
||||
oc.exchanges.incoming.first.enterprise_fees.should == [supplier_fee]
|
||||
oc.coordinator_fees.should == [coordinator_fee]
|
||||
oc.exchanges.outgoing.first.enterprise_fees.should == [distributor_fee]
|
||||
# CAN'T CHANGE COORDINATOR ANYMORE
|
||||
# select 'My coordinator', from: 'order_cycle_coordinator_id'
|
||||
|
||||
# And it should have some variants selected
|
||||
oc.exchanges.first.variants.count.should == 2
|
||||
oc.exchanges.last.variants.count.should == 2
|
||||
# And I configure some coordinator fees
|
||||
click_button 'Add coordinator fee'
|
||||
select 'Coord fee 1', from: 'order_cycle_coordinator_fee_0_id'
|
||||
click_button 'Add coordinator fee'
|
||||
click_button 'Add coordinator fee'
|
||||
click_link 'order_cycle_coordinator_fee_2_remove'
|
||||
select 'Coord fee 2', from: 'order_cycle_coordinator_fee_1_id'
|
||||
|
||||
# And my receival and pickup time and instructions should have been saved
|
||||
exchange = oc.exchanges.incoming.first
|
||||
exchange.receival_instructions.should == 'receival instructions'
|
||||
# And I add a supplier and some products
|
||||
select 'My supplier', from: 'new_supplier_id'
|
||||
click_button 'Add supplier'
|
||||
page.all("table.exchanges tr.supplier td.products").each { |e| e.click }
|
||||
|
||||
exchange = oc.exchanges.outgoing.first
|
||||
exchange.pickup_time.should == 'pickup time'
|
||||
exchange.pickup_instructions.should == 'pickup instructions'
|
||||
exchange.tag_list.should == ['wholesale']
|
||||
page.should have_selector "#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true
|
||||
page.find("#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true).click # uncheck (with visible:true filter)
|
||||
check "order_cycle_incoming_exchange_2_variants_#{v1.id}"
|
||||
check "order_cycle_incoming_exchange_2_variants_#{v2.id}"
|
||||
|
||||
# And I configure some supplier fees
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
select 'My supplier', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Supplier fee 1', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
click_link 'order_cycle_incoming_exchange_2_enterprise_fees_0_remove'
|
||||
select 'My supplier', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Supplier fee 2', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
|
||||
# And I add a distributor and some products
|
||||
select 'My distributor', from: 'new_distributor_id'
|
||||
click_button 'Add distributor'
|
||||
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'New time 0'
|
||||
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
|
||||
find(:css, "tags-input .tags input").set "wholesale\n"
|
||||
end
|
||||
|
||||
page.all("table.exchanges tr.distributor td.products").each { |e| e.click }
|
||||
|
||||
uncheck "order_cycle_outgoing_exchange_2_variants_#{v1.id}"
|
||||
check "order_cycle_outgoing_exchange_2_variants_#{v2.id}"
|
||||
|
||||
# And I configure some distributor fees
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
select 'My distributor', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Distributor fee 1', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
click_link 'order_cycle_outgoing_exchange_2_enterprise_fees_0_remove'
|
||||
select 'My distributor', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Distributor fee 2', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
|
||||
# And I click Update
|
||||
expect(page).to have_selector "#save-bar"
|
||||
click_button 'Update and Close'
|
||||
|
||||
# Then my order cycle should have been updated
|
||||
page.should have_content 'Your order cycle has been updated.'
|
||||
|
||||
page.should have_selector 'a', text: 'Plums & Avos'
|
||||
|
||||
page.should have_selector "input[value='#{order_cycle_opening_time}']"
|
||||
page.should have_selector "input[value='#{order_cycle_closing_time}']"
|
||||
page.should have_content coordinator.name
|
||||
|
||||
page.should have_selector 'td.suppliers', text: 'My supplier'
|
||||
page.should have_selector 'td.distributors', text: 'My distributor'
|
||||
|
||||
# And my coordinator fees should have been configured
|
||||
OrderCycle.last.coordinator_fee_ids.should match_array [coordinator_fee1.id, coordinator_fee2.id]
|
||||
|
||||
# And my supplier fees should have been configured
|
||||
OrderCycle.last.exchanges.incoming.last.enterprise_fee_ids.should == [supplier_fee2.id]
|
||||
|
||||
# And my distributor fees should have been configured
|
||||
OrderCycle.last.exchanges.outgoing.last.enterprise_fee_ids.should == [distributor_fee2.id]
|
||||
|
||||
# And my tags should have been save
|
||||
OrderCycle.last.exchanges.outgoing.last.tag_list.should == ['wholesale']
|
||||
|
||||
# And it should have some variants selected
|
||||
selected_initial_variants = initial_variants.take initial_variants.size - 1
|
||||
OrderCycle.last.variants.map(&:id).should match_array (selected_initial_variants.map(&:id) + [v1.id, v2.id])
|
||||
|
||||
# And the collection details should have been updated
|
||||
OrderCycle.last.exchanges.where(pickup_time: 'New time 0', pickup_instructions: 'New instructions 0').should be_present
|
||||
OrderCycle.last.exchanges.where(pickup_time: 'New time 1', pickup_instructions: 'New instructions 1').should be_present
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
scenario "editing an order cycle" do
|
||||
# Given an order cycle with all the settings
|
||||
oc = create(:order_cycle)
|
||||
@@ -273,144 +412,6 @@ feature %q{
|
||||
page.should_not have_selector 'table.exchanges tr.supplier'
|
||||
end
|
||||
|
||||
|
||||
scenario "updating an order cycle", js: true do
|
||||
# Given an order cycle with all the settings
|
||||
oc = create(:order_cycle)
|
||||
initial_variants = oc.variants.sort_by &:id
|
||||
|
||||
# And a coordinating, supplying and distributing enterprise with some products with variants
|
||||
coordinator = oc.coordinator
|
||||
supplier = create(:supplier_enterprise, name: 'My supplier')
|
||||
distributor = create(:distributor_enterprise, name: 'My distributor', with_payment_and_shipping: true)
|
||||
product = create(:product, supplier: supplier)
|
||||
v1 = create(:variant, product: product)
|
||||
v2 = create(:variant, product: product)
|
||||
|
||||
# Relationships required for interface to work
|
||||
create(:enterprise_relationship, parent: supplier, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: distributor, child: coordinator, permissions_list: [:add_to_order_cycle])
|
||||
create(:enterprise_relationship, parent: supplier, child: distributor, permissions_list: [:add_to_order_cycle])
|
||||
|
||||
# And some enterprise fees
|
||||
supplier_fee1 = create(:enterprise_fee, enterprise: supplier, name: 'Supplier fee 1')
|
||||
supplier_fee2 = create(:enterprise_fee, enterprise: supplier, name: 'Supplier fee 2')
|
||||
coordinator_fee1 = create(:enterprise_fee, enterprise: coordinator, name: 'Coord fee 1')
|
||||
coordinator_fee2 = create(:enterprise_fee, enterprise: coordinator, name: 'Coord fee 2')
|
||||
distributor_fee1 = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee 1')
|
||||
distributor_fee2 = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee 2')
|
||||
|
||||
# When I go to its edit page
|
||||
login_to_admin_section
|
||||
click_link 'Order Cycles'
|
||||
click_link oc.name
|
||||
wait_until { page.find('#order_cycle_name').value.present? }
|
||||
|
||||
# And I update it
|
||||
fill_in 'order_cycle_name', with: 'Plums & Avos'
|
||||
fill_in 'order_cycle_orders_open_at', with: '2040-11-06 06:00:00'
|
||||
fill_in 'order_cycle_orders_close_at', with: '2040-11-13 17:00:00'
|
||||
|
||||
# CAN'T CHANGE COORDINATOR ANYMORE
|
||||
# select 'My coordinator', from: 'order_cycle_coordinator_id'
|
||||
|
||||
# And I configure some coordinator fees
|
||||
click_button 'Add coordinator fee'
|
||||
select 'Coord fee 1', from: 'order_cycle_coordinator_fee_0_id'
|
||||
click_button 'Add coordinator fee'
|
||||
click_button 'Add coordinator fee'
|
||||
click_link 'order_cycle_coordinator_fee_2_remove'
|
||||
select 'Coord fee 2', from: 'order_cycle_coordinator_fee_1_id'
|
||||
|
||||
# And I add a supplier and some products
|
||||
select 'My supplier', from: 'new_supplier_id'
|
||||
click_button 'Add supplier'
|
||||
page.all("table.exchanges tr.supplier td.products").each { |e| e.click }
|
||||
|
||||
page.should have_selector "#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true
|
||||
page.find("#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true).click # uncheck (with visible:true filter)
|
||||
check "order_cycle_incoming_exchange_2_variants_#{v1.id}"
|
||||
check "order_cycle_incoming_exchange_2_variants_#{v2.id}"
|
||||
|
||||
# And I configure some supplier fees
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
select 'My supplier', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Supplier fee 1', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
within("tr.supplier-#{supplier.id}") { click_button 'Add fee' }
|
||||
click_link 'order_cycle_incoming_exchange_2_enterprise_fees_0_remove'
|
||||
select 'My supplier', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Supplier fee 2', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
|
||||
# And I add a distributor and some products
|
||||
select 'My distributor', from: 'new_distributor_id'
|
||||
click_button 'Add distributor'
|
||||
|
||||
fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'New time 0'
|
||||
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
|
||||
find(:css, "tags-input .tags input").set "wholesale\n"
|
||||
end
|
||||
|
||||
page.all("table.exchanges tr.distributor td.products").each { |e| e.click }
|
||||
|
||||
uncheck "order_cycle_outgoing_exchange_2_variants_#{v1.id}"
|
||||
check "order_cycle_outgoing_exchange_2_variants_#{v2.id}"
|
||||
|
||||
# And I configure some distributor fees
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
select 'My distributor', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Distributor fee 1', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
within("tr.distributor-#{distributor.id}") { click_button 'Add fee' }
|
||||
click_link 'order_cycle_outgoing_exchange_2_enterprise_fees_0_remove'
|
||||
select 'My distributor', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_id'
|
||||
select 'Distributor fee 2', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_fee_id'
|
||||
|
||||
# And I click Update
|
||||
expect(page).to have_selector "#save-bar"
|
||||
click_button 'Update and Close'
|
||||
|
||||
# Then my order cycle should have been updated
|
||||
page.should have_content 'Your order cycle has been updated.'
|
||||
|
||||
page.should have_selector 'a', text: 'Plums & Avos'
|
||||
|
||||
page.should have_selector "input[value='2040-11-06 06:00:00 +1100']"
|
||||
page.should have_selector "input[value='2040-11-13 17:00:00 +1100']"
|
||||
page.should have_content coordinator.name
|
||||
|
||||
page.should have_selector 'td.suppliers', text: 'My supplier'
|
||||
page.should have_selector 'td.distributors', text: 'My distributor'
|
||||
|
||||
# And my coordinator fees should have been configured
|
||||
OrderCycle.last.coordinator_fee_ids.should match_array [coordinator_fee1.id, coordinator_fee2.id]
|
||||
|
||||
# And my supplier fees should have been configured
|
||||
OrderCycle.last.exchanges.incoming.last.enterprise_fee_ids.should == [supplier_fee2.id]
|
||||
|
||||
# And my distributor fees should have been configured
|
||||
OrderCycle.last.exchanges.outgoing.last.enterprise_fee_ids.should == [distributor_fee2.id]
|
||||
|
||||
# And my tags should have been save
|
||||
OrderCycle.last.exchanges.outgoing.last.tag_list.should == ['wholesale']
|
||||
|
||||
# And it should have some variants selected
|
||||
selected_initial_variants = initial_variants.take initial_variants.size - 1
|
||||
OrderCycle.last.variants.map(&:id).should match_array (selected_initial_variants.map(&:id) + [v1.id, v2.id])
|
||||
|
||||
# And the collection details should have been updated
|
||||
OrderCycle.last.exchanges.where(pickup_time: 'New time 0', pickup_instructions: 'New instructions 0').should be_present
|
||||
OrderCycle.last.exchanges.where(pickup_time: 'New time 1', pickup_instructions: 'New instructions 1').should be_present
|
||||
end
|
||||
|
||||
|
||||
scenario "updating many order cycle opening/closing times at once", js: true do
|
||||
# Given three order cycles
|
||||
oc1 = create(:simple_order_cycle)
|
||||
@@ -907,8 +908,8 @@ feature %q{
|
||||
# Then my order cycle should have been created
|
||||
page.should have_content 'Your order cycle has been created.'
|
||||
page.should have_selector 'a', text: 'Plums & Avos'
|
||||
page.should have_selector "input[value='2040-10-17 06:00:00 +1100']"
|
||||
page.should have_selector "input[value='2040-10-24 17:00:00 +1100']"
|
||||
page.should have_selector "input[value='#{Time.zone.local(2040, 10, 17, 06, 00, 00)}']"
|
||||
page.should have_selector "input[value='#{Time.zone.local(2040, 10, 24, 17, 00, 00)}']"
|
||||
|
||||
# And it should have some variants selected
|
||||
oc = OrderCycle.last
|
||||
@@ -995,8 +996,8 @@ feature %q{
|
||||
# Then my order cycle should have been updated
|
||||
page.should have_content 'Your order cycle has been updated.'
|
||||
page.should have_selector 'a', text: 'Plums & Avos'
|
||||
page.should have_selector "input[value='2040-10-17 06:00:00 +1100']"
|
||||
page.should have_selector "input[value='2040-10-24 17:00:00 +1100']"
|
||||
page.should have_selector "input[value='#{Time.zone.local(2040, 10, 17, 06, 00, 00)}']"
|
||||
page.should have_selector "input[value='#{Time.zone.local(2040, 10, 24, 17, 00, 00)}']"
|
||||
|
||||
# And it should have a variant selected
|
||||
oc = OrderCycle.last
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user