Merge branch 'master' of https://gitea.zianxin.com/zax/biz-api-cloud-zax
This commit is contained in:
commit
195756e80a
24 files changed
+1701
-13
No files matched your search
+31
@@ -0,0 +1,31 @@
|
||||
package com.bsd.pjcloud.canteen.dto.report;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 人脸明细按维度汇总后的中间行(再映射厂区/成本中心写入刷卡明细)
|
||||
*/
|
||||
@Data
|
||||
public class CanteenReportFaceAggRow {
|
||||
|
||||
private String empNo;
|
||||
|
||||
private String empName;
|
||||
|
||||
private String legalEntity;
|
||||
|
||||
private String deptName;
|
||||
|
||||
/** 三级组织 → 消费区域 */
|
||||
private String orgLevel3;
|
||||
|
||||
/** 交易设备 → 结算台 */
|
||||
private String deviceName;
|
||||
|
||||
/** 员工刷卡 / 支付宝 */
|
||||
private String incomeType;
|
||||
|
||||
private BigDecimal amount;
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package com.bsd.pjcloud.canteen.dto.report;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 人脸消费系统导出 Excel,列序与样表一致(共 43 列)。
|
||||
* 明细入库原样落库;汇总到刷卡明细时再做字段映射。
|
||||
*/
|
||||
@Data
|
||||
public class CanteenReportFaceExcel {
|
||||
|
||||
@ExcelProperty(index = 0)
|
||||
private String orderNo;
|
||||
|
||||
@ExcelProperty(index = 1)
|
||||
private String thirdOrderNo;
|
||||
|
||||
@ExcelProperty(index = 2)
|
||||
private String createTime;
|
||||
|
||||
@ExcelProperty(index = 3)
|
||||
private String payTime;
|
||||
|
||||
@ExcelProperty(index = 4)
|
||||
private String deductTime;
|
||||
|
||||
@ExcelProperty(index = 5)
|
||||
private String orgLevel1;
|
||||
|
||||
@ExcelProperty(index = 6)
|
||||
private String orgLevel2;
|
||||
|
||||
@ExcelProperty(index = 7)
|
||||
private String orgLevel3;
|
||||
|
||||
@ExcelProperty(index = 8)
|
||||
private String canteen;
|
||||
|
||||
@ExcelProperty(index = 9)
|
||||
private String canteenArea;
|
||||
|
||||
@ExcelProperty(index = 10)
|
||||
private String consumePoint;
|
||||
|
||||
@ExcelProperty(index = 11)
|
||||
private String empName;
|
||||
|
||||
@ExcelProperty(index = 12)
|
||||
private String phone;
|
||||
|
||||
@ExcelProperty(index = 13)
|
||||
private String legalEntity;
|
||||
|
||||
@ExcelProperty(index = 14)
|
||||
private String empNo;
|
||||
|
||||
@ExcelProperty(index = 15)
|
||||
private String cardNo;
|
||||
|
||||
@ExcelProperty(index = 16)
|
||||
private String groupName;
|
||||
|
||||
@ExcelProperty(index = 17)
|
||||
private String deptName;
|
||||
|
||||
@ExcelProperty(index = 18)
|
||||
private String payMethod;
|
||||
|
||||
@ExcelProperty(index = 19)
|
||||
private String payType;
|
||||
|
||||
@ExcelProperty(index = 20)
|
||||
private String orderAmount;
|
||||
|
||||
@ExcelProperty(index = 21)
|
||||
private String changeAmount;
|
||||
|
||||
@ExcelProperty(index = 22)
|
||||
private String storedChange;
|
||||
|
||||
@ExcelProperty(index = 23)
|
||||
private String subsidyChange;
|
||||
|
||||
@ExcelProperty(index = 24)
|
||||
private String giftChange;
|
||||
|
||||
@ExcelProperty(index = 25)
|
||||
private String storedBalance;
|
||||
|
||||
@ExcelProperty(index = 26)
|
||||
private String subsidyBalance;
|
||||
|
||||
@ExcelProperty(index = 27)
|
||||
private String giftBalance;
|
||||
|
||||
@ExcelProperty(index = 28)
|
||||
private String changeOrg;
|
||||
|
||||
@ExcelProperty(index = 29)
|
||||
private String discount;
|
||||
|
||||
@ExcelProperty(index = 30)
|
||||
private String discountAmount;
|
||||
|
||||
@ExcelProperty(index = 31)
|
||||
private String discountType;
|
||||
|
||||
@ExcelProperty(index = 32)
|
||||
private String couponType;
|
||||
|
||||
@ExcelProperty(index = 33)
|
||||
private String deductAmount;
|
||||
|
||||
@ExcelProperty(index = 34)
|
||||
private String feeAmount;
|
||||
|
||||
@ExcelProperty(index = 35)
|
||||
private String mealSubsidy;
|
||||
|
||||
@ExcelProperty(index = 36)
|
||||
private String consumeType;
|
||||
|
||||
@ExcelProperty(index = 37)
|
||||
private String mealSegment;
|
||||
|
||||
@ExcelProperty(index = 38)
|
||||
private String deviceName;
|
||||
|
||||
@ExcelProperty(index = 39)
|
||||
private String deviceStatus;
|
||||
|
||||
@ExcelProperty(index = 40)
|
||||
private String remark;
|
||||
|
||||
@ExcelProperty(index = 41)
|
||||
private String operatorName;
|
||||
|
||||
@ExcelProperty(index = 42)
|
||||
private String visitorPayMethod;
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
package com.bsd.pjcloud.canteen.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 人脸消费逐笔明细:列与导出 Excel 一致(另含 biz_month/biz_date 便于分段与汇总)。
|
||||
*/
|
||||
@Data
|
||||
@TableName("canteen_report_face_detail")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "食堂报表-人脸消费逐笔明细(Excel原列)")
|
||||
public class CanteenReportFaceDetailEntity extends Model<CanteenReportFaceDetailEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private Long importLogId;
|
||||
|
||||
@Schema(description = "报表归属月")
|
||||
private String bizMonth;
|
||||
|
||||
@Schema(description = "业务日(由扣款/支付时间解析)")
|
||||
private String bizDate;
|
||||
|
||||
@Schema(description = "订单号")
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "第三方订单号")
|
||||
private String thirdOrderNo;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private String orderCreateTime;
|
||||
|
||||
@Schema(description = "支付时间")
|
||||
private String payTime;
|
||||
|
||||
@Schema(description = "扣款时间")
|
||||
private String deductTime;
|
||||
|
||||
@Schema(description = "一级组织")
|
||||
private String orgLevel1;
|
||||
|
||||
@Schema(description = "二级组织")
|
||||
private String orgLevel2;
|
||||
|
||||
@Schema(description = "三级组织")
|
||||
private String orgLevel3;
|
||||
|
||||
@Schema(description = "食堂")
|
||||
private String canteen;
|
||||
|
||||
@Schema(description = "食堂区域")
|
||||
private String canteenArea;
|
||||
|
||||
@Schema(description = "消费点")
|
||||
private String consumePoint;
|
||||
|
||||
@Schema(description = "姓名")
|
||||
private String empName;
|
||||
|
||||
@Schema(description = "手机号")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "法律归属")
|
||||
private String legalEntity;
|
||||
|
||||
@Schema(description = "人员编号")
|
||||
private String empNo;
|
||||
|
||||
@Schema(description = "卡号")
|
||||
private String cardNo;
|
||||
|
||||
@Schema(description = "分组")
|
||||
private String groupName;
|
||||
|
||||
@Schema(description = "部门")
|
||||
private String deptName;
|
||||
|
||||
@Schema(description = "支付方式")
|
||||
private String payMethod;
|
||||
|
||||
@Schema(description = "支付类型")
|
||||
private String payType;
|
||||
|
||||
@Schema(description = "订单金额")
|
||||
private BigDecimal orderAmount;
|
||||
|
||||
@Schema(description = "动账金额")
|
||||
private BigDecimal changeAmount;
|
||||
|
||||
@Schema(description = "储值动账")
|
||||
private BigDecimal storedChange;
|
||||
|
||||
@Schema(description = "补贴动账")
|
||||
private BigDecimal subsidyChange;
|
||||
|
||||
@Schema(description = "赠送动账")
|
||||
private BigDecimal giftChange;
|
||||
|
||||
@Schema(description = "储值钱包余额")
|
||||
private BigDecimal storedBalance;
|
||||
|
||||
@Schema(description = "补贴钱包余额")
|
||||
private BigDecimal subsidyBalance;
|
||||
|
||||
@Schema(description = "赠送钱包余额")
|
||||
private BigDecimal giftBalance;
|
||||
|
||||
@Schema(description = "动账组织")
|
||||
private String changeOrg;
|
||||
|
||||
@Schema(description = "优惠")
|
||||
private String discount;
|
||||
|
||||
@Schema(description = "优惠金额")
|
||||
private BigDecimal discountAmount;
|
||||
|
||||
@Schema(description = "优惠类型")
|
||||
private String discountType;
|
||||
|
||||
@Schema(description = "券类型")
|
||||
private String couponType;
|
||||
|
||||
@Schema(description = "抵扣金额")
|
||||
private BigDecimal deductAmount;
|
||||
|
||||
@Schema(description = "手续费")
|
||||
private BigDecimal feeAmount;
|
||||
|
||||
@Schema(description = "餐补")
|
||||
private BigDecimal mealSubsidy;
|
||||
|
||||
@Schema(description = "消费类型")
|
||||
private String consumeType;
|
||||
|
||||
@Schema(description = "餐段")
|
||||
private String mealSegment;
|
||||
|
||||
@Schema(description = "交易设备")
|
||||
private String deviceName;
|
||||
|
||||
@Schema(description = "设备状态")
|
||||
private String deviceStatus;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "操作员")
|
||||
private String operatorName;
|
||||
|
||||
@Schema(description = "访客餐支付方式")
|
||||
private String visitorPayMethod;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String delFlag;
|
||||
|
||||
private Long tenantId;
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.bsd.pjcloud.canteen.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("canteen_report_import_log")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "食堂报表-导入日志(演示)")
|
||||
public class CanteenReportImportLogEntity extends Model<CanteenReportImportLogEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "业务月份 yyyy-MM")
|
||||
private String bizMonth;
|
||||
|
||||
@Schema(description = "数据起日 yyyy-MM-dd")
|
||||
private String dateStart;
|
||||
|
||||
@Schema(description = "数据止日 yyyy-MM-dd")
|
||||
private String dateEnd;
|
||||
|
||||
@Schema(description = "原始文件名")
|
||||
private String fileName;
|
||||
|
||||
@Schema(description = "已存档 Excel 访问路径")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "OSS 文件名")
|
||||
private String ossFileName;
|
||||
|
||||
@Schema(description = "来源类型 FACE")
|
||||
private String sourceType;
|
||||
|
||||
@Schema(description = "Excel 有效行数")
|
||||
private Integer totalRows;
|
||||
|
||||
@Schema(description = "成功入库行数")
|
||||
private Integer successRows;
|
||||
|
||||
@Schema(description = "跳过行数")
|
||||
private Integer skipRows;
|
||||
|
||||
@Schema(description = "汇总写入刷卡明细行数")
|
||||
private Integer aggRows;
|
||||
|
||||
@Schema(description = "NONE/DONE/FAILED")
|
||||
private String aggStatus;
|
||||
|
||||
@Schema(description = "最近汇总时间")
|
||||
private LocalDateTime aggTime;
|
||||
|
||||
@Schema(description = "RUNNING/SUCCESS/FAILED")
|
||||
private String status;
|
||||
|
||||
@Schema(description = "失败原因摘要")
|
||||
private String errorMsg;
|
||||
|
||||
@Schema(description = "耗时毫秒")
|
||||
private Long costMs;
|
||||
|
||||
@Schema(description = "操作人")
|
||||
private String operator;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String delFlag;
|
||||
|
||||
private Long tenantId;
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.bsd.pjcloud.canteen.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("canteen_report_settle_park")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "食堂报表-结算台厂区配置")
|
||||
public class CanteenReportSettleParkEntity extends Model<CanteenReportSettleParkEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "结算台/交易设备名称")
|
||||
private String settleCounter;
|
||||
|
||||
@Schema(description = "厂区")
|
||||
private String park;
|
||||
|
||||
private String remark;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String delFlag;
|
||||
|
||||
private Long tenantId;
|
||||
}
|
||||
+9
@@ -22,6 +22,9 @@ public class CanteenReportSwipeEntity extends Model<CanteenReportSwipeEntity> {
|
||||
@Schema(description = "业务月份 yyyy-MM")
|
||||
private String bizMonth;
|
||||
|
||||
@Schema(description = "业务日期 yyyy-MM-dd")
|
||||
private String bizDate;
|
||||
|
||||
@Schema(description = "工号")
|
||||
private String empNo;
|
||||
|
||||
@@ -58,6 +61,12 @@ public class CanteenReportSwipeEntity extends Model<CanteenReportSwipeEntity> {
|
||||
@Schema(description = "备注标识")
|
||||
private String remarkTag;
|
||||
|
||||
@Schema(description = "导入日志ID")
|
||||
private Long importLogId;
|
||||
|
||||
@Schema(description = "来源 FACE/MANUAL/EXCEL")
|
||||
private String source;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
@Schema(description = "创建人")
|
||||
private String createBy;
|
||||
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
package com.bsd.pjcloud.canteen.report;
|
||||
|
||||
import com.bsd.pjcloud.canteen.dto.report.CanteenReportFaceExcel;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportFaceDetailEntity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 人脸 Excel → 明细原样入库;汇总时再映射收入类别 / 成本中心。
|
||||
*/
|
||||
public final class CanteenReportFaceMapper {
|
||||
|
||||
private static final Pattern DATE_PATTERN = Pattern.compile("(20\\d{2})[-/](\\d{1,2})[-/](\\d{1,2})");
|
||||
|
||||
private static final Map<String, String> LEGAL_TO_CENTER = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
for (String c : CanteenReportConstants.COST_CENTERS) {
|
||||
LEGAL_TO_CENTER.put(c, c);
|
||||
LEGAL_TO_CENTER.put(c.replace('-', '_'), c);
|
||||
LEGAL_TO_CENTER.put(c.replace('_', '-'), c);
|
||||
}
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_铝件", "嘉兴敏惠-铝件");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_塑件", "嘉兴敏惠-塑件");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_塑件BU职能", "嘉兴敏惠-塑件BU职能");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_塑件技术中心", "嘉兴敏惠-塑件技术中心");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_塑件项目中心", "嘉兴敏惠-塑件项目中心");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_研究院", "嘉兴敏惠-研究院");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏惠_地区共享", "嘉兴敏惠-地区共享");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏华_塑件工厂", "嘉兴敏华");
|
||||
LEGAL_TO_CENTER.put("嘉兴信元_塑件开发中心", "嘉兴信元-塑件开发中心");
|
||||
LEGAL_TO_CENTER.put("嘉兴信元_塑件模具厂", "嘉兴信元-塑件模具厂");
|
||||
LEGAL_TO_CENTER.put("宁波敏实汽车零部件技术研发有限公司", "宁波敏实汽车零部件技术研发有限公司");
|
||||
LEGAL_TO_CENTER.put("浙江敏能科技有限公司", "浙江敏能");
|
||||
LEGAL_TO_CENTER.put("浙江敏盛汽车零部件有限公司", "浙江敏盛");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏胜汽车零部件有限公司", "嘉兴敏胜");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏实机械有限公司", "嘉兴敏实");
|
||||
LEGAL_TO_CENTER.put("敏实海拉(嘉兴)汽车零部件有限公司", "敏实海拉");
|
||||
LEGAL_TO_CENTER.put("嘉兴敏能汽车零部件有限公司", "嘉兴敏能");
|
||||
}
|
||||
|
||||
private CanteenReportFaceMapper() {
|
||||
}
|
||||
|
||||
/** Excel 原列写入明细表(不做刷卡字段映射) */
|
||||
public static CanteenReportFaceDetailEntity toDetail(CanteenReportFaceExcel row, String bizMonth, Long importLogId) {
|
||||
if (row == null) {
|
||||
return null;
|
||||
}
|
||||
String bizDate = extractBizDate(row.getDeductTime(), row.getPayTime(), row.getCreateTime());
|
||||
BigDecimal orderAmt = firstAmount(row.getOrderAmount(), row.getChangeAmount());
|
||||
if (isBlank(row.getEmpNo()) && isBlank(row.getEmpName()) && isBlank(row.getOrderNo()) && orderAmt == null
|
||||
&& isBlank(bizDate)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CanteenReportFaceDetailEntity e = new CanteenReportFaceDetailEntity();
|
||||
e.setImportLogId(importLogId);
|
||||
if (!isBlank(bizMonth)) {
|
||||
e.setBizMonth(bizMonth.trim());
|
||||
}
|
||||
else if (bizDate != null && bizDate.length() >= 7) {
|
||||
e.setBizMonth(bizDate.substring(0, 7));
|
||||
}
|
||||
e.setBizDate(bizDate);
|
||||
|
||||
e.setOrderNo(trim(row.getOrderNo()));
|
||||
e.setThirdOrderNo(trim(row.getThirdOrderNo()));
|
||||
e.setOrderCreateTime(trim(row.getCreateTime()));
|
||||
e.setPayTime(trim(row.getPayTime()));
|
||||
e.setDeductTime(trim(row.getDeductTime()));
|
||||
e.setOrgLevel1(trim(row.getOrgLevel1()));
|
||||
e.setOrgLevel2(trim(row.getOrgLevel2()));
|
||||
e.setOrgLevel3(trim(row.getOrgLevel3()));
|
||||
e.setCanteen(trim(row.getCanteen()));
|
||||
e.setCanteenArea(trim(row.getCanteenArea()));
|
||||
e.setConsumePoint(trim(row.getConsumePoint()));
|
||||
e.setEmpName(trim(row.getEmpName()));
|
||||
e.setPhone(trim(row.getPhone()));
|
||||
e.setLegalEntity(trim(row.getLegalEntity()));
|
||||
e.setEmpNo(trim(row.getEmpNo()));
|
||||
e.setCardNo(trim(row.getCardNo()));
|
||||
e.setGroupName(trim(row.getGroupName()));
|
||||
e.setDeptName(trim(row.getDeptName()));
|
||||
e.setPayMethod(trim(row.getPayMethod()));
|
||||
e.setPayType(trim(row.getPayType()));
|
||||
e.setOrderAmount(orderAmt == null ? BigDecimal.ZERO : orderAmt);
|
||||
e.setChangeAmount(parseAmount(row.getChangeAmount()));
|
||||
e.setStoredChange(parseAmount(row.getStoredChange()));
|
||||
e.setSubsidyChange(parseAmount(row.getSubsidyChange()));
|
||||
e.setGiftChange(parseAmount(row.getGiftChange()));
|
||||
e.setStoredBalance(parseAmount(row.getStoredBalance()));
|
||||
e.setSubsidyBalance(parseAmount(row.getSubsidyBalance()));
|
||||
e.setGiftBalance(parseAmount(row.getGiftBalance()));
|
||||
e.setChangeOrg(trim(row.getChangeOrg()));
|
||||
e.setDiscount(trim(row.getDiscount()));
|
||||
e.setDiscountAmount(parseAmount(row.getDiscountAmount()));
|
||||
e.setDiscountType(trim(row.getDiscountType()));
|
||||
e.setCouponType(trim(row.getCouponType()));
|
||||
e.setDeductAmount(parseAmount(row.getDeductAmount()));
|
||||
e.setFeeAmount(parseAmount(row.getFeeAmount()));
|
||||
e.setMealSubsidy(parseAmount(row.getMealSubsidy()));
|
||||
e.setConsumeType(trim(row.getConsumeType()));
|
||||
e.setMealSegment(trim(row.getMealSegment()));
|
||||
e.setDeviceName(trim(row.getDeviceName()));
|
||||
e.setDeviceStatus(trim(row.getDeviceStatus()));
|
||||
e.setRemark(trim(row.getRemark()));
|
||||
e.setOperatorName(trim(row.getOperatorName()));
|
||||
e.setVisitorPayMethod(trim(row.getVisitorPayMethod()));
|
||||
return e;
|
||||
}
|
||||
|
||||
/** 汇总用:B扫C 等 → 支付宝;其余 → 员工刷卡 */
|
||||
public static String mapIncomeType(String payMethod, String payType) {
|
||||
String m = nvl(payMethod) + " " + nvl(payType);
|
||||
if (containsAny(m, "B扫C", "收钱吧", "支付宝", "微信", "扫码")) {
|
||||
return CanteenReportConstants.INCOME_ALIPAY;
|
||||
}
|
||||
return CanteenReportConstants.INCOME_SWIPE;
|
||||
}
|
||||
|
||||
/** 汇总用:法律归属 → 核对成本 */
|
||||
public static String mapCostCenter(String legalEntity) {
|
||||
if (isBlank(legalEntity)) {
|
||||
return "未匹配成本中心";
|
||||
}
|
||||
String raw = legalEntity.trim();
|
||||
if (LEGAL_TO_CENTER.containsKey(raw)) {
|
||||
return LEGAL_TO_CENTER.get(raw);
|
||||
}
|
||||
String norm = raw.replace('_', '-');
|
||||
if (LEGAL_TO_CENTER.containsKey(norm)) {
|
||||
return LEGAL_TO_CENTER.get(norm);
|
||||
}
|
||||
String stripped = raw.replace("有限公司", "").trim();
|
||||
for (String c : CanteenReportConstants.COST_CENTERS) {
|
||||
if (raw.contains(c) || (!stripped.isEmpty() && c.contains(stripped))) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
String compactRaw = raw.replace("-", "").replace("_", "");
|
||||
for (String c : CanteenReportConstants.COST_CENTERS) {
|
||||
String compact = c.replace("-", "").replace("_", "");
|
||||
if (compactRaw.contains(compact)) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
public static String extractBizDate(String... candidates) {
|
||||
for (String c : candidates) {
|
||||
if (isBlank(c)) {
|
||||
continue;
|
||||
}
|
||||
String s = c.trim();
|
||||
Matcher m = DATE_PATTERN.matcher(s);
|
||||
if (m.find()) {
|
||||
try {
|
||||
return LocalDate.of(Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
|
||||
Integer.parseInt(m.group(3))).toString();
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
try {
|
||||
String head = s.length() >= 10 ? s.substring(0, 10).replace('/', '-') : s.replace('/', '-');
|
||||
return LocalDate.parse(head, DateTimeFormatter.ISO_LOCAL_DATE).toString();
|
||||
}
|
||||
catch (DateTimeParseException ignored) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BigDecimal firstAmount(String... vals) {
|
||||
for (String v : vals) {
|
||||
BigDecimal b = parseAmount(v);
|
||||
if (b != null) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BigDecimal parseAmount(String v) {
|
||||
if (isBlank(v)) {
|
||||
return null;
|
||||
}
|
||||
String s = v.trim().replace(",", "").replace("¥", "").replace("元", "");
|
||||
try {
|
||||
return new BigDecimal(s);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean containsAny(String text, String... keys) {
|
||||
if (isBlank(text)) {
|
||||
return false;
|
||||
}
|
||||
for (String k : keys) {
|
||||
if (text.contains(k)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isBlank(String s) {
|
||||
return s == null || s.trim().isEmpty();
|
||||
}
|
||||
|
||||
private static String trim(String s) {
|
||||
return s == null ? null : s.trim();
|
||||
}
|
||||
|
||||
private static String nvl(String s) {
|
||||
return s == null ? "" : s;
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.bsd.pjcloud.canteen.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenReportFaceImportService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 食堂报表-人脸消费导入(明细落库 + 汇总刷卡)
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/canteenReport/faceImport")
|
||||
@Tag(description = "canteenReportFaceImport", name = "食堂报表-人脸消费导入(演示)")
|
||||
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
|
||||
public class CanteenReportFaceImportController {
|
||||
|
||||
private final CanteenReportFaceImportService faceImportService;
|
||||
|
||||
@Operation(summary = "导入日志分页")
|
||||
@GetMapping("/log/page")
|
||||
public R page(@ParameterObject Page page,
|
||||
@RequestParam(required = false) String bizMonth,
|
||||
@RequestParam(required = false) String status) {
|
||||
return R.ok(faceImportService.pageLogs(page, bizMonth, status));
|
||||
}
|
||||
|
||||
@Operation(summary = "导入日志详情")
|
||||
@GetMapping("/log/{id}")
|
||||
public R get(@PathVariable Long id) {
|
||||
return R.ok(faceImportService.getById(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "人脸逐笔明细分页")
|
||||
@GetMapping("/detail/page")
|
||||
public R detailPage(@ParameterObject Page page,
|
||||
@RequestParam(required = false) String bizMonth,
|
||||
@RequestParam(required = false) String importLogId,
|
||||
@RequestParam(required = false) String empNo,
|
||||
@RequestParam(required = false) String payMethod) {
|
||||
Long logId = null;
|
||||
if (cn.hutool.core.util.StrUtil.isNotBlank(importLogId)) {
|
||||
try {
|
||||
logId = Long.parseLong(importLogId.trim());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return R.failed("importLogId 非法");
|
||||
}
|
||||
}
|
||||
return R.ok(faceImportService.pageDetails(page, bizMonth, logId, empNo, payMethod));
|
||||
}
|
||||
|
||||
@SysLog("人脸消费Excel导入明细")
|
||||
@Operation(summary = "流式导入人脸Excel到逐笔明细表")
|
||||
@PostMapping("/import")
|
||||
public R importExcel(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(required = false) String bizMonth,
|
||||
@RequestParam(required = false) String dateStart,
|
||||
@RequestParam(required = false) String dateEnd,
|
||||
@RequestParam(defaultValue = "true") boolean replaceRange) {
|
||||
return faceImportService.importFaceExcel(file, bizMonth, dateStart, dateEnd, replaceRange);
|
||||
}
|
||||
|
||||
@SysLog("人脸明细汇总到刷卡明细")
|
||||
@Operation(summary = "统计汇总写入刷卡明细(B扫C→支付宝)")
|
||||
@PostMapping("/aggregate")
|
||||
public R aggregate(@RequestParam(required = false) String bizMonth,
|
||||
@RequestParam(required = false) String dateStart,
|
||||
@RequestParam(required = false) String dateEnd,
|
||||
@RequestParam(required = false) String importLogId,
|
||||
@RequestParam(defaultValue = "true") boolean replaceFace) {
|
||||
Long logId = null;
|
||||
if (cn.hutool.core.util.StrUtil.isNotBlank(importLogId)) {
|
||||
try {
|
||||
logId = Long.parseLong(importLogId.trim());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return R.failed("importLogId 非法: " + importLogId);
|
||||
}
|
||||
}
|
||||
return faceImportService.aggregateToSwipe(bizMonth, dateStart, dateEnd, logId, replaceFace);
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.bsd.pjcloud.canteen.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportSettleParkEntity;
|
||||
import com.bsd.pjcloud.canteen.report.CanteenReportConstants;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenReportSettleParkService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/canteenReport/settlePark")
|
||||
@Tag(description = "canteenReportSettlePark", name = "食堂报表-结算台厂区配置(演示)")
|
||||
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
|
||||
public class CanteenReportSettleParkController {
|
||||
|
||||
private final CanteenReportSettleParkService settleParkService;
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public R page(@ParameterObject Page page,
|
||||
@RequestParam(required = false) String settleCounter,
|
||||
@RequestParam(required = false) String park) {
|
||||
return R.ok(settleParkService.pageList(page, settleCounter, park));
|
||||
}
|
||||
|
||||
@Operation(summary = "厂区枚举")
|
||||
@GetMapping("/parks")
|
||||
public R parks() {
|
||||
return R.ok(CanteenReportConstants.PARKS);
|
||||
}
|
||||
|
||||
@Operation(summary = "详情")
|
||||
@GetMapping("/{id}")
|
||||
public R get(@PathVariable Long id) {
|
||||
return R.ok(settleParkService.getById(id));
|
||||
}
|
||||
|
||||
@SysLog("新增结算台厂区")
|
||||
@PostMapping
|
||||
public R add(@RequestBody CanteenReportSettleParkEntity entity) {
|
||||
return settleParkService.saveOrUpdateRow(entity);
|
||||
}
|
||||
|
||||
@SysLog("修改结算台厂区")
|
||||
@PutMapping
|
||||
public R edit(@RequestBody CanteenReportSettleParkEntity entity) {
|
||||
return settleParkService.saveOrUpdateRow(entity);
|
||||
}
|
||||
|
||||
@SysLog("删除结算台厂区")
|
||||
@DeleteMapping
|
||||
public R remove(@RequestBody Long[] ids) {
|
||||
return R.ok(settleParkService.removeBatchByIds(Arrays.asList(ids)));
|
||||
}
|
||||
|
||||
@Operation(summary = "全部列表(汇总用)")
|
||||
@GetMapping("/list")
|
||||
public R listAll() {
|
||||
List<CanteenReportSettleParkEntity> list = settleParkService.list();
|
||||
return R.ok(list);
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -37,8 +37,9 @@ public class CanteenReportSwipeController {
|
||||
@RequestParam(required = false) String park,
|
||||
@RequestParam(required = false) String incomeType,
|
||||
@RequestParam(required = false) String costCenter,
|
||||
@RequestParam(required = false) String empNo) {
|
||||
return R.ok(swipeService.pageList(page, bizMonth, park, incomeType, costCenter, empNo));
|
||||
@RequestParam(required = false) String empNo,
|
||||
@RequestParam(required = false) Long importLogId) {
|
||||
return R.ok(swipeService.pageList(page, bizMonth, park, incomeType, costCenter, empNo, importLogId));
|
||||
}
|
||||
|
||||
@Operation(summary = "详情")
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.bsd.pjcloud.canteen.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.bsd.pjcloud.canteen.dto.report.CanteenReportFaceAggRow;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportFaceDetailEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface CanteenReportFaceDetailMapper extends BaseMapper<CanteenReportFaceDetailEntity> {
|
||||
|
||||
int insertBatch(@Param("list") List<CanteenReportFaceDetailEntity> list);
|
||||
|
||||
int deletePhysicallyByImportLogId(@Param("importLogId") Long importLogId);
|
||||
|
||||
int deletePhysicallyByDateRange(@Param("bizMonth") String bizMonth,
|
||||
@Param("dateStart") String dateStart, @Param("dateEnd") String dateEnd);
|
||||
|
||||
int deletePhysicallyDateRangeExceptLog(@Param("bizMonth") String bizMonth,
|
||||
@Param("dateStart") String dateStart, @Param("dateEnd") String dateEnd,
|
||||
@Param("importLogId") Long importLogId);
|
||||
|
||||
/**
|
||||
* 按人+维度汇总;B扫C 等归入支付宝,其余归入员工刷卡。金额用订单金额。
|
||||
* 传入 importLogId 时只按批次汇总,忽略日期段。
|
||||
*/
|
||||
List<CanteenReportFaceAggRow> selectAggByMonth(@Param("bizMonth") String bizMonth,
|
||||
@Param("dateStart") String dateStart, @Param("dateEnd") String dateEnd,
|
||||
@Param("importLogId") Long importLogId);
|
||||
|
||||
long countDetail(@Param("bizMonth") String bizMonth, @Param("importLogId") Long importLogId);
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.bsd.pjcloud.canteen.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportImportLogEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CanteenReportImportLogMapper extends BaseMapper<CanteenReportImportLogEntity> {
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.bsd.pjcloud.canteen.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportSettleParkEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface CanteenReportSettleParkMapper extends BaseMapper<CanteenReportSettleParkEntity> {
|
||||
}
|
||||
+14
@@ -12,5 +12,19 @@ public interface CanteenReportSwipeMapper extends BaseMapper<CanteenReportSwipeE
|
||||
|
||||
int deletePhysicallyByBizMonth(@Param("bizMonth") String bizMonth);
|
||||
|
||||
int deletePhysicallyFaceByBizMonth(@Param("bizMonth") String bizMonth);
|
||||
|
||||
/**
|
||||
* 物理删除人脸来源在指定日期段的数据(用于半月分段覆盖导入)
|
||||
*/
|
||||
int deletePhysicallyFaceByDateRange(@Param("bizMonth") String bizMonth,
|
||||
@Param("dateStart") String dateStart, @Param("dateEnd") String dateEnd);
|
||||
|
||||
int deletePhysicallyByImportLogId(@Param("importLogId") Long importLogId);
|
||||
|
||||
int deletePhysicallyFaceRangeExceptLog(@Param("bizMonth") String bizMonth,
|
||||
@Param("dateStart") String dateStart, @Param("dateEnd") String dateEnd,
|
||||
@Param("importLogId") Long importLogId);
|
||||
|
||||
int insertBatch(@Param("list") List<CanteenReportSwipeEntity> list);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.bsd.pjcloud.canteen.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportFaceDetailEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportImportLogEntity;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
public interface CanteenReportFaceImportService extends IService<CanteenReportImportLogEntity> {
|
||||
|
||||
/**
|
||||
* 流式导入人脸 Excel → 逐笔明细表(不直接写刷卡明细)。
|
||||
*/
|
||||
R importFaceExcel(MultipartFile file, String bizMonth, String dateStart, String dateEnd, boolean replaceRange);
|
||||
|
||||
/**
|
||||
* 将明细汇总写入刷卡明细。B扫C→支付宝,其余→员工刷卡;厂区按结算台配置。
|
||||
*
|
||||
* @param bizMonth 业务月
|
||||
* @param dateStart 可选日期段
|
||||
* @param dateEnd 可选日期段
|
||||
* @param importLogId 可选,仅汇总某一批导入
|
||||
* @param replaceFace 是否先清空该月已有 FACE 汇总刷卡行
|
||||
*/
|
||||
R aggregateToSwipe(String bizMonth, String dateStart, String dateEnd, Long importLogId, boolean replaceFace);
|
||||
|
||||
Page<CanteenReportImportLogEntity> pageLogs(Page page, String bizMonth, String status);
|
||||
|
||||
Page<CanteenReportFaceDetailEntity> pageDetails(Page page, String bizMonth, Long importLogId, String empNo,
|
||||
String payMethod);
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.bsd.pjcloud.canteen.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportSettleParkEntity;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
|
||||
public interface CanteenReportSettleParkService extends IService<CanteenReportSettleParkEntity> {
|
||||
|
||||
Page<CanteenReportSettleParkEntity> pageList(Page page, String settleCounter, String park);
|
||||
|
||||
R saveOrUpdateRow(CanteenReportSettleParkEntity entity);
|
||||
}
|
||||
+2
-1
@@ -11,7 +11,8 @@ import java.util.List;
|
||||
|
||||
public interface CanteenReportSwipeService extends IService<CanteenReportSwipeEntity> {
|
||||
|
||||
Page<CanteenReportSwipeEntity> pageList(Page page, String bizMonth, String park, String incomeType, String costCenter, String empNo);
|
||||
Page<CanteenReportSwipeEntity> pageList(Page page, String bizMonth, String park, String incomeType, String costCenter,
|
||||
String empNo, Long importLogId);
|
||||
|
||||
R importExcel(List<CanteenReportSwipeExcel> rows, String bizMonth, boolean replaceMonth, BindingResult bindingResult);
|
||||
|
||||
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
package com.bsd.pjcloud.canteen.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.read.listener.ReadListener;
|
||||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteFileService;
|
||||
import com.bsd.pjcloud.canteen.dto.report.CanteenReportFaceAggRow;
|
||||
import com.bsd.pjcloud.canteen.dto.report.CanteenReportFaceExcel;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportFaceDetailEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportImportLogEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportSettleParkEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportSwipeEntity;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenReportFaceDetailMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenReportImportLogMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenReportSettleParkMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenReportSwipeMapper;
|
||||
import com.bsd.pjcloud.canteen.report.CanteenReportFaceMapper;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenReportFaceImportService;
|
||||
import com.bsd.pjcloud.common.core.constant.CommonConstants;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.tenant.TenantContextHolder;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.file.Files;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 人脸消费:Excel → 逐笔明细表;再统计汇总 → 刷卡明细。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CanteenReportFaceImportServiceImpl extends ServiceImpl<CanteenReportImportLogMapper, CanteenReportImportLogEntity>
|
||||
implements CanteenReportFaceImportService {
|
||||
|
||||
private static final int BATCH_SIZE = 1500;
|
||||
|
||||
private final CanteenReportFaceDetailMapper faceDetailMapper;
|
||||
private final CanteenReportSwipeMapper swipeMapper;
|
||||
private final CanteenReportSettleParkMapper settleParkMapper;
|
||||
private final RemoteFileService remoteFileService;
|
||||
|
||||
@Override
|
||||
public Page<CanteenReportImportLogEntity> pageLogs(Page page, String bizMonth, String status) {
|
||||
return page(page, Wrappers.<CanteenReportImportLogEntity>lambdaQuery()
|
||||
.eq(StrUtil.isNotBlank(bizMonth), CanteenReportImportLogEntity::getBizMonth, bizMonth)
|
||||
.eq(StrUtil.isNotBlank(status), CanteenReportImportLogEntity::getStatus, status)
|
||||
.orderByDesc(CanteenReportImportLogEntity::getCreateTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<CanteenReportFaceDetailEntity> pageDetails(Page page, String bizMonth, Long importLogId, String empNo,
|
||||
String payMethod) {
|
||||
return faceDetailMapper.selectPage(page, Wrappers.<CanteenReportFaceDetailEntity>lambdaQuery()
|
||||
.eq(StrUtil.isNotBlank(bizMonth), CanteenReportFaceDetailEntity::getBizMonth, bizMonth)
|
||||
.eq(importLogId != null, CanteenReportFaceDetailEntity::getImportLogId, importLogId)
|
||||
.like(StrUtil.isNotBlank(empNo), CanteenReportFaceDetailEntity::getEmpNo, empNo)
|
||||
.like(StrUtil.isNotBlank(payMethod), CanteenReportFaceDetailEntity::getPayMethod, payMethod)
|
||||
.orderByDesc(CanteenReportFaceDetailEntity::getId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R importFaceExcel(MultipartFile file, String bizMonth, String dateStart, String dateEnd,
|
||||
boolean replaceRange) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return R.failed("请上传 Excel 文件");
|
||||
}
|
||||
String originalName = file.getOriginalFilename();
|
||||
if (StrUtil.isBlank(originalName) || (!originalName.endsWith(".xlsx") && !originalName.endsWith(".xls"))) {
|
||||
return R.failed("仅支持 .xlsx / .xls");
|
||||
}
|
||||
|
||||
long t0 = System.currentTimeMillis();
|
||||
String operator = currentUser();
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
CanteenReportImportLogEntity logEntity = new CanteenReportImportLogEntity();
|
||||
logEntity.setId(IdWorker.getId());
|
||||
logEntity.setBizMonth(StrUtil.trim(bizMonth));
|
||||
logEntity.setDateStart(StrUtil.trim(dateStart));
|
||||
logEntity.setDateEnd(StrUtil.trim(dateEnd));
|
||||
logEntity.setFileName(originalName);
|
||||
logEntity.setSourceType("FACE");
|
||||
logEntity.setStatus("RUNNING");
|
||||
logEntity.setAggStatus("NONE");
|
||||
logEntity.setAggRows(0);
|
||||
logEntity.setTotalRows(0);
|
||||
logEntity.setSuccessRows(0);
|
||||
logEntity.setSkipRows(0);
|
||||
logEntity.setOperator(operator);
|
||||
logEntity.setCreateBy(operator);
|
||||
logEntity.setUpdateBy(operator);
|
||||
logEntity.setCreateTime(now);
|
||||
logEntity.setUpdateTime(now);
|
||||
logEntity.setDelFlag(CommonConstants.STATUS_NORMAL);
|
||||
logEntity.setTenantId(tenantId);
|
||||
save(logEntity);
|
||||
|
||||
File temp = null;
|
||||
try {
|
||||
temp = Files.createTempFile("canteen-face-", ".xlsx").toFile();
|
||||
file.transferTo(temp);
|
||||
archiveExcel(temp, originalName, logEntity);
|
||||
|
||||
boolean preReplace = replaceRange && StrUtil.isNotBlank(bizMonth) && StrUtil.isNotBlank(dateStart)
|
||||
&& StrUtil.isNotBlank(dateEnd);
|
||||
if (preReplace) {
|
||||
faceDetailMapper.deletePhysicallyByDateRange(bizMonth.trim(), dateStart.trim(), dateEnd.trim());
|
||||
}
|
||||
|
||||
FaceDetailAccumulator acc = new FaceDetailAccumulator(logEntity.getId(), bizMonth, operator, tenantId,
|
||||
now, faceDetailMapper, BATCH_SIZE);
|
||||
try (InputStream in = new BufferedInputStream(new FileInputStream(temp), 1 << 20)) {
|
||||
EasyExcel.read(in, CanteenReportFaceExcel.class, acc)
|
||||
.sheet()
|
||||
.headRowNumber(1)
|
||||
.doRead();
|
||||
}
|
||||
acc.flush();
|
||||
|
||||
String resolvedMonth = StrUtil.blankToDefault(StrUtil.trim(bizMonth), acc.getResolvedBizMonth());
|
||||
String resolvedStart = StrUtil.blankToDefault(StrUtil.trim(dateStart), acc.getMinDate());
|
||||
String resolvedEnd = StrUtil.blankToDefault(StrUtil.trim(dateEnd), acc.getMaxDate());
|
||||
if (StrUtil.isBlank(resolvedMonth) || StrUtil.isBlank(resolvedStart) || StrUtil.isBlank(resolvedEnd)) {
|
||||
faceDetailMapper.deletePhysicallyByImportLogId(logEntity.getId());
|
||||
failLog(logEntity, "无法确定业务月或日期段,请填写业务月与数据起止日期", t0);
|
||||
return R.failed(logEntity.getErrorMsg());
|
||||
}
|
||||
|
||||
if (replaceRange && !preReplace) {
|
||||
faceDetailMapper.deletePhysicallyDateRangeExceptLog(resolvedMonth, resolvedStart, resolvedEnd,
|
||||
logEntity.getId());
|
||||
}
|
||||
|
||||
logEntity.setBizMonth(resolvedMonth);
|
||||
logEntity.setDateStart(resolvedStart);
|
||||
logEntity.setDateEnd(resolvedEnd);
|
||||
logEntity.setTotalRows(acc.getTotalRows());
|
||||
logEntity.setSuccessRows(acc.getSuccessRows());
|
||||
logEntity.setSkipRows(acc.getSkipRows());
|
||||
logEntity.setStatus("SUCCESS");
|
||||
logEntity.setAggStatus("NONE");
|
||||
logEntity.setCostMs(System.currentTimeMillis() - t0);
|
||||
logEntity.setUpdateTime(LocalDateTime.now());
|
||||
updateById(logEntity);
|
||||
|
||||
return R.ok(logEntity, String.format(
|
||||
"明细导入成功:入库 %d 条,跳过 %d 条,日期 %s~%s,耗时 %d 秒。请点击「统计汇总到刷卡明细」生成报表数据。",
|
||||
acc.getSuccessRows(), acc.getSkipRows(), resolvedStart, resolvedEnd,
|
||||
(logEntity.getCostMs() + 999) / 1000));
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("人脸明细导入失败 logId={}", logEntity.getId(), e);
|
||||
try {
|
||||
faceDetailMapper.deletePhysicallyByImportLogId(logEntity.getId());
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
// ignore
|
||||
}
|
||||
failLog(logEntity, StrUtil.maxLength(StrUtil.blankToDefault(e.getMessage(), e.getClass().getSimpleName()), 900),
|
||||
t0);
|
||||
return R.failed("导入失败: " + e.getMessage());
|
||||
}
|
||||
finally {
|
||||
if (temp != null && temp.exists()) {
|
||||
FileUtil.del(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R aggregateToSwipe(String bizMonth, String dateStart, String dateEnd, Long importLogId,
|
||||
boolean replaceFace) {
|
||||
if (StrUtil.isBlank(bizMonth) && importLogId == null) {
|
||||
return R.failed("请传入业务月份 bizMonth,或指定某一批导入日志");
|
||||
}
|
||||
long t0 = System.currentTimeMillis();
|
||||
String operator = currentUser();
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
String month = StrUtil.trim(bizMonth);
|
||||
// 指定导入批次时:只用 importLogId,日期段不参与过滤(避免日志日期与明细 biz_date 不一致)
|
||||
String useDateStart = importLogId != null ? null : StrUtil.trim(dateStart);
|
||||
String useDateEnd = importLogId != null ? null : StrUtil.trim(dateEnd);
|
||||
|
||||
if (importLogId != null) {
|
||||
CanteenReportImportLogEntity logEntity = getById(importLogId);
|
||||
if (logEntity == null) {
|
||||
return R.failed("导入日志不存在,可能是页面 ID 精度丢失,请刷新后重试,或使用上方「统计汇总到刷卡明细」按月汇总");
|
||||
}
|
||||
if (StrUtil.isBlank(month)) {
|
||||
month = logEntity.getBizMonth();
|
||||
}
|
||||
long cnt = faceDetailMapper.countDetail(null, importLogId);
|
||||
if (cnt <= 0) {
|
||||
return R.failed(String.format(
|
||||
"该批导入日志下没有明细(importLogId=%s)。请打开「明细」确认能否查到数据;若明细也是空的,需要重新导入 Excel",
|
||||
importLogId));
|
||||
}
|
||||
}
|
||||
else {
|
||||
long cnt = faceDetailMapper.countDetail(month, null);
|
||||
if (cnt <= 0) {
|
||||
long any = faceDetailMapper.countDetail(null, null);
|
||||
if (any <= 0) {
|
||||
return R.failed("库中没有任何人脸明细,请先成功导入 Excel(导入日志里「明细入库」应大于 0)");
|
||||
}
|
||||
return R.failed(String.format(
|
||||
"归属月 %s 下没有明细(库中其它月份共有 %d 条)。请核对导入日志的「业务月」,或改选正确归属月再汇总",
|
||||
month, any));
|
||||
}
|
||||
}
|
||||
|
||||
List<CanteenReportFaceAggRow> aggRows = faceDetailMapper.selectAggByMonth(month, useDateStart, useDateEnd,
|
||||
importLogId);
|
||||
if (CollUtil.isEmpty(aggRows)) {
|
||||
return R.failed("明细存在但汇总结果为空,请检查订单金额是否都为 0");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(month) && importLogId != null) {
|
||||
CanteenReportImportLogEntity logEntity = getById(importLogId);
|
||||
if (logEntity != null) {
|
||||
month = logEntity.getBizMonth();
|
||||
}
|
||||
}
|
||||
if (StrUtil.isBlank(month)) {
|
||||
return R.failed("无法确定报表归属月");
|
||||
}
|
||||
|
||||
Map<String, String> settleParkMap = loadSettleParkMap();
|
||||
List<CanteenReportSwipeEntity> saveList = new ArrayList<>(aggRows.size());
|
||||
int unmatchedPark = 0;
|
||||
for (CanteenReportFaceAggRow row : aggRows) {
|
||||
if (row.getAmount() == null || row.getAmount().compareTo(BigDecimal.ZERO) == 0) {
|
||||
continue;
|
||||
}
|
||||
CanteenReportSwipeEntity e = new CanteenReportSwipeEntity();
|
||||
e.setId(IdWorker.getId());
|
||||
e.setBizMonth(month);
|
||||
e.setBizDate(null);
|
||||
e.setEmpNo(emptyToNull(row.getEmpNo()));
|
||||
e.setEmpName(emptyToNull(row.getEmpName()));
|
||||
e.setLegalEntity(emptyToNull(row.getLegalEntity()));
|
||||
e.setDeptName(emptyToNull(row.getDeptName()));
|
||||
e.setConsumeArea(emptyToNull(row.getOrgLevel3()));
|
||||
e.setSettleCounter(emptyToNull(row.getDeviceName()));
|
||||
e.setConsumeAmount(row.getAmount());
|
||||
e.setIncomeType(row.getIncomeType());
|
||||
e.setCostCenter(CanteenReportFaceMapper.mapCostCenter(row.getLegalEntity()));
|
||||
String park = settleParkMap.get(StrUtil.trim(row.getDeviceName()));
|
||||
if (StrUtil.isBlank(park) && StrUtil.isNotBlank(row.getDeviceName())) {
|
||||
unmatchedPark++;
|
||||
}
|
||||
e.setPark(park);
|
||||
e.setImportLogId(importLogId);
|
||||
e.setSource("FACE");
|
||||
e.setCreateBy(operator);
|
||||
e.setUpdateBy(operator);
|
||||
e.setCreateTime(now);
|
||||
e.setUpdateTime(now);
|
||||
e.setDelFlag(CommonConstants.STATUS_NORMAL);
|
||||
e.setTenantId(tenantId);
|
||||
saveList.add(e);
|
||||
}
|
||||
|
||||
if (CollUtil.isEmpty(saveList)) {
|
||||
return R.failed("汇总后可写入金额均为 0,未写入刷卡明细");
|
||||
}
|
||||
|
||||
if (replaceFace) {
|
||||
if (importLogId != null) {
|
||||
swipeMapper.deletePhysicallyByImportLogId(importLogId);
|
||||
}
|
||||
else {
|
||||
swipeMapper.deletePhysicallyFaceByBizMonth(month);
|
||||
}
|
||||
}
|
||||
|
||||
for (List<CanteenReportSwipeEntity> chunk : CollUtil.split(saveList, BATCH_SIZE)) {
|
||||
swipeMapper.insertBatch(chunk);
|
||||
}
|
||||
|
||||
if (importLogId != null) {
|
||||
CanteenReportImportLogEntity logEntity = getById(importLogId);
|
||||
if (logEntity != null) {
|
||||
logEntity.setAggRows(saveList.size());
|
||||
logEntity.setAggStatus("DONE");
|
||||
logEntity.setAggTime(now);
|
||||
logEntity.setUpdateTime(now);
|
||||
updateById(logEntity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
update(Wrappers.<CanteenReportImportLogEntity>lambdaUpdate()
|
||||
.set(CanteenReportImportLogEntity::getAggStatus, "DONE")
|
||||
.set(CanteenReportImportLogEntity::getAggTime, now)
|
||||
.set(CanteenReportImportLogEntity::getAggRows, saveList.size())
|
||||
.eq(CanteenReportImportLogEntity::getBizMonth, month)
|
||||
.eq(CanteenReportImportLogEntity::getStatus, "SUCCESS"));
|
||||
}
|
||||
|
||||
long cost = System.currentTimeMillis() - t0;
|
||||
String tip = unmatchedPark > 0
|
||||
? String.format(";有 %d 条结算台未配置厂区,请到「结算台厂区」维护后再重新汇总", unmatchedPark)
|
||||
: "";
|
||||
return R.ok(null, String.format("汇总成功:写入刷卡明细 %d 条,耗时 %d 秒%s", saveList.size(), (cost + 999) / 1000, tip));
|
||||
}
|
||||
|
||||
private Map<String, String> loadSettleParkMap() {
|
||||
List<CanteenReportSettleParkEntity> list = settleParkMapper.selectList(
|
||||
Wrappers.<CanteenReportSettleParkEntity>lambdaQuery());
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (CanteenReportSettleParkEntity e : list) {
|
||||
if (StrUtil.isNotBlank(e.getSettleCounter()) && StrUtil.isNotBlank(e.getPark())) {
|
||||
map.put(e.getSettleCounter().trim(), e.getPark().trim());
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static String emptyToNull(String s) {
|
||||
return StrUtil.isBlank(s) ? null : s.trim();
|
||||
}
|
||||
|
||||
private void archiveExcel(File temp, String originalName, CanteenReportImportLogEntity logEntity) {
|
||||
try (InputStream in = new FileInputStream(temp)) {
|
||||
MultipartFile mf = new MockMultipartFile("file", originalName,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", in);
|
||||
R upload = remoteFileService.innerUpload(mf, "canteen-report-face", null, "canteen-report-face");
|
||||
if (upload != null && upload.getData() instanceof Map) {
|
||||
Map<?, ?> data = (Map<?, ?>) upload.getData();
|
||||
Object url = data.get("url");
|
||||
Object fn = data.get("fileName");
|
||||
if (url != null) {
|
||||
logEntity.setFileUrl(String.valueOf(url));
|
||||
}
|
||||
if (fn != null) {
|
||||
logEntity.setOssFileName(String.valueOf(fn));
|
||||
}
|
||||
updateById(logEntity);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("人脸 Excel 存档失败,继续导入: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void failLog(CanteenReportImportLogEntity logEntity, String msg, long t0) {
|
||||
logEntity.setStatus("FAILED");
|
||||
logEntity.setErrorMsg(msg);
|
||||
logEntity.setCostMs(System.currentTimeMillis() - t0);
|
||||
logEntity.setUpdateTime(LocalDateTime.now());
|
||||
updateById(logEntity);
|
||||
}
|
||||
|
||||
private static String currentUser() {
|
||||
try {
|
||||
if (SecurityUtils.getUser() != null) {
|
||||
return SecurityUtils.getUser().getUsername();
|
||||
}
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static final class FaceDetailAccumulator implements ReadListener<CanteenReportFaceExcel> {
|
||||
|
||||
private final Long importLogId;
|
||||
private final String bizMonthParam;
|
||||
private final String operator;
|
||||
private final Long tenantId;
|
||||
private final LocalDateTime now;
|
||||
private final CanteenReportFaceDetailMapper faceDetailMapper;
|
||||
private final int batchSize;
|
||||
|
||||
private final List<CanteenReportFaceDetailEntity> buffer = new ArrayList<>();
|
||||
private int totalRows;
|
||||
private int successRows;
|
||||
private int skipRows;
|
||||
private String minDate;
|
||||
private String maxDate;
|
||||
private String resolvedBizMonth;
|
||||
|
||||
FaceDetailAccumulator(Long importLogId, String bizMonthParam, String operator, Long tenantId,
|
||||
LocalDateTime now, CanteenReportFaceDetailMapper faceDetailMapper, int batchSize) {
|
||||
this.importLogId = importLogId;
|
||||
this.bizMonthParam = bizMonthParam;
|
||||
this.operator = operator;
|
||||
this.tenantId = tenantId;
|
||||
this.now = now;
|
||||
this.faceDetailMapper = faceDetailMapper;
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(CanteenReportFaceExcel data, AnalysisContext context) {
|
||||
totalRows++;
|
||||
CanteenReportFaceDetailEntity e = CanteenReportFaceMapper.toDetail(data, bizMonthParam, importLogId);
|
||||
if (e == null || StrUtil.isBlank(e.getBizDate()) || StrUtil.isBlank(e.getBizMonth())) {
|
||||
skipRows++;
|
||||
return;
|
||||
}
|
||||
trackDate(e.getBizDate());
|
||||
if (resolvedBizMonth == null) {
|
||||
resolvedBizMonth = e.getBizMonth();
|
||||
}
|
||||
e.setId(IdWorker.getId());
|
||||
e.setCreateBy(operator);
|
||||
e.setUpdateBy(operator);
|
||||
e.setCreateTime(now);
|
||||
e.setUpdateTime(now);
|
||||
e.setDelFlag(CommonConstants.STATUS_NORMAL);
|
||||
e.setTenantId(tenantId);
|
||||
buffer.add(e);
|
||||
if (buffer.size() >= batchSize) {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
flush();
|
||||
}
|
||||
|
||||
void flush() {
|
||||
if (CollUtil.isEmpty(buffer)) {
|
||||
return;
|
||||
}
|
||||
faceDetailMapper.insertBatch(buffer);
|
||||
successRows += buffer.size();
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
private void trackDate(String d) {
|
||||
if (StrUtil.isBlank(d)) {
|
||||
return;
|
||||
}
|
||||
if (minDate == null || d.compareTo(minDate) < 0) {
|
||||
minDate = d;
|
||||
}
|
||||
if (maxDate == null || d.compareTo(maxDate) > 0) {
|
||||
maxDate = d;
|
||||
}
|
||||
}
|
||||
|
||||
int getTotalRows() {
|
||||
return totalRows;
|
||||
}
|
||||
|
||||
int getSuccessRows() {
|
||||
return successRows;
|
||||
}
|
||||
|
||||
int getSkipRows() {
|
||||
return skipRows;
|
||||
}
|
||||
|
||||
String getMinDate() {
|
||||
return minDate;
|
||||
}
|
||||
|
||||
String getMaxDate() {
|
||||
return maxDate;
|
||||
}
|
||||
|
||||
String getResolvedBizMonth() {
|
||||
return resolvedBizMonth;
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.bsd.pjcloud.canteen.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenReportSettleParkEntity;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenReportSettleParkMapper;
|
||||
import com.bsd.pjcloud.canteen.report.CanteenReportConstants;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenReportSettleParkService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class CanteenReportSettleParkServiceImpl extends ServiceImpl<CanteenReportSettleParkMapper, CanteenReportSettleParkEntity>
|
||||
implements CanteenReportSettleParkService {
|
||||
|
||||
@Override
|
||||
public Page<CanteenReportSettleParkEntity> pageList(Page page, String settleCounter, String park) {
|
||||
return page(page, Wrappers.<CanteenReportSettleParkEntity>lambdaQuery()
|
||||
.like(StrUtil.isNotBlank(settleCounter), CanteenReportSettleParkEntity::getSettleCounter, settleCounter)
|
||||
.eq(StrUtil.isNotBlank(park), CanteenReportSettleParkEntity::getPark, park)
|
||||
.orderByAsc(CanteenReportSettleParkEntity::getPark)
|
||||
.orderByAsc(CanteenReportSettleParkEntity::getSettleCounter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R saveOrUpdateRow(CanteenReportSettleParkEntity entity) {
|
||||
if (entity == null || StrUtil.isBlank(entity.getSettleCounter()) || StrUtil.isBlank(entity.getPark())) {
|
||||
return R.failed("结算台与厂区不能为空");
|
||||
}
|
||||
entity.setSettleCounter(entity.getSettleCounter().trim());
|
||||
entity.setPark(entity.getPark().trim());
|
||||
if (!CanteenReportConstants.PARKS.contains(entity.getPark())
|
||||
&& !CanteenReportConstants.SHARE_PARKS.contains(entity.getPark())) {
|
||||
return R.failed("厂区不在枚举内: " + entity.getPark());
|
||||
}
|
||||
long cnt = count(Wrappers.<CanteenReportSettleParkEntity>lambdaQuery()
|
||||
.eq(CanteenReportSettleParkEntity::getSettleCounter, entity.getSettleCounter())
|
||||
.ne(entity.getId() != null, CanteenReportSettleParkEntity::getId, entity.getId()));
|
||||
if (cnt > 0) {
|
||||
return R.failed("该结算台已配置厂区");
|
||||
}
|
||||
saveOrUpdate(entity);
|
||||
return R.ok(entity);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -39,13 +39,14 @@ public class CanteenReportSwipeServiceImpl extends ServiceImpl<CanteenReportSwip
|
||||
|
||||
@Override
|
||||
public Page<CanteenReportSwipeEntity> pageList(Page page, String bizMonth, String park, String incomeType,
|
||||
String costCenter, String empNo) {
|
||||
String costCenter, String empNo, Long importLogId) {
|
||||
return page(page, Wrappers.<CanteenReportSwipeEntity>lambdaQuery()
|
||||
.eq(StrUtil.isNotBlank(bizMonth), CanteenReportSwipeEntity::getBizMonth, bizMonth)
|
||||
.eq(StrUtil.isNotBlank(park), CanteenReportSwipeEntity::getPark, park)
|
||||
.eq(StrUtil.isNotBlank(incomeType), CanteenReportSwipeEntity::getIncomeType, incomeType)
|
||||
.like(StrUtil.isNotBlank(costCenter), CanteenReportSwipeEntity::getCostCenter, costCenter)
|
||||
.like(StrUtil.isNotBlank(empNo), CanteenReportSwipeEntity::getEmpNo, empNo)
|
||||
.eq(importLogId != null, CanteenReportSwipeEntity::getImportLogId, importLogId)
|
||||
.orderByDesc(CanteenReportSwipeEntity::getId));
|
||||
}
|
||||
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.bsd.pjcloud.canteen.mapper.CanteenReportFaceDetailMapper">
|
||||
|
||||
<insert id="insertBatch">
|
||||
INSERT INTO canteen_report_face_detail (
|
||||
id, import_log_id, biz_month, biz_date,
|
||||
order_no, third_order_no, order_create_time, pay_time, deduct_time,
|
||||
org_level1, org_level2, org_level3, canteen, canteen_area, consume_point,
|
||||
emp_name, phone, legal_entity, emp_no, card_no, group_name, dept_name,
|
||||
pay_method, pay_type, order_amount, change_amount,
|
||||
stored_change, subsidy_change, gift_change,
|
||||
stored_balance, subsidy_balance, gift_balance,
|
||||
change_org, discount, discount_amount, discount_type, coupon_type,
|
||||
deduct_amount, fee_amount, meal_subsidy,
|
||||
consume_type, meal_segment, device_name, device_status, remark, operator_name, visitor_pay_method,
|
||||
create_by, create_time, update_by, update_time, del_flag, tenant_id
|
||||
) VALUES
|
||||
<foreach collection="list" item="e" separator=",">
|
||||
(
|
||||
#{e.id}, #{e.importLogId}, #{e.bizMonth}, #{e.bizDate},
|
||||
#{e.orderNo}, #{e.thirdOrderNo}, #{e.orderCreateTime}, #{e.payTime}, #{e.deductTime},
|
||||
#{e.orgLevel1}, #{e.orgLevel2}, #{e.orgLevel3}, #{e.canteen}, #{e.canteenArea}, #{e.consumePoint},
|
||||
#{e.empName}, #{e.phone}, #{e.legalEntity}, #{e.empNo}, #{e.cardNo}, #{e.groupName}, #{e.deptName},
|
||||
#{e.payMethod}, #{e.payType}, #{e.orderAmount}, #{e.changeAmount},
|
||||
#{e.storedChange}, #{e.subsidyChange}, #{e.giftChange},
|
||||
#{e.storedBalance}, #{e.subsidyBalance}, #{e.giftBalance},
|
||||
#{e.changeOrg}, #{e.discount}, #{e.discountAmount}, #{e.discountType}, #{e.couponType},
|
||||
#{e.deductAmount}, #{e.feeAmount}, #{e.mealSubsidy},
|
||||
#{e.consumeType}, #{e.mealSegment}, #{e.deviceName}, #{e.deviceStatus}, #{e.remark}, #{e.operatorName}, #{e.visitorPayMethod},
|
||||
#{e.createBy}, #{e.createTime}, #{e.updateBy}, #{e.updateTime}, #{e.delFlag}, #{e.tenantId}
|
||||
)
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<delete id="deletePhysicallyByImportLogId">
|
||||
DELETE FROM canteen_report_face_detail WHERE import_log_id = #{importLogId}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePhysicallyByDateRange">
|
||||
DELETE FROM canteen_report_face_detail
|
||||
WHERE biz_month = #{bizMonth}
|
||||
AND biz_date >= #{dateStart}
|
||||
AND biz_date <= #{dateEnd}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePhysicallyDateRangeExceptLog">
|
||||
DELETE FROM canteen_report_face_detail
|
||||
WHERE biz_month = #{bizMonth}
|
||||
AND biz_date >= #{dateStart}
|
||||
AND biz_date <= #{dateEnd}
|
||||
AND (import_log_id IS NULL OR import_log_id <> #{importLogId})
|
||||
</delete>
|
||||
|
||||
<select id="selectAggByMonth" resultType="com.bsd.pjcloud.canteen.dto.report.CanteenReportFaceAggRow">
|
||||
SELECT
|
||||
IFNULL(emp_no, '') AS empNo,
|
||||
IFNULL(emp_name, '') AS empName,
|
||||
IFNULL(legal_entity, '') AS legalEntity,
|
||||
IFNULL(dept_name, '') AS deptName,
|
||||
IFNULL(org_level3, '') AS orgLevel3,
|
||||
IFNULL(device_name, '') AS deviceName,
|
||||
CASE
|
||||
WHEN IFNULL(pay_method, '') LIKE '%B扫C%'
|
||||
OR IFNULL(pay_method, '') LIKE '%收钱吧%'
|
||||
OR IFNULL(pay_method, '') LIKE '%支付宝%'
|
||||
OR IFNULL(pay_method, '') LIKE '%微信%'
|
||||
OR IFNULL(pay_type, '') LIKE '%收钱吧%'
|
||||
OR IFNULL(pay_type, '') LIKE '%支付宝%'
|
||||
THEN '支付宝'
|
||||
ELSE '员工刷卡'
|
||||
END AS incomeType,
|
||||
SUM(IFNULL(order_amount, 0)) AS amount
|
||||
FROM canteen_report_face_detail
|
||||
WHERE IFNULL(del_flag, '0') = '0'
|
||||
<if test="importLogId != null">
|
||||
AND import_log_id = #{importLogId}
|
||||
</if>
|
||||
<if test="importLogId == null and bizMonth != null and bizMonth != ''">
|
||||
AND biz_month = #{bizMonth}
|
||||
</if>
|
||||
<!-- 有 importLogId 时不再按日期过滤,避免日志日期段与明细 biz_date 不一致导致查空 -->
|
||||
<if test="importLogId == null and dateStart != null and dateStart != ''">
|
||||
AND (biz_date IS NULL OR biz_date >= #{dateStart})
|
||||
</if>
|
||||
<if test="importLogId == null and dateEnd != null and dateEnd != ''">
|
||||
AND (biz_date IS NULL OR biz_date <= #{dateEnd})
|
||||
</if>
|
||||
GROUP BY
|
||||
IFNULL(emp_no, ''),
|
||||
IFNULL(emp_name, ''),
|
||||
IFNULL(legal_entity, ''),
|
||||
IFNULL(dept_name, ''),
|
||||
IFNULL(org_level3, ''),
|
||||
IFNULL(device_name, ''),
|
||||
CASE
|
||||
WHEN IFNULL(pay_method, '') LIKE '%B扫C%'
|
||||
OR IFNULL(pay_method, '') LIKE '%收钱吧%'
|
||||
OR IFNULL(pay_method, '') LIKE '%支付宝%'
|
||||
OR IFNULL(pay_method, '') LIKE '%微信%'
|
||||
OR IFNULL(pay_type, '') LIKE '%收钱吧%'
|
||||
OR IFNULL(pay_type, '') LIKE '%支付宝%'
|
||||
THEN '支付宝'
|
||||
ELSE '员工刷卡'
|
||||
END
|
||||
</select>
|
||||
|
||||
<select id="countDetail" resultType="long">
|
||||
SELECT COUNT(1) FROM canteen_report_face_detail
|
||||
WHERE IFNULL(del_flag, '0') = '0'
|
||||
<if test="importLogId != null">
|
||||
AND import_log_id = #{importLogId}
|
||||
</if>
|
||||
<if test="bizMonth != null and bizMonth != ''">
|
||||
AND biz_month = #{bizMonth}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
+29
-4
@@ -6,18 +6,43 @@
|
||||
DELETE FROM canteen_report_swipe WHERE biz_month = #{bizMonth}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePhysicallyFaceByBizMonth">
|
||||
DELETE FROM canteen_report_swipe WHERE source = 'FACE' AND biz_month = #{bizMonth}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePhysicallyFaceByDateRange">
|
||||
DELETE FROM canteen_report_swipe
|
||||
WHERE source = 'FACE'
|
||||
AND biz_month = #{bizMonth}
|
||||
AND biz_date >= #{dateStart}
|
||||
AND biz_date <= #{dateEnd}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePhysicallyByImportLogId">
|
||||
DELETE FROM canteen_report_swipe WHERE import_log_id = #{importLogId}
|
||||
</delete>
|
||||
|
||||
<delete id="deletePhysicallyFaceRangeExceptLog">
|
||||
DELETE FROM canteen_report_swipe
|
||||
WHERE source = 'FACE'
|
||||
AND biz_month = #{bizMonth}
|
||||
AND biz_date >= #{dateStart}
|
||||
AND biz_date <= #{dateEnd}
|
||||
AND (import_log_id IS NULL OR import_log_id <> #{importLogId})
|
||||
</delete>
|
||||
|
||||
<insert id="insertBatch">
|
||||
INSERT INTO canteen_report_swipe (
|
||||
id, biz_month, emp_no, emp_name, legal_entity, dept_name,
|
||||
id, biz_month, biz_date, emp_no, emp_name, legal_entity, dept_name,
|
||||
consume_area, settle_counter, consume_amount, income_type,
|
||||
cost_center, cost_category, park, remark_tag,
|
||||
cost_center, cost_category, park, remark_tag, import_log_id, source,
|
||||
create_by, create_time, update_by, update_time, del_flag, tenant_id
|
||||
) VALUES
|
||||
<foreach collection="list" item="e" separator=",">
|
||||
(
|
||||
#{e.id}, #{e.bizMonth}, #{e.empNo}, #{e.empName}, #{e.legalEntity}, #{e.deptName},
|
||||
#{e.id}, #{e.bizMonth}, #{e.bizDate}, #{e.empNo}, #{e.empName}, #{e.legalEntity}, #{e.deptName},
|
||||
#{e.consumeArea}, #{e.settleCounter}, #{e.consumeAmount}, #{e.incomeType},
|
||||
#{e.costCenter}, #{e.costCategory}, #{e.park}, #{e.remarkTag},
|
||||
#{e.costCenter}, #{e.costCategory}, #{e.park}, #{e.remarkTag}, #{e.importLogId}, #{e.source},
|
||||
#{e.createBy}, #{e.createTime}, #{e.updateBy}, #{e.updateTime}, #{e.delFlag}, #{e.tenantId}
|
||||
)
|
||||
</foreach>
|
||||
|
||||
+4
-3
@@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 姓名/昵称:支持中文,或英文(单词间可空格,如 John Smith)
|
||||
* 姓名/昵称:支持中文、英文、数字(单词间可空格,如 John Smith、张三1)
|
||||
*/
|
||||
public final class PersonNameUtils {
|
||||
|
||||
@@ -21,8 +21,9 @@ public final class PersonNameUtils {
|
||||
|
||||
private static final int MAX_LEN = 32;
|
||||
|
||||
/** 中文 / 英文 / 数字,单词间允许空格 */
|
||||
private static final Pattern PERSON_NAME_PATTERN = Pattern.compile(
|
||||
"^(?:[\\u4E00-\\u9FA5]{1,32}|[A-Za-z]+(?:\\s[A-Za-z]+){0,8}|[\\u4E00-\\u9FA5A-Za-z]+(?:\\s[\\u4E00-\\u9FA5A-Za-z]+){0,8})$");
|
||||
"^[\\u4E00-\\u9FA5A-Za-z0-9]+(?:\\s[\\u4E00-\\u9FA5A-Za-z0-9]+){0,8}$");
|
||||
|
||||
private PersonNameUtils() {
|
||||
}
|
||||
@@ -72,7 +73,7 @@ public final class PersonNameUtils {
|
||||
if (CODE_NAME_EMPTY.equals(code) || CODE_NICKNAME_EMPTY.equals(code)) {
|
||||
return fieldLabel + "不能为空";
|
||||
}
|
||||
return fieldLabel + "仅支持中文,或英文(单词间可用空格,如 John Smith)";
|
||||
return fieldLabel + "仅支持中文、英文、数字(单词间可用空格)";
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -357,7 +357,7 @@ public class SysUserImportExportServiceImpl implements SysUserImportExportServic
|
||||
if (StrUtil.isBlank(excel.getName())) {
|
||||
excel.setName(excel.getPhone() + "学生家长");
|
||||
} else if (!PersonNameUtils.isValid(excel.getName())) {
|
||||
errorMessages.add("姓名仅支持中文,或英文(单词间可用空格),且不能超过32个字符");
|
||||
errorMessages.add("姓名仅支持中文、英文、数字(单词间可用空格),且不能超过32个字符");
|
||||
}
|
||||
if (StrUtil.isBlank(excel.getPhone())) {
|
||||
errorMessages.add("手机号不能为空");
|
||||
@@ -437,7 +437,7 @@ public class SysUserImportExportServiceImpl implements SysUserImportExportServic
|
||||
for (TeacherUserExcelVO excel : teacherUserExcelList) {
|
||||
Set<String> errorMessages = new LinkedHashSet<>();
|
||||
if (!PersonNameUtils.isValid(excel.getName())) {
|
||||
errorMessages.add("姓名仅支持中文,或英文(单词间可用空格),且不能超过32个字符");
|
||||
errorMessages.add("姓名仅支持中文、英文、数字(单词间可用空格),且不能超过32个字符");
|
||||
}
|
||||
if (StrUtil.isBlank(excel.getTeacherNo())) {
|
||||
errorMessages.add("学号不能为空");
|
||||
|
||||
Reference in new issue
Block a user