Merging with master

This commit is contained in:
Will Marshall
2014-04-11 13:09:22 +10:00
34 changed files with 493 additions and 219 deletions

View File

@@ -1,3 +1,6 @@
[![Build Status](http://ci.openfood.com.au:8080/buildStatus/icon?job=openfoodweb - tests)](http://ci.openfood.com.au:8080/job/openfoodweb%20-%20tests/)
[![Code Climate](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork.png)](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork)
# Open Food Network
Connect suppliers (ie. farmers), distributors (ie. co-ops) and

View File

@@ -1,4 +1,4 @@
orderManagementModule = angular.module("ofn.bulk_order_management", ["ofn.shared_services", "ofn.shared_directives"])
orderManagementModule = angular.module("ofn.bulk_order_management", ["ofn.shared_services", "ofn.shared_directives", "ofn.dropdown"])
orderManagementModule.config [
"$httpProvider"
@@ -7,7 +7,7 @@ orderManagementModule.config [
]
orderManagementModule.value "blankOption", ->
{ id: "", name: "All" }
{ id: "0", name: "All" }
orderManagementModule.directive "ofnLineItemUpdAttr", [
"switchClass", "pendingChanges"
@@ -107,9 +107,8 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
($scope, $http, dataFetcher, blankOption, pendingChanges) ->
$scope.initialiseVariables = ->
now = new Date
start = new Date( now.getTime() - ( 7 * (1440 * 60 * 1000) ) - (now.getTime() - now.getTimezoneOffset() * 60 * 1000) % (1440 * 60 * 1000) )
end = new Date( now.getTime() - (now.getTime() - now.getTimezoneOffset() * 60 * 1000) % (1440 * 60 * 1000) + ( 1 * ( 1440 * 60 * 1000 ) ) )
start = daysFromToday -7
end = daysFromToday 1
$scope.lineItems = []
$scope.filteredLineItems = []
$scope.confirmDelete = true
@@ -117,16 +116,13 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
$scope.endDate = formatDate end
$scope.pendingChanges = pendingChanges
$scope.quickSearch = ""
$scope.bulkActions = [ { name: "Delete", callback: $scope.deleteLineItems } ]
$scope.bulkActions = [ { name: "Delete Selected", callback: $scope.deleteLineItems } ]
$scope.selectedBulkAction = $scope.bulkActions[0]
$scope.selectedUnitsProduct = {};
$scope.selectedUnitsVariant = {};
$scope.sharedResource = false
$scope.predicate = ""
$scope.reverse = false
$scope.optionTabs =
filters: { title: "Filter Line Items", visible: false }
column_toggle: { title: "Toggle Columns", visible: false }
$scope.columns =
order_no: { name: "Order No.", visible: false }
full_name: { name: "Name", visible: true }
@@ -134,6 +130,7 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
phone: { name: "Phone", visible: false }
order_date: { name: "Order Date", visible: true }
producer: { name: "Producer", visible: true }
order_cycle: { name: "Order Cycle", visible: false }
hub: { name: "Hub", visible: false }
variant: { name: "Variant", visible: true }
quantity: { name: "Quantity", visible: true }
@@ -150,16 +147,15 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
dataFetcher("/api/enterprises/managed?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
$scope.suppliers = data
$scope.suppliers.unshift blankOption()
$scope.supplierFilter = $scope.suppliers[0]
dataFetcher("/api/enterprises/managed?template=bulk_index&q[is_distributor_eq]=true").then (data) ->
$scope.distributors = data
$scope.distributors.unshift blankOption()
$scope.distributorFilter = $scope.distributors[0]
dataFetcher("/api/order_cycles/managed").then (data) ->
ocFetcher = dataFetcher("/api/order_cycles/managed").then (data) ->
$scope.orderCycles = data
$scope.orderCycles.unshift blankOption()
$scope.orderCycleFilter = $scope.orderCycles[0]
$scope.fetchOrders()
ocFetcher.then ->
$scope.resetSelectFilters()
else if authorise_api_reponse.hasOwnProperty("error")
$scope.api_error_msg = authorise_api_reponse("error")
else
@@ -167,7 +163,7 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
$scope.fetchOrders = ->
$scope.loading = true
dataFetcher("/api/orders?template=bulk_index&q[completed_at_not_null]=true&q[completed_at_gt]=#{$scope.startDate}&q[completed_at_lt]=#{$scope.endDate}").then (data) ->
dataFetcher("/api/orders/managed?template=bulk_index&q[completed_at_not_null]=true&q[completed_at_gt]=#{$scope.startDate}&q[completed_at_lt]=#{$scope.endDate}").then (data) ->
$scope.resetOrders data
$scope.loading = false
@@ -232,6 +228,11 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
sum = sum + lineItem.quantity * lineItem.units_variant.unit_value
, 0
$scope.sumMaxUnitValues = ->
sum = $scope.filteredLineItems.reduce (sum,lineItem) ->
sum = sum + Math.max(lineItem.max_quantity,lineItem.quantity) * lineItem.units_variant.unit_value
, 0
$scope.allUnitValuesPresent = ->
for i,lineItem of $scope.filteredLineItems
return false if !lineItem.units_variant.hasOwnProperty('unit_value') || !(lineItem.units_variant.unit_value > 0)
@@ -264,30 +265,31 @@ orderManagementModule.controller "AdminOrderMgmtCtrl", [
else
''
$scope.fulfilled = ->
$scope.fulfilled = (sumOfUnitValues) ->
# A Units Variant is an API object which holds unit properies of a variant
if $scope.selectedUnitsProduct.hasOwnProperty("group_buy_unit_size") && $scope.selectedUnitsProduct.group_buy_unit_size > 0 &&
$scope.selectedUnitsProduct.hasOwnProperty("variant_unit") &&
( $scope.selectedUnitsProduct.variant_unit == "weight" || $scope.selectedUnitsProduct.variant_unit == "volume" )
Math.round( $scope.sumUnitValues() / $scope.selectedUnitsProduct.group_buy_unit_size * 1000)/1000
Math.round( sumOfUnitValues / $scope.selectedUnitsProduct.group_buy_unit_size * 1000)/1000
else
''
$scope.unitsVariantSelected = ->
!angular.equals($scope.selectedUnitsVariant,{})
$scope.shiftTab = (tab) ->
$scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined
tab.visible = !tab.visible
$scope.visibleTab = tab
$scope.resetSelectFilters = ->
$scope.distributorFilter = $scope.distributors[0].id
$scope.supplierFilter = $scope.suppliers[0].id
$scope.orderCycleFilter = $scope.orderCycles[0].id
$scope.quickSearch = ""
]
orderManagementModule.filter "selectFilter", (blankOption) ->
return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
filtered = []
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,blankOption()) || lineItem.supplier.id == selectedSupplier.id) &&
(angular.equals(selectedDistributor,blankOption()) || lineItem.order.distributor.id == selectedDistributor.id) &&
(angular.equals(selectedOrderCycle,blankOption()) || lineItem.order.order_cycle.id == selectedOrderCycle.id)
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
(angular.equals(selectedDistributor,"0") || lineItem.order.distributor.id == selectedDistributor) &&
(angular.equals(selectedOrderCycle,"0") || lineItem.order.order_cycle.id == selectedOrderCycle)
filtered
orderManagementModule.filter "variantFilter", ->
@@ -326,14 +328,25 @@ orderManagementModule.factory "switchClass", [
, timeout, true)
]
daysFromToday = (days) ->
now = new Date
now.setHours(0)
now.setMinutes(0)
now.setSeconds(0)
now.setDate( now.getDate() + days )
now
formatDate = (date) ->
year = date.getFullYear()
month = twoDigitNumber date.getMonth() + 1
day = twoDigitNumber date.getDate()
return year + "-" + month + "-" + day
formatTime = (date) ->
hours = twoDigitNumber date.getHours()
mins = twoDigitNumber date.getMinutes()
secs = twoDigitNumber date.getSeconds()
return year + "-" + month + "-" + day + " " + hours + ":" + mins + ":" + secs
return hours + ":" + mins + ":" + secs
twoDigitNumber = (number) ->
twoDigits = "" + number

View File

@@ -259,11 +259,11 @@ productEditModule.controller "AdminProductEditCtrl", [
$scope.addVariant = (product) ->
product.variants.push
id: $scope.nextVariantId()
price: null
unit_value: null
unit_description: null
on_demand: false
on_hand: null
price: null
$scope.displayProperties[product.id].showVariants = true
@@ -358,7 +358,6 @@ productEditModule.controller "AdminProductEditCtrl", [
# conflicted with some changes I made before merging my work, so for now I've reverted to the old way of
# doing things. TODO: Review together and decide on strategy here. -- Rohan, 14-1-2014
#if subset($scope.productsWithoutDerivedAttributes(), data)
if $scope.productListsMatch $scope.products, data
$scope.resetProducts data
$timeout -> $scope.displaySuccess()

View File

@@ -0,0 +1,31 @@
dropDownModule = angular.module("ofn.dropdown", [])
dropDownModule.directive "ofnDropDown", ($document) ->
link: (scope, element, attrs) ->
outsideClickListener = (event) ->
unless $(event.target).is("div.ofn_drop_down##{attrs.id} div.menu") ||
$(event.target).parents("div.ofn_drop_down##{attrs.id} div.menu").length > 0
scope.$emit "offClick"
element.click (event) ->
if !scope.expanded
event.stopPropagation()
scope.deregistrationCallback = scope.$on "offClick", ->
$document.off "click", outsideClickListener
scope.$apply ->
scope.expanded = false
element.removeClass "expanded"
scope.deregistrationCallback()
$document.on "click", outsideClickListener
scope.$apply ->
scope.expanded = true
element.addClass "expanded"
dropDownModule.directive "ofnCloseOnClick", ($document) ->
link: (scope, element, attrs) ->
element.click (event) ->
event.stopPropagation()
scope.$emit "offClick"
dropDownModule.controller "DropDownCtrl", ($scope) ->
$scope.expanded = false

View File

@@ -1,39 +1,45 @@
sharedDirectivesModule = angular.module("ofn.shared_directives", [])
sharedDirectivesModule.directive "datetimepicker", [
"$parse"
($parse) ->
return (
require: "ngModel"
link: (scope, element, attrs, ngModel) ->
element.datetimepicker
dateFormat: "yy-mm-dd"
timeFormat: "HH:mm:ss"
stepMinute: 15
onSelect: (dateText, inst) ->
scope.$apply (scope) ->
# Fires ngModel.$parsers
ngModel.$setViewValue dateText
)
]
sharedDirectivesModule.directive "datetimepicker", ->
require: "ngModel"
link: (scope, element, attrs, ngModel) ->
element.datetimepicker
dateFormat: "yy-mm-dd"
timeFormat: "HH:mm:ss"
stepMinute: 15
onSelect: (dateText, inst) ->
scope.$apply (scope) ->
# Fires ngModel.$parsers
ngModel.$setViewValue dateText
sharedDirectivesModule.directive "ofnSelect2MinSearch", [
->
return (
link: (scope, element, attrs) ->
element.select2
minimumResultsForSearch: attrs.ofnSelect2MinSearch
)
]
sharedDirectivesModule.directive "datepicker", ->
require: "ngModel"
link: (scope, element, attrs, ngModel) ->
element.datepicker
dateFormat: "yy-mm-dd"
onSelect: (dateText, inst) ->
scope.$apply (scope) ->
# Fires ngModel.$parsers
ngModel.$setViewValue dateText
sharedDirectivesModule.directive "ofnSelect2MinSearch", ->
require: 'ngModel'
link: (scope, element, attrs, ngModel) ->
element.select2
minimumResultsForSearch: attrs.ofnSelect2MinSearch
ngModel.$formatters.push (value) ->
if (value)
element.select2('val', value);
sharedDirectivesModule.directive "ofnToggleColumn", ->
link: (scope, element, attrs) ->
element.addClass "unselected" unless scope.column.visible
element.addClass "selected" if scope.column.visible
element.click "click", ->
scope.$apply ->
if scope.column.visible
scope.column.visible = false
element.addClass "unselected"
element.removeClass "selected"
else
scope.column.visible = true
element.removeClass "unselected"
element.addClass "selected"

View File

@@ -1,5 +1,4 @@
window.AuthenticationActionsCtrl = Darkswarm.controller "AuthenticationActionsCtrl", ($scope, Navigation, storage) ->
$scope.toggleLogin = ->
Navigation.navigate "/login"

View File

@@ -138,3 +138,55 @@ table#listing_enterprise_groups {
}
}
.ofn_drop_down {
padding: 7px 15px;
border-radius: 3px;
border: 1px solid #d4d4d4;
background-color: #f5f5f5;
position: relative;
display: block;
float: left;
color: #828282;
cursor: pointer;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
text-align: center;
> span {
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
}
.menu {
margin-top: 1px;
position: absolute;
float: none;
top:100%;
left: 0px;
padding: 5px 0px;
border: 1px solid #adadad;
background-color: #ffffff;
box-shadow: 1px 3px 10px #888888;
.menu_item {
margin: 0px;
padding: 2px 0px;
color: #454545;
text-align: left;
}
.menu_item:hover {
background-color: #ededed;
}
}
}
.ofn_drop_down:hover, .ofn_drop_down.expanded {
border: 1px solid #adadad;
color: #575757;
}

View File

@@ -2,6 +2,12 @@
margin-bottom: 10px;
}
.filter_clear {
input {
background-color: #DA5354;
}
}
input.update-pending {
border: solid 1px orange;
}
@@ -20,7 +26,6 @@ input.update-success {
div#group_buy_calculation {
border-radius: 3px;
border:1px solid #5498da;
background-color: #eff5fc;
div {
margin-bottom: 5px;
@@ -28,4 +33,13 @@ div#group_buy_calculation {
padding: 5px;
}
}
hr {
width: 95%;
margin: 0 auto;
}
.row span {
text-align: center;
}
}

