268 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
			
		
		
	
	
			268 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
<?php
 | 
						|
 | 
						|
namespace app\traits\order;
 | 
						|
 | 
						|
use app\exception\RepositoryException;
 | 
						|
use app\model\mall\SpuLimitTime;
 | 
						|
use app\model\OrderSku;
 | 
						|
use app\model\ShoppingCart;
 | 
						|
use app\model\Sku;
 | 
						|
use app\model\Spu;
 | 
						|
use app\repository\OrderRepository;
 | 
						|
use app\repository\SpuRepository;
 | 
						|
use Exception;
 | 
						|
use think\Collection;
 | 
						|
use think\db\exception\DataNotFoundException;
 | 
						|
use think\db\exception\DbException;
 | 
						|
use think\db\exception\ModelNotFoundException;
 | 
						|
use think\facade\Db;
 | 
						|
 | 
						|
/**
 | 
						|
 * 购物车相关
 | 
						|
 *
 | 
						|
 * Trait ShoppingCartTrait
 | 
						|
 * @package app\traits\order
 | 
						|
 */
 | 
						|
trait ShoppingCartTrait
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * 获取购物车列表
 | 
						|
     *
 | 
						|
     * @param  int  $accountId
 | 
						|
     * @param  string  $type
 | 
						|
     * @param  int  $page
 | 
						|
     * @param  int  $size
 | 
						|
     * @return array
 | 
						|
     * @throws DataNotFoundException
 | 
						|
     * @throws DbException
 | 
						|
     * @throws ModelNotFoundException
 | 
						|
     */
 | 
						|
    public function shoppingCart(int $accountId, string $type = '', int $page = 1, int $size = 20): array
 | 
						|
    {
 | 
						|
        $isScore = $type == 'score' ? 1 : 0;
 | 
						|
        $res     = [
 | 
						|
            'total'   => 0,
 | 
						|
            'current' => $page,
 | 
						|
            'size'    => $size,
 | 
						|
            'list'    => new Collection(),
 | 
						|
        ];
 | 
						|
 | 
						|
        $query        = ShoppingCart::where('account_id', $accountId)
 | 
						|
            ->where('is_score', $isScore)
 | 
						|
            ->with([
 | 
						|
                'spu'              => function ($query) {
 | 
						|
                    $query->field('id,name as spu_name,cover as spu_cover,original_price,unit');
 | 
						|
                },
 | 
						|
                'sku'           => function ($query) {
 | 
						|
                    $query->field('id,title as sku_name,main_image as sku_cover,price as sku_price,coding,spec_text,type as activity_type');
 | 
						|
                }
 | 
						|
            ]);
 | 
						|
        $res['total'] = $query->count();
 | 
						|
        if ($res['total'] > 0) {
 | 
						|
            $list = $query->order('updated_at', 'desc')
 | 
						|
                ->page($page)
 | 
						|
                ->limit($size)
 | 
						|
                ->select();
 | 
						|
            $res['list'] = $list->each(function ($item) {
 | 
						|
                if (!isset($item->sku) || !isset($item->sku->activity_type)) {
 | 
						|
                    unset($item);
 | 
						|
                } else {
 | 
						|
                    if (!isset($item->sku->spec_text)) {
 | 
						|
                        $item->sku->spec_text = [];
 | 
						|
                    } else {
 | 
						|
                        $specArr = json_decode($item->sku->spec_text, true);
 | 
						|
                        $item->sku->spec_text = $specArr;
 | 
						|
                        $item->sku->spec_info = SpuRepository::getInstance()->convertSpecInfo($specArr);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
                unset($item->spu_activity);
 | 
						|
                unset($item->activity_skus);
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        return $res;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 购物车保存
 | 
						|
     *
 | 
						|
     * @param  int  $accountId
 | 
						|
     * @param  int  $skuId
 | 
						|
     * @param  int  $num  最终购物车数量 注意 不是新增的数量 而是最终保存的数量。若=0 则删除
 | 
						|
     * @return bool
 | 
						|
     * @throws DataNotFoundException
 | 
						|
     * @throws DbException
 | 
						|
     * @throws ModelNotFoundException
 | 
						|
     * @throws RepositoryException
 | 
						|
     */
 | 
						|
    public function shoppingCartAdd(int $accountId, int $skuId, int $num = 1): bool
 | 
						|
    {
 | 
						|
        if (!$skuInfo = SpuRepository::getInstance()->infoBySkuId($skuId)) {
 | 
						|
            throw new RepositoryException('商品不存在或已下架');
 | 
						|
        }
 | 
						|
 | 
						|
        if ($item = ShoppingCart::where('account_id', $accountId)->where('sku_id', $skuId)->find()) {
 | 
						|
            $update['updated_at'] = date('Y-m-d H:i:s');
 | 
						|
            $update['spu_name']   = $skuInfo['spu_name'] ?? ($skuInfo['spu_activity_name'] ?? '');
 | 
						|
            $update['sku_price']  = $skuInfo['sku_price'];
 | 
						|
            $update['score']      = $skuInfo['sku_score'];
 | 
						|
            $update['sku_name']   = $skuInfo['sku_name'];
 | 
						|
            $update['sku_cover']  = $skuInfo['sku_cover'];
 | 
						|
 | 
						|
            $item->inc('num', $num)->update($update);
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        ShoppingCart::create([
 | 
						|
            'account_id'      => $accountId,
 | 
						|
            'spu_activity_id' => $skuInfo['spu_activity_id'] ?? 0,
 | 
						|
            'spu_id'          => $skuInfo['spu_id'],
 | 
						|
            'sku_id'          => $skuInfo['id'],
 | 
						|
            'original_price'  => $skuInfo['original_price'],
 | 
						|
            'price'           => $skuInfo['price'],
 | 
						|
            'score'           => $skuInfo['sku_score'],
 | 
						|
            'num'             => $num,
 | 
						|
            'created_at'      => date('Y-m-d H:i:s'),
 | 
						|
            'spu_name'        => $skuInfo['spu_name'] ?? ($skuInfo['spu_activity_name'] ?? ''),
 | 
						|
            'sku_price'       => $skuInfo['price'],
 | 
						|
            'sku_name'        => $skuInfo['sku_name'],
 | 
						|
            'sku_cover'       => $skuInfo['main_image'],
 | 
						|
            'is_score'        => $skuInfo['is_score'] ?? 0,
 | 
						|
        ]);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 购物车数量变更
 | 
						|
     *
 | 
						|
     * @param  int  $id
 | 
						|
     * @param  int  $num
 | 
						|
     * @return bool
 | 
						|
     * @throws DataNotFoundException
 | 
						|
     * @throws DbException
 | 
						|
     * @throws ModelNotFoundException
 | 
						|
     * @throws RepositoryException
 | 
						|
     */
 | 
						|
    public function shoppingCartChangeNum(int $id, int $num = 1): bool
 | 
						|
    {
 | 
						|
        if (!$item = ShoppingCart::where('id', $id)->find()) {
 | 
						|
            throw new RepositoryException('记录不存在');
 | 
						|
        }
 | 
						|
        return $item->save(['num' => $num]);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 购物车删除
 | 
						|
     *
 | 
						|
     * @param  int  $accountId
 | 
						|
     * @param  int  $id
 | 
						|
     * @return bool
 | 
						|
     * @throws DataNotFoundException
 | 
						|
     * @throws DbException
 | 
						|
     * @throws ModelNotFoundException
 | 
						|
     * @throws RepositoryException
 | 
						|
     */
 | 
						|
    public function shoppingCartDel(int $accountId, int $id): bool
 | 
						|
    {
 | 
						|
        if (!$item = ShoppingCart::where('id', $id)->find()) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($item['account_id'] != $accountId) {
 | 
						|
            throw new RepositoryException('这不是您的购物车商品');
 | 
						|
        }
 | 
						|
 | 
						|
        return $item->delete();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 删除指定订单相关的购物车数据
 | 
						|
     *
 | 
						|
     * @param  int  $accountId
 | 
						|
     * @param  string  $orderId
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function delShoppingCartByOrder(int $accountId, string $orderId): bool
 | 
						|
    {
 | 
						|
        Db::startTrans();
 | 
						|
        try {
 | 
						|
            $orderSkus = OrderSku::where('coding', $orderId)->field('id,coding,sku_id,num')->select();
 | 
						|
            $sku2Num   = $orderSkus->column('num', 'sku_id');
 | 
						|
            if (empty($orderSkus)) {
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
 | 
						|
            $list = ShoppingCart::where('account_id', $accountId)
 | 
						|
                ->field('id,sku_id,num')
 | 
						|
                ->whereIn('sku_id', $orderSkus->column('sku_id'))
 | 
						|
                ->lock(true)->select();
 | 
						|
 | 
						|
            $update = [];
 | 
						|
            foreach ($list as $v) {
 | 
						|
                $arr        = [];
 | 
						|
                $arr['num'] = $v['num'] - ($sku2Num[$v['sku_id']] ?? 1);
 | 
						|
                $arr['num'] = $arr['num'] < 0 ? 0 : $arr['num'];
 | 
						|
                $arr['id']  = $v['id'];
 | 
						|
 | 
						|
                $update[] = $arr;
 | 
						|
            }
 | 
						|
 | 
						|
            (new ShoppingCart())->saveAll($update);
 | 
						|
 | 
						|
            ShoppingCart::where('account_id', $accountId)->where('num', '<=', 0)->delete();
 | 
						|
 | 
						|
            Db::commit();
 | 
						|
            return true;
 | 
						|
        } catch (Exception $e) {
 | 
						|
            Db::rollback();
 | 
						|
            OrderRepository::log('清理购物车数据失败', $e);
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 检查并清理购物车不存在的商品和sku
 | 
						|
     * @param  int  $accountId
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function checkShoppingCart(int $accountId = 0): bool
 | 
						|
    {
 | 
						|
        $where = [];
 | 
						|
        if ($accountId > 0) {
 | 
						|
            $where[] = ['account_id', '=', $accountId];
 | 
						|
        }
 | 
						|
        $items = ShoppingCart::where($where)->column('spu_id,sku_id');
 | 
						|
        $spuIds = array_unique(array_column($items, 'spu_id'));
 | 
						|
        $skuIds = array_unique(array_column($items, 'sku_id'));
 | 
						|
 | 
						|
        $notExistSpu = [];
 | 
						|
        if ($spuIds) {
 | 
						|
            $existSpu = Spu::whereIn('id', $spuIds)->whereNull('deleted_at')->column('id');
 | 
						|
            $notExistSpu = array_diff($spuIds, $existSpu);
 | 
						|
        }
 | 
						|
 | 
						|
        $notExistSku = [];
 | 
						|
        if ($skuIds) {
 | 
						|
            $existSku = Sku::whereIn('id', $skuIds)->whereNull('deleted_at')->column('id');
 | 
						|
            $notExistSku = array_diff($skuIds, $existSku);
 | 
						|
        }
 | 
						|
 | 
						|
        if (!empty($notExistSku) || !empty($notExistSpu)) {
 | 
						|
            ShoppingCart::where($where)
 | 
						|
                ->where(function ($q) use ($notExistSku, $notExistSpu) {
 | 
						|
                    if (!empty($notExistSpu)) {
 | 
						|
                        $q->whereOr('spu_id', 'in', $notExistSpu);
 | 
						|
                    }
 | 
						|
                    if (!empty($notExistSku)) {
 | 
						|
                        $q->whereOr('sku_id', 'in', $notExistSku);
 | 
						|
                    }
 | 
						|
                })
 | 
						|
                ->delete();
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
        //        return ['noteSpu' => $notExistSpu, 'notSku' => $notExistSku, 'needDel' => $needDel, 'count' => count($needDel)];
 | 
						|
    }
 | 
						|
} |