Merging master into my branch to make it up to date

This commit is contained in:
summerscope
2014-09-12 14:48:19 +10:00
93 changed files with 1496 additions and 261 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -22,5 +22,6 @@
//= require ./payment_methods/payment_methods
//= require ./products/products
//= require ./shipping_methods/shipping_methods
//= require ./users/users
//= require_tree .

View File

@@ -1,6 +1,7 @@
angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
"$scope", "$http", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer",
($scope, $http, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer) ->
"$scope", "$http", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
($scope, $http, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
$scope.loading = true
$scope.initialiseVariables = ->
start = daysFromToday -7
@@ -32,14 +33,14 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
quantity: { name: "Quantity", visible: true }
max: { name: "Max", visible: true }
$scope.initialise = (spree_api_key) ->
$scope.initialise = ->
$scope.initialiseVariables()
authorise_api_reponse = ""
dataFetcher("/api/users/authorise_api?token=" + spree_api_key).then (data) ->
dataFetcher("/api/users/authorise_api?token=" + SpreeApiKey).then (data) ->
authorise_api_reponse = data
$scope.spree_api_key_ok = data.hasOwnProperty("success") and data["success"] == "Use of API Authorised"
if $scope.spree_api_key_ok
$http.defaults.headers.common["X-Spree-Token"] = spree_api_key
$http.defaults.headers.common["X-Spree-Token"] = SpreeApiKey
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
$scope.suppliers = data
$scope.suppliers.unshift blankOption()

View File

@@ -1,6 +1,8 @@
angular.module("ofn.admin").controller "AdminProductEditCtrl", [
"$scope", "$timeout", "$http", "dataFetcher", "DirtyProducts", "VariantUnitManager", "producers", "Taxons",
($scope, $timeout, $http, dataFetcher, DirtyProducts, VariantUnitManager, producers, Taxons) ->
"$scope", "$timeout", "$http", "dataFetcher", "DirtyProducts", "VariantUnitManager", "producers", "Taxons", "SpreeApiKey",
($scope, $timeout, $http, dataFetcher, DirtyProducts, VariantUnitManager, producers, Taxons, SpreeApiKey) ->
$scope.loading = true
$scope.updateStatusMessage =
text: ""
style: {}
@@ -42,14 +44,13 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", [
$scope.limit = 15
$scope.productsWithUnsavedVariants = []
$scope.initialise = (spree_api_key) ->
$scope.initialise = ->
authorise_api_reponse = ""
dataFetcher("/api/users/authorise_api?token=" + spree_api_key).then (data) ->
dataFetcher("/api/users/authorise_api?token=" + SpreeApiKey).then (data) ->
authorise_api_reponse = data
$scope.spree_api_key_ok = data.hasOwnProperty("success") and data["success"] == "Use of API Authorised"
if $scope.spree_api_key_ok
$http.defaults.headers.common["X-Spree-Token"] = spree_api_key
$http.defaults.headers.common["X-Spree-Token"] = SpreeApiKey
$scope.fetchProducts()
else if authorise_api_reponse.hasOwnProperty("error")
$scope.api_error_msg = authorise_api_reponse("error")

View File

@@ -1 +1 @@
angular.module("admin.enterprises", ["admin.payment_methods", "admin.shipping_methods"])
angular.module("admin.enterprises", ["admin.payment_methods", "admin.shipping_methods", "admin.users"])

View File

@@ -197,12 +197,13 @@ angular.module('order_cycle', ['ngResource'])
this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []})
removeExchange: (exchange) ->
incoming_index = this.order_cycle.incoming_exchanges.indexOf exchange
this.order_cycle.incoming_exchanges.splice(incoming_index, 1) if incoming_index > -1
outgoing_index = this.order_cycle.outgoing_exchanges.indexOf exchange
this.order_cycle.outgoing_exchanges.splice(outgoing_index, 1) if outgoing_index > -1
this.removeDistributionOfVariant(variant_id) for variant_id, active of exchange.variants when active
if exchange.incoming
incoming_index = this.order_cycle.incoming_exchanges.indexOf exchange
this.order_cycle.incoming_exchanges.splice(incoming_index, 1)
this.removeDistributionOfVariant(variant_id) for variant_id, active of exchange.variants when active
else
outgoing_index = this.order_cycle.outgoing_exchanges.indexOf exchange
this.order_cycle.outgoing_exchanges.splice(outgoing_index, 1) if outgoing_index > -1
addCoordinatorFee: ->
this.order_cycle.coordinator_fees.push({})

View File

@@ -0,0 +1,18 @@
angular.module("admin.users").directive "ofnUserAutocomplete", ($http) ->
link: (scope,element,attrs) ->
setTimeout ->
element.select2
multiple: false
initSelection: (element, callback) ->
callback { id: element.val(), email: attrs.email }
ajax:
url: Spree.routes.user_search
datatype: 'json'
data:(term, page) ->
{ q: term }
results: (data, page) ->
{ results: data }
formatResult: (user) ->
user.email
formatSelection: (user) ->
user.email

View File

@@ -0,0 +1 @@
angular.module("admin.users", [])

View File

@@ -1,4 +1,4 @@
Darkswarm.controller "SignupCtrl", ($scope, $http, $location, AuthenticationService) ->
Darkswarm.controller "SignupCtrl", ($scope, $http, $window, $location, Redirections, AuthenticationService) ->
$scope.path = "/signup"
$scope.errors =
email: null
@@ -6,6 +6,9 @@ Darkswarm.controller "SignupCtrl", ($scope, $http, $location, AuthenticationServ
$scope.submit = ->
$http.post("/user/spree_user", {spree_user: $scope.spree_user}).success (data)->
location.href = location.origin + location.pathname # Strips out hash fragments
if Redirections.after_login
$window.location.href = $window.location.origin + Redirections.after_login
else
$window.location.href = $window.location.origin + $window.location.pathname # Strips out hash fragments
.error (data) ->
$scope.errors = data

View File

@@ -1,7 +1,7 @@
Darkswarm.controller "AuthenticationCtrl", ($scope, AuthenticationService, SpreeUser)->
$scope.open = AuthenticationService.open
$scope.toggle = AuthenticationService.toggle
$scope.spree_user = SpreeUser.spree_user
$scope.active = AuthenticationService.active
$scope.select = AuthenticationService.select

View File

@@ -0,0 +1,11 @@
Darkswarm.controller "RegistrationCtrl", ($scope, RegistrationService, EnterpriseRegistrationService, availableCountries) ->
$scope.currentStep = RegistrationService.currentStep
$scope.enterprise = EnterpriseRegistrationService.enterprise
$scope.select = RegistrationService.select
$scope.steps = ['details','address','contact','about','images','social']
$scope.countries = availableCountries
$scope.countryHasStates = ->
$scope.enterprise.country.states.length > 0

View File

@@ -0,0 +1,15 @@
Darkswarm.controller "RegistrationFormCtrl", ($scope, RegistrationService, EnterpriseRegistrationService) ->
$scope.submitted = false
$scope.valid = (form) ->
$scope.submitted = !form.$valid
form.$valid
$scope.create = (form) ->
EnterpriseRegistrationService.create() if $scope.valid(form)
$scope.update = (nextStep, form) ->
EnterpriseRegistrationService.update(nextStep) if $scope.valid(form)
$scope.selectIfValid = (nextStep, form) ->
RegistrationService.select(nextStep) if $scope.valid(form)

View File

@@ -0,0 +1,6 @@
Darkswarm.directive "ofnInlineFlash", ->
restrict: 'E'
controller: ($scope) ->
$scope.visible = true
$scope.closeFlash = ->
$scope.visible = false

View File

@@ -4,12 +4,14 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
selectedPath: "/login"
constructor: ->
if $location.path() in ["/login", "/signup", "/forgot"]
@open()
if $location.path() in ["/login", "/signup", "/forgot"] && location.pathname isnt '/register/auth'
@open $location.path()
else if location.pathname is '/register/auth'
@open '/signup', 'registration_authentication.html'
open: (path = false)=>
open: (path = false, template = 'authentication.html') =>
@modalInstance = $modal.open
templateUrl: 'authentication.html'
templateUrl: template
windowClass: "login-modal medium"
@modalInstance.result.then @close, @close
@selectedPath = path || @selectedPath

View File

@@ -0,0 +1,57 @@
Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService, CurrentUser, spreeApiKey, Loading, availableCountries, enterpriseAttributes) ->
new class EnterpriseRegistrationService
enterprise:
user_ids: [CurrentUser.id]
email: CurrentUser.email
address: {}
country: availableCountries[0]
constructor: ->
for key, value of enterpriseAttributes
@enterprise[key] = value
create: =>
Loading.message = "Creating " + @enterprise.name
$http(
method: "POST"
url: "/api/enterprises"
data:
enterprise: @prepare()
params:
token: spreeApiKey
).success((data) =>
Loading.clear()
@enterprise.id = data
RegistrationService.select('about')
).error((data) =>
Loading.clear()
alert('Failed to create your enterprise.\nPlease ensure all fields are completely filled out.')
)
# RegistrationService.select('about')
update: (step) =>
Loading.message = "Updating " + @enterprise.name
$http(
method: "PUT"
url: "/api/enterprises/#{@enterprise.id}"
data:
enterprise: @prepare()
params:
token: spreeApiKey
).success((data) ->
Loading.clear()
RegistrationService.select(step)
).error((data) ->
Loading.clear()
alert('Failed to update your enterprise.\nPlease ensure all fields are completely filled out.')
)
# RegistrationService.select(step)
prepare: =>
enterprise = {}
excluded = [ 'address', 'country', 'id' ]
for key, value of @enterprise when key not in excluded
enterprise[key] = value
enterprise.address_attributes = @enterprise.address if @enterprise.address?
enterprise.address_attributes.country_id = @enterprise.country.id if @enterprise.country?
enterprise

View File

@@ -0,0 +1,23 @@
Darkswarm.factory "RegistrationService", (Navigation, $modal, Loading)->
new class RegistrationService
constructor: ->
@open()
open: =>
@modalInstance = $modal.open
templateUrl: 'registration.html'
windowClass: "login-modal large"
backdrop: 'static'
@modalInstance.result.then @close, @close
@select 'introduction'
select: (step)=>
@current_step = step
currentStep: =>
@current_step
close: ->
Loading.message = "Taking you back to the home page"
Navigation.go "/"

View File

@@ -0,0 +1,10 @@
%div#registration-modal{"ng-controller" => "RegistrationCtrl"}
%div{ ng: { show: "currentStep() == 'introduction'" } }
%ng-include{ src: "'registration/introduction.html'" }
%div{ ng: { repeat: 'step in steps', show: "currentStep() == step" } }
%ng-include{ src: "'registration/'+ step + '.html'" }
%div{ ng: { show: "currentStep() == 'finished'" } }
%ng-include{ src: "'registration/finished.html'" }
%a.close-reveal-modal{"ng-click" => "$close()"}
%i.ofn-i_009-close

View File

@@ -0,0 +1,44 @@
.container#registration-about
.header
%h2 Nice one!
%h5
Now let's flesh out the details about
%span.brick{"ng-show" => "enterprise.is_distributor"}
{{ enterprise.name }}
%span.turquoise{"ng-show" => "!enterprise.is_distributor" }
{{ enterprise.name }}
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'about', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('social',about)" } }
.row
.small-12.columns
.alert-box.alert{"data-alert" => ""}
{{ enterprise.name }} won't be visible on the Open Food Network until you enter a long and short description.
%a.close{:href => "#"} ×
.alert-box.info{"data-alert" => ""}
{{ enterprise.name }} has been created on the Open Food Network. If you leave at any point from here onwards, your enterprise will be saved, and you can always login to the admin section to update or continue filling out your enterprise details.
%a.close{:href => "#"} ×
.small-12.large-8.columns
.row
.small-12.columns
%label{ for: 'enterprise_description' } Short Description:
%input.chunky.small-12.columns{ id: 'enterprise_description', placeholder: "A short sentence describing your enterprise", ng: { model: 'enterprise.description' } }
.row
.small-12.columns
%label{ for: 'enterprise_long_desc' } Long Description:
%textarea.chunky.small-12.columns{ id: 'enterprise_long_desc', placeholder: "We recommend keeping your description to under 600 characters or 150 words. Why? Cus people are lazy, and don't like to read too much text online. ;)", ng: { model: 'enterprise.long_description' } }
%small {{ enterprise.long_description.length }} characters used
.small-12.large-4.columns
.row
.small-12.columns
%label{ for: 'enterprise_abn' } ABN:
%input.chunky.small-12.columns{ id: 'enterprise_abn', placeholder: "eg. 99 123 456 789", ng: { model: 'enterprise.abn' } }
.row
.small-12.columns
%label{ for: 'enterprise_acn' } ACN:
%input.chunky.small-12.columns{ id: 'enterprise_acn', placeholder: "eg. 123 456 789", ng: { model: 'enterprise.acn' } }
.row.buttons.pad-top
.small-12.columns
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,60 @@
.container#registration-address
.header
%h2
Greetings
%span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
{{ enterprise.name }}
%h5 Now we need to know where you are
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'address', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('contact',address)" } }
.row.content
.small-12.medium-12.large-7.columns
.row
.small-12.columns.field
%label{ for: 'enterprise_address' } Address:
%input.chunky.small-12.columns{ id: 'enterprise_address', name: 'address1', required: true, placeholder: "eg. 123 Cranberry Drive", required: true, ng: { model: 'enterprise.address.address1' } }
%span.error.small-12.columns{ ng: { show: "address.address1.$error.required && submitted" } }
You need to enter an address.
.row
.small-12.large-8.columns.field
%label{ for: 'enterprise_city' } Suburb:
%input.chunky.small-12.columns{ id: 'enterprise_city', name: 'city', required: true, placeholder: "eg. Northcote", ng: { model: 'enterprise.address.city' } }
%span.error.small-12.columns{ ng: { show: "address.city.$error.required && submitted" } }
You need to enter a suburb.
.small-12.large-4.columns.field
%label{ for: 'enterprise_zipcode' } Postcode:
%input.chunky.small-12.columns{ id: 'enterprise_zipcode', name: 'zipcode', required: true, placeholder: "eg. 3070", ng: { model: 'enterprise.address.zipcode' } }
%span.error.small-12.columns{ ng: { show: "address.zipcode.$error.required && submitted" } }
You need to enter a postcode.
.row
.small-12.large-8.columns.field
%label{ for: 'enterprise_country' } Country:
%select.chunky.small-12.columns{ id: 'enterprise_country', name: 'country', required: true, ng: { model: 'enterprise.country', options: 'c as c.name for c in countries' } }
%span.error.small-12.columns{ ng: { show: "address.country.$error.required && submitted" } }
You need to enter a country.
.small-12.large-4.columns.field
%label{ for: 'enterprise_state' } State:
%select.chunky.small-12.columns{ id: 'enterprise_state', name: 'state', ng: { model: 'enterprise.address.state_id', options: 's.id as s.abbr for s in enterprise.country.states', show: 'countryHasStates()', required: 'countryHasStates()' } }
%span.error.small-12.columns{ ng: { show: "address.state.$error.required && submitted" } }
You need to enter a state.
.small-12.medium-12.large-5.hide-for-small-only
// This is the location area
/ %h6
/ Location display
/ %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your enterprise's address on the Open Food Network. By default, full location is shown everywhere including street name and number."}
/ .row
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'enterpise_suburb_only', ng: { model: 'enterprise.suburb_only' } }
/ Hide my street name and street number from the public (ie. only show the suburb)
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'enterprise_on_map', ng: { model: 'enterprise.on_map' } }
/ Blur my location on the map (show an approximate, not exact pin)
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('details')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,46 @@
.container#registration-contact
.header
%h2 Last step to create your enterprise!
%h5
Who is responsible for managing
%span{ ng: { class: "{brick: enterprise.is_distributor, turquoise: !enterprise.is_distributor}" } }
{{ enterprise.name }}?
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'contact', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(contact)" } }
.row.content
.small-12.medium-12.large-7.columns
.row
.small-12.columns.field
%label{ for: 'enterprise_contact' } Primary Contact:
%input.chunky.small-12.columns{ id: 'enterprise_contact', name: 'contact', required: true, placeholder: "Contact Name", ng: { model: 'enterprise.contact' } }
%span.error.small-12.columns{ ng: { show: "contact.contact.$error.required && submitted" } }
You need to enter a primary contact.
.row
.small-12.columns.field
%label{ for: 'enterprise_email' } Email address:
%input.chunky.small-12.columns{ id: 'enterprise_email', name: 'email', type: 'email', required: true, placeholder: "eg. charlie@thefarm.com", ng: { model: 'enterprise.email' } }
%span.error.small-12.columns{ ng: { show: "(contact.email.$error.email || contact.email.$error.required) && submitted" } }
You need to enter valid email address.
.row
.small-12.columns.field
%label{ for: 'enterprise_phone' } Phone number:
%input.chunky.small-12.columns{ id: 'enterprise_phone', name: 'phone', placeholder: "eg. (03) 1234 5678", ng: { model: 'enterprise.phone' } }
.small-12.medium-12.large-5.hide-for-small-only
/ %h6
/ Contact display
/ %i.ofn-i_013-help.has-tip{ 'data-tooltip' => true, title: "Choose how you want to display your contact details on the Open Food Network."}
/ .row
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'contact_name_profile', ng: { model: 'enterprise.name_in_profile' } }   Display name in profile
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'contact_email_profile', ng: { model: 'enterprise.email_in_profile' } }   Display email in profile
/ .small-12.columns
/ %label.indent-checkbox
/ %input{ type: 'checkbox', id: 'contact_phone_profile', ng: { model: 'enterprise.phone_in_profile' } }   Display phone in profile
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('address')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,42 @@
.container#registration-details{bindonce: true}
.header
%h2 Let's Get Started
%h5{ bo: { if: "enterprise.type != 'single'" } } Woot! First we need to know what sort of enterprise you are:
%h5{ bo: { if: "enterprise.type == 'single'" } } Woot! First we need to know the name of your farm:
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'details', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "selectIfValid('address',details)" } }
.row
.small-12.columns.field
%label{ for: 'enterprise_name', bo: { if: "enterprise.type != 'single'" } } Enterprise Name:
%label{ for: 'enterprise_name', bo: { if: "enterprise.type == 'single'" } } Farm Name:
%input.chunky.small-12.columns{ id: 'enterprise_name', name: 'name', placeholder: "eg. Charlie's Awesome Farm", required: true, ng: { model: 'enterprise.name' } }
%span.error.small-12.columns{ ng: { show: "details.name.$error.required && submitted" } }
You need to enter a name for your enterprise!
.row#enterprise-types{ 'data-equalizer' => true, bo: { if: "enterprise.type != 'single'" } }
.small-12.columns.field
.row
.small-12.columns
%label Choose one:
.row
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#producer-panel{ href: "#", ng: { click: "enterprise.is_distributor = false; enterprise.is_primary_producer = true", class: "{selected: (!enterprise.is_distributor && enterprise.is_primary_producer)}" } }
.left
/ %render-svg{ path: "/assets/map-icon-producer.svg" }
%h4 I'm A Producer
%p Producers make yummy things to eat &/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#hub-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = false", class: "{selected: (enterprise.is_distributor && !enterprise.is_primary_producer)}" } }
.left
/ %render-svg{ path: "/assets/map-icon-hub.svg" }
%h4 I'm A Hub
%p Hubs connect the producer to the eater. Hubs can be co-ops, independent retailers, buying groups, wholesalers, CSA box schemes, farm-gate stalls, etc.
.small-12.medium-4.large-4.columns{ 'data-equalizer-watch' => true }
%a.panel#both-panel{ href: "#", ng: { click: "enterprise.is_distributor = true; enterprise.is_primary_producer = true", class: "{selected: (enterprise.is_distributor && enterprise.is_primary_producer)}" } }
.left
/ %render-svg{path: "/assets/map-icon-both.svg"}
%h4 I'm Both
%p Hey there, Jack-of-all-trades! Not only do you produce things to eat &/or drink, you also want to sell your yummies through an Open Food Network shopfront.
.row.buttons
.small-12.columns
%input.button.primary.right{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,18 @@
.container#registration-finished
.header
%h2 Well done!
%h5
You have successfully completed the profile for
%span.brick{"ng-show" => "enterprise.is_distributor"}
{{ enterprise.name }}
%span.turquoise{"ng-show" => "!enterprise.is_distributor" }
{{ enterprise.name }}
.content{ style: 'text-align: center'}
%h3 Why not check it out on the Open Food Network?
%a.button.primary{ type: "button", href: "/map" } Go to Map Page >
%br
%br
%h3 Next step - add some products:
%a.button.primary{ type: "button", href: "/admin/products/new" } Add a Product >

View File

@@ -0,0 +1,14 @@
.container#registration-images
.header
%h2 Thanks!
%h5 Let's upload some pretty pictures so your profile looks great! :)
%ng-include{ src: "'registration/steps.html'" }
.row.content
.row.buttons
.small-12.columns
%input.button.primary.left{ type: "button", value: "Back", ng: { click: "select('about')" } }
 
%input.button.primary.right{ type: "button", value: "Continue", ng: { click: "select('social')" } }

View File

@@ -0,0 +1,40 @@
%div
.header
%h2 Hi there!
%h4 This wizard will step you through creating a profile
.row
.small-12.medium-3.large-2.columns.text-right.hide-for-small-only
%img{:src => "/assets/potatoes.png"}
.small-12.medium-9.large-10.columns
%p
Your profile gives you an online presence on the
%strong Open Food Network,
allowing you to easily connect with potential customers or partners. You can always choose to update your info later, as well as choose to upgrade your Profile to and Online Store, where you can sell products, track orders and receive payments. Creating a profile takes about 5-10 minutes.
.row{ 'data-equalizer' => true }
.small-12.medium-6.large-6.columns.pad-top{ 'data-equalizer-watch' => true }
%h5 You'll need the following:
%ul.check-list
%li
Your enterprise address and contact details
%li
Your logo image
%li
A pretty picture for your profile header
%li
Some 'About Us' text
.small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true}
.highlight-box
%h5 Your profile entitles you to:
%ul.small-block-grid-1
%li
%i.ofn-i_020-search
A searchable listing
%li
%i.ofn-i_040-hub
A pin on the OFN map
.row
.small-12.columns
%hr
%input.button.primary{ type: "button", value: "Let's get started!", ng: { click: "select('details')" } }

View File

