OrderController.php 16.7 KB
<?php
namespace app\order\controller;
use app\coupons\model\CouponModel;
use app\order\model\OrderModel;
use cmf\controller\HomeBaseController;
use think\Db;

/**
 * @title 订单模块
 */
class OrderController extends HomeBaseController
{

    function _initialize()
    {
        require_once EXTEND_PATH . '/Payment.php';
    }

    /**
     * @title 下单页面
     * @description 默认访问接口
     * @author sᴏᴜʟ ᴏғ ᴄɪɴᴅᴇʀ
     * @url /order/Order/confirm
     * @method POST
     *
     * @param name:activity_id  type:int require:1 default:19 desc:上一页选中的活动id
     * @param name:schedule_id  type:int require:1 default:68 desc:上一页选中的批次id
     * @param name:num  type:int require:1 default:2 desc:上一页选中的购买数量
     */
    public function confirm()
    {
        $request = request();
        $post = $request->param();
        $coupons = new CouponModel;
        $post['num'] = (request()->param('num') == null) ? 1 : request()->param('num');
        $couponsList = $coupons->orderCoupon($post['activity_id'], $post['schedule_id'], $post['num'], session('user.id'));
        $schedule = Db::name('activity_schedule')
            ->field('id as schedule_id,start_time,end_time,maximum,real_join_num,addition_join_num,price')
            ->where(['activity_id' => $post['activity_id']])
            ->select();
        $total = 0;
        $choose = [];
        foreach ($schedule as $k => $v) {
            $v['start_time'] = date('Y.m.d', $v['start_time']);
            $v['end_time'] = date('Y.m.d', $v['end_time']);
            if ($v['schedule_id'] == $post['schedule_id']) {
                $allowMaximum = $v['maximum'] - ($v['real_join_num'] + $v['addition_join_num']);
                $total = $v['price'] * $post['num'];
                $choose = [
                    'schedule_id' => $post['schedule_id'],
                    'time_text' => $v['start_time'] . ' 至 ' . $v['end_time'],
                    'num' => $post['num'],
                    'allowMaximum' => $allowMaximum
                ];
            }
            unset($v['real_join_num']);
            unset($v['addition_join_num']);
            unset($v['maximum']);
            $schedule[$k] = $v;
        }
        $result = [
            'is_first' => Db::name('user')->where(['id' => session('user.id')])->value('is_first'),
            'activity' => Db::name('activity')->field('id as activity_id,name, is_down_payment as type')->where(['id' => $post['activity_id']])->find(),
            'schedule' => $schedule,
            'choose' => $choose,
            'coupons' => $couponsList,
            'down_price' => Db::name('activity')->where(['id' => $post['activity_id']])->value('down_price') * $post['num'],
            'total' => $total
        ];
        if (request()->isPost()) {
            echo json_encode(['data' => $result, 'code' => 20000]);
            exit();
        } else {
            require_once EXTEND_PATH . '/WeChatCommon.php';
            $wx = new \WeChatCommon();
            return $this->fetch(':confirm', [
                'data' => $result,
                'js_sdk' => $wx->js_sdk()
            ]);
        }
    }

