73 changed files with 0 additions and 8010 deletions
@ -1,78 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\exception\BaseException; |
|||
use app\common\model\Article as ArticleModel; |
|||
|
|||
/** |
|||
* 商品评价模型 |
|||
* Class Article |
|||
* @package app\api\model |
|||
*/ |
|||
class Article extends ArticleModel |
|||
{ |
|||
/** |
|||
* 追加字段 |
|||
* @var array |
|||
*/ |
|||
protected $append = [ |
|||
'show_views', |
|||
'view_time' |
|||
]; |
|||
|
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
public function getViewTimeAttr($value, $data) |
|||
{ |
|||
return date('Y-m-d', $data['create_time']); |
|||
} |
|||
|
|||
/** |
|||
* 文章详情 |
|||
* @param $article_id |
|||
* @return ArticleModel|null |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function detail($article_id) |
|||
{ |
|||
if (!$model = parent::detail($article_id)) { |
|||
throw new BaseException(['msg' => '文章不存在']); |
|||
} |
|||
// 累积阅读数 |
|||
$model->setInc('actual_views', 1); |
|||
return $model; |
|||
} |
|||
|
|||
/** |
|||
* 获取文章列表 |
|||
* @param int $category_id |
|||
* @param int $limit |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($category_id = 0, $limit = 15) |
|||
{ |
|||
$category_id > 0 && $this->where('category_id', '=', $category_id); |
|||
return $this->field(['article_content'], true) |
|||
->with(['image', 'category']) |
|||
->where('article_status', '=', 1) |
|||
->where('is_delete', '=', 0) |
|||
->order(['article_sort' => 'asc', 'create_time' => 'desc']) |
|||
->paginate($limit, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
} |
|||
|
|||
} |
|||
@ -1,347 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use think\Cache; |
|||
use app\api\model\store\Shop as ShopModel; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\enum\DeliveryType as DeliveryTypeEnum; |
|||
use app\common\service\delivery\Express as ExpressService; |
|||
|
|||
/** |
|||
* 购物车管理 |
|||
* Class Cart |
|||
* @package app\api\model |
|||
*/ |
|||
class Cart |
|||
{ |
|||
/* @var string $error 错误信息 */ |
|||
public $error = ''; |
|||
|
|||
/* @var \think\Model|\think\Collection $user 用户信息 */ |
|||
private $user; |
|||
|
|||
/* @var int $user_id 用户id */ |
|||
private $user_id; |
|||
|
|||
/* @var int $wxapp_id 小程序商城id */ |
|||
private $wxapp_id; |
|||
|
|||
/* @var array $cart 购物车列表 */ |
|||
private $cart = []; |
|||
|
|||
/* @var bool $clear 是否清空购物车 */ |
|||
private $clear = false; |
|||
|
|||
/** |
|||
* 构造方法 |
|||
* Cart constructor. |
|||
* @param \think\Model|\think\Collection $user |
|||
*/ |
|||
public function __construct($user) |
|||
{ |
|||
$this->user = $user; |
|||
$this->user_id = $this->user['user_id']; |
|||
$this->wxapp_id = $this->user['wxapp_id']; |
|||
$this->cart = Cache::get('cart_' . $this->user_id) ?: []; |
|||
} |
|||
|
|||
/** |
|||
* 购物车列表 (含商品信息) |
|||
* @param string $cartIds 购物车id集 |
|||
* @param int $delivery 配送方式 |
|||
* @param int $pay_type 支付方式 |
|||
* @param int $shop_id 自提门店id |
|||
* @return array |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList( |
|||
$cartIds = null, |
|||
$delivery = DeliveryTypeEnum::EXPRESS, |
|||
$pay_type = PayTypeEnum::WECHAT, |
|||
$shop_id = 0 |
|||
) |
|||
{ |
|||
// 返回的数据 |
|||
$returnData = []; |
|||
// 获取购物车商品列表 |
|||
$goodsList = $this->getGoodsList($cartIds); |
|||
// 订单商品总数量 |
|||
$orderTotalNum = array_sum(array_column($goodsList, 'total_num')); |
|||
// 订单商品总金额 |
|||
$orderTotalPrice = array_sum(array_column($goodsList, 'total_price')); |
|||
// 处理配送方式 |
|||
if ($delivery == DeliveryTypeEnum::EXPRESS) { |
|||
$this->orderExpress($returnData, $goodsList, $orderTotalPrice); |
|||
} elseif ($delivery == DeliveryTypeEnum::EXTRACT) { |
|||
$shop_id > 0 && $returnData['extract_shop'] = ShopModel::detail($shop_id); |
|||
} |
|||
// 可用优惠券列表 |
|||
$couponList = UserCoupon::getUserCouponList($this->user['user_id'], $orderTotalPrice); |
|||
return array_merge([ |
|||
'goods_list' => array_values($goodsList), // 商品列表 |
|||
'order_total_num' => $orderTotalNum, // 商品总数量 |
|||
'order_total_price' => sprintf('%.2f', $orderTotalPrice), // 商品总金额 (不含运费) |
|||
'order_pay_price' => sprintf('%.2f', $orderTotalPrice), // 实际支付金额 |
|||
'delivery' => $delivery, // 配送类型 |
|||
'coupon_list' => array_values($couponList), // 优惠券列表 |
|||
'address' => $this->user['address_default'], // 默认地址 |
|||
'exist_address' => !$this->user['address']->isEmpty(), // 是否存在收货地址 |
|||
'express_price' => '0.00', // 配送费用 |
|||
'intra_region' => true, // 当前用户收货城市是否存在配送规则中 |
|||
'extract_shop' => [], // 自提门店信息 |
|||
'pay_type' => $pay_type, // 支付方式 |
|||
'has_error' => $this->hasError(), |
|||
'error_msg' => $this->getError(), |
|||
], $returnData); |
|||
} |
|||
|
|||
/** |
|||
* 订单配送-快递配送 |
|||
* @param $returnData |
|||
* @param $goodsList |
|||
* @param $orderTotalPrice |
|||
*/ |
|||
private function orderExpress(&$returnData, $goodsList, $orderTotalPrice) |
|||
{ |
|||
// 当前用户收货城市id |
|||
$cityId = $this->user['address_default'] ? $this->user['address_default']['city_id'] : null; |
|||
// 初始化配送服务类 |
|||
$ExpressService = new ExpressService( |
|||
$this->wxapp_id, |
|||
$cityId, |
|||
$goodsList, |
|||
OrderTypeEnum::MASTER |
|||
); |
|||
// 获取不支持当前城市配送的商品 |
|||
$notInRuleGoods = $ExpressService->getNotInRuleGoods(); |
|||
// 验证商品是否在配送范围 |
|||
$intraRegion = $returnData['intra_region'] = $notInRuleGoods === false; |
|||
if ($intraRegion == false) { |
|||
$notInRuleGoodsName = $notInRuleGoods['goods_name']; |
|||
$this->setError("很抱歉,您的收货地址不在商品 [{$notInRuleGoodsName}] 的配送范围内"); |
|||
} else { |
|||
// 计算配送金额 |
|||
$ExpressService->setExpressPrice(); |
|||
} |
|||
// 订单总运费金额 |
|||
$expressPrice = $returnData['express_price'] = $ExpressService->getTotalFreight(); |
|||
// 订单总金额 (含运费) |
|||
$returnData['order_pay_price'] = bcadd($orderTotalPrice, $expressPrice, 2); |
|||
} |
|||
|
|||
/** |
|||
* 获取购物车列表 |
|||
* @param string|null $cartIds 购物车索引集 (为null时则获取全部) |
|||
* @return array |
|||
*/ |
|||
private function getCartList($cartIds = null) |
|||
{ |
|||
if (empty($cartIds)) return $this->cart; |
|||
$cartList = []; |
|||
$indexArr = (strpos($cartIds, ',') !== false) ? explode(',', $cartIds) : [$cartIds]; |
|||
foreach ($indexArr as $index) { |
|||
isset($this->cart[$index]) && $cartList[$index] = $this->cart[$index]; |
|||
} |
|||
return $cartList; |
|||
} |
|||
|
|||
/** |
|||
* 获取购物车中的商品列表 |
|||
* @param $cartIds |
|||
* @return array|bool |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getGoodsList($cartIds) |
|||
{ |
|||
// 购物车商品列表 |
|||
$goodsList = []; |
|||
// 获取购物车列表 |
|||
$cartList = $this->getCartList($cartIds); |
|||
if (empty($cartList)) { |
|||
$this->setError('当前购物车没有商品'); |
|||
return $goodsList; |
|||
} |
|||
// 购物车中所有商品id集 |
|||
$goodsIds = array_unique(array_column($cartList, 'goods_id')); |
|||
// 获取并格式化商品数据 |
|||
$goodsData = []; |
|||
foreach ((new Goods)->getListByIds($goodsIds) as $item) { |
|||
$goodsData[$item['goods_id']] = $item; |
|||
} |
|||
// 格式化购物车数据列表 |
|||
foreach ($cartList as $cart) { |
|||
// 判断商品不存在则自动删除 |
|||
if (!isset($goodsData[$cart['goods_id']])) { |
|||
$this->delete($cart['goods_id'] . '_' . $cart['goods_sku_id']); |
|||
continue; |
|||
} |
|||
/* @var Goods $goods */ |
|||
$goods = $goodsData[$cart['goods_id']]; |
|||
// 判断商品是否已删除 |
|||
if ($goods['is_delete']) { |
|||
$this->delete($cart['goods_id'] . '_' . $cart['goods_sku_id']); |
|||
continue; |
|||
} |
|||
// 商品sku信息 |
|||
$goods['goods_sku_id'] = $cart['goods_sku_id']; |
|||
// 商品sku不存在则自动删除 |
|||
if (!$goods['goods_sku'] = $goods->getGoodsSku($cart['goods_sku_id'])) { |
|||
$this->delete($cart['goods_id'] . '_' . $cart['goods_sku_id']); |
|||
continue; |
|||
} |
|||
// 判断商品是否下架 |
|||
if ($goods['goods_status']['value'] != 10) { |
|||
$this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 已下架'); |
|||
} |
|||
// 判断商品库存 |
|||
if ($cart['goods_num'] > $goods['goods_sku']['stock_num']) { |
|||
$this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 库存不足'); |
|||
} |
|||
// 商品单价 |
|||
$goods['goods_price'] = $goods['goods_sku']['goods_price']; |
|||
// 购买数量 |
|||
$goods['total_num'] = $cart['goods_num']; |
|||
// 商品总价 |
|||
$goods['total_price'] = $total_price = bcmul($goods['goods_price'], $cart['goods_num'], 2); |
|||
$goodsList[] = $goods->toArray(); |
|||
} |
|||
return $goodsList; |
|||
} |
|||
|
|||
/** |
|||
* 添加购物车 |
|||
* @param $goods_id |
|||
* @param $goods_num |
|||
* @param $goods_sku_id |
|||
* @return bool |
|||
*/ |
|||
public function add($goods_id, $goods_num, $goods_sku_id) |
|||
{ |
|||
// 购物车商品索引 |
|||
$index = $goods_id . '_' . $goods_sku_id; |
|||
// 商品信息 |
|||
$goods = Goods::detail($goods_id); |
|||
// 判断商品是否下架 |
|||
if (!$goods || $goods['is_delete'] || $goods['goods_status']['value'] != 10) { |
|||
$this->setError('很抱歉,商品信息不存在或已下架'); |
|||
return false; |
|||
} |
|||
// 商品sku信息 |
|||
$goods['goods_sku'] = $goods->getGoodsSku($goods_sku_id); |
|||
// 判断商品库存 |
|||
$cartGoodsNum = $goods_num + (isset($this->cart[$index]) ? $this->cart[$index]['goods_num'] : 0); |
|||
if ($cartGoodsNum > $goods['goods_sku']['stock_num']) { |
|||
$this->setError('很抱歉,商品库存不足'); |
|||
return false; |
|||
} |
|||
$create_time = time(); |
|||
$data = compact('goods_id', 'goods_num', 'goods_sku_id', 'create_time'); |
|||
if (empty($this->cart)) { |
|||
$this->cart[$index] = $data; |
|||
return true; |
|||
} |
|||
isset($this->cart[$index]) ? $this->cart[$index]['goods_num'] = $cartGoodsNum : $this->cart[$index] = $data; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 减少购物车中某商品数量 |
|||
* @param $goods_id |
|||
* @param $goods_sku_id |
|||
*/ |
|||
public function sub($goods_id, $goods_sku_id) |
|||
{ |
|||
$index = $goods_id . '_' . $goods_sku_id; |
|||
$this->cart[$index]['goods_num'] > 1 && $this->cart[$index]['goods_num']--; |
|||
} |
|||
|
|||
/** |
|||
* 删除购物车中指定商品 |
|||
* @param $cart_ids (支持字符串ID集) |
|||
*/ |
|||
public function delete($cart_ids) |
|||
{ |
|||
$indexArr = strpos($cart_ids, ',') !== false |
|||
? explode(',', $cart_ids) : [$cart_ids]; |
|||
foreach ($indexArr as $index) { |
|||
if (isset($this->cart[$index])) unset($this->cart[$index]); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取当前用户购物车商品总数量(含件数) |
|||
* @return int |
|||
*/ |
|||
public function getTotalNum() |
|||
{ |
|||
return array_sum(array_column($this->cart, 'goods_num')); |
|||
} |
|||
|
|||
/** |
|||
* 获取当前用户购物车商品总数量(不含件数) |
|||
* @return int |
|||
*/ |
|||
public function getGoodsNum() |
|||
{ |
|||
return count($this->cart); |
|||
} |
|||
|
|||
/** |
|||
* 析构方法 |
|||
* 将cart数据保存到缓存文件 |
|||
*/ |
|||
public function __destruct() |
|||
{ |
|||
$this->clear !== true && Cache::set('cart_' . $this->user_id, $this->cart, 86400 * 15); |
|||
} |
|||
|
|||
/** |
|||
* 清空当前用户购物车 |
|||
* @param null $cart_ids |
|||
*/ |
|||
public function clearAll($cart_ids = null) |
|||
{ |
|||
if (empty($cart_ids)) { |
|||
$this->clear = true; |
|||
Cache::rm('cart_' . $this->user_id); |
|||
} else { |
|||
$this->delete($cart_ids); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 设置错误信息 |
|||
* @param $error |
|||
*/ |
|||
private function setError($error) |
|||
{ |
|||
empty($this->error) && $this->error = $error; |
|||
} |
|||
|
|||
/** |
|||
* 是否存在错误 |
|||
* @return bool |
|||
*/ |
|||
private function hasError() |
|||
{ |
|||
return !empty($this->error); |
|||
} |
|||
|
|||
/** |
|||
* 获取错误信息 |
|||
* @return string |
|||
*/ |
|||
public function getError() |
|||
{ |
|||
return $this->error; |
|||
} |
|||
|
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Category as CategoryModel; |
|||
|
|||
/** |
|||
* 商品分类模型 |
|||
* Class Category |
|||
* @package app\common\model |
|||
*/ |
|||
class Category extends CategoryModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
// 'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
public static function getList() { |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -1,229 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\exception\BaseException; |
|||
use app\common\model\Comment as CommentModel; |
|||
use app\common\library\helper; |
|||
|
|||
/** |
|||
* 商品评价模型 |
|||
* Class Comment |
|||
* @package app\api\model |
|||
*/ |
|||
class Comment extends CommentModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'status', |
|||
'sort', |
|||
'order_id', |
|||
'goods_id', |
|||
'order_goods_id', |
|||
'is_delete', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 关联用户表 |
|||
* @return \think\model\relation\BelongsTo |
|||
*/ |
|||
public function user() |
|||
{ |
|||
return $this->belongsTo('User')->field(['user_id', 'nickName', 'avatarUrl']); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定商品评价列表 |
|||
* @param $goods_id |
|||
* @param int $scoreType |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getGoodsCommentList($goods_id, $scoreType = -1) |
|||
{ |
|||
// 筛选条件 |
|||
$filter = [ |
|||
'goods_id' => $goods_id, |
|||
'is_delete' => 0, |
|||
'status' => 1, |
|||
]; |
|||
// 评分 |
|||
$scoreType > 0 && $filter['score'] = $scoreType; |
|||
return $this->with(['user', 'OrderGoods', 'image.file']) |
|||
->where($filter) |
|||
->order(['sort' => 'asc', 'create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定评分总数 |
|||
* @param $goods_id |
|||
* @return array|false|\PDOStatement|string|\think\Model |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getTotal($goods_id) |
|||
{ |
|||
return $this->field([ |
|||
'count(comment_id) AS `all`', |
|||
'count(score = 10 OR NULL) AS `praise`', |
|||
'count(score = 20 OR NULL) AS `review`', |
|||
'count(score = 30 OR NULL) AS `negative`', |
|||
])->where([ |
|||
'goods_id' => $goods_id, |
|||
'is_delete' => 0, |
|||
'status' => 1 |
|||
])->find(); |
|||
} |
|||
|
|||
/** |
|||
* 验证订单是否允许评价 |
|||
* @param Order $order |
|||
* @return boolean |
|||
*/ |
|||
public function checkOrderAllowComment($order) |
|||
{ |
|||
// 验证订单是否已完成 |
|||
if ($order['order_status']['value'] != 30) { |
|||
$this->error = '该订单未完成,无法评价'; |
|||
return false; |
|||
} |
|||
// 验证订单是否已评价 |
|||
if ($order['is_comment'] == 1) { |
|||
$this->error = '该订单已完成评价'; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 根据已完成订单商品 添加评价 |
|||
* @param Order $order |
|||
* @param \think\Collection|OrderGoods $goodsList |
|||
* @param $post |
|||
* @return boolean |
|||
* @throws \Exception |
|||
*/ |
|||
public function addForOrder($order, $goodsList, $post) |
|||
{ |
|||
// 生成 formData |
|||
$formData = $this->formatFormData($post); |
|||
// 生成评价数据 |
|||
$data = $this->createCommentData($order['user_id'], $order['order_id'], $goodsList, $formData); |
|||
if (empty($data)) { |
|||
$this->error = '没有输入评价内容'; |
|||
return false; |
|||
} |
|||
return $this->transaction(function () use ($order, $goodsList, $formData, $data) { |
|||
// 记录评价内容 |
|||
$result = $this->isUpdate(false)->saveAll($data); |
|||
// 记录评价图片 |
|||
$this->saveAllImages($result, $formData); |
|||
// 更新订单评价状态 |
|||
$isComment = count($goodsList) === count($data); |
|||
$this->updateOrderIsComment($order, $isComment, $result); |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 更新订单评价状态 |
|||
* @param Order $order |
|||
* @param $isComment |
|||
* @param $commentList |
|||
* @return array|false |
|||
* @throws \Exception |
|||
*/ |
|||
private function updateOrderIsComment($order, $isComment, $commentList) |
|||
{ |
|||
// 更新订单商品 |
|||
$orderGoodsData = []; |
|||
foreach ($commentList as $comment) { |
|||
$orderGoodsData[] = [ |
|||
'order_goods_id' => $comment['order_goods_id'], |
|||
'is_comment' => 1 |
|||
]; |
|||
} |
|||
// 更新订单 |
|||
$isComment && $order->save(['is_comment' => 1]); |
|||
return (new OrderGoods)->saveAll($orderGoodsData); |
|||
} |
|||
|
|||
/** |
|||
* 生成评价数据 |
|||
* @param $user_id |
|||
* @param $order_id |
|||
* @param $goodsList |
|||
* @param $formData |
|||
* @return array |
|||
* @throws BaseException |
|||
*/ |
|||
private function createCommentData($user_id, $order_id, $goodsList, $formData) |
|||
{ |
|||
$data = []; |
|||
foreach ($goodsList as $goods) { |
|||
if (!isset($formData[$goods['order_goods_id']])) { |
|||
throw new BaseException(['msg' => '提交的数据不合法']); |
|||
} |
|||
$item = $formData[$goods['order_goods_id']]; |
|||
$item['content'] = trim($item['content']); |
|||
!empty($item['content']) && $data[$goods['order_goods_id']] = [ |
|||
'score' => $item['score'], |
|||
'content' => $item['content'], |
|||
'is_picture' => !empty($item['uploaded']), |
|||
'sort' => 100, |
|||
'status' => 1, |
|||
'user_id' => $user_id, |
|||
'order_id' => $order_id, |
|||
'goods_id' => $item['goods_id'], |
|||
'order_goods_id' => $item['order_goods_id'], |
|||
'wxapp_id' => self::$wxapp_id |
|||
]; |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
/** |
|||
* 格式化 formData |
|||
* @param string $post |
|||
* @return array |
|||
*/ |
|||
private function formatFormData($post) |
|||
{ |
|||
$formJsonData = htmlspecialchars_decode($post); |
|||
return helper::arrayColumn2Key(helper::jsonDecode($formJsonData), 'order_goods_id'); |
|||
} |
|||
|
|||
/** |
|||
* 记录评价图片 |
|||
* @param $commentList |
|||
* @param $formData |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
private function saveAllImages($commentList, $formData) |
|||
{ |
|||
// 生成评价图片数据 |
|||
$imageData = []; |
|||
foreach ($commentList as $comment) { |
|||
$item = $formData[$comment['order_goods_id']]; |
|||
foreach ($item['uploaded'] as $imageId) { |
|||
$imageData[] = [ |
|||
'comment_id' => $comment['comment_id'], |
|||
'image_id' => $imageId, |
|||
'wxapp_id' => self::$wxapp_id |
|||
]; |
|||
} |
|||
} |
|||
$model = new CommentImage; |
|||
return !empty($imageData) && $model->saveAll($imageData); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\CommentImage as CommentImageModel; |
|||
|
|||
/** |
|||
* 商品图片模型 |
|||
* Class GoodsImage |
|||
* @package app\api\model |
|||
*/ |
|||
class CommentImage extends CommentImageModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,86 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Coupon as CouponModel; |
|||
|
|||
/** |
|||
* 优惠券模型 |
|||
* Class Coupon |
|||
* @package app\api\model |
|||
*/ |
|||
class Coupon extends CouponModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'receive_num', |
|||
'is_delete', |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取优惠券列表 |
|||
* @param bool $user |
|||
* @param null $limit |
|||
* @param bool $only_receive |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user = false, $limit = null, $only_receive = false) |
|||
{ |
|||
// 构造查询条件 |
|||
$this->where('is_delete', '=', 0); |
|||
// 只显示可领取(未过期,未发完)的优惠券 |
|||
if ($only_receive) { |
|||
$this->where(' IF ( `total_num` > - 1, `receive_num` < `total_num`, 1 = 1 )') |
|||
->where('IF ( `expire_type` = 20, (`end_time` + 86400) >= ' . time() . ', 1 = 1 )'); |
|||
} |
|||
|
|||
// 优惠券列表 |
|||
$couponList = $this->order(['sort' => 'asc', 'create_time' => 'desc'])->limit($limit)->select(); |
|||
|
|||
// 获取用户已领取的优惠券 |
|||
if ($user !== false) { |
|||
$UserCouponModel = new UserCoupon; |
|||
$userCouponIds = $UserCouponModel->getUserCouponIds($user['user_id']); |
|||
foreach ($couponList as $key => $item) { |
|||
$couponList[$key]['is_receive'] = in_array($item['coupon_id'], $userCouponIds); |
|||
} |
|||
} |
|||
return $couponList; |
|||
} |
|||
|
|||
/** |
|||
* 验证优惠券是否可领取 |
|||
* @return bool |
|||
*/ |
|||
public function checkReceive() |
|||
{ |
|||
if ($this['total_num'] > -1 && $this['receive_num'] >= $this['total_num']) { |
|||
$this->error = '优惠券已发完'; |
|||
return false; |
|||
} |
|||
if ($this['expire_type'] == 20 && ($this->getData('end_time') + 86400) < time()) { |
|||
$this->error = '优惠券已过期'; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 累计已领取数量 |
|||
* @return int|true |
|||
* @throws \think\Exception |
|||
*/ |
|||
public function setIncReceiveNum() |
|||
{ |
|||
return $this->setInc('receive_num'); |
|||
} |
|||
|
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Delivery as DeliveryModel; |
|||
|
|||
/** |
|||
* 配送模板模型 |
|||
* Class Delivery |
|||
* @package app\api\model |
|||
*/ |
|||
class Delivery extends DeliveryModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,41 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\DeliveryRule as DeliveryRuleModel; |
|||
|
|||
/** |
|||
* 配送模板区域及运费模型 |
|||
* Class DeliveryRule |
|||
* @package app\api\model |
|||
*/ |
|||
class DeliveryRule extends DeliveryRuleModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 追加字段 |
|||
* @var array |
|||
*/ |
|||
protected $append = ['region_data']; |
|||
|
|||
/** |
|||
* 地区集转为数组格式 |
|||
* @param $value |
|||
* @param $data |
|||
* @return array |
|||
*/ |
|||
public function getRegionDataAttr($value, $data) |
|||
{ |
|||
return explode(',', $data['region']); |
|||
} |
|||
|
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Express as ExpressModel; |
|||
|
|||
/** |
|||
* 物流公司模型 |
|||
* Class Express |
|||
* @package app\api\model |
|||
*/ |
|||
class Express extends ExpressModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'express_code', |
|||
'sort', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Goods as GoodsModel; |
|||
|
|||
/** |
|||
* 商品模型 |
|||
* Class Goods |
|||
* @package app\api\model |
|||
*/ |
|||
class Goods extends GoodsModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'sales_initial', |
|||
'sales_actual', |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 商品详情:HTML实体转换回普通字符 |
|||
* @param $value |
|||
* @return string |
|||
*/ |
|||
public function getContentAttr($value) |
|||
{ |
|||
return htmlspecialchars_decode($value); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\GoodsImage as GoodsImageModel; |
|||
|
|||
/** |
|||
* 商品图片模型 |
|||
* Class GoodsImage |
|||
* @package app\api\model |
|||
*/ |
|||
class GoodsImage extends GoodsImageModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\GoodsSku as GoodsSkuModel; |
|||
|
|||
/** |
|||
* 商品规格模型 |
|||
* Class GoodsSku |
|||
* @package app\api\model |
|||
*/ |
|||
class GoodsSku extends GoodsSkuModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\GoodsSpecRel as GoodsSpecRelModel; |
|||
|
|||
/** |
|||
* 商品规格关系模型 |
|||
* Class GoodsSpecRel |
|||
* @package app\api\model |
|||
*/ |
|||
class GoodsSpecRel extends GoodsSpecRelModel |
|||
{ |
|||
} |
|||
@ -1,637 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Order as OrderModel; |
|||
|
|||
use app\api\model\GoodsSku as GoodsSkuModel; |
|||
use app\api\model\store\Shop as ShopModel; |
|||
use app\api\model\dealer\Order as DealerOrderModel; |
|||
use app\api\model\OrderGoods as OrderGoodsModel; |
|||
|
|||
use app\common\service\delivery\Express as ExpressService; |
|||
use app\api\service\Payment as PaymentService; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\order\PayStatus as PayStatusEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\enum\DeliveryType as DeliveryTypeEnum; |
|||
use app\common\exception\BaseException; |
|||
|
|||
/** |
|||
* 订单模型 |
|||
* Class Order |
|||
* @package app\api\model |
|||
*/ |
|||
class Order extends OrderModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 订单确认-立即购买 |
|||
* @param User $user |
|||
* @param int $goods_id 商品id |
|||
* @param int $goods_num |
|||
* @param int $goods_sku_id |
|||
* @param int $delivery 配送方式 |
|||
* @param int $pay_type 支付方式 |
|||
* @param int $shop_id 自提门店id |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getBuyNow( |
|||
$user, |
|||
$goods_id, |
|||
$goods_num, |
|||
$goods_sku_id, |
|||
$delivery, |
|||
$pay_type, |
|||
$shop_id = 0 |
|||
) |
|||
{ |
|||
// 商品信息 |
|||
/* @var Goods $goods */ |
|||
$goods = Goods::detail($goods_id); |
|||
// 判断商品是否下架 |
|||
if (!$goods || $goods['is_delete'] || $goods['goods_status']['value'] != 10) { |
|||
throw new BaseException(['msg' => '很抱歉,商品信息不存在或已下架']); |
|||
} |
|||
// 商品sku信息 |
|||
$goods['goods_sku'] = $goods->getGoodsSku($goods_sku_id); |
|||
// 判断商品库存 |
|||
if ($goods_num > $goods['goods_sku']['stock_num']) { |
|||
$this->setError('很抱歉,商品库存不足'); |
|||
} |
|||
// 返回的数据 |
|||
$returnData = []; |
|||
// 商品单价 |
|||
$goods['goods_price'] = $goods['goods_sku']['goods_price']; |
|||
// 商品总价 |
|||
$goods['total_num'] = $goods_num; |
|||
$goods['total_price'] = $goodsTotalPrice = bcmul($goods['goods_price'], $goods_num, 2); |
|||
// 商品详情 |
|||
$goodsList = [$goods->toArray()]; |
|||
// 处理配送方式 |
|||
if ($delivery == DeliveryTypeEnum::EXPRESS) { |
|||
$this->orderExpress($returnData, $user, $goodsList, $goodsTotalPrice); |
|||
} elseif ($delivery == DeliveryTypeEnum::EXTRACT) { |
|||
$shop_id > 0 && $returnData['extract_shop'] = ShopModel::detail($shop_id); |
|||
} |
|||
// 可用优惠券列表 |
|||
$couponList = UserCoupon::getUserCouponList($user['user_id'], $goodsTotalPrice); |
|||
return array_merge([ |
|||
'goods_list' => array_values($goodsList), // 商品详情 |
|||
'order_total_num' => $goods_num, // 商品总数量 |
|||
'order_total_price' => $goodsTotalPrice, // 商品总金额 (不含运费) |
|||
'order_pay_price' => $goodsTotalPrice, // 订单总金额 (含运费) |
|||
'delivery' => $delivery, // 配送类型 |
|||
'coupon_list' => array_values($couponList), // 优惠券列表 |
|||
'address' => $user['address_default'], // 默认地址 |
|||
'exist_address' => !$user['address']->isEmpty(), // 是否存在收货地址 |
|||
'express_price' => '0.00', // 配送费用 |
|||
'intra_region' => true, // 当前用户收货城市是否存在配送规则中 |
|||
'extract_shop' => [], // 自提门店信息 |
|||
'pay_type' => $pay_type, // 支付方式 |
|||
'has_error' => $this->hasError(), |
|||
'error_msg' => $this->getError(), |
|||
], $returnData); |
|||
} |
|||
|
|||
/** |
|||
* 订单配送-快递配送 |
|||
* @param $returnData |
|||
* @param $user |
|||
* @param $goodsList |
|||
* @param $goodsTotalPrice |
|||
*/ |
|||
private function orderExpress(&$returnData, $user, $goodsList, $goodsTotalPrice) |
|||
{ |
|||
// 当前用户收货城市id |
|||
$cityId = $user['address_default'] ? $user['address_default']['city_id'] : null; |
|||
// 初始化配送服务类 |
|||
$ExpressService = new ExpressService( |
|||
static::$wxapp_id, |
|||
$cityId, |
|||
$goodsList, |
|||
OrderTypeEnum::MASTER |
|||
); |
|||
// 获取不支持当前城市配送的商品 |
|||
$notInRuleGoods = $ExpressService->getNotInRuleGoods(); |
|||
// 验证商品是否在配送范围 |
|||
$intraRegion = $returnData['intra_region'] = $notInRuleGoods === false; |
|||
if ($intraRegion == false) { |
|||
$notInRuleGoodsName = $notInRuleGoods['goods_name']; |
|||
$this->setError("很抱歉,您的收货地址不在商品 [{$notInRuleGoodsName}] 的配送范围内"); |
|||
} else { |
|||
// 计算配送金额 |
|||
$ExpressService->setExpressPrice(); |
|||
} |
|||
// 订单总运费金额 |
|||
$expressPrice = $returnData['express_price'] = $ExpressService->getTotalFreight(); |
|||
// 订单总金额 (含运费) |
|||
$returnData['order_pay_price'] = bcadd($goodsTotalPrice, $expressPrice, 2); |
|||
} |
|||
|
|||
/** |
|||
* 创建新订单 |
|||
* @param \app\api\model\User $user |
|||
* @param array $order 订单信息 |
|||
* @param int $coupon_id 优惠券id |
|||
* @param string $remark |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
public function createOrder( |
|||
$user, |
|||
$order, |
|||
$coupon_id = null, |
|||
$remark = '') |
|||
{ |
|||
// 表单验证 |
|||
if (!$this->validateOrderForm($user, $order)) { |
|||
return false; |
|||
} |
|||
// 创建新的订单信息 |
|||
$this->transaction(function () use ($order, $user, $coupon_id, $remark) { |
|||
// 设置订单优惠券信息 |
|||
$this->setCouponPrice($order, $coupon_id); |
|||
// 记录订单信息 |
|||
$this->add($user['user_id'], $order, $remark); |
|||
// 记录收货地址 |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$this->saveOrderAddress($user['user_id'], $order['address']); |
|||
} |
|||
// 保存订单商品信息 |
|||
$this->saveOrderGoods($user['user_id'], $order); |
|||
// 更新商品库存 (针对下单减库存的商品) |
|||
$this->updateGoodsStockNum($order['goods_list']); |
|||
// 获取订单详情 |
|||
$detail = self::getUserOrderDetail($this['order_id'], $user['user_id']); |
|||
// 记录分销商订单 |
|||
DealerOrderModel::createOrder($detail); |
|||
}); |
|||
// 余额支付标记订单已支付 |
|||
if ($order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
$this->paymentByBalance($this['order_no']); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 构建微信支付请求 |
|||
* @param \app\api\model\User $user |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function paymentByWechat($user) |
|||
{ |
|||
return PaymentService::wechat( |
|||
$user, |
|||
$this['order_id'], |
|||
$this['order_no'], |
|||
$this['pay_price'], |
|||
OrderTypeEnum::MASTER |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 余额支付标记订单已支付 |
|||
* @param string $orderNo 订单号 |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function paymentByBalance($orderNo) |
|||
{ |
|||
// 获取订单详情 |
|||
$model = new \app\task\model\Order; |
|||
$order = $model->payDetail($orderNo); |
|||
// 发起余额支付 |
|||
$status = $order->paySuccess(PayTypeEnum::BALANCE); |
|||
if (!$status) { |
|||
$this->error = $order->error; |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 表单验证 (订单提交) |
|||
* @param \app\api\model\User $user 用户信息 |
|||
* @param array $order 订单信息 |
|||
* @return bool |
|||
*/ |
|||
private function validateOrderForm($user, &$order) |
|||
{ |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
if (empty($order['address'])) { |
|||
$this->error = '请先选择收货地址'; |
|||
return false; |
|||
} |
|||
} |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
if (empty($order['extract_shop'])) { |
|||
$this->error = '请先选择自提门店'; |
|||
return false; |
|||
} |
|||
} |
|||
// 余额支付时判断用户余额是否足够 |
|||
if ($order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
if ($user['balance'] < $order['order_pay_price']) { |
|||
$this->error = '用户余额不足,无法使用余额支付'; |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单优惠券信息 |
|||
* @param $order |
|||
* @param $coupon_id |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function setCouponPrice(&$order, $coupon_id) |
|||
{ |
|||
if ($coupon_id > 0 && !empty($order['coupon_list'])) { |
|||
// 获取优惠券信息 |
|||
$couponInfo = []; |
|||
foreach ($order['coupon_list'] as $coupon) |
|||
$coupon['user_coupon_id'] == $coupon_id && $couponInfo = $coupon; |
|||
if (empty($couponInfo)) throw new BaseException(['msg' => '未找到优惠券信息']); |
|||
// 计算订单金额 (抵扣后) |
|||
$orderTotalPrice = bcsub($order['order_total_price'], $couponInfo['reduced_price'], 2); |
|||
$orderTotalPrice <= 0 && $orderTotalPrice = '0.01'; |
|||
// 记录订单信息 |
|||
$order['coupon_id'] = $coupon_id; |
|||
$order['coupon_price'] = $couponInfo['reduced_price']; |
|||
$order['order_pay_price'] = bcadd($orderTotalPrice, $order['express_price'], 2); |
|||
// 设置优惠券使用状态 |
|||
$model = UserCoupon::detail($coupon_id); |
|||
$model->setIsUse(); |
|||
return true; |
|||
} |
|||
$order['coupon_id'] = 0; |
|||
$order['coupon_price'] = 0.00; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 新增订单记录 |
|||
* @param $user_id |
|||
* @param $order |
|||
* @param string $remark |
|||
* @return false|int |
|||
*/ |
|||
private function add($user_id, &$order, $remark = '') |
|||
{ |
|||
$data = [ |
|||
'user_id' => $user_id, |
|||
'order_no' => $this->orderNo(), |
|||
'total_price' => $order['order_total_price'], |
|||
'coupon_id' => $order['coupon_id'], |
|||
'coupon_price' => $order['coupon_price'], |
|||
'pay_price' => $order['order_pay_price'], |
|||
'delivery_type' => $order['delivery'], |
|||
'pay_type' => $order['pay_type'], |
|||
'buyer_remark' => trim($remark), |
|||
'wxapp_id' => self::$wxapp_id, |
|||
]; |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$data['express_price'] = $order['express_price']; |
|||
} elseif ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
$data['extract_shop_id'] = $order['extract_shop']['shop_id']; |
|||
} |
|||
return $this->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 保存订单商品信息 |
|||
* @param $user_id |
|||
* @param $order |
|||
* @return int |
|||
*/ |
|||
private function saveOrderGoods($user_id, &$order) |
|||
{ |
|||
// 订单商品列表 |
|||
$goodsList = []; |
|||
// 订单商品实付款金额 (不包含运费) |
|||
$realTotalPrice = bcsub($order['order_pay_price'], $order['express_price'], 2); |
|||
foreach ($order['goods_list'] as $goods) { |
|||
/* @var Goods $goods */ |
|||
// 计算商品实际付款价 |
|||
$total_pay_price = $realTotalPrice * $goods['total_price'] / $order['order_total_price']; |
|||
$goodsList[] = [ |
|||
'user_id' => $user_id, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
'goods_id' => $goods['goods_id'], |
|||
'goods_name' => $goods['goods_name'], |
|||
'image_id' => $goods['image'][0]['image_id'], |
|||
'deduct_stock_type' => $goods['deduct_stock_type'], |
|||
'spec_type' => $goods['spec_type'], |
|||
'spec_sku_id' => $goods['goods_sku']['spec_sku_id'], |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'goods_attr' => $goods['goods_sku']['goods_attr'], |
|||
'content' => $goods['content'], |
|||
'goods_no' => $goods['goods_sku']['goods_no'], |
|||
'goods_price' => $goods['goods_sku']['goods_price'], |
|||
'line_price' => $goods['goods_sku']['line_price'], |
|||
'goods_weight' => $goods['goods_sku']['goods_weight'], |
|||
'total_num' => $goods['total_num'], |
|||
'total_price' => $goods['total_price'], |
|||
'total_pay_price' => sprintf('%.2f', $total_pay_price), |
|||
'is_ind_dealer' => $goods['is_ind_dealer'], |
|||
'dealer_money_type' => $goods['dealer_money_type'], |
|||
'first_money' => $goods['first_money'], |
|||
'second_money' => $goods['second_money'], |
|||
'third_money' => $goods['third_money'], |
|||
]; |
|||
} |
|||
return $this->goods()->saveAll($goodsList); |
|||
} |
|||
|
|||
/** |
|||
* 更新商品库存 (针对下单减库存的商品) |
|||
* @param $goods_list |
|||
* @throws \Exception |
|||
*/ |
|||
private function updateGoodsStockNum($goods_list) |
|||
{ |
|||
$deductStockData = []; |
|||
foreach ($goods_list as $goods) { |
|||
// 下单减库存 |
|||
$goods['deduct_stock_type'] == 10 && $deductStockData[] = [ |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'stock_num' => ['dec', $goods['total_num']] |
|||
]; |
|||
} |
|||
!empty($deductStockData) && (new GoodsSkuModel)->isUpdate()->saveAll($deductStockData); |
|||
} |
|||
|
|||
/** |
|||
* 记录收货地址 |
|||
* @param $user_id |
|||
* @param $address |
|||
* @return false|\think\Model |
|||
*/ |
|||
private function saveOrderAddress($user_id, $address) |
|||
{ |
|||
if ($address['region_id'] == 0 && !empty($address['district'])) { |
|||
$address['detail'] = $address['district'] . ' ' . $address['detail']; |
|||
} |
|||
return $this->address()->save([ |
|||
'user_id' => $user_id, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
'name' => $address['name'], |
|||
'phone' => $address['phone'], |
|||
'province_id' => $address['province_id'], |
|||
'city_id' => $address['city_id'], |
|||
'region_id' => $address['region_id'], |
|||
'detail' => $address['detail'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 用户中心订单列表 |
|||
* @param $user_id |
|||
* @param string $type |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $type = 'all') |
|||
{ |
|||
// 筛选条件 |
|||
$filter = []; |
|||
// 订单数据类型 |
|||
switch ($type) { |
|||
case 'all': |
|||
break; |
|||
case 'payment'; |
|||
$filter['pay_status'] = PayStatusEnum::PENDING; |
|||
$filter['order_status'] = 10; |
|||
break; |
|||
case 'delivery'; |
|||
$filter['pay_status'] = PayStatusEnum::SUCCESS; |
|||
$filter['delivery_status'] = 10; |
|||
$filter['order_status'] = 10; |
|||
break; |
|||
case 'received'; |
|||
$filter['pay_status'] = PayStatusEnum::SUCCESS; |
|||
$filter['delivery_status'] = 20; |
|||
$filter['receipt_status'] = 10; |
|||
$filter['order_status'] = 10; |
|||
break; |
|||
case 'comment'; |
|||
$filter['is_comment'] = 0; |
|||
$filter['order_status'] = 30; |
|||
break; |
|||
} |
|||
return $this->with(['goods.image']) |
|||
->where('user_id', '=', $user_id) |
|||
->where($filter) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 取消订单 |
|||
* @return bool|false|int |
|||
* @throws \Exception |
|||
*/ |
|||
public function cancel() |
|||
{ |
|||
if ($this['delivery_status']['value'] == 20) { |
|||
$this->error = '已发货订单不可取消'; |
|||
return false; |
|||
} |
|||
$this->transaction(function () { |
|||
// 回退商品库存 |
|||
(new OrderGoodsModel)->backGoodsStock($this['goods']); |
|||
// 更新订单状态 |
|||
$this->save(['order_status' => $this['pay_status']['value'] == PayStatusEnum::SUCCESS ? 21 : 20]); |
|||
}); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 确认收货 |
|||
* @return bool |
|||
* @throws \think\exception\PDOException |
|||
*/ |
|||
public function receipt() |
|||
{ |
|||
// 验证订单是否合法 |
|||
if ($this['delivery_status']['value'] == 10 || $this['receipt_status']['value'] == 20) { |
|||
$this->error = '该订单不合法'; |
|||
return false; |
|||
} |
|||
$this->startTrans(); |
|||
try { |
|||
// 更新订单状态 |
|||
$this->save([ |
|||
'receipt_status' => 20, |
|||
'receipt_time' => time(), |
|||
'order_status' => 30 |
|||
]); |
|||
// 发放分销商佣金 |
|||
DealerOrderModel::grantMoney($this, OrderTypeEnum::MASTER); |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
$this->rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取订单总数 |
|||
* @param $user_id |
|||
* @param string $type |
|||
* @return int|string |
|||
* @throws \think\Exception |
|||
*/ |
|||
public function getCount($user_id, $type = 'all') |
|||
{ |
|||
// 筛选条件 |
|||
$filter = []; |
|||
// 订单数据类型 |
|||
switch ($type) { |
|||
case 'all': |
|||
break; |
|||
case 'payment'; |
|||
$filter['pay_status'] = PayStatusEnum::PENDING; |
|||
break; |
|||
case 'received'; |
|||
$filter['pay_status'] = PayStatusEnum::SUCCESS; |
|||
$filter['delivery_status'] = 20; |
|||
$filter['receipt_status'] = 10; |
|||
break; |
|||
case 'comment'; |
|||
$filter['order_status'] = 30; |
|||
$filter['is_comment'] = 0; |
|||
break; |
|||
} |
|||
return $this->where('user_id', '=', $user_id) |
|||
->where('order_status', '<>', 20) |
|||
->where($filter) |
|||
->count(); |
|||
} |
|||
|
|||
/** |
|||
* 订单详情 |
|||
* @param $order_id |
|||
* @param null $user_id |
|||
* @return null|static |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function getUserOrderDetail($order_id, $user_id) |
|||
{ |
|||
if (!$order = self::get([ |
|||
'order_id' => $order_id, |
|||
'user_id' => $user_id, |
|||
], [ |
|||
'goods' => ['image', 'sku', 'goods', 'refund'], |
|||
'address', 'express', 'extract_shop' |
|||
]) |
|||
) { |
|||
throw new BaseException(['msg' => '订单不存在']); |
|||
} |
|||
return $order; |
|||
} |
|||
|
|||
/** |
|||
* 判断商品库存不足 (未付款订单) |
|||
* @param $goodsList |
|||
* @return bool |
|||
*/ |
|||
public function checkGoodsStatusFromOrder(&$goodsList) |
|||
{ |
|||
foreach ($goodsList as $goods) { |
|||
// 判断商品是否下架 |
|||
if (!$goods['goods'] || $goods['goods']['goods_status']['value'] != 10) { |
|||
$this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 已下架'); |
|||
return false; |
|||
} |
|||
// 付款减库存 |
|||
if ($goods['deduct_stock_type'] == 20 && $goods['sku']['stock_num'] < 1) { |
|||
$this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 库存不足'); |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 判断当前订单是否允许核销 |
|||
* @param static $order |
|||
* @return bool |
|||
*/ |
|||
public function checkExtractOrder(&$order) |
|||
{ |
|||
if ( |
|||
$order['pay_status']['value'] == PayStatusEnum::SUCCESS |
|||
&& $order['delivery_type']['value'] == DeliveryTypeEnum::EXTRACT |
|||
&& $order['delivery_status']['value'] == 10 |
|||
) { |
|||
return true; |
|||
} |
|||
$this->setError('该订单不能被核销'); |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 当前订单是否允许申请售后 |
|||
* @return bool |
|||
*/ |
|||
public function isAllowRefund() |
|||
{ |
|||
// 允许申请售后期限 |
|||
$refund_days = Setting::getItem('trade')['order']['refund_days']; |
|||
if ($refund_days == 0) { |
|||
return false; |
|||
} |
|||
if (time() > $this['receipt_time'] + ((int)$refund_days * 86400)) { |
|||
return false; |
|||
} |
|||
if ($this['receipt_status']['value'] != 20) { |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置错误信息 |
|||
* @param $error |
|||
*/ |
|||
private function setError($error) |
|||
{ |
|||
empty($this->error) && $this->error = $error; |
|||
} |
|||
|
|||
/** |
|||
* 是否存在错误 |
|||
* @return bool |
|||
*/ |
|||
public function hasError() |
|||
{ |
|||
return !empty($this->error); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\OrderAddress as OrderAddressModel; |
|||
|
|||
/** |
|||
* 订单收货地址模型 |
|||
* Class OrderAddress |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderAddress extends OrderAddressModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\OrderGoods as OrderGoodsModel; |
|||
|
|||
/** |
|||
* 订单商品模型 |
|||
* Class OrderGoods |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderGoods extends OrderGoodsModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'content', |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取未评价的商品 |
|||
* @param $order_id |
|||
* @return OrderGoods[]|false |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function getNotCommentGoodsList($order_id) |
|||
{ |
|||
return self::all(['order_id' => $order_id, 'is_comment' => 0], ['orderM', 'image']); |
|||
} |
|||
|
|||
} |
|||
@ -1,171 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\OrderRefund as OrderRefundModel; |
|||
|
|||
/** |
|||
* 售后单模型 |
|||
* Class OrderRefund |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderRefund extends OrderRefundModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 追加字段 |
|||
* @var array |
|||
*/ |
|||
protected $append = [ |
|||
'state_text', // 售后单状态文字描述 |
|||
]; |
|||
|
|||
/** |
|||
* 售后单状态文字描述 |
|||
* @param $value |
|||
* @param $data |
|||
* @return string |
|||
*/ |
|||
public function getStateTextAttr($value, $data) |
|||
{ |
|||
// 已完成 |
|||
if ($data['status'] == 20) { |
|||
$text = [10 => '已同意退货并已退款', 20 => '已同意换货']; |
|||
return $text[$data['type']]; |
|||
} |
|||
// 已取消 |
|||
if ($data['status'] == 30) { |
|||
return '已取消'; |
|||
} |
|||
// 已拒绝 |
|||
if ($data['status'] == 10) { |
|||
// return '已拒绝'; |
|||
return $data['type'] == 10 ? '已拒绝退货退款' : '已拒绝换货'; |
|||
} |
|||
// 进行中 |
|||
if ($data['status'] == 0) { |
|||
if ($data['is_agree'] == 0) { |
|||
return '等待审核中'; |
|||
} |
|||
if ($data['type'] == 10) { |
|||
return $data['is_user_send'] ? '已发货,待平台确认' : '已同意退货,请及时发货'; |
|||
} |
|||
} |
|||
return $value; |
|||
} |
|||
|
|||
/** |
|||
* 获取用户售后单列表 |
|||
* @param $user_id |
|||
* @param int $state |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $state = -1) |
|||
{ |
|||
$state > -1 && $this->where('status', '=', $state); |
|||
return $this->with(['order_master', 'order_goods.image']) |
|||
->where('user_id', '=', $user_id) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 用户发货 |
|||
* @param $data |
|||
* @return false|int |
|||
*/ |
|||
public function delivery($data) |
|||
{ |
|||
if ( |
|||
$this['type']['value'] != 10 |
|||
|| $this['is_agree']['value'] != 10 |
|||
|| $this['is_user_send'] != 0 |
|||
) { |
|||
$this->error = '当前售后单不合法,不允许该操作'; |
|||
return false; |
|||
} |
|||
if ($data['express_id'] <= 0) { |
|||
$this->error = '请选择物流公司'; |
|||
return false; |
|||
} |
|||
if (empty($data['express_no'])) { |
|||
$this->error = '请填写物流单号'; |
|||
return false; |
|||
} |
|||
return $this->save([ |
|||
'is_user_send' => 1, |
|||
'send_time' => time(), |
|||
'express_id' => (int)$data['express_id'], |
|||
'express_no' => $data['express_no'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 新增售后单记录 |
|||
* @param $user |
|||
* @param $goods |
|||
* @param $data |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
public function apply($user, $goods, $data) |
|||
{ |
|||
$this->startTrans(); |
|||
try { |
|||
// 新增售后单记录 |
|||
$this->save([ |
|||
'order_goods_id' => $data['order_goods_id'], |
|||
'order_id' => $goods['order_id'], |
|||
'user_id' => $user['user_id'], |
|||
'type' => $data['type'], |
|||
'apply_desc' => $data['content'], |
|||
'is_agree' => 0, |
|||
'status' => 0, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
]); |
|||
// 记录凭证图片关系 |
|||
if (isset($data['images']) && !empty($data['images'])) { |
|||
$this->saveImages($this['order_refund_id'], $data['images']); |
|||
} |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
$this->rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 记录售后单图片 |
|||
* @param $order_refund_id |
|||
* @param $images |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
private function saveImages($order_refund_id, $images) |
|||
{ |
|||
// 生成评价图片数据 |
|||
$data = []; |
|||
foreach (explode(',', $images) as $image_id) { |
|||
$data[] = [ |
|||
'order_refund_id' => $order_refund_id, |
|||
'image_id' => $image_id, |
|||
'wxapp_id' => self::$wxapp_id |
|||
]; |
|||
} |
|||
return !empty($data) && (new OrderRefundImage)->saveAll($data); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\OrderRefundAddress as OrderRefundAddressModel; |
|||
|
|||
/** |
|||
* 售后单退货地址模型 |
|||
* Class OrderRefundAddress |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderRefundAddress extends OrderRefundAddressModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\OrderRefundImage as OrderRefundImageModel; |
|||
|
|||
/** |
|||
* 售后单图片模型 |
|||
* Class OrderRefundImage |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderRefundImage extends OrderRefundImageModel |
|||
{ |
|||
|
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Setting as SettingModel; |
|||
|
|||
/** |
|||
* 系统设置模型 |
|||
* Class Setting |
|||
* @package app\api\model |
|||
*/ |
|||
class Setting extends SettingModel |
|||
{ |
|||
/** |
|||
* 获取积分名称 |
|||
* @return string |
|||
*/ |
|||
public static function getPointsName() |
|||
{ |
|||
return static::getItem('points')['points_name']; |
|||
} |
|||
|
|||
/** |
|||
* 获取微信订阅消息设置 |
|||
*/ |
|||
public static function getSubmsg() |
|||
{ |
|||
$data = []; |
|||
foreach (static::getItem('submsg') as $groupName => $group) { |
|||
foreach ($group as $itemName => $item) { |
|||
$data[$groupName][$itemName]['template_id'] = $item['template_id']; |
|||
} |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Spec as SpecModel; |
|||
|
|||
/** |
|||
* 规格/属性(组)模型 |
|||
* Class Spec |
|||
* @package app\api\model |
|||
*/ |
|||
class Spec extends SpecModel |
|||
{ |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\SpecValue as SpecValueModel; |
|||
|
|||
/** |
|||
* 规格/属性(值)模型 |
|||
* Class SpecValue |
|||
* @package app\api\model |
|||
*/ |
|||
class SpecValue extends SpecValueModel |
|||
{ |
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\UploadFile as UploadFileModel; |
|||
|
|||
/** |
|||
* 文件库模型 |
|||
* Class UploadFile |
|||
* @package app\api\model |
|||
*/ |
|||
class UploadFile extends UploadFileModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,192 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use think\Cache; |
|||
use app\common\library\wechat\WxUser; |
|||
use app\common\exception\BaseException; |
|||
use app\common\model\User as UserModel; |
|||
use app\api\model\dealer\Referee as RefereeModel; |
|||
use app\api\model\dealer\Setting as DealerSettingModel; |
|||
|
|||
/** |
|||
* 用户模型类 |
|||
* Class User |
|||
* @package app\api\model |
|||
*/ |
|||
class User extends UserModel |
|||
{ |
|||
private $token; |
|||
|
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'open_id', |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 获取用户信息 |
|||
* @param $token |
|||
* @return null|static |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function getUser($token) |
|||
{ |
|||
return self::detail(['open_id' => Cache::get($token)['openid']]); |
|||
} |
|||
|
|||
/** |
|||
* 用户登录 |
|||
* @param array $post |
|||
* @return string |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function login($post) |
|||
{ |
|||
// 微信登录 获取session_key |
|||
$session = $this->wxlogin($post['code']); |
|||
// 自动注册用户 |
|||
$referee_id = isset($post['referee_id']) ? $post['referee_id'] : null; |
|||
$userInfo = json_decode(htmlspecialchars_decode($post['user_info']), true); |
|||
$user_id = $this->register($session['openid'], $userInfo, $referee_id); |
|||
// 生成token (session3rd) |
|||
$this->token = $this->token($session['openid']); |
|||
// 记录缓存, 7天 |
|||
Cache::set($this->token, $session, 86400 * 7); |
|||
return $user_id; |
|||
} |
|||
|
|||
/** |
|||
* 获取token |
|||
* @return mixed |
|||
*/ |
|||
public function getToken() |
|||
{ |
|||
return $this->token; |
|||
} |
|||
|
|||
/** |
|||
* 微信登录 |
|||
* @param $code |
|||
* @return array|mixed |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function wxlogin($code) |
|||
{ |
|||
// 获取当前小程序信息 |
|||
$wxConfig = Wxapp::getWxappCache(); |
|||
// 微信登录 (获取session_key) |
|||
$WxUser = new WxUser($wxConfig['app_id'], $wxConfig['app_secret']); |
|||
if (!$session = $WxUser->sessionKey($code)) |
|||
throw new BaseException(['msg' => 'session_key 获取失败']); |
|||
return $session; |
|||
} |
|||
|
|||
/** |
|||
* 生成用户认证的token |
|||
* @param $openid |
|||
* @return string |
|||
*/ |
|||
private function token($openid) |
|||
{ |
|||
$wxapp_id = self::$wxapp_id; |
|||
// 生成一个不会重复的随机字符串 |
|||
$guid = \getGuidV4(); |
|||
// 当前时间戳 (精确到毫秒) |
|||
$timeStamp = microtime(true); |
|||
// 自定义一个盐 |
|||
$salt = 'token_salt'; |
|||
return md5("{$wxapp_id}_{$timeStamp}_{$openid}_{$guid}_{$salt}"); |
|||
} |
|||
|
|||
/** |
|||
* 自动注册用户 |
|||
* @param $open_id |
|||
* @param $data |
|||
* @param int $referee_id |
|||
* @return mixed |
|||
* @throws \Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function register($open_id, $data, $referee_id = null) |
|||
{ |
|||
// 查询用户是否已存在 |
|||
$user = self::detail(['open_id' => $open_id]); |
|||
$model = $user ?: $this; |
|||
$data['open_id'] = $open_id; |
|||
$data['wxapp_id'] = self::$wxapp_id; |
|||
// 用户昵称 |
|||
$data['nickName'] = preg_replace('/[\xf0-\xf7].{3}/', '', $data['nickName']); |
|||
try { |
|||
$this->startTrans(); |
|||
// 保存/更新用户记录 |
|||
if (!$model->allowField(true)->save($data)) |
|||
throw new BaseException(['msg' => '用户注册失败']); |
|||
// 记录推荐人关系 |
|||
if (!$user && $referee_id > 0) |
|||
RefereeModel::createRelation($model['user_id'], $referee_id); |
|||
$this->commit(); |
|||
} catch (\Exception $e) { |
|||
$this->rollback(); |
|||
throw new BaseException(['msg' => $e->getMessage()]); |
|||
} |
|||
return $model['user_id']; |
|||
} |
|||
|
|||
/** |
|||
* 个人中心菜单列表 |
|||
* @return array |
|||
*/ |
|||
public function getMenus() |
|||
{ |
|||
$menus = [ |
|||
'address' => [ |
|||
'name' => '收货地址', |
|||
'url' => 'pages/address/index', |
|||
'icon' => 'map' |
|||
], |
|||
'coupon' => [ |
|||
'name' => '领券中心', |
|||
'url' => 'pages/coupon/coupon', |
|||
'icon' => 'lingquan' |
|||
], |
|||
'sharing_order' => [ |
|||
'name' => '拼团订单', |
|||
'url' => 'pages/sharing/order/index', |
|||
'icon' => 'pintuan' |
|||
], |
|||
'my_coupon' => [ |
|||
'name' => '我的优惠券', |
|||
'url' => 'pages/user/coupon/coupon', |
|||
'icon' => 'youhuiquan' |
|||
], |
|||
'dealer' => [ |
|||
'name' => '分销中心', |
|||
'url' => 'pages/dealer/index/index', |
|||
'icon' => 'fenxiaozhongxin' |
|||
], |
|||
'help' => [ |
|||
'name' => '我的帮助', |
|||
'url' => 'pages/user/help/index', |
|||
'icon' => 'help' |
|||
], |
|||
]; |
|||
// 判断分销功能是否开启 |
|||
if (DealerSettingModel::isOpen()) { |
|||
$menus['dealer']['name'] = DealerSettingModel::getDealerTitle(); |
|||
} else { |
|||
unset($menus['dealer']); |
|||
} |
|||
return $menus; |
|||
} |
|||
|
|||
} |
|||
@ -1,132 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Region; |
|||
use app\common\model\UserAddress as UserAddressModel; |
|||
|
|||
/** |
|||
* 用户收货地址模型 |
|||
* Class UserAddress |
|||
* @package app\common\model |
|||
*/ |
|||
class UserAddress extends UserAddressModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* @param $user_id |
|||
* @return false|static[] |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id) |
|||
{ |
|||
return self::all(compact('user_id')); |
|||
} |
|||
|
|||
/** |
|||
* 新增收货地址 |
|||
* @param User $user |
|||
* @param $data |
|||
* @return bool |
|||
* @throws \think\exception\PDOException |
|||
*/ |
|||
public function add($user, $data) |
|||
{ |
|||
// 整理地区信息 |
|||
$region = explode(',', $data['region']); |
|||
$province_id = Region::getIdByName($region[0], 1); |
|||
$city_id = Region::getIdByName($region[1], 2, $province_id); |
|||
$region_id = Region::getIdByName($region[2], 3, $city_id); |
|||
// 添加收货地址 |
|||
$this->startTrans(); |
|||
try { |
|||
$this->allowField(true)->save([ |
|||
'name' => $data['name'], |
|||
'phone' => $data['phone'], |
|||
'province_id' => $province_id, |
|||
'city_id' => $city_id, |
|||
'region_id' => $region_id, |
|||
'detail' => $data['detail'], |
|||
'district' => ($region_id === 0 && !empty($region[2])) ? $region[2] : '', |
|||
'user_id' => $user['user_id'], |
|||
'wxapp_id' => self::$wxapp_id |
|||
]); |
|||
// 设为默认收货地址 |
|||
!$user['address_id'] && $user->save(['address_id' => $this['address_id']]); |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
$this->rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 编辑收货地址 |
|||
* @param $data |
|||
* @return false|int |
|||
*/ |
|||
public function edit($data) |
|||
{ |
|||
// 添加收货地址 |
|||
$region = explode(',', $data['region']); |
|||
$province_id = Region::getIdByName($region[0], 1); |
|||
$city_id = Region::getIdByName($region[1], 2, $province_id); |
|||
$region_id = Region::getIdByName($region[2], 3, $city_id); |
|||
return $this->allowField(true)->save([ |
|||
'name' => $data['name'], |
|||
'phone' => $data['phone'], |
|||
'province_id' => $province_id, |
|||
'city_id' => $city_id, |
|||
'region_id' => $region_id, |
|||
'detail' => $data['detail'], |
|||
'district' => ($region_id === 0 && !empty($region[2])) ? $region[2] : '', |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 设为默认收货地址 |
|||
* @param null|static $user |
|||
* @return int |
|||
*/ |
|||
public function setDefault($user) |
|||
{ |
|||
// 设为默认地址 |
|||
return $user->save(['address_id' => $this['address_id']]); |
|||
} |
|||
|
|||
/** |
|||
* 删除收货地址 |
|||
* @param null|static $user |
|||
* @return int |
|||
*/ |
|||
public function remove($user) |
|||
{ |
|||
// 查询当前是否为默认地址 |
|||
$user['address_id'] == $this['address_id'] && $user->save(['address_id' => 0]); |
|||
return $this->delete(); |
|||
} |
|||
|
|||
/** |
|||
* 收货地址详情 |
|||
* @param $user_id |
|||
* @param $address_id |
|||
* @return null|static |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function detail($user_id, $address_id) |
|||
{ |
|||
return self::get(compact('user_id', 'address_id')); |
|||
} |
|||
|
|||
} |
|||
@ -1,197 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\UserCoupon as UserCouponModel; |
|||
use think\Db; |
|||
|
|||
/** |
|||
* 用户优惠券模型 |
|||
* Class UserCoupon |
|||
* @package app\api\model |
|||
*/ |
|||
class UserCoupon extends UserCouponModel |
|||
{ |
|||
/** |
|||
* 获取用户优惠券列表 |
|||
* @param $user_id |
|||
* @param bool $is_use 是否已使用 |
|||
* @param bool $is_expire 是否已过期 |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $is_use = false, $is_expire = false) |
|||
{ |
|||
return $this->where('user_id', '=', $user_id) |
|||
->where('is_use', '=', $is_use ? 1 : 0) |
|||
->where('is_expire', '=', $is_expire ? 1 : 0) |
|||
->select(); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户优惠券总数量(可用) |
|||
* @param $user_id |
|||
* @return int|string |
|||
* @throws \think\Exception |
|||
*/ |
|||
public function getCount($user_id) |
|||
{ |
|||
return $this->where('user_id', '=', $user_id) |
|||
->where('is_use', '=', 0) |
|||
->where('is_expire', '=', 0) |
|||
->count(); |
|||
} |
|||
|
|||
/** |
|||
* 获取用户优惠券ID集 |
|||
* @param $user_id |
|||
* @return array |
|||
*/ |
|||
public function getUserCouponIds($user_id) |
|||
{ |
|||
return $this->where('user_id', '=', $user_id)->column('coupon_id'); |
|||
} |
|||
|
|||
/** |
|||
* 领取优惠券 |
|||
* @param $user |
|||
* @param $coupon_id |
|||
* @return bool|false|int |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function receive($user, $coupon_id) |
|||
{ |
|||
// 获取优惠券信息 |
|||
$coupon = Coupon::detail($coupon_id); |
|||
// 验证优惠券是否可领取 |
|||
if (!$this->checkReceive($user, $coupon)) { |
|||
return false; |
|||
} |
|||
// 添加领取记录 |
|||
return $this->add($user, $coupon); |
|||
} |
|||
|
|||
/** |
|||
* 添加领取记录 |
|||
* @param $user |
|||
* @param Coupon $coupon |
|||
* @return bool |
|||
*/ |
|||
private function add($user, $coupon) |
|||
{ |
|||
// 计算有效期 |
|||
if ($coupon['expire_type'] == 10) { |
|||
$start_time = time(); |
|||
$end_time = $start_time + ($coupon['expire_day'] * 86400); |
|||
} else { |
|||
$start_time = $coupon['start_time']['value']; |
|||
$end_time = $coupon['end_time']['value']; |
|||
} |
|||
Db::startTrans(); |
|||
try { |
|||
// 添加领取记录 |
|||
$this->save([ |
|||
'coupon_id' => $coupon['coupon_id'], |
|||
'name' => $coupon['name'], |
|||
'color' => $coupon['color']['value'], |
|||
'coupon_type' => $coupon['coupon_type']['value'], |
|||
'reduce_price' => $coupon['reduce_price'], |
|||
'discount' => $coupon->getData('discount'), |
|||
'min_price' => $coupon['min_price'], |
|||
'expire_type' => $coupon['expire_type'], |
|||
'expire_day' => $coupon['expire_day'], |
|||
'start_time' => $start_time, |
|||
'end_time' => $end_time, |
|||
'apply_range' => $coupon['apply_range'], |
|||
'user_id' => $user['user_id'], |
|||
'wxapp_id' => self::$wxapp_id |
|||
]); |
|||
// 更新优惠券领取数量 |
|||
$coupon->setIncReceiveNum(); |
|||
Db::commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
Db::rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 验证优惠券是否可领取 |
|||
* @param $user |
|||
* @param Coupon $coupon |
|||
* @return bool |
|||
*/ |
|||
private function checkReceive($user, $coupon) |
|||
{ |
|||
if (!$coupon) { |
|||
$this->error = '优惠券不存在'; |
|||
return false; |
|||
} |
|||
if (!$coupon->checkReceive()) { |
|||
$this->error = $coupon->getError(); |
|||
return false; |
|||
} |
|||
// 验证是否已领取 |
|||
$userCouponIds = $this->getUserCouponIds($user['user_id']); |
|||
if (in_array($coupon['coupon_id'], $userCouponIds)) { |
|||
$this->error = '该优惠券已领取'; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 订单结算优惠券列表 |
|||
* @param $user_id |
|||
* @param $orderPayPrice |
|||
* @return mixed |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function getUserCouponList($user_id, $orderPayPrice) |
|||
{ |
|||
$list = (new self)->getList($user_id); |
|||
$data = []; |
|||
foreach ($list as $coupon) { |
|||
// 最低消费金额 |
|||
if ($orderPayPrice < $coupon['min_price']) continue; |
|||
// 有效期范围内 |
|||
if ($coupon['start_time']['value'] > time()) continue; |
|||
$key = $coupon['user_coupon_id']; |
|||
$data[$key] = [ |
|||
'user_coupon_id' => $coupon['user_coupon_id'], |
|||
'name' => $coupon['name'], |
|||
'color' => $coupon['color'], |
|||
'coupon_type' => $coupon['coupon_type'], |
|||
'reduce_price' => $coupon['reduce_price'], |
|||
'discount' => $coupon['discount'], |
|||
'min_price' => $coupon['min_price'], |
|||
'expire_type' => $coupon['expire_type'], |
|||
'start_time' => $coupon['start_time'], |
|||
'end_time' => $coupon['end_time'], |
|||
]; |
|||
// 计算打折金额 |
|||
if ($coupon['coupon_type']['value'] == 20) { |
|||
$reduce_price = $orderPayPrice * ($coupon['discount'] / 10); |
|||
$data[$key]['reduced_price'] = bcsub($orderPayPrice, $reduce_price, 2); |
|||
} else |
|||
$data[$key]['reduced_price'] = $coupon['reduce_price']; |
|||
} |
|||
return array_sort($data, 'reduced_price', true); |
|||
} |
|||
|
|||
/** |
|||
* 设置优惠券为已使用 |
|||
* @return false|int |
|||
*/ |
|||
public function setIsUse() |
|||
{ |
|||
return $this->save(['is_use' => 1]); |
|||
} |
|||
|
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\Wxapp as WxappModel; |
|||
|
|||
/** |
|||
* 微信小程序模型 |
|||
* Class Wxapp |
|||
* @package app\api\model |
|||
*/ |
|||
class Wxapp extends WxappModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'app_name', |
|||
'app_id', |
|||
'app_secret', |
|||
'mchid', |
|||
'apikey', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\WxappCategory as WxappCategoryModel; |
|||
|
|||
/** |
|||
* 微信小程序分类页模板 |
|||
* Class WxappCategory |
|||
* @package app\api\model |
|||
*/ |
|||
class WxappCategory extends WxappCategoryModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\WxappHelp as WxappHelpModel; |
|||
|
|||
/** |
|||
* 小程序帮助中心 |
|||
* Class WxappHelp |
|||
* @package app\api\model |
|||
*/ |
|||
class WxappHelp extends WxappHelpModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\WxappNavbar as WxappNavbarModel; |
|||
|
|||
/** |
|||
* 微信小程序导航栏模型 |
|||
* Class WxappNavbar |
|||
* @package app\api\model |
|||
*/ |
|||
class WxappNavbar extends WxappNavbarModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,221 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\WxappPage as WxappPageModel; |
|||
use app\api\model\sharing\Goods as SharingGoodsModel; |
|||
use app\api\model\store\Shop as ShopModel; |
|||
|
|||
/** |
|||
* 微信小程序diy页面模型 |
|||
* Class WxappPage |
|||
* @package app\api\model |
|||
*/ |
|||
class WxappPage extends WxappPageModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* DIY页面详情 |
|||
* @param User $user |
|||
* @param int $page_id |
|||
* @return mixed |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function getPageData($user, $page_id = null) |
|||
{ |
|||
// 页面详情 |
|||
$detail = $page_id > 0 ? parent::detail($page_id) : parent::getHomePage(); |
|||
// 页面diy元素 |
|||
$items = $detail['page_data']['items']; |
|||
// 页面顶部导航 |
|||
isset($detail['page_data']['page']) && $items['page'] = $detail['page_data']['page']; |
|||
// 获取动态数据 |
|||
$model = new self; |
|||
foreach ($items as $key => $item) { |
|||
if ($item['type'] === 'window') { |
|||
$items[$key]['data'] = array_values($item['data']); |
|||
} else if ($item['type'] === 'goods') { |
|||
$items[$key]['data'] = $model->getGoodsList($item); |
|||
} else if ($item['type'] === 'sharingGoods') { |
|||
$items[$key]['data'] = $model->getSharingGoodsList($item); |
|||
} else if ($item['type'] === 'coupon') { |
|||
$items[$key]['data'] = $model->getCouponList($user, $item); |
|||
} else if ($item['type'] === 'article') { |
|||
$items[$key]['data'] = $model->getArticleList($item); |
|||
} else if ($item['type'] === 'special') { |
|||
$items[$key]['data'] = $model->getSpecialList($item); |
|||
} else if ($item['type'] === 'shop') { |
|||
$items[$key]['data'] = $model->getShopList($item); |
|||
} |
|||
} |
|||
return ['page' => $items['page'], 'items' => $items]; |
|||
} |
|||
|
|||
/** |
|||
* 商品组件:获取商品列表 |
|||
* @param $item |
|||
* @return array |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getGoodsList($item) |
|||
{ |
|||
// 获取商品数据 |
|||
$model = new Goods; |
|||
if ($item['params']['source'] === 'choice') { |
|||
// 数据来源:手动 |
|||
$goodsIds = array_column($item['data'], 'goods_id'); |
|||
$goodsList = $model->getListByIds($goodsIds, 10); |
|||
} else { |
|||
// 数据来源:自动 |
|||
$goodsList = $model->getList(10, $item['params']['auto']['category'], '', |
|||
$item['params']['auto']['goodsSort'], false, $item['params']['auto']['showNum']); |
|||
} |
|||
if ($goodsList->isEmpty()) return []; |
|||
// 格式化商品列表 |
|||
$data = []; |
|||
foreach ($goodsList as $goods) { |
|||
$data[] = [ |
|||
'goods_id' => $goods['goods_id'], |
|||
'goods_name' => $goods['goods_name'], |
|||
'selling_point' => $goods['selling_point'], |
|||
'image' => $goods['image'][0]['file_path'], |
|||
'goods_price' => $goods['sku'][0]['goods_price'], |
|||
'line_price' => $goods['sku'][0]['line_price'], |
|||
]; |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
/** |
|||
* 商品组件:获取拼团商品列表 |
|||
* @param $item |
|||
* @return array |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getSharingGoodsList($item) |
|||
{ |
|||
// 获取商品数据 |
|||
$model = new SharingGoodsModel; |
|||
if ($item['params']['source'] === 'choice') { |
|||
// 数据来源:手动 |
|||
$goodsIds = array_column($item['data'], 'goods_id'); |
|||
$goodsList = $model->getListByIds($goodsIds, 10); |
|||
} else { |
|||
// 数据来源:自动 |
|||
$goodsList = $model->getList(10, $item['params']['auto']['category'], '', |
|||
$item['params']['auto']['goodsSort'], false, $item['params']['auto']['showNum']); |
|||
} |
|||
if ($goodsList->isEmpty()) return []; |
|||
// 格式化商品列表 |
|||
$data = []; |
|||
foreach ($goodsList as $goods) { |
|||
$data[] = [ |
|||
'goods_id' => $goods['goods_id'], |
|||
'goods_name' => $goods['goods_name'], |
|||
'selling_point' => $goods['selling_point'], |
|||
'people' => $goods['people'], |
|||
'goods_sales' => $goods['goods_sales'], |
|||
'image' => $goods['image'][0]['file_path'], |
|||
'sharing_price' => $goods['sku'][0]['sharing_price'], |
|||
'goods_price' => $goods['sku'][0]['goods_price'], |
|||
'line_price' => $goods['sku'][0]['line_price'], |
|||
]; |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
/** |
|||
* 优惠券组件:获取优惠券列表 |
|||
* @param $user |
|||
* @param $item |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getCouponList($user, $item) |
|||
{ |
|||
// 获取优惠券数据 |
|||
return (new Coupon)->getList($user, $item['params']['limit'], true); |
|||
} |
|||
|
|||
/** |
|||
* 文章组件:获取文章列表 |
|||
* @param $item |
|||
* @return array |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getArticleList($item) |
|||
{ |
|||
// 获取文章数据 |
|||
$model = new Article; |
|||
$articleList = $model->getList($item['params']['auto']['category'], $item['params']['auto']['showNum']); |
|||
return $articleList->isEmpty() ? [] : $articleList->toArray()['data']; |
|||
} |
|||
|
|||
/** |
|||
* 头条快报:获取头条列表 |
|||
* @param $item |
|||
* @return array |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getSpecialList($item) |
|||
{ |
|||
// 获取头条数据 |
|||
$model = new Article; |
|||
$articleList = $model->getList($item['params']['auto']['category'], $item['params']['auto']['showNum']); |
|||
return $articleList->isEmpty() ? [] : $articleList->toArray()['data']; |
|||
} |
|||
|
|||
/** |
|||
* 线下门店组件:获取门店列表 |
|||
* @param $item |
|||
* @return array |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getShopList($item) |
|||
{ |
|||
// 获取商品数据 |
|||
$model = new ShopModel; |
|||
if ($item['params']['source'] === 'choice') { |
|||
// 数据来源:手动 |
|||
$shopIds = array_column($item['data'], 'shop_id'); |
|||
$shopList = $model->getListByIds($shopIds); |
|||
} else { |
|||
// 数据来源:自动 |
|||
$shopList = $model->getList(null, false, false, $item['params']['auto']['showNum']); |
|||
} |
|||
if ($shopList->isEmpty()) return []; |
|||
// 格式化商品列表 |
|||
$data = []; |
|||
foreach ($shopList as $shop) { |
|||
$data[] = [ |
|||
'shop_id' => $shop['shop_id'], |
|||
'shop_name' => $shop['shop_name'], |
|||
'logo_image' => $shop['logo']['file_path'], |
|||
'phone' => $shop['phone'], |
|||
'region' => $shop['region'], |
|||
'address' => $shop['address'], |
|||
]; |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model; |
|||
|
|||
use app\common\model\WxappPrepayId as WxappPrepayIdModel; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
|
|||
/** |
|||
* 小程序prepay_id模型 |
|||
* Class WxappPrepayId |
|||
* @package app\api\model |
|||
*/ |
|||
class WxappPrepayId extends WxappPrepayIdModel |
|||
{ |
|||
/** |
|||
* 新增记录 |
|||
* @param $prepayId |
|||
* @param $orderId |
|||
* @param $userId |
|||
* @param int $orderType |
|||
* @return false|int |
|||
*/ |
|||
public function add($prepayId, $orderId, $userId, $orderType = OrderTypeEnum::MASTER) |
|||
{ |
|||
return $this->save([ |
|||
'prepay_id' => $prepayId, |
|||
'order_id' => $orderId, |
|||
'order_type' => $orderType, |
|||
'user_id' => $userId, |
|||
'can_use_times' => 0, |
|||
'used_times' => 0, |
|||
'expiry_time' => time() + (7 * 86400), |
|||
'wxapp_id' => self::$wxapp_id, |
|||
]); |
|||
} |
|||
|
|||
} |
|||
@ -1,76 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\article; |
|||
|
|||
use think\Cache; |
|||
use app\store\model\Article as ArticleModel; |
|||
use app\common\model\article\Category as CategoryModel; |
|||
|
|||
/** |
|||
* 文章分类模型 |
|||
* Class Category |
|||
* @package app\api\model\article |
|||
*/ |
|||
class Category extends CategoryModel |
|||
{ |
|||
/** |
|||
* 分类详情 |
|||
* @param $category_id |
|||
* @return Category|null |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function detail($category_id) |
|||
{ |
|||
return static::get($category_id); |
|||
} |
|||
|
|||
/** |
|||
* 添加新记录 |
|||
* @param $data |
|||
* @return false|int |
|||
*/ |
|||
public function add($data) |
|||
{ |
|||
$data['wxapp_id'] = self::$wxapp_id; |
|||
$this->deleteCache(); |
|||
return $this->allowField(true)->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 编辑记录 |
|||
* @param $data |
|||
* @return bool|int |
|||
*/ |
|||
public function edit($data) |
|||
{ |
|||
$this->deleteCache(); |
|||
return $this->allowField(true)->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 删除商品分类 |
|||
* @param $category_id |
|||
* @return bool|int |
|||
*/ |
|||
public function remove($category_id) |
|||
{ |
|||
// 判断是否存在文章 |
|||
$articleCount = ArticleModel::getArticleTotal(['category_id' => $category_id]); |
|||
if ($articleCount > 0) { |
|||
$this->error = '该分类下存在' . $articleCount . '个文章,不允许删除'; |
|||
return false; |
|||
} |
|||
$this->deleteCache(); |
|||
return $this->delete(); |
|||
} |
|||
|
|||
/** |
|||
* 删除缓存 |
|||
* @return bool |
|||
*/ |
|||
private function deleteCache() |
|||
{ |
|||
return Cache::rm('article_category_' . self::$wxapp_id); |
|||
} |
|||
|
|||
} |
|||
@ -1,185 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\bargain; |
|||
|
|||
use app\common\model\bargain\Active as ActiveModel; |
|||
use app\api\model\bargain\Task as TaskModel; |
|||
use app\api\model\bargain\TaskHelp as TaskHelpModel; |
|||
use app\common\service\Goods as GoodsService; |
|||
|
|||
/** |
|||
* 砍价活动模型 |
|||
* Class Active |
|||
* @package app\api\model\bargain |
|||
*/ |
|||
class Active extends ActiveModel |
|||
{ |
|||
/** |
|||
* 隐藏的字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'peoples', |
|||
'is_self_cut', |
|||
'initial_sales', |
|||
'actual_sales', |
|||
'sort', |
|||
'create_time', |
|||
'update_time', |
|||
'wxapp_id', |
|||
'is_delete', |
|||
]; |
|||
|
|||
/** |
|||
* 获取器:分享标题 |
|||
* @param $value |
|||
* @return mixed |
|||
*/ |
|||
public function getShareTitleAttr($value) |
|||
{ |
|||
return htmlspecialchars_decode($value); |
|||
} |
|||
|
|||
/** |
|||
* 获取器:砍价助力语 |
|||
* @param $value |
|||
* @return mixed |
|||
*/ |
|||
public function getPromptWordsAttr($value) |
|||
{ |
|||
return htmlspecialchars_decode($value); |
|||
} |
|||
|
|||
/** |
|||
* 活动会场列表 |
|||
* @param array $param |
|||
* @return mixed|\think\Paginator |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getHallList($param = []) |
|||
{ |
|||
return $this->getList($param); |
|||
} |
|||
|
|||
/** |
|||
* 获取砍价活动列表(根据活动id集) |
|||
* @param $activeIds |
|||
* @param array $param |
|||
* @return mixed|\think\Paginator |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getListByIds($activeIds, $param = []) |
|||
{ |
|||
$this->where('active_id', 'in', $activeIds); |
|||
return $this->getList($param); |
|||
} |
|||
|
|||
/** |
|||
* 获取砍价活动列表 |
|||
* @param $param |
|||
* @return mixed|\think\Paginator |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getList($param) |
|||
{ |
|||
// 商品列表获取条件 |
|||
$params = array_merge([ |
|||
'status' => 1, // 商品状态 |
|||
'sortType' => 'all', // 排序类型 |
|||
'sortPrice' => false, // 价格排序 高低 |
|||
'listRows' => 15, // 每页数量 |
|||
], $param); |
|||
// 排序规则 |
|||
if ($params['sortType'] === 'all') { |
|||
$this->order(['sort' => 'asc', $this->getPk() => 'desc']); |
|||
} elseif ($params['sortType'] === 'sales') { |
|||
$this->order(['active_sales' => 'desc']); |
|||
} elseif ($params['sortType'] === 'price') { |
|||
$this->order(['floor_price' => $params['sortPrice'] ? 'desc' : 'asc']); |
|||
} |
|||
// 砍价活动列表 |
|||
$list = $this->field(['*', '(actual_sales + initial_sales) as active_sales']) |
|||
->where('start_time', '<=', time()) |
|||
->where('end_time', '>=', time()) |
|||
->where('status', '=', 1) |
|||
->where('is_delete', '=', 0) |
|||
->order(['sort' => 'asc', $this->getPk() => 'desc']) |
|||
->paginate($params['listRows'], false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
// 设置商品数据 |
|||
$list = GoodsService::setGoodsData($list); |
|||
// 整理正在砍价的助力信息 |
|||
$list = $this->setHelpsData($list); |
|||
return $list; |
|||
} |
|||
|
|||
/** |
|||
* 整理正在砍价的助力信息 |
|||
* @param $list |
|||
* @return mixed |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function setHelpsData($list) |
|||
{ |
|||
$model = new TaskHelpModel; |
|||
foreach ($list as &$item) { |
|||
$item['helps'] = $model->getHelpListByActiveId($item['active_id']); |
|||
$item['helps_count'] = $model->getHelpCountByActiveId($item['active_id']); |
|||
} |
|||
return $list; |
|||
} |
|||
|
|||
/** |
|||
* 获取砍价活动详情 |
|||
* @param $activeId |
|||
* @return Active|bool|null |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getDetail($activeId) |
|||
{ |
|||
$model = static::detail($activeId); |
|||
if (empty($model) || $model['is_delete'] == true || $model['status'] == false) { |
|||
$this->error = '很抱歉,该砍价商品不存在或已下架'; |
|||
return false; |
|||
} |
|||
return $model; |
|||
} |
|||
|
|||
/** |
|||
* 获取用户是否正在参与改砍价活动,如果已参与则返回task_id |
|||
* @param $activeId |
|||
* @param bool $user |
|||
* @return bool|int |
|||
*/ |
|||
public function getWhetherPartake($activeId, $user = false) |
|||
{ |
|||
if ($user === false) { |
|||
return false; |
|||
} |
|||
return TaskModel::getHandByUser($activeId, $user['user_id']); |
|||
} |
|||
|
|||
/** |
|||
* 累计活动销量(实际) |
|||
* @return int|true |
|||
* @throws \think\Exception |
|||
*/ |
|||
public function setIncSales() |
|||
{ |
|||
return $this->setInc('actual_sales'); |
|||
} |
|||
|
|||
} |
|||
@ -1,102 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\model\dealer\Apply as ApplyModel; |
|||
|
|||
/** |
|||
* 分销商申请模型 |
|||
* Class Apply |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class Apply extends ApplyModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 是否为分销商申请中 |
|||
* @param $user_id |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function isApplying($user_id) |
|||
{ |
|||
$detail = self::detail(['user_id' => $user_id]); |
|||
return $detail ? ((int)$detail['apply_status'] === 10) : false; |
|||
} |
|||
|
|||
/** |
|||
* 提交申请 |
|||
* @param $user |
|||
* @param $name |
|||
* @param $mobile |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
* @throws \think\exception\PDOException |
|||
*/ |
|||
public function submit($user, $name, $mobile) |
|||
{ |
|||
// 成为分销商条件 |
|||
$config = Setting::getItem('condition'); |
|||
// 数据整理 |
|||
$data = [ |
|||
'user_id' => $user['user_id'], |
|||
'real_name' => trim($name), |
|||
'mobile' => trim($mobile), |
|||
'referee_id' => Referee::getRefereeUserId($user['user_id'], 1), |
|||
'apply_type' => $config['become'], |
|||
'apply_time' => time(), |
|||
'wxapp_id' => self::$wxapp_id, |
|||
]; |
|||
if ($config['become'] == 10) { |
|||
$data['apply_status'] = 10; |
|||
} elseif ($config['become'] == 20) { |
|||
$data['apply_status'] = 20; |
|||
} |
|||
return $this->add($user, $data); |
|||
} |
|||
|
|||
/** |
|||
* 更新分销商申请信息 |
|||
* @param $user |
|||
* @param $data |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
* @throws \think\exception\PDOException |
|||
*/ |
|||
private function add($user, $data) |
|||
{ |
|||
// 实例化模型 |
|||
$model = self::detail(['user_id' => $user['user_id']]) ?: $this; |
|||
// 更新记录 |
|||
$this->startTrans(); |
|||
try { |
|||
// $data['create_time'] = time(); |
|||
// 保存申请信息 |
|||
$model->save($data); |
|||
// 无需审核,自动通过 |
|||
if ($data['apply_type'] == 20) { |
|||
// 新增分销商用户记录 |
|||
User::add($user['user_id'], [ |
|||
'real_name' => $data['real_name'], |
|||
'mobile' => $data['mobile'], |
|||
'referee_id' => $data['referee_id'] |
|||
]); |
|||
} |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
$this->rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\model\dealer\Capital as CapitalModel; |
|||
|
|||
/** |
|||
* 分销商资金明细模型 |
|||
* Class Apply |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class Capital extends CapitalModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,116 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\model\dealer\Order as OrderModel; |
|||
use app\common\service\Order as OrderService; |
|||
|
|||
/** |
|||
* 分销商订单模型 |
|||
* Class Apply |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class Order extends OrderModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取分销商订单列表 |
|||
* @param $user_id |
|||
* @param int $is_settled |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $is_settled = -1) |
|||
{ |
|||
$is_settled > -1 && $this->where('is_settled', '=', !!$is_settled); |
|||
$data = $this->with(['user']) |
|||
->where('first_user_id|second_user_id|third_user_id', '=', $user_id) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
if ($data->isEmpty()) { |
|||
return $data; |
|||
} |
|||
// 整理订单信息 |
|||
$with = ['goods' => ['image', 'refund'], 'address', 'user']; |
|||
return OrderService::getOrderList($data, 'order_master', $with); |
|||
} |
|||
|
|||
/** |
|||
* 创建分销商订单记录 |
|||
* @param $order |
|||
* @param int $order_type 订单类型 (10商城订单 20拼团订单) |
|||
* @return bool|false|int |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function createOrder(&$order, $order_type = 10) |
|||
{ |
|||
// 分销订单模型 |
|||
$model = new self; |
|||
// 分销商基本设置 |
|||
$setting = Setting::getItem('basic'); |
|||
// 是否开启分销功能 |
|||
if (!$setting['is_open']) { |
|||
return false; |
|||
} |
|||
// 获取当前买家的所有上级分销商用户id |
|||
$dealerUser = $model->getDealerUserId($order['user_id'], $setting['level'], $setting['self_buy']); |
|||
// 非分销订单 |
|||
if (!$dealerUser['first_user_id']) { |
|||
return false; |
|||
} |
|||
// 计算订单分销佣金 |
|||
$capital = $model->getCapitalByOrder($order); |
|||
// 保存分销订单记录 |
|||
return $model->save([ |
|||
'user_id' => $order['user_id'], |
|||
'order_id' => $order['order_id'], |
|||
'order_type' => $order_type, |
|||
// 'order_no' => $order['order_no'], // 废弃 |
|||
'order_price' => $capital['orderPrice'], |
|||
'first_money' => max($capital['first_money'], 0), |
|||
'second_money' => max($capital['second_money'], 0), |
|||
'third_money' => max($capital['third_money'], 0), |
|||
'first_user_id' => $dealerUser['first_user_id'], |
|||
'second_user_id' => $dealerUser['second_user_id'], |
|||
'third_user_id' => $dealerUser['third_user_id'], |
|||
'is_settled' => 0, |
|||
'wxapp_id' => $model::$wxapp_id |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 获取当前买家的所有上级分销商用户id |
|||
* @param $user_id |
|||
* @param $level |
|||
* @param $self_buy |
|||
* @return mixed |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getDealerUserId($user_id, $level, $self_buy) |
|||
{ |
|||
$dealerUser = [ |
|||
'first_user_id' => $level >= 1 ? Referee::getRefereeUserId($user_id, 1, true) : 0, |
|||
'second_user_id' => $level >= 2 ? Referee::getRefereeUserId($user_id, 2, true) : 0, |
|||
'third_user_id' => $level == 3 ? Referee::getRefereeUserId($user_id, 3, true) : 0 |
|||
]; |
|||
// 分销商自购 |
|||
if ($self_buy && User::isDealerUser($user_id)) { |
|||
return [ |
|||
'first_user_id' => $user_id, |
|||
'second_user_id' => $dealerUser['first_user_id'], |
|||
'third_user_id' => $dealerUser['second_user_id'], |
|||
]; |
|||
} |
|||
return $dealerUser; |
|||
} |
|||
|
|||
} |
|||
@ -1,100 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\model\dealer\Referee as RefereeModel; |
|||
|
|||
/** |
|||
* 分销商推荐关系模型 |
|||
* Class Apply |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class Referee extends RefereeModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = []; |
|||
|
|||
/** |
|||
* 创建推荐关系 |
|||
* @param $user_id |
|||
* @param $referee_id |
|||
* @return bool |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function createRelation($user_id, $referee_id) |
|||
{ |
|||
// 分销商基本设置 |
|||
$setting = Setting::getItem('basic'); |
|||
// 是否开启分销功能 |
|||
if (!$setting['is_open']) { |
|||
return false; |
|||
} |
|||
// 自分享 |
|||
if ($user_id == $referee_id) { |
|||
return false; |
|||
} |
|||
// # 记录一级推荐关系 |
|||
// 判断当前用户是否已存在推荐关系 |
|||
if (self::isExistReferee($user_id)) { |
|||
return false; |
|||
} |
|||
// 判断推荐人是否为分销商 |
|||
if (!User::isDealerUser($referee_id)) { |
|||
return false; |
|||
} |
|||
// 新增关系记录 |
|||
$model = new self; |
|||
$model->add($referee_id, $user_id, 1); |
|||
// # 记录二级推荐关系 |
|||
if ($setting['level'] >= 2) { |
|||
// 二级分销商id |
|||
$referee_2_id = self::getRefereeUserId($referee_id, 1, true); |
|||
// 新增关系记录 |
|||
$referee_2_id > 0 && $model->add($referee_2_id, $user_id, 2); |
|||
} |
|||
// # 记录三级推荐关系 |
|||
if ($setting['level'] == 3) { |
|||
// 三级分销商id |
|||
$referee_3_id = self::getRefereeUserId($referee_id, 2, true); |
|||
// 新增关系记录 |
|||
$referee_3_id > 0 && $model->add($referee_3_id, $user_id, 3); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 新增关系记录 |
|||
* @param $dealer_id |
|||
* @param $user_id |
|||
* @param int $level |
|||
* @return bool |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function add($dealer_id, $user_id, $level = 1) |
|||
{ |
|||
// 新增推荐关系 |
|||
$wxapp_id = self::$wxapp_id; |
|||
$create_time = time(); |
|||
$this->insert(compact('dealer_id', 'user_id', 'level', 'wxapp_id', 'create_time')); |
|||
// 记录分销商成员数量 |
|||
User::setMemberInc($dealer_id, $level); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 是否已存在推荐关系 |
|||
* @param $user_id |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private static function isExistReferee($user_id) |
|||
{ |
|||
return !!self::get(['user_id' => $user_id]); |
|||
} |
|||
|
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\model\dealer\Setting as SettingModel; |
|||
|
|||
/** |
|||
* 分销商设置模型 |
|||
* Class Setting |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class Setting extends SettingModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'update_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,51 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\model\dealer\User as UserModel; |
|||
|
|||
/** |
|||
* 分销商用户模型 |
|||
* Class User |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class User extends UserModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 资金冻结 |
|||
* @param $money |
|||
* @return false|int |
|||
*/ |
|||
public function freezeMoney($money) |
|||
{ |
|||
return $this->save([ |
|||
'money' => $this['money'] - $money, |
|||
'freeze_money' => $this['freeze_money'] + $money, |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 累计分销商成员数量 |
|||
* @param $dealer_id |
|||
* @param $level |
|||
* @return int|true |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function setMemberInc($dealer_id, $level) |
|||
{ |
|||
$fields = [1 => 'first_num', 2 => 'second_num', 3 => 'third_num']; |
|||
$model = static::detail($dealer_id); |
|||
return $model->setInc($fields[$level]); |
|||
} |
|||
|
|||
} |
|||
@ -1,99 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\dealer; |
|||
|
|||
use app\common\exception\BaseException; |
|||
use app\common\model\dealer\Withdraw as WithdrawModel; |
|||
|
|||
/** |
|||
* 分销商提现明细模型 |
|||
* Class Withdraw |
|||
* @package app\api\model\dealer |
|||
*/ |
|||
class Withdraw extends WithdrawModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取分销商提现明细 |
|||
* @param $user_id |
|||
* @param int $apply_status |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $apply_status = -1) |
|||
{ |
|||
$this->where('user_id', '=', $user_id); |
|||
$apply_status > -1 && $this->where('apply_status', '=', $apply_status); |
|||
return $this->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 提交申请 |
|||
* @param User $dealer |
|||
* @param $data |
|||
* @return false|int |
|||
* @throws BaseException |
|||
*/ |
|||
public function submit($dealer, $data) |
|||
{ |
|||
// 数据验证 |
|||
$this->validation($dealer, $data); |
|||
// 新增申请记录 |
|||
$this->save(array_merge($data, [ |
|||
'user_id' => $dealer['user_id'], |
|||
'apply_status' => 10, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
])); |
|||
// 冻结用户资金 |
|||
$dealer->freezeMoney($data['money']); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 数据验证 |
|||
* @param $dealer |
|||
* @param $data |
|||
* @throws BaseException |
|||
*/ |
|||
private function validation($dealer, $data) |
|||
{ |
|||
// 结算设置 |
|||
$settlement = Setting::getItem('settlement'); |
|||
// 最低提现佣金 |
|||
if ($data['money'] <= 0) { |
|||
throw new BaseException(['msg' => '提现金额不正确']); |
|||
} |
|||
if ($dealer['money'] <= 0) { |
|||
throw new BaseException(['msg' => '当前用户没有可提现佣金']); |
|||
} |
|||
if ($data['money'] > $dealer['money']) { |
|||
throw new BaseException(['msg' => '提现金额不能大于可提现佣金']); |
|||
} |
|||
if ($data['money'] < $settlement['min_money']) { |
|||
throw new BaseException(['msg' => '最低提现金额为' . $settlement['min_money']]); |
|||
} |
|||
if (!in_array($data['pay_type'], $settlement['pay_type'])) { |
|||
throw new BaseException(['msg' => '提现方式不正确']); |
|||
} |
|||
if ($data['pay_type'] == '20') { |
|||
if (empty($data['alipay_name']) || empty($data['alipay_account'])) { |
|||
throw new BaseException(['msg' => '请补全提现信息']); |
|||
} |
|||
} elseif ($data['pay_type'] == '30') { |
|||
if (empty($data['bank_name']) || empty($data['bank_account']) || empty($data['bank_card'])) { |
|||
throw new BaseException(['msg' => '请补全提现信息']); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,193 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\recharge; |
|||
|
|||
use app\common\model\recharge\Order as OrderModel; |
|||
|
|||
use app\api\model\Setting as SettingModel; |
|||
use app\api\model\recharge\Plan as PlanModel; |
|||
use app\api\model\recharge\OrderPlan as OrderPlanModel; |
|||
|
|||
use app\common\service\Order as OrderService; |
|||
use app\common\enum\recharge\order\PayStatus as PayStatusEnum; |
|||
use app\common\enum\recharge\order\RechargeType as RechargeTypeEnum; |
|||
use app\common\exception\BaseException; |
|||
|
|||
/** |
|||
* 用户充值订单模型 |
|||
* Class Order |
|||
* @package app\api\model\recharge |
|||
*/ |
|||
class Order extends OrderModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
]; |
|||
|
|||
/** |
|||
* 获取订单列表 |
|||
* @param $userId |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($userId) |
|||
{ |
|||
// 获取列表数据 |
|||
return $this->where('user_id', '=', $userId) |
|||
->where('pay_status', '=', PayStatusEnum::SUCCESS) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 创建充值订单 |
|||
* @param \app\api\model\User $user 当前用户信息 |
|||
* @param int $planId 套餐id |
|||
* @param double $customMoney 自定义充值金额 |
|||
* @return bool|false|int |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function createOrder($user, $planId = null, $customMoney = 0.00) |
|||
{ |
|||
// 确定充值方式 |
|||
$rechargeType = $planId > 0 ? RechargeTypeEnum::PLAN : RechargeTypeEnum::CUSTOM; |
|||
// 验证用户输入 |
|||
if (!$this->validateForm($rechargeType, $planId, $customMoney)) { |
|||
$this->error = $this->error ?: '数据验证错误'; |
|||
return false; |
|||
} |
|||
// 获取订单数据 |
|||
$data = $this->getOrderData($user, $rechargeType, $planId, $customMoney); |
|||
// 记录订单信息 |
|||
return $this->saveOrder($data); |
|||
} |
|||
|
|||
/** |
|||
* 保存订单记录 |
|||
* @param $data |
|||
* @return bool|false|int |
|||
*/ |
|||
private function saveOrder($data) |
|||
{ |
|||
// 写入订单记录 |
|||
$this->save($data['order']); |
|||
// 记录订单套餐快照 |
|||
if (!empty($data['plan'])) { |
|||
$PlanModel = new OrderPlanModel; |
|||
return $PlanModel->add($this['order_id'], $data['plan']); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 生成充值订单 |
|||
* @param $user |
|||
* @param $rechargeType |
|||
* @param $planId |
|||
* @param $customMoney |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getOrderData($user, $rechargeType, $planId, $customMoney) |
|||
{ |
|||
// 订单信息 |
|||
$data = [ |
|||
'order' => [ |
|||
'user_id' => $user['user_id'], |
|||
'order_no' => 'RC' . OrderService::createOrderNo(), |
|||
'recharge_type' => $rechargeType, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
], |
|||
'plan' => [] // 订单套餐快照 |
|||
]; |
|||
// 自定义金额充值 |
|||
if ($rechargeType == RechargeTypeEnum::CUSTOM) { |
|||
$this->createDataByCustom($data, $customMoney); |
|||
} |
|||
// 套餐充值 |
|||
if ($rechargeType == RechargeTypeEnum::PLAN) { |
|||
$this->createDataByPlan($data, $planId); |
|||
} |
|||
// 实际到账金额 |
|||
$data['order']['actual_money'] = bcadd($data['order']['pay_price'], $data['order']['gift_money'], 2); |
|||
return $data; |
|||
} |
|||
|
|||
/** |
|||
* 创建套餐充值订单数据 |
|||
* @param $order |
|||
* @param $planId |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function createDataByPlan(&$order, $planId) |
|||
{ |
|||
// 获取套餐详情 |
|||
$planInfo = PlanModel::detail($planId); |
|||
if (empty($planInfo)) { |
|||
throw new BaseException(['msg' => '充值套餐不存在']); |
|||
} |
|||
$order['plan'] = $planInfo; |
|||
$order['order']['plan_id'] = $planInfo['plan_id']; |
|||
$order['order']['gift_money'] = $planInfo['gift_money']; |
|||
$order['order']['pay_price'] = $planInfo['money']; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 创建自定义充值订单数据 |
|||
* @param $order |
|||
* @param $customMoney |
|||
* @return bool |
|||
*/ |
|||
private function createDataByCustom(&$order, $customMoney) |
|||
{ |
|||
// 用户支付金额 |
|||
$order['order']['pay_price'] = $customMoney; |
|||
// 充值设置 |
|||
$setting = SettingModel::getItem('recharge'); |
|||
if ($setting['is_custom'] == false) { |
|||
return true; |
|||
} |
|||
// 根据自定义充值金额匹配满足的套餐 |
|||
$PlanModel = new PlanModel; |
|||
$matchPlanInfo = $PlanModel->getMatchPlan($customMoney); |
|||
if (!empty($matchPlanInfo)) { |
|||
$order['plan'] = $matchPlanInfo; |
|||
$order['order']['plan_id'] = $matchPlanInfo['plan_id']; |
|||
$order['order']['gift_money'] = $matchPlanInfo['gift_money']; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 表单验证 |
|||
* @param $rechargeType |
|||
* @param $planId |
|||
* @param $customMoney |
|||
* @return bool |
|||
*/ |
|||
private function validateForm($rechargeType, $planId, $customMoney) |
|||
{ |
|||
if (empty($planId) && $customMoney <= 0) { |
|||
$this->error = '请选择充值套餐或输入充值金额'; |
|||
return false; |
|||
} |
|||
// 验证自定义的金额 |
|||
if ($rechargeType == RechargeTypeEnum::CUSTOM && $customMoney <= 0) { |
|||
$this->error = '请选择充值套餐或输入充值金额'; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\recharge; |
|||
|
|||
use app\common\model\recharge\OrderPlan as OrderPlanModel; |
|||
|
|||
/** |
|||
* 用户充值订单套餐快照模型 |
|||
* Class OrderPlan |
|||
* @package app\api\model\recharge |
|||
*/ |
|||
class OrderPlan extends OrderPlanModel |
|||
{ |
|||
/** |
|||
* 新增记录 |
|||
* @param $orderId |
|||
* @param $data |
|||
* @return false|int |
|||
*/ |
|||
public function add($orderId, $data) |
|||
{ |
|||
return $this->save([ |
|||
'order_id' => $orderId, |
|||
'plan_id' => $data['plan_id'], |
|||
'plan_name' => $data['plan_name'], |
|||
'money' => $data['money'], |
|||
'gift_money' => $data['gift_money'], |
|||
'wxapp_id' => self::$wxapp_id |
|||
]); |
|||
} |
|||
|
|||
} |
|||
@ -1,73 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\recharge; |
|||
|
|||
use app\common\model\recharge\Plan as PlanModel; |
|||
|
|||
/** |
|||
* 用户充值订单模型 |
|||
* Class Plan |
|||
* @package app\api\model\recharge |
|||
*/ |
|||
class Plan extends PlanModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取器:充值金额 |
|||
* @param $value |
|||
* @return int |
|||
*/ |
|||
public function getMoneyAttr($value) |
|||
{ |
|||
return ($value == $intValue = (int)$value) ? $intValue : $value; |
|||
} |
|||
|
|||
/** |
|||
* 获取器:赠送金额 |
|||
* @param $value |
|||
* @return int |
|||
*/ |
|||
public function getGiftMoneyAttr($value) |
|||
{ |
|||
return ($value == $intValue = (int)$value) ? $intValue : $value; |
|||
} |
|||
|
|||
/** |
|||
* 获取可用的充值套餐列表 |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList() |
|||
{ |
|||
// 获取列表数据 |
|||
return $this->where('is_delete', '=', 0) |
|||
->order(['sort' => 'asc', 'money' => 'desc', 'create_time' => 'desc']) |
|||
->select(); |
|||
} |
|||
|
|||
/** |
|||
* 根据自定义充值金额匹配满足的套餐 |
|||
* @param $payPrice |
|||
* @return array|false|\PDOStatement|string|\think\Model |
|||
*/ |
|||
public function getMatchPlan($payPrice) |
|||
{ |
|||
return (new static)->where('money', '<=', $payPrice) |
|||
->where('is_delete', '=', 0) |
|||
->order(['money' => 'desc']) |
|||
->find(); |
|||
} |
|||
|
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\exception\BaseException; |
|||
use app\common\model\sharing\Active as ActiveModel; |
|||
|
|||
/** |
|||
* 拼团拼单模型 |
|||
* Class Active |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class Active extends ActiveModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 新增拼单记录 |
|||
* @param $data |
|||
* @return false|int |
|||
*/ |
|||
public function add($data) |
|||
{ |
|||
return $this->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 根据商品id获取进行中的拼单列表 |
|||
* @param $goods_id |
|||
* @param int $limit |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
*/ |
|||
public static function getActivityListByGoods($goods_id, $limit = 15) |
|||
{ |
|||
return (new static)->with(['user']) |
|||
->where('goods_id', '=', $goods_id) |
|||
->where('status', '=', 10) |
|||
->limit($limit) |
|||
->select(); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\ActiveUsers as ActiveUsersModel; |
|||
|
|||
/** |
|||
* 拼团拼单成员模型 |
|||
* Class ActiveUsers |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class ActiveUsers extends ActiveUsersModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\Category as CategoryModel; |
|||
|
|||
/** |
|||
* 拼团商品分类模型 |
|||
* Class Category |
|||
* @package app\common\model\sharing |
|||
*/ |
|||
class Category extends CategoryModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,235 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\exception\BaseException; |
|||
use app\common\model\sharing\Comment as CommentModel; |
|||
|
|||
/** |
|||
* 拼团商品评价模型 |
|||
* Class Comment |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class Comment extends CommentModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'status', |
|||
'sort', |
|||
'order_id', |
|||
'goods_id', |
|||
'order_goods_id', |
|||
'is_delete', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 关联用户表 |
|||
* @return \think\model\relation\BelongsTo |
|||
*/ |
|||
public function user() |
|||
{ |
|||
$module = self::getCalledModule() ?: 'common'; |
|||
return $this->belongsTo("app\\{$module}\\model\\User") |
|||
->field(['user_id', 'nickName', 'avatarUrl']); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定商品评价列表 |
|||
* @param $goods_id |
|||
* @param int $scoreType |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getGoodsCommentList($goods_id, $scoreType = -1) |
|||
{ |
|||
// 筛选条件 |
|||
$filter = [ |
|||
'goods_id' => $goods_id, |
|||
'is_delete' => 0, |
|||
'status' => 1, |
|||
]; |
|||
// 评分 |
|||
$scoreType > 0 && $filter['score'] = $scoreType; |
|||
return $this->with(['user', 'OrderGoods', 'image.file']) |
|||
->where($filter) |
|||
->order(['sort' => 'asc', 'create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定评分总数 |
|||
* @param $goods_id |
|||
* @return array|false|\PDOStatement|string|\think\Model |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getTotal($goods_id) |
|||
{ |
|||
return $this->field([ |
|||
'count(comment_id) AS `all`', |
|||
'count(score = 10 OR NULL) AS `praise`', |
|||
'count(score = 20 OR NULL) AS `review`', |
|||
'count(score = 30 OR NULL) AS `negative`', |
|||
])->where([ |
|||
'goods_id' => $goods_id, |
|||
'is_delete' => 0, |
|||
'status' => 1 |
|||
])->find(); |
|||
} |
|||
|
|||
/** |
|||
* 验证订单是否允许评价 |
|||
* @param Order $order |
|||
* @return boolean |
|||
*/ |
|||
public function checkOrderAllowComment($order) |
|||
{ |
|||
// 验证订单是否已完成 |
|||
if ($order['order_status']['value'] != 30) { |
|||
$this->error = '该订单未完成,无法评价'; |
|||
return false; |
|||
} |
|||
// 验证订单是否已评价 |
|||
if ($order['is_comment'] == 1) { |
|||
$this->error = '该订单已完成评价'; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 根据已完成订单商品 添加评价 |
|||
* @param Order $order |
|||
* @param \think\Collection|OrderGoods $goodsList |
|||
* @param $formJsonData |
|||
* @return boolean |
|||
* @throws \Exception |
|||
*/ |
|||
public function addForOrder($order, $goodsList, $formJsonData) |
|||
{ |
|||
// 生成 formData |
|||
$formData = $this->formatFormData($formJsonData); |
|||
// 生成评价数据 |
|||
$data = $this->createCommentData($order['user_id'], $order['order_id'], $goodsList, $formData); |
|||
if (empty($data)) { |
|||
$this->error = '没有输入评价内容'; |
|||
return false; |
|||
} |
|||
// 开启事务 |
|||
$this->startTrans(); |
|||
try { |
|||
// 记录评价内容 |
|||
$result = $this->isUpdate(false)->saveAll($data); |
|||
// 记录评价图片 |
|||
$this->saveAllImages($result, $formData); |
|||
// 更新订单评价状态 |
|||
$isComment = count($goodsList) === count($data); |
|||
$this->updateOrderIsComment($order, $isComment, $result); |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->rollback(); |
|||
$this->error = $e->getMessage(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 更新订单评价状态 |
|||
* @param Order $order |
|||
* @param $isComment |
|||
* @param $commentList |
|||
* @return array|false |
|||
* @throws \Exception |
|||
*/ |
|||
private function updateOrderIsComment($order, $isComment, &$commentList) |
|||
{ |
|||
// 更新订单商品 |
|||
$orderGoodsData = []; |
|||
foreach ($commentList as $comment) { |
|||
$orderGoodsData[] = [ |
|||
'order_goods_id' => $comment['order_goods_id'], |
|||
'is_comment' => 1 |
|||
]; |
|||
} |
|||
// 更新订单 |
|||
$isComment && $order->save(['is_comment' => 1]); |
|||
return (new OrderGoods)->saveAll($orderGoodsData); |
|||
} |
|||
|
|||
/** |
|||
* 生成评价数据 |
|||
* @param $user_id |
|||
* @param $order_id |
|||
* @param $goodsList |
|||
* @param $formData |
|||
* @return array |
|||
* @throws BaseException |
|||
*/ |
|||
private function createCommentData($user_id, $order_id, &$goodsList, &$formData) |
|||
{ |
|||
$data = []; |
|||
foreach ($goodsList as $goods) { |
|||
if (!isset($formData[$goods['order_goods_id']])) { |
|||
throw new BaseException(['msg' => '提交的数据不合法']); |
|||
} |
|||
$item = $formData[$goods['order_goods_id']]; |
|||
!empty($item['content']) && $data[$goods['order_goods_id']] = [ |
|||
'score' => $item['score'], |
|||
'content' => $item['content'], |
|||
'is_picture' => !empty($item['uploaded']), |
|||
'sort' => 100, |
|||
'status' => 1, |
|||
'user_id' => $user_id, |
|||
'order_id' => $order_id, |
|||
'goods_id' => $item['goods_id'], |
|||
'order_goods_id' => $item['order_goods_id'], |
|||
'wxapp_id' => self::$wxapp_id |
|||
]; |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
/** |
|||
* 格式化 formData |
|||
* @param string $formJsonData |
|||
* @return array |
|||
*/ |
|||
private function formatFormData($formJsonData) |
|||
{ |
|||
return array_column(json_decode($formJsonData, true), null, 'order_goods_id'); |
|||
} |
|||
|
|||
/** |
|||
* 记录评价图片 |
|||
* @param $commentList |
|||
* @param $formData |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
private function saveAllImages(&$commentList, &$formData) |
|||
{ |
|||
// 生成评价图片数据 |
|||
$imageData = []; |
|||
foreach ($commentList as $comment) { |
|||
$item = $formData[$comment['order_goods_id']]; |
|||
foreach ($item['uploaded'] as $imageId) { |
|||
$imageData[] = [ |
|||
'comment_id' => $comment['comment_id'], |
|||
'image_id' => $imageId, |
|||
'wxapp_id' => self::$wxapp_id |
|||
]; |
|||
} |
|||
} |
|||
$model = new CommentImage; |
|||
return !empty($imageData) && $model->saveAll($imageData); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\CommentImage as CommentImageModel; |
|||
|
|||
/** |
|||
* 拼团商品图片模型 |
|||
* Class GoodsImage |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class CommentImage extends CommentImageModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\Goods as GoodsModel; |
|||
|
|||
/** |
|||
* 拼团商品模型 |
|||
* Class Goods |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class Goods extends GoodsModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'sales_initial', |
|||
'sales_actual', |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 商品详情:HTML实体转换回普通字符 |
|||
* @param $value |
|||
* @return string |
|||
*/ |
|||
public function getContentAttr($value) |
|||
{ |
|||
return htmlspecialchars_decode($value); |
|||
} |
|||
|
|||
/** |
|||
* 根据商品id集获取商品列表 |
|||
* @param $goodsIds |
|||
* @param null $status |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getListByIds($goodsIds, $status = null) |
|||
{ |
|||
// 筛选条件 |
|||
$filter = ['goods_id' => ['in', $goodsIds]]; |
|||
$status > 0 && $filter['goods_status'] = $status; |
|||
if (!empty($goodsIds)) { |
|||
$this->orderRaw('field(goods_id, ' . implode(',', $goodsIds) . ')'); |
|||
} |
|||
// 获取商品列表数据 |
|||
return $this->with(['category', 'image.file', 'sku', 'spec_rel.spec', 'delivery.rule']) |
|||
->where($filter) |
|||
->select(); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\GoodsImage as GoodsImageModel; |
|||
|
|||
/** |
|||
* 拼团商品图片模型 |
|||
* Class GoodsImage |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class GoodsImage extends GoodsImageModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,24 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\GoodsSku as GoodsSkuModel; |
|||
|
|||
/** |
|||
* 拼团商品规格模型 |
|||
* Class GoodsSku |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class GoodsSku extends GoodsSkuModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\GoodsSpecRel as GoodsSpecRelModel; |
|||
|
|||
/** |
|||
* 拼团商品规格关系模型 |
|||
* Class GoodsSpecRel |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class GoodsSpecRel extends GoodsSpecRelModel |
|||
{ |
|||
} |
|||
@ -1,709 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\Order as OrderModel; |
|||
|
|||
use app\api\model\Setting as SettingModel; |
|||
use app\api\model\store\Shop as ShopModel; |
|||
use app\api\model\UserCoupon as UserCouponModel; |
|||
use app\api\model\dealer\Order as DealerOrderModel; |
|||
use app\api\model\GoodsSku as GoodsSkuModel; |
|||
use app\api\model\sharing\Goods as GoodsModel; |
|||
use app\api\model\sharing\Setting as SharingSettingModel; |
|||
use app\api\model\sharing\OrderGoods as OrderGoodsModel; |
|||
|
|||
use app\api\service\Payment as PaymentService; |
|||
|
|||
use app\common\enum\order\PayStatus as PayStatusEnum; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\DeliveryType as DeliveryTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\service\delivery\Express as ExpressService; |
|||
|
|||
use app\common\exception\BaseException; |
|||
|
|||
|
|||
/** |
|||
* 拼团订单模型 |
|||
* Class Order |
|||
* @package app\api\model |
|||
*/ |
|||
class Order extends OrderModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 订单确认 |
|||
* @param \app\api\model\User $user |
|||
* @param int $order_type 订单类型 (10单独购买 20拼团) |
|||
* @param int $goods_id 商品id |
|||
* @param int $goods_num |
|||
* @param int $goods_sku_id |
|||
* @param int $delivery 配送方式 |
|||
* @param int $pay_type 支付方式 |
|||
* @param int $shop_id 自提门店id |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
* @throws \think\Exception |
|||
*/ |
|||
public function getBuyNow( |
|||
$user, |
|||
$order_type, |
|||
$goods_id, |
|||
$goods_num, |
|||
$goods_sku_id, |
|||
$delivery, |
|||
$pay_type, |
|||
$shop_id = 0 |
|||
) |
|||
{ |
|||
// 商品信息 |
|||
/* @var GoodsModel $goods */ |
|||
$goods = GoodsModel::detail($goods_id); |
|||
// 判断商品是否下架 |
|||
if (!$goods || $goods['is_delete'] || $goods['goods_status']['value'] != 10) { |
|||
throw new BaseException(['msg' => '很抱歉,商品信息不存在或已下架']); |
|||
} |
|||
// 商品sku信息 |
|||
$goods['goods_sku'] = $goods->getGoodsSku($goods_sku_id); |
|||
// 判断商品库存 |
|||
if ($goods_num > $goods['goods_sku']['stock_num']) { |
|||
$this->setError('很抱歉,商品库存不足'); |
|||
} |
|||
// 返回的数据 |
|||
$returnData = []; |
|||
// 商品单价 (根据order_type判断单买还是拼单) |
|||
// order_type:下单类型 10=>单独购买 20=>拼团 |
|||
$goods['goods_price'] = $order_type == 10 ? $goods['goods_sku']['goods_price'] |
|||
: $goods['goods_sku']['sharing_price']; |
|||
// 商品总价 |
|||
$goods['total_num'] = $goods_num; |
|||
$goods['total_price'] = $goodsTotalPrice = bcmul($goods['goods_price'], $goods_num, 2); |
|||
// 商品详情 |
|||
$goodsList = [$goods->toArray()]; |
|||
// 处理配送方式 |
|||
if ($delivery == DeliveryTypeEnum::EXPRESS) { |
|||
$this->orderExpress($returnData, $user, $goodsList, $goodsTotalPrice); |
|||
} elseif ($delivery == DeliveryTypeEnum::EXTRACT) { |
|||
$shop_id > 0 && $returnData['extract_shop'] = ShopModel::detail($shop_id); |
|||
} |
|||
// 可用优惠券列表 |
|||
if (SharingSettingModel::getItem('basic')['is_coupon']) { |
|||
$returnData['coupon_list'] = UserCouponModel::getUserCouponList($user['user_id'], $goodsTotalPrice); |
|||
} |
|||
return array_merge([ |
|||
'order_type' => $order_type, // 订单类型 |
|||
'goods_list' => array_values($goodsList), // 商品详情 |
|||
'order_total_num' => $goods_num, // 商品总数量 |
|||
'order_total_price' => $goodsTotalPrice, // 商品总金额 (不含运费) |
|||
'order_pay_price' => $goodsTotalPrice, // 订单总金额 (含运费) |
|||
'delivery' => $delivery, // 配送类型 |
|||
'coupon_list' => [], // 优惠券列表 |
|||
'address' => $user['address_default'], // 默认地址 |
|||
'exist_address' => !$user['address']->isEmpty(), // 是否存在收货地址 |
|||
'express_price' => '0.00', // 配送费用 |
|||
'intra_region' => true, // 当前用户收货城市是否存在配送规则中 |
|||
'extract_shop' => [], // 自提门店信息 |
|||
'pay_type' => $pay_type, // 支付方式 |
|||
'has_error' => $this->hasError(), |
|||
'error_msg' => $this->getError(), |
|||
], $returnData); |
|||
} |
|||
|
|||
/** |
|||
* 订单配送-快递配送 |
|||
* @param $returnData |
|||
* @param $user |
|||
* @param $goodsList |
|||
* @param $goodsTotalPrice |
|||
*/ |
|||
private function orderExpress(&$returnData, $user, $goodsList, $goodsTotalPrice) |
|||
{ |
|||
// 当前用户收货城市id |
|||
$cityId = $user['address_default'] ? $user['address_default']['city_id'] : null; |
|||
// 初始化配送服务类 |
|||
$ExpressService = new ExpressService( |
|||
static::$wxapp_id, |
|||
$cityId, |
|||
$goodsList, |
|||
OrderTypeEnum::SHARING |
|||
); |
|||
// 获取不支持当前城市配送的商品 |
|||
$notInRuleGoods = $ExpressService->getNotInRuleGoods(); |
|||
// 验证商品是否在配送范围 |
|||
$intraRegion = $returnData['intra_region'] = $notInRuleGoods === false; |
|||
if ($intraRegion == false) { |
|||
$notInRuleGoodsName = $notInRuleGoods['goods_name']; |
|||
$this->setError("很抱歉,您的收货地址不在商品 [{$notInRuleGoodsName}] 的配送范围内"); |
|||
} else { |
|||
// 计算配送金额 |
|||
$ExpressService->setExpressPrice(); |
|||
} |
|||
// 订单总运费金额 |
|||
$expressPrice = $returnData['express_price'] = $ExpressService->getTotalFreight(); |
|||
// 订单总金额 (含运费) |
|||
$returnData['order_pay_price'] = bcadd($goodsTotalPrice, $expressPrice, 2); |
|||
} |
|||
|
|||
/** |
|||
* 创建新订单 |
|||
* @param \app\api\model\User $user |
|||
* @param array $order 订单内容 |
|||
* @param int $active_id 拼单id |
|||
* @param int $coupon_id 用户优惠券id |
|||
* @param string $remark 买家留言 |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function createOrder( |
|||
$user, |
|||
$order, |
|||
$active_id = null, |
|||
$coupon_id = null, |
|||
$remark = '' |
|||
) |
|||
{ |
|||
// 如果是参与拼单,则记录拼单id |
|||
$order['active_id'] = $active_id > 0 ? $active_id : 0; |
|||
// 表单验证 |
|||
if (!$this->validateOrderForm($user, $order)) { |
|||
return false; |
|||
} |
|||
$this->transaction(function () use ($order, $user, $coupon_id, $remark) { |
|||
// 设置订单优惠券信息 |
|||
$this->setCouponPrice($order, $coupon_id); |
|||
// 记录订单信息 |
|||
$this->add($user['user_id'], $order, $remark); |
|||
// 记录收货地址 |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$this->saveOrderAddress($user['user_id'], $order['address']); |
|||
} |
|||
// 保存订单商品信息 |
|||
$this->saveOrderGoods($user['user_id'], $order); |
|||
// 更新商品库存 (针对下单减库存的商品) |
|||
$this->updateGoodsStockNum($order['goods_list']); |
|||
// 获取订单详情 |
|||
$detail = self::getUserOrderDetail($this['order_id'], $user['user_id']); |
|||
// 记录分销商订单 |
|||
if (SharingSettingModel::getItem('basic')['is_dealer']) { |
|||
DealerOrderModel::createOrder($detail, OrderTypeEnum::SHARING); |
|||
} |
|||
// 余额支付标记订单已支付 |
|||
if ($order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
$this->paymentByBalance($this['order_no']); |
|||
} |
|||
}); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 构建微信支付请求 |
|||
* @param \app\api\model\User $user |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function paymentByWechat($user) |
|||
{ |
|||
return PaymentService::wechat( |
|||
$user, |
|||
$this['order_id'], |
|||
$this['order_no'], |
|||
$this['pay_price'], |
|||
OrderTypeEnum::SHARING |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 余额支付标记订单已支付 |
|||
* @param string $orderNo 订单号 |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function paymentByBalance($orderNo) |
|||
{ |
|||
// 获取订单详情 |
|||
$model = new \app\task\model\sharing\Order; |
|||
$order = $model->payDetail($orderNo); |
|||
// 发起余额支付 |
|||
$status = $order->paySuccess(PayTypeEnum::BALANCE); |
|||
if (!$status) { |
|||
$this->error = $order->error; |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 表单验证 (订单提交) |
|||
* @param \app\api\model\User $user 用户信息 |
|||
* @param array $order 订单信息 |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function validateOrderForm($user, &$order) |
|||
{ |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
if (empty($order['address'])) { |
|||
$this->error = '请先选择收货地址'; |
|||
return false; |
|||
} |
|||
} |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
if (empty($order['extract_shop'])) { |
|||
$this->error = '请先选择自提门店'; |
|||
return false; |
|||
} |
|||
} |
|||
// 余额支付时判断用户余额是否足够 |
|||
if ($order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
if ($user['balance'] < $order['order_pay_price']) { |
|||
$this->error = '用户余额不足,无法使用余额支付'; |
|||
return false; |
|||
} |
|||
} |
|||
// 验证拼单id是否合法 |
|||
if ($order['active_id'] > 0) { |
|||
// 拼单详情 |
|||
$detail = Active::detail($order['active_id']); |
|||
if (empty($detail)) { |
|||
$this->error = '很抱歉,拼单不存在'; |
|||
return false; |
|||
} |
|||
// 验证当前拼单是否允许加入新成员 |
|||
if (!$detail->checkAllowJoin()) { |
|||
$this->error = $detail->getError(); |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 验证拼单是否允许加入 |
|||
* @param $active_id |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function checkActiveIsAllowJoin($active_id) |
|||
{ |
|||
// 拼单详情 |
|||
$detail = Active::detail($active_id); |
|||
if (!$detail) { |
|||
throw new BaseException('很抱歉,拼单不存在'); |
|||
} |
|||
// 验证当前拼单是否允许加入新成员 |
|||
return $detail->checkAllowJoin(); |
|||
} |
|||
|
|||
/** |
|||
* 设置订单优惠券信息 |
|||
* @param $order |
|||
* @param $coupon_id |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function setCouponPrice(&$order, $coupon_id) |
|||
{ |
|||
if ($coupon_id > 0 && !empty($order['coupon_list'])) { |
|||
// 获取优惠券信息 |
|||
$couponInfo = []; |
|||
foreach ($order['coupon_list'] as $coupon) |
|||
$coupon['user_coupon_id'] == $coupon_id && $couponInfo = $coupon; |
|||
if (empty($couponInfo)) throw new BaseException(['msg' => '未找到优惠券信息']); |
|||
// 计算订单金额 (抵扣后) |
|||
$orderTotalPrice = bcsub($order['order_total_price'], $couponInfo['reduced_price'], 2); |
|||
$orderTotalPrice <= 0 && $orderTotalPrice = '0.01'; |
|||
// 记录订单信息 |
|||
$order['coupon_id'] = $coupon_id; |
|||
$order['coupon_price'] = $couponInfo['reduced_price']; |
|||
$order['order_pay_price'] = bcadd($orderTotalPrice, $order['express_price'], 2); |
|||
// 设置优惠券使用状态 |
|||
$model = UserCouponModel::detail($coupon_id); |
|||
$model->setIsUse(); |
|||
return true; |
|||
} |
|||
$order['coupon_id'] = 0; |
|||
$order['coupon_price'] = 0.00; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 新增订单记录 |
|||
* @param $user_id |
|||
* @param $order |
|||
* @param string $remark |
|||
* @return false|int |
|||
*/ |
|||
private function add($user_id, &$order, $remark = '') |
|||
{ |
|||
$data = [ |
|||
'user_id' => $user_id, |
|||
'order_type' => $order['order_type'], |
|||
'active_id' => $order['active_id'], |
|||
'order_no' => $this->orderNo(), |
|||
'total_price' => $order['order_total_price'], |
|||
'coupon_id' => $order['coupon_id'], |
|||
'coupon_price' => $order['coupon_price'], |
|||
'pay_price' => $order['order_pay_price'], |
|||
'delivery_type' => $order['delivery'], |
|||
'pay_type' => $order['pay_type'], |
|||
'buyer_remark' => trim($remark), |
|||
'wxapp_id' => self::$wxapp_id, |
|||
]; |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$data['express_price'] = $order['express_price']; |
|||
} elseif ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
$data['extract_shop_id'] = $order['extract_shop']['shop_id']; |
|||
} |
|||
return $this->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 保存订单商品信息 |
|||
* @param $user_id |
|||
* @param $order |
|||
* @return int |
|||
*/ |
|||
private function saveOrderGoods($user_id, &$order) |
|||
{ |
|||
// 订单商品列表 |
|||
$goodsList = []; |
|||
// 订单商品实付款金额 (不包含运费) |
|||
$realTotalPrice = bcsub($order['order_pay_price'], $order['express_price'], 2); |
|||
foreach ($order['goods_list'] as $goods) { |
|||
/* @var Goods $goods */ |
|||
// 计算商品实际付款价 |
|||
$total_pay_price = $realTotalPrice * $goods['total_price'] / $order['order_total_price']; |
|||
$goodsList[] = [ |
|||
'user_id' => $user_id, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
'goods_id' => $goods['goods_id'], |
|||
'goods_name' => $goods['goods_name'], |
|||
'image_id' => $goods['image'][0]['image_id'], |
|||
'selling_point' => $goods['selling_point'], |
|||
'people' => $goods['people'], |
|||
'group_time' => $goods['group_time'], |
|||
'is_alone' => $goods['is_alone'], |
|||
'deduct_stock_type' => $goods['deduct_stock_type'], |
|||
'spec_type' => $goods['spec_type'], |
|||
'spec_sku_id' => $goods['goods_sku']['spec_sku_id'], |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'goods_attr' => $goods['goods_sku']['goods_attr'], |
|||
'content' => $goods['content'], |
|||
'goods_no' => $goods['goods_sku']['goods_no'], |
|||
'goods_price' => $goods['goods_sku']['goods_price'], |
|||
'line_price' => $goods['goods_sku']['line_price'], |
|||
'goods_weight' => $goods['goods_sku']['goods_weight'], |
|||
'total_num' => $goods['total_num'], |
|||
'total_price' => $goods['total_price'], |
|||
'total_pay_price' => sprintf('%.2f', $total_pay_price), |
|||
'is_ind_dealer' => $goods['is_ind_dealer'], |
|||
'dealer_money_type' => $goods['dealer_money_type'], |
|||
'first_money' => $goods['first_money'], |
|||
'second_money' => $goods['second_money'], |
|||
'third_money' => $goods['third_money'], |
|||
]; |
|||
} |
|||
return $this->goods()->saveAll($goodsList); |
|||
} |
|||
|
|||
/** |
|||
* 更新商品库存 (针对下单减库存的商品) |
|||
* @param $goods_list |
|||
* @throws \Exception |
|||
*/ |
|||
private function updateGoodsStockNum($goods_list) |
|||
{ |
|||
$deductStockData = []; |
|||
foreach ($goods_list as $goods) { |
|||
// 下单减库存 |
|||
$goods['deduct_stock_type'] == 10 && $deductStockData[] = [ |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'stock_num' => ['dec', $goods['total_num']] |
|||
]; |
|||
} |
|||
!empty($deductStockData) && (new GoodsSkuModel)->isUpdate()->saveAll($deductStockData); |
|||
} |
|||
|
|||
/** |
|||
* 记录收货地址 |
|||
* @param $user_id |
|||
* @param $address |
|||
* @return false|\think\Model |
|||
*/ |
|||
private function saveOrderAddress($user_id, $address) |
|||
{ |
|||
if ($address['region_id'] == 0 && !empty($address['district'])) { |
|||
$address['detail'] = $address['district'] . ' ' . $address['detail']; |
|||
} |
|||
return $this->address()->save([ |
|||
'user_id' => $user_id, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
'name' => $address['name'], |
|||
'phone' => $address['phone'], |
|||
'province_id' => $address['province_id'], |
|||
'city_id' => $address['city_id'], |
|||
'region_id' => $address['region_id'], |
|||
'detail' => $address['detail'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 用户拼团订单列表 |
|||
* @param $user_id |
|||
* @param string $type |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $type = 'all') |
|||
{ |
|||
// 筛选条件 |
|||
$filter = []; |
|||
// 订单数据类型 |
|||
switch ($type) { |
|||
case 'all': |
|||
// 全部 |
|||
break; |
|||
case 'payment'; |
|||
// 待支付 |
|||
$filter['pay_status'] = PayStatusEnum::PENDING; |
|||
break; |
|||
case 'sharing'; |
|||
// 拼团中 |
|||
$filter['active.status'] = 10; |
|||
break; |
|||
case 'delivery'; |
|||
// 待发货 |
|||
$this->where('IF ( (`order`.`order_type` = 20), (`active`.`status` = 20), TRUE)'); |
|||
$filter['pay_status'] = 20; |
|||
$filter['delivery_status'] = 10; |
|||
break; |
|||
case 'received'; |
|||
// 待收货 |
|||
$filter['pay_status'] = 20; |
|||
$filter['delivery_status'] = 20; |
|||
$filter['receipt_status'] = 10; |
|||
break; |
|||
case 'comment'; |
|||
$filter['order_status'] = 30; |
|||
$filter['is_comment'] = 0; |
|||
break; |
|||
} |
|||
return $this->with(['goods.image', 'active']) |
|||
->alias('order') |
|||
->field('order.*, active.status as active_status') |
|||
->join('sharing_active active', 'order.active_id = active.active_id', 'LEFT') |
|||
->where('user_id', '=', $user_id) |
|||
->where($filter) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 取消订单 |
|||
* @return bool|false|int |
|||
*/ |
|||
public function cancel() |
|||
{ |
|||
if ($this['delivery_status']['value'] == 20) { |
|||
$this->error = '已发货订单不可取消'; |
|||
return false; |
|||
} |
|||
if ($this['order_type']['value'] == 20) { |
|||
$this->error = '拼团订单不允许取消'; |
|||
return false; |
|||
} |
|||
$this->transaction(function () { |
|||
// 回退商品库存 |
|||
(new OrderGoodsModel)->backGoodsStock($this['goods']); |
|||
// 更新订单状态 |
|||
$this->save(['order_status' => $this['pay_status']['value'] == PayStatusEnum::SUCCESS ? 21 : 20]); |
|||
}); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 确认收货 |
|||
* @return bool |
|||
* @throws \think\exception\PDOException |
|||
*/ |
|||
public function receipt() |
|||
{ |
|||
// 验证订单是否合法 |
|||
if ($this['delivery_status']['value'] == 10 || $this['receipt_status']['value'] == 20) { |
|||
$this->error = '该订单不合法'; |
|||
return false; |
|||
} |
|||
$this->startTrans(); |
|||
try { |
|||
// 更新订单状态 |
|||
$this->save([ |
|||
'receipt_status' => 20, |
|||
'receipt_time' => time(), |
|||
'order_status' => 30 |
|||
]); |
|||
// 发放分销商佣金 |
|||
DealerOrderModel::grantMoney($this, OrderTypeEnum::SHARING); |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
$this->rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取订单总数 |
|||
* @param $user_id |
|||
* @param string $type |
|||
* @return int|string |
|||
* @throws \think\Exception |
|||
*/ |
|||
public function getCount($user_id, $type = 'all') |
|||
{ |
|||
// 筛选条件 |
|||
$filter = []; |
|||
// 订单数据类型 |
|||
switch ($type) { |
|||
case 'all': |
|||
break; |
|||
case 'payment'; |
|||
$filter['pay_status'] = PayStatusEnum::PENDING; |
|||
break; |
|||
case 'received'; |
|||
$filter['pay_status'] = PayStatusEnum::SUCCESS; |
|||
$filter['delivery_status'] = 20; |
|||
$filter['receipt_status'] = 10; |
|||
break; |
|||
case 'comment'; |
|||
$filter['order_status'] = 30; |
|||
$filter['is_comment'] = 0; |
|||
break; |
|||
} |
|||
return $this->where('user_id', '=', $user_id) |
|||
->where('order_status', '<>', 20) |
|||
->where($filter) |
|||
->count(); |
|||
} |
|||
|
|||
/** |
|||
* 订单详情 |
|||
* @param $order_id |
|||
* @param $user_id |
|||
* @return array|false|\PDOStatement|string|\think\Model|static |
|||
* @throws BaseException |
|||
*/ |
|||
public static function getUserOrderDetail($order_id, $user_id) |
|||
{ |
|||
$order = (new static)->with(['goods' => ['image', 'refund'], 'address', 'express', 'extract_shop']) |
|||
->alias('order') |
|||
->field('order.*, active.status as active_status') |
|||
->join('sharing_active active', 'order.active_id = active.active_id', 'LEFT') |
|||
->where([ |
|||
'order_id' => $order_id, |
|||
'user_id' => $user_id, |
|||
// 'order_status' => ['<>', 20] |
|||
])->find(); |
|||
if (!$order) { |
|||
throw new BaseException(['msg' => '订单不存在']); |
|||
} |
|||
return $order; |
|||
} |
|||
|
|||
/** |
|||
* 判断商品库存不足 (未付款订单) |
|||
* @param $goodsList |
|||
* @return bool |
|||
*/ |
|||
public function checkGoodsStatusFromOrder(&$goodsList) |
|||
{ |
|||
foreach ($goodsList as $goods) { |
|||
// 判断商品是否下架 |
|||
if (!$goods['goods'] || $goods['goods']['goods_status']['value'] != 10) { |
|||
$this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 已下架'); |
|||
return false; |
|||
} |
|||
// 付款减库存 |
|||
if ($goods['deduct_stock_type'] == 20 && $goods['sku']['stock_num'] < 1) { |
|||
$this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 库存不足'); |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 当前订单是否允许申请售后 |
|||
* @return bool |
|||
*/ |
|||
public function isAllowRefund() |
|||
{ |
|||
// 允许申请售后期限 |
|||
$refund_days = SettingModel::getItem('trade')['order']['refund_days']; |
|||
if ($refund_days == 0) { |
|||
return false; |
|||
} |
|||
if (time() > $this['receipt_time'] + ((int)$refund_days * 86400)) { |
|||
return false; |
|||
} |
|||
if ($this['receipt_status']['value'] != 20) { |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 判断当前订单是否允许核销 |
|||
* @param static $order |
|||
* @return bool |
|||
*/ |
|||
public function checkExtractOrder(&$order) |
|||
{ |
|||
if ( |
|||
$order['pay_status']['value'] == PayStatusEnum::SUCCESS |
|||
&& $order['delivery_type']['value'] == DeliveryTypeEnum::EXTRACT |
|||
&& $order['delivery_status']['value'] == 10 |
|||
// 拼团订单验证拼单状态 |
|||
&& ($order['order_type']['value'] == 20 ? $order['active']['status']['value'] == 20 : true) |
|||
) { |
|||
return true; |
|||
} |
|||
$this->setError('该订单不能被核销'); |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 设置错误信息 |
|||
* @param $error |
|||
*/ |
|||
private function setError($error) |
|||
{ |
|||
empty($this->error) && $this->error = $error; |
|||
} |
|||
|
|||
/** |
|||
* 是否存在错误 |
|||
* @return bool |
|||
*/ |
|||
public function hasError() |
|||
{ |
|||
return !empty($this->error); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\OrderAddress as OrderAddressModel; |
|||
|
|||
/** |
|||
* 拼团订单收货地址模型 |
|||
* Class OrderAddress |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderAddress extends OrderAddressModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\OrderGoods as OrderGoodsModel; |
|||
|
|||
/** |
|||
* 拼团订单商品模型 |
|||
* Class OrderGoods |
|||
* @package app\api\model |
|||
*/ |
|||
class OrderGoods extends OrderGoodsModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'content', |
|||
'wxapp_id', |
|||
'create_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取未评价的商品 |
|||
* @param $order_id |
|||
* @return OrderGoods[]|false |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function getNotCommentGoodsList($order_id) |
|||
{ |
|||
return self::all(['order_id' => $order_id, 'is_comment' => 0], ['orderM', 'image']); |
|||
} |
|||
|
|||
} |
|||
@ -1,171 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\OrderRefund as OrderRefundModel; |
|||
|
|||
/** |
|||
* 售后单模型 |
|||
* Class OrderRefund |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class OrderRefund extends OrderRefundModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 追加字段 |
|||
* @var array |
|||
*/ |
|||
protected $append = [ |
|||
'state_text', // 售后单状态文字描述 |
|||
]; |
|||
|
|||
/** |
|||
* 售后单状态文字描述 |
|||
* @param $value |
|||
* @param $data |
|||
* @return string |
|||
*/ |
|||
public function getStateTextAttr($value, $data) |
|||
{ |
|||
// 已完成 |
|||
if ($data['status'] == 20) { |
|||
$text = [10 => '已同意退货并已退款', 20 => '已同意换货']; |
|||
return $text[$data['type']]; |
|||
} |
|||
// 已取消 |
|||
if ($data['status'] == 30) { |
|||
return '已取消'; |
|||
} |
|||
// 已拒绝 |
|||
if ($data['status'] == 10) { |
|||
// return '已拒绝'; |
|||
return $data['type'] == 10 ? '已拒绝退货退款' : '已拒绝换货'; |
|||
} |
|||
// 进行中 |
|||
if ($data['status'] == 0) { |
|||
if ($data['is_agree'] == 0) { |
|||
return '等待审核中'; |
|||
} |
|||
if ($data['type'] == 10) { |
|||
return $data['is_user_send'] ? '已发货,待平台确认' : '已同意退货,请及时发货'; |
|||
} |
|||
} |
|||
return $value; |
|||
} |
|||
|
|||
/** |
|||
* 获取用户售后单列表 |
|||
* @param $user_id |
|||
* @param int $state |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($user_id, $state = -1) |
|||
{ |
|||
$state > -1 && $this->where('status', '=', $state); |
|||
return $this->with(['order_goods.image']) |
|||
->where('user_id', '=', $user_id) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 用户发货 |
|||
* @param $data |
|||
* @return false|int |
|||
*/ |
|||
public function delivery($data) |
|||
{ |
|||
if ( |
|||
$this['type']['value'] != 10 |
|||
|| $this['is_agree']['value'] != 10 |
|||
|| $this['is_user_send'] != 0 |
|||
) { |
|||
$this->error = '当前售后单不合法,不允许该操作'; |
|||
return false; |
|||
} |
|||
if ($data['express_id'] <= 0) { |
|||
$this->error = '请选择物流公司'; |
|||
return false; |
|||
} |
|||
if (empty($data['express_no'])) { |
|||
$this->error = '请填写物流单号'; |
|||
return false; |
|||
} |
|||
return $this->save([ |
|||
'is_user_send' => 1, |
|||
'send_time' => time(), |
|||
'express_id' => (int)$data['express_id'], |
|||
'express_no' => $data['express_no'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 新增售后单记录 |
|||
* @param $user |
|||
* @param $goods |
|||
* @param $data |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
public function apply($user, $goods, $data) |
|||
{ |
|||
$this->startTrans(); |
|||
try { |
|||
// 新增售后单记录 |
|||
$this->save([ |
|||
'order_goods_id' => $data['order_goods_id'], |
|||
'order_id' => $goods['order_id'], |
|||
'user_id' => $user['user_id'], |
|||
'type' => $data['type'], |
|||
'apply_desc' => $data['content'], |
|||
'is_agree' => 0, |
|||
'status' => 0, |
|||
'wxapp_id' => self::$wxapp_id, |
|||
]); |
|||
// 记录凭证图片关系 |
|||
if (isset($data['images']) && !empty($data['images'])) { |
|||
$this->saveImages($this['order_refund_id'], $data['images']); |
|||
} |
|||
$this->commit(); |
|||
return true; |
|||
} catch (\Exception $e) { |
|||
$this->error = $e->getMessage(); |
|||
$this->rollback(); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 记录售后单图片 |
|||
* @param $order_refund_id |
|||
* @param $images |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
private function saveImages($order_refund_id, $images) |
|||
{ |
|||
// 生成评价图片数据 |
|||
$data = []; |
|||
foreach (explode(',', $images) as $image_id) { |
|||
$data[] = [ |
|||
'order_refund_id' => $order_refund_id, |
|||
'image_id' => $image_id, |
|||
'wxapp_id' => self::$wxapp_id |
|||
]; |
|||
} |
|||
return !empty($data) && (new OrderRefundImage)->saveAll($data); |
|||
} |
|||
|
|||
} |
|||
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\OrderRefundAddress as OrderRefundAddressModel; |
|||
|
|||
/** |
|||
* 售后单退货地址模型 |
|||
* Class OrderRefundAddress |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class OrderRefundAddress extends OrderRefundAddressModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
'create_time' |
|||
]; |
|||
|
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\common\model\sharing\OrderRefundImage as OrderRefundImageModel; |
|||
|
|||
/** |
|||
* 售后单图片模型 |
|||
* Class OrderRefundImage |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class OrderRefundImage extends OrderRefundImageModel |
|||
{ |
|||
|
|||
} |
|||
@ -1,38 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\sharing; |
|||
|
|||
use app\api\model\Setting as SettingModel; |
|||
use app\common\model\sharing\Setting as SharingSettingModel; |
|||
|
|||
/** |
|||
* 拼团设置模型 |
|||
* Class Setting |
|||
* @package app\api\model\sharing |
|||
*/ |
|||
class Setting extends SharingSettingModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'update_time', |
|||
]; |
|||
|
|||
public static function getSetting() |
|||
{ |
|||
// 订阅消息 |
|||
$submsgList = []; |
|||
foreach (SettingModel::getItem('submsg')['sharing'] as $key => $item) { |
|||
$submsgList[$key] = $item['template_id']; |
|||
} |
|||
return [ |
|||
// 基础设置 |
|||
'basic' => static::getItem('basic'), |
|||
// 订阅消息 |
|||
'order_submsg' => $submsgList, |
|||
]; |
|||
} |
|||
|
|||
} |
|||
@ -1,131 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\store; |
|||
|
|||
use app\common\model\store\Shop as ShopModel; |
|||
|
|||
/** |
|||
* 商家门店模型 |
|||
* Class Shop |
|||
* @package app\store\model\store |
|||
*/ |
|||
class Shop extends ShopModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 获取门店列表 |
|||
* @param null $is_check |
|||
* @param string $longitude |
|||
* @param string $latitude |
|||
* @param bool $limit |
|||
* @return array|false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($is_check = null, $longitude = '', $latitude = '', $limit = false) |
|||
{ |
|||
// 是否支持自提核销 |
|||
$is_check && $this->where('is_check', '=', $is_check); |
|||
// 获取数量 |
|||
$limit != false && $this->limit($limit); |
|||
// 获取门店列表数据 |
|||
$data = $this->where('is_delete', '=', '0') |
|||
->where('status', '=', '1') |
|||
->order(['sort' => 'asc', 'create_time' => 'desc']) |
|||
->select(); |
|||
// 根据距离排序 |
|||
if (!empty($longitude) && !empty($latitude)) { |
|||
return $this->sortByDistance($data, $longitude, $latitude); |
|||
} |
|||
return $data; |
|||
} |
|||
|
|||
/** |
|||
* 根据距离排序 |
|||
* @param string $longitude |
|||
* @param string $latitude |
|||
* @param \think\Collection|false|\PDOStatement|string $data |
|||
* @return array |
|||
* @throws |
|||
*/ |
|||
private function sortByDistance(&$data, $longitude, $latitude) |
|||
{ |
|||
// 根据距离排序 |
|||
$list = $data->isEmpty() ? [] : $data->toArray(); |
|||
$sortArr = []; |
|||
foreach ($list as &$shop) { |
|||
// 计算距离 |
|||
$distance = self::getDistance($longitude, $latitude, $shop['longitude'], $shop['latitude']); |
|||
// 排序列 |
|||
$sortArr[] = $distance; |
|||
$shop['distance'] = $distance; |
|||
if ($distance >= 1000) { |
|||
$distance = bcdiv($distance, 1000, 2); |
|||
$shop['distance_unit'] = $distance . 'km'; |
|||
} else |
|||
$shop['distance_unit'] = $distance . 'm'; |
|||
} |
|||
// 根据距离排序 |
|||
array_multisort($sortArr, SORT_ASC, $list); |
|||
return $list; |
|||
} |
|||
|
|||
/** |
|||
* 获取两个坐标点的距离 |
|||
* @param $ulon |
|||
* @param $ulat |
|||
* @param $slon |
|||
* @param $slat |
|||
* @return float |
|||
*/ |
|||
private static function getDistance($ulon, $ulat, $slon, $slat) |
|||
{ |
|||
// 地球半径 |
|||
$R = 6378137; |
|||
// 将角度转为狐度 |
|||
$radLat1 = deg2rad($ulat); |
|||
$radLat2 = deg2rad($slat); |
|||
$radLng1 = deg2rad($ulon); |
|||
$radLng2 = deg2rad($slon); |
|||
// 结果 |
|||
$s = acos(cos($radLat1) * cos($radLat2) * cos($radLng1 - $radLng2) + sin($radLat1) * sin($radLat2)) * $R; |
|||
// 精度 |
|||
$s = round($s * 10000) / 10000; |
|||
return round($s); |
|||
} |
|||
|
|||
/** |
|||
* 根据门店id集获取门店列表 |
|||
* @param $shopIds |
|||
* @return false|\PDOStatement|string|\think\Collection |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getListByIds($shopIds) |
|||
{ |
|||
// 筛选条件 |
|||
$filter = ['shop_id' => ['in', $shopIds]]; |
|||
if (!empty($shopIds)) { |
|||
$this->orderRaw('field(shop_id, ' . implode(',', $shopIds) . ')'); |
|||
} |
|||
// 获取商品列表数据 |
|||
return $this->with(['logo']) |
|||
->where('is_delete', '=', '0') |
|||
->where('status', '=', '1') |
|||
->where($filter) |
|||
->select(); |
|||
} |
|||
|
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\store\shop; |
|||
|
|||
use app\common\exception\BaseException; |
|||
use app\common\model\store\shop\Clerk as ClerkModel; |
|||
|
|||
/** |
|||
* 商家门店店员模型 |
|||
* Class Clerk |
|||
* @package app\api\model\store\shop |
|||
*/ |
|||
class Clerk extends ClerkModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time' |
|||
]; |
|||
|
|||
/** |
|||
* 店员详情 |
|||
* @param $where |
|||
* @return static |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function detail($where) |
|||
{ |
|||
/* @var static $model */ |
|||
$model = parent::detail($where); |
|||
if (!$model) { |
|||
throw new BaseException(['msg' => '未找到店员信息']); |
|||
} |
|||
return $model; |
|||
} |
|||
|
|||
/** |
|||
* 验证用户是否为核销员 |
|||
* @param $shop_id |
|||
* @return bool |
|||
*/ |
|||
public function checkUser($shop_id) |
|||
{ |
|||
if ($this['is_delete']) { |
|||
$this->error = '未找到店员信息'; |
|||
return false; |
|||
} |
|||
if ($this['shop_id'] != $shop_id) { |
|||
$this->error = '当前店员不属于该门店,没有核销权限'; |
|||
return false; |
|||
} |
|||
if (!$this['status']) { |
|||
$this->error = '当前店员状态已被禁用'; |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\store\shop; |
|||
|
|||
use app\common\model\store\shop\ClerkRel as ClerkRelModel; |
|||
|
|||
/** |
|||
* 门店店员关系记录模型 |
|||
* Class Clerk |
|||
* @package app\api\model\store\shop |
|||
*/ |
|||
class ClerkRel extends ClerkRelModel |
|||
{ |
|||
|
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\store\shop; |
|||
|
|||
use app\common\model\store\shop\Order as OrderModel; |
|||
|
|||
/** |
|||
* 商家门店核销订单记录模型 |
|||
* Class Order |
|||
* @package app\api\model\store\shop |
|||
*/ |
|||
class Order extends OrderModel |
|||
{ |
|||
|
|||
} |
|||
@ -1,38 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\user; |
|||
|
|||
use app\common\model\user\BalanceLog as BalanceLogModel; |
|||
|
|||
/** |
|||
* 用户余额变动明细模型 |
|||
* Class BalanceLog |
|||
* @package app\api\model\user |
|||
*/ |
|||
class BalanceLog extends BalanceLogModel |
|||
{ |
|||
/** |
|||
* 隐藏字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'wxapp_id', |
|||
]; |
|||
|
|||
/** |
|||
* 获取账单明细列表 |
|||
* @param $userId |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList($userId) |
|||
{ |
|||
// 获取列表数据 |
|||
return $this->where('user_id', '=', $userId) |
|||
->order(['create_time' => 'desc']) |
|||
->paginate(15, false, [ |
|||
'query' => request()->request() |
|||
]); |
|||
} |
|||
|
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\wxapp; |
|||
|
|||
use app\common\model\wxapp\Formid as FormidModel; |
|||
|
|||
/** |
|||
* form_id 模型 |
|||
* Class Formid |
|||
* @package app\api\model\wxapp |
|||
*/ |
|||
class Formid extends FormidModel |
|||
{ |
|||
/** |
|||
* 新增form_id |
|||
* @param $user_id |
|||
* @param $form_id |
|||
* @return false|int |
|||
*/ |
|||
public static function add($user_id, $form_id) |
|||
{ |
|||
$model = new self; |
|||
return $model->save([ |
|||
'user_id' => $user_id, |
|||
'form_id' => $form_id, |
|||
'expiry_time' => time() + (7 * 86400) - 10, |
|||
'wxapp_id' => self::$wxapp_id |
|||
]); |
|||
} |
|||
} |
|||
@ -1,77 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\model\wxapp; |
|||
|
|||
use app\common\model\wxapp\LiveRoom as LiveRoomModel; |
|||
use app\common\enum\live\LiveStatus as LiveStatusEnum; |
|||
|
|||
/** |
|||
* 微信小程序直播间模型 |
|||
* Class LiveRoom |
|||
* @package app\api\model\wxapp |
|||
*/ |
|||
class LiveRoom extends LiveRoomModel |
|||
{ |
|||
/** |
|||
* 隐藏的字段 |
|||
* @var array |
|||
*/ |
|||
protected $hidden = [ |
|||
'is_delete', |
|||
'wxapp_id', |
|||
'create_time', |
|||
'update_time', |
|||
]; |
|||
|
|||
/** |
|||
* 获取直播间列表 |
|||
* @return \think\Paginator |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function getList() |
|||
{ |
|||
// 直播间列表 |
|||
// mix: 可设置live_status条件来显示不同直播状态的房间 |
|||
$this->where('live_status', '<>', 107); // 已过期的不显示 |
|||
$list = $this->where('is_delete', '=', 0) |
|||
->order([ |
|||
'is_top' => 'desc', |
|||
'live_status' => 'asc', |
|||
'create_time' => 'desc' |
|||
])->paginate(15, false, [ |
|||
'query' => \request()->request() |
|||
]); |
|||
// 整理api数据 |
|||
foreach ($list as &$item) { |
|||
$item['live_status_text_1'] = LiveStatusEnum::data()[$item['live_status']]['name']; |
|||
$item['live_status_text_2'] = $item['live_status_text_1']; |
|||
$item['live_status'] == 101 && $item['live_status_text_1'] = '正在直播中'; |
|||
$item['live_status'] == 102 && $item['live_status_text_1'] = $this->semanticStartTime($item->getData('start_time')) . ' 开播'; |
|||
} |
|||
return $list; |
|||
} |
|||
|
|||
/** |
|||
* 语义化开播时间 |
|||
* @param $startTime |
|||
* @return string |
|||
*/ |
|||
private function semanticStartTime($startTime) |
|||
{ |
|||
// 转换为 YYYYMMDD 格式 |
|||
$startDate = date('Ymd', $startTime); |
|||
// 获取今天的 YYYY-MM-DD 格式 |
|||
$todyDate = date('Ymd'); |
|||
// 获取明天的 YYYY-MM-DD 格式 |
|||
$tomorrowDate = date('Ymd', strtotime('+1 day')); |
|||
// 使用IF当作字符串判断是否相等 |
|||
if ($startDate == $todyDate) { |
|||
return date('今天H:i', $startTime); |
|||
} elseif ($startDate == $tomorrowDate) { |
|||
return date('明天H:i', $startTime); |
|||
} |
|||
// 常规日期格式 |
|||
return date('m/d H:i', $startTime); |
|||
} |
|||
|
|||
} |
|||
@ -1,66 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\service; |
|||
|
|||
use app\api\model\Wxapp as WxappModel; |
|||
//use app\api\model\WxappPrepayId as WxappPrepayIdModel; |
|||
|
|||
use app\common\library\wechat\WxPay; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
|
|||
class Payment |
|||
{ |
|||
/** |
|||
* 构建订单支付参数 |
|||
* @param $user |
|||
* @param $order |
|||
* @param $payType |
|||
* @return array |
|||
* @throws \app\common\exception\BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function orderPayment($user, $order, $payType) |
|||
{ |
|||
if ($payType == PayTypeEnum::WECHAT) { |
|||
return self::wechat( |
|||
$user, |
|||
$order['order_id'], |
|||
$order['order_no'], |
|||
$order['pay_price'], |
|||
OrderTypeEnum::MASTER |
|||
); |
|||
} |
|||
return []; |
|||
} |
|||
|
|||
/** |
|||
* 构建微信支付 |
|||
* @param \app\api\model\User $user |
|||
* @param $orderId |
|||
* @param $orderNo |
|||
* @param $payPrice |
|||
* @param int $orderType |
|||
* @return array |
|||
* @throws \app\common\exception\BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public static function wechat( |
|||
$user, |
|||
$orderId, |
|||
$orderNo, |
|||
$payPrice, |
|||
$orderType = OrderTypeEnum::MASTER |
|||
) |
|||
{ |
|||
// 统一下单API |
|||
$wxConfig = WxappModel::getWxappCache($user['wxapp_id']); |
|||
$WxPay = new WxPay($wxConfig); |
|||
$payment = $WxPay->unifiedorder($orderNo, $user['open_id'], $payPrice, $orderType); |
|||
// // 记录prepay_id |
|||
// $model = new WxappPrepayIdModel; |
|||
// $model->add($payment['prepay_id'], $orderId, $user['user_id'], $orderType); |
|||
return $payment; |
|||
} |
|||
|
|||
} |
|||
@ -1,874 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\service\order; |
|||
|
|||
use app\api\model\Order as OrderModel; |
|||
|
|||
use app\api\model\User as UserModel; |
|||
use app\api\model\Goods as GoodsModel; |
|||
use app\api\model\Setting as SettingModel; |
|||
use app\api\model\store\Shop as ShopModel; |
|||
use app\api\model\UserCoupon as UserCouponModel; |
|||
use app\api\model\dealer\Order as DealerOrderModel; |
|||
|
|||
use app\api\service\User as UserService; |
|||
use app\api\service\Payment as PaymentService; |
|||
use app\api\service\coupon\GoodsDeduct as GoodsDeductService; |
|||
use app\api\service\points\GoodsDeduct as PointsDeductService; |
|||
use app\api\service\order\source\checkout\Factory as CheckoutFactory; |
|||
|
|||
use app\common\library\helper; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\DeliveryType as DeliveryTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\service\goods\source\Factory as StockFactory; |
|||
use app\common\enum\order\OrderSource as OrderSourceEnum; |
|||
use app\common\service\delivery\Express as ExpressService; |
|||
use app\common\exception\BaseException; |
|||
|
|||
/** |
|||
* 订单结算台服务类 |
|||
* Class Checkout |
|||
* @package app\api\service\order |
|||
*/ |
|||
class Checkout |
|||
{ |
|||
/* $model OrderModel 订单模型 */ |
|||
public $model; |
|||
|
|||
// 当前小程序id |
|||
private $wxapp_id; |
|||
|
|||
/* @var UserModel $user 当前用户信息 */ |
|||
private $user; |
|||
|
|||
// 订单结算商品列表 |
|||
private $goodsList = []; |
|||
|
|||
// 错误信息 |
|||
protected $error; |
|||
|
|||
/** |
|||
* 订单结算api参数 |
|||
* @var array |
|||
*/ |
|||
private $param = [ |
|||
'delivery' => null, // 配送方式 |
|||
'shop_id' => 0, // 自提门店id |
|||
'linkman' => '', // 自提联系人 |
|||
'phone' => '', // 自提联系电话 |
|||
'coupon_id' => 0, // 优惠券id |
|||
'is_use_points' => 0, // 是否使用积分抵扣 |
|||
'remark' => '', // 买家留言 |
|||
'pay_type' => PayTypeEnum::WECHAT, // 支付方式 |
|||
]; |
|||
|
|||
/** |
|||
* 订单结算的规则 |
|||
* @var array |
|||
*/ |
|||
private $checkoutRule = [ |
|||
'is_user_grade' => true, // 会员等级折扣 |
|||
'is_coupon' => true, // 优惠券抵扣 |
|||
'is_use_points' => true, // 是否使用积分抵扣 |
|||
'is_dealer' => true, // 是否开启分销 |
|||
]; |
|||
|
|||
/** |
|||
* 订单来源 |
|||
* @var array |
|||
*/ |
|||
private $orderSource = [ |
|||
'source' => OrderSourceEnum::MASTER, |
|||
'source_id' => 0, |
|||
]; |
|||
|
|||
/** |
|||
* 订单结算数据 |
|||
* @var array |
|||
*/ |
|||
private $orderData = []; |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* Checkout constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
$this->model = new OrderModel; |
|||
$this->wxapp_id = OrderModel::$wxapp_id; |
|||
} |
|||
|
|||
/** |
|||
* 设置结算台请求的参数 |
|||
* @param $param |
|||
* @return array |
|||
*/ |
|||
public function setParam($param) |
|||
{ |
|||
$this->param = array_merge($this->param, $param); |
|||
return $this->getParam(); |
|||
} |
|||
|
|||
/** |
|||
* 获取结算台请求的参数 |
|||
* @return array |
|||
*/ |
|||
public function getParam() |
|||
{ |
|||
return $this->param; |
|||
} |
|||
|
|||
/** |
|||
* 订单结算的规则 |
|||
* @param $data |
|||
* @return $this |
|||
*/ |
|||
public function setCheckoutRule($data) |
|||
{ |
|||
$this->checkoutRule = array_merge($this->checkoutRule, $data); |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单来源(普通订单、砍价订单、秒杀订单) |
|||
* @param $data |
|||
* @return $this |
|||
*/ |
|||
public function setOrderSource($data) |
|||
{ |
|||
$this->orderSource = array_merge($this->orderSource, $data); |
|||
return $this; |
|||
} |
|||
|
|||
/** |
|||
* 订单确认-结算台 |
|||
* @param $user |
|||
* @param $goodsList |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function onCheckout($user, $goodsList) |
|||
{ |
|||
$this->user = $user; |
|||
$this->goodsList = $goodsList; |
|||
// 订单确认-立即购买 |
|||
return $this->checkout(); |
|||
} |
|||
|
|||
/** |
|||
* 订单结算台 |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function checkout() |
|||
{ |
|||
// 整理订单数据 |
|||
$this->orderData = $this->getOrderData(); |
|||
// 验证商品状态, 是否允许购买 |
|||
$this->validateGoodsList(); |
|||
// 订单商品总数量 |
|||
$orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num'); |
|||
// 设置订单商品会员折扣价 |
|||
$this->setOrderGoodsGradeMoney(); |
|||
// 设置订单商品总金额(不含优惠折扣) |
|||
$this->setOrderTotalPrice(); |
|||
// 当前用户可用的优惠券列表 |
|||
$couponList = $this->getUserCouponList($this->orderData['order_total_price']); |
|||
// 计算优惠券抵扣 |
|||
$this->setOrderCouponMoney($couponList, $this->param['coupon_id']); |
|||
// 计算可用积分抵扣 |
|||
$this->setOrderPoints(); |
|||
// 计算订单商品的实际付款金额 |
|||
$this->setOrderGoodsPayPrice(); |
|||
// 设置默认配送方式 |
|||
!$this->param['delivery'] && $this->param['delivery'] = current(SettingModel::getItem('store')['delivery_type']); |
|||
// 处理配送方式 |
|||
if ($this->param['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$this->setOrderExpress(); |
|||
} elseif ($this->param['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
$this->param['shop_id'] > 0 && $this->orderData['extract_shop'] = ShopModel::detail($this->param['shop_id']); |
|||
} |
|||
// 计算订单最终金额 |
|||
$this->setOrderPayPrice(); |
|||
// 计算订单积分赠送数量 |
|||
$this->setOrderPointsBonus(); |
|||
// 返回订单数据 |
|||
return array_merge([ |
|||
'goods_list' => array_values($this->goodsList), // 商品信息 |
|||
'order_total_num' => $orderTotalNum, // 商品总数量 |
|||
'coupon_list' => array_values($couponList), // 优惠券列表 |
|||
'has_error' => $this->hasError(), |
|||
'error_msg' => $this->getError(), |
|||
], $this->orderData); |
|||
} |
|||
|
|||
/** |
|||
* 计算订单可用积分抵扣 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderPoints() |
|||
{ |
|||
// 设置默认的商品积分抵扣信息 |
|||
$this->setDefaultGoodsPoints(); |
|||
// 积分设置 |
|||
$setting = SettingModel::getItem('points'); |
|||
// 条件:后台开启下单使用积分抵扣 |
|||
if (!$setting['is_shopping_discount'] || !$this->checkoutRule['is_use_points']) { |
|||
return false; |
|||
} |
|||
// 条件:订单金额满足[?]元 |
|||
if (helper::bccomp($setting['discount']['full_order_price'], $this->orderData['order_total_price']) === 1) { |
|||
return false; |
|||
} |
|||
// 计算订单商品最多可抵扣的积分数量 |
|||
$this->setOrderGoodsMaxPointsNum(); |
|||
// 订单最多可抵扣的积分总数量 |
|||
$maxPointsNumCount = helper::getArrayColumnSum($this->goodsList, 'max_points_num'); |
|||
// 实际可抵扣的积分数量 |
|||
$actualPointsNum = min($maxPointsNumCount, $this->user['points']); |
|||
if ($actualPointsNum < 1) { |
|||
return false; |
|||
} |
|||
// 计算订单商品实际抵扣的积分数量和金额 |
|||
$GoodsDeduct = new PointsDeductService($this->goodsList); |
|||
$GoodsDeduct->setGoodsPoints($maxPointsNumCount, $actualPointsNum); |
|||
// 积分抵扣总金额 |
|||
$orderPointsMoney = helper::getArrayColumnSum($this->goodsList, 'points_money'); |
|||
$this->orderData['points_money'] = helper::number2($orderPointsMoney); |
|||
// 积分抵扣总数量 |
|||
$this->orderData['points_num'] = $actualPointsNum; |
|||
// 允许积分抵扣 |
|||
$this->orderData['is_allow_points'] = true; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 计算订单商品最多可抵扣的积分数量 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderGoodsMaxPointsNum() |
|||
{ |
|||
// 积分设置 |
|||
$setting = SettingModel::getItem('points'); |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 商品不允许积分抵扣 |
|||
if (!$goods['is_points_discount']) continue; |
|||
// 积分抵扣比例 |
|||
$deductionRatio = helper::bcdiv($setting['discount']['max_money_ratio'], 100); |
|||
// 最多可抵扣的金额 |
|||
// !!!: 此处应该是优惠券打折后的价格 |
|||
// bug: $totalPayPrice = $goods['total_price']; |
|||
$totalPayPrice = helper::bcsub($goods['total_price'], $goods['coupon_money']); |
|||
$maxPointsMoney = helper::bcmul($totalPayPrice, $deductionRatio); |
|||
// 最多可抵扣的积分数量 |
|||
$goods['max_points_num'] = helper::bcdiv($maxPointsMoney, $setting['discount']['discount_ratio'], 0); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置默认的商品积分抵扣信息 |
|||
* @return bool |
|||
*/ |
|||
private function setDefaultGoodsPoints() |
|||
{ |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 最多可抵扣的积分数量 |
|||
$goods['max_points_num'] = 0; |
|||
// 实际抵扣的积分数量 |
|||
$goods['points_num'] = 0; |
|||
// 实际抵扣的金额 |
|||
$goods['points_money'] = 0.00; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 整理订单数据(结算台初始化) |
|||
* @return array |
|||
*/ |
|||
private function getOrderData() |
|||
{ |
|||
// 系统支持的配送方式 (后台设置) |
|||
$deliveryType = SettingModel::getItem('store')['delivery_type']; |
|||
return [ |
|||
// 配送类型 |
|||
'delivery' => $this->param['delivery'] > 0 ? $this->param['delivery'] : $deliveryType[0], |
|||
// 默认地址 |
|||
'address' => $this->user['address_default'], |
|||
// 是否存在收货地址 |
|||
'exist_address' => $this->user['address_id'] > 0, |
|||
// 配送费用 |
|||
'express_price' => 0.00, |
|||
// 当前用户收货城市是否存在配送规则中 |
|||
'intra_region' => true, |
|||
// 自提门店信息 |
|||
'extract_shop' => [], |
|||
// 是否允许使用积分抵扣 |
|||
'is_allow_points' => false, |
|||
// 是否使用积分抵扣 |
|||
'is_use_points' => $this->param['is_use_points'], |
|||
// 积分抵扣金额 |
|||
'points_money' => 0.00, |
|||
// 赠送的积分数量 |
|||
'points_bonus' => 0, |
|||
// 支付方式 |
|||
'pay_type' => $this->param['pay_type'], |
|||
// 系统设置 |
|||
'setting' => $this->getSetting(), |
|||
// 记忆的自提联系方式 |
|||
'last_extract' => UserService::getLastExtract($this->user['user_id']), |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* 获取订单页面中使用到的系统设置 |
|||
* @return array |
|||
*/ |
|||
private function getSetting() |
|||
{ |
|||
// 系统支持的配送方式 (后台设置) |
|||
$deliveryType = SettingModel::getItem('store')['delivery_type']; |
|||
// 积分设置 |
|||
$pointsSetting = SettingModel::getItem('points'); |
|||
// 订阅消息 |
|||
$orderSubMsgList = []; |
|||
foreach (SettingModel::getItem('submsg')['order'] as $item) { |
|||
!empty($item['template_id']) && $orderSubMsgList[] = $item['template_id']; |
|||
} |
|||
return [ |
|||
'delivery' => $deliveryType, // 支持的配送方式 |
|||
'points_name' => $pointsSetting['points_name'], // 积分名称 |
|||
'points_describe' => $pointsSetting['describe'], // 积分说明 |
|||
'order_submsg' => $orderSubMsgList, // 订阅消息 |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* 当前用户可用的优惠券列表 |
|||
* @param $orderTotalPrice |
|||
* @return mixed |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getUserCouponList($orderTotalPrice) |
|||
{ |
|||
// 是否开启优惠券折扣 |
|||
if (!$this->checkoutRule['is_coupon']) { |
|||
return []; |
|||
} |
|||
return UserCouponModel::getUserCouponList($this->user['user_id'], $orderTotalPrice); |
|||
} |
|||
|
|||
/** |
|||
* 验证订单商品的状态 |
|||
* @return bool |
|||
*/ |
|||
private function validateGoodsList() |
|||
{ |
|||
$Checkout = CheckoutFactory::getFactory( |
|||
$this->user, |
|||
$this->goodsList, |
|||
$this->orderSource['source'] |
|||
); |
|||
$status = $Checkout->validateGoodsList(); |
|||
$status == false && $this->setError($Checkout->getError()); |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单的商品总金额(不含优惠折扣) |
|||
*/ |
|||
private function setOrderTotalPrice() |
|||
{ |
|||
// 订单商品的总金额(不含优惠券折扣) |
|||
$this->orderData['order_total_price'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_price')); |
|||
} |
|||
|
|||
/** |
|||
* 设置订单的实际支付金额(含配送费) |
|||
*/ |
|||
private function setOrderPayPrice() |
|||
{ |
|||
// 订单金额(含优惠折扣) |
|||
$this->orderData['order_price'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_pay_price')); |
|||
// 订单实付款金额(订单金额 + 运费) |
|||
$this->orderData['order_pay_price'] = helper::number2(helper::bcadd($this->orderData['order_price'], $this->orderData['express_price'])); |
|||
} |
|||
|
|||
/** |
|||
* 计算订单积分赠送数量 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderPointsBonus() |
|||
{ |
|||
// 初始化商品积分赠送数量 |
|||
foreach ($this->goodsList as &$goods) { |
|||
$goods['points_bonus'] = 0; |
|||
} |
|||
// 积分设置 |
|||
$setting = SettingModel::getItem('points'); |
|||
// 条件:后台开启开启购物送积分 |
|||
if (!$setting['is_shopping_gift']) { |
|||
return false; |
|||
} |
|||
// 设置商品积分赠送数量 |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 积分赠送比例 |
|||
$ratio = $setting['gift_ratio'] / 100; |
|||
// 计算抵扣积分数量 |
|||
$goods['points_bonus'] = !$goods['is_points_gift'] ? 0 : helper::bcmul($goods['total_pay_price'], $ratio, 0); |
|||
} |
|||
// 订单积分赠送数量 |
|||
$this->orderData['points_bonus'] = helper::getArrayColumnSum($this->goodsList, 'points_bonus'); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 计算订单商品的实际付款金额 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderGoodsPayPrice() |
|||
{ |
|||
// 商品总价 - 优惠抵扣 |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 减去优惠券抵扣金额 |
|||
$value = helper::bcsub($goods['total_price'], $goods['coupon_money']); |
|||
// 减去积分抵扣金额 |
|||
if ($this->orderData['is_allow_points'] && $this->orderData['is_use_points']) { |
|||
$value = helper::bcsub($value, $goods['points_money']); |
|||
} |
|||
$goods['total_pay_price'] = helper::number2($value); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单商品会员折扣价 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderGoodsGradeMoney() |
|||
{ |
|||
// 设置默认数据 |
|||
helper::setDataAttribute($this->goodsList, [ |
|||
// 标记参与会员折扣 |
|||
'is_user_grade' => false, |
|||
// 会员等级抵扣的金额 |
|||
'grade_ratio' => 0, |
|||
// 会员折扣的商品单价 |
|||
'grade_goods_price' => 0.00, |
|||
// 会员折扣的总额差 |
|||
'grade_total_money' => 0.00, |
|||
], true); |
|||
|
|||
// 是否开启会员等级折扣 |
|||
if (!$this->checkoutRule['is_user_grade']) { |
|||
return false; |
|||
} |
|||
// 会员等级状态 |
|||
if (!( |
|||
$this->user['grade_id'] > 0 && !empty($this->user['grade']) |
|||
&& !$this->user['grade']['is_delete'] && $this->user['grade']['status'] |
|||
)) { |
|||
return false; |
|||
} |
|||
// 计算抵扣金额 |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 判断商品是否参与会员折扣 |
|||
if (!$goods['is_enable_grade']) { |
|||
continue; |
|||
} |
|||
// 商品单独设置了会员折扣 |
|||
if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$this->user['grade_id']])) { |
|||
// 折扣比例 |
|||
$discountRatio = helper::bcdiv($goods['alone_grade_equity'][$this->user['grade_id']], 10); |
|||
} else { |
|||
// 折扣比例 |
|||
$discountRatio = helper::bcdiv($this->user['grade']['equity']['discount'], 10); |
|||
} |
|||
if ($discountRatio > 0) { |
|||
// 会员折扣后的商品总金额 |
|||
$gradeTotalPrice = max(0.01, helper::bcmul($goods['total_price'], $discountRatio)); |
|||
helper::setDataAttribute($goods, [ |
|||
'is_user_grade' => true, |
|||
'grade_ratio' => $discountRatio, |
|||
'grade_goods_price' => helper::number2(helper::bcmul($goods['goods_price'], $discountRatio), true), |
|||
'grade_total_money' => helper::number2(helper::bcsub($goods['total_price'], $gradeTotalPrice)), |
|||
'total_price' => $gradeTotalPrice, |
|||
], false); |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单优惠券抵扣信息 |
|||
* @param array $couponList 当前用户可用的优惠券列表 |
|||
* @param int $couponId 当前选择的优惠券id |
|||
* @return bool |
|||
* @throws BaseException |
|||
*/ |
|||
private function setOrderCouponMoney($couponList, $couponId) |
|||
{ |
|||
// 设置默认数据:订单信息 |
|||
helper::setDataAttribute($this->orderData, [ |
|||
'coupon_id' => 0, // 用户优惠券id |
|||
'coupon_money' => 0, // 优惠券抵扣金额 |
|||
], false); |
|||
// 设置默认数据:订单商品列表 |
|||
helper::setDataAttribute($this->goodsList, [ |
|||
'coupon_money' => 0, // 优惠券抵扣金额 |
|||
], true); |
|||
// 是否开启优惠券折扣 |
|||
if (!$this->checkoutRule['is_coupon']) { |
|||
return false; |
|||
} |
|||
// 如果没有可用的优惠券,直接返回 |
|||
if ($couponId <= 0 || empty($couponList)) { |
|||
return true; |
|||
} |
|||
// 获取优惠券信息 |
|||
$couponInfo = helper::getArrayItemByColumn($couponList, 'user_coupon_id', $couponId); |
|||
if ($couponInfo == false) { |
|||
throw new BaseException(['msg' => '未找到优惠券信息']); |
|||
} |
|||
// 计算订单商品优惠券抵扣金额 |
|||
$goodsListTemp = helper::getArrayColumns($this->goodsList, ['total_price']); |
|||
$CouponMoney = new GoodsDeductService; |
|||
$completed = $CouponMoney->setGoodsCouponMoney($goodsListTemp, $couponInfo['reduced_price']); |
|||
// 分配订单商品优惠券抵扣金额 |
|||
foreach ($this->goodsList as $key => &$goods) { |
|||
$goods['coupon_money'] = $completed[$key]['coupon_money'] / 100; |
|||
} |
|||
// 记录订单优惠券信息 |
|||
$this->orderData['coupon_id'] = $couponId; |
|||
$this->orderData['coupon_money'] = helper::number2($CouponMoney->getActualReducedMoney() / 100); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 订单配送-快递配送 |
|||
* @return bool |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function setOrderExpress() |
|||
{ |
|||
// 设置默认数据:配送费用 |
|||
helper::setDataAttribute($this->goodsList, [ |
|||
'express_price' => 0, |
|||
], true); |
|||
// 当前用户收货城市id |
|||
$cityId = $this->user['address_default'] ? $this->user['address_default']['city_id'] : null; |
|||
// 初始化配送服务类 |
|||
$ExpressService = new ExpressService($cityId, $this->goodsList, OrderTypeEnum::MASTER); |
|||
// 验证商品是否在配送范围 |
|||
$isIntraRegion = $ExpressService->isIntraRegion(); |
|||
if ($cityId > 0 && $isIntraRegion == false) { |
|||
$notInRuleGoodsName = $ExpressService->getNotInRuleGoodsName(); |
|||
$this->setError("很抱歉,您的收货地址不在商品 [{$notInRuleGoodsName}] 的配送范围内"); |
|||
} |
|||
// 订单总运费金额 |
|||
$this->orderData['intra_region'] = $isIntraRegion; |
|||
$this->orderData['express_price'] = $ExpressService->getDeliveryFee(); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 创建新订单 |
|||
* @param array $order 订单信息 |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
public function createOrder($order) |
|||
{ |
|||
// 表单验证 |
|||
if (!$this->validateOrderForm($order, $this->param['linkman'], $this->param['phone'])) { |
|||
return false; |
|||
} |
|||
// 创建新的订单 |
|||
$status = $this->model->transaction(function () use ($order) { |
|||
// 创建订单事件 |
|||
return $this->createOrderEvent($order); |
|||
}); |
|||
// 余额支付标记订单已支付 |
|||
if ($status && $order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
return $this->model->onPaymentByBalance($this->model['order_no']); |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 创建订单事件 |
|||
* @param $order |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
* @throws \Exception |
|||
*/ |
|||
private function createOrderEvent($order) |
|||
{ |
|||
// 新增订单记录 |
|||
$status = $this->add($order, $this->param['remark']); |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
// 记录收货地址 |
|||
$this->saveOrderAddress($order['address']); |
|||
} elseif ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
// 记录自提信息 |
|||
$this->saveOrderExtract($this->param['linkman'], $this->param['phone']); |
|||
} |
|||
// 保存订单商品信息 |
|||
$this->saveOrderGoods($order); |
|||
// 更新商品库存 (针对下单减库存的商品) |
|||
$this->updateGoodsStockNum($order); |
|||
// 设置优惠券使用状态 |
|||
UserCouponModel::setIsUse($this->param['coupon_id']); |
|||
// 积分抵扣情况下扣除用户积分 |
|||
if ($order['is_allow_points'] && $order['is_use_points'] && $order['points_num'] > 0) { |
|||
$describe = "用户消费:{$this->model['order_no']}"; |
|||
$this->user->setIncPoints(-$order['points_num'], $describe); |
|||
} |
|||
// 获取订单详情 |
|||
$detail = OrderModel::getUserOrderDetail($this->model['order_id'], $this->user['user_id']); |
|||
// 记录分销商订单 |
|||
$this->checkoutRule['is_dealer'] && DealerOrderModel::createOrder($detail); |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 构建支付请求的参数 |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function onOrderPayment() |
|||
{ |
|||
return PaymentService::orderPayment($this->user, $this->model, $this->param['pay_type']); |
|||
} |
|||
|
|||
/** |
|||
* 表单验证 (订单提交) |
|||
* @param array $order 订单信息 |
|||
* @param string $linkman 联系人 |
|||
* @param string $phone 联系电话 |
|||
* @return bool |
|||
*/ |
|||
private function validateOrderForm(&$order, $linkman, $phone) |
|||
{ |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
if (empty($order['address'])) { |
|||
$this->error = '您还没有选择配送地址'; |
|||
return false; |
|||
} |
|||
} |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
if (empty($order['extract_shop'])) { |
|||
$this->error = '您还没有选择自提门店'; |
|||
return false; |
|||
} |
|||
if (empty($linkman) || empty($phone)) { |
|||
$this->error = '您还没有填写联系人和电话'; |
|||
return false; |
|||
} |
|||
} |
|||
// 余额支付时判断用户余额是否足够 |
|||
if ($order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
if ($this->user['balance'] < $order['order_pay_price']) { |
|||
$this->error = '您的余额不足,无法使用余额支付'; |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 当前订单是否存在和使用积分抵扣 |
|||
* @param $order |
|||
* @return bool |
|||
*/ |
|||
private function isExistPointsDeduction($order) |
|||
{ |
|||
return $order['is_allow_points'] && $order['is_use_points']; |
|||
} |
|||
|
|||
/** |
|||
* 新增订单记录 |
|||
* @param $order |
|||
* @param string $remark |
|||
* @return false|int |
|||
*/ |
|||
private function add($order, $remark = '') |
|||
{ |
|||
// 当前订单是否存在和使用积分抵扣 |
|||
$isExistPointsDeduction = $this->isExistPointsDeduction($order); |
|||
// 订单数据 |
|||
$data = [ |
|||
'user_id' => $this->user['user_id'], |
|||
'order_no' => $this->model->orderNo(), |
|||
'total_price' => $order['order_total_price'], |
|||
'order_price' => $order['order_price'], |
|||
'coupon_id' => $order['coupon_id'], |
|||
'coupon_money' => $order['coupon_money'], |
|||
'points_money' => $isExistPointsDeduction ? $order['points_money'] : 0.00, |
|||
'points_num' => $isExistPointsDeduction ? $order['points_num'] : 0, |
|||
'pay_price' => $order['order_pay_price'], |
|||
'delivery_type' => $order['delivery'], |
|||
'pay_type' => $order['pay_type'], |
|||
'buyer_remark' => trim($remark), |
|||
'order_source' => $this->orderSource['source'], |
|||
'order_source_id' => $this->orderSource['source_id'], |
|||
'points_bonus' => $order['points_bonus'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
]; |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$data['express_price'] = $order['express_price']; |
|||
} elseif ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
$data['extract_shop_id'] = $order['extract_shop']['shop_id']; |
|||
} |
|||
// 保存订单记录 |
|||
return $this->model->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 保存订单商品信息 |
|||
* @param $order |
|||
* @return int |
|||
*/ |
|||
private function saveOrderGoods($order) |
|||
{ |
|||
// 当前订单是否存在和使用积分抵扣 |
|||
$isExistPointsDeduction = $this->isExistPointsDeduction($order); |
|||
// 订单商品列表 |
|||
$goodsList = []; |
|||
foreach ($order['goods_list'] as $goods) { |
|||
/* @var GoodsModel $goods */ |
|||
$item = [ |
|||
'user_id' => $this->user['user_id'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
'goods_id' => $goods['goods_id'], |
|||
'goods_name' => $goods['goods_name'], |
|||
'image_id' => $goods['image'][0]['image_id'], |
|||
'deduct_stock_type' => $goods['deduct_stock_type'], |
|||
'spec_type' => $goods['spec_type'], |
|||
'spec_sku_id' => $goods['goods_sku']['spec_sku_id'], |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'goods_attr' => $goods['goods_sku']['goods_attr'], |
|||
'content' => $goods['content'], |
|||
'goods_no' => $goods['goods_sku']['goods_no'], |
|||
'goods_price' => $goods['goods_sku']['goods_price'], |
|||
'line_price' => $goods['goods_sku']['line_price'], |
|||
'goods_weight' => $goods['goods_sku']['goods_weight'], |
|||
'is_user_grade' => (int)$goods['is_user_grade'], |
|||
'grade_ratio' => $goods['grade_ratio'], |
|||
'grade_goods_price' => $goods['grade_goods_price'], |
|||
'grade_total_money' => $goods['grade_total_money'], |
|||
'coupon_money' => $goods['coupon_money'], |
|||
'points_money' => $isExistPointsDeduction ? $goods['points_money'] : 0.00, |
|||
'points_num' => $isExistPointsDeduction ? $goods['points_num'] : 0, |
|||
'points_bonus' => $goods['points_bonus'], |
|||
'total_num' => $goods['total_num'], |
|||
'total_price' => $goods['total_price'], |
|||
'total_pay_price' => $goods['total_pay_price'], |
|||
'is_ind_dealer' => $goods['is_ind_dealer'], |
|||
'dealer_money_type' => $goods['dealer_money_type'], |
|||
'first_money' => $goods['first_money'], |
|||
'second_money' => $goods['second_money'], |
|||
'third_money' => $goods['third_money'], |
|||
]; |
|||
// 记录订单商品来源id |
|||
$item['goods_source_id'] = isset($goods['goods_source_id']) ? $goods['goods_source_id'] : 0; |
|||
$goodsList[] = $item; |
|||
} |
|||
return $this->model->goods()->saveAll($goodsList); |
|||
} |
|||
|
|||
/** |
|||
* 更新商品库存 (针对下单减库存的商品) |
|||
* @param $order |
|||
* @return mixed |
|||
*/ |
|||
private function updateGoodsStockNum($order) |
|||
{ |
|||
return StockFactory::getFactory($this->model['order_source'])->updateGoodsStock($order['goods_list']); |
|||
} |
|||
|
|||
/** |
|||
* 记录收货地址 |
|||
* @param $address |
|||
* @return false|\think\Model |
|||
*/ |
|||
private function saveOrderAddress($address) |
|||
{ |
|||
if ($address['region_id'] == 0 && !empty($address['district'])) { |
|||
$address['detail'] = $address['district'] . ' ' . $address['detail']; |
|||
} |
|||
return $this->model->address()->save([ |
|||
'user_id' => $this->user['user_id'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
'name' => $address['name'], |
|||
'phone' => $address['phone'], |
|||
'province_id' => $address['province_id'], |
|||
'city_id' => $address['city_id'], |
|||
'region_id' => $address['region_id'], |
|||
'detail' => $address['detail'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 保存上门自提联系人 |
|||
* @param $linkman |
|||
* @param $phone |
|||
* @return false|\think\Model |
|||
*/ |
|||
private function saveOrderExtract($linkman, $phone) |
|||
{ |
|||
// 记忆上门自提联系人(缓存),用于下次自动填写 |
|||
UserService::setLastExtract($this->model['user_id'], trim($linkman), trim($phone)); |
|||
// 保存上门自提联系人(数据库) |
|||
return $this->model->extract()->save([ |
|||
'linkman' => trim($linkman), |
|||
'phone' => trim($phone), |
|||
'user_id' => $this->model['user_id'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 设置错误信息 |
|||
* @param $error |
|||
*/ |
|||
protected function setError($error) |
|||
{ |
|||
empty($this->error) && $this->error = $error; |
|||
} |
|||
|
|||
/** |
|||
* 获取错误信息 |
|||
* @return mixed |
|||
*/ |
|||
public function getError() |
|||
{ |
|||
return $this->error ?: ''; |
|||
} |
|||
|
|||
/** |
|||
* 是否存在错误 |
|||
* @return bool |
|||
*/ |
|||
public function hasError() |
|||
{ |
|||
return !empty($this->error); |
|||
} |
|||
|
|||
} |
|||
@ -1,150 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\service\order; |
|||
|
|||
use think\Hook; |
|||
use app\api\service\Basics; |
|||
use app\api\model\User as UserModel; |
|||
use app\api\model\Order as OrderModel; |
|||
//use app\api\model\WxappPrepayId as WxappPrepayIdModel; |
|||
use app\api\model\user\BalanceLog as BalanceLogModel; |
|||
use app\common\service\goods\source\Factory as StockFactory; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\enum\user\balanceLog\Scene as SceneEnum; |
|||
|
|||
/** |
|||
* 订单支付成功服务类 |
|||
* Class PaySuccess |
|||
* @package app\api\service\order |
|||
*/ |
|||
class PaySuccess extends Basics |
|||
{ |
|||
// 订单模型 |
|||
public $model; |
|||
|
|||
// 当前用户信息 |
|||
private $user; |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* PaySuccess constructor. |
|||
* @param $orderNo |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function __construct($orderNo) |
|||
{ |
|||
// 实例化订单模型 |
|||
$this->model = OrderModel::getPayDetail($orderNo); |
|||
if (!empty($this->model)) { |
|||
$this->wxappId = $this->model['wxapp_id']; |
|||
} |
|||
// 获取用户信息 |
|||
$this->user = UserModel::detail($this->model['user_id']); |
|||
} |
|||
|
|||
/** |
|||
* 获取订单详情 |
|||
* @return OrderModel|null |
|||
*/ |
|||
public function getOrderInfo() |
|||
{ |
|||
return $this->model; |
|||
} |
|||
|
|||
/** |
|||
* 订单支付成功业务处理 |
|||
* @param $payType |
|||
* @param array $payData |
|||
* @return bool |
|||
*/ |
|||
public function onPaySuccess($payType, $payData = []) |
|||
{ |
|||
if (empty($this->model)) { |
|||
$this->error = '未找到该订单信息'; |
|||
return false; |
|||
} |
|||
// 更新付款状态 |
|||
$status = $this->updatePayStatus($payType, $payData); |
|||
// 订单支付成功行为 |
|||
if ($status == true) { |
|||
Hook::listen('order_pay_success', $this->model, OrderTypeEnum::MASTER); |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 更新付款状态 |
|||
* @param $payType |
|||
* @param array $payData |
|||
* @return bool |
|||
*/ |
|||
private function updatePayStatus($payType, $payData = []) |
|||
{ |
|||
// 验证余额支付时用户余额是否满足 |
|||
if ($payType == PayTypeEnum::BALANCE) { |
|||
if ($this->user['balance'] < $this->model['pay_price']) { |
|||
$this->error = '用户余额不足,无法使用余额支付'; |
|||
return false; |
|||
} |
|||
} |
|||
// 事务处理 |
|||
$this->model->transaction(function () use ($payType, $payData) { |
|||
// 更新订单状态 |
|||
$this->updateOrderInfo($payType, $payData); |
|||
// 累积用户总消费金额 |
|||
$this->user->setIncPayMoney($this->model['pay_price']); |
|||
// 记录订单支付信息 |
|||
$this->updatePayInfo($payType); |
|||
}); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 更新订单记录 |
|||
* @param $payType |
|||
* @param $payData |
|||
* @return false|int |
|||
* @throws \Exception |
|||
*/ |
|||
private function updateOrderInfo($payType, $payData) |
|||
{ |
|||
// 更新商品库存、销量 |
|||
StockFactory::getFactory($this->model['order_source'])->updateStockSales($this->model['goods']); |
|||
// 整理订单信息 |
|||
$order = [ |
|||
'pay_type' => $payType, |
|||
'pay_status' => 20, |
|||
'pay_time' => time() |
|||
]; |
|||
if ($payType == PayTypeEnum::WECHAT) { |
|||
$order['transaction_id'] = $payData['transaction_id']; |
|||
} |
|||
// 更新订单状态 |
|||
return $this->model->save($order); |
|||
} |
|||
|
|||
/** |
|||
* 记录订单支付信息 |
|||
* @param $payType |
|||
* @throws \think\Exception |
|||
*/ |
|||
private function updatePayInfo($payType) |
|||
{ |
|||
// 余额支付 |
|||
if ($payType == PayTypeEnum::BALANCE) { |
|||
// 更新用户余额 |
|||
$this->user->setDec('balance', $this->model['pay_price']); |
|||
BalanceLogModel::add(SceneEnum::CONSUME, [ |
|||
'user_id' => $this->user['user_id'], |
|||
'money' => -$this->model['pay_price'], |
|||
], ['order_no' => $this->model['order_no']]); |
|||
} |
|||
// 微信支付 |
|||
if ($payType == PayTypeEnum::WECHAT) { |
|||
// 更新prepay_id记录 |
|||
// WxappPrepayIdModel::updatePayStatus($this->model['order_id'], OrderTypeEnum::MASTER); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,79 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\service\recharge; |
|||
|
|||
use app\api\service\Basics; |
|||
use app\api\model\User as UserModel; |
|||
use app\api\model\recharge\Order as OrderModel; |
|||
//use app\api\model\WxappPrepayId as WxappPrepayIdModel; |
|||
use app\api\model\user\BalanceLog as BalanceLogModel; |
|||
|
|||
//use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\enum\user\balanceLog\Scene as SceneEnum; |
|||
use app\common\enum\recharge\order\PayStatus as PayStatusEnum; |
|||
|
|||
class PaySuccess extends Basics |
|||
{ |
|||
// 订单模型 |
|||
public $model; |
|||
|
|||
// 当前用户信息 |
|||
private $user; |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* PaySuccess constructor. |
|||
* @param $orderNo |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function __construct($orderNo) |
|||
{ |
|||
// 实例化订单模型 |
|||
$this->model = OrderModel::getPayDetail($orderNo); |
|||
$this->wxappId = $this->model['wxapp_id']; |
|||
// 获取用户信息 |
|||
$this->user = UserModel::detail($this->model['user_id']); |
|||
} |
|||
|
|||
/** |
|||
* 获取订单详情 |
|||
* @return OrderModel|null |
|||
*/ |
|||
public function getOrderInfo() |
|||
{ |
|||
return $this->model; |
|||
} |
|||
|
|||
/** |
|||
* 订单支付成功业务处理 |
|||
* @param int $payType 支付类型 |
|||
* @param array $payData 支付回调数据 |
|||
* @return bool |
|||
*/ |
|||
public function onPaySuccess($payType, $payData) |
|||
{ |
|||
return $this->model->transaction(function () use ($payType, $payData) { |
|||
// 更新订单状态 |
|||
$this->model->save([ |
|||
'pay_status' => PayStatusEnum::SUCCESS, |
|||
'pay_time' => time(), |
|||
'transaction_id' => $payData['transaction_id'] |
|||
]); |
|||
// 累积用户余额 |
|||
$this->user->setInc('balance', $this->model['actual_money']); |
|||
// 用户余额变动明细 |
|||
BalanceLogModel::add(SceneEnum::RECHARGE, [ |
|||
'user_id' => $this->user['user_id'], |
|||
'money' => $this->model['actual_money'], |
|||
'wxapp_id' => $this->wxappId, |
|||
], ['order_no' => $this->model['order_no']]); |
|||
// 更新prepay_id记录 |
|||
if ($payType == PayTypeEnum::WECHAT) { |
|||
// WxappPrepayIdModel::updatePayStatus($this->model['order_id'], OrderTypeEnum::RECHARGE); |
|||
} |
|||
return true; |
|||
}); |
|||
} |
|||
|
|||
} |
|||
@ -1,907 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\service\sharing\order; |
|||
|
|||
use app\api\model\sharing\Order as OrderModel; |
|||
|
|||
use app\api\model\User as UserModel; |
|||
use app\api\model\Setting as SettingModel; |
|||
use app\api\model\sharing\Goods as GoodsModel; |
|||
use app\api\model\sharing\GoodsSku as GoodsSkuModel; |
|||
use app\api\model\sharing\Active as ActiveModel; |
|||
use app\api\model\sharing\Setting as SharingSettingModel; |
|||
use app\api\model\store\Shop as ShopModel; |
|||
use app\api\model\UserCoupon as UserCouponModel; |
|||
use app\api\model\dealer\Order as DealerOrderModel; |
|||
|
|||
use app\api\service\User as UserService; |
|||
use app\api\service\Payment as PaymentService; |
|||
use app\api\service\coupon\GoodsDeduct as GoodsDeductService; |
|||
use app\api\service\points\GoodsDeduct as PointsDeductService; |
|||
|
|||
use app\common\library\helper; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\enum\DeliveryType as DeliveryTypeEnum; |
|||
use app\common\enum\order\OrderSource as OrderSourceEnum; |
|||
use app\common\service\delivery\Express as ExpressService; |
|||
use app\common\exception\BaseException; |
|||
|
|||
/** |
|||
* 订单结算台服务类 |
|||
* Class Checkout |
|||
* @package app\api\service\order |
|||
*/ |
|||
class Checkout |
|||
{ |
|||
/* $model OrderModel 订单模型 */ |
|||
public $model; |
|||
|
|||
// 当前小程序id |
|||
private $wxapp_id; |
|||
|
|||
/* @var UserModel $user 当前用户信息 */ |
|||
private $user; |
|||
|
|||
// 订单结算商品列表 |
|||
private $goodsList = []; |
|||
|
|||
// 错误信息 |
|||
protected $error; |
|||
|
|||
/** |
|||
* 订单结算api参数 |
|||
* @var array |
|||
*/ |
|||
private $param = [ |
|||
'active_id' => 0, // 参与的拼单id |
|||
'delivery' => null, // 配送方式 |
|||
'shop_id' => 0, // 自提门店id |
|||
'linkman' => '', // 自提联系人 |
|||
'phone' => '', // 自提联系电话 |
|||
'coupon_id' => 0, // 优惠券id |
|||
'is_use_points' => 0, // 是否使用积分抵扣 |
|||
'remark' => '', // 买家留言 |
|||
'pay_type' => PayTypeEnum::WECHAT, // 支付方式 |
|||
'order_type' => 20, // 下单类型 10 => 单独购买,20 => 拼团 |
|||
]; |
|||
|
|||
/** |
|||
* 订单结算的规则 |
|||
* @var array |
|||
*/ |
|||
private $checkoutRule = [ |
|||
'is_user_grade' => true, // 会员等级折扣 |
|||
'is_coupon' => true, // 优惠券抵扣 |
|||
'is_use_points' => true, // 是否使用积分抵扣 |
|||
'is_dealer' => true, // 是否开启分销 |
|||
]; |
|||
|
|||
/** |
|||
* 订单来源 |
|||
* @var array |
|||
*/ |
|||
private $orderSource = [ |
|||
'source' => OrderSourceEnum::MASTER, |
|||
'source_id' => 0, |
|||
]; |
|||
|
|||
/** |
|||
* 订单结算数据 |
|||
* @var array |
|||
*/ |
|||
private $orderData = []; |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* Checkout constructor. |
|||
*/ |
|||
public function __construct() |
|||
{ |
|||
$this->model = new OrderModel; |
|||
$this->wxapp_id = OrderModel::$wxapp_id; |
|||
} |
|||
|
|||
/** |
|||
* 设置结算台请求的参数 |
|||
* @param $param |
|||
* @return array |
|||
*/ |
|||
public function setParam($param) |
|||
{ |
|||
$this->param = array_merge($this->param, $param); |
|||
return $this->getParam(); |
|||
} |
|||
|
|||
/** |
|||
* 获取结算台请求的参数 |
|||
* @return array |
|||
*/ |
|||
public function getParam() |
|||
{ |
|||
return $this->param; |
|||
} |
|||
|
|||
/** |
|||
* 订单结算的规则 |
|||
* @param $data |
|||
*/ |
|||
public function setCheckoutRule($data) |
|||
{ |
|||
$this->checkoutRule = array_merge($this->checkoutRule, $data); |
|||
} |
|||
|
|||
/** |
|||
* 设置订单来源(普通订单、砍价订单) |
|||
* @param $data |
|||
*/ |
|||
public function setOrderSource($data) |
|||
{ |
|||
$this->orderSource = array_merge($this->orderSource, $data); |
|||
} |
|||
|
|||
/** |
|||
* 订单确认-砍价活动 |
|||
* @param $user |
|||
* @param $goodsList |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function onCheckout($user, $goodsList) |
|||
{ |
|||
$this->user = $user; |
|||
$this->goodsList = $goodsList; |
|||
// 订单确认-立即购买 |
|||
return $this->checkout(); |
|||
} |
|||
|
|||
/** |
|||
* 订单结算台 |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\Exception |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function checkout() |
|||
{ |
|||
// 整理订单数据 |
|||
$this->orderData = $this->getOrderData(); |
|||
// 验证商品状态, 是否允许购买 |
|||
$this->validateGoodsList(); |
|||
// 订单商品总数量 |
|||
$orderTotalNum = helper::getArrayColumnSum($this->goodsList, 'total_num'); |
|||
// 设置订单商品会员折扣价 |
|||
$this->setOrderGoodsGradeMoney(); |
|||
// 设置订单商品总金额(不含优惠折扣) |
|||
$this->setOrderTotalPrice(); |
|||
// 当前用户可用的优惠券列表 |
|||
$couponList = $this->getUserCouponList($this->orderData['order_total_price']); |
|||
// 计算优惠券抵扣 |
|||
$this->setOrderCouponMoney($couponList, $this->param['coupon_id']); |
|||
// 计算可用积分抵扣 |
|||
$this->setOrderPoints(); |
|||
// 计算订单商品的实际付款金额 |
|||
$this->setOrderGoodsPayPrice(); |
|||
// 设置默认配送方式 |
|||
!$this->param['delivery'] && $this->param['delivery'] = current(SettingModel::getItem('store')['delivery_type']); |
|||
// 处理配送方式 |
|||
if ($this->param['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$this->setOrderExpress(); |
|||
} elseif ($this->param['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
$this->param['shop_id'] > 0 && $this->orderData['extract_shop'] = ShopModel::detail($this->param['shop_id']); |
|||
} |
|||
// 计算订单最终金额 |
|||
$this->setOrderPayPrice(); |
|||
// 计算订单积分赠送数量 |
|||
$this->setOrderPointsBonus(); |
|||
// 返回订单数据 |
|||
return array_merge([ |
|||
'goods_list' => array_values($this->goodsList), // 商品信息 |
|||
'order_total_num' => $orderTotalNum, // 商品总数量 |
|||
'coupon_list' => array_values($couponList), // 优惠券列表 |
|||
'has_error' => $this->hasError(), |
|||
'error_msg' => $this->getError(), |
|||
], $this->orderData); |
|||
} |
|||
|
|||
/** |
|||
* 计算订单可用积分抵扣 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderPoints() |
|||
{ |
|||
// 设置默认的商品积分抵扣信息 |
|||
$this->setDefaultGoodsPoints(); |
|||
// 积分设置 |
|||
$setting = SettingModel::getItem('points'); |
|||
// 条件:后台开启下单使用积分抵扣 |
|||
if (!$setting['is_shopping_discount'] || !$this->checkoutRule['is_use_points']) { |
|||
return false; |
|||
} |
|||
// 条件:订单金额满足[?]元 |
|||
if (helper::bccomp($setting['discount']['full_order_price'], $this->orderData['order_total_price']) === 1) { |
|||
return false; |
|||
} |
|||
// 计算订单商品最多可抵扣的积分数量 |
|||
$this->setOrderGoodsMaxPointsNum(); |
|||
// 订单最多可抵扣的积分总数量 |
|||
$maxPointsNumCount = helper::getArrayColumnSum($this->goodsList, 'max_points_num'); |
|||
// 实际可抵扣的积分数量 |
|||
$actualPointsNum = min($maxPointsNumCount, $this->user['points']); |
|||
if ($actualPointsNum < 1) { |
|||
return false; |
|||
} |
|||
// 计算订单商品实际抵扣的积分数量和金额 |
|||
$GoodsDeduct = new PointsDeductService($this->goodsList); |
|||
$GoodsDeduct->setGoodsPoints($maxPointsNumCount, $actualPointsNum); |
|||
// 积分抵扣总金额 |
|||
$orderPointsMoney = helper::getArrayColumnSum($this->goodsList, 'points_money'); |
|||
$this->orderData['points_money'] = helper::number2($orderPointsMoney); |
|||
// 积分抵扣总数量 |
|||
$this->orderData['points_num'] = $actualPointsNum; |
|||
// 允许积分抵扣 |
|||
$this->orderData['is_allow_points'] = true; |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 计算订单商品最多可抵扣的积分数量 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderGoodsMaxPointsNum() |
|||
{ |
|||
// 积分设置 |
|||
$setting = SettingModel::getItem('points'); |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 商品不允许积分抵扣 |
|||
if (!$goods['is_points_discount']) continue; |
|||
// 积分抵扣比例 |
|||
$deductionRatio = helper::bcdiv($setting['discount']['max_money_ratio'], 100); |
|||
// 最多可抵扣的金额 |
|||
// !!!: 此处应该是优惠券打折后的价格 |
|||
// bug: $totalPayPrice = $goods['total_price']; |
|||
$totalPayPrice = helper::bcsub($goods['total_price'], $goods['coupon_money']); |
|||
$maxPointsMoney = helper::bcmul($totalPayPrice, $deductionRatio); |
|||
// 最多可抵扣的积分数量 |
|||
$goods['max_points_num'] = helper::bcdiv($maxPointsMoney, $setting['discount']['discount_ratio'], 0); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置默认的商品积分抵扣信息 |
|||
* @return bool |
|||
*/ |
|||
private function setDefaultGoodsPoints() |
|||
{ |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 最多可抵扣的积分数量 |
|||
$goods['max_points_num'] = 0; |
|||
// 实际抵扣的积分数量 |
|||
$goods['points_num'] = 0; |
|||
// 实际抵扣的金额 |
|||
$goods['points_money'] = 0.00; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 整理订单数据(结算台初始化) |
|||
* @return array |
|||
*/ |
|||
private function getOrderData() |
|||
{ |
|||
// 系统支持的配送方式 (后台设置) |
|||
$deliveryType = SettingModel::getItem('store')['delivery_type']; |
|||
return [ |
|||
// 订单类型 |
|||
'order_type' => $this->param['order_type'], |
|||
// 配送类型 |
|||
'delivery' => $this->param['delivery'] > 0 ? $this->param['delivery'] : $deliveryType[0], |
|||
// 默认地址 |
|||
'address' => $this->user['address_default'], |
|||
// 是否存在收货地址 |
|||
'exist_address' => $this->user['address_id'] > 0, |
|||
// 配送费用 |
|||
'express_price' => 0.00, |
|||
// 当前用户收货城市是否存在配送规则中 |
|||
'intra_region' => true, |
|||
// 自提门店信息 |
|||
'extract_shop' => [], |
|||
// 是否允许使用积分抵扣 |
|||
'is_allow_points' => false, |
|||
// 是否使用积分抵扣 |
|||
'is_use_points' => $this->param['is_use_points'], |
|||
// 积分抵扣金额 |
|||
'points_money' => 0.00, |
|||
// 赠送的积分数量 |
|||
'points_bonus' => 0, |
|||
// 支付方式 |
|||
'pay_type' => $this->param['pay_type'], |
|||
// 系统设置 |
|||
'setting' => $this->getSetting(), |
|||
// 记忆的自提联系方式 |
|||
'last_extract' => UserService::getLastExtract($this->user['user_id']), |
|||
// todo: 兼容处理 |
|||
'deliverySetting' => $deliveryType, |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* 获取订单页面中使用到的系统设置 |
|||
* @return array |
|||
*/ |
|||
private function getSetting() |
|||
{ |
|||
// 系统支持的配送方式 (后台设置) |
|||
$deliveryType = SettingModel::getItem('store')['delivery_type']; |
|||
// 积分设置 |
|||
$pointsSetting = SettingModel::getItem('points'); |
|||
// 订阅消息 |
|||
$orderSubMsgList = []; |
|||
foreach (SettingModel::getItem('submsg')['order'] as $item) { |
|||
!empty($item['template_id']) && $orderSubMsgList[] = $item['template_id']; |
|||
} |
|||
return [ |
|||
'delivery' => $deliveryType, // 支持的配送方式 |
|||
'points_name' => $pointsSetting['points_name'], // 积分名称 |
|||
'points_describe' => $pointsSetting['describe'], // 积分说明 |
|||
'order_submsg' => $orderSubMsgList, // 订阅消息 |
|||
]; |
|||
} |
|||
|
|||
/** |
|||
* 当前用户可用的优惠券列表 |
|||
* @param $orderTotalPrice |
|||
* @return mixed |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function getUserCouponList($orderTotalPrice) |
|||
{ |
|||
// 是否开启优惠券折扣 |
|||
if (!$this->checkoutRule['is_coupon'] || !SharingSettingModel::getItem('basic')['is_coupon']) { |
|||
return []; |
|||
} |
|||
return UserCouponModel::getUserCouponList($this->user['user_id'], $orderTotalPrice); |
|||
} |
|||
|
|||
/** |
|||
* 验证订单商品的状态 |
|||
*/ |
|||
private function validateGoodsList() |
|||
{ |
|||
foreach ($this->goodsList as $goods) { |
|||
// 判断商品是否下架 |
|||
if ($goods['goods_status']['value'] != 10) { |
|||
$this->setError("很抱歉,商品 [{$goods['goods_name']}] 已下架"); |
|||
} |
|||
// 判断商品库存 |
|||
if ($goods['total_num'] > $goods['goods_sku']['stock_num']) { |
|||
$this->setError("很抱歉,商品 [{$goods['goods_name']}] 库存不足"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 设置订单的商品总金额(不含优惠折扣) |
|||
*/ |
|||
private function setOrderTotalPrice() |
|||
{ |
|||
// 订单商品的总金额(不含优惠券折扣) |
|||
$this->orderData['order_total_price'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_price')); |
|||
} |
|||
|
|||
/** |
|||
* 设置订单的实际支付金额(含配送费) |
|||
*/ |
|||
private function setOrderPayPrice() |
|||
{ |
|||
// 订单金额(含优惠折扣) |
|||
$this->orderData['order_price'] = helper::number2(helper::getArrayColumnSum($this->goodsList, 'total_pay_price')); |
|||
// 订单实付款金额(订单金额 + 运费) |
|||
$this->orderData['order_pay_price'] = helper::number2(helper::bcadd($this->orderData['order_price'], $this->orderData['express_price'])); |
|||
} |
|||
|
|||
/** |
|||
* 计算订单积分赠送数量 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderPointsBonus() |
|||
{ |
|||
// 初始化商品积分赠送数量 |
|||
foreach ($this->goodsList as &$goods) { |
|||
$goods['points_bonus'] = 0; |
|||
} |
|||
// 积分设置 |
|||
$setting = SettingModel::getItem('points'); |
|||
// 条件:后台开启开启购物送积分 |
|||
if (!$setting['is_shopping_gift']) { |
|||
return false; |
|||
} |
|||
// 设置商品积分赠送数量 |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 积分赠送比例 |
|||
$ratio = $setting['gift_ratio'] / 100; |
|||
// 计算抵扣积分数量 |
|||
$goods['points_bonus'] = $goods['is_points_gift'] ? helper::bcmul($goods['total_pay_price'], $ratio, 0) : 0; |
|||
} |
|||
// 订单积分赠送数量 |
|||
$this->orderData['points_bonus'] = helper::getArrayColumnSum($this->goodsList, 'points_bonus'); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 计算订单商品的实际付款金额 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderGoodsPayPrice() |
|||
{ |
|||
// 商品总价 - 优惠抵扣 |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 减去优惠券抵扣金额 |
|||
$value = helper::bcsub($goods['total_price'], $goods['coupon_money']); |
|||
// 减去积分抵扣金额 |
|||
if ($this->orderData['is_allow_points'] && $this->orderData['is_use_points']) { |
|||
$value = helper::bcsub($value, $goods['points_money']); |
|||
} |
|||
$goods['total_pay_price'] = helper::number2($value); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单商品会员折扣价 |
|||
* @return bool |
|||
*/ |
|||
private function setOrderGoodsGradeMoney() |
|||
{ |
|||
// 设置默认数据 |
|||
helper::setDataAttribute($this->goodsList, [ |
|||
// 标记参与会员折扣 |
|||
'is_user_grade' => false, |
|||
// 会员等级抵扣的金额 |
|||
'grade_ratio' => 0, |
|||
// 会员折扣的商品单价 |
|||
'grade_goods_price' => 0.00, |
|||
// 会员折扣的总额差 |
|||
'grade_total_money' => 0.00, |
|||
], true); |
|||
|
|||
// 是否开启会员等级折扣 |
|||
if (!$this->checkoutRule['is_user_grade']) { |
|||
return false; |
|||
} |
|||
// 会员等级状态 |
|||
if (!( |
|||
$this->user['grade_id'] > 0 && !empty($this->user['grade']) |
|||
&& !$this->user['grade']['is_delete'] && $this->user['grade']['status'] |
|||
)) { |
|||
return false; |
|||
} |
|||
// 计算抵扣金额 |
|||
foreach ($this->goodsList as &$goods) { |
|||
// 判断商品是否参与会员折扣 |
|||
if (!$goods['is_enable_grade']) { |
|||
continue; |
|||
} |
|||
// 商品单独设置了会员折扣 |
|||
if ($goods['is_alone_grade'] && isset($goods['alone_grade_equity'][$this->user['grade_id']])) { |
|||
// 折扣比例 |
|||
$discountRatio = helper::bcdiv($goods['alone_grade_equity'][$this->user['grade_id']], 10); |
|||
} else { |
|||
// 折扣比例 |
|||
$discountRatio = helper::bcdiv($this->user['grade']['equity']['discount'], 10); |
|||
} |
|||
if ($discountRatio > 0) { |
|||
// 会员折扣后的商品总金额 |
|||
$gradeTotalPrice = max(0.01, helper::bcmul($goods['total_price'], $discountRatio)); |
|||
helper::setDataAttribute($goods, [ |
|||
'is_user_grade' => true, |
|||
'grade_ratio' => $discountRatio, |
|||
'grade_goods_price' => helper::number2(helper::bcmul($goods['goods_price'], $discountRatio), true), |
|||
'grade_total_money' => helper::number2(helper::bcsub($goods['total_price'], $gradeTotalPrice)), |
|||
'total_price' => $gradeTotalPrice, |
|||
], false); |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 设置订单优惠券抵扣信息 |
|||
* @param array $couponList 当前用户可用的优惠券列表 |
|||
* @param int $couponId 当前选择的优惠券id |
|||
* @return bool |
|||
* @throws BaseException |
|||
*/ |
|||
private function setOrderCouponMoney($couponList, $couponId) |
|||
{ |
|||
// 设置默认数据:订单信息 |
|||
helper::setDataAttribute($this->orderData, [ |
|||
'coupon_id' => 0, // 用户优惠券id |
|||
'coupon_money' => 0, // 优惠券抵扣金额 |
|||
], false); |
|||
// 设置默认数据:订单商品列表 |
|||
helper::setDataAttribute($this->goodsList, [ |
|||
'coupon_money' => 0, // 优惠券抵扣金额 |
|||
], true); |
|||
// 是否开启优惠券折扣 |
|||
if (!$this->checkoutRule['is_coupon']) { |
|||
return false; |
|||
} |
|||
// 如果没有可用的优惠券,直接返回 |
|||
if ($couponId <= 0 || empty($couponList)) { |
|||
return true; |
|||
} |
|||
// 获取优惠券信息 |
|||
$couponInfo = helper::getArrayItemByColumn($couponList, 'user_coupon_id', $couponId); |
|||
if ($couponInfo == false) { |
|||
throw new BaseException(['msg' => '未找到优惠券信息']); |
|||
} |
|||
// 计算订单商品优惠券抵扣金额 |
|||
$goodsListTemp = helper::getArrayColumns($this->goodsList, ['total_price']); |
|||
$CouponMoney = new GoodsDeductService; |
|||
$completed = $CouponMoney->setGoodsCouponMoney($goodsListTemp, $couponInfo['reduced_price']); |
|||
// 分配订单商品优惠券抵扣金额 |
|||
foreach ($this->goodsList as $key => &$goods) { |
|||
$goods['coupon_money'] = $completed[$key]['coupon_money'] / 100; |
|||
} |
|||
// 记录订单优惠券信息 |
|||
$this->orderData['coupon_id'] = $couponId; |
|||
$this->orderData['coupon_money'] = helper::number2($CouponMoney->getActualReducedMoney() / 100); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 订单配送-快递配送 |
|||
* @return bool |
|||
* @throws \think\db\exception\DataNotFoundException |
|||
* @throws \think\db\exception\ModelNotFoundException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function setOrderExpress() |
|||
{ |
|||
// 设置默认数据:配送费用 |
|||
helper::setDataAttribute($this->goodsList, [ |
|||
'express_price' => 0, |
|||
], true); |
|||
// 当前用户收货城市id |
|||
$cityId = $this->user['address_default'] ? $this->user['address_default']['city_id'] : null; |
|||
// 初始化配送服务类 |
|||
$ExpressService = new ExpressService($cityId, $this->goodsList, OrderTypeEnum::SHARING); |
|||
// 验证商品是否在配送范围 |
|||
$isIntraRegion = $ExpressService->isIntraRegion(); |
|||
if ($cityId > 0 && $isIntraRegion == false) { |
|||
$notInRuleGoodsName = $ExpressService->getNotInRuleGoodsName(); |
|||
$this->setError("很抱歉,您的收货地址不在商品 [{$notInRuleGoodsName}] 的配送范围内"); |
|||
} |
|||
// 订单总运费金额 |
|||
$this->orderData['intra_region'] = $isIntraRegion; |
|||
$this->orderData['express_price'] = $ExpressService->getDeliveryFee(); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 创建新订单 |
|||
* @param array $order 订单信息 |
|||
* @return bool |
|||
* @throws \Exception |
|||
*/ |
|||
public function createOrder($order) |
|||
{ |
|||
// 如果是参与拼单,则记录拼单id |
|||
$order['active_id'] = $this->param['active_id']; |
|||
// 表单验证 |
|||
if (!$this->validateOrderForm($order, $this->param['linkman'], $this->param['phone'])) { |
|||
return false; |
|||
} |
|||
// 创建新的订单 |
|||
$status = $this->model->transaction(function () use ($order) { |
|||
// 创建订单事件 |
|||
return $this->createOrderEvent($order); |
|||
}); |
|||
// 余额支付标记订单已支付 |
|||
if ($status && $order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
return $this->model->onPaymentByBalance($this->model['order_no']); |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 创建订单事件 |
|||
* @param $order |
|||
* @return bool |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
* @throws \Exception |
|||
*/ |
|||
private function createOrderEvent($order) |
|||
{ |
|||
// 新增订单记录 |
|||
$status = $this->add($order, $this->param['remark']); |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
// 记录收货地址 |
|||
$this->saveOrderAddress($order['address']); |
|||
} elseif ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
// 记录自提信息 |
|||
$this->saveOrderExtract($this->param['linkman'], $this->param['phone']); |
|||
} |
|||
// 保存订单商品信息 |
|||
$this->saveOrderGoods($order); |
|||
// 更新商品库存 (针对下单减库存的商品) |
|||
$this->updateGoodsStockNum($order['goods_list']); |
|||
// 设置优惠券使用状态 |
|||
UserCouponModel::setIsUse($this->param['coupon_id']); |
|||
// 积分抵扣情况下扣除用户积分 |
|||
if ($order['is_allow_points'] && $order['is_use_points'] && $order['points_num'] > 0) { |
|||
$describe = "用户消费:{$this->model['order_no']}"; |
|||
$this->user->setIncPoints(-$order['points_num'], $describe); |
|||
} |
|||
// 获取订单详情 |
|||
$detail = OrderModel::getUserOrderDetail($this->model['order_id'], $this->user['user_id']); |
|||
// 记录分销商订单 |
|||
if ($this->checkoutRule['is_dealer'] && SharingSettingModel::getItem('basic')['is_dealer']) { |
|||
DealerOrderModel::createOrder($detail, OrderTypeEnum::SHARING); |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 构建支付请求的参数 |
|||
* @return array |
|||
* @throws BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function onOrderPayment() |
|||
{ |
|||
return PaymentService::orderPayment($this->user, $this->model, $this->param['pay_type']); |
|||
} |
|||
|
|||
/** |
|||
* 表单验证 (订单提交) |
|||
* @param array $order 订单信息 |
|||
* @param string $linkman 联系人 |
|||
* @param string $phone 联系电话 |
|||
* @return bool |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function validateOrderForm(&$order, $linkman, $phone) |
|||
{ |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
if (empty($order['address'])) { |
|||
$this->error = '您还没有选择配送地址'; |
|||
return false; |
|||
} |
|||
} |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
if (empty($order['extract_shop'])) { |
|||
$this->error = '您还没有选择自提门店'; |
|||
return false; |
|||
} |
|||
if (empty($linkman) || empty($phone)) { |
|||
$this->error = '您还没有填写联系人和电话'; |
|||
return false; |
|||
} |
|||
} |
|||
// 余额支付时判断用户余额是否足够 |
|||
if ($order['pay_type'] == PayTypeEnum::BALANCE) { |
|||
if ($this->user['balance'] < $order['order_pay_price']) { |
|||
$this->error = '您的余额不足,无法使用余额支付'; |
|||
return false; |
|||
} |
|||
} |
|||
// 验证拼单id是否合法 |
|||
if ($order['active_id'] > 0) { |
|||
// 拼单详情 |
|||
$detail = ActiveModel::detail($order['active_id']); |
|||
if (empty($detail)) { |
|||
$this->error = '很抱歉,拼单不存在'; |
|||
return false; |
|||
} |
|||
// 验证当前拼单是否允许加入新成员 |
|||
if (!$detail->checkAllowJoin()) { |
|||
$this->error = $detail->getError(); |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 当前订单是否存在和使用积分抵扣 |
|||
* @param $order |
|||
* @return bool |
|||
*/ |
|||
private function isExistPointsDeduction($order) |
|||
{ |
|||
return $order['is_allow_points'] && $order['is_use_points']; |
|||
} |
|||
|
|||
/** |
|||
* 新增订单记录 |
|||
* @param $order |
|||
* @param string $remark |
|||
* @return false|int |
|||
*/ |
|||
private function add(&$order, $remark = '') |
|||
{ |
|||
// 当前订单是否存在和使用积分抵扣 |
|||
$isExistPointsDeduction = $this->isExistPointsDeduction($order); |
|||
// 订单数据 |
|||
$data = [ |
|||
'user_id' => $this->user['user_id'], |
|||
'order_type' => $order['order_type'], |
|||
'active_id' => $order['active_id'], |
|||
'order_no' => $this->model->orderNo(), |
|||
'total_price' => $order['order_total_price'], |
|||
'order_price' => $order['order_price'], |
|||
'coupon_id' => $order['coupon_id'], |
|||
'coupon_money' => $order['coupon_money'], |
|||
'points_money' => $isExistPointsDeduction ? $order['points_money'] : 0.00, |
|||
'points_num' => $isExistPointsDeduction ? $order['points_num'] : 0, |
|||
'pay_price' => $order['order_pay_price'], |
|||
'delivery_type' => $order['delivery'], |
|||
'pay_type' => $order['pay_type'], |
|||
'buyer_remark' => trim($remark), |
|||
// 'order_source' => $this->orderSource['source'], |
|||
// 'order_source_id' => $this->orderSource['source_id'], |
|||
'points_bonus' => $order['points_bonus'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
]; |
|||
if ($order['delivery'] == DeliveryTypeEnum::EXPRESS) { |
|||
$data['express_price'] = $order['express_price']; |
|||
} elseif ($order['delivery'] == DeliveryTypeEnum::EXTRACT) { |
|||
$data['extract_shop_id'] = $order['extract_shop']['shop_id']; |
|||
} |
|||
// 保存订单记录 |
|||
return $this->model->save($data); |
|||
} |
|||
|
|||
/** |
|||
* 保存订单商品信息 |
|||
* @param $order |
|||
* @return int |
|||
*/ |
|||
private function saveOrderGoods(&$order) |
|||
{ |
|||
// 当前订单是否存在和使用积分抵扣 |
|||
$isExistPointsDeduction = $this->isExistPointsDeduction($order); |
|||
// 订单商品列表 |
|||
$goodsList = []; |
|||
foreach ($order['goods_list'] as $goods) { |
|||
/* @var GoodsModel $goods */ |
|||
$goodsList[] = [ |
|||
'user_id' => $this->user['user_id'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
'goods_id' => $goods['goods_id'], |
|||
'goods_name' => $goods['goods_name'], |
|||
'image_id' => $goods['image'][0]['image_id'], |
|||
'people' => $goods['people'], |
|||
'group_time' => $goods['group_time'], |
|||
'is_alone' => $goods['is_alone'], |
|||
'deduct_stock_type' => $goods['deduct_stock_type'], |
|||
'spec_type' => $goods['spec_type'], |
|||
'spec_sku_id' => $goods['goods_sku']['spec_sku_id'], |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'goods_attr' => $goods['goods_sku']['goods_attr'], |
|||
'content' => $goods['content'], |
|||
'goods_no' => $goods['goods_sku']['goods_no'], |
|||
'goods_price' => $goods['goods_sku']['goods_price'], |
|||
'line_price' => $goods['goods_sku']['line_price'], |
|||
'goods_weight' => $goods['goods_sku']['goods_weight'], |
|||
'is_user_grade' => (int)$goods['is_user_grade'], |
|||
'grade_ratio' => $goods['grade_ratio'], |
|||
'grade_goods_price' => $goods['grade_goods_price'], |
|||
'grade_total_money' => $goods['grade_total_money'], |
|||
'coupon_money' => $goods['coupon_money'], |
|||
'points_money' => $isExistPointsDeduction ? $goods['points_money'] : 0.00, |
|||
'points_num' => $isExistPointsDeduction ? $goods['points_num'] : 0, |
|||
'points_bonus' => $goods['points_bonus'], |
|||
'total_num' => $goods['total_num'], |
|||
'total_price' => $goods['total_price'], |
|||
'total_pay_price' => $goods['total_pay_price'], |
|||
'is_ind_dealer' => $goods['is_ind_dealer'], |
|||
'dealer_money_type' => $goods['dealer_money_type'], |
|||
'first_money' => $goods['first_money'], |
|||
'second_money' => $goods['second_money'], |
|||
'third_money' => $goods['third_money'], |
|||
]; |
|||
} |
|||
return $this->model->goods()->saveAll($goodsList); |
|||
} |
|||
|
|||
/** |
|||
* 更新商品库存 (针对下单减库存的商品) |
|||
* @param $goods_list |
|||
* @throws \Exception |
|||
*/ |
|||
private function updateGoodsStockNum($goods_list) |
|||
{ |
|||
$deductStockData = []; |
|||
foreach ($goods_list as $goods) { |
|||
// 下单减库存 |
|||
$goods['deduct_stock_type'] == 10 && $deductStockData[] = [ |
|||
'goods_sku_id' => $goods['goods_sku']['goods_sku_id'], |
|||
'stock_num' => ['dec', $goods['total_num']] |
|||
]; |
|||
} |
|||
!empty($deductStockData) && (new GoodsSkuModel)->isUpdate()->saveAll($deductStockData); |
|||
} |
|||
|
|||
/** |
|||
* 记录收货地址 |
|||
* @param $address |
|||
* @return false|\think\Model |
|||
*/ |
|||
private function saveOrderAddress($address) |
|||
{ |
|||
if ($address['region_id'] == 0 && !empty($address['district'])) { |
|||
$address['detail'] = $address['district'] . ' ' . $address['detail']; |
|||
} |
|||
return $this->model->address()->save([ |
|||
'user_id' => $this->user['user_id'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
'name' => $address['name'], |
|||
'phone' => $address['phone'], |
|||
'province_id' => $address['province_id'], |
|||
'city_id' => $address['city_id'], |
|||
'region_id' => $address['region_id'], |
|||
'detail' => $address['detail'], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 保存上门自提联系人 |
|||
* @param $linkman |
|||
* @param $phone |
|||
* @return false|\think\Model |
|||
*/ |
|||
private function saveOrderExtract($linkman, $phone) |
|||
{ |
|||
// 记忆上门自提联系人(缓存),用于下次自动填写 |
|||
UserService::setLastExtract($this->model['user_id'], trim($linkman), trim($phone)); |
|||
// 保存上门自提联系人(数据库) |
|||
return $this->model->extract()->save([ |
|||
'linkman' => trim($linkman), |
|||
'phone' => trim($phone), |
|||
'user_id' => $this->model['user_id'], |
|||
'wxapp_id' => $this->wxapp_id, |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* 设置错误信息 |
|||
* @param $error |
|||
*/ |
|||
protected function setError($error) |
|||
{ |
|||
empty($this->error) && $this->error = $error; |
|||
} |
|||
|
|||
/** |
|||
* 获取错误信息 |
|||
* @return mixed |
|||
*/ |
|||
public function getError() |
|||
{ |
|||
return $this->error; |
|||
} |
|||
|
|||
/** |
|||
* 是否存在错误 |
|||
* @return bool |
|||
*/ |
|||
public function hasError() |
|||
{ |
|||
return !empty($this->error); |
|||
} |
|||
|
|||
} |
|||
@ -1,152 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace app\api\service\sharing\order; |
|||
|
|||
use think\Hook; |
|||
use app\api\service\Basics; |
|||
use app\api\model\User as UserModel; |
|||
use app\api\model\sharing\Order as OrderModel; |
|||
use app\api\model\sharing\Goods as GoodsModel; |
|||
use app\api\model\sharing\Active as ActiveModel; |
|||
use app\api\model\user\BalanceLog as BalanceLogModel; |
|||
//use app\api\model\WxappPrepayId as WxappPrepayIdModel; |
|||
|
|||
use app\common\enum\user\balanceLog\Scene as SceneEnum; |
|||
use app\common\enum\order\PayType as PayTypeEnum; |
|||
use app\common\enum\OrderType as OrderTypeEnum; |
|||
|
|||
/** |
|||
* 订单支付成功服务类 |
|||
* Class PaySuccess |
|||
* @package app\api\service\sharing\order |
|||
*/ |
|||
class PaySuccess extends Basics |
|||
{ |
|||
// 订单模型 |
|||
public $model; |
|||
|
|||
// 当前用户信息 |
|||
private $user; |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* PaySuccess constructor. |
|||
* @param $orderNo |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
public function __construct($orderNo) |
|||
{ |
|||
// 实例化订单模型 |
|||
$this->model = OrderModel::getPayDetail($orderNo); |
|||
if (!empty($this->model)) { |
|||
$this->wxappId = $this->model['wxapp_id']; |
|||
} |
|||
// 获取用户信息 |
|||
$this->user = UserModel::detail($this->model['user_id']); |
|||
} |
|||
|
|||
/** |
|||
* 获取订单详情 |
|||
* @return OrderModel|null |
|||
*/ |
|||
public function getOrderInfo() |
|||
{ |
|||
return $this->model; |
|||
} |
|||
|
|||
/** |
|||
* 订单支付成功业务处理 |
|||
* @param $payType |
|||
* @param array $payData |
|||
* @return bool |
|||
*/ |
|||
public function onPaySuccess($payType, $payData = []) |
|||
{ |
|||
if (empty($this->model)) { |
|||
$this->error = '未找到该订单信息'; |
|||
return false; |
|||
} |
|||
// 更新付款状态 |
|||
$status = $this->updatePayStatus($payType, $payData); |
|||
// 订单支付成功行为 |
|||
if ($status == true) { |
|||
Hook::listen('order_pay_success', $this->model, OrderTypeEnum::SHARING); |
|||
} |
|||
return $status; |
|||
} |
|||
|
|||
/** |
|||
* 更新付款状态 |
|||
* @param $payType |
|||
* @param $payData |
|||
* @return bool |
|||
*/ |
|||
private function updatePayStatus($payType, $payData) |
|||
{ |
|||
// 验证余额支付时用户余额是否满足 |
|||
if ($payType == PayTypeEnum::BALANCE) { |
|||
if ($this->user['balance'] < $this->model['pay_price']) { |
|||
$this->error = '用户余额不足,无法使用余额支付'; |
|||
return false; |
|||
} |
|||
} |
|||
$this->model->transaction(function () use ($payType, $payData) { |
|||
// 更新商品库存、销量 |
|||
(new GoodsModel)->updateStockSales($this->model['goods']); |
|||
// 更新拼单记录 |
|||
$this->saveSharingActive($this->model['goods'][0]); |
|||
// 整理订单信息 |
|||
$order = ['pay_type' => $payType, 'pay_status' => 20, 'pay_time' => time()]; |
|||
if ($payType == PayTypeEnum::WECHAT) { |
|||
$order['transaction_id'] = $payData['transaction_id']; |
|||
} |
|||
// 更新订单状态 |
|||
$this->model->save($order); |
|||
// 累积用户总消费金额 |
|||
$this->user->setIncPayMoney($this->model['pay_price']); |
|||
// 余额支付 |
|||
if ($payType == PayTypeEnum::BALANCE) { |
|||
// 更新用户余额 |
|||
$this->user->setDec('balance', $this->model['pay_price']); |
|||
BalanceLogModel::add(SceneEnum::CONSUME, [ |
|||
'user_id' => $this->user['user_id'], |
|||
'money' => -$this->model['pay_price'], |
|||
], ['order_no' => $this->model['order_no']]); |
|||
} |
|||
// 微信支付 |
|||
if ($payType == PayTypeEnum::WECHAT) { |
|||
// 更新prepay_id记录 |
|||
// WxappPrepayIdModel::updatePayStatus($this->model['order_id'], OrderTypeEnum::SHARING); |
|||
} |
|||
}); |
|||
return true; |
|||
} |
|||
|
|||
/** |
|||
* 更新拼单记录 |
|||
* @param $goods |
|||
* @return bool |
|||
* @throws \app\common\exception\BaseException |
|||
* @throws \think\exception\DbException |
|||
*/ |
|||
private function saveSharingActive($goods) |
|||
{ |
|||
// 新增/更新拼单记录 |
|||
if ($this->model['order_type']['value'] != 20) { |
|||
return false; |
|||
} |
|||
// 拼单模型 |
|||
$ActiveModel = new ActiveModel; |
|||
// 参与他人的拼单, 更新拼单记录 |
|||
if ($this->model['active_id'] > 0) { |
|||
$ActiveModel = $ActiveModel::detail($this->model['active_id']); |
|||
return $ActiveModel->onUpdate($this->model['user_id'], $this->model['order_id']); |
|||
} |
|||
// 自己发起的拼单, 新增拼单记录 |
|||
$ActiveModel->onCreate($this->model['user_id'], $this->model['order_id'], $goods); |
|||
// 记录拼单id |
|||
$this->model['active_id'] = $ActiveModel['active_id']; |
|||
return true; |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue