diff --git a/.env.example b/.env.example index 2667f8681..5f2b699aa 100644 --- a/.env.example +++ b/.env.example @@ -6,7 +6,7 @@ POSTGRES_USER=sofia_development POSTGRES_PASSWORD=1234567890abcdef POSTGRES_HOST=localhost -AMBER_CLIENT_ID= +AMBER_CLIENT_ID=987654321 AMBER_CLIENT_SECRET= FROM_EMAIL=noreply@societeitflux.nl @@ -29,7 +29,7 @@ COMPANY_KVK=41 032 169 SITE_NAME=S.O.F.I.A. SITE_SHORT_NAME=SOFIA -SITE_LONG_NAME=Streepsysteem voor de Ordentelijke Festiviteiten van Inleggend Alpha +SITE_LONG_NAME=Streepsysteem voor de Ordentelijke Festiviteiten van Inleggend Alpha SITE_ASSOCIATION=C.S.V. Alpha CODE_BEER=8010 diff --git a/.github/workflows/continuous-delivery.yml b/.github/workflows/continuous-delivery.yml index ae51732d9..c3fdf3010 100644 --- a/.github/workflows/continuous-delivery.yml +++ b/.github/workflows/continuous-delivery.yml @@ -48,7 +48,7 @@ jobs: stage: ${{ steps.get_metadata.outputs.stage }} steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Get metadata id: get_metadata @@ -98,7 +98,7 @@ jobs: - name: Checkout code if: fromJSON(needs.metadata.outputs.has_diff) - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Run merge if: fromJSON(needs.metadata.outputs.has_diff) @@ -161,19 +161,19 @@ jobs: fi - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ needs.merge.outputs.sha }} - name: Start deployment - uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3 # v1.4.0 + uses: bobheadxi/deployments@648679e8e4915b27893bd7dbc35cb504dc915bc8 # v1.5.0 id: start_deployment with: step: start env: ${{ needs.metadata.outputs.stage }} - name: Deploy - uses: appleboy/ssh-action@55dabf81b49d4120609345970c91507e2d734799 # v1.0.0 + uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0 env: STAGE: ${{ needs.metadata.outputs.stage }} with: @@ -188,7 +188,7 @@ jobs: docker-compose up -d - name: Finalize Sentry release - uses: getsentry/action-release@4744f6a65149f441c5f396d5b0877307c0db52c7 # v1.4.1 + uses: getsentry/action-release@e769183448303de84c5a06aaaddf9da7be26d6c7 # v1.7.0 env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ vars.SENTRY_ORG_NAME }} @@ -199,7 +199,7 @@ jobs: set_commits: skip - name: Finish deployment - uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3 # v1.4.0 + uses: bobheadxi/deployments@648679e8e4915b27893bd7dbc35cb504dc915bc8 # v1.5.0 if: steps.start_deployment.conclusion == 'success' && always() with: step: finish @@ -213,6 +213,8 @@ jobs: runs-on: ubuntu-latest needs: [branch_check, metadata, merge, continuous_integration, publish_image, deploy] if: (github.ref_name == 'staging' || github.ref_name == 'master') && always() + permissions: + checks: write steps: - name: Get conclusion id: get_conclusion @@ -228,11 +230,10 @@ jobs: done - name: Update Continuous Delivery check run - uses: guidojw/actions/update-check-run@abb0ee8d1336edf73383f2e5a09abd3a22f25b13 # v1.3.3 + uses: LouisBrunner/checks-action@6b626ffbad7cc56fd58627f774b9067e6118af23 # v2.0.0 with: - app_id: ${{ vars.GH_APP_ID }} - private_key: ${{ secrets.GH_APP_PRIVATE_KEY }} sha: ${{ needs.merge.outputs.sha }} + token: ${{ github.token }} name: Continuous Delivery conclusion: ${{ steps.get_conclusion.outputs.conclusion }} details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index df42dd331..5415ec8c3 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -25,12 +25,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} - name: Build test image - uses: guidojw/actions/build-docker-image@abb0ee8d1336edf73383f2e5a09abd3a22f25b13 # v1.3.3 + uses: guidojw/actions/build-docker-image@3ad963828827110a6b716a011f242bf01fdf1db4 # v1.4.7 with: file: Dockerfile build-args: | @@ -56,7 +56,7 @@ jobs: - 5432:5432 steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} @@ -71,7 +71,7 @@ jobs: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.6.26 - name: Load test image - uses: guidojw/actions/load-docker-image@abb0ee8d1336edf73383f2e5a09abd3a22f25b13 # v1.3.3 + uses: guidojw/actions/load-docker-image@3ad963828827110a6b716a011f242bf01fdf1db4 # v1.4.7 with: name: app @@ -80,8 +80,8 @@ jobs: RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} run: | EXIT_STATUS=0 - ./actionlint -ignore 'property "gh_app_private_key" is not defined' -ignore 'SC2153:' \ - -ignore 'property "sha" is not defined in object type {}' || EXIT_STATUS=$? + ./actionlint -ignore 'SC2153:' -ignore 'property "sha" is not defined in object type {}' || \ + EXIT_STATUS=$? docker run -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_HOST=localhost -e \ RAILS_MASTER_KEY --network=host app bin/ci.sh lint || EXIT_STATUS=$? exit $EXIT_STATUS @@ -105,7 +105,7 @@ jobs: - 5432:5432 steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} @@ -114,7 +114,7 @@ jobs: echo '::add-matcher::.github/problem-matchers/rspec.json' - name: Load test image - uses: guidojw/actions/load-docker-image@abb0ee8d1336edf73383f2e5a09abd3a22f25b13 # v1.3.3 + uses: guidojw/actions/load-docker-image@3ad963828827110a6b716a011f242bf01fdf1db4 # v1.4.7 with: name: app @@ -128,14 +128,14 @@ jobs: - name: Upload coverage report to Codecov if: ${{ !cancelled() }} - uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # v5.0.7 + uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 # v5.1.2 with: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} - name: Upload coverage report artifact if: ${{ !cancelled() }} - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: coverage path: coverage/ diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml index 3d65f8977..56917a14d 100644 --- a/.github/workflows/publish-image.yml +++ b/.github/workflows/publish-image.yml @@ -51,16 +51,16 @@ jobs: needs: metadata steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.sha }} fetch-depth: 0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0 - name: Login to GitHub Container Registry - uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # tag=v2.1.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ${{ vars.DOCKER_REGISTRY_URL }} username: ${{ github.repository_owner }} @@ -68,7 +68,7 @@ jobs: - name: Build and push image id: build_push_image - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: push: true context: . @@ -90,7 +90,7 @@ jobs: - name: Create Sentry release if: ${{ !(github.event_name == 'workflow_dispatch' && github.workflow == 'Publish Image') }} - uses: getsentry/action-release@4744f6a65149f441c5f396d5b0877307c0db52c7 # v1.4.1 + uses: getsentry/action-release@e769183448303de84c5a06aaaddf9da7be26d6c7 # v1.7.0 env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ vars.SENTRY_ORG_NAME }} @@ -106,6 +106,8 @@ jobs: runs-on: ubuntu-latest needs: [metadata, publish] if: github.event_name == 'workflow_dispatch' && github.workflow == 'Publish Image' && always() + permissions: + checks: write steps: - name: Get conclusion id: get_conclusion @@ -121,10 +123,9 @@ jobs: done - name: Update Publish Image check run - uses: guidojw/actions/update-check-run@abb0ee8d1336edf73383f2e5a09abd3a22f25b13 # v1.3.3 + uses: LouisBrunner/checks-action@6b626ffbad7cc56fd58627f774b9067e6118af23 # v2.0.0 with: - app_id: ${{ vars.GH_APP_ID }} - private_key: ${{ secrets.GH_APP_PRIVATE_KEY }} + token: ${{ github.token }} name: Publish Image conclusion: ${{ steps.get_conclusion.outputs.conclusion }} details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/Gemfile b/Gemfile index 29b4adc99..a2d532c92 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,7 @@ gem 'net-smtp', require: false gem 'omniauth', '~> 2.1.1' gem 'omniauth-oauth2', '~> 1.8.0' gem 'omniauth-rails_csrf_protection', '~> 1.0', '>= 1.0.1' -gem 'paper_trail', '~> 14.0.0' +gem 'paper_trail', '~> 16.0.0' gem 'paranoia', '~> 3.0.0' gem 'pg', '~> 1.5.3' gem 'puma', '~> 6.4.0' diff --git a/Gemfile.lock b/Gemfile.lock index ee088db67..c458309ec 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -101,7 +101,7 @@ GEM coderay (1.1.3) colorize (0.8.1) concurrent-ruby (1.3.4) - connection_pool (2.4.0) + connection_pool (2.4.1) consistency_fail (0.3.7) crass (1.0.6) devise (4.9.2) @@ -234,7 +234,7 @@ GEM mini_portile2 (2.8.8) mini_racer (0.6.3) libv8-node (~> 16.10.0.0) - minitest (5.24.1) + minitest (5.25.2) mollie-api-ruby (4.7.1) msgpack (1.7.0) multi_json (1.15.0) @@ -282,8 +282,8 @@ GEM omniauth (~> 2.0) open4 (1.3.4) orm_adapter (0.5.0) - paper_trail (14.0.0) - activerecord (>= 6.0) + paper_trail (16.0.0) + activerecord (>= 6.1) request_store (~> 1.4) parallel (1.23.0) paranoia (3.0.0) @@ -362,7 +362,7 @@ GEM redis-activesupport (5.3.0) activesupport (>= 3, < 8) redis-store (>= 1.3, < 2) - redis-client (0.14.1) + redis-client (0.22.2) connection_pool redis-rack (2.1.4) rack (>= 2.0.8, < 3) @@ -374,7 +374,7 @@ GEM redis-store (1.9.1) redis (>= 4, < 5) regexp_parser (2.8.0) - request_store (1.5.1) + request_store (1.7.0) rack (>= 1.4) responders (3.1.0) actionpack (>= 5.2) @@ -449,7 +449,7 @@ GEM sentry-ruby (~> 5.9.0) sidekiq (>= 3.0) shellany (0.0.1) - sidekiq (7.1.0) + sidekiq (7.1.6) concurrent-ruby (< 2) connection_pool (>= 2.3.0) rack (>= 2.2.4) @@ -569,7 +569,7 @@ DEPENDENCIES omniauth (~> 2.1.1) omniauth-oauth2 (~> 1.8.0) omniauth-rails_csrf_protection (~> 1.0, >= 1.0.1) - paper_trail (~> 14.0.0) + paper_trail (~> 16.0.0) paranoia (~> 3.0.0) pg (~> 1.5.3) pry-byebug diff --git a/app/controllers/activities_controller.rb b/app/controllers/activities_controller.rb index 1dacda3f9..6decfedf6 100644 --- a/app/controllers/activities_controller.rb +++ b/app/controllers/activities_controller.rb @@ -10,7 +10,7 @@ class ActivitiesController < ApplicationController # rubocop:disable Metrics/Cla def index authorize Activity - @activities = policy_scope(Activity.includes(%i[price_list created_by]) + @activities = policy_scope(Activity.includes(%i[price_list created_by locked_by]) .order(start_time: :desc) .page(params[:page])) @@ -19,7 +19,7 @@ def index end_time: 6.hours.from_now.beginning_of_hour ) - @price_lists_json = PriceList.all.to_json(only: %i[id name]) + @price_lists_json = PriceList.unarchived.to_json(only: %i[id name]) end def create @@ -63,8 +63,7 @@ def destroy def show # rubocop:disable Metrics/AbcSize, Metrics/MethodLength @activity = Activity.includes(:price_list, - { orders: [{ order_rows: :product }, :user, :created_by] }, - credit_mutations: [:user]).find(params[:id]) + { orders: [{ order_rows: :product }, :user, :created_by] }).find(params[:id]) authorize @activity @price_list = @activity.price_list @@ -122,8 +121,9 @@ def order_screen # rubocop:disable Metrics/MethodLength, Metrics/AbcSize def product_totals authorize Activity - activity = Activity.includes(:price_list, orders: [{ order_rows: :product }, :user]).find(params[:id]) - render json: activity.count_per_product(**params.permit(:user, :paid_with_pin, :paid_with_cash).to_h.symbolize_keys) + permitted_params = params.permit(:id, :user, :paid_with_pin, :paid_with_cash) + activity = Activity.includes(:price_list, orders: [{ order_rows: :product }, :user]).find(permitted_params[:id]) + render json: activity.count_per_product(**permitted_params.except(:id).to_h.symbolize_keys) end def sumup_callback diff --git a/app/controllers/credit_mutations_controller.rb b/app/controllers/credit_mutations_controller.rb index 4ed43df97..ddd09bc0f 100644 --- a/app/controllers/credit_mutations_controller.rb +++ b/app/controllers/credit_mutations_controller.rb @@ -1,12 +1,14 @@ class CreditMutationsController < ApplicationController before_action :authenticate_user! after_action :verify_authorized + after_action :verify_policy_scoped, only: :index def index - @credit_mutations = CreditMutation.includes(model_includes) + authorize CreditMutation + + @credit_mutations = policy_scope(CreditMutation.includes(model_includes) .order(created_at: :desc) - .page params[:page] - authorize @credit_mutations + .page(params[:page])) @new_mutation = CreditMutation.new end diff --git a/app/controllers/invoices_controller.rb b/app/controllers/invoices_controller.rb index 345b36547..ea5c788c2 100644 --- a/app/controllers/invoices_controller.rb +++ b/app/controllers/invoices_controller.rb @@ -6,7 +6,7 @@ class InvoicesController < ApplicationController def index authorize Invoice - @invoices = Invoice.all.order(created_at: :desc) + @invoices = Invoice.includes(:user, :activity, :rows).order(created_at: :desc) @activities_json = Activity.all.to_json(only: %i[id title start_time]) @invoice = Invoice.new @invoice.rows.build diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index 5a129a31e..73496787d 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -55,7 +55,7 @@ def destroy authorize @order - if @order.activity.locked? + if @order.activity&.locked? render json: {}, status: :forbidden else @order.order_rows.each do |order_row| diff --git a/app/controllers/price_lists_controller.rb b/app/controllers/price_lists_controller.rb index 6a1a02ec3..31783b5ed 100644 --- a/app/controllers/price_lists_controller.rb +++ b/app/controllers/price_lists_controller.rb @@ -2,12 +2,13 @@ class PriceListsController < ApplicationController before_action :authenticate_user! after_action :verify_authorized + after_action :verify_policy_scoped, only: :index def index - price_lists = PriceList.order(created_at: :desc) - products = Product.all.order(:id).includes(:product_prices) + authorize PriceList - authorize price_lists + price_lists = policy_scope(PriceList.order(created_at: :desc)) + products = Product.all.order(:id).includes(:product_prices) @price_list = PriceList.new diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ea3ff35e9..dadde077c 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -6,9 +6,9 @@ class UsersController < ApplicationController # rubocop:disable Metrics/ClassLen def index # rubocop:disable Metrics/AbcSize, Metrics/MethodLength authorize User - @manual_users = User.manual.active.order(:name) - @amber_users = User.in_amber.active.order(:name) - @inactive_users = User.inactive.order(:name) + @manual_users = User.manual.active.order(:name).select { |u| policy(u).show? } + @amber_users = User.in_amber.active.order(:name).select { |u| policy(u).show? } + @inactive_users = User.inactive.order(:name).select { |u| policy(u).show? } @users_credits = User.calculate_credits @manual_users_json = @manual_users.as_json(only: %w[id name]) diff --git a/app/javascript/components/activity/ProductTotals.vue b/app/javascript/components/activity/ProductTotals.vue index 83aa4e142..960c83798 100644 --- a/app/javascript/components/activity/ProductTotals.vue +++ b/app/javascript/components/activity/ProductTotals.vue @@ -23,6 +23,13 @@ {{orderTotal.amount}} x {{doubleToCurrency(orderTotal.price)}} + + Totaal + + + {{doubleToCurrency(totalAmount)}} + + @@ -56,6 +63,7 @@ export default { return { user: {}, orderTotals: [], + totalAmount: 0.0, isLoading: true }; }, @@ -71,6 +79,7 @@ export default { let params = {user: this.user.id, paid_with_cash: this.user.paid_with_cash, paid_with_pin: this.user.paid_with_pin}; this.$http.get('/activities/'+this.activity+'/product_totals', { params }).then((response) => { this.orderTotals = response.body; + this.totalAmount = this.orderTotals.reduce((a, b) => a + parseFloat(b.price), 0.0); this.isLoading = false; }); }, diff --git a/app/javascript/components/user/UsersTable.vue b/app/javascript/components/user/UsersTable.vue index cd648a70b..049919cce 100644 --- a/app/javascript/components/user/UsersTable.vue +++ b/app/javascript/components/user/UsersTable.vue @@ -26,7 +26,9 @@ - + @@ -53,7 +55,7 @@ export default { users: { type: Array, required: true - } + }, }, data() { diff --git a/app/javascript/packs/activity.js b/app/javascript/packs/activity.js index 8a59eeaba..839096a72 100644 --- a/app/javascript/packs/activity.js +++ b/app/javascript/packs/activity.js @@ -12,11 +12,18 @@ document.addEventListener('turbolinks:load', () => { var element = document.getElementById('activity'); if (element !== null) { + // Create a Vue instance for the ProductTotals component new Vue({ el: element, components: { ProductTotals } }); + + // Selects the first visible tab in the activity detail tabs + var firstTabEl = document.querySelector('#activityTabs li:first-child a'); + /* eslint-disable no-undef */ + var firstTab = new bootstrap.Tab(firstTabEl); + firstTab.show(); } }); diff --git a/app/models/credit_mutation.rb b/app/models/credit_mutation.rb index 711c15b5e..6a2f48bb2 100644 --- a/app/models/credit_mutation.rb +++ b/app/models/credit_mutation.rb @@ -8,6 +8,10 @@ class CreditMutation < ApplicationRecord validate :activity_not_locked + scope :linked_to_activity, (lambda { + where.not(activity: nil) + }) + before_destroy -> { throw(:abort) } def activity_not_locked diff --git a/app/models/order_row.rb b/app/models/order_row.rb index 407de1d78..aba802773 100644 --- a/app/models/order_row.rb +++ b/app/models/order_row.rb @@ -18,7 +18,9 @@ def copy_product_price end def no_changes_of_product_count_allowed - errors.add(:product_count, 'cannot be altered') if !new_record? && product_count_changed? && order.activity.locked? + return unless !new_record? && product_count_changed? && order.activity.locked? + + errors.add(:product_count, 'cannot be altered because the activity is locked') end def no_changes_of_price_per_product_allowed diff --git a/app/models/price_list.rb b/app/models/price_list.rb index 0b2fcca5c..dff0a3006 100644 --- a/app/models/price_list.rb +++ b/app/models/price_list.rb @@ -5,6 +5,8 @@ class PriceList < ApplicationRecord validates :name, presence: true + scope :unarchived, (-> { where(archived_at: nil) }) + def product_price_for(product) @product_price ||= ProductPrice.includes(:product).where(price_list: self) @product_price.find { |pp| pp.product == product } diff --git a/app/models/role.rb b/app/models/role.rb index 779a9ad66..55d9a47a2 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,5 +1,5 @@ class Role < ApplicationRecord - enum role_type: { treasurer: 0, main_bartender: 1 } + enum role_type: { treasurer: 0, main_bartender: 1, renting_manager: 2 } validates :role_type, :group_uid, presence: true has_many :roles_users, class_name: 'RolesUsers', dependent: :destroy, inverse_of: :role @@ -10,6 +10,8 @@ def name Rails.application.config.x.treasurer_title.capitalize elsif main_bartender? 'Hoofdtapper' + elsif renting_manager? + 'Verhuur manager' end end end diff --git a/app/models/user.rb b/app/models/user.rb index 04a78dc63..086e3d444 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -65,6 +65,10 @@ def main_bartender? @main_bartender ||= roles.where(role_type: :main_bartender).any? end + def renting_manager? + @renting_manager ||= roles.where(role_type: :renting_manager).any? + end + def update_role(groups) roles_to_have = Role.where(group_uid: groups) roles_users_to_have = roles_to_have.map { |role| RolesUsers.find_or_create_by(role: role, user: self) } diff --git a/app/policies/activity_policy.rb b/app/policies/activity_policy.rb index 66a7ce0a1..c92b4b72b 100644 --- a/app/policies/activity_policy.rb +++ b/app/policies/activity_policy.rb @@ -1,7 +1,7 @@ class ActivityPolicy < ApplicationPolicy class Scope < Scope def resolve - if user&.treasurer? + if user&.treasurer? || user&.renting_manager? scope elsif user&.main_bartender? scope.not_locked @@ -10,11 +10,11 @@ def resolve end def create? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def update? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def lock? @@ -26,18 +26,26 @@ def create_invoices? end def destroy? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end - def activity_report? - user&.treasurer? + def order_screen? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end - def order_screen? - user&.treasurer? || user&.main_bartender? + def summary? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def product_totals? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? + end + + def orders? + user&.treasurer? || user&.renting_manager? + end + + def credit_mutations? + user&.treasurer? end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index fa8cc4a04..91965a362 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -7,7 +7,7 @@ def initialize(user, record) end def index? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def show? @@ -31,7 +31,7 @@ def edit? end def destroy? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def scope diff --git a/app/policies/credit_mutation_policy.rb b/app/policies/credit_mutation_policy.rb index cd9124f39..60ab794dc 100644 --- a/app/policies/credit_mutation_policy.rb +++ b/app/policies/credit_mutation_policy.rb @@ -1,5 +1,19 @@ class CreditMutationPolicy < ApplicationPolicy - def create? + class Scope < Scope + def resolve + if user&.treasurer? + scope + elsif user&.main_bartender? + scope.linked_to_activity + end + end + end + + def index? user&.treasurer? || user&.main_bartender? end + + def create? + user&.treasurer? || (user&.main_bartender? && record.activity.present?) + end end diff --git a/app/policies/invoice_policy.rb b/app/policies/invoice_policy.rb index 781bb644f..bbc1f1f13 100644 --- a/app/policies/invoice_policy.rb +++ b/app/policies/invoice_policy.rb @@ -1,6 +1,6 @@ class InvoicePolicy < ApplicationPolicy def index? - user&.treasurer? + user&.treasurer? || user&.renting_manager? end def send_invoice? diff --git a/app/policies/order_policy.rb b/app/policies/order_policy.rb index b75e8b1ce..31b5db26d 100644 --- a/app/policies/order_policy.rb +++ b/app/policies/order_policy.rb @@ -1,7 +1,7 @@ class OrderPolicy < ApplicationPolicy class Scope < Scope - def resolve - if user&.treasurer? || user&.main_bartender? + def resolve # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + if user&.treasurer? || user&.renting_manager? || user&.main_bartender? scope elsif user scope.orders_for(user) @@ -14,6 +14,6 @@ def index? end def create? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end end diff --git a/app/policies/price_list_policy.rb b/app/policies/price_list_policy.rb index a28c98dec..545464094 100644 --- a/app/policies/price_list_policy.rb +++ b/app/policies/price_list_policy.rb @@ -1,10 +1,20 @@ class PriceListPolicy < ApplicationPolicy + class Scope < Scope + def resolve + if user&.treasurer? + scope + elsif user&.renting_manager? || user&.main_bartender? + scope.unarchived + end + end + end + def index? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def show? - user&.treasurer? || user&.main_bartender? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def create? diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index 80b8604e3..98a09333d 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -1,6 +1,6 @@ class UserPolicy < ApplicationPolicy def index? - user&.treasurer? + user&.treasurer? || user&.renting_manager? || user&.main_bartender? end def refresh_user_list? @@ -12,7 +12,7 @@ def search? end def show? - user&.treasurer? || record == user + user&.treasurer? || (user&.renting_manager? && User.manual.exists?(id: record)) || record == user end def json? @@ -20,6 +20,6 @@ def json? end def activities? - user&.treasurer? || record == user + show? end end diff --git a/app/views/activities/index.html.erb b/app/views/activities/index.html.erb index b2693cf2d..96cfa8e34 100644 --- a/app/views/activities/index.html.erb +++ b/app/views/activities/index.html.erb @@ -47,7 +47,11 @@ <%= activity.price_list.name %> <% end %> diff --git a/app/views/activities/show.html.erb b/app/views/activities/show.html.erb index 46d429286..24a97315c 100644 --- a/app/views/activities/show.html.erb +++ b/app/views/activities/show.html.erb @@ -3,7 +3,7 @@ <%= render 'edit_modal' %> <% end %> - @@ -87,172 +93,188 @@
-
-
- <% if @credit_mutations.empty? && @orders.empty? %> -
-
{{ user.id }}{{ user.name }} + {{ user.name }} + € {{parseFloat(user.credit).toFixed(2)}}
- <%= link_to activity.created_by.name, activity.created_by %> + <% if policy(activity.created_by).show? %> + <%= link_to activity.created_by.name, activity.created_by %> + <% else %> + <%= activity.created_by.name %> + <% end%>
- + <% if policy(Activity).summary? %> +
+
+ <% if @credit_mutations.empty? && @orders.empty? %> +
+
+ + + + + +
+

