892 lines
37 KiB
PHP
Executable File
892 lines
37 KiB
PHP
Executable File
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | likeshop开源商城系统
|
||
// +----------------------------------------------------------------------
|
||
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
|
||
// | gitee下载:https://gitee.com/likeshop_gitee
|
||
// | github下载:https://github.com/likeshop-github
|
||
// | 访问官网:https://www.likeshop.cn
|
||
// | 访问社区:https://home.likeshop.cn
|
||
// | 访问手册:http://doc.likeshop.cn
|
||
// | 微信公众号:likeshop技术社区
|
||
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
|
||
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
|
||
// | 禁止对系统程序代码以任何目的,任何形式的再发布
|
||
// | likeshop团队版权所有并拥有最终解释权
|
||
// +----------------------------------------------------------------------
|
||
// | author: likeshop.cn.team
|
||
// +----------------------------------------------------------------------
|
||
|
||
namespace app\api\logic;
|
||
|
||
|
||
use app\common\enum\GoodsEnum;
|
||
use app\common\enum\notice\NoticeEnum;
|
||
use app\common\enum\OrderEnum;
|
||
use app\common\enum\OrderLogEnum;
|
||
use app\common\enum\OrderRefundEnum;
|
||
use app\common\enum\PayEnum;
|
||
use app\common\enum\YesNoEnum;
|
||
use app\common\logic\BaseLogic;
|
||
use app\common\logic\OrderLogLogic;
|
||
use app\common\logic\RefundLogic;
|
||
use app\common\model\city\City;
|
||
use app\common\model\coach\Coach;
|
||
use app\common\model\deposit\DepositPackage;
|
||
use app\common\model\goods\Goods;
|
||
use app\common\model\goods\GoodsComment;
|
||
use app\common\model\goods\GoodsCommentImage;
|
||
use app\common\model\order\Order;
|
||
use app\common\model\order\OrderAppend;
|
||
use app\common\model\order\OrderGap;
|
||
use app\common\model\order\OrderGoods;
|
||
use app\common\model\pay\PayWay;
|
||
use app\common\model\RechargeOrder;
|
||
use app\common\model\shop\Shop;
|
||
use app\common\model\user\User;
|
||
use app\common\model\user\UserAddress;
|
||
use app\common\service\ConfigService;
|
||
use app\common\service\FileService;
|
||
use DateTime;
|
||
use think\Exception;
|
||
use think\facade\Db;
|
||
|
||
class OrderLogic extends BaseLogic
|
||
{
|
||
/**
|
||
* @notes 订单结算详情
|
||
* @param $params
|
||
* @return array|false
|
||
* @author ljj
|
||
* @date 2022/2/24 6:19 下午
|
||
*/
|
||
public function settlement($params)
|
||
{
|
||
try {
|
||
//获取用户信息
|
||
$user = User::findOrEmpty($params['user_id'])->toArray();
|
||
$addressId = $params['address_id'] ?? 0;
|
||
$tripWay = $params['trip_way'] ?? 0;
|
||
$appointTime = $params['appoint_time'] ?? '';
|
||
$carAmount = 0;//车费
|
||
$city = [];//当前城市
|
||
$tripWayLists = [];//出行方式列表
|
||
$userAddress = []; //地址
|
||
$coach = [];//技师信息
|
||
$distance = '';//订单距离
|
||
$tips = '';
|
||
$coach = Coach::where(['id'=>$params['coach_id']])
|
||
->field( 'id,shop_id,sn,work_photo,name,longitude,latitude,longitude_location,latitude_location,deposit,work_status,server_status')
|
||
->findOrEmpty()
|
||
->toArray();
|
||
if(empty($coach)){
|
||
throw new Exception('技师不存在');
|
||
}
|
||
if(0 == $coach['work_status']){
|
||
throw new Exception('技师休息中');
|
||
}
|
||
if(0 == $coach['server_status']){
|
||
throw new Exception('技师已暂停服务');
|
||
}
|
||
//获取服务信息
|
||
$goodsInfo = self::getOrderGoods($params['goods'],$params['appoint_time'] ?? 0);
|
||
if($appointTime){
|
||
if($appointTime <= time()){
|
||
throw new Exception('服务时间不能小于当前时间');
|
||
}
|
||
$serverTimeLists = $this->getCoachServerTime($params['coach_id'],$params['goods'][0]['id']);
|
||
$serverTimeLists = array_column($serverTimeLists,null,'time_date');
|
||
//预约天
|
||
$appointTimeMd = date('m-d',$appointTime);
|
||
//预约小时
|
||
$appointTimeHi = date('H:i',$appointTime);
|
||
$timeLists = $serverTimeLists[$appointTimeMd]['time_lists'] ?? [];
|
||
|
||
if(empty($timeLists)){
|
||
throw new Exception('预约时间错误');
|
||
}
|
||
$timeLists = array_column($timeLists,null,'time');
|
||
$time = $timeLists[$appointTimeHi] ?? [];
|
||
if(empty($time)){
|
||
throw new Exception('预约时间段错误');
|
||
}
|
||
if(2 == $time['status']){
|
||
throw new Exception('当前时间技师休息中,无法预约');
|
||
}
|
||
if(3 == $time['status']){
|
||
throw new Exception('当前时间区间有被预约,请更换其他时间区间');
|
||
}
|
||
$totalDuration = $goodsInfo['total_duration'];
|
||
$dateTime = new DateTime(date('Y-m-d H:i:s',$appointTime));
|
||
if($totalDuration > 30){
|
||
$nums = intval($totalDuration / 30);
|
||
for ($i = 0;$nums > $i;$i++){
|
||
$dateTime->modify('+30 minutes');
|
||
$appointTimeEnd = strtotime($dateTime->format('Y-m-d H:i'));
|
||
}
|
||
}else{
|
||
$dateTime->modify('+'. $totalDuration.' minutes');
|
||
$appointTimeEnd = strtotime($dateTime->format('Y-m-d H:i'));
|
||
}
|
||
$appointTimeEnd = round_date_time($appointTimeEnd);
|
||
$appointTimeEndMd = date('m-d',$appointTimeEnd);
|
||
$appointTimeEndHi = date('H:i',$appointTimeEnd);
|
||
$timeLists = $serverTimeLists[$appointTimeEndMd]['time_lists'] ?? [];
|
||
$timeLists = array_column($timeLists,null,'time');
|
||
$time = $timeLists[$appointTimeEndHi] ?? [];
|
||
if(empty($time)){
|
||
throw new Exception('当前时间区间有被预约,请更换其他时间区间');
|
||
}
|
||
if(2 == $time['status']){
|
||
throw new Exception('当前时间技师休息中,无法预约');
|
||
}
|
||
if(3 == $time['status']){
|
||
throw new Exception('当前时间区间有被预约,请更换其他时间区间');
|
||
}
|
||
}
|
||
//验证技师的接单数量
|
||
// $this->ckechCoachTakeOrderNum($coach);
|
||
|
||
|
||
//设置用户地址
|
||
$userAddress = UserAddress::getUserAddress($params['user_id'], $addressId);
|
||
$goodsCityLists = $goodsInfo['city_lists'];
|
||
if($userAddress){
|
||
$file = 'id,shop_id,sn,work_photo,name,round(st_distance_sphere(point('.$userAddress['longitude'].','.$userAddress['latitude'].'),
|
||
point(longitude_location, latitude_location))/1000,2) as distance';
|
||
if(empty($coach['longitude_location']) || empty($coach['latitude_location'])){
|
||
$file ='id,shop_id,sn,work_photo,name,round(st_distance_sphere(point('.$userAddress['longitude'].','.$userAddress['latitude'].'),
|
||
point(longitude, latitude))/1000,2) as distance';
|
||
}
|
||
$coach = Coach::where(['id'=>$params['coach_id']])
|
||
->field( $file)
|
||
->findOrEmpty()
|
||
->toArray();
|
||
|
||
// if(empty($userAddress)){
|
||
// throw new Exception('用户地址不存在,请重新选择');
|
||
// }
|
||
$city = City::where(['city_id'=>$userAddress['city_id']])->findOrEmpty()->toArray();
|
||
if($addressId && empty($city)){
|
||
throw new Exception('当前城市未开通出行方式,请联系管理员');
|
||
}
|
||
if($addressId && true !== $goodsCityLists && !in_array($userAddress['city_id'],$goodsCityLists)){
|
||
throw new Exception('抱歉,商品暂不支持该服务地址');
|
||
}
|
||
$coachServerScope = ConfigService::get('server_setting', 'coach_server_scope');
|
||
if($addressId && $coach['distance'] > $coachServerScope){
|
||
throw new Exception('当前最大服务范围'.$coachServerScope.'公里,请重新选择地址');
|
||
}
|
||
$distance = intval(ceil($coach['distance']));
|
||
$tips = '全程'.$coach['distance'].'公里,出租出行收取来回费用,白天起步价'.$city['start_price'].'元,超过'.$city['start_km'].'公里部分,每公里'.$city['continue_price'].'元';
|
||
if($city['taxi']){
|
||
$amount = 0;
|
||
if($distance <= $city['start_km']){
|
||
$amount = $city['start_price'];
|
||
}else{
|
||
$amount += $city['start_price'];
|
||
$surplus = round($distance-$city['start_km'],2);
|
||
$amount += round($city['continue_price'] * $surplus,2);
|
||
}
|
||
$tripWayLists[] = [
|
||
'type' => OrderEnum::TRIP_WAY_TAXI,
|
||
'type_desc' => OrderEnum::getTripWayDesc(OrderEnum::TRIP_WAY_TAXI),
|
||
'tips' => $tips,
|
||
'amount' => round($amount,2),
|
||
];
|
||
}
|
||
$nowH = date('H');
|
||
if($city['bus'] && $nowH > $city['bus_start_time'] && $city['bus_end_time'] > $nowH){
|
||
$tips = '当前城市'.$city['bus_start_time'].'-'.$city['bus_end_time'].'可选择交通地铁出行方式';
|
||
$tripWayLists[] = [
|
||
'type' => OrderEnum::TRIP_WAY_BUS,
|
||
'type_desc' => OrderEnum::getTripWayDesc(OrderEnum::TRIP_WAY_BUS),
|
||
'tips' => $tips,
|
||
'amount' => $city['bus_fare'],
|
||
];
|
||
}
|
||
$tripWayLists = array_column($tripWayLists,null,'type');
|
||
$carAmount = $tripWayLists[$tripWay]['amount'] ?? 0;
|
||
}
|
||
// 订单金额
|
||
$totalAmount = round($goodsInfo['total_amount']+$carAmount,2);
|
||
//订单应付金额
|
||
$orderAmount = $totalAmount;
|
||
//订单服务总数量
|
||
$totalNum = $goodsInfo['total_num'];
|
||
//订单服务总价
|
||
$totalGoodsPrice = $goodsInfo['total_amount'];
|
||
$result = [
|
||
'terminal' => $params['terminal'],
|
||
'total_num' => $totalNum,
|
||
'total_goods_price' => $totalGoodsPrice,
|
||
'total_amount' => $orderAmount,
|
||
'order_amount' => $orderAmount,
|
||
'user_id' => $user['id'],
|
||
'user_remark' => $params['user_remark'] ?? '',
|
||
'appoint_time' => $params['appoint_time'] ?? '',
|
||
'address' => $userAddress,
|
||
'goods' => $goodsInfo['goods_lists'],
|
||
'trip_way_lists' => array_values($tripWayLists),
|
||
'trip_way' => $tripWay,
|
||
'city' => $city,
|
||
'coach_id' => $params['coach_id'] ?? '',
|
||
'coach' => $coach,
|
||
'total_duration' => $goodsInfo['total_duration'],
|
||
'distance' => $distance,
|
||
'distance_desc' => $distance ? $coach['distance'].'km' : $distance,
|
||
'pay_way_list' => PayLogic::getPayWayList($params['terminal'],$params['user_id']),
|
||
'car_amount' => $carAmount,
|
||
'city_lists' => $goodsInfo['city_lists'],
|
||
];
|
||
return $result;
|
||
|
||
} catch (\Exception $e) {
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @notes 验证技师的接单数量
|
||
* @param $coach
|
||
* @return int|mixed
|
||
* @throws \think\db\exception\DataNotFoundException
|
||
* @throws \think\db\exception\DbException
|
||
* @throws \think\db\exception\ModelNotFoundException
|
||
* @author cjhao
|
||
* @date 2024/11/26 23:44
|
||
*/
|
||
public function ckechCoachTakeOrderNum($coach){
|
||
$deposit = $coach['deposit'];
|
||
$depositPackageLists = [];
|
||
$takeOrderNum = 0;
|
||
if($coach['shop_id']){
|
||
$deposit = Shop::where(['id'=>$coach['shop_id']])->value('deposit');
|
||
$where[] = ['type','=',1];
|
||
$orderNum = Order::where(['shop_id'=>$coach['shop_id']])
|
||
->where('order_status','>=',OrderEnum::ORDER_STATUS_WAIT_RECEIVING)
|
||
->where('order_status','<',OrderEnum::ORDER_STATUS_CLOSE)
|
||
->whereDay('create_time')->count();
|
||
}else{
|
||
$where[] = ['type','=',2];
|
||
$orderNum = Order::where(['coach_id'=>$coach['id']])
|
||
->where('order_status','>=',OrderEnum::ORDER_STATUS_WAIT_RECEIVING)
|
||
->where('order_status','<',OrderEnum::ORDER_STATUS_CLOSE)
|
||
->whereDay('create_time')->count();
|
||
}
|
||
$depositPackageLists = DepositPackage::where($where)->order('money desc')->select()->toArray();
|
||
//套餐列表
|
||
foreach ($depositPackageLists as $depositPackage){
|
||
if($deposit >= $depositPackage['money']){
|
||
$takeOrderNum = $depositPackage['order_limit'];
|
||
break;
|
||
|
||
}
|
||
}
|
||
if($orderNum >= $takeOrderNum){
|
||
throw new Exception('技师接单数量已达上限');
|
||
}
|
||
}
|
||
/**
|
||
* @notes 获取订单服务信息
|
||
* @param $goods
|
||
* @return array
|
||
* @author ljj
|
||
* @date 2022/2/24 6:09 下午
|
||
*/
|
||
public function getOrderGoods($postGoods,$appointTime)
|
||
{
|
||
$postGoods = array_column($postGoods,null,'id');
|
||
$goodsLists = (new Goods())->field('id,status,name,shop_id,tags,duration,image,price,overtime_price,overtime_duration,shop_ratio,commission_ratio,appoint_start_time,appoint_end_time')
|
||
->where(['id'=>array_keys($postGoods),'audit_status'=>GoodsEnum::AUDIT_STATUS_PASS])
|
||
->with(['goods_city'])
|
||
->select()
|
||
->toArray();
|
||
if(count($goodsLists) != count($postGoods)){
|
||
throw new Exception('商品已失效,请返回上个页面重新选择服务');
|
||
}
|
||
$totalAmount = 0;
|
||
$totalNum = 0;
|
||
$totalDuration = 0;
|
||
$cityLists = [];
|
||
$appointStartI = date('H:i',$appointTime);
|
||
foreach ($goodsLists as $key => $goods){
|
||
$goodsNum = $postGoods[$goods['id']]['goods_num'] ?? 0;
|
||
if(0 >= $goodsNum){
|
||
throw new Exception('商品数量或商品数据错误');
|
||
}
|
||
$goodsLists[$key]['goods_num'] = $goodsNum;
|
||
$totalAmount += round($goods['price'] * $goodsNum,2);
|
||
$totalNum += $goodsNum;
|
||
$totalDuration += ($goods['duration'] * $goodsNum);
|
||
$appointEndI = date('H:i',$appointTime+$goods['duration'] * 60);
|
||
if($goods['appoint_start_time'] >! $appointStartI && $goods['appoint_start_time'] <! $appointEndI){
|
||
throw new Exception('商品服务时间为:'.$goods['appoint_start_time'].'~'.$goods['appoint_end_time']);
|
||
}
|
||
if($goods['appoint_end_time'] >! $appointStartI && $goods['appoint_end_time'] < !$appointEndI){
|
||
throw new Exception('商品服务时间为:'.$goods['appoint_start_time'].'~'.$goods['appoint_end_time']);
|
||
}
|
||
if(empty($goods['status'])){
|
||
throw new Exception('商品已下架,请返回上个页面重新选择服务');
|
||
}
|
||
if($goods['goods_city']){
|
||
foreach ($goods['goods_city'] as $city){
|
||
$cityLists[] = $city['city_id'];
|
||
}
|
||
}else{
|
||
$cityLists = true;
|
||
}
|
||
}
|
||
//服务数量
|
||
return [
|
||
'goods_lists' => $goodsLists,
|
||
'total_amount' => $totalAmount,
|
||
'total_num' => $totalNum,
|
||
'total_duration'=> $totalDuration,
|
||
'city_lists' => $cityLists,
|
||
];
|
||
}
|
||
|
||
/**
|
||
* @notes 提交订单
|
||
* @param $params
|
||
* @return array|false
|
||
* @author ljj
|
||
* @date 2022/2/25 9:40 上午
|
||
*/
|
||
public function submitOrder($params)
|
||
{
|
||
Db::startTrans();
|
||
try {
|
||
|
||
$this->submitOrderCheck($params);
|
||
//创建订单信息
|
||
$order = self::addOrder($params);
|
||
//订单日志
|
||
(new OrderLogLogic())->record(OrderLogEnum::TYPE_USER,OrderLogEnum::USER_ADD_ORDER,$order['id'],$params['user_id']);
|
||
|
||
//提交事务
|
||
Db::commit();
|
||
return ['order_id' => $order['id'], 'type' => 'order'];
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 创建订单信息
|
||
* @param $params
|
||
* @return Order|\think\Model
|
||
* @author ljj
|
||
* @date 2022/2/25 9:40 上午
|
||
*/
|
||
public static function addOrder($params)
|
||
{
|
||
|
||
$serverFinishTime = $params['appoint_time'] + ($params['total_duration'] * 60);
|
||
$shopId = 0;
|
||
if($params['goods'][0]['shop_id']){
|
||
$shopId = $params['goods'][0]['shop_id'];
|
||
}
|
||
if($params['coach']['shop_id']){
|
||
$shopId = $params['coach']['shop_id'];
|
||
}
|
||
//创建订单信息
|
||
$order = Order::create([
|
||
'sn' => generate_sn((new Order()), 'sn'),
|
||
'user_id' => $params['user_id'],
|
||
'shop_id' => $shopId,
|
||
'coach_id' => $params['coach_id'],
|
||
'order_terminal' => $params['terminal'],
|
||
'goods_price' => $params['total_goods_price'],
|
||
'total_order_amount' => $params['order_amount'],
|
||
'order_amount' => $params['order_amount'],
|
||
'total_amount' => $params['total_amount'],
|
||
'total_num' => $params['total_num'],
|
||
'user_remark' => $params['user_remark'],
|
||
'contact' => $params['address']['contact'],
|
||
'mobile' => $params['address']['mobile'],
|
||
'province_id' => $params['address']['province_id'],
|
||
'city_id' => $params['address']['city_id'],
|
||
'district_id' => $params['address']['district_id'],
|
||
'address_id' => $params['address']['id'],
|
||
'address_snap' => json_encode($params['address']),
|
||
'trip_way' => $params['trip_way'],
|
||
'appoint_time' => $params['appoint_time'],
|
||
'server_finish_time' => $serverFinishTime,
|
||
'car_amount' => $params['car_amount'],
|
||
'car_config_snap' => $params['city'],
|
||
'order_distance' => $params['distance'],
|
||
'total_duration' => $params['total_duration'],
|
||
]);
|
||
$orderGoods = [];
|
||
foreach ($params['goods'] as $goods){
|
||
$orderGoods[] = [
|
||
'order_id' => $order->id,
|
||
'goods_id' => $goods['id'],
|
||
'goods_name' => $goods['name'],
|
||
'goods_num' => $goods['goods_num'],
|
||
'goods_image' => FileService::setFileUrl($goods['image']),
|
||
'goods_price' => $goods['price'],
|
||
'total_price' => round($goods['price'] * $goods['goods_num'],2),
|
||
'total_pay_price' => round($goods['price'] * $goods['goods_num'],2),
|
||
'duration' => $goods['duration'],
|
||
'goods_snap' => $goods
|
||
];
|
||
}
|
||
//创建订单服务信息
|
||
(new OrderGoods())->saveAll($orderGoods);
|
||
|
||
return $order;
|
||
}
|
||
|
||
/**
|
||
* @notes 订单详情
|
||
* @param $id
|
||
* @return array
|
||
* @author ljj
|
||
* @date 2022/2/28 11:23 上午
|
||
*/
|
||
public function detail($id)
|
||
{
|
||
$result = Order::field('id,sn,pay_way,goods_price,order_status,pay_status,appoint_time,order_amount,server_finish_time,create_time,coach_id,cancel_time,total_gap_amount,total_append_amount,total_order_amount,order_distance,address_snap,car_amount,user_remark')
|
||
->where(['id'=>$id])
|
||
->order('id','desc')
|
||
->append(['appoint_time','pay_way_desc','appoint_date','order_status_desc','pay_btn','gap_btn','append_btn','user_cancel_btn','del_btn','comment_btn','look_comment_btn','order_cancel_time'])
|
||
->with(['order_goods' => function($query){
|
||
$query->field('id,order_id,goods_id,goods_snap,is_comment,duration,goods_image,goods_num,goods_name,goods_price')->hidden(['goods_snap']);
|
||
},'order_gap','order_append'])
|
||
->findOrEmpty()
|
||
->toArray();
|
||
|
||
if(!isset($result['address_snap']['house_number'])){
|
||
$result['address_snap']['house_number'] = '';
|
||
}
|
||
// if(in_array($result['order_status'],[OrderEnum::ORDER_STATUS_DEPART,OrderEnum::ORDER_STATUS_ARRIVE,OrderEnum::ORDER_STATUS_START_SERVER,OrderEnum::ORDER_STATUS_SERVER_FINISH])){
|
||
$coach = Coach::where(['id'=>$result['coach_id']])->field('id,mobile,name,work_photo,sn')->findOrEmpty()->toArray();
|
||
$result['coach_info'] = [
|
||
'name' => $coach['name'] ?? '',
|
||
'work_photo' => $coach['work_photo'] ?? '',
|
||
'sn' => $coach['sn'] ?? '',
|
||
'mobile'=> $coach['mobile'],
|
||
];
|
||
// }
|
||
return $result;
|
||
|
||
}
|
||
|
||
/**
|
||
* @notes 取消订单
|
||
* @param $params
|
||
* @return bool|string
|
||
* @author ljj
|
||
* @date 2022/2/28 11:36 上午
|
||
*/
|
||
public function cancel($params)
|
||
{
|
||
// 启动事务
|
||
Db::startTrans();
|
||
try {
|
||
|
||
//TODO 已支付订单原路退回金额
|
||
$order = Order::where('id',$params['id'])->findOrEmpty()->toArray();
|
||
$totalRefundAmount = 0;
|
||
if($order['pay_status'] == PayEnum::ISPAID) {
|
||
$totalRefundAmount = $order['total_order_amount'];
|
||
(new RefundLogic())->refund($order,$order['total_order_amount'],0,OrderRefundEnum::TYPE_USER,1,$params['user_id']);
|
||
}
|
||
//更新订单状态
|
||
Order::update([
|
||
'total_refund_amount' => $totalRefundAmount,
|
||
'order_status' => OrderEnum::ORDER_STATUS_CLOSE,
|
||
'cancel_time' => time(),
|
||
],['id'=>$params['id']]);
|
||
|
||
//添加订单日志
|
||
(new OrderLogLogic())->record(OrderLogEnum::TYPE_USER,OrderLogEnum::USER_CANCEL_ORDER,$params['id'],$params['user_id']);
|
||
//取消订单-通知用户
|
||
event('Notice', [
|
||
'scene_id' => NoticeEnum::ORDER_CANCEL_NOTICE,
|
||
'params' => [
|
||
'user_id' => $order['user_id'],
|
||
'order_id' => $order['id']
|
||
]
|
||
]);
|
||
//取消订单-通知师傅
|
||
event('Notice', [
|
||
'scene_id' => NoticeEnum::ORDER_CANCEL_NOTICE_STAFF,
|
||
'params' => [
|
||
'coach_id' => $order['coach_id'],
|
||
'order_id' => $order['id']
|
||
]
|
||
]);
|
||
// 提交事务
|
||
Db::commit();
|
||
return true;
|
||
} catch (\Exception $e) {
|
||
// 回滚事务
|
||
Db::rollback();
|
||
return $e->getMessage();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 删除订单
|
||
* @param $id
|
||
* @return bool
|
||
* @author ljj
|
||
* @date 2022/2/28 11:50 上午
|
||
*/
|
||
public function del($id)
|
||
{
|
||
Order::destroy($id);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @notes 支付方式
|
||
* @param $params
|
||
* @return mixed
|
||
* @author ljj
|
||
* @date 2024/7/24 下午7:08
|
||
*/
|
||
public static function payWay($params)
|
||
{
|
||
try {
|
||
// 获取待支付金额
|
||
if ($params['from'] == 'order') {
|
||
// 订单
|
||
$order = Order::findOrEmpty($params['order_id'])->toArray();
|
||
}
|
||
if ($params['from'] == 'recharge') {
|
||
// 充值
|
||
$order = RechargeOrder::findOrEmpty($params['order_id'])->toArray();
|
||
}
|
||
|
||
if ($params['from'] == 'orderGap') {
|
||
// 补差价
|
||
$order = OrderGap::findOrEmpty($params['order_id'])->toArray();
|
||
}
|
||
if ($params['from'] == 'orderAppend') {
|
||
// 加钟
|
||
$order = OrderAppend::findOrEmpty($params['order_id'])->toArray();
|
||
}
|
||
if (empty($order)) {
|
||
throw new \Exception('订单不存在');
|
||
}
|
||
|
||
// 获取订单剩余支付时间
|
||
$cancelUnpaidOrders = ConfigService::get('transaction', 'cancel_unpaid_orders',1);
|
||
$cancelUnpaidOrdersTimes = ConfigService::get('transaction', 'cancel_unpaid_orders_times',30);
|
||
$cancelTime = 0;
|
||
if(!in_array($params['from'],['order_gap','order_append'])){
|
||
if (empty($cancelUnpaidOrders)) {
|
||
// 不自动取消待支付订单
|
||
$cancelTime = 0;
|
||
} else {
|
||
// 指定时间内取消待支付订单
|
||
$cancelTime = strtotime($order['create_time']) + intval($cancelUnpaidOrdersTimes) * 60;
|
||
}
|
||
}
|
||
$pay_way = PayWay::alias('pw')
|
||
->join('dev_pay dp', 'pw.pay_id = dp.id')
|
||
->where(['pw.scene'=>$params['scene'],'pw.status'=>YesNoEnum::YES])
|
||
->field('dp.id,dp.name,dp.pay_way,dp.image,pw.is_default')
|
||
->order(['sort'=>'asc','id'=>'desc'])
|
||
->select()
|
||
->toArray();
|
||
foreach ($pay_way as $k=>&$item) {
|
||
if ($item['pay_way'] == PayEnum::BALANCE_PAY) {
|
||
$user_money = User::where(['id' => $params['user_id']])->value('user_money');
|
||
$item['extra'] = '可用余额:'.$user_money;
|
||
}
|
||
// 充值时去除余额支付
|
||
if ($params['from'] == 'recharge' && $item['pay_way'] == PayEnum::BALANCE_PAY) {
|
||
unset($pay_way[$k]);
|
||
}
|
||
}
|
||
|
||
return [
|
||
'lists' => array_values($pay_way),
|
||
'order_amount' => $order['order_amount'],
|
||
'cancel_time' => $cancelTime,
|
||
];
|
||
} catch (\Exception $e) {
|
||
self::setError($e->getMessage());
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 获取技师服务时间
|
||
* @param $coachId
|
||
* @param $goodsId
|
||
* @return array|false
|
||
* @author cjhao
|
||
* @date 2024/11/26 22:44
|
||
*/
|
||
public function getCoachServerTime($coachId,$goodsId)
|
||
{
|
||
try {
|
||
if(empty($coachId)){
|
||
throw new Exception('请选择技师');
|
||
}
|
||
$coachServerTimeLists = \app\common\logic\CoachLogic::getCoachServerTime($coachId,$goodsId);
|
||
$timeLists = [];
|
||
// 获取当前日期的时间戳
|
||
$currentDate = strtotime(date('Y-m-d'));
|
||
// 获取明天和后天的时间戳
|
||
$tomorrowDate = strtotime('tomorrow');
|
||
$afterTomorrowDate = strtotime('+2 days',$currentDate);
|
||
foreach ($coachServerTimeLists as $key => $serverTimeList){
|
||
$timeTips = '';
|
||
$timestamp = strtotime(date('Y-'.$key));
|
||
if ($timestamp >=$currentDate && $timestamp <$tomorrowDate) {
|
||
$timeTips = '今天';
|
||
} elseif ($timestamp >=$tomorrowDate && $timestamp <$afterTomorrowDate) {
|
||
$timeTips = '明天';
|
||
} elseif ($timestamp >=$afterTomorrowDate && $timestamp < strtotime('+3 days',$currentDate)) {
|
||
$timeTips = '后天';
|
||
} else {
|
||
$weekdays = array('星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六');
|
||
$weekdayIndex = date('w',$timestamp);
|
||
$timeTips = $weekdays[$weekdayIndex];
|
||
}
|
||
$timeLists[] = [
|
||
'time_date' => $key,
|
||
'time_tips' => $timeTips,
|
||
'time_lists' => $serverTimeList
|
||
];
|
||
|
||
}
|
||
return $timeLists;
|
||
|
||
}catch (Exception $e) {
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* @notes 订单差价
|
||
* @param array $params
|
||
* @return array|false
|
||
* @author cjhao
|
||
* @date 2024/9/19 11:04
|
||
*/
|
||
public function orderGap(array $params)
|
||
{
|
||
// 启动事务
|
||
// Db::startTrans();
|
||
try {
|
||
$order = Order::where(['id'=>$params['order_id'],'user_id'=>$params['user_id']])->findOrEmpty();
|
||
if($order->isEmpty()){
|
||
throw new Exception('订单不存在');
|
||
}
|
||
if(PayEnum::UNPAID == $order->pay_status){
|
||
throw new Exception('当前订单未支付');
|
||
}
|
||
if(OrderEnum::ORDER_STATUS_SERVER_FINISH == $order->order_status){
|
||
throw new Exception('订单已完成');
|
||
}
|
||
$orderGap = OrderGap::create([
|
||
'sn' => generate_sn((new OrderGap()), 'sn'),
|
||
'user_id' => $params['user_id'],
|
||
'order_id' => $order->id,
|
||
'order_amount' => $params['order_amount'],
|
||
'remark' => $params['remark'],
|
||
]);
|
||
// 提交事务
|
||
// Db::commit();
|
||
return [
|
||
'id' => $orderGap->id,
|
||
'order_id' => $order->id,
|
||
'sn' => $orderGap->sn,
|
||
'type' => 'orderGap'
|
||
];
|
||
}catch (Exception $e){
|
||
// Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
/**
|
||
* @notes 订单加钟
|
||
* @param array $params
|
||
* @return array|bool
|
||
* @author cjhao
|
||
* @date 2024/9/20 00:40
|
||
*/
|
||
public function orderAppend(array $params)
|
||
{
|
||
Db::startTrans();
|
||
try {
|
||
$order = Order::where(['id'=>$params['order_id'],'user_id'=>$params['user_id']])->findOrEmpty();
|
||
if($order->isEmpty()){
|
||
throw new Exception('订单不存在');
|
||
}
|
||
if(PayEnum::UNPAID == $order->pay_status){
|
||
throw new Exception('当前订单未支付');
|
||
}
|
||
if(OrderEnum::ORDER_STATUS_SERVER_FINISH == $order->order_status){
|
||
throw new Exception('订单已完成');
|
||
}
|
||
$goods = Goods::where(['id'=>$params['goods'][0]['id']])->findOrEmpty()->toArray();
|
||
//加钟时长
|
||
$overtimeDuration = $goods['overtime_duration'];
|
||
//加钟价
|
||
$overtimePrice = round($goods['overtime_price'] * $params['goods'][0]['goods_num'],2);
|
||
$action = $params['action'] ?? 'settlement';
|
||
if('settlement' === $action){
|
||
return [
|
||
'order_id' => $order->id,
|
||
'goods_id' => $goods['id'],
|
||
'goods_name' => $goods['name'],
|
||
'goods_num' => (int)$params['goods'][0]['goods_num'],
|
||
'duration' => $overtimeDuration,
|
||
'goods_price' => $goods['overtime_price'],
|
||
'order_amount' => $overtimePrice,
|
||
];
|
||
}
|
||
$serverFinishTime = $order['server_finish_time'];
|
||
$totalDurations = $overtimeDuration;
|
||
//判断下订单也没有加时
|
||
$totalDuration = OrderAppend::where(['order_id'=>$order->id,'pay_status'=>PayEnum::ISPAID])->sum('duration');
|
||
if($totalDuration){
|
||
$totalDurations += $totalDuration;
|
||
}
|
||
$serverTime = point_timestamps($serverFinishTime,$totalDurations*60*$params['goods'][0]['goods_num']);
|
||
$dateTime = date('m-d',$serverFinishTime);
|
||
$coachServerTime = \app\common\logic\CoachLogic::getCoachServerTime($order['coach_id'])[$dateTime] ?? [];
|
||
$coachServerTime = array_column($coachServerTime,null,'time');
|
||
foreach ($serverTime as $key => $time){
|
||
|
||
$coachTime = $coachServerTime[$time['time']] ?? [];
|
||
if(empty($coachTime)){
|
||
throw new Exception('技师当前占无时间段可预约');
|
||
}
|
||
//开始时间是重叠的,第一个key不判断
|
||
if(0 != $key && 3 == $coachTime['status']){
|
||
throw new Exception('当前时段已被预约');
|
||
}
|
||
if(2 == $coachTime['status']){
|
||
throw new Exception( '当前时段技师在休息');
|
||
}
|
||
}
|
||
$orderAppend = OrderAppend::create([
|
||
'sn' => generate_sn((new OrderAppend()), 'sn'),
|
||
'user_id' => $params['user_id'],
|
||
'order_id' => $order->id,
|
||
'goods_id' => $goods['id'],
|
||
'goods_name' => $goods['name'],
|
||
'goods_image' => $goods['image'],
|
||
'goods_num' => $params['goods'][0]['goods_num'],
|
||
'goods_price' => $goods['overtime_price'],
|
||
'goods_snap' => $goods,
|
||
'order_amount' => $overtimePrice,
|
||
'duration' => $overtimeDuration,
|
||
]);
|
||
|
||
Db::commit();
|
||
return [
|
||
'id' => $orderAppend->id,
|
||
'order_id' => $order->id,
|
||
'sn' => $orderAppend->sn,
|
||
'type' => 'orderAppend'
|
||
];
|
||
}catch (Exception $e){
|
||
Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 订单评论
|
||
* @param $params
|
||
* @return false|void
|
||
* @author cjhao
|
||
* @date 2024/9/24 20:45
|
||
*/
|
||
public function comment($params)
|
||
{
|
||
Db::startTrans();
|
||
try {
|
||
$order = Order::where(['id'=>$params['id'],'user_id'=>$params['user_id']])->with(['order_goods'])->findOrEmpty();
|
||
if($order->isEmpty()){
|
||
throw new Exception('订单不存在');
|
||
}
|
||
if(OrderEnum::ORDER_STATUS_SERVER_FINISH != $order->order_status){
|
||
throw new Exception('订单未完成服务,不能评论');
|
||
}
|
||
$comment = GoodsComment::where(['order_goods_id'=>$order['order_goods'][0]['id']])->findOrEmpty();
|
||
if(!$comment->isEmpty()){
|
||
throw new Exception('订单已评论');
|
||
}
|
||
$goodsComment = GoodsComment::create([
|
||
'goods_id' => $order['order_goods'][0]['goods_id'],
|
||
'user_id' => $params['user_id'],
|
||
'order_goods_id' => $order['order_goods'][0]['id'],
|
||
'service_comment' => $params['service_comment'],
|
||
'comment' => $params['content'],
|
||
]);
|
||
$imageLists = $params['image_lists'] ?? [];
|
||
if($imageLists){
|
||
$commentImage = [];
|
||
foreach ($imageLists as $image){
|
||
$commentImage[] = [
|
||
'comment_id' => $goodsComment['id'],
|
||
'uri' => $image,
|
||
];
|
||
}
|
||
(new GoodsCommentImage())->saveAll($commentImage);
|
||
}
|
||
|
||
Db::commit();
|
||
return true;
|
||
}catch (Exception $e){
|
||
Db::rollback();
|
||
self::$error = $e->getMessage();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 下单前验证
|
||
* @param $params
|
||
* @return true
|
||
* @author cjhao
|
||
* @date 2025/4/27 10:56
|
||
*/
|
||
public function submitOrderCheck($params)
|
||
{
|
||
//验证在默认使用地址的情况下,默认地址是否可用
|
||
$city = $params['city'] ?? '';
|
||
$userAddress = $params['address'] ?? [];
|
||
$coach = $params['coach'] ?? [];
|
||
$goodsCityLists = $params['city_lists'] ?? [];
|
||
if(empty($params['address_id'])){
|
||
if(empty($city)){
|
||
throw new Exception('当前城市未开通出行方式,请联系管理员');
|
||
}
|
||
if(true !== $goodsCityLists && !in_array($userAddress['city_id'],$goodsCityLists)){
|
||
throw new Exception('抱歉,商品暂不支持该服务地址');
|
||
}
|
||
$coachServerScope = ConfigService::get('server_setting', 'coach_server_scope');
|
||
if($coach['distance'] > $coachServerScope){
|
||
throw new Exception('当前最大服务范围'.$coachServerScope.'公里,请重新选择地址');
|
||
}
|
||
}
|
||
return true;
|
||
|
||
|
||
}
|
||
} |