更新
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/** 仅测试显式指定的本机临时 MySQL;不 initialize 应用、不读取 .env。 */
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__) . '/vendor/topthink/framework/src/helper.php';
|
||||
|
||||
use app\adminapi\logic\stats\RevisitCohortLogic as L;
|
||||
use app\adminapi\logic\stats\RevisitRateLogic as Original;
|
||||
use app\adminapi\controller\stats\RevisitRateController;
|
||||
use app\adminapi\controller\stats\RevisitAssignRateController;
|
||||
use app\adminapi\controller\stats\RevisitInheritRateController;
|
||||
use think\Container;
|
||||
|
||||
$port = (int) getenv('REVISIT_COHORT_TEST_MYSQL_PORT');
|
||||
if ($port < 1024 || $port === 3306 || getenv('REVISIT_COHORT_TEST_DISPOSABLE') !== '1') {
|
||||
throw new RuntimeException('Set REVISIT_COHORT_TEST_DISPOSABLE=1 and an isolated loopback MySQL port');
|
||||
}
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$database = 'revisit_cohort_' . bin2hex(random_bytes(6));
|
||||
$pdo = new PDO("mysql:host=127.0.0.1;port={$port};charset=utf8mb4", 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
||||
$pdo->exec("CREATE DATABASE `{$database}` CHARACTER SET utf8mb4");
|
||||
$pdo->exec("USE `{$database}`");
|
||||
new think\App();
|
||||
$manager = new think\DbManager();
|
||||
$manager->setConfig(['default' => 'mysql', 'connections' => ['mysql' => [
|
||||
'type' => 'mysql', 'hostname' => '127.0.0.1', 'hostport' => $port, 'database' => $database,
|
||||
'username' => 'root', 'password' => '', 'charset' => 'utf8mb4', 'prefix' => 'zyt_',
|
||||
'fields_strict' => true, 'trigger_sql' => false,
|
||||
]]]);
|
||||
Container::getInstance()->instance('think\DbManager', $manager);
|
||||
Container::getInstance()->instance('config', new think\Config());
|
||||
$checks = 0;
|
||||
$expect = static function (bool $condition, string $message) use (&$checks): void {
|
||||
if (!$condition) {
|
||||
throw new RuntimeException('FAIL: ' . $message);
|
||||
}
|
||||
$checks++;
|
||||
};
|
||||
try {
|
||||
$pdo->exec('CREATE TABLE zyt_dept(id INT PRIMARY KEY,pid INT,name VARCHAR(50),sort INT DEFAULT 0,delete_time INT NULL)');
|
||||
$pdo->exec("INSERT INTO zyt_dept(id,pid,name) VALUES(10,0,'一中心'),(11,10,'一组'),(20,0,'二中心'),(21,20,'二中心甲组'),(22,20,'乙组')");
|
||||
$pdo->exec('CREATE TABLE zyt_admin(id INT PRIMARY KEY,name VARCHAR(50),delete_time INT NULL)');
|
||||
$pdo->exec("INSERT INTO zyt_admin VALUES(1,'医助甲',NULL),(2,'医助乙',NULL),(3,'一中心员工',NULL),(4,'已删除',1)");
|
||||
$pdo->exec('CREATE TABLE zyt_admin_dept(admin_id INT,dept_id INT,PRIMARY KEY(admin_id,dept_id))');
|
||||
$pdo->exec('INSERT INTO zyt_admin_dept VALUES(1,21),(2,22),(3,11),(4,21)');
|
||||
$pdo->exec('CREATE TABLE zyt_tcm_diagnosis(id INT PRIMARY KEY,patient_name VARCHAR(50),phone VARCHAR(20),revisit_slot_start_offset INT DEFAULT 0,delete_time INT NULL)');
|
||||
for ($id = 10; $id <= 17; $id++) {
|
||||
$pdo->prepare('INSERT INTO zyt_tcm_diagnosis(id,patient_name,phone,delete_time) VALUES(?,?,?,?)')
|
||||
->execute([$id, '虚构患者' . $id, '13800000000', $id === 16 ? 1 : null]);
|
||||
}
|
||||
$pdo->exec('CREATE TABLE zyt_tcm_diagnosis_assign_log(id INT PRIMARY KEY AUTO_INCREMENT,diagnosis_id INT,from_assistant_id INT,to_assistant_id INT,operator_admin_id INT DEFAULT 7,create_time INT,is_inherit INT DEFAULT 0,inherit_visit_slot INT DEFAULT 0)');
|
||||
$pdo->exec('CREATE TABLE zyt_tcm_diagnosis_auto_assign_log(diagnosis_id INT,rollback_time INT,rollback_admin_id INT)');
|
||||
$pdo->exec('CREATE TABLE zyt_tcm_prescription_order(id INT PRIMARY KEY AUTO_INCREMENT,order_no VARCHAR(50),diagnosis_id INT,create_time INT,amount DECIMAL(10,2) DEFAULT 100,creator_id INT DEFAULT 1,fulfillment_status INT NULL,delete_time INT NULL)');
|
||||
$lg = $pdo->prepare('INSERT INTO zyt_tcm_diagnosis_assign_log(diagnosis_id,from_assistant_id,to_assistant_id,create_time,is_inherit) VALUES(?,?,?,?,?)');
|
||||
foreach ([[10,0,1,'2026-09-01',0],[10,1,2,'2026-09-20',1],[11,0,1,'2026-08-01',0],
|
||||
[12,0,2,'2026-09-03',0],[13,0,3,'2026-09-03',0],[14,0,1,'2026-09-04',0],
|
||||
[15,0,1,'2026-08-01',0],[15,1,2,'2026-09-15',1],[16,0,1,'2026-09-01',0],
|
||||
[17,1,1,'2026-09-01',0]] as [$did,$from,$to,$date,$inherit]) {
|
||||
$lg->execute([$did,$from,$to,strtotime($date),$inherit]);
|
||||
}
|
||||
$o = $pdo->prepare('INSERT INTO zyt_tcm_prescription_order(order_no,diagnosis_id,create_time,fulfillment_status) VALUES(?,?,?,?)');
|
||||
foreach ([[10,'2026-09-02',3],[10,'2026-09-05',3],[10,'2026-10-01',3],[10,'2026-10-05',3],
|
||||
[11,'2026-08-02',3],[11,'2026-10-01',3],[13,'2026-09-05',3],[13,'2026-09-06',3],
|
||||
[14,'2026-09-05',3],[14,'2026-09-06',9],[15,'2026-08-02',3],[15,'2026-08-03',3],
|
||||
[15,'2026-08-04',3],[15,'2026-09-16',3],[15,'2026-09-17',4],[15,'2026-10-02',3]] as $i => [$did,$date,$status]) {
|
||||
$o->execute(['SYNTHETIC-' . $i,$did,strtotime($date),$status]);
|
||||
}
|
||||
$q = ['start_date' => '2026-09-01', 'end_date' => '2026-09-30'];
|
||||
$invoke = static function (string $class, string $action, array $params): array {
|
||||
$controller = (new ReflectionClass($class))->newInstanceWithoutConstructor();
|
||||
$request = (new think\Request())->withGet($params);
|
||||
$property = (new ReflectionClass(app\BaseController::class))->getProperty('request');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue($controller, $request);
|
||||
return $controller->$action()->getData()['data'];
|
||||
};
|
||||
foreach (['exclude', 'slot'] as $mode) {
|
||||
$legacyParams = ['month' => '2026-09', 'inherit_mode' => $mode];
|
||||
foreach (['overview', 'assignLines', 'visitOrderLines'] as $action) {
|
||||
$params = $legacyParams + ['slot' => 0];
|
||||
$expect($invoke(RevisitRateController::class, $action, $params) === Original::$action($params),
|
||||
'原Controller实际响应与原算法一致:' . $mode . '/' . $action);
|
||||
}
|
||||
}
|
||||
$legacyBaseline = Original::overview(['month' => '2026-09', 'inherit_mode' => 'exclude']);
|
||||
$expect($legacyBaseline['total']['assigned_count'] === 3 && $legacyBaseline['total']['visit4_count'] === 1,
|
||||
'原算法保留原自指派分母及当月继承订单分子规则');
|
||||
$expect($invoke(RevisitRateController::class, 'deptOptions', []) === Original::deptOptions(), '原部门下拉契约不增加新报表字段');
|
||||
$new = L::overview($q);
|
||||
$expect($invoke(RevisitAssignRateController::class, 'overview', $q + ['cohort_type' => 'inherit'])['cohort_type'] === 'new', '新指派入口固定new且使用独立Controller');
|
||||
$expect($invoke(RevisitInheritRateController::class, 'overview', $q + ['cohort_type' => 'new'])['cohort_type'] === 'inherit', '继承入口固定inherit');
|
||||
$expect(Original::overview(['month' => '2026-09', 'inherit_mode' => 'exclude']) === $legacyBaseline,
|
||||
'查询新报表不改变原报表响应');
|
||||
$expect($new['total']['assigned_count'] === 2 && $new['total']['visit2_count'] === 1, '只圈定周期内新指派,排除区间外、继承、其他中心、自指派、软删、拒收');
|
||||
$expect($new['total']['visit2_rate'] === 50.0 && $new['total']['inherit_count'] === 0, '新指派接诊率仅用新指派分母');
|
||||
$inherit = L::overview($q, 'inherit');
|
||||
$expect($inherit['total']['inherit_count'] === 2 && $inherit['total']['visit2_count'] === 2 && $inherit['total']['visit3_count'] === 2, '继承首单二诊、次单三诊,累计周期后订单且排除取消单');
|
||||
$expect(L::overview($q + ['assistant_id' => 2])['total']['assigned_count'] === 1, '医助筛选作用于汇总');
|
||||
$expect(L::overview($q + ['assistant_id' => 2])['total']['visit2_count'] === 0, '医助名下继承成交不进入其新指派分子');
|
||||
$expect(L::overview($q + ['dept_ids' => '21'])['total']['assigned_count'] === 1, '部门子树过滤');
|
||||
$expect(L::overview($q + ['dept_ids' => '20'])['total'] === $new['total'], '二中心父级包含各组');
|
||||
$expect(L::overview($q + ['dept_ids' => '10'])['rows'] === [], '不能越过二中心范围');
|
||||
$expect(L::overview($q + ['assistant_id' => 3])['rows'] === [], '其他中心医助不能绕过部门范围');
|
||||
$expect(L::assignLines($q)['count'] === $new['total']['assigned_count'], '新指派患者明细与分母对账');
|
||||
$expect(L::visitOrderLines($q + ['slot' => 2])['count'] === $new['total']['visit2_count'], '新指派订单明细与分子对账');
|
||||
$expect(L::assignLines($q, 'inherit')['count'] === $inherit['total']['inherit_count'], '继承患者明细与分母对账');
|
||||
$expect(L::visitOrderLines($q + ['slot' => 0], 'inherit')['count'] === $inherit['total']['visit_all_count'], '继承合计订单明细与汇总对账');
|
||||
$expect(L::assignLines($q + ['assistant_id' => 2, 'dept_id' => 21])['count'] === 0, '下钻部门必须与页面医助取交集');
|
||||
$expect(L::visitOrderLines($q + ['assistant_id' => 2, 'scope_assistant_id' => 1, 'slot' => 0])['count'] === 0, '下钻不能覆盖页面医助筛选');
|
||||
$options = L::deptOptions();
|
||||
$optionIds = array_column($options['assistants'], 'id');
|
||||
sort($optionIds);
|
||||
$expect($optionIds === [1, 2], '下拉排除其他中心及已删除账号');
|
||||
$expect(count($options['rows']) === 3, '部门选项仍是二中心完整子树');
|
||||
|
||||
foreach ([18 => 0, 19 => 1] as $did => $isInherit) {
|
||||
$pdo->prepare('INSERT INTO zyt_tcm_diagnosis(id,patient_name,phone) VALUES(?,?,?)')->execute([$did, '返还患者' . $did, '13800000000']);
|
||||
$lg->execute([$did,0,1,strtotime('2026-08-01'),0]);
|
||||
$lg->execute([$did,1,0,strtotime('2026-08-10'),0]);
|
||||
$lg->execute([$did,1,1,strtotime('2026-09-01'),$isInherit]);
|
||||
$o->execute(['RETURN-OLD-' . $did,$did,strtotime('2026-08-02'),3]);
|
||||
$o->execute(['RETURN-NEW-' . $did,$did,strtotime('2026-09-02'),3]);
|
||||
}
|
||||
$expect(L::overview($q)['total']['assigned_count'] === 3 && L::overview($q)['total']['visit2_count'] === 2, '释放后重新新指派给原医助正常统计');
|
||||
$expect(L::overview($q, 'inherit')['total']['inherit_count'] === 3 && L::overview($q, 'inherit')['total']['visit2_count'] === 3, '释放后重新继承给原医助正常统计');
|
||||
|
||||
// 在实际 MySQL 5.7 验证菜单脚本、幂等性与逐权限继承。
|
||||
$pdo->exec('CREATE TABLE zyt_system_menu(id INT PRIMARY KEY AUTO_INCREMENT,pid INT,type VARCHAR(1),name VARCHAR(80),icon VARCHAR(80),sort INT,perms VARCHAR(120),paths VARCHAR(120),component VARCHAR(120),selected VARCHAR(120),params VARCHAR(120),is_cache INT,is_show INT,is_disable INT,create_time INT,update_time INT)');
|
||||
$pdo->exec('CREATE TABLE zyt_system_role_menu(role_id INT,menu_id INT,PRIMARY KEY(role_id,menu_id))');
|
||||
foreach (['overview','deptOptions','assignLines','visitOrderLines'] as $i => $action) {
|
||||
$pdo->prepare('INSERT INTO zyt_system_menu(pid,type,name,perms) VALUES(100,?,?,?)')
|
||||
->execute([$i === 0 ? 'C' : 'A', $action, 'stats.revisitRate/' . $action]);
|
||||
}
|
||||
$pdo->exec('INSERT INTO zyt_system_role_menu VALUES(9,1),(9,2),(9,3)');
|
||||
$originalMenus = $pdo->query('SELECT * FROM zyt_system_menu ORDER BY id')->fetchAll(PDO::FETCH_ASSOC);
|
||||
$migration = file_get_contents(dirname(__DIR__) . '/sql/1.9.20261016/01_add_revisit_inherit_rate_menu.sql');
|
||||
$migration = preg_replace('/^--.*$/m', '', $migration);
|
||||
for ($repeat = 0; $repeat < 2; $repeat++) {
|
||||
foreach (explode(';', $migration) as $sql) {
|
||||
if (trim($sql) !== '') { $pdo->exec($sql); }
|
||||
}
|
||||
}
|
||||
$expect((int) $pdo->query("SELECT COUNT(*) FROM zyt_system_menu WHERE perms LIKE 'stats.revisitInheritRate/%'")->fetchColumn() === 4, '迁移可重复执行,页面及3个接口各登记一次');
|
||||
$expect((int) $pdo->query('SELECT COUNT(*) FROM zyt_system_role_menu WHERE role_id=9')->fetchColumn() === 6, '仅继承原有的3项对应权限');
|
||||
$expect((int) $pdo->query("SELECT COUNT(*) FROM zyt_system_role_menu rm JOIN zyt_system_menu m ON m.id=rm.menu_id WHERE rm.role_id=9 AND m.perms='stats.revisitInheritRate/visitOrderLines'")->fetchColumn() === 0, '不扩大原角色明细权限');
|
||||
$assignMigration = preg_replace('/^--.*$/m', '', file_get_contents(dirname(__DIR__) . '/sql/1.9.20261017/01_add_revisit_assign_rate_menu.sql'));
|
||||
for ($repeat = 0; $repeat < 2; $repeat++) {
|
||||
foreach (explode(';', $assignMigration) as $sql) {
|
||||
if (trim($sql) !== '') { $pdo->exec($sql); }
|
||||
}
|
||||
}
|
||||
$expect((int) $pdo->query("SELECT COUNT(*) FROM zyt_system_menu WHERE perms LIKE 'stats.revisitAssignRate/%'")->fetchColumn() === 4, '独立指派周期页面及3个接口幂等登记');
|
||||
$expect((int) $pdo->query('SELECT COUNT(*) FROM zyt_system_role_menu WHERE role_id=9')->fetchColumn() === 9, '两个独立报表均逐权限继承原角色授权');
|
||||
$expect((int) $pdo->query("SELECT COUNT(*) FROM zyt_system_role_menu rm JOIN zyt_system_menu m ON m.id=rm.menu_id WHERE rm.role_id=9 AND m.perms='stats.revisitAssignRate/visitOrderLines'")->fetchColumn() === 0, '独立指派周期接口不扩大订单明细权限');
|
||||
$expect($pdo->query('SELECT * FROM zyt_system_menu WHERE id<=4 ORDER BY id')->fetchAll(PDO::FETCH_ASSOC) === $originalMenus, '新增菜单不会改写原菜单及权限记录');
|
||||
echo "RevisitCohortDatabaseTest OK ({$checks} checks)\n";
|
||||
} finally {
|
||||
$pdo->exec("DROP DATABASE `{$database}`");
|
||||
}
|
||||
Reference in New Issue
Block a user