From 694dd0c32934702011dc3253545fee805e4ec573 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 17 Oct 2014 10:52:36 +1100 Subject: [PATCH 01/17] Enterprise user selling own produce only sees simple order cycle listing --- app/helpers/order_cycles_helper.rb | 4 ++++ app/views/admin/order_cycles/_row.html.haml | 20 +++++++++++--------- app/views/admin/order_cycles/index.html.haml | 14 ++++++++------ lib/open_food_network/permissions.rb | 6 ++++++ spec/features/admin/order_cycles_spec.rb | 20 ++++++++++++++++++++ 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/app/helpers/order_cycles_helper.rb b/app/helpers/order_cycles_helper.rb index dfd957a143..23ac74e944 100644 --- a/app/helpers/order_cycles_helper.rb +++ b/app/helpers/order_cycles_helper.rb @@ -62,6 +62,10 @@ module OrderCyclesHelper OrderCycle.active.with_distributor(@distributor).present? end + def order_cycles_simple_view + !OpenFoodNetwork::Permissions.new(spree_current_user).can_manage_complex_order_cycles? + end + def order_cycles_enabled? OpenFoodNetwork::FeatureToggle.enabled? :order_cycles end diff --git a/app/views/admin/order_cycles/_row.html.haml b/app/views/admin/order_cycles/_row.html.haml index 75e84de025..e95adff38f 100644 --- a/app/views/admin/order_cycles/_row.html.haml +++ b/app/views/admin/order_cycles/_row.html.haml @@ -4,15 +4,17 @@ %td= link_to order_cycle.name, main_app.edit_admin_order_cycle_path(order_cycle) %td= order_cycle_form.text_field :orders_open_at, :class => 'datetimepicker', :value => order_cycle.orders_open_at %td= order_cycle_form.text_field :orders_close_at, :class => 'datetimepicker', :value => order_cycle.orders_close_at - %td.suppliers - - order_cycle.suppliers.managed_by(spree_current_user).each do |s| - = s.name - %br/ - %td= order_cycle.coordinator.name - %td.distributors - - order_cycle.distributors.managed_by(spree_current_user).each do |d| - = d.name - %br/ + + - unless order_cycles_simple_view + %td.suppliers + - order_cycle.suppliers.managed_by(spree_current_user).each do |s| + = s.name + %br/ + %td= order_cycle.coordinator.name + %td.distributors + - order_cycle.distributors.managed_by(spree_current_user).each do |d| + = d.name + %br/ %td.products - variant_images = capture do diff --git a/app/views/admin/order_cycles/index.html.haml b/app/views/admin/order_cycles/index.html.haml index 1fac06f507..f649a4ab47 100644 --- a/app/views/admin/order_cycles/index.html.haml +++ b/app/views/admin/order_cycles/index.html.haml @@ -13,9 +13,10 @@ %col %col{'style' => 'width: 20%;'} %col{'style' => 'width: 20%;'} - %col - %col - %col + - unless order_cycles_simple_view + %col + %col + %col %col %col %col @@ -25,9 +26,10 @@ %th Name %th Open %th Close - %th Suppliers - %th Coordinator - %th Distributors + - unless order_cycles_simple_view + %th Suppliers + %th Coordinator + %th Distributors %th Products %th.actions %th.actions diff --git a/lib/open_food_network/permissions.rb b/lib/open_food_network/permissions.rb index 3d5df1e804..678e70941a 100644 --- a/lib/open_food_network/permissions.rb +++ b/lib/open_food_network/permissions.rb @@ -4,6 +4,12 @@ module OpenFoodNetwork @user = user end + def can_manage_complex_order_cycles? + managed_and_related_enterprises_with(:add_to_order_cycle).any? do |e| + e.sells == 'any' + end + end + # Find enterprises that an admin is allowed to add to an order cycle def order_cycle_enterprises managed_and_related_enterprises_with :add_to_order_cycle diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index febd966109..354be34671 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -572,7 +572,27 @@ feature %q{ occ = OrderCycle.last occ.name.should == "COPY OF #{oc.name}" end + end + + describe "as an enterprise user selling only my own produce" do + let(:user) { create_enterprise_user } + let(:enterprise) { create(:enterprise, is_primary_producer: true, sells: 'own') } + + use_short_wait + + before do + user.enterprise_roles.create! enterprise: enterprise + login_to_admin_as user + end + + it "shows me an index of order cycles without enterprise columns" do + create(:order_cycle, coordinator: enterprise) + visit admin_order_cycles_path + page.should_not have_selector 'th', text: 'SUPPLIERS' + page.should_not have_selector 'th', text: 'COORDINATOR' + page.should_not have_selector 'th', text: 'DISTRIBUTORS' + end end From f060da9c8db88368b41c144ba7753dd019223a91 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 17 Oct 2014 14:13:27 +1100 Subject: [PATCH 02/17] Rename angular app order_cycle -> admin.order_cycles --- app/assets/javascripts/admin/order_cycle.js.erb.coffee | 2 +- app/views/admin/order_cycles/edit.html.haml | 2 +- app/views/admin/order_cycles/new.html.haml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/admin/order_cycle.js.erb.coffee b/app/assets/javascripts/admin/order_cycle.js.erb.coffee index 64f2550466..bcfb338a15 100644 --- a/app/assets/javascripts/admin/order_cycle.js.erb.coffee +++ b/app/assets/javascripts/admin/order_cycle.js.erb.coffee @@ -1,4 +1,4 @@ -angular.module('order_cycle', ['ngResource']) +angular.module('admin.order_cycles', ['ngResource']) .controller('AdminCreateOrderCycleCtrl', ['$scope', 'OrderCycle', 'Enterprise', 'EnterpriseFee', ($scope, OrderCycle, Enterprise, EnterpriseFee) -> $scope.enterprises = Enterprise.index() $scope.supplied_products = Enterprise.supplied_products diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index 9bf0a8ca31..b22f0cf51d 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -1,4 +1,4 @@ %h1 Edit Order Cycle -= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'order_cycle', 'ng-controller' => 'AdminEditOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| += form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => 'AdminEditOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| = render 'form', :f => f diff --git a/app/views/admin/order_cycles/new.html.haml b/app/views/admin/order_cycles/new.html.haml index c2e9c924f2..de1f229258 100644 --- a/app/views/admin/order_cycles/new.html.haml +++ b/app/views/admin/order_cycles/new.html.haml @@ -1,4 +1,4 @@ %h1 New Order Cycle -= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'order_cycle', 'ng-controller' => 'AdminCreateOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| += form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => 'AdminCreateOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| = render 'form', :f => f From 078d2bac118be128429b94396ce88e1376ebb68a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 17 Oct 2014 16:50:16 +1100 Subject: [PATCH 03/17] Extract factories from order cycles admin angular --- .../admin/order_cycle.js.erb.coffee | 229 ------------------ .../services/enterprise.js.coffee | 43 ++++ .../services/enterprise_fee.js.coffee | 18 ++ .../services/order_cycle.js.coffee | 168 +++++++++++++ 4 files changed, 229 insertions(+), 229 deletions(-) create mode 100644 app/assets/javascripts/admin/order_cycles/services/enterprise.js.coffee create mode 100644 app/assets/javascripts/admin/order_cycles/services/enterprise_fee.js.coffee create mode 100644 app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee diff --git a/app/assets/javascripts/admin/order_cycle.js.erb.coffee b/app/assets/javascripts/admin/order_cycle.js.erb.coffee index bcfb338a15..6a7d565bae 100644 --- a/app/assets/javascripts/admin/order_cycle.js.erb.coffee +++ b/app/assets/javascripts/admin/order_cycle.js.erb.coffee @@ -162,235 +162,6 @@ angular.module('admin.order_cycles', ['ngResource']) $httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content') ]) - .factory('OrderCycle', ['$resource', '$window', ($resource, $window) -> - OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, { - 'index': { method: 'GET', isArray: true} - 'create': { method: 'POST'} - 'update': { method: 'PUT'}} - - { - order_cycle: - incoming_exchanges: [] - outgoing_exchanges: [] - coordinator_fees: [] - - loaded: false - - exchangeSelectedVariants: (exchange) -> - numActiveVariants = 0 - numActiveVariants++ for id, active of exchange.variants when active - numActiveVariants - - exchangeDirection: (exchange) -> - if this.order_cycle.incoming_exchanges.indexOf(exchange) == -1 then 'outgoing' else 'incoming' - - toggleProducts: (exchange) -> - exchange.showProducts = !exchange.showProducts - - setExchangeVariants: (exchange, variants, selected) -> - exchange.variants[variant] = selected for variant in variants - - addSupplier: (new_supplier_id) -> - this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []}) - - addDistributor: (new_distributor_id) -> - this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []}) - - removeExchange: (exchange) -> - if exchange.incoming - incoming_index = this.order_cycle.incoming_exchanges.indexOf exchange - this.order_cycle.incoming_exchanges.splice(incoming_index, 1) - this.removeDistributionOfVariant(variant_id) for variant_id, active of exchange.variants when active - else - outgoing_index = this.order_cycle.outgoing_exchanges.indexOf exchange - this.order_cycle.outgoing_exchanges.splice(outgoing_index, 1) if outgoing_index > -1 - - addCoordinatorFee: -> - this.order_cycle.coordinator_fees.push({}) - - removeCoordinatorFee: (index) -> - this.order_cycle.coordinator_fees.splice(index, 1) - - addExchangeFee: (exchange) -> - exchange.enterprise_fees.push({}) - - removeExchangeFee: (exchange, index) -> - exchange.enterprise_fees.splice(index, 1) - - productSuppliedToOrderCycle: (product) -> - product_variant_ids = (variant.id for variant in product.variants) - variant_ids = [product.master_id].concat(product_variant_ids) - incomingExchangesVariants = this.incomingExchangesVariants() - - # TODO: This is an O(n^2) implementation of set intersection and thus is slooow. - # Use a better algorithm if needed. - # Also, incomingExchangesVariants is called every time, when it only needs to be - # called once per change to incoming variants. Some sort of caching? - ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1) - ids.length > 0 - - variantSuppliedToOrderCycle: (variant) -> - this.incomingExchangesVariants().indexOf(variant.id) != -1 - - incomingExchangesVariants: -> - variant_ids = [] - - for exchange in this.order_cycle.incoming_exchanges - variant_ids.push(parseInt(id)) for id, active of exchange.variants when active - variant_ids - - participatingEnterpriseIds: -> - suppliers = (exchange.enterprise_id for exchange in this.order_cycle.incoming_exchanges) - distributors = (exchange.enterprise_id for exchange in this.order_cycle.outgoing_exchanges) - jQuery.unique(suppliers.concat(distributors)).sort() - - removeDistributionOfVariant: (variant_id) -> - for exchange in this.order_cycle.outgoing_exchanges - exchange.variants[variant_id] = false - - load: (order_cycle_id) -> - service = this - OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) -> - angular.extend(service.order_cycle, oc) - service.order_cycle.incoming_exchanges = [] - service.order_cycle.outgoing_exchanges = [] - for exchange in service.order_cycle.exchanges - if exchange.incoming - angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true}) - delete(exchange.receiver_id) - service.order_cycle.incoming_exchanges.push(exchange) - - else - angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true}) - delete(exchange.sender_id) - service.order_cycle.outgoing_exchanges.push(exchange) - - delete(service.order_cycle.exchanges) - service.loaded = true - - this.order_cycle - - create: -> - oc = new OrderCycle({order_cycle: this.dataForSubmit()}) - oc.$create (data) -> - if data['success'] - $window.location = '/admin/order_cycles' - else - console.log('Failed to create order cycle') - - update: -> - oc = new OrderCycle({order_cycle: this.dataForSubmit()}) - oc.$update {order_cycle_id: this.order_cycle.id}, (data) -> - if data['success'] - $window.location = '/admin/order_cycles' - else - console.log('Failed to update order cycle') - - dataForSubmit: -> - data = this.deepCopy() - data = this.removeInactiveExchanges(data) - data = this.translateCoordinatorFees(data) - data = this.translateExchangeFees(data) - data - - deepCopy: -> - data = angular.extend({}, this.order_cycle) - - # Copy exchanges - data.incoming_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.incoming_exchanges) if this.order_cycle.incoming_exchanges? - data.outgoing_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.outgoing_exchanges) if this.order_cycle.outgoing_exchanges? - - # Copy exchange fees - all_exchanges = (data.incoming_exchanges || []) + (data.outgoing_exchanges || []) - for exchange in all_exchanges - if exchange.enterprise_fees? - exchange.enterprise_fees = (angular.extend {}, fee for fee in exchange.enterprise_fees) - - data - - removeInactiveExchanges: (order_cycle) -> - order_cycle.incoming_exchanges = - (exchange for exchange in order_cycle.incoming_exchanges when exchange.active) - order_cycle.outgoing_exchanges = - (exchange for exchange in order_cycle.outgoing_exchanges when exchange.active) - order_cycle - - translateCoordinatorFees: (order_cycle) -> - order_cycle.coordinator_fee_ids = (fee.id for fee in order_cycle.coordinator_fees) - delete order_cycle.coordinator_fees - order_cycle - - translateExchangeFees: (order_cycle) -> - for exchange in order_cycle.incoming_exchanges - exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees) - delete exchange.enterprise_fees - for exchange in order_cycle.outgoing_exchanges - exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees) - delete exchange.enterprise_fees - order_cycle - }]) - - .factory('Enterprise', ['$resource', ($resource) -> - Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}}) - - { - Enterprise: Enterprise - enterprises: {} - supplied_products: [] - loaded: false - - index: -> - service = this - - Enterprise.index (data) -> - for enterprise in data - service.enterprises[enterprise.id] = enterprise - - for product in enterprise.supplied_products - service.supplied_products.push(product) - - service.loaded = true - - this.enterprises - - suppliedVariants: (enterprise_id) -> - vs = (this.variantsOf(product) for product in this.enterprises[enterprise_id].supplied_products) - [].concat vs... - - variantsOf: (product) -> - if product.variants.length > 0 - variant.id for variant in product.variants - else - [product.master_id] - - totalVariants: (enterprise) -> - numVariants = 0 - - if enterprise - counts = for product in enterprise.supplied_products - numVariants += if product.variants.length == 0 then 1 else product.variants.length - - numVariants - }]) - - .factory('EnterpriseFee', ['$resource', ($resource) -> - EnterpriseFee = $resource('/admin/enterprise_fees/:enterprise_fee_id.json', {}, {'index': {method: 'GET', isArray: true}}) - - { - EnterpriseFee: EnterpriseFee - enterprise_fees: {} - loaded: false - - index: -> - service = this - EnterpriseFee.index (data) -> - service.enterprise_fees = data - service.loaded = true - - forEnterprise: (enterprise_id) -> - enterprise_fee for enterprise_fee in this.enterprise_fees when enterprise_fee.enterprise_id == enterprise_id - }]) - .directive('datetimepicker', ['$parse', ($parse) -> (scope, element, attrs) -> # using $parse instead of scope[attrs.datetimepicker] for cases diff --git a/app/assets/javascripts/admin/order_cycles/services/enterprise.js.coffee b/app/assets/javascripts/admin/order_cycles/services/enterprise.js.coffee new file mode 100644 index 0000000000..244d050aba --- /dev/null +++ b/app/assets/javascripts/admin/order_cycles/services/enterprise.js.coffee @@ -0,0 +1,43 @@ +angular.module('admin.order_cycles').factory('Enterprise', ($resource) -> + Enterprise = $resource('/admin/enterprises/for_order_cycle/:enterprise_id.json', {}, {'index': {method: 'GET', isArray: true}}) + + { + Enterprise: Enterprise + enterprises: {} + supplied_products: [] + loaded: false + + index: (callback=null) -> + service = this + + Enterprise.index (data) -> + for enterprise in data + service.enterprises[enterprise.id] = enterprise + + for product in enterprise.supplied_products + service.supplied_products.push(product) + + service.loaded = true + (callback || angular.noop)(service.enterprises) + + this.enterprises + + suppliedVariants: (enterprise_id) -> + vs = (this.variantsOf(product) for product in this.enterprises[enterprise_id].supplied_products) + [].concat vs... + + variantsOf: (product) -> + if product.variants.length > 0 + variant.id for variant in product.variants + else + [product.master_id] + + totalVariants: (enterprise) -> + numVariants = 0 + + if enterprise + counts = for product in enterprise.supplied_products + numVariants += if product.variants.length == 0 then 1 else product.variants.length + + numVariants + }) \ No newline at end of file diff --git a/app/assets/javascripts/admin/order_cycles/services/enterprise_fee.js.coffee b/app/assets/javascripts/admin/order_cycles/services/enterprise_fee.js.coffee new file mode 100644 index 0000000000..330d7c031e --- /dev/null +++ b/app/assets/javascripts/admin/order_cycles/services/enterprise_fee.js.coffee @@ -0,0 +1,18 @@ +angular.module('admin.order_cycles').factory('EnterpriseFee', ($resource) -> + EnterpriseFee = $resource('/admin/enterprise_fees/:enterprise_fee_id.json', {}, {'index': {method: 'GET', isArray: true}}) + + { + EnterpriseFee: EnterpriseFee + enterprise_fees: {} + loaded: false + + index: -> + service = this + EnterpriseFee.index (data) -> + service.enterprise_fees = data + service.loaded = true + + forEnterprise: (enterprise_id) -> + enterprise_fee for enterprise_fee in this.enterprise_fees when enterprise_fee.enterprise_id == enterprise_id + }) + diff --git a/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee b/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee new file mode 100644 index 0000000000..5e46fdda50 --- /dev/null +++ b/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee @@ -0,0 +1,168 @@ +angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) -> + OrderCycle = $resource '/admin/order_cycles/:order_cycle_id.json', {}, { + 'index': { method: 'GET', isArray: true} + 'create': { method: 'POST'} + 'update': { method: 'PUT'}} + + { + order_cycle: + incoming_exchanges: [] + outgoing_exchanges: [] + coordinator_fees: [] + + loaded: false + + exchangeSelectedVariants: (exchange) -> + numActiveVariants = 0 + numActiveVariants++ for id, active of exchange.variants when active + numActiveVariants + + exchangeDirection: (exchange) -> + if this.order_cycle.incoming_exchanges.indexOf(exchange) == -1 then 'outgoing' else 'incoming' + + toggleProducts: (exchange) -> + exchange.showProducts = !exchange.showProducts + + setExchangeVariants: (exchange, variants, selected) -> + exchange.variants[variant] = selected for variant in variants + + addSupplier: (new_supplier_id) -> + this.order_cycle.incoming_exchanges.push({enterprise_id: new_supplier_id, incoming: true, active: true, variants: {}, enterprise_fees: []}) + + addDistributor: (new_distributor_id) -> + this.order_cycle.outgoing_exchanges.push({enterprise_id: new_distributor_id, incoming: false, active: true, variants: {}, enterprise_fees: []}) + + removeExchange: (exchange) -> + if exchange.incoming + incoming_index = this.order_cycle.incoming_exchanges.indexOf exchange + this.order_cycle.incoming_exchanges.splice(incoming_index, 1) + this.removeDistributionOfVariant(variant_id) for variant_id, active of exchange.variants when active + else + outgoing_index = this.order_cycle.outgoing_exchanges.indexOf exchange + this.order_cycle.outgoing_exchanges.splice(outgoing_index, 1) if outgoing_index > -1 + + addCoordinatorFee: -> + this.order_cycle.coordinator_fees.push({}) + + removeCoordinatorFee: (index) -> + this.order_cycle.coordinator_fees.splice(index, 1) + + addExchangeFee: (exchange) -> + exchange.enterprise_fees.push({}) + + removeExchangeFee: (exchange, index) -> + exchange.enterprise_fees.splice(index, 1) + + productSuppliedToOrderCycle: (product) -> + product_variant_ids = (variant.id for variant in product.variants) + variant_ids = [product.master_id].concat(product_variant_ids) + incomingExchangesVariants = this.incomingExchangesVariants() + + # TODO: This is an O(n^2) implementation of set intersection and thus is slooow. + # Use a better algorithm if needed. + # Also, incomingExchangesVariants is called every time, when it only needs to be + # called once per change to incoming variants. Some sort of caching? + ids = (variant_id for variant_id in variant_ids when incomingExchangesVariants.indexOf(variant_id) != -1) + ids.length > 0 + + variantSuppliedToOrderCycle: (variant) -> + this.incomingExchangesVariants().indexOf(variant.id) != -1 + + incomingExchangesVariants: -> + variant_ids = [] + + for exchange in this.order_cycle.incoming_exchanges + variant_ids.push(parseInt(id)) for id, active of exchange.variants when active + variant_ids + + participatingEnterpriseIds: -> + suppliers = (exchange.enterprise_id for exchange in this.order_cycle.incoming_exchanges) + distributors = (exchange.enterprise_id for exchange in this.order_cycle.outgoing_exchanges) + jQuery.unique(suppliers.concat(distributors)).sort() + + removeDistributionOfVariant: (variant_id) -> + for exchange in this.order_cycle.outgoing_exchanges + exchange.variants[variant_id] = false + + load: (order_cycle_id) -> + service = this + OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) -> + angular.extend(service.order_cycle, oc) + service.order_cycle.incoming_exchanges = [] + service.order_cycle.outgoing_exchanges = [] + for exchange in service.order_cycle.exchanges + if exchange.incoming + angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true}) + delete(exchange.receiver_id) + service.order_cycle.incoming_exchanges.push(exchange) + + else + angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true}) + delete(exchange.sender_id) + service.order_cycle.outgoing_exchanges.push(exchange) + + delete(service.order_cycle.exchanges) + service.loaded = true + + this.order_cycle + + create: -> + oc = new OrderCycle({order_cycle: this.dataForSubmit()}) + oc.$create (data) -> + if data['success'] + $window.location = '/admin/order_cycles' + else + console.log('Failed to create order cycle') + + update: -> + oc = new OrderCycle({order_cycle: this.dataForSubmit()}) + oc.$update {order_cycle_id: this.order_cycle.id}, (data) -> + if data['success'] + $window.location = '/admin/order_cycles' + else + console.log('Failed to update order cycle') + + dataForSubmit: -> + data = this.deepCopy() + data = this.removeInactiveExchanges(data) + data = this.translateCoordinatorFees(data) + data = this.translateExchangeFees(data) + data + + deepCopy: -> + data = angular.extend({}, this.order_cycle) + + # Copy exchanges + data.incoming_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.incoming_exchanges) if this.order_cycle.incoming_exchanges? + data.outgoing_exchanges = (angular.extend {}, exchange for exchange in this.order_cycle.outgoing_exchanges) if this.order_cycle.outgoing_exchanges? + + # Copy exchange fees + all_exchanges = (data.incoming_exchanges || []) + (data.outgoing_exchanges || []) + for exchange in all_exchanges + if exchange.enterprise_fees? + exchange.enterprise_fees = (angular.extend {}, fee for fee in exchange.enterprise_fees) + + data + + removeInactiveExchanges: (order_cycle) -> + order_cycle.incoming_exchanges = + (exchange for exchange in order_cycle.incoming_exchanges when exchange.active) + order_cycle.outgoing_exchanges = + (exchange for exchange in order_cycle.outgoing_exchanges when exchange.active) + order_cycle + + translateCoordinatorFees: (order_cycle) -> + order_cycle.coordinator_fee_ids = (fee.id for fee in order_cycle.coordinator_fees) + delete order_cycle.coordinator_fees + order_cycle + + translateExchangeFees: (order_cycle) -> + for exchange in order_cycle.incoming_exchanges + exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees) + delete exchange.enterprise_fees + for exchange in order_cycle.outgoing_exchanges + exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees) + delete exchange.enterprise_fees + order_cycle + }) + From d8b648d531ff811870bd5802ee70475795f081b2 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 17 Oct 2014 16:51:03 +1100 Subject: [PATCH 04/17] Extract name and timing form from order cycles --- app/views/admin/order_cycles/_form.html.haml | 12 +----------- .../order_cycles/_name_and_timing_form.html.haml | 11 +++++++++++ 2 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 app/views/admin/order_cycles/_name_and_timing_form.html.haml diff --git a/app/views/admin/order_cycles/_form.html.haml b/app/views/admin/order_cycles/_form.html.haml index e859374a3b..82146fabdd 100644 --- a/app/views/admin/order_cycles/_form.html.haml +++ b/app/views/admin/order_cycles/_form.html.haml @@ -1,14 +1,4 @@ -= f.label :name -= f.text_field :name, 'ng-model' => 'order_cycle.name', 'required' => true -%br/ - -.date-field - = f.label :orders_open_at, 'Orders open' - = f.text_field :orders_open_at, 'datetimepicker' => 'order_cycle.orders_open_at', 'ng-model' => 'order_cycle.orders_open_at' -.date-field - = f.label :orders_close_at, 'Orders close' - = f.text_field :orders_close_at, 'datetimepicker' => 'order_cycle.orders_close_at', 'ng-model' => 'order_cycle.orders_close_at' -%br/ += render 'name_and_timing_form', f: f %h2 Incoming diff --git a/app/views/admin/order_cycles/_name_and_timing_form.html.haml b/app/views/admin/order_cycles/_name_and_timing_form.html.haml new file mode 100644 index 0000000000..437a6a44f7 --- /dev/null +++ b/app/views/admin/order_cycles/_name_and_timing_form.html.haml @@ -0,0 +1,11 @@ += f.label :name += f.text_field :name, 'ng-model' => 'order_cycle.name', 'required' => true +%br/ + +.date-field + = f.label :orders_open_at, 'Orders open' + = f.text_field :orders_open_at, 'datetimepicker' => 'order_cycle.orders_open_at', 'ng-model' => 'order_cycle.orders_open_at' +.date-field + = f.label :orders_close_at, 'Orders close' + = f.text_field :orders_close_at, 'datetimepicker' => 'order_cycle.orders_close_at', 'ng-model' => 'order_cycle.orders_close_at' +%br/ From deedafde9ac13b609c0d4b08852e27a89fcd1a09 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 17 Oct 2014 16:55:55 +1100 Subject: [PATCH 05/17] WIP: Simple order cycle form loads and displays correct info --- .../order_cycles/controllers/simple.js.coffee | 27 ++++++++ app/helpers/order_cycles_helper.rb | 2 +- .../admin/order_cycles/_simple_form.html.haml | 18 ++++++ app/views/admin/order_cycles/new.html.haml | 9 ++- spec/features/admin/order_cycles_spec.rb | 64 +++++++++++++++++-- 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee create mode 100644 app/views/admin/order_cycles/_simple_form.html.haml diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee new file mode 100644 index 0000000000..cdc8947f25 --- /dev/null +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee @@ -0,0 +1,27 @@ +angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee) -> + $scope.enterprises = Enterprise.index (enterprises) => + enterprise = enterprises[Object.keys(enterprises)[0]] + OrderCycle.addSupplier enterprise.id + OrderCycle.addDistributor enterprise.id + + OrderCycle.setExchangeVariants(OrderCycle.order_cycle.incoming_exchanges[0], + Enterprise.suppliedVariants(enterprise.id), true) + + OrderCycle.order_cycle.coordinator_id = enterprise.id + + $scope.enterprise_fees = EnterpriseFee.index() + + $scope.order_cycle = OrderCycle.order_cycle + + $scope.loaded = -> + Enterprise.loaded && EnterpriseFee.loaded + + $scope.removeDistributionOfVariant = angular.noop + + $scope.addCoordinatorFee = ($event) -> + $event.preventDefault() + OrderCycle.addCoordinatorFee() + + $scope.enterpriseFeesForEnterprise = (enterprise_id) -> + EnterpriseFee.forEnterprise(parseInt(enterprise_id)) + diff --git a/app/helpers/order_cycles_helper.rb b/app/helpers/order_cycles_helper.rb index 23ac74e944..627d117368 100644 --- a/app/helpers/order_cycles_helper.rb +++ b/app/helpers/order_cycles_helper.rb @@ -63,7 +63,7 @@ module OrderCyclesHelper end def order_cycles_simple_view - !OpenFoodNetwork::Permissions.new(spree_current_user).can_manage_complex_order_cycles? + @order_cycles_simple_view ||= !OpenFoodNetwork::Permissions.new(spree_current_user).can_manage_complex_order_cycles? end def order_cycles_enabled? diff --git a/app/views/admin/order_cycles/_simple_form.html.haml b/app/views/admin/order_cycles/_simple_form.html.haml new file mode 100644 index 0000000000..37f7ab0152 --- /dev/null +++ b/app/views/admin/order_cycles/_simple_form.html.haml @@ -0,0 +1,18 @@ += render 'name_and_timing_form', f: f + += text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'placeholder' => 'Ready for (ie. Date / Time)', 'ng-model' => 'outgoing_exchange.pickup_time' +%br/ += text_field_tag 'order_cycle_outgoing_exchange_0_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_instructions', 'placeholder' => 'Pick-up instructions', 'ng-model' => 'outgoing_exchange.pickup_instructions' + +%div{ng: {repeat: "exchange in order_cycle.incoming_exchanges"}} + = render 'exchange_supplied_products_form' + += render 'coordinator_fees', f: f + +.actions + = f.submit @order_cycle.new_record? ? 'Create' : 'Update', 'ng-disabled' => '!loaded()' + %span{'ng-show' => 'loaded()'} + or + = link_to 'Cancel', main_app.admin_order_cycles_path + %span{'ng-hide' => 'loaded()'} Loading... + diff --git a/app/views/admin/order_cycles/new.html.haml b/app/views/admin/order_cycles/new.html.haml index de1f229258..716e537874 100644 --- a/app/views/admin/order_cycles/new.html.haml +++ b/app/views/admin/order_cycles/new.html.haml @@ -1,4 +1,9 @@ %h1 New Order Cycle -= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => 'AdminCreateOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| - = render 'form', :f => f +- ng_controller = order_cycles_simple_view ? 'AdminSimpleCreateOrderCycleCtrl' : 'AdminCreateOrderCycleCtrl' + += form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => ng_controller, 'ng-submit' => 'submit()'} do |f| + - if order_cycles_simple_view + = render 'simple_form', f: f + - else + = render 'form', f: f diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 354be34671..c579b75f7c 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -131,16 +131,16 @@ feature %q{ page.should have_selector 'td.distributors', text: 'My distributor' # And it should have some fees - OrderCycle.last.exchanges.incoming.first.enterprise_fees.should == [supplier_fee] - OrderCycle.last.coordinator_fees.should == [coordinator_fee] - OrderCycle.last.exchanges.outgoing.first.enterprise_fees.should == [distributor_fee] + oc = OrderCycle.last + oc.exchanges.incoming.first.enterprise_fees.should == [supplier_fee] + oc.coordinator_fees.should == [coordinator_fee] + oc.exchanges.outgoing.first.enterprise_fees.should == [distributor_fee] # And it should have some variants selected - OrderCycle.last.exchanges.first.variants.count.should == 2 - OrderCycle.last.exchanges.last.variants.count.should == 2 + oc.exchanges.first.variants.count.should == 2 + oc.exchanges.last.variants.count.should == 2 # And my pickup time and instructions should have been saved - oc = OrderCycle.last exchange = oc.exchanges.where(:sender_id => oc.coordinator_id).first exchange.pickup_time.should == 'pickup time' exchange.pickup_instructions.should == 'pickup instructions' @@ -575,9 +575,14 @@ feature %q{ end - describe "as an enterprise user selling only my own produce" do + describe "simplified interface for enterprise users selling only their own produce" do let(:user) { create_enterprise_user } let(:enterprise) { create(:enterprise, is_primary_producer: true, sells: 'own') } + let!(:p1) { create(:simple_product, supplier: enterprise) } + let!(:p2) { create(:simple_product, supplier: enterprise) } + let!(:p3) { create(:simple_product, supplier: enterprise) } + let!(:v) { create(:variant, product: p3) } + let!(:fee) { create(:enterprise_fee, enterprise: enterprise, name: 'Coord fee') } use_short_wait @@ -593,6 +598,51 @@ feature %q{ page.should_not have_selector 'th', text: 'COORDINATOR' page.should_not have_selector 'th', text: 'DISTRIBUTORS' end + + it "creates order cycles", js: true do + # When I go to the new order cycle page + visit admin_order_cycles_path + click_link 'New Order Cycle' + + # And I fill in the basic fields + fill_in 'order_cycle_name', with: 'Plums & Avos' + fill_in 'order_cycle_orders_open_at', with: '2014-10-17 06:00:00' + fill_in 'order_cycle_orders_close_at', with: '2014-10-24 17:00:00' + fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'pickup time' + fill_in 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'pickup instructions' + + # Then my products / variants should already be selected + page.should have_checked_field "order_cycle_incoming_exchange_0_variants_#{p1.master.id}" + page.should have_checked_field "order_cycle_incoming_exchange_0_variants_#{p2.master.id}" + page.should have_checked_field "order_cycle_incoming_exchange_0_variants_#{v.id}" + + # When I unselect a product + uncheck "order_cycle_incoming_exchange_0_variants_#{p2.master.id}" + + # And I add a fee and save + click_button 'Add coordinator fee' + select 'Coord fee', from: 'order_cycle_coordinator_fee_0_id' + click_button 'Create' + + # Then my order cycle should have been created + page.should have_content 'Your order cycle has been created.' + page.should have_selector 'a', text: 'Plums & Avos' + page.should have_selector "input[value='2012-11-06 06:00:00 +1100']" + page.should have_selector "input[value='2012-11-13 17:00:00 +1100']" + + # And it should have some variants selected + oc = OrderCycle.last + oc.exchanges.incoming.first.variants.count.should == 2 + oc.exchanges.outgoing.first.variants.count.should == 2 + + # And it should have the fee + oc.coordinator_fees.should == [fee] + + # And my pickup time and instructions should have been saved + ex = oc.exchanges.outgoing.first + ex.pickup_time.should == 'pickup time' + ex.pickup_instructions.should == 'pickup instructions' + end end From 8fb95769bf2550581a122de7d682814b293cd514 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 22 Oct 2014 17:07:45 +1100 Subject: [PATCH 06/17] Fix tested values in spec --- spec/features/admin/order_cycles_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index c579b75f7c..55623bfc18 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -627,8 +627,8 @@ feature %q{ # Then my order cycle should have been created page.should have_content 'Your order cycle has been created.' page.should have_selector 'a', text: 'Plums & Avos' - page.should have_selector "input[value='2012-11-06 06:00:00 +1100']" - page.should have_selector "input[value='2012-11-13 17:00:00 +1100']" + page.should have_selector "input[value='2014-10-17 06:00:00 +1100']" + page.should have_selector "input[value='2014-10-24 17:00:00 +1100']" # And it should have some variants selected oc = OrderCycle.last From 549ef4b79d33b9468fa27188a042c662fd73b2ee Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 22 Oct 2014 17:08:16 +1100 Subject: [PATCH 07/17] When saving an OC from the simple interface, include outgoing variants --- .../admin/order_cycles/controllers/simple.js.coffee | 3 +++ .../admin/order_cycles/services/order_cycle.js.coffee | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee index cdc8947f25..03f4128923 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee @@ -25,3 +25,6 @@ angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl $scope.enterpriseFeesForEnterprise = (enterprise_id) -> EnterpriseFee.forEnterprise(parseInt(enterprise_id)) + $scope.submit = -> + OrderCycle.mirrorIncomingToOutgoingProducts() + OrderCycle.create() diff --git a/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee b/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee index 5e46fdda50..b53c91257e 100644 --- a/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee @@ -164,5 +164,14 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) exchange.enterprise_fee_ids = (fee.id for fee in exchange.enterprise_fees) delete exchange.enterprise_fees order_cycle - }) + # In the simple UI, we don't list outgoing products. Instead, all products are considered + # part of both incoming and outgoing enterprises. This method mirrors the former to the + # latter **for order cycles with a single incoming and outgoing exchange only**. + mirrorIncomingToOutgoingProducts: -> + incoming = this.order_cycle.incoming_exchanges[0] + outgoing = this.order_cycle.outgoing_exchanges[0] + + for id, active of incoming.variants + outgoing.variants[id] = active + }) From 28352be72946015f3c91a8354db528a1eca440ca Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 22 Oct 2014 17:17:05 +1100 Subject: [PATCH 08/17] Save pickup time and instructions --- .../javascripts/admin/order_cycles/controllers/simple.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee index 03f4128923..83f0999b30 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee @@ -3,6 +3,7 @@ angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl enterprise = enterprises[Object.keys(enterprises)[0]] OrderCycle.addSupplier enterprise.id OrderCycle.addDistributor enterprise.id + $scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0] OrderCycle.setExchangeVariants(OrderCycle.order_cycle.incoming_exchanges[0], Enterprise.suppliedVariants(enterprise.id), true) From 3e61aa72677213f5a063f761d5cc38c9212cc7f5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 22 Oct 2014 17:26:22 +1100 Subject: [PATCH 09/17] Simple interface remove coordinator fee --- .../admin/order_cycles/controllers/simple.js.coffee | 4 ++++ spec/features/admin/order_cycles_spec.rb | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee index 83f0999b30..4499cd833b 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee @@ -23,6 +23,10 @@ angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl $event.preventDefault() OrderCycle.addCoordinatorFee() + $scope.removeCoordinatorFee = ($event, index) -> + $event.preventDefault() + OrderCycle.removeCoordinatorFee(index) + $scope.enterpriseFeesForEnterprise = (enterprise_id) -> EnterpriseFee.forEnterprise(parseInt(enterprise_id)) diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 55623bfc18..153f34f4a7 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -621,6 +621,11 @@ feature %q{ # And I add a fee and save click_button 'Add coordinator fee' + click_button 'Add coordinator fee' + click_link 'order_cycle_coordinator_fee_1_remove' + page.should have_select 'order_cycle_coordinator_fee_0_id' + page.should_not have_select 'order_cycle_coordinator_fee_1_id' + select 'Coord fee', from: 'order_cycle_coordinator_fee_0_id' click_button 'Create' From d47db903fb6535010ef6fb54b3cbad5b0b6a47d9 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 22 Oct 2014 19:12:51 +1100 Subject: [PATCH 10/17] Add basic styling to simple order cycle interface --- .../_name_and_timing_form.html.haml | 24 +++++++++++-------- .../admin/order_cycles/_simple_form.html.haml | 18 ++++++++++---- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/app/views/admin/order_cycles/_name_and_timing_form.html.haml b/app/views/admin/order_cycles/_name_and_timing_form.html.haml index 437a6a44f7..ed24d20f39 100644 --- a/app/views/admin/order_cycles/_name_and_timing_form.html.haml +++ b/app/views/admin/order_cycles/_name_and_timing_form.html.haml @@ -1,11 +1,15 @@ -= f.label :name -= f.text_field :name, 'ng-model' => 'order_cycle.name', 'required' => true -%br/ +.row + .alpha.two.columns + = f.label :name + .fourteen.columns.omega + = f.text_field :name, 'ng-model' => 'order_cycle.name', 'required' => true -.date-field - = f.label :orders_open_at, 'Orders open' - = f.text_field :orders_open_at, 'datetimepicker' => 'order_cycle.orders_open_at', 'ng-model' => 'order_cycle.orders_open_at' -.date-field - = f.label :orders_close_at, 'Orders close' - = f.text_field :orders_close_at, 'datetimepicker' => 'order_cycle.orders_close_at', 'ng-model' => 'order_cycle.orders_close_at' -%br/ +.row + .alpha.two.columns + = f.label :orders_open_at, 'Orders open' + .six.columns + = f.text_field :orders_open_at, 'datetimepicker' => 'order_cycle.orders_open_at', 'ng-model' => 'order_cycle.orders_open_at' + .two.columns + = f.label :orders_close_at, 'Orders close' + .six.columns.omega + = f.text_field :orders_close_at, 'datetimepicker' => 'order_cycle.orders_close_at', 'ng-model' => 'order_cycle.orders_close_at' diff --git a/app/views/admin/order_cycles/_simple_form.html.haml b/app/views/admin/order_cycles/_simple_form.html.haml index 37f7ab0152..912631bb37 100644 --- a/app/views/admin/order_cycles/_simple_form.html.haml +++ b/app/views/admin/order_cycles/_simple_form.html.haml @@ -1,11 +1,19 @@ = render 'name_and_timing_form', f: f -= text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'placeholder' => 'Ready for (ie. Date / Time)', 'ng-model' => 'outgoing_exchange.pickup_time' -%br/ -= text_field_tag 'order_cycle_outgoing_exchange_0_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_instructions', 'placeholder' => 'Pick-up instructions', 'ng-model' => 'outgoing_exchange.pickup_instructions' +.row + .alpha.two.columns + = label_tag 'Pickup time' + .six.columns + = text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'placeholder' => 'Ready for (ie. Date / Time)', 'ng-model' => 'outgoing_exchange.pickup_time' + .two.columns + = label_tag 'Pickup instructions' + .six.columns.omega + = text_field_tag 'order_cycle_outgoing_exchange_0_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_instructions', 'placeholder' => 'Pick-up instructions', 'ng-model' => 'outgoing_exchange.pickup_instructions' -%div{ng: {repeat: "exchange in order_cycle.incoming_exchanges"}} - = render 'exchange_supplied_products_form' +%table.exchanges + %tbody{ng: {repeat: "exchange in order_cycle.incoming_exchanges"}} + %tr.products + = render 'exchange_supplied_products_form' = render 'coordinator_fees', f: f From 66e13d40f4267b49828f0f8573be9ba6c2d10ebb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 22 Oct 2014 19:17:28 +1100 Subject: [PATCH 11/17] Select all works on simple order cycles interface --- .../admin/order_cycles/controllers/simple.js.coffee | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee index 4499cd833b..728b27fb4a 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee @@ -19,6 +19,12 @@ angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl $scope.removeDistributionOfVariant = angular.noop + $scope.setExchangeVariants = (exchange, variants, selected) -> + OrderCycle.setExchangeVariants(exchange, variants, selected) + + $scope.suppliedVariants = (enterprise_id) -> + Enterprise.suppliedVariants(enterprise_id) + $scope.addCoordinatorFee = ($event) -> $event.preventDefault() OrderCycle.addCoordinatorFee() From f74ec03cefe3b9002aa4d68b9da5d25d9d2f030f Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 23 Oct 2014 09:26:55 +1100 Subject: [PATCH 12/17] Rename --- .../controllers/{simple.js.coffee => simple_edit.js.coffee} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/admin/order_cycles/controllers/{simple.js.coffee => simple_edit.js.coffee} (100%) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee similarity index 100% rename from app/assets/javascripts/admin/order_cycles/controllers/simple.js.coffee rename to app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee From 2ad823a79d3da5e6140831a4019182b479bf0927 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 23 Oct 2014 09:39:23 +1100 Subject: [PATCH 13/17] Fix JS specs --- spec/javascripts/unit/order_cycle_spec.js.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/javascripts/unit/order_cycle_spec.js.coffee b/spec/javascripts/unit/order_cycle_spec.js.coffee index 2a8d001804..7ecd2b4782 100644 --- a/spec/javascripts/unit/order_cycle_spec.js.coffee +++ b/spec/javascripts/unit/order_cycle_spec.js.coffee @@ -38,7 +38,7 @@ describe 'OrderCycle controllers', -> index: jasmine.createSpy('index').andReturn('enterprise fees list') forEnterprise: jasmine.createSpy('forEnterprise').andReturn('enterprise fees for enterprise') - module('order_cycle') + module('admin.order_cycles') inject ($controller) -> ctrl = $controller 'AdminCreateOrderCycleCtrl', {$scope: scope, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee} @@ -198,7 +198,7 @@ describe 'OrderCycle controllers', -> index: jasmine.createSpy('index').andReturn('enterprise fees list') forEnterprise: jasmine.createSpy('forEnterprise').andReturn('enterprise fees for enterprise') - module('order_cycle') + module('admin.order_cycles') inject ($controller) -> ctrl = $controller 'AdminEditOrderCycleCtrl', {$scope: scope, $location: location, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee} @@ -323,7 +323,7 @@ describe 'OrderCycle services', -> Enterprise = null beforeEach -> - module 'order_cycle' + module 'admin.order_cycles' inject ($injector, _$httpBackend_)-> Enterprise = $injector.get('Enterprise') $httpBackend = _$httpBackend_ @@ -389,7 +389,7 @@ describe 'OrderCycle services', -> EnterpriseFee = null beforeEach -> - module 'order_cycle' + module 'admin.order_cycles' inject ($injector, _$httpBackend_)-> EnterpriseFee = $injector.get('EnterpriseFee') $httpBackend = _$httpBackend_ @@ -431,7 +431,7 @@ describe 'OrderCycle services', -> beforeEach -> $window = {navigator: {userAgent: 'foo'}} - module 'order_cycle', ($provide)-> + module 'admin.order_cycles', ($provide)-> $provide.value('$window', $window) null From 8b616e7d17ebf389ea2d706620758b978542a869 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 23 Oct 2014 10:21:19 +1100 Subject: [PATCH 14/17] Add unit spec for order cycles simple create controller --- .../controllers/simple_edit.js.coffee | 10 ++-- .../controllers/simple_edit.js.coffee | 49 +++++++++++++++++++ 2 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee index 728b27fb4a..e2a60e424e 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee @@ -1,19 +1,21 @@ angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, OrderCycle, Enterprise, EnterpriseFee) -> $scope.enterprises = Enterprise.index (enterprises) => + $scope.init(enterprises) + $scope.enterprise_fees = EnterpriseFee.index() + $scope.order_cycle = OrderCycle.order_cycle + + $scope.init = (enterprises) -> enterprise = enterprises[Object.keys(enterprises)[0]] OrderCycle.addSupplier enterprise.id OrderCycle.addDistributor enterprise.id $scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0] + # All variants start as checked OrderCycle.setExchangeVariants(OrderCycle.order_cycle.incoming_exchanges[0], Enterprise.suppliedVariants(enterprise.id), true) OrderCycle.order_cycle.coordinator_id = enterprise.id - $scope.enterprise_fees = EnterpriseFee.index() - - $scope.order_cycle = OrderCycle.order_cycle - $scope.loaded = -> Enterprise.loaded && EnterpriseFee.loaded diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee new file mode 100644 index 0000000000..bf2498e234 --- /dev/null +++ b/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee @@ -0,0 +1,49 @@ +describe "AdminSimpleCreateOrderCycleCtrl", -> + ctrl = null + scope = {} + OrderCycle = {} + Enterprise = {} + EnterpriseFee = {} + incoming_exchange = {} + outgoing_exchange = {} + + beforeEach -> + scope = {} + OrderCycle = + order_cycle: + incoming_exchanges: [incoming_exchange] + outgoing_exchanges: [outgoing_exchange] + addSupplier: jasmine.createSpy() + addDistributor: jasmine.createSpy() + setExchangeVariants: jasmine.createSpy() + Enterprise = + index: jasmine.createSpy() + suppliedVariants: jasmine.createSpy().andReturn('supplied variants') + EnterpriseFee = + index: jasmine.createSpy() + + module('admin.order_cycles') + inject ($controller) -> + ctrl = $controller 'AdminSimpleCreateOrderCycleCtrl', {$scope: scope, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee} + + describe "initialisation", -> + enterprise = {id: 123} + enterprises = {123: enterprise} + + beforeEach -> + scope.init(enterprises) + + it "sets up an incoming and outgoing exchange", -> + expect(OrderCycle.addSupplier).toHaveBeenCalledWith(enterprise.id) + expect(OrderCycle.addDistributor).toHaveBeenCalledWith(enterprise.id) + expect(scope.outgoing_exchange).toEqual outgoing_exchange + + it "selects all variants", -> + expect(Enterprise.suppliedVariants). + toHaveBeenCalledWith(enterprise.id) + + expect(OrderCycle.setExchangeVariants). + toHaveBeenCalledWith(incoming_exchange, 'supplied variants', true) + + it "sets the coordinator", -> + expect(OrderCycle.order_cycle.coordinator_id).toEqual enterprise.id \ No newline at end of file From 56ebe688dc74b4454b3ad441feaf200b996284da Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 23 Oct 2014 10:22:03 +1100 Subject: [PATCH 15/17] Fix file naming --- .../{simple_edit.js.coffee => simple_create.js.coffee} | 0 .../{simple_edit.js.coffee => simple_create.js.coffee} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/admin/order_cycles/controllers/{simple_edit.js.coffee => simple_create.js.coffee} (100%) rename spec/javascripts/unit/admin/order_cycles/controllers/{simple_edit.js.coffee => simple_create.js.coffee} (100%) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_create.js.coffee similarity index 100% rename from app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee rename to app/assets/javascripts/admin/order_cycles/controllers/simple_create.js.coffee diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/simple_create.js.coffee similarity index 100% rename from spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee rename to spec/javascripts/unit/admin/order_cycles/controllers/simple_create.js.coffee From f7c1340f9945585c49dbf986b1589cc5c5e7e2c6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 23 Oct 2014 11:08:27 +1100 Subject: [PATCH 16/17] Admin can view an order cycle in the simple edit form --- .../controllers/simple_edit.js.coffee | 14 +++++++ .../services/order_cycle.js.coffee | 4 +- app/views/admin/order_cycles/edit.html.haml | 9 ++++- spec/features/admin/order_cycles_spec.rb | 31 +++++++++++++++ .../controllers/simple_edit.js.coffee | 38 +++++++++++++++++++ 5 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee create mode 100644 spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee new file mode 100644 index 0000000000..bceef1b0ef --- /dev/null +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee @@ -0,0 +1,14 @@ +angular.module('admin.order_cycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, OrderCycle, Enterprise, EnterpriseFee) -> + $scope.enterprises = Enterprise.index() + $scope.enterprise_fees = EnterpriseFee.index() + $scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) => + $scope.init() + + $scope.orderCycleId = -> + $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1] + + $scope.init = -> + $scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0] + + $scope.enterpriseFeesForEnterprise = (enterprise_id) -> + EnterpriseFee.forEnterprise(parseInt(enterprise_id)) diff --git a/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee b/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee index b53c91257e..687a0164fa 100644 --- a/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/services/order_cycle.js.coffee @@ -84,7 +84,7 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) for exchange in this.order_cycle.outgoing_exchanges exchange.variants[variant_id] = false - load: (order_cycle_id) -> + load: (order_cycle_id, callback=null) -> service = this OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) -> angular.extend(service.order_cycle, oc) @@ -104,6 +104,8 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window) delete(service.order_cycle.exchanges) service.loaded = true + (callback || angular.noop)(service.order_cycle) + this.order_cycle create: -> diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index b22f0cf51d..ff40cfbbbc 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -1,4 +1,9 @@ %h1 Edit Order Cycle -= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => 'AdminEditOrderCycleCtrl', 'ng-submit' => 'submit()'} do |f| - = render 'form', :f => f +- ng_controller = order_cycles_simple_view ? 'AdminSimpleEditOrderCycleCtrl' : 'AdminEditOrderCycleCtrl' + += form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => ng_controller, 'ng-submit' => 'submit()'} do |f| + - if order_cycles_simple_view + = render 'simple_form', f: f + - else + = render 'form', f: f diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 153f34f4a7..3cff362f56 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -648,6 +648,37 @@ feature %q{ ex.pickup_time.should == 'pickup time' ex.pickup_instructions.should == 'pickup instructions' end + + scenario "editing an order cycle" do + # Given an order cycle + fee = create(:enterprise_fee, name: 'my fee', enterprise: enterprise) + oc = create(:simple_order_cycle, suppliers: [enterprise], coordinator: enterprise, distributors: [enterprise], variants: [p1.master], coordinator_fees: [fee]) + + # And the order cycle has a pickup time and pickup instructions + ex = oc.exchanges.outgoing.first + ex.update_attributes! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' + + # When I edit it + login_to_admin_section + click_link 'Order Cycles' + click_link oc.name + wait_until { page.find('#order_cycle_name').value.present? } + + # Then I should see the basic settings + page.should have_field 'order_cycle_name', with: oc.name + page.should have_field 'order_cycle_orders_open_at', with: oc.orders_open_at.to_s + page.should have_field 'order_cycle_orders_close_at', with: oc.orders_close_at.to_s + page.should have_field 'order_cycle_outgoing_exchange_0_pickup_time', with: 'pickup time' + page.should have_field 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'pickup instructions' + + # And I should see the products + page.should have_checked_field "order_cycle_incoming_exchange_0_variants_#{p1.master.id}" + page.should have_unchecked_field "order_cycle_incoming_exchange_0_variants_#{p2.master.id}" + page.should have_unchecked_field "order_cycle_incoming_exchange_0_variants_#{v.id}" + + # And I should see the coordinator fees + page.should have_select 'order_cycle_coordinator_fee_0_id', selected: 'my fee' + end end diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee new file mode 100644 index 0000000000..0e3275d886 --- /dev/null +++ b/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee @@ -0,0 +1,38 @@ +describe "AdminSimpleEditOrderCycleCtrl", -> + ctrl = null + scope = {} + location = {} + OrderCycle = {} + Enterprise = {} + EnterpriseFee = {} + incoming_exchange = {} + outgoing_exchange = {} + + beforeEach -> + scope = {} + location = + absUrl: -> + 'example.com/admin/order_cycles/27/edit' + OrderCycle = + order_cycle: + incoming_exchanges: [incoming_exchange] + outgoing_exchanges: [outgoing_exchange] + load: jasmine.createSpy() + Enterprise = + index: jasmine.createSpy() + EnterpriseFee = + index: jasmine.createSpy() + + module('admin.order_cycles') + inject ($controller) -> + ctrl = $controller 'AdminSimpleEditOrderCycleCtrl', {$scope: scope, $location: location, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee} + + describe "initialisation", -> + enterprise = {id: 123} + enterprises = {123: enterprise} + + beforeEach -> + scope.init(enterprises) + + it "sets the outgoing exchange", -> + expect(scope.outgoing_exchange).toEqual outgoing_exchange From ab76c66b6837005ee0858772bc76fb5e2955b3a6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 23 Oct 2014 11:38:15 +1100 Subject: [PATCH 17/17] Admin can update order cycles with simple interface --- .../controllers/simple_edit.js.coffee | 21 ++++++- spec/features/admin/order_cycles_spec.rb | 58 ++++++++++++++++++- 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee index bceef1b0ef..512bc0460b 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee @@ -1,14 +1,31 @@ angular.module('admin.order_cycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, OrderCycle, Enterprise, EnterpriseFee) -> + $scope.orderCycleId = -> + $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1] + $scope.enterprises = Enterprise.index() $scope.enterprise_fees = EnterpriseFee.index() $scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) => $scope.init() - $scope.orderCycleId = -> - $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1] + $scope.loaded = -> + Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded $scope.init = -> $scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0] $scope.enterpriseFeesForEnterprise = (enterprise_id) -> EnterpriseFee.forEnterprise(parseInt(enterprise_id)) + + $scope.removeDistributionOfVariant = angular.noop + + $scope.addCoordinatorFee = ($event) -> + $event.preventDefault() + OrderCycle.addCoordinatorFee() + + $scope.removeCoordinatorFee = ($event, index) -> + $event.preventDefault() + OrderCycle.removeCoordinatorFee(index) + + $scope.submit = -> + OrderCycle.mirrorIncomingToOutgoingProducts() + OrderCycle.update() diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 3cff362f56..56f3b62916 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -650,11 +650,9 @@ feature %q{ end scenario "editing an order cycle" do - # Given an order cycle + # Given an order cycle with pickup time and instructions fee = create(:enterprise_fee, name: 'my fee', enterprise: enterprise) oc = create(:simple_order_cycle, suppliers: [enterprise], coordinator: enterprise, distributors: [enterprise], variants: [p1.master], coordinator_fees: [fee]) - - # And the order cycle has a pickup time and pickup instructions ex = oc.exchanges.outgoing.first ex.update_attributes! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' @@ -679,6 +677,60 @@ feature %q{ # And I should see the coordinator fees page.should have_select 'order_cycle_coordinator_fee_0_id', selected: 'my fee' end + + scenario "updating an order cycle" do + # Given an order cycle with pickup time and instructions + fee1 = create(:enterprise_fee, name: 'my fee', enterprise: enterprise) + fee2 = create(:enterprise_fee, name: 'that fee', enterprise: enterprise) + oc = create(:simple_order_cycle, suppliers: [enterprise], coordinator: enterprise, distributors: [enterprise], variants: [p1.master], coordinator_fees: [fee1]) + ex = oc.exchanges.outgoing.first + ex.update_attributes! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' + + # When I edit it + login_to_admin_section + visit edit_admin_order_cycle_path oc + wait_until { page.find('#order_cycle_name').value.present? } + + # And I fill in the basic fields + fill_in 'order_cycle_name', with: 'Plums & Avos' + fill_in 'order_cycle_orders_open_at', with: '2014-10-17 06:00:00' + fill_in 'order_cycle_orders_close_at', with: '2014-10-24 17:00:00' + fill_in 'order_cycle_outgoing_exchange_0_pickup_time', with: 'xy' + fill_in 'order_cycle_outgoing_exchange_0_pickup_instructions', with: 'zzy' + + # And I make some product selections + uncheck "order_cycle_incoming_exchange_0_variants_#{p1.master.id}" + check "order_cycle_incoming_exchange_0_variants_#{p2.master.id}" + check "order_cycle_incoming_exchange_0_variants_#{v.id}" + uncheck "order_cycle_incoming_exchange_0_variants_#{v.id}" + + # And I select some fees and update + click_link 'order_cycle_coordinator_fee_0_remove' + page.should_not have_select 'order_cycle_coordinator_fee_0_id' + click_button 'Add coordinator fee' + select 'that fee', from: 'order_cycle_coordinator_fee_0_id' + + click_button 'Update' + + # Then my order cycle should have been updated + page.should have_content 'Your order cycle has been updated.' + page.should have_selector 'a', text: 'Plums & Avos' + page.should have_selector "input[value='2014-10-17 06:00:00 +1100']" + page.should have_selector "input[value='2014-10-24 17:00:00 +1100']" + + # And it should have a variant selected + oc = OrderCycle.last + oc.exchanges.incoming.first.variants.should == [p2.master] + oc.exchanges.outgoing.first.variants.should == [p2.master] + + # And it should have the fee + oc.coordinator_fees.should == [fee2] + + # And my pickup time and instructions should have been saved + ex = oc.exchanges.outgoing.first + ex.pickup_time.should == 'xy' + ex.pickup_instructions.should == 'zzy' + end end