getData('level'), $post); $goods_info['sub_price'] = round($goods_info['goods_price'] * $good['num'], 2); $goods_lists[] = $goods_info; //订单汇总信息 $total_num += $good['num']; $total_goods_price += $goods_info['goods_price'] * $good['num']; $give_integral_num += $goods_info['give_integral_num']; } //用户地址 $user_address = UserAddressLogic::getOrderUserAddress($post, $user_id); //运费(自提订单不需要运费) $total_shipping_price = ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? 0 :FreightLogic::calculateFreight($goods_lists, $user_address); //订单金额 $total_amount = $total_goods_price; //订单应付金额 $order_amount = $total_goods_price; //使用优惠券 if (isset($post['coupon_id']) && self::$order_type == CommonOrder::NORMAL_ORDER) { //订单优惠金额 $discount_amount_data = self::calculateDiscountAmount($goods_lists, $post['coupon_id']); $discount_amount = $discount_amount_data['total_discount']; $goods_lists = $discount_amount_data['goods']; $order_amount = $order_amount - $discount_amount; } //积分抵扣是否打开 $integral_switch = IntegralLogic::isIntegralInOrder($goods_lists) ? 1 : 0; $integral_config = ConfigServer::get('marketing', 'integral_deduction_money', 0); //积分抵扣限制 $integral_limit = ConfigServer::get('marketing', 'integral_deduction_limit', 0); //积分描述 $integral_desc = IntegralLogic::getIntegralDesc($integral_config, $integral_limit); //使用积分抵扣 $integral_amount = 0;//积分抵扣金额 $user_use_integral = 0;//用户使用的积分 $use_integral = $post['use_integral'] ?? 0;//是否使用积分 if ($use_integral == 1 && $order_amount > 0 && self::$order_type == CommonOrder::NORMAL_ORDER) { $integral_data = self::integralDeductionMoney($goods_lists, $user_id, $integral_switch, $integral_config, $integral_limit); $integral_amount = $integral_data['integral_money']; $goods_lists = $integral_data['goods']; $order_amount = $order_amount - $integral_amount; $user_use_integral = $integral_data['user_use_integral']; } if ($order_amount <= 0){ $order_amount = 0; } $order_amount += $total_shipping_price;//应付订单金额+运费 $total_amount += $total_shipping_price;//订单金额+运费 // 门店自提显示上次提货人信息 if($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF){ $selffetch_info = Order::where([ 'user_id'=>$user['id'], 'delivery_type'=>CommonOrder::DELIVERY_STATUS_SELF ]) ->field('consignee,mobile,selffetch_shop_id') ->order('id desc') ->findOrEmpty()->toArray(); //上一次提货人 $selffetch_field = [ 'id', 'name', 'image', 'contact', 'mobile', 'province', 'city', 'district', 'longitude', 'address', 'latitude', 'business_start_time', 'business_end_time', 'weekdays', 'remark', 'status', ]; $self_fetch_info = [ 'selffetch_shop_id' => $selffetch_info['selffetch_shop_id'] ?? '', 'contact' => $selffetch_info['consignee'] ?? '', 'mobile' => $selffetch_info['mobile'] ?? '', 'selffetch_shop' => SelffetchShop::where('status', 1) ->field($selffetch_field) ->append([ 'shop_address' ]) ->order('id desc') ->find($selffetch_info['selffetch_shop_id'] ?? 0), ]; } $result = [ 'order_type' => self::$order_type, 'goods_lists' => array_values($goods_lists), 'coupon_id' => $post['coupon_id'] ?? 0, 'total_num' => $total_num,//订单总数量 'total_goods_price' => round($total_goods_price, 2),//订单商品总价 'total_amount' => round($total_amount, 2),//订单总价(商品价格,运费,优惠券等) 'order_amount' => round($order_amount, 2),//订单应付价格 'give_integral_num' => intval($give_integral_num), //赠送总积分数 'address' => $user_address, 'discount_amount' => $discount_amount,//优惠券抵扣金额 'integral_amount' => $integral_amount,//积分抵扣金额 'shipping_price' => round($total_shipping_price, 2),//运费 'remark' => $post['remark'] ?? '', 'pay_way' => $post['pay_way'] ?? 0, 'user_money' => $user['user_money'],//用户余额 'user_use_integral' => $user_use_integral,//用户使用积分 'user_integral' => $user['user_integral'],//用户拥有积分 'integral_limit' => $integral_limit,// 积分抵扣限制 'integral_switch' => $integral_switch,//积分抵扣开关 'integral_config' => $integral_config,//积分抵扣配置 'integral_desc' => $integral_desc,//积分抵扣描述 'selffetch_info' => $self_fetch_info ?? null, ]; return self::dataSuccess('', $result); } catch (Exception $e){ return self::dataError($e->getMessage()); } } /** * Notes: * @param $infos * @param $item_id * @param $goods_num * @param $seckill_goods * @param $level * @param $post * @author 段誉(2021/4/1 19:00) * @return mixed */ public static function goodsTemolate($infos, $item_id, $goods_num, $seckill_goods, $level, $post) { $goods_info = $infos[$item_id]; $goods_info['goods_num'] = $goods_num; $image_str = empty($goods_info['spec_image']) ? $goods_info['image'] : $goods_info['spec_image']; $goods_info['image_str'] = UrlServer::getFileUrl($image_str); $goods_info['is_seckill'] = 0; $goods_info['discount_price'] = 0; $goods_info['integral_price'] = 0; $goods_info['original_price'] = $goods_info['goods_price'];//商品原价 $goods_info['member_price'] = $goods_info['goods_price'];//会员价格 $goods_info['is_show_member'] = 0; //是否显示会员价格 $goods_info['give_integral_num'] = 0; // 赠送积分 unset($goods_info['id']); //当前商品规格是否为秒杀商品 if (isset($seckill_goods[$item_id])) { $goods_info['goods_price'] = $seckill_goods[$item_id]['price']; $goods_info['is_seckill'] = 1; self::$order_type = CommonOrder::SECKILL_ORDER;//秒杀订单 return $goods_info; } // 如果是砍价的商品替换信息 if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) { $bargainLaunchModel = new BargainLaunch(); $launch = $bargainLaunchModel->field(true) ->where(['id'=>(int)$post['bargain_launch_id']]) ->find(); $bargainImage = $launch['goods_snap']['image'] == '' ? $launch['goods_snap']['goods_iamge'] : $launch['goods_snap']['image']; $goods_info['goods_name'] = $launch['goods_snap']['name']; $goods_info['image_str'] = UrlServer::getFileUrl($bargainImage); $goods_info['goods_price'] = $launch['current_price']; $goods_info['spec_value_str'] = $launch['goods_snap']['spec_value_str']; self::$order_type = CommonOrder::BARGAIN_ORDER;//砍价订单 return $goods_info; } // 赠送积分 if ($goods_info['give_integral_type'] == 1) { $goods_info['give_integral_num'] += ($goods_info['give_integral'] * $goods_info['goods_num']); } elseif ($goods_info['give_integral_type'] == 2) { $proportion = $goods_info['give_integral'] / 100; $give_integral_num = $proportion * $goods_info['goods_price']; $goods_info['give_integral_num'] += ($give_integral_num * $goods_info['goods_num']); } //会员折扣价格,不参与商品活动 $level_discount = UserLevel::get($level)['discount'] ?? 0; if ($goods_info['is_member'] == 1 && $level_discount > 0) { //会员折扣价格 $member_price = round($goods_info['goods_price'] * $level_discount / 10, 2); $goods_info['member_price'] = $member_price; $goods_info['goods_price'] = $member_price; $goods_info['member_discount'] = $level_discount; $goods_info['is_show_member'] = 1; return $goods_info; } return $goods_info; } /** * Notes: 积分抵扣 * @param $goods_lists 商品信息 * @param $user_id 用户id * @param $switch 积分开关 * @param $integral_config 积分配置 * @author 段誉(2021/1/30 15:00) * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function integralDeductionMoney($goods_lists, $user_id, $switch, $integral_config, $integral_limit) { $data = [ 'goods' => $goods_lists, 'integral_money' => 0, 'user_use_integral' => 0 ]; if ($switch == 0 || $integral_config == 0) { return $data; } $user = Db::name('user')->where(['id' => $user_id])->find(); //用户可抵扣积分金额 $integral_deduction_price = round($user['user_integral'] / $integral_config, 2); //满1000积分才可以使用 if ($integral_limit != 0 && $user['user_integral'] < $integral_limit) { return $data; } //扣除优惠券后的商品总金额 $total_price = 0; foreach ($goods_lists as $item) { //当前商品是否可以积分抵扣 if ($item['is_integral'] != 1) { continue; } $total_price += $item['goods_price'] * $item['goods_num'] - $item['discount_price']; } //用户积分可抵扣金额大于订单应付金额时 if ($integral_deduction_price >= $total_price) { $integral_deduction_price = $total_price; } $total_integral_money = 0; foreach ($goods_lists as &$good) { if ($item['is_integral'] != 1){ continue; } $good_price = $good['goods_price'] * $good['goods_num'] - $good['discount_price']; $discount = $good_price / $total_price * $integral_deduction_price; //每个商品抵扣的积分金额 $good['integral_price'] = round($discount, 2); $total_integral_money += $discount; } //用户积分可抵扣金额大于订单应付金额时 $user_use_integral = $user['user_integral']; if ($integral_deduction_price >= $total_price) { $user_use_integral = $integral_deduction_price * $integral_config; } return [ 'goods' => $goods_lists, 'integral_money' => $integral_deduction_price,//积分抵扣金额 'user_use_integral' => $user_use_integral //用户此次订单抵扣的积分 ]; } /** * Notes: 计算优惠金额 * @param $goods * @param $cl_id * @author 段誉(2021/1/30 15:00) * @return array * @throws Exception * 1,找出商品在优惠条件中的 总商品金额和商品数量 * 2,计算出每个商品可获得的优惠金额,最后一个商品,用总优惠券金额 - 已优惠金额 */ public static function calculateDiscountAmount($goods, $cl_id) { $coupon = Coupon::getCouponByClId($cl_id); if (empty($coupon)){ return ['goods' => $goods, 'total_discount' => 0]; } //与优惠券关联的商品id $coupon_goods = Db::name('coupon_goods') ->where(['coupon_id' => $coupon['id']]) ->column('goods_id'); $coupon_goods_data = self::discountGoods($goods, $coupon, $coupon_goods); $goods_count = $coupon_goods_data['count'];//可以优惠的商品数量 $total_goods_price = $coupon_goods_data['discount_goods'];//可以优惠的商品总金额 $total_discount = 0; $discount = 0;//每件商品优惠金额 $check_num = 0; foreach ($goods as &$good) { //指定可用时 if ($coupon['use_goods_type'] == 2 && !in_array($good['goods_id'], $coupon_goods)) { continue; } //指定不可用 if ($coupon['use_goods_type'] == 3 && in_array($good['goods_id'], $coupon_goods)) { continue; } //小计 $sub_price = $good['goods_price'] * $good['goods_num']; //每个订单商品可以获得的优惠金额 (订单商品/总商品金额) * 优惠券金额 $discount = ($sub_price) / $total_goods_price * $coupon['money']; $discount = round($discount, 2); //当前可获得优惠大于当前订单商品时 if ($discount > $sub_price) { $discount = $sub_price; } //用于判断当前是否为最后一个商品 if (($check_num + 1) == $goods_count) { $discount = round($coupon['money'] - round($total_discount, 2), 2); //当前可获得优惠大于当前订单商品时 if ($discount > $sub_price) { $discount = $sub_price; } } //商品优惠金额 $good['discount_price'] = $discount;//每个商品优惠的金额 $check_num += 1; $total_discount += $discount; } return [ 'goods' => $goods, 'total_discount' => round($total_discount, 2), ]; } /** * Notes: 订单中优惠商品的总价 * @param $goods * @param $coupon * @param $coupon_goods * @author 段誉(2021/1/30 15:00) * @return array * @throws Exception */ public static function discountGoods($goods, $coupon, $coupon_goods) { $discount_goods = 0; $count = 0; //1-全部商品;2-指定商品;3-指定商品不可用 foreach ($goods as $good){ if ($coupon['use_goods_type'] == 1){ $discount_goods += $good['goods_price'] * $good['goods_num']; $count += 1; } if (($coupon['use_goods_type'] == 2) && in_array($good['goods_id'], $coupon_goods)){ $discount_goods += $good['goods_price'] * $good['goods_num']; $count += 1; } if ($coupon['use_goods_type'] == 3 && !in_array($good['goods_id'], $coupon_goods)){ $discount_goods += $good['goods_price'] * $good['goods_num']; $count += 1; } } if ($coupon['condition_type'] == 2 && $discount_goods < $coupon['condition_money']){ throw new Exception('所结算的商品中未满足使用的金额'); } return $data = [ 'count' => $count, 'discount_goods' => $discount_goods, ]; } /** * Notes: 获取指定商品信息 * @param $item_ids * @author 段誉(2021/1/30 15:01) * @return array */ public static function getGoodsColumn($item_ids) { $field = 'i.id as item_id,g.id as goods_id,g.name as goods_name,g.status,g.del,g.image, g.is_integral,g.is_member,g.give_integral_type,g.give_integral,g.free_shipping_type, g.free_shipping,g.free_shipping_template_id,i.image as spec_image, i.spec_value_str,i.spec_value_ids,i.price as goods_price,i.volume,i.stock, i.weight,g.first_category_id,g.second_category_id,g.third_category_id,g.is_express,g.is_selffetch'; $goods = Db::name('goods g') ->join('goods_item i', 'g.id = i.goods_id') ->where('i.id', 'in', $item_ids) ->column($field, 'i.id'); return $goods; } /** * Notes: 添加订单 * @param $user_id * @param $data * @param $post * @author 段誉(2021/1/30 15:01) * @return array */ public static function add($user_id, $data, $post) { Db::startTrans(); try { $type = $post['type'] ?? ''; $order_source = $post['client']; $goods_lists = $data['goods_lists']; $user_address = $data['address']; $user = User::get($user_id); if ($post['delivery_type'] != CommonOrder::DELIVERY_STATUS_SELF && empty($data['address'])) { throw new Exception('请选择收货地址'); } if ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF && empty($post['selffetch_shop_id'])) { throw new Exception('自提门店不能为空'); } // if (isset($post['selffetch_shop_id']) && !empty($post['selffetch_shop_id'])) { // $selffetch_shop = SelffetchShop::find($post['selffetch_shop_id'])->toArray(); // if (strtotime($selffetch_shop['business_start_time']) > time() || strtotime($selffetch_shop['business_end_time']) < time()) { // throw new Exception('不在门店营业时间,无法下单'); // } // } if ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF && empty($post['consignee'])) { throw new Exception('取货人不能为空'); } if ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF && empty($post['mobile'])) { throw new Exception('联系电话不能为空'); } if ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF && !Validate::mobile($post['mobile'])) { throw new Exception('联系电话格式不正确'); } //用户当前积分 - 用户使用的积分 if ($data['user_use_integral'] > 0){ if ($user['user_integral'] < $data['user_use_integral']){ throw new Exception('积分不足'); } } // 砍价订单验证 if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) { $bargainLaunchModel = new BargainLaunch(); $launch = $bargainLaunchModel->where(['id'=>(int)$post['bargain_launch_id']])->find(); if (!$launch) { throw new Exception('砍价异常'); } if ($launch['status'] == 2) { throw new Exception('砍价失败,禁止下单'); } if ($launch['payment_limit_time'] < time() and $launch['payment_limit_time'] > 0) { throw new Exception('下单失败,超出限制时间'); } if ($launch['order_id'] > 0) { throw new Exception('您已下单了, 请勿重复操作'); } } //验证订单商品是否支持对应的配送方式 $is_express = ConfigServer::get('delivery_type', 'is_express', 1); $is_selffetch = ConfigServer::get('delivery_type', 'is_selffetch', 0); $item_ids = implode(',',array_column($post['goods'],'item_id')); $goods_ids = implode(',',GoodsItem::where('id','in', $item_ids)->column('goods_id')); $goods = Goods::where('id','in', $goods_ids)->select(); $goods_name = []; //门店自提 if ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) { if ($is_selffetch == 0) { throw new Exception('暂未开启门店自提配送方式'); } foreach ($goods as $val) { if ($val['is_selffetch'] == 0) { $goods_name[] = $val['name']; } } if (!empty($goods_name)) { // throw new Exception('商品:'.implode('、',$goods_name).'不支持门店自提!'); throw new Exception('订单存在不支持门店自提的商品!'); } }elseif ($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_EXPRESS) { //快递配送 if ($is_express == 0) { throw new Exception('暂未开启快递配送方式'); } foreach ($goods as $val) { if ($val['is_express'] == 0) { $goods_name[] = $val['name']; } } if (!empty($goods_name)) { // throw new Exception('商品:'.implode('、',$goods_name).'不支持快递配送!'); throw new Exception('订单存在不支持快递配送的商品!'); } } $extra = [ 'delivery_type'=>$post['delivery_type'], 'selffetch_shop_id'=>($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? $post['selffetch_shop_id'] : '', 'consignee'=>($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? $post['consignee'] : '', 'mobile'=>($post['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? $post['mobile'] : '' ]; $order = self::addOrder($user_id, $data, $order_source, $user_address, $extra); $order_id = $order['order_id']; self::addOrderGoods($order_id, $goods_lists); self::addOrderAfter($order_id, $user_id, $type, $data); // 砍价订单处理 if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) { $bargainLaunchModel = new BargainLaunch(); $bargainLaunchModel->where(['id'=>(int)$post['bargain_launch_id']]) ->update(['order_id'=>$order_id, 'status'=>1]); } Db::commit(); return self::dataSuccess('', ['order_id' => $order_id, 'type' => 'order']); } catch (Exception $e) { Db::rollback(); return self::dataError($e->getMessage()); } } /** * Notes: 添加订单记录 * @param $user_id * @param $data * @param $order_source * @param $user_address * @param array $extra * @author 段誉(2021/1/30 15:02) * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function addOrder($user_id, $data, $order_source, $user_address, $extra = []) { $growth_ratio = ConfigServer::get('trading', 'growth_ratio', 0); $give_growth_num = $growth_ratio > 0 ? ($data['order_amount'] / $growth_ratio) : 0; $attach_values = array( 'give_integral_scene' => ConfigServer::get('trading', 'give_integral_scene', 1), //赠送积分时机 'give_growth_scene' => ConfigServer::get('trading', 'give_growth_scene', 1), //赠送成长值时机 'give_growth_num' => intval(round($give_growth_num)), 'give_integral_num' => $data['give_integral_num'] ?? 0, ); //订单主表记录 if ($extra['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) { $order_data = [ 'order_type' => $data['order_type'], 'order_sn' => createSn('order', 'order_sn', '', 4), 'user_id' => $user_id, 'order_source' => $order_source, 'consignee' => $extra['consignee'], 'mobile' => $extra['mobile'], 'goods_price' => $data['total_goods_price'], 'order_amount' => $data['order_amount'],//应付金额 'total_amount' => $data['total_amount'],//订单总金额 'shipping_price' => $data['shipping_price'],//店铺订单运费 'total_num' => $data['total_num'],//店铺订单商品数量 'user_remark' => $data['remark'], 'create_time' => time(), 'discount_amount' => $data['discount_amount'] ?? 0,//优惠券优惠金额 'pay_way' => $data['pay_way'], 'integral_amount' => $data['integral_amount'] ?? 0, 'use_integral' => $data['user_use_integral'], 'team_id' => $extra['team_id'] ?? 0, 'team_found_id' => $extra['found_id'] ?? 0, 'attach_values' => json_encode($attach_values, JSON_UNESCAPED_UNICODE), 'delivery_type' => $extra['delivery_type'], 'selffetch_shop_id'=> $extra['selffetch_shop_id'], 'pickup_code' => create_verifier_sn('order','pickup_code','6', '') ]; }else { $order_data = [ 'order_type' => $data['order_type'], 'order_sn' => createSn('order', 'order_sn', '', 4), 'user_id' => $user_id, 'order_source' => $order_source, 'consignee' => $user_address['contact'], 'province' => $user_address['province_id'], 'city' => $user_address['city_id'], 'district' => $user_address['district_id'], 'address' => $user_address['address'], 'mobile' => $user_address['telephone'], 'goods_price' => $data['total_goods_price'], 'order_amount' => $data['order_amount'],//应付金额 'total_amount' => $data['total_amount'],//订单总金额 'shipping_price' => $data['shipping_price'],//店铺订单运费 'total_num' => $data['total_num'],//店铺订单商品数量 'user_remark' => $data['remark'], 'create_time' => time(), 'discount_amount' => $data['discount_amount'] ?? 0,//优惠券优惠金额 'pay_way' => $data['pay_way'], 'integral_amount' => $data['integral_amount'] ?? 0, 'use_integral' => $data['user_use_integral'], 'team_id' => $extra['team_id'] ?? 0, 'team_found_id' => $extra['found_id'] ?? 0, 'attach_values' => json_encode($attach_values, JSON_UNESCAPED_UNICODE), 'delivery_type' => $extra['delivery_type'] ]; } //有使用优惠券并且有优惠金额,把优惠券id保存到订单表中 if ($data['coupon_id'] > 0 && $data['discount_amount'] > 0){ $order_data['coupon_list_id'] = $data['coupon_id'];//此处coupon_id为前端传入的coupon_list_id } $order_id = Db::name('order')->insertGetId($order_data); return [ 'order_id' => $order_id, 'order_sn' => $order_data['order_sn'], 'order_amount' => $order_data['order_amount'], ]; } /** * Notes: 添加订单商品记录 * @param $order_id * @param $goods_lists * @author 段誉(2021/1/30 15:02) * @throws Exception */ public static function addOrderGoods($order_id, $goods_lists) { foreach ($goods_lists as $k1 => $good) { //商品验证 if ($good['del'] == 1 || $good['status'] != 1) { throw new Exception( '包含不存在或已下架的商品,无法下单'); } if ($good['goods_num'] > $good['stock']) { throw new Exception('商品库存不足,无法下单'); } $total_pay_price = ($good['goods_price'] * $good['goods_num']) - ($good['discount_price'] ?? 0) - ($good['integral_price'] ?? 0); $total_pay_price = $total_pay_price <= 0 ? 0 : $total_pay_price; $goods_data[] = [ 'order_id' => $order_id, 'goods_id' => $good['goods_id'], 'item_id' => $good['item_id'], 'goods_name' => $good['goods_name'], 'goods_num' => $good['goods_num'], 'goods_price' => $good['goods_price'],//商品价格单价(未扣减优惠和积分价格) 'total_price' => $good['goods_price'] * $good['goods_num'], 'total_pay_price' => $total_pay_price,//实际支付商品金额(扣除优惠金额) 'spec_value_ids' => $good['spec_value_ids'], 'discount_price' => $good['discount_price'] ?? 0,//优惠券优惠金额 'integral_price' => $good['integral_price'] ?? 0,//积分抵扣金额 'member_price' => $good['member_price'] ?? 0,//会员折扣价格 'original_price' => $good['original_price'] ?? 0,//商品原始价格 'is_seckill' => $good['is_seckill'] ?? 0, 'is_member' => $good['is_member'] ?? 0,//是否使用会员折扣;0-否;1-是 'goods_info' => json_encode($good, JSON_UNESCAPED_UNICODE), 'create_time' => time(), ]; } Db::name('order_goods')->insertAll($goods_data); } /** * Notes: 下单后操作 * @param $order_id * @param $user_id * @param $type * @param $data * @author 段誉(2021/1/30 15:03) * @throws Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @throws \think\exception\PDOException */ public static function addOrderAfter($order_id, $user_id, $type, $data) { $goods_data = $data['goods_lists']; //下单时扣减商品库存 $deduct_type = ConfigServer::get('trading','deduct_type', 1); if ($deduct_type == 1) { OrderGoodsLogic::decStock($goods_data); } //删除购物车商品 if ($type == 'cart') { $cart_items = array_column($goods_data, 'item_id'); Db::name('cart')->where([ ['user_id', '=', $user_id], ['selected', '=', 1], ['item_id', 'in', $cart_items], ])->delete(); } //是否有使用积分抵扣金额 if ($data['user_use_integral'] > 0){ IntegralLogic::handleIntegral($user_id, $data['user_use_integral'], AccountLog::order_deduction_integral, $order_id); } //有使用优惠券时更新coupon_list if ($data['coupon_id'] > 0){ \app\common\logic\CouponLogic::handleCouponByOrder($data['coupon_id'], $order_id); } //增加订单日志 OrderLogLogic::record( OrderLog::TYPE_USER, OrderLog::USER_ADD_ORDER, $order_id, $user_id, OrderLog::USER_ADD_ORDER ); } /** * Notes: 订单列表 * @param $user_id * @param $type * @param $page * @param $size * @author 段誉(2021/1/30 15:03) * @return array */ public static function getOrderList($user_id, $type, $page, $size) { $order = new Order(); $where[] = ['del', '=', 0]; $where[] = ['user_id', '=', $user_id]; switch ($type) { case 'pay': $where[] = ['order_status', '=', CommonOrder::STATUS_WAIT_PAY]; break; case 'delivery': $where[] = ['order_status', 'in', [CommonOrder::STATUS_WAIT_DELIVERY, CommonOrder::STATUS_WAIT_RECEIVE]]; break; case 'finish': $where[] = ['order_status', '=', CommonOrder::STATUS_FINISH]; break; case 'close': $where[] = ['order_status', '=', CommonOrder::STATUS_CLOSE]; break; } $count = $order->where(['del' => 0, 'user_id' => $user_id]) ->where($where) ->count(); $lists = $order->where(['del' => 0, 'user_id' => $user_id]) ->where($where) ->with(['orderGoods']) ->field('id,order_sn,order_status,pay_status,order_amount,order_status,order_type,shipping_status,create_time,delivery_type,team_found_id,pay_time,pay_way') ->page($page, $size) ->order('id desc') ->select(); $lists->append(['goods_count', 'pay_btn', 'cancel_btn', 'delivery_btn', 'take_btn', 'del_btn', 'comment_btn', 'order_cancel_time']); foreach ($lists as $list){ foreach ($list['order_goods'] as &$order_goods){ $order_good_info = json_decode($order_goods['goods_info'], true); $order_goods['goods_name'] = $order_good_info['goods_name']; $order_goods['spec_value'] = $order_good_info['spec_value_str']; $image = empty($order_good_info['spec_image']) ? $order_good_info['image'] : $order_good_info['spec_image']; $order_goods['image'] = $image; } //查看提货码按钮 $list['pickup_btn'] = ($list['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY && $list['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? 1 : 0; //订单状态描述 $list['order_status_desc'] = ($list['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY && $list['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? '待取货' : CommonOrder::getOrderStatus($list['order_status']); if ($list['order_type'] == CommonOrder::TEAM_ORDER){ $found = Db::name('team_found')->where(['id' => $list['team_found_id']])->find(); if ($found['status'] == Team::STATUS_SUCCESS){ $list['pickup_btn'] = ($list['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY && $list['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? 1 : 0; $list['order_status_desc'] = ($list['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY && $list['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? '待取货' : CommonOrder::getOrderStatus($list['order_status']); }else { $list['pickup_btn'] = 0; $list['order_status_desc'] = ($list['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY) ? Team::getStatusDesc($found['status']) : CommonOrder::getOrderStatus($list['order_status']); } } //订单类型 $list['order_type_desc'] = ($list['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? '自提订单' : CommonOrder::getOrderType($list['order_type']); } $data = [ 'list' => $lists, 'page' => $page, 'size' => $size, 'count' => $count, 'more' => is_more($count, $page, $size) ]; return $data; } /** * Notes: 订单详情 * @param $order_id * @param $user_id * @author 段誉(2021/5/25 14:13) * @return Order|array */ public static function getOrderDetail($order_id, $user_id) { $order = Order::get(['del' => 0, 'id' => $order_id, 'user_id' => $user_id], ['orderGoods']); if (!$order){ return []; } $order_append = [ 'delivery_address', 'pay_btn', 'cancel_btn', 'delivery_btn', 'take_btn', 'del_btn', 'order_cancel_time', 'pay_way_text' ]; $order_hidden = [ 'user_id', 'order_source', 'city', 'district', 'address', 'shipping_status', 'shipping_code', 'transaction_id', 'del', 'province' ]; $order->append($order_append)->hidden($order_hidden); $refund_days = ConfigServer::get('after_sale', 'refund_days', 0) * 86400; $now = time(); //显示是否评论按钮 foreach ($order->order_goods as &$item) { $item['comment_btn'] = 0; if ($order['pay_status'] == Pay::ISPAID && $order['order_status'] == CommonOrder::STATUS_FINISH && $item['is_comment'] == 0) { $item['comment_btn'] = 1; } $item['refund_btn'] = 0; $confirm_take_time = strtotime($order['confirm_take_time']) ?: 0; $refund_time = $confirm_take_time + $refund_days; if ($order['order_status'] == CommonOrder::STATUS_FINISH && $refund_time > $now && $item['refund_status'] == \app\common\model\OrderGoods::REFUND_STATUS_NO) { $item['refund_btn'] = 1; } //过了取消订单的时间,可对所有商品进行售后操作 if ($order['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY && $item['refund_status'] == \app\common\model\OrderGoods::REFUND_STATUS_NO) { //多长时间内允许客户取消 $cancel_limit = ConfigServer::get('trading', 'customer_cancel_limit', 0); $limit_time = strtotime($order['pay_time']) + $cancel_limit * 60; if ($limit_time < time()) { $item['refund_btn'] = 1; } } if ($order['order_status'] == CommonOrder::STATUS_WAIT_RECEIVE && $item['refund_status'] == \app\common\model\OrderGoods::REFUND_STATUS_NO) { $item['refund_btn'] = 1; } //售后状态 $item['after_status_desc'] = ''; if (in_array($item['refund_status'],[\app\common\model\OrderGoods::REFUND_STATUS_APPLY,\app\common\model\OrderGoods::REFUND_STATUS_WAIT])) { $item['after_status_desc'] = '售后中'; } if ($item['refund_status'] == \app\common\model\OrderGoods::REFUND_STATUS_SUCCESS) { $item['after_status_desc'] = '售后成功'; } $goods_info = json_decode($item['goods_info'], true); $item['goods_name'] = $goods_info['goods_name']; $item['spec_value'] = $goods_info['spec_value_str']; $item['image'] = empty($goods_info['spec_image']) ? $goods_info['image'] : $goods_info['spec_image']; } $order['team'] = []; if ($order['order_type'] == CommonOrder::TEAM_ORDER){ $team = TeamFound::get($order['team_found_id']); $order['team'] = [ 'need' => $team['need'], 'status' => $team['status'], ]; } //订单类型 $order['order_type_desc'] = ($order['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? '自提订单' : CommonOrder::getOrderType($order['order_type']); //订单状态 $order['order_status_desc'] = ($order['order_status'] == CommonOrder::STATUS_WAIT_DELIVERY && $order['delivery_type'] == CommonOrder::DELIVERY_STATUS_SELF) ? '待取货' : CommonOrder::getOrderStatus($order['order_status']); //自提门店 $order['selffetch_shop'] = SelffetchShop::where('id',$order['selffetch_shop_id']) ->field('id,name,province,city,district,address,business_start_time,business_end_time') ->append(['shop_address']) ->hidden(['province','city','district','address']) ->find(); //拼团状态 $order['team_status'] = Db::name('team_found')->where(['id' => $order['team_found_id']])->value('status'); return $order; } static function wxReceiveDetail($id, $user_id) { $order = Order::where('id', $id)->where('user_id', $user_id)->findOrEmpty()->toArray(); return [ 'transaction_id' => $order['transaction_id'] ?? '', ]; } /** * Notes: 取消订单 * @param $order_id * @param $user_id * @author 段誉(2021/1/30 15:04) * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function cancel($order_id, $user_id) { $order = Order::get([ 'del' => 0, 'user_id' => $user_id, 'id' => $order_id ], ['orderGoods']); if (!$order || $order['order_status'] > CommonOrder::STATUS_WAIT_DELIVERY) { return self::dataError('很抱歉!订单无法取消'); } if ($order['pay_status'] == Pay::ISPAID) { $cancel_limit = ConfigServer::get('trading', 'customer_cancel_limit', 0); $limit_time = $order->getData('pay_time') + $cancel_limit * 60; if ($limit_time < time()) { return self::dataError('很抱歉!订单已无法取消'); } } if ($order['order_type'] == CommonOrder::TEAM_ORDER && $order['pay_status'] == Pay::ISPAID){ $found = Db::name('team_found')->where(['id' => $order['team_found_id']])->find(); if ($found['status'] == 0){ return self::dataError('已支付的拼团订单需要等待拼团得出结果后才能取消喔~'); } } $after_sale = Db::name('after_sale')->where(['order_id'=>$order_id])->find(); if (!empty($after_sale)) { return self::dataError('存在售后订单,无法取消'); } Db::startTrans(); try { //取消订单 OrderRefundLogic::cancelOrder($order_id, OrderLog::TYPE_USER); //已支付的订单,取消,退款 if ($order['pay_status'] == Pay::ISPAID) { //更新订单状态 OrderRefundLogic::cancelOrderRefundUpdate($order); //订单退款 OrderRefundLogic::refund($order, $order['order_amount'], $order['order_amount']); } Db::commit(); return self::dataSuccess('取消成功'); } catch (Exception $e) { Db::rollback(); //增加退款失败记录 OrderRefundLogic::addErrorRefund($order, $e->getMessage()); return self::dataError($e->getMessage()); } } /** * Notes: 删除订单 * @param $order_id * @param $user_id * @author 段誉(2021/1/30 15:04) * @return array */ public static function del($order_id, $user_id) { $order = Order::get([ 'order_status' => CommonOrder::STATUS_CLOSE, 'user_id' => $user_id, 'id' => $order_id, 'del' => 0, ]); if (!$order) { return self::dataError('订单无法删除'); } $order->save(['del' => 1, 'update_time' => time()]); OrderLogLogic::record( OrderLog::TYPE_USER, OrderLog::USER_DEL_ORDER, $order_id, $user_id, OrderLog::USER_DEL_ORDER ); return self::dataSuccess('删除成功'); } /** * Notes: 确认收货 * @param $order_id * @param $user_id * @author 段誉(2021/1/30 15:04) * @return array */ public static function confirm($order_id, $user_id) { $order = Order::get(['del' => 0, 'id' => $order_id]); if ($order['order_status'] == CommonOrder::STATUS_FINISH) { return self::dataError('订单已完成'); } if ($order['shipping_status'] == 0) { return self::dataError('订单未发货'); } $order->order_status = CommonOrder::STATUS_FINISH; $order->update_time = time(); $order->confirm_take_time = time(); $order->save(); // 赠送成长值和积分 Hook::listen('give_reward', [ 'order_id' => $order_id, 'scene' => 3, //3=订单完成 ]); //订单日志 OrderLogLogic::record( OrderLog::TYPE_USER, OrderLog::USER_CONFIRM_ORDER, $order_id, $user_id, OrderLog::USER_CONFIRM_ORDER ); return self::dataSuccess('确认成功'); } public static function orderTraces($id, $user_id) { $order = new Order(); $order = $order->alias('o') ->join('order_goods og', 'o.id = og.order_id') ->join('goods g','g.id = og.goods_id') ->where(['o.id' => $id, 'user_id' => $user_id, 'pay_status' => Pay::ISPAID, 'o.del' => 0]) ->field('o.id,order_status,total_num,image,consignee,mobile,province,city,district,address,pay_time,confirm_take_time,o.shipping_status,shipping_time,o.delivery_id') ->append(['delivery_address']) ->find(); if(!self::checkDelivery($order['delivery_id'])){ return false; } //初始化数据 $order_tips = '已下单'; $order_traces = []; $traces = [];//物流轨迹 $shipment = [//发货 'title' => '已发货', 'tips' => '', 'time' => '', ]; $finish = [//交易完成 'title' => '交易完成', 'tips' => '', 'time' => '', ]; if ($order) { $order_delivery = Db::name('delivery')->where(['order_id' => $id])->find(); $express = ConfigServer::get('express', 'way', '', ''); //已发货 if ($express && $order['shipping_status']) { $app = ConfigServer::get($express, 'appkey', '', ''); $key = ConfigServer::get($express, 'appsecret', '', ''); //获取物流配置 if ($app && $key) { //快递配置设置为快递鸟时 if($express === 'kdniao'){ $expressage = (new Kdniao($key, $app, Env::get('app.app_debug', 'true'))); $shipping_field = 'codebird'; }else{ $expressage = (new Kd100($key, $app, Env::get('app.app_debug', 'true'))); $shipping_field = 'code100'; } //快递编码 $shipping_code = Db::name('express')->where(['id' => $order_delivery['shipping_id']])->value($shipping_field); //获取物流轨迹 if (in_array(strtolower($shipping_code ), [ 'sf', 'shunfeng' ])) { if ($express === 'kdniao') { $expressage->logistics($shipping_code, $order_delivery['invoice_no'], substr($order_delivery['mobile'],-4)); } else { $expressage->logistics($shipping_code, $order_delivery['invoice_no'], $order_delivery['mobile']); } }else { $expressage->logistics($shipping_code, $order_delivery['invoice_no']); } $traces = $expressage->logisticsFormat(); //获取不到物流轨迹时 if ($traces == false) { $traces[] = ['暂无物流信息']; } else { foreach ($traces as &$item) { $item = array_values(array_unique($item)); } } } } //待收货 if ($order['order_status'] == 2) { $shipment['tips'] = '商品已出库'; $shipment['time'] = $order['shipping_time']; } //确认收货 if ($order['order_status'] == 3) { $order_tips = '交易完成'; $finish['tips'] = '订单交易完成'; $finish['time'] = $order['confirm_take_time']; } //数据合并 $order_traces = [ 'order' => [ 'tips' => $order_tips, 'image' => UrlServer::getFileUrl($order['image']), 'count' => $order['total_num'], 'invoice_no' => $order_delivery['invoice_no'], 'shipping_name' => $order_delivery['shipping_name'], ], 'take' => [ 'contacts' => $order['consignee'], 'mobile' => $order['mobile'], 'address' => $order['delivery_address'], ], 'finish' => $finish, 'delivery' => [ 'title' => '运输中', 'traces' => $traces ], 'shipment' => $shipment, 'buy' => [ 'title' => '已下单', 'tips' => '订单提交成功', 'time' => $order['pay_time'] ], ]; return $order_traces; } return $order_traces; } /** * Notes: 配送方式无需快递的 * @param $delivery_id * @author 段誉(2021/1/30 15:05) * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public static function checkDelivery($delivery_id) { $delivery = Db::name('delivery') ->where(['id' => $delivery_id]) ->find(); if ($delivery['send_type'] == 2){ return false; } return true; } /** * @notes 核销订单列表 * @param $type * @param $user_id * @param $page * @param $size * @return array * @author ljj * @date 2021/8/18 3:58 下午 */ public static function verificationLists($type, $user_id, $page, $size) { $order = new Order(); $where[] = ['o.verification_status', '=', $type]; $where[] = ['o.del', '=', 0]; $where[] = ['o.delivery_type', '=', CommonOrder::DELIVERY_STATUS_SELF]; $where[] = ['sv.user_id', '=', $user_id]; $where[] = ['o.order_status', '=', CommonOrder::STATUS_WAIT_DELIVERY]; $where[] = ['sv.status', '=', 1]; $where[] = ['sv.del', '=', 0]; if ($type == CommonOrder::NOT_WRITTEN_OFF) { $count = $order->alias('o') ->join('selffetch_shop ss', 'ss.id = o.selffetch_shop_id') ->join('selffetch_verifier sv', 'sv.selffetch_shop_id = o.selffetch_shop_id') ->where($where) ->count(); $lists = $order->alias('o') ->join('selffetch_shop ss', 'ss.id = o.selffetch_shop_id') ->join('selffetch_verifier sv', 'sv.selffetch_shop_id = o.selffetch_shop_id') ->where($where) ->with(['orderGoods']) ->field('o.id,o.consignee,o.verification_status,o.create_time') ->page($page, $size) ->order('o.id desc') ->select(); }else { $count = Verification::where(['handle_id'=>$user_id,'verification_scene'=>Verification::TYPE_USER])->count(); $lists = $order->where('id','in', implode(',',Verification::where(['handle_id'=>$user_id,'verification_scene'=>Verification::TYPE_USER])->column('order_id'))) ->with(['orderGoods']) ->field('id,consignee,verification_status,create_time') ->page($page, $size) ->order('id desc') ->select(); } if ($count == 0) { return [ 'list' => [], 'page' => $page, 'size' => $size, 'count' => $count, 'more' => is_more($count, $page, $size) ]; } foreach ($lists as $list){ foreach ($list['order_goods'] as &$order_goods){ $order_good_info = json_decode($order_goods['goods_info'], true); $order_goods['goods_name'] = $order_good_info['goods_name']; $order_goods['spec_value'] = $order_good_info['spec_value_str']; $order_goods['image'] = empty($order_good_info['spec_image']) ? UrlServer::getFileUrl($order_good_info['image']) : UrlServer::getFileUrl($order_good_info['spec_image']); } $list['verification_status_desc'] = CommonOrder::getVerificationStatus($list['verification_status']); } return [ 'list' => $lists, 'page' => $page, 'size' => $size, 'count' => $count, 'more' => is_more($count, $page, $size) ]; } /** * @notes 提货核销 * @param $post * @return bool|string * @author ljj * @date 2021/8/18 4:36 下午 */ public static function verification($post) { $info = CommonOrder::where('pickup_code',$post['pickup_code']) ->with(['orderGoods']) ->field('id,consignee,verification_status,create_time') ->find(); $info['verification_status_desc'] = CommonOrder::getVerificationStatus($info['verification_status']); foreach ($info['order_goods'] as &$order_goods){ $order_good_info = json_decode($order_goods['goods_info'], true); $order_goods['goods_name'] = $order_good_info['goods_name']; $order_goods['spec_value'] = $order_good_info['spec_value_str']; $order_goods['image'] = empty($order_good_info['spec_image']) ? UrlServer::getFileUrl($order_good_info['image']) : UrlServer::getFileUrl($order_good_info['spec_image']); } return $info; } /** * @notes 确认提货 * @param $post * @return bool|string * @author ljj * @date 2021/8/18 7:01 下午 */ public static function verificationConfirm($post) { // 启动事务 Db::startTrans(); try { $order = Order::find($post['id']); if (empty($order)) { throw new Exception('订单不存在'); } if ($order['order_status'] != CommonOrder::STATUS_WAIT_DELIVERY) { throw new Exception('订单不允许提货'); } if ($order['delivery_type'] != CommonOrder::DELIVERY_STATUS_SELF) { throw new Exception('不是自提订单,不允许提货'); } if ($order['verification_status'] == CommonOrder::WRITTEN_OFF) { throw new Exception('订单已核销'); } $selffetch_verifier = SelffetchVerifier::where(['user_id'=>$post['user_id'],'selffetch_shop_id'=>$order['selffetch_shop_id'],'status'=>1,'del'=>0])->find(); if (empty($selffetch_verifier)) { return '非门店核销员,无法核销订单'; } foreach ($order->order_goods as $goods) { $where = [ [ 'order_goods_id', '=', $goods['id'] ], [ 'order_id', '=', $goods['order_id'] ], [ 'status', 'in', CommonAfterSale::CanNotVerificationStatusArr() ], [ 'del', '=', 0 ], ]; $after_sale = CommonAfterSale::where($where)->findOrEmpty(); if (! $after_sale->isEmpty()) { RETURN '有商品处于售后中,不能核销'; } } //添加核销记录 $snapshot = [ 'sn' => $selffetch_verifier['sn'], 'name' => $selffetch_verifier['name'] ]; $verification = new Verification; $verification->order_id = $order['id']; $verification->selffetch_shop_id = $order['selffetch_shop_id']; $verification->handle_id = $post['user_id']; $verification->verification_scene = Verification::TYPE_USER; $verification->snapshot = json_encode($snapshot); $verification->create_time = time(); $verification->save(); //更新订单状态 $order->order_status = CommonOrder::STATUS_FINISH; $order->verification_status = CommonOrder::WRITTEN_OFF; $order->update_time = time(); $order->confirm_take_time = time(); $order->save(); //订单日志 OrderLogLogic::record( OrderLog::TYPE_USER, OrderLog::USER_VERIFICATION, $order['id'], $post['user_id'], OrderLog::USER_VERIFICATION ); // 赠送成长值和积分 Hook::listen('give_reward', [ 'order_id' => $order['id'], 'scene' => 3, //3=订单完成 ]); // 提交事务 Db::commit(); return true; } catch (\Exception $e) { // 回滚事务 Db::rollback(); return $e->getMessage(); } } /** * @notes 获取配送方式 * @return array * @author ljj * @date 2021/8/19 7:17 下午 */ public static function getDeliveryType() { $is_express = ConfigServer::get('delivery_type', 'is_express', 1); $is_selffetch = ConfigServer::get('delivery_type', 'is_selffetch', 0); return [ 'is_express' => $is_express, 'is_selffetch' => $is_selffetch, ]; } }