美文网首页Ruby
订单状态切换功能: aasm状态机

订单状态切换功能: aasm状态机

作者: Sarah_友妹 | 来源:发表于2017-10-22 20:56 被阅读96次

网上商店,消费者下单后,形成了订单,在不同情形下,订单的状态也会不同。因此,我们需要有一个功能,能使订单从某种状态切换(变化)成另一种状态。这就是订单状态的切换功能,而aasm状态机正是实现这一功能的工具。

逻辑梳理


在开始实现这种功能,使用aasm状态机之前。我们需要先问自己几个问题:

  1. 订单状态有多少种
  2. 订单切换事件有多少种
  3. 在什么情况下,触发订单切换事件

弄清楚这些问题,理清它们之间的逻辑关系,有利于我们规划使用aasm,达到功能切换的目的。

我先放一张图,来形象化描述问题1、问题2:

进一步阐释

  1. 订单状态
  • 种类: 6种
  • 分别是: order_placed, paid, shipping, shipped, good_returned, order_cancelled
  1. 订单切换事件
  • 定义:它指的是订单从一种或几种状态切换/转变成另一种状态的过程
  • 种类:5种
  • 分别是:A, B, C, D, E
  • 举例说明:比如A事件的发生,意味着订单状态从order_placed改变为paid,最终结果是订单状态为paid
  1. 触发订单切换事件的条件
  • 定义:它指的是,在满足某种条件或情形下,我们就会去触发订单切换事件;从行为的先后顺利角度看,执行订单切换事件行为的“前一个行为”就是“触发订单切换事件的条件”
  • 举例说明:比如触发A事件的条件,是消费者下完订单、点击付款提交后

具体案例


Part I

解决问题1和问题2,即安装aasm以及定义订单状态和订单切换事件

Step1: 安装aasm

gem 'aasm'

执行bundle install rails s

Step2: 在orders table里,产生aasm_state栏位,用来记录订单状态
执行rails g migration add_aasm_state_to_orders
在刚才的migration 文件里,增加两行

add_column :orders, :aasm_state, :string
add_index :orders, :aasm_state

执行rake db:migrate

Step3: 在app/models/order.rb文件里,增加以下内容

include AASM
aasm do
  state :order_placed
  state :paid
  state :shipping
  state :shipped
  state :good_returned
  state :order_cancelled

  event :make_payment do
    transitions from: :order_placed, to: :paid
  end

  event : ship do
    transitions from: :paid, to: :shipping
  end

  event :deliver do
    transitions from: :shipping, to: :shipped
  end

  event :return_good do
    transitions from: :shipped, to: :good_returned
  end 

  event :cancel_order do
    transitions from: [:order_placed, :paid], to: :order_cancelled
  end

end

说明:以上步骤,解决了问题1、问题2,

Part II

解决问题3,定义触发订单切换事件的条件,此处分别针对触发事件A, B, C, D, E的条件

(一)定义触发订单切换事件A的条件

条件是:消费者下定单且提交付款之后

Step1: 定义好routing,在member do下面加入两行

resources :orders do
  member do
    post :pay_with_alipay
    post :pay_with_wechat
  end
end

Step2: 付款这个action,通常是在app/controllers/orders_controller.rb里定义的,比如是用支付宝或微信付款,则这个action可以加入一行: @order.make_payment

def pay_with_alipay
  @order = Order.find(params[:id])
  @order.set_payment_with("alipay")
  @order.make_payment
  flash[:notice] =  "已用支付宝完成付款"
  redirect_to order_path(@order)
end

def pay_with_wechat
  @order = Order.find(params[:id])
  @order.set_payment_with("wechat")
  @order.make_payment!
  flash[:notice] =  "已用微信完成付款"
  redirect_to order_path(@order)
end

Step3: 在app/models/order.rb里,分别定义和支付相关的两个方法

def set_payment_with(method)
  self.update_columns(payment_method: method)
end

def pay!
  self.update_columns(is_paid: true)
end

Step3: 事件A的触发条件,包括两个:make_payment 以及 after_commit: :pay!
所以在order.rb里,重新定义事件A

  event :maket_payment, after_commit: :pay! do
    transitions from: :order_placed, to: :paid
  end
