join("manager_project", 'project.id', '=', 'manager_project.project_id') ->join('managers', 'managers.id', '=', 'manager_project.manager_id') ->whereRaw("managers.id = " . $this->manager->id) ->select("project.id", "project.name", "project.address", "project.latitude", "project.longitude") ->get(); return response()->json($projects->toArray()); } /** * @OA\Get( * path="/manager/get-care-product/{project_id}", * tags={"管理端订单处理"}, * summary="V2-获取产品详情", * description="获取产品详情", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="project_id", in="path", @OA\Schema(type="integer"), required=true, description="project_id"), * @OA\Response( * response="200", * description="获取产品详情" * ) * ) */ public function getCareProduct($project_id) { DB::enableQueryLog(); $product = (new Product())->where("project_id", $project_id)->with([ "productItems" => function ($query) { $query->select("id", "name", "product_id", "patient_quantity", "price"); }, "productParamedicLevels" => function ($query) { $query ->select("product_paramedic_level.id", "product_paramedic_level.product_id", "product_paramedic_level.price") ->leftJoin("paramedic_level", "product_paramedic_level.paramedic_level_id", "=", "paramedic_level.id") ->addSelect("paramedic_level.name as paramedic_level_name"); }, "factors" => function ($query) { $query->with(["factorItems" => function ($query) { $query->select("id", "name", "factor_id", "price", "myindex")->orderBy("myindex"); }])->select("id", "name", "product_id")->orderBy("myindex"); }]) ->leftJoin("project", "project.id", "=", "product.project_id") ->select("product.id", "product.name", "product.project_id", "project.name as project_name")->first(); return response()->json($product->toArray()); } /** * @OA\Get( * path="/manager/get-project-orders-count/{project_id}", * tags={"管理端订单处理"}, * summary="V2-获取医院订单数量角标", * description="获取医院订单数量角标", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="project_id", in="query", @OA\Schema(type="integer"), required=true, description="医院id"), * @OA\Response( * response="200", * description="获取医院订单数量角标" * ) * ) */ public function getProjectOrdersCount($project_id) { $orders_count = []; $orders_count["all"] = (new Orders())->ofProject($project_id)->count(); $orders_count["pending"] = (new Orders())->ofProject($project_id)->whereIn("status", [Orders::STATUS_UNCONFIRMED, Orders::STATUS_UNASSIGNED])->count(); $orders_count["ongoing"] = (new Orders())->ofProject($project_id)->where("status", Orders::STATUS_ONGOING)->count(); $orders_count["finished"] = (new Orders())->ofProject($project_id)->where("status", Orders::STATUS_FINISHED)->count(); return response()->json(compact("orders_count")); } /** * @OA\Get( * path="/manager/get-projcet-orders/{project_id}", * tags={"管理端订单处理"}, * summary="V2-获取订单列表", * description="获取订单列表", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="project_id", in="path", @OA\Schema(type="integer"), required=false, description="医院ID"), * @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=false, description="查询关键词"), * @OA\Parameter(name="building_id", in="query", @OA\Schema(type="integer"), required=false, description="楼栋ID"), * @OA\Parameter(name="area_id", in="query", @OA\Schema(type="integer"), required=false, description="病区ID"), * @OA\Parameter(name="start_date_from", in="query", @OA\Schema(type="string"), required=false, description="开始服务日期区间查询的第一个值"), * @OA\Parameter(name="start_date_to", in="query", @OA\Schema(type="string"), required=false, description="开始服务日期区间查询的第二个值"), * @OA\Parameter(name="days", in="query", @OA\Schema(type="integer"), required=false, description="服务天数,以实际生成的to_date和from_date比对为准,改价为0的也算"), * @OA\Parameter(name="page", in="query", @OA\Schema(type="integer"), required=false, description="当前页码,默认为1"), * @OA\Parameter(name="page_size", in="query", @OA\Schema(type="integer"), required=false, description="每页数量,默认为5"), * @OA\Parameter(name="status", in="query", @OA\Schema(type="string"), required=false, description="订单状态:[pending=>待处理,ongoing=>进行中,finished=>已完成]"), * @OA\Response( * response="200", * description="获取订单列表" * ) * ) */ public function list($project_id) { $model = $this->_getOrderModel(); $model = $model->ofProject($project_id); if (request()->keyword) { $keyword = request()->keyword; $model = $model->where(function ($query) use ($keyword) { $query ->where("serial", "like", "%{$keyword}%") ->orWhereHas("patient", function ($query) use ($keyword) { $query->where("name", "like", "%{$keyword}%"); })->orWhereHas("customer", function ($query) use ($keyword) { $query->where("mobile", "like", "%{$keyword}%"); })->orWhereHas("paramedic", function ($query) use ($keyword) { $query->where("name", "like", "%{$keyword}%"); }); }); } if (request()->area_id) { $model = $model->whereHas("bed", function ($query) { $query->where("area_id", request()->area_id); }); } elseif (request()->building_id) { $model = $model->whereHas("bed", function ($query) { $query->where("building_id", request()->building_id); }); } if (request()->bed_id) { $model = $model->where('bed_id', request()->bed_id); } if (request()->days) { $model = $model->whereRaw(DB::raw("datediff(`to_date`,`from_date`) = " . (request()->days - 1))); } if (request()->start_date_from && request()->start_date_to) { $model = $model->whereRaw(DB::raw("UNIX_TIMESTAMP(`from_date`) between " . strtotime(request()->start_date_from) . " and " . strtotime(request()->start_date_to))); } switch (request()->status) { case "pending": $model = $model->whereIn("status", [Orders::STATUS_UNCONFIRMED, Orders::STATUS_UNASSIGNED]); break; case "ongoing": case "finished": $model = $model->where("status", constant(Orders::class . "::STATUS_" . strtoupper(request()->status))); break; default: //do nothing } $page_size = request()->page_size ?? 5; $data = $model->orderBy("id", "desc")->paginate($page_size); foreach ($data as $order) { $order = $order->refreshTotal(); $order->balance = $order->customer->balance; // 是否需要签订协议,0否1是 $order->need_agreements = $order->needAgreements(); } return response()->json($data->toArray()); } /** * @OA\Get( * path="/manager/get-affected-orders/{from_order_id}", * tags={"管理端订单处理"}, * summary="V2-获取被影响到的订单列表", * description="获取被影响到的订单列表", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="from_order_id", in="path", @OA\Schema(type="intger"), required=true, description="因为某张订单造成了影响"), * @OA\Parameter(name="from_paramedic_id", in="query", @OA\Schema(type="intger"), required=false, description="原护工的id"), * @OA\Response( * response="200", * description="获取被影响到的订单列表" * ) * ) */ public function getAffectedOrders($from_order_id, Request $request) { $order = Orders::find($from_order_id); $order = (new AttachAffectedOrders())($order, $request->from_paramedic_id); return response()->json($order->affected_orders->toArray()); } /** * @OA\post( * path="/manager/update-order-price", * tags={"管理端订单处理"}, * summary="V2-批量更新订单价格", * description="批量更新订单价格", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="available_day", in="query", @OA\Schema(type="string"), required=false, description="生效日期,仅当值为today表示同步更新当日子订单价格,为其他值表示次日起生效"), * @OA\Parameter(name="price", in="query", @OA\Schema(type="object"), required=true, description="价格提交,[{order_id:1,price:200},{...}]"), * @OA\Response( * response="200", * description="批量更新订单价格" * ) * ) */ public function updateOrderPrice(Request $request) { DB::beginTransaction(); try { $price = (array)json_decode($request->price, true); if (!$price) { return response()->json([ "errorcode" => "103", "errormsg" => "错误的价格参数" ]); } $updated = []; foreach ($price as $item) { $order = Orders::find($item["order_id"]); $order->update([ "price" => $item["price"] ]); $updated[] = $order; if ($request->available_day != "today") { continue; } //更新子订单 $res = (new OrderItems())->updateTodayItem($item["order_id"]); if (!$res["status"]) { return response()->json([ "errorcode" => "103", "errormsg" => $res["msg"] ]); } } DB::commit(); return response()->json($updated); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\Get( * path="/manager/get-order/{id}", * tags={"管理端订单处理"}, * summary="V2-获取订单详情", * description="获取订单详情", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="id"), * @OA\Response( * response="200", * description="获取订单详情" * ) * ) */ public function getOrder($id, $ajax = true) { $model = $this->_getOrderModel(); $order = $model->with([ "orderItems" => function ($query) { $query->orderBy("service_date", "desc"); }, "recharges" => function ($query) { $query->withCount("refunds"); }, "refunds" ])->find($id); $order = $order->refreshTotal(); $order->balance = $order->customer->balance; $paramedic_items = $order->orderItems->groupBy("paramedic_id"); $group_by_paramedic = []; foreach ($paramedic_items as $k => $items) { $items = $items->sortBy("id"); $paramedic = Paramedic::withTrashed()->find($k); $group_by_paramedic[] = [ "paramedic_id" => $k, "paramedic_name" => $paramedic->name, "days" => $items->count(), "from_date" => $items->first()->service_date, "to_date" => $items->last()->service_date, ]; } $order->group_by_paramedic = collect($group_by_paramedic); // 是否需要签订协议,0否1是 $order->need_agreements = $order->needAgreements($order); if ($ajax === true) { return response()->json($order->toArray()); } return $order; } /** * @OA\Get( * path="/manager/get-order-item/{id}", * tags={"管理端订单处理"}, * summary="V2-获取子订单详情", * description="获取子订单详情", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="id"), * @OA\Response( * response="200", * description="获取子订单详情" * ) * ) */ public function getOrderItem($id) { $order_item = (new OrderItems())->with([ "paramedic" => function ($query) { $query ->select("paramedic.id", "paramedic.name", "paramedic.avatar", "paramedic.sex") ->leftJoin("paramedic_level", "paramedic_level.id", "=", "paramedic.paramedic_level_id") ->addSelect("paramedic_level.name as paramedic_level_name"); }, "bed" => function ($query) { $query->select("bed.id", "bed.name", "bed.room_id", "bed.area_id", "bed.building_id") ->leftJoin("building", "building.id", "=", "bed.building_id") ->leftJoin("area", "area.id", "=", "bed.area_id") ->leftJoin("room", "room.id", "=", "bed.room_id") ->addSelect("room.name as room_name", "area.name as area_name", "building.name as building_name"); } ])->find($id); return response()->json($order_item->toArray()); } public function _getOrderModel() { $model = $order = (new Orders()) ->select( "orders.id", "orders.serial", "orders.customer_id", "orders.manager_id", "orders.bed_id", "orders.patient_id", "orders.project_id", "orders.product_id", "orders.product_item_id", "orders.product_paramedic_level_id", "orders.from_date", "orders.to_date", "orders.status", "orders.total", "orders.paid_total", "orders.contact", "orders.mobile", "orders.paramedic_id", "orders.price", "orders.factors", "orders.patient_quantity", "orders.created_at" ) ->with([ "productItem" => function ($query) { $query->select("id", "name"); }, "orderAgreements" => function ($query) { $query->with('paramedicSign', 'customerSign', 'companySign', 'file')->orderBy("id", "desc"); }, "orderAgreementByLast", "paramedicLevel" => function ($query) { $query->select("paramedic_level.id", "paramedic_level.name"); }, "project" => function ($query) { $query->select("id", "name", "range_mobile", "complaint_mobile", "content", "agreement"); }, "bed" => function ($query) { $query->select("bed.id", "bed.name", "bed.building_id", "bed.area_id") ->leftJoin("building", "building.id", "=", "bed.building_id") ->leftJoin("area", "area.id", "=", "bed.area_id") ->leftJoin("room", "room.id", "=", "bed.room_id") ->addSelect("room.name as room_name", "area.name as area_name", "building.name as building_name"); }, "customer" => function ($query) { $query->select("id", "name", "balance"); }, "patient" => function ($query) { $query->select("id", "name", "sex", "age", "mobile"); }, "paramedic" => function ($query) { $query->select("paramedic.id", "paramedic.name", "paramedic.mobile") ->leftJoin("paramedic_level", "paramedic_level.id", "=", "paramedic.paramedic_level_id") ->addSelect("paramedic_level.name as paramedic_level_name"); } ]); return $model; } /** * @OA\Get( * path="/manager/get-project-areas/{project_id}", * tags={"管理端订单处理"}, * summary="V2-获取医院病区", * description="获取医院病区", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="project_id", in="path", @OA\Schema(type="integer"), required=true, description="project id"), * @OA\Response( * response="200", * description="获取医院床位" * ) * ) */ public function getProjectAreas($project_id) { $areas = (new Area()) ->where("area.project_id", $project_id) ->select("area.id", "area.name", "area.building_id") ->leftJoin("building", "building.id", "=", "area.building_id") ->addSelect("building.name as building_name") // ->orderBy("building_name") ->orderBy("area.myindex") //->orderBy("area.name") ->get(); return response()->json($areas->toArray()); } /** * @OA\Get( * path="/manager/get-area-beds/{area_id}", * tags={"管理端订单处理"}, * summary="V2-根据病区获取病床", * description="根据病区获取病床", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="area_id", in="path", @OA\Schema(type="integer"), required=true, description="area id"), * @OA\Response( * response="200", * description="根据病区获取病床" * ) * ) */ public function getAreaBeds($area_id) { $beds = (new Bed()) ->where("bed.area_id", $area_id) ->select("bed.id", "bed.name", "bed.area_id", "bed.room_id") ->leftJoin("room", "room.id", "=", "bed.room_id") ->addSelect("room.name as room_name") ->orderBy("bed.myindex") ->get(); return response()->json($beds->toArray()); } /** * @OA\Get( * path="/manager/get-available-paramedics", * tags={"管理端订单处理"}, * summary="V2-获取可用护工列表(已基本准确,需进一步打磨)", * description="获取可用护工列表", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="bed_id", in="query", @OA\Schema(type="integer"), required=true, description="床位ID"), * @OA\Parameter(name="sex", in="query", @OA\Schema(type="string"), required=true, description="性别:[男/女]"), * @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string"), required=false, description="日期,默认为当天"), * @OA\Parameter(name="factors", in="query", @OA\Schema(type="object"), required=true, description="价格因子选择,[{id:1,factor_item_id:1},{...}],如果为空数组请传[]"), * @OA\Response( * response="200", * description="获取可用护工列表" * ) * ) */ public function getAvailableParamedics(Request $request) { $paramedics = (new Orders())->getAvailableParamedics(); return response()->json($paramedics); } /** * @OA\POST( * path="/manager/create-patient", * tags={"管理端订单处理"}, * summary="V2-创建被护理人", * description="创建被护理人", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="name", in="query", @OA\Schema(type="string"), required=true, description="姓名"), * @OA\Parameter(name="sex", in="query", @OA\Schema(type="string"), required=true, description="性别:[男/女]"), * @OA\Parameter(name="age", in="query", @OA\Schema(type="integer"), required=true, description="年龄,只需填写入院时的年龄"), * @OA\Response( * response="200", * description="创建被护理人" * ) * ) */ public function createPatient() { $data = [ "name" => request()->name, "sex" => request()->sex, "age" => request()->age, "mobile" => request()->mobile ]; $vo = (new Patient())->create($data); return response()->json($vo); } /** * @OA\POST( * path="/manager/create-order", * tags={"管理端订单处理"}, * summary="V2-创建订单", * description="创建订单", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="product_id", in="query", @OA\Schema(type="integer"), required=true, description="产品id"), * @OA\Parameter(name="product_item_id", in="query", @OA\Schema(type="integer"), required=true, description="产品型号id"), * @OA\Parameter(name="product_paramedic_level_id", in="query", @OA\Schema(type="integer"), required=true, description="产品-护工等级id"), * @OA\Parameter(name="factors", in="query", @OA\Schema(type="object"), required=true, description="价格因子选择,[{id:1,factor_item_id:1},{...}],如果为空数组请传[]"), * @OA\Parameter(name="bed_id", in="query", @OA\Schema(type="integer"), required=true, description="床位id"), * @OA\Parameter(name="paramedic_id", in="query", @OA\Schema(type="integer"), required=false, description="护工id"), * @OA\Parameter(name="patient_name", in="query", @OA\Schema(type="string"), required=true, description="被护理人姓名"), * @OA\Parameter(name="patient_mobile", in="query", @OA\Schema(type="string"), required=true, description="被护理人电话"), * @OA\Parameter(name="patient_sex", in="query", @OA\Schema(type="string"), required=true, description="被护理人性别:男,女"), * @OA\Parameter(name="patient_age", in="query", @OA\Schema(type="string"), required=true, description="被护理人年龄"), * @OA\Parameter(name="contact", in="query", @OA\Schema(type="string"), required=false, description="联系人"), * @OA\Parameter(name="mobile", in="query", @OA\Schema(type="string"), required=false, description="联系人电话"), * @OA\Parameter(name="from_date", in="query", @OA\Schema(type="string"), required=true, description="开始日期"), * @OA\Parameter(name="to_date", in="query", @OA\Schema(type="string"), required=true, description="结束日期"), * @OA\Parameter(name="price", in="query", @OA\Schema(type="number"), required=true, description="协商价格"), * @OA\Response( * response="200", * description="创建订单" * ) * ) */ public function createOrder() { DB::beginTransaction(); try { $mobile = request()->mobile ?? request()->patient_mobile; $customer = (new Customer())->firstOrCreate([ "mobile" => $mobile ]); $has_orders = Orders::where("customer_id", $customer->id)->whereIn("status", [Orders::STATUS_UNCONFIRMED, Orders::STATUS_UNASSIGNED, Orders::STATUS_ONGOING])->count(); if ($has_orders) { return response()->json([ "errorcode" => "101", "errormsg" => "客户名下有即将开始或正在进行中的订单,暂不可以再次下单" ]); } $product = (new Product())->find(request()->product_id); $product_paramedic_level = (new ProductParamedicLevel())->find(request()->product_paramedic_level_id); $product_item = (new ProductItems())->find(request()->product_item_id); $price = $product_item->price + $product_paramedic_level->price; $factors = (new Orders())->requestFactorsToOrderFactors(); $price += collect($factors)->sum("price"); if (request()->price < $price) { return response()->json([ "errorcode" => "102", "errormsg" => "协商价格不能低于系统指导价" ]); } $patient = (new Patient())->firstOrCreate([ "customer_id" => $customer->id, "name" => request()->patient_name ]); $patient->update([ "age" => request()->patient_age, "sex" => request()->patient_sex, "mobile" => request()->patient_mobile, ]); $order = (new Orders())->create([ "customer_id" => $customer->id, "project_id" => $product->id, "product_id" => request()->product_id, "patient_id" => $patient->id, "contact" => request()->contact ?? request()->patient_name, "mobile" => request()->mobile ?? request()->patient_mobile, "from_date" => request()->from_date, "to_date" => request()->to_date, "product_item_id" => request()->product_item_id, "product_paramedic_level_id" => request()->product_paramedic_level_id, "bed_id" => request()->bed_id, "paramedic_id" => request()->paramedic_id, "price" => request()->price, "factors" => json_encode($factors), "status" => request()->paramedic_id ? Orders::STATUS_ONGOING : Orders::STATUS_UNASSIGNED, "manager_id" => $this->manager->id ]); $order->getSerial(); if (request()->paramedic_id) { event(new OrderAssigned($order)); } DB::commit(); $order = $this->getOrder($order->id, false); if (request()->paramedic_id) { $order = (new AttachAffectedOrders)($order); } return response()->json($order->toArray()); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/update-order/{id}", * tags={"管理端订单处理"}, * summary="V2-订单修改(静态修改不影响当前所有子订单)", * description="订单修改", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="product_id", in="query", @OA\Schema(type="integer"), required=true, description="产品id"), * @OA\Parameter(name="product_item_id", in="query", @OA\Schema(type="integer"), required=true, description="产品型号id"), * @OA\Parameter(name="product_paramedic_level_id", in="query", @OA\Schema(type="integer"), required=true, description="产品-护工等级id"), * @OA\Parameter(name="factors", in="query", @OA\Schema(type="object"), required=true, description="价格因子选择,[{id:1,factor_item_id:1},{...}],如果为空数组请传[]"), * @OA\Parameter(name="bed_id", in="query", @OA\Schema(type="integer"), required=true, description="床位id"), * @OA\Parameter(name="paramedic_id", in="query", @OA\Schema(type="integer"), required=false, description="护工id"), * @OA\Parameter(name="patient_name", in="query", @OA\Schema(type="string"), required=true, description="被护理人姓名"), * @OA\Parameter(name="patient_mobile", in="query", @OA\Schema(type="string"), required=true, description="被护理人电话"), * @OA\Parameter(name="patient_sex", in="query", @OA\Schema(type="string"), required=true, description="被护理人性别:男,女"), * @OA\Parameter(name="patient_age", in="query", @OA\Schema(type="string"), required=true, description="被护理人年龄"), * @OA\Parameter(name="contact", in="query", @OA\Schema(type="string"), required=false, description="联系人"), * @OA\Parameter(name="mobile", in="query", @OA\Schema(type="string"), required=false, description="联系人电话"), * @OA\Parameter(name="from_date", in="query", @OA\Schema(type="string"), required=true, description="开始日期"), * @OA\Parameter(name="to_date", in="query", @OA\Schema(type="string"), required=true, description="结束日期"), * @OA\Parameter(name="price", in="query", @OA\Schema(type="number"), required=true, description="协商价格"), * @OA\Parameter(name="available_day", in="query", @OA\Schema(type="number"), required=true, description="生效日期,仅当值为today表示同步更新当日子订单价格,为其他值表示次日起生效"), * @OA\Response( * response="200", * description="订单修改", * content={ * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property( * property="errorcode", * type="integer", * description="错误码;仅在发生错误时发送" * ), * @OA\Property( * property="errormsg", * type="string", * description="返回消息;有errorcode时为错误内容,无errorcode时为提示内容" * ), * @OA\Property( * property="order.*", * type="string", * description="订单实体" * ), * @OA\Property( * property="affected_orders", * type="array", * @OA\Items(), * description="特别说明:影响到的订单,如果无此字段或数组为空表示未发生订单影响。影响到的订单实体数组,实体中的change字段(many_to_one或one_to_many)表示影响的方向" * ) * ) * ) * } * ) * ) */ public function updateOrder($id) { DB::beginTransaction(); try { $order = Orders::with(["customer", "patient", "product", "productItem", "productParamedicLevel"])->find($id); $product_paramedic_level = request()->has("product_paramedic_level_id") ? (new ProductParamedicLevel())->find(request()->product_paramedic_level_id) : $order->productParamedicLevel; $product_item = request()->has("product_item_id") ? (new ProductItems())->find(request()->product_item_id) : $order->productItem; $price = $product_item->price + $product_paramedic_level->price; if (request()->has("factors")) { $factors = (new Orders())->requestFactorsToOrderFactors(); } else { $factors = json_decode($order->factors); } $price += collect($factors)->sum("price"); if (request()->has("price") && request()->price < $price) { return response()->json([ "errorcode" => "102", "errormsg" => "协商价格不能低于系统指导价" ]); } //更新被陪护人 if (request()->has("patient_name", "patient_mobile", "patient_sex", "patient_age")) { $order->patient->update([ "name" => request()->patient_name, "age" => request()->patient_age, "sex" => request()->patient_sex, "mobile" => request()->patient_mobile, ]); } //更新订单基本信息 $from_paramedic = $order->paramedic_id; $update = (new Orders())->filterRequestColumns(request(), ["id"]); if (request()->has("contact", "patient_name") && !request()->contact) { $update["contact"] = request()->patient_name; } if (request()->has("mobile", "patient_mobile") && !request()->mobile) { $update["mobile"] = request()->patient_mobile; } if (request()->has("factors")) { $update["factors"] = json_encode($factors); } $order->update($update); //正在进行中当天的子订单修改 if ($order->isOngoing() && request()->available_day == "today") { $res = (new OrderItems())->updateTodayItem($order->id); if (!$res["status"]) { return response()->json([ "errorcode" => "103", "errormsg" => $res["msg"] ]); } } //如果原本的护工id为空且新提交了护工id,视同为派单 if ($order->isPending() && request()->paramedic_id) { $order->update([ "paramedic_id" => request()->paramedic_id, "status" => Orders::STATUS_ONGOING ]); event(new OrderAssigned($order)); } $order = (new AttachAffectedOrders)($order, $from_paramedic); DB::commit(); return response()->json($order->toArray()); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/update-order-items", * tags={"管理端订单处理"}, * summary="V2-子订单修改(覆盖单条修改),20230618更新:对早于过上月的价格锁定", * description="子订单修改", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="ids", in="query", @OA\Schema(type="integer"), required=true, description="子订单id,可传单个id或数组"), * @OA\Parameter(name="bed_id", in="query", @OA\Schema(type="integer"), required=false, description="床位id"), * @OA\Parameter(name="paramedic_id", in="query", @OA\Schema(type="integer"), required=false, description="护工id"), * @OA\Parameter(name="price", in="query", @OA\Schema(type="integer"), required=false, description="价格"), * @OA\Parameter(name="skip_warnings", in="query", @OA\Schema(type="integer"), required=false, description="跳过警示项目"), * @OA\Response( * response="200", * description="子订单修改", * content={ * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property( * property="errorcode", * type="integer", * description="错误码;仅在发生错误时发送" * ), * @OA\Property( * property="errormsg", * type="string", * description="返回消息;有errorcode时为错误内容,无errorcode时为提示内容" * ), * @OA\Property( * property="has_warnings", * type="boolean", * description="是否有警告内容;仅在有警告内容且无错误代码的情况下发送,此时读取errormsg为警告内容" * ), * @OA\Property( * property="updated_items", * type="integer", * description="更新的子订单总数;仅在成功的情况下发送" * ), * @OA\Property( * property="updated_paid_items", * type="integer", * description="产生了价格波动的子订单总数,连锁效应为每条价格波动会新增一条财务记录,并影响客户的余额;仅在成功的情况下发送" * ), * example={ * "errorcode": "105", * "errormsg": "价格补差100超过了客户余额90,请先充值", * "has_warnings": 1, * "updated_items": 10, * "updated_paid_items": 3 * } * ) * ) * } * ) * ) */ public function updateOrderItems(Request $request) { $ids = explode(",", $request->ids); $order_items = (new OrderItems())->whereHas("order")->whereIn("id", $ids)->with("customer")->get(); if (!$order_items->count()) { return response()->json([ "errorcode" => "105", "errormsg" => "没有获取到子订单" ]); } $customer = $order_items->first()->customer; $price_changed_paid_items = $order_items->filter(function ($item) use ($request) { return $request->has("price") && $item->paid_at && ($request->price != $item->total); }); $price_changed_last_month_paid_items = $price_changed_paid_items->filter(function ($item) { return (date("Ym", strtotime($item->paid_at)) != date("Ym")) || 1; }); $total_increased = $price_changed_paid_items->count() * $request->price - $price_changed_paid_items->sum("total"); $warnings = []; $errors = []; if ($price_changed_last_month_paid_items->count()) { $errors[] = "有" . $price_changed_last_month_paid_items->count() . "天往月扣款的子订单已锁定价格,不可修改"; } $manager = $this->guard()->user(); // if (!$manager->no_lock_ability) { //2023年8月份有开通一个功能,让具有权限的人可以修改往月的已扣款订单,后发现有问题,现在改为只可以对当月或上月已扣款订单进行修改 foreach ($order_items as $_item) { if ($_item->paid_at && $request->price && $_item->total != $request->price && date("Ym", strtotime($_item->service_date)) < date("Ym", strtotime("-1 month", time()))) { $errors[] = "子订单{$_item->service_date}价格已锁定"; } } // } if ($total_increased > $customer->balance) { $errors[] = "价格补差{$total_increased}超过了客户余额{$customer->balance},请先充值"; } //todo:价格低于指导价的提示 if (count($errors)) { return response()->json([ "errorcode" => "105", "errormsg" => implode(";", $errors) ]); } if (count($warnings) && !$request->skip_warnings) { return response()->json([ "has_warnings" => true, "errormsg" => implode(";", $warnings) ]); } DB::beginTransaction(); try { //根据已付款的价格异动子订单循环添加余额平衡表记录,并随时更新客户余额值,执行完毕后保存客户余额更新 foreach ($price_changed_paid_items as $price_changed_paid_item) { $total_offset = $price_changed_paid_item->total - $request->price; $customer->balance = $customer->balance + $total_offset; (new Balance())->create([ "customer_id" => $customer->id, "order_id" => $price_changed_paid_item->order_id, "belongs_type" => get_class($price_changed_paid_item), "belongs_id" => $price_changed_paid_item->id, "money" => $total_offset, "balance" => $customer->balance ]); } $customer->save(); //循环更新所有子订单 $update = []; if ($request->has("bed_id")) { $update["bed_id"] = $request->bed_id; } if ($request->has("paramedic_id")) { $update["paramedic_id"] = $request->paramedic_id; } if ($request->has("price")) { $update["total"] = $request->price; } foreach ($order_items as $order_item) { $order_item->update($update); } DB::commit(); return response()->json([ "updated_items" => count($order_items), "updated_paid_items" => count($price_changed_paid_items) ]); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/checkout-order-items/{order_id}", * tags={"管理端订单处理"}, * summary="V2-中途结算(即只依次结算子订单,并不结束订单,只需余额刚好)", * description="交互流程如下:初次请求带上just_check参数,将返回to_recharge_total值;如果to_recharge_total大于0表示需要充值,充值完成之后,去除just_check参数再次提交;如果to_recharge_total <= 0,直接去除just_check参数再次提交", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="order_id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="to_date", in="query", @OA\Schema(type="date"), required=true, description="结算到的日子"), * @OA\Parameter(name="just_check", in="query", @OA\Schema(type="boolean"), required=false, description="是否只是check一下要多少钱"), * @OA\Response( * response="200", * description="中途结算", * content={ * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property( * property="errorcode", * type="integer", * description="错误码;仅在发生错误时发送" * ), * @OA\Property( * property="errormsg", * type="string", * description="返回消息;有errorcode时为错误内容,无errorcode时为提示内容" * ), * @OA\Property( * property="prepay_total", * type="decimal", * description="总计需要预扣的金额,入参just_check为1时just_check为0但是客户余额不足时返回" * ), * @OA\Property( * property="customer_balance", * type="decimal", * description="客户余额,入参just_check为1时just_check为0但是客户余额不足时返回" * ), * @OA\Property( * property="to_recharge_total", * type="decimal", * description="需要充值的金额,入参just_check为1时(此时to_recharge_total值如果大于0则需要充值)或just_check为0但是客户余额不足时(此时to_recharge_total值一定大于0)返回" * ), * @OA\Property( * property="updated_items", * type="integer", * description="结算的子订单总数;仅在成功的情况下发送" * ), * example={ * "errorcode": "30003", * "errormsg": "截止到中途结算日,没有需要结算的子订单,如需预充值请发起收款操作", * "prepay_total": 1000, * "customer_balance": 10, * "to_recharge_total": 990, * "checkout_items": 10 * } * ) * ) * } * ) * ) */ public function checkoutOrderItems($order_id, Request $request) { $order = Orders::with("customer")->find($order_id); if ($order->status != Orders::STATUS_ONGOING) { return response()->json([ "errorcode" => 30000, "errormsg" => "订单状态不匹配" ]); } $order_items = OrderItems::where("order_id", $order_id)->whereRaw("DATEDIFF('{$request->to_date}',`service_date`) >= 0")->orderBy("service_date", "asc")->get(); $unpaid_order_items = $order_items->filter(function ($item) { return $item->total > 0 && !$item->paid_at; }); if ($order_items->count()) { $to_generate_days = Carbon::parse($order_items->last()->service_date)->diffInDays($request->to_date, false); $to_generate_start_date = Carbon::parse($order_items->last()->service_date)->addDay()->toDateString(); } else { $to_generate_days = Carbon::parse($order->from_date)->diffInDays($request->to_date, false) + 1; $to_generate_start_date = $order->from_date; } $to_generate_days = max(0, $to_generate_days); for ($i = 0; $i < $to_generate_days; $i++) { if ($i > 0) { $service_date = Carbon::parse($to_generate_start_date)->addDays($i)->toDateString(); } else { $service_date = $to_generate_start_date; } if (strtotime($service_date) >= strtotime("+1 month", strtotime(date("Y-m") . "-01"))) { return response()->json([ "errorcode" => 30003, "errormsg" => "中途结算最大时限不能超过当月月底" ]); } } $prepay_total = $unpaid_order_items->sum("total") + $to_generate_days * $order->price; $to_recharge_total = $prepay_total - $order->customer->balance; //如果只是检查一下需要充值金额,直接返回 if ($request->just_check) { return response()->json([ "prepay_total" => $prepay_total, "customer_balance" => $order->customer->balance, "to_recharge_total" => $to_recharge_total ]); } //没有需要操作的子订单,无意义 if (!$unpaid_order_items->count() && !$to_generate_days) { return response()->json([ "errorcode" => 30001, "errormsg" => "截止到中途结算日,没有需要结算的子订单,如需预充值请发起收款操作" ]); } //需要预先充值 if ($to_recharge_total > 0) { return response()->json([ "errorcode" => 30002, "errormsg" => "余额不足,请先充值", "prepay_total" => $prepay_total, "customer_balance" => $order->customer->balance, "to_recharge_total" => $to_recharge_total ]); } DB::beginTransaction(); try { foreach ($unpaid_order_items as $order_item) { //更新子订单支付状态 $order_item->update(["paid_at" => date("Y-m-d H:i:s")]); //更新客户余额(暂不保存,最后统一保存) $order->customer->balance = $order->customer->balance - $order_item->total; //创建收款记录 (new Balance())->create([ "customer_id" => $order->customer->id, "order_id" => $order->id, "belongs_type" => get_class($order_item), "belongs_id" => $order_item->id, "money" => -$order_item->total, "balance" => $order->customer->balance ]); } for ($i = 0; $i < $to_generate_days; $i++) { if ($i > 0) { $service_date = Carbon::parse($to_generate_start_date)->addDays($i)->toDateString(); } else { $service_date = $to_generate_start_date; } if (strtotime($service_date) >= strtotime("+1 month", strtotime(date("Y-m") . "-01"))) { return response()->json([ "errorcode" => 30003, "errormsg" => "中途结算最大时限不能超过当月月底,已收的多余款项将于下月使用" ]); } $order_item = (new OrderItems())->createItem($order->id, $service_date); //更新子订单支付状态 $order_item->update(["paid_at" => date("Y-m-d H:i:s")]); //更新客户余额(暂不保存,最后统一保存) $order->customer->balance = $order->customer->balance - $order_item->total; //创建收款记录 (new Balance())->create([ "customer_id" => $order->customer->id, "order_id" => $order->id, "belongs_type" => get_class($order_item), "belongs_id" => $order_item->id, "money" => -$order_item->total, "balance" => $order->customer->balance ]); } $order->customer->save(); DB::commit(); return response()->json([ "checkout_items" => count($unpaid_order_items) ]); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/checkout-order/{id}", * tags={"管理端订单处理"}, * summary="V2-订单结算", * description="交互流程如下:初次请求带上just_check参数,将返回to_recharge_total和to_refund_total值;仅在to_recharge_total和to_refund_total都为0的情况下才可以结算成功;如果to_recharge_total大于0表示需要充值,充值完成之后,剔除just_check参数再次提交;如果to_refund_total大于0表示需要退款,根据返回的退款方式操作后,剔除just_check参数再次提交", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="to_date", in="query", @OA\Schema(type="date"), required=true, description="结算到的日子"), * @OA\Parameter(name="just_check", in="query", @OA\Schema(type="boolean"), required=false, description="是否只是check一下要多少钱"), * @OA\Response( * response="200", * description="订单结算", * content={ * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property( * property="errorcode", * type="integer", * description="错误码;仅在发生错误时发送" * ), * @OA\Property( * property="errormsg", * type="string", * description="返回消息;有errorcode时为错误内容,无errorcode时为提示内容" * ), * @OA\Property( * property="prepay_total", * type="decimal", * description="总计需要扣除的金额,入参just_check为1时just_check为0但是客户余额不足时返回" * ), * @OA\Property( * property="customer_balance", * type="decimal", * description="客户余额,入参just_check为1时just_check为0但是客户余额不足时返回" * ), * @OA\Property( * property="to_recharge_total", * type="decimal", * description="需要充值的金额" * ), * @OA\Property( * property="to_refund_total", * type="decimal", * description="需要退款的金额" * ), * @OA\Property( * property="refund_payment", * type="string", * description="退款方式" * ), * @OA\Property( * property="refund_recharge_id", * type="integer", * description="在线退款原路返回对应的在线充值id" * ), * @OA\Property( * property="refund_recharge_transaction_id", * type="integer", * description="在线退款原路返回所对应的在线充值记录的支付平台交易编号" * ), * @OA\Property( * property="checkout_order_id", * type="integer", * description="结算成功返回订单id;仅在成功的情况下发送" * ), * example={ * "errorcode": "30006", * "errormsg": "结算日不能早于最后一个已服务且扣款的子订单", * "prepay_total": 100, * "customer_balance": 200, * "to_recharge_total": 0, * "to_refund_total": 100, * "refund_recharge_id": 1123, * "refund_recharge_serial": 1123, * "checkout_order_id": 777 * } * ) * ) * } * ) * ) */ public function checkoutOrder($id, Request $request) { $order = Orders::with("customer")->find($id); if ($order->status != Orders::STATUS_ONGOING) { return response()->json([ "errorcode" => 30000, "errormsg" => "订单状态不匹配" ]); } $order_items = OrderItems::where("order_id", $id) ->orderBy("service_date", "asc") ->get(); $last_paid_order_item = $order_items->filter(function ($item) { return $item->total > 0 && $item->paid_at; })->last(); //结算日早于最后一个已扣款的日期,退回先处理好子订单再结算 if ($last_paid_order_item) { if (Carbon::parse($request->to_date)->diffInDays($last_paid_order_item->service_date, false) > 0) { return response()->json([ "errorcode" => 30006, "errormsg" => "结算日不能早于最后一个已服务且扣款的子订单{$last_paid_order_item->service_date}:$request->to_date" ]); } } //计算结算数据 $unpaid_order_items = $order_items->filter(function ($item) { return $item->total > 0 && !$item->paid_at; }); if ($order_items->count()) { $to_generate_days = Carbon::parse($order_items->last()->service_date)->diffInDays($request->to_date, false); $to_generate_start_date = Carbon::parse($order_items->last()->service_date)->addDay()->toDateString(); } else { $to_generate_days = Carbon::parse($order->from_date)->diffInDays($request->to_date, false) + 1; $to_generate_start_date = $order->from_date; } $to_generate_days = max(0, $to_generate_days); $prepay_total = $unpaid_order_items->sum("total") + $to_generate_days * $order->price; $to_recharge_total = $prepay_total - $order->customer->balance; //通过以下处理后可得出三种情形:1、需要充值;2、需要退款;3、账务平衡可结单 $to_refund_total = max(0, -$to_recharge_total); $to_recharge_total = max(0, $to_recharge_total); if ($to_refund_total > 0) { $recharge_for_online_refund = $order->getOnlineRefundableRecharge($to_refund_total); } else { $recharge_for_online_refund = null; } //如果只是检查一下需要充值或退款金额,直接返回 if ($request->just_check) { return response()->json([ "prepay_total" => $prepay_total, "customer_balance" => $order->customer->balance, "to_recharge_total" => $to_recharge_total, "to_refund_total" => $to_refund_total, "refund_payment" => $recharge_for_online_refund ? $recharge_for_online_refund->payment : "cash", "refund_recharge_id" => $recharge_for_online_refund ? $recharge_for_online_refund->id : null, "refund_recharge_transaction_id" => $recharge_for_online_refund ? $recharge_for_online_refund->payment_serial : null ]); } //1、需要充值 if ($to_recharge_total > 0) { return response()->json([ "errorcode" => 30007, "errormsg" => "余额不足,请先充值", "prepay_total" => $prepay_total, "customer_balance" => $order->customer->balance, "to_recharge_total" => $to_recharge_total ]); } //2、需要退款 if ($to_refund_total > 0) { return response()->json([ "errorcode" => 30008, "errormsg" => "请先进行退款操作后再结单", "prepay_total" => $prepay_total, "customer_balance" => $order->customer->balance, "to_refund_total" => $to_refund_total, "refund_payment" => $recharge_for_online_refund ? $recharge_for_online_refund->payment : "cash", "refund_recharge_id" => $recharge_for_online_refund ? $recharge_for_online_refund->id : null, "refund_recharge_transaction_id" => $recharge_for_online_refund ? $recharge_for_online_refund->payment_serial : null ]); } //3、账务平衡可结单 DB::beginTransaction(); try { foreach ($unpaid_order_items as $order_item) { //更新子订单支付状态 $order_item->update(["paid_at" => date("Y-m-d H:i:s")]); //更新客户余额(暂不保存,最后统一保存) $order->customer->balance = $order->customer->balance - $order_item->total; //创建收款记录 (new Balance())->create([ "customer_id" => $order->customer->id, "order_id" => $order->id, "belongs_type" => get_class($order_item), "belongs_id" => $order_item->id, "money" => -$order_item->total, "balance" => $order->customer->balance ]); } for ($i = 0; $i < $to_generate_days; $i++) { if ($i > 0) { $service_date = Carbon::parse($to_generate_start_date)->addDays($i)->toDateString(); } else { $service_date = $to_generate_start_date; } $order_item = (new OrderItems())->createItem($order->id, $service_date); //更新子订单支付状态 $order_item->update(["paid_at" => date("Y-m-d H:i:s")]); //更新客户余额(暂不保存,最后统一保存) $order->customer->balance = $order->customer->balance - $order_item->total; //创建收款记录 (new Balance())->create([ "customer_id" => $order->customer->id, "order_id" => $order->id, "belongs_type" => get_class($order_item), "belongs_id" => $order_item->id, "money" => -$order_item->total, "balance" => $order->customer->balance ]); } $order->customer->save(); $order->update([ "status" => Orders::STATUS_FINISHED, "to_date" => $request->to_date ]); DB::commit(); return response()->json([ "checkout_order_id" => $order->id ]); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/scan-pay/{order_id}", * tags={"管理端订单处理"}, * summary="V2-扫用户支付码收款", * description="扫用户支付码收款", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="order_id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="money", in="query", @OA\Schema(type="number"), required=true, description="支付金额"), * @OA\Parameter(name="auth_code", in="query", @OA\Schema(type="string"), required=true, description="扫码后获取的支付码"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=true, description="支付方式:weixin,alipay"), * @OA\Response( * response="200", * description="扫用户支付码收款" * ) * ) */ public function scanPay($order_id) { if (request()->money <= 0) { return response()->json([ "errorcode" => 60003, "errormsg" => "付款金额不正确" ]); } $order = (new Orders())->with(["wechatpayAccount", "alipayAccount"])->find($order_id); Log::info("阿里云支付账号:" . $order->alipayAccount->appid); $recharge = (new Recharge())->create([ "customer_id" => $order->customer->id, "money" => request()->money, "order_id" => $order->id, "payment" => request()->type, "manager_id" => $this->manager->id ]); $recharge = $recharge->getSerial(); switch (request()->type) { case "weixin": $res = (new WxMicroPay($order->project_id))->pay($recharge); $recharge->update([ "merchant_id" => $order->wechatpayAccount->mchid ]); if ($res === true) { return response()->json(true); } else { return response()->json([ "errorcode" => 60003, "errormsg" => $res->getMessage() ]); } break; case "alipay": $res = (new AlipayF2F())->pay($recharge); $recharge->update([ "merchant_id" => $order->alipayAccount->appid ]); if ($res["status"]) { return response()->json(true); } else { return response()->json([ "errorcode" => $res["code"], "errormsg" => $res["msg"] ]); } break; default: return response()->json([ "errorcode" => 60003, "errormsg" => "不正确的支付方式" ]); } } /** * @OA\POST( * path="/manager/assign-order/{id}", * tags={"管理端订单处理"}, * summary="V2-派单", * description="派单", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="paramedic_id", in="query", @OA\Schema(type="integer"), required=true, description="护工id"), * @OA\Response( * response="200", * description="订单派单", * content={ * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property( * property="errorcode", * type="integer", * description="错误码;仅在发生错误时发送" * ), * @OA\Property( * property="errormsg", * type="string", * description="返回消息;有errorcode时为错误内容,无errorcode时为提示内容" * ), * @OA\Property( * property="order.*", * type="string", * description="订单实体" * ), * @OA\Property( * property="affected_orders", * type="array", * @OA\Items(), * description="特别说明:影响到的订单,如果无此字段或数组为空表示未发生订单影响。影响到的订单实体数组,实体中的change字段(many_to_one或one_to_many)表示影响的方向" * ) * ) * ) * } * ) * ) */ public function assignOrder($id) { $order = (new Orders())->find($id); if (!in_array($order->status, [Orders::STATUS_UNCONFIRMED, Orders::STATUS_UNASSIGNED])) { return response()->json([ "errorcode" => 50001, "errormsg" => "订单状态不适配" ]); } DB::beginTransaction(); try { $order->update([ "paramedic_id" => request()->paramedic_id, "status" => Orders::STATUS_ONGOING ]); event(new OrderAssigned($order)); DB::commit(); return response()->json($order); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/cancel-order/{id}", * tags={"管理端订单处理"}, * summary="V2-取消订单", * description="取消订单", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Response( * response="200", * description="取消订单" * ) * ) */ public function cancelOrder($id) { $order = (new Orders())->with("orderItems")->find($id); if (!in_array($order->status, [Orders::STATUS_UNCONFIRMED, Orders::STATUS_UNASSIGNED])) { return response()->json([ "errorcode" => 50001, "errormsg" => "订单状态不适配" ]); } DB::beginTransaction(); try { // 1. 获取订单的微信支付记录 $recharges = (new Recharge()) ->where("order_id", $order->id) ->whereNotNull("paid_at") ->doesntHave("refunds") ->where("payment", "weixin") ->get(); // 2. 计算支付总额 $totalPaid = (float)$recharges->sum('money'); // 3. 获取用户当前余额 $customer = $order->customer; $currentBalance = (float)$customer->balance; // 4. 如果支付总额等于用户余额,进行退款处理 if ($totalPaid > 0 && float_equals($totalPaid, $currentBalance)) { foreach ($recharges as $recharge) { // 更新用户余额 $currentBalance -= $recharge->money; $customer->balance = $currentBalance; $customer->save(); // 生成退款记录与财务记录 $refund = Refund::create([ "customer_id" => $order->customer->id, "money" => $recharge->money, "order_id" => $order->id, "payment" => $recharge->payment, "recharge_id" => $recharge->id, "merchant_id" => $recharge->merchant_id, "remark" => "取消订单,自动退款" ]); $refund->getSerial(); $balance = Balance::create([ "customer_id" => $customer->id, "order_id" => $order->id, "belongs_type" => get_class($refund), "belongs_id" => $refund->id, "money" => -$refund->money, "balance" => $currentBalance ]); } } // 5. 删除订单及子订单 foreach ($order->orderItems as $orderItem) { $orderItem->delete(); } $order->delete(); DB::commit(); return response()->json($order); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/get-balance/{customer_id}", * tags={"管理端订单处理"}, * summary="获取用户余额", * description="获取用户余额", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="customer_id", in="path", @OA\Schema(type="integer"), required=true, description="用户id"), * @OA\Response( * response="200", * description="获取用户余额" * ) * ) */ public function getBalance($customer_id) { $customer = (new Customer())->find($customer_id); if (!$customer) { return response()->json([ "errorcode" => 70001, "errormsg" => "没找到用户信息" ]); } return response()->json([ "balance" => $customer->balance ]); } /** * @OA\POST( * path="/manager/recharge-for-order/{id}", * tags={"管理端订单处理"}, * summary="V2-现金或pos刷卡充值", * description="现金或pos刷卡充值", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="payment", in="query", @OA\Schema(type="string"), required=true, description="枚举:pos=>pos机刷卡支付, cash=>现金支付"), * @OA\Parameter(name="money", in="query", @OA\Schema(type="number"), required=true, description="金额,非负数"), * @OA\Parameter(name="remark", in="query", @OA\Schema(type="string"), required=false, description="备注信息:现金支付时可以忽略;刷卡支付时,填入回单号或卡号以便财务对账"), * @OA\Response( * response="200", * description="现金或pos刷卡充值" * ) * ) */ public function rechargeForOrder($id) { $order = (new Orders())->find($id); if ($order->status != Orders::STATUS_ONGOING) { return response()->json([ "errorcode" => 30000, "errormsg" => "订单状态不匹配" ]); } DB::beginTransaction(); try { //创建充值记录 $recharge = [ "customer_id" => $order->customer->id, "money" => request()->money, "order_id" => $order->id, "payment" => request()->payment, "manager_id" => $this->manager->id, "paid_at" => date("Y-m-d H:i:s") ]; switch (request()->payment) { case "pos": case "cash": $recharge["remark"] = request()->remark; break; default: return response()->json([ "errorcode" => "0", "errormsg" => "不正确的支付方式" ]); } $recharge = (new Recharge())->create($recharge); $recharge = $recharge->getSerial(); //更新用户余额,创建流水记录 $customer_balance = $recharge->customer->balance + $recharge->money; $recharge->customer->update([ "balance" => $customer_balance ]); $balance = (new Balance())->create([ "customer_id" => $recharge->customer->id, "order_id" => $recharge->order_id, "belongs_type" => get_class($recharge), "belongs_id" => $recharge->id, "money" => $recharge->money, "balance" => $customer_balance ]); DB::commit(); return response()->json([ "recharge" => $recharge, "balance" => $balance ]); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\POST( * path="/manager/refund-for-order/{id}", * tags={"管理端订单处理"}, * summary="V2-退款", * description="退款", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="money", in="query", @OA\Schema(type="number"), required=true, description="金额,非负数"), * @OA\Parameter(name="payment", in="query", @OA\Schema(type="string"), required=true, description="退款方式:枚举cash,weixin,alipay。注意可用的退款方式从支付明细或结单时的交互反馈得出,随意提交金额可能会造成问题"), * @OA\Parameter(name="recharge_id", in="query", @OA\Schema(type="integer"), required=false, description="相关在线支付的id,用于原路返回。退款方式为weixin或alipay时,必须给出"), * @OA\Parameter(name="remark", in="query", @OA\Schema(type="string"), required=false, description="备注信息"), * @OA\Response( * response="200", * description="退款" * ) * ) */ public function refundForOrder($id) { DB::beginTransaction(); try { $order = (new Orders())->find($id); //创建退款记录 $refund = [ "customer_id" => $order->customer->id, "manager_id" => $this->manager->id, "money" => request()->money, "order_id" => $order->id, "remark" => request()->remark ]; switch (request()->payment) { case "cash": case "pos": $refund["payment"] = request()->payment; $refund["paid_at"] = date("Y-m-d H:i:s"); break; case "weixin": $recharge = Recharge::find(request()->recharge_id); $refund["payment"] = $recharge->payment; $refund["recharge_id"] = request()->recharge_id; $refund["merchant_id"] = $recharge->merchant_id; break; case "alipay": $recharge = Recharge::find(request()->recharge_id); if (!$recharge->merchant_id) { return response()->json([ "errorcode" => "0", "errormsg" => "本单支付宝退款暂不支持" ]); } $refund["payment"] = $recharge->payment; $refund["recharge_id"] = request()->recharge_id; $refund["merchant_id"] = $recharge->merchant_id; break; default: return response()->json([ "errorcode" => "0", "errormsg" => "不正确的退款方式" ]); } $refund = (new Refund())->create($refund); $refund = $refund->getSerial(); //更新用户余额,创建流水记录 $customer_balance = $refund->customer->balance - $refund->money; if ($customer_balance < 0) { return response()->json([ "errorcode" => "0", "errormsg" => "客户余额为负异常,存在重复退款操作。" ]); } $refund->customer->update([ "balance" => $customer_balance ]); $balance = (new Balance())->create([ "customer_id" => $refund->customer->id, "order_id" => $refund->order_id, "belongs_type" => get_class($refund), "belongs_id" => $refund->id, "money" => -$refund->money, "balance" => $customer_balance ]); DB::commit(); return response()->json([ "refund" => $refund, "balance" => $balance ]); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\Get( * path="/manager/get-project-paramedic-levels/{project_id}", * tags={"管理端订单处理"}, * summary="V2-获取医院护工等级", * description="获取医院护工等级", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="project_id", in="query", @OA\Schema(type="string"), required=true, description="医院ID"), * @OA\Response( * response="200", * description="获取医院护工等级" * ) * ) */ public function getProjectParamedicLevels($project_id) { $paramedic_levels = ParamedicLevel::where("project_id", $project_id)->orderBy("myindex")->get(); return response()->json($paramedic_levels->toArray()); } /** * @OA\Post( * path="/manager/change-order-status/{id}", * tags={"管理端订单处理"}, * summary="V2-更新订单状态,20230618更新:鉴定是否权限是否开启", * description="更新订单状态", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="from_status", in="query", @OA\Schema(type="integer"), required=true, description="原状态"), * @OA\Parameter(name="to_status", in="query", @OA\Schema(type="integer"), required=true, description="更新状态"), * @OA\Response( * response="200", * description="更新订单状态" * ) * ) */ public function changeOrderStatus($id) { try { $manager = $this->guard()->user(); if (!$manager->order_status_ability) { return response()->json([ "errorcode" => "4003", "errormsg" => "权限不足" ]); } $order = (new Orders())->find($id); if (request()->to_status == Orders::STATUS_ONGOING) { $other_ongoing_order = Orders::where("status", Orders::STATUS_ONGOING)->where("customer_id", $order->customer_id)->count(); if ($other_ongoing_order) { return response()->json([ "errorcode" => "2222", "errormsg" => "客户名下有其他进行中的该订单" ]); } } $res = (new ChangeOrderStatus())->__invoke($order); DB::commit(); return response()->json($order->toArray()); } catch (\Exception $exception) { DB::rollBack(); return response()->json([ "errorcode" => $exception->getCode(), "errormsg" => $exception->getMessage() ]); } } /** * @OA\Post( * path="/manager/create-order-agreements", * tags={"管理端订单处理"}, * summary="创建协议", * description="创建协议", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="order_id", in="query", @OA\Schema(type="integer"), required=true, description="订单id"), * @OA\Parameter(name="paramedic_id", in="query", @OA\Schema(type="integer"), required=true, description="护工id"), * @OA\Parameter(name="paramedic_id", in="query", @OA\Schema(type="integer"), required=true, description="护工id"), * @OA\Parameter(name="paramedic_sign_id", in="query", @OA\Schema(type="integer"), required=true, description="护工签名图片id"), * @OA\Parameter(name="customer_id", in="query", @OA\Schema(type="integer"), required=true, description="客户id"), * @OA\Parameter(name="customer_sign_id", in="query", @OA\Schema(type="integer"), required=true, description="客户签名图片id"), * @OA\Parameter(name="company_sign_id", in="query", @OA\Schema(type="integer"), required=true, description="公司签名图片id"), * @OA\Parameter(name="html", in="query", @OA\Schema(type="string"), required=true, description="协议html内容"), * @OA\Response( * response="200", * description="更新订单状态" * ) * ) */ public function createOrderAgreements() { $all = \request()->all(); $orderAgreement = orderAgreement::create($all); return response()->json($orderAgreement->toArray()); } /** * @OA\Post( * path="/manager/html-to-image", * tags={"管理端订单处理"}, * summary="html生成图片(废弃)", * description="html生成图片", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="html", in="query", @OA\Schema(type="string"), required=true, description="html内容"), * @OA\Response( * response="200", * description="html生成图片" * ) * ) */ public function htmlToImage() { $html = \request('html'); if (empty($html)) { return response()->json([ "errorcode" => "4001", "errormsg" => "html内容不能为空" ]); } // 1. 创建临时文件路径 $options = [ 'format' => 'jpg', 'quality' => 75, // 允许访问本地文件(解决Blocked access to file警告) 'enable-local-file-access' => true, ]; // 目录 $save_folder = "public"; // 文件名 $name = "agreement_" . date("YmdHis") . uniqid() . "." . $options['format']; $tempPath = storage_path("app/{$save_folder}/" . $name); // 确保临时目录存在 Storage::makeDirectory($save_folder); // 2. 生成图片到临时文件(需要两个参数:html内容和输出路径) SnappyImage::setOptions($options)->generateFromHtml($html, $tempPath); $upload = new Uploads(); $upload->original_name = $name; $upload->folder = ""; $upload->name = $name;; $upload->extension = $options['format']; $upload->creator_type = get_class($this->manager); $upload->creator_id = $this->manager->id; $upload->size = Storage::size($save_folder . "/" . $name); $upload->save(); if ($save_folder == "public") { $upload->public_path = "/storage/" . $name; } else { $upload->public_path = null; } return response()->json($upload); } }