1、销售、一体化BI汇总sql优化

2、物料分类增加逻辑
This commit is contained in:
llllon 2025-09-08 18:57:22 +08:00
parent 1f4656c7f5
commit d25795d39c
10 changed files with 602 additions and 76 deletions

View File

@ -820,36 +820,37 @@ public class PurchaseDataSummaryServiceImpl implements DataSummaryService {
List<BO> bos = new ArrayList<>();
for (String wlmc : distinctList) {
RowMap row = dailyMap.get(wlmc);
if (row == null || row.getDouble("totalAmount") == 0.0) continue;
if (row == null) continue;
double avgPrice = 0.00;
// 安全获取数值并处理空值默认值为0.0
Double totalQuantity = row.getDouble("totalQuantity");
Double totalAmount = row.getDouble("totalAmount");
double safeTotalQuantity = totalQuantity != null ? totalQuantity : 0.0;
double safeTotalAmount = totalAmount != null ? totalAmount : 0.0;
// 如果总金额为0则跳过
if (safeTotalAmount == 0.0) continue;
double avgPrice = 0.0;
BO summaryBO = new BO();
summaryBO.set("RQ", dateStr);
summaryBO.set("WLMC", wlmc);
// 安全获取数值处理可能的空值
Double totalQuantity = row.getDouble("totalQuantity");
Double totalAmount = row.getDouble("totalAmount");
if (wlmc.equals("乳液") || wlmc.equals("钛白粉") || wlmc.equals("重钙")){
double adjustedQuantity = (totalQuantity != null ? totalQuantity : 0.0) / 1000;
if (wlmc.equals("乳液") || wlmc.equals("钛白粉") || wlmc.equals("重钙")) {
double adjustedQuantity = safeTotalQuantity / 1000;
summaryBO.set("CGZL", adjustedQuantity);
// 防止除零错误
if (totalAmount != null && totalAmount != 0 && adjustedQuantity != 0) {
avgPrice = totalAmount / adjustedQuantity;
if (safeTotalAmount != 0 && adjustedQuantity != 0) {
avgPrice = safeTotalAmount / adjustedQuantity;
}
} else {
double quantity = totalQuantity != null ? totalQuantity : 0.0;
summaryBO.set("CGZL", quantity);
// 防止除零错误
if (totalAmount != null && totalAmount != 0 && quantity != 0) {
avgPrice = totalAmount / quantity;
summaryBO.set("CGZL", safeTotalQuantity);
if (safeTotalAmount != 0 && safeTotalQuantity != 0) {
avgPrice = safeTotalAmount / safeTotalQuantity;
}
}
summaryBO.set("CGZE", totalAmount != null ? totalAmount : 0.0);
summaryBO.set("CGZE", safeTotalAmount);
summaryBO.set("PJDJ", avgPrice);
summaryBO.set("BKGS", bkgs);
bos.add(summaryBO);

View File

@ -769,7 +769,7 @@ public class PurchaseDataSyncServiceImpl implements DataSyncService {
Double gaiAverage = 0.00;
int gaiSum = 0;
RowMap map1 = DBSql.getMap("SELECT SUM(RKSL) AS gaiSum, SUM(DJHYF) AS gaiPrice FROM BO_EU_DWD_PUR_PURCHASE_ORDER" +
" WHERE WLMC LIKE '%盖%' AND DJHYF < 5");
" WHERE WLMC LIKE '%盖%' AND DJHYF < 3.5 AND WLMC NOT LIKE '%桶%' AND WLMC NOT LIKE '%罐%'");
if (map1!=null){
gaiSum = map1.getInt("gaiSum");
Double gaiPrice = map1.getDouble("gaiPrice");
@ -812,34 +812,43 @@ public class PurchaseDataSyncServiceImpl implements DataSyncService {
!key.equalsIgnoreCase("BINDID")) {
if (StringUtils.isNotBlank(targetTimeField)) {
String targetTimeField1 = map.getString(targetTimeField);
Date parse = UtilDate.parse(targetTimeField1);
int year = UtilDate.getYear(parse);
String monthFormat = UtilDate.monthFormat(parse);
int day = UtilDate.getDay(parse);
bo.set("YEARMONTH", year + monthFormat);
bo.set("YEAR", year);
bo.set("MONTH", monthFormat);
bo.set("DAY", day);
if (StringUtils.isNotBlank(targetTimeField1)) { // 添加空值检查
try {
Date parse = UtilDate.parse(targetTimeField1);
int year = UtilDate.getYear(parse);
String monthFormat = UtilDate.monthFormat(parse);
int day = UtilDate.getDay(parse);
bo.set("YEARMONTH", year + monthFormat);
bo.set("YEAR", year);
bo.set("MONTH", monthFormat);
bo.set("DAY", day);
} catch (Exception e) {
LOGGER.warn("解析时间字段[{}]的值[{}]失败: {}", targetTimeField, targetTimeField1, e.getMessage());
}
} else {
LOGGER.warn("时间字段[{}]的值为空记录ID: {}", targetTimeField, map.getString("ID"));
}
}
bo.set(key, map.get(key));
}
}
// 如果是采购_入库单汇总 刷新物料名称
if (hzb.equals("BO_EU_DWD_ORDER_RKD_HZ")) {
String bkgs = bo.getString("BKGS");
String wlmc = bo.getString("WLMC");
String wlbm = bo.getString("WLBM");
String jldw = bo.getString("JLDW");
String wlfl = bo.getString("WLFL");
Double djhyfs = bo.get("DJHYF",Double.class);
// 使用 StringUtils.trimToEmpty 处理可能为 null 的字符串
String bkgs = StringUtils.trimToEmpty(bo.getString("BKGS"));
String wlmc = StringUtils.trimToEmpty(bo.getString("WLMC"));
String wlbm = StringUtils.trimToEmpty(bo.getString("WLBM"));
String jldw = StringUtils.trimToEmpty(bo.getString("JLDW"));
String wlfl = StringUtils.trimToEmpty(bo.getString("WLFL"));
Double djhyfs = bo.get("DJHYF", Double.class);
double djhyf = djhyfs != null ? djhyfs : 0.0;
String newWlmc = "";
if (StringUtils.isNotBlank(wlmc) || StringUtils.isNotBlank(wlbm)
|| StringUtils.isNotBlank(jldw)
|| StringUtils.isNotBlank(wlfl)) {
newWlmc = purchaseUtil.materialClassificationFiltering(bkgs.trim(),
wlmc.trim(), wlbm.trim(), jldw.trim(), djhyf, wlfl.trim());
newWlmc = purchaseUtil.materialClassificationFiltering(bkgs,
wlmc, wlbm, jldw, djhyf, wlfl);
if (bkgs.equals("北新嘉宝莉")) {
if (wlmc.contains("")&& !wlmc.contains("") && !wlmc.contains("") && djhyf < 3.5) {
continue;
@ -852,6 +861,9 @@ public class PurchaseDataSyncServiceImpl implements DataSyncService {
}
bo.set("WLMC", newWlmc);
bo.set("OLDWLMC", wlmc);
}else {
bo.set("WLMC", wlmc);
bo.set("OLDWLMC", wlmc);
}
// LOGGER.info("采购_入库单汇总,刷新物料名称------物料名称:{},板块公司:{},物料编码:{},入库单位:{},单价:{},物料分类:{}", wlmc, bkgs, wlbm, jldw, djhyf, wlfl);
if ("泰山石膏".equals(bkgs)) {

View File

@ -75,24 +75,40 @@ public class SaleCountDimensionImpl implements DataSummaryService {
}
if (dateRange == null || dateRange.getStartDate() == null || dateRange.getEndDate() == null) {
LOGGER.info("未提供有效时间范围,按当前日期计算");
calculateForCurrentDate(bkgs);
Calendar cal = Calendar.getInstance();
// DateRange dateRangeNow = new DateRange();
// 设置为当前月的第一天
cal.set(Calendar.DAY_OF_MONTH, 1);
dateRange.setStartDate(cal.getTime());
// 设置为当前月的最后一天
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
dateRange.setEndDate(cal.getTime());
// calculateForCurrentDate(bkgs);
calculateMonthlyData(dateRange, bkgs);
// 处理营业收入数据
newProcessRevenueData(dateRange,bkgs);
// 处理销量销额数据分页查询
newProcessSalesVolumeData(dateRange,bkgs);
// 区域两金占比
newProcessRegionTwoFundsRatio(dateRange,bkgs);
LOGGER.info("{}销售数据多维度汇总计算完成",bkgs);
} else {
LOGGER.info("开始执行销售数据多维度汇总计算(时间范围: {} 至 {})",
dateRange.getStartDate(), dateRange.getEndDate());
// 计算月度维度数据按月遍历
calculateMonthlyData(dateRange, bkgs);
// 处理营业收入数据
newProcessRevenueData(dateRange,bkgs);
// 处理销量销额数据分页查询
newProcessSalesVolumeData(dateRange,bkgs);
// 区域两金占比
newProcessRegionTwoFundsRatio(dateRange,bkgs);
LOGGER.info("销售数据多维度汇总计算完成");
LOGGER.info("{}销售数据多维度汇总计算完成",bkgs);
}
} catch (Exception e) {
String errorMsg = "销售数据汇总计算失败: " + e.getMessage();
@ -101,6 +117,120 @@ public class SaleCountDimensionImpl implements DataSummaryService {
}
}
/**
* 区域两金占比
* @param dateRange 时间范围
* @param bkgs 时间范围
*/
private void newProcessRegionTwoFundsRatio(DateRange dateRange, String bkgs) {
LOGGER.info("开始处理区域两金占比,年月: {}-{}, 板块公司: {}", dateRange.getStartDate(),dateRange.getEndDate(), bkgs);
// 删除已存在的记录
String deleteSql = "DELETE FROM " + BO_EU_XS_QYLJZB + " WHERE YEARMONTH >= ? AND BKGS = ?";
try {
int deleted = DBSql.update(deleteSql, new Object[]{YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs});
LOGGER.info("区域两金占比数据-已删除{}-{}条营业收入记录", YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), deleted);
}catch (Exception e){
LOGGER.error("区域两金占比-删除数据{}年月-{}板块数据错误删除sql为{},请检查数据库链接:{}",
YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,deleteSql,e.getMessage());
throw e;
}
try {
// 第一个SQL查询应收账款数据
String receivableSql = "SELECT t1.QYGS AS QYGS, t1.BKGS AS BKGS, DATE_FORMAT( t1.RQ, '%Y-%m' ) ASyear_month, t1.RQ AS max_rq, SUM( t1.YSYE ) AS YSZK" +
" FROM BO_EU_BNBM_DATALINKUP_XS_YSL t1" +
" INNER JOIN (" +
" SELECT QYGS, BKGS, DATE_FORMAT( RQ, '%Y-%m' ) ASyear_month, MAX( RQ ) AS max_rq" +
" FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
" WHERE RQ >= ? AND RQ < ? AND BKGS = ?" +
" GROUP BY QYGS,BKGS,DATE_FORMAT ( RQ, '%Y-%m' )" +
" ) t2 ON t1.QYGS = t2.QYGS AND t1.BKGS = t2.BKGS AND t1.RQ = t2.max_rq" +
" WHERE t1.RQ >= ? AND t1.RQ < ? AND t1.BKGS = ?" +
" GROUP BY t1.QYGS,t1.BKGS,DATE_FORMAT ( t1.RQ, '%Y-%m' ),t1.RQ";
String startDate = DATE_FORMAT.format(dateRange.getStartDate());
String endDate = DATE_FORMAT.format(dateRange.getEndDate());
LOGGER.info("应收账款数据查SQL: {}", receivableSql);
List<RowMap> receivableMaps = DBSql.getMaps(receivableSql, startDate, endDate, bkgs, startDate, endDate, bkgs);
if (receivableMaps.isEmpty()) {
LOGGER.info("{}应收账款数据无数据,停止分页查询", bkgs);
} else {
ArrayList<BO> bos = new ArrayList<>();
// 收集所有销售组织用于库存查询
List<String> xszzList = new ArrayList<>();
Map<String, RowMap> receivableMap = new HashMap<>();
for (RowMap map : receivableMaps) {
String qygs = map.getString("QYGS");
List<RowMap> maps = DBSql.getMaps("SELECT * FROM BO_EU_BNBM_QYGSDYB WHERE QYGS = '" + qygs + "'");
for (RowMap rowMap : maps) {
String xszz = rowMap.getString("XSZZ");
xszzList.add(xszz);
receivableMap.put(xszz, map);
}
}
// 合并数据并创建BO对象
for (RowMap receivable : receivableMaps) {
String xszz = receivable.getString("XSZZ");
double yszk = receivable.getDouble("YSZK");
String year_month = receivable.getString("ASyear_month");
String[] split = year_month.split("-");
double kcje = 0.0;
// 第二个SQL查询库存金额数据
if (!xszzList.isEmpty()) {
String placeholders = String.join(",", Collections.nCopies(xszzList.size(), "?"));
String inClause = xszzList.stream()
.map(s -> "'" + s.replace("'", "''") + "'") // 转义单引号防止SQL注入
.collect(Collectors.joining(","));
String inventorySql = "SELECT STOCKORGNAME, SUM(BALANCE_AMOUNT) as KCJE " +
" FROM " + BO_EU_DWD_ORDER_KC_HZ + " " +
" WHERE STOCKORGNAME IN (" + inClause + ") " +
" AND CATEGORY = '产成品' " +
" AND YEAR(INDATE) = YEAR('" + split[0] + "') " +
" AND MONTH(INDATE) = MONTH('" + split[1] + "') " +
" GROUP BY STOCKORGNAME";
LOGGER.info("库存金额数据查询SQL: {}", inventorySql);
List<RowMap> inventoryMaps = DBSql.getMaps(inventorySql);
Map<String, Double> inventoryMap = inventoryMaps.stream()
.collect(Collectors.toMap(
row -> row.getString("STOCKORGNAME"),
row -> row.getDouble("KCJE"),
(existing, replacement) -> existing
));
kcje = inventoryMap.getOrDefault(xszz, 0.0);
}
BO bo = new BO();
bo.set("YEARMONTH", year_month);
bo.set("BKGS", bkgs);
bo.set("QYGS", receivable.getString("QYGS"));
bo.set("YSZK", yszk);
bo.set("KCJE", kcje);
bos.add(bo);
}
// 批量新增BO
if (!bos.isEmpty()) {
int[] admins = SDK.getBOAPI().createDataBO(BO_EU_XS_QYLJZB, bos, UserContext.fromUID("admin"));
LOGGER.info("{}{}-{}范围区域两金占比数据处理完成,查询{}条记录,累计{}条",
bkgs, dateRange.getStartDate(), dateRange.getEndDate(), bos.size(), admins[0]);
}
}
}catch (Exception e){
LOGGER.error("两金占比-新增数据{}年月-{}板块数据错误,请检查数据库链接:{}",
YEAR_MONTH_FORMAT.format(dateRange.getStartDate()), bkgs,e.getMessage());
throw e;
}
}
/**
* 处理销量销额数据
* @param dateRange 时间范围
@ -152,7 +282,7 @@ public class SaleCountDimensionImpl implements DataSummaryService {
String gc = map.getString("KCZZ");
String yearmonth = map.getString("YEARMONTH");
BO bo = new BO();
bo.set("YEARMONTH", yearmonth);
bo.set("YEARMONTH", yearmonth.substring(0, 4) + "-" + yearmonth.substring(4));
bo.set("BKGS", bkgs);
bo.set("QYGS", map.getString("QYGS"));
bo.set("GC", gc);
@ -241,7 +371,7 @@ public class SaleCountDimensionImpl implements DataSummaryService {
String gc = map.getString("KCZZ");
String yearmonth = map.getString("YEARMONTH");
BO bo = new BO();
bo.set("YEARMONTH", yearmonth);
bo.set("YEARMONTH", yearmonth.substring(0, 4) + "-" + yearmonth.substring(4));
bo.set("BKGS", bkgs);
bo.set("QYGS", map.getString("QYGS"));
bo.set("GC", gc);
@ -288,7 +418,7 @@ public class SaleCountDimensionImpl implements DataSummaryService {
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
dateRange.setEndDate(cal.getTime());
calculateMonthlyData(dateRange, bkgs);
}
@ -305,24 +435,9 @@ public class SaleCountDimensionImpl implements DataSummaryService {
for (String yearMonth : yearMonths) {
LOGGER.info("开始处理{}月份的数据,板块公司: {}", yearMonth, bkgs);
// 4. 处理区域两金占比
LOGGER.info("开始区域两金占比");
processRegionTwoFundsRatio(conn, yearMonth, bkgs);
// 1. 处理营业收入数据
// LOGGER.info("开始营业收入数据");
// processRevenueData(conn, yearMonth, bkgs);
// 2. 处理销量销额数据
// LOGGER.info("开始销量销额数据");
// processSalesVolumeData(conn, yearMonth, bkgs);
// 3. 处理应收账款数据
LOGGER.info("开始应收账款数据");
processReceivableData(conn, yearMonth, bkgs);
}
// conn.commit();
LOGGER.info("所有月份数据处理完成");
@ -567,8 +682,8 @@ public class SaleCountDimensionImpl implements DataSummaryService {
String querySql = "SELECT QYGS, XSZZ, SHENGQU, SHIQU, QX, QCYE, LJXS, LJHK, YSYE, " +
"ZLFX0_60, ZLFX60_1, ZLFX1_2, ZLFX2_3, ZLFX3_4, ZLFX4_5, ZLFX5 " +
"FROM " + RECEIVABLE_DETAIL_TABLE + " " +
"WHERE DATE(RQ) = ? AND BKGS = ? " +
"LIMIT " + PAGE_SIZE + " OFFSET " + offset;
"WHERE DATE(RQ) = ? AND BKGS = ? ";
// +"LIMIT " + PAGE_SIZE + " OFFSET " + offset;
LOGGER.info("应收账款数据查询第{}页SQL: {}", page + 1, querySql);
List<RowMap> maps = DBSql.getMaps(conn, querySql, lastDayOfMonth, bkgs);
@ -609,11 +724,7 @@ public class SaleCountDimensionImpl implements DataSummaryService {
// 批量新增BO
if (!bos.isEmpty()) {
for (int i = 0; i < bos.size(); i += BATCH_SIZE) {
int end = Math.min(bos.size(), i + BATCH_SIZE);
List<BO> batchList = bos.subList(i, end);
SDK.getBOAPI().createDataBO(BO_EU_XS_YSZK, batchList, UserContext.fromUID("admin"));
}
SDK.getBOAPI().createDataBO(BO_EU_XS_YSZK, bos, UserContext.fromUID("admin"));
totalCount += bos.size();
LOGGER.info("应收账款数据第{}页处理完成,本页{}条记录,累计{}条", page + 1, bos.size(), totalCount);
}

View File

@ -17,7 +17,10 @@ import java.math.RoundingMode;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* 一体化销售汇总计算实现类
@ -65,6 +68,10 @@ public class SaleDataSummaryServiceImpl implements DataSummaryService {
*/
private static final String RECEIVABLE_DETAIL_TABLE = "BO_EU_BNBM_DATALINKUP_XS_YSL";
// 日期格式化
private static final SimpleDateFormat YEAR_MONTH_FORMAT = new SimpleDateFormat("yyyy-MM");
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
@Override
public void calculateSummary(DateRange dateRange, BO mainConfig) {
try {
@ -79,16 +86,67 @@ public class SaleDataSummaryServiceImpl implements DataSummaryService {
}
if (dateRange == null || dateRange.getStartDate() == null || dateRange.getEndDate() == null) {
LOGGER.info("未提供有效时间范围,按当前日期计算");
calculateForCurrentDate(bkgs);
Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day = cal.get(Calendar.DAY_OF_MONTH);
String yearMonth = String.format("%04d-%02d", year, month);
String startDate = DATE_FORMAT.format(cal.getTime());
// 1. 计算并保存产品配套率年度数据(按月存储)
// calculateAndSaveMatchingRate(year, month, yearMonth, bkgs);
newcalculateAndSaveMatchingRate(startDate, yearMonth, bkgs);
// 2. 计算并保存产品销售月明细数据
// calculateAndSaveProductMonthly(year, month, yearMonth, bkgs);
newcalculateAndSaveProductMonthly(startDate, yearMonth, bkgs);
// 3. 计算并保存应收账款品牌月明细
// calculateAndSaveReceivableBrandMonthly(year, month, yearMonth, bkgs);
newcalculateAndSaveReceivableBrandMonthly(startDate, yearMonth, bkgs);
// 4. 计算并保存应收账款年度汇总(按月存储)
// calculateAndSaveReceivableYear(year, month, yearMonth, bkgs);
newcalculateAndSaveReceivableYear(startDate, yearMonth, bkgs);
// 5. 计算并保存营业收入年度汇总(按月存储)
calculateAndSaveRevenueYear(year, month, yearMonth, bkgs);
// 6. 计算并保存产品单价日明细
// calculateAndSaveUnitPriceDaily(year, month, day, currentDate, bkgs);
newcalculateAndSaveUnitPriceDaily(startDate,year, month, day, bkgs);
} else {
LOGGER.info("开始执行销售数据多维度汇总计算(时间范围: {} 至 {})",
dateRange.getStartDate(), dateRange.getEndDate());
//从结束时间获取年月
Calendar startCal = Calendar.getInstance();
startCal.setTime(dateRange.getStartDate());
startCal.set(Calendar.DAY_OF_MONTH, 1); // 设置为月份的第一天
int year = startCal.get(Calendar.YEAR);
int month = startCal.get(Calendar.MONTH) + 1;
int day = startCal.get(Calendar.DAY_OF_MONTH);
String yearMonth = String.format("%04d-%02d", year, month);
String startDate = DATE_FORMAT.format(dateRange.getStartDate());
// 计算并保存产品配套率年度数据(按月存储)
newcalculateAndSaveMatchingRate(startDate, yearMonth, bkgs);
// 计算并保存产品销售月明细数据
newcalculateAndSaveProductMonthly(startDate, yearMonth, bkgs);
// 计算并保存应收账款品牌月明细
newcalculateAndSaveReceivableBrandMonthly(startDate, yearMonth, bkgs);
// 计算并保存应收账款年度汇总(按月存储)
newcalculateAndSaveReceivableYear(startDate, yearMonth, bkgs);
// 计算并保存产品单价日明细
newcalculateAndSaveUnitPriceDaily(startDate,year, month, day, bkgs);
// 计算月度维度数据按月遍历
calculateMonthlyData(dateRange, bkgs);
// 计算日度维度数据按天遍历
calculateDailyData(dateRange, bkgs);
// calculateDailyData(dateRange, bkgs);
LOGGER.info("销售数据多维度汇总计算完成");
}
@ -99,6 +157,344 @@ public class SaleDataSummaryServiceImpl implements DataSummaryService {
}
}
/**
* 计算并保存产品单价日明细
* @param startDate
* @param year
* @param month
* @param day
* @param bkgs
*/
private void newcalculateAndSaveUnitPriceDaily(String startDate, int year, int month, int day, String bkgs) {
try {
LOGGER.info("开始计算{}-{}-{}产品单价日明细数据", year, month, day);
//新增前删除数据YEAR(DZRQ) = '" + year + "' AND MONTH(DZRQ) = '" + month + "AND DAY(DZRQ) = '"+day+"'
int delete = DBSql.update("DELETE FROM " + UNIT_PRICE_DAILY_TABLE
+ " WHERE DATE >= '" + startDate + "' AND BKGS = '"+bkgs+"'");
LOGGER.info("准备同步{}-产品单价日明细数据,删除了{}条数据",startDate,delete);
String sql = "SELECT DZRQ,LB_1,BKGS,SQ,SUM(XSSL) AS tssales, SUM(ZSSL) AS lpsales,SUM(SSJERMB) AS revenue" +
" FROM " +SALES_DETAIL_TABLE+
" WHERE LB_1 IN ('石膏板', '轻钢龙骨', '涂料') AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%')" +
" GROUP BY DZRQ,LB_1,BKGS ORDER BY DZRQ";
List<RowMap> maps = DBSql.getMaps(sql);
if (maps!=null){
ArrayList<BO> list = new ArrayList<>();
for (RowMap map : maps) {
BigDecimal tssales = BigDecimal.valueOf(map.getDouble("tssales"));
BigDecimal lpsales = BigDecimal.valueOf(map.getDouble("lpsales"));
BigDecimal revenue = BigDecimal.valueOf(map.getDouble("revenue"));
BigDecimal unitPrice = BigDecimal.ZERO;
String bkgs1 = map.getString("BKGS");
String lb_1 = map.getString("LB_1");
BO priceBO = new BO();
priceBO.set("BKGS", bkgs1);
priceBO.set("DATE", map.getString("DZRQ"));
if ("北新嘉宝莉".equals(bkgs)) {
priceBO.set("PRODUCT_TYPE", "涂料");
}else {
priceBO.set("PRODUCT_TYPE", lb_1);
}
if (bkgs1.equals("泰山石膏")){
// 计算单价避免除零错误
if (tssales.compareTo(BigDecimal.ZERO) > 0) {
// 石膏板单位转换万元/万平方米 /平方米
if ("石膏板".equals(lb_1)) {
unitPrice = revenue.divide(tssales, 4, RoundingMode.HALF_UP);
priceBO.set("SALES_VOLUME", tssales.setScale(2, RoundingMode.HALF_UP));
}
// 轻钢龙骨单位/
if ("轻钢龙骨".equals(lb_1)) {
unitPrice = revenue.divide(lpsales, 2, RoundingMode.HALF_UP);
}
priceBO.set("SALES_VOLUME", lpsales.setScale(2, RoundingMode.HALF_UP));
}
}else {
// 计算单价避免除零错误
if (lpsales.compareTo(BigDecimal.ZERO) > 0) {
// 石膏板单位转换万元/万平方米 /平方米
if ("石膏板".equals(lb_1)) {
unitPrice = revenue.divide(lpsales, 4, RoundingMode.HALF_UP);
}
// 轻钢龙骨单位/
if ("轻钢龙骨".equals(lb_1)) {
unitPrice = revenue.divide(lpsales, 2, RoundingMode.HALF_UP);
}
priceBO.set("SALES_VOLUME", lpsales.setScale(2, RoundingMode.HALF_UP));
}
}
priceBO.set("REVENUE_AMOUNT", revenue.setScale(2, RoundingMode.HALF_UP));
priceBO.set("UNIT_PRICE", unitPrice.setScale(2, RoundingMode.HALF_UP));
list.add(priceBO);
}
SDK.getBOAPI().createDataBO(UNIT_PRICE_DAILY_TABLE,list,UserContext.fromUID("admin"));
}
LOGGER.info("产品单价日明细数据保存成功");
} catch (Exception e) {
String errorMsg = String.format("产品单价日明细数据计算失败: %s", e.getMessage());
LOGGER.error(errorMsg, e);
throw new RuntimeException(errorMsg, e);
}
}
/**
* 计算并保存应收账款年度汇总(按月存储)
* @param startDate
* @param yearMonth
* @param bkgs
*/
private void newcalculateAndSaveReceivableYear(String startDate, String yearMonth, String bkgs) {
try {
LOGGER.info("开始计算{}应收账款累计数据", startDate);
//新增前删除数据
int delete = DBSql.update("DELETE FROM " + RECEIVABLE_YEAR_TABLE
+ " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
LOGGER.info("准备同步{}-应收账款年度汇总(按月存储),删除了{}条数据",startDate,delete);
String sql = "SELECT CONCAT(YEAR(RQ), '-', LPAD(MONTH(RQ), 2, '0')) ASyear_month,BKGS," +
" SUM(QCYE) AS QCYE,SUM(LJXS) AS LJXS,SUM(LJHK) AS LJHK,(SUM(QCYE) + SUM(LJXS) - SUM(LJHK)) AS receivable" +
" FROM BO_EU_BNBM_DATALINKUP_XS_YSL" +
" WHERE RQ >= ? AND BKGS = ? AND SHENGQU IN ('新疆维吾尔自治区', '海南', '西藏')" +
" GROUP BY YEAR(RQ), MONTH(RQ)" +
" ORDER BY YEAR(RQ), MONTH(RQ)";
List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs);
//查询去年数据
LocalDate localDate = LocalDate.parse(startDate).minusYears(1);
String lastDate = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
List<RowMap> lastMaps = DBSql.getMaps(sql, lastDate, bkgs);
Map<String, RowMap> resultMap = lastMaps.stream()
.filter(row -> row.getString("ASyear_month") != null) // 过滤掉键为 null 的条目
.collect(Collectors.toMap(
row -> row.getString("ASyear_month"),
row -> row,
(oldValue, newValue) -> newValue // 重复时取新值
));
if (maps!=null){
ArrayList<BO> list = new ArrayList<>();
for (RowMap map : maps) {
String aSyear_month = map.getString("ASyear_month");
BO bo = new BO();
bo.set("YEARMONTH",aSyear_month);//年月(YYYY-MM)
bo.set("BKGS",map.getString("BKGS"));//板块公司
// bo.set("RECEIVABLE_TYPE",map.getString(""));//应收类型(板骨/涂料)
bo.set("OPENING_BALANCE",map.getString("QCYE"));//期初余额(万元)
bo.set("CUMULATIVE_SALES",map.getString("LJXS"));//累计销售(万元)
bo.set("CUMULATIVE_REPAYMENT",map.getString("LJHK"));//累计回款(万元)
bo.set("ENDING_BALANCE",map.getString("receivable"));//期末余额(万元)
// 定义日期格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
// 解析字符串为YearMonth对象
YearMonth current = YearMonth.parse(yearMonth, formatter);
// 获取上一年同月
YearMonth previous = current.minusYears(1);
String lastYearMonth = previous.format(formatter);
RowMap map1 = resultMap.get(lastYearMonth);
if (map1!=null){
double lastDou = StringUtils.isNotBlank(map1.getString("receivable"))?Double.parseDouble(map1.getString("receivable")):0;
BigDecimal last = BigDecimal.valueOf(lastDou);
double currentDou = StringUtils.isNotBlank(map.getString("receivable"))?Double.parseDouble(map.getString("receivable")):0;
BigDecimal bigDecimal = BigDecimal.valueOf(currentDou);
if (last == null || last.compareTo(BigDecimal.ZERO) == 0) {
bo.set("YOY_RATE",0.0);//同比变化率(%)
}else {
bo.set("YOY_RATE",bigDecimal.subtract(last)
.divide(last, 4, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(100)));//同比变化率(%)
}
}
list.add(bo);
}
SDK.getBOAPI().createDataBO(RECEIVABLE_YEAR_TABLE,list,UserContext.fromUID("admin"));
}
LOGGER.info("应收账款月度累计数据保存成功");
} catch (Exception e) {
String errorMsg = String.format("应收账款月度累计数据计算失败: %s", e.getMessage());
LOGGER.error(errorMsg, e);
throw new RuntimeException(errorMsg, e);
}
}
/**
*
* 计算并保存应收账款品牌月明细
* @param startDate
* @param yearMonth
* @param bkgs
*/
private void newcalculateAndSaveReceivableBrandMonthly(String startDate, String yearMonth, String bkgs) {
try {
LOGGER.info("开始计算{}应收账款品牌明细数据", yearMonth);
//新增前删除数据
int delete = DBSql.update("DELETE FROM " + RECEIVABLE_BRAND_MONTHLY_TABLE
+ " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
LOGGER.info("{}:准备同步{}-应收账款品牌月明细,删除了{}条数据",bkgs,yearMonth,delete);
String sql = "SELECT CONCAT(YEAR(t1.RQ), '-', LPAD(MONTH(t1.RQ), 2, '0')) ASyear_month,t1.BKGS AS BKGS, YEAR(t1.RQ) AS year,MONTH(t1.RQ) AS month,t1.SHENGQU,SUM(t1.YSYE) AS receivable " +
" FROM BO_EU_BNBM_DATALINKUP_XS_YSL t1 " +
" INNER JOIN (" +
" SELECT MAX(RQ) AS max_rq,YEAR(RQ) AS year,MONTH(RQ) AS month " +
" FROM BO_EU_BNBM_DATALINKUP_XS_YSL " +
" WHERE RQ >= ? AND BKGS = ? AND SHENGQU IN ('新疆维吾尔自治区', '海南', '西藏') " +
" GROUP BY YEAR(RQ), MONTH(RQ) " +
") t2 ON t1.RQ = t2.max_rq AND YEAR(t1.RQ) = t2.year AND MONTH(t1.RQ) = t2.month " +
" WHERE t1.BKGS = ? AND t1.SHENGQU IN ('新疆维吾尔自治区', '海南', '西藏') " +
" GROUP BY YEAR(t1.RQ),MONTH(t1.RQ),t1.SHENGQU " +
" ORDER BY year, month, t1.SHENGQU";
List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs, bkgs);
if (maps!=null){
ArrayList<BO> list = new ArrayList<>();
for (RowMap map : maps) {
BO bo = new BO();
bo.set("YEARMONTH",map.getString("ASyear_month"));//年月(YYYY-MM)
bo.set("BKGS",map.getString("BKGS"));//板块公司
bo.set("BRAND",map.getString("BKGS"));//品牌(龙牌/泰山/梦牌/北新/嘉宝莉)
bo.set("RECEIVABLE_AMOUNT",map.getString("receivable"));//应收账款余额(万元)
list.add(bo);
}
SDK.getBOAPI().createDataBO(RECEIVABLE_BRAND_MONTHLY_TABLE,list,UserContext.fromUID("admin"));
}
LOGGER.info("应收账款品牌月明细数据保存成功");
} catch (Exception e) {
String errorMsg = String.format("应收账款品牌月明细数据计算失败: %s", e.getMessage());
LOGGER.error(errorMsg, e);
throw new RuntimeException(errorMsg, e);
}
}
/**
* 计算并保存产品销售月明细数据
* @param startDate
* @param yearMonth
* @param bkgs
*/
private void newcalculateAndSaveProductMonthly(String startDate, String yearMonth, String bkgs) {
try {
LOGGER.info("开始计算{}-产品销售明细数据", yearMonth);
//新增前删除数据
int delete = DBSql.update("DELETE FROM " + PRODUCT_MONTHLY_TABLE
+ " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
LOGGER.info("准备同步{}-产品销售明细数据,删除了{}条数据",yearMonth,delete);
String sql = "SELECT BKGS,LB_1,LB_2 AS brand,CONCAT(YEAR, '-', LPAD(MONTH, 2, '0')) ASyear_month," +
" SUM(ZSSL) AS total_zssl, SUM(XSSL)/10000 AS total_xssl_10k, SUM(SSJERMB) AS total_ssjermb," +
" (SUM(ZSSL)/(SUM(SUM(ZSSL)) OVER (PARTITION BY LB_1, YEAR(DZRQ), MONTH(DZRQ)))) *100 AS lb1_month_zssl_total," +
" ((SUM(XSSL)/10000)/(SUM(SUM(XSSL)) OVER (PARTITION BY LB_1, YEAR(DZRQ), MONTH(DZRQ)) / 10000))*100 AS lb1_month_xssl_total_10k," +
" (SUM(SSJERMB)/(SUM(SUM(SSJERMB)) OVER (PARTITION BY LB_1, YEAR(DZRQ), MONTH(DZRQ))))*100 AS lb1_month_ssjermb_total" +
" FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
" WHERE DZRQ>? AND BKGS = ? AND LB_1 IN('石膏板','轻钢龙骨','涂料') AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%') " +
" GROUP BY LB_2,year, month" +
" ORDER BY year, month";
List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs);
ArrayList<BO> list = new ArrayList<>();
if (maps!=null){
for (RowMap map : maps) {
String lb_1 = map.getString("LB_1");
String year_month = map.getString("ASyear_month");
String brand = map.getString("brand");
BO productBO = new BO();
productBO.set("BKGS", bkgs); // 新增BKGS字段
productBO.set("YEARMONTH", year_month);
if ("北新嘉宝莉".equals(bkgs) || "北新涂料".equals(bkgs)) {
if ("其他".equals(lb_1)){
productBO.set("PRODUCT_TYPE", "其他");
}else {
productBO.set("PRODUCT_TYPE", "涂料");
}
} else if ("石膏板".equals(lb_1) || "轻钢龙骨".equals(lb_1) ) {
productBO.set("PRODUCT_TYPE", lb_1);
} else {
productBO.set("PRODUCT_TYPE", "其他");
}
productBO.set("BRAND", brand);
// 设置销量及占比
if (bkgs.contains("泰山")){
productBO.set("SALES_VOLUME",map.getString("total_xssl_10k"));// 销售量
productBO.set("SALES_VOLUME_RATIO",map.getString("lb1_month_xssl_total_10k"));// 销量占比(%)
}else {
productBO.set("SALES_VOLUME",map.getString("total_zssl"));// 销售量
productBO.set("SALES_VOLUME_RATIO",map.getString("lb1_month_zssl_total"));// 销量占比(%)
}
productBO.set("REVENUE_AMOUNT",map.getString("total_ssjermb"));// 营业收入(万元)
productBO.set("REVENUE_RATIO",map.getString("lb1_month_ssjermb_total"));// 收入占比(%)
list.add(productBO);
}
SDK.getBOAPI().createDataBO(PRODUCT_MONTHLY_TABLE,list,UserContext.fromUID("admin"));
}
LOGGER.info("产品销售月明细数据保存成功");
} catch (Exception e) {
String errorMsg = String.format("产品销售月明细数据计算失败: %s", e.getMessage());
LOGGER.error(errorMsg, e);
throw new RuntimeException(errorMsg, e);
}
}
/**
* 计算并保存产品配套率年度数据(按月存储)
* @param startDate
* @param yearMonth
* @param bkgs
*/
private void newcalculateAndSaveMatchingRate(String startDate, String yearMonth, String bkgs) {
try {
LOGGER.info("开始计算{}产品配套率数据", yearMonth);
//新增前删除数据
int delete = DBSql.update("DELETE FROM " + MATCHING_RATE_YEAR_TABLE
+ " WHERE YEARMONTH >= '" + yearMonth + "' AND BKGS = '"+bkgs+"'");
LOGGER.info("{}:准备同步{}产品配套率数据,删除了{}条数据",bkgs,yearMonth,delete);
String sql = "SELECT CONCAT(YEAR, '-', LPAD(MONTH, 2, '0')) ASyear_month,YEAR(DZRQ) AS year, MONTH(DZRQ) AS month, SUM(CASE WHEN LB_1 = '石膏板' THEN ZSSL ELSE 0 END) AS gypsum_board_sales, SUM(CASE WHEN LB_1 = '轻钢龙骨' THEN ZSSL ELSE 0 END) AS steel_keel_sales, " +
" CASE " +
" WHEN SUM(CASE WHEN LB_1 = '轻钢龙骨' THEN ZSSL ELSE 0 END) > 0 " +
" THEN ROUND(SUM(CASE WHEN LB_1 = '石膏板' THEN ZSSL ELSE 0 END) / " +
" SUM(CASE WHEN LB_1 = '轻钢龙骨' THEN ZSSL ELSE 0 END), 4) " +
" ELSE 0 " +
" END AS gypsum_to_keel_ratio " +
" FROM BO_EU_BNBM_DATALINKUP_XS_XSL_HZ " +
" WHERE DZRQ >= ? AND BKGS = ? AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%') AND LB_1 IN ('石膏板', '轻钢龙骨') " +
" GROUP BY YEAR(DZRQ), MONTH(DZRQ)" +
" ORDER BY year, month";
List<RowMap> maps = DBSql.getMaps(sql, startDate, bkgs);
ArrayList<BO> list = new ArrayList<>();
if (maps!=null) {
for (RowMap map : maps) {
String aSyear_month = map.getString("ASyear_month");
BO matchingRateBO = new BO();
matchingRateBO.set("YEARMONTH", aSyear_month);
matchingRateBO.set("BKGS", bkgs);
matchingRateBO.set("GYPSUM_SALES_VOLUME", map.getString("gypsum_board_sales"));
matchingRateBO.set("STEEL_SALES_VOLUME", map.getString("steel_keel_sales"));
matchingRateBO.set("MATCHING_RATE", map.getString("gypsum_to_keel_ratio"));
list.add(matchingRateBO);
}
}
// 保存数据
SDK.getBOAPI().createDataBO(MATCHING_RATE_YEAR_TABLE,list,UserContext.fromUID("admin"));
LOGGER.info("产品配套率月度累计数据保存成功");
} catch (Exception e) {
String errorMsg = String.format("产品配套率月度累计数据计算失败: %s", e.getMessage());
LOGGER.error(errorMsg, e);
throw new RuntimeException(errorMsg, e);
}
}
/**
* 按当前日期计算无时间范围时使用
*/
@ -151,16 +547,16 @@ public class SaleDataSummaryServiceImpl implements DataSummaryService {
LOGGER.info("计算月度汇总数据: {}-{}", year, month);
// 1. 产品配套率年度数据
calculateAndSaveMatchingRate(year, month, yearMonth, bkgs);
// calculateAndSaveMatchingRate(year, month, yearMonth, bkgs);
// 2. 产品销售月明细数据
calculateAndSaveProductMonthly(year, month, yearMonth, bkgs);
// calculateAndSaveProductMonthly(year, month, yearMonth, bkgs);
// 3. 应收账款品牌月明细
calculateAndSaveReceivableBrandMonthly(year, month, yearMonth, bkgs);
// calculateAndSaveReceivableBrandMonthly(year, month, yearMonth, bkgs);
// 4. 应收账款年度汇总
calculateAndSaveReceivableYear(year, month, yearMonth, bkgs);
// calculateAndSaveReceivableYear(year, month, yearMonth, bkgs);
// 5. 营业收入年度汇总
calculateAndSaveRevenueYear(year, month, yearMonth, bkgs);
@ -520,9 +916,6 @@ public class SaleDataSummaryServiceImpl implements DataSummaryService {
+ " WHERE YEAR(DATE) = '" + year + "' AND MONTH(DATE) = '"+month+"' AND DAY(DATE) = '"+day+"' AND BKGS = '"+bkgs+"'");
LOGGER.info("准备同步{}-产品单价日明细数据,删除了{}条数据",date,delete);
List<RowMap> maps = DBSql.getMaps("SELECT LB_1 FROM " + SALES_DETAIL_TABLE + " WHERE BKGS = '" + bkgs + "'" +
"AND (SQ LIKE '%新疆%' OR SQ LIKE '%海南%' OR SQ LIKE '%西藏%') " + // 模糊查询
" GROUP BY LB_1");
String[] lb1s = new String[]{"石膏板","轻钢龙骨","涂料"};
for (String lb_1 : lb1s) {
// String lb_1 = map.getString("LB_1");

View File

@ -1,9 +1,15 @@
package com.awspaas.user.apps.bnbm.datalinkup.util;
import com.awspaas.user.apps.bnbm.datalinkup.service.impl.SaleDataSyncServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 采购模块工具类
*/
public class PurchaseUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(PurchaseUtil.class);
/**
* 判断物料名称所属分类
* @param bkgs 板块名称
@ -49,13 +55,15 @@ public class PurchaseUtil {
newWlmc = "乳液";
}
// 钛白粉
else if (("北新防水".equals(bkgs) || "北新涂料".equals(bkgs) || "北新嘉宝莉".equals(bkgs))
&& wlmc.contains("钛白粉")) {
else if (("北新防水".equals(bkgs) || "北新涂料".equals(bkgs)) && wlmc.contains("钛白粉")) {
newWlmc = "钛白粉";
} else if ("北新嘉宝莉".equals(bkgs) && wlbm.startsWith("11PT")) {
newWlmc = "钛白粉";
}
// 重钙
else if (("北新防水".equals(bkgs) || "北新涂料".equals(bkgs) || "北新嘉宝莉".equals(bkgs))
&& wlmc.contains("重钙")) {
else if (("北新防水".equals(bkgs) || "北新涂料".equals(bkgs)) && wlmc.contains("重钙")) {
newWlmc = "重钙";
} else if ("北新嘉宝莉".equals(bkgs) && wlmc.startsWith("11TD")) {
newWlmc = "重钙";
}
// 包装袋
@ -92,6 +100,7 @@ public class PurchaseUtil {
}
}catch (Exception e){
LOGGER.info("物料分类报错:{}\n{}",e.getMessage(),e);
e.printStackTrace();
}
return newWlmc;