unit PayIntf_MisDll;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
{ /* 交易类型: '00'消费'01'撤销'02'退货'03'查余
'04'重打印'05'签到'06'结算'08'小费'09'预授权
'10'预授权追加'11'预授权完成'12'预授权撤销
'13'预授权完成撤销'14'商场分期'15'专用分期
'16'分期撤销'18'分期额度查询'19'汽车卡洗车
'20'快速支付'21'指定账户圈存'22'电子现金退货
'23'电子现金查余'24'积分兑换消费'25'积分兑换撤销
'26'积分查询'28'权益积分查询'29'权益积分消费
'30'权益积分撤销'32'卡转出转账'33'财务报销'34'财务还款
‘60’-聚合支付被扫
‘61’-聚合支付主扫
‘62’-聚合支付退货
‘63’-获取 POS 扫码枪二维码数据
‘64’-单笔聚合支付异常订单查询
'72'-聚合支付异常订单查询
‘90’-惠兜圈优惠立减银行卡
‘94’-惠兜圈立减优惠银联二维码
‘95’-云闪付优惠立减交易
‘96’-商场分期优惠立减
*/ }
TInputData = record
posid: array[0..7] of char; // /* 收银机号(8 字节,左对齐,不足部分补空格)*/
operid: array[0..7] of char; // /* 操作员号(8 字节,左对齐,不足部分补空格)*/
trans: array[0..1] of char; //交易类型 见上面
amount: array[0..11] of char; // /* 金额(12 字节,无小数点,左补 0,单位:分)*/
old_date: array[0..7] of char; // /* 原交易日期(8 字节,yyyymmdd 格式,隔日退货时用)*/
old_reference: array[0..11] of char; // /* 原交易参考号*/
old_trace: array[0..5] of char; // /* 流水号(6 字节,右对齐,左补 0,退货或重打印等用)*/
old_batch: array[0..5] of char; // /*57~62 位 原批次号*/
old_auth: array[0..5] of char; // /*63~68 位 原授权码*/
old_terno: array[0..7] of char; // /*69~76 位 原交易终端号*/
szFenqiNum: array[0..1] of char; // /*77~78 位 分期数 03,06,09,12,18,24,36,42,48,60*/
szServiceNum: array[0..1] of char; // /*79~80 位 享受服务人数*/
szGoodsNo: array[0..11] of char; // /*81~92 位 商品项目编码*/
trk2: array[0..36] of char; // /* 二磁道数据(37 字节,左对齐,不足部分补空格)*/
trk3: array[0..103] of char; // /* 三磁道数据(104 字节, 左对齐,不足部分补空格)*/
lrc: array[0..2] of char; // /* 交易校验数据(3 位从 0~9 的随机字符)*/
szOrderTrace: array[0..19] of char; // 6/16/2015 新增 收银流水(订单)号 左对齐 不足补空格
szPrefer: array[0..49] of char; // 优惠券左对齐 不足补空格
szRsv: array[0..299] of char; // 保留字段 在此输入二维码的条码数据 左对齐 不足补空格
end;
TOutPutData = record
resp_code: array[0..1] of char; // /*1~2 位 返回码 (2 字节,"00"交易成功,其他失败)*/
bank_code: array[0..3] of char; // /*3~6 位 银行行号(4 字节)*/
card_no: array[0..29] of char; // /*7~36 位 卡号:622280*********4860 */
expr: array[0..3] of char; // /*37~40 位 有效期 (4 字节) */
amount: array[0..11] of char; // /*141~52 位 金额(12 字节,无小数点,左补 0,单位:分)*/
trace: array[0..5] of char; // /*53~58 位 流水号 (6 字节,左对齐)*/
refer: array[0..11] of char; // /*59~70 位 交易参考号*/
auth: array[0..5] of char; // /*71~76 位 授权号*/
batch: array[0..5] of char; // /*77~82 位 批次号*/
date: array[0..13] of char; // /*83~96 位 交易日期(8 字节,yyyymmddhhmmss 格式)*/
userno: array[0..14] of char; // /*97~111 位 商户号*/
terno: array[0..7] of char; // /*112~119 位 终端号*/
old_terno: array[0..7] of char; // /*120~127 位 原终端号*/
resp_chin: array[0..49] of char; // /* 错误说明(左对齐,不足部分补空格)*/
OrderNo: array[0..49] of char; // /* 二维码交易订单订单号 */
trans: array[0..1] of char; // /* 交易类型 */
ChannelType: array[0..1] of char; // /* '0'银联二维码 '1'微信 '2' 支付宝 '3'龙支付 */
lrc: array[0..2] of char; // /* 交易数据校验码(3 字节)*/
end;
function PayIntf_Trans(ParkCode, OptorCode, Trans, Money, OldTrandID: string; var OrderNo: string): Boolean;
function GetInputStr(ParkCode, OptorCode, Trans, Money, OldTrandID: string; var InStr: string): Boolean;
procedure GetOutputData(OutStr: string);
procedure FillArrayChar(FillType, ParamVaule: string; var ArrVaule: array of char);
function GetOldTradeInfo(OldTrandID: string; var old_date, old_reference, old_trace: string): boolean;
function CheckDataValid(ParkCode, OptorCode, Trans, Money, OldTrandID: string): boolean;
function Obj2Json_InputData(InputData: TInputData): string;
function Obj2Json_OutputData(OutputData: TOutputData): string;
procedure MyWriteLog(const mStr: string);
function BankTrans(PInStr: Pchar; POutStr: Pchar): integer; stdcall; external 'C:\landiccbmispos\MisPos.dll'; //0- 成功 , 其他-失败
implementation
function CheckDataValid(ParkCode, OptorCode, Trans, Money, OldTrandID: string): boolean;
var
sMsg,sFileDLL: string;
begin
Result := False;
sFileDLL := 'C:\landiccbmispos\MisPos.dll';
if not FileExists(sFileDLL) then
begin
sMsg := '调用支付接口文件不存在!';
MyWriteLog(sMsg + '[' + sFileDLL + ']');
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
if (Trans <> '00') and (Trans <> '01') and (Trans <> '02')
and (Trans <> '05') and (Trans <> '06') then //'00'消费'01'撤销'02'退货'03'查余 '05'签到'06'结算
begin
sMsg := '非法的交易类型!';
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
if (Trans = '01') or (Trans = '02') then
begin
if OldTrandID = '' then
begin
sMsg := '撤销和退货时,请传入原交易单号!';
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
end;
if StrToCurrDef(Money,0) <= 0 then
begin
sMsg := '金额不允许为负数或零!';
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
Result := True;
end;
function PayIntf_Trans(ParkCode, OptorCode, Trans, Money, OldTrandID: string; var OrderNo: string): Boolean;
var
lv_nRet: integer;
InStr: string;
OutStr: string;
sMsg: string;
resp_code: string;
begin
{* 1、检查传入参数:根据文档规则
* 2、参数组合成定长字符串
* 3、调用DLL方法
* 4、解析返回定长字符串:判断结果
* 5、记录日志
*}
//检查传入参数
if not CheckDataValid(ParkCode, OptorCode, Trans, Money, OldTrandID) then
begin
Exit;
end;
//组合传入参数,形成定长字符串InStr
if not GetInputStr(ParkCode, OptorCode, Trans, Money, OldTrandID, InStr) then
begin
Exit;
end;
MyWriteLog('发送定长字符串:[' + InStr + ']');
SetLength(OutStr, SizeOf(TOutPutData));
Application.ProcessMessages;
lv_nRet := BankTrans(Pchar(InStr), Pchar(OutStr)); //调用DLL中的BankTrans方法
Application.ProcessMessages;
MyWriteLog('返回定长字符串:[' + OutStr + ']');
GetOutputData(OutStr);
if (lv_nRet <> 0) or (Copy(OutStr, 1, 2) <> '00') then
begin
sMsg := '交易失败!';
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
OrderNo := Trim(Copy(OrderNo, 158, 50));
if Copy(OrderNo, 1, 8) <> 'EEEEEEEE' then // 特殊,当退货出现异常情况, 如网络异常时, 返回头的输出参数头2个字节为00其余字符会以大写字母EE填充,
begin //同时DLL会弹出对话框。请商户及时和银行核实是否退货成功!!!
sMsg := '交易成功!';
MyWriteLog(sMsg + '[' + OrderNo + ']');
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
end else
begin
sMsg := '交易成功,单需要手工核对!';
MyWriteLog(sMsg + '[' + OrderNo + ']');
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
end;
end;
function GetInputStr(ParkCode, OptorCode, Trans, Money, OldTrandID: string; var InStr: string): Boolean;
var
old_date, old_reference, old_trace, sMsg: string;
InputData: TInputData;
begin
{交易说明:
消费 :传入必要信息为 (交易类型,金额)
退货 :传入必要信息为 (交易类型,金额,原交易参考号,原交易日期)
撤销 : 传入必要信息为 (交易类型,金额,原流水号)
查余 : 传入必要信息为 (交易类型)
注: 查询金额 操作 卡内余额显示在 密码键盘。并且不会返回对应的余额.
重打印 : 传入必要信息为 (交易类型,原流水号)
注: 重打印上一笔交易 原流水号:”000000”
签到 : 传入必要信息为 (交易类型)
结算 : 传入必要信息为 (交易类型) }
Result := False;
try
FillChar(InputData,SizeOf(TInputData),' ');
FillArrayChar('RN', ParkCode, InputData.posid);
FillArrayChar('RN', OptorCode, InputData.operid);
FillArrayChar('R0', Trans, InputData.trans);
FillArrayChar('L0', IntToStr(Trunc(StrToCurrDef(Money, 0) * 100)), InputData.amount);
if (Trans = '01') or (Trans = '02') then //'00'消费'01'撤销'02'退货'03'查余
begin
//获取原交易信息
if not GetOldTradeInfo(OldTrandID, old_date, old_reference, old_trace) then
begin
Exit;
end;
if Trans = '01' then
begin
FillArrayChar('L0', old_trace, InputData.old_trace); // /* 原流水号(6 字节,右对齐,左补 0,退货或重打印等用)*/
FillArrayChar('RN', '', InputData.old_date);
FillArrayChar('RN', '', InputData.old_reference);
end;
if Trans = '02' then
begin
FillArrayChar('L0', '', InputData.old_trace);
FillArrayChar('RN', old_date, InputData.old_date); // /* 原交易日期(8 字节,yyyymmdd 格式,隔日退货时用)*/
FillArrayChar('RN', old_reference, InputData.old_reference); // /* 原交易参考号*/
end;
end
else //非撤销和退货
begin
FillArrayChar('L0', '', InputData.old_trace);
FillArrayChar('RN', '', InputData.old_date);
FillArrayChar('RN', '', InputData.old_reference);
end;
//以下为默认填充
FillArrayChar('RN', '', InputData.old_batch); // /*57~62 位 原批次号*/
FillArrayChar('RN', '', InputData.old_auth); // /*63~68 位 原授权码*/
FillArrayChar('RN', '', InputData.old_terno); // /*69~76 位 原交易终端号*/
FillArrayChar('RN', '', InputData.szFenqiNum); // /*77~78 位 分期数 03,06,09,12,18,24,36,42,48,60*/
FillArrayChar('RN', '', InputData.szServiceNum); // /*79~80 位 享受服务人数*/
FillArrayChar('RN', '', InputData.szGoodsNo); // /*81~92 位 商品项目编码*/
FillArrayChar('RN', '', InputData.trk2); // /* 二磁道数据(37 字节,左对齐,不足部分补空格)*/
FillArrayChar('RN', '', InputData.trk3); // /* 三磁道数据(104 字节, 左对齐,不足部分补空格)*/
FillArrayChar('RN', '', InputData.lrc); // /* 交易校验数据(3 位从 0~9 的随机字符)*/
FillArrayChar('RN', '', InputData.szOrderTrace); // 6/16/2015 新增 收银流水(订单)号 左对齐 不足补空格
FillArrayChar('RN', '', InputData.szPrefer); // 优惠券左对齐 不足补空格
FillArrayChar('RN', '', InputData.szRsv); // 保留字段 在此输入二维码的条码数据 左对齐 不足补空格
//取传参的累加的定长字符串
SetLength(InStr,SizeOf(TInputData));
StrLCopy(Pchar(InStr), @InputData, SizeOf(TInputData));
sMsg := '发送信息[转换为JSON]:' + Obj2Json_InputData(InputData);
MyWriteLog(sMsg);
Result := True;
except
on e: exception do
begin
sMsg := '获取传入参数字符串异常:' + e.message;
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
end;
end;
procedure GetOutputData(OutStr: string);
var
sMsg, sTemp: string;
OutputData: TOutPutData;
begin
try
if OutStr = '' then
begin
sMsg := '交易返回参数为空!';
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
//字符串赋值给记录
FillChar(OutputData,SizeOf(TOutputData),' ');
StrLCopy(@OutputData, Pchar(OutStr), SizeOf(TOutputData));
//记录返回的信息
sTemp := '返回信息[转换为JSON]:' + Obj2Json_OutputData(OutputData);
MyWriteLog(sTemp);
except
on e: exception do
begin
sMsg := '转换返回参数异常:' + e.message;
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
end;
end;
function Obj2Json_InputData(InputData: TInputData): string;
begin
Result := '{';
Result := Result + '"posid":"' + Trim(InputData.posid) + '",';
Result := Result + '"operid":"' + Trim(InputData.operid) + '",';
Result := Result + '"trans":"' + Trim(InputData.trans) + '",';
Result := Result + '"amount":"' + Trim(InputData.amount) + '",';
Result := Result + '"old_date":"' + Trim(InputData.old_date) + '",';
Result := Result + '"old_reference":"' + Trim(InputData.old_reference) + '",';
Result := Result + '"old_trace":"' + Trim(InputData.old_trace) + '",';
Result := Result + '"old_batch":"' + Trim(InputData.old_batch) + '",';
Result := Result + '"old_auth":"' + Trim(InputData.old_auth) + '",';
Result := Result + '"old_terno":"' + Trim(InputData.old_terno) + '",';
Result := Result + '"szFenqiNum":"' + Trim(InputData.szFenqiNum) + '",';
Result := Result + '"szServiceNum":"' + Trim(InputData.szServiceNum) + '",';
Result := Result + '"szGoodsNo":"' + Trim(InputData.szGoodsNo) + '",';
Result := Result + '"trk2":"' + Trim(InputData.trk2) + '",';
Result := Result + '"trk3":"' + Trim(InputData.trk3) + '",';
Result := Result + '"lrc":"' + Trim(InputData.lrc) + '",';
Result := Result + '"szOrderTrace":"' + Trim(InputData.szOrderTrace) + '",';
Result := Result + '"szPrefer":"' + Trim(InputData.szPrefer) + '",';
Result := Result + '"szRsv":"' + Trim(InputData.szRsv) + '"';
Result := Result + '}';
end;
function Obj2Json_OutputData(OutputData: TOutputData): string;
begin
Result := '{';
Result := Result + '"resp_code":"' + Trim(OutputData.resp_code) + '",';
Result := Result + '"bank_code":"' + Trim(OutputData.bank_code) + '",';
Result := Result + '"card_no":"' + Trim(OutputData.card_no) + '",';
Result := Result + '"expr":"' + Trim(OutputData.expr) + '",';
Result := Result + '"amount":"' + Trim(OutputData.amount) + '",';
Result := Result + '"trace":"' + Trim(OutputData.trace) + '",';
Result := Result + '"refer":"' + Trim(OutputData.refer) + '",';
Result := Result + '"auth":"' + Trim(OutputData.auth) + '",';
Result := Result + '"batch":"' + Trim(OutputData.batch) + '",';
Result := Result + '"date":"' + Trim(OutputData.date) + '",';
Result := Result + '"userno":"' + Trim(OutputData.userno) + '",';
Result := Result + '"terno":"' + Trim(OutputData.terno) + '",';
Result := Result + '"old_terno":"' + Trim(OutputData.old_terno) + '",';
Result := Result + '"resp_chin":"' + Trim(OutputData.resp_chin) + '",';
Result := Result + '"OrderNo":"' + Trim(OutputData.OrderNo) + '",';
Result := Result + '"trans":"' + Trim(OutputData.trans) + '",';
Result := Result + '"ChannelType":"' + Trim(OutputData.ChannelType) + '",';
Result := Result + '"lrc":"' + Trim(OutputData.lrc) + '"';
Result := Result + '}';
end;
function GetOldTradeInfo(OldTrandID: string; var old_date, old_reference, old_trace: string): boolean;
var
sMsg: string;
begin
Result := False;
try
old_date := '20190805';
old_reference := '123456789987456';
old_trace := '123456';
Result := True;
except
on e: exception do
begin
sMsg := '获取原交易支付信息异常[原交易号:' + OldTrandID + ']:' + e.message;
MyWriteLog(sMsg);
Application.MessageBox(Pchar(sMsg), '提示', MB_OK);
Exit;
end;
end;
end;
procedure FillArrayChar(FillType, ParamVaule: string; var ArrVaule: array of char);
var
I, Len, Diff: integer;
sTemp: string;
begin
Len := Length(ArrVaule);
if Length(ParamVaule) < Len then
begin
Diff := Len - Length(ParamVaule);
for I := 1 to Diff do
begin
if Copy(FillType, 2, 1) = '0' then //填充"0"
begin
sTemp := sTemp + '0';
end
else
begin
sTemp := sTemp + ' '; //填充空格
end;
end;
if Copy(FillType, 1, 1) = 'L' then //左填充
begin
sTemp := sTemp + ParamVaule;
end
else if Copy(FillType, 1, 1) = 'R' then //右填充
begin
sTemp := ParamVaule + sTemp;
end;
end else
begin
sTemp := ParamVaule;
end;
for I := 1 to Len do
begin
ArrVaule[I - 1] := sTemp[I];
end;
end;
procedure MyWriteLog(const mStr: string);
var
f: textfile;
myDir, myFileName: string;
FileHandle: Integer;
LogType, LogDate, ModuleID: string;
begin
LogType := 'INFO';
LogDate := FormatDateTime('YYYY-MM-DD hh:nn:ss zzz', Now);
ModuleID := '';
// if not (CanLogFile in FLogFlags) then exit;
//------写入文件部分的实现--开始
myDir := ExtractFilePath(Paramstr(0));
//确定文件名称
myFileName := FormatDateTime('"PayIntf"yyyymmdd".log"', Date);
//如果可执行目录下不存在log目录创建之
if not DirectoryExists(myDir + '\log') then
CreateDir(myDir + '\log');
//如果当日日志文件不存在,则创建文件并释放句柄
if not FileExists(myDir + '\log\' + myFileName) then
begin
FileHandle := FileCreate(myDir + '\log\' + myFileName); //创建文件
FileClose(FileHandle); //释放句柄
end;
try//try...except...statements
AssignFile(f, myDir + '\log\' + myFileName);
Append(f);
Writeln(f, '$$' + Format('%6s', [LogType]) + '$$ ' + Format('%12s', [ModuleID]) + '$$' + LogDate + chr(9) + mStr);
Flush(f);
CloseFile(f);
//-----写入文件部分的实现--结束
except//try...except...statements
end; //try...except...statements
end;
end.
Delphi_调用DLL方法[调用对象下面的方法]
点赞
收藏