Cart.php 16.2 KB
<?php

namespace app\api\controller;

use app\common\controller\Api;
use app\common\model\Goods;
use app\common\model\GoodsStyle;
use app\common\controller\Wechat;
use think\Db;

/**
 * 购物车
 */
class Cart extends Api
{
    protected $noNeedLogin = ['notify'];
    protected $noNeedRight = '*';

    public function _initialize()
    {
        parent::_initialize();
        $this->model = model('app\common\model\Cart');
        $this->user = $this->auth->getUser();
    }

    /**
     * 购物车-首页
     * @ApiMethod   (GET)
     * @ApiRoute    (/api/cart/index)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */        
    public function index(){
        $this->success(__('成功'),$this->model->getList($this->user,['isbuynow'=>'0']));
    }

    /**
     * 购物车-获取购物车商品总数
     * @ApiMethod   (GET)
     * @ApiRoute    (/api/cart/getCartNum)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */        
    public function getCartNum(){
        $this->success(__('成功'),$this->model->where(['user_id'=>$this->user['id'],'isbuynow'=>'0'])->sum('goods_num'));
    }

    /**
     * 购物车-加入购物车
     * @ApiMethod   (POST)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="goods_id", type="integer", required=true, description="商品ID")
     * @ApiParams   (name="goods_num", type="integer", required=true, description="商品数量")
     * @ApiParams   (name="goods_style", type="object", sample="{'1':'11','5':'15','7':'2','14':'25','15':'\/uploads\/20200711\/3689359dcdf1146d234930cae4958110.jpg','13':'21','12':'18'}", description="商品规格 {'风格ID':'风格值'}")
     * @ApiParams   (name="user_size_id", type="integer", description="用户尺寸ID")
     * @ApiParams   (name="spec_sku_id", type="string", description="商品sku")
     * @ApiParams   (name="isbuynow", type="string", description="是否立即购买:0=否,1=是")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */
    public function add()
    {
        $post = $this->request->post();
        // 对象转json字符串
        if(!empty($post['goods_style']) && is_array($post['goods_style'])){
            $post['goods_style'] = json_encode($post['goods_style']);
        }
        if(!$cart_id = $this->model->add($this->user,$post)){
            $this->error($this->model->getError() ?: '加入购物车失败');
        }
        $this->success(__('加入购物车成功'),[
            'cart_id' => $cart_id,
            'total_num' => $this->model->where('user_id',$this->user['id'])->where('isbuynow','0')->sum('goods_num')
        ]);
    }

    /**
     * 购物车-修改尺寸
     * @ApiMethod   (GET)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_id", type="integer", required=true, description="购物车ID")
     * @ApiParams   (name="user_size_id", type="integer", required=true, description="用户尺寸ID")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */        
    public function editSize($cart_id,$user_size_id){
        $cart = $this->model->get($cart_id);
        empty($cart) && $this->error(__('购物车信息不存在'));
        $user_size = \app\common\model\UserSize::get(['user_id'=>$this->user['id'],'id'=>$user_size_id]);
        empty($user_size) && $this->error(__('尺寸信息不存在'));
        $cart->user_size_id = $user_size_id;
        $cart->save();
        $this->success(__('成功'));
    }

    /**
     * 购物车-修改定制风格
     * @ApiMethod   (GET)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_id", type="integer", required=true, description="购物车ID")
     * @ApiParams   (name="goods_style", type="object", required=true, sample="{'1':'11','5':'15','7':'2','14':'25','15':'\/uploads\/20200711\/3689359dcdf1146d234930cae4958110.jpg','13':'21','12':'18'}", description="商品风格 {'风格ID':'规格值'}")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */        
    public function editGoodsStyle($cart_id,$goods_style){
        $goods_style = htmlspecialchars_decode($goods_style);
        $cart = $this->model->get($cart_id);
        empty($cart) && $this->error(__('购物车信息不存在'));
        $cart['goods']['ismake'] == '0' && $this->error(__('该产品不属于定制商品'));
        empty($goods_style) && $this->error(__('请选择您的定制信息'));
        $model_style = GoodsStyle::get(['goods_id'=>$cart['goods_id'],'goods_style'=>$goods_style]);
        $cart->make_type = !$model_style ? '2' : '1';
        $cart->goods_style = $goods_style;
        $goods_style_arr = json_decode($goods_style,true);
        $cart->goods_price = $cart['goods']['goods_price'] + array_sum(\app\common\model\StyleValue::where('id','in',$goods_style_arr)->column('style_value_price'));
        $cart->save();
        $this->success(__('成功'));
    }