@@ -0,0 +1,35 @@
.container#registration-social
.header
%h2 Last step!
%h5 How can people find {{ enterprise.name }} online?
%ng-include{ src: "'registration/steps.html'" }
%form{ name: 'social', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "update('finished',social)" } }
.row.content
.small-12.large-7.columns
.row
.small-12.columns
%label{ for: 'enterprise_website' } Website:
%input.chunky.small-12.columns{ id: 'enterprise_website', placeholder: "eg. openfoodnetwork.org.au", ng: { model: 'enterprise.website' } }
.row
.small-12.columns
%label{ for: 'enterprise_facebook' } Facebook:
%input.chunky.small-12.columns{ id: 'enterprise_facebook', placeholder: "eg. www.facebook.com/PageNameHere", ng: { model: 'enterprise.facebook' } }
.row
.small-12.columns
%label{ for: 'enterprise_linkedin' } LinkedIn:
%input.chunky.small-12.columns{ id: 'enterprise_linkedin', placeholder: "eg. www.linkedin.com/YourNameHere", ng: { model: 'enterprise.linkedin' } }
.small-12.large-5.columns
.row
.small-12.columns
%label{ for: 'enterprise_twitter' } Twitter:
%input.chunky.small-12.columns{ id: 'enterprise_twitter', placeholder: "eg. @twitter_handle", ng: { model: 'enterprise.twitter' } }
.row
.small-12.columns
%label{ for: 'enterprise_instagram' } Instagram:
%input.chunky.small-12.columns{ id: 'enterprise_instagram', placeholder: "eg. @instagram_handle", ng: { model: 'enterprise.instagram' } }
.row.buttons
.small-12.columns
%input.button.secondary{ type: "button", value: "Back", ng: { click: "select('about')" } }
 
%input.button.primary{ type: "submit", value: "Continue" }

View File

@@ -0,0 +1,5 @@
.row#progress-bar
.small-12.medium-2.columns.item{ ng: { repeat: 'step in steps', class: "{active: (currentStep() == step),'show-for-medium-up': (currentStep() != step)}" } }
{{ $index+1 + ". " + step }}

View File

@@ -0,0 +1,17 @@
.container
.row.modal-centered
%h2 Welcome to the Open Food Network!
%h5 Start By Signing Up (or logging in):
%div{"ng-controller" => "AuthenticationCtrl"}
%tabset
%ng-include{src: "'signup.html'"}
%ng-include{src: "'login.html'"}
%ng-include{src: "'forgot.html'"}
%div{ ng: { show: "active('/signup')"} }
%hr
Already have an account?
%a{ href: "", ng: { click: "select('/login')"}}
Log in now.
%a.close-reveal-modal{"ng-click" => "$close()"}
%i.ofn-i_009-close

View File

