mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-22 05:18:51 +00:00
Merge branch 'master' into fixing_modals
Conflicts: app/assets/javascripts/darkswarm/all.js.coffee app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee app/assets/javascripts/darkswarm/directives/modal.js.coffee app/views/modals/_producer.html.haml app/views/modals/_product.html.haml app/views/shop/products.rabl
This commit is contained in:
@@ -150,7 +150,7 @@ GEM
|
||||
railties (>= 3.1)
|
||||
sprockets
|
||||
tilt
|
||||
angularjs-rails (1.2.16)
|
||||
angularjs-rails (1.2.13)
|
||||
ansi (1.4.2)
|
||||
arel (3.0.3)
|
||||
awesome_nested_set (2.1.5)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
window.Admin = angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown"]).config ($httpProvider) ->
|
||||
angular.module("ofn.admin", ["ngResource", "ngAnimate", "ofn.dropdown"]).config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content")
|
||||
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
|
||||
@@ -16,5 +16,6 @@
|
||||
//= require admin/spree_auth
|
||||
//= require admin/spree_promo
|
||||
//= require ./admin
|
||||
//= require ./products/products
|
||||
|
||||
//= require_tree .
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.controller "AdminOrderMgmtCtrl", [
|
||||
angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
"$scope", "$http", "dataFetcher", "blankOption", "pendingChanges"
|
||||
($scope, $http, dataFetcher, blankOption, pendingChanges) ->
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.controller "AdminProductEditCtrl", [
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", [
|
||||
"$scope", "$timeout", "$http", "dataFetcher", "DirtyProducts"
|
||||
($scope, $timeout, $http, dataFetcher, DirtyProducts) ->
|
||||
$scope.updateStatusMessage =
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.controller "AdminEnterpriseRelationshipsCtrl", ($scope, EnterpriseRelationships, Enterprises) ->
|
||||
angular.module("ofn.admin").controller "AdminEnterpriseRelationshipsCtrl", ($scope, EnterpriseRelationships, Enterprises) ->
|
||||
$scope.EnterpriseRelationships = EnterpriseRelationships
|
||||
$scope.Enterprises = Enterprises
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("ofn.admin").controller "enterprisesDashboardCtrl", [
|
||||
"$scope"
|
||||
($scope) ->
|
||||
$scope.activeTab = "hubs"
|
||||
]
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnConfirmLinkPath", (ofnConfirmHandler) ->
|
||||
angular.module("ofn.admin").directive "ofnConfirmLinkPath", (ofnConfirmHandler) ->
|
||||
restrict: "A"
|
||||
scope:
|
||||
path: "@ofnConfirmLinkPath"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnConfirmModelChange", (ofnConfirmHandler,$timeout) ->
|
||||
angular.module("ofn.admin").directive "ofnConfirmModelChange", (ofnConfirmHandler,$timeout) ->
|
||||
restrict: "A"
|
||||
link: (scope, element, attrs) ->
|
||||
handler = ofnConfirmHandler scope, -> scope.fetchOrders()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "datepicker", ->
|
||||
angular.module("ofn.admin").directive "datepicker", ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
element.datepicker
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "datetimepicker", ->
|
||||
angular.module("ofn.admin").directive "datetimepicker", ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
element.datetimepicker
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnDecimal", ->
|
||||
angular.module("ofn.admin").directive "ofnDecimal", ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
numRegExp = /^\d+(\.\d+)?$/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnLineItemUpdAttr", [
|
||||
angular.module("ofn.admin").directive "ofnLineItemUpdAttr", [
|
||||
"switchClass", "pendingChanges"
|
||||
(switchClass, pendingChanges) ->
|
||||
require: "ngModel"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnSelect2MinSearch", ->
|
||||
angular.module("ofn.admin").directive "ofnSelect2MinSearch", ->
|
||||
require: 'ngModel'
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
element.select2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnTaxonAutocomplete", (Taxons) ->
|
||||
angular.module("ofn.admin").directive "ofnTaxonAutocomplete", (Taxons) ->
|
||||
# Adapted from Spree's existing taxon autocompletion
|
||||
require: "ngModel"
|
||||
link: (scope,element,attrs,ngModel) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnToggleColumn", ->
|
||||
angular.module("ofn.admin").directive "ofnToggleColumn", ->
|
||||
link: (scope, element, attrs) ->
|
||||
element.addClass "selected" if scope.column.visible
|
||||
element.click "click", ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnToggleVariants", ->
|
||||
angular.module("ofn.admin").directive "ofnToggleVariants", ->
|
||||
link: (scope, element, attrs) ->
|
||||
if scope.displayProperties[scope.product.id].showVariants
|
||||
element.removeClass "icon-chevron-right"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnTrackProduct", ["DirtyProducts", (DirtyProducts) ->
|
||||
angular.module("ofn.admin").directive "ofnTrackProduct", ["DirtyProducts", (DirtyProducts) ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.directive "ofnTrackVariant", ["DirtyProducts", (DirtyProducts) ->
|
||||
angular.module("ofn.admin").directive "ofnTrackVariant", ["DirtyProducts", (DirtyProducts) ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.filter "rangeArray", ->
|
||||
angular.module("ofn.admin").filter "rangeArray", ->
|
||||
return (input,start,end) ->
|
||||
input.push(i) for i in [start..end]
|
||||
input
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.filter "selectFilter", (blankOption) ->
|
||||
angular.module("ofn.admin").filter "selectFilter", (blankOption) ->
|
||||
return (lineItems,selectedSupplier,selectedDistributor,selectedOrderCycle) ->
|
||||
filtered = []
|
||||
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedSupplier,"0") || lineItem.supplier.id == selectedSupplier) &&
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.filter "variantFilter", ->
|
||||
angular.module("ofn.admin").filter "variantFilter", ->
|
||||
return (lineItems,selectedUnitsProduct,selectedUnitsVariant,sharedResource) ->
|
||||
filtered = []
|
||||
filtered.push lineItem for lineItem in lineItems when (angular.equals(selectedUnitsProduct,{}) ||
|
||||
|
||||
1
app/assets/javascripts/admin/products/products.js.coffee
Normal file
1
app/assets/javascripts/admin/products/products.js.coffee
Normal file
@@ -0,0 +1 @@
|
||||
angular.module("admin.products", [])
|
||||
@@ -0,0 +1,46 @@
|
||||
angular.module("admin.products")
|
||||
.controller "unitsCtrl", ($scope) ->
|
||||
$scope.product = { master: {} }
|
||||
|
||||
$scope.$watch ->
|
||||
$scope.product.variant_unit_with_scale
|
||||
, ->
|
||||
if $scope.product.variant_unit_with_scale
|
||||
match = $scope.product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||
if match
|
||||
$scope.product.variant_unit = match[1]
|
||||
$scope.product.variant_unit_scale = parseFloat(match[2])
|
||||
else
|
||||
$scope.product.variant_unit = $scope.product.variant_unit_with_scale
|
||||
$scope.product.variant_unit_scale = null
|
||||
else
|
||||
$scope.product.variant_unit = $scope.product.variant_unit_scale = null
|
||||
|
||||
$scope.$watch ->
|
||||
$scope.product.master.unit_value_with_description
|
||||
, ->
|
||||
if $scope.product.master.hasOwnProperty("unit_value_with_description")
|
||||
match = $scope.product.master.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/)
|
||||
if match
|
||||
$scope.product.master.unit_value = parseFloat(match[1])
|
||||
$scope.product.master.unit_value = null if isNaN($scope.product.master.unit_value)
|
||||
$scope.product.master.unit_value *= $scope.product.variant_unit_scale if $scope.product.master.unit_value && $scope.product.variant_unit_scale
|
||||
$scope.product.master.unit_description = match[3]
|
||||
|
||||
$scope.variant_unit_options = [
|
||||
["Weight (g)", "weight_1"],
|
||||
["Weight (kg)", "weight_1000"],
|
||||
["Weight (T)", "weight_1000000"],
|
||||
["Volume (mL)", "volume_0.001"],
|
||||
["Volume (L)", "volume_1"],
|
||||
["Volume (ML)", "volume_1000000"],
|
||||
["Items", "items"]
|
||||
]
|
||||
|
||||
$scope.hasVariants = (product) ->
|
||||
Object.keys(product.variants).length > 0
|
||||
|
||||
$scope.hasUnit = (product) ->
|
||||
product.variant_unit_with_scale?
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Admin.value "blankOption", ->
|
||||
angular.module("ofn.admin").value "blankOption", ->
|
||||
{ id: "0", name: "All" }
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "ofnConfirmHandler", (pendingChanges, $compile, $q) ->
|
||||
angular.module("ofn.admin").factory "ofnConfirmHandler", (pendingChanges, $compile, $q) ->
|
||||
return (scope, callback) ->
|
||||
template = "<div id='dialog-div' style='padding: 10px'><h6>Unsaved changes currently exist, save now or ignore?</h6></div>"
|
||||
dialogDiv = $compile(template)(scope)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "dataFetcher", [
|
||||
angular.module("ofn.admin").factory "dataFetcher", [
|
||||
"$http", "$q"
|
||||
($http, $q) ->
|
||||
return (dataLocation) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "dataSubmitter", [
|
||||
angular.module("ofn.admin").factory "dataSubmitter", [
|
||||
"$http", "$q", "switchClass"
|
||||
($http, $q, switchClass) ->
|
||||
return (changeObj) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "DirtyProducts", ($parse) ->
|
||||
angular.module("ofn.admin").factory "DirtyProducts", ($parse) ->
|
||||
# Temporary service to track changes in products on admin bulk product edit
|
||||
dirtyProducts = {}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory 'EnterpriseRelationships', ($http, enterprise_relationships) ->
|
||||
angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterprise_relationships) ->
|
||||
new class EnterpriseRelationships
|
||||
create_errors: ""
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory 'Enterprises', (my_enterprises, all_enterprises) ->
|
||||
angular.module("ofn.admin").factory 'Enterprises', (my_enterprises, all_enterprises) ->
|
||||
new class Enterprises
|
||||
constructor: ->
|
||||
@my_enterprises = my_enterprises
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "pendingChanges",[
|
||||
angular.module("ofn.admin").factory "pendingChanges",[
|
||||
"dataSubmitter"
|
||||
(dataSubmitter) ->
|
||||
pendingChanges: {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "switchClass", [
|
||||
angular.module("ofn.admin").factory "switchClass", [
|
||||
"$timeout"
|
||||
($timeout) ->
|
||||
return (element,classToAdd,removeClasses,timeout) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Admin.factory "Taxons", ($resource) ->
|
||||
angular.module("ofn.admin").factory "Taxons", ($resource) ->
|
||||
resource = $resource "/admin/taxons/search"
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
Darkswarm.controller "OrderCycleCtrl", ($scope, $rootScope, OrderCycle, $timeout) ->
|
||||
Darkswarm.controller "OrderCycleCtrl", ($scope, OrderCycle, $timeout) ->
|
||||
$scope.order_cycle = OrderCycle.order_cycle
|
||||
$scope.OrderCycle = OrderCycle
|
||||
|
||||
$scope.changeOrderCycle = ->
|
||||
OrderCycle.push_order_cycle()
|
||||
$timeout ->
|
||||
$("#order_cycle_id").trigger("closeTrigger")
|
||||
|
||||
# Timeout forces this to be evaluated after everything is loaded
|
||||
# This is a hack. We should probably write our own "popover" directive
|
||||
# That takes an expression instead of a trigger, and binds to that
|
||||
$timeout =>
|
||||
if !$scope.OrderCycle.selected()
|
||||
$("#order_cycle_id").trigger("openTrigger")
|
||||
|
||||
|
||||
Darkswarm.controller "OrderCycleChangeCtrl", ($scope, OrderCycle, Product, $timeout) ->
|
||||
$scope.changeOrderCycle = ->
|
||||
OrderCycle.push_order_cycle Product.update
|
||||
$timeout ->
|
||||
$("#order_cycle_id").trigger("closeTrigger")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.controller "ProductNodeCtrl", ($scope, $sce) ->
|
||||
Darkswarm.controller "ProductNodeCtrl", ($scope) ->
|
||||
|
||||
$scope.price = ->
|
||||
if $scope.product.variants.length > 0
|
||||
@@ -9,8 +9,3 @@ Darkswarm.controller "ProductNodeCtrl", ($scope, $sce) ->
|
||||
|
||||
$scope.producer = $scope.product.supplier
|
||||
$scope.hasVariants = $scope.product.variants.length > 0
|
||||
|
||||
Darkswarm.filter "unsafe", ($sce) ->
|
||||
(val) ->
|
||||
$sce.trustAsHtml val
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ window.Darkswarm = angular.module("Darkswarm", ["ngResource",
|
||||
'infinite-scroll',
|
||||
'angular-flash.service',
|
||||
'templates',
|
||||
'ngSanitize',
|
||||
'backstretch']).config ($httpProvider, $tooltipProvider, $locationProvider, $anchorScrollProvider) ->
|
||||
$httpProvider.defaults.headers.post['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
$httpProvider.defaults.headers.put['X-CSRF-Token'] = $('meta[name="csrf-token"]').attr('content')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.factory 'Order', ($resource, Product, order, $http, CheckoutFormState, flash, Navigation)->
|
||||
Darkswarm.factory 'Order', ($resource, order, $http, CheckoutFormState, flash, Navigation)->
|
||||
new class Order
|
||||
errors: {}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
Darkswarm.factory 'OrderCycle', ($resource, Product, orderCycleData) ->
|
||||
Darkswarm.factory 'OrderCycle', ($resource, orderCycleData) ->
|
||||
class OrderCycle
|
||||
@order_cycle = orderCycleData # Object or {} due to RABL
|
||||
@push_order_cycle: ->
|
||||
@push_order_cycle: (callback) ->
|
||||
new $resource("/shop/order_cycle").save {order_cycle_id: @order_cycle.order_cycle_id}, (order_data)->
|
||||
OrderCycle.order_cycle.orders_close_at = order_data.orders_close_at
|
||||
Product.update()
|
||||
callback()
|
||||
|
||||
@orders_close_at: ->
|
||||
@order_cycle.orders_close_at if @selected()
|
||||
|
||||
@@ -9,7 +9,7 @@ Darkswarm.factory 'Product', ($resource) ->
|
||||
products: null
|
||||
loading: true
|
||||
|
||||
update: ->
|
||||
update: =>
|
||||
@data.products = $resource("/shop/products").query =>
|
||||
@data.loading = false
|
||||
@data
|
||||
|
||||
@@ -4,7 +4,23 @@ div.dashboard_item
|
||||
.centered
|
||||
text-align: center
|
||||
|
||||
.text-icon
|
||||
margin-top: 8px
|
||||
display: block
|
||||
font-size: 16px
|
||||
font-weight: bold
|
||||
color: #fff
|
||||
padding: 0px 6px
|
||||
border-radius: 10px
|
||||
&.green
|
||||
background-color: #9fc820
|
||||
&.red
|
||||
background-color: #DA5354
|
||||
&.orange
|
||||
background-color: #DA7F52
|
||||
|
||||
div.header
|
||||
height: 50px
|
||||
border-radius: 6px 6px 0px 0px
|
||||
border: 1px solid #5498da
|
||||
position: relative
|
||||
@@ -26,16 +42,41 @@ div.dashboard_item
|
||||
h3
|
||||
color: #DA7F52
|
||||
|
||||
h3
|
||||
padding: 10px 5px 10px 3%
|
||||
h3.alpha
|
||||
height: 100%
|
||||
padding: 10px 5px 0px 3%
|
||||
|
||||
a
|
||||
border-radius: 0px 4px 0px 0px
|
||||
margin-left: 8px
|
||||
height: 100%
|
||||
padding: 15px 2px 0px 2px
|
||||
|
||||
.tabs
|
||||
height: 30px
|
||||
border: solid #5498da
|
||||
border-width: 0px 0px 1px 0px
|
||||
margin-top: 3px
|
||||
div.dashboard_tab
|
||||
cursor: pointer
|
||||
height: 30px
|
||||
color: #fff
|
||||
background-color: #5498da
|
||||
padding: 5px 5px 0px 5px
|
||||
text-align: center
|
||||
font-weight: bold
|
||||
border: solid #5498da
|
||||
border-width: 1px 1px 0px 1px
|
||||
&:hover
|
||||
background-color: #9fc820
|
||||
&.selected
|
||||
color: #5498da
|
||||
background-color: #fff
|
||||
|
||||
.list
|
||||
max-height: 250px
|
||||
overflow-y: auto
|
||||
overflow-x: hidden
|
||||
|
||||
.list-title
|
||||
border: solid #5498da
|
||||
@@ -50,10 +91,11 @@ div.dashboard_item
|
||||
.list-item
|
||||
border: solid #5498da
|
||||
border-width: 0px 1px 0px 1px
|
||||
height: 38px
|
||||
span.alpha
|
||||
font-weight: bold
|
||||
margin-left: -3px
|
||||
padding: 10px 2px 10px 5%
|
||||
padding: 10px 2px 0px 5%
|
||||
span.omega
|
||||
padding-right: 13px
|
||||
margin-right: -3px
|
||||
@@ -94,10 +136,13 @@ div.dashboard_item
|
||||
color: #fff
|
||||
.icon-ok-sign
|
||||
color: #fff
|
||||
.text-icon
|
||||
&.green
|
||||
color: #9fc820
|
||||
background-color: #fff
|
||||
|
||||
a.button
|
||||
color: #fff
|
||||
padding: 15px 15px
|
||||
font-size: 110%
|
||||
font-weight: bold
|
||||
text-align: center
|
||||
@@ -110,4 +155,5 @@ div.dashboard_item
|
||||
&:hover
|
||||
background-color: #9fc820
|
||||
&.bottom
|
||||
border-radius: 0px 0px 6px 6px
|
||||
border-radius: 0px 0px 6px 6px
|
||||
padding: 15px 15px
|
||||
@@ -17,10 +17,22 @@ div.sidebar_item
|
||||
.list
|
||||
max-height: 400px
|
||||
overflow-y: auto
|
||||
|
||||
.list-item
|
||||
overflow-x: hidden
|
||||
border: solid #5498da
|
||||
border-width: 0px 1px 0px 1px
|
||||
&.red
|
||||
color: #DA5354
|
||||
border: solid #DA5354
|
||||
border-width: 0px 3px 0px 3px
|
||||
.list-item
|
||||
&.odd
|
||||
background-color: #fcf6ef
|
||||
&:hover
|
||||
background-color: #9fc820
|
||||
a
|
||||
color: #DA5354
|
||||
|
||||
.list-item
|
||||
span.alpha
|
||||
font-weight: bold
|
||||
margin-left: -3px
|
||||
@@ -29,16 +41,12 @@ div.sidebar_item
|
||||
max-width: 160px
|
||||
text-overflow: ellipsis
|
||||
span.omega
|
||||
padding: 8px 13px 8px 0px
|
||||
padding: 8px 18px 8px 0px
|
||||
margin-right: -3px
|
||||
text-align: right
|
||||
.icon-remove-sign
|
||||
color: #DA5354
|
||||
font-size: 18px
|
||||
&.red
|
||||
color: #DA5354
|
||||
border: solid #DA5354
|
||||
border-width: 0px 3px 0px 3px
|
||||
&.even
|
||||
background-color: #fff
|
||||
&.odd
|
||||
|
||||
@@ -9,3 +9,6 @@
|
||||
*/
|
||||
@import 'foundation-icons';
|
||||
|
||||
ofn-modal {
|
||||
display: block;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
@import mixins
|
||||
@import variables
|
||||
@import branding
|
||||
|
||||
.product-img
|
||||
border-bottom: 40px white solid
|
||||
border-top: 20px white solid
|
||||
border-left: 20px white solid
|
||||
border-right: 20px white solid
|
||||
outline: 1px solid #ccc
|
||||
@include box-shadow(0 1px 2px 1px rgba(0,0,0,0.25))
|
||||
|
||||
.producer-hero
|
||||
position: relative
|
||||
padding: 0
|
||||
|
||||
.producer-hero-img
|
||||
background-color: #999
|
||||
width: 100%
|
||||
height: inherit
|
||||
max-height: 260px
|
||||
overflow: hidden
|
||||
margin-top: 2em
|
||||
margin-bottom: 1em
|
||||
|
||||
|
||||
h3.producer-name
|
||||
background-color: rgba(255,255,255,0.65)
|
||||
height: 2.5em
|
||||
width: 100%
|
||||
position: absolute
|
||||
bottom: 0
|
||||
padding: 0.5em
|
||||
|
||||
.producer-logo
|
||||
max-width: 220px
|
||||
|
||||
@media only screen and (max-width: 1024px)
|
||||
.product-img
|
||||
margin-top: 2em
|
||||
margin-bottom: 1em
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
.row
|
||||
max-width: 74em
|
||||
|
||||
.reveal-modal
|
||||
position: fixed
|
||||
|
||||
@@ -81,7 +81,8 @@
|
||||
padding-top: 1em
|
||||
input.button.right
|
||||
float: left
|
||||
|
||||
|
||||
|
||||
product:hover, product:focus, product:active
|
||||
border-color: $clr-brick
|
||||
@include box-shadow(0 0 3px 0 $clr-brick-bright)
|
||||
|
||||
@@ -15,7 +15,6 @@ class Enterprise < ActiveRecord::Base
|
||||
has_and_belongs_to_many :payment_methods, join_table: 'distributors_payment_methods', class_name: 'Spree::PaymentMethod', foreign_key: 'distributor_id'
|
||||
has_and_belongs_to_many :shipping_methods, join_table: 'distributors_shipping_methods', class_name: 'Spree::ShippingMethod', foreign_key: 'distributor_id'
|
||||
|
||||
|
||||
delegate :latitude, :longitude, :city, :state_name, :to => :address
|
||||
|
||||
accepts_nested_attributes_for :address
|
||||
@@ -124,6 +123,14 @@ class Enterprise < ActiveRecord::Base
|
||||
self.supplied_products.where('count_on_hand > 0').present?
|
||||
end
|
||||
|
||||
def supplied_and_active_products_on_hand
|
||||
self.supplied_products.where('spree_products.count_on_hand > 0').active
|
||||
end
|
||||
|
||||
def active_products_in_order_cycles
|
||||
self.supplied_and_active_products_on_hand.in_an_active_order_cycle
|
||||
end
|
||||
|
||||
def to_param
|
||||
"#{id}-#{name.parameterize}"
|
||||
end
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Spree::Classification.class_eval do
|
||||
before_destroy :dont_destroy_if_primary_taxon
|
||||
|
||||
def dont_destroy_if_primary_taxon
|
||||
if product.primary_taxon == taxon
|
||||
errors.add :base, "Taxon #{taxon.name} is the primary taxon of #{product.name} and cannot be deleted"
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6,7 +6,6 @@ Spree::Product.class_eval do
|
||||
|
||||
|
||||
belongs_to :supplier, :class_name => 'Enterprise'
|
||||
belongs_to :primary_taxon, class_name: 'Spree::Taxon'
|
||||
|
||||
has_many :product_distributions, :dependent => :destroy
|
||||
has_many :distributors, :through => :product_distributions
|
||||
@@ -14,10 +13,9 @@ Spree::Product.class_eval do
|
||||
accepts_nested_attributes_for :product_distributions, :allow_destroy => true
|
||||
delegate_belongs_to :master, :unit_value, :unit_description
|
||||
|
||||
attr_accessible :supplier_id, :primary_taxon_id, :distributor_ids, :product_distributions_attributes, :group_buy, :group_buy_unit_size, :variant_unit, :variant_unit_scale, :variant_unit_name, :unit_value, :unit_description, :notes
|
||||
attr_accessible :supplier_id, :distributor_ids, :product_distributions_attributes, :group_buy, :group_buy_unit_size, :variant_unit, :variant_unit_scale, :variant_unit_name, :unit_value, :unit_description, :notes
|
||||
|
||||
validates_presence_of :supplier
|
||||
validates_presence_of :primary_taxon
|
||||
|
||||
validates_presence_of :variant_unit, if: :has_variants?
|
||||
validates_presence_of :variant_unit_scale,
|
||||
@@ -27,7 +25,6 @@ Spree::Product.class_eval do
|
||||
|
||||
after_initialize :set_available_on_to_now, :if => :new_record?
|
||||
after_save :update_units
|
||||
before_save :add_primary_taxon_to_taxons
|
||||
|
||||
|
||||
# -- Joins
|
||||
@@ -78,6 +75,12 @@ Spree::Product.class_eval do
|
||||
scope :in_order_cycle, lambda { |order_cycle| with_order_cycles_inner.
|
||||
merge(Exchange.outgoing).
|
||||
where('order_cycles.id = ?', order_cycle) }
|
||||
|
||||
scope :in_an_active_order_cycle, lambda { with_order_cycles_inner.
|
||||
merge(OrderCycle.active).
|
||||
merge(Exchange.outgoing).
|
||||
where('order_cycles.id IS NOT NULL') }
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
scoped
|
||||
@@ -121,6 +124,10 @@ Spree::Product.class_eval do
|
||||
order_cycle.variants_distributed_by(distributor).where(product_id: self)
|
||||
end
|
||||
|
||||
def primary_taxon
|
||||
self.taxons.order.first
|
||||
end
|
||||
|
||||
# Build a product distribution for each distributor
|
||||
def build_product_distributions_for_user user
|
||||
Enterprise.is_distributor.managed_by(user).each do |distributor|
|
||||
@@ -156,10 +163,6 @@ Spree::Product.class_eval do
|
||||
end
|
||||
end
|
||||
|
||||
def add_primary_taxon_to_taxons
|
||||
taxons << primary_taxon unless taxons.find_by_id(primary_taxon)
|
||||
end
|
||||
|
||||
def self.all_variant_unit_option_types
|
||||
Spree::OptionType.where('name LIKE ?', 'unit_%%')
|
||||
end
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
|
||||
:insert_top => "[data-hook='admin_product_form_right']",
|
||||
:partial => "spree/admin/products/primary_taxon_form",
|
||||
:name => "add_primary_taxon_to_admin_product")
|
||||
@@ -1,4 +0,0 @@
|
||||
Deface::Override.new(:virtual_path => "spree/admin/products/new",
|
||||
:insert_before => "[data-hook='new_product_attrs']",
|
||||
:partial => "spree/admin/products/primary_taxon_form",
|
||||
:name => "add_primary_taxon_to_admin_product_new")
|
||||
@@ -4,3 +4,4 @@
|
||||
= f.label :notes, t(:notes)
|
||||
= f.text_area :notes, { :class => 'fullwidth', rows: 5 }
|
||||
= f.error_message_on :notes
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/ insert_top "[data-hook='admin_product_form_right']"
|
||||
|
||||
= render 'spree/admin/products/primary_taxon_form', f: f
|
||||
@@ -0,0 +1,63 @@
|
||||
/ replace "fieldset[data-hook='new_product']"
|
||||
|
||||
%fieldset{ id: "new_product" }
|
||||
%legend{align: "center"}= t(:new_product)
|
||||
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
= f.field_container :name do
|
||||
= f.label :name, t(:name)
|
||||
%span.required *
|
||||
%br/
|
||||
= f.text_field :name, :class => 'fullwidth title'
|
||||
= f.error_message_on :name
|
||||
.five.columns.omega
|
||||
= f.field_container :supplier do
|
||||
= f.label :supplier
|
||||
%span.required *
|
||||
= f.collection_select(:supplier_id, Enterprise.is_primary_producer.managed_by(spree_current_user).by_name, :id, :name, {:include_blank => true}, {:class => "select2 fullwidth"})
|
||||
= f.error_message_on :supplier
|
||||
|
||||
.row
|
||||
.alpha.six.columns
|
||||
= render 'spree/admin/products/primary_taxon_form', f: f
|
||||
.five.columns
|
||||
= f.field_container :price do
|
||||
= f.label :price, t(:price)
|
||||
%span.required *
|
||||
%br/
|
||||
= f.text_field :price, :class => 'fullwidth'
|
||||
= f.error_message_on :price
|
||||
.five.columns.omega
|
||||
= f.field_container :on_hand do
|
||||
= f.label :on_hand, t(:on_hand)
|
||||
%span.required *
|
||||
%br/
|
||||
= f.text_field :on_hand, :class => 'fullwidth'
|
||||
= f.error_message_on :on_hand
|
||||
|
||||
.row{ 'ng-controller' => 'unitsCtrl' }
|
||||
.six.columns.alpha
|
||||
= f.label :variant_unit_with_scale, :units
|
||||
%select.select2.fullwidth{ id: 'product_variant_unit_with_scale', 'ng-model' => 'product.variant_unit_with_scale', 'ng-options' => 'unit[1] as unit[0] for unit in variant_unit_options' }
|
||||
%option{'value' => '', 'ng-hide' => "hasUnit(product)"}
|
||||
%input{ type: 'hidden', 'ng-value' => 'product.variant_unit', name: 'product[variant_unit]' }
|
||||
%input{ type: 'hidden', 'ng-value' => 'product.variant_unit_scale', name: 'product[variant_unit_scale]' }
|
||||
.five.columns
|
||||
= f.label :product_unit_value_with_description, :value
|
||||
%input.fullwidth{ id: 'product_unit_value_with_description', 'ng-model' => 'product.master.unit_value_with_description', :type => 'text', :placeholder => 'eg. 2', 'ng-disabled' => "!hasUnit(product)" }
|
||||
%input{ type: 'hidden', 'ng-value' => 'product.master.unit_value', name: 'product[unit_value]' }
|
||||
%input{ type: 'hidden', 'ng-value' => 'product.master.unit_description', name: 'product[unit_description]' }
|
||||
.five.columns.omega{ 'ng-show' => "product.variant_unit_with_scale == 'items'" }
|
||||
= f.label :product_variant_unit_name, :unit_name
|
||||
%input.fullwidth{ id: 'product_variant_unit_name','ng-model' => 'product.variant_unit_name', :name => 'product[variant_unit_name]', :placeholder => 'eg. bunches', :type => 'text' }
|
||||
|
||||
#product-from-prototype.clearfix{"data-hook" => "product-from-prototype"}
|
||||
= render :file => 'spree/admin/prototypes/show' if @prototype
|
||||
= render :partial => 'spree/admin/shared/new_resource_links'
|
||||
|
||||
|
||||
:javascript
|
||||
angular.element(document.getElementById("new_product")).ready(function() {
|
||||
angular.bootstrap(document.getElementById("new_product"), ['admin.products']);
|
||||
});
|
||||
@@ -1,59 +1,63 @@
|
||||
- payment_methods_color = @payment_methods.count > 0 ? (@enterprise.payment_methods.count > 0 ? "blue" : "red") : "red"
|
||||
.sidebar_item.four.columns.alpha#payment_methods
|
||||
.four.columns.alpha.header{ class: "#{@payment_methods.count > 0 ? "blue" : "red"}" }
|
||||
.four.columns.alpha.header{ class: "#{payment_methods_color}" }
|
||||
%span.four.columns.alpha.centered Payment Methods
|
||||
- if @payment_methods.count > 0
|
||||
.four.columns.alpha.list
|
||||
.four.columns.alpha.list{ class: "#{payment_methods_color}" }
|
||||
- if @payment_methods.count > 0
|
||||
-# = hidden_field_tag "enterprise[payment_method_ids][]", []
|
||||
- @payment_methods.each do |payment_method|
|
||||
%a.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{edit_admin_payment_method_path(payment_method)}" }
|
||||
%span.three.columns.alpha
|
||||
= payment_method.name
|
||||
%span.one.column.omega
|
||||
= f.check_box :payment_method_ids, { :multiple => true }, payment_method.id, nil
|
||||
- else
|
||||
.four.columns.alpha.list-item.red
|
||||
%span.three.columns.alpha None Available
|
||||
%span.one.column.omega
|
||||
%span.icon-remove-sign
|
||||
%a.four.columns.alpha.button{ href: "#{new_admin_payment_method_path}", class: "#{@payment_methods.count > 0 ? "blue" : "red"}" }
|
||||
= f.check_box :payment_method_ids, { multiple: true }, payment_method.id, nil
|
||||
- else
|
||||
.four.columns.alpha.list-item
|
||||
%span.three.columns.alpha None Available
|
||||
%span.one.column.omega
|
||||
%span.icon-remove-sign
|
||||
%a.four.columns.alpha.button{ href: "#{new_admin_payment_method_path}", class: "#{payment_methods_color}" }
|
||||
CREATE NEW
|
||||
%span.icon-arrow-right
|
||||
|
||||
- shipping_methods_color = @shipping_methods.count > 0 ? (@enterprise.shipping_methods.count > 0 ? "blue" : "red") : "red"
|
||||
.sidebar_item.four.columns.alpha#shipping_methods
|
||||
.four.columns.alpha.header{ class: "#{@shipping_methods.count > 0 ? "blue" : "red"}" }
|
||||
.four.columns.alpha.header{ class: "#{shipping_methods_color}" }
|
||||
%span.four.columns.alpha.centered Shipping Methods
|
||||
- if @shipping_methods.count > 0
|
||||
.four.columns.alpha.list
|
||||
.four.columns.alpha.list{ class: "#{shipping_methods_color}" }
|
||||
- if @shipping_methods.count > 0
|
||||
- @shipping_methods.each do |shipping_method|
|
||||
%a.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{edit_admin_shipping_method_path(shipping_method)}" }
|
||||
%span.three.columns.alpha
|
||||
= shipping_method.name
|
||||
%span.one.column.omega
|
||||
= f.check_box :shipping_method_ids, { :multiple => true }, shipping_method.id, nil
|
||||
- else
|
||||
.four.columns.alpha.list-item.red
|
||||
%span.three.columns.alpha None Available
|
||||
%span.one.column.omega
|
||||
%span.icon-remove-sign
|
||||
%a.four.columns.alpha.button{ href: "#{new_admin_shipping_method_path}", class: "#{@payment_methods.count > 0 ? "blue" : "red"}" }
|
||||
- else
|
||||
.four.columns.alpha.list-item
|
||||
%span.three.columns.alpha None Available
|
||||
%span.one.column.omega
|
||||
%span.icon-remove-sign
|
||||
%a.four.columns.alpha.button{ href: "#{new_admin_shipping_method_path}", class: "#{shipping_methods_color}" }
|
||||
CREATE NEW
|
||||
%span.icon-arrow-right
|
||||
|
||||
- enterprise_fees_color = @enterprise_fees.count > 0 ? "blue" : "red"
|
||||
.sidebar_item.four.columns.alpha#enterprise_fees
|
||||
.four.columns.alpha.header{ class: "#{@enterprise_fees.count > 0 ? "blue" : "red"}" }
|
||||
.four.columns.alpha.header{ class: "#{enterprise_fees_color}" }
|
||||
%span.four.columns.alpha.centered Enterprise Fees
|
||||
- if @enterprise_fees.count > 0
|
||||
.four.columns.alpha.list
|
||||
.four.columns.alpha.list{ class: "#{enterprise_fees_color}" }
|
||||
- if @enterprise_fees.count > 0
|
||||
- @enterprise_fees.each do |enterprise_fee|
|
||||
%a.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{main_app.admin_enterprise_fees_path}" }
|
||||
%span.three.columns.alpha
|
||||
= enterprise_fee.name
|
||||
%span.one.column.omega
|
||||
|
||||
- else
|
||||
.four.columns.alpha.list-item.red
|
||||
%span.three.columns.alpha None Available
|
||||
%span.one.column.omega
|
||||
%span.icon-remove-sign
|
||||
%a.four.columns.alpha.button{ href: "#{main_app.admin_enterprise_fees_path}", class: "#{@enterprise_fees.count > 0 ? "blue" : "red"}" }
|
||||
- else
|
||||
.four.columns.alpha.list-item.red
|
||||
%span.three.columns.alpha None Available
|
||||
%span.one.column.omega
|
||||
%span.icon-remove-sign
|
||||
%a.four.columns.alpha.button{ href: "#{main_app.admin_enterprise_fees_path}", class: "#{enterprise_fees_color}" }
|
||||
CREATE NEW
|
||||
%span.icon-arrow-right
|
||||
@@ -1,3 +1,4 @@
|
||||
%h2 Producers
|
||||
%p Our producers make all the delicious food you can shop for on the Open Food Network.
|
||||
%h5 Our producers make the food! All the delicious!
|
||||
%p More text goes here.
|
||||
%a.close-reveal-modal{"ng-click" => "cancel()"} ×
|
||||
@@ -1,5 +1,4 @@
|
||||
%ofn-modal{title: "{{product.name}}"}
|
||||
|
||||
.row
|
||||
.columns.small-12.large-6
|
||||
%img.product-img{"ng-src" => "{{product.master.images[0].large_url}}", "ng-if" => "product.master.images[0]"}
|
||||
@@ -9,4 +8,3 @@
|
||||
{{product.name}}
|
||||
%p {{product.description}}
|
||||
%a.close-reveal-modal{"ng-click" => "$close()"} ×
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
%shop.darkswarm
|
||||
- content_for :order_cycle_form do
|
||||
|
||||
%strong.avenir Ready for
|
||||
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
"ng-change" => "changeOrderCycle()",
|
||||
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}",
|
||||
"popover-placement" => "bottom", "popover" => "When do you want to get your order?", "popover-trigger" => "openTrigger"}
|
||||
%div{"ng-controller" => "OrderCycleChangeCtrl"}
|
||||
%strong.avenir Ready for
|
||||
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
"ng-change" => "changeOrderCycle()",
|
||||
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}",
|
||||
"popover-placement" => "bottom", "popover" => "When do you want to get your order?", "popover-trigger" => "openTrigger"}
|
||||
|
||||
%closing{"ng-if" => "OrderCycle.selected()"}
|
||||
Orders close
|
||||
%strong {{ OrderCycle.orders_close_at() | date_in_words }}
|
||||
%closing{"ng-if" => "OrderCycle.selected()"}
|
||||
Orders close
|
||||
%strong {{ OrderCycle.orders_close_at() | date_in_words }}
|
||||
|
||||
= render partial: "shopping_shared/details"
|
||||
|
||||
.row
|
||||
= render partial: "shop/products/form"
|
||||
|
||||
= render partial: "shared/footer"
|
||||
= render partial: "shared/footer"
|
||||
|
||||
@@ -14,5 +14,3 @@
|
||||
- else
|
||||
%form.custom
|
||||
= yield :order_cycle_form
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
%div.dashboard_item.sixteen.columns.alpha#enterprises
|
||||
%div.dashboard_item.sixteen.columns.alpha#enterprises{ 'ng-app' => 'ofn.admin', 'ng-controller' => "enterprisesDashboardCtrl" }
|
||||
%div.header.sixteen.columns.alpha{ :class => "#{@enterprises.count > 0 ? "" : "red"}"}
|
||||
%h3.thirteen.columns.alpha My Enterprises
|
||||
- if @enterprises.any?
|
||||
%a.three.columns.omega.icon-plus.button.blue{ href: "#{main_app.new_admin_enterprise_path}" }
|
||||
%a.three.columns.omega.icon-plus.button.blue.white-bottom{ href: "#{main_app.new_admin_enterprise_path}" }
|
||||
CREATE NEW
|
||||
- else
|
||||
%a.with-tip{ title: "Enterprises are Producers and/or Hubs and are the basic unit of organisation within the Open Food Network." } What's this?
|
||||
- if @enterprises.any?
|
||||
%div.sixteen.columns.alpha.tabs
|
||||
%div.dashboard_tab.eight.columns.alpha.blue{ ng: { class: "{selected: activeTab == 'hubs'}", click: "activeTab = 'hubs'" } } HUBS
|
||||
%div.dashboard_tab.eight.columns.omega.blue{ ng: { class: "{selected: activeTab == 'producers'}", click: "activeTab = 'producers'" } } PRODUCERS
|
||||
- if @enterprises.empty?
|
||||
%div.sixteen.columns.alpha.list-item.red
|
||||
%span.text.fifteen.columns.alpha You don't have any enterprises yet.
|
||||
@@ -15,40 +19,69 @@
|
||||
CREATE A NEW ENTERPRISE
|
||||
%span.icon-arrow-right
|
||||
- else
|
||||
%div.sixteen.columns.alpha.list-title
|
||||
%span.five.columns.alpha Name
|
||||
%span.centered.three.columns Payment Methods
|
||||
%span.centered.three.columns Shipping Methods
|
||||
%span.centered.three.columns Enterprise Fees
|
||||
%div.sixteen.columns.alpha.list
|
||||
- @enterprises.each do |enterprise|
|
||||
%a.sixteen.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{main_app.edit_admin_enterprise_path(enterprise)}" }
|
||||
%span.five.columns.alpha
|
||||
= enterprise.name
|
||||
%span.symbol.three.columns.centered
|
||||
- payment_method_count = enterprise.payment_methods.count
|
||||
- if payment_method_count < 1 && enterprise.is_distributor
|
||||
%span.icon-remove-sign.with-tip{ title: "#{enterprise.name} has no Payment Methods" }
|
||||
- elsif enterprise.is_primary_producer
|
||||
%span.icon-ok-sign.with-tip{ title: "Producers (like #{enterprise.name}) do not require Payment Methods." }
|
||||
- else
|
||||
%span.icon-ok-sign.with-tip{ title: "#{payment_method_count} Payment Method#{payment_method_count > 1 ? "s" : ""}" }
|
||||
%span.symbol.three.columns.centered
|
||||
- shipping_method_count = enterprise.shipping_methods.count
|
||||
- if shipping_method_count < 1 && enterprise.is_distributor
|
||||
%span.icon-remove-sign.with-tip{ title: "#{enterprise.name} has no Shipping Methods" }
|
||||
- elsif enterprise.is_primary_producer
|
||||
%span.icon-ok-sign.with-tip{ title: "Producers (like #{enterprise.name}) do not require Shipping Methods." }
|
||||
-else
|
||||
%span.icon-ok-sign.with-tip{ title: "#{shipping_method_count} Shipping Method#{shipping_method_count > 1 ? "s" : ""}" }
|
||||
%span.symbol.three.columns.centered
|
||||
- fee_count = enterprise.enterprise_fees.count
|
||||
- if fee_count > 0
|
||||
%span.icon-ok-sign.with-tip{ title: "#{fee_count} Fee#{fee_count > 1 ? "s" : ""}" }
|
||||
- else
|
||||
%span.icon-warning-sign.with-tip{ title: "#{enterprise.name} has no Enterprise Fees" }
|
||||
%span.two.columns.omega.right
|
||||
%span.icon-arrow-right
|
||||
%div.hubs_tab{ ng: { show: "activeTab == 'hubs'"} }
|
||||
%div.sixteen.columns.alpha.list-title
|
||||
%span.five.columns.alpha Name
|
||||
%span.centered.three.columns Payment Methods
|
||||
%span.centered.three.columns Shipping Methods
|
||||
%span.centered.three.columns Enterprise Fees
|
||||
%div.sixteen.columns.alpha.list
|
||||
- @enterprises.is_distributor.each do |enterprise|
|
||||
%a.sixteen.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{main_app.edit_admin_enterprise_path(enterprise)}" }
|
||||
%span.five.columns.alpha
|
||||
= enterprise.name
|
||||
%span.symbol.three.columns.centered
|
||||
- payment_method_count = enterprise.payment_methods.count
|
||||
- if payment_method_count < 1 && enterprise.is_distributor
|
||||
%span.icon-remove-sign.with-tip{ title: "#{enterprise.name} has no Payment Methods" }
|
||||
- elsif enterprise.is_primary_producer
|
||||
%span.icon-ok-sign.with-tip{ title: "Producers (like #{enterprise.name}) do not require Payment Methods." }
|
||||
- else
|
||||
%span.icon-ok-sign.with-tip{ title: "#{payment_method_count} Payment Method#{payment_method_count > 1 ? "s" : ""}" }
|
||||
%span.symbol.three.columns.centered
|
||||
- shipping_method_count = enterprise.shipping_methods.count
|
||||
- if shipping_method_count < 1 && enterprise.is_distributor
|
||||
%span.icon-remove-sign.with-tip{ title: "#{enterprise.name} has no Shipping Methods" }
|
||||
- elsif enterprise.is_primary_producer
|
||||
%span.icon-ok-sign.with-tip{ title: "Producers (like #{enterprise.name}) do not require Shipping Methods." }
|
||||
-else
|
||||
%span.icon-ok-sign.with-tip{ title: "#{shipping_method_count} Shipping Method#{shipping_method_count > 1 ? "s" : ""}" }
|
||||
%span.symbol.three.columns.centered
|
||||
- fee_count = enterprise.enterprise_fees.count
|
||||
- if fee_count > 0
|
||||
%span.icon-ok-sign.with-tip{ title: "#{fee_count} Fee#{fee_count > 1 ? "s" : ""}" }
|
||||
- else
|
||||
%span.icon-warning-sign.with-tip{ title: "#{enterprise.name} has no Enterprise Fees" }
|
||||
%span.two.columns.omega.right
|
||||
%span.icon-arrow-right
|
||||
%div.producers_tab{ ng: { show: "activeTab == 'producers'"} }
|
||||
%div.list-title.sixteen.columns.alpha
|
||||
%span.five.columns.alpha Name
|
||||
%span.centered.three.columns Total Products
|
||||
%span.centered.three.columns Active Products
|
||||
%span.centered.three.columns Products in OCs
|
||||
%div.sixteen.columns.alpha.list
|
||||
- @enterprises.is_primary_producer.each do |enterprise|
|
||||
%a.sixteen.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{main_app.edit_admin_enterprise_path(enterprise)}" }
|
||||
%span.five.columns.alpha
|
||||
= enterprise.name
|
||||
%span.symbol.three.columns.centered
|
||||
%span.one.column.alpha
|
||||
%span.text-icon.one.column.centered{ class: "#{enterprise.supplied_products.not_deleted.count > 0 ? "green" : "red" }" }
|
||||
= enterprise.supplied_products.not_deleted.count
|
||||
%span.one.column.omega
|
||||
%span.symbol.three.columns.centered
|
||||
%span.one.column.alpha
|
||||
%span.text-icon.one.column.centered{ class: "#{enterprise.supplied_and_active_products_on_hand.count > 0 ? "green" : "red" }" }
|
||||
= enterprise.supplied_and_active_products_on_hand.count
|
||||
%span.one.column.omega
|
||||
%span.symbol.three.columns.centered
|
||||
%span.one.column.alpha
|
||||
%span.text-icon.one.column.centered{ class: "#{enterprise.active_products_in_order_cycles.count > 0 ? "green" : "orange" }" }
|
||||
= enterprise.active_products_in_order_cycles.count
|
||||
%span.one.column.omega
|
||||
%span.two.columns.omega.right
|
||||
%span.icon-arrow-right
|
||||
%a.sixteen.columns.alpha.button.bottom.blue{ href: "#{main_app.admin_enterprises_path}" }
|
||||
MANAGE MY ENTERPRISES
|
||||
%span.icon-arrow-right
|
||||
@@ -132,7 +132,7 @@
|
||||
%td{ 'ng-show' => 'columns.on_hand.visible' }
|
||||
%span{ 'ng-bind' => 'product.on_hand', :name => 'on_hand', 'ng-show' => '!hasOnDemandVariants(product) && (hasVariants(product) || product.on_demand)' }
|
||||
%input.field{ 'ng-model' => 'product.on_hand', :name => 'on_hand', 'ofn-track-product' => 'on_hand', 'ng-hide' => 'hasVariants(product) || product.on_demand', :type => 'number' }
|
||||
%td{ 'ng-show' => 'columns.taxons.visible' }
|
||||
%td{ 'ng-if' => 'columns.taxons.visible' }
|
||||
%input.fullwidth{ :type => 'text', 'ng-model' => 'product.taxon_ids', 'ofn-taxon-autocomplete' => '', 'ofn-track-product' => 'taxon_ids' }
|
||||
%td{ 'ng-show' => 'columns.available_on.visible' }
|
||||
%input{ 'ng-model' => 'product.available_on', :name => 'available_on', 'ofn-track-product' => 'available_on', 'datetimepicker' => 'product.available_on', type: "text" }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= tab :overview, :route => :admin, :icon => 'icon-dashboard' %>
|
||||
<%= tab :dashboard, :route => :admin, :icon => 'icon-dashboard' %>
|
||||
<%= tab :orders, :payments, :creditcard_payments, :shipments, :credit_cards, :return_authorizations, :url => admin_orders_path('q[s]' => 'completed_at desc'), :icon => 'icon-shopping-cart' %>
|
||||
<%= tab :products , :option_types, :properties, :prototypes, :variants, :product_properties, :taxons, :url => bulk_edit_admin_products_path, :icon => 'icon-th-large' %>
|
||||
<%= tab :reports, :icon => 'icon-file' %>
|
||||
|
||||
@@ -32,6 +32,11 @@ class AddForeignKeys < ActiveRecord::Migration
|
||||
say "Destroying #{orphaned_exchange_variants.count} orphaned ExchangeVariants (of total #{ExchangeVariant.count})"
|
||||
orphaned_exchange_variants.destroy_all
|
||||
|
||||
# Remove orphaned ExchangeFee records
|
||||
orphaned_exchange_fees = ExchangeFee.joins('LEFT OUTER JOIN enterprise_fees ON enterprise_fees.id=exchange_fees.enterprise_fee_id').where('enterprise_fees.id IS NULL')
|
||||
say "Destroying #{orphaned_exchange_fees.count} orphaned ExchangeFees (of total #{ExchangeFee.count})"
|
||||
orphaned_exchange_fees.destroy_all
|
||||
|
||||
# Remove orphaned Spree::InventoryUnits
|
||||
orphaned_inventory_units = Spree::InventoryUnit.joins('LEFT OUTER JOIN spree_variants ON spree_variants.id=spree_inventory_units.variant_id').where('spree_variants.id IS NULL')
|
||||
say "Destroying #{orphaned_inventory_units.count} orphaned InventoryUnits (of total #{Spree::InventoryUnit.count})"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
class AddPrimaryTaxonToProducts < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :spree_products, :primary_taxon_id, :integer
|
||||
add_index :spree_products, :primary_taxon_id
|
||||
add_foreign_key :spree_products, :spree_taxons, column: :primary_taxon_id
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20140522044009) do
|
||||
ActiveRecord::Schema.define(:version => 20140522015012) do
|
||||
|
||||
create_table "adjustment_metadata", :force => true do |t|
|
||||
t.integer "adjustment_id"
|
||||
@@ -681,7 +681,6 @@ ActiveRecord::Schema.define(:version => 20140522044009) do
|
||||
t.float "variant_unit_scale"
|
||||
t.string "variant_unit_name"
|
||||
t.text "notes"
|
||||
t.integer "primary_taxon_id"
|
||||
end
|
||||
|
||||
add_index "spree_products", ["available_on"], :name => "index_products_on_available_on"
|
||||
@@ -689,7 +688,6 @@ ActiveRecord::Schema.define(:version => 20140522044009) do
|
||||
add_index "spree_products", ["name"], :name => "index_products_on_name"
|
||||
add_index "spree_products", ["permalink"], :name => "index_products_on_permalink"
|
||||
add_index "spree_products", ["permalink"], :name => "permalink_idx_unique", :unique => true
|
||||
add_index "spree_products", ["primary_taxon_id"], :name => "index_spree_products_on_primary_taxon_id"
|
||||
|
||||
create_table "spree_products_promotion_rules", :id => false, :force => true do |t|
|
||||
t.integer "product_id"
|
||||
@@ -1094,7 +1092,6 @@ ActiveRecord::Schema.define(:version => 20140522044009) do
|
||||
add_foreign_key "spree_products", "enterprises", name: "spree_products_supplier_id_fk", column: "supplier_id"
|
||||
add_foreign_key "spree_products", "spree_shipping_categories", name: "spree_products_shipping_category_id_fk", column: "shipping_category_id"
|
||||
add_foreign_key "spree_products", "spree_tax_categories", name: "spree_products_tax_category_id_fk", column: "tax_category_id"
|
||||
add_foreign_key "spree_products", "spree_taxons", name: "spree_products_primary_taxon_id_fk", column: "primary_taxon_id"
|
||||
|
||||
add_foreign_key "spree_products_promotion_rules", "spree_products", name: "spree_products_promotion_rules_product_id_fk", column: "product_id"
|
||||
add_foreign_key "spree_products_promotion_rules", "spree_promotion_rules", name: "spree_products_promotion_rules_promotion_rule_id_fk", column: "promotion_rule_id"
|
||||
|
||||
86
lib/tasks/users.rake
Normal file
86
lib/tasks/users.rake
Normal file
@@ -0,0 +1,86 @@
|
||||
require 'csv'
|
||||
|
||||
namespace :openfoodnetwork do
|
||||
|
||||
namespace :dev do
|
||||
desc 'export users to CSV'
|
||||
task export_users: :environment do
|
||||
CSV.open('db/users.csv', 'wb') do |csv|
|
||||
csv << header
|
||||
users.each do |user|
|
||||
csv << row(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc 'import users from CSV'
|
||||
task import_users: :environment do
|
||||
ActionMailer::Base.delivery_method = :test
|
||||
|
||||
CSV.foreach('db/users.csv') do |row|
|
||||
next if row[0] == 'encrypted_password'
|
||||
|
||||
create_user_from row
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def users
|
||||
# Skip some spambot users
|
||||
Spree::User.all.reject { |u| u.email =~ /example.net/ }
|
||||
end
|
||||
|
||||
|
||||
def header
|
||||
["encrypted_password", "password_salt", "email", "remember_token", "persistence_token", "reset_password_token", "perishable_token", "sign_in_count", "failed_attempts", "last_request_at", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip", "login", "created_at", "updated_at", "authentication_token", "unlock_token", "locked_at", "remember_created_at", "reset_password_sent_at",
|
||||
|
||||
"role_name",
|
||||
|
||||
"ship_address_firstname", "ship_address_lastname", "ship_address_address1", "ship_address_address2", "ship_address_city", "ship_address_zipcode", "ship_address_phone", "ship_address_state", "ship_address_country", "ship_address_created_at", "ship_address_updated_at", "ship_address_company",
|
||||
|
||||
"bill_address_firstname", "bill_address_lastname", "bill_address_address1", "bill_address_address2", "bill_address_city", "bill_address_zipcode", "bill_address_phone", "bill_address_state", "bill_address_country", "bill_address_created_at", "bill_address_updated_at", "bill_address_company",]
|
||||
end
|
||||
|
||||
|
||||
def row(user)
|
||||
sa = user.orders.last.andand.ship_address
|
||||
ba = user.orders.last.andand.bill_address
|
||||
|
||||
[user.encrypted_password, user.password_salt, user.email, user.remember_token, user.persistence_token, user.reset_password_token, user.perishable_token, user.sign_in_count, user.failed_attempts, user.last_request_at, user.current_sign_in_at, user.last_sign_in_at, user.current_sign_in_ip, user.last_sign_in_ip, user.login, user.created_at, user.updated_at, user.authentication_token, user.unlock_token, user.locked_at, user.remember_created_at, user.reset_password_sent_at,
|
||||
|
||||
user.spree_roles.first.andand.name,
|
||||
|
||||
sa.andand.firstname, sa.andand.lastname, sa.andand.address1, sa.andand.address2, sa.andand.city, sa.andand.zipcode, sa.andand.phone, sa.andand.state, sa.andand.country, sa.andand.created_at, sa.andand.updated_at, sa.andand.company,
|
||||
|
||||
ba.andand.firstname, ba.andand.lastname, ba.andand.address1, ba.andand.address2, ba.andand.city, ba.andand.zipcode, ba.andand.phone, ba.andand.state, ba.andand.country, ba.andand.created_at, ba.andand.updated_at, ba.andand.company,]
|
||||
end
|
||||
|
||||
|
||||
def create_user_from(row)
|
||||
user = Spree::User.create!({password: 'changeme123', password_confirmation: 'changeme123', email: row[2], remember_token: row[3], persistence_token: row[4], reset_password_token: row[5], perishable_token: row[6], sign_in_count: row[7], failed_attempts: row[8], last_request_at: row[9], current_sign_in_at: row[10], last_sign_in_at: row[11], current_sign_in_ip: row[12], last_sign_in_ip: row[13], login: row[14], created_at: row[15], updated_at: row[16], authentication_token: row[17], unlock_token: row[18], locked_at: row[19], remember_created_at: row[20], reset_password_sent_at: row[21]}, without_protection: true)
|
||||
|
||||
user.update_column :encrypted_password, row[0]
|
||||
user.update_column :password_salt, row[1]
|
||||
|
||||
# Safer if we don't make new users into admins
|
||||
#role = Spree::Role.find_by_name row[24]
|
||||
#user.spree_roles << role if role
|
||||
|
||||
sa_state = Spree::State.find_by_name row[30]
|
||||
sa_country = Spree::Country.find_by_name row[31]
|
||||
sa = Spree::Address.create!({firstname: row[23], lastname: row[24], address1: row[25], address2: row[26], city: row[27], zipcode: row[28], phone: row[29], state: sa_state, country: sa_country, created_at: row[32], updated_at: row[33], company: row[34]}, without_protection: true)
|
||||
user.update_column :ship_address_id, sa.id
|
||||
|
||||
ba_state = Spree::State.find_by_name row[42]
|
||||
ba_country = Spree::Country.find_by_name row[43]
|
||||
ba = Spree::Address.create!({firstname: row[35], lastname: row[36], address1: row[37], address2: row[38], city: row[39], zipcode: row[40], phone: row[41], state: ba_state, country: ba_country, created_at: row[44], updated_at: row[45], company: row[46]}, without_protection: true)
|
||||
user.update_column :bill_address_id, ba.id
|
||||
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
puts "#{row[2]} - #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,9 +2,6 @@ require 'ffaker'
|
||||
require 'spree/core/testing_support/factories'
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :classification, class: Spree::Classification do
|
||||
end
|
||||
|
||||
factory :order_cycle, :parent => :simple_order_cycle do
|
||||
coordinator_fees { [create(:enterprise_fee, enterprise: coordinator)] }
|
||||
|
||||
@@ -153,9 +150,6 @@ end
|
||||
|
||||
|
||||
FactoryGirl.modify do
|
||||
factory :product do
|
||||
primary_taxon { Spree::Taxon.first || FactoryGirl.create(:taxon) }
|
||||
end
|
||||
factory :simple_product do
|
||||
# Fix product factory name sequence with Kernel.rand so it is not interpreted as a Spree::Product method
|
||||
# Pull request: https://github.com/spree/spree/pull/1964
|
||||
@@ -163,7 +157,6 @@ FactoryGirl.modify do
|
||||
sequence(:name) { |n| "Product ##{n} - #{Kernel.rand(9999)}" }
|
||||
|
||||
supplier { Enterprise.is_primary_producer.first || FactoryGirl.create(:supplier_enterprise) }
|
||||
primary_taxon { Spree::Taxon.first || FactoryGirl.create(:taxon) }
|
||||
on_hand 3
|
||||
|
||||
variant_unit 'weight'
|
||||
|
||||
@@ -236,9 +236,7 @@ feature %q{
|
||||
|
||||
fill_in 'product_name', :with => 'Big Bag Of Apples'
|
||||
select(s.name, :from => 'product_supplier_id')
|
||||
choose('product_group_buy_0')
|
||||
fill_in 'product_price', :with => '10.00'
|
||||
fill_in 'product_available_on', :with => Date.today.strftime("%Y/%m/%d")
|
||||
click_button 'Create'
|
||||
|
||||
URI.parse(current_url).path.should == '/admin/products/bulk_edit'
|
||||
|
||||
@@ -6,7 +6,6 @@ feature %q{
|
||||
} do
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
let!(:taxon) { create(:taxon) }
|
||||
|
||||
background do
|
||||
@supplier = create(:supplier_enterprise, :name => 'New supplier')
|
||||
@@ -23,7 +22,6 @@ feature %q{
|
||||
|
||||
fill_in 'product_name', with: 'A new product !!!'
|
||||
fill_in 'product_price', with: '19.99'
|
||||
select taxon.name, from: "product_primary_taxon_id"
|
||||
select 'New supplier', from: 'product_supplier_id'
|
||||
|
||||
click_button 'Create'
|
||||
@@ -45,29 +43,23 @@ feature %q{
|
||||
|
||||
product.reload
|
||||
product.distributors.sort.should == [@distributors[0], @distributors[2]].sort
|
||||
|
||||
|
||||
product.product_distributions.map { |pd| pd.enterprise_fee }.sort.should == [@enterprise_fees[0], @enterprise_fees[2]].sort
|
||||
end
|
||||
|
||||
scenario "making a product into a group buy product" do
|
||||
product = create(:simple_product, name: 'group buy product')
|
||||
|
||||
scenario "creating a group buy product" do
|
||||
login_to_admin_section
|
||||
|
||||
click_link 'Products'
|
||||
click_link 'New Product'
|
||||
visit spree.edit_admin_product_path(product)
|
||||
|
||||
fill_in 'product_name', :with => 'A new product !!!'
|
||||
fill_in 'product_price', :with => '19.99'
|
||||
select taxon.name, from: "product_primary_taxon_id"
|
||||
select 'New supplier', :from => 'product_supplier_id'
|
||||
choose 'product_group_buy_1'
|
||||
fill_in 'Group buy unit size', :with => '10'
|
||||
|
||||
click_button 'Create'
|
||||
click_button 'Update'
|
||||
|
||||
flash_message.should == 'Product "A new product !!!" has been successfully created!'
|
||||
product = Spree::Product.find_by_name('A new product !!!')
|
||||
flash_message.should == 'Product "group buy product" has been successfully updated!'
|
||||
product.reload
|
||||
product.group_buy.should be_true
|
||||
product.group_buy_unit_size.should == 10.0
|
||||
end
|
||||
@@ -104,7 +96,6 @@ feature %q{
|
||||
|
||||
page.should have_selector('#product_supplier_id')
|
||||
select 'Another Supplier', :from => 'product_supplier_id'
|
||||
select taxon.name, from: "product_primary_taxon_id"
|
||||
|
||||
# Should only have suppliers listed which the user can manage
|
||||
within "#product_supplier_id" do
|
||||
|
||||
@@ -338,6 +338,16 @@ describe Enterprise do
|
||||
end
|
||||
end
|
||||
|
||||
describe "supplied_and_active_products_on_hand" do
|
||||
it "find only active products which are in stock" do
|
||||
supplier = create(:supplier_enterprise)
|
||||
inactive_product = create(:product, supplier: supplier, on_hand: 1, available_on: Date.tomorrow)
|
||||
out_of_stock_product = create(:product, supplier: supplier, on_hand: 0, available_on: Date.yesterday)
|
||||
p1 = create(:product, supplier: supplier, on_hand: 1, available_on: Date.yesterday)
|
||||
supplier.supplied_and_active_products_on_hand.should == [p1]
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding variants distributed by the enterprise" do
|
||||
it "finds the master variant" do
|
||||
d = create(:distributor_enterprise)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe Classification do
|
||||
let(:product) { create(:simple_product) }
|
||||
let(:taxon) { create(:taxon) }
|
||||
let(:classification) { create(:classification, taxon: taxon, product: product) }
|
||||
|
||||
it "won't destroy if classification is the primary taxon" do
|
||||
product.primary_taxon = taxon
|
||||
classification.destroy.should be_false
|
||||
classification.errors.messages[:base].should == ["Taxon #{taxon.name} is the primary taxon of #{product.name} and cannot be deleted"]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,6 @@ module Spree
|
||||
|
||||
describe "associations" do
|
||||
it { should belong_to(:supplier) }
|
||||
it { should belong_to(:primary_taxon) }
|
||||
it { should have_many(:product_distributions) }
|
||||
end
|
||||
|
||||
@@ -14,12 +13,6 @@ module Spree
|
||||
create(:product).should be_valid
|
||||
end
|
||||
|
||||
it "requires a primary taxon" do
|
||||
product = create(:simple_product)
|
||||
product.primary_taxon = nil
|
||||
product.should_not be_valid
|
||||
end
|
||||
|
||||
it "requires a supplier" do
|
||||
product = create(:simple_product)
|
||||
product.supplier = nil
|
||||
@@ -237,6 +230,20 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
describe "in_an_active_order_cycle" do
|
||||
it "shows products in order cycle distribution" do
|
||||
s = create(:supplier_enterprise)
|
||||
d2 = create(:distributor_enterprise)
|
||||
d3 = create(:distributor_enterprise)
|
||||
p1 = create(:product)
|
||||
p2 = create(:product)
|
||||
p3 = create(:product)
|
||||
oc2 = create(:simple_order_cycle, suppliers: [s], distributors: [d2], variants: [p2.master], orders_close_at: 1.day.ago)
|
||||
oc2 = create(:simple_order_cycle, suppliers: [s], distributors: [d3], variants: [p3.master], orders_close_at: Date.tomorrow)
|
||||
Product.in_an_active_order_cycle.should == [p3]
|
||||
end
|
||||
end
|
||||
|
||||
describe "access roles" do
|
||||
before(:each) do
|
||||
@e1 = create(:enterprise)
|
||||
@@ -558,10 +565,10 @@ module Spree
|
||||
describe "Taxons" do
|
||||
let(:taxon1) { create(:taxon) }
|
||||
let(:taxon2) { create(:taxon) }
|
||||
let(:product) { create(:simple_product) }
|
||||
let(:product) { create(:simple_product, taxons: [taxon1, taxon2]) }
|
||||
|
||||
it "returns the first taxon as the primary taxon" do
|
||||
product.taxons.should == [product.primary_taxon]
|
||||
product.primary_taxon.should == taxon1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user