    /**
     * 购物车-修改规格
     * @ApiMethod   (GET)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_id", type="integer", required=true, description="购物车ID")
     * @ApiParams   (name="spec_sku_id", type="string", required=true, sample="1_5", description="商品规格")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */        
    public function editGoodsSpec($cart_id,$spec_sku_id){
        $cart = $this->model->get($cart_id);
        empty($cart) && $this->error(__('购物车信息不存在'));
        empty($spec_sku_id) && $this->error(__('请选择规格'));
        // 检查库存
        $goods = Goods::get($cart['goods_id'],['spec_rel.spec']);
        $goods_sku = $goods->getGoodsSku($spec_sku_id);
        if($goods['ismake'] == '0' && $goods_sku['stock_num'] < $cart['goods_num']){
            $this->error(__('商品库存不足'.$cart['goods_num'].'件'));
        }
        $cart->spec_sku_id = $spec_sku_id;
        $cart->goods_price = $goods_sku['goods_price'];
        $cart->save();
        $this->success(__('成功'));
    }

    /**
     * 购物车-修改商品数量
     * @ApiMethod   (GET)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_id", type="integer", required=true, description="购物车ID")
     * @ApiParams   (name="goods_num", type="integer", required=true, description="商品数量")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */        
    public function editGoodsNum($cart_id,$goods_num){
        $cart = $this->model->get($cart_id);
        empty($cart) && $this->error(__('购物车信息不存在'));
        $goods_num < 1 && $this->error(__('商品数量不能小于1'));
        if($cart['goods']['ismake'] == '0' && $cart['spec']['stock_num'] < $goods_num){
            $this->error(__('商品库存不足'.$goods_num.'件'));
        }
        $cart->goods_num = $goods_num;
        $cart->save();
        $this->success(__('成功'));
    }

    /**
     * 购物车-删除
     * @ApiMethod   (POST)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_id", type="integer", required=true, description="购物车ID")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */
    public function delete($cart_id)
    {
        $this->model->where('id',$cart_id)->delete();
        $this->success(__('成功'));
    }

    /**
     * 购物车-选中取消
     * @ApiMethod   (POST)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_ids", type="string", required=true, description="购物车ID集合")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */
    public function select($cart_ids)
    {
        $where = [
            'user_id' => $this->user['id'],
            'isbuynow' => '0'
        ];
        // 传过来的选中
        $this->model
            ->where($where)
            ->where('id','in',$cart_ids)
            ->update(['isselected'=>'1']);
        // 未传过来的取消选中
        $this->model
            ->where($where)
            ->where('id','notin',$cart_ids)
            ->update(['isselected'=>'0']);
        $this->success(__('成功'));
    }

