|
|
@@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.collection.CollectionUtil;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.XML;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
|
|
@@ -49,7 +51,12 @@ import org.springframework.util.Assert;
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.io.OutputStream;
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.net.Socket;
|
|
|
+import java.net.SocketTimeoutException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
@@ -185,6 +192,160 @@ public class DistributorServiceImpl implements DistributorService {
|
|
|
return distributor.getId();
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public String createCardNo(Long id) {
|
|
|
+ DistributorDO distributorDO = distributorMapper.selectById(id);
|
|
|
+ if(distributorDO==null){
|
|
|
+ throw exception(DISTRIBUTOR_NOT_EXISTS);
|
|
|
+ }
|
|
|
+ if(StringUtils.isNotBlank(distributorDO.getCmbShortNo())){
|
|
|
+ throw exception(DISTRIBUTOR_SHORT_EXISTS);
|
|
|
+ }
|
|
|
+ return createChildNo(distributorDO);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String createChildNo(DistributorDO distributor) {
|
|
|
+ String host = "10.1.10.105";
|
|
|
+ int port = 15999;
|
|
|
+ String name = "宜畅式东士煌本孔凰于慊官送";
|
|
|
+ Random random = new Random();
|
|
|
+ int randomNumber = random.nextInt(90000) + 10000;
|
|
|
+ String cardNo = distributor.getUserId().toString()+""+randomNumber;
|
|
|
+ try {
|
|
|
+ // 1. 获取当前时间,用于组装公共包头流水与日期
|
|
|
+ Date now = new Date();
|
|
|
+ String reqDate = new SimpleDateFormat("yyyyMMdd").format(now);
|
|
|
+ String reqTime = new SimpleDateFormat("HHmmss").format(now);
|
|
|
+ // 构造请求方流水号 (保证唯一性)
|
|
|
+ int randomNumber2 = random.nextInt(1000) + 1000;
|
|
|
+ String reqSeqNo = new SimpleDateFormat("yyyyMMddHHmmss").format(now) + ""+randomNumber2+"";
|
|
|
+ // 2. 构造 CMLT40 增加多级账簿 XML 请求报文
|
|
|
+ String xmlData = "<ap>\n" +
|
|
|
+ " <CCTransCode>CMLT40</CCTransCode>\n" +
|
|
|
+ " <ProductID>ICC</ProductID>\n" +
|
|
|
+ " <ChannelType>ERP</ChannelType>\n" +
|
|
|
+ " <CorpNo>17999953800000028</CorpNo>\n" +
|
|
|
+ " <OpNo></OpNo>\n" +
|
|
|
+ " <AuthNo></AuthNo>\n" +
|
|
|
+ " <ReqSeqNo>" + reqSeqNo + "</ReqSeqNo>\n" +
|
|
|
+ " <ReqDate>" + reqDate + "</ReqDate>\n" +
|
|
|
+ " <ReqTime>" + reqTime + "</ReqTime>\n" +
|
|
|
+ " <Sign></Sign>\n" +
|
|
|
+ " <Corp>\n" +
|
|
|
+ " <DbLogAccName>"+name+distributor.getName()+"</DbLogAccName>\n" +
|
|
|
+ " <IntTyp>0</IntTyp>\n" +
|
|
|
+ " <DbIntType>F</DbIntType>\n" +
|
|
|
+ " <DbRit>0.00</DbRit>\n" +
|
|
|
+ " <DbAddType>1</DbAddType>\n" +
|
|
|
+ " <DbRatType>00002000</DbRatType>\n" +
|
|
|
+ " <DbRatPct>0.00</DbRatPct>\n" +
|
|
|
+ " <DbRatAdd>0.00</DbRatAdd>\n" +
|
|
|
+ " <CrIntType>F</CrIntType>\n" +
|
|
|
+ " <CrRit>0.00</CrRit>\n" +
|
|
|
+ " <CrAddType>1</CrAddType>\n" +
|
|
|
+ " <CrRatType>00002000</CrRatType>\n" +
|
|
|
+ " <CrRatPct>0.00</CrRatPct>\n" +
|
|
|
+ " <CrRatAdd>0.00</CrRatAdd>\n" +
|
|
|
+ " <PmtHd>01</PmtHd>\n" +
|
|
|
+ " <ActInf>0</ActInf>\n" +
|
|
|
+ " </Corp>\n" +
|
|
|
+ " <Cmp>\n" +
|
|
|
+ " <DbProv>17</DbProv>\n" +
|
|
|
+ " <DbAccNo>342101046484369</DbAccNo>\n" +
|
|
|
+ " <DbLogAccNo>"+cardNo+"</DbLogAccNo>\n" +
|
|
|
+ " <DbCur>01</DbCur>\n" +
|
|
|
+ " <CrLogAccNo>0000000000</CrLogAccNo>\n" +
|
|
|
+ " <LogAccBkOInd>0</LogAccBkOInd>\n" +
|
|
|
+ " </Cmp>\n" +
|
|
|
+ "</ap>";
|
|
|
+
|
|
|
+ // 3. 按照约定编码报文 (ERP上送报文必须为GBK字符集)
|
|
|
+ byte[] xmlBytes = xmlData.getBytes("GBK");
|
|
|
+
|
|
|
+ // 4. 构造7字节包头
|
|
|
+ // 第1字节为加密标志(0-不加密),后6字节为数据包长度(包含加密标志位),不足6位在右边用空格补足
|
|
|
+// int packetLen = xmlBytes.length + 1;
|
|
|
+ int packetLen = xmlBytes.length;
|
|
|
+ String lengthStr = String.format("%-6s", packetLen);
|
|
|
+ String headerStr = "0" + lengthStr;
|
|
|
+ byte[] headerBytes = headerStr.getBytes("GBK");
|
|
|
+
|
|
|
+ // 拼接完整的待发送字节数组
|
|
|
+ byte[] fullPacket = new byte[headerBytes.length + xmlBytes.length];
|
|
|
+ System.arraycopy(headerBytes, 0, fullPacket, 0, headerBytes.length);
|
|
|
+ System.arraycopy(xmlBytes, 0, fullPacket, headerBytes.length, xmlBytes.length);
|
|
|
+
|
|
|
+ // 5. 发送 TCP/IP Socket 同步短连接请求
|
|
|
+ System.out.println("正在连接到前置机 " + host + ":" + port + "...");
|
|
|
+ Socket socket = new Socket(host, port);
|
|
|
+ // 设置读取超时时间为 30 秒
|
|
|
+// socket.setSoTimeout(30000);
|
|
|
+
|
|
|
+ OutputStream out = socket.getOutputStream();
|
|
|
+ out.write(fullPacket);
|
|
|
+ out.flush();
|
|
|
+ System.out.println("请求报文发送成功,等待响应...\n");
|
|
|
+ System.out.println("请求报文发送成功,等待响应...\n"+new String(fullPacket, "GBK"));
|
|
|
+
|
|
|
+// BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
|
|
|
+// PrintWriter out2 = new PrintWriter(socket.getOutputStream(), true);
|
|
|
+//
|
|
|
+// String inputLine;
|
|
|
+// while ((inputLine = in.readLine()) != null) {
|
|
|
+// System.out.println("Received: " + inputLine);
|
|
|
+// out2.println("Echo: " + inputLine); // 回显客户端发送的数据
|
|
|
+// }
|
|
|
+
|
|
|
+ // 6. 接收并解析前置机返回的报文
|
|
|
+ InputStream in = socket.getInputStream();
|
|
|
+ byte[] buffer = new byte[1024];
|
|
|
+ int bytesRead;
|
|
|
+ // 使用 StringBuilder 拼接读取到的报文内容,必须以 GBK 解码
|
|
|
+ StringBuilder responseBuilder = new StringBuilder();
|
|
|
+
|
|
|
+ while ((bytesRead = in.read(buffer)) != -1) {
|
|
|
+ responseBuilder.append(new String(buffer, 0, bytesRead, "GBK"));
|
|
|
+ }
|
|
|
+
|
|
|
+ socket.close();
|
|
|
+ in.close();
|
|
|
+ out.close();
|
|
|
+
|
|
|
+ String recvData = responseBuilder.toString();
|
|
|
+ if (recvData.length() >= 7) {
|
|
|
+ String respHeader = recvData.substring(0, 7);
|
|
|
+ String respXml = recvData.substring(7);
|
|
|
+ System.out.println("收到前置机响应头: '" + respHeader + "'");
|
|
|
+ System.out.println("收到前置机响应报文:\n" + respXml);
|
|
|
+ JSONObject jsonObject = XML.toJSONObject(respXml);
|
|
|
+ System.out.println(jsonObject);
|
|
|
+
|
|
|
+ JSONObject ap = jsonObject.getJSONObject("ap");
|
|
|
+ String respCode = ap.getStr("RespCode");
|
|
|
+ if(!"0000".equals(respCode)){
|
|
|
+ System.err.println("交易发送异常,异常信息:"+ap.getStr("RespInfo"));
|
|
|
+ return "创建子账薄失败:"+ap.getStr("RespInfo");
|
|
|
+ }else {
|
|
|
+ String resultCode = ap.getJSONObject("Cmp").getStr("DbLogAccNo");
|
|
|
+ System.err.println("卡号:" + resultCode);
|
|
|
+ distributorMapper.updateShortCode(distributor.getId(),resultCode);
|
|
|
+ return "创建子账薄成功:"+resultCode;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ System.out.println("响应报文异常或为空");
|
|
|
+ return "创建子账薄失败:响应报文异常或为空";
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (SocketTimeoutException e) {
|
|
|
+ System.err.println("交易发送超时,请检查ICT前置机通讯状态。");
|
|
|
+ return "创建子账薄失败:交易发送超时";
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("交易发送异常: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ return "创建子账薄失败:"+e.getMessage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public DistributorImportRespVO importDistributorList(List<DistributorImportExcelVO> distributorImportExcelVOS) {
|
|
|
for (DistributorImportExcelVO distributorImportExcelVO : distributorImportExcelVOS) {
|