|
|
<?php
|
|
|
|
|
|
namespace Tests\Feature;
|
|
|
|
|
|
use App\Services\Admin\YeWu\PlanListService;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
use Tests\TestCase;
|
|
|
|
|
|
class PlanListServiceTest extends TestCase
|
|
|
{
|
|
|
protected function setUp(): void
|
|
|
{
|
|
|
parent::setUp();
|
|
|
$this->initTestData();
|
|
|
}
|
|
|
|
|
|
protected function tearDown(): void
|
|
|
{
|
|
|
$this->cleanupTestData();
|
|
|
parent::tearDown();
|
|
|
}
|
|
|
|
|
|
private function initTestData()
|
|
|
{
|
|
|
$this->cleanupTestData();
|
|
|
|
|
|
DB::table('s_department')->insert([
|
|
|
'id' => 9999,
|
|
|
'department_name' => '测试科室',
|
|
|
'department_number' => 'TEST001',
|
|
|
'department_status' => 1,
|
|
|
'is_del' => 0,
|
|
|
]);
|
|
|
|
|
|
DB::table('s_appointment_type')->insert([
|
|
|
'id' => 9999,
|
|
|
'name' => '测试渠道',
|
|
|
'jiancheng' => '测试',
|
|
|
'status' => 1,
|
|
|
'is_del' => 0,
|
|
|
]);
|
|
|
|
|
|
DB::table('s_period')->insert([
|
|
|
'id' => 9999,
|
|
|
'period_name' => '测试时段',
|
|
|
'period_begin_time' => '08:00:00',
|
|
|
'period_end_time' => '10:00:00',
|
|
|
'department_id' => 9999,
|
|
|
'date_type' => 1,
|
|
|
'period_status' => 1,
|
|
|
]);
|
|
|
|
|
|
DB::table('s_department_resources')->insert([
|
|
|
'id' => 9999,
|
|
|
'department_id' => 9999,
|
|
|
'department_resources_name' => '测试资源',
|
|
|
'is_del' => 0,
|
|
|
]);
|
|
|
|
|
|
DB::table('s_source_roster_detail')->insert([
|
|
|
'id' => 9999,
|
|
|
'department_id' => 9999,
|
|
|
'resources_id' => 9999,
|
|
|
'period_id' => 9999,
|
|
|
'device_id' => '1',
|
|
|
'date' => date('Y-m-d', strtotime('+1 day')),
|
|
|
'begin_time' => '08:00:00',
|
|
|
'end_time' => '10:00:00',
|
|
|
'end_reservation_time' => '23:59:59',
|
|
|
'patient_type' => '0,1,2,3',
|
|
|
'weekname' => '1',
|
|
|
'status' => 1,
|
|
|
'is_del' => 0,
|
|
|
]);
|
|
|
|
|
|
DB::table('s_source_roster_detail_count')->insert([
|
|
|
'id' => 9999,
|
|
|
'roster_detail_id' => 9999,
|
|
|
'appointment_type_id' => 9999,
|
|
|
'count' => 10,
|
|
|
'used_count' => 3,
|
|
|
'locked_count' => 0,
|
|
|
'version' => 1,
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
private function cleanupTestData()
|
|
|
{
|
|
|
DB::table('s_list')->where('reg_num', 'like', 'TEST_REG_%')->delete();
|
|
|
DB::table('s_list_log')->where('reg_num', 'like', 'TEST_REG_%')->delete();
|
|
|
|
|
|
$tables = [
|
|
|
's_source_roster_detail_count',
|
|
|
's_source_roster_detail', 's_department_resources',
|
|
|
's_period', 's_appointment_type', 's_department'
|
|
|
];
|
|
|
foreach ($tables as $table) {
|
|
|
DB::table($table)->where('id', '>=', 9999)->delete();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private function createTestList($status = 1, $detail = 'default')
|
|
|
{
|
|
|
if ($detail === 'default') {
|
|
|
$detail = json_encode([['roster_detail_count_id' => 9999, 'count' => 2]]);
|
|
|
}
|
|
|
|
|
|
return DB::table('s_list')->insertGetId([
|
|
|
'list_status' => $status,
|
|
|
'reg_num' => 'TEST_REG_' . time() . '_' . rand(1000, 9999),
|
|
|
'user_name' => '测试患者',
|
|
|
'entrust' => '测试检查项目',
|
|
|
'entrust_code' => 'TEST001',
|
|
|
'patient_type' => 1,
|
|
|
'roster_id' => 9999,
|
|
|
'appointment_type_id' => 9999,
|
|
|
'appointment_use_plan_detail' => $detail,
|
|
|
'reservation_date' => date('Y-m-d', strtotime('+1 day')),
|
|
|
'reservation_time' => 9999,
|
|
|
'is_del' => 0,
|
|
|
'is_nullify' => 0,
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
public function test_release_source_from_detail()
|
|
|
{
|
|
|
$countBefore = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(3, $countBefore->used_count);
|
|
|
|
|
|
$detail = json_encode([['roster_detail_count_id' => 9999, 'count' => 2]]);
|
|
|
$listId = $this->createTestList(1, $detail);
|
|
|
|
|
|
$service = new PlanListService();
|
|
|
$result = $service->releaseSourceFromDetail($listId);
|
|
|
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$countAfter = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(1, $countAfter->used_count);
|
|
|
$this->assertEquals(2, $countAfter->version);
|
|
|
|
|
|
echo "\n✅ 测试1通过: releaseSourceFromDetail 精确释放号源成功\n";
|
|
|
echo " 释放前 used_count=3, 释放后 used_count=1, version从1变为2\n";
|
|
|
}
|
|
|
|
|
|
public function test_release_source_with_version_check()
|
|
|
{
|
|
|
DB::table('s_source_roster_detail_count')->where('id', 9999)->update(['version' => 5]);
|
|
|
|
|
|
$detail = json_encode([['roster_detail_count_id' => 9999, 'count' => 1]]);
|
|
|
$listId = $this->createTestList(1, $detail);
|
|
|
|
|
|
$service = new PlanListService();
|
|
|
$result = $service->releaseSourceFromDetail($listId);
|
|
|
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$countAfter = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(6, $countAfter->version);
|
|
|
|
|
|
echo "\n✅ 测试2通过: 乐观锁version正确递增\n";
|
|
|
echo " 释放前 version=5, 释放后 version=6\n";
|
|
|
}
|
|
|
|
|
|
public function test_release_source_fallback_when_no_detail()
|
|
|
{
|
|
|
DB::table('s_source_roster_detail_count')->where('id', 9999)->update(['used_count' => 3, 'version' => 1]);
|
|
|
DB::table('s_list')->where('reg_num', 'like', 'TEST_REG_%')->delete();
|
|
|
|
|
|
$listId = $this->createTestList(1, null);
|
|
|
$mainInfo = DB::table('s_list')->where('id', $listId)->first();
|
|
|
|
|
|
$countBefore = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(3, $countBefore->used_count, '初始used_count应为3');
|
|
|
|
|
|
$service = new PlanListService();
|
|
|
$result = $service->releaseSourceFromDetail($listId, $mainInfo);
|
|
|
|
|
|
$this->assertTrue($result, 'releaseSourceFromDetail应返回true');
|
|
|
|
|
|
$countAfter = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(2, $countAfter->used_count, '释放后used_count应为2');
|
|
|
|
|
|
echo "\n✅ 测试3通过: 无明细时fallback降级释放成功\n";
|
|
|
echo " 无appointment_use_plan_detail时,按roster_id+appointment_type_id释放1个名额\n";
|
|
|
}
|
|
|
|
|
|
public function test_release_source_multiple_channels()
|
|
|
{
|
|
|
DB::table('s_source_roster_detail_count')->insert([
|
|
|
'id' => 10000,
|
|
|
'roster_detail_id' => 9999,
|
|
|
'appointment_type_id' => 10000,
|
|
|
'count' => 5,
|
|
|
'used_count' => 3,
|
|
|
'locked_count' => 0,
|
|
|
'version' => 1,
|
|
|
]);
|
|
|
|
|
|
$detail = json_encode([
|
|
|
['roster_detail_count_id' => 9999, 'count' => 2],
|
|
|
['roster_detail_count_id' => 10000, 'count' => 1],
|
|
|
]);
|
|
|
$listId = $this->createTestList(1, $detail);
|
|
|
|
|
|
$service = new PlanListService();
|
|
|
$result = $service->releaseSourceFromDetail($listId);
|
|
|
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$count1 = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$count2 = DB::table('s_source_roster_detail_count')->where('id', 10000)->first();
|
|
|
|
|
|
$this->assertEquals(1, $count1->used_count);
|
|
|
$this->assertEquals(2, $count2->used_count);
|
|
|
|
|
|
DB::table('s_source_roster_detail_count')->where('id', 10000)->delete();
|
|
|
|
|
|
echo "\n✅ 测试4通过: 多渠道合并号源精确释放成功\n";
|
|
|
echo " 渠道9999: used_count从3变为1\n";
|
|
|
echo " 渠道10000: used_count从3变为2\n";
|
|
|
}
|
|
|
|
|
|
public function test_release_source_with_insufficient_used_count()
|
|
|
{
|
|
|
DB::table('s_source_roster_detail_count')->where('id', 9999)->update(['used_count' => 1]);
|
|
|
|
|
|
$detail = json_encode([['roster_detail_count_id' => 9999, 'count' => 5]]);
|
|
|
$listId = $this->createTestList(1, $detail);
|
|
|
|
|
|
$service = new PlanListService();
|
|
|
$result = $service->releaseSourceFromDetail($listId);
|
|
|
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$countAfter = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(0, $countAfter->used_count);
|
|
|
|
|
|
echo "\n✅ 测试5通过: 释放数量大于used_count时,置零并记录警告日志\n";
|
|
|
echo " 尝试释放5个,实际只有1个,已置零并记录日志\n";
|
|
|
}
|
|
|
|
|
|
public function test_cancel_yu_yue_clears_detail()
|
|
|
{
|
|
|
$detail = json_encode([['roster_detail_count_id' => 9999, 'count' => 2]]);
|
|
|
$listId = $this->createTestList(1, $detail);
|
|
|
$listInfo = DB::table('s_list')->where('id', $listId)->first();
|
|
|
|
|
|
$service = new PlanListService();
|
|
|
$result = $service->CancelYuYue($listId, $listInfo->reg_num);
|
|
|
|
|
|
$this->assertTrue($result['status']);
|
|
|
|
|
|
$listAfter = DB::table('s_list')->where('id', $listId)->first();
|
|
|
$this->assertEquals(0, $listAfter->list_status);
|
|
|
$this->assertNull($listAfter->appointment_use_plan_detail);
|
|
|
|
|
|
$countAfter = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$this->assertEquals(1, $countAfter->used_count);
|
|
|
|
|
|
echo "\n✅ 测试6通过: CancelYuYue正确释放号源并清空明细\n";
|
|
|
echo " list_status变为0, appointment_use_plan_detail被清空\n";
|
|
|
echo " used_count从3变为1\n";
|
|
|
}
|
|
|
|
|
|
public function test_optimistic_lock_conflict_detection()
|
|
|
{
|
|
|
$countRecord = DB::table('s_source_roster_detail_count')->where('id', 9999)->first();
|
|
|
$oldVersion = $countRecord->version;
|
|
|
|
|
|
$affected = DB::table('s_source_roster_detail_count')
|
|
|
->where(['id' => 9999, 'version' => $oldVersion])
|
|
|
->update([
|
|
|
'used_count' => DB::raw('used_count + 1'),
|
|
|
'version' => DB::raw('version + 1'),
|
|
|
]);
|
|
|
|
|
|
$this->assertEquals(1, $affected);
|
|
|
|
|
|
$conflictAffected = DB::table('s_source_roster_detail_count')
|
|
|
->where(['id' => 9999, 'version' => $oldVersion])
|
|
|
->update([
|
|
|
'used_count' => DB::raw('used_count + 1'),
|
|
|
'version' => DB::raw('version + 1'),
|
|
|
]);
|
|
|
|
|
|
$this->assertEquals(0, $conflictAffected);
|
|
|
|
|
|
echo "\n✅ 测试7通过: 乐观锁冲突检测生效\n";
|
|
|
echo " 第一次更新成功(affected=1)\n";
|
|
|
echo " 第二次使用旧version更新失败(affected=0)\n";
|
|
|
}
|
|
|
} |