+ + Er zijn nog geen bestellingen en er is nog niet ingelegd + +

+
+ + <% else %> +
+ + + + + + + + + + <% Product.categories.each do |category| %> + <% if Rails.application.config.x.codes[category.first.to_sym] != nil %> + + + + + + <% end %> + <% end %> + + + + + + +
ResultaatCodeCredit
<%= t(category.first).capitalize %> + <%= Rails.application.config.x.codes[category.first.to_sym] %> + + <%= number_to_currency(@revenue_by_category[category[0]] || 0, unit: '€') %> +
Totaal opbrengsten + <%= number_to_currency(@revenue_total, unit: '€') %> + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BalansCodeDebitCredit
Inleg Zatladder Inlegsysteem<%= Rails.application.config.x.codes[:credit_mutation] %> + <%= number_to_currency(@credit_mutations_total, unit: '€') %> +
Contante bestellingen<%= number_to_currency(@revenue_with_cash, unit: '€') %>
+ + Totaal kas + + <%= Rails.application.config.x.codes[:cash] %><%= number_to_currency(@cash_total, unit: '€') %>
Omzet Pin<%= Rails.application.config.x.codes[:pin] %><%= number_to_currency(@revenue_with_pin, unit: '€') %>
Omzet Zatladder Inlegsysteem<%= Rails.application.config.x.codes[:credit_mutation] %><%= number_to_currency(@revenue_with_credit, unit: '€') %>
+
+ <% end %> + + <% end %> + <% if policy(Activity).credit_mutations? %> +
+
+ + <% if @credit_mutations.empty? %> - -

