You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1928 lines
87 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers\Manager;
use AlicFeng\IdentityCard\InfoHelper;
use App\Actions\AttachAffectedOrders;
use App\Actions\ChangeOrderStatus;
use App\Customer;
use App\Events\OrderAssigned;
use App\Libs\AlipayF2F;
use App\Libs\WxMicroPay;
use App\Models\Area;
use App\Models\Balance;
use App\Models\Bed;
use App\Models\OrderAgreement;
use App\Models\OrderItems;
use App\Models\Orders;
use App\Models\Paramedic;
use App\Models\ParamedicLevel;
use App\Models\Patient;
use App\Models\Product;
use App\Models\ProductItems;
use App\Models\ProductParamedicLevel;
use App\Models\Project;
use App\Models\Recharge;
use App\Models\Refund;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Intervention\Image\Facades\Image;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use function GuzzleHttp\Psr7\str;
class OrdersController extends CommonController
{
/**
* @OA\Get(
* path="/manager/get-projects",
* tags={"管理端订单处理"},
* summary="V2 获取医院列表",
* description="获取医院列表",
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
* description="获取医院列表"
* )
* )
*/
public function getProjects()
{
$projects = (new Project())
->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;
}
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);
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");
},
"paramedicLevel" => function ($query) {
$query->select("paramedic_level.id", "paramedic_level.name");
},
"project" => function ($query) {
$query->select("id", "name");
},
"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");
});
$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")->find($order_id);
$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" => env("ALI_APP_ID")
]);
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="退款方式枚举cashweixinalipay。注意可用的退款方式从支付明细或结单时的交互反馈得出随意提交金额可能会造成问题"),
* @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="file_id", in="query", @OA\Schema(type="integer"), required=true, description="协议文件id"),
* @OA\Response(
* response="200",
* description="更新订单状态"
* )
* )
*/
public function createOrderAgreements()
{
$all = \request()->all();
$orderAgreement = orderAgreement::create($all);
return response()->json($orderAgreement->toArray());
}
}