['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]"); } // 行为三 $coupon = $extra['coupon']; if (!empty($coupon)) { Db::name('unishop_coupon_user')->where('id',$coupon['cu_id'])->update(['status'=>1]); } // 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'])); } }*/ $delivery = []; /*$address = (new Address)->where(['id' => $extra['address_id'], 'user_id' => $extra['userId']])->find(); if (!$address) { throw new Exception(__('Address not exist')); }*/ $address = []; // 条件四 if ($extra['coupon_id']) { // $coupon = Coupon::get($extra['coupon_id']); $coupon = Db::name('unishop_coupon_user')->alias('cu') ->field(['cu.id as cu_id','c.id','c.title','c.least','c.value','c.starttime','c.endtime']) ->join('unishop_coupon c','cu.coupon_id = c.id','LEFT') ->where('cu.user_id',$extra['userId']) ->where('cu.status',0) ->where('c.deletetime',NULL) ->where('c.switch',Coupon::SWITCH_ON) // ->where('c.starttime','<',time()) // ->where('c.endtime','>',time()) ->where('cu.id',$extra['coupon_id']) ->find(); if(!empty($coupon)){ if ($coupon['starttime'] > time() || $coupon['endtime'] < time()) { throw new Exception('此优惠券不可用'); } // 至少消费多少钱 if ($coupon['least'] > $orderPrice) { throw new Exception('选中的优惠券不满足使用条件'); } }else{ $coupon = []; } } else { $coupon = []; } $params = [$products, $delivery, $coupon, $baseProductInfo, $address, $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 ... } }