skyouc
2025-03-05 bc76a082becae4e5d344ae1b193582be38761d2d
#新增
1. 新增编规则生成功能
2. 新增PO单同步功能
12个文件已添加
8个文件已修改
1319 ■■■■■ 已修改文件
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/ErpApiController.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/Order.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/OrderItem.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/enums/OrderType.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/enums/OrderWorkType.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/ErpApiService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ErpApiServiceImpl.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/config/WebMvcConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/utils/DateUtils.java 726 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/MatnrController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Purchase.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/PurchaseItem.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/ScheduleJobs.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/entity/SerialRule.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/enums/SerialRuleReset.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/enums/SerialRuleType.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/utils/SerialRuleUtils.java 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/ErpApiController.java
New file
@@ -0,0 +1,52 @@
package com.vincent.rsf.server.api.controller;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.server.api.controller.params.Order;
import com.vincent.rsf.server.api.service.ErpApiService;
import com.vincent.rsf.server.system.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
 * @author Ryan
 * @version 1.0
 * @title ErpApiController
 * @description
 * @create 2025/3/4 13:19
 */
@RestController
@RequestMapping("/erp")
@Api(tags = "ERP接口对接")
public class ErpApiController extends BaseController {
    @Autowired
    private ErpApiService erpApiService;
    /**
     * @author Ryan
     * @description 接收ERP推送的PO单据
     * @throws
     * @return
     * @time 2025/3/4 13:57
     */
    @ApiOperation(value = "接收同步ERP采购单")
    @PostMapping("/sync/purchase")
    public R syncPurchases(@RequestBody List<Order> orders) {
        if (orders.isEmpty()) {
            return R.error("推送订单不能为空,请检查校验后再操作!!");
        }
        if (!erpApiService.syncPurchasee(orders)) {
            return R.error("保存失败");
        } else {
            return R.ok("保存成功!!");
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/Order.java
New file
@@ -0,0 +1,56 @@
package com.vincent.rsf.server.api.controller.params;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
 * @author Ryan
 * @version 1.0
 * @title PurchaseOrder
 * @description
 * @create 2025/3/4 13:41
 */
@Data
@Accessors(chain = true)
@ApiModel(value = "PurchaseOrder", description = "入库单据")
public class Order implements Serializable {
    @ApiModelProperty(value = "单据编码")
    private String code;
    @ApiModelProperty(value = "需求数量", required = true)
    private Double anfme;
    @ApiModelProperty(value = "已收货数量",required = true)
    private Double qty;
    @ApiModelProperty(value = "收货中数量", required = true)
    private Double workQty;
    @ApiModelProperty(value = "计划收货时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date startTime;
    @ApiModelProperty(value = "计划收货结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;
    @ApiModelProperty(value = "项目编码")
    private String projectCode;
    @ApiModelProperty(value = "业务类型")
    private String wkType;
    @ApiModelProperty(value = "单据明细")
    private List<OrderItem> children;
}
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/params/OrderItem.java
New file
@@ -0,0 +1,53 @@
package com.vincent.rsf.server.api.controller.params;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
 * @author Ryan
 * @version 1.0
 * @title OrderItem
 * @description
 * @create 2025/3/5 16:23
 */
@Data
@Accessors(chain = true)
@ApiModel(value = "OrderItem", description = "入库单据")
public class OrderItem implements Serializable {
    @ApiModelProperty(value = "明细数量")
    private Double anfme;
    @ApiModelProperty(value = "已完成数量")
    private Double qty;
    @ApiModelProperty(value = "erp主键")
    private String erpId;
    @ApiModelProperty(value = "物料编码")
    private String matnrCode;
    @ApiModelProperty(value = "物料名称")
    private String matnrName;
    @ApiModelProperty(value = "单位")
    private String unit;
    @ApiModelProperty(value = "标包数量")
    private String nromQty;
    @ApiModelProperty(value = "供应商名称")
    private String splrName;
    @ApiModelProperty(value = "供应商编码")
    private String splrCode;
    @ApiModelProperty(value = "供应商批次")
    private String splrBatch;
}
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/enums/OrderType.java
New file
@@ -0,0 +1,24 @@
package com.vincent.rsf.server.api.entity.enums;
/**
 * @author Ryan
 * @version 1.0
 * @title PurchaseType
 * @description
 * @create 2025/3/5 15:54
 */
public enum OrderType {
    //订单类型
    ORDER_PURCHASE_IN("purchase", "采购入库单"),
    ORDER_OUT("out", "采购出库单"),
    ;
    OrderType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public String type;
    public String desc;
}
rsf-server/src/main/java/com/vincent/rsf/server/api/entity/enums/OrderWorkType.java
New file
@@ -0,0 +1,29 @@
package com.vincent.rsf.server.api.entity.enums;
/**
 * @author Ryan
 * @version 1.0
 * @title PurchaseType
 * @description
 * @create 2025/3/5 15:54
 */
public enum OrderWorkType {
    //订单类型
    ORDER_PURCHASE_IN("purchase", "采购单"),
    ORDER_PROD_IN("prod", "生产领料单"),
    ORDER_DONE_IN("done", "完工入料单"),
    ORDER_SALE_IN("sale", "销售订单"),
    ORDER_PROD_BACK_IN("prod back", "生产退料单"),
    ORDER_SPLR_BACK_OUT("supplier back", "供应商出货单"),
    ORDER_SALE_BACK_IN("sale back", "销售退货单")
    ;
    OrderWorkType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public String type;
    public String desc;
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/ErpApiService.java
New file
@@ -0,0 +1,18 @@
package com.vincent.rsf.server.api.service;
import com.vincent.rsf.server.api.controller.params.Order;
import java.util.List;
/**
 * @author Ryan
 * @version 1.0
 * @title ErpApiService
 * @description
 * @create 2025/3/4 16:23
 */
public interface ErpApiService {
    boolean syncPurchasee(List<Order> orders);
}
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ErpApiServiceImpl.java
New file
@@ -0,0 +1,72 @@
package com.vincent.rsf.server.api.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.api.controller.params.OrderItem;
import com.vincent.rsf.server.api.entity.enums.OrderType;
import com.vincent.rsf.server.manager.entity.PurchaseItem;
import com.vincent.rsf.server.manager.service.PurchaseItemService;
import com.vincent.rsf.server.manager.service.PurchaseService;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.api.controller.params.Order;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import com.vincent.rsf.server.api.service.ErpApiService;
import com.vincent.rsf.server.manager.entity.Purchase;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
 * @author Ryan
 * @version 1.0
 * @title ErpApiServiceImpl
 * @description
 * @create 2025/3/4 16:27
 */
@Service
public class ErpApiServiceImpl extends ServiceImpl implements ErpApiService {
    @Autowired
    private PurchaseService purchaseService;
    @Autowired
    private PurchaseItemService purchaseItemService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean syncPurchasee(List<Order> orders) {
        if (orders.isEmpty()) {
            throw new CoolException("单据内容不能为空!!");
        }
        orders.forEach(ors -> {
            Purchase purchase = new Purchase();
            BeanUtils.copyProperties(ors, purchase);
            String wkVal = SerialRuleUtils.generateRuleCode(SerialRuleCode.PURCHASE_CODE, purchase);
            purchase.setCode(wkVal)
                    .setType(OrderType.ORDER_PURCHASE_IN.type);
            if (!purchaseService.save(purchase)) {
                throw new CoolException("采购单据保存失败");
            }
            //判断子列表不为空
            if (!ors.getChildren().isEmpty()) {
                ArrayList<PurchaseItem> list = new ArrayList<>();
                ors.getChildren().forEach(orderItem -> {
                    PurchaseItem item = new PurchaseItem();
                    BeanUtils.copyProperties(orderItem, item);
                    item.setPurchaseId(purchase.getId());
                    list.add(item);
                });
                if (!purchaseItemService.saveBatch(list)) {
                    throw new CoolException("采购单明细保存失败!!");
                }
            }
        });
        return true;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/common/config/WebMvcConfig.java
@@ -26,7 +26,7 @@
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getAsyncHandlerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**","/v3/**","/doc.html/**", "/swagger-ui.html/**");
                .excludePathPatterns("/swagger-resources/**", "/webjars/**","/erp/**", "/v2/**","/v3/**","/doc.html/**", "/swagger-ui.html/**");
    }
    @Bean
rsf-server/src/main/java/com/vincent/rsf/server/common/security/SecurityConfig.java
@@ -39,6 +39,7 @@
            "/system/info",
            "/tenant/list",
            "/email/code",
            "/erp/**",
            "/login",
            "/register",
            "/druid/**",
rsf-server/src/main/java/com/vincent/rsf/server/common/utils/DateUtils.java
New file
@@ -0,0 +1,726 @@
package com.vincent.rsf.server.common.utils;
import org.apache.tika.utils.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
 * 日期时间工具类
 *
 * @author Ryan
 * @createTime 2018-07-19 10:42:00
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public final static String YYYYMMDDHHMMSS_PATTER = "yyyyMMddHHmmss";
    public final static String YYYYMMDDHHMMSS_PATTER_HB = "YYYY-MM-dd HH:mm:ss.SSS";
    public final static String YYYYMMDDHHMMSS_PATTER_HB1 = "YYYY-MM-dd HH:mm:ss.000";
    public static String datetimeFormat = "yyyy-MM-dd HH:mm:ss";
    public final static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM/dd", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM.dd", "yyyy.MM", "YYYY-MM-dd HH:mm:ss.SSS"};
    public static Date now() {
        return Calendar.getInstance().getTime();
    }
    /**
     * 仅显示年月日,例如 2021-08-11.
     */
    public static final String DATE_PATTERN = "yyyy-MM-dd";
    /**
     * 一天的结束时间,仅显示时分秒
     */
    private static final String END_TIME = "23:59:59";
    /**
     * @Description: 返回 yyyy-MM-dd HH:mm:ss
     */
    public static String nowDate() {
        return getDate(new Date());
    }
    /**
     * 将日期字符串转换为日期类型
     *
     * @param pattern 日期字符串格式 不传则为 yyyy-MM-dd
     * @return
     * @throws ParseException
     */
    public static Date nowDate(String pattern) throws ParseException {
        if (StringUtils.isBlank(pattern)) {
            pattern = "yyyy-MM-dd";
        }
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        return df.parse(df.format(new Date()));
    }
    /**
     * 获取指定日期当周星期一的时间
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //获取本周第一天
        calendar.set(Calendar.WEEK_OF_YEAR, calendar.get(Calendar.WEEK_OF_YEAR));
        int dayOfWeek = 0;
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
            dayOfWeek = -6;
        } else {
            dayOfWeek = 2 - calendar.get(Calendar.DAY_OF_WEEK);
        }
        calendar.add(Calendar.DAY_OF_WEEK, dayOfWeek);
        return calendar.getTime();
    }
    public static Date getFirstDayOfWeekT(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //获取本周第一天
        calendar.set(Calendar.WEEK_OF_YEAR, calendar.get(Calendar.WEEK_OF_YEAR));
        int dayOfWeek = 0;
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
            dayOfWeek = -6;
        } else {
            dayOfWeek = 2 - calendar.get(Calendar.DAY_OF_WEEK);
        }
        calendar.add(Calendar.DAY_OF_WEEK, dayOfWeek);
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat(DATE_PATTERN);
        try {
            return df.parse(df.format(calendar.getTime()));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 获取指定日期当周星期日的时间
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(date);
        // Sunday
        calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek() + 6);
        return calendar.getTime();
    }
    /**
     * 获取指定日期当月第一天的时间
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }
    /**
     * 获取指定日期当月最后一天的时间
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar.getTime();
    }
    /**
     * 获取指定日期当年第一天的时间
     *
     * @param date
     * @return
     */
    public static Date getFirstDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, date.getYear() + 1900);
        return calendar.getTime();
    }
    /**
     * 获取指定日期当年最后一天的时间
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, date.getYear() + 1900);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        return calendar.getTime();
    }
    /**
     * 获取两个日期相隔的天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static float getDateDiffOfDays(Date startDate, Date endDate) {
        long diff = endDate.getTime() - startDate.getTime();
        return diff / (24 * 60 * 60 * 1000);
    }
    /**
     * 获取每天工作小时数。例如:早上9点上班,下午6点下班,休息一个小时,工作时间为8
     *
     * @param startTime 开始时间,格式:HHmm。例如早上7点半,使用0730表示
     * @param endTime   结束时间,格式:HHmm。例如下午6点半,使用1830表示
     * @param restHours 休息时间
     * @return
     */
    public static float getWorkHours(String startTime, String endTime, float restHours) {
        Date m = new Date();
        m.setHours(Integer.parseInt(startTime.substring(0, 2)) - 1);
        m.setMinutes(Integer.parseInt(startTime.substring(2)));
        Date a = new Date();
        a.setHours(Integer.parseInt(endTime.substring(0, 2)) - 1);
        a.setMinutes(Integer.parseInt(endTime.substring(2)));
        return (a.getTime() - m.getTime()) / (1000 * 60 * 60 * 1.0f) - restHours;
    }
    /**
     * 将日期字符串转换为日期类型
     *
     * @param dateStr 日期字符串
     * @param pattern 日期字符串格式
     * @return
     * @throws ParseException
     */
    public static Date parse(String dateStr, String pattern) throws ParseException {
        if (StringUtils.isBlank(dateStr)) {
            return null;
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.parse(dateStr);
    }
    /**
     * 日期型字符串转化为日期 格式
     * { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
     * "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm",
     * "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" }
     */
    public static Date parse(String str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str, parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }
    public static String formatToAnotherPattern(String dateStr, String pattern, String anotherPatter) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        Date date = dateFormat.parse(dateStr);
        dateFormat = new SimpleDateFormat(anotherPatter);
        return dateFormat.format(date);
    }
    /**
     * 获取日期时间字符串
     *
     * @param date 需要转化的日期时间
     * @return String 日期时间字符串,例如 2015-08-11
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }
    public static String format(Date date, String pattern) {
        if (date == null) {
            return "";
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.format(date);
    }
    public static Date addHours(Date date, int amount) {
        return add(date, Calendar.HOUR_OF_DAY, amount);
    }
    public static Date addDays(Date date, int amount) {
        return add(date, Calendar.DAY_OF_MONTH, amount);
    }
    public static Date addYear(Date date, int amount) {
        return add(date, Calendar.YEAR, amount);
    }
    public static Date addMonth(Date date, int amount) {
        return add(date, Calendar.MONTH, amount);
    }
    private static Date add(Date date, int calendarField, int amount) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(calendarField, amount);
        return c.getTime();
    }
    /**
     * 将毫秒格式化,如果大于60秒,返回 1分xx秒,大于60分钟,返回 1小时xx分xx秒
     *
     * @param ms 毫秒
     * @return
     */
    public static String formatTime(long ms) {
        if (ms < 1000) { //毫秒
            return ms + "毫秒";
        } else if (ms / 1000 < 60) {
            // 小于60秒,以秒显示
            return ms / 1000 + "秒";
        } else if (ms / 1000 / 60 < 60) {
            // 小于60分,以分显示
            return ms / 1000 / 60 + "分" + (ms / 1000 % 60) + "秒";
        } else if (ms / 1000 / 60 / 60 < 24) {
            // 小于24小时
            return (ms / 1000 / 60 / 60) + "时" + (ms / 1000 % 60) + "分" + (ms / 1000 / 60 % 60) + "秒";
        } else {
            return (ms / 1000 / 60 / 60 / 24) + "天" + (ms / 1000 / 60 / 60) + "时" + (ms / 1000 % 60) + "分" + (ms / 1000 / 60 % 60) + "秒";
        }
    }
    public static Date dateToISODate(Date date) {
        //T代表后面跟着时间,Z代表UTC统一时间
        SimpleDateFormat format =
                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        format.setCalendar(new GregorianCalendar(new SimpleTimeZone(0, "GMT")));
        String isoDate = format.format(date);
        try {
            return format.parse(isoDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        //Combines this date-time with a time-zone to create a  ZonedDateTime.
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        //Tue Mar 27 14:17:17 CST 2018
        return Date.from(zdt.toInstant());
    }
    public static String localDateTimeToString(LocalDateTime localDateTime) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(datetimeFormat);
        return fmt.format(localDateTime);
    }
    public static LocalDateTime stringToLocalDateTime(String str) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(datetimeFormat);
        return LocalDateTime.parse(str, fmt);
    }
    public static LocalDateTime stringToLocalDateTime(String str, String fmtStr) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(fmtStr);
        return LocalDateTime.parse(str, fmt);
    }
    /**
     * Date转LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        try {
            Instant instant = date.toInstant();
            ZoneId zoneId = ZoneId.systemDefault();
            return instant.atZone(zoneId).toLocalDateTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * @Description:获取当前日期 yyyy-MM-dd HH:mm:ss
     * @Author wyt
     * @Date 2020/8/21
     */
    public static String getDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(datetimeFormat);
        return sdf.format(date);
    }
    public static String getDate(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }
    /**
     * @Description: 判断是否是合法日期格式
     * @Author wyt
     * @Date 2021/2/24
     */
    public static boolean isValidDate(String str, String fmt) {
        if (StringUtils.isBlank(str)) {
            return false;
        }
        boolean convertSuccess = true;
        // 指定日期格式为四位年/两位月份/两位日期,注意yyyy/MM/dd区分大小写;
        SimpleDateFormat format = new SimpleDateFormat(fmt);
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期,比如2007/02/29会被接受,并转换成2007/03/01
            format.setLenient(false);
            Date date = format.parse(str);
            long time = date.getTime();
            if (time < 14400) {
                convertSuccess = false;
            }
        } catch (ParseException e) {
            // e.printStackTrace();
            // 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }
    /**
     * 计算两个日期相差的秒数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int calLastedTime(Date startDate, Date endDate) {
        long a = endDate.getTime();
        long b = startDate.getTime();
        int c = (int) ((a - b) / 1000);
        return c;
    }
    /**
     * 获取本月的第一天
     *
     * @return Calendar 日历
     */
    public static Calendar getStartDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance(Locale.CHINA);
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar;
    }
    /**
     * 根据日历返回日期时间字符串
     *
     * @param calendar 日历
     * @return String 日期时间字符串
     */
    public static String getDateTimeStr(Calendar calendar) {
        StringBuffer buf = new StringBuffer("");
        buf.append(calendar.get(Calendar.YEAR));
        buf.append("-");
        buf.append(calendar.get(Calendar.MONTH) + 1 > 9 ? calendar.get(Calendar.MONTH) + 1 + ""
                : "0" + (calendar.get(Calendar.MONTH) + 1));
        buf.append("-");
        buf.append(calendar.get(Calendar.DAY_OF_MONTH) > 9 ? calendar.get(Calendar.DAY_OF_MONTH) + ""
                : "0" + calendar.get(Calendar.DAY_OF_MONTH));
        buf.append(" ");
        buf.append(calendar.get(Calendar.HOUR_OF_DAY) > 9 ? calendar.get(Calendar.HOUR_OF_DAY) + ""
                : "0" + calendar.get(Calendar.HOUR_OF_DAY));
        buf.append(":");
        buf.append(calendar.get(Calendar.MINUTE) > 9 ? calendar.get(Calendar.MINUTE) + ""
                : "0" + calendar.get(Calendar.MINUTE));
        buf.append(":");
        buf.append(calendar.get(Calendar.SECOND) > 9 ? calendar.get(Calendar.SECOND) + ""
                : "0" + calendar.get(Calendar.SECOND));
        return buf.toString();
    }
    /**
     * 获取指定日期当月第一天的日期字符串
     *
     * @param date 指定日期
     * @return String 格式:yyyy-MM-dd HH:mm:ss
     */
    public static String getMonthStartTimeStr(Date date) {
        return getDateTimeStr(getStartDayOfMonth(date));
    }
    /**
     * 获得指定日期所在日的结束时间字符串
     *
     * @param date 指定日期
     * @return String 例如:2021-08-11 23:59:59
     */
    public static String getDateEndTimeStr(Date date) {
        String result = format(date, DATE_PATTERN);
        return result.concat(" ").concat(END_TIME);
    }
    /**
     * 时间戳转日期
     *
     * @param msStr 时间戳
     * @return 不为空:yyyy-MM-dd HH:mm:ss格式日期,为空:返回null
     */
    public static String transForDate(String msStr) {
        if (StringUtils.isBlank(msStr)) {
            return null;
        }
        long msl = Long.parseLong(msStr);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(msl);
    }
    /**
     * 判断是否是时间戳
     *
     * @param msStr 时间戳
     * @return 不为空,并且是时间戳格式,返回true
     */
    public static boolean isTimeStamp(String msStr) {
        if (StringUtils.isBlank(msStr)) {
            return false;
        }
        boolean is = false;
        try {
            if (transForDate(msStr) != null) {
                is = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return is;
    }
    /**
     * 如果endDate>startDate,返回true,否则返回false
     *
     * @param startDate 开始日期字符串
     * @param endDate   结束日期字符串
     * @return boolean
     */
    public static boolean compareDate(Date startDate, Date endDate) {
        String startDateStr = format(startDate, DATE_PATTERN);
        String endDateStr = format(endDate, DATE_PATTERN);
        return compareDate(startDateStr, endDateStr);
    }
    /**
     * @param thisDate  –  当前日期
     * @param otherDate – 比较日期
     * @Description:把时间格式化到秒级继续比较 yyyy-MM-dd HH:mm:ss
     * 如果thisDate>otherDate,返回 1,
     * thisDate=otherDate,   返回 0,
     * thisDate<otherDate,   返回 -1,
     * @Returns int
     **/
    public static int compareDateBySecond(Date thisDate, Date otherDate) {
        String thisDateStr = format(thisDate, datetimeFormat);
        String otherDateStr = format(otherDate, datetimeFormat);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datetimeFormat);
        try {
            Date tDate = simpleDateFormat.parse(thisDateStr);
            Date oDate = simpleDateFormat.parse(otherDateStr);
            return tDate.compareTo(oDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return thisDate.compareTo(otherDate);
    }
    public static boolean compareDate(String startDateStr, String endDateStr) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_PATTERN);
        try {
            Date startDate = simpleDateFormat.parse(startDateStr);
            Date endDate = simpleDateFormat.parse(endDateStr);
            return endDate.after(startDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
    /**
     * 指定时间往前或往后几天
     *
     * @param day 天数
     * @return
     */
    public static String getTimeBeforeDay(int day, String fmt) {
        if (StringUtils.isBlank(fmt)) {
            fmt = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date nowDate = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(nowDate);
        calendar.add(Calendar.DATE, day);
        Date updateDate = calendar.getTime();
        return sdf.format(updateDate);
    }
    /**
     * 获取日期所在月第一天零点
     *
     * @return
     */
    public static Date getFirstDayZeroOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }
    /**
     * 获取日期零点
     *
     * @return
     */
    public static Date getDayZero(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }
    /**
     * 获取指定日期当周星期一的时间
     *
     * @param date
     * @return
     */
    public static Date getFirstDayZeroOfWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //获取本周第一天
        calendar.set(Calendar.WEEK_OF_YEAR, calendar.get(Calendar.WEEK_OF_YEAR));
        int dayOfWeek = 0;
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
            dayOfWeek = -6;
        } else {
            dayOfWeek = 2 - calendar.get(Calendar.DAY_OF_WEEK);
        }
        calendar.add(Calendar.DAY_OF_WEEK, dayOfWeek);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }
    /**
     * @author Ryan
     * @param: [date]
     * @return: java.time.LocalDate
     * @date: 2023/7/28
     * @description: 获取当前时间的前一年
     */
    public static Date getCurrDateOfLastYear(Date date, String perciod, boolean isMinus, Integer num) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime of = LocalDateTime.ofInstant(instant, zoneId);
        LocalDate localDate = of.toLocalDate();
        ZonedDateTime zonedDateTime = null;
        if (perciod.equals("year")) {
            if (isMinus) {
                zonedDateTime = localDate.minusYears(num).atStartOfDay(zoneId);
            } else {
                zonedDateTime = localDate.plusYears(num).atStartOfDay(zoneId);
            }
        } else if (perciod.equals("months")) {
            if (isMinus) {
                zonedDateTime = localDate.minusMonths(num).atStartOfDay(zoneId);
            } else {
                zonedDateTime = localDate.plusMonths(num).atStartOfDay(zoneId);
            }
        } else if (perciod.equals("week")) {
            if (isMinus) {
                zonedDateTime = localDate.minusWeeks(num).atStartOfDay(zoneId);
            } else {
                zonedDateTime = localDate.plusWeeks(num).atStartOfDay(zoneId);
            }
        } else {
            if (isMinus) {
                zonedDateTime = localDate.minusDays(num).atStartOfDay(zoneId);
            } else {
                zonedDateTime = localDate.plusDays(num).atStartOfDay(zoneId);
            }
        }
        return Date.from(zonedDateTime.toInstant());
    }
    public static Date getCurrDateOfLastYear(Date date, Integer num) {
        return getCurrDateOfLastYear(date, "year", true, num);
    }
    //给日期增加指定年
    public static Date addYears(Date date, Integer num) {
        // 创建Calendar对象
        Calendar calendar = Calendar.getInstance();
        // 设置待操作的日期
        calendar.setTime(date);
        // 增加三年
        calendar.add(Calendar.YEAR, num);
        // 获取增加后的日期
        Date newDate = calendar.getTime();
        return newDate;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/AsnOrderController.java
@@ -107,4 +107,6 @@
        ExcelUtil.build(ExcelUtil.create(asnOrderService.list(), AsnOrder.class), response);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/MatnrController.java
@@ -1,9 +1,5 @@
package com.vincent.rsf.server.manager.controller;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.imports.ExcelImportService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.framework.common.Cools;
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/Purchase.java
@@ -2,6 +2,8 @@
import java.text.SimpleDateFormat;
import java.util.Date;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -28,6 +30,7 @@
import java.util.Date;
@Data
@Accessors(chain = true)
@TableName("man_purchase")
public class Purchase implements Serializable {
@@ -80,7 +83,7 @@
    /**
     * 已收货数量
     */
    @ApiModelProperty(value= "已收货数量")
    @ApiModelProperty(value= "收货中数量")
    private Double workQty;
    /**
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/PurchaseItem.java
@@ -3,6 +3,8 @@
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.text.SimpleDateFormat;
import java.util.Date;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -22,6 +24,7 @@
import java.util.Date;
@Data
@Accessors(chain = true)
@TableName("man_purchase_item")
public class PurchaseItem implements Serializable {
@@ -80,7 +83,7 @@
     * 标准包装
     */
    @ApiModelProperty(value= "标准包装")
    private Double nomQty;
    private Double nromQty;
    /**
     * ASN单据数量
@@ -98,19 +101,19 @@
     * 供应商名称
     */
    @ApiModelProperty(value= "供应商名称")
    private String pulrName;
    private String splrName;
    /**
     * 供应商编码
     */
    @ApiModelProperty(value= "供应商编码")
    private String pulrCode;
    private String splrCode;
    /**
     * 供应商批次
     */
    @ApiModelProperty(value= "供应商批次")
    private String pulrBatch;
    private String splrBatch;
    /**
     * 状态 1: 正常  0: 冻结  
@@ -165,7 +168,7 @@
    public PurchaseItem() {}
    public PurchaseItem(Long purchaseId,String erpId,String matnrCode,String matnrName,String unit,Double anfme,Double qty,Double nomQty,Double asnQty,Double printQty,String pulrName,String pulrCode,String pulrBatch,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
    public PurchaseItem(Long purchaseId,String erpId,String matnrCode,String matnrName,String unit,Double anfme,Double qty,Double nromQty,Double asnQty,Double printQty,String splrName,String splrCode,String splrBatch,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
        this.purchaseId = purchaseId;
        this.erpId = erpId;
        this.matnrCode = matnrCode;
@@ -173,12 +176,12 @@
        this.unit = unit;
        this.anfme = anfme;
        this.qty = qty;
        this.nomQty = nomQty;
        this.nromQty = nromQty;
        this.asnQty = asnQty;
        this.printQty = printQty;
        this.pulrName = pulrName;
        this.pulrCode = pulrCode;
        this.pulrBatch = pulrBatch;
        this.splrName = splrName;
        this.splrCode = splrCode;
        this.splrBatch = splrBatch;
        this.status = status;
        this.deleted = deleted;
        this.tenantId = tenantId;
rsf-server/src/main/java/com/vincent/rsf/server/manager/utils/ScheduleJobs.java
@@ -2,16 +2,18 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.common.utils.DateUtils;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
 * @author Ryan
@@ -20,6 +22,7 @@
 * @description
 * @create 2025/3/3 15:38
 */
@Component
public class ScheduleJobs {
    @Autowired
@@ -37,26 +40,31 @@
    private AsnOrderItemService asnOrderItemService;
    /**
     * @author Ryan
     * @description  根据PO单据生成ASN单
     * @description  根据PO单据生成ASN单,自动生成ASN单为全量生成
     * @throws
     * @return
     * @time 2025/3/3 15:44
     */
    @Scheduled(cron = "0/10 * * * * ? ")
    @Scheduled(cron = "0 0/30 * * * ?  ")
    @Transactional(rollbackFor = Exception.class)
    public void genAsnOrder() {
        //获取未生成ASN单据
        List<Purchase> purchases = purchaseService.list(new LambdaQueryWrapper<Purchase>().eq(Purchase::getStatus, 2));
        List<Purchase> purchases = purchaseService.list(new LambdaQueryWrapper<Purchase>().eq(Purchase::getStatus, 0));
        //采购单为空,直接跳出当前任务
        if (purchases.isEmpty()) {
            return;
        }
        //生成ASN单据
        purchases.forEach(purchase -> {
            List<PurchaseItem> items = purchaseItemService.list(new LambdaQueryWrapper<PurchaseItem>().eq(PurchaseItem::getPurchaseId, purchase.getId()));
            //子列表为空数据,直接跳出
            if (items.isEmpty()) {
            if (!Objects.isNull(purchase.getStartTime())) {
                //判断起始时间是否大于当前时间
                if (DateUtils.compareDate(new Date(), purchase.getStartTime())) {
                return;
                }
            }
            List<PurchaseItem> items = purchaseItemService.list(new LambdaQueryWrapper<PurchaseItem>().eq(PurchaseItem::getPurchaseId, purchase.getId()));
            if (items.isEmpty()) {
                throw new CoolException("子列表数据为空,请查询PO单是否正确录入!!");
            }
            AsnOrder order = new AsnOrder();
            order.setAnfme(purchase.getAnfme())
@@ -74,8 +82,8 @@
                orderItem.setAnfme(item.getAnfme())
                        .setAsnId(purchase.getId())
                        .setQty(item.getQty())
                        .setSplrName(item.getPulrName())
                        .setSplrCode(item.getPulrCode())
                        .setSplrName(item.getSplrName())
                        .setSplrCode(item.getSplrCode())
                        .setMatnk(item.getMatnrName())
                        .setPoDetlId(item.getId() + "")
                        .setPurQty(item.getAnfme())
@@ -88,6 +96,13 @@
                throw new CoolException(("Asn单据明细保存失败!!"));
            }
            //任务执行完成,修改已完成数量和PO单执行状态
            purchase.setQty(purchase.getAnfme()).setStatus(1);
            if (!purchaseService.save(purchase)) {
                throw new CoolException("PO单执行完成后,保存失败!!");
            }
        });
    }
rsf-server/src/main/java/com/vincent/rsf/server/system/constant/SerialRuleCode.java
New file
@@ -0,0 +1,13 @@
package com.vincent.rsf.server.system.constant;
/**
 * @author Ryan
 * @version 1.0
 * @title SerialRuleCode
 * @description
 * @create 2025/3/4 17:02
 */
public class SerialRuleCode {
    public final static String PURCHASE_CODE = "sys_purchase_code";
}
rsf-server/src/main/java/com/vincent/rsf/server/system/entity/SerialRule.java
@@ -3,6 +3,8 @@
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.text.SimpleDateFormat;
import java.util.Date;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -22,6 +24,7 @@
import java.util.Date;
@Data
@Accessors(chain = true)
@TableName("sys_serial_rule")
public class SerialRule implements Serializable {
@@ -68,7 +71,7 @@
     * 当前值
     */
    @ApiModelProperty(value= "当前值")
    private String currValue;
    private Integer currValue;
    /**
     * 最近生成编码
@@ -81,6 +84,9 @@
     */
    @ApiModelProperty(value= "状态 1: 正常  0: 冻结  ")
    private Integer status;
    @ApiModelProperty(value = "流水号最大长度")
    private Integer maxLen;
    /**
     * 是否删除 1: 是  0: 否  
@@ -129,7 +135,7 @@
    public SerialRule() {}
    public SerialRule(String code,String name,String delimit,String reset,String resetDep,String currValue,String lastCode,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
    public SerialRule(String code,String name,String delimit,String reset,String resetDep,Integer currValue,String lastCode,Integer status,Integer deleted,Integer tenantId,Long createBy,Date createTime,Long updateBy,Date updateTime,String memo) {
        this.code = code;
        this.name = name;
        this.delimit = delimit;
rsf-server/src/main/java/com/vincent/rsf/server/system/enums/SerialRuleReset.java
New file
@@ -0,0 +1,27 @@
package com.vincent.rsf.server.system.enums;
/**
 * @author Ryan
 * @version 1.0
 * @title SerialRuleRest
 * @description
 * @create 2025/3/5 09:44
 */
public enum SerialRuleReset {
    //重置类型:年
    SERIAL_REST_TYPE_YEAR("year", "年"),
    //重置类型:月
    SERIAL_REST_TYPE_MONTH("month", "月"),
    //重置类型:日
    SERIAL_REST_TYPE_DAYS("day", "日")
    ;
    public String type;
    public String desc;
    SerialRuleReset(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/system/enums/SerialRuleType.java
New file
@@ -0,0 +1,29 @@
package com.vincent.rsf.server.system.enums;
/**
 * @author Ryan
 * @version 1.0
 * @title SerialRuleType
 * @description
 * @create 2025/3/5 08:11
 */
public enum SerialRuleType {
    //常量值
    WK_CONSTANT("1", "常量"),
    //流水号
    WK_SERIAL_NO("2", "流水号"),
    //日期
    WK_DATE_FORMAT("3", "日期"),
    //字段
    WK_FEILD("4", "字段")
    ;
    public String wkType;
    public String wkName;
    SerialRuleType(String type, String name){
        this.wkType = type;
        this.wkName = name;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/system/utils/SerialRuleUtils.java
New file
@@ -0,0 +1,140 @@
package com.vincent.rsf.server.system.utils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vincent.rsf.framework.common.SpringUtils;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.common.utils.DateUtils;
import com.vincent.rsf.server.system.entity.SerialRule;
import com.vincent.rsf.server.system.entity.SerialRuleItem;
import com.vincent.rsf.server.system.enums.SerialRuleReset;
import com.vincent.rsf.server.system.enums.SerialRuleType;
import com.vincent.rsf.server.system.service.SerialRuleItemService;
import com.vincent.rsf.server.system.service.SerialRuleService;
import org.apache.tika.utils.StringUtils;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * @author Ryan
 * @version 1.0
 * @title 生成规则编码功能
 * @description
 * @create 2025/3/5 08:01
 */
public class SerialRuleUtils {
    /**
     * @author Ryan
     * @description 根据编码规则生成编码号
     * @throws
     * @return 编码号
     * @time 2025/3/5 08:52
     */
    public static String generateRuleCode(String code, Object obj) {
        SerialRuleService ruleService = SpringUtils.getBean(SerialRuleService.class);
        //获取规则编码主单
        SerialRule serialRule = ruleService
                .getOne(new LambdaQueryWrapper<SerialRule>()
                        .eq(SerialRule::getCode, code));
        if (Objects.isNull(serialRule)) {
            throw new CoolException("采购编码规则不存在!!");
        }
        SerialRuleItemService serialRuleItemService = SpringUtils.getBean(SerialRuleItemService.class);
        //获取规则编码明细
        List<SerialRuleItem> ruleItems = serialRuleItemService
                .list(new LambdaQueryWrapper<SerialRuleItem>()
                        .eq(SerialRuleItem::getRuleId, serialRule.getId())
                        .orderByAsc(SerialRuleItem::getSort));
        if (Objects.isNull(ruleItems)) {
            throw new CoolException("编码规则明细为空!!");
        }
        StringBuffer buffer = new StringBuffer();
        ruleItems.forEach(rule -> {
            if (rule.getWkType().equals(SerialRuleType.WK_CONSTANT.wkType)) {
                buffer.append(rule.getFeildValue());
            } else if (rule.getWkType().equals(SerialRuleType.WK_SERIAL_NO.wkType)) {
                String result = "", format = "";
                if (serialRule.getReset().equals(SerialRuleReset.SERIAL_REST_TYPE_YEAR.type)) {
                     format = DateUtils.format(new Date(), "yyyy");
                } else if (serialRule.getReset().equals(SerialRuleReset.SERIAL_REST_TYPE_MONTH.type)) {
                     format = DateUtils.format(new Date(), "MM");
                } else {
                     format = DateUtils.format(new Date(), "dd");
                }
                //当前值自动加1
                Integer curVal = serialRule.getCurrValue() + 1;
                //字符串左边自加补0
                String lef =  StringUtils.leftPad(curVal + "", serialRule.getMaxLen(), "0");
                //最近一次流水号
                result = format + lef;
                //修改最后编码,当前值
                serialRule.setCurrValue(curVal);
                buffer.append(result);
            } else if (rule.getWkType().equals(SerialRuleType.WK_DATE_FORMAT.wkType)) {
                //获取时间14位格式时间值yyyyMMddHHmmss
                String format = DateUtils.format(new Date(), DateUtils.YYYYMMDDHHMMSS_PATTER);
                //判断是否设置截取长度和起始截取位置
                buffer.append(subStr(format, rule.getLenStr(), rule.getLen()));
            } else if (rule.getWkType().equals(SerialRuleType.WK_FEILD.wkType)) {
                String subStr = subStr(objectToMap(obj).get(rule.getFeildValue()).toString(), rule.getLenStr(), rule.getLen());
                buffer.append(subStr);
            }
        });
        serialRule.setLastCode(buffer.toString());
        //修改当前规则编码号至数据库
        if (!ruleService.saveOrUpdate(serialRule)) {
            throw new CoolException("规则编码保存失败!!");
        }
        return buffer.toString();
    }
    /**
     * @author Ryan
     * @description 根据字段长度及,起始位置截取字符串
     * @throws
     * @return
     * @time 2025/3/5 13:00
     */
    public static String subStr(String str, Integer start, Integer end) {
        StringBuffer buffer = new StringBuffer();
        //判断是否设置截取长度和起始截取位置
        if (Objects.isNull(start) || end == 0) {
            buffer.append(str);
        } else {
            if (str.length() <= (end + start)) {
                throw new CoolException("截取字符起出字符串长度,请查看规则设定!!");
            }
            //返回起始位置lenStr开始,终点位置为lenStr + len长度的字符串
            String substring  = str.substring(start, (start + end));
            buffer.append(substring);
        }
        return buffer.toString();
    }
    /**
     * @author Ryan
     * @description Object 转 Map字段
     * @throws
     * @return
     * @time 2025/3/5 14:00
     */
    public static Map<?, ?> objectToMap (Object obj) {
        if (obj == null) {
            return null;
        }
        ObjectMapper objectMapper = new ObjectMapper();
        Map<?, ?> mappedObject = objectMapper.convertValue(obj, Map.class);
        return mappedObject;
    }
}