| New file |
| | |
| | | package com.zy.asrs.controller; |
| | | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | import com.core.annotations.ManagerAuth; |
| | | import com.core.common.R; |
| | | import com.zy.asrs.entity.MonthlySettle; |
| | | import com.zy.asrs.entity.param.DateRangeParam; |
| | | import com.zy.asrs.entity.param.MonthlySettleQueryParam; |
| | | import com.zy.asrs.service.MonthlySettleService; |
| | | import com.zy.common.web.BaseController; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | |
| | | @RestController |
| | | public class MonthlySettleController extends BaseController { |
| | | |
| | | @Autowired |
| | | private MonthlySettleService monthlySettleService; |
| | | |
| | | /** |
| | | * 获取月结信息 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/{id}/auth") |
| | | @ManagerAuth |
| | | public R get(@PathVariable("id") Long id) { |
| | | return R.ok(monthlySettleService.selectById(id)); |
| | | } |
| | | |
| | | /** |
| | | * 分页查询月结列表 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/list/auth") |
| | | @ManagerAuth |
| | | public R list(MonthlySettleQueryParam param) { |
| | | Page<MonthlySettle> page = new Page<>(param.getCurr(), param.getLimit()); |
| | | java.util.Map<String, Object> condition = new java.util.HashMap<>(); |
| | | if (param.getSettleNo() != null && !param.getSettleNo().trim().isEmpty()) { |
| | | condition.put("settleNo", param.getSettleNo()); |
| | | } |
| | | if (param.getStatus() != null) { |
| | | condition.put("status", param.getStatus()); |
| | | } |
| | | if (param.getStartDate() != null && !param.getStartDate().trim().isEmpty() |
| | | && param.getEndDate() != null && !param.getEndDate().trim().isEmpty()) { |
| | | condition.put("startDate", param.getStartDate()); |
| | | condition.put("endDate", param.getEndDate()); |
| | | } |
| | | page.setCondition(condition); |
| | | return R.ok(monthlySettleService.getPage(page)); |
| | | } |
| | | |
| | | /** |
| | | * 获取最近的月结记录 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/latest/auth") |
| | | @ManagerAuth |
| | | public R getLatest() { |
| | | MonthlySettle latest = monthlySettleService.getLatestSettle(); |
| | | return R.ok(latest); |
| | | } |
| | | |
| | | /** |
| | | * 获取下一个月结的起始日期 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/nextStartDate/auth") |
| | | @ManagerAuth |
| | | public R getNextStartDate() { |
| | | Date nextStartDate = monthlySettleService.getNextStartDate(); |
| | | if (nextStartDate != null) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | return R.ok(sdf.format(nextStartDate)); |
| | | } |
| | | return R.ok(null); |
| | | } |
| | | |
| | | /** |
| | | * 获取最晚月结记录的结束日期 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/latestEndDate/auth") |
| | | @ManagerAuth |
| | | public R getLatestEndDate() { |
| | | Date latestEndDate = monthlySettleService.getLatestEndDate(); |
| | | if (latestEndDate != null) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | return R.ok(sdf.format(latestEndDate)); |
| | | } |
| | | return R.ok(null); |
| | | } |
| | | |
| | | /** |
| | | * 检查月结时间范围内是否有未完成的订单 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/checkUnfinished/auth") |
| | | @ManagerAuth |
| | | public R checkUnfinished(DateRangeParam param) { |
| | | boolean hasUnfinished = monthlySettleService.hasUnfinishedOrders(param.getStartDate(), param.getEndDate()); |
| | | if (hasUnfinished) { |
| | | return R.error("月结时间范围内存在未完成的订单,无法进行月结"); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * 发起月结 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/start/auth") |
| | | @ManagerAuth |
| | | public R startSettle(DateRangeParam param) { |
| | | return R.ok(monthlySettleService.startSettle(param.getStartDate(), param.getEndDate(), getUserId())); |
| | | } |
| | | |
| | | /** |
| | | * 获取月结统计信息 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/statistics/{id}/auth") |
| | | @ManagerAuth |
| | | public R getStatistics(@PathVariable("id") Long id) { |
| | | return R.ok(monthlySettleService.getSettleStatistics(id)); |
| | | } |
| | | |
| | | /** |
| | | * 删除月结记录 |
| | | */ |
| | | @RequestMapping(value = "/monthlySettle/{id}/auth", method = RequestMethod.DELETE) |
| | | @ManagerAuth |
| | | public R delete(@PathVariable("id") Long id) { |
| | | monthlySettleService.deleteSettle(id); |
| | | return R.ok("删除成功"); |
| | | } |
| | | |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity; |
| | | |
| | | import com.baomidou.mybatisplus.annotations.TableField; |
| | | import com.baomidou.mybatisplus.annotations.TableId; |
| | | import com.baomidou.mybatisplus.annotations.TableName; |
| | | import com.baomidou.mybatisplus.enums.IdType; |
| | | import com.core.common.Cools; |
| | | import com.core.common.SpringUtils; |
| | | import com.zy.system.entity.User; |
| | | import com.zy.system.service.UserService; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | |
| | | @Data |
| | | @TableName("man_monthly_settle") |
| | | public class MonthlySettle implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ID |
| | | */ |
| | | @ApiModelProperty(value = "ID") |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | /** |
| | | * 月结编号 |
| | | */ |
| | | @ApiModelProperty(value = "月结编号") |
| | | @TableField("settle_no") |
| | | private String settleNo; |
| | | |
| | | /** |
| | | * 起始日期 |
| | | */ |
| | | @ApiModelProperty(value = "起始日期") |
| | | @TableField("start_date") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date startDate; |
| | | |
| | | /** |
| | | * 结束日期 |
| | | */ |
| | | @ApiModelProperty(value = "结束日期") |
| | | @TableField("end_date") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date endDate; |
| | | |
| | | /** |
| | | * 状态 0:待月结 1:已月结 |
| | | */ |
| | | @ApiModelProperty(value = "状态 0:待月结 1:已月结") |
| | | private Integer status; |
| | | |
| | | /** |
| | | * 总入库数量 |
| | | */ |
| | | @ApiModelProperty(value = "总入库数量") |
| | | @TableField("total_in_qty") |
| | | private BigDecimal totalInQty; |
| | | |
| | | /** |
| | | * 总出库数量 |
| | | */ |
| | | @ApiModelProperty(value = "总出库数量") |
| | | @TableField("total_out_qty") |
| | | private BigDecimal totalOutQty; |
| | | |
| | | /** |
| | | * 物料种类数 |
| | | */ |
| | | @ApiModelProperty(value = "物料种类数") |
| | | @TableField("total_materials") |
| | | private Integer totalMaterials; |
| | | |
| | | /** |
| | | * 备注 |
| | | */ |
| | | @ApiModelProperty(value = "备注") |
| | | private String memo; |
| | | |
| | | /** |
| | | * 创建人员 |
| | | */ |
| | | @ApiModelProperty(value = "创建人员") |
| | | @TableField("create_by") |
| | | private Long createBy; |
| | | |
| | | /** |
| | | * 创建时间 |
| | | */ |
| | | @ApiModelProperty(value = "创建时间") |
| | | @TableField("create_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date createTime; |
| | | |
| | | /** |
| | | * 修改人员 |
| | | */ |
| | | @ApiModelProperty(value = "修改人员") |
| | | @TableField("update_by") |
| | | private Long updateBy; |
| | | |
| | | /** |
| | | * 修改时间 |
| | | */ |
| | | @ApiModelProperty(value = "修改时间") |
| | | @TableField("update_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date updateTime; |
| | | |
| | | /** |
| | | * 删除标记 0:未删除 1:已删除 |
| | | */ |
| | | @ApiModelProperty(value = "删除标记 0:未删除 1:已删除") |
| | | @TableField("is_deleted") |
| | | private Integer isDeleted; |
| | | |
| | | public String getStatus$() { |
| | | if (null == this.status) { |
| | | return null; |
| | | } |
| | | switch (this.status) { |
| | | case 0: |
| | | return "待月结"; |
| | | case 1: |
| | | return "已月结"; |
| | | default: |
| | | return String.valueOf(this.status); |
| | | } |
| | | } |
| | | |
| | | |
| | | public String getStartDate$() { |
| | | if (Cools.isEmpty(this.startDate)) { |
| | | return ""; |
| | | } |
| | | return new SimpleDateFormat("yyyy-MM-dd").format(this.startDate); |
| | | } |
| | | |
| | | public String getEndDate$() { |
| | | if (Cools.isEmpty(this.endDate)) { |
| | | return ""; |
| | | } |
| | | return new SimpleDateFormat("yyyy-MM-dd").format(this.endDate); |
| | | } |
| | | |
| | | public String getCreateBy$() { |
| | | UserService service = SpringUtils.getBean(UserService.class); |
| | | User user = service.selectById(this.createBy); |
| | | if (!Cools.isEmpty(user)) { |
| | | return String.valueOf(user.getUsername()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public String getCreateTime$() { |
| | | if (Cools.isEmpty(this.createTime)) { |
| | | return ""; |
| | | } |
| | | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime); |
| | | } |
| | | |
| | | public String getUpdateBy$() { |
| | | UserService service = SpringUtils.getBean(UserService.class); |
| | | User user = service.selectById(this.updateBy); |
| | | if (!Cools.isEmpty(user)) { |
| | | return String.valueOf(user.getUsername()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public String getUpdateTime$() { |
| | | if (Cools.isEmpty(this.updateTime)) { |
| | | return ""; |
| | | } |
| | | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime); |
| | | } |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity; |
| | | |
| | | import com.baomidou.mybatisplus.annotations.TableField; |
| | | import com.baomidou.mybatisplus.annotations.TableId; |
| | | import com.baomidou.mybatisplus.annotations.TableName; |
| | | import com.baomidou.mybatisplus.enums.IdType; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.util.Date; |
| | | |
| | | @Data |
| | | @TableName("man_monthly_settle_detail") |
| | | public class MonthlySettleDetail implements Serializable { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** |
| | | * ID |
| | | */ |
| | | @ApiModelProperty(value = "ID") |
| | | @TableId(value = "id", type = IdType.AUTO) |
| | | private Long id; |
| | | |
| | | /** |
| | | * 月结主表ID |
| | | */ |
| | | @ApiModelProperty(value = "月结主表ID") |
| | | @TableField("settle_id") |
| | | private Long settleId; |
| | | |
| | | /** |
| | | * 月结编号 |
| | | */ |
| | | @ApiModelProperty(value = "月结编号") |
| | | @TableField("settle_no") |
| | | private String settleNo; |
| | | |
| | | // ========== 基本信息 ========== |
| | | /** |
| | | * 物料编码 |
| | | */ |
| | | @ApiModelProperty(value = "物料编码") |
| | | private String matnr; |
| | | |
| | | /** |
| | | * 批次(订单明细批次) |
| | | */ |
| | | @ApiModelProperty(value = "批次") |
| | | private String batch; |
| | | |
| | | /** |
| | | * 物料名称(月结时从订单明细表获取) |
| | | */ |
| | | @ApiModelProperty(value = "物料名称") |
| | | private String maktx; |
| | | |
| | | /** |
| | | * 品牌(月结时从订单明细表获取) |
| | | */ |
| | | @ApiModelProperty(value = "品牌") |
| | | private String brand; |
| | | |
| | | // ========== 数量信息 ========== |
| | | /** |
| | | * 期初库存(上期结余) |
| | | */ |
| | | @ApiModelProperty(value = "期初库存(上期结余)") |
| | | @TableField("beginning_qty") |
| | | private BigDecimal beginningQty; |
| | | |
| | | /** |
| | | * 本期入库数量 |
| | | */ |
| | | @ApiModelProperty(value = "本期入库数量") |
| | | @TableField("in_qty") |
| | | private BigDecimal inQty; |
| | | |
| | | /** |
| | | * 本期出库数量 |
| | | */ |
| | | @ApiModelProperty(value = "本期出库数量") |
| | | @TableField("out_qty") |
| | | private BigDecimal outQty; |
| | | |
| | | /** |
| | | * 期末库存(期初+入库-出库) |
| | | */ |
| | | @ApiModelProperty(value = "期末库存(期初+入库-出库)") |
| | | @TableField("ending_qty") |
| | | private BigDecimal endingQty; |
| | | |
| | | /** |
| | | * 当前实际库存数量 |
| | | */ |
| | | @ApiModelProperty(value = "当前实际库存数量") |
| | | @TableField("stock_qty") |
| | | private BigDecimal stockQty; |
| | | |
| | | /** |
| | | * 差异数量(实际库存-期末库存) |
| | | */ |
| | | @ApiModelProperty(value = "差异数量(实际库存-期末库存)") |
| | | @TableField("diff_qty") |
| | | private BigDecimal diffQty; |
| | | |
| | | // ========== 关联字段(通过关联查询获取,不存储在明细表中)========== |
| | | |
| | | /** |
| | | * 规格(优先从出入库订单明细表获取,如果为空则从物料表获取) |
| | | */ |
| | | @ApiModelProperty(value = "规格") |
| | | @TableField(exist = false) |
| | | private String specs; |
| | | |
| | | /** |
| | | * 型号(优先从出入库订单明细表获取,如果为空则从物料表获取) |
| | | */ |
| | | @ApiModelProperty(value = "型号") |
| | | @TableField(exist = false) |
| | | private String model; |
| | | |
| | | /** |
| | | * 颜色(优先从出入库订单明细表获取,如果为空则从物料表获取) |
| | | */ |
| | | @ApiModelProperty(value = "颜色") |
| | | @TableField(exist = false) |
| | | private String color; |
| | | |
| | | /** |
| | | * 单位(从物料表获取) |
| | | */ |
| | | @ApiModelProperty(value = "单位") |
| | | @TableField(exist = false) |
| | | private String unit; |
| | | |
| | | // ========== 时间信息 ========== |
| | | /** |
| | | * 创建时间 |
| | | */ |
| | | @ApiModelProperty(value = "创建时间") |
| | | @TableField("create_time") |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
| | | private Date createTime; |
| | | |
| | | /** |
| | | * 删除标记 0:未删除 1:已删除 |
| | | */ |
| | | @ApiModelProperty(value = "删除标记 0:未删除 1:已删除") |
| | | @TableField("is_deleted") |
| | | private Integer isDeleted; |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity.param; |
| | | |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import org.springframework.format.annotation.DateTimeFormat; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 日期范围参数 |
| | | */ |
| | | @Data |
| | | public class DateRangeParam { |
| | | |
| | | /** |
| | | * 起始日期 |
| | | */ |
| | | @ApiModelProperty(value = "起始日期", required = true) |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private Date startDate; |
| | | |
| | | /** |
| | | * 结束日期(可以接受 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss 格式) |
| | | */ |
| | | @ApiModelProperty(value = "结束日期", required = true) |
| | | @DateTimeFormat(pattern = "yyyy-MM-dd") |
| | | private Date endDate; |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity.param; |
| | | |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 月结查询参数 |
| | | */ |
| | | @Data |
| | | public class MonthlySettleQueryParam { |
| | | |
| | | /** |
| | | * 当前页 |
| | | */ |
| | | @ApiModelProperty(value = "当前页") |
| | | private Integer curr = 1; |
| | | |
| | | /** |
| | | * 每页数量 |
| | | */ |
| | | @ApiModelProperty(value = "每页数量") |
| | | private Integer limit = 10; |
| | | |
| | | /** |
| | | * 月结编号 |
| | | */ |
| | | @ApiModelProperty(value = "月结编号") |
| | | private String settleNo; |
| | | |
| | | /** |
| | | * 状态 |
| | | */ |
| | | @ApiModelProperty(value = "状态") |
| | | private Integer status; |
| | | |
| | | /** |
| | | * 起始日期 |
| | | */ |
| | | @ApiModelProperty(value = "起始日期") |
| | | private String startDate; |
| | | |
| | | /** |
| | | * 结束日期 |
| | | */ |
| | | @ApiModelProperty(value = "结束日期") |
| | | private String endDate; |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity.result; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * 物料出入库统计 |
| | | */ |
| | | @Data |
| | | public class MaterialInOutStatDTO { |
| | | |
| | | /** |
| | | * 物料编码 |
| | | */ |
| | | private String matnr; |
| | | |
| | | /** |
| | | * 物料名称 |
| | | */ |
| | | private String maktx; |
| | | |
| | | /** |
| | | * 批次 |
| | | */ |
| | | private String batch; |
| | | |
| | | /** |
| | | * 品牌 |
| | | */ |
| | | private String brand; |
| | | |
| | | /** |
| | | * 入库数量 |
| | | */ |
| | | private BigDecimal inQty; |
| | | |
| | | /** |
| | | * 出库数量 |
| | | */ |
| | | private BigDecimal outQty; |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity.result; |
| | | |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * 月结结果 |
| | | */ |
| | | @Data |
| | | public class MonthlySettleResultVO { |
| | | |
| | | /** |
| | | * 月结ID |
| | | */ |
| | | @ApiModelProperty(value = "月结ID") |
| | | private Long settleId; |
| | | |
| | | /** |
| | | * 月结编号 |
| | | */ |
| | | @ApiModelProperty(value = "月结编号") |
| | | private String settleNo; |
| | | |
| | | /** |
| | | * 总入库数量 |
| | | */ |
| | | @ApiModelProperty(value = "总入库数量") |
| | | private BigDecimal totalInQty; |
| | | |
| | | /** |
| | | * 总出库数量 |
| | | */ |
| | | @ApiModelProperty(value = "总出库数量") |
| | | private BigDecimal totalOutQty; |
| | | |
| | | /** |
| | | * 物料种类数 |
| | | */ |
| | | @ApiModelProperty(value = "物料种类数") |
| | | private Integer totalMaterials; |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity.result; |
| | | |
| | | import com.zy.asrs.entity.MonthlySettle; |
| | | import com.zy.asrs.entity.MonthlySettleDetail; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 月结统计信息 |
| | | */ |
| | | @Data |
| | | public class MonthlySettleStatisticsVO { |
| | | |
| | | /** |
| | | * 月结主记录 |
| | | */ |
| | | @ApiModelProperty(value = "月结主记录") |
| | | private MonthlySettle settle; |
| | | |
| | | /** |
| | | * 月结明细列表 |
| | | */ |
| | | @ApiModelProperty(value = "月结明细列表") |
| | | private List<MonthlySettleDetail> details; |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.entity.result; |
| | | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | /** |
| | | * 上期月结期末库存 |
| | | */ |
| | | @Data |
| | | public class PreviousSettleEndingQtyDTO { |
| | | |
| | | /** |
| | | * 物料编码 |
| | | */ |
| | | private String matnr; |
| | | |
| | | /** |
| | | * 批次 |
| | | */ |
| | | private String batch; |
| | | |
| | | /** |
| | | * 品牌 |
| | | */ |
| | | private String brand; |
| | | |
| | | /** |
| | | * 期末库存 |
| | | */ |
| | | private BigDecimal endingQty; |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.mapper.BaseMapper; |
| | | import com.zy.asrs.entity.MonthlySettleDetail; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | @Repository |
| | | public interface MonthlySettleDetailMapper extends BaseMapper<MonthlySettleDetail> { |
| | | |
| | | /** |
| | | * 查询月结明细(关联物料表) |
| | | */ |
| | | List<MonthlySettleDetail> selectDetailWithMat(@Param("settleId") Long settleId); |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.mapper; |
| | | |
| | | import com.baomidou.mybatisplus.mapper.BaseMapper; |
| | | import com.zy.asrs.entity.MonthlySettle; |
| | | import com.zy.asrs.entity.result.MaterialInOutStatDTO; |
| | | import com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | @Repository |
| | | public interface MonthlySettleMapper extends BaseMapper<MonthlySettle> { |
| | | |
| | | /** |
| | | * 获取最近的月结记录 |
| | | */ |
| | | MonthlySettle selectLatestSettle(); |
| | | |
| | | /** |
| | | * 统计月结时间范围内的订单数量 |
| | | */ |
| | | int countOrdersInRange(@Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | /** |
| | | * 统计月结时间范围内未完成的订单数量(入库和出库) |
| | | */ |
| | | int countUnfinishedOrdersInRange(@Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | /** |
| | | * 统计月结时间范围内的物料出入库数量(合并入库和出库) |
| | | */ |
| | | List<MaterialInOutStatDTO> statisticsMaterialInOut(@Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | /** |
| | | * 获取上一个月结的物料期末库存 |
| | | */ |
| | | List<PreviousSettleEndingQtyDTO> getPreviousSettleEndingQty(@Param("previousSettleId") Long previousSettleId); |
| | | |
| | | /** |
| | | * 更新入库订单的月结信息 |
| | | */ |
| | | int updateOrderSettleInfo(@Param("settleId") Long settleId, @Param("settleNo") String settleNo, |
| | | @Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | /** |
| | | * 更新出库订单的月结信息 |
| | | */ |
| | | int updateOrderSettleInfoPakout(@Param("settleId") Long settleId, @Param("settleNo") String settleNo, |
| | | @Param("startDate") String startDate, @Param("endDate") String endDate); |
| | | |
| | | /** |
| | | * 清除入库订单的月结信息 |
| | | */ |
| | | int clearOrderSettleInfo(@Param("settleId") Long settleId); |
| | | |
| | | /** |
| | | * 清除出库订单的月结信息 |
| | | */ |
| | | int clearOrderSettleInfoPakout(@Param("settleId") Long settleId); |
| | | } |
| | | |
| New file |
| | |
| | | package com.zy.asrs.service; |
| | | |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | import com.baomidou.mybatisplus.service.IService; |
| | | import com.zy.asrs.entity.MonthlySettle; |
| | | import com.zy.asrs.entity.result.MonthlySettleResultVO; |
| | | import com.zy.asrs.entity.result.MonthlySettleStatisticsVO; |
| | | |
| | | import java.util.Date; |
| | | |
| | | public interface MonthlySettleService extends IService<MonthlySettle> { |
| | | |
| | | /** |
| | | * 获取最近的月结记录 |
| | | */ |
| | | MonthlySettle getLatestSettle(); |
| | | |
| | | /** |
| | | * 获取下一个月结的起始日期 |
| | | */ |
| | | Date getNextStartDate(); |
| | | |
| | | /** |
| | | * 获取最晚月结记录的结束日期 |
| | | */ |
| | | Date getLatestEndDate(); |
| | | |
| | | /** |
| | | * 检查月结时间范围内是否有未完成的订单 |
| | | */ |
| | | boolean hasUnfinishedOrders(Date startDate, Date endDate); |
| | | |
| | | /** |
| | | * 发起月结 |
| | | */ |
| | | MonthlySettleResultVO startSettle(Date startDate, Date endDate, Long userId); |
| | | |
| | | /** |
| | | * 获取月结统计信息 |
| | | */ |
| | | MonthlySettleStatisticsVO getSettleStatistics(Long settleId); |
| | | |
| | | /** |
| | | * 分页查询月结列表 |
| | | */ |
| | | Page<MonthlySettle> getPage(Page<MonthlySettle> page); |
| | | |
| | | /** |
| | | * 删除月结记录 |
| | | */ |
| | | void deleteSettle(Long settleId); |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | package com.zy.asrs.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.baomidou.mybatisplus.plugins.Page; |
| | | import com.baomidou.mybatisplus.service.impl.ServiceImpl; |
| | | import com.core.common.SnowflakeIdWorker; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.asrs.entity.MonthlySettle; |
| | | import com.zy.asrs.entity.MonthlySettleDetail; |
| | | import com.zy.asrs.entity.result.MaterialInOutStatDTO; |
| | | import com.zy.asrs.entity.result.MonthlySettleResultVO; |
| | | import com.zy.asrs.entity.result.MonthlySettleStatisticsVO; |
| | | import com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO; |
| | | import com.zy.asrs.mapper.MonthlySettleDetailMapper; |
| | | import com.zy.asrs.mapper.MonthlySettleMapper; |
| | | import com.zy.asrs.service.ManLocDetlService; |
| | | import com.zy.asrs.service.MonthlySettleService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | @Slf4j |
| | | @Service("monthlySettleService") |
| | | public class MonthlySettleServiceImpl extends ServiceImpl<MonthlySettleMapper, MonthlySettle> implements MonthlySettleService { |
| | | |
| | | @Autowired |
| | | private MonthlySettleDetailMapper monthlySettleDetailMapper; |
| | | @Autowired |
| | | private ManLocDetlService manLocDetlService; |
| | | @Autowired |
| | | private SnowflakeIdWorker snowflakeIdWorker; |
| | | |
| | | @Override |
| | | public MonthlySettle getLatestSettle() { |
| | | return this.baseMapper.selectLatestSettle(); |
| | | } |
| | | |
| | | @Override |
| | | public Date getNextStartDate() { |
| | | MonthlySettle latestSettle = getLatestSettle(); |
| | | if (latestSettle == null) { |
| | | // 如果没有月结记录,返回null,由前端选择起始日期 |
| | | return null; |
| | | } |
| | | // 返回最晚月结记录结束日期的下一天(起始日期应该是结束日期+1天的00:00:00) |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(latestSettle.getEndDate()); |
| | | // 先设置为当天的00:00:00,然后加1天,确保返回的是下一天的00:00:00 |
| | | cal.set(Calendar.HOUR_OF_DAY, 0); |
| | | cal.set(Calendar.MINUTE, 0); |
| | | cal.set(Calendar.SECOND, 0); |
| | | cal.set(Calendar.MILLISECOND, 0); |
| | | cal.add(Calendar.DAY_OF_MONTH, 1); |
| | | return cal.getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public Date getLatestEndDate() { |
| | | MonthlySettle latestSettle = getLatestSettle(); |
| | | if (latestSettle == null) { |
| | | return null; |
| | | } |
| | | // 返回最晚月结记录的结束日期(格式化为当天的00:00:00,用于显示) |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(latestSettle.getEndDate()); |
| | | cal.set(Calendar.HOUR_OF_DAY, 0); |
| | | cal.set(Calendar.MINUTE, 0); |
| | | cal.set(Calendar.SECOND, 0); |
| | | cal.set(Calendar.MILLISECOND, 0); |
| | | return cal.getTime(); |
| | | } |
| | | |
| | | @Override |
| | | public boolean hasUnfinishedOrders(Date startDate, Date endDate) { |
| | | // 结束日期+23:59:59 |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(endDate); |
| | | cal.set(Calendar.HOUR_OF_DAY, 23); |
| | | cal.set(Calendar.MINUTE, 59); |
| | | cal.set(Calendar.SECOND, 59); |
| | | cal.set(Calendar.MILLISECOND, 999); |
| | | endDate = cal.getTime(); |
| | | |
| | | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); |
| | | SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String startDateStr = dateFormat.format(startDate); |
| | | String endDateStr = dateTimeFormat.format(endDate); |
| | | int count = this.baseMapper.countUnfinishedOrdersInRange(startDateStr, endDateStr); |
| | | return count > 0; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public MonthlySettleResultVO startSettle(Date startDate, Date endDate, Long userId) { |
| | | // 结束日期+23:59:59 |
| | | Calendar cal = Calendar.getInstance(); |
| | | cal.setTime(endDate); |
| | | cal.set(Calendar.HOUR_OF_DAY, 23); |
| | | cal.set(Calendar.MINUTE, 59); |
| | | cal.set(Calendar.SECOND, 59); |
| | | cal.set(Calendar.MILLISECOND, 999); |
| | | endDate = cal.getTime(); |
| | | |
| | | // 检查起始日期必须大于最晚月结记录的结束日期 |
| | | MonthlySettle latestSettle = getLatestSettle(); |
| | | if (latestSettle != null) { |
| | | Calendar startCal = Calendar.getInstance(); |
| | | startCal.setTime(startDate); |
| | | startCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | startCal.set(Calendar.MINUTE, 0); |
| | | startCal.set(Calendar.SECOND, 0); |
| | | startCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | Calendar latestEndCal = Calendar.getInstance(); |
| | | latestEndCal.setTime(latestSettle.getEndDate()); |
| | | latestEndCal.set(Calendar.HOUR_OF_DAY, 0); |
| | | latestEndCal.set(Calendar.MINUTE, 0); |
| | | latestEndCal.set(Calendar.SECOND, 0); |
| | | latestEndCal.set(Calendar.MILLISECOND, 0); |
| | | |
| | | // 起始日期必须大于最晚结束日期,不能等于或小于 |
| | | if (!startCal.getTime().after(latestEndCal.getTime())) { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | throw new CoolException("起始日期必须大于最晚月结记录的结束日期:" + sdf.format(latestSettle.getEndDate())); |
| | | } |
| | | } |
| | | |
| | | // 检查是否有未完成的订单 |
| | | if (hasUnfinishedOrders(startDate, endDate)) { |
| | | throw new CoolException("月结时间范围内存在未完成的订单,无法进行月结"); |
| | | } |
| | | |
| | | // 统计物料出入库数量(合并入库和出库) |
| | | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); |
| | | SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
| | | String startDateStr = dateFormat.format(startDate); |
| | | String endDateStr = dateTimeFormat.format(endDate); |
| | | List<MaterialInOutStatDTO> materialStats = this.baseMapper.statisticsMaterialInOut(startDateStr, endDateStr); |
| | | |
| | | // 检查是否有出入库历史订单 |
| | | if (materialStats == null || materialStats.isEmpty()) { |
| | | throw new CoolException("月结时间范围内没有出入库历史订单,无法进行月结"); |
| | | } |
| | | |
| | | // 获取上一个月结记录(用于计算期初库存) |
| | | MonthlySettle previousSettle = getLatestSettle(); |
| | | Map<String, BigDecimal> previousEndingQtyMap = new HashMap<>(); |
| | | if (previousSettle != null) { |
| | | List<PreviousSettleEndingQtyDTO> previousDetails = this.baseMapper.getPreviousSettleEndingQty(previousSettle.getId()); |
| | | for (PreviousSettleEndingQtyDTO detail : previousDetails) { |
| | | String key = detail.getMatnr() + "_" + |
| | | (detail.getBatch() != null ? detail.getBatch() : "") + "_" + |
| | | (detail.getBrand() != null ? detail.getBrand() : ""); |
| | | BigDecimal endingQty = detail.getEndingQty() != null ? detail.getEndingQty() : BigDecimal.ZERO; |
| | | previousEndingQtyMap.put(key, endingQty); |
| | | } |
| | | } |
| | | |
| | | // 生成月结编号 |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); |
| | | String settleNo = "MS" + sdf.format(new Date()) + String.format("%04d", snowflakeIdWorker.nextId() % 10000); |
| | | |
| | | // 创建月结主记录 |
| | | MonthlySettle monthlySettle = new MonthlySettle(); |
| | | monthlySettle.setSettleNo(settleNo); |
| | | monthlySettle.setStartDate(startDate); |
| | | monthlySettle.setEndDate(endDate); |
| | | monthlySettle.setStatus(1); // 已月结 |
| | | monthlySettle.setIsDeleted(0); // 未删除 |
| | | monthlySettle.setCreateBy(userId); |
| | | monthlySettle.setCreateTime(new Date()); |
| | | this.insert(monthlySettle); |
| | | |
| | | BigDecimal totalInQty = BigDecimal.ZERO; |
| | | BigDecimal totalOutQty = BigDecimal.ZERO; |
| | | int materialCount = 0; |
| | | |
| | | // 创建月结明细 |
| | | for (MaterialInOutStatDTO stat : materialStats) { |
| | | // 1. 提取基础信息 |
| | | String matnr = stat.getMatnr(); |
| | | String batch = stat.getBatch() != null ? stat.getBatch() : ""; |
| | | String brand = stat.getBrand() != null ? stat.getBrand() : ""; |
| | | String maktx = stat.getMaktx(); |
| | | |
| | | // 2. 提取数量信息 |
| | | BigDecimal inQty = stat.getInQty() != null ? stat.getInQty() : BigDecimal.ZERO; |
| | | BigDecimal outQty = stat.getOutQty() != null ? stat.getOutQty() : BigDecimal.ZERO; |
| | | |
| | | // 3. 计算库存相关数量 |
| | | BigDecimal beginningQty = getBeginningQty(matnr, batch, brand, previousEndingQtyMap); |
| | | BigDecimal endingQty = calculateEndingQty(beginningQty, inQty, outQty); |
| | | BigDecimal stockQtyDecimal = getCurrentStockQty(matnr, batch); |
| | | BigDecimal diffQty = calculateDiffQty(stockQtyDecimal, endingQty); |
| | | |
| | | // 4. 创建并保存明细记录 |
| | | MonthlySettleDetail detail = buildMonthlySettleDetail( |
| | | monthlySettle.getId(), settleNo, matnr, batch, maktx, brand, |
| | | beginningQty, inQty, outQty, endingQty, stockQtyDecimal, diffQty |
| | | ); |
| | | detail.setIsDeleted(0); // 未删除 |
| | | monthlySettleDetailMapper.insert(detail); |
| | | |
| | | // 5. 累计统计 |
| | | totalInQty = totalInQty.add(inQty); |
| | | totalOutQty = totalOutQty.add(outQty); |
| | | materialCount++; |
| | | } |
| | | |
| | | // 更新月结主记录 |
| | | monthlySettle.setTotalInQty(totalInQty); |
| | | monthlySettle.setTotalOutQty(totalOutQty); |
| | | monthlySettle.setTotalMaterials(materialCount); |
| | | monthlySettle.setStatus(1); // 已月结 |
| | | monthlySettle.setUpdateBy(userId); |
| | | monthlySettle.setUpdateTime(new Date()); |
| | | this.updateById(monthlySettle); |
| | | |
| | | // 更新订单的月结信息(入库和出库都要更新) |
| | | this.baseMapper.updateOrderSettleInfo(monthlySettle.getId(), settleNo, startDateStr, endDateStr); |
| | | this.baseMapper.updateOrderSettleInfoPakout(monthlySettle.getId(), settleNo, startDateStr, endDateStr); |
| | | |
| | | MonthlySettleResultVO result = new MonthlySettleResultVO(); |
| | | result.setSettleId(monthlySettle.getId()); |
| | | result.setSettleNo(settleNo); |
| | | result.setTotalInQty(totalInQty); |
| | | result.setTotalOutQty(totalOutQty); |
| | | result.setTotalMaterials(materialCount); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public MonthlySettleStatisticsVO getSettleStatistics(Long settleId) { |
| | | MonthlySettle settle = this.selectById(settleId); |
| | | if (settle == null || (settle.getIsDeleted() != null && settle.getIsDeleted() == 1)) { |
| | | throw new CoolException("月结记录不存在"); |
| | | } |
| | | |
| | | // 关联物料表查询明细 |
| | | List<MonthlySettleDetail> details = monthlySettleDetailMapper.selectDetailWithMat(settleId); |
| | | |
| | | MonthlySettleStatisticsVO result = new MonthlySettleStatisticsVO(); |
| | | result.setSettle(settle); |
| | | result.setDetails(details); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public Page<MonthlySettle> getPage(Page<MonthlySettle> page) { |
| | | Map<String, Object> condition = page.getCondition(); |
| | | EntityWrapper<MonthlySettle> wrapper = new EntityWrapper<>(); |
| | | wrapper.eq("is_deleted", 0); |
| | | |
| | | if (condition != null) { |
| | | if (condition.get("settleNo") != null) { |
| | | wrapper.like("settle_no", condition.get("settleNo").toString()); |
| | | } |
| | | if (condition.get("status") != null) { |
| | | wrapper.eq("status", condition.get("status")); |
| | | } |
| | | if (condition.get("startDate") != null && condition.get("endDate") != null) { |
| | | wrapper.ge("start_date", condition.get("startDate")); |
| | | wrapper.le("end_date", condition.get("endDate")); |
| | | } |
| | | } |
| | | |
| | | wrapper.orderBy("create_time", false); |
| | | List<MonthlySettle> list = this.selectList(wrapper); |
| | | |
| | | EntityWrapper<MonthlySettle> countWrapper = new EntityWrapper<>(); |
| | | countWrapper.eq("is_deleted", 0); |
| | | if (condition != null) { |
| | | if (condition.get("settleNo") != null) { |
| | | countWrapper.like("settle_no", condition.get("settleNo").toString()); |
| | | } |
| | | if (condition.get("status") != null) { |
| | | countWrapper.eq("status", condition.get("status")); |
| | | } |
| | | if (condition.get("startDate") != null && condition.get("endDate") != null) { |
| | | countWrapper.ge("start_date", condition.get("startDate")); |
| | | countWrapper.le("end_date", condition.get("endDate")); |
| | | } |
| | | } |
| | | page.setRecords(list); |
| | | page.setTotal(this.selectCount(countWrapper)); |
| | | return page; |
| | | } |
| | | |
| | | /** |
| | | * 获取期初库存(上期结余) |
| | | */ |
| | | private BigDecimal getBeginningQty(String matnr, String batch, String brand, Map<String, BigDecimal> previousEndingQtyMap) { |
| | | String key = matnr + "_" + batch + "_" + brand; |
| | | return previousEndingQtyMap.getOrDefault(key, BigDecimal.ZERO); |
| | | } |
| | | |
| | | /** |
| | | * 计算期末库存(期初+入库-出库) |
| | | */ |
| | | private BigDecimal calculateEndingQty(BigDecimal beginningQty, BigDecimal inQty, BigDecimal outQty) { |
| | | return beginningQty.add(inQty).subtract(outQty); |
| | | } |
| | | |
| | | /** |
| | | * 获取当前实际库存数量 |
| | | */ |
| | | private BigDecimal getCurrentStockQty(String matnr, String batch) { |
| | | Double stockQty = manLocDetlService.queryStockAnfme(matnr, batch); |
| | | return stockQty != null ? BigDecimal.valueOf(stockQty) : BigDecimal.ZERO; |
| | | } |
| | | |
| | | /** |
| | | * 计算差异数量(实际库存-期末库存) |
| | | */ |
| | | private BigDecimal calculateDiffQty(BigDecimal stockQty, BigDecimal endingQty) { |
| | | return stockQty.subtract(endingQty); |
| | | } |
| | | |
| | | /** |
| | | * 构建月结明细对象 |
| | | */ |
| | | private MonthlySettleDetail buildMonthlySettleDetail( |
| | | Long settleId, String settleNo, String matnr, String batch, String maktx, String brand, |
| | | BigDecimal beginningQty, BigDecimal inQty, BigDecimal outQty, BigDecimal endingQty, |
| | | BigDecimal stockQty, BigDecimal diffQty) { |
| | | MonthlySettleDetail detail = new MonthlySettleDetail(); |
| | | // 基本信息 |
| | | detail.setSettleId(settleId); |
| | | detail.setSettleNo(settleNo); |
| | | detail.setMatnr(matnr); |
| | | detail.setBatch(batch); |
| | | detail.setMaktx(maktx); |
| | | detail.setBrand(brand); |
| | | // 数量信息 |
| | | detail.setBeginningQty(beginningQty); |
| | | detail.setInQty(inQty); |
| | | detail.setOutQty(outQty); |
| | | detail.setEndingQty(endingQty); |
| | | detail.setStockQty(stockQty); |
| | | detail.setDiffQty(diffQty); |
| | | // 时间信息 |
| | | detail.setCreateTime(new Date()); |
| | | return detail; |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public void deleteSettle(Long settleId) { |
| | | MonthlySettle settle = this.selectById(settleId); |
| | | if (settle == null || (settle.getIsDeleted() != null && settle.getIsDeleted() == 1)) { |
| | | throw new CoolException("月结记录不存在"); |
| | | } |
| | | |
| | | // 清除出入库订单的月结信息 |
| | | this.baseMapper.clearOrderSettleInfo(settleId); |
| | | this.baseMapper.clearOrderSettleInfoPakout(settleId); |
| | | |
| | | // 逻辑删除月结明细 |
| | | EntityWrapper<MonthlySettleDetail> detailWrapper = new EntityWrapper<>(); |
| | | detailWrapper.eq("settle_id", settleId); |
| | | detailWrapper.eq("is_deleted", 0); |
| | | List<MonthlySettleDetail> details = monthlySettleDetailMapper.selectList(detailWrapper); |
| | | if (details != null && !details.isEmpty()) { |
| | | for (MonthlySettleDetail detail : details) { |
| | | detail.setIsDeleted(1); |
| | | monthlySettleDetailMapper.updateById(detail); |
| | | } |
| | | } |
| | | |
| | | // 逻辑删除月结主记录 |
| | | settle.setIsDeleted(1); |
| | | settle.setUpdateTime(new Date()); |
| | | this.updateById(settle); |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | <?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.zy.asrs.mapper.MonthlySettleDetailMapper"> |
| | | |
| | | <!-- 通用查询映射结果 --> |
| | | <resultMap id="BaseResultMap" type="com.zy.asrs.entity.MonthlySettleDetail"> |
| | | <id column="id" property="id" /> |
| | | <result column="settle_id" property="settleId" /> |
| | | <result column="settle_no" property="settleNo" /> |
| | | <result column="matnr" property="matnr" /> |
| | | <result column="batch" property="batch" /> |
| | | <result column="maktx" property="maktx" /> |
| | | <result column="brand" property="brand" /> |
| | | <result column="beginning_qty" property="beginningQty" /> |
| | | <result column="in_qty" property="inQty" /> |
| | | <result column="out_qty" property="outQty" /> |
| | | <result column="ending_qty" property="endingQty" /> |
| | | <result column="stock_qty" property="stockQty" /> |
| | | <result column="diff_qty" property="diffQty" /> |
| | | <result column="create_time" property="createTime" /> |
| | | <result column="is_deleted" property="isDeleted" /> |
| | | </resultMap> |
| | | |
| | | <!-- 关联物料表的查询映射结果(获取其他物料信息) --> |
| | | <resultMap id="DetailWithMatResultMap" type="com.zy.asrs.entity.MonthlySettleDetail" extends="BaseResultMap"> |
| | | <result column="specs" property="specs" /> |
| | | <result column="model" property="model" /> |
| | | <result column="color" property="color" /> |
| | | <result column="unit" property="unit" /> |
| | | </resultMap> |
| | | |
| | | <!-- 查询月结明细(从明细表查询,关联物料表获取补充信息) --> |
| | | <select id="selectDetailWithMat" resultMap="DetailWithMatResultMap"> |
| | | SELECT |
| | | d.id, |
| | | d.settle_id, |
| | | d.settle_no, |
| | | d.matnr, |
| | | d.batch, |
| | | d.maktx, |
| | | d.brand, |
| | | d.beginning_qty, |
| | | d.in_qty, |
| | | d.out_qty, |
| | | d.ending_qty, |
| | | d.stock_qty, |
| | | d.diff_qty, |
| | | d.create_time, |
| | | m.specs, |
| | | m.model, |
| | | m.color, |
| | | m.unit |
| | | FROM man_monthly_settle_detail d |
| | | LEFT JOIN man_mat m ON d.matnr = m.matnr |
| | | WHERE d.settle_id = #{settleId} |
| | | AND d.is_deleted = 0 |
| | | ORDER BY d.matnr, d.batch |
| | | </select> |
| | | |
| | | </mapper> |
| | | |
| | | |
| New file |
| | |
| | | <?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.zy.asrs.mapper.MonthlySettleMapper"> |
| | | |
| | | <!-- 通用查询映射结果 --> |
| | | <resultMap id="BaseResultMap" type="com.zy.asrs.entity.MonthlySettle"> |
| | | <id column="id" property="id" /> |
| | | <result column="settle_no" property="settleNo" /> |
| | | <result column="start_date" property="startDate" /> |
| | | <result column="end_date" property="endDate" /> |
| | | <result column="status" property="status" /> |
| | | <result column="total_in_qty" property="totalInQty" /> |
| | | <result column="total_out_qty" property="totalOutQty" /> |
| | | <result column="total_materials" property="totalMaterials" /> |
| | | <result column="memo" property="memo" /> |
| | | <result column="create_by" property="createBy" /> |
| | | <result column="create_time" property="createTime" /> |
| | | <result column="update_by" property="updateBy" /> |
| | | <result column="update_time" property="updateTime" /> |
| | | <result column="is_deleted" property="isDeleted" /> |
| | | </resultMap> |
| | | |
| | | <!-- 获取最近的月结记录 --> |
| | | <select id="selectLatestSettle" resultMap="BaseResultMap"> |
| | | SELECT TOP 1 * FROM man_monthly_settle |
| | | WHERE is_deleted = 0 |
| | | ORDER BY end_date DESC |
| | | </select> |
| | | |
| | | <!-- 统计月结时间范围内的订单数量 --> |
| | | <select id="countOrdersInRange" resultType="int"> |
| | | SELECT COUNT(*) FROM man_order |
| | | WHERE status = 1 |
| | | AND order_time >= #{startDate} |
| | | AND order_time <= #{endDate} |
| | | </select> |
| | | |
| | | <!-- 统计月结时间范围内未完成的订单数量(入库和出库) --> |
| | | <select id="countUnfinishedOrdersInRange" resultType="int"> |
| | | SELECT COUNT(*) FROM ( |
| | | SELECT DISTINCT o.id FROM man_order_log_pakin o |
| | | INNER JOIN man_order_detl_log_pakin od ON o.id = od.order_id |
| | | WHERE o.status = 1 |
| | | AND CONVERT(date, o.order_time) >= #{startDate} |
| | | AND o.order_time <= #{endDate} |
| | | AND o.move_status != 2 |
| | | AND (od.anfme > od.qty OR od.qty IS NULL) |
| | | AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0) |
| | | UNION |
| | | SELECT DISTINCT o.id FROM man_order_log_pakout o |
| | | INNER JOIN man_order_detl_log_pakout od ON o.id = od.order_id |
| | | WHERE o.status = 1 |
| | | AND CONVERT(date, o.order_time) >= #{startDate} |
| | | AND o.order_time <= #{endDate} |
| | | AND o.move_status != 2 |
| | | AND (od.anfme > od.qty OR od.qty IS NULL) |
| | | AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0) |
| | | ) t |
| | | </select> |
| | | |
| | | <!-- 统计月结时间范围内的物料出入库数量(合并入库出库) --> |
| | | <select id="statisticsMaterialInOut" resultType="com.zy.asrs.entity.result.MaterialInOutStatDTO"> |
| | | SELECT |
| | | matnr, |
| | | MAX(maktx) as maktx, |
| | | batch, |
| | | brand, |
| | | SUM(in_qty) as inQty, |
| | | SUM(out_qty) as outQty |
| | | FROM ( |
| | | SELECT |
| | | od.matnr, |
| | | MAX(od.maktx) as maktx, |
| | | ISNULL(od.batch, '') as batch, |
| | | ISNULL(od.brand, '') as brand, |
| | | SUM(od.qty) as in_qty, |
| | | 0 as out_qty |
| | | FROM man_order_log_pakin o |
| | | INNER JOIN man_order_detl_log_pakin od ON o.id = od.order_id |
| | | WHERE o.status = 1 |
| | | AND CONVERT(date, o.order_time) >= #{startDate} |
| | | AND o.order_time <= #{endDate} |
| | | AND o.move_status = 2 |
| | | AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0) |
| | | GROUP BY od.matnr, od.batch, od.brand |
| | | UNION ALL |
| | | SELECT |
| | | od.matnr, |
| | | MAX(od.maktx) as maktx, |
| | | ISNULL(od.batch, '') as batch, |
| | | ISNULL(od.brand, '') as brand, |
| | | 0 as in_qty, |
| | | SUM(od.qty) as out_qty |
| | | FROM man_order_log_pakout o |
| | | INNER JOIN man_order_detl_log_pakout od ON o.id = od.order_id |
| | | WHERE o.status = 1 |
| | | AND CONVERT(date, o.order_time) >= #{startDate} |
| | | AND o.order_time <= #{endDate} |
| | | AND o.move_status = 2 |
| | | AND (o.monthly_settle_id IS NULL OR o.monthly_settle_id = 0) |
| | | GROUP BY od.matnr, od.batch, od.brand |
| | | ) t |
| | | GROUP BY matnr, batch, brand |
| | | </select> |
| | | |
| | | <!-- 获取上一个月结的物料期末库存 --> |
| | | <select id="getPreviousSettleEndingQty" resultType="com.zy.asrs.entity.result.PreviousSettleEndingQtyDTO"> |
| | | SELECT |
| | | matnr, |
| | | batch, |
| | | brand, |
| | | ending_qty as endingQty |
| | | FROM man_monthly_settle_detail |
| | | WHERE settle_id = #{previousSettleId} |
| | | </select> |
| | | |
| | | <!-- 更新入库订单的月结信息 --> |
| | | <update id="updateOrderSettleInfo"> |
| | | UPDATE man_order_log_pakin |
| | | SET monthly_settle_id = #{settleId}, |
| | | monthly_settle_no = #{settleNo} |
| | | WHERE status = 1 |
| | | AND CONVERT(date, order_time) >= #{startDate} |
| | | AND order_time <= #{endDate} |
| | | AND move_status = 2 |
| | | AND (monthly_settle_id IS NULL OR monthly_settle_id = 0) |
| | | </update> |
| | | |
| | | <!-- 更新出库订单的月结信息 --> |
| | | <update id="updateOrderSettleInfoPakout"> |
| | | UPDATE man_order_log_pakout |
| | | SET monthly_settle_id = #{settleId}, |
| | | monthly_settle_no = #{settleNo} |
| | | WHERE status = 1 |
| | | AND CONVERT(date, order_time) >= #{startDate} |
| | | AND order_time <= #{endDate} |
| | | AND move_status = 2 |
| | | AND (monthly_settle_id IS NULL OR monthly_settle_id = 0) |
| | | </update> |
| | | |
| | | <!-- 清除入库订单的月结信息 --> |
| | | <update id="clearOrderSettleInfo"> |
| | | UPDATE man_order_log_pakin |
| | | SET monthly_settle_id = NULL, |
| | | monthly_settle_no = NULL |
| | | WHERE monthly_settle_id = #{settleId} |
| | | </update> |
| | | |
| | | <!-- 清除出库订单的月结信息 --> |
| | | <update id="clearOrderSettleInfoPakout"> |
| | | UPDATE man_order_log_pakout |
| | | SET monthly_settle_id = NULL, |
| | | monthly_settle_no = NULL |
| | | WHERE monthly_settle_id = #{settleId} |
| | | </update> |
| | | |
| | | </mapper> |
| | | |
| | | |
| New file |
| | |
| | | var pageCurr; |
| | | layui.config({ |
| | | base: baseUrl + "/static/layui/lay/modules/" |
| | | }).use(['layer', 'form', 'table', 'util', 'admin', 'laydate', 'laytpl'], function () { |
| | | var $ = layui.jquery; |
| | | var layer = layui.layer; |
| | | var form = layui.form; |
| | | var table = layui.table; |
| | | var util = layui.util; |
| | | var admin = layui.admin; |
| | | var layDate = layui.laydate; |
| | | var laytpl = layui.laytpl; |
| | | |
| | | // 渲染表格 |
| | | tableIns = table.render({ |
| | | elem: '#monthlySettle', |
| | | url: baseUrl + '/monthlySettle/list/auth', |
| | | headers: {token: localStorage.getItem('token')}, |
| | | method: 'POST', |
| | | page: true, |
| | | cellMinWidth: 100, |
| | | where: {}, |
| | | cols: [[ |
| | | {type: 'numbers'}, |
| | | {field: 'settleNo', title: '月结编号', width: 180}, |
| | | {field: 'startDate$', align: 'center', title: '起始日期', width: 120}, |
| | | {field: 'endDate$', align: 'center', title: '结束日期', width: 120}, |
| | | {field: 'totalInQty', align: 'center', title: '总入库数量', width: 120}, |
| | | {field: 'totalOutQty', align: 'center', title: '总出库数量', width: 120}, |
| | | {field: 'totalMaterials', align: 'center', title: '物料种类数', width: 120}, |
| | | {field: 'createTime$', title: '创建时间', minWidth: 180, width: 180}, |
| | | {align: 'center', title: '操作', toolbar: '#operate', width: 180} |
| | | ]], |
| | | request: { |
| | | pageName: 'curr', |
| | | pageSize: 'limit' |
| | | }, |
| | | parseData: function (res) { |
| | | return { |
| | | 'code': res.code, |
| | | 'msg': res.msg, |
| | | 'count': res.data.total, |
| | | 'data': res.data.records |
| | | } |
| | | }, |
| | | response: { |
| | | statusCode: 200 |
| | | }, |
| | | done: function (res, curr, count) { |
| | | if (res.code === 403) { |
| | | top.location.href = baseUrl + "/"; |
| | | } |
| | | pageCurr = curr; |
| | | } |
| | | }); |
| | | |
| | | // 搜索 |
| | | form.on('submit(search)', function (data) { |
| | | pageCurr = 1; |
| | | tableReload(false); |
| | | }); |
| | | |
| | | // 重置 |
| | | form.on('submit(reset)', function (data) { |
| | | pageCurr = 1; |
| | | clearFormVal($('#search-box')); |
| | | // 手动清空日期范围选择器 |
| | | $('input[name="date_range"]').val(''); |
| | | // 显式清空表格配置中的 where 参数 |
| | | if (tableIns && tableIns.config) { |
| | | tableIns.config.where = {}; |
| | | } |
| | | // 使用 setTimeout 确保表单值被完全清空后再重新加载表格 |
| | | setTimeout(function() { |
| | | tableReload(false); |
| | | }, 0); |
| | | }); |
| | | |
| | | // 日期范围选择器 |
| | | layDate.render({ |
| | | elem: '.layui-laydate-range', |
| | | type: 'date', |
| | | range: true |
| | | }); |
| | | |
| | | // 发起月结 |
| | | $('#startSettleBtn').click(function () { |
| | | showStartSettleDialog(); |
| | | }); |
| | | |
| | | // 显示发起月结弹窗 |
| | | function showStartSettleDialog() { |
| | | admin.open({ |
| | | type: 1, |
| | | title: '发起月结', |
| | | content: $('#startSettleDialog').html(), |
| | | area: '500px', |
| | | success: function (layero, dIndex) { |
| | | var startDateIns = null; |
| | | var endDateIns = null; |
| | | |
| | | // 初始化结束日期选择器(先初始化,后续再设置min) |
| | | // 使用 setTimeout 确保 DOM 已完全渲染 |
| | | setTimeout(function() { |
| | | var $endDate = layero.find('#endDate'); |
| | | if ($endDate.length > 0) { |
| | | endDateIns = layDate.render({ |
| | | elem: $endDate[0], |
| | | type: 'date', |
| | | done: function(value, date, endDate){ |
| | | var startDate = layero.find('#startDate').val(); |
| | | if (startDate && value < startDate) { |
| | | layer.msg('结束日期不能早于起始日期', {icon: 2}); |
| | | layero.find('#endDate').val(''); |
| | | checkUnfinishedOrders(startDate, ''); |
| | | return; |
| | | } |
| | | checkUnfinishedOrders(startDate, value); |
| | | } |
| | | }); |
| | | } |
| | | }, 50); |
| | | |
| | | // 获取下一个月结的起始日期(最晚月结记录结束日期的下一天) |
| | | $.ajax({ |
| | | url: baseUrl + '/monthlySettle/nextStartDate/auth', |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | if (res.code === 200) { |
| | | // 数据在 msg 字段中 |
| | | var nextStartDate = res.msg; |
| | | // 确保 nextStartDate 是字符串格式 |
| | | if (nextStartDate != null && nextStartDate !== '') { |
| | | // 转换为字符串,处理可能的数字或其他类型 |
| | | nextStartDate = String(nextStartDate).trim(); |
| | | if (nextStartDate !== '' && nextStartDate !== 'null') { |
| | | // 使用 setTimeout 确保 DOM 已完全渲染 |
| | | setTimeout(function() { |
| | | // 使用 layero.find 查找弹窗内的元素 |
| | | var $startDate = layero.find('#startDate'); |
| | | if ($startDate.length > 0) { |
| | | $startDate.val(nextStartDate); |
| | | $startDate.attr('readonly', true); |
| | | $startDate.css('background-color', '#f5f5f5'); |
| | | $startDate.css('cursor', 'not-allowed'); |
| | | console.log('已设置起始日期:', $startDate.val()); |
| | | } else { |
| | | console.error('未找到 #startDate 元素'); |
| | | } |
| | | }, 50); |
| | | |
| | | // 获取最晚结束日期用于提示 |
| | | $.ajax({ |
| | | url: baseUrl + '/monthlySettle/latestEndDate/auth', |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | method: 'POST', |
| | | success: function (latestRes) { |
| | | var latestEndDate = (latestRes.code === 200 && latestRes.msg) ? String(latestRes.msg) : ''; |
| | | var tipMsg = latestEndDate |
| | | ? '提示:最晚月结记录结束日期为 ' + latestEndDate + ',本次月结起始日期已自动设置为 ' + nextStartDate + ',不可修改' |
| | | : '提示:本次月结起始日期已自动设置为 ' + nextStartDate + ',不可修改'; |
| | | layero.find('#settleTip').html(tipMsg); |
| | | }, |
| | | error: function() { |
| | | layero.find('#settleTip').html('提示:本次月结起始日期已自动设置为 ' + nextStartDate + ',不可修改'); |
| | | } |
| | | }); |
| | | |
| | | // 重新渲染结束日期选择器,设置最小日期为起始日期 |
| | | setTimeout(function() { |
| | | endDateIns = layDate.render({ |
| | | elem: layero.find('#endDate')[0], |
| | | type: 'date', |
| | | min: nextStartDate, |
| | | done: function(value, date, endDate){ |
| | | var startDate = layero.find('#startDate').val(); |
| | | if (startDate && value < startDate) { |
| | | layer.msg('结束日期不能早于起始日期', {icon: 2}); |
| | | layero.find('#endDate').val(''); |
| | | checkUnfinishedOrders(startDate, ''); |
| | | return; |
| | | } |
| | | checkUnfinishedOrders(startDate, value); |
| | | } |
| | | }); |
| | | }, 100); |
| | | } |
| | | } else { |
| | | // 没有月结记录,允许自由选择起始日期 |
| | | setTimeout(function() { |
| | | var $startDate = layero.find('#startDate'); |
| | | if ($startDate.length > 0) { |
| | | startDateIns = layDate.render({ |
| | | elem: $startDate[0], |
| | | type: 'date', |
| | | done: function(value, date, endDate){ |
| | | // 当起始日期改变时,重新渲染结束日期选择器,设置最小日期 |
| | | var currentEndDate = layero.find('#endDate').val(); |
| | | if (currentEndDate && currentEndDate < value) { |
| | | layero.find('#endDate').val(''); |
| | | layero.find('#settleTip').html('<span style="color: #ff5722;">警告:结束日期不能早于起始日期,请重新选择结束日期</span>'); |
| | | } |
| | | |
| | | // 重新渲染结束日期选择器 |
| | | endDateIns = layDate.render({ |
| | | elem: layero.find('#endDate')[0], |
| | | type: 'date', |
| | | min: value, |
| | | done: function(endValue, endDate, endEndDate){ |
| | | if (value && endValue < value) { |
| | | layer.msg('结束日期不能早于起始日期', {icon: 2}); |
| | | layero.find('#endDate').val(''); |
| | | checkUnfinishedOrders(value, ''); |
| | | return; |
| | | } |
| | | checkUnfinishedOrders(value, endValue); |
| | | } |
| | | }); |
| | | |
| | | checkUnfinishedOrders(value, layero.find('#endDate').val()); |
| | | } |
| | | }); |
| | | layero.find('#settleTip').html('提示:首次月结,请选择起始日期'); |
| | | } |
| | | }, 50); |
| | | } |
| | | } else if (res.code === 403) { |
| | | top.location.href = baseUrl + "/"; |
| | | } |
| | | }, |
| | | error: function() { |
| | | // 如果获取失败,允许自由选择起始日期 |
| | | setTimeout(function() { |
| | | var $startDate = layero.find('#startDate'); |
| | | if ($startDate.length > 0) { |
| | | startDateIns = layDate.render({ |
| | | elem: $startDate[0], |
| | | type: 'date', |
| | | done: function(value, date, endDate){ |
| | | var currentEndDate = layero.find('#endDate').val(); |
| | | if (currentEndDate && currentEndDate < value) { |
| | | layero.find('#endDate').val(''); |
| | | layero.find('#settleTip').html('<span style="color: #ff5722;">警告:结束日期不能早于起始日期,请重新选择结束日期</span>'); |
| | | } |
| | | |
| | | endDateIns = layDate.render({ |
| | | elem: layero.find('#endDate')[0], |
| | | type: 'date', |
| | | min: value, |
| | | done: function(endValue, endDate, endEndDate){ |
| | | if (value && endValue < value) { |
| | | layer.msg('结束日期不能早于起始日期', {icon: 2}); |
| | | layero.find('#endDate').val(''); |
| | | checkUnfinishedOrders(value, ''); |
| | | return; |
| | | } |
| | | checkUnfinishedOrders(value, endValue); |
| | | } |
| | | }); |
| | | |
| | | checkUnfinishedOrders(value, layero.find('#endDate').val()); |
| | | } |
| | | }); |
| | | layero.find('#settleTip').html('提示:请选择起始日期'); |
| | | } |
| | | }, 50); |
| | | } |
| | | }); |
| | | |
| | | // 表单提交事件 |
| | | form.on('submit(startSettleSubmit)', function (data) { |
| | | var startDate = layero.find('#startDate').val(); |
| | | var endDate = layero.find('#endDate').val(); |
| | | |
| | | if (!startDate || !endDate) { |
| | | layer.msg('请选择起始日期和结束日期', {icon: 2}); |
| | | return false; |
| | | } |
| | | |
| | | if (startDate > endDate) { |
| | | layer.msg('结束日期不能早于起始日期,请重新选择', {icon: 2}); |
| | | return false; |
| | | } |
| | | |
| | | // 将结束日期设置为当天的 23:59:59 |
| | | var endDateTime = endDate + ' 23:59:59'; |
| | | |
| | | layer.load(2); |
| | | $.ajax({ |
| | | url: baseUrl + '/monthlySettle/start/auth', |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | data: { |
| | | startDate: startDate, |
| | | endDate: endDateTime |
| | | }, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | layer.closeAll('loading'); |
| | | if (res.code === 200) { |
| | | layer.close(dIndex); |
| | | tableIns.reload({page: {curr: 1}}); |
| | | layer.msg(res.msg || '月结成功', {icon: 1}); |
| | | } else if (res.code === 403) { |
| | | top.location.href = baseUrl + "/"; |
| | | } else { |
| | | layer.msg(res.msg || '月结失败', {icon: 2}); |
| | | } |
| | | }, |
| | | error: function() { |
| | | layer.closeAll('loading'); |
| | | layer.msg('月结请求失败', {icon: 2}); |
| | | } |
| | | }); |
| | | return false; |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 检查未完成的订单 |
| | | function checkUnfinishedOrders(startDate, endDate) { |
| | | if (!startDate && !endDate) { |
| | | $('#settleTip').html('<span style="color: #999;">请选择起始日期和结束日期</span>'); |
| | | return; |
| | | } |
| | | |
| | | if (!startDate) { |
| | | $('#settleTip').html('<span style="color: #999;">请选择起始日期</span>'); |
| | | return; |
| | | } |
| | | |
| | | if (!endDate) { |
| | | $('#settleTip').html('<span style="color: #999;">请选择结束日期</span>'); |
| | | return; |
| | | } |
| | | |
| | | // 验证日期范围 |
| | | if (startDate > endDate) { |
| | | $('#settleTip').html('<span style="color: #ff5722;">警告:结束日期不能早于起始日期,请重新选择</span>'); |
| | | return; |
| | | } |
| | | |
| | | $.ajax({ |
| | | url: baseUrl + '/monthlySettle/checkUnfinished/auth', |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | data: { |
| | | startDate: startDate, |
| | | endDate: endDate |
| | | }, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | if (res.code === 200) { |
| | | $('#settleTip').html('<span style="color: #5FB878;">✓ 日期范围有效,可以正常进行月结</span>'); |
| | | } else { |
| | | $('#settleTip').html('<span style="color: #ff5722;">警告:' + (res.msg || '月结时间范围内存在未完成的订单,无法进行月结') + '</span>'); |
| | | } |
| | | }, |
| | | error: function() { |
| | | $('#settleTip').html('<span style="color: #ff5722;">检查失败,请重试</span>'); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 工具条点击事件 |
| | | table.on('tool(monthlySettle)', function (obj) { |
| | | var data = obj.data; |
| | | var layEvent = obj.event; |
| | | if (layEvent === 'detail') { |
| | | showDetailDialog(data); |
| | | } else if (layEvent === 'delete') { |
| | | deleteSettle(data); |
| | | } |
| | | }); |
| | | |
| | | // 显示明细弹窗 |
| | | function showDetailDialog(data) { |
| | | layer.load(2); |
| | | $.ajax({ |
| | | url: baseUrl + '/monthlySettle/statistics/' + data.id + '/auth', |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | layer.closeAll('loading'); |
| | | if (res.code === 200) { |
| | | var settle = res.data.settle; |
| | | var details = res.data.details; |
| | | |
| | | // 先渲染模板 |
| | | var template = $('#detailDialog').html(); |
| | | var html = laytpl(template).render(settle); |
| | | |
| | | admin.open({ |
| | | type: 1, |
| | | title: '月结明细 - ' + settle.settleNo, |
| | | content: html, |
| | | area: ['90%', '80%'], |
| | | success: function (layero, dIndex) { |
| | | // 渲染明细表格(对账单格式) |
| | | table.render({ |
| | | elem: '#detailTable', |
| | | data: details, |
| | | page: true, |
| | | cellMinWidth: 100, |
| | | cols: [[ |
| | | {type: 'numbers', title: '序号', width: 60, align: 'center'}, |
| | | {field: 'matnr', title: '物料编码', width: 150}, |
| | | {field: 'maktx', title: '物料名称', width: 200}, |
| | | {field: 'batch', title: '批次', width: 120}, |
| | | {field: 'brand', title: '品牌', width: 120}, |
| | | { |
| | | field: 'beginningQty', |
| | | align: 'right', |
| | | title: '期初库存', |
| | | width: 120, |
| | | templet: function (d) { |
| | | var qty = parseFloat(d.beginningQty || 0); |
| | | return qty.toFixed(2); |
| | | } |
| | | }, |
| | | { |
| | | field: 'inQty', |
| | | align: 'right', |
| | | title: '本期入库', |
| | | width: 120, |
| | | templet: function (d) { |
| | | var qty = parseFloat(d.inQty || 0); |
| | | return qty.toFixed(2); |
| | | } |
| | | }, |
| | | { |
| | | field: 'outQty', |
| | | align: 'right', |
| | | title: '本期出库', |
| | | width: 120, |
| | | templet: function (d) { |
| | | var qty = parseFloat(d.outQty || 0); |
| | | return qty.toFixed(2); |
| | | } |
| | | }, |
| | | { |
| | | field: 'endingQty', |
| | | align: 'right', |
| | | title: '期末库存', |
| | | width: 120, |
| | | templet: function (d) { |
| | | var qty = parseFloat(d.endingQty || 0); |
| | | return qty.toFixed(2); |
| | | } |
| | | }, |
| | | { |
| | | field: 'stockQty', |
| | | align: 'right', |
| | | title: '实际库存', |
| | | width: 120, |
| | | templet: function (d) { |
| | | var qty = parseFloat(d.stockQty || 0); |
| | | return qty.toFixed(2); |
| | | } |
| | | }, |
| | | { |
| | | field: 'diffQty', |
| | | align: 'right', |
| | | title: '差异数量', |
| | | width: 120, |
| | | templet: function (d) { |
| | | var diff = parseFloat(d.diffQty || 0); |
| | | if (diff > 0) { |
| | | return '<span style="color: #5FB878;">+' + diff.toFixed(2) + '</span>'; |
| | | } else if (diff < 0) { |
| | | return '<span style="color: #ff5722;">' + diff.toFixed(2) + '</span>'; |
| | | } else { |
| | | return diff.toFixed(2); |
| | | } |
| | | } |
| | | } |
| | | ]] |
| | | }); |
| | | } |
| | | }); |
| | | } else if (res.code === 403) { |
| | | top.location.href = baseUrl + "/"; |
| | | } else { |
| | | layer.msg(res.msg || '获取明细失败', {icon: 2}); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 删除月结记录 |
| | | function deleteSettle(data) { |
| | | layer.confirm('确认要删除月结记录 "' + data.settleNo + '" 吗?删除后将清除关联的出入库订单月结信息,可以重新进行月结。', { |
| | | shade: .1, |
| | | skin: 'layui-layer-admin' |
| | | }, function (i) { |
| | | layer.close(i); |
| | | layer.load(2); |
| | | $.ajax({ |
| | | url: baseUrl + '/monthlySettle/' + data.id + '/auth', |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | method: 'DELETE', |
| | | success: function (res) { |
| | | layer.closeAll('loading'); |
| | | if (res.code === 200) { |
| | | tableIns.reload({page: {curr: 1}}); |
| | | layer.msg(res.msg || '删除成功', {icon: 1}); |
| | | } else if (res.code === 403) { |
| | | top.location.href = baseUrl + "/"; |
| | | } else { |
| | | layer.msg(res.msg || '删除失败', {icon: 2}); |
| | | } |
| | | }, |
| | | error: function() { |
| | | layer.closeAll('loading'); |
| | | layer.msg('删除失败', {icon: 2}); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | function tableReload(child) { |
| | | var searchData = {}; |
| | | $.each($('#search-box [name]').serializeArray(), function() { |
| | | var value = this.value; |
| | | // 处理日期范围字段 |
| | | if (this.name === 'date_range') { |
| | | // 只处理非空值 |
| | | if (value && value.trim() !== '') { |
| | | var dates = value.split(' - '); |
| | | if (dates.length === 2) { |
| | | var startDate = dates[0].trim(); |
| | | var endDate = dates[1].trim(); |
| | | if (startDate !== '' && endDate !== '') { |
| | | searchData.startDate = startDate; |
| | | searchData.endDate = endDate; |
| | | } |
| | | } |
| | | } |
| | | } else if (this.name === 'settle_no') { |
| | | // 只处理非空值 |
| | | var trimmedValue = value ? value.trim() : ''; |
| | | if (trimmedValue !== '') { |
| | | searchData.settleNo = trimmedValue; |
| | | } |
| | | } |
| | | }); |
| | | debugger; // 调试用:检查 searchData 的值 |
| | | |
| | | // 获取 table 实例 |
| | | var tableInstance = child ? parent.tableIns : tableIns; |
| | | |
| | | // 如果 searchData 为空对象,需要显式传入覆盖所有可能参数的对象 |
| | | // 因为 layui table 可能会合并旧的参数,即使传入空对象也可能保留旧值 |
| | | if (Object.keys(searchData).length === 0) { |
| | | if (tableInstance && tableInstance.config) { |
| | | // 先保存旧的 where 中可能存在的所有键 |
| | | var oldWhereKeys = []; |
| | | if (tableInstance.config.where) { |
| | | for (var key in tableInstance.config.where) { |
| | | if (tableInstance.config.where.hasOwnProperty(key)) { |
| | | oldWhereKeys.push(key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 完全替换 where 对象 |
| | | tableInstance.config.where = {}; |
| | | |
| | | // 如果之前有参数,创建一个明确覆盖的对象,将所有旧参数设置为空字符串 |
| | | // 使用空字符串而不是 null,因为 layui 可能会过滤 null 值 |
| | | if (oldWhereKeys.length > 0) { |
| | | var overrideWhere = {}; |
| | | oldWhereKeys.forEach(function(key) { |
| | | overrideWhere[key] = ''; // 设置为空字符串来覆盖旧值 |
| | | }); |
| | | searchData = overrideWhere; |
| | | console.log('创建覆盖对象,旧参数键:', oldWhereKeys, '覆盖对象:', JSON.stringify(overrideWhere)); |
| | | } else { |
| | | // 即使没有旧参数,也创建一个包含所有可能参数的空对象 |
| | | // 这样可以确保覆盖任何可能的旧参数 |
| | | searchData = { |
| | | settleNo: '', |
| | | startDate: '', |
| | | endDate: '' |
| | | }; |
| | | console.log('创建默认覆盖对象:', JSON.stringify(searchData)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 构建 reload 参数 |
| | | var reloadOptions = { |
| | | where: searchData, |
| | | page: { |
| | | curr: pageCurr |
| | | }, |
| | | done: function (res, curr, count) { |
| | | if (res.code === 403) { |
| | | top.location.href = baseUrl+"/"; |
| | | } |
| | | pageCurr=curr; |
| | | if (res.data.length === 0 && count !== 0) { |
| | | var reloadTableInstance = child ? parent.tableIns : tableIns; |
| | | // 如果 searchData 为空,也完全替换 where 对象 |
| | | if (Object.keys(searchData).length === 0 && reloadTableInstance && reloadTableInstance.config) { |
| | | reloadTableInstance.config.where = {}; |
| | | } |
| | | reloadTableInstance.reload({ |
| | | where: searchData, |
| | | page: { |
| | | curr: pageCurr-1 |
| | | } |
| | | }); |
| | | pageCurr -= 1; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 调试:打印 reload 前的配置 |
| | | console.log('reload 前的 config.where:', JSON.stringify(tableInstance.config ? tableInstance.config.where : 'no config')); |
| | | console.log('reload 时的 where 参数:', JSON.stringify(reloadOptions.where)); |
| | | |
| | | tableInstance.reload(reloadOptions); |
| | | |
| | | // 调试:打印 reload 后的配置 |
| | | setTimeout(function() { |
| | | console.log('reload 后的 config.where:', JSON.stringify(tableInstance.config ? tableInstance.config.where : 'no config')); |
| | | }, 100); |
| | | } |
| New file |
| | |
| | | <!DOCTYPE html> |
| | | <html lang="en"> |
| | | <head> |
| | | <meta charset="utf-8"> |
| | | <title>月结管理</title> |
| | | <meta name="renderer" content="webkit"> |
| | | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> |
| | | <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all"> |
| | | <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all"> |
| | | <link rel="stylesheet" href="../../static/css/cool.css" media="all"> |
| | | </head> |
| | | <body> |
| | | |
| | | <div class="layui-fluid"> |
| | | <div class="layui-card"> |
| | | <div class="layui-card-body"> |
| | | <div class="layui-form toolbar" id="search-box"> |
| | | <div class="layui-form-item"> |
| | | <div class="layui-inline"> |
| | | <div class="layui-input-inline mr0"> |
| | | <input name="settle_no" class="layui-input" type="text" placeholder="输入月结编号"/> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline" style="width: 300px"> |
| | | <div class="layui-input-inline"> |
| | | <input class="layui-input layui-laydate-range" name="date_range" type="text" placeholder="起始日期 - 结束日期" autocomplete="off" style="width: 300px"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline"> |
| | | <button class="layui-btn icon-btn" lay-filter="search" lay-submit> |
| | | <i class="layui-icon"></i>搜索 |
| | | </button> |
| | | <button id="startSettleBtn" class="layui-btn icon-btn layui-btn-normal"> |
| | | <i class="layui-icon"></i>发起月结 |
| | | </button> |
| | | <button type="button" class="layui-btn icon-btn layui-btn-primary" lay-filter="reset" lay-submit> |
| | | <i class="layui-icon"></i>重置 |
| | | </button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <table class="layui-hide" id="monthlySettle" lay-filter="monthlySettle" ></table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 表格操作列 --> |
| | | <script type="text/html" id="operate"> |
| | | <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看明细</a> |
| | | <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delete">删除</a> |
| | | </script> |
| | | |
| | | <!-- 发起月结弹窗 --> |
| | | <script type="text/html" id="startSettleDialog"> |
| | | <form id="startSettleForm" lay-filter="startSettleForm" class="layui-form model-form"> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label">起始日期:</label> |
| | | <div class="layui-input-block"> |
| | | <input id="startDate" name="startDate" placeholder="选择起始日期" type="text" class="layui-input" autocomplete="off" lay-verType="tips" lay-verify="required"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label">结束日期:</label> |
| | | <div class="layui-input-block"> |
| | | <input id="endDate" name="endDate" placeholder="选择结束日期" type="text" class="layui-input" autocomplete="off" lay-verType="tips" lay-verify="required"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label">提示:</label> |
| | | <div class="layui-input-block"> |
| | | <div id="settleTip" style="color: #ff5722;"></div> |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item text-right"> |
| | | <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> |
| | | <button class="layui-btn" lay-filter="startSettleSubmit" lay-submit>确认月结</button> |
| | | </div> |
| | | </form> |
| | | </script> |
| | | |
| | | <!-- 月结明细弹窗 --> |
| | | <script type="text/html" id="detailDialog"> |
| | | <div style="padding: 20px;"> |
| | | <div class="layui-row"> |
| | | <div class="layui-col-md6"> |
| | | {{# if(d.settleNo) { }} |
| | | <p><strong>月结编号:</strong>{{ d.settleNo }}</p> |
| | | {{# } }} |
| | | {{# if(d.startDate$) { }} |
| | | <p><strong>起始日期:</strong>{{ d.startDate$ }}</p> |
| | | {{# } }} |
| | | {{# if(d.endDate$) { }} |
| | | <p><strong>结束日期:</strong>{{ d.endDate$ }}</p> |
| | | {{# } }} |
| | | </div> |
| | | <div class="layui-col-md6"> |
| | | {{# if(d.totalInQty !== null && d.totalInQty !== undefined) { }} |
| | | <p><strong>总入库数量:</strong>{{ d.totalInQty }}</p> |
| | | {{# } }} |
| | | {{# if(d.totalOutQty !== null && d.totalOutQty !== undefined) { }} |
| | | <p><strong>总出库数量:</strong>{{ d.totalOutQty }}</p> |
| | | {{# } }} |
| | | {{# if(d.totalMaterials !== null && d.totalMaterials !== undefined) { }} |
| | | <p><strong>物料种类数:</strong>{{ d.totalMaterials }}</p> |
| | | {{# } }} |
| | | </div> |
| | | </div> |
| | | <hr class="layui-bg-gray"> |
| | | <table id="detailTable" lay-filter="detailTable"></table> |
| | | </div> |
| | | </script> |
| | | |
| | | <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> |
| | | <script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script> |
| | | <script type="text/javascript" src="../../static/js/monthlySettle/monthlySettle.js" charset="utf-8"></script> |
| | | </body> |
| | | </html> |
| | | |
| | | |