Commit e6ed9d79 by ivan Lan

Add spec generator

parent 0f1cc029
...@@ -36,17 +36,19 @@ module Shotengai ...@@ -36,17 +36,19 @@ module Shotengai
def create_controllers def create_controllers
raise 'Illegal role. Only merchant or customer' unless role.in?(['merchant', 'customer']) raise 'Illegal role. Only merchant or customer' unless role.in?(['merchant', 'customer'])
@controller_prefix = options[:namespace].blank? ? '' : (options[:namespace].camelize + '::') @role = role
@namespace, @product, @order = options.values_at(:namespace, :product, :order)
@controller_prefix = @namespace.blank? ? '' : (@namespace.camelize + '::')
{ {
'products' => options[:product], 'products' => @product,
'orders' => options[:order], 'orders' => @order,
'product_series' => "#{options[:product]}Series", 'product_series' => "#{@product}Series",
'product_snapshots' => "#{options[:product]}Snapshot", 'product_snapshots' => "#{@product}Snapshot",
}.each do |key, klass_name| }.each do |key, klass_name|
@key, @klass_name, @role = key, klass_name, role @key, @klass_name = key, klass_name
template "template_controller.rb", template "template_controller.rb",
"app/controllers/#{options[:namespace]}/#{klass_name.underscore.pluralize}_controller.rb" "app/controllers/#{@namespace}/#{@klass_name.underscore.pluralize}_controller.rb"
end end
end end
end end
......
module Shotengai
module Generators
class SpecGenerator < Rails::Generators::Base
source_root File.expand_path("../../templates/spec", __FILE__)
desc "Copy swagger spec of tempalte MVC to your application."
class_option :customer, type: :string, required: true,
desc: "Customer class name"
class_option :merchant, type: :string, required: true,
desc: "Merchant class name"
class_option :product, type: :string, required: true,
desc: "Product class name"
class_option :order, type: :string, required: true,
desc: "Order class name"
def copy_spec
@customer_class_name, @merchant_class_name, @product_class_name, @order_class_name =
options.values_at(:customer, :merchant, :product, :order)
Dir["#{self.class.source_root}/**/*.rb"].each do |path|
relative_path = path.gsub(self.class.source_root, '')
template path, "app/spec/shotengai/#{relative_path}"
end
end
end
end
end
FactoryGirl.define do
factory :merchant, '<%= @merhcant_class_name %>' do
end
end
# == Schema Information
#
# Table name: shotengai_orders
#
# id :integer not null, primary key
# seq :integer
# address :string(255)
# pay_time :datetime
# delivery_time :datetime
# receipt_time :datetime
# delivery_way :string(255)
# delivery_cost :string(255)
# merchant_remark :text(65535)
# mark :string(255)
# customer_remark :text(65535)
# status :string(255)
# type :string(255)
# meta :json
# buyer_id :integer
# buyer_type :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_shotengai_orders_on_buyer_id_and_buyer_type (buyer_id,buyer_type)
# index_shotengai_orders_on_type (type)
#
FactoryGirl.define do
factory :order, class_name: '<%= @order_class_name %>' do
end
end
# == Schema Information
#
# Table name: shotengai_products
#
# id :integer not null, primary key
# title :string(255)
# status :string(255)
# spec :json
# default_series_id :integer
# need_express :boolean
# need_time_attr :boolean
# cover_image :string(255)
# banners :json
# detail :json
# type :string(255)
# meta :json
# manager_id :integer
# manager_type :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_shotengai_products_on_manager_id_and_manager_type (manager_id,manager_type)
# index_shotengai_products_on_type (type)
#
FactoryGirl.define do
factory :product, class: '<%= @product_class_name %>' do
title 'Test Product Title'
# status
spec {
{
"颜色" => ["黑色", "红色", "白色"],
"大小" => ["S", "M", "L"],
}
}
# default_series_id ''
need_express true
# need_time_attr true
cover_image 'cover_image.image'
banners { [ 'image1', 'iamge2' ] }
detail {
{
"使用说明" => "xxxxxxxx...",
"产品参数" => "参数 参数..."
}
}
# type "
meta {
{
"meta1" => "111",
"meta2" => "222",
}
}
end
end
# == Schema Information
#
# Table name: shotengai_series
#
# id :integer not null, primary key
# original_price :decimal(9, 2)
# price :decimal(9, 2)
# stock :integer
# spec :json
# type :string(255)
# meta :json
# shotengai_product_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_shotengai_series_on_shotengai_product_id (shotengai_product_id)
# index_shotengai_series_on_type (type)
#
FactoryGirl.define do
factory :product_series, class: '<%= "#{@product_class_name}Series" %>' do
original_price 100
price 80
stock 10
spec {
{
"颜色" => "红色",
"大小" => "S",
}
}
# type
meta {
{
"series_meta1" => "111",
"series_meta2" => "222",
}
}
end
end
# == Schema Information
#
# Table name: shotengai_snapshots
#
# id :integer not null, primary key
# original_price :decimal(9, 2)
# price :decimal(9, 2)
# revised_amount :decimal(9, 2)
# count :integer
# spec :json
# banners :json
# cover_image :string(255)
# detail :json
# type :string(255)
# meta :json
# shotengai_series_id :integer
# shotengai_order_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_shotengai_snapshots_on_shotengai_order_id (shotengai_order_id)
# index_shotengai_snapshots_on_shotengai_series_id (shotengai_series_id)
# index_shotengai_snapshots_on_type (type)
#
FactoryGirl.define do
factory :product_snapshot, class: '<%= "#{@product_class_name}Snapshot" %>' do
original_price 100
price 80
count 2
spec {
{
"颜色" => "红色",
"大小" => "S",
}
}
banners { ['iamge 1', 'iamge 2'] }
cover_image 'cover_image 1'
detail {
{
"使用说明" => "xxxxxxxx...",
"产品参数" => "参数 参数..."
}
}
meta {
{
"meta1" => "111",
"meta2" => "222",
}
}
end
end
FactoryGirl.define do
factory :user, class_name: '<%= @customer_class_name %>' do
end
end
require 'swagger_helper'
namespace = '<%= @customer_class_name.underscore %>'
RSpec.describe "#{namespace}/orders", type: :request, capture_examples: true, tags: ["#{namespace} API", "order"] do
before do
@user = create(:user)
@products = create_list(:product, 3)
@product_1 = @products.first
@series_1 = create(
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
@snapshot_1 = create(:product_snapshot, series: @series_1, count: 2)
@snapshot_2 = create(:product_snapshot, series: @series_1, count: 5)
@snapshot_other = create(:product_snapshot, series: @series_2, count: 5)
@orders = create_list(:order, 3, buyer: @user)
@order_1 = @orders.first
@cart = @order_1.class.cart_class.create!(buyer: @user)
@snapshot_1.update!(order: @order_1)
@snapshot_other.update!(order: @order_1)
@snapshot_2.update!(order_cart: @cart)
end
path "/#{namespace}/orders/cart" do
get(summary: '用户 购物车') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
response(200, description: 'cart') do
it { expect(JSON.parse(response.body)['snapshots'].count).to eq(1) }
end
end
end
path "/#{namespace}/orders/add_to_cart" do
post(summary: '用户 添加快照至购物车( using series_id & count )') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
parameter :snapshot, in: :body, schema: {
type: :object, properties: {
snapshot: {
type: :object, properties: {
shotengai_series_id: { type: :integer },
count: { type: :integer },
}
}
}
}
response(201, description: 'Create snapshot and add it to the cart') do
let(:snapshot) {
{
snapshot: {
shotengai_series_id: @series_1.id,
count: 10,
}
}
}
it {
expect(JSON.parse(response.body)['count']).to eq(10)
expect(@cart.snapshots.count).to eq(2)
}
end
end
end
path "/#{namespace}/orders" do
get(summary: '用户 订单列表') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
parameter :status, in: :query, type: :string
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['orders'].count).to eq(3) }
end
response(200, description: 'filter by status') do
before { @orders.last.pay! }
let(:status) { 'paid' }
it { expect(JSON.parse(response.body)['orders'].count).to eq(1) }
end
end
post(summary: '用户 创建订单(using incr_snapshot_ids') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
parameter :order, in: :body, schema: {
type: :object, properties: {
order: {
type: :object, properties: {
address: { type: :string },
user_remark: { type: :text },
incr_snapshot_ids: { type: :array },
# gone_snapshot_ids: { type: :array },
}
}
}
}
response(201, description: 'successful') do
let(:order) {{
order: {
address: 'This is an special address.',
user_remark: 'user remark ...',
incr_snapshot_ids: [ @snapshot_2.id ],
}
}}
it {
body = JSON.parse(response.body)
expect(body['snapshots'].count).to eq(1)
expect(body['snapshots'].first['id']).to eq(@snapshot_2.id)
expect(@snapshot_2.reload.is_in_cart).to eq(false)
}
end
response(400, description: 'failed, Cannot edit a snapshot which order was already paid.') do
let(:order) {{
order: {
incr_snapshot_ids: [ @snapshot_1.id ],
}
}}
before {
@order_1.pay!
}
it {
expect(response.status).to eq(400)
}
end
end
end
path "/#{namespace}/orders/create_directly" do
post(summary: 'create order') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
parameter :order_and_snapshot_params, in: :body, schema: {
type: :object, properties: {
order: {
type: :object, properties: {
address: { type: :string },
user_remark: { type: :text },
},
snapshot: {
type: :object, properties: {
shotengai_series_id: { type: :integer },
count: { type: :integer },
}
}
}
}
}
response(201, description: 'successful') do
let(:order_and_snapshot_params) {
{
order: {
address: 'This is an special address.',
user_remark: 'user remark ...'
},
snapshot: {
shotengai_series_id: @series_1.id,
count: 10,
}
}
}
it {
body = JSON.parse(response.body)
expect(body['snapshots'].count).to eq(1)
expect(body['snapshots'].first['shotengai_series_id']).to eq(@series_1.id)
}
end
end
end
path "/#{namespace}/orders/{id}" do
parameter :id, in: :path, type: :integer
let(:id) { @order_1.id }
get(summary: '用户 订单详情') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['snapshots'].count).to eq(@order_1.snapshots.count)
}
end
end
patch(
summary: 'update order
【 incr_snapshot_ids 移入该order的snapshot_id 数组,
gone_snapshot_ids 移入购物车的 snapshot_id 数组 】'
) do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
parameter :order, in: :body, schema: {
type: :object, properties: {
order: {
type: :object, properties: {
address: { type: :string },
user_remark: { type: :text },
incr_snapshot_ids: { type: :array },
gone_snapshot_ids: { type: :array },
}
}
}
}
response(200, description: 'successful') do
let(:order) {{
order: {
address: 'This is an special address.',
user_remark: 'user remark ...',
incr_snapshot_ids: [ @snapshot_2.id ],
gone_snapshot_ids: [ @snapshot_1.id ],
}
}}
it {
expect(@order_1.reload.address).to eq('This is an special address.')
# Move @snapshot_1 out of order to the cart
expect(@snapshot_1.reload.is_in_cart).to eq(true)
# Move @snapshot_2 into order
expect(@snapshot_2.reload.is_in_cart).to eq(false)
}
end
response(403, description: 'failed, Can edit a unpaid order only.') do
let(:order) {{
order: {
address: 'This is an special address.',
user_remark: 'user remark ...'
}
}}
before { @order_1.pay! }
it {
expect(response.status).to eq(403)
}
end
end
end
path "/#{namespace}/orders/{id}/pay" do
parameter :id, in: :path, type: :integer
let(:id) { @order_1.id }
post(summary: '用户 支付订单') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['pay_time']).not_to be_nil }
end
end
end
path "/#{namespace}/orders/{id}/cancel" do
parameter :id, in: :path, type: :integer
let(:id) { @order_1.id }
post(summary: '用户 取消未支付订单') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['status']).to eq('canceled') }
end
response(400, description: 'failed , you can cancel a order which status is unpaid') do
before { @order_1.pay! }
it { expect(response.status).to eq(400) }
end
end
end
path "/#{namespace}/orders/{id}/get_it" do
parameter :id, in: :path, type: :integer
let(:id) { @order_1.id }
post(summary: '用户 确认收货') do
produces 'application/json'
consumes 'application/json'
parameter :buyer_type, in: :query, type: :string
parameter :buyer_id, in: :query, type: :integer
let(:buyer_id) { @user.id }
let(:buyer_type) { @user.class.name }
before { @order_1.update!(status: 'delivering') }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['receipt_time']).not_to be_nil }
end
end
end
end
require 'swagger_helper'
namespace = '<%= @customer_class_name.underscore %>'
RSpec.describe "#{namespace}/products/:product_id/product_series", type: :request, capture_examples: true, tags: ["#{namespace} API", "product_series"] do
before do
@products = create_list(:product, 3)
@product_1 = @products.first
@series_1 = create(
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
end
path "/#{namespace}/products/{product_id}/product_series" do
parameter :product_id, in: :path, type: :string
let(:product_id) { @product_1.id }
get(summary: '用户 某商品的 商品系列 列表') do
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['product_series'].count).to eq(@product_1.series.count)
}
end
end
end
path "/#{namespace}/products/{product_id}/product_series/{id}" do
parameter :id, in: :path, type: :string
parameter :product_id, in: :path, type: :string
let(:product_id) { @product_1.id }
let(:id) { @series_1.id }
get(summary: '用户 商品系列的详情') do
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
# it { p response.body }
end
end
end
end
require 'swagger_helper'
namespace = '<%= @customer_class_name.underscore %>'
RSpec.describe "#{namespace}/product_snapshots", type: :request, capture_examples: true, tags: ["#{namespace} API", "product_snapshots"] do
before do
@products = create_list(:product, 3)
@product_1 = @products.first
@series_1 = create(
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
@snapshot_1 = create(:product_snapshot, series: @series_1, count: 2)
@snapshot_2 = create(:product_snapshot, series: @series_1, count: 5)
@snapshot_other = create(:product_snapshot, series: @series_2, count: 5)
@order = create(:order)
@cart = Order::Cart.create!
@snapshot_1.update!(order: @order)
@snapshot_other.update!(order: @order)
@snapshot_2.update!(order_cart: @cart)
end
path "/#{namespace}/product_snapshots" do
get(summary: '用户 快照列表 三参数可仍以任意组合') do
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
parameter :series_id, in: :query, type: :integer
parameter :order_id, in: :query, type: :string
parameter :in_cart, in: :query, type: :boolean
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful, query by product_series_id') do
let(:series_id) { @series_1.id }
it {
expect(JSON.parse(response.body)['product_snapshots'].count).to eq(@series_1.snapshots.in_order.count)
}
end
response(200, description: 'successful, query by order_id') do
let(:order_id) { @order.id }
it {
expect(JSON.parse(response.body)['product_snapshots'].count).to eq(@order.snapshots.count)
}
end
response(200, description: 'successful, in_cart') do
let(:in_cart) { true }
it {
expect(JSON.parse(response.body)['product_snapshots'].count).to eq(@cart.snapshots.count)
}
end
end
end
path "/#{namespace}/product_snapshots/{id}" do
let(:id) { @snapshot_1.id }
get(summary: '商户 商品快照的详情') do
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON(response.body)['total_price']).to eq('%.1f'% @snapshot_1.total_price) }
end
end
end
# path "/#{namespace}/product_series/{product_series_id}/product_snapshots" do
# parameter :product_series_id, in: :path, type: :integer
# parameter :order_id, in: :path, type: :string
# parameter :in_cart, in: :path, type: :boolean
# let(:product_series_id) { @series_1.id }
# get(summary: '用户 快照列表 三参数可仍以任意组合') do
# parameter :page, in: :query, type: :string
# parameter :per_page, in: :query, type: :string
# let(:page) { 1 }
# let(:per_page) { 100 }
# produces 'application/json'
# consumes 'application/json'
# response(200, description: 'successful') do
# it {
# expect(JSON.parse(response.body)['product_snapshots'].count).to eq(1)
# }
# end
# end
# post(summary: '用户 创建快照 ') do
# parameter :product_snapshot, in: :body, schema: {
# type: :object, properties: {
# product_snapshot: {
# type: :object, properties: {
# count: { type: :integer },
# buyer_id: { type: :integer },
# buyer_type: { type: :string },
# }
# }
# }
# }
# produces 'application/json'
# consumes 'application/json'
# response(200, description: 'successful') do
# let(:product_snapshot) {
# {
# product_snapshot: {
# count: 10,
# buyer_id: @user.id,
# buyer_type: @user.class.name,
# }
# }
# }
# it {
# expect(JSON.parse(response.body)[':shotengai_series_id']).to eq(@series_1.id)
# expect(JSON.parse(response.body)['count']).to eq(10)
# }
# end
# end
# end
# path "/#{namespace}/orders/{order_id}/product_snapshots" do
# parameter :order_id, in: :path, type: :string
# let(:order_id) { @order.id }
# get(summary: '用户 (某订单中) 的快照列表') do
# parameter :page, in: :query, type: :string
# parameter :per_page, in: :query, type: :string
# let(:page) { 1 }
# let(:per_page) { 100 }
# produces 'application/json'
# consumes 'application/json'
# response(200, description: 'successful') do
# it {
# expect(JSON.parse(response.body)['product_snapshots'].count).to eq(2)
# }
# end
# end
# end
# path "/#{namespace}/product_series/{product_series_id}/product_snapshots/{id}" do
# parameter :product_series_id, in: :path, type: :string
# parameter :id, in: :path, type: :string
# let(:product_series_id) { @series_1.id }
# let(:id) { @snapshot_1.id }
# get(summary: '商户 商品快照的详情') do
# produces 'application/json'
# consumes 'application/json'
# response(200, description: 'successful') do
# it { expect(JSON(response.body)['product_status_zh']).to eq('未上架'), 'check product_status_zh' }
# end
# end
# patch(summary: 'update product_snapshot 修改 revised_amount') do
# produces 'application/json'
# consumes 'application/json'
# parameter :product_snapshot, in: :body, schema: {
# type: :object, properties: {
# product_snapshot: {
# type: :object, properties: {
# revised_amount: { type: :decimal }
# }
# }
# }
# }
# response(200, description: 'successful') do
# let(:product_snapshot) {
# { product_snapshot: { revised_amount: 233 } }
# }
# it 'revised_amount as the total_price' do
# expect(@snapshot_1.reload.revised_amount).to eq(233)
# end
# end
# response(403, description: 'failed, can update a snapshot of unpaid order only ') do
# let(:product_snapshot) {
# { product_snapshot: { revised_amount: 233 } }
# }
# before { @snapshot_1.order.pay! }
# it 'revised_amount as the total_price' do
# expect(response.status).to eq(403)
# end
# end
# end
# end
end
require 'swagger_helper'
namespace = '<%= @customer_class_name.underscore %>'
RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, tags: ["#{namespace} API", "product"] do
before do
class Catalog < Shotengai::Catalog; end
@clothes = Catalog.create!(name: '衣服')
@jacket = Catalog.create!(name: '上衣', super_catalog: @clothes)
@products = create_list(:product, 3)
@product_1 = @products.first
@product_1.update(catalog_list: ['衣服'])
@series = create(:product_series, product: @product_1)
end
path "/#{namespace}/products" do
get(summary: '用户 商品列表') do
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
parameter :catalog_list, in: :query, type: :array
let(:page) { 1 }
let(:per_page) { 2 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['products'].count).to eq(2) }
end
response(200, description: 'filter by catalog') do
let(:catalog_list) { @product_1.catalog_list }
it { expect(JSON.parse(response.body)['products'].count).to eq(1) }
end
end
end
path "/#{namespace}/products/{id}" do
parameter 'id', in: :path, type: :string
let(:id) { @product_1.id }
get(summary: '用户 商品详情') do
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['series'].count).to eq(@product_1.series.count), "correct product's series"
}
end
end
end
end
require 'swagger_helper'
namespace = '<%= @merchant_class_name.underscore %>'
RSpec.describe "#{namespace}/orders", type: :request, capture_examples: true, tags: ["#{namespace} API", "order"] do
before do
@products = create_list(:product, 3)
@product_1 = @products.first
@series_1 = create(
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
@snapshot_1 = create(:product_snapshot, series: @series_1, count: 2)
@snapshot_2 = create(:product_snapshot, series: @series_1, count: 5)
@snapshot_other = create(:product_snapshot, series: @series_2, count: 5)
@orders = create_list(:order, 3)
@order_1 = @orders.first
@cart = Order::Cart.create!
@snapshot_1.update!(order: @order_1)
@snapshot_other.update!(order: @order_1)
@snapshot_2.update!(order_cart: @cart)
end
path "/#{namespace}/orders" do
get(summary: '商家 订单列表') do
# QUESTION: 商家需要 查看 未支付的订单?
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
parameter :status, in: :query, type: :string
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['orders'].count).to eq(3) }
end
response(200, description: 'filter by status') do
before { @orders.last.pay! }
let(:status) { 'paid' }
it { expect(JSON.parse(response.body)['orders'].count).to eq(1) }
end
end
end
path "/#{namespace}/orders/{id}" do
parameter 'id', in: :path, type: :string
let(:id) { @order_1.id }
get(summary: '商户 订单详情') do
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['snapshots'].count).to eq(@order_1.snapshots.count)
}
end
end
patch(summary: 'update product') do
produces 'application/json'
consumes 'application/json'
parameter :order, in: :body, schema: {
type: :object, properties: {
order: {
type: :object, properties: {
mark: { type: :string },
merchant_remark: { type: :text },
}
}
}
}
response(200, description: 'successful') do
let(:order) {{
order: {
mark: 'red mark',
merchant_remark: 'merchant remark ...'
}
}}
it {
expect(@order_1.reload.mark).to eq('red mark')
}
end
end
end
path "/#{namespace}/orders/{id}/send_out" do
parameter 'id', in: :path, type: :string
let(:id) { @order_1.id }
post(summary: '商户 确认订单开始配送') do
before { @order_1.pay! }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['delivery_time']).not_to be_nil }
end
end
post(summary: '商户 确认订单开始配送') do
produces 'application/json'
consumes 'application/json'
response(400, description: 'failed wrong initial status') do
it { expect(response.status).to eq(400) }
end
end
end
end
require 'swagger_helper'
namespace = '<%= @merchant_class_name.underscore %>'
RSpec.describe "#{namespace}/products/:product_id/product_series", type: :request, capture_examples: true, tags: ["#{namespace} API", "product_series"] do
before do
@clothes = Catalog.create!(name: '衣服')
@jacket = Catalog.create!(name: '上衣', super_catalog: @clothes)
@products = create_list(:product, 3)
@product_1 = @products.first
@product_1.update(catalog_list: ['衣服'])
@series_1 = create(
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
end
path "/#{namespace}/products/{product_id}/product_series" do
parameter :product_id, in: :path, type: :string
let(:product_id) { @product_1.id }
get(summary: '商家 某商品的 商品系列 列表') do
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['product_series'].count).to eq(@product_1.series.count)
}
end
end
post(summary: '管理员新建 商品系列') do
parameter :product_series, in: :body, schema: {
type: :object, properties: {
product_series: {
type: :object, properties: {
original_price: { type: :decimal },
price: { type: :decimal },
stock: { type: :integer },
spec: {
type: :object,
properties: {
color: { type: :array },
size: { type: :array },
},
},
meta: {
type: :object,
properties: {
meta1: { type: :string },
meta2: { type: :integer },
},
},
}
}
}
}
produces 'application/json'
consumes 'application/json'
response(201, description: 'successful') do
product_series_attrs = FactoryGirl.attributes_for(:product_series)
let(:product_series) {
{ product_series: product_series_attrs }
}
it 'check attrs' do
body = JSON.parse(response.body)
expect(body['shotengai_product_id']).to eq(@product_1.id), 'methods default_query successful '
expect(body['cover_image']).to eq(@product_1.cover_image), 'delegate info to product successful'
end
end
response(400, description: 'failed, duplicate spec') do
product_series_attrs = FactoryGirl.attributes_for(:product_series)
let(:product_series) {
{ product_series: product_series_attrs.merge(spec: @series_1.spec) }
}
it 'duplicate spec' do
expect(response.status).to eq(400)
# p body = JSON.parse(response.body)
end
end
end
end
path "/#{namespace}/products/{product_id}/product_series/{id}" do
parameter :id, in: :path, type: :string
parameter :product_id, in: :path, type: :string
let(:product_id) { @product_1.id }
let(:id) { @series_1.id }
get(summary: '商户 商品系列的详情') do
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
# it { p response.body }
end
end
patch(summary: 'update product_series') do
produces 'application/json'
consumes 'application/json'
parameter :product_series, in: :body, schema: {
type: :object, properties: {
product_series: {
type: :object, properties: {
original_price: { type: :decimal },
price: { type: :decimal },
stock: { type: :integer },
spec: {
type: :object,
properties: {
color: { type: :array },
size: { type: :array },
},
},
meta: {
type: :object,
properties: {
meta1: { type: :string },
meta2: { type: :integer },
},
},
}
}
}
}
response(200, description: 'successful') do
let(:product_series) { { product_series: FactoryGirl.attributes_for(:product_series) } }
end
end
delete(summary: 'delete product_series') do
produces 'application/json'
consumes 'application/json'
response(204, description: 'successful') do
end
end
end
end
require 'swagger_helper'
namespace = '<%= @merchant_class_name.underscore %>'
RSpec.describe "#{namespace}/product_snapshots", type: :request, capture_examples: true, tags: ["#{namespace} API", "product_snapshots"] do
before do
@products = create_list(:product, 3)
@product_1 = @products.first
@series_1 = create(
:product_series,
product: @product_1,
spec: {
"颜色" => "白色",
"大小" => "S",
}
)
@series_2 = create(
:product_series, {
product: @product_1,
spec: {
"颜色" => "黑色",
"大小" => "S",
}
}
)
@snapshot_1 = create(:product_snapshot, series: @series_1, count: 2)
@snapshot_2 = create(:product_snapshot, series: @series_1, count: 5)
@snapshot_other = create(:product_snapshot, series: @series_2, count: 5)
@order = create(:order)
@cart = Order::Cart.create!
@snapshot_1.update!(order: @order)
@snapshot_other.update!(order: @order)
@snapshot_2.update!(order_cart: @cart)
end
path "/#{namespace}/product_series/{product_series_id}/product_snapshots" do
parameter :product_id, in: :path, type: :string
let(:product_series_id) { @series_1.id }
get(summary: '商家 (某商品系列中) 的已“在订单中”的快照列表') do
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['product_snapshots'].count).to eq(1)
}
end
end
end
path "/#{namespace}/orders/{order_id}/product_snapshots" do
parameter :order_id, in: :path, type: :string
let(:order_id) { @order.id }
get(summary: '商家 (某订单中) 的快照列表') do
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
let(:page) { 1 }
let(:per_page) { 100 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['product_snapshots'].count).to eq(2)
}
end
end
end
path "/#{namespace}/product_series/{product_series_id}/product_snapshots/{id}" do
parameter :product_series_id, in: :path, type: :string
parameter :id, in: :path, type: :string
let(:product_series_id) { @series_1.id }
let(:id) { @snapshot_1.id }
get(summary: '商户 商品快照的详情') do
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON(response.body)['product_status_zh']).to eq('未上架'), 'check product_status_zh' }
end
end
patch(summary: 'update product_snapshot 修改 revised_amount') do
produces 'application/json'
consumes 'application/json'
parameter :product_snapshot, in: :body, schema: {
type: :object, properties: {
product_snapshot: {
type: :object, properties: {
revised_amount: { type: :decimal }
}
}
}
}
response(200, description: 'successful') do
let(:product_snapshot) {
{ product_snapshot: { revised_amount: 233 } }
}
it 'revised_amount as the total_price' do
expect(@snapshot_1.reload.revised_amount).to eq(233)
end
end
response(403, description: 'failed, can update a snapshot of unpaid order only ') do
let(:product_snapshot) {
{ product_snapshot: { revised_amount: 233 } }
}
before { @snapshot_1.order.pay! }
it 'revised_amount as the total_price' do
expect(response.status).to eq(403)
end
end
end
end
end
require 'swagger_helper'
namespace = '<%= @merchant_class_name.underscore %>'
RSpec.describe "#{namespace}/products", type: :request, capture_examples: true, tags: ["#{namespace} API", "product"] do
before do
@merchant = create(:merchant)
class Catalog < Shotengai::Catalog; end
@clothes = Catalog.create!(name: '衣服')
@jacket = Catalog.create!(name: '上衣', super_catalog: @clothes)
@products = create_list(:product, 3)
@product_1 = @products.first
@product_1.update(catalog_list: ['衣服'])
@series = create(:product_series, product: @product_1)
end
path "/#{namespace}/products" do
get(summary: '商家 商品列表') 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 }
parameter :page, in: :query, type: :string
parameter :per_page, in: :query, type: :string
parameter :catalog_list, in: :query, type: :array
let(:page) { 1 }
let(:per_page) { 2 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it { expect(JSON.parse(response.body)['products'].count).to eq(2) }
end
response(200, description: 'filter by catalog') do
let(:catalog_list) { @product_1.catalog_list }
it { expect(JSON.parse(response.body)['products'].count).to eq(1) }
end
end
post(summary: '管理员新建商品') 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 }
parameter :product, in: :body, schema: {
type: :object, properties: {
product: {
type: :object, properties: {
title: { type: :string },
default_series_id: { type: :integer },
need_express: { type: :boolean },
need_time_attr: { type: :boolean },
cover_image: { type: :string },
banners: { type: :array },
detail: {
type: :object,
properties: {
product_detail: { type: :string },
notice: { type: :string },
}
},
spec: {
type: :object,
properties: {
color: { type: :array },
size: { type: :array },
},
},
meta: {
type: :object,
properties: {
meta1: { type: :string },
meta2: { type: :ineteger },
},
},
catalog_list: { type: :array }
}
}
}
}
produces 'application/json'
consumes 'application/json'
response(201, description: 'successful') do
product_attrs = FactoryGirl.attributes_for(:product)
let(:product) {
{
product: product_attrs.merge(
default_series_id: @series.id,
catalog_list: ['衣服', '上衣'],
)
}
}
it 'check attrs' do
body = JSON.parse(response.body)
the_same_values = ['spec', 'banners', 'detail', 'meta', 'title', 'need_express', 'need_time_attr'] # and so on
expect(product_attrs.values_at the_same_values).to eq(body.values_at the_same_values)
expect(body['default_series']['id']).to eq(@series.id), 'correct default_series'
expect(body['catalog_list']).to eq(['衣服', '上衣']), 'add catalog list successful'
end
end
end
end
path "/#{namespace}/products/{id}" do
parameter 'id', in: :path, type: :string
let(:id) { @product_1.id }
get(summary: '商户 商品详情') 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 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
it {
expect(JSON.parse(response.body)['series'].count).to eq(@product_1.series.count), "correct product's series"
}
end
end
patch(summary: 'update product') 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 }
produces 'application/json'
consumes 'application/json'
parameter :product, in: :body, schema: {
type: :object, properties: {
product: {
type: :object, properties: {
title: { type: :string },
default_series_id: { type: :integer },
need_express: { type: :boolean },
need_time_attr: { type: :boolean },
cover_image: { type: :string },
banners: { type: :array },
detail: {
type: :object,
properties: {
product_detail: { type: :string },
notice: { type: :string },
}
},
spec: {
type: :object,
properties: {
color: { type: :array },
size: { type: :array },
},
},
meta: {
type: :object,
properties: {
meta1: { type: :string },
meta2: { type: :ineteger },
},
},
catalog_list: { type: :array }
}
}
}
}
response(200, description: 'successful') do
let(:product) { { product: FactoryGirl.attributes_for(:product) } }
end
end
delete(summary: 'delete product') 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 }
produces 'application/json'
consumes 'application/json'
response(204, description: 'successful') do
end
end
end
path "/#{namespace}/products/{id}/put_on_shelf" do
parameter 'id', in: :path, type: :string
let(:id) { @product_1.id }
post(summary: '商户 上架商品') 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 }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
# it { p response.body }
end
end
end
path "/#{namespace}/products/{id}/sold_out" do
parameter 'id', in: :path, type: :string
let(:id) { @product_1.id }
post(summary: '商户 下架商品') 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 }
before { @product_1.update!(status: 'on_sale') }
produces 'application/json'
consumes 'application/json'
response(200, description: 'successful') do
# it { p response.body }
end
end
end
end
...@@ -2,6 +2,6 @@ json.extract! product, :id, :title, :status, :status_zh, ...@@ -2,6 +2,6 @@ json.extract! product, :id, :title, :status, :status_zh,
:need_express, :need_time_attr, :need_express, :need_time_attr,
:cover_image, :banners, :spec, :detail, :meta :cover_image, :banners, :spec, :detail, :meta
# TODO: NOTE: catalog_list is only vaild in the template example # TODO: NOTE: catalog_list is only vaild in the template example
json.catalog_list product.catalog_list json.catalog_list product.catalog_list if product.respond_to?(:catalog_list)
json.default_series product.default_series, partial: 'shotengai/share/series_simple', as: :series json.default_series product.default_series, partial: 'shotengai/share/series_simple', as: :series
json.series product.series, partial: 'shotengai/share/series_simple', as: :series json.series product.series, partial: 'shotengai/share/series_simple', as: :series
\ No newline at end of file
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