Commit c5829391 by yubin

Merge remote-tracking branch 'origin/master'

parents 4830f5a8 eb21f58e
......@@ -8,11 +8,14 @@ import com.scpyun.base.db.service.CommonService;
import com.scpyun.base.utils.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
......@@ -45,14 +48,36 @@ public class KeyDmBorrowServiceImpl {
if (map == null) map = new HashMap<>();
return commonService.findPage(namespace + "selectHistoryList", map);
}
@Transactional(rollbackFor = Exception.class)
@ApiOperation(value = "保存申请(含明细)", desc = "新增或修改申请")
public String save(Map<String, Object> map) {
if (map == null) throw new CustomException("参数不能为空");
System.out.println(map);
Object id = map.get("id");
List<Map<String, Object>> details = (List<Map<String, Object>>) map.get("details");
Map<String, Object> user = (Map<String, Object>) map.get("_user");
//日期格式转换
// 日期格式转换:兼容 2025-12-26 和 2025-12-25T16:00:00.000Z 两种格式
String dateStr = (String) map.get("expected_return_date");
Date expected_return_date = null;
if (dateStr != null && !dateStr.trim().isEmpty()) {
try {
if (dateStr.contains("T") || dateStr.contains("Z")) {
// 处理带时区的ISO格式:转换为东八区日期
DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_INSTANT;
Instant instant = Instant.parse(dateStr);
// 转换为东八区的LocalDate
LocalDate localDate = instant.atZone(ZoneId.of("Asia/Shanghai")).toLocalDate();
expected_return_date = java.sql.Date.valueOf(localDate);
} else {
// 处理纯日期格式(2025-12-26)
LocalDate localDate = LocalDate.parse(dateStr);
expected_return_date = java.sql.Date.valueOf(localDate);
}
} catch (DateTimeParseException e) {
throw new CustomException("日期格式错误,支持格式:2025-12-26 或 2025-12-26T16:00:00.000Z");
}
}
map.put("expected_return_date", expected_return_date);
if (id == null || String.valueOf(id).trim().isEmpty()) {
map.put("id",UUID.randomUUID().toString());
map.put("application_no","borrow");
......@@ -60,15 +85,10 @@ public class KeyDmBorrowServiceImpl {
map.put("applicant_name", user.get("name"));
map.put("department_id", user.get("company_id"));
map.put("department_name", user.get("company_name"));
//日期格式转换
Instant instant = Instant.parse((String) map.get("expected_return_date"));
LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
Date expected_return_date = java.sql.Date.valueOf(localDate);
map.put("expected_return_date",expected_return_date);
map.put("approval_status", 0);
map.put("issue_status", 0);
map.put("order_no", 0);
System.out.println(map);
// insert application
if (commonService.insert(namespace + "insert", map) != 1) throw new CustomException("保存失败");
// insert details if any
......@@ -83,8 +103,6 @@ public class KeyDmBorrowServiceImpl {
int aff = commonService.update(namespace + "update", map);
if (aff < 0) throw new CustomException("保存失败");
// for simplicity, delete old details and insert new
System.out.println("---------------------------------------------");
System.out.println(id);
commonService.delete(namespace + "deleteDetailsByApplicationId", map);
if (details != null) {
for (Map<String, Object> d : details) {
......@@ -112,19 +130,105 @@ public class KeyDmBorrowServiceImpl {
return SUCCESS;
}
// 开启事务,发生异常时全量回滚
@Transactional(rollbackFor = Exception.class)
@ApiOperation(value = "审批通过", desc = "审批通过并生成出库,更新库存与日志")
public String approve(Map<String, Object> map) {
if (map == null || map.get("id") == null) throw new CustomException("参数缺失");
// 设置申请为通过
// 1. 严格参数校验
if (map == null || map.get("id") == null || map.get("id").toString().trim().isEmpty()) {
throw new CustomException("参数缺失:申请ID不能为空");
}
// 2. 更新审批状态为通过
int aff = commonService.update(namespace + "approve", map);
if (aff < 0) throw new CustomException("审批失败");
// 生成出库记录(mapper 实现)
// 受影响行数为0代表未找到对应申请,判定为审批失败
if (aff == 0) {
throw new CustomException("审批失败:未找到ID为" + map.get("id") + "的申请记录");
}
// 3. 生成出库记录
commonService.insert(namespace + "insertOutboundByApplication", map);
// 更新库存(mapper 内部处理)
commonService.update(namespace + "updateInventoryByApplication", map);
// 写操作日志(mapper 内部处理)
commonService.insert(namespace + "insertMaterialLogByApplication", map);
return SUCCESS;
commonService.insert(namespace + "insertOutboundDetail", map);
// 4. 获取申领明细
Map<String, Object> detailItemsMap = getById(map);
List<Map<String, Object>> detailsList = (List<Map<String, Object>>) detailItemsMap.get("details");
// 校验明细列表非空
if (detailsList == null || detailsList.isEmpty()) {
throw new CustomException("审批失败:该申请无物料申领明细");
}
StringBuffer sb = new StringBuffer();
// 遍历处理每个物料
for (Map<String, Object> details : detailsList) {
if (details == null || details.get("material_id") == null) {
sb.append("物料明细为空,已跳过处理;");
continue;
}
// 5. 查询物料库存信息
Map<String, Object> inventoryMap = commonService.getObject(namespace + "selectInventoryByMaterialId", details);
if (inventoryMap == null) {
String materialName = (String) details.get("material_name");
sb.append((materialName == null ? "未知物料" : materialName) + "无库存信息,已跳过申领;");
continue;
}
// 6. 空值处理:获取库存相关字段,默认值为0
int totalQuantity = getIntValue(inventoryMap, "total_quantity");
int borrowedQuantity = getIntValue(inventoryMap, "borrowed_quantity");
int damagedQuantity = getIntValue(inventoryMap, "damaged_quantity");
int borrowQuantity = getIntValue(details, "apply_quantity");
String materialName = (String) details.get("material_name");
materialName = materialName == null ? "未知物料" : materialName;
// 7. 判断是否为消耗品(can_borrow=0 为消耗品,其他为非消耗品)
int canBorrow = getIntValue(inventoryMap, "can_borrow");
int remainQuantity; // 剩余可申领数量
String updateSqlId; // 库存更新的SQL ID
if (canBorrow == 0) {
// 消耗品:总库存 - 本次申领数量
remainQuantity = totalQuantity - borrowQuantity;
updateSqlId = namespace + "updateInventoryTotalQuantity";
} else {
// 非消耗品:总库存 - 已借 - 损坏 - 本次申领
remainQuantity = totalQuantity - borrowedQuantity - damagedQuantity - borrowQuantity;
updateSqlId = namespace + "updateInventoryBorrowedQuantity";
}
// 8. 库存校验与扣减
if (remainQuantity > 0 && borrowQuantity > 0) {
int row = commonService.update(updateSqlId, details);
if (row > 0) {
sb.append(materialName + "申领成功,库存已扣减;");
} else {
sb.append(materialName + "申领失败:库存扣减操作未生效;");
}
} else {
sb.append(materialName + "该物料库存不足(剩余可申领:" + remainQuantity + "),已跳过申领;");
}
}
// 插入日志:传当前物料的明细,而非整个申请的明细
detailItemsMap.put("op_type", 2);
commonService.insert(materialNamespace + "insertLog", detailItemsMap);
return sb.toString();
}
// 工具方法:安全获取Map中的int值,避免空指针和类型转换异常
private int getIntValue(Map<String, Object> map, String key) {
if (map == null || map.get(key) == null) {
return 0;
}
Object value = map.get(key);
if (value instanceof Integer) {
return (Integer) value;
}
try {
return Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
return 0;
}
}
@ApiOperation(value = "审批驳回", desc = "审批驳回,需保存意见")
......@@ -143,11 +247,9 @@ public class KeyDmBorrowServiceImpl {
ret.putAll(app == null ? new HashMap<>() : app);
List<Map<String, Object>> details = commonService.findList(detailNamespace + "selectDetailsByApplicationId", map);
ret.put("details", details == null ? new java.util.ArrayList<>() : details);
System.out.println(ret);
// logs from material log by application relation
List<Map<String, Object>> logs = commonService.findList(materialNamespace + "selectLogsByApplicationId", map);
ret.put("logs", logs == null ? new java.util.ArrayList<>() : logs);
System.out.println(ret);
return ret;
}
}
......
......@@ -38,6 +38,11 @@ public class KeyDmUserCategoryServiceImpl {
return commonService.findList(namespace + "selectPermissionConfigList", null);
}
@ApiOperation(value = "获取人员权限配置列表", desc = "从字典获取权限并关联用户")
public List<Map<String, Object>> selectUserDmPermissionList(Map<String, Object> map) {
return commonService.findList(namespace + "selectUserDmPermissionList", map);
}
@ApiOperation(value = "保存权限用户配置", desc = "保存权限对应的用户配置")
public String savePermissionUsers(Map<String, Object> map) {
if (map == null || map.get("permission_code") == null) {
......
......@@ -12,7 +12,7 @@
<if test="params.params.application_no != null and params.params.application_no != ''">
AND application_no LIKE CONCAT('%', #{params.params.application_no}, '%')
</if>
<if test="params.params.approval_status != null and params.params.approval_status != ''">
<if test="params.params.approval_status != null">
AND approval_status = #{params.params.approval_status}
</if>
</where>
......@@ -74,7 +74,7 @@
</update>
<update id="approve" parameterType="map">
UPDATE jl_key_dm_borrow_application SET approval_status = 9, approval_time = NOW(), issue_status = 1, update_by = #{_user.id}, update_time = NOW() WHERE id = #{id}
UPDATE jl_key_dm_borrow_application SET approval_status = 9, approval_time = NOW(), issue_time = NOW(), issue_status = 1, update_by = #{_user.id}, update_time = NOW() WHERE id = #{id}
</update>
<update id="reject" parameterType="map">
......@@ -94,16 +94,37 @@
FROM jl_key_dm_borrow_application WHERE id = #{id}
</insert>
<select id="selectInventoryByMaterialId" parameterType="map" resultType="map">
select i.*,m.can_borrow
from jl_key_dm_inventory as i
left join jl_key_dm_material as m
on m.id = i.material_id
where material_id = #{material_id}
</select>
<!-- 更新库存:根据申请明细扣减可用库存(mapper 内部实现以事务执行) -->
<update id="updateInventoryTotalQuantity" parameterType="map">
<!-- 简化:调用存储过程或在 mapper 中实现逐条更新 -->
<!-- 实际实现依赖于业务,留给 mapper/服务调用具体 SQL -->
update jl_key_dm_inventory
set total_quantity = total_quantity - #{apply_quantity}
where material_id = #{material_id}
</update>
<!-- 更新库存:根据申请明细扣减可用库存(mapper 内部实现以事务执行) -->
<update id="updateInventoryByApplication" parameterType="map">
<update id="updateInventoryBorrowedQuantity" parameterType="map">
<!-- 简化:调用存储过程或在 mapper 中实现逐条更新 -->
<!-- 实际实现依赖于业务,留给 mapper/服务调用具体 SQL -->
update jl_key_dm_inventory set
update jl_key_dm_inventory
set borrowed_quantity = borrowed_quantity + #{apply_quantity}
where material_id = #{material_id}
</update>
<!-- 插入日志 -->
<insert id="insertMaterialLogByApplication" parameterType="map">
<!-- 简化:实现者可在业务层调用单条插入,此处为占位 -->
insert into jl_key_dm_material_log()
</insert>
<select id="selectLogsByApplicationId" parameterType="map">
......
......@@ -11,7 +11,11 @@
</insert>
<select id="selectDetailsByApplicationId" parameterType="map" resultType="map">
SELECT * FROM jl_key_dm_borrow_application_detail WHERE application_id = #{id} AND is_used = 1 ORDER BY create_time ASC
SELECT bd.*,m.category_id
FROM jl_key_dm_borrow_application_detail as bd
left join jl_key_dm_material as m
on m.id = bd.material_id
WHERE bd.application_id = #{id} AND bd.is_used = 1 ORDER BY bd.create_time ASC
</select>
</mapper>
......
......@@ -111,7 +111,11 @@
</insert>
<select id="selectLogsByInboundId" parameterType="map" resultType="map">
SELECT * FROM jl_key_dm_material_log WHERE relation_id = #{id} AND is_used = 1 ORDER BY create_time ASC
SELECT ml.*,m.material_name
FROM jl_key_dm_material_log as ml
left join jl_key_dm_material as m
on m.id = ml.material_id
WHERE ml.relation_id = #{id} AND ml.is_used = 1 ORDER BY ml.create_time ASC
</select>
</mapper>
......
......@@ -8,13 +8,18 @@
) VALUES
<foreach collection="details" item="item" separator=",">
(
UUID(),#{item.category_id},#{item.id},1,#{item.inbound_id},#{item.id},#{item.inbound_quantity},#{item.unit_price},#{item.total_amount},1,#{_user.id},NOW()
UUID(),#{item.category_id},#{item.material_id},#{op_type},#{id},#{item.material_id},#{item.apply_quantity},#{item.unit_price},#{item.total_amount},1,#{create_by},NOW()
)
</foreach>
</insert>
<select id="selectLogsByApplicationId" parameterType="map" resultType="map">
SELECT * FROM jl_key_dm_material_log WHERE relation_id = #{id} AND is_used = 1 ORDER BY create_time ASC
SELECT ml.*,m.material_name
FROM jl_key_dm_material_log as ml
left join jl_key_dm_material as m
on ml.material_id = m.id
WHERE relation_id = #{id}
AND ml.is_used = 1 ORDER BY ml.create_time ASC
</select>
</mapper>
......
......@@ -78,17 +78,19 @@
SELECT l.user_id AS uid, l.user_name AS uname, 1 AS leave_app, 0 AS leave_approve, 0 AS borrow_app, 0 AS inbound_cnt, COALESCE(l.duration,0) AS leave_duration
FROM jl_key_dm_leave_application l
<where>
AND l.is_used = 1 AND l.STATUS != 0
<if test="start != null and start != ''">
AND l.create_time &gt; #{start}
AND l.start_time &gt; #{start}
</if>
<if test="end != null and end != ''">
AND l.create_time &lt; #{end}
AND l.start_time &lt; #{end}
</if>
</where>
UNION ALL
SELECT r.approver_id AS uid, r.approver_name AS uname, 0, CASE WHEN r.approver_result = 1 THEN 1 ELSE 0 END, 0, 0, 0
FROM jl_key_dm_leave_approval_record r
<where>
AND r.is_used = 1 AND r.STATUS = 2
<if test="start != null and start != ''">
AND r.approver_time &gt; #{start}
</if>
......@@ -100,22 +102,24 @@
SELECT b.applicant_id AS uid, b.applicant_name AS uname, 0, 0, 1, 0, 0
FROM jl_key_dm_borrow_application b
<where>
AND b.is_used = 1 AND b.approval_status != 0
<if test="start != null and start != ''">
AND b.create_time &gt; #{start}
AND b.submit_time &gt; #{start}
</if>
<if test="end != null and end != ''">
AND b.create_time &lt; #{end}
AND b.submit_time &lt; #{end}
</if>
</where>
UNION ALL
SELECT o.receiver_id AS uid, o.receiver_name AS uname, 0, 0, 0, 1, 0
FROM jl_key_dm_outbound_record o
SELECT ir.create_by AS uid, du.`name` AS uname, 0, 0, 0, 1, 0
FROM jl_key_dm_inbound_record ir LEFT JOIN jl_key_dm_user du on ir.create_by = du.id
<where>
AND ir.is_used = 1
<if test="start != null and start != ''">
AND o.create_time &gt; #{start}
AND ir.create_time &gt; #{start}
</if>
<if test="end != null and end != ''">
AND o.create_time &lt; #{end}
AND ir.create_time &lt; #{end}
</if>
</where>
) t
......@@ -127,9 +131,9 @@
<select id="selectWorkloadDetails" parameterType="map" resultType="map">
<choose>
<when test="type == 'leave'">
SELECT id, user_id, user_name, start_time, end_time, duration, reason FROM jl_key_dm_leave_application
SELECT id, user_id, user_name, start_time, end_time, duration, reason, `status` FROM jl_key_dm_leave_application
<where>
AND user_id = #{user_id}
AND user_id = #{user_id} AND STATUS != 0
<if test="start != null and start != ''">
AND create_time &gt; #{start}
</if>
......@@ -140,19 +144,19 @@
ORDER BY create_time DESC
</when>
<when test="type == 'inventory'">
SELECT b.application_no, b.applicant_id, b.applicant_name, d.material_name, d.apply_quantity
SELECT b.application_no, b.applicant_id, b.applicant_name, d.material_name, b.approval_status, d.apply_quantity, d.returned_quantity,b.submit_time
FROM jl_key_dm_borrow_application_detail d
LEFT JOIN jl_key_dm_borrow_application b ON b.id = d.application_id
<where>
b.applicant_id = #{user_id}
AND b.is_used = 1 AND b.approval_status != 0 AND b.applicant_id = #{user_id}
<if test="start != null and start != ''">
AND b.create_time &gt; #{start}
AND b.submit_time &gt; #{start}
</if>
<if test="end != null and end != ''">
AND b.create_time &lt; #{end}
AND b.submit_time &lt; #{end}
</if>
</where>
ORDER BY b.create_time DESC
ORDER BY b.submit_time DESC
</when>
<otherwise>
SELECT 1 AS dummy
......
......@@ -48,6 +48,14 @@
)
</insert>
<!-- 获取人员日常管理权限列表 -->
<select id="selectUserDmPermissionList" resultType="map">
SELECT
pu.permission_code as code
FROM jl_key_dm_permission_user pu
WHERE pu.user_id = #{_user.id}
</select>
<!-- ===== 请假类型管理 ===== -->
<select id="selectLeaveTypeList" parameterType="page" resultType="map">
SELECT
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论