购物车功能点
1.0 购物车列表
2.0 添加到购物车
3.0 更新、删除购物车商品
4.0 选择或取消购物车商品
1.0下单
2.0订单支付、超时取消
3.0 确认收货
4.0订单评价
5.0订单列表、详情
er图设计
添加购物车的思路:
如果已经存在购物车货品,则增加数量;
否则添加新的购物车货品项.
逻辑思路
1.0 校验参数
$goodsId = $this->verifyId('goodsId', 0);
$productId = $this->verifyId('productId', 0);
$number = $this->verifyPositiveInteger('number', 0);
//2.0判断商品是否存在(主要判断商品是否可以购买)
if($number <= 0){
return $this->badArgument();
}
$goods = GoodsService::getInstance()->getGoods($goodsId);
if (is_null($goods) || !$goods->is_on_sale) {
return $this->fail(CodeResponse::GOODS_UNSHELVE);
}
//判断购物车中是否存在此规格商品
$product = GoodsServices::getInstance()->getGoodsProductById($productId);
if (is_null($product) || $product->number < $number) {
return $this->fail(CodeResponse::GOODS_NO_STOCK);
}
//获取购物车商品
CartServices::getInstance()->add($this->userId(), $goodsId, $productId, $number);
//如果没有添加购物车就添加一个新的,如果有就添加数量
更新:逻辑梳理
//1.0接收参数
$id = $this->verifyId('id', 0);
$goodsId = $this->verifyId('goodsId', 0);
$productId = $this->verifyId('productId', 0);
$number = $this->verifyPositiveInteger('number', 0);
//2.0获取当前购物车
$cart = CartServices::getInstance()->getCartById($this->userId(), $id);
//3.0如果购物车是null返回错误
if (is_null($cart)) {
return $this->badArgumentValue();
}
//4.0//判断当前购物车是否等于当前购物车以及其他参数
if ($cart->goods_id != $goodsId || $cart->product_id != $productId) {
return $this->badArgumentValue();
}
//5.0判断当前货品是否下架
$goods = GoodsServices::getInstance()->getGoods($goodsId);
if (is_null($goods) || !$goods->is_on_sale) {
return $this->fail(CodeResponse::GOODS_UNSHELVE);
}
//6.0判断商品的库存是否足够
$product = GoodsServices::getInstance()->getGoodsProductById($productId);
if (is_null($product) || $product->number < $number) {
return $this->fail(CodeResponse::GOODS_NO_STOCK);
}
//7.0修改购物车
$cart->number = $number;
$ret = $cart->save();
return $this->failOrSuccess($ret);
购物车:删除
逻辑:删除id
//验证是否数组是否为空
$productIds = $this->verifyArrayNotEmpty('productIds', []);
CartServices::getInstance()->delete($this->userId(), $productIds);
return $this->index();
立即购买
逻辑梳理:立即购买与加入购物车的逻辑很相识
区别
1.如果购物车内已经存在购物车货品,前者的逻辑是添加,这里的逻辑是数量覆盖。
2.0添加成功以后,前者的逻辑是返回当前购物车数量,这里的逻辑是返回对应购物车像的ID
/**
* 立即购买
* @return JsonResponse
* @throws BusinessException
*/
public function fastadd()
{
$goodsId = $this->verifyId('goodsId', 0);
$productId = $this->verifyId('productId', 0);
$number = $this->verifyPositiveInteger('number', 0);
$cart = CartServices::getInstance()->fastadd($this->userId(), $goodsId, $productId, $number);
return $this->success($cart->id);
}
public function fastadd($userId, $goodsId, $productId, $number)
{
//获取商品信息
list($goods, $product) = $this->getGoodsInfo($goodsId, $productId);
$cartProduct = $this->getCartProduct($userId, $goodsId, $productId);
if (is_null($cartProduct)) {
return $this->newCart($userId, $goods, $product, $number);
} else {
return $this->editCart($cartProduct, $product, $number);
}
}
public function getGoodsInfo($goodsId, $productId)
{
$goods = GoodsServices::getInstance()->getGoods($goodsId);
if (is_null($goods) || !$goods->is_on_sale) {
$this->throwBusinessException(CodeResponse::GOODS_UNSHELVE);
}
$product = GoodsServices::getInstance()->getGoodsProductById($productId);
if (is_null($product)) {
$this->throwBusinessException(CodeResponse::GOODS_NO_STOCK);
}
return [$goods, $product];
}
public function getCartProduct($userId, $goodsId, $productId)
{
return Cart::query()->where('user_id', $userId)->where('goods_id', $goodsId)
->where('product_id', $productId)->first();
}
public function newCart($userId, Goods $goods, GoodsProduct $product, $number)
{
if ($number > $product->number) {
$this->throwBusinessException(CodeResponse::GOODS_NO_STOCK);
}
$cart = Cart::new();
$cart->goods_sn = $goods->goods_sn;
$cart->goods_name = $goods->name;
$cart->pic_url = $product->url ?: $goods->pic_url;
$cart->price = $product->price;
$cart->specifications = $product->specifications;
$cart->user_id = $userId;
$cart->checked = true;
$cart->number = $number;
$cart->goods_id = $goods->id;
$cart->product_id = $product->id;
$cart->save();
return $cart;
}
public function editCart($existCart, $product, $num)
{
if ($num > $product->number) {
$this->throwBusinessException(CodeResponse::GOODS_NO_STOCK);
}
$existCart->number = $num;
$existCart->save();
return $existCart;
}
购物车列表接口
//逻辑梳理
//1.0购物车列表是需要登录
//2.0根据用户获取相关的数据记录
//3.0循环一下购物车获取一下还没有失效的商品
//4.0统计购物车商品的总件数金额等
//5.0最后拼装返回
//获取购物车列表
public function getCartList($userId)
{
return Cart::query()->where('user_id', $userId)->get();
}
public function getValidCartList($userId)
{
//获取有效的商品列表
$list = $this->getCartList($userId);
$goodsIds = $list->pluck('goods_id')->toArray();
//获取商品信息
$goodsList = GoodsServices::getInstance()
->getGoodsListByIds($goodsIds)->keyBy('id');
//记录无效的商品id
$invalidCartIds = [];
//对数组进行过滤
$list = $list->filter(function (Cart $cart) use ($goodsList, &$invalidCartIds) {
/** @var Goods $goods */
//拿到商品信息
$goods = $goodsList->get($cart->goods_id);
//过滤
$isValid = !empty($goods) && $goods->is_on_sale;
if (!$isValid) {
$invalidCartIds[] = $cart->id;
}
return $isValid;
});
//删除无效的商品id
$this->deleteCartList($invalidCartIds);
return $list;
}
public function deleteCartList($ids)
{
if (empty($ids)) {
return 0;
}
return Cart::query()->whereIn('id', $ids)->delete();
}
/**
* 购物车列表信息
* @return JsonResponse
* @throws Exception
*/
public function index()
{
$list = CartServices::getInstance()->getValidCartList($this->userId());
//总数
$goodsCount = 0;
//总金额
$goodsAmount = 0;
//选中商品的总数
$checkedGoodsCount = 0;
//选中的总金额
$checkedGoodsAmount = 0;
foreach ($list as $item) {
$goodsCount += $item->number;
$amount = bcmul($item->price, $item->number, 2);
$goodsAmount = bcadd($goodsAmount, $amount, 2);
if ($item->checked) {
$checkedGoodsCount += $item->number;
$checkedGoodsAmount = bcadd($checkedGoodsAmount, $amount, 2);
}
}
return $this->success(
[
'cartList' => $list->toArray(),
'cartTotal' => [
'goodsCount' => $goodsCount,
'goodsAmount' => (double) $goodsAmount,
'checkedGoodsCount' => $checkedGoodsCount,
'checkedGoodsAmount' => (double) $checkedGoodsAmount,
]
]
);
}
下单前逻辑确认
public function checkout()
{
//验证id
$cartId = $this->verifyInteger('cartId');
$addressId = $this->verifyInteger('addressId');
$couponId = $this->verifyInteger('couponId');
$grouponRulesId = $this->verifyInteger('grouponRulesId');
// 获取地址
$address = AddressServices::getInstance()->getAddressOrDefault($this->userId(), $addressId);
$addressId = $address->id ?? 0;
// 获取购物车的商品列表
$checkedGoodsList = CartServices::getInstance()->getCheckedCartList($this->userId(), $cartId);
// 计算商品总金额
$grouponPrice = 0;
$checkedGoodsPrice = CartServices::getInstance()->getCartPriceCutGroupon($checkedGoodsList, $grouponRulesId,
$grouponPrice);
// 获取优惠券信息
$availableCouponLength = 0;
$couponUser = CouponServices::getInstance()->getMostMeetPriceCoupon($this->userId(), $couponId,
$checkedGoodsPrice, $availableCouponLength);
// 兼容litemall的返回
if ($couponId == -1 || is_null($couponId)) {
// if (is_null($couponUser)) {
$couponId = -1;
$userCouponId = -1;
$couponPrice = 0;
} else {
$couponId = $couponUser->coupon_id ?? 0;
$userCouponId = $couponUser->id ?? 0;
$couponPrice = CouponServices::getInstance()->getCoupon($couponId)->discount ?? 0;
}
// 运费
$freightPrice = OrderServices::getInstance()->getFreight($checkedGoodsPrice);
// 计算订单金额
$orderPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderPrice = bcsub($orderPrice, $couponPrice, 2);
$orderPrice = max(0, $orderPrice);
return $this->success([
"addressId" => $addressId,
"couponId" => $couponId,
"userCouponId" => $userCouponId,
"cartId" => $cartId,
"grouponRulesId" => $grouponRulesId,
"grouponPrice" => $grouponPrice,
"checkedAddress" => $address,
"availableCouponLength" => $availableCouponLength,
"goodsTotalPrice" => $checkedGoodsPrice,
"freightPrice" => $freightPrice,
"couponPrice" => $couponPrice,
"orderTotalPrice" => $orderPrice,
"actualPrice" => $orderPrice,
"checkedGoodsList" => $checkedGoodsList->toArray(),
]);
}
/**
* 获取地址或者返回默认地址
* @param $userId
* @param null $addressId
* @return Address|Builder|Model|object|null
* @throws BusinessException
*/
public function getAddressOrDefault($userId, $addressId = null)
{
// 获取地址
if (empty($addressId)) {
$address = AddressServices::getInstance()->getDefaultAddress($userId);
} else {
$address = AddressServices::getInstance()->getAddress($userId, $addressId);
if (empty($address)) {
$this->throwBadArgumentValue();
}
}
return $address;
}
public function getDefaultAddress($userId)
{
//返回默认地址
return Address::query()->where('user_id', $userId)
->where('is_default', 1)->first();
}
/**
* 获取用户地址
* @param $userId
* @param $addressId
* @return Address|Model|null
*/
public function getAddress($userId, $addressId)
{
return Address::query()->where('user_id', $userId)->where('id', $addressId)
->first();
}
/**
* 获取已选择购物车商品列表
* @param $userId
* @param $cartId
* @return Cart[]|Collection
* @throws BusinessException
*/
public function getCheckedCartList($userId, $cartId = null)
{
if (empty($cartId)) {
$checkedGoodsList = $this->getCheckedCarts($userId);
} else {
$cart = $this->getCartById($userId, $cartId);
if (empty($cart)) {
$this->throwBadArgumentValue();
}
$checkedGoodsList = collect([$cart]);
}
return $checkedGoodsList;
}
public function getCheckedCarts($userId)
{
return Cart::query()->where('user_id', $userId)
->where('checked', 1)->get();
}
public function getCartById($userId, $id)
{
return Cart::query()->where('user_id', $userId)->where('id', $id)->first();
}
public function getCartPriceCutGroupon($checkedGoodsList, $grouponRulesId, &$grouponPrice = 0)
{
//获取一下团购规则
$grouponRules = GrouponServices::getInstance()->getGrouponRulesById($grouponRulesId);
$checkedGoodsPrice = 0;
//循环一下获取到购物车的列表
foreach ($checkedGoodsList as $cart) {
//(如果有团购商品就用团购规则来计算,如果没有就用原价)
//所以需要判断goods_id == 购物车->goods_id
if ($grouponRules && $grouponRules->goods_id == $cart->goods_id) {
//计算团购优惠的总金额
$grouponPrice = bcmul($grouponRules->discount, $cart->number, 2);
//如果都满足减折扣
$price = bcsub($cart->price, $grouponRules->discount, 2);
} else {
$price = $cart->price;
}
//计算单个商品的总金额
$price = bcmul($price, $cart->number, 2);
//计算所有商品的总金额
$checkedGoodsPrice = bcadd($checkedGoodsPrice, $price, 2);
}
return $checkedGoodsPrice;
}
先创建一个枚举用来区别不同的优惠卷
<?php
namespace App\Enums;
class CouponUserEnums
{
const STATUS_USABLE = 0;
const STATUS_USED = 1;
const STATUS_EXPIRED = 2;
const STATUS_OUT = 3;
}
/**
* 验证当前价格是否可以使用这张优惠券
* @param Coupon $coupon
* @param CouponUser $couponUser
* @param double $price
* @return bool
* @throws Exception
*/
public function checkCouponAndPrice($coupon, $couponUser, $price)
{
//如果优惠用户为空返回错误
if (empty($couponUser)) {
return false;
}
//如果优惠券为空返回错误
if (empty($coupon)) {
return false;
}
//如果用户与优惠卷 id不一样说明 数据不一致.
if ($couponUser->coupon_id != $coupon->id) {
return false;
}
//如果优惠券的状态不是0的话,那也是不能使用的
if ($coupon->status != CouponEnums::STATUS_NORMAL) {
return false;
}
//验证优惠卷支持的商品类型
if ($coupon->goods_type != CouponEnums::GOODS_TYPE_ALL) {
return false;
}
//需要满足最低消费金额
if (bccomp($coupon->min, $price) == 1) {
return false;
}
$now = now();
switch ($coupon->time_type) {
case CouponEnums::TIME_TYPE_TIME:
$start = Carbon::parse($coupon->start_time);
$end = Carbon::parse($coupon->end_time);
//如果当前时间在开始时间或者结束时间之后
if ($now->isBefore($start) || $now->isAfter($end)) {
return false;
}
break;
//算相对时间:从优惠卷领娶的时间开始算
case CouponEnums::TIME_TYPE_DAYS:
//当前时间加上有效时间
$expired = Carbon::parse($couponUser->add_time)->addDays($coupon->days);
//如果超过了有效时间
if ($now->isAfter($expired)) {
return false;
}
break;
default:
return false;
}
return true;
}
public function getMeetPriceCouponAndSort($userId, $price)
{
//获娶可以用的优惠券
$couponUsers = CouponServices::getInstance()->getUsableCoupons($userId);
//获取优惠卷的id列表
$couponIds = $couponUsers->pluck('coupon_id')->toArray();
//批量获取优惠券
$coupons = CouponServices::getInstance()->getCoupons($couponIds)->keyBy('id');
//过滤不需要的内容filter
return $couponUsers->filter(function (CouponUser $couponUser) use ($coupons, $price) {
/** @var Coupon $coupon */
$coupon = $coupons->get($couponUser->coupon_id);
return CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $price);
//默认选取优惠力度最大的
})->sortByDesc(function (CouponUser $couponUser) use ($coupons) {
/** @var Coupon $coupon */
$coupon = $coupons->get($couponUser->coupon_id);
return $coupon->discount;//discount优惠金额
});
}
一下代码还会进行封装切勿复制粘贴
public function getMeetPriceCouponAndSort($userId, $price)
{
//获娶可以用的优惠券
$couponUsers = CouponServices::getInstance()->getUsableCoupons($userId);
//获取优惠卷的id列表
$couponIds = $couponUsers->pluck('coupon_id')->toArray();
//批量获取优惠券
$coupons = CouponServices::getInstance()->getCoupons($couponIds)->keyBy('id');
//过滤不需要的内容filter
return $couponUsers->filter(function (CouponUser $couponUser) use ($coupons, $price) {
/** @var Coupon $coupon */
$coupon = $coupons->get($couponUser->coupon_id);
return CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $price);
//默认选取优惠力度最大的
})->sortByDesc(function (CouponUser $couponUser) use ($coupons) {
/** @var Coupon $coupon */
$coupon = $coupons->get($couponUser->coupon_id);
return $coupon->discount;//discount优惠金额
});
//初始化优惠卷价格
$couponFirst = 0;
//如果couponId是null或者couponId == -1 不使用优惠卷
if(is_null($couponId) || $couponId == -1;){
$userCouponId = -1;
}elseif ($couponId == 0){
/** @var CouponUser $couponUser */
$couponUser = $couponUsers->first();
$couponId = $couponUser->coupon_id ?? 0;
//获取优惠信息
$couponPrice = CouponServices::getInstance()->getCoupon($couponId)->discount ?? 0;
} else {
//如果传了$couponId
//获取$coupon对象信息
$coupon = CouponServices::getInstance()->getCoupon($couponId);
//获取$coupon 对象信息
$couponUser = CouponServices::getInstance()->getCouponUser($userCouponId);
//验证这个优惠卷是否可用
$is = CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $price);
if ($is) {
$couponPrice = $coupon->disscount ?? 0 ;
//下面两句可以省略不写 因为 验证通过了肯定可以
//$couponId = $couponUser -> coupon_id ?? 0;
// $userCouponId = $couponUser -> id ?? 0;
}
}
}
}
public function getCouponUser($id, $columns = ['*'])
{
return CouponUser::query()->find($id, $columns);
}
到此优惠卷相关内容已经完成 接下来 算运费
在这里插入代码片
<?php
namespace App\Services;
use App\Models\System;
class SystemServices extends BaseServices
{
// 小程序相关配置
const LITEMALL_WX_INDEX_NEW = "litemall_wx_index_new";
const LITEMALL_WX_INDEX_HOT = "litemall_wx_index_hot";
const LITEMALL_WX_INDEX_BRAND = "litemall_wx_index_brand";
const LITEMALL_WX_INDEX_TOPIC = "litemall_wx_index_topic";
const LITEMALL_WX_INDEX_CATLOG_LIST = "litemall_wx_catlog_list";
const LITEMALL_WX_INDEX_CATLOG_GOODS = "litemall_wx_catlog_goods";
const LITEMALL_WX_SHARE = "litemall_wx_share";
// 运费相关配置
const LITEMALL_EXPRESS_FREIGHT_VALUE = "litemall_express_freight_value";
const LITEMALL_EXPRESS_FREIGHT_MIN = "litemall_express_freight_min";
// 订单相关配置
const LITEMALL_ORDER_UNPAID = "litemall_order_unpaid";
const LITEMALL_ORDER_UNCONFIRM = "litemall_order_unconfirm";
const LITEMALL_ORDER_COMMENT = "litemall_order_comment";
// 商场相关配置
const LITEMALL_MALL_NAME = "litemall_mall_name";
const LITEMALL_MALL_ADDRESS = "litemall_mall_address";
const LITEMALL_MALL_PHONE = "litemall_mall_phone";
const LITEMALL_MALL_QQ = "litemall_mall_qq";
const LITEMALL_MALL_LONGITUDE = "litemall_mall_longitude";
const LITEMALL_MALL_Latitude = "litemall_mall_latitude";
public function getOrderUnConfirmDays()
{
return (int) $this->get(self::LITEMALL_ORDER_UNCONFIRM);
}
public function getOrderUnpaidDelayMinutes()
{
return (int) $this->get(self::LITEMALL_ORDER_UNPAID);
}
public function getFreightValue()
{
return (double) $this->get(self::LITEMALL_EXPRESS_FREIGHT_VALUE);
}
public function getFreightMin()
{
return (double) $this->get(self::LITEMALL_EXPRESS_FREIGHT_MIN);
}
//获取 系统配置方法
public function get($key)
{
$value = System::query()->where('key_name', $key)->first(['key_value']);
$value = $value['key_value'] ?? null;
if ($value == 'false' || $value == 'FALSE') {
return false;
}
if ($value == 'true' || $value == 'TRUE') {
return true;
}
return $value;
}
}
public function getMeetPriceCouponAndSort($userId, $price)
{
//获娶可以用的优惠券
$couponUsers = CouponServices::getInstance()->getUsableCoupons($userId);
//获取优惠卷的id列表
$couponIds = $couponUsers->pluck('coupon_id')->toArray();
//批量获取优惠券
$coupons = CouponServices::getInstance()->getCoupons($couponIds)->keyBy('id');
//过滤不需要的内容filter
return $couponUsers->filter(function (CouponUser $couponUser) use ($coupons, $price) {
/** @var Coupon $coupon */
$coupon = $coupons->get($couponUser->coupon_id);
return CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $price);
//默认选取优惠力度最大的
})->sortByDesc(function (CouponUser $couponUser) use ($coupons) {
/** @var Coupon $coupon */
$coupon = $coupons->get($couponUser->coupon_id);
return $coupon->discount;//discount优惠金额
});
//初始化优惠卷价格
$couponFirst = 0;
//如果couponId是null或者couponId == -1 不使用优惠卷
if(is_null($couponId) || $couponId == -1;){
$couponId = -1;
$userCouponId = -1;
}elseif ($couponId == 0){
/** @var CouponUser $couponUser */
$couponUser = $couponUsers->first();
$couponId = $couponUser->coupon_id ?? 0;
//获取优惠信息
$couponPrice = CouponServices::getInstance()->getCoupon($couponId)->discount ?? 0;
} else {
//如果传了$couponId
//获取$coupon对象信息
$coupon = CouponServices::getInstance()->getCoupon($couponId);
//获取$coupon 对象信息
$couponUser = CouponServices::getInstance()->getCouponUser($userCouponId);
//验证这个优惠卷是否可用
$is = CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $price);
if ($is) {
$couponPrice = $coupon->disscount ?? 0 ;
//下面两句可以省略不写 因为 验证通过了肯定可以
//$couponId = $couponUser -> coupon_id ?? 0;
// $userCouponId = $couponUser -> id ?? 0;
}
}
//运费
$freightPrice = 0;
//获取最低运费
$freightMin = SYstemServices::getInstance()->getFreightMin();
if (bccomp($freightMin, $price) == 1) {
$freightPrice = SystemServices::getInstance()->getFreightValue();
}
// 计算订单金额 +运费-优惠卷
$orderPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderPrice = bcsub($orderPrice, $couponPrice, 2);
return $this->success([
"addressId" => $addressId,
"couponId" => $couponId,
"userCouponId" => $userCouponId,
"cartId" => $cartId,
"grouponRulesId" => $grouponRulesId,
"grouponPrice" => $grouponPrice,
"checkedAddress" => $address,
"availableCouponLength" => $availableCouponLength,
"goodsTotalPrice" => $checkedGoodsPrice,
"freightPrice" => $freightPrice,
"couponPrice" => $couponPrice,
"orderTotalPrice" => $orderPrice,
"actualPrice" => $orderPrice,
"checkedGoodsList" => $checkedGoodsList->toArray(),
]);
}
}
public function getFreightValue()
{
return (double) $this->get(self::LITEMALL_EXPRESS_FREIGHT_VALUE);
}
优化下单前信息确认
/**
* 下单前信息确认
* @return JsonResponse
* @throws BusinessException
* @throws Exception
*/
public function checkout()
{
//验证id
$cartId = $this->verifyInteger('cartId');
$addressId = $this->verifyInteger('addressId');
$couponId = $this->verifyInteger('couponId');
$grouponRulesId = $this->verifyInteger('grouponRulesId');
// 获取地址
$address = AddressServices::getInstance()->getAddressOrDefault($this->userId(), $addressId);
$addressId = $address->id ?? 0;
// 获取购物车的商品列表
$checkedGoodsList = CartServices::getInstance()->getCheckedCartList($this->userId(), $cartId);
// 计算商品总金额
$grouponPrice = 0;
$checkedGoodsPrice = CartServices::getInstance()->getCartPriceCutGroupon($checkedGoodsList, $grouponRulesId,
$grouponPrice);
// 获取优惠券信息
$availableCouponLength = 0;
$couponUser = CouponServices::getInstance()->getMostMeetPriceCoupon($this->userId(), $couponId,
$checkedGoodsPrice, $availableCouponLength);
// 兼容litemall的返回
if ($couponId == -1 || is_null($couponId)) {
// if (is_null($couponUser)) {
$couponId = -1;
$userCouponId = -1;
$couponPrice = 0;
} else {
$couponId = $couponUser->coupon_id ?? 0;
$userCouponId = $couponUser->id ?? 0;
$couponPrice = CouponServices::getInstance()->getCoupon($couponId)->discount ?? 0;
}
// 运费
$freightPrice = OrderServices::getInstance()->getFreight($checkedGoodsPrice);
// 计算订单金额
$orderPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderPrice = bcsub($orderPrice, $couponPrice, 2);
$orderPrice = max(0, $orderPrice);
return $this->success([
"addressId" => $addressId,
"couponId" => $couponId,
"userCouponId" => $userCouponId,
"cartId" => $cartId,
"grouponRulesId" => $grouponRulesId,
"grouponPrice" => $grouponPrice,
"checkedAddress" => $address,
"availableCouponLength" => $availableCouponLength,
"goodsTotalPrice" => $checkedGoodsPrice,
"freightPrice" => $freightPrice,
"couponPrice" => $couponPrice,
"orderTotalPrice" => $orderPrice,
"actualPrice" => $orderPrice,
"checkedGoodsList" => $checkedGoodsList->toArray(),
]);
}
}
/**
* 获取地址或者返回默认地址
* @param $userId
* @param null $addressId
* @return Address|Builder|Model|object|null
* @throws BusinessException
*/
public function getAddressOrDefault($userId, $addressId = null)
{
// 获取地址
if (empty($addressId)) {
$address = AddressServices::getInstance()->getDefaultAddress($userId);
} else {
$address = AddressServices::getInstance()->getAddress($userId, $addressId);
if (empty($address)) {
$this->throwBadArgumentValue();
}
}
return $address;
}
public function getDefaultAddress($userId)
{
return Address::query()->where('user_id', $userId)
->where('is_default', 1)->first();
}
/**
* 获取用户地址
* @param $userId
* @param $addressId
* @return Address|Model|null
*/
public function getAddress($userId, $addressId)
{
return Address::query()->where('user_id', $userId)->where('id', $addressId)
->first();
}
/**
* @throws BusinessException
*/
public function throwBadArgumentValue()
{
$this->throwBusinessException(CodeResponse::PARAM_VALUE_ILLEGAL);
}
// 获取购物车的商品列表
c
h
e
c
k
e
d
G
o
o
d
s
L
i
s
t
=
C
a
r
t
S
e
r
v
i
c
e
s
:
:
g
e
t
I
n
s
t
a
n
c
e
(
)
−
>
g
e
t
C
h
e
c
k
e
d
C
a
r
t
L
i
s
t
(
checkedGoodsList = CartServices::getInstance()->getCheckedCartList(
checkedGoodsList=CartServices::getInstance()−>getCheckedCartList(this->userId(), $cartId);
/**
* 获取已选择购物车商品列表
* @param $userId
* @param $cartId
* @return Cart[]|Collection
* @throws BusinessException
*/
public function getCheckedCartList($userId, $cartId = null)
{
if (empty($cartId)) {
$checkedGoodsList = $this->getCheckedCarts($userId);
} else {
$cart = $this->getCartById($userId, $cartId);
if (empty($cart)) {
$this->throwBadArgumentValue();
}
$checkedGoodsList = collect([$cart]);
}
return $checkedGoodsList;
}
public function getCheckedCarts($userId)
{
return Cart::query()->where('user_id', $userId)
->where('checked', 1)->get();
}
public function getCartById($userId, $id)
{
return Cart::query()->where('user_id', $userId)->where('id', $id)->first();
}
/**
* @throws BusinessException
*/
public function throwBadArgumentValue()
{
$this->throwBusinessException(CodeResponse::PARAM_VALUE_ILLEGAL);
}
这里以引用的方式传进来会getCartPriceCutGroupon方法执行后重新赋值
// 计算商品总金额
$grouponPrice = 0;
$checkedGoodsPrice = CartServices::getInstance()->getCartPriceCutGroupon($checkedGoodsList, $grouponRulesId,
$grouponPrice);
public function getCartPriceCutGroupon($checkedGoodsList, $grouponRulesId, &$grouponPrice = 0)
{
//获取一下团购规则
$grouponRules = GrouponServices::getInstance()->getGrouponRulesById($grouponRulesId);
$checkedGoodsPrice = 0;
//循环一下获取到购物车的列表
foreach ($checkedGoodsList as $cart) {
//(如果有团购商品就用团购规则来计算,如果没有就用原价)
//所以需要判断goods_id == 购物车->goods_id
if ($grouponRules && $grouponRules->goods_id == $cart->goods_id) {
//计算团购优惠的总金额
$grouponPrice = bcmul($grouponRules->discount, $cart->number, 2);
//如果都满足减折扣
$price = bcsub($cart->price, $grouponRules->discount, 2);
} else {
$price = $cart->price;
}
//计算单个商品的总金额
$price = bcmul($price, $cart->number, 2);
//计算所有商品的总金额
$checkedGoodsPrice = bcadd($checkedGoodsPrice, $price, 2);
}
return $checkedGoodsPrice;
}
// 获取优惠券信息
$availableCouponLength = 0;
$couponUser = CouponServices::getInstance()->getMostMeetPriceCoupon($this->userId(), $couponId,
$checkedGoodsPrice, $availableCouponLength);
// 兼容litemall的返回 如果是空就返回 -1 如果不是非空就返回正常信息
if ($couponId == -1 || is_null($couponId)) {
// if (is_null($couponUser)) {
$couponId = -1;
$userCouponId = -1;
$couponPrice = 0;
} else {
$couponId = $couponUser->coupon_id ?? 0;
$userCouponId = $couponUser->id ?? 0;
$couponPrice = CouponServices::getInstance()->getCoupon($couponId)->discount ?? 0;
}
/**
* 获取适合当前价格的优惠券
* @param $userId
* @param $couponId
* @param $price
* @param int $availableCouponLength
* @return CouponUser|null
* @throws Exception
*/
public function getMostMeetPriceCoupon($userId, $couponId, $price, &$availableCouponLength = 0)
{
$couponUsers = $this->getMeetPriceCouponAndSort($userId, $price);
$availableCouponLength = $couponUsers->count();
if (is_null($couponId) || $couponId == -1) {
return null;
}
if (!empty($couponId)) {
$coupon = $this->getCoupon($couponId);
$couponUser = $this->getCouponUserByCouponId($userId, $couponId);
$is = $this->checkCouponAndPrice($coupon, $couponUser, $price);
if ($is) {
return $couponUser;
}
}
return $couponUsers->first();
}
最后重构
// 运费
$freightPrice = OrderServices::getInstance()->getFreight($checkedGoodsPrice);
// 计算订单金额
$orderPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderPrice = bcsub($orderPrice, $couponPrice, 2);
$orderPrice = max(0, $orderPrice);
return $this->success([
"addressId" => $addressId,
"couponId" => $couponId,
"userCouponId" => $userCouponId,
"cartId" => $cartId,
"grouponRulesId" => $grouponRulesId,
"grouponPrice" => $grouponPrice,
"checkedAddress" => $address,
"availableCouponLength" => $availableCouponLength,
"goodsTotalPrice" => $checkedGoodsPrice,
"freightPrice" => $freightPrice,
"couponPrice" => $couponPrice,
"orderTotalPrice" => $orderPrice,
"actualPrice" => $orderPrice,
"checkedGoodsList" => $checkedGoodsList->toArray(),
]);
/**
* 获取运费
* @param $price
* @return float|int
*/
public function getFreight($price)
{
$freightPrice = 0;
$freightMin = SystemServices::getInstance()->getFreightMin();
if (bccomp($freightMin, $price) == 1) {
$freightPrice = SystemServices::getInstance()->getFreightValue();
}
return $freightPrice;
}
public function getOrderByUserIdAndId($userId, $orderId)
{
return Order::query()->where('user_id', $userId)->find($orderId);
}
下单逻辑实在是有点恶心.后期还会整理 有些地方还可以整理
由于参数过长这里我们可以封装一下
/**
* 提交订单
* @return JsonResponse
* @throws BusinessException
* @throws Throwable
*/
public function submit()
{
//入参
$input = OrderSubmitInput::new();
//调用提交订单方法 transaction是开启事务
$order = DB::transaction(function () use ($input) {
return OrderServices::getInstance()->submit($this->userId(), $input);
});
return $this->success([
'orderId' => $order->id,
'grouponLikeId' => $input->grouponLinkId ?? 0
]);
}
/**
* 提交订单
* @param $userId
* @param OrderSubmitInput $input
* @return Order|void
* @throws BusinessException
*/
public function submit($userId, OrderSubmitInput $input)
{
// 验证团购规则的有效性
if (!empty($input->grouponRulesId)) {
GrouponServices::getInstance()->checkGrouponValid($userId, $input->grouponRulesId);
}
$address = AddressServices::getInstance()->getAddress($userId, $input->addressId);
if (empty($address)) {
return $this->throwBadArgumentValue();
}
// 获取购物车的商品列表
$checkedGoodsList = CartServices::getInstance()->getCheckedCartList($userId, $input->cartId);
// 计算商品总金额
$grouponPrice = 0;
$checkedGoodsPrice = CartServices::getInstance()->getCartPriceCutGroupon($checkedGoodsList,
$input->grouponRulesId,
$grouponPrice);
// 获取优惠券面额
$couponPrice = 0;
if ($input->couponId > 0) {
$coupon = CouponServices::getInstance()->getCoupon($input->couponId);
$couponUser = CouponServices::getInstance()->getCouponUser($input->userCouponId);
$is = CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $checkedGoodsPrice);
if ($is) {
$couponPrice = $coupon->discount;
}
}
// 运费
$freightPrice = $this->getFreight($checkedGoodsPrice);
// 计算订单金额
$orderTotalPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderTotalPrice = bcsub($orderTotalPrice, $couponPrice, 2);
$orderTotalPrice = max(0, $orderTotalPrice);
$order = Order::new();
$order->user_id = $userId;
$order->order_sn = $this->generateOrderSn();
$order->order_status = OrderEnums::STATUS_CREATE;
$order->consignee = $address->name;
$order->mobile = $address->tel;
$order->address = $address->province.$address->city.$address->county." ".$address->address_detail;
$order->message = $input->message;
$order->goods_price = $checkedGoodsPrice;
$order->freight_price = $freightPrice;
$order->integral_price = 0;
$order->coupon_price = $couponPrice;
$order->order_price = $orderTotalPrice;
$order->actual_price = $orderTotalPrice;
$order->groupon_price = $grouponPrice;
$order->save();
// 写入订单商品记录
$this->saveOrderGoods($checkedGoodsList, $order->id);
// 清理购物车记录
CartServices::getInstance()->clearCartGoods($userId, $input->cartId);
// 减库存
$this->reduceProductsStock($checkedGoodsList);
// 添加团购记录
GrouponServices::getInstance()->openOrJoinGroupon($userId, $order->id, $input->grouponRulesId,
$input->grouponLinkId);
// 设置超时任务
dispatch(new OrderUnpaidTimeEndJob($userId, $order->id));
return $order;
}
//此时暂时控制器的代码
// 计算商品总金额
$grouponPrice = 0;
$checkedGoodsPrice = CartServices::getInstance()->getCartPriceCutGroupon($checkedGoodsList,
$input->grouponRulesId,
$grouponPrice);
// 获取优惠券面额
$couponPrice = 0;
if ($input->couponId > 0) {
$coupon = CouponServices::getInstance()->getCoupon($input->couponId);
$couponUser = CouponServices::getInstance()->getCouponUser($input->userCouponId);
$is = CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $checkedGoodsPrice);
if ($is) {
$couponPrice = $coupon->discount;
}
}
// 运费
$freightPrice = $this->getFreight($checkedGoodsPrice);
// 计算订单金额
$orderTotalPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderTotalPrice = bcsub($orderTotalPrice, $couponPrice, 2);
$orderTotalPrice = max(0, $orderTotalPrice);
优化后
/**
* 提交订单
* @param $userId
* @param OrderSubmitInput $input
* @return Order|void
* @throws BusinessException
*/
public function submit($userId, OrderSubmitInput $input)
{
// 验证团购规则的有效性
if (!empty($input->grouponRulesId)) {
//校验用户是否可以开启或参与某个团购活动
GrouponServices::getInstance()->checkGrouponValid($userId, $input->grouponRulesId);
}
//获取收获地址
$address = AddressServices::getInstance()->getAddress($userId, $input->addressId);
//如果获取不到的话抛出异常
if (empty($address)) {
return $this->throwBadArgumentValue();
}
// 获取购物车的商品列表 计算总金额需要先获取商品列表
$checkedGoodsList = CartServices::getInstance()->getCheckedCartList($userId, $input->cartId);
// 计算商品总金额
$grouponPrice = 0;
$checkedGoodsPrice = CartServices::getInstance()->getCartPriceCutGroupon($checkedGoodsList,
$input->grouponRulesId,
$grouponPrice);
// 获取优惠券面额 逻辑:这里只要用户选中了就代表是最终的选择
$couponPrice = 0;
if ($input->couponId > 0) {
//获取优惠卷信息
$coupon = CouponServices::getInstance()->getCoupon($input->couponId);
//获取优惠用户
$couponUser = CouponServices::getInstance()->getCouponUser($input->userCouponId);
$is = CouponServices::getInstance()->checkCouponAndPrice($coupon, $couponUser, $checkedGoodsPrice);
if ($is) {
$couponPrice = $coupon->discount;
}
}
// 运费
$freightPrice = $this->getFreight($checkedGoodsPrice);
// 计算订单金额
$orderTotalPrice = bcadd($checkedGoodsPrice, $freightPrice, 2);
$orderTotalPrice = bcsub($orderTotalPrice, $couponPrice, 2);
$orderTotalPrice = max(0, $orderTotalPrice);
//保存订单
$order = Order::new();
$order->user_id = $userId;
$order->order_sn = $this->generateOrderSn();
$order->order_status = OrderEnums::STATUS_CREATE;
$order->consignee = $address->name;
$order->mobile = $address->tel;
$order->address = $address->province.$address->city.$address->county." ".$address->address_detail;
$order->message = $input->message;
$order->goods_price = $checkedGoodsPrice;
$order->freight_price = $freightPrice;
$order->integral_price = 0;
$order->coupon_price = $couponPrice;
$order->order_price = $orderTotalPrice;
$order->actual_price = $orderTotalPrice;
$order->groupon_price = $grouponPrice;
$order->save();
// 写入订单商品记录
$this->saveOrderGoods($checkedGoodsList, $order->id);
// 清理购物车记录
CartServices::getInstance()->clearCartGoods($userId, $input->cartId);
// 减库存 这里的减库存的逻辑可以先跳过
$this->reduceProductsStock($checkedGoodsList);
// 添加团购记录
GrouponServices::getInstance()->openOrJoinGroupon($userId, $order->id, $input->grouponRulesId,
$input->grouponLinkId);
// 设置超时任务
dispatch(new OrderUnpaidTimeEndJob($userId, $order->id));
return $order;
}
public function reduceProductsStock($goodsList)
{
foreach ($goodsList as $cart) {
//获取商品的信息
$products = GoodsServices::getInstance()->getGoodsProductsByIds($productIds)->keyBy('id');
//判断货品信息是否获取到了
if (empty($product)) {
$this->throwBadArgumentValue();
}
//判断库存是否充足
if ($product->number < $cart->number) {
$this->throwBusinessException(CodeResponse::GOODS_NO_STOCK);
}
//减库存 decrement方法可以自动减库存
GoodsProduct::query()->where('id',$product->id)->where('number','>',$cart->number)
->decrement('number',$cart->number);
}
}