    /**
     * 结算和支付(结算用GET,支付用POST)
     * @ApiMethod   (POST)
     * @ApiHeaders  (name=token, type=string, required=true, description="请求的Token")
     * @ApiParams   (name="cart_ids", type="string", required=true, description="购物车ID集合")
     * @ApiParams   (name="user_address_id", type="integer", description="用户地址ID")
     * @ApiParams   (name="user_coupon_id", type="integer", description="用户优惠券ID")
     * @ApiParams   (name="score_switch", type="integer", description="积分开关:0=关,1=开")
     * @ApiReturnParams   (name="code", type="integer", required=true, sample="0")
     * @ApiReturnParams   (name="msg", type="string", required=true, sample="返回成功")
     * @ApiReturnParams   (name="data", type="object", description="扩展数据返回")
     * @ApiReturn   ({
         'code':'1',
         'msg':'返回成功'
        })
     */
    public function pay()
    {
        $data = $this->request->param();
        empty($data['cart_ids']) && $this->error(__('参数【cart_ids】不能为空'));
        $order = $this->model->getList($this->user,['id'=>['in',$data['cart_ids']]],$data);
        if (!$this->request->isPost()) {
            $this->success(__('成功'),$order);
        }
        // 生成订单信息错误
        if ($this->model->getError()) {
            $this->error($this->model->getError());
        }
        // 创建订单
        $model = new \app\common\model\Order;
        if ($model->add($this->user['id'], $order)) {
            // 删除结算购物车商品
            $this->model->where(['id'=>['in',$data['cart_ids']]])->delete();
            if($order['order_price'] > 0){
                // 发起微信支付
                $Wechat = new Wechat;
                $order['order_price'] = 0.01;//测试金额
                if(!$payment = $Wechat->wxPay($model['order_no'], $this->user['openid'], $order['order_price'])){
                    $this->error($Wechat->getError());
                }
                // $payment = [];
            }else{
                $this->notifyTest($model['order_no']);
                $payment = [];
            }
            $this->success(__('成功'),[
                'payment' => $payment,
                'order_id' => $model['id']
            ]);
        }
        $error = $model->getError() ?: '订单创建失败';
        return $this->error($error);
    }

    /**
     * 异步回调
     */
    public function notify()
    {
        $payment = Wechat::payment();
        $response = $payment->handlePaidNotify(function($message, $fail){
            if ($message['return_code'] !== 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
                return $fail('通信失败,请稍后再通知我');
            }
            // 用户支付失败 - 支付失败也需要返回true,表示服务器已处理,不然微信会反复通知,没有意义
            if ($message['result_code'] === 'FAIL') {
                return true;
            }
            // 支付成功后的业务逻辑
            if ($message['result_code'] === 'SUCCESS') {
                Db::startTrans();
                try {
                    // 处理订单
                    $this->handleOrder($message['out_trade_no']);
                    Db::commit();
                } catch (\think\exception\PDOException $e) {
                    Db::rollback();
                    return $fail('服务器处理失败,请稍后再通知我');
                } catch (\think\Exception $e) {
                    Db::rollback();
                    return $fail('服务器处理失败,请稍后再通知我');
                }
            }
            return true;
        });
        $response->send(); // return $response;
    }

    /**
     * 异步回调
     */
    public function notifyTest($order_no)
    {
        Db::startTrans();
        try {
            $this->handleOrder($order_no);
            Db::commit();
        } catch (\think\exception\PDOException $e) {
            Db::rollback();
            return false;
        } catch (\think\Exception $e) {
            Db::rollback();
            return false;
        }
        return true;
    }

    /**
     * 异步回调-处理订单
     */
    private function handleOrder($order_no)
    {
        $order = \app\common\model\Order::get(['order_no'=>$order_no]);
        if (!$order || $order['pay_status'] == '1') { // 如果订单不存在 或者 订单已经支付过了
            return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了
        }
        $order->pay_time = time(); // 更新支付时间为当前时间
        $order->pay_status = '1';
        $order->save();
        // 非定制商品减库存
        $deductStockData = [];
        foreach($order['goods'] as $v){
            if($v['goods']['ismake'] == '0'){
                $deductStockData[] = [
                    'id' => $v['spec']['id'],
                    'stock_num' => ['dec', $v['goods_num']]
                ];
            }
        }
        !empty($deductStockData) && (new \app\common\model\GoodsSpec)->isUpdate()->saveAll($deductStockData);
        return true;
    }
}