Cart.php 13.9 KB
<?php

namespace app\common\model;

use think\Model;
use fast\Tree;

class Cart extends Model
{
    // 开启自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';

    // 追加属性
    protected $append = [
        'goods_style_text',
        'make_type_text'
    ];

    // 错误提示
    public $error = '';

    // 状态码
    public $code = 0;

    /**
     * 商品
     */
    public function goods(){
        return $this->belongsTo('Goods', 'goods_id')->setEagerlyType(0);
    }

    /**
     * 尺寸
     */
    public function userSize(){
        return $this->belongsTo('UserSize', 'user_size_id');
    }

    /**
     * 定制项详情
     */
    public function getGoodsStyleTextAttr($value,$data){
        $goods_style_text = [];
        if(!empty($data['goods_style'])){
            $goods_style = json_decode($data['goods_style'],true);
            foreach($goods_style as $k => $v){
                $style = Style::where('id',$k)->field('style_name,style_type')->find()->toArray();
                $style['style_value'] = '';
                switch ($style['style_type']) {
                    case '1':
                        $style['style_value'] = StyleValue::where('id',$v)->value('style_value_name');
                        break;
                    case '2':
                        $style['style_value'] = $v;
                        break;
                    case '3':
                        $style['style_value'] = cdnurl($v,true);
                        break;
                }
                $goods_style_text[] = $style;
            }
        }
        return $goods_style_text;
    }

    /**
     * 定制项名称
     */
    public function getMakeTypeTextAttr($value,$data){
        $make_type_arr = ['0'=>'','1'=>'模特款','2'=>'自定义'];
        return $make_type_arr[$data['make_type']];
    }

    /**
     * 加入购物车
     */
    public function add($user,$data)
    {
        $goods = Goods::get($data['goods_id'],['spec_rel.spec']);
        if(empty($goods)){
            $this->setError(__('商品不存在'));
            return false;
        }
        if(empty($user['mobile'])){
            $this->setError(__('抱歉,该商品只有会员才能购买'),2);
            return false;
        }
        // 定制品
        if($goods['ismake'] == '1'){
            $user_size = UserSize::get(['user_id'=>$user['id'],'id'=>$data['user_size_id']]);
            if(empty($user_size)){
                $this->setError(__('尺寸信息不存在'));
                return false;
            }
            if(empty($data['goods_style'])){
                $this->setError(__('请选择定制项'));
                return false;
            }
            $data['goods_style'] = htmlspecialchars_decode($data['goods_style']);
            $goods_style = GoodsStyle::get(['goods_style'=>$data['goods_style']]);
            if($goods_style){
                $data['make_type'] = '1';
                $data['goods_price'] = $goods['goods_price'] + $goods_style['goods_style_price'];
            }else{
                $data['make_type'] = '2';
                $goods_style = json_decode($data['goods_style'],true);
                $data['goods_price'] = $goods['goods_price'] + array_sum(StyleValue::where('id','in',$goods_style)->column('style_value_price'));
            }
            $stock_num = 9999999;
        }else{
        // 非定制
            $spec_sku_id = '';
            if($goods['spec_type'] == '2'){
                if(empty($data['spec_sku_id'])){
                    $this->setError(__('请选择规格'));
                    return false;
                }
                $spec_sku_id = $data['spec_sku_id'];
            }
            $goods_sku = $goods->getGoodsSku($spec_sku_id);
            $data['make_type'] = '0';
            $data['goods_price'] = $goods_sku['goods_price'];
            $stock_num = $goods_sku['stock_num'];
        }
        // 加入购物车
        if(empty($data['isbuynow'])){
            $cart = $this->get([
                'user_id' => $user['id'],
                'goods_id' => $data['goods_id'],
                'spec_sku_id' => !empty($data['spec_sku_id']) ? $data['spec_sku_id'] : '',
                'goods_style' => !empty($data['goods_style']) ? $data['goods_style'] : '',
                'user_size_id' => !empty($data['user_size_id']) ? $data['user_size_id'] : 0,
                'isbuynow' => '0' 
            ]);
            if(!empty($cart)){
                $cart_goods_num = $data['goods_num'] + $cart['goods_num'];
                if($cart_goods_num > $stock_num){
                    $this->setError('很抱歉,商品库存不足');
                    return false;
                }
                $cart->goods_num = $cart_goods_num;
                $cart->save();
                return $cart['id'];
            }
            $data['isbuynow'] = '0';
        }
        // 首次加入购物车或立即购买
        if($data['goods_num'] > $stock_num){
            $this->setError('很抱歉,商品库存不足');
            return false;
        }
        $this->allowField(true)->save(array_merge([
            'user_id'=>$user['id']
        ],$data));
        return $this->id;
    }