(二)定义触发订单切换事件B, C, D, E的条件

B: 管理员在后台点击“出货”按钮
C: 管理员在后台点击“已出货”按钮
D: 管理员在后台点击“退货”按钮
E: 管理员在后台点击“取消订单”按钮

Step1: 定义好routing, 在member do下面加入四行,这四行分别对应以上“触发订单切换事件B, C, D, E 条件"的routing

namespace :admin do
  resources :orders do
    member do
      post :ship
      post :shipped
      post :return
      post :cancel
    end
  end
end

Step2: 定义好以上条件的action,在app/controllers/admin/orders_controller.rb文件里,写以下代码,让action里包含了事件的执行

def ship
  @order = Order.find(params[:id])
  @ordr.ship!
  redirect_to admin_order_path(@order)
end

def shipped
  @order = Order.find(params[:id])
  @ordr.deliver!
  redirect_to admin_order_path(@order)
end

def return
  @order = Order.find(params[:id])
  @ordr.return_good!
  redirect_to admin_order_path(@order)
end

def cancel
  @order = Order.find(params[:id])
  @ordr.cancel_order!
  redirect_to admin_order_path(@order)
end

Step3: 写好view,让每个订单可以因其不同状态被管理员在后台点击切换
新增一个文件touch app/views/admin/orders/_state.html.erb
在该文件里,写入

<div style="padding: 10px; float: right; ">

<% case order.aasm_state do %>
<% when "order_placed" %>
  <%= link_to("取消订单", cancel_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %>

<% when "paid" %>
  <%= link_to("取消订单", cancel_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %>
  <%= link_to("出货", ship_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %>

<% when "shipping" %>
  <%= link_to("已出货", shipped_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %>

<% when "shipped" %>
  <%= link_to("退货", return_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %>

<% when "good_returned" %>
  <span class="label label-default">已退货</span>

<% when "order_cancelled" %>
  <span class="label label-default">已取消订单</span>

<% end %>
<div>

在app/views/admin/orders/show.html.erb里,新增一行

<%= render "state", order: @order %>

总结


经过逻辑梳理,理解运作机制,能帮助我们事先规划好,便于后续实作代码。
通过具体案例,运用上面的逻辑梳理,落到实处写代码,实现订单状态切换的功能。

相关文章

  • 订单状态切换功能: aasm状态机

    网上商店,消费者下单后,形成了订单,在不同情形下,订单的状态也会不同。因此,我们需要有一个功能,能使订单从某种状态...

  • 拼团业务流程、逻辑与后台功能

    1、业务主流程 2、逻辑 3、 拼团订单状态机 4、后台功能

  • aasm 交换机 订单状态交换功能

    使用: gem 'aasm' 2.设置一个初始状态 3.状态转换初始状态为published(未审核),审核通过,...

  • 有限状态机

    状态机,控制各个状态。1、各个状态内部,返回要跳转的下一个状态,状态机会自动切换状态;2、也可以外部调用状态机,手...

  • 状态机

    有限状态机 finite-state machine FSM 有限状态机在设计交易订单系统时,会存在正向状态(待...

  • 交易系统

    订单管理 订单状态: 审核状态: 上方的状态更多的是业务表示的状态, 而不是技术实现上的逻辑状态机.比如 退款关闭...

  • spring statemachine-多个状态机共存

    1、多个状态机的搞法    在实际的企业应用中,基本不可能只有一个状态机流程在跑,比如订单,肯定是很多个订单在运行...

  • 常见幂等性接口设计方案

    1 状态机幂等针对更新操作,比如业务上需要修改订单状态,订单有 待支付、支付中、支付成功、支付失败、订单超时关闭等...

  • 状态机

    本文源自《谈谈状态机》。 我经常在工作中听到状态机的概念,尤其是我们公司的支付系统,订单状态在接收到某个事件后需要...

  • FSM01

    1.在游戏开发过程中,涉及到复杂的状态切换时,可以运用状态模式以及状态机来高效地完成任务。 2.有限状态机的实现方...

网友评论

    本文标题:订单状态切换功能: aasm状态机

    本文链接:https://www.haomeiwen.com/subject/jmfnuxtx.html