- Er zijn nog geen bestellingen en er is nog niet ingelegd + Er zijn nog geen correcties en er is nog niet ingelegd

-
- <% else %> -
- + <% else %> - - - + + + + - <% Product.categories.each do |category| %> - <% if Rails.application.config.x.codes[category.first.to_sym] != nil %> - - - - - - <% end %> + <% @credit_mutations.each do |mutation| %> + + + + + + <% end %> - - - - - -
ResultaatCodeCredit#TijdGebruikerBedrag
<%= t(category.first).capitalize %> - <%= Rails.application.config.x.codes[category.first.to_sym] %> - - <%= number_to_currency(@revenue_by_category[category[0]] || 0, unit: '€') %> -
<%= mutation.id %><%= l mutation.created_at, format: :time_only %> + <% if policy(User).show? %> + <%= link_to mutation.user.name, mutation.user %> + <% else %> + <%= mutation.user.name %> + <% end %> + <%= number_to_currency(mutation.amount, unit: '€') %>
Totaal opbrengsten - <%= number_to_currency(@revenue_total, unit: '€') %> - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BalansCodeDebitCredit
Inleg Zatladder Inlegsysteem<%= Rails.application.config.x.codes[:credit_mutation] %> - <%= number_to_currency(@credit_mutations_total, unit: '€') %> -
Contante bestellingen<%= number_to_currency(@revenue_with_cash, unit: '€') %>
- - Totaal kas - - <%= Rails.application.config.x.codes[:cash] %><%= number_to_currency(@cash_total, unit: '€') %>
Omzet Pin<%= Rails.application.config.x.codes[:pin] %><%= number_to_currency(@revenue_with_pin, unit: '€') %>
Omzet Zatladder Inlegsysteem<%= Rails.application.config.x.codes[:credit_mutation] %><%= number_to_currency(@revenue_with_credit, unit: '€') %>
-
- <% end %>
- -
-
- - <% if @credit_mutations.empty? %> - - - - <% else %> - - - - - - - - - - <% @credit_mutations.each do |mutation| %> - - - - - - <% end %> - - <% end %> -
-

