|
|
|
|
@ -17,6 +17,7 @@ class PlanListService
|
|
|
|
|
{
|
|
|
|
|
date_default_timezone_set('PRC');
|
|
|
|
|
|
|
|
|
|
$allEmergency = true;
|
|
|
|
|
$allDevice = [];//所有医嘱检查项目绑定的设备id
|
|
|
|
|
$commPatientType = [];//所有医嘱共同的病人类型
|
|
|
|
|
$zhanweiCount=0;//勾选的检查项目共计占多少名额
|
|
|
|
|
@ -24,6 +25,11 @@ class PlanListService
|
|
|
|
|
// $info = DB::table('s_list')->where(['reg_num' => $regnum, 'entrust_id' => $entrustid, 'episodeid' => $episodeid, 'is_nullify' => 0])->first();
|
|
|
|
|
$info = DB::table('s_list')->where(['entrust_id' => $entrustid, 'is_nullify' => 0])->first();
|
|
|
|
|
if (!$info) return \Yz::echoError1('没有找到对应医嘱信息:'.$entrustid);
|
|
|
|
|
|
|
|
|
|
if (!isset($info->his_is_emergency) || $info->his_is_emergency != 1) {
|
|
|
|
|
$allEmergency = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$itemInfo = DB::table('s_check_item')->where(['item_name' => $info->entrust, 'status' => 1, "is_del" => 0])->get();
|
|
|
|
|
if (count($itemInfo) == 0) return \Yz::echoError1('没有找到可用的检查项目信息');
|
|
|
|
|
$itemInfo = $itemInfo[0];
|
|
|
|
|
@ -179,22 +185,34 @@ WHERE
|
|
|
|
|
'mainInfo' => $info,
|
|
|
|
|
'plan_list' => $pp,
|
|
|
|
|
'zhanWeiCount'=>$zhanweiCount,
|
|
|
|
|
'earliestPlan'=>$earliestPlan
|
|
|
|
|
'earliestPlan'=>$earliestPlan,
|
|
|
|
|
'is_emergency' => $allEmergency,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//开始预约占用名额
|
|
|
|
|
public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$do_user=null)
|
|
|
|
|
public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_emergency=0,$do_user=null)
|
|
|
|
|
{
|
|
|
|
|
date_default_timezone_set('PRC');
|
|
|
|
|
$nowdatetime = date("Y-m-d H:i:s");
|
|
|
|
|
// $planid = request('planid');
|
|
|
|
|
// $appointment_type = request('appointment_type');//渠道id
|
|
|
|
|
// $mainlistid = request('mainlistid');//主表id
|
|
|
|
|
// $do_type = request('dotype');//操作类型,1预约,2改约
|
|
|
|
|
// if (!isset($do_type)) return \Yz::echoError1('参数:操作类型 不能为空');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($is_emergency == 1 && !empty($do_user)) {//如果是加急,校验用户是否有加急权限
|
|
|
|
|
$do_user_info=DB::table('users')->where('id',$do_user)->first();
|
|
|
|
|
if(!$do_user_info){
|
|
|
|
|
return \Yz::echoError1('无效的用户ID,无法进行加急预约');
|
|
|
|
|
}else{
|
|
|
|
|
$special_privileges=[];
|
|
|
|
|
$decoded=json_decode($do_user_info->special_privileges,true);
|
|
|
|
|
if(is_array($decoded)){
|
|
|
|
|
$special_privileges=$decoded;
|
|
|
|
|
}
|
|
|
|
|
if(!in_array('emergency', $special_privileges)){
|
|
|
|
|
return \Yz::echoError1('无权进行加急预约');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
$is_emergency=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$planInfo = DB::table('s_source_roster_detail')->where(['id' => $planid, 'status' => 1, 'is_del' => 0])->first();
|
|
|
|
|
if (!$planInfo) return \Yz::echoError1('当前时段不可用');
|
|
|
|
|
@ -334,7 +352,18 @@ WHERE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if ($planZongCount < ($planZongUsedCount + $planZongLockedCount + $zhanweiCount)) return \Yz::echoError1('当前预约时间名额不足');
|
|
|
|
|
if ($planZongCount < ($planZongUsedCount + $planZongLockedCount + $zhanweiCount)){
|
|
|
|
|
if($is_emergency!==1){
|
|
|
|
|
return \Yz::echoError1('当前预约时间名额不足');
|
|
|
|
|
}else{ //如果是紧急预约,则把未分配的 强制加到当前预约渠道
|
|
|
|
|
foreach ($roster_detail_counts as $key=> $roster_detail_count) {
|
|
|
|
|
if($roster_detail_count->appointment_type_id==$appointment_type){
|
|
|
|
|
$plan_qudao_tempCount[$key]=$weifenpeiCount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//判断某人这些待预约项目里,是否存在互斥
|
|
|
|
|
@ -363,28 +392,38 @@ WHERE
|
|
|
|
|
try {
|
|
|
|
|
//更新计划明细表使用数量
|
|
|
|
|
$up_plan_count_all_success =true;
|
|
|
|
|
$appointment_use_plan_detail_arr=[];//预约各个号源占用号源详情
|
|
|
|
|
foreach ($roster_detail_counts as $key => $planCount) {
|
|
|
|
|
if($plan_qudao_tempCount[$key]==0) continue;
|
|
|
|
|
$u = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['id' => $planCount->id])
|
|
|
|
|
->whereRaw('count >= (used_count + IFNULL(locked_count, 0) + ?)', [$plan_qudao_tempCount[$key]])
|
|
|
|
|
->increment('used_count',$plan_qudao_tempCount[$key]);
|
|
|
|
|
|
|
|
|
|
$query = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id]);
|
|
|
|
|
// 【核心修改】只有非紧急预约时,才检查名额是否充足
|
|
|
|
|
if ($is_emergency!==1) {
|
|
|
|
|
$query->whereRaw('count >= (used_count + IFNULL(locked_count, 0) + ?)', [$plan_qudao_tempCount[$key]]);
|
|
|
|
|
}
|
|
|
|
|
$u = $query->increment('used_count', $plan_qudao_tempCount[$key]);
|
|
|
|
|
|
|
|
|
|
if(!$u){
|
|
|
|
|
$up_plan_count_all_success=false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$appointment_use_plan_detail_arr[]=[
|
|
|
|
|
"roster_detail_count_id"=>$planCount->id,
|
|
|
|
|
"count"=>$plan_qudao_tempCount[$key],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($up_plan_count_all_success) {
|
|
|
|
|
foreach ($roster_detail_counts as $key => $planCount) {
|
|
|
|
|
$cha = DB::table('s_source_roster_detail_count')->where(['id' => $planCount->id])->first();
|
|
|
|
|
|
|
|
|
|
if ($is_emergency!==1) {
|
|
|
|
|
if ($cha->count < $cha->used_count + ($cha->locked_count ?? 0)) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return \Yz::echoError1('操作失败1');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return \Yz::echoError1('操作失败');
|
|
|
|
|
@ -405,10 +444,11 @@ WHERE
|
|
|
|
|
'xuhao' => $xvhao,
|
|
|
|
|
'appointment_type_id' => $appointment_type,
|
|
|
|
|
'qudao_appointment_type_id' => $appointment_type,
|
|
|
|
|
'appointment_use_plan_detail'=>$appointment_use_plan_detail_arr
|
|
|
|
|
];
|
|
|
|
|
$list_all_success =true;
|
|
|
|
|
$offset = 0;
|
|
|
|
|
|
|
|
|
|
$u_mainList=false;
|
|
|
|
|
foreach($plan_qudao_tempCount as $key=>$length){
|
|
|
|
|
if($length==0) continue;
|
|
|
|
|
$u_data['appointment_type_id']= $appointment_types[$key];
|
|
|
|
|
@ -445,7 +485,52 @@ WHERE
|
|
|
|
|
// if(count($mainlistids)>1) return \Yz::echoError1('请选择1条医嘱改约,暂不支持批量');
|
|
|
|
|
$note = "改约";
|
|
|
|
|
//如果是改约,则恢复原来的数量
|
|
|
|
|
$u_old = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $oldMainInfo->roster_id, 'appointment_type_id' => $oldMainInfo->appointment_type_id, ['used_count', '>', 0]])->decrement('used_count');
|
|
|
|
|
$useDetailJson = $oldMainInfo->appointment_use_plan_detail;
|
|
|
|
|
if (empty($useDetailJson)) {
|
|
|
|
|
return \Yz::echoError1('取消失败:缺少占位明细数据,无法精确回退,请联系管理员');
|
|
|
|
|
}
|
|
|
|
|
$useDetails = json_decode($useDetailJson, true);
|
|
|
|
|
if (!is_array($useDetails)) {
|
|
|
|
|
return \Yz::echoError1('取消失败:占位明细数据格式错误');
|
|
|
|
|
}
|
|
|
|
|
foreach ($useDetails as $detail) {
|
|
|
|
|
$rosterDetailCountId = $detail['roster_detail_count_id'] ?? null;
|
|
|
|
|
$countToRelease = (int)($detail['count'] ?? 0);
|
|
|
|
|
|
|
|
|
|
if (!$rosterDetailCountId || $countToRelease <= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$affected = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['id' => $rosterDetailCountId])
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->where('used_count', '>=', $countToRelease) // 防御性编程:确保不会减成负数
|
|
|
|
|
->decrement('used_count', $countToRelease);
|
|
|
|
|
if ($affected == 0) {
|
|
|
|
|
// 如果 affected 为 0,可能是记录不存在,或者 used_count 不足
|
|
|
|
|
$checkRecord = DB::table('s_source_roster_detail_count')->where(['id' => $rosterDetailCountId])->first();
|
|
|
|
|
if (!$checkRecord) {
|
|
|
|
|
Log::error("改约-号源记录缺失", [
|
|
|
|
|
'MainListId' => $oldMainInfo->id,
|
|
|
|
|
'count_id' => $rosterDetailCountId
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
if ($checkRecord->used_count < $countToRelease) {
|
|
|
|
|
// 【关键修改】:余额不足,但不阻断取消
|
|
|
|
|
$actualRelease = $checkRecord->used_count; // 最多只能退这么多
|
|
|
|
|
|
|
|
|
|
if ($actualRelease > 0) {
|
|
|
|
|
// 把剩余的余额全部退完,强制设为 0 (或者 decrement actualRelease)
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['id' => $rosterDetailCountId])
|
|
|
|
|
->update(['used_count' => 0]); // 直接置零,防止浮点数或并发问题
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 记录严重报警日志
|
|
|
|
|
$msg = "数据不一致警告:订单 {$oldMainInfo->id} 试图退还 {$countToRelease} 个名额,但渠道 {$rosterDetailCountId} 仅剩 {$checkRecord->used_count} 个。";
|
|
|
|
|
Log::error($msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -557,116 +642,50 @@ WHERE
|
|
|
|
|
if ($mainInfo->list_status != 1) {
|
|
|
|
|
return \Yz::echoError1('该记录无法取消,当前状态:' . $mainInfo->list_status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 获取检查项目信息(判断是否可用)
|
|
|
|
|
$item = DB::table('s_check_item')
|
|
|
|
|
->where(['item_code' => $mainInfo->entrust_code, 'status' => 1, 'is_del' => 0])
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$item) {
|
|
|
|
|
return \Yz::echoError1('此检查项目不可用');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$zhanweiCount = (int)$item->use_seats; // 该预约占用的号源数量
|
|
|
|
|
$rosterId = $mainInfo->roster_id; // 排班详情ID
|
|
|
|
|
|
|
|
|
|
if ($zhanweiCount <= 0) {
|
|
|
|
|
$zhanweiCount = 1; // 防止配置错误,默认至少占1个号源
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 查询排班详情并加锁(确保号源操作安全)
|
|
|
|
|
$planInfo = DB::table('s_source_roster_detail')
|
|
|
|
|
->where(['id' => $rosterId])
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$planInfo) {
|
|
|
|
|
return \Yz::echoError1('号源排班信息不存在');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 获取当前预约类型的合并渠道配置
|
|
|
|
|
$appointment_type_link = DB::table('s_appointment_type_ratio')
|
|
|
|
|
->where([
|
|
|
|
|
'department_id' => $planInfo->department_id,
|
|
|
|
|
'appointment_type_id' => $mainInfo->appointment_type_id
|
|
|
|
|
])
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
// 构建可用的预约类型列表(包含自身 + 合并渠道)
|
|
|
|
|
$appointment_types = [$mainInfo->appointment_type_id];
|
|
|
|
|
if (!empty($appointment_type_link->link)) {
|
|
|
|
|
$linkTypes = json_decode($appointment_type_link->link, true);
|
|
|
|
|
if (is_array($linkTypes)) {
|
|
|
|
|
$appointment_types = array_merge($appointment_types, $linkTypes);
|
|
|
|
|
}
|
|
|
|
|
$appointment_types = array_unique($appointment_types); // 去重
|
|
|
|
|
sort($appointment_types);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. 获取当前渠道已使用的号源数量
|
|
|
|
|
$currentCountRecord = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $mainInfo->appointment_type_id])
|
|
|
|
|
->lockForUpdate() // 加锁
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$currentCountRecord) {
|
|
|
|
|
return \Yz::echoError1('当前渠道号源计数记录不存在');
|
|
|
|
|
$useDetailJson = $mainInfo->appointment_use_plan_detail;
|
|
|
|
|
if (empty($useDetailJson)) {
|
|
|
|
|
return \Yz::echoError1('取消失败:缺少占位明细数据,无法精确回退,请联系管理员');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$usedCurrent = (int)$currentCountRecord->used_count;
|
|
|
|
|
|
|
|
|
|
// 7. 开始释放号源:优先从当前渠道释放,不足则从合并渠道扣除
|
|
|
|
|
$remainingRelease = $zhanweiCount; // 还需释放的数量
|
|
|
|
|
|
|
|
|
|
// 先从当前预约类型渠道释放
|
|
|
|
|
if ($usedCurrent >= $remainingRelease) {
|
|
|
|
|
// 当前渠道足够释放
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $mainInfo->appointment_type_id])
|
|
|
|
|
->decrement('used_count', $remainingRelease);
|
|
|
|
|
$remainingRelease = 0;
|
|
|
|
|
} else {
|
|
|
|
|
// 当前渠道不够,全部释放当前渠道
|
|
|
|
|
$releasedFromCurrent = $usedCurrent;
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $mainInfo->appointment_type_id])
|
|
|
|
|
->update(['used_count' => 0]);
|
|
|
|
|
$remainingRelease -= $releasedFromCurrent;
|
|
|
|
|
$useDetails = json_decode($useDetailJson, true);
|
|
|
|
|
if (!is_array($useDetails)) {
|
|
|
|
|
return \Yz::echoError1('取消失败:占位明细数据格式错误');
|
|
|
|
|
}
|
|
|
|
|
foreach ($useDetails as $detail) {
|
|
|
|
|
$rosterDetailCountId = $detail['roster_detail_count_id'] ?? null;
|
|
|
|
|
$countToRelease = (int)($detail['count'] ?? 0);
|
|
|
|
|
|
|
|
|
|
// 如果还有剩余要释放的号源,从合并渠道中扣除
|
|
|
|
|
if ($remainingRelease > 0) {
|
|
|
|
|
foreach ($appointment_types as $typeId) {
|
|
|
|
|
// 跳过当前已处理的渠道
|
|
|
|
|
if ($typeId == $mainInfo->appointment_type_id) {
|
|
|
|
|
if (!$rosterDetailCountId || $countToRelease <= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$mergeCountRecord = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $typeId])
|
|
|
|
|
$affected = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['id' => $rosterDetailCountId])
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$mergeCountRecord || $mergeCountRecord->used_count <= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
->where('used_count', '>=', $countToRelease) // 防御性编程:确保不会减成负数
|
|
|
|
|
->decrement('used_count', $countToRelease);
|
|
|
|
|
if ($affected == 0) {
|
|
|
|
|
// 如果 affected 为 0,可能是记录不存在,或者 used_count 不足
|
|
|
|
|
$checkRecord = DB::table('s_source_roster_detail_count')->where(['id' => $rosterDetailCountId])->first();
|
|
|
|
|
if (!$checkRecord) {
|
|
|
|
|
Log::error("取消预约-记录缺失", [
|
|
|
|
|
'MainListId' => $MainListId,
|
|
|
|
|
'count_id' => $rosterDetailCountId
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
if ($checkRecord->used_count < $countToRelease) {
|
|
|
|
|
// 【关键修改】:余额不足,但不阻断取消
|
|
|
|
|
$actualRelease = $checkRecord->used_count; // 最多只能退这么多
|
|
|
|
|
|
|
|
|
|
$deduct = min($mergeCountRecord->used_count, $remainingRelease);
|
|
|
|
|
if ($actualRelease > 0) {
|
|
|
|
|
// 把剩余的余额全部退完,强制设为 0 (或者 decrement actualRelease)
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $typeId])
|
|
|
|
|
->decrement('used_count', $deduct);
|
|
|
|
|
|
|
|
|
|
$remainingRelease -= $deduct;
|
|
|
|
|
|
|
|
|
|
if ($remainingRelease <= 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
->where(['id' => $rosterDetailCountId])
|
|
|
|
|
->update(['used_count' => 0]); // 直接置零,防止浮点数或并发问题
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果最终仍无法完全释放所需号源数量,说明数据异常(理论上不应发生)
|
|
|
|
|
if ($remainingRelease > 0) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return \Yz::echoError1('号源释放失败:合并渠道号源不足,无法完成释放');
|
|
|
|
|
// 记录严重报警日志
|
|
|
|
|
$msg = "数据不一致警告:订单 {$MainListId} 试图退还 {$countToRelease} 个名额,但渠道 {$rosterDetailCountId} 仅剩 {$checkRecord->used_count} 个。";
|
|
|
|
|
Log::error($msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|