    /**
     * @title 提交订单
     * @description 默认访问接口
     * @author sᴏᴜʟ ᴏғ ᴄɪɴᴅᴇʀ
     * @url /order/Order/done
     * @method POST
     *
     * @param name:activity_id  type:int require:1 default:19 desc:活动id
     * @param name:schedule_id  type:int require:1 default:68 desc:批次id
     * @param name:num  type:int require:1 default:2 desc:购买数量
     * @param name:escort  type:char require:1 default:同行人id字符串(逗号分隔) desc:1,2,3
     * @param name:payment  type:int require:1 default:支付方式 desc:0余额,1微信,2支付宝
     * @param name:discount_coupon_id  type:int require:0 default:112 desc:优惠券id
     * @param name:room  type:char require:1 default:1 desc:房间信息
     * @param name:desc  type:text require:1 default:0 desc:商家备注
     */
    public function done()
    {
        $request = request();
        if ($request->isPost()) {
            $post = $request->param();
            $data['user_id'] = session('user.id');
            $data['order_sn'] = date('YmdHis') . rand(0, 9999);
            $data['activity_id'] = $post['activity_id'];
            $data['schedule_id'] = $post['schedule_id'];
            $data['add_time'] = time();
            $activity = Db::name('activity')->field('is_down_payment,down_price')->where(['id' => $post['activity_id']])->find();
            $data['order_type'] = $activity['is_down_payment'];
            $data['is_use_discount_coupon'] = (empty($post['discount_coupon_id'])) ? 0 : 1;
            $data['discount_coupon_id'] = $post['discount_coupon_id'];
            $data['payment'] = $post['payment'];
            $data['status'] = 1;
            $data['room'] = $post['room'];
            $data['desc'] = $post['desc'];
            $final_price = $this->getFinalPrice($data['activity_id'], $data['schedule_id'], $post['num'], $data['discount_coupon_id']);
            $post['escort'] = substr($post['escort'], 0, strlen($post['escort']) - 1);
            if (empty($post['escort'])) {
                echo json_encode(['msg' => '请选择出行人', 'code' => 40000]);
                exit();
            }
            $this->checkOrder($data['schedule_id'], $data['payment'], $post['escort'], $post['num'], $final_price);
            Db::startTrans();
            if (Db::name('order_info')->insert($data)) {
                $oid = Db::name('order_info')->getLastInsID();
                $detail = [];
                $explode_escort = explode(',', $post['escort']);
                for ($i = 0; $i < $post['num']; $i++) {
                    $detail[$i] = [
                        'oid' => $oid,
                        'escort_id' => $explode_escort[$i],
                        'status' => 0
                    ];
                }
                if (Db::name('order_detail')->insertAll($detail)) {
                    //☆在这就要将优惠券变为已使用☆
                    if ($data['is_use_discount_coupon'] == 1 && !empty($data['discount_coupon_id'])) {
                        $coupons = [
                            'id' => $post['discount_coupon_id'],
                            'use_time' => time(),
                            'status' => 2
                        ];
                        if (!(Db::name('discount_coupon')->update($coupons))) {
                            Db::rollback();
                        }
                    }
                    //插入订单记录表(包含订单总价)
                    $log = [
                        'oid' => $oid,
                        'order_amount' => $final_price,
                        'type' => $data['order_type']
                    ];
                    if (Db::name('order_log')->insert($log)) {
                        Db::commit();
                        //首次下单状态改变
                        Db::name('user')->update(['id' => session('user.id'), 'is_first' => 0]);

                        //微信支付
                        if ($data['payment'] == 1) {
                            $info = [
                                'attach' => $oid,
                                'openid' => session('user.openid'),
                                'body' => '萨米户外',
                                'total_fee' => $final_price
                            ];
                            $this->success('微信支付', url('user/Center/orderDetail', ['oid' => $oid]), $this->wxPay($info));
                        } //支付宝支付
                        elseif ($data['payment'] == 2) {
                            $this->alipay('201810182015', '购买', 0.01, '商品');
                        } //余额支付
                        elseif ($data['payment'] == 0) {
                            $model = new OrderModel;
                            if ($model->orderCallBack($oid)) {
                                echo json_encode(['msg' => '下单成功', 'code' => 20000, 'url' => url('user/Center/orderDetail', ['oid' => $oid])]);
                                exit();
                            } else {
                                echo json_encode(['msg' => '下单失败', 'code' => 40000]);
                                exit();
                            }
                        } else {
                            echo json_encode(['msg' => '未知错误', 'code' => 40000]);
                            exit();
                        }
                    }
                }
            } else {
                Db::rollback();
                echo json_encode(['msg' => '下单失败', 'code' => 40000]);
                exit();
            }
        } else {
            echo json_encode(['msg' => '非法操作', 'code' => 40000]);
            exit();
        }
    }

    //个人中心继续付款
    public function done2()
    {
        $request = request();
        if ($request->isPost()) {
            $oid = $request->param('oid');
            $info = Db::name('order_info')->alias('o')
                ->field('status,order_type,a.down_price,s.price')
                ->join('activity a', 'o.activity_id=a.id')
                ->join('activity_schedule s ', 'o.schedule_id=s.id')
                ->where(['o.id' => $oid])->find();
            $num = Db::name('order_detail')->where(['oid' => $oid, 'status' => ['neq', 2]])->count();
            if ($info['status'] == 1) {
                if ($info['order_type'] == 0) {
                    $order_amount = $num * $info['price'];
                } elseif ($info['order_type'] == 1) {
                    $order_amount = $num * $info['down_price'];
                } else {
                    echo json_encode(['msg' => '未知错误', 'code' => 40000]);
                    exit();
                }
            } elseif ($info['status'] == 3) {
                $order_amount = $num * $info['price'];
            } else {
                echo json_encode(['msg' => '未知错误', 'code' => 40000]);
                exit();
            }
            //再次支付的支付方式,先更新支付方式
            $payment = $request->param('payment');
            Db::name('order_info')->update(['id' => $oid, 'payment' => $payment]);
            if ($payment == 0) {
                $model = new OrderModel;
                $balance = Db::name('user')->where(['id'=>session('user.id')])->value('balance');
                if($balance < $order_amount) {
                    echo json_encode(['msg' => '您的余额不足', 'code' => 40000]);
                    exit();
                }
                if ($model->orderCallBack($oid, $order_amount)) {
                    //如果是有定金订单,则需要更新order_log
                    if ($info['order_type'] == 1) {
                        Db::name('order_log')->where(['oid' => $oid])->update(['order_amount' => $order_amount]);
                    }
                    echo json_encode(['msg' => '支付成功', 'code' => 20000, 'url' => url('user/Center/orderDetail', ['oid' => $oid])]);
                    exit();
                } else {
                    echo json_encode(['msg' => '支付失败', 'code' => 40000]);
                    exit();
                }
            } elseif ($payment == 1) {
                $data = [
                    'attach' => $oid,
                    'openid' => session('user.openid'),
                    'body' => '萨米户外',
                    'total_fee' => $order_amount
                ];
                echo json_encode(['msg' => '微信支付', 'data' => $this->wxPay($data), 'code' => 20000, 'url' => url('user/Center/orderDetail', ['oid' => $oid])]);
                exit();
            } elseif ($payment == 2) {
                echo json_encode(['msg' => '支付宝支付', 'code' => 20000]);
            } else {
                echo json_encode(['msg' => '未知错误', 'code' => 40000]);
                exit();
            }
        } else {
            echo json_encode(['msg' => '非法操作', 'code' => 40000]);
            exit();
        }
    }

