// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Models\GoodsCategoryModel; use App\Models\GoodsCollectModel; use App\Models\GoodsModel; use App\Models\GoodsSkuModel; use App\Models\MemberCouponModel; use App\Models\MemberModel; use App\Services\BaseService; use App\Services\ConfigService; use App\Services\RedisService; /** * 商品管理-服务类 * @author laravel开发员 * @since 2020/11/11 * @package App\Services\Api */ class GoodsService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 */ public function __construct() { $this->model = new GoodsModel(); } /** * 静态入口 */ public static function make() { if (!self::$instance) { self::$instance = new static(); } return self::$instance; } /** * 列表数据 * @param $params * @param int $pageSize * @return array */ public function getDataList($params, $pageSize = 15) { $cacheKey = "caches:goods:list_{$pageSize}_" . ($params ? md5(json_encode($params)) : 0); $datas = RedisService::get($cacheKey); if (empty($datas)) { $query = $this->getQuery($params) ->orderBy('a.create_time', 'desc') ->orderBy('a.id', 'desc'); $field = ["a.*"]; $list = $query->select($field) ->paginate($pageSize > 0 ? $pageSize : 9999999); $list = $list ? $list->toArray() : []; if ($list) { $datas = [ 'pageSize' => $pageSize, 'total' => isset($list['total']) ? $list['total'] : 0, 'list' => isset($list['data']) ? $list['data'] : [] ]; RedisService::set($cacheKey, $datas, rand(3, 5)); } } return $datas; } /** * 查询条件 * @param $params * @return mixed */ public function getQuery($params) { $where = ['a.status' => 1, 'a.mark' => 1]; $status = isset($params['status']) ? $params['status'] : 1; if ($status > 0) { $where['a.status'] = $status; } else { unset($where['a.status']); } $model = $this->model->with(['category','sku']) ->from('goods as a') ->where(function ($query) use ($params) { // 分类 $categoryId = isset($params['category_id'])? intval($params['category_id']) : 0; if($categoryId>0){ $query->where('a.category_id', $categoryId); } // 店铺 $storeId = isset($params['store_id'])? intval($params['store_id']) : 0; if($storeId>0){ $query->where('a.store_id', $storeId); } $keyword = isset($params['keyword']) ? trim($params['keyword']) : ''; if ($keyword) { $query->where(function ($query) use ($keyword) { $query->where('a.goods_name', 'like', "%{$keyword}%") ->orWhere('a.tags','like',"%{$keyword}%"); }); } $type = isset($params['type']) ? $params['type'] : 0; if($type){ $query->where('a.type', $type); } $isRecommend = isset($params['is_recommend']) ? $params['is_recommend'] : 0; if($isRecommend){ $query->where('a.is_recommend', $isRecommend); } $isNew = isset($params['is_new']) ? $params['is_new'] : 0; if($isNew){ $query->where('a.is_new', $isNew); } })->where($where); return $model; } /** * 分类 * @return array|mixed */ public function getCategoryList() { $cacheKey = "caches:goods:categoryList"; $datas = RedisService::get($cacheKey); if($datas){ return $datas; } $datas = GoodsCategoryModel::where(['pid'=>0,'status'=>1,'mark'=>1]) ->select(['id','name','icon','pid','sort']) ->orderBy('sort','desc') ->orderBy('id','asc') ->get(); $datas = $datas? $datas->toArray() : []; if($datas){ RedisService::set($cacheKey, $datas, rand(300,600)); } return $datas; } /** * 详情信息 * @param $id * @return mixed */ public function getInfo($id,$userId=0) { $cacheKey = "caches:goods:info_{$id}_{$userId}"; $info = RedisService::get($cacheKey); if ($info) { return $info; } $info = $this->model->with(['category','skus'])->where(['id' => $id])->first(); $info = $info ? $info->toArray() : []; if ($info) { RedisService::set($cacheKey, $info, rand(10, 20)); } return $info; } /** * 收藏 * @param $userId * @param $goodsId * @return array|false */ public function collect($userId, $goodsId) { $info = $this->model->where(['id' => $goodsId,'status'=>1,'mark'=>1])->first(); $info = $info ? $info->toArray() : []; if(empty($info)){ $this->error = '商品已下架'; return false; } if($id = GoodsCollectModel::where(['user_id'=>$userId,'goods_id'=>$goodsId,'mark'=>1])->value('id')){ GoodsCollectModel::where(['id'=>$id])->update(['mark'=>0,'update_time'=>time()]); $this->error = '取消收藏'; RedisService::clear("caches:goods:info_{$id}_{$userId}"); return ['id'=>$id,'is_collect'=>0]; }else{ if(!$id = GoodsCollectModel::insertGetId(['user_id'=>$userId,'goods_id'=>$goodsId,'status'=>1,'mark'=>1,'create_time'=>time(),'update_time'=>time()])){ $this->error = '收藏失败'; return false; } $this->error = '收藏成功'; RedisService::clear("caches:goods:info_{$id}_{$userId}"); return ['id'=>$id,'is_collect'=>1]; } } /** * @param $ids * @param $goods * @param $userId * @param $orderNo 订单号 * @return array|false */ public function getOrderGoods($ids, $goods, $userId, $orderNo='', $discountPoint=0, $couponId=0) { if(empty($ids) || empty($goods)){ $this->error = '请选择商品'; return false; } // 用户信息 if(empty($orderNo)){ $userInfo = MemberModel::with(['levelData'])->where(['id' => $userId, 'mark' => 1]) ->select(['id','openid','vip_expired','member_level', 'status']) ->first(); $userInfo = $userInfo?$userInfo->toArray() : []; $status = isset($userInfo['status']) ? $userInfo['status'] : 0; $openid = isset($userInfo['openid']) ? $userInfo['openid'] : 0; $vipExpired = isset($userInfo['vip_expired']) ? $userInfo['vip_expired'] : 0; $levelData = isset($userInfo['level_data']) ? $userInfo['level_data'] : []; if (empty($userInfo) || $status != 1) { $this->error = 1045; return false; } if (empty($openid)) { $this->error = 1042; return false; } // 有效会员 if($vipExpired != 0){ $discountPoint = isset($levelData['discount']) ? $levelData['discount'] : 0; // 会员折扣 } } // 优惠券信息 $couponInfo = []; if($couponId){ $couponInfo = MemberCouponModel::where(['coupon_id'=>$couponId,'user_id'=>$userId,'mark'=>1])->first(); $couponType = isset($couponInfo['coupon_type'])?$couponInfo['coupon_type'] : 0; $couponStatus = isset($couponInfo['status'])?$couponInfo['status'] : 0; $startTime = isset($couponInfo['start_time'])?$couponInfo['start_time'] : 0; $endTime = isset($couponInfo['end_time'])?$couponInfo['end_time'] : 0; // 下单需验证 if($orderNo){ if(empty($couponInfo) || $couponType<=0){ $this->error = '优惠券无效'; return false; } if($couponStatus != 1){ $this->error = '该优惠券已使用,请刷新后重试~'; return false; } if($startTime > time()){ $this->error = '该优惠券使用时间未到~'; return false; } if($endTime && $endTime < time()){ $this->error = '该优惠券已过期~'; return false; } } } $list = $this->model->whereIn('id', $ids) ->where(['status'=>1,'mark'=>1]) ->select(['id as goods_id','goods_name','type','category_id','store_id','delivery_fee','sku_type','price','stock','unit','weight','thumb']) ->get() ->keyBy('goods_id'); $list = $list? $list->toArray() : []; if($list){ $isGoodsCoupon = false; $skus = GoodsSkuModel::whereIn('goods_id', $ids)->select(['id','sku_name','price','stock'])->get()->keyBy('id'); $skus = $skus?$skus->toArray() :[]; $result = ['discount_point'=>floatval($discountPoint),'store_id'=>0,'coupon_id'=>$couponId,'coupon_total'=>0,'discount_total'=>0.00,'delivery_fee'=>0.00,'goods_total'=>0,'order_total'=>0,'count'=>0,'goods'=>[]]; foreach ($goods as $params){ $goodsId = isset($params['id'])?$params['id']:0; $skuId = isset($params['sku_id'])?$params['sku_id']:0; $num = isset($params['num'])?$params['num']:0; $item = isset($list[$goodsId])?$list[$goodsId] : []; if(empty($item)){ continue; } $item['order_no'] = $orderNo; $id = isset($item['goods_id'])?$item['goods_id']:0; $goodsName = isset($item['goods_name'])?$item['goods_name']:''; $storeId = isset($item['store_id'])?$item['store_id']:0; $deliveryFee = isset($item['delivery_fee'])?$item['delivery_fee']:0; $stock = isset($item['stock'])?$item['stock']:0; $skuType = isset($item['sku_type'])?$item['sku_type']: 1; $skuData = isset($skus[$skuId])? $skus[$skuId]:[]; $skuPrice = isset($skuData['price'])?$skuData['price']:0; $skuStock = isset($skuData['stock'])?$skuData['stock']:0; $skuName = isset($skuData['sku_name'])?$skuData['sku_name']:''; $price = $skuType==2 ? $skuPrice : $item['price']; unset($item['skus']); if($result['store_id'] && $storeId != $result['store_id']){ $this->error = '一次只能购买同一个商家的商品,请核对后重试~'; return false; } if($stock<=0 || $num>$stock){ $this->error = $skuId? "商品[{$goodsName}]规格[{$skuName}]库存不足~" : "商品[{$goodsName}]库存不足~"; return false; } if($skuType==2 && ($skuStock<=0 || $num>$skuStock)){ $this->error = "商品[{$goodsName}]规格[{$skuName}]库存不足~"; return false; } if($num>0 && $goodsId == $id && $price>0){ $result['store_id'] = $storeId; $result['delivery_fee'] = max($deliveryFee,$result['delivery_fee']); $item['user_id'] = $userId; $item['sku_id'] = $skuId; if(empty($orderNo)){ $item['sku'] = $skuData; } $item['price'] = $price; $item['total'] = $price; $item['num'] = $num; $total = round($price * $num,2); // 计算优惠 $couponData = $this->countCouponTotal($goodsId, $total, $couponInfo); if(!$couponData){ return false; } // 是否商品使用的优惠券 $couponTotal = isset($couponData['coupon_total'])?$couponData['coupon_total'] : 0; $payTotal = isset($couponData['total'])?$couponData['total'] : 0; if($payTotal){ $item['total'] = $payTotal; //$total = $payTotal; $item['coupon_id'] = $couponId; $item['coupon_total'] = floatval($couponTotal); $result['coupon_id'] = $couponId; $result['coupon_total'] = floatval($couponTotal); $isGoodsCoupon = true; }else{ $item['total'] = $total; } $item['thumb'] = $orderNo?get_image_path($item['thumb']):$item['thumb']; $result['goods'][] = $item; $result['goods_total'] += $total; $result['order_total'] += $total; $result['count']++; } } // 非商品优惠券,整个订单的优惠券 $discountTotal = 0; $couponTotal = $result['coupon_total']; if($couponId && !$isGoodsCoupon){ $couponData = $this->countCouponTotal(0, $result['order_total'], $couponInfo); if(!$couponData){ return false; } $couponTotal = isset($couponData['coupon_total'])?$couponData['coupon_total'] : 0; $result['coupon_total'] = floatval($couponTotal); } // 会员折扣 if($discountPoint>0 && $discountPoint<10){ $discountTotal = floatval(moneyFormat( $result['order_total']*(1-$discountPoint/10),2)); $result['discount_total'] = $discountTotal; } // 折后订单总金额 $result['order_total'] = floatval(moneyFormat($result['order_total']-$couponTotal-$discountTotal,2)); // 实付订单总金额加上运费 $result['pay_total'] = floatval(moneyFormat($result['order_total'] + $result['delivery_fee'],2)); return $result; } return false; } /** * 优惠券计算 * @param $goodsId * @param $total * @param $couponInfo * @return array|bool|int */ public function countCouponTotal($goodsId, $total, $couponInfo) { $couponStatus = isset($couponInfo['status'])?$couponInfo['status'] : 0; $couponType = isset($couponInfo['coupon_type'])?$couponInfo['coupon_type'] : 0; $couponGoodsIds = isset($couponInfo['goods_ids'])&& $couponInfo['goods_ids']?explode(',', $couponInfo['goods_ids']) : []; // 按商品或全平台(非购买券) if($goodsId && $couponType != 20 && ($couponGoodsIds && !in_array($goodsId, $couponGoodsIds))){ $this->error = "优惠券非该商品使用"; return false; } if($total <= 0 ){ $this->error = "消费金额错误"; return false; } if($couponInfo && $couponStatus != 1){ $this->error = "该优惠券已被使用"; return false; } $endTime = isset($couponInfo['end_time'])?$couponInfo['end_time']:0; $startTime = isset($couponInfo['start_time'])?$couponInfo['start_time']:0; if($startTime && time() < $startTime){ $this->error = '优惠券使用时间未到'; return false; } if($endTime>0 && time() > $endTime){ $this->error = '优惠券已过期'; return false; } // 满减券 if($couponType == 10){ $minPrice = isset($couponInfo['min_price'])?$couponInfo['min_price']:0; $reducePrice = isset($couponInfo['reduce_price'])?$couponInfo['reduce_price']:0; if($total<= $reducePrice){ $this->error = '金额不足优惠券使用条件'; return false; } // 满足最低消费 if($reducePrice && $minPrice && $total >= $minPrice){ return ['total'=>moneyFormat($total-$reducePrice,2),'coupon_total'=>$reducePrice]; } } // 购买券 else if($couponType == 20){ $reducePrice = isset($couponInfo['reduce_price'])?$couponInfo['reduce_price']:0; if($total<= $reducePrice){ $this->error = '金额不足优惠券使用条件'; return -1; } return ['total'=>moneyFormat($total-$reducePrice,2),'coupon_total'=>$reducePrice]; } // 折扣券 else if($couponType == 30){ $reducePrice = isset($couponInfo['reduce_price'])?$couponInfo['reduce_price']:0; $discount = isset($couponInfo['discount'])?$couponInfo['discount']:0; $payTotal = moneyFormat($total * $discount/10, 2); return ['total'=>$payTotal,'coupon_total'=> moneyFormat($total-$payTotal,2)]; } return true; } /** * 专区商品 * @param $type 专区类型:2-午夜限定,3-蜜友优选 * @return array|mixed */ public function getListByZoneType($type, $limit=0) { $limit = $limit?$limit : ConfigService::make()->getConfigByCode("zone_type{$type}_num", 6); $cacheKey = "caches:goods:zoneList_{$type}_{$limit}"; $data = RedisService::get($cacheKey); if($data){ return $data; } $data = $this->model->with(['sku'])->where(['zone_type'=>$type,'status'=>1,'mark'=>1]) ->select(['id','thumb','price','market_price','sku_type','goods_name','sales','stock','category_id','type','zone_type','is_new','status']) ->orderBy('sort','desc') ->orderBy('id','asc') ->get(); $data = $data? $data->toArray() :[]; if($data){ RedisService::set($cacheKey, $data, rand(10, 20)); } return $data; } }