报表检查表
This commit is contained in:
@@ -220,7 +220,7 @@ public class LbGoodsServiceImpl extends ServiceImpl<LbGoodsMapper, LbGoods> impl
|
||||
w.le(LbGoods::getUpdatedAt, updatedEnd);
|
||||
}
|
||||
|
||||
w.orderByDesc(LbGoods::getUpdatedAt).orderByDesc(LbGoods::getId);
|
||||
w.orderByDesc(LbGoods::getPrice).orderByDesc(LbGoods::getId);
|
||||
|
||||
Page<LbGoods> page = this.page(new Page<>(current, size), w);
|
||||
result.put("success", true);
|
||||
|
||||
@@ -66,7 +66,21 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
private static final int RESULT_CHECK_COL_BUY_TOTAL_FEE = 20;
|
||||
private static final int RESULT_CHECK_COL_SELL_DETAIL = 21;
|
||||
private static final int RESULT_CHECK_COL_SELL_TOTAL = 22;
|
||||
private static final int RESULT_CHECK_LAST_COL = RESULT_CHECK_COL_SELL_TOTAL;
|
||||
/** 结果表检查表 Y 列:Z 列订单金额对应昵称;Z 列:S 列多笔订单金额逐行展开。 */
|
||||
private static final int RESULT_CHECK_COL_BUY_ORDER_NICKNAME = 24;
|
||||
private static final int RESULT_CHECK_COL_BUY_ORDER_AMOUNT = 25;
|
||||
/** 结果表检查表 AA 列:按 Y 列昵称汇总 Z 列订单金额。 */
|
||||
private static final int RESULT_CHECK_COL_BUY_ORDER_YZ_SUM = 26;
|
||||
/** 结果表检查表 AC 列:AD 列卖出订单金额对应昵称;AD 列:V 列多笔卖出金额逐行展开。 */
|
||||
private static final int RESULT_CHECK_COL_SELL_ORDER_NICKNAME = 28;
|
||||
private static final int RESULT_CHECK_COL_SELL_ORDER_AMOUNT = 29;
|
||||
/** 结果表检查表 AE 列:按 AC 列昵称汇总 AD 列卖出订单金额。 */
|
||||
private static final int RESULT_CHECK_COL_SELL_ORDER_AD_SUM = 30;
|
||||
/** 结果表检查表 AF~AH:总表与检查表买入差异核对。 */
|
||||
private static final int RESULT_CHECK_COL_BUY_DIFF_SUMMARY = 31;
|
||||
private static final int RESULT_CHECK_COL_BUY_DIFF_CHECK = 32;
|
||||
private static final int RESULT_CHECK_COL_BUY_DIFF = 33;
|
||||
private static final int RESULT_CHECK_LAST_COL = RESULT_CHECK_COL_BUY_DIFF;
|
||||
private static final BigDecimal RESULT_CHECK_BUY_TOTAL_FEE_RATE = new BigDecimal("0.01");
|
||||
|
||||
private static final int PAYMENT_COL_NAME = 0;
|
||||
@@ -140,6 +154,7 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
fillResultCheckSheet(
|
||||
workbook.getSheetAt(RESULT_CHECK_SHEET_INDEX),
|
||||
resultSheet,
|
||||
workbook.getSheetAt(SUMMARY_SHEET_INDEX),
|
||||
userIdByNickname,
|
||||
buyTotalByBuyerId,
|
||||
buyDetailByBuyerId,
|
||||
@@ -454,6 +469,7 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
private static void fillResultCheckSheet(
|
||||
Sheet target,
|
||||
Sheet resultSource,
|
||||
Sheet summarySheet,
|
||||
Map<String, String> userIdByNickname,
|
||||
Map<String, BigDecimal> buyTotalByBuyerId,
|
||||
Map<String, String> buyDetailByBuyerId,
|
||||
@@ -540,11 +556,353 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
}
|
||||
|
||||
fillResultCheckColumnsMandNByIandKNickname(target, styles);
|
||||
fillResultCheckColumnZFromColumnS(target, styles);
|
||||
fillResultCheckColumnAdFromColumnV(target, styles);
|
||||
fillResultCheckColumnAaSumByYNickname(target, styles);
|
||||
fillResultCheckColumnAeSumByAcNickname(target, styles);
|
||||
writeResultCheckColumnLAndMSum(target, styles);
|
||||
writeResultCheckBuyAmountDiffRows(target, summarySheet, styles);
|
||||
autoSizeColumns(target, RESULT_CHECK_LAST_COL);
|
||||
shrinkResultCheckDetailColumnWidths(target);
|
||||
}
|
||||
|
||||
/** 结果表检查表:末行追加 L、M 列数据合计。 */
|
||||
/** 结果表检查表 S、V 列(订单/卖出金额明细)宽度缩小为当前 20%。 */
|
||||
private static void shrinkResultCheckDetailColumnWidths(Sheet sheet) {
|
||||
shrinkColumnWidthToRatio(sheet, RESULT_CHECK_COL_BUY_DETAIL, 0.2d);
|
||||
shrinkColumnWidthToRatio(sheet, RESULT_CHECK_COL_SELL_DETAIL, 0.2d);
|
||||
}
|
||||
|
||||
private static void shrinkColumnWidthToRatio(Sheet sheet, int col, double ratio) {
|
||||
int currentWidth = sheet.getColumnWidth(col);
|
||||
int shrunk = Math.max(256, (int) Math.round(currentWidth * ratio));
|
||||
sheet.setColumnWidth(col, shrunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* S 列(订单金额明细)含多笔订单时,按「+」拆分后逐行写入 Z 列,Y 列写入对应昵称;仅 1 笔订单不写 Y/Z。
|
||||
*/
|
||||
private static void fillResultCheckColumnZFromColumnS(Sheet sheet, SheetStyles styles) {
|
||||
int dataEndRow = resolveResultCheckDataEndRow(sheet);
|
||||
if (dataEndRow < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String buyDetail = readPaymentCellText(row.getCell(RESULT_CHECK_COL_BUY_DETAIL));
|
||||
if (buyDetail.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<BigDecimal> amounts = parseOrderAmountDetailText(buyDetail);
|
||||
if (amounts.size() <= 1) {
|
||||
continue;
|
||||
}
|
||||
String nickname = readPaymentCellText(row.getCell(RESULT_CHECK_COL_NICKNAME));
|
||||
if (nickname.isEmpty()) {
|
||||
nickname = readPaymentCellText(row.getCell(RESULT_CHECK_COL_CURRENT_NICKNAME));
|
||||
}
|
||||
|
||||
int writeRow = rowIdx;
|
||||
for (BigDecimal amount : amounts) {
|
||||
writeRow = findNextEmptyResultCheckColumnZ(sheet, writeRow);
|
||||
Row targetRow = ensureResultCheckRow(sheet, writeRow, styles);
|
||||
createPaymentActualCell(
|
||||
targetRow, RESULT_CHECK_COL_BUY_ORDER_AMOUNT, amount, paymentActualStyle(writeRow, styles));
|
||||
if (!nickname.isEmpty() && isResultCheckColumnYEmpty(targetRow)) {
|
||||
createTextCell(targetRow, RESULT_CHECK_COL_BUY_ORDER_NICKNAME, nickname, styles.textStyle);
|
||||
}
|
||||
writeRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* V 列(卖出金额明细)含多笔订单时,按「+」拆分后逐行写入 AD 列,AC 列写入 Q 列昵称;仅 1 笔订单不写 AC/AD。
|
||||
*/
|
||||
private static void fillResultCheckColumnAdFromColumnV(Sheet sheet, SheetStyles styles) {
|
||||
int dataEndRow = resolveResultCheckDataEndRow(sheet);
|
||||
if (dataEndRow < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String sellDetail = readPaymentCellText(row.getCell(RESULT_CHECK_COL_SELL_DETAIL));
|
||||
if (sellDetail.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
List<BigDecimal> amounts = parseOrderAmountDetailText(sellDetail);
|
||||
if (amounts.size() <= 1) {
|
||||
continue;
|
||||
}
|
||||
String nickname = readPaymentCellText(row.getCell(RESULT_CHECK_COL_NICKNAME));
|
||||
|
||||
int writeRow = rowIdx;
|
||||
for (BigDecimal amount : amounts) {
|
||||
writeRow = findNextEmptyResultCheckColumnAd(sheet, writeRow);
|
||||
Row targetRow = ensureResultCheckRow(sheet, writeRow, styles);
|
||||
createPaymentActualCell(
|
||||
targetRow, RESULT_CHECK_COL_SELL_ORDER_AMOUNT, amount, paymentActualStyle(writeRow, styles));
|
||||
if (!nickname.isEmpty() && isResultCheckColumnAcEmpty(targetRow)) {
|
||||
createTextCell(targetRow, RESULT_CHECK_COL_SELL_ORDER_NICKNAME, nickname, styles.textStyle);
|
||||
}
|
||||
writeRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** AE 列:按 AC 列昵称汇总 AD 列卖出订单金额,连续相同昵称仅末行展示。 */
|
||||
private static void fillResultCheckColumnAeSumByAcNickname(Sheet sheet, SheetStyles styles) {
|
||||
int dataEndRow = resolveResultCheckDataEndRow(sheet);
|
||||
if (dataEndRow < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, BigDecimal> sumByAcNickname = new HashMap<>();
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String acName = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_SELL_ORDER_NICKNAME)));
|
||||
if (acName.isEmpty() || isResultCheckColumnAdEmpty(row)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal adValue = readNumericCellValue(row.getCell(RESULT_CHECK_COL_SELL_ORDER_AMOUNT));
|
||||
sumByAcNickname.merge(acName, adValue, BigDecimal::add);
|
||||
}
|
||||
|
||||
Set<Integer> displayRows = resolveConsecutiveLastRowsByColumnAc(sheet, dataEndRow);
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String acName = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_SELL_ORDER_NICKNAME)));
|
||||
if (displayRows.contains(rowIdx)) {
|
||||
BigDecimal sum = sumByAcNickname.getOrDefault(acName, BigDecimal.ZERO);
|
||||
createPaymentActualCell(
|
||||
row, RESULT_CHECK_COL_SELL_ORDER_AD_SUM, sum, paymentActualStyle(rowIdx, styles));
|
||||
} else {
|
||||
createTextCell(row, RESULT_CHECK_COL_SELL_ORDER_AD_SUM, "", styles.textStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** AA 列:按 Y 列昵称汇总 Z 列订单金额,连续相同昵称仅末行展示。 */
|
||||
private static void fillResultCheckColumnAaSumByYNickname(Sheet sheet, SheetStyles styles) {
|
||||
int dataEndRow = resolveResultCheckDataEndRow(sheet);
|
||||
if (dataEndRow < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, BigDecimal> sumByYNickname = new HashMap<>();
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String yName = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_BUY_ORDER_NICKNAME)));
|
||||
if (yName.isEmpty() || isResultCheckColumnZEmpty(row)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal zValue = readNumericCellValue(row.getCell(RESULT_CHECK_COL_BUY_ORDER_AMOUNT));
|
||||
sumByYNickname.merge(yName, zValue, BigDecimal::add);
|
||||
}
|
||||
|
||||
Set<Integer> displayRows = resolveConsecutiveLastRowsByColumnY(sheet, dataEndRow);
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String yName = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_BUY_ORDER_NICKNAME)));
|
||||
if (displayRows.contains(rowIdx)) {
|
||||
BigDecimal sum = sumByYNickname.getOrDefault(yName, BigDecimal.ZERO);
|
||||
createPaymentActualCell(
|
||||
row, RESULT_CHECK_COL_BUY_ORDER_YZ_SUM, sum, paymentActualStyle(rowIdx, styles));
|
||||
} else {
|
||||
createTextCell(row, RESULT_CHECK_COL_BUY_ORDER_YZ_SUM, "", styles.textStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Integer> resolveConsecutiveLastRowsByColumnY(Sheet sheet, int dataEndRow) {
|
||||
Set<Integer> displayRows = new HashSet<>();
|
||||
String groupNickname = null;
|
||||
int groupLastRow = -1;
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
groupNickname = null;
|
||||
groupLastRow = -1;
|
||||
continue;
|
||||
}
|
||||
String yName = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_BUY_ORDER_NICKNAME)));
|
||||
if (yName.isEmpty()) {
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
groupNickname = null;
|
||||
groupLastRow = -1;
|
||||
continue;
|
||||
}
|
||||
if (!yName.equals(groupNickname)) {
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
groupNickname = yName;
|
||||
}
|
||||
groupLastRow = rowIdx;
|
||||
}
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
return displayRows;
|
||||
}
|
||||
|
||||
private static Set<Integer> resolveConsecutiveLastRowsByColumnAc(Sheet sheet, int dataEndRow) {
|
||||
Set<Integer> displayRows = new HashSet<>();
|
||||
String groupNickname = null;
|
||||
int groupLastRow = -1;
|
||||
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
groupNickname = null;
|
||||
groupLastRow = -1;
|
||||
continue;
|
||||
}
|
||||
String acName = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_SELL_ORDER_NICKNAME)));
|
||||
if (acName.isEmpty()) {
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
groupNickname = null;
|
||||
groupLastRow = -1;
|
||||
continue;
|
||||
}
|
||||
if (!acName.equals(groupNickname)) {
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
groupNickname = acName;
|
||||
}
|
||||
groupLastRow = rowIdx;
|
||||
}
|
||||
flushResultCheckNicknameGroup(displayRows, groupNickname, groupLastRow);
|
||||
return displayRows;
|
||||
}
|
||||
|
||||
private static List<BigDecimal> parseOrderAmountDetailText(String detail) {
|
||||
if (detail == null || detail.isBlank()) {
|
||||
return List.of();
|
||||
}
|
||||
List<BigDecimal> amounts = new ArrayList<>();
|
||||
for (String part : detail.split("\\+")) {
|
||||
String trimmed = part.trim();
|
||||
if (trimmed.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
amounts.add(new BigDecimal(trimmed));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// skip invalid segment
|
||||
}
|
||||
}
|
||||
return amounts;
|
||||
}
|
||||
|
||||
private static int findNextEmptyResultCheckColumnZ(Sheet sheet, int startRow) {
|
||||
int rowIdx = Math.max(1, startRow);
|
||||
while (true) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultCheckColumnZEmpty(row)) {
|
||||
return rowIdx;
|
||||
}
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
private static int findNextEmptyResultCheckColumnAd(Sheet sheet, int startRow) {
|
||||
int rowIdx = Math.max(1, startRow);
|
||||
while (true) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultCheckColumnAdEmpty(row)) {
|
||||
return rowIdx;
|
||||
}
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnYEmpty(Row row) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
Cell cell = row.getCell(RESULT_CHECK_COL_BUY_ORDER_NICKNAME);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
if (cell.getCellType() == CellType.STRING) {
|
||||
String text = cell.getStringCellValue();
|
||||
return text == null || text.trim().isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnZEmpty(Row row) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
Cell cell = row.getCell(RESULT_CHECK_COL_BUY_ORDER_AMOUNT);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
if (cell.getCellType() == CellType.STRING) {
|
||||
String text = cell.getStringCellValue();
|
||||
return text == null || text.trim().isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnAcEmpty(Row row) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
Cell cell = row.getCell(RESULT_CHECK_COL_SELL_ORDER_NICKNAME);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
if (cell.getCellType() == CellType.STRING) {
|
||||
String text = cell.getStringCellValue();
|
||||
return text == null || text.trim().isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnAdEmpty(Row row) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
Cell cell = row.getCell(RESULT_CHECK_COL_SELL_ORDER_AMOUNT);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
if (cell.getCellType() == CellType.STRING) {
|
||||
String text = cell.getStringCellValue();
|
||||
return text == null || text.trim().isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 结果表检查表:末行追加 L、M、T、W、Z、AA 列数据合计。 */
|
||||
private static void writeResultCheckColumnLAndMSum(Sheet sheet, SheetStyles styles) {
|
||||
int lastRow = sheet.getLastRowNum();
|
||||
if (lastRow < 1) {
|
||||
@@ -562,6 +920,10 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
|
||||
BigDecimal sumL = BigDecimal.ZERO;
|
||||
BigDecimal sumM = BigDecimal.ZERO;
|
||||
BigDecimal sumT = BigDecimal.ZERO;
|
||||
BigDecimal sumW = BigDecimal.ZERO;
|
||||
BigDecimal sumZ = BigDecimal.ZERO;
|
||||
BigDecimal sumAa = BigDecimal.ZERO;
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
@@ -571,6 +933,18 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
if (!isResultCheckColumnMEmpty(row)) {
|
||||
sumM = sumM.add(readNumericCellValue(row.getCell(RESULT_CHECK_COL_IK_NICKNAME_L_SUM)));
|
||||
}
|
||||
if (!isResultCheckColumnTEmpty(row)) {
|
||||
sumT = sumT.add(readNumericCellValue(row.getCell(RESULT_CHECK_COL_BUY_TOTAL)));
|
||||
}
|
||||
if (!isResultCheckColumnWEmpty(row)) {
|
||||
sumW = sumW.add(readNumericCellValue(row.getCell(RESULT_CHECK_COL_SELL_TOTAL)));
|
||||
}
|
||||
if (!isResultCheckColumnZEmpty(row)) {
|
||||
sumZ = sumZ.add(readNumericCellValue(row.getCell(RESULT_CHECK_COL_BUY_ORDER_AMOUNT)));
|
||||
}
|
||||
if (!isResultCheckColumnAaEmpty(row)) {
|
||||
sumAa = sumAa.add(readNumericCellValue(row.getCell(RESULT_CHECK_COL_BUY_ORDER_YZ_SUM)));
|
||||
}
|
||||
}
|
||||
|
||||
int sumRowIdx = dataEndRow + 1;
|
||||
@@ -582,6 +956,163 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
createTextCell(sumRow, RESULT_MATCH_NEG_NAME, "求和", styles.summaryTextStyle);
|
||||
createPaymentActualCell(sumRow, RESULT_MATCH_AMT, sumL, styles.summaryRoundedAmountStyle);
|
||||
createPaymentActualCell(sumRow, RESULT_CHECK_COL_IK_NICKNAME_L_SUM, sumM, styles.summaryRoundedAmountStyle);
|
||||
createDecimalCell(sumRow, RESULT_CHECK_COL_BUY_TOTAL, sumT, styles.summaryAmountStyle);
|
||||
createDecimalCell(sumRow, RESULT_CHECK_COL_SELL_TOTAL, sumW, styles.summaryAmountStyle);
|
||||
createPaymentActualCell(sumRow, RESULT_CHECK_COL_BUY_ORDER_AMOUNT, sumZ, styles.summaryRoundedAmountStyle);
|
||||
createPaymentActualCell(sumRow, RESULT_CHECK_COL_BUY_ORDER_YZ_SUM, sumAa, styles.summaryRoundedAmountStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 总表 D 列(当日买入)与检查表 T 列(订单买入)按昵称核对;差异写在求和行之后。
|
||||
* 总表 A 列昵称 ↔ 检查表 Q 列昵称。
|
||||
*/
|
||||
private static void writeResultCheckBuyAmountDiffRows(
|
||||
Sheet checkSheet, Sheet summarySheet, SheetStyles styles) {
|
||||
if (summarySheet == null) {
|
||||
return;
|
||||
}
|
||||
int sumRowIdx = findResultCheckSumRowIndex(checkSheet);
|
||||
if (sumRowIdx < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, BigDecimal> summaryBuyByNickname = readSummaryDailyBuyByNickname(summarySheet);
|
||||
Map<String, BigDecimal> checkBuyByNickname = readCheckBuyByNickname(checkSheet, sumRowIdx - 1);
|
||||
List<BuyAmountDiffItem> diffItems = buildBuyAmountDiffItems(summaryBuyByNickname, checkBuyByNickname);
|
||||
|
||||
BigDecimal summaryTotal = readSummarySheetDailyBuyTotal(summarySheet);
|
||||
Row sumRow = checkSheet.getRow(sumRowIdx);
|
||||
BigDecimal checkTotal = sumRow == null
|
||||
? BigDecimal.ZERO
|
||||
: readNumericCellValue(sumRow.getCell(RESULT_CHECK_COL_BUY_TOTAL));
|
||||
|
||||
int writeRow = sumRowIdx + 1;
|
||||
Row titleRow = ensureResultCheckRow(checkSheet, writeRow++, styles);
|
||||
createTextCell(titleRow, RESULT_MATCH_NEG_NAME, "【买入核对差异】", styles.summaryTextStyle);
|
||||
|
||||
if (summaryTotal.compareTo(checkTotal) != 0) {
|
||||
Row totalDiffRow = ensureResultCheckRow(checkSheet, writeRow++, styles);
|
||||
createTextCell(totalDiffRow, RESULT_MATCH_NEG_NAME, "合计差异", styles.summaryTextStyle);
|
||||
createTextCell(totalDiffRow, RESULT_CHECK_COL_NICKNAME, "合计", styles.summaryTextStyle);
|
||||
createDecimalCell(totalDiffRow, RESULT_CHECK_COL_BUY_DIFF_SUMMARY, summaryTotal, styles.summaryAmountStyle);
|
||||
createDecimalCell(totalDiffRow, RESULT_CHECK_COL_BUY_DIFF_CHECK, checkTotal, styles.summaryAmountStyle);
|
||||
createDecimalCell(
|
||||
totalDiffRow,
|
||||
RESULT_CHECK_COL_BUY_DIFF,
|
||||
summaryTotal.subtract(checkTotal),
|
||||
styles.summaryAmountStyle);
|
||||
}
|
||||
|
||||
if (diffItems.isEmpty()) {
|
||||
Row okRow = ensureResultCheckRow(checkSheet, writeRow, styles);
|
||||
createTextCell(okRow, RESULT_MATCH_NEG_NAME, "无昵称级差异", styles.textStyle);
|
||||
return;
|
||||
}
|
||||
|
||||
for (BuyAmountDiffItem item : diffItems) {
|
||||
Row row = ensureResultCheckRow(checkSheet, writeRow++, styles);
|
||||
createTextCell(row, RESULT_MATCH_NEG_NAME, item.reason(), styles.textStyle);
|
||||
createTextCell(row, RESULT_CHECK_COL_NICKNAME, item.nickname(), styles.textStyle);
|
||||
if (item.summaryBuyAmt() != null) {
|
||||
createDecimalCell(row, RESULT_CHECK_COL_BUY_DIFF_SUMMARY, item.summaryBuyAmt(), styles.amountStyle);
|
||||
}
|
||||
if (item.checkBuyAmt() != null) {
|
||||
createDecimalCell(row, RESULT_CHECK_COL_BUY_DIFF_CHECK, item.checkBuyAmt(), styles.amountStyle);
|
||||
}
|
||||
createDecimalCell(row, RESULT_CHECK_COL_BUY_DIFF, item.diffAmt(), styles.amountStyle);
|
||||
}
|
||||
}
|
||||
|
||||
private static int findResultCheckSumRowIndex(Sheet sheet) {
|
||||
for (int rowIdx = sheet.getLastRowNum(); rowIdx >= 1; rowIdx--) {
|
||||
Row row = sheet.getRow(rowIdx);
|
||||
if (row != null && isResultMatchSumLabelRow(row)) {
|
||||
return rowIdx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static Map<String, BigDecimal> readSummaryDailyBuyByNickname(Sheet summarySheet) {
|
||||
Map<String, BigDecimal> buyByNickname = new LinkedHashMap<>();
|
||||
int lastRow = summarySheet.getLastRowNum();
|
||||
for (int rowIdx = 1; rowIdx <= lastRow; rowIdx++) {
|
||||
Row row = summarySheet.getRow(rowIdx);
|
||||
if (row == null) {
|
||||
continue;
|
||||
}
|
||||
String nickname = normalizeResultCheckNickname(readPaymentCellText(row.getCell(COL_NICKNAME)));
|
||||
if (nickname.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
buyByNickname.put(nickname, readNumericCellValue(row.getCell(COL_DAILY_BUY)));
|
||||
}
|
||||
return buyByNickname;
|
||||
}
|
||||
|
||||
private static BigDecimal readSummarySheetDailyBuyTotal(Sheet summarySheet) {
|
||||
int lastRow = summarySheet.getLastRowNum();
|
||||
if (lastRow < 1) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
Row lastDataRow = summarySheet.getRow(lastRow);
|
||||
if (lastDataRow == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return readNumericCellValue(lastDataRow.getCell(COL_DAILY_BUY));
|
||||
}
|
||||
|
||||
private static Map<String, BigDecimal> readCheckBuyByNickname(Sheet checkSheet, int dataEndRow) {
|
||||
Map<String, BigDecimal> buyByNickname = new LinkedHashMap<>();
|
||||
for (int rowIdx = 1; rowIdx <= dataEndRow; rowIdx++) {
|
||||
Row row = checkSheet.getRow(rowIdx);
|
||||
if (row == null || isResultMatchSumLabelRow(row)) {
|
||||
continue;
|
||||
}
|
||||
String nickname = normalizeResultCheckNickname(
|
||||
readPaymentCellText(row.getCell(RESULT_CHECK_COL_NICKNAME)));
|
||||
if (nickname.isEmpty() || isResultCheckColumnTEmpty(row)) {
|
||||
continue;
|
||||
}
|
||||
buyByNickname.put(nickname, readNumericCellValue(row.getCell(RESULT_CHECK_COL_BUY_TOTAL)));
|
||||
}
|
||||
return buyByNickname;
|
||||
}
|
||||
|
||||
private static List<BuyAmountDiffItem> buildBuyAmountDiffItems(
|
||||
Map<String, BigDecimal> summaryBuyByNickname,
|
||||
Map<String, BigDecimal> checkBuyByNickname) {
|
||||
LinkedHashSet<String> allNicknames = new LinkedHashSet<>();
|
||||
allNicknames.addAll(summaryBuyByNickname.keySet());
|
||||
allNicknames.addAll(checkBuyByNickname.keySet());
|
||||
|
||||
List<BuyAmountDiffItem> diffItems = new ArrayList<>();
|
||||
for (String nickname : allNicknames) {
|
||||
boolean inSummary = summaryBuyByNickname.containsKey(nickname);
|
||||
boolean inCheck = checkBuyByNickname.containsKey(nickname);
|
||||
BigDecimal summaryAmt = summaryBuyByNickname.get(nickname);
|
||||
BigDecimal checkAmt = checkBuyByNickname.get(nickname);
|
||||
|
||||
if (inSummary && !inCheck) {
|
||||
diffItems.add(new BuyAmountDiffItem(
|
||||
nickname, summaryAmt, null, "仅总表有", summaryAmt));
|
||||
} else if (!inSummary && inCheck) {
|
||||
diffItems.add(new BuyAmountDiffItem(
|
||||
nickname, null, checkAmt, "仅检查表有", defaultZero(checkAmt).negate()));
|
||||
} else if (inSummary && summaryAmt.compareTo(checkAmt) != 0) {
|
||||
diffItems.add(new BuyAmountDiffItem(
|
||||
nickname, summaryAmt, checkAmt, "金额不一致", summaryAmt.subtract(checkAmt)));
|
||||
}
|
||||
}
|
||||
return diffItems;
|
||||
}
|
||||
|
||||
private record BuyAmountDiffItem(
|
||||
String nickname,
|
||||
BigDecimal summaryBuyAmt,
|
||||
BigDecimal checkBuyAmt,
|
||||
String reason,
|
||||
BigDecimal diffAmt) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -721,6 +1252,44 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnTEmpty(Row row) {
|
||||
return isResultCheckNumericColumnEmpty(row, RESULT_CHECK_COL_BUY_TOTAL);
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnWEmpty(Row row) {
|
||||
return isResultCheckNumericColumnEmpty(row, RESULT_CHECK_COL_SELL_TOTAL);
|
||||
}
|
||||
|
||||
private static boolean isResultCheckNumericColumnEmpty(Row row, int col) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
Cell cell = row.getCell(col);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
if (cell.getCellType() == CellType.STRING) {
|
||||
String text = cell.getStringCellValue();
|
||||
return text == null || text.trim().isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isResultCheckColumnAaEmpty(Row row) {
|
||||
if (row == null) {
|
||||
return true;
|
||||
}
|
||||
Cell cell = row.getCell(RESULT_CHECK_COL_BUY_ORDER_YZ_SUM);
|
||||
if (cell == null || cell.getCellType() == CellType.BLANK) {
|
||||
return true;
|
||||
}
|
||||
if (cell.getCellType() == CellType.STRING) {
|
||||
String text = cell.getStringCellValue();
|
||||
return text == null || text.trim().isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 参与 K 列汇总:I、K 列昵称均非空。 */
|
||||
private static boolean includeRowForColumnKSum(String iName, String kName) {
|
||||
return !iName.isEmpty() && !kName.isEmpty();
|
||||
@@ -865,6 +1434,15 @@ public final class LbDailyUserTradeReportExportSupport {
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_TOTAL_FEE, "1%金额", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_SELL_DETAIL, "卖出金额明细", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_SELL_TOTAL, "当日卖出金额", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_ORDER_NICKNAME, "订单昵称", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_ORDER_AMOUNT, "订单金额", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_ORDER_YZ_SUM, "Y昵称Z列合计", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_SELL_ORDER_NICKNAME, "卖出订单昵称", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_SELL_ORDER_AMOUNT, "卖出订单金额", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_SELL_ORDER_AD_SUM, "AC昵称AD列合计", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_DIFF_SUMMARY, "总表买入", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_DIFF_CHECK, "检查表买入", styles.headerStyle);
|
||||
createHeaderCell(header, RESULT_CHECK_COL_BUY_DIFF, "买入差异", styles.headerStyle);
|
||||
}
|
||||
|
||||
private static void copyResultSheetContent(Sheet source, Sheet target) {
|
||||
|
||||
Reference in New Issue
Block a user