    /**
     * 计算订单最终价格
     * @param $activityId
     * @param $scheduleId
     * @param $num
     * @param null $discountCouponId
     * @return float|int|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function getFinalPrice($activityId, $scheduleId, $num, $discountCouponId = null)
    {
        $info = Db::name('activity')->field('is_down_payment,down_price')->where(['id' => $activityId])->find();
        //如果有定金则支付定金*数量
        if ($info['is_down_payment'] == 1) {
            $sum = $info['down_price'] * $num;
        } //如果没有定金则支付批次金额*数量
        else {
            $price = Db::name('activity_schedule')->where(['activity_id' => $activityId, 'id' => $scheduleId])->value('price');
            $sum = $price * $num;
        }
        //如果有使用优惠券
        if (!empty($discountCouponId)) {
            //判断该优惠券是否已使用
            $coupons = Db::name('discount_coupon')->field('status,reduce,overflow')->where(['id' => $discountCouponId])->find();
            if ($coupons['status'] == 1) {
                //是否符合满减
                if ($sum >= $coupons['overflow']) {
                    $sum -= $coupons['reduce'];
                }
            }
        }
        return $sum;
    }

    /**
     * 订单校验
     * @param $scheduleId
     * @param int $payment
     * @param $escort
     * @param $num
     * @param $finalPrice
     */
    private function checkOrder($scheduleId, $payment = 0, $escort, $num, $finalPrice)
    {
        if ($scheduleId == null) {
            echo json_encode(['msg' => '请选择活动批次', 'code' => 40000]);
            exit();
        }
        //判断活动是否过期
        if (Db::name('activity_schedule')->where(['id' => $scheduleId])->value('deadline') < time()) {
            echo json_encode(['msg' => '本次活动已过期,请重新选择', 'code' => 40000]);
            exit();
        }
        //判断出行人与购买数量是否匹配
        $escortNum = (strlen($escort) == 1) ? 1 : count(explode(',', $escort));
        if ($escortNum != $num) {
            echo json_encode(['msg' => '购买数量需与出行人数量一致', 'code' => 40000]);
            exit();
        }
        //判断支付方式
        if (($payment != 0 && $payment != 1 && $payment != 2 && $payment) || $payment == null) {
            echo json_encode(['msg' => '请选择支付方式', 'code' => 40000]);
            exit();
        }
        //判断用户余额能否支持余额支付
        if ($payment == 0) {
            if (Db::name('user')->where(['id' => session('user.id')])->value('balance') < $finalPrice) {
                echo json_encode(['msg' => '您的余额不足,请选择其他支付方式', 'code' => 40000]);
                exit();
            }
        }
    }

    //微信支付
    private function wxPay($info)
    {
        $pay = new \Payment($info['attach'], $info['openid'], $info['body'], 1/*$info['total_fee'] * 100*/);
        return $pay->pay();
    }

    public function notify()
    {
        $pay = new \Payment();
        $return = $pay->handleNotify();
        if(!empty($return)) {
            $order = new OrderModel;
            $order->orderCallBack($return['attach'], $return['total_fee']);
        }
    }

    //欢迎支付宝支付
    private function alipay($out_trade_no, $subject, $total_amount, $body)
    {
        if(!cmf_is_wechat()) {
            header("Content-type: text/html; charset=utf-8");
            require_once EXTEND_PATH . '/alipay/wappay/service/AlipayTradeService.php';
            require_once EXTEND_PATH . '/alipay/wappay/buildermodel/AlipayTradeWapPayContentBuilder.php';
            require EXTEND_PATH . '/alipay/config.php';

            //超时时间
            $timeout_express = "1m";

            $payRequestBuilder = new \AlipayTradeWapPayContentBuilder();
            $payRequestBuilder->setBody($body);
            $payRequestBuilder->setSubject($subject);
            $payRequestBuilder->setOutTradeNo($out_trade_no);
            $payRequestBuilder->setTotalAmount($total_amount);
            $payRequestBuilder->setTimeExpress($timeout_express);

            $payResponse = new \AlipayTradeService($config);
            $payResponse->wapPay($payRequestBuilder, $config['return_url'], $config['notify_url']);
        }else {
            $this->redirect(url('order/Order/alipayDo'));
        }
    }

    //微信中转页面
    public function alipayDo() {
        return $this->fetch(':pay');
    }

    //支付宝回调
    public function alipayNotify() {

    }

}