diff --git a/app/Customer.php b/app/Customer.php index 47c8bee..b705b14 100644 --- a/app/Customer.php +++ b/app/Customer.php @@ -4,6 +4,7 @@ namespace App; use App\Models\Balance; use App\Models\Patient; +use App\Models\Recharge; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Tymon\JWTAuth\Contracts\JWTSubject; @@ -87,7 +88,7 @@ class Customer extends Authenticatable implements JWTSubject * @var array */ protected $fillable = [ - 'name', 'username', 'password', 'openid', 'balance','mobile' + 'name', 'username', 'password', 'openid', 'balance', 'mobile' ]; /** @@ -111,11 +112,24 @@ class Customer extends Authenticatable implements JWTSubject public function patients() { - return $this->hasMany(Patient::class,"customer_id"); + return $this->hasMany(Patient::class, "customer_id"); } public function balances() { - return $this->hasMany(Balance::class,"customer_id"); + return $this->hasMany(Balance::class, "customer_id"); + } + + public function recharges() + { + return $this->hasMany(Recharge::class, "customer_id")->whereNotNull("paid_at"); + } + + public function getOnlineRefundableRecharge($amount) + { + //todo:根据交易状态是否可以退款、以及多次退款金额是否足够进行更精准筛选 + //but:出问题的几率微乎其微可以忽略 + $recharge = Recharge::where("customer", $this->id)->whereNotNull("paid_at")->doesntHave("refunds")->orderBy("id", "desc")->first(); + return $recharge; } } diff --git a/app/Http/Controllers/Manager/OrdersController.php b/app/Http/Controllers/Manager/OrdersController.php index 015c039..aad90b7 100644 --- a/app/Http/Controllers/Manager/OrdersController.php +++ b/app/Http/Controllers/Manager/OrdersController.php @@ -892,14 +892,14 @@ class OrdersController extends CommonController * @OA\POST( * path="/manager/checkout-order/{order_id}", * summary="V2-订单结算", - * description="交互流程如下:初次请求带上just_check参数,将返回to_recharge_total值;如果to_recharge_total大于0表示需要充值,充值完成之后,去除just_check参数再次提交;如果to_recharge_total <= 0,直接去除just_check参数再次提交", + * description="交互流程如下:初次请求带上just_check参数,将返回to_recharge_total或to_refund_total值;如果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="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="中途结算", + * description="订单结算", * content={ * @OA\MediaType( * mediaType="application/json", @@ -917,7 +917,7 @@ class OrdersController extends CommonController * @OA\Property( * property="prepay_total", * type="decimal", - * description="总计需要预扣的金额,入参just_check为1时just_check为0但是客户余额不足时返回" + * description="总计需要扣除的金额,入参just_check为1时just_check为0但是客户余额不足时返回" * ), * @OA\Property( * property="customer_balance", @@ -927,20 +927,43 @@ class OrdersController extends CommonController * @OA\Property( * property="to_recharge_total", * type="decimal", - * description="需要充值的金额,入参just_check为1时(此时to_recharge_total值如果大于0则需要充值)或just_check为0但是客户余额不足时(此时to_recharge_total值一定大于0)返回" + * description="需要充值的金额" + * ), + * @OA\Property( + * property="to_refund_total", + * type="decimal", + * description="需要退款的金额" * ), * @OA\Property( - * property="updated_items", + * property="refund_payment", + * type="string", + * description="退款方式" + * ), + * @OA\Property( + * property="refund_recharge_id", * type="integer", - * description="结算的子订单总数;仅在成功的情况下发送" + * description="在线退款原路返回对应的在线充值id" + * ), + * @OA\Property( + * property="refund_recharge_serial", + * type="integer", + * description="在线退款原路返回所对应的在线充值记录的支付平台交易编号" + * ), + * @OA\Property( + * property="checkout_order_id", + * type="integer", + * description="结算成功返回订单id;仅在成功的情况下发送" * ), * example={ - * "errorcode": "30003", - * "errormsg": "截止到中途结算日,没有需要结算的子订单,如需预充值请发起收款操作", - * "prepay_total": 1000, - * "customer_balance": 10, - * "to_recharge_total": 990, - * "checkout_items": 10 + * "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 * } * ) * ) @@ -989,35 +1012,53 @@ class OrdersController extends CommonController $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->customer->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 - ]); - } - - //没有需要操作的子订单,无意义 - if (!$unpaid_order_items->count() && !$to_generate_days) { - return response()->json([ - "errorcode" => 30001, - "errormsg" => "截止到中途结算日,没有需要结算的子订单,如需预充值请发起收款操作" + "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_serial" => $recharge_for_online_refund ? $recharge_for_online_refund->payment_serial : null ]); } - //需要预先充值 + //1、需要充值 if ($to_recharge_total > 0) { return response()->json([ - "errorcode" => 30002, + "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_serial" => $recharge_for_online_refund ? $recharge_for_online_refund->payment_serial : null + ]); + } + //3、账务平衡可结单 DB::beginTransaction(); try { for ($i = 0; $i < $to_generate_days; $i++) { @@ -1049,10 +1090,13 @@ class OrdersController extends CommonController } $order->customer->save(); + $order->update([ + "status" => Orders::STATUS_FINISHED + ]); DB::commit(); return response()->json([ - "checkout_items" => count($unpaid_order_items) + "checkout_order_id" => $order->id ]); } catch (\Exception $exception) { DB::rollBack(); @@ -1063,7 +1107,6 @@ class OrdersController extends CommonController } } - /** * @OA\POST( * path="/manager/scan-pay/{order_id}", @@ -1322,8 +1365,8 @@ class OrdersController extends CommonController * @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,online。注意可用的退款方式需要通过pre-chackout获取,随意提交金额可能会造成问题"), - * @OA\Parameter(name="recharge_id", in="query", @OA\Schema(type="integer"), required=false, description="相关在线支付的id,用于原路返回。退款方式为online时,必须给出"), + * @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", @@ -1336,7 +1379,6 @@ class OrdersController extends CommonController DB::beginTransaction(); try { $order = (new Orders())->find($id); - //创建退款记录 $refund = [ "customer_id" => $order->customer->id, @@ -1351,7 +1393,8 @@ class OrdersController extends CommonController $refund["payment"] = request()->payment; $refund["paid_at"] = date("Y-m-d H:i:s"); break; - case "online": + case "weixin": + case "alipay": $recharge = Recharge::find(request()->recharge_id); $refund["payment"] = $recharge->payment; $refund["recharge_id"] = request()->recharge_id;