diff --git a/application/admin/controller/school/activity/RefundRason.php b/application/admin/controller/school/activity/RefundRason.php new file mode 100644 index 0000000..ee59319 --- /dev/null +++ b/application/admin/controller/school/activity/RefundRason.php @@ -0,0 +1,37 @@ +model = new \app\admin\model\school\activity\RefundRason; + + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + +} diff --git a/application/admin/lang/zh-cn/school/activity/refund_rason.php b/application/admin/lang/zh-cn/school/activity/refund_rason.php new file mode 100644 index 0000000..99dbedc --- /dev/null +++ b/application/admin/lang/zh-cn/school/activity/refund_rason.php @@ -0,0 +1,10 @@ + '选项', + 'Refund_scale_json' => '额外参数', + 'Weigh' => '权重', + 'Createtime' => '创建时间', + 'Updatetime' => '修改时间', + 'Deletetime' => '删除时间' +]; diff --git a/application/admin/model/school/activity/RefundRason.php b/application/admin/model/school/activity/RefundRason.php new file mode 100644 index 0000000..5e331b1 --- /dev/null +++ b/application/admin/model/school/activity/RefundRason.php @@ -0,0 +1,50 @@ +getPk(); + $row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]); + } + }); + } + + + + + + + + + +} diff --git a/application/api/controller/school/NewActivity.php b/application/api/controller/school/NewActivity.php index 39d2bff..2b02ab1 100644 --- a/application/api/controller/school/NewActivity.php +++ b/application/api/controller/school/NewActivity.php @@ -127,7 +127,7 @@ class NewActivity extends Base $params["city"] = $this->request->get('city/s', ''); //机构店铺id $params["district"] = $this->request->get('district/s', ''); //机构店铺id - $params["status"] = $this->request->get('status/s', '-2'); //机构店铺id + $params["status"] = $this->request->get('status/s', ''); //机构店铺id $params["recommend"] = $this->request->get('recommend/s', ''); //机构店铺id $params["hot"] = $this->request->get('hot/s', ''); //机构店铺id $params["new"] = $this->request->get('new/s', ''); //机构店铺id diff --git a/application/api/controller/school/newactivity/Order.php b/application/api/controller/school/newactivity/Order.php index 28c805b..b67f7f7 100644 --- a/application/api/controller/school/newactivity/Order.php +++ b/application/api/controller/school/newactivity/Order.php @@ -226,7 +226,34 @@ class Order extends Base $order_no = $this->request->post('order_no/s', ''); //订单号 try{ //当前申请状态 - $res = $this->model->freeCancel($order_no,$user_id,true,'user',0,true); + $res = $this->model->freeCancel($order_no,$user_id,true,'user',$user_id,true); + }catch (\Throwable $e){ + $this->error($e->getMessage()); + } + $this->success('活动订单取消成功', $res); + } + + + + + + /** + * @ApiTitle(付费活动支付后取消接口) + * @ApiSummary(付费活动支付后取消接口(支付后,活动开始前)) + * @ApiMethod(POST) + * @ApiParams(name = "order_no", type = "string",required=true,description = "订单号") + * @ApiReturn({ + * + *}) + */ + public function paidcancel(){ + $user_id = 0; + $user = $this->auth->getUser();//登录用户 + if($user)$user_id = $user['id']; + $order_no = $this->request->post('order_no/s', ''); //订单号 + try{ + //当前申请状态 + $res = $this->model->paidCancel($order_no,$user_id,true,'user',$user_id,false,true); }catch (\Throwable $e){ $this->error($e->getMessage()); } diff --git a/application/api/controller/school/newactivity/Pay.php b/application/api/controller/school/newactivity/Pay.php index 6188efa..ab485f6 100644 --- a/application/api/controller/school/newactivity/Pay.php +++ b/application/api/controller/school/newactivity/Pay.php @@ -285,11 +285,14 @@ class Pay extends Base Log::write('notifyr-result:' . json_encode($data)); + $out_refund_no = $data['out_refund_no']; $out_trade_no = $data['out_trade_no']; + //获取退款金额 + $price = 0; // 退款 - $this->refundFinish($out_trade_no, $out_refund_no,$platform,$data); + $this->refundFinish($out_trade_no, $out_refund_no,$platform,$data,$price); return $pay->success()->send(); @@ -303,7 +306,7 @@ class Pay extends Base } - private function refundFinish($out_trade_no, $out_refund_no,$platform,$refund_json) { + private function refundFinish($out_trade_no, $out_refund_no,$platform,$refund_json,$price=0) { // $order = Order::where('order_sn', $out_trade_no)->find(); // $refundLog = \app\admin\model\shopro\order\RefundLog::where('refund_sn', $out_refund_no)->find(); @@ -318,7 +321,7 @@ class Pay extends Base // Db::transaction(function () use ($order, $item, $refundLog) { // \app\admin\model\shopro\order\Order::refundFinish($order, $item, $refundLog); // }); - $this->model::refundSuccess($out_refund_no,$refund_json,true); + $this->model::refundSuccess($out_refund_no,$refund_json,$price,true); return true; } diff --git a/application/common/hooks.php b/application/common/hooks.php index 9ad4367..d3f48a9 100644 --- a/application/common/hooks.php +++ b/application/common/hooks.php @@ -290,19 +290,24 @@ $newactivityOrderHooks = [ 'activity_order_cancel_after' => [ // 订单取消后 'app\\common\\listener\\activity\\OrderHook' ], + + + 'activity_order_auth_fail_after' => [ // 新活动订单售后退款发起 + 'app\\common\\listener\\activity\\OrderHook' + ], + + // 'classes_activity_order_auth_success_after' => [ // 订单审核通过后 // 'app\\common\\listener\\activityorder\\OrderHook' // ], -// 'classes_activity_order_auth_fail_after' => [ // 订单审核失败后 -// 'app\\common\\listener\\activityorder\\OrderHook' -// ], + // -// 'classes_activity_order_refund_success_after'=> [ // 订单审核失败后退款成功 -// 'app\\common\\listener\\activityorder\\OrderHook' -// ], -// 'classes_activity_order_refund_fail_after'=> [ // 订单审核失败后退款成功 -// 'app\\common\\listener\\activityorder\\OrderHook' -// ], + 'activity_order_refund_success_after'=> [ // 订单退款成功 + 'app\\common\\listener\\activity\\OrderHook' + ], + 'activity_order_refund_fail_after'=> [ // 订单售后退款失败 + 'app\\common\\listener\\activity\\OrderHook' + ], 'activity_order_finish_after' => [ // 订单完成后 'app\\common\\listener\\activity\\OrderHook' ], diff --git a/application/common/listener/activity/OrderHook.php b/application/common/listener/activity/OrderHook.php index 388bef9..e721160 100644 --- a/application/common/listener/activity/OrderHook.php +++ b/application/common/listener/activity/OrderHook.php @@ -298,5 +298,193 @@ class OrderHook + // 新活动订单售后退款发起 + public function activityOrderAuthFailAfter(&$params) + { + ['order' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id] = $params; + + + $order = Order::where("id" , $order["id"])->find(); + $detail = $order->detail; + $user = $order->user; + //记录订单日志 + $mini_type = "activity_order"; + $to_id = $order["user_id"]; + $status ="activity"; + $params=[ + "event"=>"activity_order_auth_fail_after", + "order_id"=>$order["id"], + "order_no"=>$order["order_no"], + "activity_id"=>$order["activity_id"], + ]; + $param = [ + "title"=>$detail["title"], + "order_no" => $order["order_no"], + "nickname" => $user["nickname"], + "realname" => $user["realname"], + "mobile" => $user["mobile"], + "price" => $order["totalprice"], + "payprice" => $order["payprice"], + "real_refundprice" => $order["real_refundprice"], + "sub_refundprice" => $order["sub_refundprice"], + "reason" => $order["reason"], + "address"=>$detail["address"]."(".$detail["address_detail"].")", + "start_time" => date("Y-m-d H:i",$detail["start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "end_time" => date("Y-m-d H:i",$detail["end_time"]), + "sign_start_time" => date("Y-m-d H:i",$detail["sign_start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "sign_end_time" => date("Y-m-d H:i",$detail["sign_end_time"]), + ]; + + //发用户 + (new MessageConfig) + ->setTemplate($params["event"]."_user") + ->setTemplateData($param) + ->setToUid($to_id) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + //发所有核销员 + (new MessageConfig) + ->setTemplate($params["event"]."_verification") + ->setTemplateData($param) + ->setToUid($detail["user_id"]) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + + } + + + + + + + + // 订单退款成功 + public function activityOrderRefundSuccessAfter(&$params) + { + ["order"=>$order] = $params; + + $order = Order::where("id" , $order["id"])->find(); + + $detail = $order->detail; + $user = $order->user; + //记录订单日志 + $mini_type = "activity_order"; + $to_id = $order["user_id"]; + $status ="activity"; + $params=[ + "event"=>"activity_order_refund_success_after", + "order_id"=>$order["id"], + "order_no"=>$order["order_no"], + "activity_id"=>$order["activity_id"], + ]; + $param = [ + "title"=>$detail["title"], + "order_no" => $order["order_no"], + "nickname" => $user["nickname"], + "realname" => $user["realname"], + "mobile" => $user["mobile"], + "price" => $order["totalprice"], + "payprice" => $order["payprice"], + "real_refundprice" => $order["real_refundprice"], + "sub_refundprice" => $order["sub_refundprice"], + "reason" => $order["reason"], + "address"=>$detail["address"]."(".$detail["address_detail"].")", + "start_time" => date("Y-m-d H:i",$detail["start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "end_time" => date("Y-m-d H:i",$detail["end_time"]), + "sign_start_time" => date("Y-m-d H:i",$detail["sign_start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "sign_end_time" => date("Y-m-d H:i",$detail["sign_end_time"]), + ]; + + (new MessageConfig) + ->setTemplate($params["event"]) + ->setTemplateData($param) + ->setToUid($to_id) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + + + } + + + + + + // 订单支付成功后 + public function activityOrderRefundFailAfter(&$params) + { + ["order"=>$order] = $params; + + $order = Order::where("id" , $order["id"])->find(); + $detail = $order->detail; + $user = $order->user; + + //记录订单日志 + $mini_type = "activity_order"; + $to_id = $order["user_id"]; + $status ="activity"; + $params=[ + "event"=>"activity_order_refund_fail_after", + "order_id"=>$order["id"], + "order_no"=>$order["order_no"], + "activity_id"=>$order["activity_id"], + ]; + $param = [ + "title"=>$detail["title"], + "order_no" => $order["order_no"], + "nickname" => $user["nickname"], + "realname" => $user["realname"], + "mobile" => $user["mobile"], + "price" => $order["totalprice"], + "payprice" => $order["payprice"], + "real_refundprice" => $order["real_refundprice"], + "sub_refundprice" => $order["sub_refundprice"], + "reason" => $order["reason"], + "address"=>$detail["address"]."(".$detail["address_detail"].")", + "start_time" => date("Y-m-d H:i",$detail["start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "end_time" => date("Y-m-d H:i",$detail["end_time"]), + "sign_start_time" => date("Y-m-d H:i",$detail["sign_start_time"]), //格式化日期格式 $order["start_time"], //格式化日期格式 + "sign_end_time" => date("Y-m-d H:i",$detail["sign_end_time"]), + ]; + + //发用户 + (new MessageConfig) + ->setTemplate($params["event"]."_user") + ->setTemplateData($param) + ->setToUid($to_id) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + //发所有核销员 + + (new MessageConfig) + ->setTemplate($params["event"]."_verification") + ->setTemplateData($param) + ->setToUid($detail["user_id"]) + ->setMessageStatus($status) + ->setMessageMiniType($mini_type) + ->setMessageParams($params) + ->sendMessage(); + + + + } + + + + + + + + + + + } \ No newline at end of file diff --git a/application/common/model/school/activity/Activity.php b/application/common/model/school/activity/Activity.php index 1f912c6..595f0b4 100644 --- a/application/common/model/school/activity/Activity.php +++ b/application/common/model/school/activity/Activity.php @@ -493,6 +493,12 @@ class Activity extends BaseModel if(!$refund){ throw new \Exception("退款策略不存在"); } + $paid_activity_min_price = config("site.paid_activity_min_price"); + if($params["price"]<$paid_activity_min_price){ + throw new \Exception("活动售价不能低于".$paid_activity_min_price."元"); + } + + } if($params["price"]<0)$params["price"]=0; @@ -724,6 +730,9 @@ class Activity extends BaseModel if (isset($my) && $my && isset($my_user_id) && $my_user_id) { $selfetch = $selfetch->where("{$a}user_id", 'in', ''.$my_user_id); } + if($my ==1 && empty($my_user_id)){ + $selfetch = $selfetch->where("{$a}user_id", 'in', [-3]); + } @@ -1212,7 +1221,7 @@ class Activity extends BaseModel if($trans){ self::rollbackTrans(); } - throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + throw new \Exception($e->getMessage()); } return $row; } @@ -1298,7 +1307,7 @@ class Activity extends BaseModel $row = self::where("id",$id)->where("status","in",["1","2","3","4"])->find(); - if(!$row) throw new \Exception("活动不取消或已结束"); + if(!$row) throw new \Exception("活动已取消或已结束"); if($check) { if($oper_type=='user' && $row["user_id"] != $oper_id) throw new \Exception("您无权取消该活动"); @@ -1322,7 +1331,7 @@ class Activity extends BaseModel \think\Hook::listen('new_activity_cancel_success_after', $data); //自动退款检测:如果有订单,则自动取消 - //...待实现 + $this->orderAllCancel($id); if($trans){ self::commitTrans(); @@ -1337,6 +1346,47 @@ class Activity extends BaseModel } + + public function orderAllCancel($activity_id,$trans=false){ +//判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + //查询待支付订单,执行订单取消 + $orders = Order::where("activity_id",$activity_id)->where("status","in",['0'])->select(); + foreach ($orders as $order){ + (new Order)->freeCancel($order['id'],0,false,'admin',0); + } + //查询所有免费订单,执行取消 + $orders = Order::where("activity_id",$activity_id)->where("payprice",0)->where("status","in",['0','2','3',"9"])->select(); + foreach ($orders as $order){ + (new Order)->freeCancel($order['id'],0,false,'admin',0); + } + //查询所有付费订单,执行退款取消 + $orders = Order::where("activity_id",$activity_id)->where("payprice",">",0)->where("status","in",["2","3","9"])->select(); + foreach ($orders as $order){ + (new Order)->paidCancel($order['id'],0,false,'admin',0,true); + } + //处于售后中的直接售后同意按全款退? + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $res; + } + + + + public function getActivityAuthIds($user_id,$vaild=false) { diff --git a/application/common/model/school/activity/order/Order.php b/application/common/model/school/activity/order/Order.php index e18ff4f..05c0cff 100644 --- a/application/common/model/school/activity/order/Order.php +++ b/application/common/model/school/activity/order/Order.php @@ -13,6 +13,8 @@ use think\Cache; use think\Model; use traits\model\SoftDelete; +use Yansongda\Pay\Pay; + class Order extends BaseModel { @@ -622,7 +624,9 @@ class Order extends BaseModel $order_data["settle_log_time"] = $activity_info["settlement_time"]; //根据手续费比例$activity_info["fee_scale"] 计算手续费 $order_data["fee_price"] = bcmul($order_data["totalprice"],$order_data["fee_scale"],2); - + //手续费保底不能低于site.activity_settle_min_fee + $min_fee = config("site.activity_settle_min_fee"); + $order_data["fee_price"] = $order_data["fee_price"] < $min_fee ? $min_fee : $order_data["fee_price"]; return compact('order_data','activity_info','user_data',"num"); } @@ -709,7 +713,7 @@ class Order extends BaseModel self::paySetData($order,$notify); //释放结算订单 - (new SettleLog)->generatorLog($order['id']); +// (new SettleLog)->generatorLog($order['id']); // //如果需要快捷预约 // $classes_lib_spec_id = $order['classes_lib_spec_id']; @@ -1211,7 +1215,7 @@ class Order extends BaseModel //释放结算订单 - (new SettleLog)->generatorLog($order['id']); +// (new SettleLog)->generatorLog($order['id']); //调用支付成功事件 $data = ['order' => $order]; @@ -1232,7 +1236,7 @@ class Order extends BaseModel * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ - public static function getHaveCancelFreeOrder($order_no){ + public static function getHaveCancelFreeOrder($order_no,$check=false){ // $where = [self::STATUS_NOPAY,self::STATUS_PAYED]; $order = self::where('order_no|id|pay_no',$order_no)->find(); $detail = $order->detail; @@ -1245,11 +1249,12 @@ class Order extends BaseModel throw new \Exception("只有未支付的单才可以取消!"); } }else{ - if(!in_array($order['status'],['0','2'])){ + + if($check && !in_array($order['status'],['0','2'])){ throw new \Exception("免费单只有进行中订单可取消,已取消请忽重复取消!"); } } - + if(!$check) return $order; //活动开始后不可取消 $time = time(); if ($detail['start_time'] < $time) throw new \Exception("活动开始后不可取消!"); @@ -1265,8 +1270,8 @@ class Order extends BaseModel * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ - public static function updateFreeCancel($order){ - if(is_string($order))$order = self::getHaveCancelFreeOrder($order); + public static function updateFreeCancel($order,$check=false){ + if(is_string($order))$order = self::getHaveCancelFreeOrder($order,$check); $order->status = "-3";//refund_status $order->canceltime = time(); $order->save(); @@ -1283,7 +1288,7 @@ class Order extends BaseModel */ public function freeCancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){ //得到可取消订单 - $order = self::getHaveCancelFreeOrder($order_no); + $order = self::getHaveCancelFreeOrder($order_no,$check); if($check){ //用户操作权限检测 self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type); @@ -1300,7 +1305,7 @@ class Order extends BaseModel //事务逻辑 //更新订单取消状态 - $order = self::updateFreeCancel($order); + $order = self::updateFreeCancel($order,$check); //插入订单取消日志 if(!$user_id ||$order["user_id"] !=$user_id ){ OrderLog::log($order['id'],"[系统操作]活动订单取消成功",$oper_type ?: 'user', $oper_id ?: $order['user_id']); @@ -1354,7 +1359,7 @@ class Order extends BaseModel foreach ($list as $order) { //取消订单 - self::freeCancel($order['id'],0,false,'admin',0); + (new self)->freeCancel($order['id'],0,false,'admin',0); $count++; } if ($trans) { @@ -1382,7 +1387,7 @@ class Order extends BaseModel * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ - public static function getHaveCancelPaidOrder($order_no){ + public static function getHaveCancelPaidOrder($order_no,$check=true){ // $where = [self::STATUS_NOPAY,self::STATUS_PAYED]; $order = self::where('order_no|id|pay_no',$order_no)->find(); $detail = $order->detail; @@ -1391,12 +1396,14 @@ class Order extends BaseModel //非免费单进行中无法取消 if($order['totalprice'] != 0){ //非免费单只有未退款可退 - if(!in_array($order['status'],["2","3"])){ + if(!in_array($order['status'],["2","3","9"])){ throw new \Exception("只有已报名和核销中的单才可以取消!"); } }else{ throw new \Exception("免费单请走免费订单取消接口!"); } + + if($check){ //根据不同退款策略判断当前时间点是否可取消并退款 $refund_status = $detail["refund_status"]; //活动开始后不可取消,只能走售后 @@ -1414,30 +1421,78 @@ class Order extends BaseModel throw new \Exception("不支持的退款策略,请走售后流程!"); } - - + } return $order; } - /**更新免费订单取消状态以及未支付取消 + /**更新付费订单取消状态 * @param $order * @return array|false|\PDOStatement|string|Model * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ - public static function updatePaidCancel($order){ - if(is_string($order))$order = self::getHaveCancelFreeOrder($order); + public static function updatePaidCancel($order,$check=true){ + if(is_string($order))$order = self::getHaveCancelPaidOrder($order,$check); $order->status = "-3";//refund_status $order->canceltime = time(); $order->save(); + + //将所有资金结算记录作废 + $data = [ + "status" =>"-1", + "canceltime" => time(), + ]; + SettleLog::where("activity_order_id",$order["id"])->where("status","in",['1','2'])->update($data); + + return $order; + } + + + /**得到可审核订单 + * @param $order_no + * @return array|false|\PDOStatement|string|Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getHaveExamineOrder($order_no){ +// $where = [self::STATUS_NOPAY,self::STATUS_PAYED]; + $order = self::where('order_no|id|pay_no',$order_no)->where("status","in",["-3",'4'])->find(); + if(!$order)throw new \Exception("不是待审核的订单!"); + + return $order; + } + + + + /**更新订单结算中状态 + * @param $order + * @return array|false|\PDOStatement|string|Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function updateExamineFailSettlement($order,$reason="",$oper_id = 0,$oper_type='user'){ + if(is_string($order))$order = self::getHaveExamineOrder($order); + $order->before_status = $order->status; + $order->status = "5"; + $order->auth_status = "1"; + $order->server_status = "6"; + $order->auth_time = time(); + $order->refundsendtime = time(); + $order->reason = $reason; + $order->auth_user_id = $oper_id; + $order->auth_type = $oper_type; + $order->save(); return $order; } - /**免费订单取消以及未支付取消 + + /**付费订单取消 * @param $order_no * @param int $user_id * @param bool $check @@ -1445,9 +1500,9 @@ class Order extends BaseModel * @return bool * @throws \Exception */ - public function paidCancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){ + public function paidCancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$activity_cancel=false,$trans=false){ //得到可取消订单 - $order = self::getHaveCancelFreeOrder($order_no); + $order = self::getHaveCancelPaidOrder($order_no,$check); if($check){ //用户操作权限检测 self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type); @@ -1464,12 +1519,12 @@ class Order extends BaseModel //事务逻辑 //更新订单取消状态 - $order = self::updateFreeCancel($order); + $order = self::updatePaidCancel($order,$check); //插入订单取消日志 if(!$user_id ||$order["user_id"] !=$user_id ){ - OrderLog::log($order['id'],"[系统操作]活动订单取消成功",$oper_type ?: 'user', $oper_id ?: $order['user_id']); + OrderLog::log($order['id'],"[系统操作]活动订单取消成功,款项在一个工作日内将自动退还",$oper_type ?: 'user', $oper_id ?: $order['user_id']); }else{ - OrderLog::log($order['id'],"活动订单取消成功",$oper_type ?: 'user', $oper_id ?: $order['user_id']); + OrderLog::log($order['id'],"活动订单取消成功,款项在一个工作日内将自动退还",$oper_type ?: 'user', $oper_id ?: $order['user_id']); } //调用订单取消事件 @@ -1478,6 +1533,23 @@ class Order extends BaseModel //执行课时数更新 $res1 = self::statisticsAndUpdateClassesNumber($order['id']); + //执行退款 + //调用退款发起 + //更新订单状态 + $reason = "活动取消自动退款"; + $order = self::updateExamineFailSettlement($order['order_no'],"",$user_id ?: $oper_id,$oper_type); + + //审核失败逻辑 + OrderLog::log($order['id'],"活动取消退款,原因;{$reason},如有退款额度,该活动单将自动退款以便重新下单(没有请忽略)",$oper_type ?: 'user', $oper_id ?: $order['user_id']); + //调用订单事件 + $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id]; + \think\Hook::listen('activity_order_auth_fail_after', $data); + //计算自动退款额度 + $refundprice = $this->countRefundAmount($order["id"],$activity_cancel); + if($refundprice>0){ + //执行退款 + self::orderRefund($order['order_no'],$refundprice,$oper_type,$oper_id); + } if($trans){ self::commitTrans(); @@ -1492,6 +1564,382 @@ class Order extends BaseModel } + /** 如果是自动退款,根据退款策略计算应退款额 + * @param $order_id + * @param $trans + * @return true + * @throws \Exception + */ + public function countRefundAmount($order_id,$activity_cancel=false,$trans=false){ + $price = 0; + $order = self::where('id',$order_id)->find(); + if(!$order) return $price; + $detail = $order->detail; + if(!$detail) return $price; + // +//判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + + //根据不同退款策略判断当前时间点是否可取消并退款 + $refund_status = $detail["refund_status"]; + //活动开始后不可取消,只能走售后 + $time = time(); + + if($activity_cancel){ + //活动取消退全款 + $price = $order["sub_refundprice"]; + + }else{ + + switch ($refund_status){ + case "1": //不退款 + + throw new \Exception("当前活动不支持取消退款,请走售后流程!"); + break; + case "3": //开始前退 + case "5": //随时退 退全款 + $price = $order["sub_refundprice"]; + break; + default: + throw new \Exception("不支持的退款策略,请走售后流程!"); + + } + + } + + + + + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $price; + } + + + /**得到可直接退款订单(正常取消退全款非售后) + * @param $order_no + * @return array|false|\PDOStatement|string|Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getHaveRefundOrder($refund_sn){ +// $where = [self::STATUS_NOPAY,self::STATUS_PAYED]; + $order = self::where('refund_no|order_no|id',$refund_sn)->where('status','5')->where("sub_refundprice",">",0)->find(); + if(!$order)throw new \Exception("不是可直接退款的订单!"); + + return $order; + } + + + + + + /**预约订单退款(退全款) + * @param $order + * @param $refund_money + * @param $trans + */ + public static function orderRefund($order,$refund_money,$oper_type='user',$oper_id=0,$trans=false,$admin=false){ + if(is_numeric($order))$order = self::getHaveRefundOrder($order); + if(!$order)throw new \Exception("找不到订单"); + //判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + //生成退款单号 + if(!$order['refund_no']){ + $order['refund_no'] = get_order_sn(); +// $order->save(); + } + if(!$refund_money)$refund_money = $order['sub_refundprice']; + if($refund_money<=0)$refund_money = 0; + if(!$refund_money)throw new \Exception("退款金额异常!"); + + //保存应退款额 + $order->total_refundprice = $refund_money; + $order->save(); + + + //事务逻辑 + switch ($order['pay_type']) { + case "wechat": //微信退款 + + self::wechatRefund($order,$refund_money,$oper_type,$oper_id); + break; +// case "alipay": //支付宝退款 +// self::alipayRefund($order,$refund_money,$oper_type,$oper_id); +// break; +// case "wallet": //钱包支付退款 +// self::walletRefund($order,$refund_money,$oper_type,$oper_id); +// break; +// case "offline": //线下支付退款 +// +// break; + default: + throw new \Exception("订单币种异常!"); + } + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $res; + } + + + + + /**微信退款 + * @param $order + * @param $refund_money + */ + public static function wechatRefund($order,$refund_money,$refund_desc="",$oper_type='user',$oper_id=0,$trans=false){ + //判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + //事务逻辑 + //创建订单退款订单 + + + $classesorder = $order; + $detail = $order->detail; + + + + //执行微信退款sdk + $order_data = [ + 'out_trade_no' => $classesorder->order_no + ]; + $total_fee = $classesorder->payprice * 100; + $refund_fee = $refund_money * 100; + + $order_data = array_merge($order_data, [ + 'out_refund_no' => $order->refund_no, + 'total_fee' => $total_fee, + 'refund_fee' => $refund_fee, + 'refund_desc' => $refund_desc ?: "活动[{$detail["title"]}]订单[ID:{$classesorder['id']}]退款{$refund_money}已到账户", + ]); + + $config = Service::getConfig('wechat',[],$classesorder->platform); + + + + $notify_url = request()->domain() . '/api/school.newactivity.pay/notifyr/payment/' . $classesorder->pay_type . '/platform/' . $classesorder->platform; + + $config['notify_url'] = $notify_url; + $pay = Pay::wechat($config); + +// throw new \Exception($trans."111测试错误!".$order["status"]); + $result = $pay->refund($order_data); + + \think\Log::write('refund-result' . json_encode($result)); + + + if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') { + $res = true; + } else { + throw new \Exception($result['return_msg']); + } + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $res; + } + + /**同意并发放退款金额 + * @param $order 退款单号 + * @return array|false|\PDOStatement|string|Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function updateRefundOrder($order,$price=0,$pay_json=[]){ + if(is_string($order))$order = self::getHaveRefundOrder($order); +// //如果$price为0,尝试从$pay_json退款回调中获取退款金额 +// if(!$price && $pay_json){ +// if(isset($pay_json['refund_fee']))$price = bcdiv($pay_json['refund_fee'],100,2); +// } + + + +// $order->before_status = $order->status;//refund_status + $order->status = "6"; + $order->server_status = "6"; + $order->real_refundprice = bcadd($order->real_refundprice ?:'0', $price?:$order->total_refundprice ,2); + $order->sub_refundprice = bcsub($order->sub_refundprice ?:'0', $price?:$order->total_refundprice ,2); + $order->refundtime = time(); + $order->refund_json = json_encode($pay_json); + $order->save(); + return $order; + } + + + /**退款成功处理逻辑(需修改) + * @param $refund_sn + * @param bool $trans + * @return bool + * @throws \Exception + */ + public static function refundSuccess($refund_sn,$refund_json=[],$price=0,$trans=false){ + //得到机构售后提交确认订单 + $order = self::getHaveRefundOrder($refund_sn); + + //判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + //事务逻辑 + + //更新订单状态为同意 + $order = self::updateRefundOrder($refund_sn,$price,$refund_json); + + //插入订单日志 + OrderLog::log($order['id'],"活动订单退款已原路退回", 'admin', 0); + + //执行课时数更新 + $res1 = self::statisticsAndUpdateClassesNumber($order['id']); + + //调用订单取消事件 + $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$order['user_id'],"oper_type"=>'admin',"oper_id"=>0]; + \think\Hook::listen('activity_order_refund_success_after', $data); + + + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $res; + + } + + + + + /**订单退款失败记录 + * @param $order + * @param $refund_money + * @param $trans + */ + public static function orderRefundFail($order,$msg,$oper_type='user',$oper_id=0,$trans=false,$admin=false){ + if(is_numeric($order))$order = self::getOrder($order); + if(!$order)throw new \Exception("找不到订单"); + //判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + //事务逻辑 + $order->refund_error = $msg; + $order->save(); + //插入订单日志 + OrderLog::log($order['id'],"活动订单退款失败:".$msg, $oper_type, $oper_id); + + //调用订单取消事件 + $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$order['user_id'],"oper_type"=>$oper_type,"oper_id"=>$oper_id]; + \think\Hook::listen('activity_order_refund_fail_after', $data); + + if($trans){ + self::commitTrans(); + } + }catch (\Throwable $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $res; + } + + + + + /**得到可直接退款订单(正常取消退全款非售后) + * @param $order_no + * @return array|false|\PDOStatement|string|Model + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\ModelNotFoundException + * @throws \think\exception\DbException + */ + public static function getHaveAfterSalesOrder($refund_sn){ +// $where = [self::STATUS_NOPAY,self::STATUS_PAYED]; + $order = self::where('refund_no|order_no|id',$refund_sn)->where('status','5')->where("sub_refundprice",">",0)->find(); + if(!$order)throw new \Exception("不是可直接退款的订单!"); + + return $order; + } + + + /** 发起售后 + * @param $order_no + * @param $trans + * @return true + * @throws \Exception + */ + public function afterSales($order,$trans=false){ + if(is_numeric($order))$order = self::getHaveAfterSalesOrder($order); + if(!$order)throw new \Exception("找不到订单"); + // + +//判断逻辑 + if($trans){ + self::beginTrans(); + } + $res = true; + try{ + + if($trans){ + self::commitTrans(); + } + }catch (\Exception $e){ + if($trans){ + self::rollbackTrans(); + } + throw new \Exception($e->getMessage().$e->getFile().$e->getLine()); + } + return $res; + } + diff --git a/application/common/model/school/activity/order/SettleLog.php b/application/common/model/school/activity/order/SettleLog.php index 5f82027..7a296bb 100644 --- a/application/common/model/school/activity/order/SettleLog.php +++ b/application/common/model/school/activity/order/SettleLog.php @@ -3,6 +3,7 @@ namespace app\common\model\school\activity\order; use app\common\model\BaseModel; +use app\common\model\school\activity\Activity; use app\common\model\user\withdrawal\UserwithdrawalLog; use think\Model; use traits\model\SoftDelete; @@ -109,6 +110,93 @@ class SettleLog extends BaseModel } + + + /** + * 检测订单结算 + */ + public static function timeoutSettleActivityCheck($activity_id,$trans = false){ + $count = 0; + if ($trans) { + self::beginTrans(); + } + try { + + $orders = Order::where("payprice",">",0) //支付单 + ->where("pay_type",'wechat') //微信支付 + ->where("sub_refundprice",">",0) //剩余未退大于0 + ->where("activity_id",$activity_id) //当前活动 + ->where("status","in",["-3","9","6"]) + ->select(); + foreach ($orders as $order){ + //剩余金额大于手续费的订单,并且未插入此结算单的 + $sub_refundprice = bcsub($order["sub_refundprice"],$order["fee_price"]); + if($sub_refundprice > 0){ + $log = self::where("activity_order_id",$order["id"])->where("status","not in",["-1"])->find(); + if(!$log){ + (new self)->generatorLog($order["id"]); + } + } + + } + + + if ($trans) { + self::commitTrans(); + } + } catch (\Exception $e) { + if ($trans) { + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $count; + } + + + + + /** + * 检测订单结算 + */ + public function timeoutSettleCheck($trans = false){ + $count = 0; + + if ($trans) { + self::beginTrans(); + } + try { + //查询更新所有活动状态 + Activity::timeoutCheck(); + //延后时间(秒) + $delay = config("site.activity_end_settle") ?: 0; + $time = time(); + //查询处于可结算状态的订单(活动结束时间戳 , 延后时间 =超时可以结算的活动) + $time = $time - $delay; + $activityList = Activity::where("status",'5')->where("end_time",'<',$time)->select(); + foreach ($activityList as $activity){ + //对活动订单进行结算记录插入 + $this->timeoutSettleActivityCheck($activity["id"]); + } + + + //检测更新所有结算订状态 + SettleLog::timeoutCheck(null,null); + if ($trans) { + self::commitTrans(); + } + } catch (\Exception $e) { + if ($trans) { + self::rollbackTrans(); + } + throw new \Exception($e->getMessage()); + } + return $count; + } + + + + /** 生成结算记录 * @param $order_id * @param $trans