request->queryParams; $searchModel = new HisRequestSearch(); $dataProvider = $searchModel->search($search); return $this->apiCollection([ 'count' => $dataProvider->count, 'dataModels' => $dataProvider->models, ], $dataProvider->totalCount); }*/ #[OA\Post( path: "/his-request", summary: "Create data hospital request API", operationId: "hisRequestCreate", tags: ["HisRequest"], security: [["bearerAuth" => []]], requestBody: new OA\RequestBody( required: true, content: new OA\JsonContent(ref: "#/components/schemas/CreateHisRequest") ), responses: [ new OA\Response( response: 201, description: "Created", content: new OA\JsonContent(ref: "#/components/schemas/HisRequest") ), new OA\Response( response: 422, description: "Validation error", content: new OA\JsonContent(ref: "#/components/schemas/ErrorValidate") ), ] )] public function actionCreate() { // ---------- Helper: HL7 DTM converters ---------- $hl7Date = function (?string $s): ?string { $s = trim((string)$s); if ($s === '') return null; $y = substr($s, 0, 4); $m = substr($s, 4, 2); $d = substr($s, 6, 2); if (!checkdate((int)$m, (int)$d, (int)$y)) return null; return sprintf('%04d-%02d-%02d', $y, $m, $d); }; $hl7DateTime = function (?string $s): ?string { $s = trim((string)$s); if ($s === '') return null; $y = substr($s, 0, 4); $m = substr($s, 4, 2); $d = substr($s, 6, 2); $H = strlen($s) >= 10 ? substr($s, 8, 2) : '00'; $i = strlen($s) >= 12 ? substr($s, 10, 2) : '00'; $S = strlen($s) >= 14 ? substr($s, 12, 2) : '00'; if (!checkdate((int)$m, (int)$d, (int)$y)) return null; return sprintf('%04d-%02d-%02d %02d:%02d:%02d', $y, $m, $d, $H, $i, $S); }; // ---------- Read & normalize body ---------- $root = Yii::$app->request->getBodyParams(); // payload อาจมาเป็น {'HisRequest':{...}} หรือเป็น {...} ตรง ๆ $reqData = $root['HisRequest'] ?? $root; //error_log('[HisRequest] INCOMING: ' . print_r($reqData, true)); if (HisRequest::find()->where(['message_control_id' => $reqData['message_control_id'] ?? null])->exists()) { return $this->apiConflict( 'DUPLICATE_MESSAGE', 'Duplicate message_control_id: ' . ($reqData['message_control_id'] ?? 'unknown'), ['message_control_id' => $reqData['message_control_id'] ?? null] ); } $tx = Yii::$app->db->beginTransaction(); try { // ======================= // 1) SAVE his_request // ======================= $req = new HisRequest(); //$req->import_at = date('Y-m-d H:i:s'); // แปลง DTM ก่อนเซฟ (ถ้า model ใช้ DATE/DATETIME) $reqData['request_datetime'] = $hl7DateTime($reqData['request_datetime'] ?? null); $reqData['date_time_of_message'] = $hl7DateTime($reqData['date_time_of_message'] ?? null); $reqData['date_time_of_birth'] = $hl7Date($reqData['date_time_of_birth'] ?? null); $reqData['admit_date_time'] = $hl7DateTime($reqData['admit_date_time'] ?? null); $reqData['discharge_date_time'] = $hl7DateTime($reqData['discharge_date_time'] ?? null); $reqData['date_time_of_transaction'] = $hl7DateTime($reqData['date_time_of_transaction'] ?? null); // เผื่อ message_type แยกแล้ว ใส่ทั้งสาม field if (!empty($reqData['message_type']) && empty($reqData['message_type_code'])) { $parts = explode('^', $reqData['message_type']); $reqData['message_type_code'] = $parts[0] ?? null; $reqData['message_type_name'] = $parts[1] ?? null; } // map ลง model (ให้แน่ใจว่า HisRequest::rules() รับฟิลด์ทั้งหมดเป็น safe หรือกำหนดตามเหมาะสม) $req->attributes = $reqData; if (!$req->save()) { error_log('[HisRequest] ERROR: ' . json_encode($req->errors, JSON_UNESCAPED_UNICODE)); throw new \Exception('Save his_request failed'); } // ======================= // 2) SAVE his_obr (+ his_obx) // ======================= $orders = $reqData['orders'] ?? []; foreach ($orders as $oIdx => $o) { if (empty($o['obr'])) continue; // ไม่มี OBR ข้าม $obrIn = $o['obr']; $obr = new HisObr(); $obr->his_request_id = $req->id; // แปลง DTM OBR $obrIn['requested_date_time'] = $hl7DateTime($obrIn['requested_date_time'] ?? null); // map fields (ตาม schema ล่าสุด) $mapFields = [ 'obr_set_id', 'obr_placer_order_number', 'obr_filler_order_number', // raw และ flatten ของ universal_service 'universal_service', 'universal_service_id', 'universal_service_text', 'universal_service_name_of_coding_system', 'universal_service_alternate_id', 'universal_service_alternate_text', 'name_of_alternate_coding_system', 'priority', 'requested_date_time', 'relevant_clinical_info', // specimen 'specimen_source', 'specimen_source_code', 'specimen_source_name', // ordering provider 'obr_ordering_provider_id', 'obr_ordering_provider_last_name', 'obr_ordering_provider_first_name', 'obr_ordering_provider_middle_name', 'obr_ordering_provider_prefix_name', // etc. 'placer_field_1', 'ward_code_name', 'charge_to_practice', ]; foreach ($mapFields as $f) { if (array_key_exists($f, $obrIn)) { $obr->$f = $obrIn[$f]; } } // ถ้ามี ORC ระดับก้อน (ออปชั่น) if (!empty($o['orc'])) { $orc = $o['orc']; $obr->orc_order_control = $orc['order_control'] ?? null; $obr->orc_placer_no = $orc['orc_placer_order_number'] ?? null; $obr->orc_filler_no = $orc['orc_filler_order_number'] ?? null; $obr->orc_status = $orc['order_status'] ?? null; $obr->orc_datetime_tx = $hl7DateTime($orc['date_time_of_transaction'] ?? null); $obr->orc_ordering_provider_raw = $orc['orc_ordering_provider'] ?? null; $obr->orc_ordering_provider_id = $orc['orc_ordering_provider_id'] ?? null; $obr->orc_ordering_provider_lastname = $orc['orc_ordering_provider_last_name'] ?? null; $obr->orc_ordering_provider_firstname = $orc['orc_ordering_provider_first_name'] ?? null; $obr->orc_entering_org = $orc['entering_organization'] ?? null; $obr->orc_entering_device = $orc['entering_device'] ?? null; } if (!$obr->save()) { error_log('[HisObr] ERROR: ' . json_encode($obr->errors, JSON_UNESCAPED_UNICODE)); throw new \Exception('Save his_obr failed at index ' . $oIdx); } // ---------- OBX ---------- $obxArr = $o['obx'] ?? []; foreach ($obxArr as $xIdx => $x) { $obx = new HisObx(); $obx->his_obr_id = $obr->id; // map ชื่อฟิลด์ให้ตรงกับ schema (เราใช้ obx_text, obx_values) $obx->set_id = $x['set_id'] ?? null; $obx->value_type = $x['value_type'] ?? null; $obx->identifier = $x['id'] ?? null; $obx->obx_text = $x['text'] ?? null; $obx->coding_system = $x['system'] ?? null; // values: อาจมาเป็น array หรือ string; ถ้า array ให้ join ด้วย "~" $values = $x['values'] ?? null; if (is_array($values)) { $values = implode('~', $values); } $obx->obx_values = $values; $obx->units = $x['units'] ?? null; $obx->reference_range = $x['reference_range'] ?? null; $obx->result_status = $x['result_status'] ?? null; if (!$obx->save()) { error_log('[HisObx] ERROR: ' . json_encode($obx->errors, JSON_UNESCAPED_UNICODE)); throw new \Exception('Save his_obx failed at req=' . $req->id . ' obr=' . $obr->id . ' idx=' . $xIdx); } } } $tx->commit(); // ตอบกลับข้อมูลที่สร้าง (จะส่งเฉพาะ his_request ตามเดิม) return $this->apiCreated($req, 'CREATE_COMPLETED'); } catch (\Throwable $e) { $tx->rollBack(); error_log('[HisRequest] ROLLBACK: ' . $e->getMessage()); return $this->apiValidate(['error' => [$e->getMessage()]]); } } // ---------- End of actionCreate ---------- /* #[OA\Put( path: "/his-request/{id}", summary: "Update data hospital import", operationId: "hisRequestUpdate", tags: ["HisRequest"], parameters: [ new OA\Parameter( name: "id", in: "path", required: true, description: "HisRequest ID", schema: new OA\Schema(type: "integer", example: 123) ), ], requestBody: new OA\RequestBody( required: true, content: new OA\JsonContent(ref: "#/components/schemas/UpdateHisRequest") ), responses: [ new OA\Response( response: 202, description: "Accepted", content: new OA\JsonContent(ref: "#/components/schemas/HisRequest") ), new OA\Response( response: 422, description: "Validation error", content: new OA\JsonContent(ref: "#/components/schemas/ErrorValidate") ), new OA\Response(response: 404, description: "Not found"), ] )] public function actionUpdate($id) { $dataRequest['HisRequest'] = Yii::$app->request->getBodyParams(); $model = $this->findModel($id); if ($model->load($dataRequest) && $model->save()) { return $this->apiUpdated($model); } return $this->apiValidate($model->errors); } #[OA\Get( path: "/his-request/{id}", summary: "Get data hospital import", operationId: "hisRequestView", tags: ["HisRequest"], parameters: [ new OA\Parameter( name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer", example: 123) ), ], responses: [ new OA\Response( response: 200, description: "OK", content: new OA\JsonContent(ref: "#/components/schemas/HisRequest") ), new OA\Response(response: 404, description: "Not found"), ] )] public function actionView($id) { return $this->apiItem($this->findModel($id)); } #[OA\Delete( path: "/his-request/{id}", summary: "Delete data hospital import", operationId: "hisRequestDelete", tags: ["HisRequest"], parameters: [ new OA\Parameter( name: "id", in: "path", required: true, schema: new OA\Schema(type: "integer", example: 123) ), ], responses: [ new OA\Response(response: 202, description: "Accepted"), new OA\Response(response: 404, description: "Not found"), ] )] public function actionDelete($id) { if ($this->findModel($id)->delete()) { return $this->apiDeleted(true); } return $this->apiDeleted(false); } protected function findModel($id) { if (($model = HisRequest::findOne($id)) !== null) { return $model; } throw new NotFoundHttpException('Resource not found'); } */ }