Commit 7ebcb238 by ivan Lan

Refactory Catalog tagging with id & Improve spec for the change

parent 8f0730f9
require 'swagger_helper' require 'swagger_helper'
namespace = '<%= @namespace %>' namespace = '<%= @namespace %>'
RSpec.describe "#{namespace}/products/:product_id/product_series", type: :request, capture_examples: true, tags: ["#{namespace} API", "product_series"] do RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, tags: ["#{namespace} API", "product"] do
before do before do
class Catalog < Shotengai::Catalog; end
@clothes = Catalog.create!(name: '衣服')
@jacket = Catalog.create!(name: '上衣', super_catalog: @clothes)
@products = create_list(:product, 3) @products = create_list(:product, 3)
@product_1 = @products.first @product_1 = @products.first
@product_1.update(catalog_ids: @clothes.id)
@series_1 = create( @series = create(:product_series, product: @product_1)
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
end end
path "/#{namespace}/products/{product_id}/product_series" do path "/#{namespace}/products" do
parameter :product_id, in: :path, type: :string
let(:product_id) { @product_1.id }
get(summary: '用户 某商品的 商品系列 列表') do
get(summary: '用户 商品列表') do
parameter :page, in: :query, type: :string parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string parameter :per_page, in: :query, type: :string
parameter :catalog_ids, in: :query, type: :array
let(:page) { 1 } let(:page) { 1 }
let(:per_page) { 100 } let(:per_page) { 999 }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
response(200, description: 'successful') do response(200, description: 'successful') do
it { it { expect(JSON.parse(response.body)['products'].count).to eq(Product.count) }
expect(JSON.parse(response.body)['product_series'].count).to eq(@product_1.series.count) end
}
response(200, description: 'filter by catalog') do
let(:catalog_ids) { [@clothes.id] }
it { expect(JSON.parse(response.body)['products'].count).to eq(1) }
end end
end end
end end
path "/#{namespace}/product_series/{id}" do path "/#{namespace}/products/{id}" do
parameter :id, in: :path, type: :string parameter 'id', in: :path, type: :string
let(:id) { @series_1.id } let(:id) { @product_1.id }
get(summary: '用户 商品系列的详情') do get(summary: '用户 商品详情') do
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
response(200, description: 'successful') do response(200, description: 'successful') do
# it { p response.body } it {
expect(JSON.parse(response.body)['series'].count).to eq(@product_1.series.count), "correct product's series"
}
end end
end end
end end
......
...@@ -2,7 +2,8 @@ require 'swagger_helper' ...@@ -2,7 +2,8 @@ require 'swagger_helper'
namespace = '<%= @namespace %>' namespace = '<%= @namespace %>'
RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, tags: ["#{namespace} API", "product"] do RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, tags: ["#{namespace} API", "product"] do
before do before do
@merchant = create(:merchant) @merchant = Merchant.register "merchant", "password"
@auth_token = Merchant.login "merchant", "password"
class Catalog < Shotengai::Catalog; end class Catalog < Shotengai::Catalog; end
@clothes = Catalog.create!(name: '衣服') @clothes = Catalog.create!(name: '衣服')
...@@ -10,38 +11,32 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -10,38 +11,32 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
@products = create_list(:product, 3, manager: @merchant) @products = create_list(:product, 3, manager: @merchant)
@product_1 = @products.first @product_1 = @products.first
@product_1.update(catalog_list: ['衣服']) @product_1.update(catalog_ids: @clothes.id)
@series = create(:product_series, product: @product_1) @series = create(:product_series, product: @product_1)
end end
path "/#{namespace}/products" do path "/#{namespace}/products" do
parameter :manager_type, in: :query, type: :string
parameter :manager_id, in: :query, type: :integer
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
get(summary: '商家 商品列表') do get(summary: '商家 商品列表') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
parameter :page, in: :query, type: :string parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string parameter :per_page, in: :query, type: :string
parameter :status, in: :query, type: :string parameter :status, in: :query, type: :string
parameter :catalog_list, in: :query, type: :array parameter :catalog_ids, in: :query, type: :array
let(:page) { 1 } let(:page) { 1 }
let(:per_page) { 2 } let(:per_page) { 999 }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
response(200, description: 'successful') do response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['products'].count).to eq(2) }
it { expect(JSON.parse(response.body)['products'].count).to eq(Product.where(manager: @merchant).count) }
end end
response(200, description: 'filter by catalog') do response(200, description: 'filter by catalog') do
let(:catalog_list) { @product_1.catalog_list } let(:catalog_ids) { [@clothes.id] }
it { expect(JSON.parse(response.body)['products'].count).to eq(1) } it { expect(JSON.parse(response.body)['products'].count).to eq(1) }
end end
...@@ -53,17 +48,15 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -53,17 +48,15 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
end end
post(summary: '管理员新建商品') do post(summary: '管理员新建商品') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
parameter :product, in: :body, schema: { parameter :product, in: :body, schema: {
type: :object, properties: { type: :object, properties: {
product: { product: {
type: :object, properties: { type: :object, properties: {
title: { type: :string }, title: { type: :string },
# default_series_id: { type: :integer }, default_series_id: { type: :integer },
need_express: { type: :boolean }, need_express: { type: :boolean },
need_time_attr: { type: :boolean }, need_time_attr: { type: :boolean },
cover_image: { type: :string }, cover_image: { type: :string },
...@@ -89,7 +82,7 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -89,7 +82,7 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
meta2: { type: :ineteger }, meta2: { type: :ineteger },
}, },
}, },
catalog_list: { type: :array } catalog_ids: { type: :array }
} }
} }
} }
...@@ -103,7 +96,7 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -103,7 +96,7 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
{ {
product: product_attrs.merge( product: product_attrs.merge(
default_series_id: @series.id, default_series_id: @series.id,
catalog_list: ['衣服', '上衣'], catalog_ids: [@clothes.id, @jacket.id],
) )
} }
} }
...@@ -125,10 +118,8 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -125,10 +118,8 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
let(:ids) { @products.first(2).map(&:id) } let(:ids) { @products.first(2).map(&:id) }
let(:event) { 'put_on_shelf' } let(:event) { 'put_on_shelf' }
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
response(200, description: 'successful') do response(200, description: 'successful') do
...@@ -143,16 +134,9 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -143,16 +134,9 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
parameter 'id', in: :path, type: :string parameter 'id', in: :path, type: :string
let(:id) { @product_1.id } let(:id) { @product_1.id }
parameter :manager_type, in: :query, type: :string
parameter :manager_id, in: :query, type: :integer
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
get(summary: '商户 商品详情') do get(summary: '商户 商品详情') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
response(200, description: 'successful') do response(200, description: 'successful') do
...@@ -162,10 +146,8 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -162,10 +146,8 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
end end
end end
patch(summary: 'update product') do patch(summary: 'update product') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
...@@ -201,7 +183,7 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -201,7 +183,7 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
meta2: { type: :ineteger }, meta2: { type: :ineteger },
}, },
}, },
catalog_list: { type: :array } catalog_ids: { type: :array }
} }
} }
} }
...@@ -213,10 +195,8 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -213,10 +195,8 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
end end
delete(summary: 'delete product') do delete(summary: 'delete product') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
...@@ -229,16 +209,9 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -229,16 +209,9 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
parameter 'id', in: :path, type: :string parameter 'id', in: :path, type: :string
let(:id) { @product_1.id } let(:id) { @product_1.id }
parameter :manager_type, in: :query, type: :string
parameter :manager_id, in: :query, type: :integer
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
post(summary: '商户 上架商品') do post(summary: '商户 上架商品') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
produces 'application/json' produces 'application/json'
consumes 'application/json' consumes 'application/json'
...@@ -252,16 +225,9 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, ...@@ -252,16 +225,9 @@ RSpec.describe "#{namespace}/products", type: :request, capture_examples: true,
parameter 'id', in: :path, type: :string parameter 'id', in: :path, type: :string
let(:id) { @product_1.id } let(:id) { @product_1.id }
parameter :manager_type, in: :query, type: :string
parameter :manager_id, in: :query, type: :integer
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
post(summary: '商户 下架商品') do post(summary: '商户 下架商品') do
parameter :manager_type, in: :query, type: :string parameter 'Merchant-Token', in: :header, type: :string
parameter :manager_id, in: :query, type: :integer let('Merchant-Token') { @auth_token.token }
let(:manager_id) { @merchant.id }
let(:manager_type) { @merchant.class.name }
before { @product_1.update!(status: 'on_sale') } before { @product_1.update!(status: 'on_sale') }
produces 'application/json' produces 'application/json'
......
...@@ -4,3 +4,4 @@ json.extract! order, :id, :seq, :address, :amount ...@@ -4,3 +4,4 @@ json.extract! order, :id, :seq, :address, :amount
:delivery_way, :delivery_cost, :delivery_way, :delivery_cost,
:merchant_remark, :mark, :customer_remark, :merchant_remark, :mark, :customer_remark,
:status, :status_zh, :meta, :created_at :status, :status_zh, :meta, :created_at
json.snapshots order.snapshots, partial: 'shotengai/share/snapshot_simple', as: :snapshot
...@@ -47,6 +47,13 @@ module Shotengai ...@@ -47,6 +47,13 @@ module Shotengai
where(super_catalog_id: nil).map(&:tree) where(super_catalog_id: nil).map(&:tree)
end end
def ids_to_tags ids
where(id: ids).map(&:tag_chain).reduce(:|)
end
def parse_tag tag
tag.split('-').last
end
# def input_from_file # def input_from_file
# end # end
end end
...@@ -57,6 +64,10 @@ module Shotengai ...@@ -57,6 +64,10 @@ module Shotengai
ary ary
end end
def tag
"#{self.class.name}-#{id}"
end
def nest_level def nest_level
ancestors.count ancestors.count
end end
...@@ -65,6 +76,10 @@ module Shotengai ...@@ -65,6 +76,10 @@ module Shotengai
ancestors.map(&:name) ancestors.map(&:name)
end end
def tag_chain
ancestors.map(&:tag)
end
def brothers def brothers
super_catalog.sub_catalogs super_catalog.sub_catalogs
end end
......
...@@ -9,9 +9,9 @@ module Shotengai ...@@ -9,9 +9,9 @@ module Shotengai
skip_before_action :buyer_auth skip_before_action :buyer_auth
def index_query resources def index_query resources
params[:catalog_list] ? p params[:catalog_ids]
resources.tagged_with(params[:catalog_list], on: :catalogs) : p ::Catalog.find_by_id(params[:catalog_ids])
resources resources.catalog_list_filter(::Catalog.find_by_id(params[:catalog_ids]))
end end
end end
end end
......
...@@ -13,10 +13,8 @@ module Shotengai ...@@ -13,10 +13,8 @@ module Shotengai
end end
def index_query resources def index_query resources
( resources.catalog_list_filter(
params[:catalog_list] ? ::Catalog.find_by_id(params[:catalog_ids])
resources.tagged_with(params[:catalog_list], on: :catalogs) :
resources
).where( ).where(
params[:status].blank?.! && { status: params[:status] } params[:status].blank?.! && { status: params[:status] }
) )
...@@ -60,7 +58,7 @@ module Shotengai ...@@ -60,7 +58,7 @@ module Shotengai
# NOTE: :catalog_list is a default catalog list for template example, maybe should move it to the template controller, but it need add controller template for every controller # NOTE: :catalog_list is a default catalog list for template example, maybe should move it to the template controller, but it need add controller template for every controller
params.require(resource_key).permit( params.require(resource_key).permit(
:title, :default_series_id, :title, :default_series_id,
:need_express, :need_time_attr, :cover_image, catalog_list: [], :need_express, :need_time_attr, :cover_image, catalog_ids: [],
banners: [] banners: []
).merge( ).merge(
{ spec: spec, detail: detail, meta: meta } { spec: spec, detail: detail, meta: meta }
......
...@@ -111,14 +111,29 @@ module Shotengai ...@@ -111,14 +111,29 @@ module Shotengai
catalog_class = catalog_class_name.constantize catalog_class = catalog_class_name.constantize
tag_name = options[:as] || catalog_class.model_name.singular tag_name = options[:as] || catalog_class.model_name.singular
acts_as_taggable_on tag_name.to_sym acts_as_taggable_on tag_name.to_sym
# set { validate_name_chain: false } to skip the validate_name_chain list_name = "#{tag_name}_list".to_sym
# 只有完整替换(只属于一个分类)的时候才进行验证,add remove 暂时未添加 class_eval do
# Just catalogs_list= have a validation # define_method("#{tag_name}_list=") { |value|
options[:validate_name_chain].eql?(false) || class_eval do # super catalog_class.validate_name_chain(value)
define_method("#{tag_name}_list=") { |value| # }
super catalog_class.validate_name_chain(value)
scope "#{list_name}_filter".to_sym, ->(catalogs) {
tags = catalogs && catalogs.try(:tag) || catalogs&.map(&:tag)
tags ? tagged_with(tags, on: list_name) : all
}
define_method("#{tag_name}_ids=") { |ids|
send("#{list_name}=", catalog_class.ids_to_tags(ids))
}
define_method(list_name) {
catalog_class.where(id: super().map { |tag| Shotengai::Catalog.parse_tag(tag) }).select(:name).map(&:name)
} }
end end
# instance_eval do
# define_method(:)
# end
end end
end end
......
...@@ -99,11 +99,11 @@ module Shotengai ...@@ -99,11 +99,11 @@ module Shotengai
###### view ###### view
def total_price def total_price
revised_amount || count * self.price (revised_amount || count.to_d * self.price).round(2)
end end
def total_original_price def total_original_price
count * original_price (count * original_price).round(2)
end end
def is_in_cart def is_in_cart
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment