diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index b369712fb1..d0f7c30ced 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -381,6 +381,10 @@ class Enterprise < ApplicationRecord sells == 'any' end + def is_producer + is_primary_producer && sells == 'none' + end + # Simplify enterprise categories for frontend logic and icons, and maybe other things. def category # Make this crazy logic human readable so we can argue about it sanely. diff --git a/app/models/spree/ability.rb b/app/models/spree/ability.rb index 3bce37ff4d..a14bd45d0b 100644 --- a/app/models/spree/ability.rb +++ b/app/models/spree/ability.rb @@ -47,7 +47,11 @@ module Spree add_group_management_abilities user if can_manage_groups? user add_product_management_abilities user if can_manage_products? user add_order_cycle_management_abilities user if can_manage_order_cycles? user - add_order_management_abilities user if can_manage_orders? user + if can_manage_orders? user + add_order_management_abilities user + elsif can_manage_line_items_in_orders? user + add_manage_line_items_abilities user + end add_relationship_management_abilities user if can_manage_relationships? user end @@ -81,7 +85,13 @@ module Spree # Users can manage orders if they have a sells own/any enterprise. def can_manage_orders?(user) - ( user.enterprises.map(&:sells) & %w(own any) ).any? + user.can_manage_orders? + end + + # Users can manage line items in orders if they have producer enterprise and + # any of order distributors allow them to edit their orders. + def can_manage_line_items_in_orders?(user) + user.can_manage_line_items_in_orders? end def can_manage_relationships?(user) @@ -343,6 +353,15 @@ module Spree end end + def add_manage_line_items_abilities(user) + can [:admin, :read, :index], Spree::Order do |order| + if order.distributor&.enable_producers_to_edit_orders + user_enterprises_ids = user.enterprises.ids + order.variants.any? { |variant| user_enterprises_ids.include?(variant.supplier_id) } + end + end + end + def add_relationship_management_abilities(user) can [:admin, :index, :create], EnterpriseRelationship can [:destroy], EnterpriseRelationship do |enterprise_relationship| diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index 10dc76c2f0..8b95992855 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -171,6 +171,14 @@ module Spree scope :invoiceable, -> { where(state: [:complete, :resumed]) } scope :by_state, lambda { |state| where(state:) } scope :not_state, lambda { |state| where.not(state:) } + scope :editable_by_producers, ->(enterprises) { + joins( + :distributor, line_items: :supplier + ).where( + supplier: { id: enterprises.ids }, + distributor: { enable_producers_to_edit_orders: true } + ) + } def initialize(*_args) @checkout_processing = nil diff --git a/app/models/spree/user.rb b/app/models/spree/user.rb index 0bbe9d60f2..a4de77ca00 100644 --- a/app/models/spree/user.rb +++ b/app/models/spree/user.rb @@ -147,6 +147,22 @@ module Spree Enterprise.joins(:connected_apps).merge(ConnectedApps::AffiliateSalesData.ready) end + # Users can manage orders if they have a sells own/any enterprise. or is admin + def can_manage_orders? + @can_manage_orders ||= (enterprises.pluck(:sells).intersect?(%w(own any)) or admin?) + end + + # Users can manage line items in orders if they have producer enterprise and + # any of order distributors allow them to edit their orders. + def can_manage_line_items_in_orders? + @can_manage_line_items_in_orders ||= begin + has_any_producer = enterprises.any?(&:is_producer) + has_producer_editable_orders = Spree::Order.editable_by_producers(enterprises).exists? + has_any_producer && has_producer_editable_orders + end + end + + protected def password_required? diff --git a/app/services/permissions/order.rb b/app/services/permissions/order.rb index d4c2f4b0ea..8af71079de 100644 --- a/app/services/permissions/order.rb +++ b/app/services/permissions/order.rb @@ -23,9 +23,16 @@ module Permissions # Any orders that the user can edit def editable_orders - orders = Spree::Order. - where(managed_orders_where_values. - or(coordinated_orders_where_values)) + orders = if @user.can_manage_line_items_in_orders_only? + Spree::Order.joins(:distributor).where( + id: produced_orders.select(:id), + distributor: { enable_producers_to_edit_orders: true } + ) + else + Spree::Order.where( + managed_orders_where_values.or(coordinated_orders_where_values) + ) + end filtered_orders(orders) end @@ -79,6 +86,13 @@ module Permissions reduce(:and) end + def produced_orders + Spree::Order.with_line_items_variants_and_products_outer. + where( + spree_variants: { supplier_id: @permissions.managed_enterprises.select("enterprises.id") } + ) + end + def produced_orders_where_values Spree::Order.with_line_items_variants_and_products_outer. where( diff --git a/app/views/spree/admin/orders/index.html.haml b/app/views/spree/admin/orders/index.html.haml index 26a7965a69..0deea9b1ab 100644 --- a/app/views/spree/admin/orders/index.html.haml +++ b/app/views/spree/admin/orders/index.html.haml @@ -3,9 +3,10 @@ - content_for :minimal_js, true -- content_for :page_actions do - %li - = button_link_to t('.new_order'), spree.new_admin_order_url, icon: 'icon-plus', id: 'admin_new_order' +- if can?(:create, Spree::Order) + - content_for :page_actions do + %li + = button_link_to t('.new_order'), spree.new_admin_order_url, icon: 'icon-plus', id: 'admin_new_order' = render partial: 'spree/admin/shared/order_sub_menu'