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; } }