    /**
     * 购物车列表
     */
    public function getList($user,$where,$data=[])
    {
        $list = $this->where('user_id',$user['id'])->where($where)->select();
        $total_num = 0;
        $total_price = 0;
        $total_goods_weight = 0;
        $cart_list = [];
        foreach ($list as $key => $cart) {
            // 判断商品不存在则自动删除
            $goods = Goods::get($cart['goods_id'],['spec_rel.spec']);
            if (!$goods) {
                $this->where('goods_id',$cart['goods_id'])->delete();
                continue;
            }
            // 商品sku不存在则自动删除
            if (!$cart['goods_sku'] = $goods->getGoodsSku($cart['spec_sku_id'])) {
                $this->where(['goods_id'=>$cart['goods_id'],'spec_sku_id'=>$cart['spec_sku_id']])->delete();
                continue;
            }
            // 判断商品是否下架
            if ($goods['issale'] != '1') {
                $this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 已下架');
            }
            // 判断商品库存
            if ($goods['ismake'] == '0' && $cart['goods_num'] > $cart['goods_sku']['stock_num']) {
                $this->setError('很抱歉,商品 [' . $goods['goods_name'] . '] 库存不足');
            }
            $cart['goods_total_price'] = bcmul($cart['goods_price'], $cart['goods_num'], 2);
            // 只计算选中商品
            if($cart['isselected'] == '1'){
                // 商品总数
                $total_num += $cart['goods_num'];
                // 商品总价
                $total_price += $cart['goods_total_price'];
                // 商品总重量
                $total_goods_weight += bcmul($cart['goods_sku']['goods_weight'], $cart['goods_num'], 2);
            }
            // 显示商品信息
            $cart->goods->visible(['goods_name','goods_image','category_ids','spec_type']);
            // 显示用户尺寸信息
            if(!$cart->user_size){
                $cart->user_size = [];
            }else{
                $cart->user_size->visible(['id','name','size_text']);
            }
            // 显示购物车数据
            $cart_list[] = $cart->visible([
                'id',
                'goods_id',
                'goods_style',
                'goods_style_text',
                'goods_price',
                'goods_num',
                'make_type',
                'goods',
                'user_size',
                'isselected'
            ])->append([
                'goods_total_price',
                'goods_sku'
            ])->toArray();
        }
        // 地址
        $address = UserAddress::get(['user_id'=>$user['id'],'isdefault'=>'1']);
        if(!empty($data['user_address_id'])){
            if(!$address = UserAddress::get($data['user_address_id'])){
                $this->setError('地址不存在');
            }
        }
        // 运费
        $express = config('site.express');
        krsort($express);
        $express_price = 0;
        foreach($express as $k => $v){
            if($total_goods_weight > $k){
                $express_price = $v;
                break;
            } 
        }
        // 优惠券
        $coupon = [
            'list' => $this->orderCouponList($user,$cart_list),
            'user_coupon_id' => 0,
            'coupon_name' => '暂无可用',
            'coupon_price' => 0,
        ];
        if(!empty($data['user_coupon_id'])){
            if(!$user_coupon = UserCoupon::get($data['user_coupon_id'])){
                $coupon['user_coupon_id'] = $data['user_coupon_id'];
                $coupon['coupon_name'] = $user_coupon['coupon']['coupon_name'];
                $coupon['coupon_price'] = $user_coupon['coupon']['coupon_price'];
            }
        }else{
            if(count($coupon['list']) > 0 && $coupon['list'][0]['isusable'] == '1'){
                $coupon['user_coupon_id'] = $coupon['list'][0]['id'];
                $coupon['coupon_name'] = $coupon['list'][0]['coupon']['coupon_name'];
                $coupon['coupon_price'] = $coupon['list'][0]['coupon']['coupon_price'];
            }
        }
        // 实际支付金额
        $order_price = bcadd($total_price, $express_price, 2);
        // 积分
        $score = ['score'=>$user['score'],'score_price'=>0,'use_score'=>0,'scoreprice'=>config('site.scoreprice')];
        if(!empty($data['score_switch']) && $coupon['coupon_price'] < $order_price){
            // 减去优惠券的金额
            $sub_price = bcsub($order_price, $coupon['coupon_price'], 2);
            $scoreprice = $score['scoreprice']; // 消费多少积分抵扣1元
            $user_score_price = bcdiv($user['score'],$scoreprice,2); // 用户积分能抵扣多少钱
            if($sub_price >= $user_score_price){
                $score['score_price'] = $user_score_price;
                $score['use_score'] = $user['score'];
            }else{
                $score['score_price'] = $sub_price;
                $score['use_score'] = bcmul($sub_price,$scoreprice);
            }
        }
        // 优惠金额
        if($coupon['coupon_price'] >= $order_price){
            $reduce_price = $order_price;
        }else{
            $reduce_price = bcadd($coupon['coupon_price'], $score['score_price'], 2);
        }
        $order_price = bcsub($order_price, $reduce_price, 2);
        return [
            'goods_list' => $cart_list,
            'total_num' => $total_num,
            'total_price' => $total_price,
            'express_price' => $express_price,
            //以下订单需要的信息
            'address' => !empty($address) ? $address->toArray() : [],
            'score' => $score,
            'coupon' => $coupon,
            'reduce_price' => $reduce_price,
            'order_price' => $order_price,
        ];
    }

