DiverseYouthNightSchool/application/common/model/school/classes/order/ServiceOrder.php

1504 lines
52 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\common\model\school\classes\order;
use addons\epay\library\Service;
use app\admin\model\Admin;
use app\common\model\BaseModel;
use app\common\model\dyqc\ManystoreShop;
use app\common\model\manystore\Shop;
use app\common\model\ManystoreConfig;
use app\common\model\school\classes\ClassesLib;
use app\common\model\User;
use app\manystore\model\Manystore;
use think\Model;
use traits\model\SoftDelete;
use think\Session;
use Yansongda\Pay\Exceptions\GatewayException;
use Yansongda\Pay\Pay;
class ServiceOrder extends BaseModel
{
use SoftDelete;
// 表名
protected $name = 'school_classes_service_order';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = 'deletetime';
// 追加属性
protected $append = [
'status_text',
'service_stauts_text',
'sales_type_text',
'platform_text',
'pay_type_text',
'refundtime_text',
'rejecttime_text',
'handletime_text',
'confirmtime_text',
'checkouttime_text'
];
public function getStatusList()
{
return ['1' => __('Status 1'), '4' => __('Status 4'), '7' => __('Status 7'), '-3' => __('Status -3')];
}
public function getServiceStautsList()
{
return ['1' => __('Service_stauts 1'), '4' => __('Service_stauts 4'), '7' => __('Service_stauts 7'),'10' => __('Service_stauts 10'), '-3' => __('Service_stauts -3')];
}
public function getSalesTypeList()
{
return ['-3' => __('Sales_type -3'), '1' => __('Sales_type 1'), '4' => __('Sales_type 4'), '7' => __('Sales_type 7'), '10' => __('Sales_type 10')];
}
public function getPlatformList()
{
return ['miniapp' => __('Platform miniapp')];
}
public function getPayTypeList()
{
return ['yue' => __('Pay_type yue'), 'wechat' => __('Pay_type wechat')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getServiceStautsTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['service_stauts']) ? $data['service_stauts'] : '');
$list = $this->getServiceStautsList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getSalesTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['sales_type']) ? $data['sales_type'] : '');
$list = $this->getSalesTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getPlatformTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['platform']) ? $data['platform'] : '');
$list = $this->getPlatformList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getPayTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['pay_type']) ? $data['pay_type'] : '');
$list = $this->getPayTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getRefundtimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['refundtime']) ? $data['refundtime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getRejecttimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['rejecttime']) ? $data['rejecttime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getHandletimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['handletime']) ? $data['handletime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getConfirmtimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['confirmtime']) ? $data['confirmtime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getCheckouttimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['checkouttime']) ? $data['checkouttime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
protected function setRefundtimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setRejecttimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setHandletimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setConfirmtimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setCheckouttimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
public function getRejectImagesAttr($value, $data)
{
$imagesArray = [];
if (!empty($value)) {
$imagesArray = explode(',', $value);
foreach ($imagesArray as &$v) {
$v = cdnurl($v, true);
}
return $imagesArray;
}
return $imagesArray;
}
public function classesorder()
{
return $this->belongsTo(Order::class, 'classes_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function user()
{
return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function detail()
{
return $this->belongsTo(OrderDetail::class, 'classes_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function lib()
{
return $this->belongsTo(ClassesLib::class, 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function manystore()
{
return $this->belongsTo(Manystore::class, 'manystore_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function shop()
{
return $this->belongsTo(ManystoreShop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
/**发起售后
* @param $params
* @param bool $trans
* @throws \Exception
*/
public function afterSales($classes_order,$reason,$mark='更新订单状态',$oper_type='user',$oper_id = 0,$trans=false){
// var_dump($order);
if(is_numeric($classes_order)||is_string($classes_order))$classes_order = Order::where('order_no|id',$classes_order)->find();
if(!$classes_order)throw new \Exception("找不到订单");
//操作人信息(可扩展)
$data = [
'oper_type'=>$oper_type ?: 'user',
'oper_id'=>$oper_id ?: $classes_order['user_id'],
'log_text'=>$mark,
];
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
$order = $this->createOrder($classes_order,$reason,$mark,$oper_type,$oper_id);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $order;
}
public static function getCost($order_no,$classes_order,$reason,$param=[],$check = false){
if(is_numeric($classes_order)||is_string($classes_order))$classes_order = Order::where('order_no|id',$classes_order)->find();
//先更新订单为最新订单
Order::statisticsAndUpdateClassesNumber($classes_order->id);
//代下单时将下单人修正成课程下单人,不影响后续判断
$user_id = $classes_order["user_id"];
if(isset($param["help_user_id"]) && $param["help_user_id"]){
}
//校验订单参数
$detail = $classes_order->detail;
$classes_lib_info = $detail;
//用户
$user_info = User::get($user_id);
$user_data = [
"nickname"=>$user_info["nickname"],
"realname"=>$user_info["realname"],
"avatar"=>$user_info["avatar"],
"mobile"=>$user_info["mobile"],
"money" =>$user_info["money"],
"score" =>$user_info["score"],
];
//组装订单下单数据
$order_data = [];
$order_data["order_no"] = $order_no;
$order_data["user_id"] = $user_id;
$order_data["classes_order_id"] = $classes_order["id"];
$order_data["classes_order_detail_id"] = $detail["id"];
$order_data["classes_lib_id"] = $detail["classes_lib_id"];
$order_data["manystore_id"] = $detail["manystore_id"];
$order_data["shop_id"] = $detail["shop_id"];
$order_data["status"] = '1';
$order_data["service_stauts"] = '1';
$order_data["sales_type"] = '-3';
$order_data["platform"] = $classes_order["platform"];
$order_data["pay_type"] = $classes_order["pay_type"];
$order_data["reason"] = $reason;
//计算退款金额
//得到租户端配置
$manystore_config = ManystoreConfig::manystore_config($detail["shop_id"]);
$loss_ratio = $manystore_config["loss_ratio"];
//修正比例大于100则等于100小于0则等于0
$loss_ratio = $loss_ratio > 100 ? 100 : $loss_ratio;
$loss_ratio = $loss_ratio < 0 ? 0 : $loss_ratio;
$order_data["loss_proportion"] = $loss_ratio;
//自动计算应退全额:
// (课程单价 减去 (课程单价乘以课程损耗比) )等于 每个课时应退金额
//损耗单价
$unit_loss_price = bcdiv(bcmul($detail["unit_price"],$loss_ratio,2), 100,2);
//修复误差小于0
$unit_loss_price = $unit_loss_price < 0 ? 0 : $unit_loss_price;
//损耗后单价
$unit_sub_loss_price = bcsub($detail["unit_price"],$unit_loss_price,2);
//修复误差小于0
$unit_sub_loss_price = $unit_sub_loss_price < 0 ? 0 : $unit_sub_loss_price;
//剩余课时数
$sub_num = $detail["sub_num"];
//用bc系列函数计算小数取两位 剩余课时数 * 每个课时应退金额 = 课程应退金额
$order_data["auto_recommend_price"] = bcmul($sub_num,$unit_sub_loss_price,2);
//修复误差:如果金额大于剩余未退金额,则取剩余未退金额
$order_data["auto_recommend_price"] = $order_data["auto_recommend_price"] > $classes_order["sub_refundprice"] ? $classes_order["sub_refundprice"] : $order_data["auto_recommend_price"];
//用bc系列函数计算小数取两位剩余课时数 * 每个课时单价 = 课程应退全额
$order_data["auto_price"] = bcmul($sub_num,$detail["unit_price"],2);
//修复误差:如果金额大于剩余未退金额,则取剩余未退金额
$order_data["auto_price"] = $order_data["auto_price"] > $classes_order["sub_refundprice"] ? $classes_order["sub_refundprice"] : $order_data["auto_price"];
//用bc系列函数计算小数取两位课程单价乘以课程损耗比* 剩余课时数 等于 每个课时应退金额
$order_data["auto_loss_price"] = bcmul($sub_num,$unit_loss_price,2);
$order_data["auto_loss_unit_price"] = $unit_loss_price;
$order_data["sub_refundprice"] = $classes_order["sub_refundprice"];
$classes_order_data = [
'before_status'=>$classes_order["status"],
'status' => "4",
'server_status' => '3',
'reason' => $reason,
'classes_service_order_id'=>0,
];
return compact('order_data','classes_lib_info','user_data','classes_order_data');
}
public function createOrder($classes_order,$reason,$mark='更新订单状态',$oper_type='user',$oper_id = 0){
if(is_numeric($classes_order)||is_string($classes_order))$classes_order = Order::where('order_no|id',$classes_order)->find();
$order_no = get_order_sn();
$this->orderVaild($order_no,$classes_order,$reason,$oper_type,$oper_id,[],true);
//订单创建信息
$order_info = self::getCost($order_no,$classes_order,$reason,[],true);
//组装订单数据
$order_data = $order_info["order_data"];
$classes_order_data = $order_info["classes_order_data"];
//创建售后单
$serverorder = self::create($order_data);
$classes_order_data["classes_service_order_id"] = $serverorder["id"];
//更新课程订单
$classes_order->allowField(true)->save($classes_order_data);
//记录订单日志
ServiceOrderLog::log($serverorder['id'],$mark ?:"售后单申请已提交,等待商家处理",$oper_type,$oper_id);
//7事件
$data = ['serviceorder' => $serverorder,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_create_after', $data);
return self::showInfo($order_no);
}
/**展示订单信息
* @param $order_no
* @param $price_info
* @return array
*/
public static function showInfo($order_no, $price_info = []){
$data = [];
$data['order_no'] =$order_no;
$data['order_info'] = self::getDetail($order_no);
return array_merge($data,$price_info);
}
/**得到订单详情
* @param $order_no
*/
public static function getDetail($order_no,$classes_lib_id = []){
$model = self::where('order_no|id',$order_no);
if($classes_lib_id)$model = $model->where("classes_lib_id","in",$classes_lib_id);
$data = $model->find();
if(!$data) return $data;
//加载订单详情
$data->detail->teacher;
//订单用户
// $data->user;
$data->user->visible(['id','nickname','mobile','avatar','realname']);
//订单机构
$data->shop;
// //得到二维码
// $data->code_url = Common::getQrcode([
// 'text' => $data['code'],
// 'size' => 200,
// ]);
// $data->one_code_url = Common::getBarcode([
// 'text' => $data['code'],
// 'size' => 200,
// ]);
return $data;
}
/**订单校验
* @param $user_id 用户id
* @param $classes_lib_id 课程id
* @param $order_no 订单号
* @param $param 表单扩展参数
* @return bool
*/
public function orderVaild($order_no,$classes_order,$reason,$oper_type='user',$oper_id = 0,$params=[],$check=false){
if(is_numeric($classes_order)||is_string($classes_order))$classes_order = Order::where('order_no|id',$classes_order)->find();
if(!$classes_order||!$reason )throw new \Exception("缺少必要参数");
//默认校验订单是否已创建
if($check){
//判断订单是否已创建
$order_info = self::where(['order_no'=>$order_no])->find();
if($order_info) throw new \Exception("订单已生成,如需重新下单请退出页面重新进入!");
}
$user_id = $classes_order["user_id"];
//校验订单参数
//操作人权限验证
self::checkOptionAuth($classes_order["id"],$oper_id ?:$user_id,$oper_type,true);
//免费单无法申请售后
if($classes_order["payprice"]==0 && $classes_order["totalprice"] == 0 ) throw new \Exception("免费课程无法申请售后!");
//只有使用中的订单可以申请售后
if($classes_order["status"] != '3' ) throw new \Exception("该订单当前状态无法申请售后!");
//存在售后中的订单
$count = self::where( 'classes_order_id',$classes_order["id"])->where("status","not in","7,-3")->count();
if($count > 0) throw new \Exception("该订单已存在正在进行中的售后单,请等待售后处理!");
//用户存不存在
$user_info = User::where('id',$user_id)->find();
if(!$user_info) throw new \Exception("用户不存在!");
return true;
}
/** 课时订单操作权限检测
* @param $order 订单
* @param $oper_id 操作人id
* @param $oper_type 操作人类型user-用户或员工admin-管理员
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function checkOptionAuth($classes_order_id,$oper_id,$oper_type,$only_user=false,$only_shop=false,$only_admin=false){
//课程是否存在并上架
$classesOrder = \app\common\model\school\classes\order\Order::where("id",$classes_order_id)->find();
if(!$classesOrder)throw new \Exception("订单不存在!");
switch ($oper_type) {
case 'user':
if($only_admin)throw new \Exception("您无权操作该订单!");
//自己或操作员
if($oper_id != $classesOrder["user_id"]){
if($only_user) throw new \Exception("您无权操作该订单!");
//说明是操作员
$help_user_info = User::where('id',$oper_id)->find();
if(!$help_user_info) throw new \Exception("代下单员工不存在!");
$classes_lib_ids = (new ClassesLib)->getClassesAuthIds($oper_id);
//判断当前订单课程是否在此课程授权范围内
if(!in_array($classesOrder["classes_lib_id"],$classes_lib_ids)) throw new \Exception("该课程不在您的授权范围内,无法代操作!");
}else{
$classes_lib_ids = (new ClassesLib)->getClassesAuthIds($oper_id);
//不是员工并且想操作只有机构能操作的单
if(!in_array($classesOrder["classes_lib_id"],$classes_lib_ids) && $only_shop)throw new \Exception("您无权操作该订单!");
}
break;
case 'admin':
$admin_info = Admin::where('id',$oper_id)->find();
if(!$admin_info) throw new \Exception("代下单管理员不存在!");
break;
case 'shop':
if($only_admin)throw new \Exception("您无权操作该订单!");
if($only_user) throw new \Exception("您无权操作该订单!");
$admin_info = Manystore::where('id',$oper_id)->find();
if(!$admin_info) throw new \Exception("代下单管理员不存在!");
$classes_lib_ids = ClassesLib::where("manystore_id",$oper_id)->column("id");
//判断当前订单课程是否在此课程授权范围内
if(!in_array($classesOrder["classes_lib_id"],$classes_lib_ids)) throw new \Exception("该课程不在您的授权范围内,无法代操作!");
break;
default:
throw new \Exception("请选择正确的代下单类型!");
}
}
/**得到可取消订单
* @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 getHaveCancelOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id',$order_no)
->where("status","in",['1'])
->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 updateCancel($order){
if(is_string($order))$order = self::getHaveCancelOrder($order);
$order->status = "-3";//refund_status
$order->canceltime = time();
$order->save();
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 orderRestore($classes_order){
if(is_numeric($classes_order)||is_string($classes_order))$classes_order = Order::where('order_no|id',$classes_order)->find();
$classes_order->status = $classes_order->before_status;//refund_status
$classes_order->before_status = '0';
$classes_order->server_status = '0';//refund_status
$classes_order->reason = '';
$classes_order->classes_service_order_id = 0;
$classes_order->save();
return $classes_order;
}
/**订单取消
* @param $order_no
* @param int $user_id
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function cancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到可取消订单
$order = self::getHaveCancelOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['classes_order_id'],$user_id ?: $oper_id,$oper_type,true);
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新售后为取消状态
$order = self::updateCancel($order);
//还原课程订单
self::orderRestore($order["classes_order_id"]);
//插入订单取消日志
if(!$user_id ||$order["user_id"] !=$user_id ){
ServiceOrderLog::log($order['id'],"[系统操作]课程订单已取消售后",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
ServiceOrderLog::log($order['id'],"课程订单已取消售后",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_cancel_after', $data);
//执行课时数更新
$res1 = order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res1;
}
/**得到基础条件
* @param $status
* @param null $model
* @param string $alisa
*/
public static function getBaseWhere($whereData = [], $model = null, $alisa = '',$with = false)
{
if (!$model) {
$model = new static;
if ($alisa&&!$with) $model = $model->alias($alisa);
}
if ($alisa) $alisa = $alisa . '.';
$tableFields = (new static)->getTableFields();
foreach ($tableFields as $fields)
{
if(in_array($fields, ['status',"service_stauts","sales_type",'classes_lib_id','classes_order_id','user_id','classes_order_detail_id']))continue;
// if (isset($whereData[$fields]) && $whereData[$fields]) $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
if (isset($whereData[$fields]) && $whereData[$fields]){
if(is_array($whereData[$fields])){
$model = $model->where("{$alisa}{$fields}", $whereData[$fields][0], $whereData[$fields][1]);
}else{
$model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
}
}
}
if (isset($whereData['status']) && $whereData['status']) $model = $model->where("{$alisa}status", 'in', $whereData['status']);
if (isset($whereData['service_stauts']) && $whereData['service_stauts']) $model = $model->where("{$alisa}service_stauts", 'in', $whereData['service_stauts']);
if (isset($whereData['sales_type']) && $whereData['sales_type']) $model = $model->where("{$alisa}sales_type", 'in', $whereData['sales_type']);
if (isset($whereData['not_status'])) $model = $model->where("{$alisa}status", 'not in', $whereData['not_status']);
if (isset($whereData['keywords'])&&$whereData['keywords']) $model = $model->where("{$alisa}order_no|{$alisa}id|{$alisa}reason", '=', $whereData['keywords']);
if (isset($whereData['time'])&&$whereData['time']){
$model = $model->time(["{$alisa}createtime",$whereData['time']]);
}
if (isset($whereData['user_id']) && $whereData['user_id']) $model = $model->where("{$alisa}user_id", '=', $whereData['user_id']);
if (isset($whereData['classes_order_id']) && $whereData['classes_order_id']) $model = $model->where("{$alisa}classes_order_id", 'in', $whereData['classes_order_id']);
//classes_order_detail_id
if (isset($whereData['classes_order_detail_id']) && $whereData['classes_order_detail_id']) $model = $model->where("{$alisa}classes_order_detail_id", 'in', $whereData['classes_order_detail_id']);
if (isset($whereData['classes_lib_ids']) && $whereData['classes_lib_ids']) $model = $model->where("{$alisa}classes_lib_id", 'in', $whereData['classes_lib_ids']);
if (isset($whereData['classes_lib_id']) && $whereData['classes_lib_id']) $model = $model->where("{$alisa}classes_lib_id", 'in', $whereData['classes_lib_id']);
return $model;
}
public static function allList($user_id,$page, $limit,$keywords,$status,$service_stauts,$sales_type,$classes_order_id=[],$classes_order_detail_id=[],$classes_lib_id=[]){
$with_field = [
'user'=>['nickname','mobile','avatar','realname'],
'base'=>['*'],
'classesorder'=>['*'],
'detail'=>['*'],
];
$alisa = (new self)->getWithAlisaName();
$sort = "field({$alisa}.status,'1','4','7','-3') asc,{$alisa}.id desc";
$serch_where = ['status'=>$status,'user_id'=>$user_id,
'keywords'=>$keywords,"classes_order_id"=>$classes_order_id,
"classes_order_detail_id"=>$classes_order_detail_id,"classes_lib_id"=>$classes_lib_id,
"service_stauts"=>$service_stauts,"sales_type"=>$sales_type
];
// if($type)$serch_where['type'] = $type;
return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
}
public static function baseCount($where = []){
$cancel_number = self::getBaseWhere(array_merge(['status'=>'-3'],$where))->count();
$processing_number = self::getBaseWhere(array_merge(['status'=>'4'],$where))->count();
$un_processing_number = self::getBaseWhere(array_merge(['status'=>'1'],$where))->count();
$finish_number = self::getBaseWhere(array_merge(['status'=>'7'],$where))->count();
return compact('cancel_number','processing_number','un_processing_number','finish_number');
}
/**订单数量统计
* @param int $user_id
* @return array
*/
public static function orderCount($user_id = 0,$classes_order_id=0,$classes_lib_id=[]){
return self::baseCount(['user_id'=>$user_id,"classes_lib_id"=>$classes_lib_id,"classes_order_id"=>$classes_order_id]);
}
public static function workList($page, $limit,$keywords,$status,$service_stauts,$sales_type,$classes_order_id=[],$classes_order_detail_id=[],$classes_lib_id=[],$classes_lib_ids=[]){
$with_field = [
'user'=>['nickname','mobile','avatar','realname'],
'base'=>['*'],
'classesorder'=>['*'],
'detail'=>['*'],
];
$alisa = (new self)->getWithAlisaName();
$sort = "field({$alisa}.status,'1','4','7','-3') asc,{$alisa}.id desc";
$serch_where = ['status'=>$status,'keywords'=>$keywords,"classes_lib_id"=>$classes_lib_id,"classes_lib_ids"=>$classes_lib_ids,"classes_order_id"=>$classes_order_id,"classes_order_detail_id"=>$classes_order_detail_id
,"service_stauts"=>$service_stauts,"sales_type"=>$sales_type
];
// if($type)$serch_where['type'] = $type;
return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
}
/**订单数量统计
* @param int $user_id
* @return array
*/
public static function workCount($classes_order_id=0,$classes_lib_id=[],$classes_lib_ids=[]){
return self::baseCount(["classes_lib_id"=>$classes_lib_id,"classes_lib_ids"=>$classes_lib_ids,"classes_order_id"=>$classes_order_id]);
}
/**得到机构售后提交确认订单
* @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 getHaveShopConfirmationOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id',$order_no)
->where("status","in",['1'])
->where("service_stauts","in",['1'])
->find();
if(!$order)throw new \Exception("只有待机构确认订单可提交!");
return $order;
}
/**机构售后提交确认信息
* @param $order_no
* @param int $user_id
* @param string $status yes同意 no拒绝
*@param string $price 商定价格
*@param string $reject_reason 拒绝原因
*@param string $reject_images 拒绝图片说明
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function shopConfirmation($order_no,$status,$price,$reject_reason,$reject_images,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到机构售后提交确认订单
$order = self::getHaveShopConfirmationOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['classes_order_id'],$user_id ?: $oper_id,$oper_type,false,true);
}
$classesorder = $order->classesorder;
if(!$classesorder)throw new \Exception("订单不存在!");
switch ($status){
case 'yes':
//同意
//验证价格正确性
//金额必须小于等于剩余未退全额
$price = floatval($price);
if($price > $classesorder['sub_refundprice']){
throw new \Exception("价格必须小于等于剩余应退全额!");
}
//数据修正大于剩余未退全额 则等于剩余未退
$price = $price > $classesorder['sub_refundprice'] ? $classesorder['sub_refundprice'] : $price;
if($price<=0)throw new \Exception("同意退款必须大于0");
break;
case 'no':
//拒绝
//拒绝原因必填
if(!$reject_reason)throw new \Exception("拒绝原因必填!");
break;
default:
throw new \Exception("参数错误!");
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新售后为取消状态
switch ($status){
case 'yes':
//同意
//更新订单状态为同意
$order = self::updateShopConfirmationOrder($order,$price);
//插入订单日志
if(!$user_id ||$order["user_id"] !=$user_id ){
ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后机构已处理,待用户同意",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
ServiceOrderLog::log($order['id'],"课程订单售后机构已处理,待用户同意",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_shop_confirm_after', $data);
break;
case 'no':
//拒绝
//更新
//更新售后为机构驳回结单状态
$order = self::updateShopRejectCancel($order,$reject_reason,$reject_images);
//还原课程订单
self::orderRestore($order["classes_order_id"]);
//插入订单日志
if(!$user_id ||$order["user_id"] !=$user_id ){
ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后机构驳回",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
ServiceOrderLog::log($order['id'],"课程订单售后机构驳回",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_shop_reject_after', $data);
break;
default:
throw new \Exception("参数错误!");
}
//执行课时数更新
$res1 = order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res1;
}
/**机构同意并确认价格
* @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 updateShopConfirmationOrder($order,$price){
if(is_string($order))$order = self::getHaveShopConfirmationOrder($order);
$order->status = "4";//refund_status
$order->service_stauts = "4";
$order->sales_type = "-3";
$order->tbc_price = $price;
$order->handletime = time();
$order->save();
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 updateShopRejectCancel($order,$reject_reason,$reject_images){
if(is_string($order))$order = self::getHaveShopConfirmationOrder($order);
$order->status = "7";//refund_status
$order->service_stauts = "-3";
$order->sales_type = "1";
$order->reject_reason = $reject_reason;
$order->reject_images = $reject_images;
$order->rejecttime = time();
$order->checkouttime = time();
$order->save();
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 getHaveUserConfirmationOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id',$order_no)
->where("status","in",['4'])
->where("service_stauts","in",['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 updateUserConfirmationOrder($order){
if(is_string($order))$order = self::getHaveUserConfirmationOrder($order);
$order->status = "4";//refund_status
$order->service_stauts = "7";
$order->sales_type = "-3";
$order->c_price = $order->tbc_price;
$order->confirmtime = time();
$order->save();
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 updateUserRejectCancel($order,$reject_reason,$reject_images){
if(is_string($order))$order = self::getHaveUserConfirmationOrder($order);
$order->status = "7";//refund_status
$order->service_stauts = "-3";
$order->sales_type = "4";
$order->reject_reason = $reject_reason;
$order->reject_images = $reject_images;
$order->rejecttime = time();
$order->checkouttime = time();
$order->save();
return $order;
}
/**用户售后提交确认信息
* @param $order_no
* @param int $user_id
* @param string $status yes同意 no拒绝
*@param string $reject_reason 拒绝原因
*@param string $reject_images 拒绝图片说明
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function userConfirmation($order_no,$status,$reject_reason,$reject_images,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到机构售后提交确认订单
$order = self::getHaveUserConfirmationOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['classes_order_id'],$user_id ?: $oper_id,$oper_type,true);
}
$classesorder = $order->classesorder;
if(!$classesorder)throw new \Exception("订单不存在!");
switch ($status){
case 'yes':
//同意
break;
case 'no':
//拒绝
//拒绝原因必填
if(!$reject_reason)throw new \Exception("拒绝原因必填!");
break;
default:
throw new \Exception("参数错误!");
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新售后为取消状态
switch ($status){
case 'yes':
//同意
//更新订单状态为同意
$order = self::updateUserConfirmationOrder($order);
//插入订单日志
if(!$user_id ||$order["user_id"] !=$user_id ){
ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后用户已同意售后退款,系统退款结算中",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
ServiceOrderLog::log($order['id'],"课程订单售后用户已同意售后退款,系统退款结算中",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_user_confirm_after', $data);
break;
case 'no':
//拒绝
//更新
//更新售后为机构驳回结单状态
$order = self::updateUserRejectCancel($order,$reject_reason,$reject_images);
//还原课程订单
self::orderRestore($order["classes_order_id"]);
//插入订单日志
if(!$user_id ||$order["user_id"] !=$user_id ){
ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后用户驳回",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
ServiceOrderLog::log($order['id'],"课程订单售后用户驳回",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_user_reject_after', $data);
break;
default:
throw new \Exception("参数错误!");
}
//执行课时数更新
$res1 = order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res1;
}
/**得到机构售后提交确认订单
* @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 getHaveAdminConfirmationOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id',$order_no)
->where("status","in",['4'])
->where("service_stauts","in",['7'])
->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 updateAdminConfirmationOrder($order,$pay_json=[]){
if(is_string($order))$order = self::getHaveAdminConfirmationOrder($order);
$order->status = "7";//refund_status
$order->service_stauts = "10";
$order->sales_type = "10";
$order->real_refundprice = $order->c_price;
$order->sub_refundprice = bcsub($order->sub_refundprice,$order->real_refundprice,2);
$order->refundtime = time();
$order->checkouttime = time();
$order->pay_json = $pay_json;
$order->save();
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 updateAdminRejectCancel($order,$reject_reason,$reject_images){
if(is_string($order))$order = self::getHaveAdminConfirmationOrder($order);
$order->status = "7";//refund_status
$order->service_stauts = "-3";
$order->sales_type = "7";
$order->reject_reason = $reject_reason;
$order->reject_images = $reject_images;
$order->rejecttime = time();
$order->checkouttime = time();
$order->save();
return $order;
}
/**平台售后提交确认信息
* @param $order_no
* @param int $user_id
* @param string $status yes同意 no拒绝
*@param string $reject_reason 拒绝原因
*@param string $reject_images 拒绝图片说明
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function adminConfirmation($order_no,$status,$reject_reason,$reject_images,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到机构售后提交确认订单
$order = self::getHaveAdminConfirmationOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['classes_order_id'],$user_id ?: $oper_id,$oper_type,true);
}
$classesorder = $order->classesorder;
if(!$classesorder)throw new \Exception("订单不存在!");
switch ($status){
case 'yes':
//同意
break;
case 'no':
//拒绝
//拒绝原因必填
if(!$reject_reason)throw new \Exception("拒绝原因必填!");
break;
default:
throw new \Exception("参数错误!");
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新售后为取消状态
switch ($status){
case 'yes':
//同意
self::orderRefund($order,$order['c_price'],$oper_type,$oper_id,$trans=false,$admin=false);
//更新订单状态为同意
// $order = self::updateAdminConfirmationOrder($order);
//
// //插入订单日志
// if(!$user_id ||$order["user_id"] !=$user_id ){
// ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后系统退款已原路退回",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
// }else{
// ServiceOrderLog::log($order['id'],"课程订单售后系统退款已原路退回",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
// }
//
// //调用订单取消事件
// $data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
// \think\Hook::listen('classes_serviceorder_system_confirm_after', $data);
break;
case 'no':
//拒绝
//更新
//更新售后为机构驳回结单状态
$order = self::updateAdminRejectCancel($order,$reject_reason,$reject_images);
//还原课程订单
self::orderRestore($order["classes_order_id"]);
//插入订单日志
if(!$user_id ||$order["user_id"] !=$user_id ){
ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后记录异常,系统已强制终止售后",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
ServiceOrderLog::log($order['id'],"课程订单售后记录异常,系统已强制终止售后",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_serviceorder_system_reject_after', $data);
break;
default:
throw new \Exception("参数错误!");
}
//执行课时数更新
$res1 = order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res1;
}
/**微信退款
* @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->classesorder;
$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->order_no,
'total_fee' => $total_fee,
'refund_fee' => $refund_fee,
'refund_desc' => $refund_desc ?: "课程[{$detail["title"]}]订单[ID:{$classesorder['id']}]退款{$refund_money}已到账户",
]);
$config = Service::getConfig('wechat');
$notify_url = request()->domain() . '/api/school/pay/notifyr/payment/' . $classesorder->pay_type . '/platform/' . $classesorder->platform;
$config['notify_url'] = $notify_url;
$pay = Pay::wechat($config);
$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());
}
return $res;
}
/**退款成功处理逻辑
* @param $refund_sn
* @param bool $trans
* @return bool
* @throws \Exception
*/
public static function refundSuccess($refund_sn,$trans=false){
//得到机构售后提交确认订单
$order = self::getHaveAdminConfirmationOrder($refund_sn);
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新订单状态为同意
$order = self::updateAdminConfirmationOrder($order);
//插入订单日志
ServiceOrderLog::log($order['id'],"[系统操作]课程订单售后系统退款已原路退回", 'admin', 0);
//调用订单取消事件
$data = ['serviceorder' => $order,"user_id"=>$order['user_id'],"oper_type"=>'admin',"oper_id"=>0];
\think\Hook::listen('classes_serviceorder_system_confirm_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 orderRefund($order,$refund_money,$oper_type='user',$oper_id=0,$trans=false,$admin=false){
if(is_numeric($order))$order = self::getBaseWhere(['id'=>$order])->find();
if(!$order)throw new \Exception("找不到订单");
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
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;
}
}