diff --git a/app/controllers/api/products_controller.rb b/app/controllers/api/products_controller.rb new file mode 100644 index 000000000..b48777b5c --- /dev/null +++ b/app/controllers/api/products_controller.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +# API Controller for resources of type Product +# Products are used in store +class API::ProductsController < API::ApiController + before_action :authenticate_user!, except: %i[index show] + before_action :set_product, only: %i[update destroy] + + def index + @products = ProductService.list + end + + def show; end + + def create + authorize Product + @product = Product.new(product_params) + if @product.save + render status: :created + else + render json: @product.errors.full_messages, status: :unprocessable_entity + end + end + + def update + authorize @product + + if @product.update(product_params) + render status: :ok + else + render json: @product.errors.full_messages, status: :unprocessable_entity + end + end + + def destroy + authorize @product + @product.destroy + head :no_content + end + + private + + def set_product + @product = Product.find(params[:id]) + end + + def product_params + params.require(:product).permit(:name, :slug, :sku, :description, :is_active, + :product_category_id, :amount, :quantity_min, + :low_stock_alert, :low_stock_threshold) + end +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 000000000..48d439822 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,3 @@ +class Product < ApplicationRecord + belongs_to :product_category +end diff --git a/app/policies/product_policy.rb b/app/policies/product_policy.rb new file mode 100644 index 000000000..f64026b79 --- /dev/null +++ b/app/policies/product_policy.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Check the access policies for API::ProductsController +class ProductPolicy < ApplicationPolicy + def create? + user.privileged? + end + + def update? + user.privileged? + end + + def destroy? + user.privileged? + end +end diff --git a/app/services/product_service.rb b/app/services/product_service.rb new file mode 100644 index 000000000..d31f61ae8 --- /dev/null +++ b/app/services/product_service.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Provides methods for Product +class ProductService + def self.list + Product.all + end +end diff --git a/app/views/api/products/_product.json.jbuilder b/app/views/api/products/_product.json.jbuilder new file mode 100644 index 000000000..b18ee0374 --- /dev/null +++ b/app/views/api/products/_product.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.extract! product, :id, :name, :slug, :sku, :description, :is_active, :product_category_id, :amount, :quantity_min, :stock, :low_stock_alert, :low_stock_threshold diff --git a/app/views/api/products/create.json.jbuilder b/app/views/api/products/create.json.jbuilder new file mode 100644 index 000000000..867abc99b --- /dev/null +++ b/app/views/api/products/create.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.partial! 'api/products/product', product: @product diff --git a/app/views/api/products/index.json.jbuilder b/app/views/api/products/index.json.jbuilder new file mode 100644 index 000000000..bc58aeb30 --- /dev/null +++ b/app/views/api/products/index.json.jbuilder @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +json.array! @products do |product| + json.partial! 'api/products/product', product: product +end diff --git a/app/views/api/products/show.json.jbuilder b/app/views/api/products/show.json.jbuilder new file mode 100644 index 000000000..867abc99b --- /dev/null +++ b/app/views/api/products/show.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.partial! 'api/products/product', product: @product diff --git a/app/views/api/products/update.json.jbuilder b/app/views/api/products/update.json.jbuilder new file mode 100644 index 000000000..867abc99b --- /dev/null +++ b/app/views/api/products/update.json.jbuilder @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +json.partial! 'api/products/product', product: @product diff --git a/config/routes.rb b/config/routes.rb index 6abcf4dca..e9dc37f22 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -154,6 +154,8 @@ Rails.application.routes.draw do patch 'position', on: :member end + resources :products + # for admin resources :trainings do get :availabilities, on: :member diff --git a/db/migrate/20220712153708_create_products.rb b/db/migrate/20220712153708_create_products.rb new file mode 100644 index 000000000..154e1a896 --- /dev/null +++ b/db/migrate/20220712153708_create_products.rb @@ -0,0 +1,19 @@ +class CreateProducts < ActiveRecord::Migration[5.2] + def change + create_table :products do |t| + t.string :name + t.string :slug + t.string :sku + t.text :description + t.boolean :is_active, default: false + t.belongs_to :product_category, foreign_key: true + t.integer :amount + t.integer :quantity_min + t.jsonb :stock, default: { internal: 0, external: 0 } + t.boolean :low_stock_alert, default: false + t.integer :low_stock_threshold + + t.timestamps + end + end +end diff --git a/db/migrate/20220712160137_create_join_table_product_machine.rb b/db/migrate/20220712160137_create_join_table_product_machine.rb new file mode 100644 index 000000000..874005fd0 --- /dev/null +++ b/db/migrate/20220712160137_create_join_table_product_machine.rb @@ -0,0 +1,8 @@ +class CreateJoinTableProductMachine < ActiveRecord::Migration[5.2] + def change + create_join_table :products, :machines do |t| + # t.index [:product_id, :machine_id] + # t.index [:machine_id, :product_id] + end + end +end diff --git a/db/schema.rb b/db/schema.rb index e65091513..1222e9bcf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -367,6 +367,11 @@ ActiveRecord::Schema.define(version: 2022_07_20_135828) do t.index ["machine_id"], name: "index_machines_availabilities_on_machine_id" end + create_table "machines_products", id: false, force: :cascade do |t| + t.bigint "product_id", null: false + t.bigint "machine_id", null: false + end + create_table "notifications", id: :serial, force: :cascade do |t| t.integer "receiver_id" t.string "attached_object_type" @@ -591,6 +596,23 @@ ActiveRecord::Schema.define(version: 2022_07_20_135828) do t.index ["parent_id"], name: "index_product_categories_on_parent_id" end + create_table "products", force: :cascade do |t| + t.string "name" + t.string "slug" + t.string "sku" + t.text "description" + t.boolean "is_active", default: false + t.bigint "product_category_id" + t.integer "amount" + t.integer "quantity_min" + t.jsonb "stock", default: {"external"=>0, "internal"=>0} + t.boolean "low_stock_alert", default: false + t.integer "low_stock_threshold" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["product_category_id"], name: "index_products_on_product_category_id" + end + create_table "profile_custom_fields", force: :cascade do |t| t.string "label" t.boolean "required", default: false @@ -1112,6 +1134,7 @@ ActiveRecord::Schema.define(version: 2022_07_20_135828) do add_foreign_key "prepaid_packs", "groups" add_foreign_key "prices", "groups" add_foreign_key "prices", "plans" + add_foreign_key "products", "product_categories" add_foreign_key "project_steps", "projects" add_foreign_key "project_users", "projects" add_foreign_key "project_users", "users"