View File

@@ -80,9 +80,9 @@ li.column-list-item {
border-radius: 3px;
padding: 2px 20px;
margin: 2px 1px;
border: 2px solid #5498da;
background-color: #5498da;
color: white;
background-color: white;
border: 2px solid lightgray;
color: darkgray;
font-size: 100%;
cursor: default;
text-align: center;
@@ -94,10 +94,10 @@ li.column-list-item {
user-select: none;
}
li.column-list-item.unselected {
background-color: white;
border: 2px solid lightgray;
color: darkgray;
li.column-list-item.selected {
border: 2px solid #5498da;
background-color: #5498da;
color: white;
font-size: 100%;
}

View File

@@ -10,7 +10,7 @@ class Shop::ShopController < BaseController
def products
unless @products = current_order_cycle.andand
.valid_products_distributed_by(current_distributor).andand
.select { |p| p.has_stock_for_distribution?(current_order_cycle, current_distributor) }.andand
.select { |p| !p.deleted? && p.has_stock_for_distribution?(current_order_cycle, current_distributor) }.andand
.sort_by {|p| p.name }
render json: "", status: 404

View File

@@ -1,6 +1,11 @@
Spree::Admin::OrdersController.class_eval do
before_filter :load_spree_api_key, :only => :bulk_management
# We need to add expections for collection actions other than :index here
# because spree_auth_devise causes load_order to be called, which results
# in an auth failure as the @order object is nil for collection actions
before_filter :check_authorization, :except => :bulk_management
respond_override :index => { :html =>
{ :success => lambda {
# Filter orders to only show those distributed by current user (or all for admin user)

View File

@@ -0,0 +1,13 @@
Spree::Api::OrdersController.class_eval do
# We need to add expections for collection actions other than :index here
# because Spree's API controller causes authorize_read! to be called, which
# results in an ActiveRecord::NotFound Exception as the order object is not
# defined for collection actions
before_filter :authorize_read!, :except => [:managed]
def managed
@orders = Spree::Order.ransack(params[:q]).result.managed_by(current_api_user).page(params[:page]).per(params[:per_page])
respond_with(@orders, default_template: :index)
end
end

View File

@@ -23,7 +23,7 @@ class AbilityDecorator
# Enterprise User can only access orders that they are a distributor for
can [:index, :create], Spree::Order
can [:admin, :read, :update, :fire, :resend], Spree::Order do |order|
can [:admin, :read, :update, :bulk_management, :fire, :resend], Spree::Order do |order|
# We allow editing orders with a nil distributor as this state occurs
# during the order creation process from the admin backend
order.distributor.nil? || user.enterprises.include?(order.distributor)

View File

@@ -1,6 +1,6 @@
module Spree
Adjustment.class_eval do
has_one :metadata, class_name: 'AdjustmentMetadata'
has_one :metadata, class_name: 'AdjustmentMetadata', dependent: :destroy
scope :enterprise_fee, where(originator_type: 'EnterpriseFee')
end

View File

@@ -85,6 +85,7 @@ Spree::Order.class_eval do
def set_order_cycle!(order_cycle)
self.order_cycle = order_cycle
self.distributor = nil unless order_cycle.nil? || order_cycle.has_distributor?(distributor)
self.empty!
save!
end

View File

@@ -155,4 +155,4 @@
.omega.four.columns
= image_tag @object.promo_image.url if @object.promo_image.present?
= f.file_field :pro_image
= f.file_field :promo_image

View File

@@ -9,7 +9,7 @@ r.element :order_cycle, @order_cycle do
r.element :id
end
r.list_of :exchanges do |exchange|
r.list_of :exchanges, @order_cycle.exchanges.order('id ASC') do |exchange|
r.element :id
r.element :sender_id
r.element :receiver_id

View File

@@ -6,78 +6,97 @@
%div{ 'ng-app' => 'ofn.bulk_order_management', 'ng-controller' => 'AdminOrderMgmtCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
%div{ 'ng-show' => '!spree_api_key_ok' }
{{ api_error_msg }}
.option_tab_titles{ :class => "sixteen columns alpha" }
%h6{ :class => "three columns alpha", 'ng-repeat' => "tab in optionTabs", "ng-click" => "shiftTab(tab)", "ng-class" => "tab.visible && 'selected' || !tab.visible && 'unselected'"}
{{ tab.title }}
.filters{ :class => "nine columns alpha", 'ng-show' => 'optionTabs.filters.visible' }
.row{ :class => "six columns alpha" }
.date_filter{ :class => "three columns alpha" }
%label{ :for => 'start_date_filter' }Start Date
%br
%input{ :class => "three columns alpha", :type => "text", :id => 'start_date_filter', 'ng-model' => 'startDate', 'datetimepicker' => "startDate", 'ofn-confirm-change' => "startDate" }
.date_filter{ :class => "three columns alpha" }
%label{ :for => 'end_date_filter' }End Date
%br
%input{ :class => "three columns alpha", :type => "text", :id => 'end_date_filter', 'ng-model' => 'endDate', 'datetimepicker' => "endDate", 'ofn-confirm-change' => "endDate" }
.row{ :class => "nine columns alpha" }
.filter_select{ :class => "three columns alpha" }
%label{ :for => 'supplier_filter' }Producer
%br
%select{ :class => "three columns alpha", :id => 'supplier_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'supplierFilter', 'ng-options' => 's.name for s in suppliers' }
.filter_select{ :class => "three columns alpha" }
%label{ :for => 'distributor_filter' }Hub
%br
%select{ :class => "three columns alpha", :id => 'distributor_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'distributorFilter', 'ng-options' => 'd.name for d in distributors'}
.filter_select{ :class => "three columns alpha" }
%label{ :for => 'order_cycle_filter' }Order Cycle
%br
%select{ :class => "three columns alpha", :id => 'order_cycle_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'orderCycleFilter', 'ng-options' => 'oc.name for oc in orderCycles'}
.column_toggle{ :class => "nine columns alpha", "ng-show" => 'optionTabs.column_toggle.visible' }
%ul.column-list{ :class => "nine columns alpha" }
%li.column-list-item{ :class => "three columns alpha", 'ofn-toggle-column' => 'column', 'ng-repeat' => 'column in columns' }
{{ column.name }}
%div{ :class => "nine columns alpha", 'ng-show' => '!optionTabs.filters.visible && !optionTabs.column_toggle.visible && unitsVariantSelected()' } &nbsp;.
%div#group_buy_calculation{ :class => "seven columns alpha", 'ng-show' => 'unitsVariantSelected()' }
%div{ :class => "seven columns alpha" }
%h6{ :class => "five columns alpha", 'ng-show' => 'sharedResource' } {{ selectedUnitsProduct.name + ": ALL" }}
%h6{ :class => "five columns alpha", 'ng-hide' => 'sharedResource' } {{ selectedUnitsVariant.unit_text }}
%h6{ :class => "two column omega" }
%a{ 'ng-click' => 'selectedUnitsVariant = {};selectedUnitsProduct = {}' } Clear
%div{ :class => "seven columns alpha" }
%span{ :class => "five columns alpha" }
Group Buy Unit Size
%span{ :class => "two columns omega" }
{{ formattedValueWithUnitName( selectedUnitsProduct.group_buy_unit_size, selectedUnitsProduct, selectedUnitsVariant ) }}
%div{ :class => "seven columns alpha" }
%span{ :class => "five columns alpha" }
Fulfilled Units
%span{ :class => "two columns omega" }
{{ fulfilled() }}
%div{ :class => "seven columns alpha" }
%span{ :class => "five columns alpha" }
Total Units Ordered
%span{ :class => "two columns omega" }
{{ formattedValueWithUnitName( sumUnitValues(), selectedUnitsProduct, selectedUnitsVariant ) }}
%div.shared_resource{ :class => "seven columns alpha" }
%span{ :class => "five columns alpha" } Shared Resource?
%span{ :class => 'two columns omega' }
.filters{ :class => "sixteen columns alpha" }
.date_filter{ :class => "two columns alpha" }
%label{ :for => 'start_date_filter' }Start Date
%br
%input{ :class => "two columns alpha", :type => "text", :id => 'start_date_filter', 'ng-model' => 'startDate', 'datepicker' => "startDate", 'ofn-confirm-change' => "startDate" }
.date_filter{ :class => "two columns" }
%label{ :for => 'end_date_filter' }End Date
%br
%input{ :class => "two columns alpha", :type => "text", :id => 'end_date_filter', 'ng-model' => 'endDate', 'datepicker' => "endDate", 'ofn-confirm-change' => "endDate" }
.one.column &nbsp;
.filter_select{ :class => "three columns" }
%label{ :for => 'supplier_filter' }Producer
%br
%select{ :class => "three columns alpha", :id => 'supplier_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'supplierFilter', 'ng-options' => 's.id as s.name for s in suppliers' }
.filter_select{ :class => "three columns" }
%label{ :for => 'distributor_filter' }Hub
%br
%select{ :class => "three columns alpha", :id => 'distributor_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'distributorFilter', 'ng-options' => 'd.id as d.name for d in distributors'}
.filter_select{ :class => "three columns" }
%label{ :for => 'order_cycle_filter' }Order Cycle
%br
%select{ :class => "three columns alpha", :id => 'order_cycle_filter', 'ofn-select2-min-search' => 5, 'ng-model' => 'orderCycleFilter', 'ng-options' => 'oc.id as oc.name for oc in orderCycles'}
.filter_clear{ :class => "two columns omega" }
%label{ :for => 'clear_all_filters' }
%br
%input.fullwidth{ :type => 'button', :id => 'clear_all_filters', :value => "Clear All", 'ng-click' => "resetSelectFilters()" }
%hr{ :class => "sixteen columns alpha", 'ng-show' => 'unitsVariantSelected()' }
%div#group_buy_calculation{ :class => "sixteen columns alpha", 'ng-show' => 'unitsVariantSelected()' }
%div.shared_resource{ :class => "four columns alpha" }
%span{ :class => 'three columns alpha' }
%input{ type: 'checkbox', :id => 'shared_resource', 'ng-model' => 'sharedResource'}
%div{ :class => "seven columns alpha", 'ng-hide' => 'allUnitValuesPresent()' }
%span{ :class => "seven columns alpha", style: 'color:red' }
Shared Resource?
%div{ :class => "eight columns" }
%h6{ :class => "eight columns alpha", 'ng-show' => 'sharedResource', style: 'text-align: center;' } {{ selectedUnitsProduct.name + ": ALL" }}
%h6{ :class => "eight columns alpha", 'ng-hide' => 'sharedResource', style: 'text-align: center;' } {{ selectedUnitsVariant.unit_text }}
%div{ :class => "four columns omega" }
%h6{ :class => "four columns alpha", :style => 'text-align: right;' }
%a{ 'ng-click' => 'selectedUnitsVariant = {};selectedUnitsProduct = {};sharedResource=false;' } Clear
%hr
.row
.one.column.alpha &nbsp;
.two.columns
%span.two.columns Group Buy Unit Size
%span.two.columns {{ formattedValueWithUnitName( selectedUnitsProduct.group_buy_unit_size, selectedUnitsProduct, selectedUnitsVariant ) }}
.one.column &nbsp;
.two.columns
%span.two.columns Total Quantity Ordered
%span.two.columns {{ formattedValueWithUnitName( sumUnitValues(), selectedUnitsProduct, selectedUnitsVariant ) }}
.one.column &nbsp;
.two.columns
%span.two.columns Max Quantity Ordered
%span.two.columns {{ formattedValueWithUnitName( sumMaxUnitValues(), selectedUnitsProduct, selectedUnitsVariant ) }}
.one.column &nbsp;
.two.columns
%span.two.columns Current Fulfilled Units
%span.two.columns {{ fulfilled(sumUnitValues()) }}
.one.column &nbsp;
.two.columns
%span.two.columns Max Fulfilled Units
%span.two.columns {{ fulfilled(sumMaxUnitValues()) }}
.one.column.omega &nbsp;
%div{ :class => "eight columns alpha", 'ng-hide' => 'allUnitValuesPresent()' }
%span{ :class => "eight columns alpha", style: 'color:red' }
WARNING: Some variants do not have a unit value
%hr{ :class => "sixteen columns alpha", :style => "margin-bottom: 15px" }
%div.loading{ :class => "sixteen columns alpha", 'ng-show' => 'loading' }
%h4 Loading Line Items...
%div{ :class => "sixteen columns alpha", 'ng-show' => '!loading && lineItems.length == 0'}
%h4{ :style => 'color:red;' } No matching line items found.
%div{ 'ng-hide' => 'loading || lineItems.length == 0' }
.controls{ :class => "sixteen columns alpha", :style => "margin-bottom: 15px;" }
%input{ :class => "three columns alpha", :type => "text", :id => 'quick_search', 'ng-model' => 'quickSearch', :placeholder => 'Quick Search' }
%div{ :class => "three columns alpha" }
%select{ :class => "three columns alpha", :id => 'bulk_actions', 'ofn-select2-min-search' => 10, 'ng-model' => 'selectedBulkAction', 'ng-options' => 'a as a.name for a in bulkActions' }
%div{ :class => "three columns alpha" }
%input{ :class => "three columns alpha", :value => "Run", :type => "button", :id => 'bulk_execute', 'ng-click' => 'selectedBulkAction.callback(filteredLineItems)' }
%table.index#listing_orders.bulk
%input{ :class => "fullwidth", :type => "text", :id => 'quick_search', 'ng-model' => 'quickSearch', :placeholder => 'Quick Search' }
%div{ :class => "three columns" }
%div.ofn_drop_down{ 'ng-controller' => "DropDownCtrl", :id => "bulk_actions_dropdown", 'ofn-drop-down' => true }
%span{ :class => 'icon-check' } &nbsp; Actions
%span{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
%div.menu{ 'ng-show' => "expanded" }
%div.menu_item{ :class => "three columns alpha", 'ng-repeat' => "action in bulkActions", 'ng-click' => "selectedBulkAction.callback(filteredLineItems)", 'ofn-close-on-click' => true }
%span{ :class => 'three columns omega' } {{action.name }}
%div{ :class => "seven columns" } &nbsp;
%div{ :class => "three columns omega" }
%div.ofn_drop_down{ 'ng-controller' => "DropDownCtrl", :id => "columns_dropdown", 'ofn-drop-down' => true, :style => 'float:right;' }
%span{ :class => 'icon-reorder' } &nbsp; Columns
%span{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
%div.menu{ 'ng-show' => "expanded" }
%div.menu_item{ :class => "three columns alpha", 'ng-repeat' => "column in columns", 'ofn-toggle-column' => true }
%span{ :class => 'one column alpha', :style => 'text-align: center'} {{ column.visible && "&#10003;" || !column.visible && "&nbsp;" }}
%span{ :class => 'two columns omega' } {{column.name }}
%div.loading{ :class => "sixteen columns alpha", 'ng-show' => 'loading' }
%h4 Loading Line Items...
%div{ :class => "sixteen columns alpha", 'ng-show' => '!loading && filteredLineItems.length == 0'}
%h4{ :style => 'color:red;' } No matching line items found.
%div{ 'ng-hide' => 'loading || filteredLineItems.length == 0' }
%table.index#listing_orders.bulk{ :class => "sixteen columns alpha" }
%thead
%tr
%th.bulk
@@ -94,6 +113,8 @@
%a{ :href => '', 'ng-click' => "predicate = 'order.completed_at'; reverse = !reverse" } Order Date
%th.producer{ 'ng-show' => 'columns.producer.visible' }
%a{ :href => '', 'ng-click' => "predicate = 'supplier.name'; reverse = !reverse" } Producer
%th.order_cycle{ 'ng-show' => 'columns.order_cycle.visible' }
%a{ :href => '', 'ng-click' => "predicate = 'order.order_cycle.name'; reverse = !reverse" } Order Cycle
%th.hub{ 'ng-show' => 'columns.hub.visible' }
%a{ :href => '', 'ng-click' => "predicate = 'order.distributor.name'; reverse = !reverse" } Hub
%th.variant{ 'ng-show' => 'columns.variant.visible' }
@@ -112,12 +133,13 @@
%td.phone{ 'ng-show' => 'columns.phone.visible' } {{ line_item.order.phone }}
%td.date{ 'ng-show' => 'columns.order_date.visible' } {{ line_item.order.completed_at }}
%td.producer{ 'ng-show' => 'columns.producer.visible' } {{ line_item.supplier.name }}
%td.order_cycle{ 'ng-show' => 'columns.order_cycle.visible' } {{ line_item.order.order_cycle.name }}
%td.hub{ 'ng-show' => 'columns.hub.visible' } {{ line_item.order.distributor.name }}
%td.variant{ 'ng-show' => 'columns.variant.visible' }
%a{ 'ng-click' => "setSelectedUnitsVariant(line_item.units_product,line_item.units_variant)" } {{ line_item.units_variant.unit_text }}
%td.quantity{ 'ng-show' => 'columns.quantity.visible' }
%input{ :type => 'number', :name => 'quantity', 'ng-model' => "line_item.quantity", 'ofn-line-item-upd-attr' => "quantity" }
%td.max{ 'ng-show' => 'columns.max.visible' } {{ line_item.max }}
%td.max{ 'ng-show' => 'columns.max.visible' } {{ line_item.max_quantity }}
%td.actions
%a{ 'ng-click' => "deleteLineItem(line_item)", :class => "delete-line-item icon-trash no-text" }
%input{ :type => "button", 'value' => 'Update', 'ng-click' => 'pendingChanges.submitAll()' }

View File

@@ -24,11 +24,11 @@
%div{ :class => "four columns alpha" }
Column:
%br.clear
%select.select2.fullwidth{ 'ng-model' => 'filterProperty', :id => "filter_property", 'ng-options' => 'fc.name for fc in filterableColumns' }
%select.fullwidth{ 'ng-model' => 'filterProperty', :id => "filter_property", 'ng-options' => 'fc.name for fc in filterableColumns', 'ofn-select2-min-search' => 10 }
%div{ :class => "four columns omega" }
Filter Type:
%br.clear
%select.select2.fullwidth{ 'ng-model' => 'filterPredicate', :id => "filter_predicate", 'ng-options' => 'ft.name for ft in filterTypes' }
%select.fullwidth{ 'ng-model' => 'filterPredicate', :id => "filter_predicate", 'ng-options' => 'ft.name for ft in filterTypes', 'ofn-select2-min-search' => 10 }
%div{ :class => "six columns omega" }
Value:
%br.clear

View File

@@ -1,6 +1,7 @@
object @variant
attributes :id, :price, :options_text, :unit_value, :unit_description, :on_demand
attributes :id, :options_text, :unit_value, :unit_description, :on_demand
# Infinity is not a valid JSON object, but Rails encodes it anyway
node( :on_hand ) { |v| v.on_hand.to_f.finite? ? v.on_hand : "On demand" }
node( :on_hand ) { |v| v.on_hand.nil? ? 0 : ( v.on_hand.to_f.finite? ? v.on_hand : "On demand" ) }
node( :price ) { |v| v.price.nil? ? 0.to_f : v.price }

View File

@@ -24,7 +24,7 @@ Payment Details
<% end %>
<%- if @order.shipping_method.require_ship_address %>
<%- if @order.shipping_method.andand.require_ship_address %>
============================================================
Shipping Details
============================================================

View File

@@ -15,6 +15,7 @@ module.exports = function(config) {
'app/assets/javascripts/admin/shared_directives.js.coffee',
'app/assets/javascripts/admin/shared_services.js.coffee',
'app/assets/javascripts/admin/dropdown.js.coffee',
'app/assets/javascripts/admin/order_cycle.js.erb.coffee',
'app/assets/javascripts/admin/bulk_order_management.js.coffee',
'app/assets/javascripts/admin/bulk_product_update.js.coffee',

View File

@@ -104,6 +104,10 @@ Spree::Core::Engine.routes.prepend do
get :managed, on: :collection
end
resources :orders do
get :managed, on: :collection
end
resources :enterprises do
get :managed, on: :collection
end

View File

@@ -0,0 +1,38 @@
class AddMissingIndexes < ActiveRecord::Migration
def change
add_index :adjustment_metadata, :enterprise_id
add_index :carts, :user_id
add_index :coordinator_fees, :order_cycle_id
add_index :coordinator_fees, :enterprise_fee_id
add_index :distributors_payment_methods, :distributor_id
add_index :distributors_payment_methods, :payment_method_id
add_index :enterprise_fees, :enterprise_id
add_index :enterprise_groups_enterprises, :enterprise_group_id
add_index :enterprise_groups_enterprises, :enterprise_id
add_index :enterprise_roles, :user_id
add_index :enterprise_roles, :enterprise_id
add_index :enterprises, :address_id
add_index :exchange_fees, :exchange_id
add_index :exchange_fees, :enterprise_fee_id
add_index :exchange_variants, :exchange_id
add_index :exchange_variants, :variant_id
add_index :exchanges, :order_cycle_id
add_index :exchanges, :sender_id
add_index :exchanges, :receiver_id
add_index :exchanges, :payment_enterprise_id
add_index :product_distributions, :product_id
add_index :product_distributions, :distributor_id
add_index :product_distributions, :enterprise_fee_id
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20140324025840) do
ActiveRecord::Schema.define(:version => 20140402032034) do
create_table "adjustment_metadata", :force => true do |t|
t.integer "adjustment_id"
@@ -22,11 +22,14 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
end
add_index "adjustment_metadata", ["adjustment_id"], :name => "index_adjustment_metadata_on_adjustment_id"
add_index "adjustment_metadata", ["enterprise_id"], :name => "index_adjustment_metadata_on_enterprise_id"
create_table "carts", :force => true do |t|
t.integer "user_id"
end
add_index "carts", ["user_id"], :name => "index_carts_on_user_id"
create_table "cms_blocks", :force => true do |t|
t.integer "page_id", :null => false
t.string "identifier", :null => false
@@ -149,11 +152,17 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.integer "enterprise_fee_id"
end
add_index "coordinator_fees", ["enterprise_fee_id"], :name => "index_coordinator_fees_on_enterprise_fee_id"
add_index "coordinator_fees", ["order_cycle_id"], :name => "index_coordinator_fees_on_order_cycle_id"
create_table "distributors_payment_methods", :id => false, :force => true do |t|
t.integer "distributor_id"
t.integer "payment_method_id"
end
add_index "distributors_payment_methods", ["distributor_id"], :name => "index_distributors_payment_methods_on_distributor_id"
add_index "distributors_payment_methods", ["payment_method_id"], :name => "index_distributors_payment_methods_on_payment_method_id"
create_table "distributors_shipping_methods", :id => false, :force => true do |t|
t.integer "distributor_id"
t.integer "shipping_method_id"
@@ -170,6 +179,8 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "updated_at", :null => false
end
add_index "enterprise_fees", ["enterprise_id"], :name => "index_enterprise_fees_on_enterprise_id"
create_table "enterprise_groups", :force => true do |t|
t.string "name"
t.boolean "on_front_page"
@@ -181,11 +192,17 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.integer "enterprise_id"
end
add_index "enterprise_groups_enterprises", ["enterprise_group_id"], :name => "index_enterprise_groups_enterprises_on_enterprise_group_id"
add_index "enterprise_groups_enterprises", ["enterprise_id"], :name => "index_enterprise_groups_enterprises_on_enterprise_id"
create_table "enterprise_roles", :force => true do |t|
t.integer "user_id"
t.integer "enterprise_id"
end
add_index "enterprise_roles", ["enterprise_id"], :name => "index_enterprise_roles_on_enterprise_id"
add_index "enterprise_roles", ["user_id"], :name => "index_enterprise_roles_on_user_id"
create_table "enterprises", :force => true do |t|
t.string "name"
t.string "description"
@@ -215,6 +232,8 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "promo_image_updated_at"
end
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
create_table "exchange_fees", :force => true do |t|
t.integer "exchange_id"
t.integer "enterprise_fee_id"
@@ -222,6 +241,9 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "updated_at", :null => false
end
add_index "exchange_fees", ["enterprise_fee_id"], :name => "index_exchange_fees_on_enterprise_fee_id"
add_index "exchange_fees", ["exchange_id"], :name => "index_exchange_fees_on_exchange_id"
create_table "exchange_variants", :force => true do |t|
t.integer "exchange_id"
t.integer "variant_id"
@@ -229,6 +251,9 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.datetime "updated_at", :null => false
end
add_index "exchange_variants", ["exchange_id"], :name => "index_exchange_variants_on_exchange_id"
add_index "exchange_variants", ["variant_id"], :name => "index_exchange_variants_on_variant_id"
create_table "exchanges", :force => true do |t|
t.integer "order_cycle_id"
t.integer "sender_id"
@@ -241,6 +266,11 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.boolean "incoming", :default => false, :null => false
end
add_index "exchanges", ["order_cycle_id"], :name => "index_exchanges_on_order_cycle_id"
add_index "exchanges", ["payment_enterprise_id"], :name => "index_exchanges_on_payment_enterprise_id"
add_index "exchanges", ["receiver_id"], :name => "index_exchanges_on_receiver_id"
add_index "exchanges", ["sender_id"], :name => "index_exchanges_on_sender_id"
create_table "landing_page_images", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
@@ -267,6 +297,10 @@ ActiveRecord::Schema.define(:version => 20140324025840) do
t.integer "enterprise_fee_id"
end
add_index "product_distributions", ["distributor_id"], :name => "index_product_distributions_on_distributor_id"
add_index "product_distributions", ["enterprise_fee_id"], :name => "index_product_distributions_on_enterprise_fee_id"
add_index "product_distributions", ["product_id"], :name => "index_product_distributions_on_product_id"
create_table "spree_activators", :force => true do |t|
t.string "description"
t.datetime "expires_at"

View File

@@ -24,7 +24,7 @@ module Spree
context "as a normal user" do
before :each do
spree_get :index, { :template => 'bulk_index', :format => :json }
spree_get :managed, { :template => 'bulk_index', :format => :json }
end
it "retrieves a list of orders with appropriate attributes, including line items with appropriate attributes" do

View File

@@ -161,43 +161,10 @@ feature %q{
let!(:o1) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now ) }
let!(:li1) { FactoryGirl.create(:line_item, order: o1, :quantity => 5 ) }
context "using tabs to hide and display page controls" do
it "shows a column display toggle button, which shows a list of columns when clicked" do
visit '/admin/orders/bulk_management'
page.should have_selector "div.column_toggle", :visible => false
page.should have_selector "div.option_tab_titles h6.unselected", :text => "Toggle Columns"
first("div.option_tab_titles h6", :text => "Toggle Columns").click
page.should have_selector "div.option_tab_titles h6.selected", :text => "Toggle Columns"
page.should have_selector "div.column_toggle", :visible => true
page.should have_selector "li.column-list-item", text: "Producer"
page.should have_selector "div.filters", :visible => false
page.should have_selector "div.option_tab_titles h6.unselected", :text => "Filter Line Items"
first("div.option_tab_titles h6", :text => "Filter Line Items").click
page.should have_selector "div.option_tab_titles h6.unselected", :text => "Toggle Columns"
page.should have_selector "div.option_tab_titles h6.selected", :text => "Filter Line Items"
page.should have_selector "div.filters", :visible => true
first("div.option_tab_titles h6", :text => "Filter Line Items").click
page.should have_selector "div.option_tab_titles h6.unselected", :text => "Filter Line Items"
page.should have_selector "div.option_tab_titles h6.unselected", :text => "Toggle Columns"
page.should have_selector "div.filters", :visible => false
page.should have_selector "div.column_toggle", :visible => false
end
end
context "using column display toggle" do
it "shows a column display toggle button, which shows a list of columns when clicked" do
visit '/admin/orders/bulk_management'
first("div.option_tab_titles h6", :text => "Toggle Columns").click
page.should have_selector "th", :text => "NAME"
page.should have_selector "th", :text => "ORDER DATE"
page.should have_selector "th", :text => "PRODUCER"
@@ -205,10 +172,8 @@ feature %q{
page.should have_selector "th", :text => "QUANTITY"
page.should have_selector "th", :text => "MAX"
page.should have_selector "div.option_tab_titles h6", :text => "Toggle Columns"
page.should have_selector "div ul.column-list li.column-list-item", text: "Producer"
first("li.column-list-item", text: "Producer").click
first("div#columns_dropdown", :text => "COLUMNS").click
first("div#columns_dropdown div.menu div.menu_item", text: "Producer").click
page.should_not have_selector "th", :text => "PRODUCER"
page.should have_selector "th", :text => "NAME"
@@ -235,7 +200,6 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
first("div.option_tab_titles h6", :text => "Filter Line Items").click
end
it "displays a select box for producers, which filters line items by the selected supplier" do
@@ -320,6 +284,21 @@ feature %q{
page.should_not have_selector "tr#li_#{li1.id}", visible: true
page.should have_selector "tr#li_#{li2.id}", visible: true
end
it "displays a 'Clear All' button which sets all select filters to 'All'" do
select2_select oc1.name, from: "order_cycle_filter"
select2_select d1.name, from: "distributor_filter"
select2_select s1.name, from: "supplier_filter"
page.should have_selector "tr#li_#{li1.id}", visible: true
page.should_not have_selector "tr#li_#{li2.id}", visible: true
page.should have_button "Clear All"
click_button "Clear All"
page.should have_selector "div#s2id_order_cycle_filter a.select2-choice", text: "All"
page.should have_selector "div#s2id_supplier_filter a.select2-choice", text: "All"
page.should have_selector "div#s2id_distributor_filter a.select2-choice", text: "All"
page.should have_selector "tr#li_#{li1.id}", visible: true
page.should have_selector "tr#li_#{li2.id}", visible: true
end
end
context "using quick search" do
@@ -359,12 +338,11 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
first("div.option_tab_titles h6", :text => "Filter Line Items").click
end
it "displays date fields for filtering orders, with default values set" do
one_week_ago = (Date.today - 7).strftime("%F %T")
tonight = Date.tomorrow.strftime("%F %T")
one_week_ago = Date.today.prev_day(7).strftime("%F")
tonight = Date.tomorrow.strftime("%F")
page.should have_field "start_date_filter", with: one_week_ago
page.should have_field "end_date_filter", with: tonight
end
@@ -376,12 +354,12 @@ feature %q{
end
it "displays only line items whose orders meet the date restriction criteria, when changed" do
fill_in "start_date_filter", :with => (Date.today - 9).strftime("%F %T")
fill_in "start_date_filter", :with => (Date.today - 9).strftime("%F")
page.should have_selector "tr#li_#{li1.id}", visible: true
page.should have_selector "tr#li_#{li2.id}", visible: true
page.should_not have_selector "tr#li_#{li3.id}", visible: true
fill_in "end_date_filter", :with => (Date.today + 3).strftime("%F %T")
fill_in "end_date_filter", :with => (Date.today + 3).strftime("%F")
page.should have_selector "tr#li_#{li1.id}", visible: true
page.should have_selector "tr#li_#{li2.id}", visible: true
page.should have_selector "tr#li_#{li3.id}", visible: true
@@ -447,13 +425,11 @@ feature %q{
end
it "displays a bulk action select box with a list of actions" do
list_of_actions = ['Delete']
find("div.select2-container#s2id_bulk_actions").click
list_of_actions.each { |a| page.should have_selector "div.select2-drop-active ul.select2-results li", text: a }
end
it "displays a bulk action button" do
page.should have_button "bulk_execute"
list_of_actions = ['Delete Selected']
find("div#bulk_actions_dropdown").click
within("div#bulk_actions_dropdown") do
list_of_actions.each { |action_name| page.should have_selector "div.menu_item", text: action_name }
end
end
context "performing actions" do
@@ -463,8 +439,8 @@ feature %q{
within("tr#li_#{li2.id} td.bulk") do
check "bulk"
end
select2_select "Delete", :from => "bulk_actions"
click_button "bulk_execute"
find("div#bulk_actions_dropdown").click
find("div#bulk_actions_dropdown div.menu_item", :text => "Delete Selected" ).click
page.should have_selector "tr#li_#{li1.id}", visible: true
page.should_not have_selector "tr#li_#{li2.id}", visible: true
end
@@ -483,8 +459,8 @@ feature %q{
it "only applies the delete action to filteredLineItems" do
check "toggle_bulk"
fill_in "quick_search", with: o1.number
select2_select "Delete", :from => "bulk_actions"
click_button "bulk_execute"
find("div#bulk_actions_dropdown").click
find("div#bulk_actions_dropdown div.menu_item", :text => "Delete Selected" ).click
fill_in "quick_search", with: ''
page.should_not have_selector "tr#li_#{li1.id}", visible: true
page.should have_selector "tr#li_#{li2.id}", visible: true
@@ -525,8 +501,8 @@ feature %q{
let!(:p3) { FactoryGirl.create(:product_with_option_types, group_buy: true, group_buy_unit_size: 5000, variant_unit: "weight", variants: [FactoryGirl.create(:variant, unit_value: 1000)] ) }
let!(:v3) { p3.variants.first }
let!(:o3) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now ) }
let!(:li3) { FactoryGirl.create(:line_item, order: o3, variant: v3, quantity: 3 ) }
let!(:li4) { FactoryGirl.create(:line_item, order: o2, variant: v3, quantity: 1 ) }
let!(:li3) { FactoryGirl.create(:line_item, order: o3, variant: v3, quantity: 3, max_quantity: 6 ) }
let!(:li4) { FactoryGirl.create(:line_item, order: o2, variant: v3, quantity: 1, max_quantity: 3 ) }
before :each do
visit '/admin/orders/bulk_management'
@@ -539,12 +515,16 @@ feature %q{
page.should have_selector "div#group_buy_calculation", :visible => true
within "div#group_buy_calculation" do
page.should have_text "Group Buy Unit"
page.should have_text "Group Buy Unit Size"
page.should have_text "5 kg"
page.should have_text "Fulfilled Units"
page.should have_text "0.8"
page.should have_text "Total Units Ordered"
page.should have_text "Total Quantity Ordered"
page.should have_text "4 kg"
page.should have_text "Max Quantity Ordered"
page.should have_text "9 kg"
page.should have_text "Current Fulfilled Units"
page.should have_text "0.8"
page.should have_text "Max Fulfilled Units"
page.should have_text "1.8"
page.should have_selector "div.shared_resource", :visible => true
within "div.shared_resource" do
page.should have_selector "span", :text => "Shared Resource?"
@@ -575,4 +555,30 @@ feature %q{
end
end
end
context "as an enterprise manager" do
let(:s1) { create(:supplier_enterprise, name: 'First Supplier') }
let(:s2) { create(:supplier_enterprise, name: 'Another Supplier') }
let(:d1) { create(:distributor_enterprise, name: 'First Distributor') }
let(:d2) { create(:distributor_enterprise, name: 'Another Distributor') }
let!(:o1) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now, distributor: d1 ) }
let!(:o2) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now, distributor: d2 ) }
let!(:line_item_distributed) { FactoryGirl.create(:line_item, order: o1 ) }
let!(:line_item_not_distributed) { FactoryGirl.create(:line_item, order: o2 ) }
before(:each) do
@enterprise_user = create_enterprise_user
@enterprise_user.enterprise_roles.build(enterprise: s1).save
@enterprise_user.enterprise_roles.build(enterprise: d1).save
login_to_admin_as @enterprise_user
end
it "shows only line item from orders that I supply" do
visit '/admin/orders/bulk_management'
page.should have_selector "tr#li_#{line_item_distributed.id}", :visible => true
page.should_not have_selector "tr#li_#{line_item_not_distributed.id}", :visible => true
end
end
end

View File

@@ -141,9 +141,9 @@ feature %q{
page.should have_selector 'td.distributors', text: 'My distributor'
# And it should have some fees
OrderCycle.last.exchanges.first.enterprise_fees.should == [supplier_fee]
OrderCycle.last.coordinator_fees.should == [coordinator_fee]
OrderCycle.last.exchanges.last.enterprise_fees.should == [distributor_fee]
OrderCycle.last.exchanges.incoming.first.enterprise_fees.should == [supplier_fee]
OrderCycle.last.coordinator_fees.should == [coordinator_fee]
OrderCycle.last.exchanges.outgoing.first.enterprise_fees.should == [distributor_fee]
# And it should have some variants selected
OrderCycle.last.exchanges.first.variants.count.should == 2

View File

@@ -58,7 +58,6 @@ feature "enterprises distributor info as rich text" do
end
scenario "viewing distributor info with product distribution", js: true do
ActionMailer::Base.deliveries.clear
d = create(:distributor_enterprise, distributor_info: 'Chu ge sai yubi dan <strong>bisento</strong> tobi ashi yubi ge omote.', next_collection_at: 'Thursday 2nd May')
p = create(:product, :distributors => [d])
@@ -67,6 +66,7 @@ feature "enterprises distributor info as rich text" do
login_to_consumer_section
visit spree.select_distributor_order_path(d)
ActionMailer::Base.deliveries.clear
# -- Product details page
visit spree.product_path p
@@ -110,6 +110,7 @@ feature "enterprises distributor info as rich text" do
setup_shipping_details d
login_to_consumer_section
ActionMailer::Base.deliveries.clear
click_link 'Green Grass'
visit enterprise_path d
@@ -146,7 +147,7 @@ feature "enterprises distributor info as rich text" do
zone = create(:zone)
c = Spree::Country.find_by_name('Australia')
Spree::ZoneMember.create(:zoneable => c, :zone => zone)
create(:shipping_method, zone: zone)
create(:shipping_method, zone: zone, require_ship_address: false)
create(:payment_method, :description => 'Cheque payment method', distributors: [distributor])
end

View File

@@ -15,7 +15,10 @@ feature "As a consumer I want to check out my cart", js: true do
create_enterprise_group_for distributor
end
describe "Login behaviour" do
# This was refactored in the new checkout
# We have monkey-patched in some of the new features
# Test suite works in that branch
pending "Login behaviour" do
let(:user) { create_enterprise_user }
before do
select_distributor

View File

@@ -143,13 +143,14 @@ feature "As a consumer I want to shop with a distributor", js: true do
end
end
describe "filtering on hand and on demand products" do
describe "filtering products" do
let(:oc) { create(:simple_order_cycle, distributors: [distributor]) }
let(:p1) { create(:simple_product, on_demand: false) }
let(:p2) { create(:simple_product, on_demand: true) }
let(:p3) { create(:simple_product, on_demand: false) }
let(:p4) { create(:simple_product, on_demand: false) }
let(:p5) { create(:simple_product, on_demand: false) }
let(:p6) { create(:simple_product, on_demand: false) }
let(:v1) { create(:variant, product: p4, unit_value: 2) }
let(:v2) { create(:variant, product: p4, unit_value: 3, on_demand: false) }
let(:v3) { create(:variant, product: p4, unit_value: 4, on_demand: true) }
@@ -162,6 +163,8 @@ feature "As a consumer I want to shop with a distributor", js: true do
p1.master.update_attribute(:count_on_hand, 1)
p2.master.update_attribute(:count_on_hand, 0)
p3.master.update_attribute(:count_on_hand, 0)
p6.master.update_attribute(:count_on_hand, 1)
p6.delete
v1.update_attribute(:count_on_hand, 1)
v2.update_attribute(:count_on_hand, 0)
v3.update_attribute(:count_on_hand, 0)
@@ -172,6 +175,7 @@ feature "As a consumer I want to shop with a distributor", js: true do
exchange.variants << p1.master
exchange.variants << p2.master
exchange.variants << p3.master
exchange.variants << p6.master
exchange.variants << v1
exchange.variants << v2
exchange.variants << v3
@@ -203,6 +207,9 @@ feature "As a consumer I want to shop with a distributor", js: true do
# It does not show products that have no available variants in this distribution
page.should_not have_content p5.name
# It does not show deleted products
page.should_not have_content p6.name
end
end

View File

@@ -40,7 +40,7 @@ describe "AdminOrderMgmtCtrl", ->
describe "fetching orders", ->
beforeEach ->
scope.initialiseVariables()
httpBackend.expectGET("/api/orders?template=bulk_index&q[completed_at_not_null]=true&q[completed_at_gt]=SomeDate&q[completed_at_lt]=SomeDate").respond "list of orders"
httpBackend.expectGET("/api/orders/managed?template=bulk_index&q[completed_at_not_null]=true&q[completed_at_gt]=SomeDate&q[completed_at_lt]=SomeDate").respond "list of orders"
it "makes a call to dataFetcher, with current start and end date parameters", ->
scope.fetchOrders()
@@ -256,9 +256,7 @@ describe "AdminOrderMgmtCtrl", ->
it "returns the quantity of fulfilled group buy units", ->
scope.selectedUnitsProduct = { variant_unit: "weight", group_buy_unit_size: 1000 }
spyOn(scope,"sumUnitValues").andReturn 1500
expect(scope.fulfilled()).toEqual 1.5
expect(scope.sumUnitValues).toHaveBeenCalled()
expect(scope.fulfilled(1500)).toEqual 1.5
describe "allUnitValuesPresent()", ->
it "returns false if the unit_value of any item in filteredLineItems does not exist", ->
@@ -303,6 +301,18 @@ describe "AdminOrderMgmtCtrl", ->
sp2 = scope.filteredLineItems[2].units_variant.unit_value * scope.filteredLineItems[2].quantity
expect(scope.sumUnitValues()).toEqual (sp0 + sp1 + sp2)
describe "sumMaxUnitValues()", ->
it "returns the sum of the product of unit_value and maxOf(max_quantity,quantity) for specified line_items", ->
scope.filteredLineItems = [
{ units_variant: { unit_value: 1 }, quantity: 2, max_quantity: 5 }
{ units_variant: { unit_value: 2 }, quantity: 3, max_quantity: 1 }
{ units_variant: { unit_value: 3 }, quantity: 7, max_quantity: 10 }
]
sp0 = scope.filteredLineItems[0].units_variant.unit_value * Math.max(scope.filteredLineItems[0].quantity, scope.filteredLineItems[0].max_quantity)
sp1 = scope.filteredLineItems[1].units_variant.unit_value * Math.max(scope.filteredLineItems[1].quantity, scope.filteredLineItems[1].max_quantity)
sp2 = scope.filteredLineItems[2].units_variant.unit_value * Math.max(scope.filteredLineItems[2].quantity, scope.filteredLineItems[2].max_quantity)
expect(scope.sumMaxUnitValues()).toEqual (sp0 + sp1 + sp2)
describe "formatting a value based upon the properties of a specified Units Variant", ->
# A Units Variant is an API object which holds unit properies of a variant
@@ -598,8 +608,10 @@ describe "Auxiliary functions", ->
expect(twoDigitNumber(1)).toEqual "01"
expect(twoDigitNumber(9)).toEqual "09"
describe "formatting a date", ->
it "returns a date formatted as yyyy-mm-dd hh-MM:ss", ->
describe "formatting dates and times", ->
date = null
beforeEach ->
date = new Date
date.setYear(2010)
date.setMonth(5) # Zero indexed, so 5 is June
@@ -607,4 +619,9 @@ describe "Auxiliary functions", ->
date.setHours(5)
date.setMinutes(10)
date.setSeconds(30)
expect(formatDate(date)).toEqual "2010-06-15 05:10:30"
it "returns a date formatted as yyyy-mm-dd", ->
expect(formatDate(date)).toEqual "2010-06-15"
it "returns a time formatted as hh-MM:ss", ->
expect(formatTime(date)).toEqual "05:10:30"

View File

@@ -17,6 +17,7 @@ describe Spree::OrderMailer do
product_distribution = create(:product_distribution, :product => product, :distributor => @distributor)
@shipping_instructions = "pick up on thursday please!"
@order1 = create(:order, :distributor => @distributor, :bill_address => @bill_address, :special_instructions => @shipping_instructions)
ActionMailer::Base.deliveries = []
end
it "should send an email when given an order" do

View File

@@ -181,14 +181,19 @@ describe Spree::Order do
end
describe "setting the order cycle" do
let(:oc) { create(:simple_order_cycle) }
it "empties the cart when changing the order cycle" do
subject.should_receive(:empty!)
subject.set_order_cycle! oc
end
it "sets the order cycle when no distributor is set" do
oc = create(:simple_order_cycle)
subject.set_order_cycle! oc
subject.order_cycle.should == oc
end
it "keeps the distributor when it is available in the new order cycle" do
oc = create(:simple_order_cycle)
d = create(:distributor_enterprise)
create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: d, incoming: false)
@@ -200,7 +205,6 @@ describe Spree::Order do
end
it "clears the distributor if it is not available at that order cycle" do
oc = create(:simple_order_cycle)
d = create(:distributor_enterprise)
subject.distributor = d
@@ -211,7 +215,6 @@ describe Spree::Order do
end
it "clears the order cycle when setting to nil" do
oc = create(:simple_order_cycle)
d = create(:distributor_enterprise)
subject.set_order_cycle! oc
subject.distributor = d