|
|
@@ -0,0 +1,250 @@
|
|
|
+package com.malk.jiuan.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.excel.EasyExcel;
|
|
|
+import com.alibaba.excel.read.listener.PageReadListener;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.malk.jiuan.entity.ConvertSales;
|
|
|
+import com.malk.jiuan.entity.Sales;
|
|
|
+import com.malk.jiuan.entity.SalesReturn;
|
|
|
+import com.malk.jiuan.service.JiuanService;
|
|
|
+import com.malk.server.dingtalk.DDR_New;
|
|
|
+import com.malk.service.dingtalk.DDClient;
|
|
|
+import com.malk.utils.UtilHttp;
|
|
|
+import com.malk.utils.UtilMap;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import okhttp3.*;
|
|
|
+import okio.BufferedSink;
|
|
|
+import okio.Okio;
|
|
|
+import okio.Sink;
|
|
|
+import org.apache.logging.log4j.util.Strings;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.io.BufferedWriter;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileWriter;
|
|
|
+import java.io.IOException;
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.text.DecimalFormat;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class JiuanServiceImpl implements JiuanService {
|
|
|
+ private final static String SHOP_NUMBER = "TJMP1F140";//商铺号
|
|
|
+ private final static String CASH_REGISTER_Number = "1400";//收银机号
|
|
|
+ private final static String GOODS_NUMBER = "00101701";//货品编码
|
|
|
+
|
|
|
+ private final static String DATE_PATTERN1 = "yyyy-MM-dd HH:mm:ss";
|
|
|
+ private final static String DATE_PATTERN2 = "yyyyMMddHHmmss";
|
|
|
+ private final static String DATE_PATTERN3 = "yyyyMMdd";
|
|
|
+
|
|
|
+ @Value(value = "${dingtalk.spaceId}")
|
|
|
+ private String SPACE_ID;
|
|
|
+
|
|
|
+ @Value(value = "${dingtalk.unionId}")
|
|
|
+ private String UNION_ID;
|
|
|
+
|
|
|
+ @Value(value = "${saveFile.path}")
|
|
|
+ private String saveFilePath;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DDClient ddClient;
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void convertFile() {
|
|
|
+ // 获取当前时间
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ // 定义格式:yyyyMMddhhmmss
|
|
|
+ DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern(DATE_PATTERN2);
|
|
|
+ // 定义格式:yyyyMMdd
|
|
|
+ DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern(DATE_PATTERN3);
|
|
|
+ // 格式化时间
|
|
|
+ String formattedTime = now.format(formatter2);
|
|
|
+
|
|
|
+ String formattedTime3 = now.format(formatter3);
|
|
|
+
|
|
|
+ //搜索钉盘文件
|
|
|
+ Map query = new HashMap();
|
|
|
+ query.put("parentId",0);
|
|
|
+ query.put("unionId", UNION_ID);
|
|
|
+ query.put("maxResults",10);
|
|
|
+ query.put("orderBy","CREATE_TIME");
|
|
|
+ query.put("order","DESC");
|
|
|
+ DDR_New ddrNew = (DDR_New) UtilHttp.doGet("https://api.dingtalk.com/v1.0/storage/spaces/" + SPACE_ID + "/dentries", ddClient.initTokenHeader(), query, DDR_New.class);
|
|
|
+
|
|
|
+ List<Map> dentries = ddrNew.getDentries();
|
|
|
+
|
|
|
+ String fileId = "";
|
|
|
+ String fileName = "";
|
|
|
+
|
|
|
+ for (Map dentry : dentries) {
|
|
|
+ String name = UtilMap.getString(dentry, "name");
|
|
|
+ if (name.contains(formattedTime3)) {
|
|
|
+ fileId = UtilMap.getString(dentry, "id");
|
|
|
+ fileName = name;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取文件下载信息
|
|
|
+ query.keySet().removeIf(key -> !key.equals("unionId"));
|
|
|
+ DDR_New ddrNew2 = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/storage/spaces/" + SPACE_ID + "/dentries/" + fileId + "/downloadInfos/query", ddClient.initTokenHeader(), query, null,DDR_New.class);
|
|
|
+
|
|
|
+ Map headerSignatureInfo = ddrNew2.getHeaderSignatureInfo();
|
|
|
+
|
|
|
+ Map<String,String> headers = UtilMap.getMap(headerSignatureInfo, "headers");
|
|
|
+
|
|
|
+ List<String> resourceUrls = UtilMap.getList(headerSignatureInfo, "resourceUrls");
|
|
|
+
|
|
|
+ downloadDdFile(resourceUrls.get(0) ,headers, saveFilePath + fileName);
|
|
|
+
|
|
|
+ List<Sales> salesList = new ArrayList<>();
|
|
|
+
|
|
|
+ //销售单
|
|
|
+ EasyExcel.read(saveFilePath + fileName, Sales.class, new PageReadListener<Sales>(dataList -> {
|
|
|
+ for (Sales Sales : dataList) {
|
|
|
+ log.info("读取到一条数据{}", JSON.toJSONString(Sales));
|
|
|
+ salesList.add(Sales);
|
|
|
+ }
|
|
|
+ })).sheet(0).doRead();
|
|
|
+
|
|
|
+ //退货单
|
|
|
+ EasyExcel.read(saveFilePath + fileName, SalesReturn.class, new PageReadListener<SalesReturn>(dataList -> {
|
|
|
+ for (SalesReturn salesReturn : dataList) {
|
|
|
+ log.info("读取到一条数据{}", JSON.toJSONString(salesReturn));
|
|
|
+ Sales sales = new Sales();
|
|
|
+ sales.setZfze(salesReturn.getYtze());//应退金额
|
|
|
+ sales.setZfsj(salesReturn.getTksj());//退款时间
|
|
|
+ sales.setZffs(salesReturn.getZffs());//支付方式
|
|
|
+ salesList.add(sales);
|
|
|
+ }
|
|
|
+ })).sheet(1).doRead();
|
|
|
+
|
|
|
+ //支付时间升序
|
|
|
+ List<Sales> sortedSalesList = salesList.stream()
|
|
|
+ .sorted(Comparator.comparing(Sales::getZfsj))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ AtomicInteger counter = new AtomicInteger(1);
|
|
|
+ String currentDatePrefix = "";
|
|
|
+
|
|
|
+ List<ConvertSales> convertSalesList = new ArrayList<>();
|
|
|
+
|
|
|
+ for (Sales sales : sortedSalesList) {
|
|
|
+ // 获取日期的YYMMDD部分
|
|
|
+ LocalDate date = sales.getZfsj().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
|
|
+ LocalDateTime localDateTime = sales.getZfsj().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
|
|
+
|
|
|
+ String datePrefix = date.format(DateTimeFormatter.ofPattern("yyMMdd"));
|
|
|
+
|
|
|
+ // 如果日期变化,重置计数器
|
|
|
+ if (!datePrefix.equals(currentDatePrefix)) {
|
|
|
+ currentDatePrefix = datePrefix;
|
|
|
+ counter.set(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成流水号:YYMMDD + 4位流水(不足补零)
|
|
|
+ String serialNumber = String.format("%s%04d", datePrefix, counter.getAndIncrement());
|
|
|
+
|
|
|
+ ConvertSales convertSales = new ConvertSales();
|
|
|
+
|
|
|
+ convertSales.setRow1(CASH_REGISTER_Number);//收银机号
|
|
|
+
|
|
|
+ convertSales.setRow2(serialNumber);//交易流水号
|
|
|
+
|
|
|
+ convertSales.setRow3(localDateTime.format(DateTimeFormatter.ofPattern(DATE_PATTERN1)));//支付时间
|
|
|
+
|
|
|
+ convertSales.setRow4(new DecimalFormat("0.00").format(sales.getZfze()));//整单实收金额
|
|
|
+
|
|
|
+ convertSales.setRow5(GOODS_NUMBER);//货品编号
|
|
|
+
|
|
|
+ //交易方式
|
|
|
+ if (Strings.isNotBlank(sales.getZffs())){
|
|
|
+ switch (sales.getZffs()){
|
|
|
+ case "现金支付" : convertSales.setRow6("01");break;
|
|
|
+ case "其他" : convertSales.setRow6("06");break;
|
|
|
+ /*case "刷卡支付" : convertSales.setRow6("02");break;
|
|
|
+ case "外挂POS机" : convertSales.setRow6("03");break;
|
|
|
+ case "储值卡" : convertSales.setRow6("04");break;
|
|
|
+ case "代金卷" : convertSales.setRow6("05");break;*/
|
|
|
+ default: convertSales.setRow6("03");break;//外挂pos机
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ convertSalesList.add(convertSales);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将对象列表写入文件
|
|
|
+
|
|
|
+
|
|
|
+ String newFileName = SHOP_NUMBER + "_" + formattedTime + "_LIST.txt";
|
|
|
+// String newFileName = SHOP_NUMBER + "_" + "20250819235959" + "_LIST.txt";
|
|
|
+ writeObjectsToFile(convertSalesList, "d:\\" + newFileName);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param url 调用获取下载信息接口获取的internalResourceUrls
|
|
|
+ * @param path 文件要下载的目标路径
|
|
|
+ * @param headers 调用下载信息接口获取的headers
|
|
|
+ */
|
|
|
+ public static void downloadDdFile(String url,Map<String,String> headers,String path){
|
|
|
+ OkHttpClient client = new OkHttpClient();
|
|
|
+ Request request = new Request.Builder()
|
|
|
+ .url(url)
|
|
|
+ .headers(Headers.of(headers))
|
|
|
+ .build();
|
|
|
+ try (Response response = client.newCall(request).execute()) { // 同步请求
|
|
|
+ if (!response.isSuccessful()) {
|
|
|
+ throw new IOException("服务器返回错误: " + response.code());
|
|
|
+ }
|
|
|
+ File dest = new File(path);
|
|
|
+ try (BufferedSink sink = Okio.buffer(Okio.sink(dest))) {
|
|
|
+ sink.writeAll(response.body().source());
|
|
|
+ System.out.println("文件下载成功: " + dest.getAbsolutePath());
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> void writeObjectsToFile(List<T> objects, String filePath) {
|
|
|
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
|
|
|
+ if (objects == null || objects.size() == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取对象的所有字段(包括私有字段)
|
|
|
+ Field[] fields = objects.get(0).getClass().getDeclaredFields();
|
|
|
+
|
|
|
+ // 遍历对象数组
|
|
|
+ for (T obj : objects) {
|
|
|
+ StringBuilder line = new StringBuilder();
|
|
|
+
|
|
|
+ // 遍历每个字段
|
|
|
+ for (Field field : fields) {
|
|
|
+ field.setAccessible(true); // 允许访问私有字段
|
|
|
+ Object value = field.get(obj);
|
|
|
+ line.append(value != null ? value.toString() : "").append(",");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 写入行(以逗号结尾后换行)
|
|
|
+ writer.write(line.toString());
|
|
|
+ writer.newLine();
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("数据已成功写入文件: " + filePath);
|
|
|
+ } catch (IOException | IllegalAccessException e) {
|
|
|
+ System.err.println("写入文件时出错: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|