mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-04-03 06:59:14 +00:00
Merge branch master into properties
This commit is contained in:
2
.mailmap
Normal file
2
.mailmap
Normal file
@@ -0,0 +1,2 @@
|
||||
Rob Harrington <oeoeaio@gmail.com>
|
||||
Laura Summers <summerscope@gmail.com>
|
||||
2
Gemfile
2
Gemfile
@@ -15,6 +15,8 @@ gem 'spree_auth_devise', :github => 'spree/spree_auth_devise', :branch => '1-3-s
|
||||
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
#gem 'spree_paypal_express', :github => "spree-contrib/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
|
||||
gem 'delayed_job_active_record'
|
||||
gem 'daemons'
|
||||
gem 'comfortable_mexican_sofa'
|
||||
|
||||
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
|
||||
|
||||
12
Gemfile.lock
12
Gemfile.lock
@@ -217,6 +217,7 @@ GEM
|
||||
safe_yaml (~> 0.9.0)
|
||||
css_parser (1.3.5)
|
||||
addressable
|
||||
daemons (1.2.2)
|
||||
dalli (2.7.2)
|
||||
database_cleaner (0.7.1)
|
||||
db2fog (0.8.0)
|
||||
@@ -229,6 +230,11 @@ GEM
|
||||
debugger-ruby_core_source (~> 1.2.3)
|
||||
debugger-linecache (1.2.0)
|
||||
debugger-ruby_core_source (1.2.3)
|
||||
delayed_job (4.0.4)
|
||||
activesupport (>= 3.0, < 4.2)
|
||||
delayed_job_active_record (4.0.2)
|
||||
activerecord (>= 3.0, < 4.2)
|
||||
delayed_job (>= 3.0, < 4.1)
|
||||
devise (2.2.8)
|
||||
bcrypt-ruby (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
@@ -334,7 +340,7 @@ GEM
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
method_source (0.8.1)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.6.2)
|
||||
momentjs-rails (2.5.1)
|
||||
@@ -518,7 +524,7 @@ GEM
|
||||
xml-simple (1.1.4)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
zeus (0.13.3)
|
||||
zeus (0.15.4)
|
||||
method_source (>= 0.6.7)
|
||||
|
||||
PLATFORMS
|
||||
@@ -538,11 +544,13 @@ DEPENDENCIES
|
||||
comfortable_mexican_sofa
|
||||
compass-rails
|
||||
custom_error_message!
|
||||
daemons
|
||||
dalli
|
||||
database_cleaner (= 0.7.1)
|
||||
db2fog
|
||||
debugger-linecache
|
||||
deface!
|
||||
delayed_job_active_record
|
||||
factory_girl_rails
|
||||
figaro
|
||||
foreigner
|
||||
|
||||
@@ -95,4 +95,4 @@ usage instructions.
|
||||
|
||||
## Licence
|
||||
|
||||
Copyright (c) 2012 - 2013 Open Food Foundation, released under the AGPL licence.
|
||||
Copyright (c) 2012 - 2015 Open Food Foundation, released under the AGPL licence.
|
||||
|
||||
BIN
app/assets/images/noimage/group.png
Normal file
BIN
app/assets/images/noimage/group.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
app/assets/images/open-food-network-beta-black.png
Normal file
BIN
app/assets/images/open-food-network-beta-black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -19,6 +19,7 @@
|
||||
//= require ../shared/ng-infinite-scroll.min.js
|
||||
//= require ./admin
|
||||
//= require ./enterprises/enterprises
|
||||
//= require ./enterprise_groups/enterprise_groups
|
||||
//= require ./payment_methods/payment_methods
|
||||
//= require ./products/products
|
||||
//= require ./shipping_methods/shipping_methods
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
angular.module("admin.enterprise_groups")
|
||||
.controller "enterpriseGroupCtrl", ($scope, SideMenu) ->
|
||||
$scope.menu = SideMenu
|
||||
@@ -0,0 +1,15 @@
|
||||
angular.module("admin.enterprise_groups")
|
||||
.controller "sideMenuCtrl", ($scope, SideMenu) ->
|
||||
$scope.menu = SideMenu
|
||||
$scope.select = SideMenu.select
|
||||
|
||||
$scope.menu.setItems [
|
||||
{ name: 'Primary Details', icon_class: "icon-user" }
|
||||
{ name: 'Users', icon_class: "icon-user" }
|
||||
{ name: 'About', icon_class: "icon-pencil" }
|
||||
{ name: 'Images', icon_class: "icon-picture" }
|
||||
{ name: 'Contact', icon_class: "icon-phone" }
|
||||
{ name: 'Web', icon_class: "icon-globe" }
|
||||
]
|
||||
|
||||
$scope.select(0)
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.enterprise_groups", ["admin.side_menu", "admin.users", "textAngular"])
|
||||
@@ -13,6 +13,7 @@ angular.module("admin.enterprises")
|
||||
{ name: 'About', icon_class: "icon-pencil" }
|
||||
{ name: 'Business Details', icon_class: "icon-briefcase" }
|
||||
{ name: 'Images', icon_class: "icon-picture" }
|
||||
{ name: "Properties", icon_class: "icon-tags", show: "showProperties()" }
|
||||
{ name: "Shipping Methods", icon_class: "icon-truck", show: "showShippingMethods()" }
|
||||
{ name: "Payment Methods", icon_class: "icon-money", show: "showPaymentMethods()" }
|
||||
{ name: "Enterprise Fees", icon_class: "icon-tasks", show: "showEnterpriseFees()" }
|
||||
@@ -28,6 +29,9 @@ angular.module("admin.enterprises")
|
||||
else
|
||||
true
|
||||
|
||||
$scope.showProperties = ->
|
||||
!!$scope.Enterprise.is_primary_producer
|
||||
|
||||
$scope.showShippingMethods = ->
|
||||
enterprisePermissions.can_manage_shipping_methods && $scope.Enterprise.sells != "none"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
angular.module('admin.order_cycles', ['ngResource'])
|
||||
.controller('AdminCreateOrderCycleCtrl', ['$scope', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
.controller('AdminCreateOrderCycleCtrl', ['$scope', '$filter', 'OrderCycle', 'Enterprise', 'EnterpriseFee', 'ocInstance', ($scope, $filter, OrderCycle, Enterprise, EnterpriseFee, ocInstance) ->
|
||||
$scope.enterprises = Enterprise.index(coordinator_id: ocInstance.coordinator_id)
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
$scope.order_cycle = OrderCycle.new({ coordinator_id: ocInstance.coordinator_id})
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded
|
||||
@@ -27,14 +27,14 @@ angular.module('admin.order_cycles', ['ngResource'])
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
|
||||
$scope.incomingExchangesVariants = ->
|
||||
OrderCycle.incomingExchangesVariants()
|
||||
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
|
||||
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
|
||||
|
||||
$scope.exchangeDirection = (exchange) ->
|
||||
OrderCycle.exchangeDirection(exchange)
|
||||
|
||||
$scope.participatingEnterprises = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds()
|
||||
$scope.enterprisesWithFees = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds() when $scope.enterpriseFeesForEnterprise(id).length > 0
|
||||
|
||||
$scope.toggleProducts = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
@@ -79,12 +79,12 @@ angular.module('admin.order_cycles', ['ngResource'])
|
||||
OrderCycle.create()
|
||||
])
|
||||
|
||||
.controller('AdminEditOrderCycleCtrl', ['$scope', '$location', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, $location, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
|
||||
.controller('AdminEditOrderCycleCtrl', ['$scope', '$filter', '$location', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, $filter, $location, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: order_cycle_id)
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: order_cycle_id)
|
||||
|
||||
$scope.order_cycle = OrderCycle.load(order_cycle_id)
|
||||
|
||||
$scope.loaded = ->
|
||||
@@ -108,14 +108,14 @@ angular.module('admin.order_cycles', ['ngResource'])
|
||||
$scope.variantSuppliedToOrderCycle = (variant) ->
|
||||
OrderCycle.variantSuppliedToOrderCycle(variant)
|
||||
|
||||
$scope.incomingExchangesVariants = ->
|
||||
OrderCycle.incomingExchangesVariants()
|
||||
$scope.incomingExchangeVariantsFor = (enterprise_id) ->
|
||||
$filter('filterExchangeVariants')(OrderCycle.incomingExchangesVariants(), $scope.order_cycle.visible_variants_for_outgoing_exchanges[enterprise_id])
|
||||
|
||||
$scope.exchangeDirection = (exchange) ->
|
||||
OrderCycle.exchangeDirection(exchange)
|
||||
|
||||
$scope.participatingEnterprises = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds()
|
||||
$scope.enterprisesWithFees = ->
|
||||
$scope.enterprises[id] for id in OrderCycle.participatingEnterpriseIds() when $scope.enterpriseFeesForEnterprise(id).length > 0
|
||||
|
||||
$scope.toggleProducts = ($event, exchange) ->
|
||||
$event.preventDefault()
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee) ->
|
||||
$scope.enterprises = Enterprise.index (enterprises) =>
|
||||
$scope.init(enterprises)
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee, ocInstance) ->
|
||||
$scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, =>
|
||||
# TODO: make this a get method, which only fetches one enterprise
|
||||
$scope.enterprises = Enterprise.index {coordinator_id: ocInstance.coordinator_id}, (enterprises) =>
|
||||
$scope.init(enterprises)
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
|
||||
$scope.init = (enterprises) ->
|
||||
enterprise = enterprises[Object.keys(enterprises)[0]]
|
||||
|
||||
@@ -2,8 +2,8 @@ angular.module('admin.order_cycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
$scope.orderCycleId = ->
|
||||
$location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
|
||||
$scope.enterprises = Enterprise.index()
|
||||
$scope.enterprise_fees = EnterpriseFee.index()
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) =>
|
||||
$scope.init()
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.order_cycles").filter "filterExchangeVariants", ->
|
||||
return (variants, rules) ->
|
||||
if variants? && rules?
|
||||
return (variant for variant in variants when variant in rules)
|
||||
else
|
||||
return []
|
||||
@@ -0,0 +1,4 @@
|
||||
angular.module("admin.order_cycles").filter "visibleProductVariants", ->
|
||||
return (product, exchange, rules) ->
|
||||
variants = product.variants.concat( [{ "id": product.master_id}] )
|
||||
return (variant for variant in variants when variant.id in rules[exchange.enterprise_id])
|
||||
@@ -0,0 +1,3 @@
|
||||
angular.module("admin.order_cycles").filter "visibleProducts", ($filter) ->
|
||||
return (products, exchange, rules) ->
|
||||
return (product for product in products when $filter('visibleProductVariants')(product, exchange, rules).length > 0)
|
||||
@@ -1,24 +1,28 @@
|
||||
angular.module('admin.order_cycles').factory('Enterprise', ($resource) ->
|
||||
Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
|
||||
Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
order_cycle_id: '@order_cycle_id'
|
||||
coordinator_id: '@coordinator_id'
|
||||
})
|
||||
{
|
||||
Enterprise: Enterprise
|
||||
enterprises: {}
|
||||
supplied_products: []
|
||||
loaded: false
|
||||
|
||||
index: (callback=null) ->
|
||||
service = this
|
||||
|
||||
Enterprise.index (data) ->
|
||||
index: (params={}, callback=null) ->
|
||||
Enterprise.index params, (data) =>
|
||||
for enterprise in data
|
||||
service.enterprises[enterprise.id] = enterprise
|
||||
@enterprises[enterprise.id] = enterprise
|
||||
|
||||
for product in enterprise.supplied_products
|
||||
service.supplied_products.push(product)
|
||||
@supplied_products.push(product)
|
||||
|
||||
service.loaded = true
|
||||
(callback || angular.noop)(service.enterprises)
|
||||
@loaded = true
|
||||
(callback || angular.noop)(@enterprises)
|
||||
|
||||
this.enterprises
|
||||
|
||||
@@ -40,4 +44,4 @@ angular.module('admin.order_cycles').factory('Enterprise', ($resource) ->
|
||||
numVariants += if product.variants.length == 0 then 1 else product.variants.length
|
||||
|
||||
numVariants
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
angular.module('admin.order_cycles').factory('EnterpriseFee', ($resource) ->
|
||||
EnterpriseFee = $resource('/admin/enterprise_fees/:enterprise_fee_id.json', {}, {'index': {method: 'GET', isArray: true}})
|
||||
EnterpriseFee = $resource('/admin/enterprise_fees/for_order_cycle/:enterprise_fee_id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
order_cycle_id: '@order_cycle_id'
|
||||
coordinator_id: '@coordinator_id'
|
||||
})
|
||||
|
||||
{
|
||||
EnterpriseFee: EnterpriseFee
|
||||
enterprise_fees: {}
|
||||
loaded: false
|
||||
|
||||
index: ->
|
||||
service = this
|
||||
EnterpriseFee.index (data) ->
|
||||
service.enterprise_fees = data
|
||||
service.loaded = true
|
||||
index: (params={}) ->
|
||||
EnterpriseFee.index params, (data) =>
|
||||
@enterprise_fees = data
|
||||
@loaded = true
|
||||
|
||||
forEnterprise: (enterprise_id) ->
|
||||
enterprise_fee for enterprise_fee in this.enterprise_fees when enterprise_fee.enterprise_id == enterprise_id
|
||||
enterprise_fee for enterprise_fee in @enterprise_fees when enterprise_fee.enterprise_id == enterprise_id
|
||||
})
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) ->
|
||||
OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, {
|
||||
OrderCycle = $resource '/admin/order_cycles/:action_name/:order_cycle_id.json', {}, {
|
||||
'index': { method: 'GET', isArray: true}
|
||||
'new' : { method: 'GET', params: { action_name: "new" } }
|
||||
'create': { method: 'POST'}
|
||||
'update': { method: 'PUT'}}
|
||||
|
||||
{
|
||||
order_cycle:
|
||||
incoming_exchanges: []
|
||||
outgoing_exchanges: []
|
||||
coordinator_fees: []
|
||||
order_cycle: {}
|
||||
|
||||
loaded: false
|
||||
|
||||
@@ -24,7 +22,9 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
exchange.showProducts = !exchange.showProducts
|
||||
|
||||
setExchangeVariants: (exchange, variants, selected) ->
|
||||
exchange.variants[variant] = selected for variant in variants
|
||||
direction = if exchange.incoming then "incoming" else "outgoing"
|
||||
editable = @order_cycle["editable_variants_for_#{direction}_exchanges"][exchange.enterprise_id] || []
|
||||
exchange.variants[variant] = selected for variant in variants when variant in editable
|
||||
|
||||
addSupplier: (new_supplier_id) ->
|
||||
this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []})
|
||||
@@ -84,6 +84,20 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
for exchange in this.order_cycle.outgoing_exchanges
|
||||
exchange.variants[variant_id] = false
|
||||
|
||||
new: (params, callback=null) ->
|
||||
OrderCycle.new params, (oc) =>
|
||||
delete oc.$promise
|
||||
delete oc.$resolved
|
||||
angular.extend(@order_cycle, oc)
|
||||
@order_cycle.incoming_exchanges = []
|
||||
@order_cycle.outgoing_exchanges = []
|
||||
delete(@order_cycle.exchanges)
|
||||
@loaded = true
|
||||
|
||||
(callback || angular.noop)(@order_cycle)
|
||||
|
||||
@order_cycle
|
||||
|
||||
load: (order_cycle_id, callback=null) ->
|
||||
service = this
|
||||
OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) ->
|
||||
@@ -127,6 +141,7 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
|
||||
dataForSubmit: ->
|
||||
data = this.deepCopy()
|
||||
data = this.stripNonSubmittableAttributes(data)
|
||||
data = this.removeInactiveExchanges(data)
|
||||
data = this.translateCoordinatorFees(data)
|
||||
data = this.translateExchangeFees(data)
|
||||
@@ -147,6 +162,14 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
|
||||
|
||||
data
|
||||
|
||||
stripNonSubmittableAttributes: (order_cycle) ->
|
||||
delete order_cycle.id
|
||||
delete order_cycle.viewing_as_coordinator
|
||||
delete order_cycle.editable_variants_for_incoming_exchanges
|
||||
delete order_cycle.editable_variants_for_outgoing_exchanges
|
||||
delete order_cycle.visible_variants_for_outgoing_exchanges
|
||||
order_cycle
|
||||
|
||||
removeInactiveExchanges: (order_cycle) ->
|
||||
order_cycle.incoming_exchanges =
|
||||
(exchange for exchange in order_cycle.incoming_exchanges when exchange.active)
|
||||
|
||||
@@ -11,9 +11,9 @@ $ ->
|
||||
|
||||
# Temporarily handles the cart showing stuff
|
||||
$(document).ready ->
|
||||
$('#cart_adjustments').hide()
|
||||
$('.cart_adjustment').hide()
|
||||
|
||||
$('th.cart-adjustment-header a').click ->
|
||||
$('#cart_adjustments').toggle()
|
||||
$('td.cart-adjustments a').click ->
|
||||
$('.cart_adjustment').toggle()
|
||||
$(this).html('Item Handling Fees (included in item totals)')
|
||||
false
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Darkswarm.controller "GroupEnterpriseNodeCtrl", ($scope, CurrentHub) ->
|
||||
|
||||
$scope.active = false
|
||||
|
||||
$scope.toggle = ->
|
||||
$scope.active = !$scope.active
|
||||
|
||||
$scope.open = ->
|
||||
$scope.active
|
||||
|
||||
$scope.current = ->
|
||||
$scope.hub.id is CurrentHub.hub.id
|
||||
@@ -0,0 +1,12 @@
|
||||
Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsService) ->
|
||||
$scope.totalActive = FilterSelectorsService.totalActive
|
||||
$scope.clearAll = FilterSelectorsService.clearAll
|
||||
$scope.filterText = FilterSelectorsService.filterText
|
||||
$scope.FilterSelectorsService = FilterSelectorsService
|
||||
$scope.query = Search.search()
|
||||
$scope.activeTaxons = []
|
||||
$scope.show_profiles = false
|
||||
$scope.filtersActive = false
|
||||
|
||||
$scope.$watch "query", (query)->
|
||||
Search.search query
|
||||
@@ -0,0 +1,14 @@
|
||||
Darkswarm.controller "GroupPageCtrl", ($scope, group_enterprises, Enterprises, MapConfiguration, OfnMap) ->
|
||||
$scope.Enterprises = Enterprises
|
||||
|
||||
group_enterprises_ids = group_enterprises.map (enterprise) =>
|
||||
enterprise.id
|
||||
is_in_group = (enterprise) ->
|
||||
group_enterprises_ids.indexOf(enterprise.id) != -1
|
||||
|
||||
$scope.group_producers = Enterprises.producers.filter is_in_group
|
||||
$scope.group_hubs = Enterprises.hubs.filter is_in_group
|
||||
|
||||
$scope.map = angular.copy MapConfiguration.options
|
||||
$scope.mapMarkers = OfnMap.enterprise_markers group_enterprises
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Darkswarm.controller "MapCtrl", ($scope, MapConfiguration, OfnMap)->
|
||||
$scope.OfnMap = OfnMap
|
||||
$scope.map = MapConfiguration.options
|
||||
$scope.map = angular.copy MapConfiguration.options
|
||||
|
||||
@@ -3,7 +3,7 @@ Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, Enterpris
|
||||
$scope.enterprise = EnterpriseRegistrationService.enterprise
|
||||
$scope.select = RegistrationService.select
|
||||
|
||||
$scope.steps = ['details','contact','type','about','images','social']
|
||||
$scope.steps = ['details', 'contact', 'type', 'about', 'images', 'social']
|
||||
|
||||
$scope.countries = availableCountries
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
Darkswarm.controller "TabsCtrl", ($scope, $rootScope, $location, OrderCycle) ->
|
||||
Darkswarm.controller "TabsCtrl", ($scope, $rootScope, $location) ->
|
||||
# Return active if supplied path matches url hash path.
|
||||
$scope.active = (path)->
|
||||
$location.hash() == path
|
||||
|
||||
# Toggle tab selected status by setting the url hash path.
|
||||
# Select tab by setting the url hash path.
|
||||
$scope.select = (path)->
|
||||
$location.hash path
|
||||
|
||||
# Toggle tab selected status by setting the url hash path.
|
||||
$scope.toggle = (path)->
|
||||
if $scope.active(path)
|
||||
$location.hash ""
|
||||
else
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Darkswarm.directive "linkToService", ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
scope: {
|
||||
ref: '='
|
||||
service: '='
|
||||
}
|
||||
template: '<a href="{{ref | ext_url: service}}" target="_blank" ng-show="ref"></a>'
|
||||
@@ -0,0 +1,7 @@
|
||||
Darkswarm.filter "ext_url", ->
|
||||
urlPattern = /^https?:\/\//
|
||||
(url, prefix) ->
|
||||
if !url || url.match(urlPattern)
|
||||
url
|
||||
else
|
||||
prefix + url
|
||||
@@ -1,9 +1,10 @@
|
||||
Darkswarm.filter 'shipping', ()->
|
||||
Darkswarm.filter 'shipping', ()->
|
||||
(objects, options)->
|
||||
objects ||= []
|
||||
options ?= null
|
||||
|
||||
if options.pickup and !options.delivery
|
||||
|
||||
if !options
|
||||
objects
|
||||
else if options.pickup and !options.delivery
|
||||
objects.filter (obj)->
|
||||
obj.pickup
|
||||
else if options.delivery and !options.pickup
|
||||
|
||||
@@ -8,6 +8,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
|
||||
for line_item in @line_items
|
||||
line_item.variant.line_item = line_item
|
||||
Variants.register line_item.variant
|
||||
line_item.variant.extended_name = @extendedVariantName(line_item.variant)
|
||||
|
||||
orderChanged: =>
|
||||
@unsaved()
|
||||
@@ -63,8 +64,17 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
|
||||
@create_line_item(variant) unless exists
|
||||
|
||||
create_line_item: (variant)->
|
||||
variant.extended_name = @extendedVariantName(variant)
|
||||
variant.line_item =
|
||||
variant: variant
|
||||
quantity: null
|
||||
max_quantity: null
|
||||
@line_items.push variant.line_item
|
||||
@line_items.push variant.line_item
|
||||
|
||||
extendedVariantName: (variant) =>
|
||||
if variant.product_name == variant.name_to_display
|
||||
variant.product_name
|
||||
else
|
||||
name = "#{variant.product_name} - #{variant.name_to_display}"
|
||||
name += " (#{variant.options_text})" if variant.options_text
|
||||
name
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter)->
|
||||
Darkswarm.factory "OfnMap", (Enterprises, EnterpriseModal, visibleFilter) ->
|
||||
new class OfnMap
|
||||
constructor: ->
|
||||
@enterprises = (@extend(enterprise) for enterprise in visibleFilter(Enterprises.enterprises))
|
||||
@enterprises = @enterprise_markers(Enterprises.enterprises)
|
||||
|
||||
enterprise_markers: (enterprises) ->
|
||||
@extend(enterprise) for enterprise in visibleFilter(enterprises)
|
||||
|
||||
# Adding methods to each enterprise
|
||||
extend: (enterprise)->
|
||||
extend: (enterprise) ->
|
||||
new class MapMarker
|
||||
# We're whitelisting attributes because GMaps tries to crawl
|
||||
# our data, and our data is recursive, so it breaks
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
font-size: 120%
|
||||
cursor: pointer
|
||||
text-transform: uppercase
|
||||
&.odd
|
||||
&:nth-child(odd)
|
||||
background-color: #ebf3fb
|
||||
&.even
|
||||
&:nth-child(even)
|
||||
background-color: #ffffff
|
||||
&:hover
|
||||
background-color: #eaf0f5
|
||||
|
||||
@@ -75,7 +75,7 @@ ordercycle
|
||||
|
||||
|
||||
button.graph-button
|
||||
z-index: 9999999
|
||||
// z-index: 9999999
|
||||
border: 1px solid transparent
|
||||
padding: 0
|
||||
margin: 0
|
||||
|
||||
@@ -30,21 +30,20 @@
|
||||
text-decoration: underline
|
||||
|
||||
span.margin-top
|
||||
margin-top: 0.5rem
|
||||
margin-top: 0.5rem
|
||||
display: inline-block
|
||||
|
||||
// Generic text resize
|
||||
@media all and (max-width: 640px)
|
||||
@media all and (max-width: 640px)
|
||||
&, & *
|
||||
font-size: 0.875rem
|
||||
font-size: 0.875rem
|
||||
fat > div label
|
||||
&, & *
|
||||
font-size: 0.75rem
|
||||
&, & *
|
||||
font-size: 0.75rem
|
||||
|
||||
|
||||
.active_table_row
|
||||
// Inherits from active_table
|
||||
border: 1px solid transparent
|
||||
// Inherits from active_table
|
||||
.active_table_row
|
||||
border: 1px solid transparent
|
||||
@include border-radius(0.5em)
|
||||
|
||||
// Foundation overrides
|
||||
@@ -77,15 +76,15 @@
|
||||
.active_table_row:last-child
|
||||
border-bottom: 1px solid $disabled-bright
|
||||
@include border-radius-mixed(0, 0, 0.5em, 0.5em)
|
||||
|
||||
|
||||
|
||||
|
||||
//Open row sections
|
||||
.fat > div
|
||||
border-top: 1px solid #aaa
|
||||
@media all and (max-width: 640px)
|
||||
@media all and (max-width: 640px)
|
||||
margin-top: 1em
|
||||
|
||||
ul, ol
|
||||
ul, ol
|
||||
font-size: 0.875rem
|
||||
|
||||
[class*="block-grid-"] > li
|
||||
@@ -97,10 +96,10 @@
|
||||
margin-top: 0.25rem
|
||||
margin-bottom: 0.25rem
|
||||
color: #777
|
||||
|
||||
|
||||
p.trans-sentence
|
||||
text-transform: capitalize
|
||||
|
||||
|
||||
&.closed
|
||||
&:hover, &:active, &:focus
|
||||
.active_table_row.closed
|
||||
@@ -113,7 +112,3 @@
|
||||
&.open
|
||||
.active_table_row:first-child
|
||||
color: $dark-grey
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -25,5 +25,6 @@ $disabled-v-dark: #808080
|
||||
$med-grey: #666
|
||||
$med-drk-grey: #444
|
||||
$dark-grey: #333
|
||||
$light-grey: #ddd
|
||||
$black: #000
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
@import branding
|
||||
@import animations
|
||||
|
||||
.order-summary
|
||||
background-color: #e1f0f5
|
||||
padding: 1em
|
||||
width: 100%
|
||||
|
||||
checkout
|
||||
display: block
|
||||
|
||||
@@ -55,7 +60,6 @@ checkout
|
||||
text-align: left
|
||||
|
||||
// Logic to swap out up / down accordion icons
|
||||
|
||||
//Foundation overrides
|
||||
dd > a
|
||||
@include csstrans
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@import branding
|
||||
@import mixins
|
||||
|
||||
// Search page
|
||||
#groups
|
||||
background-color: $clr-brick-light
|
||||
background-image: url("/assets/groups.svg")
|
||||
@@ -8,35 +9,97 @@
|
||||
background-repeat: no-repeat
|
||||
padding-bottom: 20px
|
||||
|
||||
a > .group-name
|
||||
&:hover, &:focus, &:active
|
||||
text-decoration: underline
|
||||
|
||||
.groups-icons
|
||||
text-align: right
|
||||
a
|
||||
font-size: 1.5em
|
||||
|
||||
.groups-header
|
||||
border: 2px solid $clr-brick-light-bright
|
||||
@include border-radius-mixed(0.5em, 0.5em, 0, 0)
|
||||
margin: -1rem 0 1rem
|
||||
padding: 1rem 0.9375rem
|
||||
@media screen and (min-width: 640px)
|
||||
border: 0 none
|
||||
@include border-radius(0)
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
.group
|
||||
padding-bottom: 40px
|
||||
hr
|
||||
border-bottom: 10px solid white
|
||||
outline: 0
|
||||
border-top: 0
|
||||
margin: 0
|
||||
padding-bottom: 0.5em
|
||||
.row div
|
||||
font-size: 110%
|
||||
.row a
|
||||
vertical-align: middle
|
||||
.ofn-i_035-groups
|
||||
font-size: 120%
|
||||
vertical-align: middle
|
||||
|
||||
// Individual Page
|
||||
#group-page
|
||||
.group-logo, .group-header
|
||||
text-align: center
|
||||
.group-logo
|
||||
padding-bottom: 1em
|
||||
max-height: 200px
|
||||
.group-name
|
||||
border-bottom: 1px solid #ccc
|
||||
@media screen and (min-width: 768px)
|
||||
.group-logo, .group-header
|
||||
text-align: left
|
||||
.group-logo
|
||||
max-height: 120px
|
||||
float: left
|
||||
padding-right: 1em
|
||||
background-color: white
|
||||
|
||||
.group-hero
|
||||
position: relative
|
||||
padding: 0
|
||||
border: 10px solid white
|
||||
background: white
|
||||
// Tabs
|
||||
.tabs dd a // Mobile first
|
||||
padding: 0.25rem 0.45rem 0rem
|
||||
font-size: 0.75rem
|
||||
border: none
|
||||
margin-bottom: -2px
|
||||
margin-right: 2px
|
||||
text-transform: capitalize
|
||||
@include avenir
|
||||
@include border-radius(1em 0.25em 0 0)
|
||||
@include gradient($disabled-light, $disabled-bright)
|
||||
@media screen and (min-width: 768px)
|
||||
.tabs dd a
|
||||
padding: 0.5rem 1rem 0.25em
|
||||
font-size: 0.875rem
|
||||
@include border-radius(1.5em 0.25em 0 0)
|
||||
@media screen and (min-width: 1024px)
|
||||
.tabs dd a
|
||||
padding: 0.75rem 1.5rem 0.5em
|
||||
font-size: 1rem
|
||||
@include border-radius(2em 0.25em 0 0)
|
||||
.tabs dd.active a
|
||||
@include gradient(white, white)
|
||||
margin-bottom: -1px
|
||||
border-top: 1px solid $light-grey
|
||||
border-left: 1px solid $light-grey
|
||||
border-right: 1px solid $light-grey
|
||||
border-bottom: 0
|
||||
.tabs-content
|
||||
border-top: 1px solid $light-grey
|
||||
border-left: 1px solid $light-grey
|
||||
border-right: 1px solid $light-grey
|
||||
border-bottom: 1px solid $light-grey
|
||||
padding: 1.5em
|
||||
|
||||
h3.group-name
|
||||
margin-top: 0.5em
|
||||
margin-bottom: 0.15em
|
||||
|
||||
img.group-logo
|
||||
max-width: 220px
|
||||
max-height: 86px
|
||||
float: right
|
||||
padding-top: 10px
|
||||
|
||||
|
||||
img.group-hero-img
|
||||
background-color: black
|
||||
width: 100%
|
||||
height: inherit
|
||||
max-height: 260px
|
||||
min-height: 120px
|
||||
overflow: hidden
|
||||
// Producers tab
|
||||
.producers
|
||||
background-image: none
|
||||
.active_table .active_table_node a.is_distributor, .active_table .active_table_node a.is_distributor i.ofn-i_059-producer
|
||||
color: $clr-turquoise
|
||||
// Hubs tab
|
||||
.hubs
|
||||
background-image: none
|
||||
padding-top: 0
|
||||
padding-bottom: 0
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
height: 100%
|
||||
width: 100%
|
||||
|
||||
img
|
||||
// https://github.com/zurb/foundation/issues/112
|
||||
// https://github.com/zurb/foundation/issues/112
|
||||
img
|
||||
max-width: none
|
||||
height: auto
|
||||
|
||||
#pac-input
|
||||
#pac-input
|
||||
@include big-input(#888, #333, $clr-brick)
|
||||
@include big-input-static
|
||||
font-size: 1.5rem
|
||||
|
||||
@@ -120,5 +120,21 @@
|
||||
background-repeat: no-repeat
|
||||
background-size: 100% auto
|
||||
|
||||
|
||||
@mixin gradient($gradient-clr1, $gradient-clr2)
|
||||
background: $gradient-clr1
|
||||
// Old browsers
|
||||
background: -moz-linear-gradient(top, $gradient-clr1 0%, $gradient-clr2 100%)
|
||||
// FF3.6+
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, $gradient-clr1), color-stop(100%, $gradient-clr2))
|
||||
// Chrome,Safari4+
|
||||
background: -webkit-linear-gradient(top, $gradient-clr1 0%, $gradient-clr2 100%)
|
||||
// Chrome10+,Safari5.1+
|
||||
background: -o-linear-gradient(top, $gradient-clr1 0%, $gradient-clr2 100%)
|
||||
// Opera 11.10+
|
||||
background: -ms-linear-gradient(top, $gradient-clr1 0%, $gradient-clr2 100%)
|
||||
// IE10+
|
||||
background: linear-gradient(to bottom, $gradient-clr1 0%, $gradient-clr2 100%)
|
||||
// W3C
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='$gradient-clr1', endColorstr='$gradient-clr2',GradientType=0 )
|
||||
// IE6-8
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
font-size: 1rem
|
||||
font-weight: 400
|
||||
color: $disabled-dark
|
||||
border-bottom: 1px solid $disabled-dark
|
||||
border-bottom: 1px solid $light-grey
|
||||
margin-top: 0.75rem
|
||||
margin-bottom: 0.5rem
|
||||
|
||||
@@ -67,8 +67,8 @@
|
||||
margin-bottom: 0.5rem
|
||||
overflow-y: scroll
|
||||
overflow-x: hidden
|
||||
border-bottom: 1px solid #999
|
||||
@include box-shadow(0 2px 2px -2px #999)
|
||||
border-bottom: 1px solid $light-grey
|
||||
@include box-shadow(0 2px 2px -2px $light-grey)
|
||||
|
||||
.enterprise-logo, img
|
||||
float: left
|
||||
|
||||
@@ -42,10 +42,22 @@
|
||||
height: auto
|
||||
top: 0px
|
||||
|
||||
// Shopping cart
|
||||
#cart-detail
|
||||
.cart-item-delete
|
||||
a.delete
|
||||
font-size: 1.125em
|
||||
|
||||
.item-thumb-image
|
||||
display: none
|
||||
@media screen and (min-width: 640px)
|
||||
display: inline-block
|
||||
float: left
|
||||
padding-right: 0.5em
|
||||
width: 36px
|
||||
height: 36px
|
||||
|
||||
|
||||
|
||||
#edit-cart
|
||||
button, .button
|
||||
|
||||
@@ -16,27 +16,45 @@
|
||||
@font-face
|
||||
font-family: 'AvenirMed'
|
||||
src: url("/AvenirLTStd-Medium.otf") format("opentype")
|
||||
|
||||
body
|
||||
font-family: 'Open Sans', Calibri, Candara, Segoe, "Segoe UI", Optima, Arial, sans-serif
|
||||
|
||||
$font-helvetica: "Helvetica Neue", "HelveticaNeue", "Helvetica", Helvetica, Arial, sans-serif
|
||||
|
||||
a
|
||||
color: $clr-brick
|
||||
&:hover
|
||||
&:hover, &:focus, &:active
|
||||
text-decoration: none
|
||||
color: $clr-brick-bright
|
||||
|
||||
.text-big
|
||||
font-size: 1.5rem
|
||||
font-weight: 300
|
||||
|
||||
small, .small
|
||||
font-size: 0.75rem
|
||||
|
||||
.text-small
|
||||
font-size: 0.875rem
|
||||
margin-bottom: 0.5rem
|
||||
font-family: $font-helvetica
|
||||
&, & *
|
||||
font-size: 0.875rem
|
||||
|
||||
.text-normal
|
||||
font-weight: 400
|
||||
font-family: $font-helvetica
|
||||
|
||||
.text-skinny
|
||||
font-weight: 300
|
||||
font-family: $font-helvetica
|
||||
|
||||
.word-wrap
|
||||
word-wrap: break-word
|
||||
|
||||
.pre-wrap
|
||||
white-space: pre-wrap
|
||||
|
||||
.pre-line
|
||||
white-space: pre-line
|
||||
|
||||
.light
|
||||
color: #999
|
||||
@@ -81,6 +99,9 @@ ul.check-list
|
||||
.light-grey
|
||||
color: #666666
|
||||
|
||||
.pad
|
||||
padding: 1em
|
||||
|
||||
.pad-top
|
||||
padding-top: 1em
|
||||
|
||||
|
||||
@@ -56,6 +56,23 @@ table.social
|
||||
table.order-summary
|
||||
border-collapse: separate
|
||||
border-spacing: 0px 10px
|
||||
tbody tr td
|
||||
padding-left: 5px
|
||||
padding-right: 5px
|
||||
thead tr th
|
||||
background-color: #f2f2f2
|
||||
border-bottom: 1px solid black
|
||||
padding-left: 5px
|
||||
padding-right: 5px
|
||||
h4
|
||||
margin-top: 15px
|
||||
tfoot
|
||||
tr:first-child td
|
||||
border-top: 1px solid black
|
||||
padding-top: 5px
|
||||
tr td
|
||||
padding-left: 5px
|
||||
padding-right: 5px
|
||||
|
||||
.social .soc-btn
|
||||
padding: 3px 7px
|
||||
@@ -245,6 +262,10 @@ ul
|
||||
tr td
|
||||
padding: 15px
|
||||
|
||||
.pad
|
||||
tr td
|
||||
padding: 15px
|
||||
|
||||
.column-wrap
|
||||
padding: 0!important
|
||||
margin: 0 auto
|
||||
|
||||
@@ -20,6 +20,17 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def for_order_cycle
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: ActiveModel::ArraySerializer.new( @collection,
|
||||
each_serializer: Api::Admin::EnterpriseFeeSerializer, controller: self
|
||||
).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
@enterprise_fee_set = EnterpriseFeeSet.new(params[:enterprise_fee_set])
|
||||
if @enterprise_fee_set.save
|
||||
@@ -59,12 +70,26 @@ module Admin
|
||||
|
||||
def load_data
|
||||
@calculators = EnterpriseFee.calculators.sort_by(&:name)
|
||||
@tax_categories = Spree::TaxCategory.order('is_default DESC, name ASC')
|
||||
end
|
||||
|
||||
def collection
|
||||
collection = EnterpriseFee.managed_by(spree_current_user).order('enterprise_id', 'fee_type', 'name')
|
||||
collection = collection.for_enterprise(current_enterprise) if current_enterprise
|
||||
collection
|
||||
case action
|
||||
when :for_order_cycle
|
||||
order_cycle = OrderCycle.find_by_id(params[:order_cycle_id]) if params[:order_cycle_id]
|
||||
coordinator = Enterprise.find_by_id(params[:coordinator_id]) if params[:coordinator_id]
|
||||
order_cycle = OrderCycle.new(coordinator: coordinator) if order_cycle.nil? && coordinator.present?
|
||||
enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, order_cycle).visible_enterprises
|
||||
return EnterpriseFee.for_enterprises(enterprises).order('enterprise_id', 'fee_type', 'name')
|
||||
else
|
||||
collection = EnterpriseFee.managed_by(spree_current_user).order('enterprise_id', 'fee_type', 'name')
|
||||
collection = collection.for_enterprise(current_enterprise) if current_enterprise
|
||||
collection
|
||||
end
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
[:index, :for_order_cycle]
|
||||
end
|
||||
|
||||
def current_enterprise
|
||||
|
||||
@@ -1,22 +1,50 @@
|
||||
module Admin
|
||||
class EnterpriseGroupsController < ResourceController
|
||||
before_filter :load_data, except: :index
|
||||
before_filter :load_object_data, only: [:new, :edit, :create, :update]
|
||||
|
||||
def index
|
||||
@enterprise_groups = @enterprise_groups.managed_by(spree_current_user)
|
||||
end
|
||||
|
||||
def move_up
|
||||
@enterprise_group = EnterpriseGroup.find params[:enterprise_group_id]
|
||||
@enterprise_group.move_higher
|
||||
EnterpriseGroup.with_isolation_level_serializable do
|
||||
@enterprise_group = EnterpriseGroup.find params[:enterprise_group_id]
|
||||
@enterprise_group.move_higher
|
||||
end
|
||||
redirect_to main_app.admin_enterprise_groups_path
|
||||
end
|
||||
|
||||
def move_down
|
||||
@enterprise_group = EnterpriseGroup.find params[:enterprise_group_id]
|
||||
@enterprise_group.move_lower
|
||||
EnterpriseGroup.with_isolation_level_serializable do
|
||||
@enterprise_group = EnterpriseGroup.find params[:enterprise_group_id]
|
||||
@enterprise_group.move_lower
|
||||
end
|
||||
redirect_to main_app.admin_enterprise_groups_path
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_resource_with_address
|
||||
enterprise_group = build_resource_without_address
|
||||
enterprise_group.address = Spree::Address.new
|
||||
enterprise_group.address.country = Spree::Country.find_by_id(Spree::Config[:default_country_id])
|
||||
enterprise_group
|
||||
end
|
||||
alias_method_chain :build_resource, :address
|
||||
|
||||
private
|
||||
|
||||
def load_data
|
||||
@countries = Spree::Country.order(:name)
|
||||
@enterprises = Enterprise.activated
|
||||
end
|
||||
|
||||
def load_object_data
|
||||
@owner_email = @enterprise_group.andand.owner.andand.email || ""
|
||||
end
|
||||
|
||||
|
||||
def collection
|
||||
EnterpriseGroup.by_position
|
||||
end
|
||||
|
||||
@@ -7,17 +7,19 @@ module Admin
|
||||
before_filter :check_can_change_sells, only: :update
|
||||
before_filter :check_can_change_bulk_sells, only: :bulk_update
|
||||
before_filter :override_owner, only: :create
|
||||
before_filter :override_sells, only: :create
|
||||
before_filter :check_can_change_owner, only: :update
|
||||
before_filter :check_can_change_bulk_owner, only: :bulk_update
|
||||
before_filter :check_can_change_managers, only: :update
|
||||
before_filter :strip_new_properties, only: [:create, :update]
|
||||
before_filter :load_properties, only: [:edit, :update]
|
||||
before_filter :setup_property, only: [:edit]
|
||||
|
||||
|
||||
helper 'spree/products'
|
||||
include ActionView::Helpers::TextHelper
|
||||
include OrderCyclesHelper
|
||||
|
||||
def for_order_cycle
|
||||
@collection = order_cycle_permitted_enterprises
|
||||
end
|
||||
|
||||
def set_sells
|
||||
enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
|
||||
attributes = { sells: params[:sells] }
|
||||
@@ -45,17 +47,35 @@ module Admin
|
||||
|
||||
def bulk_update
|
||||
@enterprise_set = EnterpriseSet.new(collection, params[:enterprise_set])
|
||||
touched_enterprises = @enterprise_set.collection.select(&:changed?)
|
||||
if @enterprise_set.save
|
||||
flash[:success] = 'Enterprises updated successfully'
|
||||
flash[:success] = "Enterprises updated successfully"
|
||||
|
||||
# 18-3-2015: It seems that the form for this action sometimes loads bogus values for
|
||||
# the 'sells' field, and submitting that form results in a bunch of enterprises with
|
||||
# values that have mysteriously changed. This statement is here to help debug that
|
||||
# issue, and should be removed (along with its display in index.html.haml) when the
|
||||
# issue has been resolved.
|
||||
flash[:action] = "Updated #{pluralize(touched_enterprises.count, 'enterprise')}: #{touched_enterprises.map(&:name).join(', ')}"
|
||||
|
||||
redirect_to main_app.admin_enterprises_path
|
||||
else
|
||||
touched_ids = params[:enterprise_set][:collection_attributes].values.map { |v| v[:id].to_i }
|
||||
@enterprise_set.collection.select! { |e| touched_ids.include? e.id }
|
||||
@enterprise_set.collection.select! { |e| touched_enterprises.include? e }
|
||||
flash[:error] = 'Update failed'
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
def for_order_cycle
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: ActiveModel::ArraySerializer.new( @collection,
|
||||
each_serializer: Api::Admin::ForOrderCycle::EnterpriseSerializer, spree_current_user: spree_current_user
|
||||
).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def build_resource_with_address
|
||||
@@ -83,10 +103,18 @@ module Admin
|
||||
end
|
||||
|
||||
def collection
|
||||
# TODO was ordered with is_distributor DESC as well, not sure why or how we want to sort this now
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
editable_enterprises.
|
||||
order('is_primary_producer ASC, name')
|
||||
case action
|
||||
when :for_order_cycle
|
||||
order_cycle = OrderCycle.find_by_id(params[:order_cycle_id]) if params[:order_cycle_id]
|
||||
coordinator = Enterprise.find_by_id(params[:coordinator_id]) if params[:coordinator_id]
|
||||
order_cycle = OrderCycle.new(coordinator: coordinator) if order_cycle.nil? && coordinator.present?
|
||||
return OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, order_cycle).visible_enterprises
|
||||
else
|
||||
# TODO was ordered with is_distributor DESC as well, not sure why or how we want to sort this now
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
editable_enterprises.
|
||||
order('is_primary_producer ASC, name')
|
||||
end
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
@@ -119,6 +147,14 @@ module Admin
|
||||
params[:enterprise][:owner_id] = spree_current_user.id unless spree_current_user.admin?
|
||||
end
|
||||
|
||||
def override_sells
|
||||
unless spree_current_user.admin?
|
||||
has_hub = spree_current_user.owned_enterprises.is_hub.any?
|
||||
new_enterprise_is_producer = Enterprise.new(params[:enterprise]).is_primary_producer
|
||||
params[:enterprise][:sells] = (has_hub && !new_enterprise_is_producer) ? 'any' : 'none'
|
||||
end
|
||||
end
|
||||
|
||||
def check_can_change_owner
|
||||
unless ( spree_current_user == @enterprise.owner ) || spree_current_user.admin?
|
||||
params[:enterprise].delete :owner_id
|
||||
@@ -139,9 +175,27 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def strip_new_properties
|
||||
unless spree_current_user.admin? || params[:enterprise][:producer_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:enterprise][:producer_properties_attributes].each do |key, property|
|
||||
params[:enterprise][:producer_properties_attributes].delete key unless names.include? property[:property_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def load_properties
|
||||
@properties = Spree::Property.pluck(:name)
|
||||
end
|
||||
|
||||
def setup_property
|
||||
@enterprise.producer_properties.build
|
||||
end
|
||||
|
||||
# Overriding method on Spree's resource controller
|
||||
def location_after_save
|
||||
if params[:enterprise].key? :producer_properties_attributes
|
||||
refered_from_edit = URI(request.referer).path == main_app.edit_admin_enterprise_path(@enterprise)
|
||||
if params[:enterprise].key?(:producer_properties_attributes) && !refered_from_edit
|
||||
main_app.admin_enterprises_path
|
||||
else
|
||||
main_app.edit_admin_enterprise_path(@enterprise)
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
require 'open_food_network/permissions'
|
||||
require 'open_food_network/order_cycle_permissions'
|
||||
require 'open_food_network/order_cycle_form_applicator'
|
||||
|
||||
module Admin
|
||||
class OrderCyclesController < ResourceController
|
||||
include OrderCyclesHelper
|
||||
|
||||
before_filter :load_order_cycle_set, :only => :index
|
||||
before_filter :load_data_for_index, :only => :index
|
||||
before_filter :require_coordinator, only: :new
|
||||
before_filter :remove_protected_attrs, only: [:update]
|
||||
before_filter :remove_unauthorized_bulk_attrs, only: [:bulk_update]
|
||||
around_filter :protect_invalid_destroy, only: :destroy
|
||||
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json
|
||||
format.json do
|
||||
render json: Api::Admin::OrderCycleSerializer.new(@order_cycle, current_user: spree_current_user).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json
|
||||
format.json do
|
||||
render json: Api::Admin::OrderCycleSerializer.new(@order_cycle, current_user: spree_current_user).to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,7 +35,7 @@ module Admin
|
||||
|
||||
respond_to do |format|
|
||||
if @order_cycle.save
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, order_cycle_permitted_enterprises).go!
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, spree_current_user).go!
|
||||
|
||||
flash[:notice] = 'Your order cycle has been created.'
|
||||
format.html { redirect_to admin_order_cycles_path }
|
||||
@@ -43,7 +52,7 @@ module Admin
|
||||
|
||||
respond_to do |format|
|
||||
if @order_cycle.update_attributes(params[:order_cycle])
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, order_cycle_permitted_enterprises).go!
|
||||
OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, spree_current_user).go!
|
||||
|
||||
flash[:notice] = 'Your order cycle has been updated.'
|
||||
format.html { redirect_to admin_order_cycles_path }
|
||||
@@ -72,18 +81,63 @@ module Admin
|
||||
|
||||
|
||||
protected
|
||||
def collection
|
||||
ocs = OrderCycle.managed_by(spree_current_user)
|
||||
def collection(show_more=false)
|
||||
ocs = OrderCycle.accessible_by(spree_current_user)
|
||||
|
||||
ocs.undated +
|
||||
ocs.soonest_closing +
|
||||
ocs.soonest_opening +
|
||||
ocs.most_recently_closed
|
||||
(show_more ? ocs.closed : ocs.recently_closed)
|
||||
end
|
||||
|
||||
private
|
||||
def load_order_cycle_set
|
||||
@order_cycle_set = OrderCycleSet.new :collection => collection
|
||||
def load_data_for_index
|
||||
@show_more = !!params[:show_more]
|
||||
@order_cycle_set = OrderCycleSet.new :collection => collection(@show_more)
|
||||
end
|
||||
|
||||
def require_coordinator
|
||||
if params[:coordinator_id] && @order_cycle.coordinator = permitted_coordinating_enterprises_for(@order_cycle).find_by_id(params[:coordinator_id])
|
||||
return
|
||||
end
|
||||
|
||||
available_coordinators = permitted_coordinating_enterprises_for(@order_cycle).select(&:confirmed?)
|
||||
case available_coordinators.count
|
||||
when 0
|
||||
flash[:error] = "None of your enterprises have permission to coordinate an order cycle"
|
||||
redirect_to main_app.admin_order_cycles_path
|
||||
when 1
|
||||
@order_cycle.coordinator = available_coordinators.first
|
||||
else
|
||||
flash[:error] = "You don't have permission to create an order cycle coordinated by that enterprise" if params[:coordinator_id]
|
||||
render :set_coordinator
|
||||
end
|
||||
end
|
||||
|
||||
def protect_invalid_destroy
|
||||
begin
|
||||
yield
|
||||
rescue ActiveRecord::InvalidForeignKey
|
||||
redirect_to main_app.admin_order_cycles_url
|
||||
flash[:error] = "That order cycle has been selected by a customer and cannot be deleted. To prevent customers from accessing it, please close it instead."
|
||||
end
|
||||
end
|
||||
|
||||
def remove_protected_attrs
|
||||
params[:order_cycle].delete :coordinator_id
|
||||
|
||||
unless Enterprise.managed_by(spree_current_user).include?(@order_cycle.coordinator)
|
||||
params[:order_cycle].delete_if{ |k,v| [:name, :orders_open_at, :orders_close_at].include? k.to_sym }
|
||||
end
|
||||
end
|
||||
|
||||
def remove_unauthorized_bulk_attrs
|
||||
params[:order_cycle_set][:collection_attributes].each do |i, hash|
|
||||
order_cycle = OrderCycle.find(hash[:id])
|
||||
unless Enterprise.managed_by(spree_current_user).include?(order_cycle.andand.coordinator)
|
||||
params[:order_cycle_set][:collection_attributes].delete i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,27 +2,18 @@ require 'open_food_network/spree_api_key_loader'
|
||||
|
||||
module Admin
|
||||
class VariantOverridesController < ResourceController
|
||||
include OrderCyclesHelper
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
|
||||
before_filter :load_spree_api_key, only: :index
|
||||
before_filter :load_data
|
||||
|
||||
def index
|
||||
@hubs = order_cycle_hub_enterprises(without_validation: true)
|
||||
|
||||
# Used in JS to look up the name of the producer of each product
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_producers
|
||||
|
||||
@hub_permissions = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_enterprises_per_hub
|
||||
@variant_overrides = VariantOverride.for_hubs(@hubs)
|
||||
end
|
||||
|
||||
|
||||
def bulk_update
|
||||
collection_hash = Hash[params[:variant_overrides].each_with_index.map { |vo, i| [i, vo] }]
|
||||
vo_set = VariantOverrideSet.new collection_attributes: collection_hash
|
||||
vo_set = VariantOverrideSet.new @variant_overrides, collection_attributes: collection_hash
|
||||
|
||||
# Ensure we're authorised to update all variant overrides
|
||||
vo_set.collection.each { |vo| authorize! :update, vo }
|
||||
@@ -40,6 +31,21 @@ module Admin
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def load_data
|
||||
@hubs = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_hubs.by_name
|
||||
|
||||
# Used in JS to look up the name of the producer of each product
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_producers
|
||||
|
||||
@hub_permissions = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
variant_override_enterprises_per_hub
|
||||
@variant_overrides = VariantOverride.for_hubs(@hubs)
|
||||
end
|
||||
|
||||
def collection
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,7 +63,9 @@ module Api
|
||||
end
|
||||
|
||||
def override_sells
|
||||
params[:enterprise][:sells] = 'unspecified'
|
||||
has_hub = current_api_user.owned_enterprises.is_hub.any?
|
||||
new_enterprise_is_producer = !!params[:enterprise][:is_primary_producer]
|
||||
params[:enterprise][:sells] = (has_hub && !new_enterprise_is_producer) ? 'any' : 'unspecified'
|
||||
end
|
||||
|
||||
def override_visible
|
||||
|
||||
@@ -19,6 +19,7 @@ class CheckoutController < Spree::CheckoutController
|
||||
|
||||
def update
|
||||
if @order.update_attributes(object_params)
|
||||
check_order_for_phantom_fees
|
||||
fire_event('spree.checkout.update')
|
||||
while @order.state != "complete"
|
||||
if @order.state == "payment"
|
||||
@@ -58,6 +59,20 @@ class CheckoutController < Spree::CheckoutController
|
||||
|
||||
private
|
||||
|
||||
def check_order_for_phantom_fees
|
||||
phantom_fees = @order.adjustments.joins('LEFT OUTER JOIN spree_line_items ON spree_line_items.id = spree_adjustments.source_id').
|
||||
where("originator_type = 'EnterpriseFee' AND source_type = 'Spree::LineItem' AND spree_line_items.id IS NULL")
|
||||
|
||||
if phantom_fees.any?
|
||||
Bugsnag.notify(RuntimeError.new("Phantom Fees"), {
|
||||
phantom_fees: {
|
||||
phantom_total: phantom_fees.sum(&:amount).to_s,
|
||||
phantom_fees: phantom_fees.as_json
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
# Copied and modified from spree. Remove check for order state, since the state machine is
|
||||
# progressed all the way in one go with the one page checkout.
|
||||
def object_params
|
||||
@@ -110,7 +125,7 @@ class CheckoutController < Spree::CheckoutController
|
||||
last_used_bill_address, last_used_ship_address = find_last_used_addresses(@order.email)
|
||||
preferred_bill_address, preferred_ship_address = spree_current_user.bill_address, spree_current_user.ship_address if spree_current_user.respond_to?(:bill_address) && spree_current_user.respond_to?(:ship_address)
|
||||
@order.bill_address ||= preferred_bill_address || last_used_bill_address || Spree::Address.default
|
||||
@order.ship_address ||= preferred_ship_address || last_used_ship_address || Spree::Address.default
|
||||
@order.ship_address ||= preferred_ship_address || last_used_ship_address || Spree::Address.default
|
||||
end
|
||||
|
||||
def after_payment
|
||||
|
||||
@@ -5,4 +5,8 @@ class GroupsController < BaseController
|
||||
def index
|
||||
@groups = EnterpriseGroup.on_front_page.by_position
|
||||
end
|
||||
|
||||
def show
|
||||
@group = EnterpriseGroup.find params[:id]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ Spree::Admin::ProductsController.class_eval do
|
||||
include OrderCyclesHelper
|
||||
before_filter :load_form_data, :only => [:bulk_edit, :new, :create, :edit, :update]
|
||||
before_filter :load_spree_api_key, :only => [:bulk_edit, :variant_overrides]
|
||||
before_filter :strip_new_properties, only: [:create, :update]
|
||||
|
||||
alias_method :location_after_save_original, :location_after_save
|
||||
|
||||
@@ -95,4 +96,13 @@ Spree::Admin::ProductsController.class_eval do
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).managed_product_enterprises.is_primary_producer.by_name
|
||||
@taxons = Spree::Taxon.order(:name)
|
||||
end
|
||||
|
||||
def strip_new_properties
|
||||
unless spree_current_user.admin? || params[:product][:product_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:product][:product_properties_attributes].each do |key, property|
|
||||
params[:product][:product_properties_attributes].delete key unless names.include? property[:property_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@ require 'open_food_network/order_grouper'
|
||||
require 'open_food_network/customers_report'
|
||||
require 'open_food_network/users_and_enterprises_report'
|
||||
require 'open_food_network/order_cycle_management_report'
|
||||
require 'open_food_network/sales_tax_report'
|
||||
|
||||
Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
@@ -27,7 +28,8 @@ Spree::Admin::ReportsController.class_eval do
|
||||
["Addresses", :addresses]
|
||||
],
|
||||
order_cycle_management: [
|
||||
["Payment Methods Report", :payment_methods_report]
|
||||
["Payment Methods Report", :payment_methods],
|
||||
["Delivery Report", :delivery]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -58,7 +60,6 @@ Spree::Admin::ReportsController.class_eval do
|
||||
@report_types = REPORT_TYPES[:customers]
|
||||
@report_type = params[:report_type]
|
||||
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params
|
||||
|
||||
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
@@ -68,14 +69,13 @@ Spree::Admin::ReportsController.class_eval do
|
||||
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user, params
|
||||
|
||||
@search = Spree::Order.complete.not_state(:canceled).managed_by(spree_current_user).search(params[:q])
|
||||
|
||||
@orders = @search.result
|
||||
|
||||
render_report(@report.header, @report.table, params[:csv], "order_cycle_management_#{timestamp}.csv")
|
||||
end
|
||||
|
||||
def orders_and_distributors
|
||||
params[:q] = {} unless params[:q]
|
||||
params[:q] ||= {}
|
||||
|
||||
if params[:q][:completed_at_gt].blank?
|
||||
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
|
||||
@@ -103,8 +103,38 @@ Spree::Admin::ReportsController.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
def sales_tax
|
||||
params[:q] ||= {}
|
||||
|
||||
if params[:q][:completed_at_gt].blank?
|
||||
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
|
||||
else
|
||||
params[:q][:completed_at_gt] = Time.zone.parse(params[:q][:completed_at_gt]).beginning_of_day rescue Time.zone.now.beginning_of_month
|
||||
end
|
||||
|
||||
if params[:q] && !params[:q][:completed_at_lt].blank?
|
||||
params[:q][:completed_at_lt] = Time.zone.parse(params[:q][:completed_at_lt]).end_of_day rescue ""
|
||||
end
|
||||
params[:q][:meta_sort] ||= "completed_at.desc"
|
||||
|
||||
@search = Spree::Order.complete.not_state(:canceled).managed_by(spree_current_user).search(params[:q])
|
||||
orders = @search.result
|
||||
@distributors = Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
|
||||
@report = OpenFoodNetwork::SalesTaxReport.new orders
|
||||
unless params[:csv]
|
||||
render :html => @report
|
||||
else
|
||||
csv_string = CSV.generate do |csv|
|
||||
csv << @report.header
|
||||
@report.table.each { |row| csv << row }
|
||||
end
|
||||
send_data csv_string, :filename => "sales_tax.csv"
|
||||
end
|
||||
end
|
||||
|
||||
def bulk_coop
|
||||
params[:q] = {} unless params[:q]
|
||||
params[:q] ||= {}
|
||||
|
||||
if params[:q][:completed_at_gt].blank?
|
||||
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
|
||||
@@ -257,7 +287,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
end
|
||||
|
||||
def payments
|
||||
params[:q] = {} unless params[:q]
|
||||
params[:q] ||= {}
|
||||
|
||||
if params[:q][:completed_at_gt].blank?
|
||||
params[:q][:completed_at_gt] = Time.zone.now.beginning_of_month
|
||||
@@ -495,18 +525,26 @@ Spree::Admin::ReportsController.class_eval do
|
||||
table_items = @line_items
|
||||
@include_blank = 'All'
|
||||
|
||||
header = ["Hub", "Customer", "Email", "Phone", "Producer", "Product", "Variant", "Amount", "Item (#{currency_symbol})", "Item + Fees (#{currency_symbol})", "Dist (#{currency_symbol})", "Ship (#{currency_symbol})", "Total (#{currency_symbol})", "Paid?",
|
||||
"Shipping", "Delivery?", "Ship street", "Ship street 2", "Ship city", "Ship postcode", "Ship state", "Order notes"]
|
||||
header = ["Hub", "Customer", "Email", "Phone", "Producer", "Product", "Variant",
|
||||
"Amount", "Item (#{currency_symbol})", "Item + Fees (#{currency_symbol})", "Admin & Handling (#{currency_symbol})", "Ship (#{currency_symbol})", "Total (#{currency_symbol})", "Paid?",
|
||||
"Shipping", "Delivery?",
|
||||
"Ship Street", "Ship Street 2", "Ship City", "Ship Postcode", "Ship State",
|
||||
"Comments", "SKU",
|
||||
"Order Cycle", "Payment Method", "Customer Code", "Tags",
|
||||
"Billing Street 1", "Billing Street 2", "Billing City", "Billing Postcode", "Billing State"
|
||||
]
|
||||
|
||||
rsa = proc { |line_items| line_items.first.order.shipping_method.andand.require_ship_address }
|
||||
|
||||
columns = [ proc { |line_items| line_items.first.order.distributor.name },
|
||||
columns = [
|
||||
proc { |line_items| line_items.first.order.distributor.name },
|
||||
proc { |line_items| line_items.first.order.bill_address.firstname + " " + line_items.first.order.bill_address.lastname },
|
||||
proc { |line_items| line_items.first.order.email },
|
||||
proc { |line_items| line_items.first.order.bill_address.phone },
|
||||
proc { |line_items| line_items.first.variant.product.supplier.name },
|
||||
proc { |line_items| line_items.first.variant.product.name },
|
||||
proc { |line_items| line_items.first.variant.full_name },
|
||||
|
||||
proc { |line_items| line_items.sum { |li| li.quantity } },
|
||||
proc { |line_items| line_items.sum { |li| li.amount } },
|
||||
proc { |line_items| line_items.sum { |li| li.amount_with_adjustments } },
|
||||
@@ -517,25 +555,40 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
proc { |line_items| line_items.first.order.shipping_method.andand.name },
|
||||
proc { |line_items| rsa.call(line_items) ? 'Y' : 'N' },
|
||||
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.address1 if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.address2 if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.city if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.zipcode if rsa.call(line_items) },
|
||||
proc { |line_items| line_items.first.order.ship_address.andand.state if rsa.call(line_items) },
|
||||
|
||||
proc { |line_items| line_items.first.order.special_instructions }]
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| line_items.first.variant.product.sku },
|
||||
|
||||
proc { |line_items| line_items.first.order.order_cycle.andand.name },
|
||||
proc { |line_items| line_items.first.order.payments.first.andand.payment_method.andand.name },
|
||||
proc { |line_items| line_items.first.order.user.andand.customer_of(line_items.first.order.distributor).andand.code },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.address1 },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.address2 },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.city },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.zipcode },
|
||||
proc { |line_items| line_items.first.order.bill_address.andand.state } ]
|
||||
|
||||
rules = [ { group_by: proc { |line_item| line_item.order.distributor },
|
||||
sort_by: proc { |distributor| distributor.name } },
|
||||
{ group_by: proc { |line_item| line_item.order },
|
||||
sort_by: proc { |order| order.bill_address.lastname + " " + order.bill_address.firstname },
|
||||
summary_columns: [ proc { |line_items| line_items.first.order.distributor.name },
|
||||
summary_columns: [
|
||||
proc { |line_items| line_items.first.order.distributor.name },
|
||||
proc { |line_items| line_items.first.order.bill_address.firstname + " " + line_items.first.order.bill_address.lastname },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "TOTAL" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| line_items.sum { |li| li.amount } },
|
||||
proc { |line_items| line_items.sum { |li| li.amount_with_adjustments } },
|
||||
@@ -546,13 +599,27 @@ Spree::Admin::ReportsController.class_eval do
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" } ] },
|
||||
proc { |line_items| line_items.first.order.special_instructions } ,
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| line_items.first.order.order_cycle.andand.name },
|
||||
proc { |line_items| line_items.first.order.payments.first.andand.payment_method.andand.name },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" },
|
||||
proc { |line_items| "" }
|
||||
] },
|
||||
|
||||
{ group_by: proc { |line_item| line_item.variant.product },
|
||||
sort_by: proc { |product| product.name } },
|
||||
@@ -641,7 +708,8 @@ Spree::Admin::ReportsController.class_eval do
|
||||
:products_and_inventory => {:name => "Products & Inventory", :description => ''},
|
||||
:sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" },
|
||||
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" },
|
||||
:order_cycle_management => {:name => "Order Cycle Management", :description => ''}
|
||||
:order_cycle_management => {:name => "Order Cycle Management", :description => ''},
|
||||
:sales_tax => { :name => "Sales Tax", :description => "Sales Tax For Orders" }
|
||||
}
|
||||
# Return only reports the user is authorized to view.
|
||||
reports.select { |action| can? action, :report }
|
||||
|
||||
@@ -20,15 +20,6 @@ Spree::Api::ProductsController.class_eval do
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def distributable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
order_cycle_enterprises.is_primary_producer.by_name
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
|
||||
@@ -62,6 +62,10 @@ module Admin
|
||||
admin_inject_json_ams_array "ofn.admin", "variantOverrides", @variant_overrides, Api::Admin::VariantOverrideSerializer
|
||||
end
|
||||
|
||||
def admin_inject_order_cycle_instance
|
||||
render partial: "admin/json/injection_ams", locals: {ngModule: 'admin.order_cycles', name: 'ocInstance', json: "{coordinator_id: '#{@order_cycle.coordinator.id}'}"}
|
||||
end
|
||||
|
||||
def admin_inject_spree_api_key
|
||||
render partial: "admin/json/injection_ams", locals: {ngModule: 'ofn.admin', name: 'SpreeApiKey', json: "'#{@spree_api_key.to_s}'"}
|
||||
end
|
||||
|
||||
@@ -1,2 +1,23 @@
|
||||
module GroupsHelper
|
||||
|
||||
def link_to_service(baseurl, name, html_options = {})
|
||||
return if name.blank?
|
||||
html_options = html_options.merge target: '_blank'
|
||||
link_to ext_url(baseurl, name), html_options do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
def ext_url(prefix, url)
|
||||
if url =~ /^https?:\/\//i
|
||||
url
|
||||
else
|
||||
prefix + url
|
||||
end
|
||||
end
|
||||
|
||||
def strip_url(url)
|
||||
url.andand.sub(/^https?:\/\//i, '')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -3,41 +3,32 @@ module OrderCyclesHelper
|
||||
@current_order_cycle ||= current_order(false).andand.order_cycle
|
||||
end
|
||||
|
||||
def order_cycle_permitted_enterprises
|
||||
OpenFoodNetwork::Permissions.new(spree_current_user).order_cycle_enterprises
|
||||
def permitted_enterprises_for(order_cycle)
|
||||
OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, order_cycle).visible_enterprises
|
||||
end
|
||||
|
||||
def order_cycle_producer_enterprises
|
||||
order_cycle_permitted_enterprises.is_primary_producer.by_name
|
||||
def permitted_producer_enterprises_for(order_cycle)
|
||||
permitted_enterprises_for(order_cycle).is_primary_producer.by_name
|
||||
end
|
||||
|
||||
def order_cycle_coordinating_enterprises
|
||||
order_cycle_permitted_enterprises.is_distributor.by_name
|
||||
def permitted_producer_enterprise_options_for(order_cycle)
|
||||
validated_enterprise_options permitted_producer_enterprises_for(order_cycle), confirmed: true
|
||||
end
|
||||
|
||||
def order_cycle_hub_enterprises(options={})
|
||||
enterprises = order_cycle_permitted_enterprises.is_distributor.by_name
|
||||
def permitted_coordinating_enterprises_for(order_cycle)
|
||||
Enterprise.managed_by(spree_current_user).is_distributor.by_name
|
||||
end
|
||||
|
||||
if options[:without_validation]
|
||||
enterprises
|
||||
else
|
||||
enterprises.map do |e|
|
||||
disabled_message = nil
|
||||
if e.shipping_methods.empty? && e.payment_methods.available.empty?
|
||||
disabled_message = 'no shipping or payment methods'
|
||||
elsif e.shipping_methods.empty?
|
||||
disabled_message = 'no shipping methods'
|
||||
elsif e.payment_methods.available.empty?
|
||||
disabled_message = 'no payment methods'
|
||||
end
|
||||
def permitted_coordinating_enterprise_options_for(order_cycle)
|
||||
validated_enterprise_options permitted_coordinating_enterprises_for(order_cycle), confirmed: true
|
||||
end
|
||||
|
||||
if disabled_message
|
||||
["#{e.name} (#{disabled_message})", e.id, {disabled: true}]
|
||||
else
|
||||
[e.name, e.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
def permitted_hub_enterprises_for(order_cycle)
|
||||
permitted_enterprises_for(order_cycle).is_hub.by_name
|
||||
end
|
||||
|
||||
def permitted_hub_enterprise_options_for(order_cycle)
|
||||
validated_enterprise_options permitted_hub_enterprises_for(order_cycle), confirmed: true, shipping_and_payment_methods: true
|
||||
end
|
||||
|
||||
def order_cycle_status_class(order_cycle)
|
||||
@@ -68,8 +59,12 @@ module OrderCyclesHelper
|
||||
OrderCycle.active.with_distributor(@distributor).present?
|
||||
end
|
||||
|
||||
def order_cycles_simple_view
|
||||
@order_cycles_simple_view ||= !OpenFoodNetwork::Permissions.new(spree_current_user).can_manage_complex_order_cycles?
|
||||
def order_cycles_simple_index
|
||||
@order_cycles_simple_index ||= !OpenFoodNetwork::Permissions.new(spree_current_user).can_manage_complex_order_cycles?
|
||||
end
|
||||
|
||||
def order_cycles_simple_form
|
||||
@order_cycles_simple_form ||= @order_cycle.coordinator.sells == 'own'
|
||||
end
|
||||
|
||||
def order_cycles_enabled?
|
||||
@@ -80,4 +75,36 @@ module OrderCyclesHelper
|
||||
order_cycle.exchanges.to_enterprises(current_distributor).outgoing.first.pickup_time
|
||||
end
|
||||
|
||||
def can_delete?(order_cycle)
|
||||
Spree::Order.where(order_cycle_id: order_cycle).none?
|
||||
end
|
||||
|
||||
def viewing_as_coordinator_of?(order_cycle)
|
||||
Enterprise.managed_by(spree_current_user).include? order_cycle.coordinator
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validated_enterprise_options(enterprises, options={})
|
||||
enterprises.map do |e|
|
||||
disabled_message = nil
|
||||
if options[:shipping_and_payment_methods] && (e.shipping_methods.empty? || e.payment_methods.available.empty?)
|
||||
if e.shipping_methods.empty? && e.payment_methods.available.empty?
|
||||
disabled_message = 'no shipping or payment methods'
|
||||
elsif e.shipping_methods.empty?
|
||||
disabled_message = 'no shipping methods'
|
||||
elsif e.payment_methods.available.empty?
|
||||
disabled_message = 'no payment methods'
|
||||
end
|
||||
elsif options[:confirmed] && !e.confirmed?
|
||||
disabled_message = 'unconfirmed'
|
||||
end
|
||||
|
||||
if disabled_message
|
||||
["#{e.name} (#{disabled_message})", e.id, {disabled: true}]
|
||||
else
|
||||
[e.name, e.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
6
app/jobs/confirm_order_job.rb
Normal file
6
app/jobs/confirm_order_job.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
ConfirmOrderJob = Struct.new(:order_id) do
|
||||
def perform
|
||||
Spree::OrderMailer.confirm_email_for_customer(order_id).deliver
|
||||
Spree::OrderMailer.confirm_email_for_shop(order_id).deliver
|
||||
end
|
||||
end
|
||||
6
app/jobs/confirm_signup_job.rb
Normal file
6
app/jobs/confirm_signup_job.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
ConfirmSignupJob = Struct.new(:user_id) do
|
||||
def perform
|
||||
user = Spree::User.find user_id
|
||||
Spree::UserMailer.signup_confirmation(user).deliver
|
||||
end
|
||||
end
|
||||
6
app/jobs/welcome_enterprise_job.rb
Normal file
6
app/jobs/welcome_enterprise_job.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
WelcomeEnterpriseJob = Struct.new(:enterprise_id) do
|
||||
def perform
|
||||
enterprise = Enterprise.find enterprise_id
|
||||
EnterpriseMailer.welcome(enterprise).deliver
|
||||
end
|
||||
end
|
||||
10
app/models/customer.rb
Normal file
10
app/models/customer.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class Customer < ActiveRecord::Base
|
||||
belongs_to :enterprise
|
||||
belongs_to :user, :class_name => Spree.user_class
|
||||
|
||||
validates :code, presence: true, uniqueness: {scope: :enterprise_id}
|
||||
validates :email, presence: true
|
||||
validates :enterprise_id, presence: true
|
||||
|
||||
scope :of, ->(enterprise) { where(enterprise_id: enterprise) }
|
||||
end
|
||||
@@ -15,6 +15,7 @@ class Enterprise < ActiveRecord::Base
|
||||
|
||||
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
|
||||
has_many :producer_properties, foreign_key: 'producer_id'
|
||||
has_many :properties, through: :producer_properties
|
||||
has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy
|
||||
has_many :distributed_orders, :class_name => 'Spree::Order', :foreign_key => 'distributor_id'
|
||||
belongs_to :address, :class_name => 'Spree::Address'
|
||||
@@ -114,6 +115,9 @@ class Enterprise < ActiveRecord::Base
|
||||
scope :with_distributed_products_outer,
|
||||
joins('LEFT OUTER JOIN product_distributions ON product_distributions.distributor_id = enterprises.id').
|
||||
joins('LEFT OUTER JOIN spree_products ON spree_products.id = product_distributions.product_id')
|
||||
scope :with_order_cycles_as_supplier_outer,
|
||||
joins("LEFT OUTER JOIN exchanges ON (exchanges.sender_id = enterprises.id AND exchanges.incoming = 't')").
|
||||
joins('LEFT OUTER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)')
|
||||
scope :with_order_cycles_as_distributor_outer,
|
||||
joins("LEFT OUTER JOIN exchanges ON (exchanges.receiver_id = enterprises.id AND exchanges.incoming = 'f')").
|
||||
joins('LEFT OUTER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)')
|
||||
@@ -253,6 +257,10 @@ class Enterprise < ActiveRecord::Base
|
||||
self.sells != "none"
|
||||
end
|
||||
|
||||
def is_hub
|
||||
self.sells == 'any'
|
||||
end
|
||||
|
||||
# Simplify enterprise categories for frontend logic and icons, and maybe other things.
|
||||
def category
|
||||
# Make this crazy logic human readable so we can argue about it sanely.
|
||||
@@ -340,7 +348,7 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def send_welcome_email
|
||||
EnterpriseMailer.welcome(self).deliver
|
||||
Delayed::Job.enqueue WelcomeEnterpriseJob.new(self.id)
|
||||
end
|
||||
|
||||
def strip_url(url)
|
||||
@@ -366,26 +374,30 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def relate_to_owners_enterprises
|
||||
# When a new enterprise is created, we relate them to all enterprises owned by
|
||||
# the same owner, in both directions. So all enterprises owned by the same owner
|
||||
# will have permissions to every other one, in both directions.
|
||||
# When a new producer is created, it grants permissions to all pre-existing hubs
|
||||
# When a new hub is created,
|
||||
# - it grants permissions to all pre-existing hubs
|
||||
# - all producers grant permission to it
|
||||
|
||||
enterprises = owner.owned_enterprises.where('enterprises.id != ?', self)
|
||||
|
||||
enterprises.each do |enterprise|
|
||||
# We grant permissions to all pre-existing hubs
|
||||
hub_permissions = [:add_to_order_cycle]
|
||||
hub_permissions << :create_variant_overrides if is_primary_producer
|
||||
enterprises.is_hub.each do |enterprise|
|
||||
EnterpriseRelationship.create!(parent: self,
|
||||
child: enterprise,
|
||||
permissions_list: [:add_to_order_cycle,
|
||||
:manage_products,
|
||||
:edit_profile,
|
||||
:create_variant_overrides])
|
||||
permissions_list: hub_permissions)
|
||||
end
|
||||
|
||||
EnterpriseRelationship.create!(parent: enterprise,
|
||||
child: self,
|
||||
permissions_list: [:add_to_order_cycle,
|
||||
:manage_products,
|
||||
:edit_profile,
|
||||
:create_variant_overrides])
|
||||
# All pre-existing producers grant permission to new hubs
|
||||
if is_hub
|
||||
enterprises.is_primary_producer.each do |enterprise|
|
||||
EnterpriseRelationship.create!(parent: enterprise,
|
||||
child: self,
|
||||
permissions_list: [:add_to_order_cycle,
|
||||
:create_variant_overrides])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
class EnterpriseFee < ActiveRecord::Base
|
||||
belongs_to :enterprise
|
||||
belongs_to :tax_category, class_name: 'Spree::TaxCategory', foreign_key: 'tax_category_id'
|
||||
has_and_belongs_to_many :order_cycles, join_table: 'coordinator_fees'
|
||||
has_many :exchange_fees, dependent: :destroy
|
||||
has_many :exchanges, through: :exchange_fees
|
||||
@@ -8,7 +9,7 @@ class EnterpriseFee < ActiveRecord::Base
|
||||
|
||||
calculated_adjustments
|
||||
|
||||
attr_accessible :enterprise_id, :fee_type, :name, :calculator_type
|
||||
attr_accessible :enterprise_id, :fee_type, :name, :tax_category_id, :calculator_type
|
||||
|
||||
FEE_TYPES = %w(packing transport admin sales fundraising)
|
||||
PER_ORDER_CALCULATORS = ['Spree::Calculator::FlatRate', 'Spree::Calculator::FlexiRate']
|
||||
@@ -19,6 +20,7 @@ class EnterpriseFee < ActiveRecord::Base
|
||||
|
||||
|
||||
scope :for_enterprise, lambda { |enterprise| where(enterprise_id: enterprise) }
|
||||
scope :for_enterprises, lambda { |enterprises| where(enterprise_id: enterprises) }
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
require 'open_food_network/locking'
|
||||
|
||||
class EnterpriseGroup < ActiveRecord::Base
|
||||
acts_as_list
|
||||
|
||||
has_and_belongs_to_many :enterprises
|
||||
belongs_to :owner, class_name: 'Spree::User', foreign_key: :owner_id, inverse_of: :owned_groups
|
||||
belongs_to :address, :class_name => 'Spree::Address'
|
||||
accepts_nested_attributes_for :address
|
||||
validates :address, presence: true, associated: true
|
||||
before_validation :set_undefined_address_fields
|
||||
before_validation :set_unused_address_fields
|
||||
after_find :unset_undefined_address_fields
|
||||
after_save :unset_undefined_address_fields
|
||||
|
||||
validates :name, presence: true
|
||||
validates :description, presence: true
|
||||
|
||||
attr_accessible :name, :description, :long_description, :on_front_page, :enterprise_ids
|
||||
attr_accessible :owner_id
|
||||
attr_accessible :logo, :promo_image
|
||||
attr_accessible :address_attributes
|
||||
attr_accessible :email, :website, :facebook, :instagram, :linkedin, :twitter
|
||||
|
||||
delegate :phone, :address1, :address2, :city, :zipcode, :state, :country, :to => :address
|
||||
|
||||
has_attached_file :logo,
|
||||
styles: {medium: "100x100"},
|
||||
@@ -28,4 +43,32 @@ class EnterpriseGroup < ActiveRecord::Base
|
||||
|
||||
scope :by_position, order('position ASC')
|
||||
scope :on_front_page, where(on_front_page: true)
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
scoped
|
||||
else
|
||||
where('owner_id = ?', user.id)
|
||||
end
|
||||
}
|
||||
|
||||
def set_unused_address_fields
|
||||
address.firstname = address.lastname = 'unused' if address.present?
|
||||
end
|
||||
|
||||
def set_undefined_address_fields
|
||||
return unless address.present?
|
||||
address.phone.present? || address.phone = 'undefined'
|
||||
address.address1.present? || address.address1 = 'undefined'
|
||||
address.city.present? || address.city = 'undefined'
|
||||
address.zipcode.present? || address.zipcode = 'undefined'
|
||||
end
|
||||
|
||||
def unset_undefined_address_fields
|
||||
return unless address.present?
|
||||
address.phone.sub!(/^undefined$/, '')
|
||||
address.address1.sub!(/^undefined$/, '')
|
||||
address.city.sub!(/^undefined$/, '')
|
||||
address.zipcode.sub!(/^undefined$/, '')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -28,4 +28,8 @@ class EnterpriseRelationship < ActiveRecord::Base
|
||||
def permissions_list=(perms)
|
||||
perms.andand.each { |name| permissions.build name: name }
|
||||
end
|
||||
|
||||
def has_permission?(name)
|
||||
permissions.map(&:name).map(&:to_sym).include? name.to_sym
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,6 +22,7 @@ class Exchange < ActiveRecord::Base
|
||||
scope :to_enterprise, lambda { |enterprise| where(receiver_id: enterprise) }
|
||||
scope :from_enterprises, lambda { |enterprises| where('exchanges.sender_id IN (?)', enterprises) }
|
||||
scope :to_enterprises, lambda { |enterprises| where('exchanges.receiver_id IN (?)', enterprises) }
|
||||
scope :involving, lambda { |enterprises| where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises).select('DISTINCT exchanges.*') }
|
||||
scope :supplying_to, lambda { |distributor| where('exchanges.incoming OR exchanges.receiver_id = ?', distributor) }
|
||||
scope :with_variant, lambda { |variant| joins(:exchange_variants).where('exchange_variants.variant_id = ?', variant) }
|
||||
scope :with_any_variant, lambda { |variants| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', variants).select('DISTINCT exchanges.*') }
|
||||
|
||||
@@ -19,7 +19,14 @@ class OrderCycle < ActiveRecord::Base
|
||||
scope :undated, where(orders_open_at: nil, orders_close_at: nil)
|
||||
|
||||
scope :soonest_closing, lambda { active.order('order_cycles.orders_close_at ASC') }
|
||||
# TODO This method returns all the closed orders. So maybe we can replace it with :recently_closed.
|
||||
scope :most_recently_closed, lambda { closed.order('order_cycles.orders_close_at DESC') }
|
||||
|
||||
scope :recently_closed, -> {
|
||||
closed.
|
||||
where("order_cycles.orders_close_at >= ?", 31.days.ago).
|
||||
order("order_cycles.orders_close_at DESC") }
|
||||
|
||||
scope :soonest_opening, lambda { upcoming.order('order_cycles.orders_open_at ASC') }
|
||||
|
||||
scope :distributing_product, lambda { |product|
|
||||
|
||||
@@ -6,7 +6,9 @@ class AbilityDecorator
|
||||
def initialize(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
|
||||
add_product_management_abilities user if can_manage_products? user
|
||||
add_order_cycle_management_abilities user if can_manage_order_cycles? user
|
||||
add_order_management_abilities user if can_manage_orders? user
|
||||
add_relationship_management_abilities user if can_manage_relationships? user
|
||||
end
|
||||
@@ -21,12 +23,24 @@ class AbilityDecorator
|
||||
user.enterprises.present?
|
||||
end
|
||||
|
||||
# Users can manage a group if they have one.
|
||||
def can_manage_groups?(user)
|
||||
user.owned_groups.present?
|
||||
end
|
||||
|
||||
# Users can manage products if they have an enterprise that is not a profile.
|
||||
def can_manage_products?(user)
|
||||
can_manage_enterprises?(user) &&
|
||||
user.enterprises.any? { |e| e.category != :hub_profile && e.producer_profile_only != true }
|
||||
end
|
||||
|
||||
# Users can manage order cycles if they manage a sells own/any enterprise
|
||||
# OR if they manage a producer which is included in any order cycles
|
||||
def can_manage_order_cycles?(user)
|
||||
can_manage_orders?(user) ||
|
||||
OrderCycle.accessible_by(user).any?
|
||||
end
|
||||
|
||||
# Users can manage orders if they have a sells own/any enterprise.
|
||||
def can_manage_orders?(user)
|
||||
( user.enterprises.map(&:sells) & %w(own any) ).any?
|
||||
@@ -41,6 +55,14 @@ class AbilityDecorator
|
||||
can [:create], Enterprise
|
||||
end
|
||||
|
||||
def add_group_management_abilities(user)
|
||||
can [:admin, :index], :overview
|
||||
can [:admin, :index], EnterpriseGroup
|
||||
can [:read, :edit, :update], EnterpriseGroup do |group|
|
||||
user.owned_groups.include? group
|
||||
end
|
||||
end
|
||||
|
||||
def add_enterprise_management_abilities(user)
|
||||
# Spree performs authorize! on (:create, nil) when creating a new order from admin, and also (:search, nil)
|
||||
# when searching for variants to add to the order
|
||||
@@ -81,7 +103,7 @@ class AbilityDecorator
|
||||
|
||||
can [:admin, :index, :read, :update, :bulk_update], VariantOverride do |vo|
|
||||
hub_auth = OpenFoodNetwork::Permissions.new(user).
|
||||
order_cycle_enterprises.is_distributor.
|
||||
variant_override_hubs.
|
||||
include? vo.hub
|
||||
|
||||
producer_auth = OpenFoodNetwork::Permissions.new(user).
|
||||
@@ -101,6 +123,17 @@ class AbilityDecorator
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory], :report
|
||||
end
|
||||
|
||||
def add_order_cycle_management_abilities(user)
|
||||
can [:admin, :index, :read, :edit, :update], OrderCycle do |order_cycle|
|
||||
OrderCycle.accessible_by(user).include? order_cycle
|
||||
end
|
||||
can [:bulk_update, :clone, :destroy], OrderCycle do |order_cycle|
|
||||
user.enterprises.include? order_cycle.coordinator
|
||||
end
|
||||
can [:for_order_cycle], Enterprise
|
||||
can [:for_order_cycle], EnterpriseFee
|
||||
end
|
||||
|
||||
def add_order_management_abilities(user)
|
||||
# Enterprise User can only access orders that they are a distributor for
|
||||
can [:index, :create], Spree::Order
|
||||
@@ -118,10 +151,6 @@ class AbilityDecorator
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::ReturnAuthorization
|
||||
|
||||
can [:create], OrderCycle
|
||||
can [:admin, :index, :read, :edit, :update, :bulk_update, :clone], OrderCycle do |order_cycle|
|
||||
user.enterprises.include? order_cycle.coordinator
|
||||
end
|
||||
can [:for_order_cycle], Enterprise
|
||||
|
||||
can [:admin, :index, :read, :create, :edit, :update], ExchangeVariant
|
||||
can [:admin, :index, :read, :create, :edit, :update], Exchange
|
||||
@@ -139,7 +168,7 @@ class AbilityDecorator
|
||||
end
|
||||
|
||||
# Reports page
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report
|
||||
can [:admin, :index, :customers, :group_buys, :bulk_coop, :sales_tax, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -3,5 +3,17 @@ module Spree
|
||||
has_one :metadata, class_name: 'AdjustmentMetadata', dependent: :destroy
|
||||
|
||||
scope :enterprise_fee, where(originator_type: 'EnterpriseFee')
|
||||
scope :included_tax, where(originator_type: 'Spree::TaxRate', adjustable_type: 'Spree::LineItem')
|
||||
|
||||
attr_accessible :included_tax
|
||||
|
||||
def set_included_tax!(rate)
|
||||
tax = amount - (amount / (1 + rate))
|
||||
set_absolute_included_tax! tax
|
||||
end
|
||||
|
||||
def set_absolute_included_tax!(tax)
|
||||
update_attributes! included_tax: tax.round(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
Spree::AppConfiguration.class_eval do
|
||||
# This file decorates the existing preferences file defined by Spree.
|
||||
# It allows us to add our own global configuration variables, which
|
||||
# we can allow to be modified in the UI by adding appropriate form
|
||||
# elements to existing or new configuration pages.
|
||||
# This file decorates the existing preferences file defined by Spree.
|
||||
# It allows us to add our own global configuration variables, which
|
||||
# we can allow to be modified in the UI by adding appropriate form
|
||||
# elements to existing or new configuration pages.
|
||||
|
||||
# Tax Preferences
|
||||
preference :products_require_tax_category, :boolean, default: false
|
||||
end
|
||||
# Tax Preferences
|
||||
preference :products_require_tax_category, :boolean, default: false
|
||||
preference :shipping_tax_rate, :decimal, default: 0
|
||||
end
|
||||
|
||||
@@ -26,6 +26,7 @@ Spree::LineItem.class_eval do
|
||||
def price_with_adjustments
|
||||
# EnterpriseFee#create_locked_adjustment applies adjustments on line items to their parent order,
|
||||
# so line_item.adjustments returns an empty array
|
||||
return 0 if quantity == 0
|
||||
(price + order.adjustments.where(source_id: id).sum(&:amount) / quantity).round(2)
|
||||
end
|
||||
|
||||
|
||||
7
app/models/spree/money_decorator.rb
Normal file
7
app/models/spree/money_decorator.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
Spree::Money.class_eval do
|
||||
|
||||
# return the currency symbol (on it's own) for the current default currency
|
||||
def self.currency_symbol
|
||||
Money.new(0, Spree::Config[:currency]).symbol
|
||||
end
|
||||
end
|
||||
@@ -68,7 +68,7 @@ Spree::Order.class_eval do
|
||||
|
||||
scope :with_payment_method_name, lambda { |payment_method_name|
|
||||
joins(:payments => :payment_method).
|
||||
where('spree_payment_methods.name = ?', payment_method_name).
|
||||
where('spree_payment_methods.name IN (?)', payment_method_name).
|
||||
select('DISTINCT spree_orders.*')
|
||||
}
|
||||
|
||||
@@ -103,13 +103,17 @@ Spree::Order.class_eval do
|
||||
def add_variant(variant, quantity = 1, max_quantity = nil, currency = nil)
|
||||
line_items(:reload)
|
||||
current_item = find_line_item_by_variant(variant)
|
||||
if current_item
|
||||
Bugsnag.notify(RuntimeError.new("Order populator weirdness"), {
|
||||
|
||||
# Notify bugsnag if we get line items with a quantity of zero
|
||||
if quantity == 0
|
||||
Bugsnag.notify(RuntimeError.new("Zero Quantity Line Item"), {
|
||||
current_item: current_item.as_json,
|
||||
line_items: line_items.map(&:id),
|
||||
reloaded: line_items(:reload).map(&:id),
|
||||
variant: variant.as_json
|
||||
})
|
||||
end
|
||||
|
||||
if current_item
|
||||
current_item.quantity = quantity
|
||||
current_item.max_quantity = max_quantity
|
||||
|
||||
@@ -198,16 +202,21 @@ Spree::Order.class_eval do
|
||||
Spree::ShippingMethod.all_available(self, display_on)
|
||||
end
|
||||
|
||||
def shipping_tax
|
||||
adjustments(:reload).shipping.sum &:included_tax
|
||||
end
|
||||
|
||||
def enterprise_fee_tax
|
||||
adjustments(:reload).enterprise_fee.sum &:included_tax
|
||||
end
|
||||
|
||||
def total_tax
|
||||
(adjustments + price_adjustments).sum &:included_tax
|
||||
end
|
||||
|
||||
# Overrride of Spree method, that allows us to send separate confirmation emails to user and shop owners
|
||||
def deliver_order_confirmation_email
|
||||
begin
|
||||
Spree::OrderMailer.confirm_email_for_customer(self.id).deliver
|
||||
Spree::OrderMailer.confirm_email_for_shop(self.id).deliver
|
||||
rescue Exception => e
|
||||
Bugsnag.notify(e)
|
||||
logger.error("#{e.class.name}: #{e.message}")
|
||||
logger.error(e.backtrace * "\n")
|
||||
end
|
||||
Delayed::Job.enqueue ConfirmOrderJob.new(id)
|
||||
end
|
||||
|
||||
|
||||
|
||||
11
app/models/spree/shipment_decorator.rb
Normal file
11
app/models/spree/shipment_decorator.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
module Spree
|
||||
Shipment.class_eval do
|
||||
def ensure_correct_adjustment_with_included_tax
|
||||
ensure_correct_adjustment_without_included_tax
|
||||
|
||||
adjustment.set_included_tax! Config.shipping_tax_rate if Config.shipment_inc_vat
|
||||
end
|
||||
|
||||
alias_method_chain :ensure_correct_adjustment, :included_tax
|
||||
end
|
||||
end
|
||||
3
app/models/spree/shipping_category_decorator.rb
Normal file
3
app/models/spree/shipping_category_decorator.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
Spree::ShippingCategory.class_eval do
|
||||
attr_accessible :temperature_controlled
|
||||
end
|
||||
12
app/models/spree/tax_rate_decorator.rb
Normal file
12
app/models/spree/tax_rate_decorator.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
Spree::TaxRate.class_eval do
|
||||
def adjust_with_included_tax(order)
|
||||
adjust_without_included_tax(order)
|
||||
|
||||
order.reload
|
||||
(order.adjustments.tax + order.price_adjustments).each do |a|
|
||||
a.set_absolute_included_tax! a.amount
|
||||
end
|
||||
end
|
||||
|
||||
alias_method_chain :adjust, :included_tax
|
||||
end
|
||||
@@ -2,7 +2,9 @@ Spree.user_class.class_eval do
|
||||
has_many :enterprise_roles, :dependent => :destroy
|
||||
has_many :enterprises, through: :enterprise_roles
|
||||
has_many :owned_enterprises, class_name: 'Enterprise', foreign_key: :owner_id, inverse_of: :owner
|
||||
has_many :owned_groups, class_name: 'EnterpriseGroup', foreign_key: :owner_id, inverse_of: :owner
|
||||
has_one :cart
|
||||
has_many :customers
|
||||
|
||||
accepts_nested_attributes_for :enterprise_roles, :allow_destroy => true
|
||||
|
||||
@@ -11,6 +13,7 @@ Spree.user_class.class_eval do
|
||||
|
||||
validate :limit_owned_enterprises
|
||||
|
||||
|
||||
def known_users
|
||||
if admin?
|
||||
Spree::User.scoped
|
||||
@@ -29,14 +32,19 @@ Spree.user_class.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
def customer_of(enterprise)
|
||||
customers.of(enterprise).first
|
||||
end
|
||||
|
||||
def send_signup_confirmation
|
||||
Spree::UserMailer.signup_confirmation(self).deliver
|
||||
Delayed::Job.enqueue ConfirmSignupJob.new(id)
|
||||
end
|
||||
|
||||
def can_own_more_enterprises?
|
||||
owned_enterprises(:reload).size < enterprise_limit
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def limit_owned_enterprises
|
||||
|
||||
@@ -76,7 +76,9 @@ Spree::Variant.class_eval do
|
||||
|
||||
def full_name
|
||||
return unit_to_display if display_name.blank?
|
||||
display_name + " (" + unit_to_display + ")"
|
||||
return display_name if display_name.downcase.include? unit_to_display.downcase
|
||||
return unit_to_display if unit_to_display.downcase.include? display_name.downcase
|
||||
"#{display_name} (#{unit_to_display})"
|
||||
end
|
||||
|
||||
def name_to_display
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class VariantOverrideSet < ModelSet
|
||||
def initialize(attributes={})
|
||||
super(VariantOverride, VariantOverride.all, attributes, nil,
|
||||
def initialize(collection, attributes={})
|
||||
super(VariantOverride, collection, attributes, nil,
|
||||
proc { |attrs| attrs['price'].blank? && attrs['count_on_hand'].blank? } )
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/shared/_configuration_menu",
|
||||
:name => "add_enterprise_groups_to_admin_configurations_menu",
|
||||
:insert_bottom => "[data-hook='admin_configurations_sidebar_menu']",
|
||||
:text => "<li><%= link_to 'Enterprise Groups', main_app.admin_enterprise_groups_path %></li>",
|
||||
:partial => 'enterprise_groups/admin_configurations_menu',
|
||||
:original => '')
|
||||
@@ -1,5 +0,0 @@
|
||||
Deface::Override.new(:virtual_path => "spree/layouts/admin",
|
||||
:name => "add_enterprises_admin_tab",
|
||||
:insert_bottom => "[data-hook='admin_tabs'], #admin_tabs[data-hook]",
|
||||
:text => "<%= tab :enterprises, :url => main_app.admin_enterprises_path %>",
|
||||
:original => '6999548b86c700f2cc5d4f9d297c94b3617fd981')
|
||||
@@ -1,5 +0,0 @@
|
||||
Deface::Override.new(:virtual_path => "spree/layouts/admin",
|
||||
:name => "add_order_cycles_admin_tab",
|
||||
:insert_bottom => "[data-hook='admin_tabs'], #admin_tabs[data-hook]",
|
||||
:text => "<%= tab :order_cycles, :url => main_app.admin_order_cycles_path %>",
|
||||
:original => 'd4e321201ecb543e92192a031c8896a45dde3576')
|
||||
@@ -1,5 +0,0 @@
|
||||
Deface::Override.new(:virtual_path => "spree/shared/_order_details",
|
||||
:replace => "[data-hook='order_item_description']",
|
||||
:partial => "spree/orders/order_item_description",
|
||||
:name => "order_item_description",
|
||||
:original => '1729abc5f441607b09cc0d44843a8dfd660ac5e0')
|
||||
@@ -0,0 +1,6 @@
|
||||
/ replace_contents "td.property_name"
|
||||
|
||||
- if spree_current_user.admin?
|
||||
= f.text_field :property_name, :class => 'autocomplete'
|
||||
- else
|
||||
= f.select :property_name, @properties, { :include_blank => true }, { class: 'select2 fullwidth' }
|
||||
@@ -0,0 +1,5 @@
|
||||
/ insert_bottom "div[data-hook='admin_shipping_category_form_fields']"
|
||||
|
||||
%div.field.align-center{"data-hook" => "name"}
|
||||
= f.label :temperature_controlled, t(:temperature_controlled)
|
||||
= f.check_box :temperature_controlled
|
||||
@@ -0,0 +1,5 @@
|
||||
/ insert_after "[data-hook='category_row'] td:first-child"
|
||||
|
||||
%td.align-center
|
||||
= shipping_category.temperature_controlled ? 'Yes' : 'No'
|
||||
%br/
|
||||
@@ -0,0 +1,4 @@
|
||||
/ insert_after "[data-hook='categories_header'] th:first-child"
|
||||
|
||||
%th
|
||||
Temperature Controlled
|
||||
@@ -0,0 +1,5 @@
|
||||
/ insert_after "[data-hook='shipment_vat']"
|
||||
|
||||
.field.align-center{ "data-hook" => "shipping_tax_rate" }
|
||||
= number_field_tag "preferences[shipping_tax_rate]", Spree::Config[:shipping_tax_rate].to_f, in: 0.0..1.0, step: 0.01
|
||||
= label_tag nil, t(:shipping_tax_rate)
|
||||
@@ -0,0 +1,2 @@
|
||||
/ insert_bottom "[data-hook='admin_tabs'], #admin_tabs[data-hook]"
|
||||
= tab :enterprises, :url => main_app.admin_enterprises_path
|
||||
@@ -0,0 +1,2 @@
|
||||
/ insert_bottom "[data-hook='admin_tabs'], #admin_tabs[data-hook]"
|
||||
= tab :enterprise_groups, :url => main_app.admin_enterprise_groups_path, label: 'groups'
|
||||
@@ -0,0 +1,2 @@
|
||||
/ insert_bottom "[data-hook='admin_tabs'], #admin_tabs[data-hook]"
|
||||
= tab :order_cycles, :url => main_app.admin_order_cycles_path
|
||||
@@ -3,7 +3,7 @@ class EnterpriseFeePresenter
|
||||
@controller, @enterprise_fee, @index = controller, enterprise_fee, index
|
||||
end
|
||||
|
||||
delegate :id, :enterprise_id, :fee_type, :name, :calculator_type, :to => :enterprise_fee
|
||||
delegate :id, :enterprise_id, :fee_type, :name, :tax_category_id, :calculator_type, :to => :enterprise_fee
|
||||
|
||||
def enterprise_fee
|
||||
@enterprise_fee
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
class Api::Admin::BasicEnterpriseFeeSerializer < ActiveModel::Serializer
|
||||
attributes :id, :enterprise_id
|
||||
end
|
||||
23
app/serializers/api/admin/enterprise_fee_serializer.rb
Normal file
23
app/serializers/api/admin/enterprise_fee_serializer.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class Api::Admin::EnterpriseFeeSerializer < ActiveModel::Serializer
|
||||
attributes :id, :enterprise_id, :fee_type, :name, :tax_category_id, :calculator_type
|
||||
attributes :enterprise_name, :calculator_description, :calculator_settings
|
||||
|
||||
def enterprise_name
|
||||
object.enterprise.andand.name
|
||||
end
|
||||
|
||||
def calculator_description
|
||||
object.calculator.andand.description
|
||||
end
|
||||
|
||||
def calculator_settings
|
||||
result = nil
|
||||
|
||||
options[:controller].send(:with_format, :html) do
|
||||
result = options[:controller].render_to_string :partial => 'admin/enterprise_fees/calculator_settings', :locals => {:enterprise_fee => object}
|
||||
end
|
||||
|
||||
result.gsub('[0]', '[{{ $index }}]').gsub('_0_', '_{{ $index }}_')
|
||||
end
|
||||
|
||||
end
|
||||
17
app/serializers/api/admin/exchange_serializer.rb
Normal file
17
app/serializers/api/admin/exchange_serializer.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class Api::Admin::ExchangeSerializer < ActiveModel::Serializer
|
||||
attributes :id, :sender_id, :receiver_id, :incoming, :variants, :pickup_time, :pickup_instructions
|
||||
|
||||
has_many :enterprise_fees, serializer: Api::Admin::BasicEnterpriseFeeSerializer
|
||||
|
||||
def variants
|
||||
permitted = Spree::Variant.where("1=0")
|
||||
if object.incoming
|
||||
permitted = OpenFoodNetwork::OrderCyclePermissions.new(options[:current_user], object.order_cycle).
|
||||
visible_variants_for_incoming_exchanges_from(object.sender)
|
||||
else
|
||||
permitted = OpenFoodNetwork::OrderCyclePermissions.new(options[:current_user], object.order_cycle).
|
||||
visible_variants_for_outgoing_exchanges_to(object.receiver)
|
||||
end
|
||||
Hash[ object.variants.merge(permitted).map { |v| [v.id, true] } ]
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :managed, :supplied_products
|
||||
|
||||
def managed
|
||||
Enterprise.managed_by(options[:spree_current_user]).include? object
|
||||
end
|
||||
|
||||
def supplied_products
|
||||
objects = object.supplied_products.not_deleted
|
||||
serializer = Api::Admin::ForOrderCycle::SuppliedProductSerializer
|
||||
ActiveModel::ArraySerializer.new(objects, each_serializer: serializer )
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
class Api::Admin::ForOrderCycle::SuppliedProductSerializer < ActiveModel::Serializer
|
||||
attributes :name, :supplier_name, :image_url, :master_id, :variants
|
||||
|
||||
def supplier_name
|
||||
object.supplier.andand.name
|
||||
end
|
||||
|
||||
def image_url
|
||||
object.images.present? ? object.images.first.attachment.url(:mini) : nil
|
||||
end
|
||||
|
||||
def master_id
|
||||
object.master.id
|
||||
end
|
||||
|
||||
def variants
|
||||
object.variants.map do |variant|
|
||||
{ id: variant.id, label: variant.full_name }
|
||||
end
|
||||
end
|
||||
end
|
||||
64
app/serializers/api/admin/order_cycle_serializer.rb
Normal file
64
app/serializers/api/admin/order_cycle_serializer.rb
Normal file
@@ -0,0 +1,64 @@
|
||||
class Api::Admin::OrderCycleSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :orders_open_at, :orders_close_at, :coordinator_id, :exchanges
|
||||
attributes :editable_variants_for_incoming_exchanges, :editable_variants_for_outgoing_exchanges
|
||||
attributes :visible_variants_for_outgoing_exchanges
|
||||
attributes :viewing_as_coordinator
|
||||
|
||||
has_many :coordinator_fees, serializer: Api::IdSerializer
|
||||
|
||||
def orders_open_at
|
||||
object.orders_open_at.to_s
|
||||
end
|
||||
|
||||
def orders_close_at
|
||||
object.orders_close_at.to_s
|
||||
end
|
||||
|
||||
def viewing_as_coordinator
|
||||
Enterprise.managed_by(options[:current_user]).include? object.coordinator
|
||||
end
|
||||
|
||||
def exchanges
|
||||
scoped_exchanges = OpenFoodNetwork::OrderCyclePermissions.new(options[:current_user], object).visible_exchanges.order('id ASC')
|
||||
ActiveModel::ArraySerializer.new(scoped_exchanges, {each_serializer: Api::Admin::ExchangeSerializer, current_user: options[:current_user] })
|
||||
end
|
||||
|
||||
def editable_variants_for_incoming_exchanges
|
||||
# For each enterprise that the current user is able to see in this order cycle,
|
||||
# work out which variants should be editable within incoming exchanges from that enterprise
|
||||
editable = {}
|
||||
permissions = OpenFoodNetwork::OrderCyclePermissions.new(options[:current_user], object)
|
||||
enterprises = permissions.visible_enterprises
|
||||
enterprises.each do |enterprise|
|
||||
variants = permissions.editable_variants_for_incoming_exchanges_from(enterprise).pluck(:id)
|
||||
editable[enterprise.id] = variants if variants.any?
|
||||
end
|
||||
editable
|
||||
end
|
||||
|
||||
def editable_variants_for_outgoing_exchanges
|
||||
# For each enterprise that the current user is able to see in this order cycle,
|
||||
# work out which variants should be editable within incoming exchanges from that enterprise
|
||||
editable = {}
|
||||
permissions = OpenFoodNetwork::OrderCyclePermissions.new(options[:current_user], object)
|
||||
enterprises = permissions.visible_enterprises
|
||||
enterprises.each do |enterprise|
|
||||
variants = permissions.editable_variants_for_outgoing_exchanges_to(enterprise).pluck(:id)
|
||||
editable[enterprise.id] = variants if variants.any?
|
||||
end
|
||||
editable
|
||||
end
|
||||
|
||||
def visible_variants_for_outgoing_exchanges
|
||||
# For each enterprise that the current user is able to see in this order cycle,
|
||||
# work out which variants should be visible within outgoing exchanges from that enterprise
|
||||
visible = {}
|
||||
permissions = OpenFoodNetwork::OrderCyclePermissions.new(options[:current_user], object)
|
||||
enterprises = permissions.visible_enterprises
|
||||
enterprises.each do |enterprise|
|
||||
variants = permissions.visible_variants_for_outgoing_exchanges_to(enterprise).pluck(:id)
|
||||
visible[enterprise.id] = variants if variants.any?
|
||||
end
|
||||
visible
|
||||
end
|
||||
end
|
||||
@@ -36,12 +36,10 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
:long_description, :website, :instagram, :linkedin, :twitter,
|
||||
:facebook, :is_primary_producer, :is_distributor, :phone, :visible,
|
||||
:email, :hash, :logo, :promo_image, :path, :pickup, :delivery,
|
||||
:icon, :icon_font, :producer_icon_font, :category
|
||||
:icon, :icon_font, :producer_icon_font, :category, :producers, :hubs
|
||||
|
||||
has_many :distributed_taxons, key: :taxons, serializer: Api::IdSerializer
|
||||
has_many :supplied_taxons, serializer: Api::IdSerializer
|
||||
has_many :distributors, key: :hubs, serializer: Api::IdSerializer
|
||||
has_many :suppliers, key: :producers, serializer: Api::IdSerializer
|
||||
|
||||
has_one :address, serializer: Api::AddressSerializer
|
||||
|
||||
@@ -73,6 +71,14 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
enterprise_shop_path(object)
|
||||
end
|
||||
|
||||
def producers
|
||||
ActiveModel::ArraySerializer.new(object.suppliers.activated, {each_serializer: Api::IdSerializer})
|
||||
end
|
||||
|
||||
def hubs
|
||||
ActiveModel::ArraySerializer.new(object.distributors.activated, {each_serializer: Api::IdSerializer})
|
||||
end
|
||||
|
||||
# Map svg icons.
|
||||
def icon
|
||||
icons = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user