| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 | <?phpnamespace addons\unishop\behavior;use addons\unishop\extend\Ali;use addons\unishop\extend\Hashids;use addons\unishop\extend\Wechat;use addons\unishop\model\Address;use addons\unishop\model\Config;use addons\unishop\model\DeliveryRule as DeliveryRuleModel;use addons\unishop\model\OrderProduct;use addons\unishop\model\Product;use app\admin\model\unishop\Coupon;use think\Db;use think\Exception;/** * 订单相关行为 * Class Order * @package addons\unishop\behavior */class Order{    /**     * 创建订单之后     * 行为一:根据订单减少商品库存 增加"已下单未支付数量"     * 行为二:如果选了购物车的就删除购物车的信息     * @param array $params 商品属性     * @param array $extra [specNumber] => ['spec1' => 'number1','spec2' => 'number2']     */    public function createOrderAfter(&$params, $extra)    {        // 行为一        $key = 0;        $productExtend = new \addons\unishop\extend\Product;        $prefix = \think\Config::get('database.prefix');        if (Config::isPessimism()) {            // 悲观锁            foreach ($extra['specNumber'] as $spec => $number) {                $result = 0;                if (is_numeric($spec) && $params[$key]['use_spec'] == Product::SPEC_OFF) {                    $result = Db::execute('UPDATE ' . $prefix . "unishop_product SET no_buy_yet = no_buy_yet+{$number}, real_sales = real_sales+{$number}, stock = stock-{$number} WHERE id = {$params[$key]['id']}");                } else if ($params[$key]['use_spec'] == Product::SPEC_ON) {                    $info = $productExtend->getBaseData($params[$key], $spec);                    // mysql<5.7.13时用                    //if (mysql < 5.7.13) {                    $spec = str_replace(',', '","', $spec);                    $search = '"stock":"' . $info['stock'] . '","value":["' . $spec . '"]';                    $stock = $info['stock'] - $number;                    $replace = '"stock":\"' . $stock . '\","value":["' . $spec . '"]';                    $sql = 'UPDATE ' . $prefix . "unishop_product SET no_buy_yet = no_buy_yet+{$number}, stock = stock-{$number}, real_sales = real_sales+{$number} ,`specTableList` = REPLACE(specTableList,'$search','$replace') WHERE id = {$params[$key]['id']}";                    $result = Db::execute($sql);                    //}                    //下面语句直接操作JSON                    //if (mysql >= 5.7.13) {                    //$info['stock'] -= $number;                    //$result = Db::execute("UPDATE fa_unishop_product SET no_buy_yet = no_buy_yet+{$number}, real_sales = real_sales+{$number}, stock = stock-{$number},specTableList = JSON_REPLACE(specTableList, '$[{$info['key']}].stock', {$info['stock']}) WHERE id = {$params[$key]['id']}");                    //}                }                if ($result == 0) { // 锁生效                    throw new Exception('下单失败,请重试');                }                $key++;            }        } else {            // 乐观锁            foreach ($extra['specNumber'] as $spec => $number) {                $result = 0;                if (is_numeric($spec) && $params[$key]['use_spec'] == Product::SPEC_OFF) {                    $result = Db::execute('UPDATE ' . $prefix . "unishop_product SET no_buy_yet = no_buy_yet+{$number}, real_sales = real_sales+{$number}, stock = stock-{$number} WHERE id = {$params[$key]['id']} AND stock = {$params[$key]['stock']}");                } else if ($params[$key]['use_spec'] == Product::SPEC_ON) {                    $info = $productExtend->getBaseData($params[$key], $spec);                    // mysql<5.7.13时用                    //if (mysql < 5.7.13) {                    $spec = str_replace(',', '","', $spec);                    $search = '"stock":"' . $info['stock'] . '","value":["' . $spec . '"]';                    $stock = $info['stock'] - $number;                    $replace = '"stock":\"' . $stock . '\","value":["' . $spec . '"]';                    $sql = 'UPDATE ' . $prefix . "unishop_product SET no_buy_yet = no_buy_yet+{$number}, real_sales = real_sales+{$number}, stock = stock-{$number},`specTableList` = REPLACE(specTableList,'$search','$replace') WHERE id = {$params[$key]['id']} AND stock = {$params[$key]['stock']}";                    $result = Db::execute($sql);                    //}                    //下面语句直接操作JSON                    //if (mysql >= 5.7.13) {                    //$info['stock'] -= $number;                    //$result = Db::execute("UPDATE fa_unishop_product SET no_buy_yet = no_buy_yet+{$number}, real_sales = real_sales+{$number}, stock = stock-{$number},specTableList = JSON_REPLACE(specTableList, '$[{$info['key']}].stock', {$info['stock']}) WHERE id = {$params[$key]['id']} AND stock = {$params[$key]['stock']}");                    //}                }                if ($result == 0) { // 锁生效                    throw new Exception('下单失败,请重试');                }                $key++;            }        }        // 行为二        if (!empty($extra['cart'])) {            $cart = $extra['cart'];            Db::execute('DELETE FROM ' . $prefix . "unishop_cart WHERE id IN ($cart) AND user_id = $extra[userId]");        }        // More ...    }    /**     * 检查是否符合创建订单的条件     * 条件1:商品是否存在     * 条件2:商品库存情况     * 条件3:收货地址是否在范围内     * 条件4:是否使用优惠券,优惠券能否可用     * @param array $params     * @param array $extra     * @throws Exception     * @throws \think\exception\DbException     */    public function createOrderBefore(&$params, $extra)    {        $specs = explode(',', $extra['spec']);        foreach ($specs as &$spec) {            $spec = str_replace('|', ',', $spec);        }        $numbers = explode(',', $extra['number']);        $productIds = explode(',', $extra['product_id']);        if (count($specs) !== count($numbers) || count($specs) !== count($productIds)) {            throw new Exception(__('Parameter error'));        }        // 订单价格        $orderPrice = 0;        // 条件一        $products = [];        foreach ($productIds as $key => &$productId) {            $productId = Hashids::decodeHex($productId);            $products[$key] = Db::name('unishop_product')                ->where(['id' => $productId, 'switch' => Product::SWITCH_ON])                ->lock(Config::isPessimism()) // Todo 是否使用悲观锁                ->find();            if (!$products[$key]) {                throw new Exception(__('There are not exist or Offline'));            }        }        if (count($products) == 0 || count($productIds) != count($products)) {            throw new Exception(__('There are offline product'));        }        // 从购物车下单多个商品时,有同一个商品的不同规格导致减库存问题        if (count($productIds) > 0) {            $reduceStock = [];            foreach ($products as $key => $value) {                if (!isset($reduceStock[$value['id']])) {                    $reduceStock[$value['id']] = $numbers[$key];                } else {                    $products[$key]['stock'] -= $reduceStock[$value['id']];                    $reduceStock[$value['id']] += $numbers[$key];                }            }        }        // 条件二        foreach ($products as $key => $product) {            $productInfo = (new \addons\unishop\extend\Product())->getBaseData($product, $specs[$key] ? $specs[$key] : '');            if ($productInfo['stock'] < $numbers[$key]) {                throw new Exception(__('Insufficient inventory,%s pieces left', $productInfo['stock']));            }            $orderPrice = bcadd($orderPrice, bcmul($productInfo['sales_price'], $numbers[$key], 2), 2);            $baseProductInfo[] = $productInfo;        }//        // 条件三//        $delivery = (new DeliveryRuleModel())->cityInScopeOfDelivery($extra['city_id'], $extra['delivery_id']);//        if (!$delivery) {//            throw new Exception(__('Your receiving address is not within the scope of delivery'));//        } else {//            if ($delivery['min'] > array_sum($numbers)) {//                throw new Exception(__('You must purchase at least %s item to use this shipping method', $delivery['min']));//            }//        }//        $address = (new Address)->where(['id' => $extra['address_id'], 'user_id' => $extra['userId']])->find();//        if (!$address) {//            throw new Exception(__('Address not exist'));//        }//        // 条件四//        if ($extra['coupon_id']) {//            $coupon = Coupon::get($extra['coupon_id']);//            if ($coupon['switch'] == Coupon::SWITCH_OFF || $coupon['deletetime'] || $coupon['starttime'] > time() || $coupon['endtime'] < time()) {//                throw new Exception('此优惠券不可用');//            }//            // 至少消费多少钱//            if ($coupon['least'] > $orderPrice) {//                throw new Exception('选中的优惠券不满足使用条件');//            }//        } else {//            $coupon = [];//        }        $coupon = [];        $params = [$products, '', $coupon, $baseProductInfo, '', $orderPrice, $specs, $numbers];    }    /**     * 支付成功     * 行为一:更改订单的支付状态,更新支付时间。     * 行为二:减少商品的已下单但未支付的数量     * @param $params     * @param $extra     * @throws \think\db\exception\DataNotFoundException     * @throws \think\db\exception\ModelNotFoundException     * @throws \think\exception\DbException     */    public function paidSuccess(&$params, $extra)    {        $order = &$params;        $order->have_paid = time();// 更新支付时间为当前时间        $order->pay_type = $extra['pay_type'];        $order->save();        $orderProductModel = new OrderProduct();        $orderProducts = $orderProductModel            ->with('product')            ->where(['order_id' => $order->id])            ->select();        foreach ($orderProducts as $product) {            if (isset($product->product)) {                $product->product->no_buy_yet -= $product->number;                $product->product->save();            }        }        // More ...    }    /**     * 支付失败     * @param $params     */    public function paidFail(&$params)    {        $order = &$params;        $order->have_paid = \addons\unishop\model\Order::PAID_NO;        $order->save();        // More ...    }    /**     * 订单退款     * 行为一:退款     * @param array $params 订单数据     */    public function orderRefund(&$params)    {        $order = &$params;        // 行为一        switch ($order['pay_type']) {            case \addons\unishop\model\Order::PAY_WXPAY:                $app = Wechat::initEasyWechat('payment');                $result = $app->refund->byOutTradeNumber($params['out_trade_no'], $params['out_trade_no'], bcmul($params['total_price'], 100), bcmul($params['refund']['amount'], 100), [                    // 可在此处传入其他参数,详细参数见微信支付文档                    'refund_desc' => $params['refund']['reason_type'],                ]);                break;            case \addons\unishop\model\Order::PAY_ALIPAY:                $alipay = Ali::initAliPay();                $order = [                    'out_trade_no' => $params['out_trade_no'],                    'refund_amount' => $params['total_price'],                ];                $result = $alipay->refund($order);                break;        }        // More ...    }}
 |