- - Er zijn nog geen correcties en er is nog niet ingelegd - -

-
#TijdGebruikerBedrag
<%= mutation.id %><%= l mutation.created_at, format: :time_only %><%= link_to mutation.user.name, mutation.user %><%= number_to_currency(mutation.amount, unit: '€') %>
+ +
- - <% if current_user.treasurer? %> + <% end %> + <% if policy(Activity).orders? %>
@@ -301,7 +323,7 @@ <% order.order_rows.each_with_index do |order_row, i| %> <%= order_row.product.name %> <% if order_row.product_count > 1 %> - ( <%= order_row.product_count %> x) + (<%= order_row.product_count %>x) <% end %> <% if i < order.order_rows.size - 1 %> , @@ -316,13 +338,15 @@ <% end %> -
-
-
- + <% if policy(Activity).product_totals? %> +
+
+
+ +
-
+ <% end %>
diff --git a/app/views/index/index.html.erb b/app/views/index/index.html.erb index 45247a974..0c14c6fb6 100644 --- a/app/views/index/index.html.erb +++ b/app/views/index/index.html.erb @@ -3,7 +3,7 @@
- <% if current_user&.treasurer? || current_user&.main_bartender? %> + <% if current_user&.treasurer? || current_user&.renting_manager? || current_user&.main_bartender? %>
Welkom, <%= current_user.name %> @@ -49,7 +49,7 @@ <% end %> - <% if @current_activities&.any? %> + <% if policy(Activity).order_screen? && @current_activities&.any? %>

Direct naar het streepscherm diff --git a/app/views/invoices/_modal.html.erb b/app/views/invoices/_modal.html.erb index 9b229b0dd..0f3e144e9 100644 --- a/app/views/invoices/_modal.html.erb +++ b/app/views/invoices/_modal.html.erb @@ -19,7 +19,7 @@
@@ -27,7 +29,9 @@

- + <% if policy(Invoice).send_invoice? %> + + <% end %> @@ -40,7 +44,11 @@ <%= link_to invoice.human_id, invoice %> - + + <% end %> <% end %> diff --git a/app/views/invoices/show.html.erb b/app/views/invoices/show.html.erb index bfcd4daa1..e4f9d064a 100644 --- a/app/views/invoices/show.html.erb +++ b/app/views/invoices/show.html.erb @@ -63,7 +63,7 @@
Naam Mailadres StatusVerstuurVerstuur
- <%= link_to invoice.user.name, invoice.user %> + <% if policy(invoice.user).show? %> + <%= link_to invoice.user.name, invoice.user %> + <% else %> + <%= invoice.user.name %> + <% end%> <%= link_to invoice.activity.title, invoice.activity %> @@ -57,13 +65,15 @@ <%= t(invoice.status).humanize %> - <% if invoice.pending? %> - <%= simple_form_for invoice, wrapper: :horizontal_form, url: send_invoice_invoice_path(id: invoice.id), method: :post do |f| %> - <%= f.button :submit, 'Factuur versturen', class: 'btn btn-primary' %> + <% if policy(Invoice).send_invoice? %> + + <% if invoice.pending? %> + <%= simple_form_for invoice, wrapper: :horizontal_form, url: send_invoice_invoice_path(id: invoice.id), method: :post do |f| %> + <%= f.button :submit, 'Factuur versturen', class: 'btn btn-primary' %> + <% end %> <% end %> - <% end %> -
- <% unless @invoice.paid? %> + <% if policy(Invoice).send_invoice? && !@invoice.paid? %> <%= link_to pay_invoice_url @invoice.token do %> <% end %> diff --git a/app/views/partials/_navigation_bar.html.erb b/app/views/partials/_navigation_bar.html.erb index a70b5f94b..e4ebdf08f 100644 --- a/app/views/partials/_navigation_bar.html.erb +++ b/app/views/partials/_navigation_bar.html.erb @@ -13,14 +13,14 @@ <%= fa_icon 'home', class: 'me-2', text: 'Home' %> <% end %> - <% if current_user&.main_bartender? || current_user&.treasurer? %> + <% if policy(Activity).index? %> <% end %> - <% if current_user&.treasurer? %> + <% if current_user&.treasurer? || current_user&.renting_manager? %> + <% end %> + <% if current_user&.treasurer? %> + <% end %> + <% if policy(:zatladder).index? %> + <% end %> + <% if policy(Invoice).index? %> - <% if policy(Payment).index? %> - - <% end %> + <% end %> + <% if policy(Payment).index? %> + + <% end %> + <% if policy(:finance_overview).index? %>
-
- - + <% if policy(PriceList).create? %> + + <% end %>
+ <% if policy(PriceList).archive? %> +
+ + +
+ <% end %> - +
@@ -39,7 +43,7 @@ - @@ -91,7 +95,7 @@ {{ productPriceToCurrency(findPrice(product, priceList)) }} - diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index d43f11001..9617f796c 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -9,23 +9,27 @@ <%= content_tag :div, id: 'users-index', data: {manual_users: @manual_users_json, amber_users: @amber_users_json, inactive_users: @inactive_users_json} do %>

Handmatig aangemaakte gebruikers

- + <% if policy(User).create? %> + + <% end %>

<%= Rails.application.config.x.site_association %> gebruikers

