diff --git a/app/assets/javascripts/admin/admin.js.coffee b/app/assets/javascripts/admin/admin.js.coffee index 76154e9e20..edebc019e5 100644 --- a/app/assets/javascripts/admin/admin.js.coffee +++ b/app/assets/javascripts/admin/admin.js.coffee @@ -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, */*" \ No newline at end of file diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js index 99c936c4d7..3fdd45585a 100644 --- a/app/assets/javascripts/admin/all.js +++ b/app/assets/javascripts/admin/all.js @@ -16,5 +16,6 @@ //= require admin/spree_auth //= require admin/spree_promo //= require ./admin +//= require ./products/products //= require_tree . diff --git a/app/assets/javascripts/admin/bulk_order_management.js.coffee b/app/assets/javascripts/admin/bulk_order_management.js.coffee index 7a1edcbca6..9ba34790a8 100644 --- a/app/assets/javascripts/admin/bulk_order_management.js.coffee +++ b/app/assets/javascripts/admin/bulk_order_management.js.coffee @@ -1,4 +1,4 @@ -Admin.controller "AdminOrderMgmtCtrl", [ +angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [ "$scope", "$http", "dataFetcher", "blankOption", "pendingChanges" ($scope, $http, dataFetcher, blankOption, pendingChanges) -> diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee index 4df57d6689..8d50a3dc1f 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee @@ -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 = diff --git a/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee b/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee index c66e79c046..665753a522 100644 --- a/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee +++ b/app/assets/javascripts/admin/controllers/enterprise_relationships_controller.js.coffee @@ -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 diff --git a/app/assets/javascripts/admin/controllers/enterprises_dashboard_controller.js.coffee b/app/assets/javascripts/admin/controllers/enterprises_dashboard_controller.js.coffee new file mode 100644 index 0000000000..ad72ff3529 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/enterprises_dashboard_controller.js.coffee @@ -0,0 +1,5 @@ +angular.module("ofn.admin").controller "enterprisesDashboardCtrl", [ + "$scope" + ($scope) -> + $scope.activeTab = "hubs" +] \ No newline at end of file diff --git a/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee b/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee index e0e0511f0c..2c8dba4baf 100644 --- a/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee +++ b/app/assets/javascripts/admin/directives/confirm_link_path.js.coffee @@ -1,4 +1,4 @@ -Admin.directive "ofnConfirmLinkPath", (ofnConfirmHandler) -> +angular.module("ofn.admin").directive "ofnConfirmLinkPath", (ofnConfirmHandler) -> restrict: "A" scope: path: "@ofnConfirmLinkPath" diff --git a/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee b/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee index aba2cd919e..a0b5272981 100644 --- a/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee +++ b/app/assets/javascripts/admin/directives/confirm_model_change.js.coffee @@ -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() diff --git a/app/assets/javascripts/admin/directives/date_picker.js.coffee b/app/assets/javascripts/admin/directives/date_picker.js.coffee index 3a07bfd3f5..6b5cac3e1b 100644 --- a/app/assets/javascripts/admin/directives/date_picker.js.coffee +++ b/app/assets/javascripts/admin/directives/date_picker.js.coffee @@ -1,4 +1,4 @@ -Admin.directive "datepicker", -> +angular.module("ofn.admin").directive "datepicker", -> require: "ngModel" link: (scope, element, attrs, ngModel) -> element.datepicker diff --git a/app/assets/javascripts/admin/directives/datetime_picker.js.coffee b/app/assets/javascripts/admin/directives/datetime_picker.js.coffee index 232d958b99..b0d91e538a 100644 --- a/app/assets/javascripts/admin/directives/datetime_picker.js.coffee +++ b/app/assets/javascripts/admin/directives/datetime_picker.js.coffee @@ -1,4 +1,4 @@ -Admin.directive "datetimepicker", -> +angular.module("ofn.admin").directive "datetimepicker", -> require: "ngModel" link: (scope, element, attrs, ngModel) -> element.datetimepicker diff --git a/app/assets/javascripts/admin/directives/decimal.js.coffee b/app/assets/javascripts/admin/directives/decimal.js.coffee index 8077f90c06..f4bed8e371 100644 --- a/app/assets/javascripts/admin/directives/decimal.js.coffee +++ b/app/assets/javascripts/admin/directives/decimal.js.coffee @@ -1,4 +1,4 @@ -Admin.directive "ofnDecimal", -> +angular.module("ofn.admin").directive "ofnDecimal", -> require: "ngModel" link: (scope, element, attrs, ngModel) -> numRegExp = /^\d+(\.\d+)?$/ diff --git a/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee b/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee index a71aa42997..c83d7fdc0f 100644 --- a/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee +++ b/app/assets/javascripts/admin/directives/line_item_upd_attr.js.coffee @@ -1,4 +1,4 @@ -Admin.directive "ofnLineItemUpdAttr", [ +angular.module("ofn.admin").directive "ofnLineItemUpdAttr", [ "switchClass", "pendingChanges" (switchClass, pendingChanges) -> require: "ngModel" diff --git a/app/assets/javascripts/admin/directives/select2_min_search.js.coffee b/app/assets/javascripts/admin/directives/select2_min_search.js.coffee index c33beb710e..1d55d886aa 100644 --- a/app/assets/javascripts/admin/directives/select2_min_search.js.coffee +++ b/app/assets/javascripts/admin/directives/select2_min_search.js.coffee @@ -1,4 +1,4 @@ -Admin.directive "ofnSelect2MinSearch", -> +angular.module("ofn.admin").directive "ofnSelect2MinSearch", -> require: 'ngModel' link: (scope, element, attrs, ngModel) -> element.select2 diff --git a/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee b/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee index 0705d04a23..e5713274ef 100644 --- a/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee +++ b/app/assets/javascripts/admin/directives/taxon_autocomplete.js.coffee @@ -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) -> diff --git a/app/assets/javascripts/admin/directives/toggle_column.js.coffee b/app/assets/javascripts/admin/directives/toggle_column.js.coffee index 2337a0fb58..1b8487eeb1 100644 --- a/app/assets/javascripts/admin/directives/toggle_column.js.coffee +++ b/app/assets/javascripts/admin/directives/toggle_column.js.coffee @@ -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", -> diff --git a/app/assets/javascripts/admin/directives/toggle_variants.js.coffee b/app/assets/javascripts/admin/directives/toggle_variants.js.coffee index 8c07490359..879942d698 100644 --- a/app/assets/javascripts/admin/directives/toggle_variants.js.coffee +++ b/app/assets/javascripts/admin/directives/toggle_variants.js.coffee @@ -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" diff --git a/app/assets/javascripts/admin/directives/track_product.js.coffee b/app/assets/javascripts/admin/directives/track_product.js.coffee index 3667794712..a4ea3865c0 100644 --- a/app/assets/javascripts/admin/directives/track_product.js.coffee +++ b/app/assets/javascripts/admin/directives/track_product.js.coffee @@ -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) -> diff --git a/app/assets/javascripts/admin/directives/track_variant.js.coffee b/app/assets/javascripts/admin/directives/track_variant.js.coffee index 189d5043fe..ab17ebcfa5 100644 --- a/app/assets/javascripts/admin/directives/track_variant.js.coffee +++ b/app/assets/javascripts/admin/directives/track_variant.js.coffee @@ -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) -> diff --git a/app/assets/javascripts/admin/filters/range_array.js.coffee b/app/assets/javascripts/admin/filters/range_array.js.coffee index 5056476f1b..be4a020442 100644 --- a/app/assets/javascripts/admin/filters/range_array.js.coffee +++ b/app/assets/javascripts/admin/filters/range_array.js.coffee @@ -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 \ No newline at end of file diff --git a/app/assets/javascripts/admin/filters/select_filter.js.coffee b/app/assets/javascripts/admin/filters/select_filter.js.coffee index 562be954b2..2b03abd613 100644 --- a/app/assets/javascripts/admin/filters/select_filter.js.coffee +++ b/app/assets/javascripts/admin/filters/select_filter.js.coffee @@ -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) && diff --git a/app/assets/javascripts/admin/filters/variant_filter.js.coffee b/app/assets/javascripts/admin/filters/variant_filter.js.coffee index 039c4cc46f..ddbc0f2711 100644 --- a/app/assets/javascripts/admin/filters/variant_filter.js.coffee +++ b/app/assets/javascripts/admin/filters/variant_filter.js.coffee @@ -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,{}) || diff --git a/app/assets/javascripts/admin/products/products.js.coffee b/app/assets/javascripts/admin/products/products.js.coffee new file mode 100644 index 0000000000..e922d40a34 --- /dev/null +++ b/app/assets/javascripts/admin/products/products.js.coffee @@ -0,0 +1 @@ +angular.module("admin.products", []) \ No newline at end of file diff --git a/app/assets/javascripts/admin/products/units_controller.js.coffee b/app/assets/javascripts/admin/products/units_controller.js.coffee new file mode 100644 index 0000000000..9070648e21 --- /dev/null +++ b/app/assets/javascripts/admin/products/units_controller.js.coffee @@ -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? + + \ No newline at end of file diff --git a/app/assets/javascripts/admin/services/blank_option.js.coffee b/app/assets/javascripts/admin/services/blank_option.js.coffee index 9913a6511d..42ff69a77b 100644 --- a/app/assets/javascripts/admin/services/blank_option.js.coffee +++ b/app/assets/javascripts/admin/services/blank_option.js.coffee @@ -1,2 +1,2 @@ -Admin.value "blankOption", -> +angular.module("ofn.admin").value "blankOption", -> { id: "0", name: "All" } \ No newline at end of file diff --git a/app/assets/javascripts/admin/services/confirm_handler.js.coffee b/app/assets/javascripts/admin/services/confirm_handler.js.coffee index 51b92848dc..88655e34e3 100644 --- a/app/assets/javascripts/admin/services/confirm_handler.js.coffee +++ b/app/assets/javascripts/admin/services/confirm_handler.js.coffee @@ -1,4 +1,4 @@ -Admin.factory "ofnConfirmHandler", (pendingChanges, $compile, $q) -> +angular.module("ofn.admin").factory "ofnConfirmHandler", (pendingChanges, $compile, $q) -> return (scope, callback) -> template = "
Unsaved changes currently exist, save now or ignore?
" dialogDiv = $compile(template)(scope) diff --git a/app/assets/javascripts/admin/services/data_fetcher.js.coffee b/app/assets/javascripts/admin/services/data_fetcher.js.coffee index 0227d26fc7..735e4cc6bb 100644 --- a/app/assets/javascripts/admin/services/data_fetcher.js.coffee +++ b/app/assets/javascripts/admin/services/data_fetcher.js.coffee @@ -1,4 +1,4 @@ -Admin.factory "dataFetcher", [ +angular.module("ofn.admin").factory "dataFetcher", [ "$http", "$q" ($http, $q) -> return (dataLocation) -> diff --git a/app/assets/javascripts/admin/services/data_submitter.js.coffee b/app/assets/javascripts/admin/services/data_submitter.js.coffee index 6a08ca2d33..7d121ec645 100644 --- a/app/assets/javascripts/admin/services/data_submitter.js.coffee +++ b/app/assets/javascripts/admin/services/data_submitter.js.coffee @@ -1,4 +1,4 @@ -Admin.factory "dataSubmitter", [ +angular.module("ofn.admin").factory "dataSubmitter", [ "$http", "$q", "switchClass" ($http, $q, switchClass) -> return (changeObj) -> diff --git a/app/assets/javascripts/admin/services/dirty_products.js.coffee b/app/assets/javascripts/admin/services/dirty_products.js.coffee index bb8614205e..16c10e1e34 100644 --- a/app/assets/javascripts/admin/services/dirty_products.js.coffee +++ b/app/assets/javascripts/admin/services/dirty_products.js.coffee @@ -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 = {} diff --git a/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee b/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee index 0469aa5637..e07b992112 100644 --- a/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee +++ b/app/assets/javascripts/admin/services/enterprise_relationships.js.coffee @@ -1,4 +1,4 @@ -Admin.factory 'EnterpriseRelationships', ($http, enterprise_relationships) -> +angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterprise_relationships) -> new class EnterpriseRelationships create_errors: "" diff --git a/app/assets/javascripts/admin/services/enterprises.js.coffee b/app/assets/javascripts/admin/services/enterprises.js.coffee index 199b6294c3..5b5fd6a009 100644 --- a/app/assets/javascripts/admin/services/enterprises.js.coffee +++ b/app/assets/javascripts/admin/services/enterprises.js.coffee @@ -1,4 +1,5 @@ -Admin.factory 'Enterprises', (enterprises) -> +angular.module("ofn.admin").factory 'Enterprises', (my_enterprises, all_enterprises) -> new class Enterprises constructor: -> - @enterprises = enterprises + @my_enterprises = my_enterprises + @all_enterprises = all_enterprises diff --git a/app/assets/javascripts/admin/services/pending_changes.js.coffee b/app/assets/javascripts/admin/services/pending_changes.js.coffee index df66900aa7..d72a4ac7bc 100644 --- a/app/assets/javascripts/admin/services/pending_changes.js.coffee +++ b/app/assets/javascripts/admin/services/pending_changes.js.coffee @@ -1,4 +1,4 @@ -Admin.factory "pendingChanges",[ +angular.module("ofn.admin").factory "pendingChanges",[ "dataSubmitter" (dataSubmitter) -> pendingChanges: {} diff --git a/app/assets/javascripts/admin/services/switch_class.js.coffee b/app/assets/javascripts/admin/services/switch_class.js.coffee index bdd61dac2e..e39c52d1f6 100644 --- a/app/assets/javascripts/admin/services/switch_class.js.coffee +++ b/app/assets/javascripts/admin/services/switch_class.js.coffee @@ -1,4 +1,4 @@ -Admin.factory "switchClass", [ +angular.module("ofn.admin").factory "switchClass", [ "$timeout" ($timeout) -> return (element,classToAdd,removeClasses,timeout) -> diff --git a/app/assets/javascripts/admin/services/taxons.js.coffee b/app/assets/javascripts/admin/services/taxons.js.coffee index 5e17dca657..1779ec3518 100644 --- a/app/assets/javascripts/admin/services/taxons.js.coffee +++ b/app/assets/javascripts/admin/services/taxons.js.coffee @@ -1,4 +1,4 @@ -Admin.factory "Taxons", ($resource) -> +angular.module("ofn.admin").factory "Taxons", ($resource) -> resource = $resource "/admin/taxons/search" return { diff --git a/app/assets/javascripts/darkswarm/all.js.coffee b/app/assets/javascripts/darkswarm/all.js.coffee index 20d849f60c..2c07d069c4 100644 --- a/app/assets/javascripts/darkswarm/all.js.coffee +++ b/app/assets/javascripts/darkswarm/all.js.coffee @@ -5,6 +5,7 @@ # #= require angular #= require angular-cookies +#= require angular-sanitize #= require angular-resource #= require ../shared/mm-foundation-tpls-0.2.0-SNAPSHOT #= require ../shared/bindonce.min.js diff --git a/app/assets/javascripts/darkswarm/controllers/checkout/accordion_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout/accordion_controller.js.coffee index b6f533e751..38f41c6f6b 100644 --- a/app/assets/javascripts/darkswarm/controllers/checkout/accordion_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/checkout/accordion_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "AccordionCtrl", ($scope, storage) -> +Darkswarm.controller "AccordionCtrl", ($scope, storage, $timeout) -> $scope.accordion = details: true shipping: false @@ -9,3 +9,8 @@ Darkswarm.controller "AccordionCtrl", ($scope, storage) -> $scope.show = (name)-> $scope.accordion[name] = true + $timeout => + if $scope.checkout.$valid + for k, v of $scope.accordion + $scope.accordion[k] = false + diff --git a/app/assets/javascripts/darkswarm/controllers/checkout/details_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout/details_controller.js.coffee index c9d559a0d0..8153c24f92 100644 --- a/app/assets/javascripts/darkswarm/controllers/checkout/details_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/checkout/details_controller.js.coffee @@ -1,5 +1,6 @@ Darkswarm.controller "DetailsCtrl", ($scope) -> angular.extend(this, new FieldsetMixin($scope)) + $scope.name = "details" $scope.nextPanel = "billing" @@ -11,11 +12,3 @@ Darkswarm.controller "DetailsCtrl", ($scope) -> $scope.fullName = -> [$scope.order.bill_address.firstname ? null, $scope.order.bill_address.lastname ? null].join(" ").trim() - - - #$scope.$watch -> - #$scope.detailsValid() - #, (valid)-> - #if valid - #$scope.show("billing") - diff --git a/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee index 8fd47c49f8..850f58b33e 100644 --- a/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee @@ -1,3 +1,6 @@ -Darkswarm.controller "GroupsCtrl", ($scope, Groups) -> +Darkswarm.controller "GroupsCtrl", ($scope, Groups, $anchorScroll, $rootScope) -> $scope.Groups = Groups $scope.order = 'position' + + $rootScope.$on "$locationChangeSuccess", (newRoute, oldRoute) -> + $anchorScroll() diff --git a/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee index 29e81ae861..555e49c539 100644 --- a/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/order_cycle_controller.js.coffee @@ -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") diff --git a/app/assets/javascripts/darkswarm/controllers/producer_node_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/producer_node_controller.js.coffee index 2f3bf1ce00..d46106a830 100644 --- a/app/assets/javascripts/darkswarm/controllers/producer_node_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/producer_node_controller.js.coffee @@ -1,6 +1,6 @@ Darkswarm.controller "ProducerNodeCtrl", ($scope, HashNavigation, $anchorScroll) -> $scope.toggle = -> - HashNavigation.navigate $scope.producer.hash + HashNavigation.toggle $scope.producer.hash $scope.open = -> HashNavigation.active($scope.producer.hash) diff --git a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee index 959423e3ca..f016d2e43f 100644 --- a/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products/product_node_controller.js.coffee @@ -8,5 +8,4 @@ Darkswarm.controller "ProductNodeCtrl", ($scope) -> $scope.product.price $scope.producer = $scope.product.supplier - $scope.hasVariants = $scope.product.variants.length > 0 diff --git a/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee new file mode 100644 index 0000000000..92cf8dedfc --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/tabs/producers_controller.js.coffee @@ -0,0 +1,2 @@ +Darkswarm.controller "ProducersTabCtrl", ($scope, CurrentHub) -> + $scope.CurrentHub = CurrentHub diff --git a/app/assets/javascripts/darkswarm/darkswarm.js.coffee b/app/assets/javascripts/darkswarm/darkswarm.js.coffee index fe128b963a..8d26384c14 100644 --- a/app/assets/javascripts/darkswarm/darkswarm.js.coffee +++ b/app/assets/javascripts/darkswarm/darkswarm.js.coffee @@ -5,6 +5,7 @@ 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') diff --git a/app/assets/javascripts/darkswarm/directives/modal.js.coffee b/app/assets/javascripts/darkswarm/directives/modal.js.coffee index 6f62c7cb45..c8ed5df4af 100644 --- a/app/assets/javascripts/darkswarm/directives/modal.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/modal.js.coffee @@ -8,11 +8,10 @@ Darkswarm.directive "ofnModal", ($modal)-> link: (scope, elem, attrs, ctrl, transclude)-> scope.title = attrs.title contents = null - # We're using an isolate scope, which is a child of the original scope # We have to compile the transclude against the original scope, not the isolate transclude scope.$parent, (clone)-> contents = clone elem.on "click", => - scope.modalInstance = $modal.open(controller: ctrl, template: contents) + scope.modalInstance = $modal.open(controller: ctrl, template: contents, scope: scope.$parent) diff --git a/app/assets/javascripts/darkswarm/filters/strip_url.js.coffee b/app/assets/javascripts/darkswarm/filters/strip_url.js.coffee new file mode 100644 index 0000000000..dcc86b600a --- /dev/null +++ b/app/assets/javascripts/darkswarm/filters/strip_url.js.coffee @@ -0,0 +1,6 @@ +Darkswarm.filter "stripUrl", -> + stripper = /(https?:\/\/)?(www\.)?(.*)/ + (url) -> + url.match(stripper).pop() + + diff --git a/app/assets/javascripts/darkswarm/services/checkout_form_state.js.coffee b/app/assets/javascripts/darkswarm/services/checkout_form_state.js.coffee index 9d68efba64..6fedb6b3c6 100644 --- a/app/assets/javascripts/darkswarm/services/checkout_form_state.js.coffee +++ b/app/assets/javascripts/darkswarm/services/checkout_form_state.js.coffee @@ -1,3 +1,3 @@ Darkswarm.factory 'CheckoutFormState', ()-> - # Just a singleton place to store data about the form statr + # Just a singleton place to store data about the form state new class CheckoutFormState diff --git a/app/assets/javascripts/darkswarm/services/order.js.coffee b/app/assets/javascripts/darkswarm/services/order.js.coffee index 2357fd42da..8078cf8fc3 100644 --- a/app/assets/javascripts/darkswarm/services/order.js.coffee +++ b/app/assets/javascripts/darkswarm/services/order.js.coffee @@ -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: {} diff --git a/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee b/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee index 1bb23446a2..0c5176328b 100644 --- a/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee +++ b/app/assets/javascripts/darkswarm/services/order_cycle.js.coffee @@ -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() diff --git a/app/assets/javascripts/darkswarm/services/product.js.coffee b/app/assets/javascripts/darkswarm/services/product.js.coffee index e58b83bacc..406e122de1 100644 --- a/app/assets/javascripts/darkswarm/services/product.js.coffee +++ b/app/assets/javascripts/darkswarm/services/product.js.coffee @@ -9,7 +9,7 @@ Darkswarm.factory 'Product', ($resource) -> products: null loading: true - update: -> + update: => @data.products = $resource("/shop/products").query => @data.loading = false @data diff --git a/app/assets/stylesheets/admin/dashboard_item.css.sass b/app/assets/stylesheets/admin/dashboard_item.css.sass index ca33dd99fb..e24d60b277 100644 --- a/app/assets/stylesheets/admin/dashboard_item.css.sass +++ b/app/assets/stylesheets/admin/dashboard_item.css.sass @@ -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 \ No newline at end of file + border-radius: 0px 0px 6px 6px + padding: 15px 15px \ No newline at end of file diff --git a/app/assets/stylesheets/admin/sidebar-item.css.sass b/app/assets/stylesheets/admin/sidebar-item.css.sass index e3e23f85a4..fc19154e94 100644 --- a/app/assets/stylesheets/admin/sidebar-item.css.sass +++ b/app/assets/stylesheets/admin/sidebar-item.css.sass @@ -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 diff --git a/app/assets/stylesheets/darkswarm/all.scss b/app/assets/stylesheets/darkswarm/all.scss index a8ac8af078..80e43cdc8b 100644 --- a/app/assets/stylesheets/darkswarm/all.scss +++ b/app/assets/stylesheets/darkswarm/all.scss @@ -9,3 +9,6 @@ */ @import 'foundation-icons'; +ofn-modal { + display: block; +} \ No newline at end of file diff --git a/app/assets/stylesheets/darkswarm/images.css.sass b/app/assets/stylesheets/darkswarm/images.css.sass deleted file mode 100644 index 927e906842..0000000000 --- a/app/assets/stylesheets/darkswarm/images.css.sass +++ /dev/null @@ -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 - - - - - diff --git a/app/assets/stylesheets/darkswarm/overrides.css.sass b/app/assets/stylesheets/darkswarm/overrides.css.sass index fcec6b455d..917d6dd2e3 100644 --- a/app/assets/stylesheets/darkswarm/overrides.css.sass +++ b/app/assets/stylesheets/darkswarm/overrides.css.sass @@ -1,2 +1,5 @@ .row max-width: 74em + +.reveal-modal + position: fixed diff --git a/app/assets/stylesheets/darkswarm/shop.css.sass b/app/assets/stylesheets/darkswarm/shop.css.sass index e0030a7d7a..a23458b941 100644 --- a/app/assets/stylesheets/darkswarm/shop.css.sass +++ b/app/assets/stylesheets/darkswarm/shop.css.sass @@ -27,7 +27,6 @@ margin-right: 12px location font-family: "AvenirBla_IE", "AvenirBla" - padding-right: 16px @media all and (max-width: 768px) location, location + small display: block @@ -58,21 +57,23 @@ @media all and (max-width: 768px) font-size: 1.2em select - width: 280px + width: inherit display: inline-block vackground: transparent - border-width: 2px - border-color: #666666 + border-width: 1px + border-color: #999 + color: #666 font-size: 1em margin-bottom: 0 - padding: 8px 0px 8px 12px + padding: 8px 20px 8px 12px @media all and (max-width: 768px) font-size: 1.2em - width: 180px + // width: 180px closing - font-size: 0.875em + color: black + font-size: 1.5em display: block - padding-top: 14px + padding-bottom: 20px products display: block @@ -81,7 +82,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) diff --git a/app/controllers/admin/enterprise_relationships_controller.rb b/app/controllers/admin/enterprise_relationships_controller.rb index 46ac45a3e5..212bf3849d 100644 --- a/app/controllers/admin/enterprise_relationships_controller.rb +++ b/app/controllers/admin/enterprise_relationships_controller.rb @@ -1,8 +1,9 @@ module Admin class EnterpriseRelationshipsController < ResourceController def index - @enterprises = Enterprise.managed_by(spree_current_user).by_name - @enterprise_relationships = EnterpriseRelationship.by_name + @my_enterprises = Enterprise.managed_by(spree_current_user).by_name + @all_enterprises = Enterprise.by_name + @enterprise_relationships = EnterpriseRelationship.by_name.involving_enterprises @my_enterprises end def create diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 46273d0eff..566c660112 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -23,7 +23,7 @@ module Admin respond_to do |format| if @order_cycle.save - OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle).go! + OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, managed_enterprises).go! flash[:notice] = 'Your order cycle has been created.' format.html { redirect_to admin_order_cycles_path } @@ -40,7 +40,7 @@ module Admin respond_to do |format| if @order_cycle.update_attributes(params[:order_cycle]) - OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle).go! + OpenFoodNetwork::OrderCycleFormApplicator.new(@order_cycle, managed_enterprises).go! flash[:notice] = 'Your order cycle has been updated.' format.html { redirect_to admin_order_cycles_path } diff --git a/app/controllers/spree/admin/orders_controller_decorator.rb b/app/controllers/spree/admin/orders_controller_decorator.rb index 51c7acba09..27d9a36943 100644 --- a/app/controllers/spree/admin/orders_controller_decorator.rb +++ b/app/controllers/spree/admin/orders_controller_decorator.rb @@ -15,11 +15,10 @@ Spree::Admin::OrdersController.class_eval do 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 \ No newline at end of file +end diff --git a/app/controllers/spree/store_controller_decorator.rb b/app/controllers/spree/store_controller_decorator.rb new file mode 100644 index 0000000000..09c2efc7b4 --- /dev/null +++ b/app/controllers/spree/store_controller_decorator.rb @@ -0,0 +1,7 @@ +class Spree::StoreController + layout 'darkswarm' + + def unauthorized + render 'shared/unauthorized', :status => 401 + end +end diff --git a/app/helpers/enterprises_helper.rb b/app/helpers/enterprises_helper.rb index 4b0f2f4a93..ed22831589 100644 --- a/app/helpers/enterprises_helper.rb +++ b/app/helpers/enterprises_helper.rb @@ -2,6 +2,10 @@ module EnterprisesHelper def current_distributor @current_distributor ||= current_order(false).andand.distributor end + + def managed_enterprises + Enterprise.managed_by(spree_current_user) + end def enterprises_options enterprises enterprises.map { |enterprise| [enterprise.name + ": " + enterprise.address.address1 + ", " + enterprise.address.city, enterprise.id.to_i] } diff --git a/app/helpers/shared_helper.rb b/app/helpers/shared_helper.rb index 828277cb57..f856a088d1 100644 --- a/app/helpers/shared_helper.rb +++ b/app/helpers/shared_helper.rb @@ -14,16 +14,6 @@ module SharedHelper klass end - # all suppliers of current distributor's products - def current_producers - if current_distributor && current_order_cycle - variants = current_order_cycle.variants_distributed_by(current_distributor) - Enterprise.supplying_variant_in(variants) - else - [] - end - end - def enterprise_user? spree_current_user.andand.enterprises.andand.count.to_i > 0 end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index a72c6fdbd6..dd40744492 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -18,8 +18,8 @@ class Enterprise < ActiveRecord::Base delegate :latitude, :longitude, :city, :state_name, :to => :address accepts_nested_attributes_for :address - has_attached_file :logo, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png" - has_attached_file :promo_image, :styles => { :large => "570x380>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png" + has_attached_file :logo, :styles => { :medium => "300x300>", :thumb => "100x100>" } + has_attached_file :promo_image, :styles => { :large => "260x1200#", :thumb => "100x100>" } validates_presence_of :name validates_presence_of :address @@ -123,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 diff --git a/app/models/enterprise_group.rb b/app/models/enterprise_group.rb index 6c163b087a..1cea76db72 100644 --- a/app/models/enterprise_group.rb +++ b/app/models/enterprise_group.rb @@ -9,7 +9,7 @@ class EnterpriseGroup < ActiveRecord::Base attr_accessible :name, :description, :long_description, :on_front_page, :enterprise_ids attr_accessible :promo_image - has_attached_file :promo_image, styles: {medium: "800>400"} + has_attached_file :promo_image, styles: {large: "260x1200#"} validates_attachment_content_type :promo_image, :content_type => /\Aimage\/.*\Z/ attr_accessible :logo diff --git a/app/models/enterprise_relationship.rb b/app/models/enterprise_relationship.rb index 09fff8ba03..26bf8fc012 100644 --- a/app/models/enterprise_relationship.rb +++ b/app/models/enterprise_relationship.rb @@ -9,4 +9,8 @@ class EnterpriseRelationship < ActiveRecord::Base joins('LEFT JOIN enterprises AS parent_enterprises ON parent_enterprises.id = enterprise_relationships.parent_id'). joins('LEFT JOIN enterprises AS child_enterprises ON child_enterprises.id = enterprise_relationships.child_id') scope :by_name, with_enterprises.order('parent_enterprises.name, child_enterprises.name') + + scope :involving_enterprises, ->(enterprises) { + where('parent_id IN (?) OR child_id IN (?)', enterprises, enterprises) + } end diff --git a/app/models/exchange.rb b/app/models/exchange.rb index 18c3f81447..c491748d5d 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -54,6 +54,10 @@ class Exchange < ActiveRecord::Base incoming? ? 'supplier' : 'distributor' end + def participant + incoming? ? sender : receiver + end + def to_h(core_only=false) h = attributes.merge({ 'variant_ids' => variant_ids.sort, 'enterprise_fee_ids' => enterprise_fee_ids.sort }) h.reject! { |k| %w(id order_cycle_id created_at updated_at).include? k } if core_only diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index ee83e85bf7..44e7d5e02e 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -1,6 +1,6 @@ - class AbilityDecorator include CanCan::Ability + def initialize(user) if user.enterprises.count > 0 @@ -53,6 +53,11 @@ class AbilityDecorator (user.enterprises & shipping_method.distributors).any? end + can [:admin, :index, :create], EnterpriseRelationship + can [:destroy], EnterpriseRelationship do |enterprise_relationship| + user.enterprises.include? enterprise_relationship.parent + end + can [:create], OrderCycle can [:admin, :index, :read, :edit, :update, :bulk_update, :clone], OrderCycle do |order_cycle| user.enterprises.include? order_cycle.coordinator diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index ba7cbc253d..0140586668 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -75,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 diff --git a/app/overrides/spree/admin/products/_form/add_primary_taxon_field.html.haml.deface b/app/overrides/spree/admin/products/_form/add_primary_taxon_field.html.haml.deface new file mode 100644 index 0000000000..efd7ccbfaf --- /dev/null +++ b/app/overrides/spree/admin/products/_form/add_primary_taxon_field.html.haml.deface @@ -0,0 +1,3 @@ +/ insert_top "[data-hook='admin_product_form_right']" + += render 'spree/admin/products/primary_taxon_form', f: f \ No newline at end of file diff --git a/app/overrides/spree/admin/products/new/replace_form.html.haml.deface b/app/overrides/spree/admin/products/new/replace_form.html.haml.deface new file mode 100644 index 0000000000..e964e9a704 --- /dev/null +++ b/app/overrides/spree/admin/products/new/replace_form.html.haml.deface @@ -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']); + }); diff --git a/app/views/admin/enterprise_relationships/_data.html.haml b/app/views/admin/enterprise_relationships/_data.html.haml index 2361755707..7c13978e90 100644 --- a/app/views/admin/enterprise_relationships/_data.html.haml +++ b/app/views/admin/enterprise_relationships/_data.html.haml @@ -1,3 +1,4 @@ :javascript angular.module('ofn.admin').value('enterprise_relationships', #{render partial: "admin/json/enterprise_relationships", object: @enterprise_relationships}); - angular.module('ofn.admin').value('enterprises', #{render partial: "admin/json/enterprises", object: @enterprises}); + angular.module('ofn.admin').value('my_enterprises', #{render partial: "admin/json/enterprises", object: @my_enterprises}); + angular.module('ofn.admin').value('all_enterprises', #{render partial: "admin/json/enterprises", object: @all_enterprises}); diff --git a/app/views/admin/enterprise_relationships/_form.html.haml b/app/views/admin/enterprise_relationships/_form.html.haml index 5cc10b0fe1..1a737ec3a5 100644 --- a/app/views/admin/enterprise_relationships/_form.html.haml +++ b/app/views/admin/enterprise_relationships/_form.html.haml @@ -1,9 +1,9 @@ %tr %td - %select{name: "enterprise_relationship_parent_name", "ng-model" => "parent_id", "ng-options" => "e.id as e.name for e in Enterprises.enterprises"} + %select{name: "enterprise_relationship_parent_id", "ng-model" => "parent_id", "ng-options" => "e.id as e.name for e in Enterprises.my_enterprises"} %td permits %td - %select{name: "enterprise_relationship_child_name", "ng-model" => "child_id", "ng-options" => "e.id as e.name for e in Enterprises.enterprises"} + %select{name: "enterprise_relationship_child_id", "ng-model" => "child_id", "ng-options" => "e.id as e.name for e in Enterprises.all_enterprises"} %td.actions %input{type: "button", value: "Create", "ng-click" => "create()"} .errors {{ EnterpriseRelationships.create_errors }} diff --git a/app/views/admin/enterprises/_sidebar.html.haml b/app/views/admin/enterprises/_sidebar.html.haml index 578612ec6f..0390cb289a 100644 --- a/app/views/admin/enterprises/_sidebar.html.haml +++ b/app/views/admin/enterprises/_sidebar.html.haml @@ -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 \ No newline at end of file diff --git a/app/views/admin/enterprises/index.rabl b/app/views/admin/enterprises/index.rabl new file mode 100644 index 0000000000..9e1ee893d1 --- /dev/null +++ b/app/views/admin/enterprises/index.rabl @@ -0,0 +1,14 @@ +collection @collection + +attributes :id, :name + +child supplied_products: :supplied_products do |product| + attributes :name + node(:supplier_name) { |p| p.supplier.andand.name } + node(:image_url) { |p| p.images.present? ? p.images.first.attachment.url(:mini) : nil } + node(:master_id) { |p| p.master.id } + child variants: :variants do |variant| + attributes :id + node(:label) { |v| v.options_text } + end +end diff --git a/app/views/admin/enterprises/index.rep b/app/views/admin/enterprises/index.rep deleted file mode 100644 index beaceef8a4..0000000000 --- a/app/views/admin/enterprises/index.rep +++ /dev/null @@ -1,15 +0,0 @@ -r.list_of :enterprises, @collection do - r.element :id - r.element :name - - r.list_of :supplied_products do |product| - r.element :name - r.element :supplier_name, product.supplier.andand.name - r.element :image_url, product.images.present? ? product.images.first.attachment.url(:mini) : nil - r.element :master_id, product.master.id - r.list_of :variants do |variant| - r.element :id - r.element :label, variant.options_text - end - end -end diff --git a/app/views/admin/order_cycles/_exchange_distributed_products_form.html.haml b/app/views/admin/order_cycles/_exchange_distributed_products_form.html.haml index 3f7d7ba578..ae0b9b7349 100644 --- a/app/views/admin/order_cycles/_exchange_distributed_products_form.html.haml +++ b/app/views/admin/order_cycles/_exchange_distributed_products_form.html.haml @@ -1,7 +1,7 @@ %td{:colspan => 3} .exchange-select-all-variants %label - = check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants', 1, 1, 'ng-model' => 'exchange.select_all_variants', 'ng-click' => 'setExchangeVariants(exchange, incomingExchangesVariants(), exchange.select_all_variants)', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' + = check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants', 1, 1, 'ng-model' => 'exchange.select_all_variants', 'ng-change' => 'setExchangeVariants(exchange, incomingExchangesVariants(), exchange.select_all_variants)', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' Select all .exchange-product{'ng-repeat' => 'product in supplied_products | filter:productSuppliedToOrderCycle'} diff --git a/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml b/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml index 6ad13a88a6..ac791d7fd2 100644 --- a/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml +++ b/app/views/admin/order_cycles/_exchange_supplied_products_form.html.haml @@ -2,7 +2,7 @@ %td{:colspan => 3} .exchange-select-all-variants %label - = check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_select_all_variants', 1, 1, 'ng-model' => 'exchange.select_all_variants', 'ng-click' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_select_all_variants' + = check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_select_all_variants', 1, 1, 'ng-model' => 'exchange.select_all_variants', 'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_select_all_variants' Select all .exchange-product{'ng-repeat' => 'product in enterprises[exchange.enterprise_id].supplied_products'} diff --git a/app/views/checkout/_billing.html.haml b/app/views/checkout/_billing.html.haml index 6ab949e36e..27fc2b202f 100644 --- a/app/views/checkout/_billing.html.haml +++ b/app/views/checkout/_billing.html.haml @@ -1,7 +1,7 @@ %fieldset#billing %ng-form{"ng-controller" => "BillingCtrl", name: "billing"} - %h5{"ng-class" => "{valid: billing.$valid, dirty: details.$dirty}"} + %h5{"ng-class" => "{valid: billing.$valid, dirty: billing.$dirty}"} %span.right %label.label.round.alert.right %i.ofn-i_009-close diff --git a/app/views/checkout/_payment.html.haml b/app/views/checkout/_payment.html.haml index 39b40675bf..045882ade3 100644 --- a/app/views/checkout/_payment.html.haml +++ b/app/views/checkout/_payment.html.haml @@ -1,7 +1,7 @@ %fieldset#payment %ng-form{"ng-controller" => "PaymentCtrl", name: "payment"} - %h5{"ng-class" => "{valid: payment.$valid, dirty: details.$dirty}"} + %h5{"ng-class" => "{valid: payment.$valid, dirty: payment.$dirty}"} %span.right %label.label.round.alert.right %i.ofn-i_009-close diff --git a/app/views/checkout/_shipping.html.haml b/app/views/checkout/_shipping.html.haml index 3712b995ac..e5208d5f60 100644 --- a/app/views/checkout/_shipping.html.haml +++ b/app/views/checkout/_shipping.html.haml @@ -1,7 +1,7 @@ %fieldset#shipping %ng-form{"ng-controller" => "ShippingCtrl", name: "shipping"} - %h5{"ng-class" => "{valid: shipping.$valid, dirty: details.$dirty}"} + %h5{"ng-class" => "{valid: shipping.$valid, dirty: shipping.$dirty}"} %span.right %label.label.round.alert.right %i.ofn-i_009-close diff --git a/app/views/groups/index.html.haml b/app/views/groups/index.html.haml index 0e9ae1b185..56dfeacaad 100644 --- a/app/views/groups/index.html.haml +++ b/app/views/groups/index.html.haml @@ -17,18 +17,18 @@ "ng-debounce" => "150", "ofn-disable-enter" => true} - .group{"ng-repeat" => "group in Groups.groups | filter:query | orderBy:order"} - + .group{"ng-repeat" => "group in Groups.groups | filter:query | orderBy:order", + name: "group{{group.id}}", + id: "group{{group.id}}"} .row.pad-top{bindonce: true} .small-12.columns .group-hero - %img.group-hero-img{"bo-src" => "{{group.promo_image}}"} - %img.group-logo{"bo-src" => "group.logo"} + %img.group-hero-img{"bo-src" => "group.promo_image"} + %img.group-logo{"bo-src" => "group.logo", "bo-if" => "group.logo"} %h3.group-name %i.ofn-i_035-groups {{ group.name }} %h5.group-description {{ group.description }} - / Will - scale large images down to 1200px wide, crop in to img aspect ratio 60W:13H .row.pad-top{bindonce: true} .small-6.columns diff --git a/app/views/json/_current_hub.rabl b/app/views/json/_current_hub.rabl index ab67cce3cc..7f615bb07a 100644 --- a/app/views/json/_current_hub.rabl +++ b/app/views/json/_current_hub.rabl @@ -1,2 +1,8 @@ object current_distributor attributes :name, :id + +if current_distributor + child suppliers: :producers do + extends "json/producer" + end +end diff --git a/app/views/json/_groups.rabl b/app/views/json/_groups.rabl index 9475b425c4..27325bb850 100644 --- a/app/views/json/_groups.rabl +++ b/app/views/json/_groups.rabl @@ -6,5 +6,9 @@ child enterprises: :enterprises do end node :logo do |group| - group.logo(:original) + group.logo(:medium) if group.logo.exists? +end + +node :promo_image do |group| + group.promo_image(:large) if group.promo_image.exists? end diff --git a/app/views/json/_hubs.rabl b/app/views/json/_hubs.rabl index dc589b878b..c118b4504f 100644 --- a/app/views/json/_hubs.rabl +++ b/app/views/json/_hubs.rabl @@ -6,11 +6,7 @@ child distributed_taxons: :taxons do end child suppliers: :producers do - attributes :name, :id, :description, :long_description - - node :promo_image do |producer| - producer.promo_image.url - end + extends "json/producer" end node :pickup do |hub| diff --git a/app/views/json/_producer.rabl b/app/views/json/_producer.rabl new file mode 100644 index 0000000000..4c0efae8e1 --- /dev/null +++ b/app/views/json/_producer.rabl @@ -0,0 +1,5 @@ +attributes :name, :id, :description, :long_description + +node :promo_image do |producer| + producer.promo_image.url +end diff --git a/app/views/modals/_producer.html.haml b/app/views/modals/_producer.html.haml index 6031537089..13f8026195 100644 --- a/app/views/modals/_producer.html.haml +++ b/app/views/modals/_producer.html.haml @@ -5,39 +5,35 @@ / Will - scale large images down to 1200px wide, crop in to img aspect ratio 60W:13H %h3.producer-name {{ producer.name }} .row - .columns.small-12.large-6{"ng-bind-html" => "{{producer.long_description}}"} - / Will to fix this + .columns.small-12.large-6{"ng-bind-html" => "producer.long_description"} .columns.small-12.large-6 - / Will needs logic to add in following only if data is available for each type: - / Will needs better formatting of URLs printed on-screen (minus http://www.) - / Will needs formatting of URLs driving %a regardless of user input (plus http://www.) - %img.producer-logo{"ng-src" => "{{producer.logo}}"} + %img.producer-logo{"ng-src" => "{{producer.logo}}", "ng-if" => "producer.logo"} %h4 Stay in touch with {{ producer.name }} - %ul.small-block-grid-1 - %li - %a{href: "{{producer.website}}", target: "_blank" } + %ul.small-block-grid-1{bindonce: true} + %li{"ng-if" => "producer.website"} + %a{"ng-href" => "http://{{producer.website | stripUrl}}", target: "_blank" } %i.fi-web - {{ producer.website }} - %li - %a{href: "{{producer.twitter}}", target: "_blank"} - / Will needs logic to allow user to input @twitterhandle to drive a logical URL + {{ producer.website | stripUrl }} + + %li{"ng-if" => "producer.twitter"} + %a{"ng-href" => "http://twitter.com/{{producer.twitter}}", target: "_blank"} %i.fi-social-twitter {{ producer.twitter }} - %li - %a{href: "{{producer.facebook}}", target: "_blank"} + + %li{"ng-if" => "producer.facebook"} + %a{"ng-href" => "http://{{producer.facebook | stripUrl}}", target: "_blank"} %i.fi-social-facebook - {{ producer.facebook }} - %li - %a{href: "{{producer.linkedin}}", target: "_blank"} + {{ producer.facebook | stripUrl }} + + %li{"ng-if" => "producer.linkedin"} + %a{"ng-href" => "http://{{producer.linkedin | stripUrl}}", target: "_blank"} %i.fi-social-linkedin - {{ producer.linkedin }} - %li - %a{href: "{{producer.instagram}}", target: "_blank"} - / Will needs logic to allow user to input @instagramhandle to drive a logical URL + {{ producer.linkedin | stripUrl }} + + %li{"ng-if" => "producer.instagram"} + %a{"ng-href" => "http://instagram.com/{{producer.instagram}}", target: "_blank"} %i.fi-social-instagram {{ producer.instagram }} - / %pre - / {{ producer | json }} - %a.close-reveal-modal{"ng-click" => "$close()"} × \ No newline at end of file + %a.close-reveal-modal{"ng-click" => "$close()"} × diff --git a/app/views/modals/_product.html.haml b/app/views/modals/_product.html.haml index 70137ba987..9c071b51eb 100644 --- a/app/views/modals/_product.html.haml +++ b/app/views/modals/_product.html.haml @@ -1,14 +1,10 @@ %ofn-modal{title: "{{product.name}}"} - .row .columns.small-12.large-6 - %img.product-img{"ng-src" => "{{product.master.images[0].large_url}}"} + %img.product-img{"ng-src" => "{{product.master.images[0].large_url}}", "ng-if" => "product.master.images[0]"} .columns.small-12.large-6 %h2 %img{"ng-src" => "{{product.primary_taxon.icon}}"} {{product.name}} %p {{product.description}} - / %pre - / {{ product | json }} %a.close-reveal-modal{"ng-click" => "$close()"} × - \ No newline at end of file diff --git a/app/views/producers/_fat.html.haml b/app/views/producers/_fat.html.haml index 45b3bf8dd0..3313db6552 100644 --- a/app/views/producers/_fat.html.haml +++ b/app/views/producers/_fat.html.haml @@ -5,7 +5,7 @@ {{ producer.taxons | printArrayOfObjects }} .columns.small-8 %strong About us - %p.trans-sentence + %p {{ producer.description }} .row.active_table_row.link{"ng-show" => "open()", "ng-repeat" => "hub in producer.distributors"} diff --git a/app/views/shared/unauthorized.html.haml b/app/views/shared/unauthorized.html.haml new file mode 100644 index 0000000000..fcf3f3bf27 --- /dev/null +++ b/app/views/shared/unauthorized.html.haml @@ -0,0 +1 @@ +Unauthorized diff --git a/app/views/shop/products.rabl b/app/views/shop/products.rabl index ee5e567285..b1567a311a 100644 --- a/app/views/shop/products.rabl +++ b/app/views/shop/products.rabl @@ -13,10 +13,10 @@ child :supplier => :supplier do attributes :id, :name, :description, :long_description, :website, :instagram, :facebook, :linkedin, :twitter node :logo do |supplier| - supplier.logo.url + supplier.logo(:medium) if supplier.logo.exists? end node :promo_image do |supplier| - supplier.promo_image.url + supplier.promo_image(:large) if supplier.promo_image.exists? end end diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 5a3af9684e..6212ef746d 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -21,7 +21,7 @@ %div{"bo-if" => "hasVariants"} = render partial: "shop/products/variants" - .variant.row{"bo-if" => "!hasVariants"} + .variants.row{"bo-if" => "!hasVariants"} = render partial: "shop/products/master" .row diff --git a/app/views/shop/products/_master.html.haml b/app/views/shop/products/_master.html.haml index 7398912bda..bd8a8cd3de 100644 --- a/app/views/shop/products/_master.html.haml +++ b/app/views/shop/products/_master.html.haml @@ -1,4 +1,4 @@ -.small-1.column +.small-1.columns %span.bulk{"bo-if" => "product.group_buy"} bulk   diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml index e41c6ef440..22ce416336 100644 --- a/app/views/shop/products/_summary.html.haml +++ b/app/views/shop/products/_summary.html.haml @@ -1,5 +1,5 @@ .row.summary - .small-1.column + .small-1.columns %img{"bo-src" => "product.master.images[0].small_url"} .small-4.columns.summary-header diff --git a/app/views/shop/products/_variants.html.haml b/app/views/shop/products/_variants.html.haml index 14ff8eff24..6751f8c62c 100644 --- a/app/views/shop/products/_variants.html.haml +++ b/app/views/shop/products/_variants.html.haml @@ -1,7 +1,7 @@ .row.variants{bindonce: true, "ng-repeat" => "variant in product.variants"} - .small-1.column + .small-1.columns %span.bulk{"bo-if" => "product.group_buy"} bulk   diff --git a/app/views/shop/show.html.haml b/app/views/shop/show.html.haml index b94bd59bf9..ad0080edae 100644 --- a/app/views/shop/show.html.haml +++ b/app/views/shop/show.html.haml @@ -1,19 +1,25 @@ %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"} + %closing{"ng-if" => "OrderCycle.selected()"} + Next order closing + %strong {{ OrderCycle.orders_close_at() | date_in_words }} - %closing{"ng-if" => "OrderCycle.selected()"} - Orders close - %strong {{ OrderCycle.orders_close_at() | date_in_words }} + %span Ready for pickup + + / Will this label should be a variable to reflect pickup or delivery as appropriate + + %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"} + + = render partial: "shopping_shared/details" .row = render partial: "shop/products/form" -= render partial: "shared/footer" \ No newline at end of file += render partial: "shared/footer" diff --git a/app/views/shopping_shared/_details.html.haml b/app/views/shopping_shared/_details.html.haml index 37edfa3c16..2a8e1b10b1 100644 --- a/app/views/shopping_shared/_details.html.haml +++ b/app/views/shopping_shared/_details.html.haml @@ -1,14 +1,11 @@ -= render partial: "shopping_shared/modals" - %navigation %distributor.details.row #distributor_title %img.left{src: current_distributor.logo.url(:thumb)} - %h4 + %h3 = current_distributor.name %location= current_distributor.address.city - %small - %a{href: "/"} Change location + / Will this needs to be a drop-down to choose either pick-up point or delivery once shipping methods are implemented = render partial: "shopping_shared/order_cycles" diff --git a/app/views/shopping_shared/_groups.html.haml b/app/views/shopping_shared/_groups.html.haml index a218d6aeb5..e9ebb219b3 100644 --- a/app/views/shopping_shared/_groups.html.haml +++ b/app/views/shopping_shared/_groups.html.haml @@ -1,10 +1,5 @@ -.content#groups +.content %ul - for group in current_distributor.groups %li - %h4= group.name - %ul - - for sibling in group.enterprises.except(current_distributor) - %li - %a{"data-reveal-id" => "sibling_details_#{sibling.id}", "data-reveal" => ""} - = sibling.name + %a{href: main_app.groups_path(anchor: "#/#group#{group.id}")}= group.name diff --git a/app/views/shopping_shared/_modals.html.haml b/app/views/shopping_shared/_modals.html.haml deleted file mode 100644 index ad92f1957f..0000000000 --- a/app/views/shopping_shared/_modals.html.haml +++ /dev/null @@ -1,36 +0,0 @@ -- for producer in current_producers - .reveal-modal{id: "producer_details_#{producer.id}", "data-reveal" => ""} - .row - - if producer.logo.exists? - .large-1.columns - %img.left{src: producer.logo.url(:thumb)} - .large-11.columns - %h2 - = producer.name - .row - .large-8.columns - = producer.long_description.andand.html_safe - - - if producer.promo_image.exists? - .large-4.columns - %img.about.right{src: producer.promo_image.url(:large)} - %a.close-reveal-modal × - - -- for group in current_distributor.groups - - for sibling in group.enterprises.except(current_distributor) - .reveal-modal{id: "sibling_details_#{sibling.id}", "data-reveal" => ""} - .row - - if sibling.logo.exists? - .large-1.columns - %img.left{src: sibling.logo.url(:thumb)} - .large-11.columns - %h2 - = sibling.name - .row - .large-8.columns - = sibling.long_description.andand.html_safe - - if sibling.promo_image.exists? - .large-4.columns - %img.about.right{src: sibling.promo_image.url(:large)} - %a.close-reveal-modal × diff --git a/app/views/shopping_shared/_order_cycles.html.haml b/app/views/shopping_shared/_order_cycles.html.haml index 91517e0c1c..195389df91 100644 --- a/app/views/shopping_shared/_order_cycles.html.haml +++ b/app/views/shopping_shared/_order_cycles.html.haml @@ -14,5 +14,3 @@ - else %form.custom = yield :order_cycle_form - - diff --git a/app/views/shopping_shared/_producers.html.haml b/app/views/shopping_shared/_producers.html.haml index 32f09869e8..584d75ff35 100644 --- a/app/views/shopping_shared/_producers.html.haml +++ b/app/views/shopping_shared/_producers.html.haml @@ -1,6 +1,4 @@ -.content#producers +.content#producers{"ng-controller" => "ProducersTabCtrl"} %ul - - for producer in current_producers - %li - %a{"data-reveal-id" => "producer_details_#{producer.id}", "data-reveal" => ""} - = producer.name + %li{"ng-repeat" => "producer in CurrentHub.producers"} + = render partial: "modals/producer" diff --git a/app/views/spree/admin/overview/_enterprises.html.haml b/app/views/spree/admin/overview/_enterprises.html.haml index 4042381502..85dc93c2ee 100644 --- a/app/views/spree/admin/overview/_enterprises.html.haml +++ b/app/views/spree/admin/overview/_enterprises.html.haml @@ -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 \ No newline at end of file diff --git a/app/views/spree/admin/products/_primary_taxon_form.html.haml b/app/views/spree/admin/products/_primary_taxon_form.html.haml new file mode 100644 index 0000000000..a844f4f447 --- /dev/null +++ b/app/views/spree/admin/products/_primary_taxon_form.html.haml @@ -0,0 +1,5 @@ += f.field_container :primary_taxon_id do + = f.label :primary_taxon_id + %br + = f.collection_select(:primary_taxon_id, Spree::Taxon.all, :id, :name, {:include_blank => true}, {:class => "select2 fullwidth"}) + = f.error_message_on :primary_taxon_id diff --git a/app/views/spree/admin/products/bulk_edit.html.haml b/app/views/spree/admin/products/bulk_edit.html.haml index ee74fd9662..fa295adb47 100644 --- a/app/views/spree/admin/products/bulk_edit.html.haml +++ b/app/views/spree/admin/products/bulk_edit.html.haml @@ -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" } diff --git a/app/views/spree/admin/shared/_tabs.html.erb b/app/views/spree/admin/shared/_tabs.html.erb index ab66dbf1de..2228d4ac7b 100644 --- a/app/views/spree/admin/shared/_tabs.html.erb +++ b/app/views/spree/admin/shared/_tabs.html.erb @@ -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' %> diff --git a/app/views/spree/shared/_order_details.html.haml b/app/views/spree/shared/_order_details.html.haml index 559a0227f1..b6ff00925d 100644 --- a/app/views/spree/shared/_order_details.html.haml +++ b/app/views/spree/shared/_order_details.html.haml @@ -16,8 +16,6 @@ .columns.large-2 %h6 = t(:shipping_method) - \: - = link_to "(#{t(:edit)})", checkout_state_path(:delivery) unless @order.completed? .delivery = order.shipping_method.name .columns.large-4 diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb new file mode 100644 index 0000000000..c40b9a4130 --- /dev/null +++ b/config/initializers/paperclip.rb @@ -0,0 +1,3 @@ +Paperclip::Attachment.default_options[:convert_options] = { + all: "-auto-orient" +} diff --git a/db/migrate/20140402033428_add_foreign_keys.rb b/db/migrate/20140402033428_add_foreign_keys.rb index f072127158..fce1ffd009 100644 --- a/db/migrate/20140402033428_add_foreign_keys.rb +++ b/db/migrate/20140402033428_add_foreign_keys.rb @@ -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})" diff --git a/db/migrate/20140522044009_add_primary_taxon_to_products.rb b/db/migrate/20140522044009_add_primary_taxon_to_products.rb new file mode 100644 index 0000000000..f6ff3cfe96 --- /dev/null +++ b/db/migrate/20140522044009_add_primary_taxon_to_products.rb @@ -0,0 +1,7 @@ +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 diff --git a/lib/open_food_network/order_cycle_form_applicator.rb b/lib/open_food_network/order_cycle_form_applicator.rb index dc5056d53a..6556223dac 100644 --- a/lib/open_food_network/order_cycle_form_applicator.rb +++ b/lib/open_food_network/order_cycle_form_applicator.rb @@ -5,8 +5,10 @@ module OpenFoodNetwork # translation is more a responsibility of Angular, so I'd be inclined to refactor this class to move # as much as possible (if not all) of its logic into Angular. class OrderCycleFormApplicator - def initialize(order_cycle) + # The applicator will only touch exchanges where a permitted enterprise is the participant + def initialize(order_cycle, permitted_enterprises) @order_cycle = order_cycle + @permitted_enterprises = permitted_enterprises end def go! @@ -56,19 +58,25 @@ module OpenFoodNetwork def add_exchange(sender_id, receiver_id, incoming, attrs={}) attrs = attrs.reverse_merge(:sender_id => sender_id, :receiver_id => receiver_id, :incoming => incoming) - exchange = @order_cycle.exchanges.create! attrs - @touched_exchanges << exchange + exchange = @order_cycle.exchanges.build attrs + + if permission_for exchange + exchange.save! + @touched_exchanges << exchange + end end def update_exchange(sender_id, receiver_id, incoming, attrs={}) exchange = @order_cycle.exchanges.where(:sender_id => sender_id, :receiver_id => receiver_id, :incoming => incoming).first - exchange.update_attributes!(attrs) - @touched_exchanges << exchange + if permission_for exchange + exchange.update_attributes!(attrs) + @touched_exchanges << exchange + end end def destroy_untouched_exchanges - untouched_exchanges.each { |exchange| exchange.destroy } + with_permission(untouched_exchanges).each(&:destroy) end def untouched_exchanges @@ -76,6 +84,14 @@ module OpenFoodNetwork @order_cycle.exchanges.reject { |ex| touched_exchange_ids.include? ex.id } end + def with_permission(exchanges) + exchanges.select { |ex| permission_for(ex) } + end + + def permission_for(exchange) + @permitted_enterprises.include? exchange.participant + end + def exchange_variant_ids(exchange) exchange[:variants].select { |k, v| v }.keys.map { |k| k.to_i } diff --git a/lib/tasks/users.rake b/lib/tasks/users.rake new file mode 100644 index 0000000000..323c679fb0 --- /dev/null +++ b/lib/tasks/users.rake @@ -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 diff --git a/spec/controllers/spree/store_controller_spec.rb b/spec/controllers/spree/store_controller_spec.rb new file mode 100644 index 0000000000..e1b94de185 --- /dev/null +++ b/spec/controllers/spree/store_controller_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe Spree::StoreController do + controller(Spree::StoreController) do + before_filter :unauthorized + def index + render text: "" + end + end + it "redirects to home when unauthorized" do + get :index + response.should render_template("shared/unauthorized", layout: 'darkswarm') + end +end diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb index 79981bbd16..963cd04f8d 100644 --- a/spec/features/admin/bulk_order_management_spec.rb +++ b/spec/features/admin/bulk_order_management_spec.rb @@ -206,7 +206,7 @@ feature %q{ page.should have_selector "tr#li_#{li2.id}", visible: true select2_select s1.name, from: "supplier_filter" page.should have_selector "tr#li_#{li1.id}", visible: true - page.should_not have_selector "tr#li_#{li2.id}", visible: true + page.should_not have_selector "tr#li_#{li2.id}" end it "displays all line items when 'All' is selected from supplier filter" do diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index 7174da9758..d89280df80 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -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' diff --git a/spec/features/admin/enterprise_relationships_spec.rb b/spec/features/admin/enterprise_relationships_spec.rb index ea95f86ba4..1443cd4c34 100644 --- a/spec/features/admin/enterprise_relationships_spec.rb +++ b/spec/features/admin/enterprise_relationships_spec.rb @@ -7,70 +7,108 @@ feature %q{ include AuthenticationWorkflow include WebHelper - before { login_to_admin_section } + + context "as a site administrator" do + before { login_to_admin_section } + + scenario "listing relationships" do + # Given some enterprises with relationships + e1, e2, e3, e4 = create(:enterprise), create(:enterprise), create(:enterprise), create(:enterprise) + create(:enterprise_relationship, parent: e1, child: e2) + create(:enterprise_relationship, parent: e3, child: e4) + + # When I go to the relationships page + click_link 'Enterprises' + click_link 'Relationships' + + # Then I should see the relationships + within('table#enterprise-relationships') do + page.should have_relationship e1, e2 + page.should have_relationship e3, e4 + end + end - scenario "listing relationships" do - # Given some enterprises with relationships - e1, e2, e3, e4 = create(:enterprise), create(:enterprise), create(:enterprise), create(:enterprise) - create(:enterprise_relationship, parent: e1, child: e2) - create(:enterprise_relationship, parent: e3, child: e4) + scenario "creating a relationship" do + e1 = create(:enterprise, name: 'One') + e2 = create(:enterprise, name: 'Two') - # When I go to the relationships page - click_link 'Enterprises' - click_link 'Relationships' + visit admin_enterprise_relationships_path + select 'One', from: 'enterprise_relationship_parent_id' + select 'Two', from: 'enterprise_relationship_child_id' + click_button 'Create' - # Then I should see the relationships - within('table#enterprise-relationships') do - page.should have_table_row [e1.name, 'permits', e2.name, ''] - page.should have_table_row [e3.name, 'permits', e4.name, ''] + page.should have_relationship e1, e2 + EnterpriseRelationship.where(parent_id: e1, child_id: e2).should be_present + end + + + scenario "attempting to create a relationship with invalid data" do + e1 = create(:enterprise, name: 'One') + e2 = create(:enterprise, name: 'Two') + create(:enterprise_relationship, parent: e1, child: e2) + + expect do + # When I attempt to create a duplicate relationship + visit admin_enterprise_relationships_path + select 'One', from: 'enterprise_relationship_parent_id' + select 'Two', from: 'enterprise_relationship_child_id' + click_button 'Create' + + # Then I should see an error message + page.should have_content "That relationship is already established." + end.to change(EnterpriseRelationship, :count).by(0) + end + + + scenario "deleting a relationship" do + e1 = create(:enterprise, name: 'One') + e2 = create(:enterprise, name: 'Two') + er = create(:enterprise_relationship, parent: e1, child: e2) + + visit admin_enterprise_relationships_path + page.should have_relationship e1, e2 + + first("a.delete-enterprise-relationship").click + + page.should_not have_relationship e1, e2 + EnterpriseRelationship.where(id: er.id).should be_empty end end - scenario "creating a relationship" do - e1 = create(:enterprise, name: 'One') - e2 = create(:enterprise, name: 'Two') + context "as an enterprise user" do + let!(:d1) { create(:distributor_enterprise) } + let!(:d2) { create(:distributor_enterprise) } + let!(:d3) { create(:distributor_enterprise) } + let(:enterprise_user) { create_enterprise_user([d1]) } - visit admin_enterprise_relationships_path - select 'One', from: 'enterprise_relationship_parent_name' - select 'Two', from: 'enterprise_relationship_child_name' - click_button 'Create' + let!(:er1) { create(:enterprise_relationship, parent: d1, child: d2) } + let!(:er2) { create(:enterprise_relationship, parent: d2, child: d1) } + let!(:er3) { create(:enterprise_relationship, parent: d2, child: d3) } - page.should have_table_row [e1.name, 'permits', e2.name, ''] - EnterpriseRelationship.where(parent_id: e1, child_id: e2).should be_present - end + before { login_to_admin_as enterprise_user } - - scenario "attempting to create a relationship with invalid data" do - e1 = create(:enterprise, name: 'One') - e2 = create(:enterprise, name: 'Two') - create(:enterprise_relationship, parent: e1, child: e2) - - expect do - # When I attempt to create a duplicate relationship + scenario "enterprise user can only see relationships involving their enterprises" do visit admin_enterprise_relationships_path - select 'One', from: 'enterprise_relationship_parent_name' - select 'Two', from: 'enterprise_relationship_child_name' - click_button 'Create' - # Then I should see an error message - page.should have_content "That relationship is already established." - end.to change(EnterpriseRelationship, :count).by(0) + page.should have_relationship d1, d2 + page.should have_relationship d2, d1 + page.should_not have_relationship d2, d3 + end + + + scenario "enterprise user can only add their own enterprises as parent" do + visit admin_enterprise_relationships_path + page.should have_select 'enterprise_relationship_parent_id', options: ['', d1.name] + page.should have_select 'enterprise_relationship_child_id', options: ['', d1.name, d2.name, d3.name] + end end - scenario "deleting a relationship" do - e1 = create(:enterprise, name: 'One') - e2 = create(:enterprise, name: 'Two') - er = create(:enterprise_relationship, parent: e1, child: e2) + private - visit admin_enterprise_relationships_path - page.should have_table_row [e1.name, 'permits', e2.name, ''] - - first("a.delete-enterprise-relationship").click - - page.should_not have_table_row [e1.name, 'permits', e2.name, ''] - EnterpriseRelationship.where(id: er.id).should be_empty + def have_relationship(parent, child) + have_table_row [parent.name, 'permits', child.name, ''] end end diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 6cb3a501a4..2423a6dc05 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -514,6 +514,15 @@ feature %q{ # I should not see exchanges for supplier2 or distributor2 page.all('tr.supplier').count.should == 1 page.all('tr.distributor').count.should == 1 + + # When I save, then those exchanges should remain + click_button 'Update' + page.should have_content "Your order cycle has been updated." + + oc.reload + oc.suppliers.sort.should == [supplier1, supplier2] + oc.coordinator.should == supplier1 + oc.distributors.sort.should == [distributor1, distributor2] end scenario "cloning an order cycle" do diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb index b9f9d7a206..efe531224d 100644 --- a/spec/features/admin/products_spec.rb +++ b/spec/features/admin/products_spec.rb @@ -46,23 +46,20 @@ feature %q{ 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 '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 diff --git a/spec/helpers/shared_helper_spec.rb b/spec/helpers/shared_helper_spec.rb index d28a6eb7b3..92c688d1ae 100644 --- a/spec/helpers/shared_helper_spec.rb +++ b/spec/helpers/shared_helper_spec.rb @@ -23,37 +23,4 @@ describe SharedHelper do helper.stub(:current_order) { order } helper.distributor_link_class(d1).should =~ /empties-cart/ end - - describe "finding current producers" do - it "finds producers for the current distribution" do - s = create(:supplier_enterprise) - d = create(:distributor_enterprise) - p = create(:simple_product) - oc = create(:simple_order_cycle, suppliers: [s], distributors: [d], variants: [p.master]) - - helper.stub(:current_order_cycle) { oc } - helper.stub(:current_distributor) { d } - - helper.current_producers.should == [s] - end - - it "returns [] when no order cycle set" do - d = double(:distributor) - - helper.stub(:current_order_cycle) { nil } - helper.stub(:current_distributor) { d } - - helper.current_producers.should == [] - end - - it "returns [] when no distributor set" do - oc = double(:order_cycle) - - helper.stub(:current_order_cycle) { oc } - helper.stub(:current_distributor) { nil } - - helper.current_producers.should == [] - - end - end end diff --git a/spec/javascripts/application_spec.js b/spec/javascripts/application_spec.js index 9e821754de..df629c1c81 100644 --- a/spec/javascripts/application_spec.js +++ b/spec/javascripts/application_spec.js @@ -1,6 +1,7 @@ //= require angular //= require angular-resource //= require angular-animate +//= require angular-sanitize //= require angular-mocks //= require angular-cookies //= require angular-backstretch.js diff --git a/spec/javascripts/unit/darkswarm/controllers/checkout/accordion_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/checkout/accordion_controller_spec.js.coffee index 1c0c199351..d35fb93e86 100644 --- a/spec/javascripts/unit/darkswarm/controllers/checkout/accordion_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/checkout/accordion_controller_spec.js.coffee @@ -1,19 +1,40 @@ describe "AccordionCtrl", -> ctrl = null - scope = scope + scope = null beforeEach -> module "Darkswarm" localStorage.clear() - inject ($controller, $rootScope) -> - scope = $rootScope.$new() - scope.order = - id: 129 - ctrl = $controller 'AccordionCtrl', {$scope: scope} - it "defaults the details accordion to visible", -> - expect(scope.accordion.details).toEqual true + describe "loading incomplete form", -> + beforeEach -> + inject ($controller, $rootScope) -> + scope = $rootScope.$new() + scope.order = + id: 129 + ctrl = $controller 'AccordionCtrl', {$scope: scope} - it "changes accordion", -> - scope.show "shipping" - expect(scope.accordion["shipping"]).toEqual true + it "defaults the details accordion to visible", -> + expect(scope.accordion.details).toEqual true + + it "changes accordion", -> + scope.show "shipping" + expect(scope.accordion["shipping"]).toEqual true + + describe "loading complete form", -> + beforeEach -> + inject ($controller, $rootScope) -> + scope = $rootScope.$new() + scope.checkout = + $valid: true + scope.order = + id: 129 + ctrl = $controller 'AccordionCtrl', {$scope: scope} + + it "automatically closes all sections if the entire form is valid", -> + waitsFor -> + (scope.accordion.details and + scope.accordion.shipping and + scope.accordion.payment and + scope.accordion.billing) == false + , "the accordion to close", 100 diff --git a/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee b/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee new file mode 100644 index 0000000000..f34df5cc71 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/filters/strip_url_spec.js.coffee @@ -0,0 +1,16 @@ +describe 'filtering urls', -> + filter = null + + beforeEach -> + module 'Darkswarm' + inject ($filter) -> + filter = $filter('stripUrl') + + it "removes http and www", -> + expect(filter("http://www.footle.com")).toEqual "footle.com" + + it "removes https and www", -> + expect(filter("https://www.footle.com")).toEqual "footle.com" + + it "removes just www", -> + expect(filter("www.footle.com")).toEqual "footle.com" diff --git a/spec/javascripts/unit/darkswarm/services/order_cycle_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/order_cycle_spec.js.coffee index f7a65867e8..93dd7de79c 100644 --- a/spec/javascripts/unit/darkswarm/services/order_cycle_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/order_cycle_spec.js.coffee @@ -21,14 +21,14 @@ describe 'OrderCycle service', -> $httpBackend.expectPOST("/shop/order_cycle", {"order_cycle_id" : 10}).respond(200) spyOn(mockProduct, "update") OrderCycle.order_cycle.order_cycle_id = 10 - OrderCycle.push_order_cycle() + OrderCycle.push_order_cycle mockProduct.update $httpBackend.flush() expect(mockProduct.update).toHaveBeenCalled() it "updates the orders_close_at attr after update", -> datestring = "2013-12-20T00:00:00+11:00" $httpBackend.expectPOST("/shop/order_cycle").respond({orders_close_at: datestring}) - OrderCycle.push_order_cycle() + OrderCycle.push_order_cycle mockProduct.update $httpBackend.flush() expect(OrderCycle.order_cycle.orders_close_at).toEqual(datestring) diff --git a/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee index fedcf23629..4f6c711f99 100644 --- a/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee @@ -29,7 +29,6 @@ describe 'Order service', -> inject ($injector, _$httpBackend_)-> $httpBackend = _$httpBackend_ - $httpBackend.expectGET("/shop/products").respond 200, [] Order = $injector.get("Order") Navigation = $injector.get("Navigation") flash = $injector.get("flash") @@ -77,7 +76,6 @@ describe 'Order service', -> $httpBackend.flush() expect(Order.errors).toEqual {error: "frogs"} - it "Munges the order attributes to add _attributes as Rails needs", -> expect(Order.preprocess().bill_address_attributes).not.toBe(undefined) expect(Order.preprocess().bill_address).toBe(undefined) diff --git a/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb b/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb index 81cd925569..c63d1eac25 100644 --- a/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb +++ b/spec/lib/open_food_network/order_cycle_form_applicator_spec.rb @@ -11,7 +11,7 @@ module OpenFoodNetwork oc = double(:order_cycle, :coordinator_id => coordinator_id, :exchanges => [], :incoming_exchanges => [incoming_exchange], :outgoing_exchanges => []) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.should_receive(:exchange_variant_ids).with(incoming_exchange).and_return([1, 3]) applicator.should_receive(:exchange_exists?).with(supplier_id, coordinator_id, true).and_return(false) @@ -29,7 +29,7 @@ module OpenFoodNetwork oc = double(:order_cycle, :coordinator_id => coordinator_id, :exchanges => [], :incoming_exchanges => [], :outgoing_exchanges => [outgoing_exchange]) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.should_receive(:exchange_variant_ids).with(outgoing_exchange).and_return([1, 3]) applicator.should_receive(:exchange_exists?).with(coordinator_id, distributor_id, false).and_return(false) @@ -51,7 +51,7 @@ module OpenFoodNetwork :incoming_exchanges => [incoming_exchange], :outgoing_exchanges => []) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.should_receive(:exchange_variant_ids).with(incoming_exchange).and_return([1, 3]) applicator.should_receive(:exchange_exists?).with(supplier_id, coordinator_id, true).and_return(true) @@ -73,7 +73,7 @@ module OpenFoodNetwork :incoming_exchanges => [], :outgoing_exchanges => [outgoing_exchange]) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.should_receive(:exchange_variant_ids).with(outgoing_exchange).and_return([1, 3]) applicator.should_receive(:exchange_exists?).with(coordinator_id, distributor_id, false).and_return(true) @@ -95,7 +95,7 @@ module OpenFoodNetwork :incoming_exchanges => [], :outgoing_exchanges => []) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.should_receive(:destroy_untouched_exchanges) @@ -108,20 +108,61 @@ module OpenFoodNetwork e2 = double(:exchange2, id: 1, foo: 2) oc = double(:order_cycle, :exchanges => [e1]) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.instance_eval do @touched_exchanges = [e2] end applicator.send(:untouched_exchanges).should == [] end + + it "does not destroy exchanges involving enterprises it does not have permission to touch" do + applicator = OrderCycleFormApplicator.new(nil, []) + exchanges = double(:exchanges) + permitted_exchanges = [double(:exchange), double(:exchange)] + + applicator.should_receive(:with_permission).with(exchanges) { permitted_exchanges } + applicator.stub(:untouched_exchanges) { exchanges } + permitted_exchanges.each { |ex| ex.should_receive(:destroy) } + + applicator.send(:destroy_untouched_exchanges) + end end it "converts exchange variant ids hash to an array of ids" do - applicator = OrderCycleFormApplicator.new(nil) + applicator = OrderCycleFormApplicator.new(nil, []) applicator.send(:exchange_variant_ids, {:enterprise_id => 123, :variants => {'1' => true, '2' => false, '3' => true}}).should == [1, 3] end + + describe "filtering exchanges for permission" do + describe "checking permission on a single exchange" do + it "returns true when it has permission" do + e = double(:enterprise) + ex = double(:exchange, participant: e) + + applicator = OrderCycleFormApplicator.new(nil, [e]) + applicator.send(:permission_for, ex).should be_true + end + + it "returns false otherwise" do + e = double(:enterprise) + ex = double(:exchange, participant: e) + + applicator = OrderCycleFormApplicator.new(nil, []) + applicator.send(:permission_for, ex).should be_false + end + end + + describe "filtering many exchanges" do + it "returns exchanges involving enterprises we have permission to touch" do + ex1, ex2 = double(:exchange), double(:exchange) + applicator = OrderCycleFormApplicator.new(nil, []) + applicator.stub(:permission_for).and_return(true, false) + applicator.send(:with_permission, [ex1, ex2]).should == [ex1] + end + end + end end context "integration specs" do @@ -132,7 +173,7 @@ module OpenFoodNetwork it "checks whether exchanges exist" do oc = FactoryGirl.create(:simple_order_cycle) exchange = FactoryGirl.create(:exchange, order_cycle: oc) - applicator = OrderCycleFormApplicator.new(oc) + applicator = OrderCycleFormApplicator.new(oc, []) applicator.send(:exchange_exists?, exchange.sender_id, exchange.receiver_id, exchange.incoming).should be_true applicator.send(:exchange_exists?, exchange.sender_id, exchange.receiver_id, !exchange.incoming).should be_false @@ -143,10 +184,10 @@ module OpenFoodNetwork end it "adds exchanges" do - oc = FactoryGirl.create(:simple_order_cycle) - applicator = OrderCycleFormApplicator.new(oc) sender = FactoryGirl.create(:enterprise) receiver = FactoryGirl.create(:enterprise) + oc = FactoryGirl.create(:simple_order_cycle) + applicator = OrderCycleFormApplicator.new(oc, [sender, receiver]) incoming = true variant1 = FactoryGirl.create(:variant) variant2 = FactoryGirl.create(:variant) @@ -167,10 +208,11 @@ module OpenFoodNetwork end it "updates exchanges" do - oc = FactoryGirl.create(:simple_order_cycle) - applicator = OrderCycleFormApplicator.new(oc) sender = FactoryGirl.create(:enterprise) receiver = FactoryGirl.create(:enterprise) + oc = FactoryGirl.create(:simple_order_cycle) + applicator = OrderCycleFormApplicator.new(oc, [sender, receiver]) + incoming = true variant1 = FactoryGirl.create(:variant) variant2 = FactoryGirl.create(:variant) @@ -189,6 +231,34 @@ module OpenFoodNetwork exchange.enterprise_fees.sort.should == [enterprise_fee2, enterprise_fee3] applicator.send(:touched_exchanges).should == [exchange] end + + it "does not add exchanges it is not permitted to touch" do + sender = FactoryGirl.create(:enterprise) + receiver = FactoryGirl.create(:enterprise) + oc = FactoryGirl.create(:simple_order_cycle) + applicator = OrderCycleFormApplicator.new(oc, []) + incoming = true + + expect do + applicator.send(:touched_exchanges=, []) + applicator.send(:add_exchange, sender.id, receiver.id, incoming) + end.to change(Exchange, :count).by(0) + end + + it "does not update exchanges it is not permitted to touch" do + sender = FactoryGirl.create(:enterprise) + receiver = FactoryGirl.create(:enterprise) + oc = FactoryGirl.create(:simple_order_cycle) + applicator = OrderCycleFormApplicator.new(oc, []) + incoming = true + exchange = FactoryGirl.create(:exchange, order_cycle: oc, sender: sender, receiver: receiver, incoming: incoming) + variant1 = FactoryGirl.create(:variant) + + applicator.send(:touched_exchanges=, []) + applicator.send(:update_exchange, sender.id, receiver.id, incoming, {:variant_ids => [variant1.id]}) + + exchange.variants.should_not == [variant1] + end end end end diff --git a/spec/models/enterprise_relationship_spec.rb b/spec/models/enterprise_relationship_spec.rb index 7cca07472e..b715674594 100644 --- a/spec/models/enterprise_relationship_spec.rb +++ b/spec/models/enterprise_relationship_spec.rb @@ -2,15 +2,32 @@ require 'spec_helper' describe EnterpriseRelationship do describe "scopes" do + let(:e1) { create(:enterprise, name: 'A') } + let(:e2) { create(:enterprise, name: 'B') } + let(:e3) { create(:enterprise, name: 'C') } + it "sorts by parent, child enterprise name" do - e1 = create(:enterprise, name: 'A') - e2 = create(:enterprise, name: 'B') - e3 = create(:enterprise, name: 'C') er1 = create(:enterprise_relationship, parent: e1, child: e3) er2 = create(:enterprise_relationship, parent: e2, child: e1) er3 = create(:enterprise_relationship, parent: e1, child: e2) EnterpriseRelationship.by_name.should == [er3, er1, er2] end + + describe "finding relationships involving some enterprises" do + let!(:er) { create(:enterprise_relationship, parent: e1, child: e2) } + + it "returns relationships where an enterprise is the parent" do + EnterpriseRelationship.involving_enterprises([e1]).should == [er] + end + + it "returns relationships where an enterprise is the child" do + EnterpriseRelationship.involving_enterprises([e2]).should == [er] + end + + it "does not return other relationships" do + EnterpriseRelationship.involving_enterprises([e3]).should == [] + end + end end end diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index f375b8890a..d93bc78dd6 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -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) diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index ed6cdbfc93..0dfceadbad 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -48,7 +48,7 @@ describe Exchange do e.enterprise_fees.count.should == 1 end - describe "reporting whether it is an incoming exchange" do + describe "exchange directionality" do let(:supplier) { create(:supplier_enterprise) } let(:coordinator) { create(:distributor_enterprise) } let(:distributor) { create(:distributor_enterprise) } @@ -56,12 +56,24 @@ describe Exchange do let(:incoming_exchange) { oc.exchanges.create! sender: supplier, receiver: coordinator, incoming: true } let(:outgoing_exchange) { oc.exchanges.create! sender: coordinator, receiver: distributor, incoming: false } - it "returns true for incoming exchanges" do - incoming_exchange.should be_incoming + describe "reporting whether it is an incoming exchange" do + it "returns true for incoming exchanges" do + incoming_exchange.should be_incoming + end + + it "returns false for outgoing exchanges" do + outgoing_exchange.should_not be_incoming + end end - it "returns false for outgoing exchanges" do - outgoing_exchange.should_not be_incoming + describe "finding the exchange participant (the enterprise other than the coordinator)" do + it "returns the sender for incoming exchanges" do + incoming_exchange.participant.should == supplier + end + + it "returns the receiver for outgoing exchanges" do + outgoing_exchange.participant.should == distributor + end end end diff --git a/spec/models/spree/ability_spec.rb b/spec/models/spree/ability_spec.rb index fc13925bae..111c8e5196 100644 --- a/spec/models/spree/ability_spec.rb +++ b/spec/models/spree/ability_spec.rb @@ -17,6 +17,9 @@ module Spree let(:p1) { create(:product, supplier: s1, distributors:[d1, d2]) } let(:p2) { create(:product, supplier: s2, distributors:[d1, d2]) } + let(:er1) { create(:enterprise_relationship, parent: s1, child: d1) } + let(:er2) { create(:enterprise_relationship, parent: d1, child: s1) } + subject { user } let(:user) { nil } @@ -72,6 +75,18 @@ module Spree should have_ability([:admin, :index, :read, :create, :edit], for: Spree::Classification) end + it "should be able to read and create enterprise relationships" do + should have_ability([:admin, :index, :create], for: EnterpriseRelationship) + end + + it "should be able to destroy enterprise relationships for its enterprises" do + should have_ability(:destroy, for: er1) + end + + it "should not be able to destroy enterprise relationships for other enterprises" do + should_not have_ability(:destroy, for: er2) + end + end context "when is a distributor enterprise user" do @@ -146,6 +161,18 @@ module Spree it "should be able to read/write ShippingMethods" do should have_ability([:admin, :index, :create, :update, :destroy], for: Spree::ShippingMethod) end + + it "should be able to read and create enterprise relationships" do + should have_ability([:admin, :index, :create], for: EnterpriseRelationship) + end + + it "should be able to destroy enterprise relationships for its enterprises" do + should have_ability(:destroy, for: er2) + end + + it "should not be able to destroy enterprise relationships for other enterprises" do + should_not have_ability(:destroy, for: er1) + end end context 'Order Cycle co-ordinator' do diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb index 6d90b70761..a5333b6d11 100644 --- a/spec/models/spree/product_spec.rb +++ b/spec/models/spree/product_spec.rb @@ -230,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) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 49a7f39250..4f96a09070 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -71,26 +71,20 @@ RSpec.configure do |config| # rspec-rails. config.infer_base_class_for_anonymous_controllers = false - # ## Filters - # + # Filters config.filter_run_excluding :skip => true, :future => true, :to_figure_out => true - config.before(:each) do - Spree::Address.any_instance.stub(:geocode).and_return([1,1]) + # DatabaseCleaner + config.before(:suite) { DatabaseCleaner.clean_with :deletion, {except: ['spree_countries', 'spree_states']} } + config.before(:each) { DatabaseCleaner.strategy = :transaction } + config.before(:each, js: true) { DatabaseCleaner.strategy = :deletion, {except: ['spree_countries', 'spree_states']} } + config.before(:each) { DatabaseCleaner.start } + config.after(:each) { DatabaseCleaner.clean } - if example.metadata[:js] - DatabaseCleaner.strategy = :deletion, { :except => ['spree_countries', 'spree_states'] } - else - DatabaseCleaner.strategy = :transaction - end - - DatabaseCleaner.start - end - - config.after(:each) do - DatabaseCleaner.clean - end + # Geocoding + config.before(:each) { Spree::Address.any_instance.stub(:geocode).and_return([1,1]) } + # Helpers config.include Rails.application.routes.url_helpers config.include Spree::UrlHelpers config.include Spree::CheckoutHelpers @@ -103,7 +97,7 @@ RSpec.configure do |config| config.include OpenFoodNetwork::DistributionHelper config.include ActionView::Helpers::DateHelper - # Factory girl + # FactoryGirl require 'factory_girl_rails' config.include FactoryGirl::Syntax::Methods diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb index 6add44834e..3a2cb82128 100644 --- a/spec/support/request/web_helper.rb +++ b/spec/support/request/web_helper.rb @@ -1,4 +1,22 @@ module WebHelper + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + # By default, Capybara uses a 30 s wait time, which is more reliable for CI, but too slow + # for TDD. Use this to make tests fail fast. Usage: + # + # describe "foo" do + # use_short_wait + # ... + # end + def use_short_wait + around { |example| Capybara.using_wait_time(2) { example.run } } + end + end + + def current_path_should_be path current_path = URI.parse(current_url).path current_path.should == path