mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-04 02:31:33 +00:00
Merge branch 'master' of github.com:openfoodfoundation/openfoodnetwork into bulk-product-edit
This commit is contained in:
10
Gemfile.lock
10
Gemfile.lock
@@ -23,7 +23,7 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree.git
|
||||
revision: 4e0075b07acb56864aca89eee3d9670136176c23
|
||||
revision: afcc23e489eb604a3e2651598a7c8364e2acc7b3
|
||||
branch: 1-3-stable
|
||||
specs:
|
||||
spree (1.3.6.beta)
|
||||
@@ -123,7 +123,7 @@ GEM
|
||||
active_link_to (1.0.0)
|
||||
active_model_serializers (0.8.1)
|
||||
activemodel (>= 3.0)
|
||||
activemerchant (1.46.0)
|
||||
activemerchant (1.48.0)
|
||||
activesupport (>= 3.2.14, < 5.0.0)
|
||||
builder (>= 2.1.2, < 4.0.0)
|
||||
i18n (>= 0.6.9)
|
||||
@@ -181,7 +181,7 @@ GEM
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cliver (0.3.2)
|
||||
cocaine (0.5.5)
|
||||
cocaine (0.5.7)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.0.9)
|
||||
coffee-rails (3.2.2)
|
||||
@@ -191,7 +191,7 @@ GEM
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.3.3)
|
||||
colorize (0.7.5)
|
||||
colorize (0.7.7)
|
||||
columnize (0.3.6)
|
||||
comfortable_mexican_sofa (1.6.24)
|
||||
active_link_to (~> 1.0.0)
|
||||
@@ -496,7 +496,7 @@ GEM
|
||||
sprockets (>= 2.0.0)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.43)
|
||||
tzinfo (0.3.44)
|
||||
uglifier (1.2.4)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (>= 1.0.2)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
[](https://buildkite.com/open-food-foundation/open-food-network)
|
||||
[](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork)
|
||||
|
||||
# Open Food Network
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
"$scope", "$http", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
|
||||
($scope, $http, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
|
||||
"$scope", "$http", "$filter", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
|
||||
($scope, $http, $filter, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
|
||||
$scope.loading = true
|
||||
|
||||
$scope.initialiseVariables = ->
|
||||
@@ -42,13 +42,15 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
if $scope.spree_api_key_ok
|
||||
$http.defaults.headers.common["X-Spree-Token"] = SpreeApiKey
|
||||
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
|
||||
$scope.suppliers = data
|
||||
$scope.suppliers = $filter('orderBy')(data, 'name')
|
||||
$scope.suppliers.unshift blankOption()
|
||||
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_distributor_eq]=true").then (data) ->
|
||||
$scope.distributors = data
|
||||
dataFetcher("/api/enterprises/accessible?template=bulk_index&q[sells_in][]=own&q[sells_in][]=any").then (data) ->
|
||||
$scope.distributors = $filter('orderBy')(data, 'name')
|
||||
$scope.distributors.unshift blankOption()
|
||||
ocFetcher = dataFetcher("/api/order_cycles/accessible").then (data) ->
|
||||
ocFetcher = dataFetcher("/api/order_cycles/accessible?as=distributor&q[orders_close_at_gt]=#{formatDate(daysFromToday(-90))}").then (data) ->
|
||||
$scope.orderCycles = data
|
||||
$scope.orderCyclesByID = []
|
||||
$scope.orderCyclesByID[oc.id] = oc for oc in $scope.orderCycles
|
||||
$scope.orderCycles.unshift blankOption()
|
||||
$scope.fetchOrders()
|
||||
ocFetcher.then ->
|
||||
@@ -60,7 +62,7 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
|
||||
$scope.fetchOrders = ->
|
||||
$scope.loading = true
|
||||
dataFetcher("/api/orders/managed?template=bulk_index;page=1;per_page=500;q[completed_at_not_null]=true;q[completed_at_gt]=#{$scope.startDate};q[completed_at_lt]=#{$scope.endDate}").then (data) ->
|
||||
dataFetcher("/api/orders/managed?template=bulk_index;page=1;per_page=500;q[state_not_eq]=canceled;q[completed_at_not_null]=true;q[completed_at_gt]=#{$scope.startDate};q[completed_at_lt]=#{$scope.endDate}").then (data) ->
|
||||
$scope.resetOrders data
|
||||
$scope.loading = false
|
||||
|
||||
@@ -162,6 +164,11 @@ angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
|
||||
$scope.supplierFilter = $scope.suppliers[0].id
|
||||
$scope.orderCycleFilter = $scope.orderCycles[0].id
|
||||
$scope.quickSearch = ""
|
||||
|
||||
$scope.$watch "orderCycleFilter", (newVal, oldVal) ->
|
||||
unless $scope.orderCycleFilter == "0" || angular.equals(newVal, oldVal)
|
||||
$scope.startDate = $scope.orderCyclesByID[$scope.orderCycleFilter].first_order
|
||||
$scope.endDate = $scope.orderCyclesByID[$scope.orderCycleFilter].last_order
|
||||
]
|
||||
|
||||
daysFromToday = (days) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%div{ style: "display: inline-block" }
|
||||
%active-selector{ ng: { repeat: "selector in selectors()", show: "ifDefined(selector.fits, true)" } }
|
||||
%div{bindonce:true, style: "display: inline-block" }
|
||||
%active-selector{ ng: { repeat: "selector in allSelectors", show: "ifDefined(selector.fits, true)" } }
|
||||
%render-svg{path: "{{selector.object.icon}}", ng: { if: "selector.object.icon"} }
|
||||
%span {{ selector.object.name }}
|
||||
%span{"bo-text" => "selector.object.name"}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
%div.contact-container{bindonce: true}
|
||||
%div.modal-centered{"bo-if" => "enterprise.email || enterprise.website || enterprise.phone"}
|
||||
%p.modal-header Contact
|
||||
%p{"ng-if" => "enterprise.phone"}
|
||||
{{ enterprise.phone }}
|
||||
%p{"bo-if" => "enterprise.phone", "bo-text" => "enterprise.phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.email"}
|
||||
%a{"ng-href" => "{{enterprise.email | stripUrl}}", target: "_blank", mailto: true}
|
||||
%span.email
|
||||
{{ enterprise.email | stripUrl }}
|
||||
%a{"bo-href" => "enterprise.email | stripUrl", target: "_blank", mailto: true}
|
||||
%span.email{"bo-bind" => "enterprise.email | stripUrl"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "enterprise.website"}
|
||||
%a{"ng-href" => "http://{{enterprise.website | stripUrl}}", target: "_blank" }
|
||||
{{ enterprise.website | stripUrl }}
|
||||
%a{"bo-href-i" => "http://{{enterprise.website | stripUrl}}", target: "_blank", "bo-bind" => "enterprise.website | stripUrl"}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
.highlight{"ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
|
||||
.highlight{bindonce: true, "ng-class" => "{'is_distributor' : enterprise.is_distributor}"}
|
||||
.highlight-top.row
|
||||
.small-12.medium-7.large-8.columns
|
||||
%h3{"ng-if" => "enterprise.is_distributor"}
|
||||
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise", bindonce: true}
|
||||
%a{"bo-href" => "enterprise.path", "ofn-empties-cart" => "enterprise"}
|
||||
%i{"ng-class" => "enterprise.icon_font"}
|
||||
%span {{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
%h3{"ng-if" => "!enterprise.is_distributor", "ng-class" => "{'is_producer' : enterprise.is_primary_producer}"}
|
||||
%i{"ng-class" => "enterprise.icon_font"}
|
||||
%span {{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
.small-12.medium-5.large-4.columns.text-right.small-only-text-left
|
||||
%p {{ [enterprise.address.city, enterprise.address.state_name] | printArray}}
|
||||
%img.hero-img{"ng-src" => "{{enterprise.promo_image}}"}
|
||||
%p{"bo-bind" => "[enterprise.address.city, enterprise.address.state_name] | printArray"}
|
||||
%img.hero-img{"bo-src" => "enterprise.promo_image"}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
%div.modal-centered{"ng-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%div.modal-centered{bindonce: true, "bo-if" => "enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||
%p.modal-header Follow
|
||||
.follow-icons{bindonce: true}
|
||||
%span{"ng-if" => "enterprise.twitter"}
|
||||
%a{"ng-href" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
.follow-icons
|
||||
%span{"bo-if" => "enterprise.twitter"}
|
||||
%a{"bo-href-i" => "http://twitter.com/{{enterprise.twitter}}", target: "_blank"}
|
||||
%i.ofn-i_041-twitter
|
||||
|
||||
%span{"ng-if" => "enterprise.facebook"}
|
||||
%a{"ng-href" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.facebook"}
|
||||
%a{"bo-href-i" => "http://{{enterprise.facebook | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_044-facebook
|
||||
|
||||
%span{"ng-if" => "enterprise.linkedin"}
|
||||
%a{"ng-href" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.linkedin"}
|
||||
%a{"bo-href-i" => "http://{{enterprise.linkedin | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_042-linkedin
|
||||
|
||||
%span{"ng-if" => "enterprise.instagram"}
|
||||
%a{"ng-href" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%span{"bo-if" => "enterprise.instagram"}
|
||||
%a{"bo-href-i" => "http://instagram.com/{{enterprise.instagram}}", target: "_blank"}
|
||||
%i.ofn-i_043-instagram
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
.cta-container.small-12.columns
|
||||
%label
|
||||
Shop for
|
||||
%strong {{enterprise.name}}
|
||||
%strong{"bo-text" => "enterprise.name"}
|
||||
products at:
|
||||
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs",
|
||||
"bo-href" => "hub.path",
|
||||
@@ -10,7 +10,7 @@
|
||||
"ofn-empties-cart" => "hub"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "hub.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!hub.active"}
|
||||
.hub-name {{hub.name}}
|
||||
.button-address {{ hub.address.city }} , {{hub.address.state_name}}
|
||||
.hub-name{"bo-text" => "hub.name"}
|
||||
.button-address{"bo-bind" => "[hub.address.city, hub.address.state_name] | printArray"}
|
||||
/ %i.ofn-i_007-caret-right
|
||||
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
"ofn-empties-cart" => "enterprise"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "enterprise.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!enterprise.active"}
|
||||
.hub-name {{enterprise.name}}
|
||||
.button-address {{ enterprise.address.city }} , {{enterprise.address.state_name}}
|
||||
.hub-name{"bo-text" => "enterprise.name"}
|
||||
.button-address{"bo-bind" => "[enterprise.address.city, enterprise.address.state_name] | printArray"}
|
||||
/ %i.ofn-i_007-caret-right
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
.row
|
||||
.row{bindonce: true}
|
||||
|
||||
.columns.small-12.large-6.product-header
|
||||
%h3 {{product.name}}
|
||||
%h3{"bo-text" => "product.name"}
|
||||
%span
|
||||
%em from
|
||||
%span.avenir {{ enterprise.name }}
|
||||
%span.avenir{"bo-text" => "enterprise.name"}
|
||||
|
||||
%br
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
%div{"ng-if" => "product.description"}
|
||||
%hr
|
||||
%p.text-small {{product.description}}
|
||||
%p.text-small{"bo-text" => "product.description"}
|
||||
%hr
|
||||
|
||||
.columns.small-12.large-6
|
||||
%img.product-img{"ng-src" => "{{product.largeImage}}", "ng-if" => "product.largeImage"}
|
||||
%img.product-img.placeholder{"ng-src" => "/assets/noimage/large.png", "ng-if" => "!product.largeImage"}
|
||||
%img.product-img{"bo-src" => "product.largeImage", "bo-if" => "product.largeImage"}
|
||||
%img.product-img.placeholder{"bo-src" => "'/assets/noimage/large.png'", "bo-if" => "!product.largeImage"}
|
||||
|
||||
%ng-include{src: "'partials/close.html'"}
|
||||
|
||||
3
app/assets/stylesheets/admin/icons.css.scss
Normal file
3
app/assets/stylesheets/admin/icons.css.scss
Normal file
@@ -0,0 +1,3 @@
|
||||
@import 'plugins/font-awesome';
|
||||
|
||||
.icon-refund:before { @extend .icon-ok:before }
|
||||
@@ -13,7 +13,8 @@ module Api
|
||||
end
|
||||
|
||||
def accessible
|
||||
@enterprises = Enterprise.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
permitted = OpenFoodNetwork::Permissions.new(current_api_user).order_cycle_enterprises
|
||||
@enterprises = permitted.ransack(params[:q]).result
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
|
||||
|
||||
@@ -9,7 +9,16 @@ module Api
|
||||
end
|
||||
|
||||
def accessible
|
||||
@order_cycles = OrderCycle.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
@order_cycles = if params[:as] == "distributor"
|
||||
OrderCycle.ransack(params[:q]).result.
|
||||
involving_managed_distributors_of(current_api_user).order('updated_at DESC')
|
||||
elsif params[:as] == "producer"
|
||||
OrderCycle.ransack(params[:q]).result.
|
||||
involving_managed_producers_of(current_api_user).order('updated_at DESC')
|
||||
else
|
||||
OrderCycle.ransack(params[:q]).result.accessible_by(current_api_user)
|
||||
end
|
||||
|
||||
render params[:template] || :bulk_index
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Spree::Admin::LineItemsController.class_eval do
|
||||
private
|
||||
|
||||
def load_order
|
||||
@order = Spree::Order.find_by_number!(params[:order_id])
|
||||
authorize! :update, @order
|
||||
end
|
||||
end
|
||||
@@ -323,7 +323,7 @@ Spree::Admin::ReportsController.class_eval do
|
||||
sort_by: proc { |payment_state| payment_state } },
|
||||
{ group_by: proc { |payment| payment.order.distributor },
|
||||
sort_by: proc { |distributor| distributor.name } },
|
||||
{ group_by: proc { |payment| payment.payment_method },
|
||||
{ group_by: proc { |payment| Spree::PaymentMethod.unscoped { payment.payment_method } },
|
||||
sort_by: proc { |method| method.name } } ]
|
||||
|
||||
when "itemised_payment_totals"
|
||||
@@ -406,27 +406,34 @@ Spree::Admin::ReportsController.class_eval do
|
||||
end
|
||||
params[:q][:meta_sort] ||= "completed_at.desc"
|
||||
|
||||
# -- Search
|
||||
@search = Spree::Order.complete.not_state(:canceled).managed_by(spree_current_user).search(params[:q])
|
||||
orders = @search.result
|
||||
@line_items = orders.map do |o|
|
||||
lis = o.line_items.managed_by(spree_current_user)
|
||||
lis = lis.supplied_by_any(params[:supplier_id_in]) if params[:supplier_id_in].present?
|
||||
lis
|
||||
end.flatten
|
||||
#payments = orders.map { |o| o.payments.select { |payment| payment.completed? } }.flatten # Only select completed payments
|
||||
permissions = OpenFoodNetwork::Permissions.new(spree_current_user)
|
||||
|
||||
# -- Prepare form options
|
||||
my_distributors = Enterprise.is_distributor.managed_by(spree_current_user)
|
||||
my_suppliers = Enterprise.is_primary_producer.managed_by(spree_current_user)
|
||||
# -- Search
|
||||
|
||||
@search = Spree::Order.complete.not_state(:canceled).search(params[:q])
|
||||
orders = permissions.visible_orders.merge(@search.result)
|
||||
|
||||
@line_items = permissions.visible_line_items.merge(Spree::LineItem.where(order_id: orders))
|
||||
@line_items = @line_items.supplied_by_any(params[:supplier_id_in]) if params[:supplier_id_in].present?
|
||||
|
||||
line_items_with_hidden_details = @line_items.where('"spree_line_items"."id" NOT IN (?)', permissions.editable_line_items)
|
||||
@line_items.select{ |li| line_items_with_hidden_details.include? li }.each do |line_item|
|
||||
# TODO We should really be hiding customer code here too, but until we
|
||||
# have an actual association between order and customer, it's a bit tricky
|
||||
line_item.order.bill_address.assign_attributes(firstname: "HIDDEN", lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
|
||||
line_item.order.ship_address.assign_attributes(firstname: "HIDDEN", lastname: "", phone: "", address1: "", address2: "", city: "", zipcode: "", state: nil)
|
||||
line_item.order.assign_attributes(email: "HIDDEN")
|
||||
end
|
||||
|
||||
# My distributors and any distributors distributing products I supply
|
||||
@distributors = my_distributors | Enterprise.with_distributed_products_outer.merge(Spree::Product.in_any_supplier(my_suppliers))
|
||||
@distributors = permissions.visible_enterprises_for_order_reports.is_distributor
|
||||
|
||||
# My suppliers and any suppliers supplying products I distribute
|
||||
@suppliers = my_suppliers | my_distributors.map { |d| Spree::Product.in_distributor(d) }.flatten.map(&:supplier).uniq
|
||||
@suppliers = permissions.visible_enterprises_for_order_reports.is_primary_producer
|
||||
|
||||
@order_cycles = OrderCycle.active_or_complete.
|
||||
involving_managed_distributors_of(spree_current_user).order('orders_close_at DESC')
|
||||
|
||||
@order_cycles = OrderCycle.active_or_complete.accessible_by(spree_current_user).order('orders_close_at DESC')
|
||||
@report_types = REPORT_TYPES[:orders_and_fulfillment]
|
||||
@report_type = params[:report_type]
|
||||
|
||||
|
||||
@@ -162,17 +162,6 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
}
|
||||
|
||||
# Return enterprises that participate in order cycles that user coordinates, sends to or receives from
|
||||
scope :accessible_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
scoped
|
||||
else
|
||||
with_order_cycles_outer.
|
||||
where('order_cycles.id IN (?)', OrderCycle.accessible_by(user)).
|
||||
select('DISTINCT enterprises.*')
|
||||
end
|
||||
}
|
||||
|
||||
def self.find_near(suburb)
|
||||
enterprises = []
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class OrderCycle < ActiveRecord::Base
|
||||
closed.
|
||||
where("order_cycles.orders_close_at >= ?", 31.days.ago).
|
||||
order("order_cycles.orders_close_at DESC") }
|
||||
|
||||
|
||||
scope :soonest_opening, lambda { upcoming.order('order_cycles.orders_open_at ASC') }
|
||||
|
||||
scope :distributing_product, lambda { |product|
|
||||
@@ -64,6 +64,23 @@ class OrderCycle < ActiveRecord::Base
|
||||
joins('LEFT OUTER JOIN enterprises ON (enterprises.id = exchanges.sender_id OR enterprises.id = exchanges.receiver_id)')
|
||||
}
|
||||
|
||||
scope :involving_managed_distributors_of, lambda { |user|
|
||||
enterprises = Enterprise.managed_by(user)
|
||||
|
||||
# Order cycles where I managed an enterprise at either end of an outgoing exchange
|
||||
# ie. coordinator or distibutor
|
||||
joins(:exchanges).merge(Exchange.outgoing).
|
||||
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises)
|
||||
}
|
||||
|
||||
scope :involving_managed_producers_of, lambda { |user|
|
||||
enterprises = Enterprise.managed_by(user)
|
||||
|
||||
# Order cycles where I managed an enterprise at either end of an incoming exchange
|
||||
# ie. coordinator or producer
|
||||
joins(:exchanges).merge(Exchange.incoming).
|
||||
where('exchanges.receiver_id IN (?) OR exchanges.sender_id IN (?)', enterprises, enterprises)
|
||||
}
|
||||
|
||||
def self.first_opening_for(distributor)
|
||||
with_distributor(distributor).soonest_opening.first
|
||||
|
||||
@@ -120,7 +120,7 @@ class AbilityDecorator
|
||||
can [:admin, :index, :read, :create, :edit], Spree::Classification
|
||||
|
||||
# Reports page
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory], :report
|
||||
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report
|
||||
end
|
||||
|
||||
def add_order_cycle_management_abilities(user)
|
||||
@@ -144,11 +144,27 @@ class AbilityDecorator
|
||||
end
|
||||
can [:admin, :bulk_management], Spree::Order if user.admin? || user.enterprises.any?(&:is_distributor)
|
||||
can [:admin, :create], Spree::LineItem
|
||||
can [:destroy], Spree::LineItem do |item|
|
||||
user.admin? || user.enterprises.include?(order.distributor) || user == order.order_cycle.manager
|
||||
end
|
||||
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Payment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Shipment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::Adjustment
|
||||
can [:admin, :index, :read, :create, :edit, :update, :fire], Spree::ReturnAuthorization
|
||||
can [:destroy], Spree::Adjustment do |adjustment|
|
||||
# Sharing code with destroying a line item. This should be unified and probably applied for other actions as well.
|
||||
binding.pry
|
||||
if user.admin?
|
||||
true
|
||||
elsif adjustment.adjustable.instance_of? Spree::Order
|
||||
order = adjustment.adjustable
|
||||
user.enterprises.include?(order.distributor) || user == order.order_cycle.manager
|
||||
elsif adjustment.adjustable.instance_of? Spree::LineItem
|
||||
order = adjustment.adjustable.order
|
||||
user.enterprises.include?(order.distributor) || user == order.order_cycle.manager
|
||||
end
|
||||
end
|
||||
|
||||
can [:create], OrderCycle
|
||||
|
||||
|
||||
52
app/models/spree/payment_decorator.rb
Normal file
52
app/models/spree/payment_decorator.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module Spree
|
||||
Payment.class_eval do
|
||||
# Pin payments lacks void and credit methods, but it does have refund
|
||||
# Here we swap credit out for refund and remove void as a possible action
|
||||
def actions_with_pin_payment_adaptations
|
||||
actions = actions_without_pin_payment_adaptations
|
||||
if payment_method.is_a? Gateway::Pin
|
||||
actions << 'refund' if actions.include? 'credit'
|
||||
actions.reject! { |a| ['credit', 'void'].include? a }
|
||||
end
|
||||
actions
|
||||
end
|
||||
alias_method_chain :actions, :pin_payment_adaptations
|
||||
|
||||
|
||||
def refund!(refund_amount=nil)
|
||||
protect_from_connection_error do
|
||||
check_environment
|
||||
|
||||
refund_amount = calculate_refund_amount(refund_amount)
|
||||
|
||||
if payment_method.payment_profiles_supported?
|
||||
response = payment_method.refund((refund_amount * 100).round, source, response_code, gateway_options)
|
||||
else
|
||||
response = payment_method.refund((refund_amount * 100).round, response_code, gateway_options)
|
||||
end
|
||||
|
||||
record_response(response)
|
||||
|
||||
if response.success?
|
||||
self.class.create({ :order => order,
|
||||
:source => self,
|
||||
:payment_method => payment_method,
|
||||
:amount => refund_amount.abs * -1,
|
||||
:response_code => response.authorization,
|
||||
:state => 'completed' }, :without_protection => true)
|
||||
else
|
||||
gateway_error(response)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def calculate_refund_amount(refund_amount=nil)
|
||||
refund_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
|
||||
refund_amount.to_f
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,9 @@
|
||||
Spree.user_class.class_eval do
|
||||
handle_asynchronously :send_reset_password_instructions
|
||||
if method_defined? :send_reset_password_instructions_with_delay
|
||||
Bugsnag.notify RuntimeError.new "send_reset_password_instructions already handled asyncronously - double-calling results in infinite job loop"
|
||||
else
|
||||
handle_asynchronously :send_reset_password_instructions
|
||||
end
|
||||
|
||||
has_many :enterprise_roles, :dependent => :destroy
|
||||
has_many :enterprises, through: :enterprise_roles
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/ replace "code[erb-loud]:contains('button t(:update)')"
|
||||
|
||||
= button t(:update_and_recalculate_fees), 'icon-refresh'
|
||||
@@ -1,9 +1,11 @@
|
||||
object @order_cycle
|
||||
|
||||
attributes :id, :name
|
||||
node( :first_order ) { |order| order.orders_open_at.strftime("%F") }
|
||||
node( :last_order ) { |order| (order.orders_close_at + 1.day).strftime("%F") }
|
||||
node( :suppliers ) do |oc|
|
||||
partial 'api/enterprises/bulk_index', :object => oc.suppliers
|
||||
end
|
||||
node( :distributors ) do |oc|
|
||||
partial 'api/enterprises/bulk_index', :object => oc.distributors
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,13 +20,11 @@
|
||||
.row.pad-top{bindonce: true}
|
||||
.small-12.medium-6.columns
|
||||
.groups-header
|
||||
%a{"ng-href" => "/groups/{{group.id}}"}
|
||||
%a{"bo-href-i" => "/groups/{{group.id}}"}
|
||||
%i.ofn-i_035-groups
|
||||
%span.group-name
|
||||
{{ group.name }}
|
||||
%span.group-name{"bo-text" => "group.name"}
|
||||
.small-3.medium-2.columns
|
||||
%p
|
||||
{{ group.state }}
|
||||
%p{"bo-text" => "group.state"}
|
||||
.small-9.medium-4.columns.groups-icons
|
||||
%p
|
||||
%link-to-service.ofn-i_050-mail-circle{service: '""', ref: 'group.email.split("").reverse().join("")', mailto: true}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
.trans-sentence
|
||||
%span.fat-taxons{"ng-repeat" => "taxon in hub.taxons"}
|
||||
%render-svg{path: "{{taxon.icon}}"}
|
||||
{{taxon.name}}
|
||||
%span{"bo-text" => "taxon.name"}
|
||||
%div.show-for-medium-up{"bo-if" => "hub.taxons.length==0"}
|
||||
|
||||
.columns.small-12.medium-3.large-2.fat
|
||||
@@ -25,7 +25,6 @@
|
||||
%li{"ng-repeat" => "enterprise in hub.producers"}
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
%span
|
||||
{{ enterprise.name }}
|
||||
%span{"bo-text" => "enterprise.name"}
|
||||
%div.show-for-medium-up{"bo-if" => "hub.producers.length==0"}
|
||||
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
|
||||
.columns.small-12.medium-6.large-5.skinny-head
|
||||
%a.hub{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
%i{ng: {class: "hub.icon_font"}}
|
||||
%span.margin-top.hub-name-listing {{ hub.name | truncate:40}}
|
||||
%i{bo: {class: "hub.icon_font"}}
|
||||
%span.margin-top.hub-name-listing{"bo-bind" => "hub.name | truncate:40"}
|
||||
|
||||
.columns.small-4.medium-2.large-2
|
||||
%span.margin-top {{ hub.address.city }}
|
||||
%span.margin-top{"bo-text" => "hub.address.city"}
|
||||
.columns.small-2.medium-1.large-1
|
||||
%span.margin-top {{ hub.address.state_name | uppercase }}
|
||||
%span.margin-top{"bo-bind" => "hub.address.state_name | uppercase"}
|
||||
|
||||
.columns.small-6.medium-3.large-4.text-right{"bo-if" => "hub.active"}
|
||||
%a.hub.open_closed{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
%i.ofn-i_033-open-sign
|
||||
%span.margin-top{ bo: { if: "current()" } }
|
||||
%em Shopping here
|
||||
%span.margin-top{ bo: { if: "!current()" } } {{ hub.orders_close_at | sensible_timeframe }}
|
||||
%span.margin-top{ bo: { if: "!current()" } }
|
||||
%span{"bo-bind" => "hub.orders_close_at | sensible_timeframe"}
|
||||
|
||||
.columns.small-6.medium-3.large-4.text-right{"bo-if" => "!hub.active"}
|
||||
%a.hub.open_closed{"bo-href" => "hub.path", "ng-class" => "{primary: hub.active, secondary: !hub.active}", "ofn-empties-cart" => "hub"}
|
||||
@@ -28,12 +29,12 @@
|
||||
.columns.small-12.medium-6.large-5.skinny-head
|
||||
%a.hub{"ng-click" => "openModal(hub)", "ng-class" => "{primary: hub.active, secondary: !hub.active}"}
|
||||
%i{ng: {class: "hub.icon_font"}}
|
||||
%span.margin-top.hub-name-listing {{ hub.name | truncate:40}}
|
||||
%span.margin-top.hub-name-listing{"bo-bind" => "hub.name | truncate:40"}
|
||||
|
||||
.columns.small-4.medium-2.large-2
|
||||
%span.margin-top {{ hub.address.city }}
|
||||
%span.margin-top{"bo-text" => "hub.address.city"}
|
||||
.columns.small-2.medium-1.large-1
|
||||
%span.margin-top {{ hub.address.state_name | uppercase }}
|
||||
%span.margin-top{"bo-bind" => "hub.address.state_name | uppercase"}
|
||||
|
||||
.columns.small-6.medium-3.large-4.text-right
|
||||
%span.margin-top{ bo: { if: "!current()" } }
|
||||
|
||||
@@ -41,3 +41,4 @@
|
||||
|
||||
#footer
|
||||
%loading
|
||||
= render 'shared/analytics'
|
||||
|
||||
@@ -1,68 +1,68 @@
|
||||
.row.active_table_row{"ng-show" => "open()", "ng-click" => "toggle()", "ng-class" => "{'open' : !ofn-i_032-closed-sign()}"}
|
||||
.row.active_table_row{"ng-if" => "open()", "ng-click" => "toggle()", "ng-class" => "{'open' : !ofn-i_032-closed-sign()}"}
|
||||
|
||||
.columns.small-12.medium-7.large-7.fat
|
||||
/ Will add in long description available once clean up HTML formatting producer.long_description
|
||||
%div{"bo-if" => "producer.description"}
|
||||
%label About us
|
||||
%img.right.show-for-medium-up{"ng-src" => "{{producer.logo}}" }
|
||||
%p.text-small
|
||||
{{ producer.description }}
|
||||
%img.right.show-for-medium-up{"bo-src" => "producer.logo" }
|
||||
%p.text-small{ "bo-text" => "producer.description"}
|
||||
%div.show-for-medium-up{"bo-if" => "producer.description.length==0"}
|
||||
%label
|
||||
|
||||
.columns.small-12.medium-5.large-5.fat
|
||||
|
||||
%div{"ng-if" => "producer.supplied_taxons"}
|
||||
%div{"bo-if" => "producer.supplied_taxons"}
|
||||
%label Shop for
|
||||
%p.trans-sentence
|
||||
%span.fat-taxons{"ng-repeat" => "taxon in producer.supplied_taxons"}
|
||||
%render-svg{path: "{{taxon.icon}}"}
|
||||
{{taxon.name}}
|
||||
%span{"bo-text" => "taxon.name"}
|
||||
|
||||
%div.show-for-medium-up{"ng-if" => "producer.supplied_taxons.length==0"}
|
||||
|
||||
|
||||
%div{"ng-if" => "producer.email || producer.website || producer.phone"}
|
||||
%div{"bo-if" => "producer.email || producer.website || producer.phone"}
|
||||
%label Contact
|
||||
|
||||
%p.word-wrap{"ng-if" => "producer.phone"}
|
||||
Call {{ producer.phone }}
|
||||
%p.word-wrap{"bo-if" => "producer.phone"}
|
||||
Call
|
||||
%span{"bo-text" => "producer.phone"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "producer.email"}
|
||||
%a{"ng-href" => "{{producer.email | stripUrl}}", target: "_blank", mailto: true}
|
||||
%span.email {{ producer.email | stripUrl }}
|
||||
%p.word-wrap{"bo-if" => "producer.email"}
|
||||
%a{"bo-href" => "producer.email | stripUrl", target: "_blank", mailto: true}
|
||||
%span.email{"bo-bind" => "producer.email | stripUrl"}
|
||||
|
||||
%p.word-wrap{"ng-if" => "producer.website"}
|
||||
%a{"ng-href" => "http://{{producer.website | stripUrl}}", target: "_blank" }
|
||||
%span {{ producer.website | stripUrl }}
|
||||
%p.word-wrap{"bo-if" => "producer.website"}
|
||||
%a{"bo-href-i" => "http://{{producer.website | stripUrl}}", target: "_blank" }
|
||||
%span{"bo-bind" => "producer.website | stripUrl"}
|
||||
|
||||
%div{"ng-if" => "producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
|
||||
%div{"bo-if" => "producer.twitter || producer.facebook || producer.linkedin || producer.instagram"}
|
||||
%label Follow
|
||||
.follow-icons{bindonce: true}
|
||||
%span{"ng-if" => "producer.twitter"}
|
||||
%a{"ng-href" => "http://twitter.com/{{producer.twitter}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.twitter"}
|
||||
%a{"bo-href-i" => "http://twitter.com/{{producer.twitter}}", target: "_blank"}
|
||||
%i.ofn-i_041-twitter
|
||||
|
||||
%span{"ng-if" => "producer.facebook"}
|
||||
%a{"ng-href" => "http://{{producer.facebook | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.facebook"}
|
||||
%a{"bo-href-i" => "http://{{producer.facebook | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_044-facebook
|
||||
|
||||
%span{"ng-if" => "producer.linkedin"}
|
||||
%a{"ng-href" => "http://{{producer.linkedin | stripUrl}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.linkedin"}
|
||||
%a{"bo-href-i" => "http://{{producer.linkedin | stripUrl}}", target: "_blank"}
|
||||
%i.ofn-i_042-linkedin
|
||||
|
||||
%span{"ng-if" => "producer.instagram"}
|
||||
%a{"ng-href" => "http://instagram.com/{{producer.instagram}}", target: "_blank"}
|
||||
%span{"bo-if" => "producer.instagram"}
|
||||
%a{"bo-href-i" => "http://instagram.com/{{producer.instagram}}", target: "_blank"}
|
||||
%i.ofn-i_043-instagram
|
||||
|
||||
.row.active_table_row.pad-top{"ng-show" => "open()", "bo-if" => "producer.hubs"}
|
||||
.row.active_table_row.pad-top{"ng-if" => "open()", "bo-if" => "producer.hubs"}
|
||||
.columns.small-12
|
||||
.row
|
||||
.columns.small-12.fat
|
||||
%div{"bo-if" => "producer.name"}
|
||||
%label
|
||||
Shop for
|
||||
%span.turquoise {{ producer.name }}
|
||||
%span.turquoise{"bo-text" => "producer.name"}
|
||||
products at:
|
||||
%div.show-for-medium-up{"bo-if" => "!producer.name"}
|
||||
|
||||
@@ -73,6 +73,6 @@
|
||||
"bo-class" => "{primary: hub.active, secondary: !hub.active}"}
|
||||
%i.ofn-i_033-open-sign{"bo-if" => "hub.active"}
|
||||
%i.ofn-i_032-closed-sign{"bo-if" => "!hub.active"}
|
||||
.hub-name {{hub.name}}
|
||||
.button-address {{ [hub.address.city, hub.address.state_name] | printArray }}
|
||||
.hub-name{"bo-text" => "hub.name"}
|
||||
.button-address{"bo-bind" => "[hub.address.city, hub.address.state_name] | printArray"}
|
||||
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
.columns.small-12.medium-4.large-4.skinny-head
|
||||
%span{"bo-if" => "producer.is_distributor" }
|
||||
%a.is_distributor{"bo-href" => "producer.path" }
|
||||
%i{ng: {class: "producer.producer_icon_font"}}
|
||||
%i{bo: {class: "producer.producer_icon_font"}}
|
||||
%span.margin-top
|
||||
%strong {{ producer.name }}
|
||||
%strong{"bo-text" => "producer.name"}
|
||||
%span.producer-name{"bo-if" => "!producer.is_distributor" }
|
||||
%i{ng: {class: "producer.producer_icon_font"}}
|
||||
%i{bo: {class: "producer.producer_icon_font"}}
|
||||
%span.margin-top
|
||||
%strong {{ producer.name }}
|
||||
%strong{"bo-text" => "producer.name"}
|
||||
|
||||
|
||||
.columns.small-6.medium-3.large-3
|
||||
%span.margin-top {{ producer.address.city }}
|
||||
%span.margin-top{"bo-text" => "producer.address.city"}
|
||||
.columns.small-4.medium-3.large-4
|
||||
%span.margin-top {{ producer.address.state_name | uppercase }}
|
||||
%span.margin-top{"bo-bind" => "producer.address.state_name | uppercase"}
|
||||
.columns.small-2.medium-2.large-1.text-right
|
||||
%span.margin-top
|
||||
%i{"ng-class" => "{'ofn-i_005-caret-down' : !open(), 'ofn-i_006-caret-up' : open()}"}
|
||||
|
||||
8
app/views/shared/_analytics.html.haml
Normal file
8
app/views/shared/_analytics.html.haml
Normal file
@@ -0,0 +1,8 @@
|
||||
:javascript
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-62912229-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
@@ -7,14 +7,13 @@
|
||||
.small-10.medium-10.large-11.columns.summary-header
|
||||
%h3
|
||||
%a{"ng-click" => "triggerProductModal()"}
|
||||
{{ product.name }}
|
||||
%span{"bo-text" => "product.name"}
|
||||
%i.ofn-i_057-expand
|
||||
%small
|
||||
%em from
|
||||
%span
|
||||
%enterprise-modal
|
||||
%i.ofn-i_036-producers
|
||||
{{ enterprise.name }}
|
||||
%i.ofn-i_036-producers{"bo-text" => "enterprise.name"}
|
||||
.small-2.medium-2.large-1.columns.text-center
|
||||
.taxon-flag
|
||||
%render-svg{path: "{{product.primary_taxon.icon}}"}
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
include_blank: true)
|
||||
%br
|
||||
%br
|
||||
= label_tag nil, "Report Type: "
|
||||
= select_tag(:report_type, options_for_select(@report_types, @report_type))
|
||||
%br
|
||||
%br
|
||||
= check_box_tag :csv
|
||||
= label_tag :csv, "Download as csv"
|
||||
%br
|
||||
@@ -41,4 +45,3 @@
|
||||
- if @report.table.empty?
|
||||
%tr
|
||||
%td{:colspan => "2"}= t(:none)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ module OpenFoodNetwork
|
||||
|
||||
if @coordinator.sells == "any"
|
||||
# If the coordinator sells any, relationships come into play
|
||||
granting(:add_to_order_cycle, to: [@coordinator]).pluck(:id).each do |enterprise_id|
|
||||
related_enterprises_granting(:add_to_order_cycle, to: [@coordinator]).pluck(:id).each do |enterprise_id|
|
||||
coordinator_permitted << enterprise_id
|
||||
end
|
||||
|
||||
@@ -30,19 +30,19 @@ module OpenFoodNetwork
|
||||
Enterprise.where(id: coordinator_permitted | all_active)
|
||||
else
|
||||
# Any enterprises that I manage directly, which have granted P-OC to the coordinator
|
||||
managed_permitted = granting(:add_to_order_cycle, to: [@coordinator], scope: managed_participating_enterprises ).pluck(:id)
|
||||
managed_permitted = related_enterprises_granting(:add_to_order_cycle, to: [@coordinator], scope: managed_participating_enterprises ).pluck(:id)
|
||||
|
||||
# Any hubs in this OC that have been granted P-OC by producers I manage in this OC
|
||||
hubs_permitted = granted(:add_to_order_cycle, by: managed_participating_producers, scope: @order_cycle.distributors).pluck(:id)
|
||||
hubs_permitted = related_enterprises_granted(:add_to_order_cycle, by: managed_participating_producers, scope: @order_cycle.distributors).pluck(:id)
|
||||
|
||||
# Any hubs in this OC that have granted P-OC to producers I manage in this OC
|
||||
hubs_permitting = granting(:add_to_order_cycle, to: managed_participating_producers, scope: @order_cycle.distributors).pluck(:id)
|
||||
hubs_permitting = related_enterprises_granting(:add_to_order_cycle, to: managed_participating_producers, scope: @order_cycle.distributors).pluck(:id)
|
||||
|
||||
# Any producers in this OC that have been granted P-OC by hubs I manage in this OC
|
||||
producers_permitted = granted(:add_to_order_cycle, by: managed_participating_hubs, scope: @order_cycle.suppliers).pluck(:id)
|
||||
producers_permitted = related_enterprises_granted(:add_to_order_cycle, by: managed_participating_hubs, scope: @order_cycle.suppliers).pluck(:id)
|
||||
|
||||
# Any producers in this OC that have granted P-OC to hubs I manage in this OC
|
||||
producers_permitting = granting(:add_to_order_cycle, to: managed_participating_hubs, scope: @order_cycle.suppliers).pluck(:id)
|
||||
producers_permitting = related_enterprises_granting(:add_to_order_cycle, to: managed_participating_hubs, scope: @order_cycle.suppliers).pluck(:id)
|
||||
|
||||
managed_active = []
|
||||
hubs_active = []
|
||||
@@ -125,7 +125,7 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
# Any variants of any producers that have granted the hub P-OC
|
||||
producers = granting(:add_to_order_cycle, to: [hub], scope: Enterprise.is_primary_producer)
|
||||
producers = related_enterprises_granting(:add_to_order_cycle, to: [hub], scope: Enterprise.is_primary_producer)
|
||||
permitted_variants = Spree::Variant.joins(:product).where('spree_products.supplier_id IN (?)', producers)
|
||||
|
||||
# PLUS any variants that are already in an outgoing exchange of this hub, so things don't break
|
||||
@@ -138,7 +138,7 @@ module OpenFoodNetwork
|
||||
Spree::Variant.where(id: coordinator_variants | permitted_variants | active_variants)
|
||||
else
|
||||
# Any variants produced by MY PRODUCERS that are in this order cycle, where my producer has granted P-OC to the hub
|
||||
producers = granting(:add_to_order_cycle, to: [hub], scope: managed_participating_producers)
|
||||
producers = related_enterprises_granting(:add_to_order_cycle, to: [hub], scope: managed_participating_producers)
|
||||
permitted_variants = Spree::Variant.joins(:product).where('spree_products.supplier_id IN (?)', producers)
|
||||
|
||||
# PLUS any of my incoming producers' variants that are already in an outgoing exchange of this hub, so things don't break
|
||||
@@ -162,7 +162,7 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
# Any variants of any producers that have granted the hub P-OC
|
||||
producers = granting(:add_to_order_cycle, to: [hub], scope: Enterprise.is_primary_producer)
|
||||
producers = related_enterprises_granting(:add_to_order_cycle, to: [hub], scope: Enterprise.is_primary_producer)
|
||||
permitted_variants = Spree::Variant.joins(:product).where('spree_products.supplier_id IN (?)', producers)
|
||||
|
||||
# PLUS any variants that are already in an outgoing exchange of this hub, so things don't break
|
||||
@@ -175,10 +175,10 @@ module OpenFoodNetwork
|
||||
Spree::Variant.where(id: coordinator_variants | permitted_variants | active_variants)
|
||||
else
|
||||
# Any of my managed producers in this order cycle granted P-OC by the hub
|
||||
granted_producers = granted(:add_to_order_cycle, by: [hub], scope: managed_participating_producers)
|
||||
granted_producers = related_enterprises_granted(:add_to_order_cycle, by: [hub], scope: managed_participating_producers)
|
||||
|
||||
# Any variants produced by MY PRODUCERS that are in this order cycle, where my producer has granted P-OC to the hub
|
||||
granting_producers = granting(:add_to_order_cycle, to: [hub], scope: granted_producers)
|
||||
granting_producers = related_enterprises_granting(:add_to_order_cycle, to: [hub], scope: granted_producers)
|
||||
permitted_variants = Spree::Variant.joins(:product).where('spree_products.supplier_id IN (?)', granting_producers)
|
||||
|
||||
Spree::Variant.where(id: permitted_variants)
|
||||
@@ -216,7 +216,7 @@ module OpenFoodNetwork
|
||||
# Find my managed hubs in this order cycle
|
||||
hubs = managed_participating_hubs
|
||||
# Any incoming exchange where the producer has granted P-OC to one or more of those hubs
|
||||
producers = granting(:add_to_order_cycle, to: hubs, scope: Enterprise.is_primary_producer).pluck :id
|
||||
producers = related_enterprises_granting(:add_to_order_cycle, to: hubs, scope: Enterprise.is_primary_producer).pluck :id
|
||||
permitted_exchanges = @order_cycle.exchanges.incoming.where(sender_id: producers).pluck :id
|
||||
|
||||
# TODO: remove active_exchanges when we think it is safe to do so
|
||||
@@ -235,7 +235,7 @@ module OpenFoodNetwork
|
||||
# Find my producers in this order cycle
|
||||
producers = managed_participating_producers.pluck :id
|
||||
# Any outgoing exchange where the distributor has been granted P-OC by one or more of those producers
|
||||
hubs = granted(:add_to_order_cycle, by: producers, scope: Enterprise.is_hub)
|
||||
hubs = related_enterprises_granted(:add_to_order_cycle, by: producers, scope: Enterprise.is_hub)
|
||||
permitted_exchanges = @order_cycle.exchanges.outgoing.where(receiver_id: hubs).pluck :id
|
||||
|
||||
# TODO: remove active_exchanges when we think it is safe to do so
|
||||
|
||||
@@ -5,23 +5,28 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def can_manage_complex_order_cycles?
|
||||
managed_and_related_enterprises_with(:add_to_order_cycle).any? do |e|
|
||||
managed_and_related_enterprises_granting(: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
|
||||
def visible_enterprises_for_order_reports
|
||||
managed_and_related_enterprises_with :add_to_order_cycle
|
||||
end
|
||||
|
||||
def order_cycle_enterprises
|
||||
# Return enterprises that the user manages and those that have granted P-OC to managed enterprises
|
||||
managed_and_related_enterprises_granting :add_to_order_cycle
|
||||
end
|
||||
|
||||
# Find enterprises for which an admin is allowed to edit their profile
|
||||
def editable_enterprises
|
||||
managed_and_related_enterprises_with :edit_profile
|
||||
managed_and_related_enterprises_granting :edit_profile
|
||||
end
|
||||
|
||||
def variant_override_hubs
|
||||
managed_and_related_enterprises_with(:add_to_order_cycle).is_hub
|
||||
managed_and_related_enterprises_granting(:add_to_order_cycle).is_hub
|
||||
end
|
||||
|
||||
def variant_override_producers
|
||||
@@ -33,7 +38,7 @@ module OpenFoodNetwork
|
||||
# override variants
|
||||
# {hub1_id => [producer1_id, producer2_id, ...], ...}
|
||||
def variant_override_enterprises_per_hub
|
||||
hubs = managed_and_related_enterprises_with(:add_to_order_cycle).is_distributor
|
||||
hubs = managed_and_related_enterprises_granting(:add_to_order_cycle).is_distributor
|
||||
|
||||
# Permissions granted by create_variant_overrides relationship from producer to hub
|
||||
permissions = Hash[
|
||||
@@ -56,6 +61,51 @@ module OpenFoodNetwork
|
||||
permissions
|
||||
end
|
||||
|
||||
# Find enterprises that an admin is allowed to add to an order cycle
|
||||
def visible_orders
|
||||
# Any orders that I can edit
|
||||
editable = editable_orders.pluck(:id)
|
||||
|
||||
# Any orders placed through hubs that my producers have granted P-OC, and which contain my their products
|
||||
# This is pretty complicated but it's looking for order where at least one of my producers has granted
|
||||
# P-OC to the distributor AND the order contains products of at least one of THE SAME producers
|
||||
granted_distributors = related_enterprises_granted(:add_to_order_cycle, by: managed_enterprises.is_primary_producer)
|
||||
produced = Spree::Order.with_line_items_variants_and_products_outer.
|
||||
where(
|
||||
"spree_orders.distributor_id IN (?) AND spree_products.supplier_id IN (?)",
|
||||
granted_distributors,
|
||||
related_enterprises_granting(:add_to_order_cycle, to: granted_distributors).merge(managed_enterprises.is_primary_producer)
|
||||
).pluck(:id)
|
||||
|
||||
Spree::Order.where(id: editable | produced)
|
||||
end
|
||||
|
||||
# Find enterprises that an admin is allowed to add to an order cycle
|
||||
def editable_orders
|
||||
# Any orders placed through any hub that I manage
|
||||
managed = Spree::Order.where(distributor_id: managed_enterprises.pluck(:id)).pluck(:id)
|
||||
|
||||
# Any order that is placed through an order cycle one of my managed enterprises coordinates
|
||||
coordinated = Spree::Order.where(order_cycle_id: coordinated_order_cycles.pluck(:id)).pluck(:id)
|
||||
|
||||
Spree::Order.where(id: managed | coordinated )
|
||||
end
|
||||
|
||||
def visible_line_items
|
||||
# Any line items that I can edit
|
||||
editable = editable_line_items.pluck(:id)
|
||||
|
||||
# Any from visible orders, where the product is produced by one of my managed producers
|
||||
produced = Spree::LineItem.where(order_id: visible_orders.pluck(:id)).joins(:product).
|
||||
where('spree_products.supplier_id IN (?)', managed_enterprises.is_primary_producer.pluck(:id))
|
||||
|
||||
Spree::LineItem.where(id: editable | produced)
|
||||
end
|
||||
|
||||
def editable_line_items
|
||||
Spree::LineItem.where(order_id: editable_orders)
|
||||
end
|
||||
|
||||
def managed_products
|
||||
managed_enterprise_products_ids = managed_enterprise_products.pluck :id
|
||||
permitted_enterprise_products_ids = related_enterprise_products.pluck :id
|
||||
@@ -63,7 +113,7 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def managed_product_enterprises
|
||||
managed_and_related_enterprises_with :manage_products
|
||||
managed_and_related_enterprises_granting :manage_products
|
||||
end
|
||||
|
||||
def manages_one_enterprise?
|
||||
@@ -73,11 +123,30 @@ module OpenFoodNetwork
|
||||
|
||||
private
|
||||
|
||||
def managed_and_related_enterprises_with(permission)
|
||||
managed_enterprise_ids = managed_enterprises.pluck :id
|
||||
permitting_enterprise_ids = related_enterprises_with(permission).pluck :id
|
||||
def admin?
|
||||
@user.admin?
|
||||
end
|
||||
|
||||
Enterprise.where('id IN (?)', managed_enterprise_ids + permitting_enterprise_ids)
|
||||
def managed_and_related_enterprises_granting(permission)
|
||||
if admin?
|
||||
Enterprise.scoped
|
||||
else
|
||||
managed_enterprise_ids = managed_enterprises.pluck :id
|
||||
permitting_enterprise_ids = related_enterprises_granting(permission).pluck :id
|
||||
|
||||
Enterprise.where('id IN (?)', managed_enterprise_ids + permitting_enterprise_ids)
|
||||
end
|
||||
end
|
||||
|
||||
def managed_and_related_enterprises_with(permission)
|
||||
if admin?
|
||||
Enterprise.scoped
|
||||
else
|
||||
managed = managed_enterprises.pluck(:id)
|
||||
granting = related_enterprises_granting(permission).pluck(:id)
|
||||
granted = related_enterprises_granted(permission).pluck(:id)
|
||||
Enterprise.where(id: managed | granting | granted)
|
||||
end
|
||||
end
|
||||
|
||||
def managed_enterprises
|
||||
@@ -85,16 +154,12 @@ module OpenFoodNetwork
|
||||
@managed_enterprises = Enterprise.managed_by(@user)
|
||||
end
|
||||
|
||||
def related_enterprises_with(permission)
|
||||
parent_ids = EnterpriseRelationship.
|
||||
permitting(managed_enterprises).
|
||||
with_permission(permission).
|
||||
pluck(:parent_id)
|
||||
|
||||
Enterprise.where('id IN (?)', parent_ids)
|
||||
def coordinated_order_cycles
|
||||
return @coordinated_order_cycles unless @coordinated_order_cycles.nil?
|
||||
@coordinated_order_cycles = OrderCycle.managed_by(@user)
|
||||
end
|
||||
|
||||
def granting(permission, options={})
|
||||
def related_enterprises_granting(permission, options={})
|
||||
parent_ids = EnterpriseRelationship.
|
||||
permitting(options[:to] || managed_enterprises).
|
||||
with_permission(permission).
|
||||
@@ -103,7 +168,7 @@ module OpenFoodNetwork
|
||||
(options[:scope] || Enterprise).where('enterprises.id IN (?)', parent_ids)
|
||||
end
|
||||
|
||||
def granted(permission, options={})
|
||||
def related_enterprises_granted(permission, options={})
|
||||
child_ids = EnterpriseRelationship.
|
||||
permitted_by(options[:by] || managed_enterprises).
|
||||
with_permission(permission).
|
||||
@@ -117,7 +182,7 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def related_enterprise_products
|
||||
Spree::Product.where('supplier_id IN (?)', related_enterprises_with(:manage_products))
|
||||
Spree::Product.where('supplier_id IN (?)', related_enterprises_granting(:manage_products))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,6 +12,13 @@ function exit_unless_master_merged {
|
||||
fi
|
||||
}
|
||||
|
||||
function succeed_if_master_merged {
|
||||
if [[ `git branch -a --merged origin/$BUILDKITE_BRANCH` == *origin/master* ]]; then
|
||||
echo "This branch already has the current master merged."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
function drop_and_recreate_database {
|
||||
# Adapted from: http://stackoverflow.com/questions/12924466/capistrano-with-postgresql-error-database-is-being-accessed-by-other-users
|
||||
psql -U openfoodweb postgres <<EOF
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
source ./script/ci/includes.sh
|
||||
|
||||
echo "--- Verifying branch is based on current master"
|
||||
exit_unless_master_merged
|
||||
|
||||
echo "--- Pushing branch"
|
||||
echo git push origin $BUILDKITE_COMMIT:master
|
||||
git push origin $BUILDKITE_COMMIT:master
|
||||
|
||||
14
script/ci/merge_master_into_branch.sh
Executable file
14
script/ci/merge_master_into_branch.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
source ./script/ci/includes.sh
|
||||
|
||||
echo "--- Checking if master has already been merged"
|
||||
succeed_if_master_merged
|
||||
|
||||
echo "--- Merging master into this branch"
|
||||
git checkout $BUILDKITE_BRANCH
|
||||
git merge origin/$BUILDKITE_BRANCH
|
||||
git merge origin/master -m "Auto-merge from CI [skip ci]"
|
||||
git push origin $BUILDKITE_BRANCH
|
||||
git checkout origin/$BUILDKITE_BRANCH
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
# Add production git remote if required
|
||||
PROD_TEST=`git remote | grep -s 'production' || true`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
source ./script/ci/includes.sh
|
||||
|
||||
# Add staging git remote if required
|
||||
|
||||
@@ -4,109 +4,210 @@ require 'spree/api/testing_support/helpers'
|
||||
module Api
|
||||
describe OrderCyclesController do
|
||||
include Spree::Api::TestingSupport::Helpers
|
||||
include AuthenticationWorkflow
|
||||
render_views
|
||||
|
||||
let!(:oc1) { FactoryGirl.create(:simple_order_cycle) }
|
||||
let!(:oc2) { FactoryGirl.create(:simple_order_cycle) }
|
||||
let(:coordinator) { oc1.coordinator }
|
||||
let(:attributes) { [:id, :name, :suppliers, :distributors] }
|
||||
describe "managed" do
|
||||
let!(:oc1) { FactoryGirl.create(:simple_order_cycle) }
|
||||
let!(:oc2) { FactoryGirl.create(:simple_order_cycle) }
|
||||
let(:coordinator) { oc1.coordinator }
|
||||
let(:attributes) { [:id, :name, :suppliers, :distributors] }
|
||||
|
||||
before do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => current_api_user
|
||||
end
|
||||
before do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => current_api_user
|
||||
end
|
||||
|
||||
context "as a normal user" do
|
||||
sign_in_as_user!
|
||||
context "as a normal user" do
|
||||
sign_in_as_user!
|
||||
|
||||
it "should deny me access to managed order cycles" do
|
||||
spree_get :managed, { :format => :json }
|
||||
assert_unauthorized!
|
||||
it "should deny me access to managed order cycles" do
|
||||
spree_get :managed, { :format => :json }
|
||||
assert_unauthorized!
|
||||
end
|
||||
end
|
||||
|
||||
context "as an enterprise user" do
|
||||
sign_in_as_enterprise_user! [:coordinator]
|
||||
|
||||
it "retrieves a list of variants with appropriate attributes" do
|
||||
get :managed, { :format => :json }
|
||||
keys = json_response.first.keys.map{ |key| key.to_sym }
|
||||
attributes.all?{ |attr| keys.include? attr }.should == true
|
||||
end
|
||||
end
|
||||
|
||||
context "as an administrator" do
|
||||
sign_in_as_admin!
|
||||
|
||||
it "retrieves a list of variants with appropriate attributes" do
|
||||
get :managed, { :format => :json }
|
||||
keys = json_response.first.keys.map{ |key| key.to_sym }
|
||||
attributes.all?{ |attr| keys.include? attr }.should == true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as an enterprise user" do
|
||||
sign_in_as_enterprise_user! [:coordinator]
|
||||
describe "accessible" do
|
||||
context "without :as parameter" do
|
||||
let(:oc_supplier) { create(:supplier_enterprise) }
|
||||
let(:oc_distributor) { create(:distributor_enterprise) }
|
||||
let(:other_supplier) { create(:supplier_enterprise) }
|
||||
let(:oc_supplier_user) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
user.enterprise_roles.create(enterprise: oc_supplier)
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let(:oc_distributor_user) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
user.enterprise_roles.create(enterprise: oc_distributor)
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let(:other_supplier_user) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
user.enterprise_roles.create(enterprise: other_supplier)
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let!(:order_cycle) { create(:simple_order_cycle, suppliers: [oc_supplier], distributors: [oc_distributor]) }
|
||||
|
||||
it "retrieves a list of variants with appropriate attributes" do
|
||||
get :managed, { :format => :json }
|
||||
keys = json_response.first.keys.map{ |key| key.to_sym }
|
||||
attributes.all?{ |attr| keys.include? attr }.should == true
|
||||
end
|
||||
end
|
||||
context "as the user of a supplier to an order cycle" do
|
||||
before :each do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => oc_supplier_user
|
||||
spree_get :accessible, { :template => 'bulk_index', :format => :json }
|
||||
end
|
||||
|
||||
context "as an administrator" do
|
||||
sign_in_as_admin!
|
||||
it "gives me access" do
|
||||
json_response.length.should == 1
|
||||
json_response[0]['id'].should == order_cycle.id
|
||||
end
|
||||
end
|
||||
|
||||
it "retrieves a list of variants with appropriate attributes" do
|
||||
get :managed, { :format => :json }
|
||||
keys = json_response.first.keys.map{ |key| key.to_sym }
|
||||
attributes.all?{ |attr| keys.include? attr }.should == true
|
||||
end
|
||||
end
|
||||
context "as the user of some other supplier" do
|
||||
before :each do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => other_supplier_user
|
||||
spree_get :accessible, { :template => 'bulk_index', :format => :json }
|
||||
end
|
||||
|
||||
context "using the accessible action to list order cycles" do
|
||||
let(:oc_supplier) { create(:supplier_enterprise) }
|
||||
let(:oc_distributor) { create(:distributor_enterprise) }
|
||||
let(:other_supplier) { create(:supplier_enterprise) }
|
||||
let(:oc_supplier_user) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
user.enterprise_roles.create(enterprise: oc_supplier)
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let(:oc_distributor_user) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
user.enterprise_roles.create(enterprise: oc_distributor)
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let(:other_supplier_user) do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
user.enterprise_roles.create(enterprise: other_supplier)
|
||||
user.save!
|
||||
user
|
||||
end
|
||||
let!(:order_cycle) { create(:simple_order_cycle, suppliers: [oc_supplier], distributors: [oc_distributor]) }
|
||||
it "does not give me access" do
|
||||
json_response.length.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
context "as the user of a supplier to an order cycle" do
|
||||
before :each do
|
||||
context "as the user of a hub for the order cycle" do
|
||||
before :each do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => oc_distributor_user
|
||||
spree_get :accessible, { :template => 'bulk_index', :format => :json }
|
||||
end
|
||||
|
||||
it "gives me access" do
|
||||
json_response.length.should == 1
|
||||
json_response[0]['id'].should == order_cycle.id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when the :as parameter is set to 'distributor'" do
|
||||
let(:user) { create_enterprise_user }
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:producer) { create(:supplier_enterprise) }
|
||||
let(:coordinator) { create(:distributor_enterprise) }
|
||||
let!(:oc) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor], suppliers: [producer]) }
|
||||
|
||||
let(:params) { { format: :json, as: 'distributor' } }
|
||||
|
||||
before do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => oc_supplier_user
|
||||
spree_get :accessible, { :template => 'bulk_index', :format => :json }
|
||||
Spree.user_class.stub :find_by_spree_api_key => user
|
||||
end
|
||||
|
||||
it "gives me access" do
|
||||
json_response.length.should == 1
|
||||
json_response[0]['id'].should == order_cycle.id
|
||||
context "as the manager of a supplier in an order cycle" do
|
||||
before do
|
||||
user.enterprise_roles.create(enterprise: producer)
|
||||
spree_get :accessible, params
|
||||
end
|
||||
|
||||
it "does not return the order cycle" do
|
||||
expect(assigns(:order_cycles)).to_not include oc
|
||||
end
|
||||
end
|
||||
|
||||
context "as the manager of a distributor in an order cycle" do
|
||||
before do
|
||||
user.enterprise_roles.create(enterprise: distributor)
|
||||
spree_get :accessible, params
|
||||
end
|
||||
|
||||
it "returns the order cycle" do
|
||||
expect(assigns(:order_cycles)).to include oc
|
||||
end
|
||||
end
|
||||
|
||||
context "as the manager of the coordinator of an order cycle" do
|
||||
before do
|
||||
user.enterprise_roles.create(enterprise: coordinator)
|
||||
spree_get :accessible, params
|
||||
end
|
||||
|
||||
it "returns the order cycle" do
|
||||
expect(assigns(:order_cycles)).to include oc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as the user of some other supplier" do
|
||||
before :each do
|
||||
context "when the :as parameter is set to 'producer'" do
|
||||
let(:user) { create_enterprise_user }
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:producer) { create(:supplier_enterprise) }
|
||||
let(:coordinator) { create(:distributor_enterprise) }
|
||||
let!(:oc) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor], suppliers: [producer]) }
|
||||
|
||||
let(:params) { { format: :json, as: 'producer' } }
|
||||
|
||||
before do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => other_supplier_user
|
||||
spree_get :accessible, { :template => 'bulk_index', :format => :json }
|
||||
Spree.user_class.stub :find_by_spree_api_key => user
|
||||
end
|
||||
|
||||
it "does not give me access" do
|
||||
json_response.length.should == 0
|
||||
end
|
||||
end
|
||||
context "as the manager of a producer in an order cycle" do
|
||||
before do
|
||||
user.enterprise_roles.create(enterprise: producer)
|
||||
spree_get :accessible, params
|
||||
end
|
||||
|
||||
context "as the user of a hub for the order cycle" do
|
||||
before :each do
|
||||
stub_authentication!
|
||||
Spree.user_class.stub :find_by_spree_api_key => oc_distributor_user
|
||||
spree_get :accessible, { :template => 'bulk_index', :format => :json }
|
||||
it "returns the order cycle" do
|
||||
expect(assigns(:order_cycles)).to include oc
|
||||
end
|
||||
end
|
||||
|
||||
it "gives me access" do
|
||||
json_response.length.should == 1
|
||||
json_response[0]['id'].should == order_cycle.id
|
||||
context "as the manager of a distributor in an order cycle" do
|
||||
before do
|
||||
user.enterprise_roles.create(enterprise: distributor)
|
||||
spree_get :accessible, params
|
||||
end
|
||||
|
||||
it "does not return the order cycle" do
|
||||
expect(assigns(:order_cycles)).to_not include oc
|
||||
end
|
||||
end
|
||||
|
||||
context "as the manager of the coordinator of an order cycle" do
|
||||
before do
|
||||
user.enterprise_roles.create(enterprise: coordinator)
|
||||
spree_get :accessible, params
|
||||
end
|
||||
|
||||
it "returns the order cycle" do
|
||||
expect(assigns(:order_cycles)).to include oc
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Admin::ReportsController do
|
||||
|
||||
|
||||
# Given two distributors and two suppliers
|
||||
let(:ba) { create(:address) }
|
||||
let(:si) { "pick up on thursday please" }
|
||||
let(:s1) { create(:supplier_enterprise, address: create(:address)) }
|
||||
let(:s2) { create(:supplier_enterprise, address: create(:address)) }
|
||||
let(:s3) { create(:supplier_enterprise, address: create(:address)) }
|
||||
let(:d1) { create(:distributor_enterprise, address: create(:address)) }
|
||||
let(:d2) { create(:distributor_enterprise, address: create(:address)) }
|
||||
let(:d3) { create(:distributor_enterprise, address: create(:address)) }
|
||||
let(:c1) { create(:distributor_enterprise) }
|
||||
let(:c2) { create(:distributor_enterprise) }
|
||||
let(:s1) { create(:supplier_enterprise) }
|
||||
let(:s2) { create(:supplier_enterprise) }
|
||||
let(:s3) { create(:supplier_enterprise) }
|
||||
let(:d1) { create(:distributor_enterprise) }
|
||||
let(:d2) { create(:distributor_enterprise) }
|
||||
let(:d3) { create(:distributor_enterprise) }
|
||||
let(:p1) { create(:product, price: 12.34, distributors: [d1], supplier: s1) }
|
||||
let(:p2) { create(:product, price: 23.45, distributors: [d2], supplier: s2) }
|
||||
let(:p3) { create(:product, price: 34.56, distributors: [d3], supplier: s3) }
|
||||
|
||||
# Given two order cycles with both distributors
|
||||
let(:ocA) { create(:simple_order_cycle, distributors: [d1, d2], suppliers: [s1, s2, s3], variants: [p1.master, p3.master]) }
|
||||
let(:ocB) { create(:simple_order_cycle, distributors: [d1, d2], suppliers: [s1, s2, s3], variants: [p2.master]) }
|
||||
let(:ocA) { create(:simple_order_cycle, coordinator: c1, distributors: [d1, d2], suppliers: [s1, s2, s3], variants: [p1.master, p3.master]) }
|
||||
let(:ocB) { create(:simple_order_cycle, coordinator: c2, distributors: [d1, d2], suppliers: [s1, s2, s3], variants: [p2.master]) }
|
||||
|
||||
# orderA1 can only be accessed by s1, s3 and d1
|
||||
let!(:orderA1) do
|
||||
@@ -53,15 +55,29 @@ describe Spree::Admin::ReportsController do
|
||||
order.save
|
||||
order
|
||||
end
|
||||
|
||||
# As a Distributor Enterprise user for d1
|
||||
|
||||
# As manager of a coordinator (c1)
|
||||
context "Coordinator Enterprise User" do
|
||||
before { login_as_enterprise_user [c1] }
|
||||
|
||||
describe 'Orders & Fulfillment' do
|
||||
it "shows all orders in order cycles I coordinate" do
|
||||
spree_get :orders_and_fulfillment
|
||||
|
||||
assigns(:line_items).map(&:order).should include orderA1, orderA2
|
||||
assigns(:line_items).map(&:order).should_not include orderB1, orderB2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# As a Distributor Enterprise user for d1
|
||||
context "Distributor Enterprise User" do
|
||||
before { login_as_enterprise_user [d1] }
|
||||
|
||||
describe 'Orders and Distributors' do
|
||||
it "only shows orders that I have access to" do
|
||||
spree_get :orders_and_distributors
|
||||
|
||||
|
||||
assigns(:search).result.should include(orderA1, orderB1)
|
||||
assigns(:search).result.should_not include(orderA2)
|
||||
assigns(:search).result.should_not include(orderB2)
|
||||
@@ -71,7 +87,7 @@ describe Spree::Admin::ReportsController do
|
||||
describe 'Bulk Coop' do
|
||||
it "only shows orders that I have access to" do
|
||||
spree_get :bulk_coop
|
||||
|
||||
|
||||
assigns(:search).result.should include(orderA1, orderB1)
|
||||
assigns(:search).result.should_not include(orderA2)
|
||||
assigns(:search).result.should_not include(orderB2)
|
||||
@@ -81,7 +97,7 @@ describe Spree::Admin::ReportsController do
|
||||
describe 'Payments' do
|
||||
it "only shows orders that I have access to" do
|
||||
spree_get :payments
|
||||
|
||||
|
||||
assigns(:search).result.should include(orderA1, orderB1)
|
||||
assigns(:search).result.should_not include(orderA2)
|
||||
assigns(:search).result.should_not include(orderB2)
|
||||
@@ -89,12 +105,11 @@ describe Spree::Admin::ReportsController do
|
||||
end
|
||||
|
||||
describe 'Orders & Fulfillment' do
|
||||
it "only shows orders that I have access to" do
|
||||
it "only shows orders that I distribute" do
|
||||
spree_get :orders_and_fulfillment
|
||||
|
||||
assigns(:search).result.should include(orderA1, orderB1)
|
||||
assigns(:search).result.should_not include(orderA2)
|
||||
assigns(:search).result.should_not include(orderB2)
|
||||
assigns(:line_items).map(&:order).should include orderA1, orderB1
|
||||
assigns(:line_items).map(&:order).should_not include orderA2, orderB2
|
||||
end
|
||||
|
||||
it "only shows the selected order cycle" do
|
||||
@@ -114,19 +129,31 @@ describe Spree::Admin::ReportsController do
|
||||
it "only shows product line items that I am supplying" do
|
||||
spree_get :bulk_coop
|
||||
|
||||
assigns(:line_items).map(&:product).should include(p1)
|
||||
assigns(:line_items).map(&:product).should_not include(p2)
|
||||
assigns(:line_items).map(&:product).should_not include(p3)
|
||||
assigns(:line_items).map(&:product).should include p1
|
||||
assigns(:line_items).map(&:product).should_not include p2, p3
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Orders & Fulfillment' do
|
||||
it "only shows product line items that I am supplying" do
|
||||
spree_get :orders_and_fulfillment
|
||||
context "where I have granted P-OC to the distributor" do
|
||||
before do
|
||||
create(:enterprise_relationship, parent: s1, child: d1, permissions_list: [:add_to_order_cycle])
|
||||
end
|
||||
|
||||
assigns(:line_items).map(&:product).should include(p1)
|
||||
assigns(:line_items).map(&:product).should_not include(p2)
|
||||
assigns(:line_items).map(&:product).should_not include(p3)
|
||||
it "only shows product line items that I am supplying" do
|
||||
spree_get :orders_and_fulfillment
|
||||
|
||||
assigns(:line_items).map(&:product).should include p1
|
||||
assigns(:line_items).map(&:product).should_not include p2, p3
|
||||
end
|
||||
end
|
||||
|
||||
context "where I have not granted P-OC to the distributor" do
|
||||
it "does not show me line_items I supply" do
|
||||
spree_get :orders_and_fulfillment
|
||||
|
||||
assigns(:line_items).map(&:product).should_not include p1, p2, p3
|
||||
end
|
||||
end
|
||||
|
||||
it "only shows the selected order cycle" do
|
||||
@@ -143,7 +170,7 @@ describe Spree::Admin::ReportsController do
|
||||
|
||||
it "should build distributors for the current user" do
|
||||
spree_get :products_and_inventory
|
||||
assigns(:distributors).sort.should == [d1, d2, d3].sort
|
||||
assigns(:distributors).sort.should == [c1, c2, d1, d2, d3].sort
|
||||
end
|
||||
|
||||
it "builds suppliers for the current user" do
|
||||
@@ -184,7 +211,7 @@ describe Spree::Admin::ReportsController do
|
||||
|
||||
it "should build distributors for the current user" do
|
||||
spree_get :customers
|
||||
assigns(:distributors).sort.should == [d1, d2, d3].sort
|
||||
assigns(:distributors).sort.should == [c1, c2, d1, d2, d3].sort
|
||||
end
|
||||
|
||||
it "builds suppliers for the current user" do
|
||||
|
||||
@@ -10,15 +10,15 @@ feature "Authentication", js: true do
|
||||
|
||||
scenario "logging into admin redirects home, then back to admin" do
|
||||
# This is the first admin spec, so give a little extra load time for slow systems
|
||||
Capybara.using_wait_time(60) do
|
||||
Capybara.using_wait_time(120) do
|
||||
visit spree.admin_path
|
||||
end
|
||||
|
||||
fill_in "Email", with: user.email
|
||||
fill_in "Password", with: user.password
|
||||
click_login_button
|
||||
page.should have_content "DASHBOARD"
|
||||
current_path.should == spree.admin_path
|
||||
fill_in "Email", with: user.email
|
||||
fill_in "Password", with: user.password
|
||||
click_login_button
|
||||
page.should have_content "DASHBOARD"
|
||||
current_path.should == spree.admin_path
|
||||
end
|
||||
end
|
||||
|
||||
scenario "viewing my account" do
|
||||
|
||||
@@ -238,8 +238,9 @@ feature %q{
|
||||
end
|
||||
|
||||
context "order_cycle filter" do
|
||||
let!(:oc1) { FactoryGirl.create(:simple_order_cycle ) }
|
||||
let!(:oc2) { FactoryGirl.create(:simple_order_cycle ) }
|
||||
let!(:distributor) { create(:distributor_enterprise) }
|
||||
let!(:oc1) { FactoryGirl.create(:simple_order_cycle, distributors: [distributor]) }
|
||||
let!(:oc2) { FactoryGirl.create(:simple_order_cycle, distributors: [distributor]) }
|
||||
let!(:o1) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now, order_cycle: oc1 ) }
|
||||
let!(:o2) { FactoryGirl.create(:order, state: 'complete', completed_at: Time.now, order_cycle: oc2 ) }
|
||||
let!(:li1) { FactoryGirl.create(:line_item, order: o1 ) }
|
||||
@@ -255,20 +256,22 @@ feature %q{
|
||||
find("div.select2-container#s2id_order_cycle_filter").click
|
||||
order_cycle_names.each { |ocn| page.should have_selector "div.select2-drop-active ul.select2-results li", text: ocn }
|
||||
find("div.select2-container#s2id_order_cycle_filter").click
|
||||
page.should have_selector "tr#li_#{li1.id}", visible: true
|
||||
page.should have_selector "tr#li_#{li2.id}", visible: true
|
||||
page.should have_selector "tr#li_#{li1.id}"
|
||||
page.should have_selector "tr#li_#{li2.id}"
|
||||
select2_select oc1.name, from: "order_cycle_filter"
|
||||
page.should have_selector "tr#li_#{li1.id}", visible: true
|
||||
page.should_not have_selector "tr#li_#{li2.id}", visible: true
|
||||
page.should have_selector "#loading img.spinner"
|
||||
page.should_not have_selector "#loading img.spinner"
|
||||
page.should have_selector "tr#li_#{li1.id}"
|
||||
page.should_not have_selector "tr#li_#{li2.id}"
|
||||
end
|
||||
|
||||
it "displays all line items when 'All' is selected from order_cycle filter" do
|
||||
select2_select oc1.name, from: "order_cycle_filter"
|
||||
page.should have_selector "tr#li_#{li1.id}", visible: true
|
||||
page.should_not have_selector "tr#li_#{li2.id}", visible: true
|
||||
page.should have_selector "tr#li_#{li1.id}"
|
||||
page.should_not have_selector "tr#li_#{li2.id}"
|
||||
select2_select "All", from: "order_cycle_filter"
|
||||
page.should have_selector "tr#li_#{li1.id}", visible: true
|
||||
page.should have_selector "tr#li_#{li2.id}", visible: true
|
||||
page.should have_selector "tr#li_#{li1.id}"
|
||||
page.should have_selector "tr#li_#{li2.id}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -211,8 +211,9 @@ feature %q{
|
||||
end
|
||||
|
||||
it "handles order cycles with nil opening or closing times" do
|
||||
oc = create(:simple_order_cycle, name: "My Order Cycle", orders_open_at: Time.now, orders_close_at: nil)
|
||||
o = create(:order, order_cycle: oc)
|
||||
distributor = create(:distributor_enterprise)
|
||||
oc = create(:simple_order_cycle, name: "My Order Cycle", distributors: [distributor], orders_open_at: Time.now, orders_close_at: nil)
|
||||
o = create(:order, order_cycle: oc, distributor: distributor)
|
||||
|
||||
login_to_admin_section
|
||||
visit spree.orders_and_fulfillment_admin_reports_path
|
||||
|
||||
@@ -22,8 +22,8 @@ describe "AdminOrderMgmtCtrl", ->
|
||||
returnedOrderCycles = [ "oc1", "oc2", "oc3" ]
|
||||
httpBackend.expectGET("/api/users/authorise_api?token=API_KEY").respond success: "Use of API Authorised"
|
||||
httpBackend.expectGET("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").respond returnedSuppliers
|
||||
httpBackend.expectGET("/api/enterprises/accessible?template=bulk_index&q[is_distributor_eq]=true").respond returnedDistributors
|
||||
httpBackend.expectGET("/api/order_cycles/accessible").respond returnedOrderCycles
|
||||
httpBackend.expectGET("/api/enterprises/accessible?template=bulk_index&q[sells_in][]=own&q[sells_in][]=any").respond returnedDistributors
|
||||
httpBackend.expectGET("/api/order_cycles/accessible?as=distributor&q[orders_close_at_gt]=SomeDate").respond returnedOrderCycles
|
||||
spyOn(scope, "initialiseVariables").andCallThrough()
|
||||
spyOn(scope, "fetchOrders").andReturn "nothing"
|
||||
#spyOn(returnedSuppliers, "unshift")
|
||||
@@ -33,8 +33,8 @@ describe "AdminOrderMgmtCtrl", ->
|
||||
httpBackend.flush()
|
||||
|
||||
expect(scope.suppliers).toEqual [{ id : '0', name : 'All' }, 'list of suppliers']
|
||||
expect(scope.distributors).toEqual [ { id : '0', name : 'All' }, 'list of distributors' ]
|
||||
expect(scope.orderCycles).toEqual [ { id : '0', name : 'All' }, 'oc1', 'oc2', 'oc3' ]
|
||||
expect(scope.distributors).toEqual [ { id : '0', name : 'All' }, 'list of distributors' ]
|
||||
expect(scope.orderCycles).toEqual [ { id : '0', name : 'All' }, 'oc1', 'oc2', 'oc3' ]
|
||||
|
||||
expect(scope.initialiseVariables.calls.length).toBe 1
|
||||
expect(scope.fetchOrders.calls.length).toBe 1
|
||||
@@ -43,7 +43,7 @@ describe "AdminOrderMgmtCtrl", ->
|
||||
describe "fetching orders", ->
|
||||
beforeEach ->
|
||||
scope.initialiseVariables()
|
||||
httpBackend.expectGET("/api/orders/managed?template=bulk_index;page=1;per_page=500;q[completed_at_not_null]=true;q[completed_at_gt]=SomeDate;q[completed_at_lt]=SomeDate").respond "list of orders"
|
||||
httpBackend.expectGET("/api/orders/managed?template=bulk_index;page=1;per_page=500;q[state_not_eq]=canceled;q[completed_at_not_null]=true;q[completed_at_gt]=SomeDate;q[completed_at_lt]=SomeDate").respond "list of orders"
|
||||
|
||||
it "makes a call to dataFetcher, with current start and end date parameters", ->
|
||||
scope.fetchOrders()
|
||||
|
||||
@@ -8,16 +8,71 @@ module OpenFoodNetwork
|
||||
let(:e1) { create(:enterprise) }
|
||||
let(:e2) { create(:enterprise) }
|
||||
|
||||
describe "finding managed and related enterprises granting a particular permission" do
|
||||
describe "as super admin" do
|
||||
before { allow(user).to receive(:admin?) { true } }
|
||||
|
||||
it "returns all enterprises" do
|
||||
expect(permissions.send(:managed_and_related_enterprises_granting, :some_permission)).to eq [e1, e2]
|
||||
end
|
||||
end
|
||||
|
||||
describe "as an enterprise user" do
|
||||
let(:e3) { create(:enterprise) }
|
||||
before { allow(user).to receive(:admin?) { false } }
|
||||
|
||||
it "returns only my managed enterprises any that have granting them P-OC" do
|
||||
expect(permissions).to receive(:managed_enterprises) { Enterprise.where(id: e1) }
|
||||
expect(permissions).to receive(:related_enterprises_granting).with(:some_permission) { Enterprise.where(id: e3) }
|
||||
expect(permissions.send(:managed_and_related_enterprises_granting, :some_permission)).to eq [e1, e3]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding managed and related enterprises granting or granted a particular permission" do
|
||||
describe "as super admin" do
|
||||
before { allow(user).to receive(:admin?) { true } }
|
||||
|
||||
it "returns all enterprises" do
|
||||
expect(permissions.send(:managed_and_related_enterprises_granting, :some_permission)).to eq [e1, e2]
|
||||
end
|
||||
end
|
||||
|
||||
describe "as an enterprise user" do
|
||||
let(:e3) { create(:enterprise) }
|
||||
let(:e4) { create(:enterprise) }
|
||||
before { allow(user).to receive(:admin?) { false } }
|
||||
|
||||
it "returns only my managed enterprises any that have granting them P-OC" do
|
||||
expect(permissions).to receive(:managed_enterprises) { Enterprise.where(id: e1) }
|
||||
expect(permissions).to receive(:related_enterprises_granting).with(:some_permission) { Enterprise.where(id: e3) }
|
||||
expect(permissions).to receive(:related_enterprises_granted).with(:some_permission) { Enterprise.where(id: e4) }
|
||||
expect(permissions.send(:managed_and_related_enterprises_with, :some_permission)).to eq [e1, e3, e4]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding enterprises that can be selected in order report filters" do
|
||||
let(:e) { double(:enterprise) }
|
||||
|
||||
it "returns managed and related enterprises with add_to_order_cycle permission" do
|
||||
expect(permissions).to receive(:managed_and_related_enterprises_with).
|
||||
with(:add_to_order_cycle).
|
||||
and_return([e])
|
||||
|
||||
expect(permissions.visible_enterprises_for_order_reports).to eq [e]
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding enterprises that can be added to an order cycle" do
|
||||
let(:e) { double(:enterprise) }
|
||||
|
||||
it "returns managed and related enterprises with add_to_order_cycle permission" do
|
||||
permissions.
|
||||
should_receive(:managed_and_related_enterprises_with).
|
||||
expect(permissions).to receive(:managed_and_related_enterprises_granting).
|
||||
with(:add_to_order_cycle).
|
||||
and_return([e])
|
||||
|
||||
permissions.order_cycle_enterprises.should == [e]
|
||||
expect(permissions.order_cycle_enterprises).to eq [e]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,7 +81,7 @@ module OpenFoodNetwork
|
||||
|
||||
it "returns managed and related enterprises with edit_profile permission" do
|
||||
permissions.
|
||||
should_receive(:managed_and_related_enterprises_with).
|
||||
should_receive(:managed_and_related_enterprises_granting).
|
||||
with(:edit_profile).
|
||||
and_return([e])
|
||||
|
||||
@@ -55,6 +110,7 @@ module OpenFoodNetwork
|
||||
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: hub.id) }
|
||||
permissions.stub(:admin?) { false }
|
||||
end
|
||||
|
||||
it "returns enterprises as hub_id => [producer, ...]" do
|
||||
@@ -133,7 +189,7 @@ module OpenFoodNetwork
|
||||
|
||||
it "returns managed and related enterprises with manage_products permission" do
|
||||
permissions.
|
||||
should_receive(:managed_and_related_enterprises_with).
|
||||
should_receive(:managed_and_related_enterprises_granting).
|
||||
with(:manage_products).
|
||||
and_return([e])
|
||||
|
||||
@@ -148,30 +204,31 @@ module OpenFoodNetwork
|
||||
|
||||
it "returns the enterprises" do
|
||||
permissions.stub(:managed_enterprises) { e2 }
|
||||
permissions.send(:related_enterprises_with, permission).should == [e1]
|
||||
permissions.send(:related_enterprises_granting, permission).should == [e1]
|
||||
end
|
||||
|
||||
it "returns an empty array when there are none" do
|
||||
permissions.stub(:managed_enterprises) { e1 }
|
||||
permissions.send(:related_enterprises_with, permission).should == []
|
||||
permissions.send(:related_enterprises_granting, permission).should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding enterprises that are managed or with a particular permission" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where('1=0') }
|
||||
permissions.stub(:related_enterprises_with) { Enterprise.where('1=0') }
|
||||
permissions.stub(:related_enterprises_granting) { Enterprise.where('1=0') }
|
||||
permissions.stub(:admin?) { false }
|
||||
end
|
||||
|
||||
it "returns managed enterprises" do
|
||||
permissions.should_receive(:managed_enterprises) { Enterprise.where(id: e1) }
|
||||
permissions.send(:managed_and_related_enterprises_with, permission).should == [e1]
|
||||
permissions.send(:managed_and_related_enterprises_granting, permission).should == [e1]
|
||||
end
|
||||
|
||||
it "returns permitted enterprises" do
|
||||
permissions.should_receive(:related_enterprises_with).with(permission).
|
||||
permissions.should_receive(:related_enterprises_granting).with(permission).
|
||||
and_return(Enterprise.where(id: e2))
|
||||
permissions.send(:managed_and_related_enterprises_with, permission).should == [e2]
|
||||
permissions.send(:managed_and_related_enterprises_granting, permission).should == [e2]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -180,10 +237,141 @@ module OpenFoodNetwork
|
||||
let!(:p) { create(:simple_product, supplier: e) }
|
||||
|
||||
it "returns supplied products" do
|
||||
permissions.should_receive(:related_enterprises_with).with(:manage_products) { [e] }
|
||||
permissions.should_receive(:related_enterprises_granting).with(:manage_products) { [e] }
|
||||
|
||||
permissions.send(:related_enterprise_products).should == [p]
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding orders that are visible in reports" do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:coordinator) { create(:distributor_enterprise) }
|
||||
let(:random_enterprise) { create(:distributor_enterprise) }
|
||||
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor]) }
|
||||
let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor ) }
|
||||
let!(:line_item) { create(:line_item, order: order) }
|
||||
let!(:producer) { create(:supplier_enterprise) }
|
||||
|
||||
before do
|
||||
permissions.stub(:coordinated_order_cycles) { Enterprise.where("1=0") }
|
||||
end
|
||||
|
||||
context "as the hub through which the order was placed" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: distributor) }
|
||||
end
|
||||
|
||||
it "should let me see the order" do
|
||||
expect(permissions.visible_orders).to include order
|
||||
end
|
||||
end
|
||||
|
||||
context "as the coordinator of the order cycle through which the order was placed" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: coordinator) }
|
||||
permissions.stub(:coordinated_order_cycles) { OrderCycle.where(id: order_cycle) }
|
||||
end
|
||||
|
||||
it "should let me see the order" do
|
||||
expect(permissions.visible_orders).to include order
|
||||
end
|
||||
end
|
||||
|
||||
context "as a producer which has granted P-OC to the distributor of an order" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: producer) }
|
||||
create(:enterprise_relationship, parent: producer, child: distributor, permissions_list: [:add_to_order_cycle])
|
||||
end
|
||||
|
||||
context "which contains my products" do
|
||||
before do
|
||||
line_item.product.supplier = producer
|
||||
line_item.product.save
|
||||
end
|
||||
|
||||
it "should let me see the order" do
|
||||
expect(permissions.visible_orders).to include order
|
||||
end
|
||||
end
|
||||
|
||||
context "which does not contain my products" do
|
||||
it "should not let me see the order" do
|
||||
expect(permissions.visible_orders).to_not include order
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as an enterprise that is a distributor in the order cycle, but not the distributor of the order" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: random_enterprise) }
|
||||
end
|
||||
|
||||
it "should not let me see the order" do
|
||||
expect(permissions.visible_orders).to_not include order
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding line items that are visible in reports" do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:coordinator) { create(:distributor_enterprise) }
|
||||
let(:random_enterprise) { create(:distributor_enterprise) }
|
||||
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, distributors: [distributor]) }
|
||||
let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor ) }
|
||||
let!(:line_item1) { create(:line_item, order: order) }
|
||||
let!(:line_item2) { create(:line_item, order: order) }
|
||||
let!(:producer) { create(:supplier_enterprise) }
|
||||
|
||||
before do
|
||||
permissions.stub(:coordinated_order_cycles) { Enterprise.where("1=0") }
|
||||
end
|
||||
|
||||
context "as the hub through which the parent order was placed" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: distributor) }
|
||||
end
|
||||
|
||||
it "should let me see the line_items" do
|
||||
expect(permissions.visible_line_items).to include line_item1, line_item2
|
||||
end
|
||||
end
|
||||
|
||||
context "as the coordinator of the order cycle through which the parent order was placed" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: coordinator) }
|
||||
permissions.stub(:coordinated_order_cycles) { OrderCycle.where(id: order_cycle) }
|
||||
end
|
||||
|
||||
it "should let me see the line_items" do
|
||||
expect(permissions.visible_line_items).to include line_item1, line_item2
|
||||
end
|
||||
end
|
||||
|
||||
context "as the manager producer which has granted P-OC to the distributor of the parent order" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: producer) }
|
||||
create(:enterprise_relationship, parent: producer, child: distributor, permissions_list: [:add_to_order_cycle])
|
||||
|
||||
line_item1.product.supplier = producer
|
||||
line_item1.product.save
|
||||
end
|
||||
|
||||
it "should let me see the line_items pertaining to variants I produce" do
|
||||
ps = permissions.visible_line_items
|
||||
expect(ps).to include line_item1
|
||||
expect(ps).to_not include line_item2
|
||||
end
|
||||
end
|
||||
|
||||
context "as an enterprise that is a distributor in the order cycle, but not the distributor of the parent order" do
|
||||
before do
|
||||
permissions.stub(:managed_enterprises) { Enterprise.where(id: random_enterprise) }
|
||||
end
|
||||
|
||||
it "should not let me see the line_items" do
|
||||
expect(permissions.visible_line_items).to_not include line_item1, line_item2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -558,35 +558,6 @@ describe Enterprise do
|
||||
enterprises.should include e2
|
||||
end
|
||||
end
|
||||
|
||||
describe "accessible_by" do
|
||||
it "shows only enterprises that are invloved in order cycles which are common to those managed by the given user" do
|
||||
user = create(:user)
|
||||
user.spree_roles = []
|
||||
e1 = create(:enterprise)
|
||||
e2 = create(:enterprise)
|
||||
e3 = create(:enterprise)
|
||||
e4 = create(:enterprise)
|
||||
e1.enterprise_roles.build(user: user).save
|
||||
oc = create(:simple_order_cycle, coordinator: e2, suppliers: [e1], distributors: [e3])
|
||||
|
||||
enterprises = Enterprise.accessible_by user
|
||||
enterprises.length.should == 3
|
||||
enterprises.should include e1, e2, e3
|
||||
enterprises.should_not include e4
|
||||
end
|
||||
|
||||
it "shows all enterprises for admin user" do
|
||||
user = create(:admin_user)
|
||||
e1 = create(:enterprise)
|
||||
e2 = create(:enterprise)
|
||||
|
||||
enterprises = Enterprise.managed_by user
|
||||
enterprises.length.should == 2
|
||||
enterprises.should include e1
|
||||
enterprises.should include e2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "callbacks" do
|
||||
|
||||
@@ -213,7 +213,7 @@ module Spree
|
||||
end
|
||||
|
||||
it "should be able to read some reports" do
|
||||
should have_ability([:admin, :index, :customers, :bulk_coop, :orders_and_fulfillment, :products_and_inventory], for: :report)
|
||||
should have_ability([:admin, :index, :customers, :bulk_coop, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], for: :report)
|
||||
end
|
||||
|
||||
it "should not be able to read other reports" do
|
||||
@@ -400,7 +400,7 @@ module Spree
|
||||
end
|
||||
|
||||
it "should be able to read some reports" do
|
||||
should have_ability([:admin, :index, :customers, :sales_tax, :group_buys, :bulk_coop, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory], for: :report)
|
||||
should have_ability([:admin, :index, :customers, :sales_tax, :group_buys, :bulk_coop, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], for: :report)
|
||||
end
|
||||
|
||||
it "should not be able to read other reports" do
|
||||
|
||||
128
spec/models/spree/payment_spec.rb
Normal file
128
spec/models/spree/payment_spec.rb
Normal file
@@ -0,0 +1,128 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe Payment do
|
||||
describe "available actions" do
|
||||
context "for most gateways" do
|
||||
let(:payment) { create(:payment, source: create(:credit_card)) }
|
||||
|
||||
it "can capture and void" do
|
||||
payment.actions.sort.should == %w(capture void).sort
|
||||
end
|
||||
|
||||
describe "when a payment has been taken" do
|
||||
before do
|
||||
payment.stub(:state) { 'completed' }
|
||||
payment.stub(:order) { double(:order, payment_state: 'credit_owed') }
|
||||
end
|
||||
|
||||
it "can void and credit" do
|
||||
payment.actions.sort.should == %w(void credit).sort
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "for Pin Payments" do
|
||||
let(:d) { create(:distributor_enterprise) }
|
||||
let(:pin) { Gateway::Pin.create! name: 'pin', distributor_ids: [d.id]}
|
||||
let(:payment) { create(:payment, source: create(:credit_card), payment_method: pin) }
|
||||
|
||||
it "does not void" do
|
||||
payment.actions.should_not include 'void'
|
||||
end
|
||||
|
||||
describe "when a payment has been taken" do
|
||||
before do
|
||||
payment.stub(:state) { 'completed' }
|
||||
payment.stub(:order) { double(:order, payment_state: 'credit_owed') }
|
||||
end
|
||||
|
||||
it "can refund instead of crediting" do
|
||||
payment.actions.should_not include 'credit'
|
||||
payment.actions.should include 'refund'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "refunding" do
|
||||
let(:payment) { create(:payment) }
|
||||
let(:success) { double(:success? => true, authorization: 'abc123') }
|
||||
let(:failure) { double(:success? => false) }
|
||||
|
||||
it "always checks the environment" do
|
||||
payment.payment_method.stub(:refund) { success }
|
||||
payment.should_receive(:check_environment)
|
||||
payment.refund!
|
||||
end
|
||||
|
||||
describe "calculating refund amount" do
|
||||
it "returns the parameter amount when given" do
|
||||
payment.send(:calculate_refund_amount, 123).should === 123.0
|
||||
end
|
||||
|
||||
it "refunds up to the value of the payment when the outstanding balance is larger" do
|
||||
payment.stub(:credit_allowed) { 123 }
|
||||
payment.stub(:order) { double(:order, outstanding_balance: 1000) }
|
||||
payment.send(:calculate_refund_amount).should == 123
|
||||
end
|
||||
|
||||
it "refunds up to the outstanding balance of the order when the payment is larger" do
|
||||
payment.stub(:credit_allowed) { 1000 }
|
||||
payment.stub(:order) { double(:order, outstanding_balance: 123) }
|
||||
payment.send(:calculate_refund_amount).should == 123
|
||||
end
|
||||
end
|
||||
|
||||
describe "performing refunds" do
|
||||
before do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.should_receive(:refund).and_return(success)
|
||||
end
|
||||
|
||||
it "performs the refund without payment profiles" do
|
||||
payment.payment_method.stub(:payment_profiles_supported?) { false }
|
||||
payment.refund!
|
||||
end
|
||||
|
||||
it "performs the refund with payment profiles" do
|
||||
payment.payment_method.stub(:payment_profiles_supported?) { true }
|
||||
payment.refund!
|
||||
end
|
||||
end
|
||||
|
||||
it "records the response" do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.stub(:refund).and_return(success)
|
||||
payment.should_receive(:record_response).with(success)
|
||||
payment.refund!
|
||||
end
|
||||
|
||||
it "records a payment on success" do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.stub(:refund).and_return(success)
|
||||
payment.stub(:record_response)
|
||||
|
||||
expect do
|
||||
payment.refund!
|
||||
end.to change(Payment, :count).by(1)
|
||||
|
||||
p = Payment.last
|
||||
p.order.should == payment.order
|
||||
p.source.should == payment
|
||||
p.payment_method.should == payment.payment_method
|
||||
p.amount.should == -123
|
||||
p.response_code.should == success.authorization
|
||||
p.state.should == 'completed'
|
||||
end
|
||||
|
||||
it "logs the error on failure" do
|
||||
payment.stub(:calculate_refund_amount) { 123 }
|
||||
payment.payment_method.stub(:refund).and_return(failure)
|
||||
payment.stub(:record_response)
|
||||
payment.should_receive(:gateway_error).with(failure)
|
||||
payment.refund!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user