This commit is contained in:
Your Name
2026-08-03 09:51:53 +08:00
parent 81d6a38e26
commit 22a371a733
10 changed files with 215 additions and 96 deletions
+9
View File
@@ -424,6 +424,15 @@ export function prescriptionOrderEdit(params: Record<string, unknown>) {
return request.post({ url: '/tcm.prescriptionOrder/edit', params }) return request.post({ url: '/tcm.prescriptionOrder/edit', params })
} }
/** 仅修改业务订单的承运商与快递单号;所有履约状态均可使用 */
export function prescriptionOrderDdcode(params: {
id: number
express_company: string
tracking_number: string
}) {
return request.post({ url: '/tcm.prescriptionOrder/ddcode', params })
}
/** 业务订单详情:仅修改关联处方的患者姓名与手机号 */ /** 业务订单详情:仅修改关联处方的患者姓名与手机号 */
export function prescriptionOrderPatchPrescriptionPatient(params: { export function prescriptionOrderPatchPrescriptionPatient(params: {
id: number id: number
@@ -2255,6 +2255,7 @@ import {
prescriptionOrderAuditPayment, prescriptionOrderAuditPayment,
prescriptionOrderAuditPrescription, prescriptionOrderAuditPrescription,
prescriptionOrderDetail, prescriptionOrderDetail,
prescriptionOrderDdcode,
prescriptionOrderEdit, prescriptionOrderEdit,
prescriptionOrderLists, prescriptionOrderLists,
prescriptionOrderExport, prescriptionOrderExport,
@@ -3243,9 +3244,8 @@ function canRefundRow(row: { fulfillment_status?: number; payment_slip_audit_sta
return (fs === 5 || fs === 6 || fs === 3 || fs === 9) && Number(row.payment_slip_audit_status) === 1 return (fs === 5 || fs === 6 || fs === 3 || fs === 9) && Number(row.payment_slip_audit_status) === 1
} }
function canQuickTrackRow(row: { fulfillment_status?: number }) { function canQuickTrackRow(_row: { fulfillment_status?: number }) {
// 仅已发货(5) 可修改快递单号;已签收(6) 不可再改 return true
return Number(row.fulfillment_status) === 5
} }
function canUploadPharmacyRow(row: { function canUploadPharmacyRow(row: {
@@ -4094,33 +4094,8 @@ async function submitQuickTrack() {
} }
quickTrackSaving.value = true quickTrackSaving.value = true
try { try {
// 先拉详情,获取所有必填字段,再只覆盖快递信息 await prescriptionOrderDdcode({
const res: any = await prescriptionOrderDetail({ id: quickTrackRowId.value }) id: quickTrackRowId.value,
const d = res?.data ?? res
if (!d) {
feedback.msgError('加载订单数据失败')
return
}
await prescriptionOrderEdit({
id: d.id,
recipient_name: d.recipient_name || '',
recipient_phone: d.recipient_phone || '',
shipping_province: d.shipping_province || '',
shipping_city: d.shipping_city || '',
shipping_district: d.shipping_district || '',
shipping_address: d.shipping_address || '',
is_follow_up: d.is_follow_up ? 1 : 0,
medication_days: (d.medication_days != null && String(d.medication_days).trim() !== '') ? d.medication_days : '',
prev_staff: d.prev_staff || '',
service_channel: d.service_channel || '',
service_package: d.service_package || '',
fee_type: Number(d.fee_type) || 3,
amount: Number(d.amount) || 0,
remark_extra: d.remark_extra || '',
remark_assistant: d.remark_assistant || '',
internal_cost: (d.internal_cost != null && d.internal_cost !== '') ? d.internal_cost : '',
pay_order_ids: Array.isArray(d.pay_order_ids) ? d.pay_order_ids : [],
// 仅覆盖快递字段
express_company: quickTrackForm.express_company || 'auto', express_company: quickTrackForm.express_company || 'auto',
tracking_number: quickTrackForm.tracking_number.trim() tracking_number: quickTrackForm.tracking_number.trim()
}) })
@@ -4129,17 +4104,6 @@ async function submitQuickTrack() {
getLists() getLists()
// 若详情 Drawer 打开且是同一订单,同步刷新 // 若详情 Drawer 打开且是同一订单,同步刷新
await detailDrawerRef.value?.refreshIfCurrent(quickTrackRowId.value) await detailDrawerRef.value?.refreshIfCurrent(quickTrackRowId.value)
// 仅保存前为履约中(2)时才询问确认发货;已发货(5)/已签收(6)等修改单号不再弹窗
if (canShipRow({ fulfillment_status: Number(d.fulfillment_status) })) {
try {
await ElMessageBox.confirm(
`快递单号「${quickTrackForm.tracking_number}」已保存,是否立即确认发货?`,
'确认发货',
{ type: 'success', confirmButtonText: '确认发货', cancelButtonText: '稍后再说' }
)
openShip({ id: quickTrackRowId.value, tracking_number: quickTrackForm.tracking_number, express_company: quickTrackForm.express_company })
} catch { /* 用户点了「稍后」 */ }
}
} catch { } catch {
/* 拦截器已提示 */ /* 拦截器已提示 */
} finally { } finally {
@@ -2713,6 +2713,7 @@ import {
prescriptionOrderAuditPayment, prescriptionOrderAuditPayment,
prescriptionOrderAuditPrescription, prescriptionOrderAuditPrescription,
prescriptionOrderDetail, prescriptionOrderDetail,
prescriptionOrderDdcode,
prescriptionOrderEdit, prescriptionOrderEdit,
prescriptionOrderLists, prescriptionOrderLists,
prescriptionOrderPaidPayOrders, prescriptionOrderPaidPayOrders,
@@ -3551,8 +3552,8 @@ function canRefundRow(row: { fulfillment_status?: number; payment_slip_audit_sta
return (fs === 5 || fs === 6 || fs === 3 || fs === 9) && Number(row.payment_slip_audit_status) === 1 return (fs === 5 || fs === 6 || fs === 3 || fs === 9) && Number(row.payment_slip_audit_status) === 1
} }
function canQuickTrackRow(row: { fulfillment_status?: number }) { function canQuickTrackRow(_row: { fulfillment_status?: number }) {
return Number(row.fulfillment_status) === 5 return true
} }
function canUploadPharmacyRow(row: { function canUploadPharmacyRow(row: {
@@ -4900,33 +4901,8 @@ async function submitQuickTrack() {
} }
quickTrackSaving.value = true quickTrackSaving.value = true
try { try {
// await prescriptionOrderDdcode({
const res: any = await prescriptionOrderDetail({ id: quickTrackRowId.value }) id: quickTrackRowId.value,
const d = res?.data ?? res
if (!d) {
feedback.msgError('加载订单数据失败')
return
}
await prescriptionOrderEdit({
id: d.id,
recipient_name: d.recipient_name || '',
recipient_phone: d.recipient_phone || '',
shipping_province: d.shipping_province || '',
shipping_city: d.shipping_city || '',
shipping_district: d.shipping_district || '',
shipping_address: d.shipping_address || '',
is_follow_up: d.is_follow_up ? 1 : 0,
medication_days: (d.medication_days != null && String(d.medication_days).trim() !== '') ? d.medication_days : '',
prev_staff: d.prev_staff || '',
service_channel: d.service_channel || '',
service_package: d.service_package || '',
fee_type: Number(d.fee_type) || 3,
amount: Number(d.amount) || 0,
remark_extra: d.remark_extra || '',
remark_assistant: d.remark_assistant || '',
internal_cost: (d.internal_cost != null && d.internal_cost !== '') ? d.internal_cost : '',
pay_order_ids: Array.isArray(d.pay_order_ids) ? d.pay_order_ids : [],
//
express_company: quickTrackForm.express_company || 'auto', express_company: quickTrackForm.express_company || 'auto',
tracking_number: quickTrackForm.tracking_number.trim() tracking_number: quickTrackForm.tracking_number.trim()
}) })
@@ -4939,19 +4915,9 @@ async function submitQuickTrack() {
const r: any = await prescriptionOrderDetail({ id: quickTrackRowId.value }) const r: any = await prescriptionOrderDetail({ id: quickTrackRowId.value })
const nd = r?.data ?? r ?? null const nd = r?.data ?? r ?? null
if (nd) detailData.value = nd if (nd) detailData.value = nd
await fetchLogs(quickTrackRowId.value)
} catch { /* 静默 */ } } catch { /* 静默 */ }
} }
// (2)(5)/(6)
if (canShipRow({ fulfillment_status: Number(d.fulfillment_status) })) {
try {
await ElMessageBox.confirm(
`快递单号「${quickTrackForm.tracking_number}」已保存,是否立即确认发货?`,
'确认发货',
{ type: 'success', confirmButtonText: '确认发货', cancelButtonText: '稍后再说' }
)
openShip({ id: quickTrackRowId.value, tracking_number: quickTrackForm.tracking_number, express_company: quickTrackForm.express_company })
} catch { /* 用户点了「稍后」 */ }
}
} catch { } catch {
/* 拦截器已提示 */ /* 拦截器已提示 */
} finally { } finally {
@@ -131,6 +131,26 @@ class PrescriptionOrderController extends BaseAdminController
return $this->success('保存成功', $result); return $this->success('保存成功', $result);
} }
/**
* 仅修改承运商与快递单号,不受订单履约状态或远端药房快照锁限制。
*/
public function ddcode()
{
$params = (new PrescriptionOrderValidate())->post()->goCheck('ddcode');
$result = PrescriptionOrderLogic::ddcode(
(int) $params['id'],
(string) ($params['express_company'] ?? 'auto'),
(string) $params['tracking_number'],
$this->adminId,
$this->adminInfo
);
if ($result === false) {
return $this->fail(PrescriptionOrderLogic::getError());
}
return $this->success('快递单号已保存', $result);
}
public function updateAmount() public function updateAmount()
{ {
$params = (new PrescriptionOrderValidate())->post()->goCheck('updateAmount'); $params = (new PrescriptionOrderValidate())->post()->goCheck('updateAmount');
@@ -1904,21 +1904,72 @@ class PrescriptionOrderLogic
} }
/** /**
* 甘草已提交后仅更新物流字段(tracking_number、express_company),忽略金额/地址等其它请求参数 * 仅修改承运商与快递单号。物流信息不属于药房下单快照,因此允许在所有履约状态下修正
* *
* @param array<string,mixed> $params
* @return array<string,mixed>|false * @return array<string,mixed>|false
*/ */
private static function editGancaoLogisticsOnly( public static function ddcode(
PrescriptionOrder $order, int $id,
array $params, string $expressCompany,
string $trackingNumber,
int $adminId, int $adminId,
array $adminInfo array $adminInfo
) { ) {
$order->tracking_number = mb_substr(trim((string) ($params['tracking_number'] ?? '')), 0, 80); self::setError('');
if (array_key_exists('express_company', $params)) { try {
$order->express_company = self::normalizeExpressCompany($params['express_company']); return LockedPharmacySnapshotMutation::execute(
$id,
static fn () => self::ddcodeLocked(
$id,
$expressCompany,
$trackingNumber,
$adminId,
$adminInfo
),
false
);
} catch (\Throwable $exception) {
if (self::getError() === '') {
self::setError($exception->getMessage());
}
return false;
} }
}
/** @return array<string,mixed>|false */
private static function ddcodeLocked(
int $id,
string $expressCompany,
string $trackingNumber,
int $adminId,
array $adminInfo
) {
self::$error = '';
$trackingNumber = mb_substr(trim($trackingNumber), 0, 80);
if ($trackingNumber === '') {
self::$error = '快递单号不能为空';
return false;
}
$order = PrescriptionOrder::where('id', $id)->whereNull('delete_time')->find();
if (!$order) {
self::$error = '订单不存在';
return false;
}
if (!self::canAccessOrder($order, $adminId, $adminInfo)) {
self::$error = '无权限操作';
return false;
}
$oldTrackingNumber = trim((string) ($order->tracking_number ?? ''));
$oldExpressCompany = self::normalizeExpressCompany((string) ($order->express_company ?? 'auto'));
$newExpressCompany = self::normalizeExpressCompany($expressCompany);
$order->tracking_number = $trackingNumber;
$order->express_company = $newExpressCompany;
try { try {
$order->save(); $order->save();
@@ -1932,8 +1983,15 @@ class PrescriptionOrderLogic
(int) $order->id, (int) $order->id,
$adminId, $adminId,
$adminInfo, $adminInfo,
'edit', 'fill_tracking',
'甘草订单已提交,仅更新快递信息(单号/承运商)' sprintf(
'修改快递信息:单号「%s」→「%s」,承运商「%s」→「%s」',
$oldTrackingNumber !== '' ? $oldTrackingNumber : '空',
$trackingNumber,
$oldExpressCompany,
$newExpressCompany
),
true
); );
$out = $order->toArray(); $out = $order->toArray();
@@ -5370,7 +5428,14 @@ class PrescriptionOrderLogic
]; ];
} }
private static function writeLog(int $orderId, int $adminId, array $adminInfo, string $action, string $summary): void private static function writeLog(
int $orderId,
int $adminId,
array $adminInfo,
string $action,
string $summary,
bool $strict = false
): void
{ {
$adminName = $adminInfo['name'] ?? ''; $adminName = $adminInfo['name'] ?? '';
if ($adminName === '' && $adminId > 0) { if ($adminName === '' && $adminId > 0) {
@@ -5388,7 +5453,10 @@ class PrescriptionOrderLogic
try { try {
$log->save(); $log->save();
} catch (\Throwable $e) { } catch (\Throwable $e) {
// 忽略日志写入错误 if ($strict) {
throw new \RuntimeException('操作日志写入失败,快递信息未保存', 0, $e);
}
// 非关键日志沿用历史容错行为
} }
} }
@@ -59,6 +59,7 @@ class PrescriptionOrderValidate extends BaseValidate
'action.require' => '请选择审核操作', 'action.require' => '请选择审核操作',
'patient_name.require' => '请输入患者姓名', 'patient_name.require' => '请输入患者姓名',
'phone.require' => '请输入手机号', 'phone.require' => '请输入手机号',
'tracking_number.require' => '请输入快递单号',
'phone_tail.regex' => '手机后四位仅支持数字', 'phone_tail.regex' => '手机后四位仅支持数字',
'reason.require' => '请填写退款原因', 'reason.require' => '请填写退款原因',
]; ];
@@ -75,6 +76,7 @@ class PrescriptionOrderValidate extends BaseValidate
'is_follow_up', 'prev_staff', 'service_channel', 'service_package', 'is_follow_up', 'prev_staff', 'service_channel', 'service_package',
'tracking_number', 'express_company', 'fee_type', 'amount', 'remark_extra', 'remark_assistant', 'pay_order_ids', 'tracking_number', 'express_company', 'fee_type', 'amount', 'remark_extra', 'remark_assistant', 'pay_order_ids',
], ],
'ddcode' => ['id', 'tracking_number', 'express_company'],
'logisticsTrace' => ['id', 'phone_tail'], 'logisticsTrace' => ['id', 'phone_tail'],
'logisticsJdUpdate' => ['id'], 'logisticsJdUpdate' => ['id'],
'auditPrescription' => ['id', 'action', 'remark'], 'auditPrescription' => ['id', 'action', 'remark'],
@@ -106,6 +108,14 @@ class PrescriptionOrderValidate extends BaseValidate
->append('amount', 'require|float|egt:0'); ->append('amount', 'require|float|egt:0');
} }
public function ddcode(): PrescriptionOrderValidate
{
return $this->only(['id', 'tracking_number', 'express_company'])
->append('id', 'require|integer|gt:0')
->append('tracking_number', 'require|max:80')
->append('express_company', 'max:20');
}
public function patchPrescriptionUsage(): PrescriptionOrderValidate public function patchPrescriptionUsage(): PrescriptionOrderValidate
{ {
return $this->only(['id', 'times_per_day', 'usage_days', 'medication_days', 'aux_times_per_day', 'aux_usage_days']) return $this->only(['id', 'times_per_day', 'usage_days', 'medication_days', 'aux_times_per_day', 'aux_usage_days'])
@@ -59,6 +59,17 @@ FROM DUAL
WHERE @po_menu_id IS NOT NULL WHERE @po_menu_id IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.prescriptionOrder/edit'); AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.prescriptionOrder/edit');
INSERT INTO zyt_system_menu (
pid, type, name, icon, sort, perms, paths, component,
selected, params, is_cache, is_show, is_disable, create_time, update_time
)
SELECT
@po_menu_id, 'A', '修改快递单号', '', 31, 'tcm.prescriptionOrder/ddcode', '', '',
'', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
FROM DUAL
WHERE @po_menu_id IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.prescriptionOrder/ddcode');
INSERT INTO zyt_system_menu ( INSERT INTO zyt_system_menu (
pid, type, name, icon, sort, perms, paths, component, pid, type, name, icon, sort, perms, paths, component,
selected, params, is_cache, is_show, is_disable, create_time, update_time selected, params, is_cache, is_show, is_disable, create_time, update_time
@@ -0,0 +1,23 @@
-- 处方业务订单:独立修改快递单号权限。
-- 执行后需在「角色权限」中为允许修改物流信息的角色勾选本按钮权限。
SET @po_menu_id := (
SELECT id
FROM zyt_system_menu
WHERE perms = 'tcm.prescriptionOrder/lists'
LIMIT 1
);
INSERT INTO zyt_system_menu (
pid, type, name, icon, sort, perms, paths, component,
selected, params, is_cache, is_show, is_disable, create_time, update_time
)
SELECT
@po_menu_id, 'A', '修改快递单号', '', 31,
'tcm.prescriptionOrder/ddcode', '', '',
'', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
FROM DUAL
WHERE @po_menu_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM zyt_system_menu WHERE perms = 'tcm.prescriptionOrder/ddcode'
);
@@ -23,6 +23,10 @@ $assertTrue(
str_contains($controllerSource, 'confirmGancaoSubmission'), str_contains($controllerSource, 'confirmGancaoSubmission'),
'admin API must expose an actionable Gancao reconciliation endpoint' 'admin API must expose an actionable Gancao reconciliation endpoint'
); );
$assertTrue(
str_contains($controllerSource, 'public function ddcode()'),
'admin API must expose a dedicated tracking correction endpoint'
);
$assertTrue( $assertTrue(
str_contains($migrationSource, '`lease_expires_at`'), str_contains($migrationSource, '`lease_expires_at`'),
'pharmacy submission claims must persist an explicit lease expiry' 'pharmacy submission claims must persist an explicit lease expiry'
+47 -3
View File
@@ -799,14 +799,14 @@ $assertTrue(
'remote payload must reload the canonical order after acquiring the durable claim' 'remote payload must reload the canonical order after acquiring the durable claim'
); );
$assertTrue( $assertTrue(
substr_count($prescriptionOrderLogicSource, 'LockedPharmacySnapshotMutation::execute(') >= 7, substr_count($prescriptionOrderLogicSource, 'LockedPharmacySnapshotMutation::execute(') >= 8,
'order edit, patient, ship, withdraw, audit revoke, ship-mode and usage mutations must run inside locked snapshot transactions' 'order edit, logistics, patient, ship, withdraw, audit revoke, ship-mode and usage mutations must run inside locked snapshot transactions'
); );
$assertTrue( $assertTrue(
substr_count($prescriptionLogicSource, 'LockedPharmacySnapshotMutation::executeForPrescription(') >= 4, substr_count($prescriptionLogicSource, 'LockedPharmacySnapshotMutation::executeForPrescription(') >= 4,
'prescription edit, patient patch, delete and void must lock every linked order and claim before saving' 'prescription edit, patient patch, delete and void must lock every linked order and claim before saving'
); );
foreach (['patchPrescriptionPatient', 'edit', 'ship', 'withdraw', 'revokeRxAudit', 'setShipMode', 'patchPrescriptionUsage'] as $method) { foreach (['patchPrescriptionPatient', 'edit', 'ddcode', 'ship', 'withdraw', 'revokeRxAudit', 'setShipMode', 'patchPrescriptionUsage'] as $method) {
$start = (int) strpos($prescriptionOrderLogicSource, 'public static function ' . $method . '('); $start = (int) strpos($prescriptionOrderLogicSource, 'public static function ' . $method . '(');
$end = (int) strpos($prescriptionOrderLogicSource, 'private static function ' . $method . 'Locked(', $start); $end = (int) strpos($prescriptionOrderLogicSource, 'private static function ' . $method . 'Locked(', $start);
$wrapperSource = substr($prescriptionOrderLogicSource, $start, $end - $start); $wrapperSource = substr($prescriptionOrderLogicSource, $start, $end - $start);
@@ -844,6 +844,35 @@ $assertTrue(
!str_contains($shipLockedSource, '->ship_mode ='), !str_contains($shipLockedSource, '->ship_mode ='),
'shipping logistics must never overwrite the pharmacy target snapshot' 'shipping logistics must never overwrite the pharmacy target snapshot'
); );
$ddcodeStart = (int) strpos($prescriptionOrderLogicSource, 'public static function ddcode(');
$ddcodeLockedStart = (int) strpos($prescriptionOrderLogicSource, 'private static function ddcodeLocked(', $ddcodeStart);
$ddcodeEnd = (int) strpos($prescriptionOrderLogicSource, 'public static function ship(', $ddcodeLockedStart);
$ddcodeWrapperSource = substr($prescriptionOrderLogicSource, $ddcodeStart, $ddcodeLockedStart - $ddcodeStart);
$ddcodeLockedSource = substr($prescriptionOrderLogicSource, $ddcodeLockedStart, $ddcodeEnd - $ddcodeLockedStart);
$assertTrue(
(bool) preg_match(
'/LockedPharmacySnapshotMutation::execute\(.*?self::ddcodeLocked\(.*?\),\s*false\s*\)/s',
$ddcodeWrapperSource
),
'tracking correction must keep row locks and transactions while bypassing only the remote snapshot mutability assertion'
);
preg_match_all('/\$order->([a-z_]+)\s*=/', $ddcodeLockedSource, $ddcodeAssignedFieldMatches);
$assertSame(
['tracking_number', 'express_company'],
array_values(array_unique($ddcodeAssignedFieldMatches[1] ?? [])),
'tracking correction must write only the tracking number and carrier fields'
);
$assertTrue(
!str_contains($ddcodeLockedSource, '$order->fulfillment_status')
&& !str_contains($ddcodeLockedSource, 'assertRemoteSnapshotMutable'),
'tracking correction must be available in every fulfillment state and for remotely submitted orders'
);
$assertTrue(
str_contains($ddcodeLockedSource, "'fill_tracking'")
&& str_contains($ddcodeLockedSource, "'修改快递信息:单号")
&& str_contains($ddcodeLockedSource, "\n true\n );"),
'tracking correction must append a strict operation log containing old and new logistics values'
);
$assertTrue( $assertTrue(
substr_count($prescriptionLogicSource, 'remoteSnapshotLockErrorForPrescription') >= 2, substr_count($prescriptionLogicSource, 'remoteSnapshotLockErrorForPrescription') >= 2,
'consumer prescription edit and patient patch must enforce the linked order snapshot lock' 'consumer prescription edit and patient patch must enforce the linked order snapshot lock'
@@ -1459,6 +1488,9 @@ $assertTrue(
$tcmApi = (string) file_get_contents(dirname(__DIR__, 3) . '/admin/src/api/tcm.ts'); $tcmApi = (string) file_get_contents(dirname(__DIR__, 3) . '/admin/src/api/tcm.ts');
$desktopOrderPage = (string) file_get_contents(dirname(__DIR__, 3) . '/admin/src/views/consumer/prescription/order_list.vue'); $desktopOrderPage = (string) file_get_contents(dirname(__DIR__, 3) . '/admin/src/views/consumer/prescription/order_list.vue');
$mobileOrderPage = (string) file_get_contents(dirname(__DIR__, 3) . '/admin/src/views/consumer/prescription/order_list_h5.vue'); $mobileOrderPage = (string) file_get_contents(dirname(__DIR__, 3) . '/admin/src/views/consumer/prescription/order_list_h5.vue');
$ddcodeMigration = (string) file_get_contents(
dirname(__DIR__, 2) . '/sql/1.9.20260803/add_prescription_order_ddcode_menu.sql'
);
$gancaoReconcileComponent = (string) file_get_contents( $gancaoReconcileComponent = (string) file_get_contents(
dirname(__DIR__, 3) . '/admin/src/views/consumer/prescription/components/GancaoSubmissionReconcileButton.vue' dirname(__DIR__, 3) . '/admin/src/views/consumer/prescription/components/GancaoSubmissionReconcileButton.vue'
); );
@@ -1486,6 +1518,18 @@ $assertTrue(
str_contains($tcmApi, "url: '/tcm.prescriptionOrder/uploadToPharmacy'"), str_contains($tcmApi, "url: '/tcm.prescriptionOrder/uploadToPharmacy'"),
'unified pharmacy API client must use the independently registered upload URI' 'unified pharmacy API client must use the independently registered upload URI'
); );
$assertTrue(
str_contains($tcmApi, "url: '/tcm.prescriptionOrder/ddcode'")
&& str_contains($ddcodeMigration, "'tcm.prescriptionOrder/ddcode'"),
'tracking correction API and its dedicated permission must be registered together'
);
$assertTrue(
str_contains($desktopOrderPage, 'await prescriptionOrderDdcode({')
&& str_contains($mobileOrderPage, 'await prescriptionOrderDdcode({')
&& (bool) preg_match('/function canQuickTrackRow\([^)]*\)\s*\{\s*return true\s*\}/', $desktopOrderPage)
&& (bool) preg_match('/function canQuickTrackRow\([^)]*\)\s*\{\s*return true\s*\}/', $mobileOrderPage),
'desktop and mobile tracking correction must use the dedicated API in every fulfillment state'
);
$assertTrue( $assertTrue(
str_contains($desktopOrderPage, "v-perms=\"['tcm.prescriptionOrder/uploadToPharmacy']\""), str_contains($desktopOrderPage, "v-perms=\"['tcm.prescriptionOrder/uploadToPharmacy']\""),
'unified pharmacy buttons must require the new upload permission' 'unified pharmacy buttons must require the new upload permission'