diff --git a/app/controllers/api/orders_controller.rb b/app/controllers/api/orders_controller.rb index a03eb3b36b..e214575ea1 100644 --- a/app/controllers/api/orders_controller.rb +++ b/app/controllers/api/orders_controller.rb @@ -1,5 +1,10 @@ module Api class OrdersController < BaseController + def show + authorize! :read, order + render json: @order, serializer: Api::OrderDetailedSerializer + end + def index authorize! :admin, Spree::Order @@ -19,5 +24,9 @@ module Api each_serializer: Api::Admin::OrderSerializer ) end + + def order + @order ||= Spree::Order.find_by_number!(params[:id]) + end end end diff --git a/app/serializers/api/adjustment_serializer.rb b/app/serializers/api/adjustment_serializer.rb new file mode 100644 index 0000000000..5f0938cbcb --- /dev/null +++ b/app/serializers/api/adjustment_serializer.rb @@ -0,0 +1,8 @@ +module Api + class AdjustmentSerializer < ActiveModel::Serializer + attributes :id, :amount, :label, :eligible + attributes :source_type, :source_id + attributes :adjustable_type, :adjustable_id + attributes :originator_type, :originator_id + end +end diff --git a/app/serializers/api/order_detailed_serializer.rb b/app/serializers/api/order_detailed_serializer.rb new file mode 100644 index 0000000000..424f7d91b7 --- /dev/null +++ b/app/serializers/api/order_detailed_serializer.rb @@ -0,0 +1,12 @@ +module Api + class OrderDetailedSerializer < Api::Admin::OrderSerializer + has_one :shipping_method, serializer: Api::ShippingMethodSerializer + has_one :ship_address, serializer: Api::AddressSerializer + has_one :bill_address, serializer: Api::AddressSerializer + + has_many :line_items, serializer: Api::LineItemSerializer + has_many :adjustments, serializer: Api::AdjustmentSerializer + + has_many :payments, serializer: Api::PaymentSerializer + end +end diff --git a/config/routes/api.rb b/config/routes/api.rb index 94b9e180f0..75d3638016 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -15,7 +15,7 @@ Openfoodnetwork::Application.routes.draw do resources :variants, :only => [:index] - resources :orders, only: [:index] do + resources :orders, only: [:index, :show] do get :managed, on: :collection resources :shipments, :only => [:create, :update] do diff --git a/spec/controllers/api/orders_controller_spec.rb b/spec/controllers/api/orders_controller_spec.rb index 0819733e82..50a0614bb5 100644 --- a/spec/controllers/api/orders_controller_spec.rb +++ b/spec/controllers/api/orders_controller_spec.rb @@ -5,13 +5,17 @@ module Api include AuthenticationWorkflow render_views + let!(:regular_user) { create(:user) } + let!(:admin_user) { create(:admin_user) } + + let!(:distributor) { create(:distributor_enterprise) } + let!(:coordinator) { create(:distributor_enterprise) } + let!(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator) } + describe '#index' do - let!(:distributor) { create(:distributor_enterprise) } let!(:distributor2) { create(:distributor_enterprise) } - let!(:supplier) { create(:supplier_enterprise) } - let!(:coordinator) { create(:distributor_enterprise) } let!(:coordinator2) { create(:distributor_enterprise) } - let!(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator) } + let!(:supplier) { create(:supplier_enterprise) } let!(:order_cycle2) { create(:simple_order_cycle, coordinator: coordinator2) } let!(:order1) do create(:order, order_cycle: order_cycle, state: 'complete', completed_at: Time.zone.now, @@ -45,8 +49,6 @@ module Api create(:line_item_with_shipment, order: order3, product: create(:product, supplier: supplier)) end - let!(:regular_user) { create(:user) } - let!(:admin_user) { create(:admin_user) } context 'as a regular user' do before do @@ -156,6 +158,109 @@ module Api end end + describe "#show" do + let!(:order) { create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor ) } + + context "Resource not found" do + before { allow(controller).to receive(:spree_current_user) { admin_user } } + + it "when no order number is given" do + get :show, id: nil + expect_resource_not_found + end + + it "when order number given is not in the systen" do + get :show, id: "X1321313232" + expect_resource_not_found + end + + def expect_resource_not_found + expect(json_response).to eq( "error" => "The resource you were looking for could not be found." ) + expect(response.status).to eq(404) + end + end + + context "access" do + it "returns unauthorized, as a regular user" do + allow(controller).to receive(:spree_current_user) { regular_user } + get :show, id: order.number + assert_unauthorized! + end + + it "returns the order, as an admin user" do + allow(controller).to receive(:spree_current_user) { admin_user } + get :show, id: order.number + expect_order + end + + it "returns the order, as the order distributor owner" do + allow(controller).to receive(:spree_current_user) { order.distributor.owner } + get :show, id: order.number + expect_order + end + + it "returns unauthorized, as the order product's supplier owner" do + allow(controller).to receive(:spree_current_user) { order.line_items.first.variant.product.supplier.owner } + get :show, id: order.number + assert_unauthorized! + end + + it "returns the order, as the Order Cycle coorinator owner" do + allow(controller).to receive(:spree_current_user) { order.order_cycle.coordinator.owner } + get :show, id: order.number + expect_order + end + end + + context "as distributor owner" do + let!(:order) { create(:completed_order_with_fees, order_cycle: order_cycle, distributor: distributor ) } + + before { allow(controller).to receive(:spree_current_user) { order.distributor.owner } } + + it "can view an order not in a standard state" do + order.update_attributes(completed_at: nil, state: 'shipped') + get :show, id: order.number + expect_order + end + + it "returns an order with all required fields" do + get :show, id: order.number + expect_order + expect_detailed_attributes_to_be_present(json_response) + + expect(json_response[:bill_address][:address1]).to eq(order.bill_address.address1) + expect(json_response[:bill_address][:lastname]).to eq(order.bill_address.lastname) + expect(json_response[:ship_address][:address1]).to eq(order.ship_address.address1) + expect(json_response[:ship_address][:lastname]).to eq(order.ship_address.lastname) + expect(json_response[:shipping_method][:name]).to eq(order.shipping_method.name) + json_response[:adjustments].each do |adjustment| + if adjustment[:label] == "Transaction fee" + expect(adjustment[:amount]).to eq(order.adjustments.payment_fee.first.amount.to_s) + elsif json_response[:adjustments].first[:label] == "Shipping" + expect(adjustment[:amount]).to eq(order.adjustments.shipping.first.amount.to_s) + end + end + expect(json_response[:payments].first[:amount]).to eq(order.payments.first.amount.to_s) + expect(json_response[:line_items].size).to eq(order.line_items.size) + expect(json_response[:line_items].first[:variant][:product_name]). to eq(order.line_items.first.variant.product.name) + end + end + + def expect_order + expect(response.status).to eq 200 + expect_correct_order(json_response, order) + end + + def expect_correct_order(json_response, order) + expect(json_response[:number]).to eq(order.number) + expect(json_response[:email]).to eq(order.email) + end + + def expect_detailed_attributes_to_be_present(json_response) + expect(order_detailed_attributes.all?{ |attr| json_response.key? attr.to_s }).to eq(true) + end + end + private def serialized_orders(orders) @@ -181,5 +286,13 @@ module Api :distributor_name, :special_instructions, :payment_capture_path ] end + + def order_detailed_attributes + [ + :number, :item_total, :total, :state, :adjustment_total, :payment_total, + :completed_at, :shipment_state, :payment_state, :email, :special_instructions, + :adjustments, :payments, :bill_address, :ship_address, :line_items, :shipping_method + ] + end end end