|
|
@@ -0,0 +1,693 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace app\common\service;
|
|
|
+
|
|
|
+use app\common\model\ShopCartModel;
|
|
|
+use app\common\model\ShopGoods;
|
|
|
+use app\common\model\ShopGoodsModel;
|
|
|
+use app\common\model\ShopGoodsSpec;
|
|
|
+use app\common\model\ShopOrder;
|
|
|
+use app\common\model\ShopOrderGoodsModel;
|
|
|
+use app\common\model\ShopOrderShippingModel;
|
|
|
+use app\common\model\UserAddressModel;
|
|
|
+use jobs\ShopOrderJob;
|
|
|
+use think\Exception;
|
|
|
+use think\facade\Db;
|
|
|
+use utils\Queue;
|
|
|
+use utils\RedisCache;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 商城订单服务 by wes
|
|
|
+ * Class ShopOrderService
|
|
|
+ * @package app\common\service
|
|
|
+ */
|
|
|
+class ShopOrderService
|
|
|
+{
|
|
|
+ protected static $instance = null;
|
|
|
+ protected $model = null;
|
|
|
+
|
|
|
+ public function __construct()
|
|
|
+ {
|
|
|
+ $this->model = new ShopOrder();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 静态化入口
|
|
|
+ * @return static|null
|
|
|
+ */
|
|
|
+ public static function make()
|
|
|
+ {
|
|
|
+ if (!self::$instance) {
|
|
|
+ self::$instance = new static();
|
|
|
+ }
|
|
|
+
|
|
|
+ return self::$instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 商城下单
|
|
|
+ * @param $uid 用户ID
|
|
|
+ * @param $buyGoods 购买的商品数组
|
|
|
+ * @param $payType 支付方式
|
|
|
+ * @param $request 请求数据
|
|
|
+ * @param int $cartIds 购物车ID数组
|
|
|
+ * @param int $cls 赠送月卡功能开关
|
|
|
+ * @return array
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public function createOrder($uid, $buyGoods, $payType, $request, $cartIds = 0, $cls = 0)
|
|
|
+ {
|
|
|
+ // 获取收货地址信息
|
|
|
+ $orderType = 1; // 订单类型 1商城订单 2积分订单 3.兑换券 4.锁定积分兑换 5.福袋发货订单
|
|
|
+ $addressId = $request->post('address', '');
|
|
|
+ $remark = $request->post('order_remark', '');
|
|
|
+ if (!$addressId || !$userAddress = UserAddressModel::getAddressIdDetails((int)$addressId)) {
|
|
|
+ throw new Exception('获取收货地址失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ $addressUid = isset($userAddress['uid']) ? $userAddress['uid'] : 0;
|
|
|
+ if ($addressUid != $uid) {
|
|
|
+ throw new Exception('收货地址信息异常');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (empty($buyGoods)) {
|
|
|
+ throw new Exception('商品参数错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 未支付订单数量验证
|
|
|
+ $count = ShopOrderService::make()->checkBuyCountByTime($uid, 1, 0);
|
|
|
+ $noPayLimit = env('common.ORDER_NO_PAY_LIMIT', 5);
|
|
|
+ if ($count >= $noPayLimit) {
|
|
|
+ throw new Exception("2小时内未支付的订单不能超过{$noPayLimit}个,下单失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 订单商品数据处理
|
|
|
+ $i = 0;
|
|
|
+ $nowTime = time();
|
|
|
+ $orderId = $this->model->max('order_id') + 1;
|
|
|
+ $orderDatas = $orderGoods = $orders = $shippingList = [];
|
|
|
+ $expireTime = time() + intval(env('common.ORDER_EXPIRES_TIME'));
|
|
|
+ Db::startTrans();
|
|
|
+ try {
|
|
|
+ foreach ($buyGoods as $k => $v) {
|
|
|
+ $goodsSn = isset($v['goods_sn']) ? trim($v['goods_sn']) : 0;
|
|
|
+ $specId = isset($v['spec_id']) ? trim($v['spec_id']) : 0;
|
|
|
+ $num = isset($v['num']) ? intval($v['num']) : 0;
|
|
|
+ if ($num < 1) {
|
|
|
+ throw new Exception('请先选择商品数量哦');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 商品信息验证
|
|
|
+ $goodsInfo = ShopGoodsService::make()->getCacheInfo($v['goods_sn']);
|
|
|
+ if (!$goodsInfo) {
|
|
|
+ throw new Exception('商品参数错误或已下架,请返回刷新列表');
|
|
|
+ }
|
|
|
+ if ($goodsInfo['goods_type'] == 2) {
|
|
|
+ throw new Exception('商福袋商品不能购买');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 商品限购验证
|
|
|
+ if ($goodsInfo['restrictions_num'] > 0) {
|
|
|
+ $count = ShopOrderGoodsService::make()->getCountByUserAndGoods($uid, $goodsSn);
|
|
|
+
|
|
|
+ if ($count > $goodsInfo['restrictions_num']) {
|
|
|
+ throw new Exception('超过限购');
|
|
|
+ }
|
|
|
+ if ($v['num'] + $count > $goodsInfo['restrictions_num']) {
|
|
|
+ throw new Exception('超过限购数量,还可购买:' . ($goodsInfo['restrictions_num'] - $count) . '件');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 商品库存验证
|
|
|
+ if ($goodsSn && $specId && $num > 0) {
|
|
|
+ $stock = ShopGoodsSpecService::make()->getStock($goodsSn, $specId);
|
|
|
+ if ($num > $stock) {
|
|
|
+ throw new Exception('下单失败,所选商品含有库存不足的商品:SN-' . $goodsSn);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 是否赠送月卡
|
|
|
+ $giveVip = 0;
|
|
|
+ $goodsGiveVip = isset($goodsInfo['give_vip']) ? $goodsInfo['give_vip'] : 0;
|
|
|
+ if ($cls == 1 && $goodsGiveVip) {
|
|
|
+ $giveVip = $goodsGiveVip;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 同商品订单数据
|
|
|
+ if (!isset($orderDatas[$goodsSn]) || empty($orderDatas[$goodsSn])) {
|
|
|
+ $orderSn = createdOrderSn();
|
|
|
+ $orders[] = $orderSn;
|
|
|
+ $orderId = $orderId + $i;
|
|
|
+ $orderDatas[$goodsSn] = [
|
|
|
+ 'order_id' => $orderId,
|
|
|
+ 'order_sn' => $orderSn,
|
|
|
+ 'total_price' => 0,
|
|
|
+ 'payment' => 0,
|
|
|
+ 'user_id' => $uid,
|
|
|
+ 'status' => 0, // 待付款
|
|
|
+ 'ship_postfee' => 0,
|
|
|
+ 'rebate_score' => 0, //总返利积分
|
|
|
+ 'created_time' => date('Y-m-d H:i:s', $nowTime + $i),
|
|
|
+ 'updated_time' => date('Y-m-d H:i:s', $nowTime + $i),
|
|
|
+ 'give_vip' => $giveVip,
|
|
|
+ 'order_remark' => $remark,
|
|
|
+ 'pay_type' => $payType,
|
|
|
+ 'order_type' => $orderType,
|
|
|
+ 'coupon_number' => '',
|
|
|
+ 'expires_time' => sr_getcurtime($expireTime + $i),
|
|
|
+ 'supplier_name' => isset($goodsInfo['supplier_name']) ? $goodsInfo['supplier_name'] : '',
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 构建订单配送数据
|
|
|
+ $shippingList[$orderSn] = [
|
|
|
+ 'order_id' => $orderId,
|
|
|
+ 'sp_name' => $userAddress['name'],
|
|
|
+ 'sp_mobile' => $userAddress['mobile'],
|
|
|
+ 'sp_province' => $userAddress['sp_province'],
|
|
|
+ 'sp_city' => $userAddress['sp_city'],
|
|
|
+ 'sp_county' => $userAddress['sp_county'],
|
|
|
+ 'sp_remark' => $userAddress['remark'],
|
|
|
+ 'sp_mergename' => $userAddress['mergename'],
|
|
|
+ 'created_time' => date('Y-m-d H:i:s', $nowTime + $i),
|
|
|
+ 'updated_time' => date('Y-m-d H:i:s', $nowTime + $i),
|
|
|
+ ];
|
|
|
+
|
|
|
+ $i++;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 订单商品规格数据
|
|
|
+ $goodsSpec = ShopGoodsSpecService::make()->getDataByGoods($goodsInfo['goods_id'], $specId);
|
|
|
+ $goodsSpecId = isset($goodsSpec['goods_spec_id']) ? $goodsSpec['goods_spec_id'] : 0;
|
|
|
+ $weight = isset($goodsSpec['weight']) ? $goodsSpec['weight'] : 0;
|
|
|
+ $price = isset($goodsSpec['price']) ? $goodsSpec['price'] : 0;
|
|
|
+
|
|
|
+ // 同一个商品数据合计
|
|
|
+ $totalFee = bcmul($num, $price, 3);
|
|
|
+ $totalWeight = bcmul($num, $weight, 3);
|
|
|
+ $orderDatas[$goodsSn]['total_weight'] = isset($orderDatas[$goodsSn]['total_weight']) ? bcadd($orderDatas[$goodsSn]['total_weight'], $totalWeight, 3) : $totalWeight;
|
|
|
+ $orderDatas[$goodsSn]['total_price'] = isset($orderDatas[$goodsSn]['total_price']) ? bcadd($orderDatas[$goodsSn]['total_price'], $totalFee, 3) : $totalFee;
|
|
|
+ $orderDatas[$goodsSn]['num'] = isset($orderDatas[$goodsSn]['num']) ? intval($orderDatas[$goodsSn]['num'] + $num) : $num;
|
|
|
+
|
|
|
+ // 返还积分/金额合计
|
|
|
+ $rebateScore = isset($goodsInfo['rebate_score']) ? bcmul($num, $goodsInfo['rebate_score'], 3) : 0;
|
|
|
+ $rebateMoney = isset($goodsInfo['rebate_money']) ? bcmul($num, $goodsInfo['rebate_money'], 3) : 0;
|
|
|
+ $orderDatas[$goodsSn]['rebate_score'] = isset($orderDatas[$goodsSn]['rebate_score']) ? bcadd($orderDatas[$goodsSn]['rebate_score'], $rebateScore, 3) : $rebateScore;
|
|
|
+ $orderDatas[$goodsSn]['rebate_money'] = isset($orderDatas[$goodsSn]['rebate_money']) ? bcadd($orderDatas[$goodsSn]['rebate_money'], $rebateScore, 3) : $rebateMoney;
|
|
|
+ $orderDatas[$goodsSn]['rebate_money'] = 0; // 临时覆盖值
|
|
|
+
|
|
|
+ // 邮费计算合计
|
|
|
+ $postFee = 0;
|
|
|
+ $costPostFee = true;
|
|
|
+ if ($costPostFee) {
|
|
|
+ $city = isset($userAddress['city']) ? $userAddress['city'] : '';
|
|
|
+ $postData = [
|
|
|
+ 'goods_sn' => $goodsInfo['goods_sn'],
|
|
|
+ 'num' => $orderDatas[$goodsSn]['num'],
|
|
|
+ 'total_price' => $orderDatas[$goodsSn]['total_price'],
|
|
|
+ 'total_weight' => $orderDatas[$goodsSn]['total_weight'],
|
|
|
+ ];
|
|
|
+ $postTemplateId = isset($goodsInfo['post_template_id']) ? $goodsInfo['post_template_id'] : 0;
|
|
|
+ $postFee = ShopOrderService::make()->postFee($city, $postData, $postTemplateId); // 邮费
|
|
|
+ }
|
|
|
+
|
|
|
+ $orderDatas[$goodsSn]['ship_postfee'] = $postFee;
|
|
|
+ $orderDatas[$goodsSn]['payment'] = bcadd($orderDatas[$goodsSn]['total_price'], $postFee, 3);
|
|
|
+
|
|
|
+ // 订单商品
|
|
|
+ $orderGoods[] = [
|
|
|
+ 'order_id' => $orderDatas[$goodsSn]['order_id'],
|
|
|
+ 'goods_id' => $goodsInfo['goods_id'],
|
|
|
+ 'goods_name' => $goodsInfo['goods_name'],
|
|
|
+ 'goods_category' => $goodsInfo['category'],
|
|
|
+ 'goods_img' => isset($goodsSpec['picture']) && $goodsSpec['picture'] ? $goodsSpec['picture'] : $goodsInfo['goods_img'],
|
|
|
+ 'num' => $num,
|
|
|
+ 'price' => $price,
|
|
|
+ 'total_fee' => $totalFee,
|
|
|
+ 'goods_spec_id' => $goodsSpecId,
|
|
|
+ 'spec_ids' => isset($goodsSpec['spec_ids']) ? $goodsSpec['spec_ids'] : '',
|
|
|
+ 'spec_text' => isset($goodsSpec['spec_text']) ? $goodsSpec['spec_text'] : '',
|
|
|
+ 'rebate_score' => isset($goodsSpec['rebate_score']) ? $goodsSpec['rebate_score'] : 0,
|
|
|
+ 'total_rebate_score' => $orderDatas[$goodsSn]['rebate_score'],
|
|
|
+ 'uid' => $uid
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 扣库存
|
|
|
+ if (!ShopGoodsSpec::where(['goods_spec_id' => $goodsSpecId])->dec('stock', $num)->update()) {
|
|
|
+ throw new Exception('商品库存处理失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 扣除商品总库存
|
|
|
+ if (!ShopGoods::where(['goods_id' => $goodsInfo['goods_id']])->dec('inventory', $num)->update()) {
|
|
|
+ throw new Exception('商品库存处理失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 增加销量
|
|
|
+ if (in_array($orderType, [3, 4, 5])) {
|
|
|
+ if (!ShopGoodsModel::where(['goods_id' => $goodsInfo['goods_id']])
|
|
|
+ ->inc('sales_volume', $num)
|
|
|
+ ->inc('real_sales_volume', $num)
|
|
|
+ ->update()) {
|
|
|
+ throw new Exception('商品销量处理失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除商品相关实时数据缓存
|
|
|
+ RedisCache::keyDel('caches:goods:list_*');
|
|
|
+ RedisCache::keyDel('caches:goodsSpec:list_*');
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if (empty($orders) || empty($orderGoods)) {
|
|
|
+ throw new Exception('订单数据错误,下单失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 批量写入订单数据
|
|
|
+ $data = array_values($orderDatas);
|
|
|
+ if (!$this->model->insertAll($data)) {
|
|
|
+ Db::rollback();
|
|
|
+ throw new Exception('下单失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 批量写入订单商品数据
|
|
|
+ $data = array_values($orderGoods);
|
|
|
+ if (!ShopOrderGoodsModel::insertAll($data)) {
|
|
|
+ Db::rollback();
|
|
|
+ throw new Exception('下单失败,订单商品处理错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入配送单数据
|
|
|
+ $data = array_values($shippingList);
|
|
|
+ if (!ShopOrderShippingModel::insertAll($data)) {
|
|
|
+ Db::rollback();
|
|
|
+ throw new Exception('下单失败,订单配送数据处理错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 超时过期订单队列任务处理
|
|
|
+ if (in_array($orderType, [1, 3]) && $orders) {
|
|
|
+ $ex_time = intval(env('common.ORDER_EXPIRES_TIME', 60 * 60));
|
|
|
+ Queue::instance()->log('订单过期执行成功')
|
|
|
+ ->job(ShopOrderJob::class)
|
|
|
+ ->do('ShopOrderExpired')
|
|
|
+ ->secs($ex_time)
|
|
|
+ ->push([$orders[0]]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证检查购物车数据
|
|
|
+ if ($cartIds && is_array($cartIds)) {
|
|
|
+ ShopCartModel::where('id', 'in', $cartIds)->where(['user_id' => $uid])->delete();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除单一购物车数据
|
|
|
+ $cartId = $request->post('cart_id', 0);
|
|
|
+ if ($cartId) {
|
|
|
+ ShopCartModel::where('id', $cartId)->delete();
|
|
|
+ }
|
|
|
+
|
|
|
+ $cacheKey = "caches:orders:u_{$uid}_{$orderType}:create_{$payType}_" . date('YmdHis') . rand(10, 99);
|
|
|
+ RedisCache::set($cacheKey, ['uid' => $uid, 'orderDatas' => $orderDatas, 'shipping' => $shippingList, 'orderGoods' => $orderGoods, 'post' => $request->post()], 7200);
|
|
|
+
|
|
|
+ Db::commit();
|
|
|
+ return $orders;
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ throw new Exception($e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下单数据
|
|
|
+ * @param $buyGoods 购买商品
|
|
|
+ * @param $request
|
|
|
+ * @return array
|
|
|
+ * @throws Exception
|
|
|
+ * @throws \think\db\exception\DataNotFoundException
|
|
|
+ * @throws \think\db\exception\DbException
|
|
|
+ * @throws \think\db\exception\ModelNotFoundException
|
|
|
+ */
|
|
|
+ public function buyDetail($buyGoods, $request)
|
|
|
+ {
|
|
|
+ $addressId = $request->post('address_id', 0);
|
|
|
+ if (!$address = UserAddressModel::getAddressIdDetails($addressId, $request->uid, 1)) {
|
|
|
+ throw new Exception('订单地址错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ $details = $goodsSnArr = [];
|
|
|
+ $paymentTotal = 0; // 总订单金额
|
|
|
+ $totalRebateScore = 0; // 总返还积分
|
|
|
+ $totalNum = 0; // 商品总数量
|
|
|
+ $curXzmoney = SystemConfigService::make()->getConfigByName('xz_cur_money', '', 'xzconfig');
|
|
|
+ foreach ($buyGoods as $k => $v) {
|
|
|
+ $goodsSn = isset($v['goods_sn']) ? $v['goods_sn'] : '';
|
|
|
+ $specId = isset($v['spec_id']) ? $v['spec_id'] : 0;
|
|
|
+ $num = isset($v['num']) ? intval($v['num']) : 0;
|
|
|
+ $totalNum += $num;
|
|
|
+ if ($num <= 0) {
|
|
|
+ throw new Exception('下单失败,请先选择商品数量');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 商品信息
|
|
|
+ if (!$goodsSn || !$goodsInfo = ShopGoodsService::make()->getCacheInfo($goodsSn)) {
|
|
|
+ throw new Exception('下单失败,商品参数错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 订单商品规格数据
|
|
|
+ $goodsSnArr[] = $goodsSn;
|
|
|
+ $goodsSpec = ShopGoodsSpecService::make()->getDataByGoods($goodsInfo['goods_id'], $specId);
|
|
|
+ $weight = isset($goodsSpec['weight']) ? $goodsSpec['weight'] : 0;
|
|
|
+ $price = isset($goodsSpec['price']) ? $goodsSpec['price'] : 0;
|
|
|
+ if (empty($goodsSpec)) {
|
|
|
+ throw new Exception('下单失败,存在无效商品');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 商品数据
|
|
|
+ $postFee = '0.00';
|
|
|
+ $rebateScore = bcmul($num, $goodsSpec['rebate_score'], 2);
|
|
|
+ $totalFee = bcmul($num, $price, 2);
|
|
|
+ $totalWeight = bcmul($num, $weight, 3);
|
|
|
+
|
|
|
+ // 组装订单商品数据
|
|
|
+ $details[$goodsSn]['total_rebate_score'] = isset($details[$goodsSn]['total_rebate_score']) ? bcadd($details[$goodsSn]['total_rebate_score'], $rebateScore, 3) : $rebateScore; //总返利积分
|
|
|
+ $details[$goodsSn]['total_num'] = isset($details[$goodsSn]['total_num']) ? bcadd($details[$goodsSn]['total_num'], $num, 3) : $num; //总数量
|
|
|
+ $details[$goodsSn]['total_price'] = isset($details[$goodsSn]['total_price']) ? bcadd($details[$goodsSn]['total_price'], $totalFee, 3) : $totalFee; // 总金额
|
|
|
+ $details[$goodsSn]['total_weight'] = isset($details[$goodsSn]['total_weight']) ? bcadd($details[$goodsSn]['total_weight'], $totalWeight, 3) : $totalWeight; // 总重量
|
|
|
+ $details[$goodsSn]['post_fee'] = $postFee;
|
|
|
+ $details[$goodsSn]['payment'] = bcadd($details[$goodsSn]['total_price'], $details[$goodsSn]['post_fee'], 2);
|
|
|
+ $details[$goodsSn]['supplier_name'] = $goodsInfo['supplier_name'];
|
|
|
+
|
|
|
+ $goodsName = isset($goodsInfo['goods_name']) ? $goodsInfo['goods_name'] : '';
|
|
|
+ $goodsName = $goodsName ? str_replace(' ', '', $goodsName) : '';
|
|
|
+ $goodsName = mb_strlen($goodsName, 'utf-8') > 20 ? mb_substr($goodsName, 0, 19, 'utf-8') : $goodsName;
|
|
|
+ $goodsType = isset($goodsInfo['goods_type']) ? $goodsInfo['goods_type'] : 0;
|
|
|
+ if ($goodsType == 5) {
|
|
|
+ $price = getXzPirceWithPrice($curXzmoney, $price);
|
|
|
+ $totalFee = getXzPirceWithPrice($curXzmoney, $totalFee);
|
|
|
+ }
|
|
|
+ $goods = [
|
|
|
+ 'goods_sn' => $goodsInfo['goods_sn'],
|
|
|
+ 'goods_id' => $goodsInfo['goods_id'],
|
|
|
+ 'goods_type' => $goodsType,
|
|
|
+ 'goods_name' => $goodsName,
|
|
|
+ 'picture' => $goodsSpec['picture'] ?: $goodsInfo['goods_img'],
|
|
|
+ 'num' => $num, //数量
|
|
|
+ 'price' => $price,//单价
|
|
|
+ 'weight' => $goodsSpec['weight'], //重量
|
|
|
+ 'total_fee' => $totalFee, //总价
|
|
|
+ 'rebate_score' => $goodsSpec['rebate_score'],//单个返利积分
|
|
|
+ 'total_items_rebate_score' => $rebateScore,//总返利积分
|
|
|
+ 'spec_ids' => $goodsSpec['spec_ids'],
|
|
|
+ 'spec_text' => $goodsSpec['spec_text'],
|
|
|
+ 'post_template_id' => $goodsInfo['post_template_id'], //是否包邮,否就是运费模板ID
|
|
|
+ 'stock' => $goodsSpec['stock'],
|
|
|
+ 'supplier_name' => $goodsInfo['supplier_name']
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 参数合计
|
|
|
+ $totalNum += $num;
|
|
|
+ $paymentTotal += bcadd($totalFee, $postFee, 3);
|
|
|
+ $totalRebateScore = bcadd($totalRebateScore, $rebateScore, 3);
|
|
|
+ $details[$goodsSn]['goods'][] = $goods;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ $total = [
|
|
|
+ 'count_payment' => sprintf("%.2f", $paymentTotal),
|
|
|
+ 'count_rebate_score' => $totalRebateScore,
|
|
|
+ 'count_num' => $totalNum,
|
|
|
+ ];
|
|
|
+
|
|
|
+ return ['address' => $address, 'buyDetail' => array_values($details), 'total' => $total];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消订单
|
|
|
+ */
|
|
|
+ public function cancelOrder($data, $userId)
|
|
|
+ {
|
|
|
+ $nowTime = date('Y-m-d H:i:s', time());
|
|
|
+ $data = $this->model->where(['order_sn' => $data['order_sn'], 'user_id' => $userId])->field('order_id,status,order_sn')->findOrEmpty();
|
|
|
+ if (empty($data)) {
|
|
|
+ throw new Exception('参数错误');
|
|
|
+ }
|
|
|
+ if ($data['status'] != 0) {
|
|
|
+ throw new Exception('订单状态错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::startTrans();
|
|
|
+ if (!$this->model->where(['order_sn' => $data['order_sn']])->save(['status' => 3, 'updated_time' => $nowTime])) {
|
|
|
+ Db::rollback();
|
|
|
+ throw new Exception('取消失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ $updateStock = $this->model->alias('a')->where(['a.order_sn' => $data['order_sn'], 'a.user_id' => $userId])
|
|
|
+ ->leftJoin('shop_order_goods og', 'og.order_id=a.order_id')
|
|
|
+ ->leftJoin('shop_goods_spec gs', 'gs.goods_spec_id=og.goods_spec_id')
|
|
|
+ ->leftJoin('shop_goods g', 'g.goods_id=og.goods_id')
|
|
|
+ ->update([
|
|
|
+ 'g.inventory'=> Db::raw('g.inventory + og.num'),
|
|
|
+ 'gs.stock'=> Db::raw('gs.stock + og.num'),
|
|
|
+ ]);
|
|
|
+ if (!$updateStock) {
|
|
|
+ Db::rollback();
|
|
|
+ throw new Exception('取消失败,库存处理错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ Db::commit();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 确定订单
|
|
|
+ */
|
|
|
+ public function receiveOrder($data, $userId)
|
|
|
+ {
|
|
|
+ $nowTime = date('Y-m-d H:i:s', time());
|
|
|
+ $data = $this->model->where(['order_sn' => $data['order_sn'], 'user_id' => $userId])->findOrEmpty()->toArray();
|
|
|
+ if (empty($data)) {
|
|
|
+ throw new Exception('参数错误');
|
|
|
+ }
|
|
|
+ if ($data['status'] != 2) {
|
|
|
+ throw new Exception('订单状态错误');
|
|
|
+ }
|
|
|
+
|
|
|
+ return $this->model->where(['order_sn' => $data['order_sn']])->save(['status' => 4, 'updated_time' => $nowTime]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算运费
|
|
|
+ * @param $address 用户地址
|
|
|
+ * @param $data 商品数据
|
|
|
+ * @param $express_template_id 模板ID
|
|
|
+ * 获取运费
|
|
|
+ */
|
|
|
+ public function postFee($address, $data, $express_template_id)
|
|
|
+ {
|
|
|
+ //获取运费模板
|
|
|
+ $expressDelivery = ExpressDeliveryService::make()->getDataByTemplate($express_template_id);
|
|
|
+ //获取运费模板列表
|
|
|
+ $expressDeliveryItems = ExpressShippingMethodService::make()->getListByTemplate($express_template_id);
|
|
|
+
|
|
|
+ $price_method_field = '';
|
|
|
+ switch ($expressDelivery['price_method']) {
|
|
|
+ case 1:
|
|
|
+ $price_method_field = $data['total_price']; //按金额
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ $price_method_field = $data['num']; //按件数
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ $price_method_field = $data['total_weight']; //按重量
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($expressDelivery['price_method'] == 1) {
|
|
|
+
|
|
|
+ //计算默认运费 【配送区域、免运费金额、达标时运费、未达标时运费;】
|
|
|
+ if ($price_method_field < $expressDelivery['default_free_price']) {
|
|
|
+ $default_postfee = $expressDelivery['default_fastandard_price'];
|
|
|
+ } else {
|
|
|
+ //达标时运费
|
|
|
+ $default_postfee = $expressDelivery['default_price'];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (empty($expressDeliveryItems)) {
|
|
|
+ return $default_postfee;
|
|
|
+ }
|
|
|
+
|
|
|
+ //按指定地区计算邮费
|
|
|
+ foreach ($expressDeliveryItems as $k => $node) {
|
|
|
+ if (in_array($address, explode(',', $node['address_items_ids']))) {
|
|
|
+ //未达标运费
|
|
|
+ if ($price_method_field < $node['free_price']) {
|
|
|
+ return $node['fastandard_price'];
|
|
|
+ } else {
|
|
|
+ //达标时运费
|
|
|
+ return $node['price'];
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return $default_postfee;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //按件数 重量计费 【配送区域、首件、达标时运费、续件、未达标时运费】
|
|
|
+ //计算默认运费
|
|
|
+ if ($price_method_field <= $expressDelivery['default_pieces']) {
|
|
|
+ $default_postfee = $expressDelivery['default_price'];
|
|
|
+ } else {
|
|
|
+ //达到续件条件时的运费
|
|
|
+ if ($expressDelivery['add_pieces']) {
|
|
|
+ //配置过续件费用
|
|
|
+ //续件数 = (下单件数 - 首件) /续件数
|
|
|
+ //总运费 = 首件运费 + (续件数 * 续件费用)
|
|
|
+ $add_pieces = bcdiv(($price_method_field - $expressDelivery['default_pieces']), $expressDelivery['add_pieces'], 2);
|
|
|
+ $default_postfee = bcadd($expressDelivery['default_price'], bcmul($add_pieces, $expressDelivery['add_price'], 2), 2);
|
|
|
+ } else {
|
|
|
+ //未配置过续件,按首件价格
|
|
|
+ $default_postfee = $expressDelivery['default_price'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (empty($expressDeliveryItems)) {
|
|
|
+ return $default_postfee;
|
|
|
+ }
|
|
|
+ //按指定地区计算邮费
|
|
|
+ foreach ($expressDeliveryItems as $k => $node) {
|
|
|
+ if (in_array($address, explode(',', $node['address_items_ids']))) {
|
|
|
+ //未达到续件条件时的运费
|
|
|
+ if ($price_method_field <= $node['pieces']) {
|
|
|
+ return $node['price'];
|
|
|
+ } else {
|
|
|
+ //达到续件条件时的运费
|
|
|
+ if ($node['add_pieces']) {
|
|
|
+ //配置过续件费用
|
|
|
+ //续件数 = (下单件数 - 首件) /续件数
|
|
|
+ //总运费 = 首件运费 + (续件数 * 续件费用)
|
|
|
+ $add_pieces = bcdiv(($price_method_field - $node['pieces']), $node['add_pieces'], 2);
|
|
|
+ return bcadd($node['price'], bcmul($add_pieces, $node['add_price'], 2), 2);
|
|
|
+ } else {
|
|
|
+ //未配置过续件,按首件价格
|
|
|
+ return $node['price'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return $default_postfee;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证商品库存
|
|
|
+ * @param $data
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public function checkStock($data)
|
|
|
+ {
|
|
|
+ foreach ($data as $key => $value) {
|
|
|
+ $num = array_sum(array_column($value, 'num'));
|
|
|
+ $goodsSn = isset($value[0]['goods_sn']) ? $value[0]['goods_sn'] : 0;
|
|
|
+ $specId = isset($value[0]['spec_id']) ? $value[0]['spec_id'] : 0;
|
|
|
+ if ($goodsSn && $specId && $num > 0) {
|
|
|
+ $stock = ShopGoodsSpecService::make()->getStock($goodsSn, $specId);
|
|
|
+ if ($num > $stock) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 2小时内未付款订单数
|
|
|
+ * @param $uid
|
|
|
+ * @param int $orderType
|
|
|
+ * @param int $status
|
|
|
+ * @return array|int|mixed
|
|
|
+ * @throws \think\db\exception\DbException
|
|
|
+ */
|
|
|
+ public function checkBuyCountByTime($uid, $orderType = 1, $status = 0)
|
|
|
+ {
|
|
|
+ $cacheKey = "caches:orders:unpayCount:{$uid}_{$orderType}_{$status}";
|
|
|
+ $data = RedisCache::get($cacheKey);
|
|
|
+ if ($data) {
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ $data = $this->model->where(['user_id' => $uid, 'order_type' => $orderType, 'status' => $status])
|
|
|
+ ->whereTime('created_time', '-2 hours')
|
|
|
+ ->count('order_id');
|
|
|
+ if ($data) {
|
|
|
+ RedisCache::set($cacheKey, $data, rand(3, 5));
|
|
|
+ }
|
|
|
+
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据单号获取订单信息(有缓存)
|
|
|
+ * @param $orderSn 订单号
|
|
|
+ * @param int $uid 所属用户ID
|
|
|
+ * @param string $field 返沪字段
|
|
|
+ * @param bool $cache 是否缓存,默认是
|
|
|
+ * @return array|mixed
|
|
|
+ */
|
|
|
+ public function getInfoBySn($orderSn, $uid=0, $field='', $cache=true)
|
|
|
+ {
|
|
|
+ $cacheKey = "caches:orders:info:sn{$orderSn}_{$uid}".($field? '_'.md5($field):'');
|
|
|
+ $data = RedisCache::get($cacheKey);
|
|
|
+ if($data && $cache){
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+ $where = ['order_sn'=> $orderSn,'user_id'=> 0,'status'=>1];
|
|
|
+ if($uid>0){
|
|
|
+ $where['user_id'] = $uid;
|
|
|
+ }else{
|
|
|
+ unset($where['user_id']);
|
|
|
+ }
|
|
|
+
|
|
|
+ $field = $field? $field : 'order_id,order_sn,user_id,payment,total_price,status,pay_type,rebate_score,rebate_money,num,order_type,give_vip,coupon_number,hg_status,hg_enable';
|
|
|
+ $data = $this->model->where($where)->field($field)->findOrEmpty();
|
|
|
+ $data = $data? $data->toArray() : [];
|
|
|
+ if($data && $cache){
|
|
|
+ RedisCache::set($cacheKey, $data, rand(5,10));
|
|
|
+ }
|
|
|
+
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据单号获取订单信息(有缓存)
|
|
|
+ * @param $orderSn 订单号
|
|
|
+ * @param int $uid 所属用户ID
|
|
|
+ * @param string $field 返沪字段
|
|
|
+ * @param bool $cache 是否缓存,默认是
|
|
|
+ * @return array|mixed
|
|
|
+ */
|
|
|
+ public function getInfoById($orderId, $uid=0, $field='', $cache=true)
|
|
|
+ {
|
|
|
+ $cacheKey = "caches:orders:info:id{$orderId}_{$uid}".($field? '_'.md5($field):'');
|
|
|
+ $data = RedisCache::get($cacheKey);
|
|
|
+ if($data && $cache){
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+ $where = ['order_id'=> $orderId,'user_id'=> 0,'status'=>1];
|
|
|
+ if($uid>0){
|
|
|
+ $where['user_id'] = $uid;
|
|
|
+ }else{
|
|
|
+ unset($where['user_id']);
|
|
|
+ }
|
|
|
+
|
|
|
+ $field = $field? $field : 'order_id,order_sn,user_id,payment,total_price,status,pay_type,rebate_score,rebate_money,num,order_type,give_vip,coupon_number,hg_status,hg_enable';
|
|
|
+ $data = $this->model->where($where)->field($field)->findOrEmpty();
|
|
|
+ $data = $data? $data->toArray() : [];
|
|
|
+ if($data && $cache){
|
|
|
+ RedisCache::set($cacheKey, $data, rand(5,10));
|
|
|
+ }
|
|
|
+
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+}
|