$validator->setLang($testLang)); function orderEditTimeExpect(bool $condition, string $message): void { if (!$condition) { fwrite(STDERR, "FAIL: {$message}\n"); exit(1); } } $valid = [ 'id' => 1, 'patient_id' => 0, 'order_type' => 3, 'payment_time' => '2026-08-22 11:37:27', 'create_time' => '2026-08-22 11:40:03', ]; orderEditTimeExpect( (new OrderValidate())->scene('edit')->check($valid), 'valid payment and creation times pass validation' ); $withoutPaymentTime = $valid; $withoutPaymentTime['payment_time'] = ''; orderEditTimeExpect( (new OrderValidate())->scene('edit')->check($withoutPaymentTime), 'unpaid orders may keep an empty payment time' ); $invalidPaymentTime = $valid; $invalidPaymentTime['payment_time'] = '2026-99-99 25:61:61'; orderEditTimeExpect( !(new OrderValidate())->scene('edit')->check($invalidPaymentTime), 'invalid payment time is rejected' ); $missingCreateTime = $valid; $missingCreateTime['create_time'] = ''; orderEditTimeExpect( !(new OrderValidate())->scene('edit')->check($missingCreateTime), 'creation time is required' ); $logic = file_get_contents(dirname(__DIR__) . '/app/adminapi/logic/order/OrderLogic.php'); orderEditTimeExpect(is_string($logic), 'order logic source is readable'); orderEditTimeExpect( str_contains($logic, "array_key_exists('payment_time', \$params)") && str_contains($logic, "in_array((int)\$order->status, [2, 4], true)") && str_contains($logic, 'normalizeEditedCreateTime('), 'order edit protects payment status and supports legacy creation timestamps' ); $logicReflection = new ReflectionClass(OrderLogic::class); $normalizeCreateTime = $logicReflection->getMethod('normalizeEditedCreateTime'); orderEditTimeExpect( $normalizeCreateTime->invoke(null, 1724300000, '2026-08-22 11:40:03') === strtotime('2026-08-22 11:40:03'), 'legacy integer creation times remain Unix timestamps' ); orderEditTimeExpect( $normalizeCreateTime->invoke(null, '2026-08-22 10:00:00', '2026-08-22 11:40:03') === '2026-08-22 11:40:03', 'datetime creation times remain canonical strings' ); $adminView = file_get_contents(dirname(__DIR__, 2) . '/admin/src/views/order/index.vue'); orderEditTimeExpect(is_string($adminView), 'admin order view source is readable'); orderEditTimeExpect( str_contains($adminView, 'v-model="editOrderForm.payment_time"') && str_contains($adminView, 'v-model="editOrderForm.create_time"') && str_contains($adminView, 'v-if="isEditPaymentTimeEditable"') && str_contains($adminView, 'payload.payment_time = editOrderForm.value.payment_time') && str_contains($adminView, 'create_time: editOrderForm.value.create_time'), 'admin edit dialog submits payment and creation times' ); echo "Order edit time contract: OK\n";