feat(mapping): 完成 PHIS 健康档案转换(T-212)
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type healthRecordEnvelope struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"msg"`
|
||||
Compress bool `json:"compress"`
|
||||
Data HealthRecordTask `json:"data"`
|
||||
}
|
||||
|
||||
// HealthRecordTask is one PHIS health-record upload task. Credentials returned
|
||||
// under data.doctor are deliberately absent from this model.
|
||||
type HealthRecordTask struct {
|
||||
Doctor Doctor `json:"doctor"`
|
||||
Record HealthRecord `json:"record"`
|
||||
ArchID string `json:"archId"`
|
||||
BusinessID string `json:"businessId"`
|
||||
EMPIID string `json:"empiId"`
|
||||
PHRID string `json:"phrId"`
|
||||
CardNo string `json:"cardNo"`
|
||||
CardType string `json:"cardType"`
|
||||
}
|
||||
|
||||
type Doctor struct {
|
||||
RealName string `json:"realName"`
|
||||
DoctorID string `json:"doctorId"`
|
||||
}
|
||||
|
||||
type HealthRecord struct {
|
||||
HomePlace string `json:"homePlace"`
|
||||
DeadFlag string `json:"deadFlag"`
|
||||
IDCard string `json:"idCard"`
|
||||
MobileNumber string `json:"mobileNumber"`
|
||||
InputUser string `json:"inputUser"`
|
||||
MaritalStatusCode string `json:"maritalStatusCode"`
|
||||
WorkCode string `json:"workCode"`
|
||||
Contact string `json:"contact"`
|
||||
WaterSourceCode string `json:"shhjCheckYS"`
|
||||
ManaUnitID string `json:"manaUnitId"`
|
||||
PastDiseaseCode string `json:"diseasetext_radio_jb"`
|
||||
FamilyMother string `json:"diseasetextCheckMQ"`
|
||||
FamilySiblings string `json:"diseasetextCheckXDJM"`
|
||||
InputDate string `json:"inputDate"`
|
||||
GeneticDisease string `json:"diseasetextRedioYCBS"`
|
||||
FamilyChildren string `json:"diseasetextCheckZN"`
|
||||
BloodTypeCode string `json:"bloodTypeCode"`
|
||||
CreateUnit string `json:"createUnit"`
|
||||
DrugAllergy string `json:"diseasetext_check_gm"`
|
||||
Birthday string `json:"birthday"`
|
||||
SignFlag string `json:"signFlag"`
|
||||
RhBloodCode string `json:"rhBloodCode"`
|
||||
IsFillSHHJ string `json:"isFillShhj"`
|
||||
EducationCode string `json:"educationCode"`
|
||||
InsuranceCode string `json:"insuranceCode"`
|
||||
InputUnit string `json:"inputUnit"`
|
||||
RegionCode string `json:"regionCode"`
|
||||
FamilyFather string `json:"diseasetext_check_fq"`
|
||||
ExposureHistory string `json:"diseasetext_check_bl"`
|
||||
WorkPlace string `json:"workPlace"`
|
||||
NationCode string `json:"nationCode"`
|
||||
CreateDate string `json:"createDate"`
|
||||
RegisteredPermanent string `json:"registeredPermanent"`
|
||||
Address string `json:"address"`
|
||||
HomePlaceNumber string `json:"homePlaceNumber"`
|
||||
CardType string `json:"cardType"`
|
||||
UpdatedAt string `json:"updateTime"`
|
||||
CookAirTool string `json:"shhjCheckCFPFSS"`
|
||||
Disability string `json:"diseasetextCheckCJ"`
|
||||
PersonName string `json:"personName"`
|
||||
SexCode string `json:"sexCode"`
|
||||
Washroom string `json:"shhjCheckCS"`
|
||||
ManaDoctorID string `json:"manaDoctorId"`
|
||||
AddressNumber string `json:"adressNumber"`
|
||||
PastTransfusionCode string `json:"diseasetext_sx"`
|
||||
CreateTime string `json:"createTime"`
|
||||
PastSurgeryCode string `json:"diseasetext_ss"`
|
||||
CreateUser string `json:"createUser"`
|
||||
ContactPhone string `json:"contactPhone"`
|
||||
PastTraumaCode string `json:"diseasetext_ws"`
|
||||
FuelType string `json:"shhjCheckRLLX"`
|
||||
LivestockColumn string `json:"shhjCheckQCL"`
|
||||
}
|
||||
|
||||
func DecodeHealthRecordTask(raw []byte) (HealthRecordTask, error) {
|
||||
var envelope healthRecordEnvelope
|
||||
if err := json.Unmarshal(raw, &envelope); err != nil {
|
||||
return HealthRecordTask{}, fmt.Errorf("decode PHIS health record: %w", err)
|
||||
}
|
||||
if envelope.Code != 200 {
|
||||
return HealthRecordTask{}, fmt.Errorf("phis response code=%d message=%s", envelope.Code, envelope.Message)
|
||||
}
|
||||
envelope.Data.ArchID = strings.TrimSpace(envelope.Data.ArchID)
|
||||
if envelope.Data.ArchID == "" {
|
||||
return HealthRecordTask{}, fmt.Errorf("archId is required")
|
||||
}
|
||||
return envelope.Data, nil
|
||||
}
|
||||
|
||||
func (t HealthRecordTask) SourceRecordID() string {
|
||||
return t.ArchID
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeHealthRecordTaskKeepsBusinessFieldsAndDropsCredentials(t *testing.T) {
|
||||
raw, err := os.ReadFile("testdata/health_record.json")
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile: %v", err)
|
||||
}
|
||||
|
||||
task, err := DecodeHealthRecordTask(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodeHealthRecordTask: %v", err)
|
||||
}
|
||||
if task.ArchID != "ARCH-001" || task.BusinessID != "BUSINESS-001" || task.EMPIID != "EMPI-001" || task.PHRID != "PHR-001" {
|
||||
t.Fatalf("identifiers = %#v", task)
|
||||
}
|
||||
if task.SourceRecordID() != "ARCH-001" {
|
||||
t.Fatalf("SourceRecordID = %q", task.SourceRecordID())
|
||||
}
|
||||
if task.Doctor.DoctorID != "DOC001" || task.Doctor.RealName != "测试医生" {
|
||||
t.Fatalf("doctor = %#v", task.Doctor)
|
||||
}
|
||||
if task.Record.IDCard != "440000********1234" || task.Record.AddressNumber != "1号" {
|
||||
t.Fatalf("record = %#v", task.Record)
|
||||
}
|
||||
|
||||
sanitized, err := json.Marshal(task)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal: %v", err)
|
||||
}
|
||||
if strings.Contains(string(sanitized), "sxtAccount") || strings.Contains(string(sanitized), "sxtPassword") || strings.Contains(string(sanitized), "IGNORED_") {
|
||||
t.Fatalf("credentials survived decoding: %s", sanitized)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeHealthRecordTaskRejectsMissingStableArchiveID(t *testing.T) {
|
||||
raw := []byte(`{"code":200,"data":{"record":{"idCard":"440000********1234"},"businessId":"BUSINESS-001"}}`)
|
||||
|
||||
_, err := DecodeHealthRecordTask(raw)
|
||||
if err == nil || !strings.Contains(err.Error(), "archId is required") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeHealthRecordTaskRejectsFailedPHISResponse(t *testing.T) {
|
||||
raw := []byte(`{"code":500,"msg":"failed","data":{"archId":"ARCH-001"}}`)
|
||||
|
||||
_, err := DecodeHealthRecordTask(raw)
|
||||
if err == nil || !strings.Contains(err.Error(), "phis response code=500") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
}
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"compress": false,
|
||||
"data": {
|
||||
"doctor": {
|
||||
"sxtAccount": "IGNORED_ACCOUNT",
|
||||
"sxtPassword": "IGNORED_PASSWORD",
|
||||
"realName": "测试医生",
|
||||
"doctorId": "DOC001"
|
||||
},
|
||||
"record": {
|
||||
"homePlace": "测试户籍地址",
|
||||
"deadFlag": "n",
|
||||
"idCard": "440000********1234",
|
||||
"mobileNumber": "13900000000",
|
||||
"inputUser": "DOC001",
|
||||
"maritalStatusCode": "20",
|
||||
"workCode": "Y",
|
||||
"contact": "测试联系人",
|
||||
"shhjCheckYS": "1",
|
||||
"manaUnitId": "123456789",
|
||||
"diseasetext_radio_jb": "0201",
|
||||
"diseasetextCheckMQ": "0801",
|
||||
"diseasetextCheckXDJM": "0901",
|
||||
"inputDate": "2026-07-15",
|
||||
"diseasetextRedioYCBS": "0501",
|
||||
"diseasetextCheckZN": "1001",
|
||||
"bloodTypeCode": "5",
|
||||
"createUnit": "123456789",
|
||||
"diseasetext_check_gm": "0101",
|
||||
"birthday": "1980-01-02",
|
||||
"signFlag": "n",
|
||||
"rhBloodCode": "3",
|
||||
"isFillShhj": "y",
|
||||
"educationCode": "70",
|
||||
"insuranceCode": "02",
|
||||
"inputUnit": "123456789",
|
||||
"regionCode": "441625000000",
|
||||
"diseasetext_check_fq": "0701",
|
||||
"diseasetext_check_bl": "1201",
|
||||
"workPlace": "测试单位",
|
||||
"nationCode": "01",
|
||||
"createDate": "2026-07-15",
|
||||
"registeredPermanent": "1",
|
||||
"address": "测试现住址",
|
||||
"homePlaceNumber": "2号",
|
||||
"cardType": "01",
|
||||
"updateTime": "2026-07-15 10:20:30",
|
||||
"shhjCheckCFPFSS": "2",
|
||||
"diseasetextCheckCJ": "1101",
|
||||
"personName": "测试居民",
|
||||
"sexCode": "1",
|
||||
"shhjCheckCS": "1",
|
||||
"manaDoctorId": "DOC001",
|
||||
"adressNumber": "1号",
|
||||
"diseasetext_sx": "0401",
|
||||
"createTime": "2026-07-15 09:00:00",
|
||||
"diseasetext_ss": "0301",
|
||||
"createUser": "DOC001",
|
||||
"contactPhone": "13800000000",
|
||||
"diseasetext_ws": "0601",
|
||||
"shhjCheckRLLX": "3",
|
||||
"shhjCheckQCL": "0"
|
||||
},
|
||||
"archId": "ARCH-001",
|
||||
"businessId": "BUSINESS-001",
|
||||
"empiId": "EMPI-001",
|
||||
"phrId": "PHR-001",
|
||||
"cardNo": "",
|
||||
"cardType": ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user