Skip to content

Commit

Permalink
用户界面 - 使用优惠券下单
Browse files Browse the repository at this point in the history
  • Loading branch information
leo108 committed Dec 23, 2018
1 parent 7dc64dc commit d74735f
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 22 deletions.
25 changes: 25 additions & 0 deletions app/Exceptions/CouponCodeUnavailableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace App\Exceptions;

use Illuminate\Http\Request;
use Exception;

class CouponCodeUnavailableException extends Exception
{
public function __construct($message, int $code = 403)
{
parent::__construct($message, $code);
}

// 当这个异常被触发时,会调用 render 方法来输出给用户
public function render(Request $request)
{
// 如果用户通过 Api 请求,则返回 JSON 格式的错误信息
if ($request->expectsJson()) {
return response()->json(['msg' => $this->message], $this->code);
}
// 否则返回上一页并带上错误信息
return redirect()->back()->withErrors(['coupon_code' => $this->message]);
}
}
1 change: 1 addition & 0 deletions app/Exceptions/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Handler extends ExceptionHandler
*/
protected $dontReport = [
InvalidRequestException::class,
CouponCodeUnavailableException::class,
];

/**
Expand Down
22 changes: 3 additions & 19 deletions app/Http/Controllers/CouponCodesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,18 @@

namespace App\Http\Controllers;

use App\Exceptions\CouponCodeUnavailableException;
use App\Models\CouponCode;
use Carbon\Carbon;

class CouponCodesController extends Controller
{
public function show($code)
{
// 判断优惠券是否存在
if (!$record = CouponCode::where('code', $code)->first()) {
abort(404);
throw new CouponCodeUnavailableException('优惠券不存在');
}

// 如果优惠券没有启用,则等同于优惠券不存在
if (!$record->enabled) {
abort(404);
}

if ($record->total - $record->used <= 0) {
return response()->json(['msg' => '该优惠券已被兑完'], 403);
}

if ($record->not_before && $record->not_before->gt(Carbon::now())) {
return response()->json(['msg' => '该优惠券现在还不能使用'], 403);
}

if ($record->not_after && $record->not_after->lt(Carbon::now())) {
return response()->json(['msg' => '该优惠券已过期'], 403);
}
$record->checkAvailable();

return $record;
}
Expand Down
13 changes: 12 additions & 1 deletion app/Http/Controllers/OrdersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
namespace App\Http\Controllers;

use App\Events\OrderReviewed;
use App\Exceptions\CouponCodeUnavailableException;
use App\Exceptions\InvalidRequestException;
use App\Http\Requests\ApplyRefundRequest;
use App\Http\Requests\OrderRequest;
use App\Http\Requests\SendReviewRequest;
use App\Models\CouponCode;
use App\Models\UserAddress;
use App\Models\Order;
use Carbon\Carbon;
Expand All @@ -19,8 +21,17 @@ public function store(OrderRequest $request, OrderService $orderService)
{
$user = $request->user();
$address = UserAddress::find($request->input('address_id'));
$coupon = null;

return $orderService->store($user, $address, $request->input('remark'), $request->input('items'));
// 如果用户提交了优惠码
if ($code = $request->input('coupon_code')) {
$coupon = CouponCode::where('code', $code)->first();
if (!$coupon) {
throw new CouponCodeUnavailableException('优惠券不存在');
}
}
// 参数中加入 $coupon 变量
return $orderService->store($user, $address, $request->input('remark'), $request->input('items'), $coupon);
}

public function index(Request $request)
Expand Down
47 changes: 47 additions & 0 deletions app/Models/CouponCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace App\Models;

use App\Exceptions\CouponCodeUnavailableException;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;

Expand Down Expand Up @@ -50,6 +52,51 @@ public function getDescriptionAttribute()
return $str.''.str_replace('.00', '', $this->value);
}

public function checkAvailable($orderAmount = null)
{
if (!$this->enabled) {
throw new CouponCodeUnavailableException('优惠券不存在');
}

if ($this->total - $this->used <= 0) {
throw new CouponCodeUnavailableException('该优惠券已被兑完');
}

if ($this->not_before && $this->not_before->gt(Carbon::now())) {
throw new CouponCodeUnavailableException('该优惠券现在还不能使用');
}

if ($this->not_after && $this->not_after->lt(Carbon::now())) {
throw new CouponCodeUnavailableException('该优惠券已过期');
}

if (!is_null($orderAmount) && $orderAmount < $this->min_amount) {
throw new CouponCodeUnavailableException('订单金额不满足该优惠券最低金额');
}
}

public function getAdjustedPrice($orderAmount)
{
// 固定金额
if ($this->type === self::TYPE_FIXED) {
// 为了保证系统健壮性,我们需要订单金额最少为 0.01 元
return max(0.01, $orderAmount - $this->value);
}

return number_format($orderAmount * (100 - $this->value) / 100, 2, '.', '');
}

public function changeUsed($increase = true)
{
// 传入 true 代表新增用量,否则是减少用量
if ($increase) {
// 与检查 SKU 库存类似,这里需要检查当前用量是否已经超过总量
return $this->newQuery()->where('id', $this->id)->where('used', '<', $this->total)->increment('used');
} else {
return $this->decrement('used');
}
}

public static function findAvailableCode($length = 16)
{
do {
Expand Down
23 changes: 21 additions & 2 deletions app/Services/OrderService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,20 @@
use App\Exceptions\InvalidRequestException;
use App\Jobs\CloseOrder;
use Carbon\Carbon;
use App\Models\CouponCode;
use App\Exceptions\CouponCodeUnavailableException;

class OrderService
{
public function store(User $user, UserAddress $address, $remark, $items)
public function store(User $user, UserAddress $address, $remark, $items, CouponCode $coupon = null)
{
// 如果传入了优惠券,则先检查是否可用
if ($coupon) {
// 但此时我们还没有计算出订单总金额,因此先不校验
$coupon->checkAvailable();
}
// 开启一个数据库事务
$order = \DB::transaction(function () use ($user, $address, $remark, $items) {
$order = \DB::transaction(function () use ($user, $address, $remark, $items, $coupon) {
// 更新此地址的最后使用时间
$address->update(['last_used_at' => Carbon::now()]);
// 创建一个订单
Expand Down Expand Up @@ -51,6 +58,18 @@ public function store(User $user, UserAddress $address, $remark, $items)
throw new InvalidRequestException('该商品库存不足');
}
}
if ($coupon) {
// 总金额已经计算出来了,检查是否符合优惠券规则
$coupon->checkAvailable($totalAmount);
// 把订单金额修改为优惠后的金额
$totalAmount = $coupon->getAdjustedPrice($totalAmount);
// 将订单与优惠券关联
$order->couponCode()->associate($coupon);
// 增加优惠券的用量,需判断返回值
if ($coupon->changeUsed() <= 0) {
throw new CouponCodeUnavailableException('该优惠券已被兑完');
}
}
// 更新订单总金额
$order->update(['total_amount' => $totalAmount]);

Expand Down
1 change: 1 addition & 0 deletions resources/views/cart/index.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
address_id: $('#order-form').find('select[name=address]').val(),
items: [],
remark: $('#order-form').find('textarea[name=remark]').val(),
coupon_code: $('input[name=coupon_code]').val(), // 从优惠码输入框中获取优惠码
};
// 遍历 <table> 标签内所有带有 data-id 属性的 <tr> 标签,也就是每一个购物车中的商品 SKU
$('table tr[data-id]').each(function () {
Expand Down

0 comments on commit d74735f

Please sign in to comment.