toValidator([ 'cart_ids' => 'nullable|string', 'drug_ids' => 'required|string', ], [], [ 'cart_ids' => '购物车商品', 'drug_ids' => '商品', ]); $cart_ids = string_to_array($request->input('cart_ids')); $drug_ids = string_to_array($request->input('drug_ids')); $numbers = string_to_array($request->input('numbers')); $drugs = Drug::with([ 'drugstoreDrug' => function (Relation $relation) { $relation->select(['drug_id', 'price']) ->where('drugstore_id', $this->getDrugstoreId()); }, ]) ->select(['id', 'drug_name', 'usage', 'specification', 'image']) ->whereHasIn('drugStoreRelation', function (Builder $builder) { $builder->where('store_id', $this->getStoreId()); }) ->whereIn('id', $drug_ids) ->get() ->keyBy('id'); $carts = []; if (count($cart_ids)) { $carts = Cart::with([ 'drug' => function (Relation $relation) { $relation->select(['id']); } ]) ->whereHasIn('drug') ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->whereIn('id', $cart_ids) ->get() ->keyBy('drug.id'); } $data = []; $fee = 0; $new_drug_ids = $new_cart_ids = []; foreach ($drug_ids as $k => $drug_id) { if (!isset($drugs[$drug_id])) { json_error('商品信息已更新,请重新下单'); } $drug = $drugs[$drug_id]; if (!$drug['drugstoreDrug']) { json_error('商品信息已更新,请重新下单'); } $new_drug_ids[] = $drug_id; $drug['qty'] = $numbers[$k] ?? 1; if (isset($carts[$drug_id])) { $new_cart_ids[] = $carts[$drug_id]['id']; $drug['qty'] = $carts[$drug_id]['qty']; } $fee += $drug['drugstoreDrug']['price'] * $drug['qty']; $data[] = $drug; } $store = $this->getStore(); $expressFeeInfo = ExpressFee::getDefaultExpressFee(); if (!$expressFeeInfo) { json_error('运费信息错误'); } $isFree = $fee >= $expressFeeInfo->free_express_fee; $express_fee = $isFree ? 0 : $expressFeeInfo->base_express_fee; $fee_total = $isFree ? $fee : ($expressFeeInfo->base_express_fee + $fee); json_success([ 'store_name' => $store->name, 'fee' => $fee, 'is_free' => $isFree, 'express_fee' => $express_fee, 'fee_total' => $fee_total, 'data' => $data, 'drug_ids' => $new_drug_ids, 'cart_ids' => $new_cart_ids, ]); } /** * 提交订单 * * @param Request $request * @return void * @throws \Throwable */ public function submit(Request $request) { $this->toValidator([ 'address_id' => 'required|integer', 'cart_ids' => 'nullable|string', 'drug_ids' => 'required|string', 'numbers' => 'required|string', ], [ 'address_id' => '请选择地址', ], [ 'cart_ids' => '购物车商品', 'drug_ids' => '商品', 'numbers' => '商品数量', ]); $cart_ids = string_to_array($request->input('cart_ids')); $drug_ids = string_to_array($request->input('drug_ids')); $numbers = string_to_array($request->input('numbers')); $address_id = $request->input('address_id'); $remark = $request->input('remark'); if (count($drug_ids) != count($numbers)) { json_error('商品数量不正确'); } $address = Address::where('user_id', $this->userId()) ->where('id', $address_id) ->first(); if (!$address) { json_error('用户地址获取失败'); } $expressFeeInfo = ExpressFee::getDefaultExpressFee(); if (!$expressFeeInfo) { json_error('运费信息错误'); } $drugs = Drug::with([ 'drugStoreRelation' => function (Relation $relation) { $relation->where('store_id', $this->getStoreId()); }, 'drugstoreDrug' => function (Relation $relation) { $relation->where('drugstore_id', $this->getDrugstoreId()); }, ]) ->whereHasIn('drugStoreRelation', function (Builder $builder) { $builder->where('store_id', $this->getStoreId()); }) ->whereIn('id', $drug_ids) ->get(); /* @var Drug $drug */ foreach ($drugs as $k => $drug) { if (!$drug->drugstoreDrug) { if (!$drug['drugstoreDrug']) { json_error('商品信息已更新,请重新下单'); } if ($drug->drugstoreDrug->stock < $numbers[$k]) { json_error("{$drug->drug_name}库存不足"); } } } $order_no = Carbon::now()->format('YmdHis') . rand(10000, 99999) . rand(10000, 99999); DB::beginTransaction(); try { $productOrder = ProductOrder::create([ 'store_id' => $this->getStoreId(), 'drugstore_id' => $this->getDrugstoreId(), 'user_id' => $this->userId(), 'order_no' => $order_no, 'order_type' => ProductOrder::ORDER_TYPE_SHOP, 'type' => ProductOrder::TYPE_WECHAT, 'is_pay' => ProductOrder::IS_PAY_FALSE, 'status' => ProductOrder::STATUS_UNPAID, 'pay_method' => ProductOrder::PAY_METHOD_ONLINE, 'remark' => $remark, 'address_id' => $address->id, 'express_name' => $address->name, 'express_mobile' => $address->mobile, 'express_region' => $address->region, 'express_address' => $address->detail_address, ]); $productOrder->logs()->create([ 'content' => '下单成功' ]); $fee = 0; /* @var Drug $drug */ foreach ($drugs as $k => $drug) { $fee += $drug->drugstoreDrug->price * $numbers[$k]; $productOrder->items()->create([ 'drug_id' => $drug->id, 'drug_image' => $drug->image, 'number' => $numbers[$k], 'price' => $drug->drugstoreDrug->price, 'drug_name' => $drug->drug_name, 'small_info' => $drug->small_info, ]); $drug->drugstoreDrug->stock -= $numbers[$k]; $drug->drugstoreDrug->frozen_number += $numbers[$k]; $drug->drugstoreDrug->save(); } $isFree = $fee >= $expressFeeInfo->free_express_fee; $express_fee = $isFree ? 0 : $expressFeeInfo->base_express_fee; $fee_total = $isFree ? $fee : ($expressFeeInfo->base_express_fee + $fee); $productOrder->fill([ 'items_price' => $fee, 'total_pay_price' => $fee_total, 'trans_expenses' => $express_fee, 'free_ship' => $isFree ? ProductOrder::FREE_SHIP_TRUE : ProductOrder::FREE_SHIP_FALSE, ])->update(); if (count($cart_ids)) { Cart::where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->whereIn('id', $cart_ids) ->delete(); } // // 同步数据 // $productOrder->refresh(); // $productOrder->load(['items']); // Artisan::call('data:sync', [ // '--type' => 'product_order_sync', // '--data' => $productOrder->toArray(), // ]); ProductOrderCancelJob::dispatch($productOrder->id)->delay(now()->addMinutes(15)); DB::commit(); } catch (Exception $exception) { DB::rollBack(); log_s('下单错误:' . var_export($request->all(), true) . $exception->getMessage() . $exception->getTraceAsString(), 'order', 'error'); json_error('下单错误,请重试'); } json_success('下单成功,请支付', [ 'order_id' => $productOrder->id, ]); } /** * 订单列表 * * @return void */ public function lists(Request $request) { $this->toValidator([ 'type' => 'nullable|string', ], [], [ 'type' => '类型', ]); $type = $request->input('type'); $keyword = $request->input('keyword'); $lists = ProductOrder::with([ 'store:id,name', 'items', 'prescription:id,prescription_type', ]) ->select([ 'id', 'store_id', 'order_no', 'p_id', 'order_type', 'is_pay', 'total_pay_price', 'items_price', 'status', 'trans_expenses', 'cancel_status', ]) ->when($type, function (Builder $builder) use ($type) { if ($type == 'unpaid') { $builder->where('status', ProductOrder::STATUS_UNPAID); } elseif ($type == 'wait_send') { $builder->where('status', ProductOrder::STATUS_WAIT_SEND); } elseif ($type == 'wait_accept') { $builder->where('status', ProductOrder::STATUS_WAIT_ACCEPT); } elseif ($type == 'finished') { $builder->whereIn('status', [ ProductOrder::STATUS_WAIT_COMMENT, ProductOrder::STATUS_REFUND, ProductOrder::STATUS_REFUNDING, ProductOrder::STATUS_ACCEPTED, ProductOrder::STATUS_CONFIRM, ProductOrder::STATUS_CANCEL, ]); } }) ->when($keyword, function (Builder $builder) use ($keyword) { $builder->whereHasIn('items', fn(Builder $builder) => $builder->where('drug_name', 'like', "%$keyword%")); }) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->latest() ->paginate(request('per_page')); $lists->getCollection()->each(function (ProductOrder $productOrder) { $productOrder->append(['status_string', 'cancel_status_string']); if ($productOrder->prescription) { $productOrder->prescription->append(['prescription_type_string']); } }); json_page($lists); } /** * 订单详情 * * @param Request $request * @return void. */ public function detail(Request $request) { $this->toValidator([ 'order_id' => 'required|integer', ], [], [ 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); /* @var ProductOrder $productOrder */ $productOrder = ProductOrder::with([ 'items', 'prescription:id,content,prescription_type', ]) ->where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if ($productOrder->express_no_id && $productOrder->status == ProductOrder::STATUS_WAIT_ACCEPT) { Artisan::call('express', [ 'type' => 'update', '--id' => $productOrder->express_no_id, ]); $productOrder->load(['expressNo.detail']); } if ( $productOrder->prescription && in_array($productOrder->prescription->prescription_type, [Prescription::CHINESE_MEDICINES_DECOCTION_PIECE, Prescription::DISPENSING_GRANULES] )) { json_success(new ProductOrderDetailResource($productOrder)); } else { json_success(new ProductOrderDetailResource($productOrder)); } } /** * 物流详情 * * @param Request $request * @return void. */ public function expressDetail(Request $request) { $this->toValidator([ 'order_id' => 'required|integer', ], [], [ 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); $productOrder = ProductOrder::where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if (!$productOrder->express_no_id) { json_error('无物流信息'); } Artisan::call('express', [ 'type' => 'update', '--id' => $productOrder->express_no_id, ]); $productOrder->load(['expressNo.details']); if (!$productOrder->expressNo) { json_error('无物流信息'); } json_success([ 'address' => $productOrder->only([ 'express_name', 'express_mobile', 'express_region', 'express_address', 'express_no_id', ]), 'express' => $productOrder->expressNo, ]); } /** * 获取支付 * * @return void */ public function getPay(Request $request) { $this->toValidator([ 'order_id' => 'required|integer', ], [], [ 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); $productOrder = ProductOrder::where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if (!$productOrder->express_name) { json_error('请选择收货地址'); } if ($productOrder->is_pay == ProductOrder::IS_PAY_TRUE) { json_error('订单已支付'); } if ($productOrder->status != ProductOrder::STATUS_UNPAID) { json_error('支付失败,订单状态为' . $productOrder->status_string); } /* @var Bill $bill */ $bill = $productOrder->bills()->create([ 'user_id' => 1, 'openid' => $this->user()->openid, 'title' => $this->getStore()->name . "订单支付", 'pay_way' => Bill::PAY_WAY_WECHAT, 'pay_amount' => $productOrder->total_pay_price, ]); // 开发测试用 if (app()->isLocal() && file_exists(base_path('./../dev.ini'))) { $order = [ 'out_trade_no' => $bill->pay_no, 'description' => $bill->title, 'amount' => [ 'total' => $bill->pay_amount * 100, ], ]; $result = Pay::wechat()->scan($order); if (isset($result['code'])) { json_error($result['message'] ?? ''); } json_success($result->toArray()); } $order = [ 'out_trade_no' => $bill->pay_no, 'description' => $bill->title, 'amount' => [ 'total' => $bill->pay_amount * 100, ], 'payer' => [ 'openid' => $bill->openid, ] ]; $result = Pay::wechat()->mini($order); if (isset($result['code'])) { json_error($result['message'] ?? ''); } json_success($result->toArray()); } /** * 取消订单 * * @param Request $request * @return void * @throws \Throwable */ public function cancel(Request $request) { $this->toValidator([ 'order_id' => 'required|integer', ], [], [ 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); $productOrder = ProductOrder::where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if ($productOrder->is_pay == ProductOrder::IS_PAY_TRUE) { json_error('订单已支付'); } if ($productOrder->status != ProductOrder::STATUS_UNPAID) { json_error('取消失败,订单状态为' . $productOrder->status_string); } DB::beginTransaction(); try { $productOrder->status = ProductOrder::STATUS_CANCEL; $productOrder->cancel_status = ProductOrder::CANCEL_STATUS_FALSE; $productOrder->cancel_time = time(); $productOrder->cancel_remark = '用户主动取消'; $productOrder->save(); $productOrder->logs()->create([ 'content' => '未支付用户取消订单' ]); $this->createNotice($productOrder, '您的订单已取消'); $productOrder->loadMissing(['items.drugstoreDrug' => fn(Relation $relation) => $relation->where('drugstore_id', $productOrder->drugstore_id)]); foreach ($productOrder->items as $item) { if ($item->drugstoreDrug) { $item->drugstoreDrug->stock += $item->number; $item->drugstoreDrug->frozen_number -= $item->number; $item->drugstoreDrug->save(); } } // // 同步数据 // $productOrder->refresh(); // $productOrder->load(['items']); // Artisan::call('data:sync', [ // '--type' => 'product_order_sync', // '--data' => $productOrder->toArray(), // ]); if ($productOrder->is_online == ProductOrder::IS_ONLINE_TRUE && $productOrder->sync_order_no) { // 同步数据(老) Artisan::call('data:sync-old', [ '--type' => 'syncOrder', '--data' => json_encode([ 'order_no' => $productOrder->sync_order_no, 'status' => 2, // 1已支付 2已取消 3已退款 'time' => Carbon::createFromTimestamp($productOrder->cancel_time)->toDateTimeString(), ]), ]); } DB::commit(); } catch (Exception $exception) { DB::rollBack(); log_s('取消错误:' . var_export($request->all(), true) . $exception->getMessage() . $exception->getTraceAsString(), 'order', 'error'); json_error('取消错误,请重试'); } json_success('取消成功'); } /** * 确认收货 * * @param Request $request * @return void * @throws \Throwable */ public function confirm(Request $request) { $this->toValidator([ 'order_id' => 'required|integer', ], [], [ 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); /* @var ProductOrder $productOrder */ $productOrder = ProductOrder::where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if ($productOrder->status != ProductOrder::STATUS_WAIT_ACCEPT) { json_error('确认收货失败,订单状态为' . $productOrder->status_string); } DB::beginTransaction(); try { $productOrder->status = ProductOrder::STATUS_CONFIRM; $productOrder->save(); $productOrder->logs()->create([ 'content' => '用户确认收货' ]); $this->createNotice($productOrder, '您的订单已确认收货'); $productOrder->loadMissing(['items.drugstoreDrug' => fn(Relation $relation) => $relation->where('drugstore_id', $productOrder->drugstore_id)]); foreach ($productOrder->items as $item) { if ($item->drugstoreDrug) { $item->drugstoreDrug->frozen_number -= $item->number; $item->drugstoreDrug->save(); } } // // 同步数据 // $productOrder->refresh(); // $productOrder->load(['items']); // Artisan::call('data:sync', [ // '--type' => 'product_order_sync', // '--data' => $productOrder->toArray(), // ]); if ($productOrder->order_type === 5) { $client = new \GuzzleHttp\Client(); $response = $client->request('POST', 'https://api.xiaokang88.com/open-api/client-confirm', [ 'json' => [ 'order_id' => $order_id, ] ]); $body = json_decode($response->getBody()->getContents(), true); if ($body['code'] != 0) { exit($body['message']); } } DB::commit(); } catch (Exception $exception) { DB::rollBack(); log_s('确认收货错误:' . var_export($request->all(), true) . $exception->getMessage() . $exception->getTraceAsString(), 'order', 'error'); json_error('确认收货错误,请重试'); } json_success('确认收货成功'); } /** * 退款基础信息 * * @return void */ public function refundBase(Request $request) { $this->toValidator([ 'order_id' => 'required|integer', ], [], [ 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); $productOrder = ProductOrder::where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if (!in_array($productOrder->status, [ ProductOrder::STATUS_WAIT_SEND, ProductOrder::STATUS_WAIT_ACCEPT, ProductOrder::STATUS_WAIT_COMMENT, ProductOrder::STATUS_ACCEPTED, ProductOrder::STATUS_CONFIRM, ])) { json_error('申请失败,订单状态为' . $productOrder->status_string); } $reasons = pluck_to_array(ProductOrderRefund::REASON); $refundTypes = pluck_to_array(ProductOrderRefund::REFUND_TYPE); json_success([ 'total_pay_price' => $productOrder->total_pay_price, 'trans_expenses' => $productOrder->trans_expenses, 'reasons' => $reasons, 'refund_types' => $refundTypes, ]); } /** * 申请退款 * * @param Request $request * @return void * @throws \Throwable */ public function refundSubmit(Request $request) { $this->toValidator([ 'refund_type' => 'required|integer', 'reason_id' => 'required|integer', 'order_id' => 'required|integer', ], [], [ 'refund_type' => '退款类型', 'reason_id' => '退款原因', 'order_id' => '订单号', ]); $order_id = $request->input('order_id'); $refund_type = $request->input('refund_type'); $reason_id = $request->input('reason_id'); $image = $request->input('image'); /* @var ProductOrder $productOrder */ $productOrder = ProductOrder::where('id', $order_id) ->where('store_id', $this->getStoreId()) ->where('user_id', $this->userId()) ->first(); if (!$productOrder) { json_error('订单信息不存在'); } if (!in_array($productOrder->status, [ ProductOrder::STATUS_WAIT_SEND, ProductOrder::STATUS_WAIT_ACCEPT, ProductOrder::STATUS_WAIT_COMMENT, ProductOrder::STATUS_ACCEPTED, ProductOrder::STATUS_CONFIRM, ])) { json_error('申请失败,订单状态为' . $productOrder->status_string); } if ($productOrder->is_pay != ProductOrder::IS_PAY_TRUE) { json_error('申请失败,订单尚未支付'); } if ($productOrder->cancel_status == ProductOrder::CANCEL_STATUS_TRUE) { json_error('申请失败,订单已取消'); } if (!in_array($productOrder->refund_status, [ ProductOrder::REFUND_STATUS_NORMAL, ProductOrder::REFUND_STATUS_CANCEL, ])) { json_error('申请失败,订单退款状态为' . $productOrder->refund_status_string); } if (in_array($productOrder->status, [ ProductOrder::STATUS_WAIT_ACCEPT, ProductOrder::STATUS_WAIT_COMMENT, ProductOrder::STATUS_ACCEPTED, ProductOrder::STATUS_CONFIRM, ])) { if (now()->diffInDays($productOrder->created_at) > 30) { json_error('申请失败,已超过最大申请时效'); } } DB::beginTransaction(); $refundResult = []; try { $beforeStatus = $productOrder->status; $productOrder->status = ProductOrder::STATUS_REFUNDING; $productOrder->refund_status = $beforeStatus == ProductOrder::STATUS_WAIT_SEND ? ProductOrder::REFUND_STATUS_AGREE : ProductOrder::REFUND_STATUS_APPLYING; $productOrder->save(); $productOrder->logs()->create([ 'content' => '用户申请退款' ]); /* @var ProductOrderRefund $orderRefund */ $orderRefund = $productOrder->refunds()->create([ 'user_id' => $productOrder->user_id, 'order_id' => $productOrder->id, 'reason' => ProductOrderRefund::REASON[$reason_id], 'refund_images' => $image, 'refund_type' => ProductOrder::STATUS_WAIT_SEND ? ProductOrderRefund::REFUND_TYPE_REFUND_ONLY : ProductOrderRefund::REFUND_TYPE[$refund_type], 'refund_no' => ProductOrderRefund::getNewNumber('refund_no'), 'refund_price' => $productOrder->total_pay_price, 'is_refund' => ProductOrderRefund::IS_REFUND_FALSE, 'status' => $beforeStatus == ProductOrder::STATUS_WAIT_SEND ? ProductOrderRefund::STATUS_PASS : ProductOrderRefund::STATUS_APPLY, ]); if ($beforeStatus == ProductOrder::STATUS_WAIT_SEND) { $refundResult = $productOrder->toRefund($productOrder->total_pay_price, $orderRefund->refund_no); } DB::commit(); } catch (Exception $exception) { DB::rollBack(); log_s('申请错误:' . var_export($request->all(), true) . $exception->getMessage() . $exception->getTraceAsString(), 'order', 'error'); json_error('申请错误,请重试'); } if (count($refundResult)) { response()->json($refundResult)->throwResponse(); } json_success('申请成功'); } }