<?php namespace app\api\controller; use app\common\controller\Api; use app\common\model\Goods; use app\common\model\GoodsStyle; use app\common\model\GoodsSpec; use app\common\controller\Wechat; use think\Db; /** * 购物车 */ class Cart extends Api { protected $noNeedLogin = ['getCartNum','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->model ->where('isbuynow','1') ->where('createtime','<',time()-86400) ->delete(); // 购物车数据 $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(){ $total_num = $this->model->where(['user_id'=>$this->auth->id,'isbuynow'=>'0'])->sum('goods_num'); $this->success(__('成功'),compact('total_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() ?: '加入购物车失败',null,$this->model->getCode()); } $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')); // 检查库存 $goods = Goods::get($cart['goods_id'],['spec_rel.spec']); $goods_sku = $goods->getGoodsSku($cart['spec_sku_id']); if($goods['ismake'] == '0' && $goods_sku['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();//接收get和post两种数据 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(); $this->error($e->getMessage()); return false; } catch (\think\Exception $e) { Db::rollback(); $this->error($e->getMessage()); 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(); // 整理批量更新商品销量 $goodsSave = []; // 批量更新商品规格:sku销量、库存 $goodsSpecSave = []; foreach($order['goods'] as $v){ $goodsSave[] = [ 'id' => $v['goods_id'], 'sale_num' => ['inc', $v['goods_num']] ]; $specData = [ 'id' => Goods::get($v['goods_id'],['spec_rel.spec'])->getGoodsSku($v['spec_sku_id'])['id'], 'sale_num' => ['inc', $v['goods_num']] ]; // 非定制商品减库存 if($v['goods']['ismake'] == '0'){ $specData['stock_num'] = ['dec', $v['goods_num']]; } $goodsSpecSave[] = $specData; } // 更新商品总销量 (new Goods)->allowField(true)->isUpdate()->saveAll($goodsSave); // 更新商品规格库存 (new GoodsSpec)->allowField(true)->isUpdate()->saveAll($goodsSpecSave); // 订单支付-赠送积分 if($order['order_price'] > 0){ $sendscore = config('site.sendscore'); // 消费多少元赠送1积分 $score = bcdiv($order['order_price'],$sendscore); // 赠送积分 if($score >= 1){ \app\common\model\User::score($score,$order['user_id'],'订单支付-赠送积分'); } } return true; } }