unit UnitExtendPresHandler; interface uses Db, DBTables, SysUtils,Classes,uuadd; type TExtendPresHandler = class private FUrl: string; FAppKey: string; FSignMethod: string; FFormat: string; FPrivateKey: string; function GetPresStockList(cflsh0: string): string; function GetPresBody(cflsh0: string): string; function GetPresDetail(cflsh0: string): string; function GetServerMillionsTimestamp:string; function GetJsonPairByDataeSet(dt: TDataSet): string; function GetJsonPairOneRow(dt: TDataSet): string; function GetSignByMd5(preSignData: string): string; function GetSignBySha256(preSignData: string): string; function GetPostData(in_methodName, timestamp, sign, jsonData: string): string; function HttpPost(url,postData: string):string; procedure LogInfo(content: string); procedure LogError(content: string); function GetJsonValue(srcJson, item: string): string; procedure InsertWYCF(cflsh0, fhmsg0, fhurl0: string); procedure DeleteWYCF(cflsh0: string); public constructor Create(url, appKey, privateKey, signMethod, format: string); class function IsAllExtendYP(presDetail: TDataSet; var msg: string): Boolean; class procedure ChangeZBY(presDetail: TDataSet; sfzby0: string); //数据库是否存在外延处方记录 class function IsExistExtendPres(cflsh0: string): boolean; //查询处方是否够库存 function CheckStockByPres(cflsh0: string; var msg: string): Boolean; //保存外延处方 function SaveExtendPres(cflsh0: string; var msg: string): Boolean; //取消外延处方 function CancelExtendPres(cflsh0: string; var msg: string): Boolean; //获取外延处方状态列表 function GetExtendPresList(cflsh0: string; var res, msg: string): Boolean; //外延处方是否已发药 已发药不能修改 function CanEditExtendPres(cflsh0: string; var msg: string):Boolean; end; TPair = record key: string; value: string; end; TPairArray = array of TPair; function InitExtendPresHandlerUnit(var msg: string): Boolean; var ExtendPresHandler: TExtendPresHandler; ExtendPresInitSuccess: Boolean = False; implementation uses HisPrivate, HisPublic, IdHashMessageDigest, IdHTTP, util_utf8, UnitDJson, CryptoAPI; function InitExtendPresHandlerUnit(var msg: string): Boolean; var url, key, privateKey: string; begin Result := False; if (not YS_SFQYWYCF) or ExtendPresInitSuccess then begin Result := True; Exit; end; with TQuery.Create(nil) do try DatabaseName := 'his_db'; SQL.Add('select bh0000, mc0000 from bm_tyzd00 where zdmc00 = ''外延处方'' and yxbz00 = 1'); Open; if IsEmpty then begin msg := '未配置外延处方接口地址字典'; Result := False; Exit; end; First; while not Eof do begin if LowerCase(Trim(fieldbyname('bh0000').AsString)) = 'url' then url := Trim(fieldbyname('mc0000').AsString) else if LowerCase(Trim(fieldByname('BH0000').AsString)) = 'appkey' then key := Trim(fieldbyname('mc0000').AsString) else if LowerCase(Trim(fieldByname('BH0000').AsString)) = 'privatekey' then privateKey := Trim(fieldbyname('mc0000').AsString) ; Next; end; if url = '' then begin msg := '外延处方地址为空'; Result := False; Exit; end; ExtendPresHandler := TExtendPresHandler.Create(url, key, privateKey, 'sha-256', 'json'); Result := True; ExtendPresInitSuccess := True; finally Free; end; end; function Compare(const pair1, pair2: TPair): Integer; begin Result := CompareText(pair1.key, pair2.key); end; procedure Swap(var pair1, pair2: TPair); var temp: TPair; begin temp := pair1; pair1 := pair2; pair2 := temp; end; procedure Sort(var pairs: TPairArray); var i, n: Integer; Swapped: Boolean; begin n := Length(pairs); repeat Swapped := False; for i := 1 to n - 1 do begin if Compare(pairs[i - 1], pairs[i]) > 0 then begin Swap(pairs[i - 1], pairs[i]); Swapped := True; end; end; dec(n); until not Swapped; end; { TExtendPresHandler } function TExtendPresHandler.CancelExtendPres(cflsh0: string; var msg: string): Boolean; var methodName: string; timestamp: string; preSignStr: string; sign: string; body: string; postData: string; response: string; rawBody: string; pairs: TPairArray; i: Integer; begin Result := False; try if not IsExistExtendPres(cflsh0) then begin Result := True; Exit; end; if not CanEditExtendPres(cflsh0, msg) then begin msg :=msg + '当前处方不允许修改'; Exit; end; Result := False; methodName := 'pop.api.prescription.cancel'; body := '{"prescriptionId":"' + cflsh0 + '"}'; //获取服务器时间戳 timestamp := GetServerMillionsTimestamp; //总共要拼接的键值对数量 i := 6; SetLength(pairs, i); //从高往低填充数组 Dec(i); pairs[i].key := 'app_key'; pairs[i].value := FAppKey; Dec(i); pairs[i].key := 'format'; pairs[i].value := FFormat; Dec(i); pairs[i].key := 'method'; pairs[i].value := methodName; Dec(i); pairs[i].key := 'sign_method'; pairs[i].value := FSignMethod; Dec(i); //获取服务器时间戳 timestamp := GetServerMillionsTimestamp; pairs[i].key := 'timestamp'; pairs[i].value := timestamp; Dec(i); pairs[i].key := 'prescriptionId'; pairs[i].value := cflsh0; rawBody := ''; Sort(pairs); for i:= Low(pairs) to High(pairs) do rawBody := rawBody + pairs[i].key + pairs[i].value; //按ASCII 顺序排序 preSignStr :=FPrivateKey + rawBody; //获取md5签名 if FSignMethod = 'md5' then sign := GetSignByMd5(preSignStr) else sign := GetSignBySha256(preSignStr); postData := GetPostData(methodName, timestamp, sign, body); response := HttpPost(FUrl, postData); with TJsonNode.Create do try if not TryParse(response) then begin msg := '处方取消,解析返回json失败'; LogError(msg + response); Exit; end; if not Child('payload').Child('data').Child('result').AsBoolean then begin msg := Child('payload').Child('data').Child('msg').AsString; Exit; end else if Child('payload').Child('data').Child('optionResult').AsString <> 'OK' then begin msg := '外延处方取消失败,不允许删除。'; Exit; end; finally Free; end; DeleteWYCF(cflsh0); except on e: Exception do begin msg := '外延处方CancelExtendPres接口发生未知异常'; LogError(msg + e.Message); Exit; end; end; Result := True; end; function TExtendPresHandler.CanEditExtendPres(cflsh0: string; var msg: string): Boolean; var res: string; lsMsg: string; resJson: TJsonNode; begin Result := False; if not GetExtendPresList(cflsh0, res, lsMsg) then begin LogError(lsMsg); msg := '获取外延处方状态失败,' + lsMsg; Exit; end; resJson := TJsonNode.Create; try resJson.Parse(res); if resJson.Child('payload').Child('data').Child('prescriptionList').Count = 0 then begin Result := true; Exit; end; with resJson.Child('payload').Child('data').Child('prescriptionList').GetEnumerator do try MoveNext; if StrToInt(Current.Child('prescriptionOrderStatus').Value) > 1 then begin msg := '外延处方已发药,不允许删除'; Exit; end; finally Free; end; finally FreeAndNil(resJson); end; Result := True; end; class procedure TExtendPresHandler.ChangeZBY(presDetail: TDataSet; sfzby0: string); {------------------------------------------------------------------------------- 过程名: TExtendPresHandler.IsAllZBY 说明: 把数据集的所有明细sfzby0 改为入参的sfzby0 日期: 2020.09.17 参数: presDetail: TDataSet; var msg: string 返回值: Boolean -------------------------------------------------------------------------------} begin if presDetail.IsEmpty then Exit; presDetail.DisableControls; try presDetail.First; //这里不能用这种方式去改sfzby0 因为改自备药标志会触发计算总金额方法 而计算总金额算法又会用到明显的数据集 while not presDetail.Eof do begin presDetail.Edit; presDetail.FieldByName('sfzby0').AsString := sfzby0; presDetail.Next; end; finally presDetail.EnableControls; end; end; //检查外延处方平台库存是否充足 function TExtendPresHandler.CheckStockByPres(cflsh0: string; var msg: string): Boolean; var methodName: string; timestamp: string; preSignStr: string; sign: string; body: string; postData: string; response: string; rawBody: string; noPassDrugCode: string; begin Result := False; try methodName := 'pop.api.item.stock.check'; //获取开方数量 try body := GetPresStockList(cflsh0); except on e:Exception do begin msg := e.Message; Exit; end; end; with TJsonNode.Create do try Parse(body); rawBody := Child('stockListStr').AsString; body := '{"stockListStr":"'+ rawBody + '"}'; rawBody := StringReplace(rawBody,'\"', '"', [rfReplaceAll]); finally Free; end; //获取服务器时间戳 timestamp := GetServerMillionsTimestamp; //按ASCII 顺序排序 preSignStr :=FPrivateKey +'app_key' + FAppKey + 'format'+ FFormat + 'method'+ methodName + 'sign_method' + FSignMethod + 'stockListStr' + rawBody + 'timestamp' + timestamp; //获取md5签名 if FSignMethod = 'md5' then sign := GetSignByMd5(preSignStr) else sign := GetSignBySha256(preSignStr); postData := GetPostData(methodName, timestamp, sign, body); try response := HttpPost(FUrl, postData); except on e: Exception do begin msg := e.Message; Exit; end; end; with TJsonNode.Create do try if not TryParse(response) then begin msg := '解析json失败'; LogError(msg + response); Exit; end; if not Child('payload').Child('data').Child('result').AsBoolean then begin msg := Child('payload').Child('data').Child('msg').AsString; Exit; end else if not Child('payload').Child('data').Child('checkStock').Child('checkSuccess').AsBoolean then begin noPassDrugCode := ''; with Child('payload').Child('data').Child('checkStock').Child('drugCommonCode').GetEnumerator do try while MoveNext do noPassDrugCode := noPassDrugCode + Current.Value + ','; finally Free; end; if noPassDrugCode <> '' then System.Delete(noPassDrugCode, Length(noPassDrugCode), 1); msg := '以下药品库存不足'+ #10#13 + noPassDrugCode; Exit; end; finally Free; end; except on e: Exception do begin msg := '外延处方CheckStockByPres接口发生未知异常'; LogError(msg + e.Message); Exit; end; end; Result := true; end; constructor TExtendPresHandler.Create(url, appKey, privateKey, signMethod, format: string); begin FUrl := url; FAppKey := appKey; FSignMethod := signMethod; FFormat := format; FPrivateKey := privateKey; end; procedure TExtendPresHandler.DeleteWYCF(cflsh0: string); begin with TQuery.Create(nil) do try DatabaseName := 'his_db'; SQL.Add('delete from ys_wycf00 where cflsh0 =rpad(:cflsh0, 16, '' '')'); ParamByName('cflsh0').AsString := cflsh0; ExecSQL; finally Free; end; end; function TExtendPresHandler.GetExtendPresList(cflsh0: string; var res, msg: string): Boolean; var methodName: string; timestamp: string; preSignStr: string; sign: string; body: string; postData: string; response: string; rawBody: string; pairs: TPairArray; i: Integer; begin Result := False; try methodName := 'pop.api.prescription.list'; body := '{"hospitalPrescriptionId":"'+ cflsh0 +'"}'; //获取服务器时间戳 timestamp := GetServerMillionsTimestamp; i := 6; SetLength(pairs, i); //从高往低填充数组 Dec(i); pairs[i].key := 'app_key'; pairs[i].value := FAppKey; Dec(i); pairs[i].key := 'format'; pairs[i].value := FFormat; Dec(i); pairs[i].key := 'method'; pairs[i].value := methodName; Dec(i); pairs[i].key := 'sign_method'; pairs[i].value := FSignMethod; Dec(i); //获取服务器时间戳 timestamp := GetServerMillionsTimestamp; pairs[i].key := 'timestamp'; pairs[i].value := timestamp; Dec(i); pairs[i].key := 'hospitalPrescriptionId'; pairs[i].value := cflsh0; rawBody := ''; Sort(pairs); for i:= Low(pairs) to High(pairs) do rawBody := rawBody + pairs[i].key + pairs[i].value; //按ASCII 顺序排序 preSignStr :=FPrivateKey + rawBody; //获取md5签名 if FSignMethod = 'md5' then sign := GetSignByMd5(preSignStr) else sign := GetSignBySha256(preSignStr); postData := GetPostData(methodName, timestamp, sign, body); response := HttpPost(FUrl, postData); with TJsonNode.Create do try if not TryParse(response) then begin msg := '获取处方列表,解析返回json失败'; LogError(msg + response); Exit; end; if not Child('payload').Child('data').Child('result').AsBoolean then begin msg := Child('payload').Child('data').Child('msg').AsString; Exit; end; finally Free; end; except on e: Exception do begin msg := '外延处方GetExtendPresList接口发生未知异常'; LogError(msg + e.Message); Exit; end; end; res := response; Result := true; end; function TExtendPresHandler.GetJsonPairByDataeSet(dt: TDataSet): string; var i: Integer; tmpStr: string; begin dt.First; Result := ''; while not dt.Eof do begin Result := Result + '{'; tmpStr := ''; for i:= 0 to dt.Fields.Count - 1 do begin if Trim(dt.Fields[i].AsString) <> '' then tmpStr := tmpStr + '\\\"' + dt.Fields[i].FieldName + '\\\":\\\"' + dt.Fields[i].AsString + '\\\",'; end; if tmpStr <> '' then Delete(tmpStr, Length(tmpStr), 1); Result := Result + tmpStr + '},'; dt.Next; end; if Result <> '' then Delete(Result, Length(Result), 1); end; function TExtendPresHandler.GetJsonPairOneRow(dt: TDataSet): string; var i: Integer; begin dt.First; Result := ''; for i := 0 to dt.Fields.Count - 1 do begin if Trim(dt.Fields[i].AsString) <> '' then Result := Result + '"' + dt.Fields[i].FieldName + '":"' + dt.Fields[i].AsString + '",'; end; end; function TExtendPresHandler.GetJsonValue(srcJson, item: string): string; var strlist: TStringList; i: integer; begin srcJson := copy(srcJson, pos('"' + item + '"', srcJson), length(srcJson) - pos('"' + item + '"', srcJson) + 1); if pos(',', srcJson) > 0 then srcJson := copy(srcJson, 1, pos(',', srcJson) - 1) else srcJson := copy(srcJson, 1, pos('}', srcJson) - 1); strlist := TStringList.Create; try srcJson := StringReplace(srcJson, #13, '', [rfReplaceAll]); srcJson := StringReplace(srcJson, #10, '', [rfReplaceAll]); strlist.Text := StringReplace(srcJson, '"', #13#10, [rfreplaceall]); //如果原字符串包含回车换行就有问题 所以要先替换回车 for i := 0 to strlist.Count - 1 do begin if strlist[i] = item then begin if i + 2 > strlist.Count - 1 then//数字 result := StringReplace(strlist[i + 1], ':', '', []) else result := strlist[i + 2]; end; end; finally strlist.Free; end; end; function TExtendPresHandler.GetPostData(in_methodName, timestamp, sign, jsonData: string): string; begin with TJsonNode.Create do try Add('appKey', FAppKey); Add('timestamp', timestamp); Add('method', in_methodName); Add('signMethod', FSignMethod); Add('format', FFormat); Add('sign', sign); Add('postData', jsonData); Result := ToString; finally Free; end; end; function TExtendPresHandler.GetPresBody(cflsh0: string): string; var tmpQry: TQuery; begin tmpQry := TQuery.Create(nil); with tmpQry do try DatabaseName := 'his_db'; SQL.Add('select "prescriptionId", "prescriptionTime", "insuranceType", "patientName",' + #13#10 + ' "patientIdCard" , "patientMobile" , "describe" , "preliminary",' + #13#10 + ' "doctorName" , "hospitalUserId", "prescriptionSource",' + #13#10 + ' "patientCode", "departmentName", "doctorSignPic", "socialCard",' + #13#10 + ' "visitNo", "idCardType", "peoplePayType", "peoplePayNo",' + #13#10 + ' "institutionCode", "doctorCode", "socialCategoryCode", "socialCategoryName",' + #13#10 + ' "operatorCode", "operatorName", "splitFlag", "auditPharmacistName",' + #13#10 + ' "diagnosisCode", "diagnosisName", "icdCode", "icdVersion",' + #13#10 + ' "hospitalId", "doctorMedicalId", "pharmacistMedicalId", "doctorSignature",' + #13#10 + ' "pharmacistSignature", "prescriptionUrl"' + #13#10 + ' from VW_YS_WYCF00' + #13#10 + ' where "prescriptionId" = rpad(:cflsh0, 16, '' '')'); ParamByName('cflsh0').AsString := cflsh0; Open; if IsEmpty then begin LogError('处方号'+ cflsh0 + '未查询到数据,调用外延处方同步接口失败' + #10#13 + 'sql语句:'+ SQL.Text); raise Exception.Create('处方号'+ cflsh0 + '未查询到数据,调用外延处方同步接口失败'); end; Result := '{' + GetJsonPairOneRow(tmpQry); Result := Result + '"drugInformation":' + '"' + GetPresDetail(cflsh0) + '"}'; finally Free; end; end; function TExtendPresHandler.GetPresDetail(cflsh0: string): string; var tmpQry: TQuery; tmpStr: string; begin tmpQry := TQuery.Create(nil); with tmpQry do try DatabaseName := 'his_db'; SQL.Add('select "name", "specification", "amount", "instructions",' + #13#10 + '"frequency", "number", "unit", "productUnit",' + #13#10 + '"usage", "drugCommonCode", "productNo", "useLimit",' + #13#10 + '"splitFlag", "splitNum", "splitUnit", "drugProvinceMedical",' + #13#10 + '"medicalInsuranceCode", "manufacturer", "approvalNum", "drugGPOId",' + #13#10 + '"price", "days", "drugDosageForm", "drugDosageFormName"' + #13#10 + 'from VW_YS_WYCFMX' + #13#10 + 'where "prescriptionId" = rpad(:cflsh0, 16, '' '')'); ParamByName('cflsh0').AsString := cflsh0; Open; if IsEmpty then begin LogError('处方号'+ cflsh0 +'未找到处方明细,调用外延处方同步接口失败'+ #10#13 + 'sql语句:'+ SQL.Text); raise Exception.Create('处方号'+ cflsh0 +'未找到处方明细,调用外延处方同步接口失败'); end; Result := '['; tmpStr := ''; while not eof do begin tmpStr := tmpStr + GetJsonPairByDataeSet(tmpQry) + ','; end; if tmpStr <> '' then System.Delete(tmpStr, Length(tmpStr), 1); Result := Result + tmpStr + ']'; finally Free; end; end; function TExtendPresHandler.GetPresStockList(cflsh0: string): string; var tmpQry: TQuery; begin tmpQry := TQuery.Create(nil); with tmpQry do try DatabaseName := 'His_db'; SQL.Add('select c.yjjypm "drugCommonCode", b.ypzsl0 "qty"' + #13#10 + ' from ys_cfxxb0 a' + #13#10 + ' join ys_cfmx00 b' + #13#10 + ' on a.cflsh0 = b.cflsh0' + #13#10 + ' join bm_yd0000 c' + #13#10 + ' on b.ypnm00 = c.ypnm00' + #13#10 + ' where a.cflsh0 = rpad(:cflsh0, 16, '' '')'); ParamByName('cflsh0').AsString := cflsh0; Open; if IsEmpty then raise Exception.Create('该'+ Trim(cflsh0)+'处方未查询到药品明细数据'); Result := '{"stockListStr":"[' + GetJsonPairByDataeSet(tmpQry) + ']"}'; finally free; end; end; function TExtendPresHandler.GetServerMillionsTimestamp: string; begin with TQuery.Create(nil) do try DatabaseName := 'His_db'; SQL.Add('SELECT (SYSDATE - TO_DATE(''1970-1-1 8'', ''YYYY-MM-DD HH24'')) * 86400000 +' + #13#10 + ' TO_NUMBER(TO_CHAR(SYSTIMESTAMP(3), ''FF'')) AS MILLIONS' + #13#10 + ' FROM DUAL'); Open; Result := FieldByName('MILLIONS').AsString; finally Free; end; end; function TExtendPresHandler.GetSignByMd5(preSignData: string): string; begin with TIdHashMessageDigest5.Create do try //生成签名(把二进制转化为大写的十六进制) Result := AsHex(HashValue(Utf8Encode(preSignData))); //大写的 finally Free; end; end; function TExtendPresHandler.GetSignBySha256(preSignData: string): string; var shaResult: Integer; desStr: string; begin // Result := UpperCase(THisHelper.SHAStrByUTF8(preSignData)); shaResult := HashStr(HASH_SHA256, Utf8Encode(preSignData), desStr); if shaResult = HASH_NOERROR then Result := UpperCase(desStr) else Result := ''; end; function TExtendPresHandler.HttpPost(url, postData: string): string; var AStrStream,ARespStream:TStringStream; IdHttp : TIdHTTP; begin try LogInfo('接口地址:' + url + #10#13 + '入参:' + postData); IdHttp := TIdHTTP.Create(nil); IdHttp.Request.ContentType := 'application/json;charset=utf-8'; IdHttp.ConnectTimeout := 10000; IdHttp.ReadTimeout := 10000; AStrStream := TStringStream.Create(UTF8Encode(trim(postData))); ARespStream := TStringStream.Create(''); try IdHttp.Post(trim(url), AStrStream, ARespStream); except on e: Exception do begin LogError('url = '+ url + #10#13 + '访问地址错误:'+ e.Message + #10#13 + 'postData = ' + postData); raise Exception.Create('url = '+ url + #10#13 + '访问地址错误:'+ e.Message); end; end; result := UTF8ToAnsi(ARespStream.DataString); LogInfo('出参:' + Result); finally IdHttp.free; AStrStream.free; ARespStream.free; end; end; procedure TExtendPresHandler.InsertWYCF(cflsh0, fhmsg0, fhurl0: string); begin if IsExistExtendPres(cflsh0) then DeleteWYCF(cflsh0); with TQuery.Create(nil) do try DatabaseName := 'his_db'; SQL.Add('insert into ys_wycf00(' + #13#10 + 'CFLSH0, CFZT00, FHMSG0, FHURL0)' + #13#10 + 'select' + #13#10 + 'a."prescriptionId",''1'', :fhmsg0, :fhurl0' + #13#10 + ' from vw_ys_wycf00 a' + #13#10 + ' where a."prescriptionId" = rpad(:cflsh0, 16, '' '')'); ParamByName('fhmsg0').AsString := fhmsg0; ParamByName('fhurl0').AsString := fhurl0; ParamByName('cflsh0').AsString := cflsh0; ExecSQL; finally Free; end; end; class function TExtendPresHandler.IsAllExtendYP(presDetail: TDataSet; var msg: string): Boolean; {------------------------------------------------------------------------------- 过程名: TExtendPresHandler.IsAllExtendYP 说明: 获取数据集中是否所有药品都是外延处方药品,含非外延处方药品的返回false 并且把药品名称以Msg出参返回 多个药品用,隔开 日期: 2020.09.17 参数: presDetail: TDataSet; var msg: string 返回值: Boolean -------------------------------------------------------------------------------} begin Result := True; msg := ''; if presDetail.IsEmpty then Exit; presDetail.DisableControls; with TQuery.Create(nil) do try DatabaseName := 'His_DB'; SQL.Add('select count(1) IsExtendYP from bm_yd0000 where ypnm00 =:ypnm00 and SFWYCF = 1'); presDetail.First; while not presDetail.Eof do begin if Trim(presDetail.FieldByName('ypnm00').AsString) = '' then begin presDetail.Next; Continue; end; Close; ParamByName('ypnm00').AsString := presDetail.fieldByName('ypnm00').AsString; Open; if FieldByName('IsExtendYP').AsInteger = 0 then msg := msg + presDetail.fieldbyname('ypmc00').AsString + ','; presDetail.Next; end; Result := msg = ''; if not Result then system.Delete(msg, Length(msg), 1); finally presDetail.EnableControls; Free; end; end; class function TExtendPresHandler.IsExistExtendPres(cflsh0: string): boolean; {------------------------------------------------------------------------------- 过程名: TExtendPresHandler.IsExtendPres 说明: 判断处方是否外延处方 日期: 2020.09.17 参数: cflsh0: string 返回值: boolean -------------------------------------------------------------------------------} begin with TQuery.Create(nil) do try DatabaseName := 'His_db'; SQL.Add('select count(1) presCount from YS_WYCF00 where cflsh0 = rpad(:cflsh0, 16, '' '')'); ParamByName('cflsh0').AsString := cflsh0; Open; Result := FieldByName('presCount').AsInteger > 0; finally Free; end; end; procedure TExtendPresHandler.LogError(content: string); begin LogInfo(content); SaveTxt_Log('医生护士站日志', '外延处方日志error', content, ''); end; procedure TExtendPresHandler.LogInfo(content: string); begin SaveTxt_Log('医生护士站日志', '外延处方日志Info', content, ''); end; function TExtendPresHandler.SaveExtendPres(cflsh0: string; var msg: string): Boolean; var methodName: string; timestamp: string; preSignStr: string; sign: string; body: string; postData: string; response: string; existExtendPres: Boolean; rawBody: string; bodyJson: TJsonNode; pairs: TPairArray; i: Integer; begin Result := False; try //如果已存在外延处方 则先取消再保存 existExtendPres := IsExistExtendPres(cflsh0); if existExtendPres then if not CanEditExtendPres(cflsh0, msg) then Exit else if not CancelExtendPres(cflsh0, msg) then Exit; methodName := 'pop.api.prescription.sync'; //获取开方数量 body := GetPresBody(cflsh0); bodyJson := TJsonNode.Create; try if not bodyJson.TryParse(body) then begin LogError('body Json解析错误 ' + body); msg := '外延处方body json解析错误,请联系管理员'; Exit; end; //总共要拼接的键值对数量 i := bodyJson.Count + 5; SetLength(pairs, i); //从高往低填充数组 Dec(i); pairs[i].key := 'app_key'; pairs[i].value := FAppKey; Dec(i); pairs[i].key := 'format'; pairs[i].value := FFormat; Dec(i); pairs[i].key := 'method'; pairs[i].value := methodName; Dec(i); pairs[i].key := 'sign_method'; pairs[i].value := FSignMethod; Dec(i); //获取服务器时间戳 timestamp := GetServerMillionsTimestamp; pairs[i].key := 'timestamp'; pairs[i].value := timestamp; with bodyJson.GetEnumerator do try rawBody := '{'; while MoveNext do begin Dec(i); pairs[i].key := Current.Name; pairs[i].value := Current.AsString; if pairs[i].key = 'drugInformation' then begin pairs[i].value := StringReplace(pairs[i].value, '\"', '"', [rfReplaceAll]); end; rawBody := rawBody + '"'+ Current.Name + '":"'+ Current.AsString +'",'; end; System.Delete(rawBody, Length(rawBody), 1); rawBody := rawBody + '}'; finally Free; end; finally FreeAndNil(bodyJson); end; body := ''; Sort(pairs); for i:= Low(pairs) to High(pairs) do body := body + pairs[i].key + pairs[i].value; //按ASCII 顺序排序 preSignStr :=FPrivateKey + body; //获取md5签名 if FSignMethod = 'md5' then sign := GetSignByMd5(preSignStr) else sign := GetSignBySha256(preSignStr); postData := GetPostData(methodName, timestamp, sign, rawBody); response := HttpPost(FUrl, postData); with TJsonNode.Create do try if not TryParse(response) then begin msg := '处方同步,解析返回json失败'; LogError(msg + response); Exit; end; if not Child('payload').Child('data').Child('result').AsBoolean then begin msg := Child('payload').Child('data').Child('msg').AsString; Exit; end; finally Free; end; InsertWYCF(cflsh0, '', ''); except on e: Exception do begin msg := '外延处方SaveExtendPres接口发生未知异常'; LogError(msg + e.Message); Exit; end; end; Result := True; end; initialization finalization if Assigned(ExtendPresHandler) then FreeAndNil(ExtendPresHandler); end.