@@ -1,12 +1,12 @@
%tab#sign-up-content{"ng-controller" => "SignupCtrl",
heading: "Sign up",
%tab#sign-up-content{"ng-controller" => "SignupCtrl",
heading: "Sign up",
active: "active(path)",
select: "select(path)"}
%form{"ng-submit" => "submit()"}
.row
.large-12.columns
%label{for: "email"} Your email
%input.title.input-text{name: "email",
%input.title.input-text{name: "email",
type: "email",
id: "email",
tabindex: 1,
@@ -16,7 +16,7 @@
.row
.large-12.columns
%label{for: "password"} Choose a password
%input.title.input-text{name: "password",
%input.title.input-text{name: "password",
type: "password",
id: "password",
autocomplete: "off",
@@ -27,7 +27,7 @@
.row
.large-12.columns
%label{for: "password_confirmation"} Confirm password
%input.title.input-text{name: "password_confirmation",
%input.title.input-text{name: "password_confirmation",
type: "password",
id: "password_confirmation",
autocomplete: "off",
@@ -35,7 +35,7 @@
"ng-model" => "spree_user.password_confirmation"}
.row
.large-12.columns
%input.button.primary{name: "commit",
tabindex: "3",
type: "submit",
%input.button.primary{name: "commit",
tabindex: "3",
type: "submit",
value: "Sign up now"}

View File

@@ -22,8 +22,6 @@ dialog, .reveal-modal
top: 10%
max-height: 80%
.reveal-modal-bg
background-color: rgba(0,0,0,0.65)

View File

@@ -0,0 +1,115 @@
@import branding
@import mixins
#registration-modal
.header
text-align: center
background-color: #efefef
padding-bottom: 1rem
.container
background-color: #ffffff
.content
// margin-bottom: 15px
i
font-size: 150%
.buttons
ofn-inline-flash
display: block
padding: 15px
position: relative
margin-bottom: 10px
&.brick
background-color: $clr-brick-light
border: 2px solid $clr-brick
color: $clr-brick
&.turquoise
background-color: $clr-turquoise-light
border: 2px solid $clr-turquoise
color: $clr-turquoise
.close-button
position: absolute
top: 0px
right: 0px
.field
margin-bottom: 15px
input.chunky
padding: 8px
font-size: 105%
label.indent-checkbox
display: block
padding-left: 20px
text-indent: -17px
input
margin: 0px
label
margin-bottom: 3px
ol, ul
// font-size: 80%
font-size: 0.875rem
padding: 0
margin: 0
ol
list-style-type: decimal
.highlight-box
background: white
padding: 1rem 1.2rem
@media all and (max-width: 640px)
margin-top: 1rem
#progress-bar
margin-bottom: 15px
.item
padding: 12px 0px
text-transform: uppercase
text-align: center
background-color: #333
border: 2px solid #333
color: #fff
.item.active
background-color: #cccccc
border: 2px solid #333
color: #333
@include box-shadow(inset 0 0 1px 0 #fff)
#registration-details
#enterprise-types
a.panel
display: block
background-color: #efefef
color: black
@media all and (min-width: 768px)
min-height: 200px
&:hover
background-color: #fff
&#producer-panel:hover
&, & *
color: $clr-turquoise
&#hub-panel:hover, &#both-panel:hover
&, & *
color: $clr-brick
&.selected
&, & *
color: #fff
&#hub-panel, &#both-panel
background-color: $clr-brick-bright
&:hover
&, & *
color: white
&#producer-panel
background-color: $clr-turquoise-bright
&:hover
&, & *
color: white
p
clear: both
font-size: 0.875rem

View File

@@ -48,6 +48,9 @@ small, .small
.turquoise
color: $clr-turquoise
.brick
color: $clr-brick
@mixin avenir
font-family: "AvenirBla_IE", "AvenirBla"
@@ -55,8 +58,8 @@ h1, h2, h3, h4, h5, h6, .avenir
@include avenir
padding: 0px
ul.bullet-list
margin: 0
ul.bullet-list, ul.check-list
margin: 0 0 0 1.25em !important
li
list-style: none
line-height: 1.5
@@ -64,12 +67,16 @@ ul.bullet-list
li:before
content: "\e609"
font-family: "OFN"
margin-left: -1.25em
display: inline-block
font-weight: normal
font-style: normal
font-variant: normal
text-transform: none
ul.check-list
li:before
content: "\e632"
.light-grey
color: #666666

View File

@@ -3,9 +3,10 @@ module Admin
before_filter :load_enterprise_set, :only => :index
before_filter :load_countries, :except => :index
before_filter :load_methods_and_fees, :only => [:new, :edit, :update, :create]
create.after :grant_management
before_filter :check_type, only: :update
before_filter :check_bulk_type, only: :bulk_update
before_filter :override_owner, only: :create
before_filter :check_owner, only: :update
helper 'spree/products'
include OrderCyclesHelper
@@ -39,14 +40,6 @@ module Admin
private
# When an enterprise user creates another enterprise, it is granted management
# permission for it
def grant_management
unless spree_current_user.has_spree_role? 'admin'
spree_current_user.enterprise_roles.create(enterprise: @object)
end
end
def load_enterprise_set
@enterprise_set = EnterpriseSet.new :collection => collection
end
@@ -81,6 +74,16 @@ module Admin
params[:enterprise].delete :type unless spree_current_user.admin?
end
def override_owner
params[:enterprise][:owner_id] = spree_current_user.id unless spree_current_user.admin?
end
def check_owner
unless spree_current_user == @enterprise.owner || spree_current_user.admin?
params[:enterprise].delete :owner_id
end
end
# Overriding method on Spree's resource controller
def location_after_save
if params[:enterprise].key? :producer_properties_attributes

View File

@@ -1,5 +1,8 @@
module Api
class EnterprisesController < Spree::Api::BaseController
before_filter :override_owner, only: [:create, :update]
before_filter :check_type, only: :update
respond_to :json
def managed
@@ -11,5 +14,37 @@ module Api
@enterprises = Enterprise.ransack(params[:q]).result.accessible_by(current_api_user)
render params[:template] || :bulk_index
end
def create
authorize! :create, Enterprise
@enterprise = Enterprise.new(params[:enterprise])
if @enterprise.save
render text: @enterprise.id, :status => 201
else
invalid_resource!(@enterprise)
end
end
def update
authorize! :update, Enterprise
@enterprise = Enterprise.find(params[:id])
if @enterprise.update_attributes(params[:enterprise])
render text: @enterprise.id, :status => 200
else
invalid_resource!(@enterprise)
end
end
private
def override_owner
params[:enterprise][:owner_id] = current_api_user.id
end
def check_type
params[:enterprise].delete :type unless current_api_user.admin?
end
end
end

View File

@@ -0,0 +1,25 @@
require 'open_food_network/spree_api_key_loader'
class RegistrationController < BaseController
include OpenFoodNetwork::SpreeApiKeyLoader
before_filter :load_spree_api_key, only: :index
before_filter :check_user, except: :authenticate
layout 'registration'
def index
@enterprise_attributes = { type: 'profile' }
end
def store
@enterprise_attributes = { is_distributor: true, is_primary_producer: true, type: 'single' }
render :index
end
private
def check_user
if spree_current_user.nil?
redirect_to registration_auth_path(anchor: "signup?after_login=#{request.env['PATH_INFO']}")
end
end
end

View File

@@ -1,4 +1,7 @@
require 'open_food_network/spree_api_key_loader'
Spree::Admin::OrdersController.class_eval do
include OpenFoodNetwork::SpreeApiKeyLoader
before_filter :load_spree_api_key, :only => :bulk_management
# We need to add expections for collection actions other than :index here
@@ -14,11 +17,4 @@ Spree::Admin::OrdersController.class_eval do
page(params[:page]).
per(params[:per_page] || Spree::Config[:orders_per_page])
} } }
private
def load_spree_api_key
current_user.generate_spree_api_key! unless spree_current_user.spree_api_key
@spree_api_key = spree_current_user.spree_api_key
end
end

View File

@@ -1,5 +1,9 @@
require 'open_food_network/spree_api_key_loader'
Spree::Admin::ProductsController.class_eval do
before_filter :load_bpe_data, :only => :bulk_edit
include OpenFoodNetwork::SpreeApiKeyLoader
before_filter :load_form_data, :only => [:bulk_edit, :new, :edit]
before_filter :load_spree_api_key, :only => :bulk_edit
alias_method :location_after_save_original, :location_after_save
@@ -85,9 +89,7 @@ Spree::Admin::ProductsController.class_eval do
private
def load_bpe_data
current_user.generate_spree_api_key! unless spree_current_user.spree_api_key
@spree_api_key = spree_current_user.spree_api_key
def load_form_data
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).managed_product_enterprises.is_primary_producer.by_name
@taxons = Spree::Taxon.order(:name)
end

View File

@@ -37,7 +37,9 @@ module Admin
admin_inject_json_ams_array "ofn.admin", "users", @users, Api::Admin::UserSerializer
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
def admin_inject_json_ams(ngModule, name, data, serializer, opts = {})

View File

@@ -2,18 +2,18 @@ module InjectionHelper
def inject_enterprises
inject_json_ams "enterprises", Enterprise.all, Api::EnterpriseSerializer, active_distributors: @active_distributors
end
def inject_current_order
inject_json_ams "currentOrder", current_order, Api::CurrentOrderSerializer, current_distributor: current_distributor, current_order_cycle: current_order_cycle
end
def inject_available_shipping_methods
inject_json_ams "shippingMethods", available_shipping_methods,
inject_json_ams "shippingMethods", available_shipping_methods,
Api::ShippingMethodSerializer, current_order: current_order
end
def inject_available_payment_methods
inject_json_ams "paymentMethods", current_order.available_payment_methods,
inject_json_ams "paymentMethods", current_order.available_payment_methods,
Api::PaymentMethodSerializer
end
@@ -21,6 +21,18 @@ module InjectionHelper
inject_json_ams "taxons", Spree::Taxon.all, Api::TaxonSerializer
end
def inject_spree_api_key
render partial: "json/injection_ams", locals: {name: 'spreeApiKey', json: "'#{@spree_api_key.to_s}'"}
end
def inject_available_countries
inject_json_ams "availableCountries", available_countries, Api::CountrySerializer
end
def inject_enterprise_attributes
render partial: "json/injection_ams", locals: {name: 'enterpriseAttributes', json: "#{@enterprise_attributes.to_json}"}
end
def inject_json(name, partial, opts = {})
render partial: "json/injection", locals: {name: name, partial: partial}.merge(opts)
end

View File

@@ -0,0 +1,12 @@
class EnterpriseMailer < Spree::BaseMailer
def creation_confirmation(enterprise)
find_enterprise(enterprise)
subject = "#{@enterprise.name} is now on #{Spree::Config[:site_name]}"
mail(:to => @enterprise.owner.email, :from => from_address, :subject => subject)
end
private
def find_enterprise(enterprise)
@enterprise = enterprise.is_a?(Enterprise) ? enterprise : Enterprise.find(enterprise)
end
end

View File

@@ -6,6 +6,8 @@ class Enterprise < ActiveRecord::Base
acts_as_gmappable :process_geocoding => false
after_create :send_creation_email
has_and_belongs_to_many :groups, class_name: 'EnterpriseGroup'
has_many :producer_properties, foreign_key: 'producer_id'
has_many :supplied_products, :class_name => 'Spree::Product', :foreign_key => 'supplier_id', :dependent => :destroy
@@ -16,6 +18,7 @@ class Enterprise < ActiveRecord::Base
has_many :enterprise_fees
has_many :enterprise_roles, :dependent => :destroy
has_many :users, through: :enterprise_roles
belongs_to :owner, class_name: 'Spree::User', foreign_key: :owner_id, inverse_of: :owned_enterprises
has_and_belongs_to_many :payment_methods, join_table: 'distributors_payment_methods', class_name: 'Spree::PaymentMethod', foreign_key: 'distributor_id'
has_many :distributor_shipping_methods, foreign_key: :distributor_id
has_many :shipping_methods, through: :distributor_shipping_methods
@@ -46,7 +49,10 @@ class Enterprise < ActiveRecord::Base
validates :name, presence: true
validates :type, presence: true, inclusion: {in: TYPES}
validates :address, presence: true, associated: true
validates_presence_of :owner
validate :enforce_ownership_limit, if: lambda { owner_id_changed? }
before_validation :ensure_owner_is_manager, if: lambda { owner_id_changed? }
before_validation :set_unused_address_fields
after_validation :geocode_address
@@ -223,6 +229,10 @@ class Enterprise < ActiveRecord::Base
private
def send_creation_email
EnterpriseMailer.creation_confirmation(self).deliver
end
def strip_url(url)
url.andand.sub /(https?:\/\/)?/, ''
end
@@ -234,4 +244,14 @@ class Enterprise < ActiveRecord::Base
def geocode_address
address.geocode if address.changed?
end
def ensure_owner_is_manager
users << owner unless users.include?(owner) || owner.admin?
end
def enforce_ownership_limit
unless owner.can_own_more_enterprises?
errors.add(:owner, "^You are not permitted to own own any more enterprises (limit is #{owner.enterprise_limit}).")
end
end
end

View File

@@ -1,13 +1,16 @@
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_one :cart
accepts_nested_attributes_for :enterprise_roles, :allow_destroy => true
attr_accessible :enterprise_ids, :enterprise_roles_attributes
attr_accessible :enterprise_ids, :enterprise_roles_attributes, :enterprise_limit
after_create :send_signup_confirmation
validate :limit_owned_enterprises
def build_enterprise_roles
Enterprise.all.each do |enterprise|
unless self.enterprise_roles.find_by_enterprise_id enterprise.id
@@ -19,4 +22,16 @@ Spree.user_class.class_eval do
def send_signup_confirmation
Spree::UserMailer.signup_confirmation(self).deliver
end
def can_own_more_enterprises?
owned_enterprises(:reload).size < enterprise_limit
end
private
def limit_owned_enterprises
if owned_enterprises.size > enterprise_limit
errors.add(:owned_enterprises, "^The nominated user is not permitted to own own any more enterprises (limit is #{enterprise_limit}).")
end
end
end

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
:insert_top => "[data-hook='admin_product_form_right']",
:partial => "spree/admin/products/supplier_form",
:name => "add_supplier_to_admin_product",
:original => '18bd94de3eb8bdf8b669932bf04fc59e2e85288b')

View File

@@ -1,4 +0,0 @@
/ insert_after "[data-hook='long_description']"
%tr{'data-hook' => 'distributor_info'}
%th Distributor Info:
%td= @enterprise.distributor_info.andand.html_safe

View File

@@ -0,0 +1,7 @@
/ insert_top "[data-hook='admin_product_form_right']"
= f.field_container :supplier do
= f.label :supplier
%br
= f.collection_select(:supplier_id, @producers, :id, :name, {:include_blank => true}, {:class => "select2"})
= f.error_message_on :supplier

View File

@@ -7,7 +7,7 @@
= f.field_container :supplier do
= f.label :supplier_id, t(: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.collection_select(:supplier_id, @producers, :id, :name, {:include_blank => true}, {:class => "select2 fullwidth"})
= f.error_message_on :supplier
.six.columns.omega
= f.field_container :name do

View File

@@ -0,0 +1,5 @@
/ insert_bottom "div[data-hook='admin_user_form_fields'] div.alpha"
= f.field_container :enterprise_limit do
= f.label :enterprise_limit, t(:enterprise_limit)
= f.text_field :enterprise_limit, :class => 'fullwidth'

View File

@@ -0,0 +1,3 @@
/ insert_before "td[data-hook='admin_users_index_row_actions']"
%td.user_enterprise_limit= user.enterprise_limit

View File

@@ -0,0 +1,3 @@
/ insert_before "th[data-hook='admin_users_index_header_actions']"
%th= sort_link @search,:enterprise_limit, t(:enterprise_limit)

View File

@@ -0,0 +1,6 @@
/ replace "table#listing_users colgroup"
%colgroup
%col{ style: "width: 65%" }
%col{ style: "width: 20%" }
%col{ style: "width: 15%" }

View File

@@ -0,0 +1,3 @@
/ replace "code[erb-loud]:contains('link_to user.email, object_url(user)')"
= link_to user.email, edit_object_url(user)

View File

@@ -1,6 +0,0 @@
Deface::Override.new(:virtual_path => "spree/admin/users/_form",
:insert_after => "[data-hook='admin_user_form_fields']",
:partial => "spree/admin/users/enterprises_form",
:name => "add_enterprises_to_user"
)

View File

@@ -0,0 +1,5 @@
class Api::CountrySerializer < ActiveModel::Serializer
attributes :id, :name, :states
has_many :states, serializer: Api::StateSerializer
end

View File

@@ -0,0 +1,3 @@
class Api::StateSerializer < ActiveModel::Serializer
attributes :id, :name, :abbr
end

View File

@@ -11,5 +11,5 @@
%table#enterprise-roles
%tbody
= render 'form'
%tr{"ng-repeat" => "enterprise_role in EnterpriseRoles.enterprise_roles | filter:query"}
%tr{"ng-repeat" => "enterprise_role in EnterpriseRoles.enterprise_roles | filter:query", id: "enterprise_role_{{enterprise_role.id}}"}
= render 'enterprise_role'

View File

@@ -1,6 +1,3 @@
- content_for :head do
= render 'shared/cms_elrte_head'
- content_for :page_actions do
%li= button_link_to "Back to enterprises list", main_app.admin_enterprises_path, icon: 'icon-arrow-left'
@@ -23,6 +20,16 @@
.eight.columns.omega
= f.collection_select :group_ids, EnterpriseGroup.all, :id, :name, {}, class: "select2 fullwidth", multiple: true, placeholder: "Start typing to search available groups..."
- if spree_current_user.admin?
.row
.three.columns.alpha
=f.label :owner_id, 'Owner'
.with-tip{'data-powertip' => "The primary user responsible for this enterprise."}
%a What's this?
.eight.columns
- owner_email = @enterprise.andand.owner.andand.email || ""
= f.hidden_field :owner_id, class: "select2 fullwidth", 'ofn-user-autocomplete' => true, email: owner_email
.row
.three.columns.alpha
%label Enterprise Type(s)
@@ -174,20 +181,8 @@
.row
.alpha.three.columns
= f.label :long_description, 'About Us'
%br
Tell us about yourself. This information appears on your public profile (under "About Us")
.omega.eight.columns
= f.text_area :long_description, class: 'rich_text', placeholder: 'Tell us about yourself. This information appears on your public profile (under "About Us")'
.row
.alpha.three.columns
= f.label :distributor_info, 'How does your hub work?'
%br
%em (Hub only)
%br
Explain your distribution offer/s - this information appears on your public profile (under "How does it work?")
.omega.eight.columns
= f.text_area :distributor_info, class: 'rich_text', placeholder: 'Hub only: Explain your distribution offer/s - this is more detailed information that the user can access by clicking on "How does it work?"'
/ TODO: editor breaks scrolling with arrow keys
= f.text_area :long_description, rows: 6, placeholder: 'Tell us about yourself. This information appears on your public profile (under "About Us")', class: 'fullwidth'
%fieldset.eleven.columns.alpha.no-border-bottom
%legend IMAGES
.row

View File

@@ -2,8 +2,9 @@
Enterprises
- content_for :page_actions do
%li#new_product_link
= button_link_to "New Enterprise", main_app.new_admin_enterprise_path, :icon => 'icon-plus', :id => 'admin_new_enterprise_link'
- if spree_current_user.can_own_more_enterprises?
%li#new_product_link
= button_link_to "New Enterprise", main_app.new_admin_enterprise_path, :icon => 'icon-plus', :id => 'admin_new_enterprise_link'
= render 'admin/shared/enterprises_sub_menu'
@@ -11,16 +12,20 @@
%table#listing_enterprises.index
%colgroup
%col{style: "width: 25%;"}/
%col{style: "width: 10%;"}/
%col{style: "width: 15%;"}/
%col{style: "width: 5%;"}/
%col{style: "width: 10%;"}/
%col{style: "width: 20%;"}/
- if spree_current_user.admin?
%col{style: "width: 12%;"}/
%col{style: "width: 18%;"}/
%col{style: "width: 25%;"}/
%thead
%tr{"data-hook" => "enterprises_header"}
%th Name
%th Role
%th Visible?
%th Type
- if spree_current_user.admin?
%th Type
%th Owner
%th
%tbody
= f.fields_for :collection do |enterprise_form|
@@ -34,7 +39,9 @@
= enterprise_form.check_box :is_distributor
Hub
%td= enterprise_form.check_box :visible
%td= enterprise_form.select :type, Enterprise::TYPES, {}, class: 'select2 fullwidth'
- if spree_current_user.admin?
%td= enterprise_form.select :type, Enterprise::TYPES, {}, class: 'select2 fullwidth'
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"
%td{"data-hook" => "admin_users_index_row_actions"}
= render 'actions', enterprise: enterprise
- if @enterprises.empty?

View File

@@ -0,0 +1,9 @@
%h1
= @enterprise.name + " has been created"
%h3
Why not check it out on
%a{ href: "#{map_url}" }
= Spree::Config[:site_name] + "?"
If you have any questions, please get in touch with us at: hello@openfoodnetwork.org

View File

@@ -0,0 +1,36 @@
%html
%head
%meta{charset: 'utf-8'}/
%meta{name: 'viewport', content: "width=device-width,initial-scale=1.0"}/
%title= content_for?(:title) ? yield(:title) : 'Welcome to Open Food Network'
- if Rails.env.production?
= favicon_link_tag
- else
= favicon_link_tag "/favicon-staging.ico"
%link{href: "https://fonts.googleapis.com/css?family=Open+Sans:400,700", rel: "stylesheet", type: "text/css"}/
= yield :scripts
%script{src: "//maps.googleapis.com/maps/api/js?libraries=places&sensor=false"}
= stylesheet_link_tag "darkswarm/all"
= javascript_include_tag "darkswarm/all"
= render "layouts/bugherd_script"
= csrf_meta_tags
%body.off-canvas{"ng-app" => "Darkswarm", style: 'background-image: url("/assets/home/ofn_bg_1.jpg")' }
/ [if lte IE 8]
= render partial: "shared/ie_warning"
= javascript_include_tag "iehack"
= inject_json "user", "current_user"
.off-canvas-wrap{offcanvas: true}
.inner-wrap
%section{ role: "main" }
= yield
#footer
%loading

View File

@@ -0,0 +1 @@
%div{"ng-controller" => "AuthenticationCtrl"}

View File

@@ -0,0 +1,4 @@
=inject_spree_api_key
=inject_available_countries
=inject_enterprise_attributes
%div{ "ng-controller" => "RegistrationCtrl" }

View File

@@ -4,7 +4,9 @@
= render :partial => 'spree/admin/shared/order_sub_menu'
%div{ 'ng-app' => 'ofn.admin', 'ng-controller' => 'AdminOrderMgmtCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
=admin_inject_spree_api_key
%div{ ng: { app: 'ofn.admin', controller: 'AdminOrderMgmtCtrl', init: 'initialise()' } }
%div{ 'ng-show' => '!spree_api_key_ok' }
{{ api_error_msg }}
.filters{ :class => "sixteen columns alpha" }

View File

@@ -1,7 +1,8 @@
%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.white-bottom{ href: "#{main_app.new_admin_enterprise_path}" }
CREATE NEW
- if spree_current_user.can_own_more_enterprises?
%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?

View File

@@ -1,5 +0,0 @@
= f.field_container :supplier do
= f.label :supplier
%br
= f.collection_select(:supplier_id, Enterprise.is_primary_producer.managed_by(spree_current_user).by_name, :id, :name, {:include_blank => true}, {:class => "select2"})
= f.error_message_on :supplier

View File

@@ -1,7 +1,7 @@
= render 'spree/admin/products/bulk_edit/header'
= render 'spree/admin/products/bulk_edit/data'
%div{ 'ng-app' => 'ofn.admin', 'ng-controller' => 'AdminProductEditCtrl', 'ng-init' => "initialise('#{@spree_api_key}');loading=true;" }
%div{ ng: { app: 'ofn.admin', controller: 'AdminProductEditCtrl', init: 'initialise()' } }
= render 'spree/admin/products/bulk_edit/filters'
%hr.sixteen.columns.alpha

View File

@@ -1,2 +1,3 @@
= admin_inject_producers
= admin_inject_taxons
= admin_inject_spree_api_key

View File

@@ -1,13 +0,0 @@
%fieldset
%legend 'Manage Enterprises'
= f.field_container :enterprise_roles do
- f.object.build_enterprise_roles
%table
= f.fields_for :enterprise_roles do |enterprise_form|
%tr
%td
= hidden_field_tag "#{enterprise_form.object_name}[_destroy]", 1, :id => nil
= check_box_tag "#{enterprise_form.object_name}[_destroy]", 0, !enterprise_form.object.new_record?
%td
= label_tag "#{enterprise_form.object_name}[_destroy]", enterprise_form.object.enterprise.name
= enterprise_form.hidden_field :enterprise_id

View File

@@ -5,6 +5,10 @@ Openfoodnetwork::Application.routes.draw do
get "/map", to: "map#index", as: :map
get "/register", to: "registration#index", as: :registration
get "/register/store", to: "registration#store", as: :store_registration
get "/register/auth", to: "registration#authenticate", as: :registration_auth
resource :shop, controller: "shop" do
get :products
post :order_cycle

View File

@@ -0,0 +1,20 @@
class AddOwnerToEnterprise < ActiveRecord::Migration
def up
add_column :enterprises, :owner_id, :integer
add_index :enterprises, :owner_id
Enterprise.all.each do |e|
owner = e.users.find{ |u| !u.admin? }
admin_owner = e.users.find &:admin?
any_admin = Spree::User.admin.first
e.update_column :owner_id, (owner || admin_owner || any_admin )
end
add_foreign_key :enterprises, :spree_users, column: :owner_id
change_column :enterprises, :owner_id, :integer, null: false
end
def down
remove_column :enterprises, :owner_id
end
end

View File

@@ -0,0 +1,18 @@
class AddEnterpriseLimitToSpreeUsers < ActiveRecord::Migration
def up
add_column :spree_users, :enterprise_limit, :integer, default: 1, null: false
Spree::User.all.each do |u|
e_count = u.owned_enterprises.length
if u.admin? || e_count > 1
e_limit = 100
e_limit = 1000 if u.admin?
u.update_column :enterprise_limit, e_limit
end
end
end
def down
remove_column :spree_users, :enterprise_limit
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20140826043521) do
ActiveRecord::Schema.define(:version => 20140904003026) do
create_table "adjustment_metadata", :force => true do |t|
t.integer "adjustment_id"
@@ -265,9 +265,11 @@ ActiveRecord::Schema.define(:version => 20140826043521) do
t.string "instagram"
t.string "linkedin"
t.string "type", :default => "profile", :null => false
t.integer "owner_id", :null => false
end
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
add_index "enterprises", ["owner_id"], :name => "index_enterprises_on_owner_id"
create_table "exchange_fees", :force => true do |t|
t.integer "exchange_id"
@@ -969,6 +971,7 @@ ActiveRecord::Schema.define(:version => 20140826043521) do
t.string "spree_api_key", :limit => 48
t.datetime "reset_password_sent_at"
t.string "api_key", :limit => 40
t.integer "enterprise_limit", :default => 1, :null => false
end
add_index "spree_users", ["email"], :name => "email_idx_unique", :unique => true
@@ -1069,6 +1072,7 @@ ActiveRecord::Schema.define(:version => 20140826043521) do
add_foreign_key "enterprise_roles", "spree_users", name: "enterprise_roles_user_id_fk", column: "user_id"
add_foreign_key "enterprises", "spree_addresses", name: "enterprises_address_id_fk", column: "address_id"
add_foreign_key "enterprises", "spree_users", name: "enterprises_owner_id_fk", column: "owner_id"
add_foreign_key "exchange_fees", "enterprise_fees", name: "exchange_fees_enterprise_fee_id_fk"
add_foreign_key "exchange_fees", "exchanges", name: "exchange_fees_exchange_id_fk"

View File

@@ -0,0 +1,12 @@
module OpenFoodNetwork
module SpreeApiKeyLoader
def load_spree_api_key
if spree_current_user
spree_current_user.generate_spree_api_key! unless spree_current_user.spree_api_key
@spree_api_key = spree_current_user.spree_api_key
else
@spree_api_key = nil
end
end
end
end

View File

@@ -2,7 +2,12 @@ require 'spec_helper'
module Admin
describe EnterprisesController do
let(:distributor) { create(:distributor_enterprise) }
let(:distributor_owner) do
user = create(:user)
user.spree_roles = []
user
end
let(:distributor) { create(:distributor_enterprise, owner: distributor_owner ) }
let(:user) do
user = create(:user)
user.spree_roles = []
@@ -22,6 +27,7 @@ module Admin
it "grants management permission if the current user is an enterprise user" do
controller.stub spree_current_user: user
enterprise_params[:enterprise][:owner_id] = user
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
@@ -30,11 +36,50 @@ module Admin
it "does not grant management permission to admins" do
controller.stub spree_current_user: admin_user
enterprise_params[:enterprise][:owner_id] = admin_user
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
admin_user.enterprise_roles.where(enterprise_id: enterprise).should be_empty
end
it "it overrides the owner_id submitted by the user unless current_user is super admin" do
controller.stub spree_current_user: user
enterprise_params[:enterprise][:owner_id] = admin_user
spree_put :create, enterprise_params
enterprise = Enterprise.find_by_name 'zzz'
user.enterprise_roles.where(enterprise_id: enterprise).first.should be
end
end
describe "updating an enterprise" do
it "allows current owner to change ownership" do
controller.stub spree_current_user: distributor_owner
update_params = { id: distributor, enterprise: { owner_id: user } }
spree_post :update, update_params
distributor.reload
expect(distributor.owner).to eq user
end
it "allows super admin to change ownership" do
controller.stub spree_current_user: admin_user
update_params = { id: distributor, enterprise: { owner_id: user } }
spree_post :update, update_params
distributor.reload
expect(distributor.owner).to eq user
end
it "does not allow managers to change ownership" do
controller.stub spree_current_user: user
update_params = { id: distributor, enterprise: { owner_id: user } }
spree_post :update, update_params
distributor.reload
expect(distributor.owner).to eq distributor_owner
end
end
describe "updating an enterprise" do

View File

@@ -0,0 +1,15 @@
require 'spec_helper'
describe RegistrationController do
describe "redirecting when user not logged in" do
it "index" do
get :index
response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register")
end
it "store" do
get :store
response.should redirect_to registration_auth_path(anchor: "signup?after_login=/register/store")
end
end
end

View File

@@ -82,6 +82,7 @@ FactoryGirl.define do
end
factory :enterprise, :class => Enterprise do
owner { FactoryGirl.create :user }
sequence(:name) { |n| "Enterprise #{n}" }
type 'full'
description 'enterprise'

View File

@@ -305,7 +305,6 @@ feature %q{
expect(page).to have_select "producer", selected: s1.name
expect(page).to have_field "available_on", with: p.available_on.strftime("%F %T")
expect(page).to have_field "price", with: "10.0"
save_screenshot '/Users/rob/Desktop/ss.png'
expect(page).to have_selector "div#s2id_p#{p.id}_category a.select2-choice"
expect(page).to have_select "variant_unit_with_scale", selected: "Volume (L)"
expect(page).to have_field "on_hand", with: "6"
@@ -745,8 +744,6 @@ feature %q{
permissions_list: [:manage_products])
end
use_short_wait
before do
@enterprise_user = create_enterprise_user
@enterprise_user.enterprise_roles.build(enterprise: supplier_managed1).save
@@ -779,6 +776,28 @@ feature %q{
expect(page).to have_field 'product_name', with: product_supplied_inactive.name
end
it "allows me to create a product" do
taxon = create(:taxon, name: 'Fruit')
visit '/admin/products/bulk_edit'
find("a", text: "NEW PRODUCT").click
expect(page).to have_content 'NEW PRODUCT'
expect(page).to have_select 'product_supplier_id', with_options: [supplier_managed1.name, supplier_managed2.name, supplier_permitted.name]
within 'fieldset#new_product' do
fill_in 'product_name', with: 'Big Bag Of Apples'
select supplier_permitted.name, from: 'product_supplier_id'
fill_in 'product_price', with: '10.00'
select taxon.name, from: 'product_primary_taxon_id'
end
click_button 'Create'
expect(URI.parse(current_url).path).to eq '/admin/products/bulk_edit'
expect(flash_message).to eq 'Product "Big Bag Of Apples" has been successfully created!'
expect(page).to have_field "product_name", with: 'Big Bag Of Apples'
end
it "allows me to update a product" do
p = product_supplied_permitted

View File

@@ -71,7 +71,9 @@ feature %q{
visit admin_enterprise_roles_path
page.should have_relationship u, e
first("a.delete-enterprise-role").click
within("#enterprise_role_#{er.id}") do
find("a.delete-enterprise-role").click
end
page.should_not have_relationship u, e
EnterpriseRole.where(id: er.id).should be_empty

View File

@@ -17,42 +17,18 @@ feature %q{
let(:distributor_profile) { create(:distributor_enterprise, name: 'Distributor profile', type: 'profile') }
describe "creating an enterprise user" do
context "with no enterprises managed" do
it "assigns an enterprise to a user" do
context "with a limitted number of owned enterprises" do
scenario "setting the enterprise ownership limit" do
user.enterprise_limit.should == 1
login_to_admin_section
click_link 'Users'
click_link user.email
click_link 'Edit'
check supplier2.name
fill_in "user_enterprise_limit", with: 2
click_button 'Update'
user.enterprises.count.should == 1
user.enterprises.first.name.should == supplier2.name
end
end
context "with existing enterprises managed" do
before do
user.enterprise_roles.create!(enterprise: supplier1)
user.enterprise_roles.create!(enterprise: distributor1)
end
it "can remove and add enterprise management for a user" do
login_to_admin_section
click_link 'Users'
click_link user.email
click_link 'Edit'
uncheck distributor1.name # remove
check distributor2.name # add
click_button 'Update'
user.enterprises.count.should == 2
user.enterprises.should include supplier1
user.enterprises.should include distributor2
user.reload
expect(user.enterprise_limit).to eq 2
end
end
end

View File

@@ -38,6 +38,9 @@ feature %q{
scenario "editing enterprises in bulk" do
s = create(:supplier_enterprise)
d = create(:distributor_enterprise, type: 'profile')
d_manager = create_enterprise_user
d_manager.enterprise_roles.build(enterprise: d).save
expect(d.owner).to_not eq d_manager
login_to_admin_section
click_link 'Enterprises'
@@ -46,12 +49,14 @@ feature %q{
expect(page).to have_checked_field "enterprise_set_collection_attributes_0_visible"
uncheck "enterprise_set_collection_attributes_0_visible"
select 'full', from: "enterprise_set_collection_attributes_0_type"
select d_manager.email, from: 'enterprise_set_collection_attributes_0_owner_id'
end
click_button "Update"
flash_message.should == 'Enterprises updated successfully'
distributor = Enterprise.find(d.id)
expect(distributor.visible).to eq false
expect(distributor.type).to eq 'full'
expect(distributor.owner).to eq d_manager
end
scenario "viewing an enterprise" do
@@ -64,35 +69,31 @@ feature %q{
page.should have_content e.name
end
scenario "creating a new enterprise" do
scenario "creating a new enterprise", js:true do
eg1 = create(:enterprise_group, name: 'eg1')
eg2 = create(:enterprise_group, name: 'eg2')
payment_method = create(:payment_method)
shipping_method = create(:shipping_method)
enterprise_fee = create(:enterprise_fee)
login_to_admin_section
click_link 'Enterprises'
# Navigating
admin = quick_login_as_admin
visit '/admin/enterprises'
click_link 'New Enterprise'
fill_in 'enterprise_name', :with => 'Eaterprises'
choose 'Full'
fill_in 'enterprise_description', :with => 'Connecting farmers and eaters'
fill_in 'enterprise_long_description', :with => 'Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.'
fill_in 'enterprise_distributor_info', :with => 'Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.'
# Checking shipping and payment method sidebars work
uncheck 'enterprise_is_primary_producer'
check 'enterprise_is_distributor'
select eg1.name, from: 'enterprise_group_ids'
page.should_not have_checked_field "enterprise_payment_method_ids_#{payment_method.id}"
page.should_not have_checked_field "enterprise_shipping_method_ids_#{shipping_method.id}"
# Filling in details
fill_in 'enterprise_name', :with => 'Eaterprises'
select2_search admin.email, from: 'Owner'
choose 'Full'
check "enterprise_payment_method_ids_#{payment_method.id}"
check "enterprise_shipping_method_ids_#{shipping_method.id}"
select2_search eg1.name, from: 'Groups'
fill_in 'enterprise_contact', :with => 'Kirsten or Ren'
fill_in 'enterprise_phone', :with => '0413 897 321'
fill_in 'enterprise_email', :with => 'info@eaterprises.com.au'
@@ -106,14 +107,16 @@ feature %q{
fill_in 'enterprise_address_attributes_address1', :with => '35 Ballantyne St'
fill_in 'enterprise_address_attributes_city', :with => 'Thornbury'
fill_in 'enterprise_address_attributes_zipcode', :with => '3072'
select('Australia', :from => 'enterprise_address_attributes_country_id')
select('Victoria', :from => 'enterprise_address_attributes_state_id')
select2_search 'Australia', :from => 'Country'
select2_search 'Victoria', :from => 'State'
fill_in 'enterprise_description', :with => 'Connecting farmers and eaters'
fill_in 'enterprise_long_description', :with => 'Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.'
click_button 'Create'
flash_message.should == 'Enterprise "Eaterprises" has been successfully created!'
end
scenario "editing an existing enterprise" do
scenario "editing an existing enterprise", js: true do
@enterprise = create(:enterprise)
e2 = create(:enterprise)
eg1 = create(:enterprise_group, name: 'eg1')
@@ -121,14 +124,18 @@ feature %q{
payment_method = create(:payment_method, distributors: [e2])
shipping_method = create(:shipping_method, distributors: [e2])
enterprise_fee = create(:enterprise_fee, enterprise: @enterprise )
user = create(:user)
login_to_admin_section
admin = quick_login_as_admin
click_link 'Enterprises'
all("a", text:'Edit Profile').first.click
visit '/admin/enterprises'
within "tr.enterprise-#{@enterprise.id}" do
all("a", text: 'Edit Profile').first.click
end
fill_in 'enterprise_name', :with => 'Eaterprises'
choose 'Single'
select2_search user.email, from: 'Owner'
fill_in 'enterprise_description', :with => 'Connecting farmers and eaters'
fill_in 'enterprise_long_description', :with => 'Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.'
@@ -143,7 +150,7 @@ feature %q{
page.should have_selector "#shipping_methods"
page.should have_selector "#enterprise_fees"
select eg1.name, from: 'enterprise_group_ids'
select2_search eg1.name, from: 'Groups'
page.should_not have_checked_field "enterprise_payment_method_ids_#{payment_method.id}"
page.should_not have_checked_field "enterprise_shipping_method_ids_#{shipping_method.id}"
@@ -162,13 +169,15 @@ feature %q{
fill_in 'enterprise_address_attributes_address1', :with => '35 Ballantyne St'
fill_in 'enterprise_address_attributes_city', :with => 'Thornbury'
fill_in 'enterprise_address_attributes_zipcode', :with => '3072'
select('Australia', :from => 'enterprise_address_attributes_country_id')
select('Victoria', :from => 'enterprise_address_attributes_state_id')
select2_search 'Australia', :from => 'Country'
select2_search 'Victoria', :from => 'State'
click_button 'Update'
flash_message.should == 'Enterprise "Eaterprises" has been successfully updated!'
page.should have_field 'enterprise_name', :with => 'Eaterprises'
@enterprise.reload
expect(@enterprise.owner).to eq user
page.should have_checked_field "enterprise_payment_method_ids_#{payment_method.id}"
page.should have_checked_field "enterprise_shipping_method_ids_#{shipping_method.id}"
@@ -248,56 +257,91 @@ feature %q{
let(:supplier2) { create(:supplier_enterprise, name: 'Another Supplier') }
let(:distributor1) { create(:distributor_enterprise, name: 'First Distributor') }
let(:distributor2) { create(:distributor_enterprise, name: 'Another Distributor') }
let(:enterprise_user) { create_enterprise_user }
before(:each) do
@new_user = create_enterprise_user
@new_user.enterprise_roles.build(enterprise: supplier1).save
@new_user.enterprise_roles.build(enterprise: distributor1).save
enterprise_user.enterprise_roles.build(enterprise: supplier1).save
enterprise_user.enterprise_roles.build(enterprise: distributor1).save
login_to_admin_as @new_user
login_to_admin_as enterprise_user
end
scenario "can view enterprises I have permission to" do
oc_user_coordinating = create(:simple_order_cycle, { coordinator: supplier1, name: 'Order Cycle 1' } )
oc_for_other_user = create(:simple_order_cycle, { coordinator: supplier2, name: 'Order Cycle 2' } )
context "listing enterprises" do
scenario "displays enterprises I have permission to manage" do
oc_user_coordinating = create(:simple_order_cycle, { coordinator: supplier1, name: 'Order Cycle 1' } )
oc_for_other_user = create(:simple_order_cycle, { coordinator: supplier2, name: 'Order Cycle 2' } )
click_link "Enterprises"
click_link "Enterprises"
within("tr.enterprise-#{distributor1.id}") do
expect(page).to have_content distributor1.name
expect(page).to have_checked_field "enterprise_set_collection_attributes_0_is_distributor"
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_0_is_primary_producer"
expect(page).to have_select "enterprise_set_collection_attributes_0_type"
within("tr.enterprise-#{distributor1.id}") do
expect(page).to have_content distributor1.name
expect(page).to have_checked_field "enterprise_set_collection_attributes_0_is_distributor"
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_0_is_primary_producer"
expect(page).to_not have_select "enterprise_set_collection_attributes_0_type"
end
within("tr.enterprise-#{supplier1.id}") do
expect(page).to have_content supplier1.name
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_1_is_distributor"
expect(page).to have_checked_field "enterprise_set_collection_attributes_1_is_primary_producer"
expect(page).to_not have_select "enterprise_set_collection_attributes_1_type"
end
expect(page).to_not have_content "supplier2.name"
expect(page).to_not have_content "distributor2.name"
expect(find("#content-header")).to have_link "New Enterprise"
end
within("tr.enterprise-#{supplier1.id}") do
expect(page).to have_content supplier1.name
expect(page).to have_unchecked_field "enterprise_set_collection_attributes_1_is_distributor"
expect(page).to have_checked_field "enterprise_set_collection_attributes_1_is_primary_producer"
expect(page).to have_select "enterprise_set_collection_attributes_1_type"
end
context "when I have reached my enterprise ownership limit" do
it "does not display the link to create a new enterprise" do
enterprise_user.owned_enterprises.push [supplier1]
expect(page).to_not have_content "supplier2.name"
expect(page).to_not have_content "distributor2.name"
click_link "Enterprises"
page.should have_content supplier1.name
page.should have_content distributor1.name
expect(find("#content-header")).to_not have_link "New Enterprise"
end
end
end
scenario "creating an enterprise" do
# When I create an enterprise
click_link 'Enterprises'
click_link 'New Enterprise'
fill_in 'enterprise_name', with: 'zzz'
fill_in 'enterprise_address_attributes_address1', with: 'z'
fill_in 'enterprise_address_attributes_city', with: 'z'
fill_in 'enterprise_address_attributes_zipcode', with: 'z'
click_button 'Create'
context "creating an enterprise" do
before do
# When I create an enterprise
click_link 'Enterprises'
click_link 'New Enterprise'
fill_in 'enterprise_name', with: 'zzz'
fill_in 'enterprise_address_attributes_address1', with: 'z'
fill_in 'enterprise_address_attributes_city', with: 'z'
fill_in 'enterprise_address_attributes_zipcode', with: 'z'
end
# Then it should be created
page.should have_content 'Enterprise "zzz" has been successfully created!'
enterprise = Enterprise.last
enterprise.name.should == 'zzz'
scenario "without violating rules" do
click_button 'Create'
# And I should be managing it
Enterprise.managed_by(@new_user).should include enterprise
# Then it should be created
page.should have_content 'Enterprise "zzz" has been successfully created!'
enterprise = Enterprise.last
enterprise.name.should == 'zzz'
# And I should be managing it
Enterprise.managed_by(enterprise_user).should include enterprise
end
context "overstepping my owned enterprises limit" do
before do
create(:enterprise, owner: enterprise_user)
end
it "shows me an error message" do
click_button 'Create'
# Then it should show me an error
expect(page).to_not have_content 'Enterprise "zzz" has been successfully created!'
expect(page).to have_content "You are not permitted to own own any more enterprises (limit is 1)."
end
end
end
scenario "editing enterprises I have permission to" do

View File

@@ -16,7 +16,7 @@ feature %q{
Spree::Admin::OverviewController.any_instance.stub(:spree_current_user).and_return @enterprise_user
quick_login_as @enterprise_user
end
context "with no enterprises" do
it "prompts the user to create a new enteprise" do
visit '/admin'
@@ -42,9 +42,8 @@ feature %q{
page.should have_selector ".dashboard_item#order_cycles"
page.should have_selector ".dashboard_item#enterprises .list-item", text: d1.name
page.should have_selector ".dashboard_item#enterprises .button.bottom", text: "MANAGE MY ENTERPRISES"
end
context "but no products or order cycles" do
it "prompts the user to create a new product and to manage order cycles" do
visit '/admin'

View File

@@ -86,11 +86,14 @@ feature %q{
context "as an enterprise user" do
before(:each) do
before do
@new_user = create_enterprise_user
@supplier2 = create(:supplier_enterprise, name: 'Another Supplier')
@supplier_permitted = create(:supplier_enterprise, name: 'Permitted Supplier')
@new_user.enterprise_roles.build(enterprise: @supplier2).save
@new_user.enterprise_roles.build(enterprise: @distributors[0]).save
create(:enterprise_relationship, parent: @supplier_permitted, child: @supplier2,
permissions_list: [:manage_products])
login_to_admin_as @new_user
end
@@ -116,9 +119,8 @@ feature %q{
select taxon.name, from: "product_primary_taxon_id"
# Should only have suppliers listed which the user can manage
within "#product_supplier_id" do
page.should_not have_content @supplier.name
end
page.should have_select 'product_supplier_id', with_options: [@supplier2.name, @supplier_permitted.name]
page.should_not have_select 'product_supplier_id', with_options: [@supplier.name]
click_button 'Create'
@@ -127,6 +129,18 @@ feature %q{
product.supplier.should == @supplier2
end
scenario "editing a product" do
product = create(:simple_product, name: 'a product', supplier: @supplier2)
visit spree.edit_admin_product_path product
select 'Permitted Supplier', from: 'product_supplier_id'
click_button 'Update'
flash_message.should == 'Product "a product" has been successfully updated!'
product.reload
product.supplier.should == @supplier_permitted
end
scenario "editing product distributions" do
product = create(:simple_product, supplier: @supplier2)

View File

@@ -10,7 +10,6 @@ feature "Authentication", js: true do
visit groups_path(anchor: "login?after_login=#{producers_path}")
fill_in "Email", with: user.email
fill_in "Password", with: user.password
save_screenshot "/Users/willmarshall/Desktop/wtf.png"
click_login_button
page.should have_content "Find local producers"
current_path.should == producers_path

View File

@@ -0,0 +1,115 @@
require 'spec_helper'
feature "Registration", js: true do
include WebHelper
describe "Registering a Profile", use_short_wait do
let(:user) { create(:user, password: "password", password_confirmation: "password") }
it "Allows a logged in user to register a profile" do
visit registration_path
expect(URI.parse(current_url).path).to eq registration_auth_path
# Logging in
click_link "Log in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button 'Log in'
# Log in was successful, introduction shown
expect(page).to have_content "This wizard will step you through creating a profile"
expect(URI.parse(current_url).path).to eq registration_path
# Done reading introduction
click_button "Let's get started!"
# Filling in details
expect(page).to have_content "Woot! First we need to know what sort of enterprise you are:"
fill_in 'enterprise_name', with: "My Awesome Enterprise"
click_link 'both-panel'
click_button 'Continue'
# Filling in address
expect(page).to have_content 'Greetings My Awesome Enterprise'
fill_in 'enterprise_address', with: '123 Abc Street'
fill_in 'enterprise_city', with: 'Northcote'
fill_in 'enterprise_zipcode', with: '3070'
select 'Australia', from: 'enterprise_country'
select 'Vic', from: 'enterprise_state'
click_button 'Continue'
# Filling in Contact Details
expect(page).to have_content 'Who is responsible for managing My Awesome Enterprise?'
fill_in 'enterprise_contact', with: 'Saskia Munroe'
page.should have_field 'enterprise_email', with: user.email
fill_in 'enterprise_phone', with: '12 3456 7890'
click_button 'Continue'
# Enterprise should be created
expect(page).to have_content 'Nice one!'
# e = Enterprise.find_by_name('My Awesome Enterprise')
# expect(e.address.address1).to eq "123 Abc Street"
# expect(e.is_distributor).to eq true
# expect(e.is_primary_producer).to eq true
# expect(e.contact).to eq "Saskia Munroe"
# Filling in about
fill_in 'enterprise_description', with: 'Short description'
fill_in 'enterprise_long_desc', with: 'Long description'
fill_in 'enterprise_abn', with: '12345'
fill_in 'enterprise_acn', with: '54321'
click_button 'Continue'
# Enterprise should be updated
expect(page).to have_content 'Last step!'
# e.reload
# expect(e.description).to eq "Short description"
# expect(e.long_description).to eq "Long description"
# expect(e.abn).to eq '12345'
# expect(e.acn).to eq '54321'
# Filling in social
fill_in 'enterprise_website', with: 'www.shop.com'
fill_in 'enterprise_facebook', with: 'FaCeBoOk'
fill_in 'enterprise_linkedin', with: 'LiNkEdIn'
fill_in 'enterprise_twitter', with: '@TwItTeR'
fill_in 'enterprise_instagram', with: '@InStAgRaM'
click_button 'Continue'
# Done
expect(page).to have_content "You have successfully completed the profile for My Awesome Enterprise"
# e.reload
# expect(e.website).to eq "www.shop.com"
# expect(e.facebook).to eq "FaCeBoOk"
# expect(e.linkedin).to eq "LiNkEdIn"
# expect(e.twitter).to eq "@TwItTeR"
# expect(e.instagram).to eq "@InStAgRaM"
end
it "Allows a logged in user to register a store" do
visit store_registration_path
expect(URI.parse(current_url).path).to eq registration_auth_path
# Logging in
click_link "Log in"
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button 'Log in'
# Log in was successful, introduction shown
expect(page).to have_content "This wizard will step you through creating a profile"
expect(URI.parse(current_url).path).to eq store_registration_path
# Done reading introduction
click_button "Let's get started!"
# Details Page
expect(page).to have_content "Woot! First we need to know the name of your farm:"
expect(page).to_not have_selector '#enterprise-types'
# Everything from here should be covered in 'profile' spec
end
end
end

View File

@@ -188,7 +188,7 @@ feature "As a consumer I want to check out my cart", js: true do
# Order should have a payment with the correct amount
o = Spree::Order.complete.first
o.payments.first.amount.should == 15.79
o.payments.first.amount.should == 11.23
end
it "shows the payment processing failed message when submitted with an invalid credit card" do

View File

@@ -12,5 +12,5 @@ describe "enterprise relationships", ->
EnterpriseRelationships = _EnterpriseRelationships_
it "presents permission names", ->
expect(EnterpriseRelationships.permission_presentation("add_to_order_cycle")).toEqual "can add to order cycle"
expect(EnterpriseRelationships.permission_presentation("manage_products")).toEqual "can manage the products of"
expect(EnterpriseRelationships.permission_presentation("add_to_order_cycle")).toEqual "to add to order cycle"
expect(EnterpriseRelationships.permission_presentation("manage_products")).toEqual "to manage products"

View File

@@ -2,7 +2,9 @@ describe "AdminOrderMgmtCtrl", ->
ctrl = scope = httpBackend = VariantUnitManager = null
beforeEach ->
module "ofn.admin"
module "ofn.admin", ($provide) ->
$provide.value 'SpreeApiKey', 'API_KEY'
return
beforeEach inject(($controller, $rootScope, $httpBackend, _VariantUnitManager_) ->
scope = $rootScope.$new()
ctrl = $controller
@@ -18,7 +20,7 @@ describe "AdminOrderMgmtCtrl", ->
returnedSuppliers = ["list of suppliers"]
returnedDistributors = ["list of distributors"]
returnedOrderCycles = [ "oc1", "oc2", "oc3" ]
httpBackend.expectGET("/api/users/authorise_api?token=api_key").respond success: "Use of API Authorised"
httpBackend.expectGET("/api/users/authorise_api?token=API_KEY").respond success: "Use of API Authorised"
httpBackend.expectGET("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").respond returnedSuppliers
httpBackend.expectGET("/api/enterprises/accessible?template=bulk_index&q[is_distributor_eq]=true").respond returnedDistributors
httpBackend.expectGET("/api/order_cycles/accessible").respond returnedOrderCycles
@@ -27,7 +29,7 @@ describe "AdminOrderMgmtCtrl", ->
#spyOn(returnedSuppliers, "unshift")
#spyOn(returnedDistributors, "unshift")
#spyOn(returnedOrderCycles, "unshift")
scope.initialise "api_key"
scope.initialise()
httpBackend.flush()
expect(scope.suppliers).toEqual [{ id : '0', name : 'All' }, 'list of suppliers']

View File

@@ -165,7 +165,7 @@ describe "filtering products for submission to database", ->
variant_unit: 'weight'
variant_unit_scale: 1
]
# TODO Not an exhaustive test, is there a better way to do this?
it "only returns the properties of products which ought to be updated", ->
available_on = new Date()
@@ -238,6 +238,7 @@ describe "AdminProductEditCtrl", ->
module ($provide)->
$provide.value "producers", []
$provide.value "taxons", []
$provide.value 'SpreeApiKey', 'API_KEY'
null
beforeEach inject((_$controller_, _$timeout_, $rootScope, _$httpBackend_, _DirtyProducts_) ->
@@ -252,9 +253,9 @@ describe "AdminProductEditCtrl", ->
describe "loading data upon initialisation", ->
it "gets a list of producers and then resets products with a list of data", ->
$httpBackend.expectGET("/api/users/authorise_api?token=api_key").respond success: "Use of API Authorised"
$httpBackend.expectGET("/api/users/authorise_api?token=API_KEY").respond success: "Use of API Authorised"
spyOn($scope, "fetchProducts").andReturn "nothing"
$scope.initialise "api_key"
$scope.initialise()
$httpBackend.flush()
expect($scope.fetchProducts.calls.length).toEqual 1
expect($scope.spree_api_key_ok).toEqual true

View File

@@ -0,0 +1,85 @@
describe "EnterpriseRegistrationService", ->
EnterpriseRegistrationService = null
$httpBackend = null
availableCountries = []
enterpriseAttributes =
name: "Enterprise 1"
something: true
spreeApiKey = "keykeykeykey"
CurrentUser =
id: 2
email: 'lalala@email.com'
RegistrationServiceMock =
select: -> null
beforeEach ->
module('Darkswarm')
angular.module('Darkswarm').value 'availableCountries', availableCountries
angular.module('Darkswarm').value 'enterpriseAttributes', enterpriseAttributes
angular.module('Darkswarm').value 'spreeApiKey', spreeApiKey
angular.module('Darkswarm').value 'CurrentUser', CurrentUser
angular.module('Darkswarm').value 'RegistrationService', RegistrationServiceMock
inject ($injector, _$httpBackend_) ->
$httpBackend = _$httpBackend_
EnterpriseRegistrationService = $injector.get("EnterpriseRegistrationService")
it "adds the specified attributes to the ERS enterprise object", ->
expect(EnterpriseRegistrationService.enterprise.name).toBe "Enterprise 1"
expect(EnterpriseRegistrationService.enterprise.something).toBe true
describe "creating an enterprise", ->
describe "success", ->
beforeEach ->
spyOn(RegistrationServiceMock, "select")
$httpBackend.expectPOST("/api/enterprises?token=keykeykeykey").respond 200, 6
EnterpriseRegistrationService.create()
$httpBackend.flush()
it "stores the id of the created enterprise", ->
expect(EnterpriseRegistrationService.enterprise.id).toBe 6
it "moves the user to the about page", ->
expect(RegistrationServiceMock.select).toHaveBeenCalledWith 'about'
describe "failure", ->
beforeEach ->
spyOn(RegistrationServiceMock, "select")
spyOn(window, "alert")
$httpBackend.expectPOST("/api/enterprises?token=keykeykeykey").respond 400, 6
EnterpriseRegistrationService.create()
$httpBackend.flush()
it "alerts the user to failure", ->
expect(window.alert).toHaveBeenCalledWith 'Failed to create your enterprise.\nPlease ensure all fields are completely filled out.'
it "does not move the user to the about page", ->
expect(RegistrationServiceMock.select).not.toHaveBeenCalled
describe "updating an enterprise", ->
beforeEach ->
EnterpriseRegistrationService.enterprise.id = 78
spyOn(RegistrationServiceMock, "select")
describe "success", ->
beforeEach ->
$httpBackend.expectPUT("/api/enterprises/78?token=keykeykeykey").respond 200, 6
EnterpriseRegistrationService.update('step')
$httpBackend.flush()
it "moves the user to the about page", ->
expect(RegistrationServiceMock.select).toHaveBeenCalledWith 'step'
describe "failure", ->
beforeEach ->
spyOn(window, "alert")
$httpBackend.expectPUT("/api/enterprises/78?token=keykeykeykey").respond 400, 6
EnterpriseRegistrationService.update('step')
$httpBackend.flush()
it "alerts the user to failure", ->
expect(window.alert).toHaveBeenCalledWith 'Failed to update your enterprise.\nPlease ensure all fields are completely filled out.'
it "does not move the user to the about page", ->
expect(RegistrationServiceMock.select).not.toHaveBeenCalled

View File

@@ -8,18 +8,21 @@ describe "Hubs service", ->
active: false
orders_close_at: new Date()
is_distributor: true
has_shopfront: true
}
{
id: 3
active: false
orders_close_at: new Date()
is_distributor: true
has_shopfront: true
}
{
id: 1
active: true
orders_close_at: new Date()
is_distributor: true
has_shopfront: true
}
]

View File

@@ -516,30 +516,44 @@ describe 'OrderCycle services', ->
]
describe 'removing exchanges', ->
it 'removes incoming exchanges', ->
exchange = {enterprise_id: '123', active: true, variants: {}, enterprise_fees: []}
OrderCycle.order_cycle.incoming_exchanges = [exchange]
OrderCycle.removeExchange(exchange)
expect(OrderCycle.order_cycle.incoming_exchanges).toEqual []
exchange = null
it 'removes outgoing exchanges', ->
exchange = {enterprise_id: '123', active: true, variants: {}, enterprise_fees: []}
OrderCycle.order_cycle.outgoing_exchanges = [exchange]
OrderCycle.removeExchange(exchange)
expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual []
it 'removes distribution of all exchange variants', ->
beforeEach ->
spyOn(OrderCycle, 'removeDistributionOfVariant')
exchange =
enterprise_id: '123'
active: true
incoming: false
variants: {1: true, 2: false, 3: true}
enterprise_fees: []
OrderCycle.order_cycle.incoming_exchanges = [exchange]
OrderCycle.removeExchange(exchange)
expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('1')
expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalledWith('2')
expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('3')
describe "removing incoming exchanges", ->
beforeEach ->
exchange.incoming = true
OrderCycle.order_cycle.incoming_exchanges = [exchange]
it 'removes the exchange', ->
OrderCycle.removeExchange(exchange)
expect(OrderCycle.order_cycle.incoming_exchanges).toEqual []
it 'removes distribution of all exchange variants', ->
OrderCycle.removeExchange(exchange)
expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('1')
expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalledWith('2')
expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('3')
describe "removing outgoing exchanges", ->
beforeEach ->
exchange.incoming = false
OrderCycle.order_cycle.outgoing_exchanges = [exchange]
it 'removes the exchange', ->
OrderCycle.removeExchange(exchange)
expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual []
it "does not remove distribution of any variants", ->
OrderCycle.removeExchange(exchange)
expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalled()
it 'adds coordinator fees', ->
OrderCycle.addCoordinatorFee()

View File

@@ -0,0 +1,13 @@
require 'spec_helper'
describe EnterpriseMailer do
before do
@enterprise = create(:enterprise)
ActionMailer::Base.deliveries = []
end
it "should send an email when given an enterprise" do
EnterpriseMailer.creation_confirmation(@enterprise).deliver
ActionMailer::Base.deliveries.count.should == 1
end
end

View File

@@ -1,8 +1,10 @@
require 'spec_helper'
describe Enterprise do
include AuthenticationWorkflow
describe "associations" do
it { should belong_to(:owner) }
it { should have_many(:supplied_products) }
it { should have_many(:distributed_orders) }
it { should belong_to(:address) }
@@ -51,11 +53,44 @@ describe Enterprise do
e.suppliers
end
end
describe "ownership" do
let(:u1) { create_enterprise_user }
let(:u2) { create_enterprise_user }
let!(:e) { create(:enterprise, owner: u1 ) }
it "adds new owner to list of managers" do
expect(e.owner).to eq u1
expect(e.users).to include u1
expect(e.users).to_not include u2
e.owner = u2
e.save!
e.reload
expect(e.owner).to eq u2
expect(e.users).to include u1, u2
end
it "validates ownership limit" do
expect(u1.enterprise_limit).to be 1
expect(u1.owned_enterprises(:reload)).to eq [e]
e2 = create(:enterprise, owner: u2 )
expect{
e2.owner = u1
e2.save!
}.to raise_error ActiveRecord::RecordInvalid, "Validation failed: You are not permitted to own own any more enterprises (limit is 1)."
end
end
end
describe "validations" do
subject { FactoryGirl.create(:distributor_enterprise, :address => FactoryGirl.create(:address)) }
it { should validate_presence_of(:name) }
it "requires an owner" do
expect{
e = create(:enterprise, owner: nil)
}.to raise_error ActiveRecord::RecordInvalid, "Validation failed: Owner can't be blank"
end
end
describe "delegations" do
@@ -74,7 +109,7 @@ describe Enterprise do
Enterprise.visible.should == [s1]
end
end
describe "distributors_with_active_order_cycles" do
it "finds active distributors by order cycles" do
s = create(:supplier_enterprise)
@@ -441,8 +476,8 @@ describe Enterprise do
end
describe "presentation of attributes" do
let(:distributor) {
create(:distributor_enterprise,
let(:distributor) {
create(:distributor_enterprise,
website: "http://www.google.com",
facebook: "www.facebook.com/roger",
linkedin: "https://linkedin.com")

View File

@@ -1,6 +1,30 @@
describe Spree.user_class do
context "#create" do
describe "associations" do
it { should have_many(:owned_enterprises) }
describe "enterprise ownership" do
let(:u1) { create(:user, enterprise_limit: 2) }
let(:u2) { create(:user, enterprise_limit: 1) }
let!(:e1) { create(:enterprise, owner: u1) }
let!(:e2) { create(:enterprise, owner: u1) }
it "provides access to owned enterprises" do
expect(u1.owned_enterprises(:reload)).to include e1, e2
end
it "enforces the limit on the number of enterprise owned" do
expect(u2.owned_enterprises(:reload)).to eq []
u2.owned_enterprises << e1
expect(u2.save!).to_not raise_error
expect {
u2.owned_enterprises << e2
u2.save!
}.to raise_error ActiveRecord::RecordInvalid, "Validation failed: The nominated user is not permitted to own own any more enterprises (limit is 1)."
end
end
end
context "#create" do
it "should send a signup email" do
Spree::UserMailer.should_receive(:signup_confirmation).and_return(double(:deliver => true))
create(:user)

View File

@@ -6,7 +6,7 @@ module AuthenticationWorkflow
def quick_login_as_admin
admin_role = Spree::Role.find_or_create_by_name!('admin')
admin_user = create(:user,
admin_user = create(:user,
:password => 'passw0rd',
:password_confirmation => 'passw0rd',
:remember_me => false,
@@ -25,7 +25,7 @@ module AuthenticationWorkflow
def login_to_admin_section
admin_role = Spree::Role.find_or_create_by_name!('admin')
admin_user = create(:user,
admin_user = create(:user,
:password => 'passw0rd',
:password_confirmation => 'passw0rd',
:remember_me => false,
@@ -38,7 +38,7 @@ module AuthenticationWorkflow
end
def create_enterprise_user(enterprises = [])
new_user = create(:user, email: 'enterprise@hub.com', password: 'blahblah', :password_confirmation => 'blahblah', )
new_user = create(:user, password: 'blahblah', :password_confirmation => 'blahblah')
new_user.spree_roles = [] # for some reason unbeknown to me, this new user gets admin permissions by default.
for enterprise in enterprises do
new_user.enterprise_roles.build(enterprise: enterprise).save