- - <%= link_to refresh_user_list_users_path, class: 'btn btn-primary btn-sm me-1' do %> - <%= fa_icon 'refresh' %> - Synchroniseer gebruikers - <% end %> - + <% if policy(User).refresh_user_list? %> + + <%= link_to refresh_user_list_users_path, class: 'btn btn-primary btn-sm me-1' do %> + <%= fa_icon 'refresh' %> + Synchroniseer gebruikers + <% end %> + + <% end %>
diff --git a/db/seeds.rb b/db/seeds.rb index a307eeab8..3043c9a22 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -42,7 +42,7 @@ FactoryBot.create_list(:invoice, 3, :with_rows) p 'Seeding roles...' -Role.create(role_type: :treasurer, group_uid: 3) -Role.create(role_type: :main_bartender, group_uid: 3) -Role.create(role_type: :main_bartender, group_uid: 2) +Role.create(role_type: :treasurer, group_uid: 4) +Role.create(role_type: :renting_manager, group_uid: 5) +Role.create(role_type: :main_bartender, group_uid: 6) # rubocop:enable Rails/Output diff --git a/spec/controllers/activities_controller/create_invoices_spec.rb b/spec/controllers/activities_controller/create_invoices_spec.rb index 5bc9c24b7..95ee573cb 100644 --- a/spec/controllers/activities_controller/create_invoices_spec.rb +++ b/spec/controllers/activities_controller/create_invoices_spec.rb @@ -21,6 +21,13 @@ expect(request.status).to eq 403 end + it 'unauthenticated when as renting-manager' do + sign_in create(:user, :renting_manager) + request + + expect(request.status).to eq 403 + end + context 'when as treasurer' do let(:user) { create(:user, :treasurer) } diff --git a/spec/controllers/activities_controller/create_spec.rb b/spec/controllers/activities_controller/create_spec.rb index b138e9701..91c31f2c3 100644 --- a/spec/controllers/activities_controller/create_spec.rb +++ b/spec/controllers/activities_controller/create_spec.rb @@ -9,11 +9,26 @@ post :create, params: { activity: activity.attributes } end - it 'creates a new activity' do + it 'treasurer creates a new activity' do sign_in create(:user, :treasurer) expect { request }.to(change(Activity, :count).by(1)) end + it 'renting-manager creates a new activity' do + sign_in create(:user, :renting_manager) + expect { request }.to(change(Activity, :count).by(1)) + end + + it 'main-bartender creates a new activity' do + sign_in create(:user, :main_bartender) + expect { request }.to(change(Activity, :count).by(1)) + end + + it 'user cannot create a new activity' do + sign_in create(:user) + expect { request }.not_to change(Activity, :count) + end + it 'redirects after create' do sign_in create(:user, :treasurer) request diff --git a/spec/controllers/activities_controller/destroy_spec.rb b/spec/controllers/activities_controller/destroy_spec.rb index 43b89c29f..7333ef35c 100644 --- a/spec/controllers/activities_controller/destroy_spec.rb +++ b/spec/controllers/activities_controller/destroy_spec.rb @@ -23,7 +23,7 @@ it { expect(request.status).to eq 403 } end - describe 'when as main bartender' do + describe 'when as main-bartender' do let(:user) { create(:user, :main_bartender) } context 'when with empty activity' do @@ -39,6 +39,22 @@ end end + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + context 'when with empty activity' do + it { expect(request.status).to eq 302 } + it { expect(Activity.count).to eq 0 } + end + + context 'when with non-empty activity' do + let(:additional_records) { create(:order, activity: activity) } + + it { expect(request.status).to eq 302 } + it { expect(Activity.count).to eq 1 } + end + end + describe 'when as treasurer' do let(:user) { create(:user, :treasurer) } diff --git a/spec/controllers/activities_controller/index_spec.rb b/spec/controllers/activities_controller/index_spec.rb index a0222d81d..ca837556f 100644 --- a/spec/controllers/activities_controller/index_spec.rb +++ b/spec/controllers/activities_controller/index_spec.rb @@ -32,6 +32,17 @@ end end + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it do + expect(request.status).to eq 200 + expect(assigns(:activities).size).to eq 3 + expect(assigns(:price_lists_json)).to eq PriceList.all.to_json(only: %i[id name]) + expect(assigns(:activity)).to be_an_instance_of(Activity) + end + end + describe 'when as treasurer' do let(:user) { create(:user, :treasurer) } diff --git a/spec/controllers/activities_controller/lock_spec.rb b/spec/controllers/activities_controller/lock_spec.rb index 416f14bd9..e12c328db 100644 --- a/spec/controllers/activities_controller/lock_spec.rb +++ b/spec/controllers/activities_controller/lock_spec.rb @@ -21,6 +21,13 @@ expect(request.status).to eq 403 end + it 'unauthenticated when as renting-manager' do + sign_in create(:user, :renting_manager) + request + + expect(request.status).to eq 403 + end + context 'when as treasurer' do let(:user) { create(:user, :treasurer) } diff --git a/spec/controllers/activities_controller/product_totals_spec.rb b/spec/controllers/activities_controller/product_totals_spec.rb index 57d0cfb1c..1b5838c3a 100644 --- a/spec/controllers/activities_controller/product_totals_spec.rb +++ b/spec/controllers/activities_controller/product_totals_spec.rb @@ -33,6 +33,76 @@ expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 6 expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 end + + context 'when filtering for user' do + let(:order) { create(:order, activity: activity, user: user) } + let(:params) { { id: activity.id, user: user.id } } + + it do + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 2 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + end + + context 'when filtering for cash' do + let(:order) { create(:order, activity: activity, paid_with_cash: true) } + let(:params) { { id: activity.id, paid_with_cash: true } } + + it do + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 2 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + end + + context 'when filtering for pin' do + let(:order) { create(:order, activity: activity, paid_with_pin: true) } + let(:params) { { id: activity.id, paid_with_pin: true } } + + it do + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 2 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + end + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it do + expect(request.status).to eq 200 + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 6 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + + context 'when filtering for user' do + let(:order) { create(:order, activity: activity, user: user) } + let(:params) { { id: activity.id, user: user.id } } + + it do + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 2 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + end + + context 'when filtering for cash' do + let(:order) { create(:order, activity: activity, paid_with_cash: true) } + let(:params) { { id: activity.id, paid_with_cash: true } } + + it do + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 2 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + end + + context 'when filtering for pin' do + let(:order) { create(:order, activity: activity, paid_with_pin: true) } + let(:params) { { id: activity.id, paid_with_pin: true } } + + it do + expect(json.find { |item| item['name'] == products.first[:name] }['amount']).to eq 2 + expect(json.find { |item| item['name'] == products.last[:name] }['amount']).to eq 3 + end + end end describe 'when as treasurer' do diff --git a/spec/controllers/activities_controller/update_spec.rb b/spec/controllers/activities_controller/update_spec.rb index cb0472769..f9bf95e37 100644 --- a/spec/controllers/activities_controller/update_spec.rb +++ b/spec/controllers/activities_controller/update_spec.rb @@ -29,6 +29,13 @@ it { expect(activity.title).to eq 'New Title' } end + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it { expect(request.status).to eq 302 } + it { expect(activity.title).to eq 'New Title' } + end + describe 'when as treasurer' do let(:user) { create(:user, :treasurer) } diff --git a/spec/controllers/credit_mutations_controller/create_spec.rb b/spec/controllers/credit_mutations_controller/create_spec.rb new file mode 100644 index 000000000..df987739f --- /dev/null +++ b/spec/controllers/credit_mutations_controller/create_spec.rb @@ -0,0 +1,67 @@ +require 'rails_helper' + +describe CreditMutationsController, type: :controller do + describe 'POST create' do + let(:user) { create(:user) } + let(:credit_mutation) do + build(:credit_mutation, user: user) + end + let(:credit_mutation_with_activity) do + build(:credit_mutation, activity: create(:activity), user: user) + end + let(:request1) do + post :create, params: { credit_mutation: credit_mutation.attributes, format: :json } + end + let(:request2) do + post :create, params: { credit_mutation: credit_mutation_with_activity.attributes, format: :json } + end + + context 'when as treasurer' do + it 'creates a new credit_mutation' do + sign_in create(:user, :treasurer) + expect { request1 }.to(change(CreditMutation, :count).by(1)) + end + + it 'creates a new credit_mutation linked to an activity' do + sign_in create(:user, :treasurer) + expect { request2 }.to(change(CreditMutation, :count).by(1)) + end + end + + context 'when as renting-manager' do + it 'creates a new credit_mutation' do + sign_in create(:user, :renting_manager) + expect { request1 }.not_to change(CreditMutation, :count) + end + + it 'creates a new credit_mutation linked to an activity' do + sign_in create(:user, :renting_manager) + expect { request2 }.not_to change(CreditMutation, :count) + end + end + + context 'when as main-bartender' do + it 'creates a new credit_mutation' do + sign_in create(:user, :main_bartender) + expect { request1 }.not_to change(CreditMutation, :count) + end + + it 'creates a new credit_mutation linked to an activity' do + sign_in create(:user, :main_bartender) + expect { request2 }.to(change(CreditMutation, :count).by(1)) + end + end + + context 'when as user' do + it 'creates a new credit_mutation' do + sign_in create(:user) + expect { request1 }.not_to change(CreditMutation, :count) + end + + it 'creates a new credit_mutation linked to an activity' do + sign_in create(:user) + expect { request2 }.not_to change(CreditMutation, :count) + end + end + end +end diff --git a/spec/controllers/credit_mutations_controller/index_spec.rb b/spec/controllers/credit_mutations_controller/index_spec.rb new file mode 100644 index 000000000..088cedf93 --- /dev/null +++ b/spec/controllers/credit_mutations_controller/index_spec.rb @@ -0,0 +1,50 @@ +require 'rails_helper' + +describe CreditMutationsController, type: :controller do + describe 'GET index' do + let(:credit_mutation) { create(:credit_mutation, user: create(:user)) } + let(:credit_mutation_with_activity) { create(:credit_mutation, activity: create(:activity), user: create(:user)) } + let(:request) { get :index } + + before do + credit_mutation + credit_mutation_with_activity + sign_in user + request + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it 'shows credit_mutations' do + expect(request.status).to eq 200 + expect(assigns(:credit_mutations).size).to eq 2 + end + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it 'shows credit_mutations' do + expect(response).to have_http_status(:forbidden) + end + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it 'shows credit_mutations' do + expect(request.status).to eq 200 + expect(assigns(:credit_mutations).size).to eq 1 + end + end + + describe 'when as user' do + let(:user) { create(:user) } + + it 'shows credit_mutations' do + expect(response).to have_http_status(:forbidden) + end + end + end +end diff --git a/spec/controllers/invoices_controller/create_spec.rb b/spec/controllers/invoices_controller/create_spec.rb new file mode 100644 index 000000000..892eec3f2 --- /dev/null +++ b/spec/controllers/invoices_controller/create_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +describe InvoicesController, type: :controller do + describe 'POST create' do + let(:invoice) do + build(:invoice, user: create(:user), activity: create(:activity, :locked)) + end + let(:request) do + post :create, params: { invoice: invoice.attributes } + end + + it 'treasurer creates a new invoice' do + sign_in create(:user, :treasurer) + expect { request }.to(change(Invoice, :count).by(1)) + end + + it 'renting-manager cannot create a new invoice' do + sign_in create(:user, :renting_manager) + expect { request }.not_to change(Invoice, :count) + end + + it 'main-bartender cannot create a new invoice' do + sign_in create(:user, :main_bartender) + expect { request }.not_to change(Invoice, :count) + end + + it 'user cannot create a new invoice' do + sign_in create(:user) + expect { request }.not_to change(Invoice, :count) + end + + it 'redirects after create' do + sign_in create(:user, :treasurer) + request + expect(response).to be_redirect + end + end +end diff --git a/spec/controllers/invoices_controller/index_spec.rb b/spec/controllers/invoices_controller/index_spec.rb index afe2d4101..ab7fad4e9 100644 --- a/spec/controllers/invoices_controller/index_spec.rb +++ b/spec/controllers/invoices_controller/index_spec.rb @@ -17,6 +17,24 @@ end end + context 'when as renting-manager' do + it 'shows invoices' do + sign_in create(:user, :renting_manager) + get :index + + expect(assigns(:invoices).size).to eq invoices.size + end + end + + context 'when as main-bartender' do + it 'forbids' do + sign_in create(:user, :main_bartender) + get :index + + expect(response).to have_http_status(:forbidden) + end + end + context 'when as user' do it 'forbids' do sign_in create(:user) diff --git a/spec/controllers/invoices_controller/show_spec.rb b/spec/controllers/invoices_controller/show_spec.rb index e6cfc6453..a18763cd2 100644 --- a/spec/controllers/invoices_controller/show_spec.rb +++ b/spec/controllers/invoices_controller/show_spec.rb @@ -17,6 +17,24 @@ end end + context 'when as renting-manager' do + it 'shows invoice' do + sign_in create(:user, :renting_manager) + get :show, params: { id: invoice.id } + + expect(response).to have_http_status(:ok) + end + end + + context 'when as main-bartender' do + it 'forbids' do + sign_in create(:user, :main_bartender) + get :show, params: { id: invoice.id } + + expect(response).to have_http_status(:forbidden) + end + end + context 'when as user' do it 'forbids' do sign_in create(:user) diff --git a/spec/controllers/orders_controller/create_spec.rb b/spec/controllers/orders_controller/create_spec.rb new file mode 100644 index 000000000..d863db985 --- /dev/null +++ b/spec/controllers/orders_controller/create_spec.rb @@ -0,0 +1,74 @@ +require 'rails_helper' + +describe OrdersController, type: :controller do + describe 'POST create' do + let(:activity) { create(:activity) } + let(:locked_activity) { create(:activity) } + let(:order) do + build(:order, activity: activity, user: create(:user)) + end + let(:order_on_locked_activity) do + build(:order, activity: locked_activity, user: create(:user)) + end + let(:request) do + post :create, params: { order: order.attributes } + end + let(:request_on_locked_activity) do + post :create, params: { order: order_on_locked_activity.attributes } + end + + before do + locked_activity.update(locked_by: create(:user)) + + sign_in user + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it 'when with order on activity' do + expect { request }.to(change(Order, :count).by(1)) + end + + it 'when with order on locked activty' do + expect { request_on_locked_activity }.not_to change(Order, :count) + end + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it 'when with order on activity' do + expect { request }.to(change(Order, :count).by(1)) + end + + it 'when with order on locked activty' do + expect { request_on_locked_activity }.not_to change(Order, :count) + end + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it 'when with order on activity' do + expect { request }.to(change(Order, :count).by(1)) + end + + it 'when with order on locked activty' do + expect { request_on_locked_activity }.not_to change(Order, :count) + end + end + + describe 'when as user' do + let(:user) { create(:user) } + + it 'when with order on activity' do + expect { request }.not_to change(Order, :count) + end + + it 'when with order on locked activty' do + expect { request_on_locked_activity }.not_to change(Order, :count) + end + end + end +end diff --git a/spec/controllers/orders_controller/destroy_spec.rb b/spec/controllers/orders_controller/destroy_spec.rb new file mode 100644 index 000000000..6a5ef5beb --- /dev/null +++ b/spec/controllers/orders_controller/destroy_spec.rb @@ -0,0 +1,101 @@ +require 'rails_helper' + +describe OrdersController, type: :controller do + describe 'DELETE destroy' do + let(:activity) { create(:activity) } + let(:locked_activity) { create(:activity) } + let(:order) do + create(:order, activity: activity, user: create(:user)) + end + let(:order_on_locked_activity) do + create(:order, activity: locked_activity, user: create(:user)) + end + let(:products) { activity.price_list.products.sample(2) } + let(:request) do + delete :destroy, params: { id: order.id } + end + let(:request_on_locked_activity) do + delete :destroy, params: { id: order_on_locked_activity.id } + end + + before do + create(:order_row, order: order, product_count: 2, product: activity.price_list.products.first) + create(:order_row, order: order_on_locked_activity, product_count: 2, product: locked_activity.price_list.products.first) + locked_activity.update(locked_by: create(:user)) + + sign_in user + end + + describe 'when without permission' do + let(:user) { create(:user) } + + it 'when with order on activity' do + request + expect(request.status).to eq 403 + expect(Order.count).to eq 2 + expect(Order.first.order_rows.first.product_count).to eq 2 + end + + it 'when with order on locked activty' do + request_on_locked_activity + expect(request_on_locked_activity.status).to eq 403 + expect(Order.count).to eq 2 + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it 'when with order on activity' do + request + expect(request.status).to eq 200 + expect(Order.count).to eq 2 + expect(Order.first.order_rows.first.product_count).to eq 0 + end + + it 'when with order on locked activity' do + request_on_locked_activity + expect(response).to have_http_status(:forbidden) + expect(Order.count).to eq 2 + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it 'when with order on activity' do + request + expect(request.status).to eq 200 + expect(Order.count).to eq 2 + expect(Order.first.order_rows.first.product_count).to eq 0 + end + + it 'when with order on locked activity' do + request_on_locked_activity + expect(response).to have_http_status(:forbidden) + expect(Order.count).to eq 2 + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it 'when with order on activity' do + request + expect(request.status).to eq 200 + expect(Order.count).to eq 2 + expect(Order.first.order_rows.first.product_count).to eq 0 + end + + it 'when with order on locked activity' do + request_on_locked_activity + expect(response).to have_http_status(:forbidden) + expect(Order.count).to eq 2 + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + end +end diff --git a/spec/controllers/orders_controller/index_spec.rb b/spec/controllers/orders_controller/index_spec.rb index 8164c9cfc..46974cc6e 100644 --- a/spec/controllers/orders_controller/index_spec.rb +++ b/spec/controllers/orders_controller/index_spec.rb @@ -3,13 +3,18 @@ describe OrdersController, type: :controller do describe 'GET index' do let(:alice) { create(:user, :treasurer) } + let(:bob) { create(:user, :renting_manager) } + let(:carl) { create(:user, :main_bartender) } + let(:amber) { create(:user, :from_amber) } let(:eve) { create(:user) } let(:orders_alice) { create_list(:order, 2, user: alice) } + let(:orders_amber) { create_list(:order, 2, user: amber) } let(:orders_eve) { create_list(:order, 2, user: eve) } before do orders_alice + orders_amber orders_eve end @@ -21,12 +26,65 @@ expect(Order.where(user: alice)).to match_array assigns(:orders) end - it 'show other users orders' do + it 'show other manual users orders' do sign_in alice get :index, params: { user_id: eve.id, format: :json } expect(Order.where(user: eve)).to match_array assigns(:orders) end + + it 'shows other amber users orders' do + sign_in alice + get :index, params: { user_id: amber.id, format: :json } + + expect(Order.where(user: amber)).to match_array assigns(:orders) + end + end + + context 'when as renting-manager' do + it 'shows own orders' do + sign_in bob + get :index, params: { user_id: bob.id, format: :json } + + expect(Order.where(user: bob)).to match_array assigns(:orders) + end + + it 'shows other manual users orders' do + sign_in bob + get :index, params: { user_id: eve.id, format: :json } + + expect(Order.where(user: eve)).to match_array assigns(:orders) + end + + it 'shows other amber users orders' do + sign_in bob + get :index, params: { user_id: amber.id, format: :json } + + expect(Order.where(user: amber)).to match_array assigns(:orders) + end + end + + context 'when as main-bartender' do + it 'shows own orders' do + sign_in carl + get :index, params: { user_id: carl.id, format: :json } + + expect(Order.where(user: carl)).to match_array assigns(:orders) + end + + it 'shows other manual users orders' do + sign_in carl + get :index, params: { user_id: eve.id, format: :json } + + expect(Order.where(user: eve)).to match_array assigns(:orders) + end + + it 'shows other amber users orders' do + sign_in carl + get :index, params: { user_id: amber.id, format: :json } + + expect(Order.where(user: amber)).to match_array assigns(:orders) + end end context 'when as normal user' do @@ -37,12 +95,19 @@ expect(Order.where(user: eve)).to match_array assigns(:orders) end - it 'user cannot see other users orders' do + it 'user cannot see other manual users orders' do sign_in eve get :index, params: { user_id: alice.id, format: :json } expect(assigns(:orders)).to be_empty end + + it 'user cannot see other amber users orders' do + sign_in eve + get :index, params: { user_id: amber.id, format: :json } + + expect(assigns(:orders)).to be_empty + end end end end diff --git a/spec/controllers/orders_controller/update_spec.rb b/spec/controllers/orders_controller/update_spec.rb new file mode 100644 index 000000000..1da12b7ad --- /dev/null +++ b/spec/controllers/orders_controller/update_spec.rb @@ -0,0 +1,95 @@ +require 'rails_helper' + +describe OrdersController, type: :controller do + describe 'PUT update' do + let(:activity) { create(:activity) } + let(:locked_activity) { create(:activity) } + let(:order) do + create(:order, activity: activity, user: create(:user)) + end + let(:order_on_locked_activity) do + create(:order, activity: locked_activity, user: create(:user)) + end + let(:products) { activity.price_list.products.sample(2) } + let(:request) do + put :update, params: { id: order.id, order_rows_attributes: [{ id: order.order_rows.first.id, product_count: 3 }] } + end + let(:request_on_locked_activity) do + put :update, + params: { id: order_on_locked_activity.id, + order_rows_attributes: [{ id: order_on_locked_activity.order_rows.first.id, product_count: 3 }] } + end + + before do + create(:order_row, order: order, product_count: 2, product: activity.price_list.products.first) + create(:order_row, order: order_on_locked_activity, product_count: 2, product: locked_activity.price_list.products.first) + locked_activity.update(locked_by: create(:user)) + + sign_in user + end + + describe 'when without permission' do + let(:user) { create(:user) } + + it 'when with order on activity' do + request + expect(request.status).to eq 403 + expect(Order.first.order_rows.first.product_count).to eq 2 + end + + it 'when with order on locked activty' do + request_on_locked_activity + expect(request_on_locked_activity.status).to eq 403 + expect(Order.first.order_rows.first.product_count).to eq 2 + end + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it 'when with order on activity' do + request + expect(request.status).to eq 200 + expect(Order.first.order_rows.first.product_count).to eq 3 + end + + it 'when with order on locked activity' do + request_on_locked_activity + expect(response).to have_http_status(:unprocessable_entity) + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it 'when with order on activity' do + request + expect(request.status).to eq 200 + expect(Order.first.order_rows.first.product_count).to eq 3 + end + + it 'when with order on locked activity' do + request_on_locked_activity + expect(response).to have_http_status(:unprocessable_entity) + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it 'when with order on activity' do + request + expect(request.status).to eq 200 + expect(Order.first.order_rows.first.product_count).to eq 3 + end + + it 'when with order on locked activity' do + request_on_locked_activity + expect(response).to have_http_status(:unprocessable_entity) + expect(Order.first.order_rows.last.product_count).to eq 2 + end + end + end +end diff --git a/spec/controllers/payments_controller/index_spec.rb b/spec/controllers/payments_controller/index_spec.rb index 1290c97b5..495c5ec7d 100644 --- a/spec/controllers/payments_controller/index_spec.rb +++ b/spec/controllers/payments_controller/index_spec.rb @@ -17,6 +17,24 @@ end end + context 'when as renting-manager' do + it 'forbids' do + sign_in create(:user, :renting_manager) + get :index + + expect(response).to have_http_status(:forbidden) + end + end + + context 'when as main-bartender' do + it 'forbids' do + sign_in create(:user, :main_bartender) + get :index + + expect(response).to have_http_status(:forbidden) + end + end + context 'when as user' do it 'forbids' do sign_in create(:user) diff --git a/spec/controllers/price_lists_controller/archive_spec.rb b/spec/controllers/price_lists_controller/archive_spec.rb new file mode 100644 index 000000000..d50a8d4d8 --- /dev/null +++ b/spec/controllers/price_lists_controller/archive_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +describe PriceListsController, type: :controller do + describe 'POST /:id/archive' do + let(:price_list) do + create(:price_list) + end + let(:request) do + post :archive, params: { id: price_list.id, format: :json } + end + + before do + sign_in user + request + price_list.reload + end + + describe 'treasurer can archive a price_list' do + let(:user) { create(:user, :treasurer) } + + it { expect(request.status).to eq 200 } + it { expect(price_list.archived_at.today?).to be true } + end + + describe 'renting-manager cannot archive a price_list' do + let(:user) { create(:user, :renting_manager) } + + it { expect(request.status).to eq 403 } + end + + describe 'main-bartender cannot archive a price_list' do + let(:user) { create(:user, :main_bartender) } + + it { expect(request.status).to eq 403 } + end + + describe 'user cannot archive a price_list' do + let(:user) { create(:user) } + + it { expect(request.status).to eq 403 } + end + end +end diff --git a/spec/controllers/price_lists_controller/create_spec.rb b/spec/controllers/price_lists_controller/create_spec.rb new file mode 100644 index 000000000..d95fd49b4 --- /dev/null +++ b/spec/controllers/price_lists_controller/create_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +describe PriceListsController, type: :controller do + describe 'POST create' do + let(:price_list) do + build(:price_list) + end + let(:request) do + post :create, params: { price_list: price_list.attributes } + end + + it 'treasurer can create a new price_list' do + sign_in create(:user, :treasurer) + expect { request }.to(change(PriceList, :count).by(1)) + end + + it 'renting-manager cannot create a new price_list' do + sign_in create(:user, :renting_manager) + expect { request }.not_to change(PriceList, :count) + end + + it 'main-bartender cannot create a new price_list' do + sign_in create(:user, :main_bartender) + expect { request }.not_to change(PriceList, :count) + end + + it 'user cannot create a new price_list' do + sign_in create(:user) + expect { request }.not_to change(PriceList, :count) + end + + it 'redirects after create' do + sign_in create(:user, :treasurer) + request + expect(response).to be_redirect + end + end +end diff --git a/spec/controllers/price_lists_controller/index_spec.rb b/spec/controllers/price_lists_controller/index_spec.rb new file mode 100644 index 000000000..dbf3f234a --- /dev/null +++ b/spec/controllers/price_lists_controller/index_spec.rb @@ -0,0 +1,52 @@ +require 'rails_helper' + +describe PriceListsController, type: :controller do + describe 'GET index' do + let(:archived_price_lists) { create_list(:price_list, 3, :archived) } + let(:unarchived_price_lists) { create_list(:price_list, 3) } + + before do + archived_price_lists + unarchived_price_lists + end + + context 'when as treasurer' do + it 'shows all price_lists' do + sign_in create(:user, :treasurer) + get :index + + expect(assigns(:price_lists_json)).to eq PriceList.all.order(created_at: :desc).to_json(except: %i[created_at updated_at + deleted_at]) + end + end + + context 'when as renting-manager' do + it 'shows unarchived price_lists' do + sign_in create(:user, :renting_manager) + get :index + + expect(assigns(:price_lists_json)).to eq PriceList.unarchived.order(created_at: :desc).to_json(except: %i[created_at updated_at + deleted_at]) + end + end + + context 'when as main-bartender' do + it 'shows unarchived price_lists' do + sign_in create(:user, :main_bartender) + get :index + + expect(assigns(:price_lists_json)).to eq PriceList.unarchived.order(created_at: :desc).to_json(except: %i[created_at updated_at + deleted_at]) + end + end + + context 'when as user' do + it 'forbids' do + sign_in create(:user) + get :index + + expect(response).to have_http_status(:forbidden) + end + end + end +end diff --git a/spec/controllers/price_lists_controller/unarchive_spec.rb b/spec/controllers/price_lists_controller/unarchive_spec.rb new file mode 100644 index 000000000..796728f49 --- /dev/null +++ b/spec/controllers/price_lists_controller/unarchive_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +describe PriceListsController, type: :controller do + describe 'POST /:id/unarchive' do + let(:price_list) do + create(:price_list) + end + let(:request) do + post :unarchive, params: { id: price_list.id, format: :json } + end + + before do + sign_in user + request + price_list.reload + end + + describe 'treasurer can unarchive a price_list' do + let(:user) { create(:user, :treasurer) } + + it { expect(request.status).to eq 200 } + it { expect(price_list.archived_at).to be_nil } + end + + describe 'renting-manager cannot unarchive a price_list' do + let(:user) { create(:user, :renting_manager) } + + it { expect(request.status).to eq 403 } + end + + describe 'main-bartender cannot unarchive a price_list' do + let(:user) { create(:user, :main_bartender) } + + it { expect(request.status).to eq 403 } + end + + describe 'user cannot unarchive a price_list' do + let(:user) { create(:user) } + + it { expect(request.status).to eq 403 } + end + end +end diff --git a/spec/controllers/price_lists_controller/update_spec.rb b/spec/controllers/price_lists_controller/update_spec.rb new file mode 100644 index 000000000..7cb136db8 --- /dev/null +++ b/spec/controllers/price_lists_controller/update_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +describe PriceListsController, type: :controller do + describe 'PUT update' do + let(:price_list) do + create(:price_list) + end + let(:request) do + put :update, params: { id: price_list.id, price_list: price_list.attributes } + end + + before do + sign_in user + price_list.name = 'New Name' + request + price_list.reload + end + + describe 'when without permission' do + let(:user) { create(:user) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it { expect(request.status).to eq 302 } + it { expect(price_list.name).to eq 'New Name' } + end + end +end diff --git a/spec/controllers/products_controller/create_spec.rb b/spec/controllers/products_controller/create_spec.rb new file mode 100644 index 000000000..51101e35b --- /dev/null +++ b/spec/controllers/products_controller/create_spec.rb @@ -0,0 +1,32 @@ +require 'rails_helper' + +describe ProductsController, type: :controller do + describe 'POST create' do + let(:product) do + build(:product) + end + let(:request) do + post :create, params: { product: product.attributes } + end + + it 'treasurer can create a new product' do + sign_in create(:user, :treasurer) + expect { request }.to(change(Product, :count).by(1)) + end + + it 'renting-manager cannot create a new product' do + sign_in create(:user, :renting_manager) + expect { request }.not_to change(Product, :count) + end + + it 'main-bartender cannot create a new product' do + sign_in create(:user, :main_bartender) + expect { request }.not_to change(Product, :count) + end + + it 'user cannot create a new product' do + sign_in create(:user) + expect { request }.not_to change(Product, :count) + end + end +end diff --git a/spec/controllers/products_controller/update_spec.rb b/spec/controllers/products_controller/update_spec.rb new file mode 100644 index 000000000..8c5c6de7d --- /dev/null +++ b/spec/controllers/products_controller/update_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +describe ProductsController, type: :controller do + describe 'PUT update' do + let(:product) do + create(:product, product_prices: [create(:product_price)]) + end + let(:request) do + put :update, + params: { id: product.id, + product: product.attributes.merge({ product_prices_attributes: [product.product_prices.first.attributes] }) } + end + + before do + sign_in user + product.product_prices.first.price = 10.00 + request + product.reload + end + + describe 'when without permission' do + let(:user) { create(:user) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it { expect(request.status).to eq 200 } + it { expect(product.product_prices.first.price).to eq 10.00 } + end + end +end diff --git a/spec/controllers/users_controller/create_spec.rb b/spec/controllers/users_controller/create_spec.rb new file mode 100644 index 000000000..b2de00877 --- /dev/null +++ b/spec/controllers/users_controller/create_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' + +describe UsersController, type: :controller do + describe 'POST create' do + let(:user) do + build(:user, :manual) + end + let(:request) do + post :create, params: { user: user.attributes } + end + + it 'treasurer can create a new user' do + sign_in create(:user, :treasurer) + expect { request }.to(change(User, :count).by(1)) + end + + it 'renting-manager cannot create a new user' do + sign_in create(:user, :renting_manager) + expect { request }.not_to change(User, :count) + end + + it 'main-bartender cannot create a new user' do + sign_in create(:user, :main_bartender) + expect { request }.not_to change(User, :count) + end + + it 'user cannot create a new user' do + sign_in create(:user) + expect { request }.not_to change(User, :count) + end + + it 'redirects after create' do + sign_in create(:user, :treasurer) + request + expect(response).to be_redirect + end + end +end diff --git a/spec/controllers/users_controller/index_spec.rb b/spec/controllers/users_controller/index_spec.rb new file mode 100644 index 000000000..4d2b37dba --- /dev/null +++ b/spec/controllers/users_controller/index_spec.rb @@ -0,0 +1,58 @@ +require 'rails_helper' + +describe UsersController, type: :controller do + describe 'GET index' do + let(:alice) { create(:user, :treasurer, :manual) } + let(:bob) { create(:user, :renting_manager, :manual) } + let(:carl) { create(:user, :main_bartender, :manual) } + let(:amber) { create(:user, :from_amber) } + let(:eve) { create(:user, :manual) } + + before do + alice + bob + carl + amber + eve + end + + context 'when as treasurer' do + it 'shows all users' do + sign_in alice + get :index + + expect(assigns(:manual_users).size).to eq 4 + expect(assigns(:amber_users).size).to eq 1 + end + end + + context 'when as renting-manager' do + it 'shows manual users' do + sign_in bob + get :index + + expect(assigns(:manual_users).size).to eq 4 + expect(assigns(:amber_users).size).to eq 0 + end + end + + context 'when as main-bartender' do + it 'shows own user' do + sign_in carl + get :index + + expect(assigns(:manual_users).size).to eq 1 + expect(assigns(:amber_users).size).to eq 0 + end + end + + context 'when as user' do + it 'forbids' do + sign_in eve + get :index + + expect(response).to have_http_status(:forbidden) + end + end + end +end diff --git a/spec/controllers/users_controller/show_spec.rb b/spec/controllers/users_controller/show_spec.rb new file mode 100644 index 000000000..b1b383987 --- /dev/null +++ b/spec/controllers/users_controller/show_spec.rb @@ -0,0 +1,77 @@ +require 'rails_helper' + +describe UsersController, type: :controller do + describe 'GET show' do + let(:amber) { create(:user, :from_amber) } + let(:eve) { create(:user, :manual) } + + before do + amber + eve + end + + context 'when as treasurer' do + it 'shows manual user' do + sign_in create(:user, :treasurer) + get :show, params: { id: eve.id } + + expect(response).to have_http_status(:ok) + end + + it 'shows amber user' do + sign_in create(:user, :treasurer) + get :show, params: { id: amber.id } + + expect(response).to have_http_status(:ok) + end + end + + context 'when as renting-manager' do + it 'shows manual user' do + sign_in create(:user, :renting_manager) + get :show, params: { id: eve.id } + + expect(response).to have_http_status(:ok) + end + + it 'forbids showing amber user' do + sign_in create(:user, :renting_manager) + get :show, params: { id: amber.id } + + expect(response).to have_http_status(:forbidden) + end + end + + context 'when as main-bartender' do + it 'forbids showing manual user' do + sign_in create(:user, :main_bartender) + get :show, params: { id: eve.id } + + expect(response).to have_http_status(:forbidden) + end + + it 'forbids showing amber user' do + sign_in create(:user, :main_bartender) + get :show, params: { id: amber.id } + + expect(response).to have_http_status(:forbidden) + end + end + + context 'when as user' do + it 'forbids showing manual user' do + sign_in create(:user) + get :show, params: { id: eve.id } + + expect(response).to have_http_status(:forbidden) + end + + it 'forbids showing amber user' do + sign_in create(:user) + get :show, params: { id: amber.id } + + expect(response).to have_http_status(:forbidden) + end + end + end +end diff --git a/spec/controllers/users_controller/update_spec.rb b/spec/controllers/users_controller/update_spec.rb new file mode 100644 index 000000000..3d3d6a2ef --- /dev/null +++ b/spec/controllers/users_controller/update_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +describe UsersController, type: :controller do + describe 'PUT update' do + let(:user) do + create(:user, :manual) + end + let(:request) do + put :update, params: { id: user.id, user: user.attributes } + end + + before do + sign_in user + user.name = 'New Name' + request + user.reload + end + + describe 'when as user' do + let(:user) { create(:user) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as main-bartender' do + let(:user) { create(:user, :main_bartender) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as renting-manager' do + let(:user) { create(:user, :renting_manager) } + + it { expect(request.status).to eq 403 } + end + + describe 'when as treasurer' do + let(:user) { create(:user, :treasurer) } + + it { expect(request.status).to eq 302 } + it { expect(user.name).to eq 'New Name' } + end + end +end diff --git a/spec/factories/price_list.rb b/spec/factories/price_list.rb index 9960d1804..2044f8c6d 100644 --- a/spec/factories/price_list.rb +++ b/spec/factories/price_list.rb @@ -16,6 +16,10 @@ with_specific_products { true } end + trait :archived do + archived_at { 1.day.ago } + end + after(:create) do |price_list, evaluator| if evaluator.with_all_products Product.all.each do |product| diff --git a/spec/factories/role.rb b/spec/factories/role.rb index 6deb8d414..4f59d06b0 100644 --- a/spec/factories/role.rb +++ b/spec/factories/role.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :role do - role_type { %i[treasurer main_bartender].sample } + role_type { %i[treasurer main_bartender renting_manager].sample } group_uid { rand(1...100) } end end diff --git a/spec/factories/user.rb b/spec/factories/user.rb index 6beb9806d..5ead18872 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -15,5 +15,19 @@ user.roles = [FactoryBot.create(:role, role_type: :main_bartender)] end end + + trait(:renting_manager) do + after :create do |user, _evaluator| + user.roles = [FactoryBot.create(:role, role_type: :renting_manager)] + end + end + + trait(:from_amber) do + provider { 'amber_oauth2' } + end + + trait(:manual) do + provider { nil } + end end end diff --git a/spec/models/role_spec.rb b/spec/models/role_spec.rb index 1e782d2f7..7e16e5980 100644 --- a/spec/models/role_spec.rb +++ b/spec/models/role_spec.rb @@ -26,7 +26,13 @@ it { expect(role.name).to eq Rails.application.config.x.treasurer_title.capitalize } end - context 'when main bartender' do + context 'when renting-manager' do + subject(:role) { build_stubbed(:role, role_type: :renting_manager) } + + it { expect(role.name).to eq 'Verhuur manager' } + end + + context 'when main-bartender' do subject(:role) { build_stubbed(:role, role_type: :main_bartender) } it { expect(role.name).to eq 'Hoofdtapper' }
ID +
+ @@ -101,19 +105,22 @@
- + <% if policy(Product).create? %> + + <% end %>
- - + + +