    /**
     * 订单优惠券
     */
    public function orderCouponList($user,$cart_list){
        $new_cart_list = [];
        foreach ($cart_list as $key => $value) {
            if($value['isselected'] == '1'){
                $new_cart_list[$value['goods_id']][] = $value;
            }
        }
        $coupon_id_arr = [];
        $tree = Tree::instance()->init(collection(Category::order('weigh desc,id desc')->select())->toArray(), 'pid');
        foreach($new_cart_list as $goods_id => $v){
            $goods_total_price = array_sum(array_column($v, 'goods_total_price'));
            // 商品所属分类
            $filter = [];
            foreach(explode(',',$v[0]['goods']['category_ids']) as $v){
                $id_arr = $tree->getParentsIds($v,true);
                foreach($id_arr as $val){
                    $filter[] = "find_in_set($val,category_ids)";
                }
            }
            $where = implode(' or ',$filter)." or category_ids = ''";
            
            $coupon_id_arr = array_unique(
                array_merge(
                    Coupon::where('limit_price','<=',$goods_total_price)
                        ->where('expiretime','>',time())
                        ->where($where)
                        ->column('id'),
                    $coupon_id_arr
                )
            );
        }
        $coupon_ids = implode(',', $coupon_id_arr) ?: '0';

        $list = UserCoupon::alias('uc')
            ->join('coupon c','c.id = uc.coupon_id')
            ->with('coupon')
            ->where('uc.user_id',$user['id'])
            ->where('uc.status','1')
            ->where('c.expiretime','>',time())
            ->field("
                uc.id,
                uc.coupon_id,
                uc.status,
                from_unixtime(c.expiretime,'%Y-%m-%d') expiretime,
                CASE
                    WHEN c.id in ({$coupon_ids}) THEN '1'
                    ELSE '0'
                END isusable
            ")
            ->order(['isusable'=>'desc','c.coupon_price'=>'desc'])
            ->select();
        foreach($list as $v){
            $v->visible(['id','status','expiretime','isusable','coupon']);
            $v->getRelation('coupon')->visible(['id','coupon_name','coupon_price','limit_price','category_ids','rule']);
        }
        return $list;
    }

    /**
     * 设置错误信息
     * @param $error
     */
    private function setError($error,$code=0)
    {
        empty($this->error) && $this->error = $error;
        $this->code = $code;
    }

    /**
     * 是否存在错误
     * @return bool
     */
    private function hasError()
    {
        return !empty($this->error);
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * 获取状态码
     * @return string
     */
    public function getCode()
    {
        return $this->code;
    }
}