From 52e09a6b7b7054fc51b9d4bf5f1fbec0a57e60f1 Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期三, 08 四月 2026 11:37:39 +0800
Subject: [PATCH] 云仓回报调整
---
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/support/HttpAuditSupport.java | 122 +++++
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/mapper/HttpAuditLogMapper.java | 9
rsf-admin/src/page/system/httpAuditLog/index.jsx | 8
rsf-http-audit/src/main/resources/META-INF/spring.factories | 2
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java | 57 ++
pom.xml | 1
rsf-open-api/pom.xml | 5
rsf-server/src/main/java/com/vincent/rsf/server/api/feign/CloudWmsErpFeignClient.java | 19
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java | 4
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/CloudWmsReportServiceImpl.java | 175 ++++++-
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InOutResultReportParam.java | 6
rsf-admin/src/i18n/zh.js | 19
rsf-admin/src/i18n/en.js | 19
rsf-admin/src/page/ResourceContent.js | 3
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/HttpAuditLogServiceImpl.java | 11
rsf-server/src/main/resources/application-dev.yml | 26
rsf-server/pom.xml | 5
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/entity/HttpAuditLog.java | 67 ++
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java | 63 ++
rsf-admin/src/page/system/httpAuditLog/HttpAuditLogList.jsx | 82 +++
rsf-http-audit/pom.xml | 45 +
rsf-open-api/src/main/resources/application-dev.yml | 5
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/CloudWmsMockController.java | 75 ++-
rsf-server/src/main/java/com/vincent/rsf/server/api/integration/dap/DapIlcwmsResponseNormalizer.java | 57 ++
rsf-admin/src/page/system/httpAuditLog/HttpAuditLogShow.jsx | 59 ++
rsf-server/src/main/java/com/vincent/rsf/server/api/feign/fallback/CloudWmsErpFeignClientFallback.java | 17
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java | 50 ++
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionRequest.java | 20
rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/HttpAuditFilter.java | 126 +++++
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionLine.java | 30 +
version/db/sys_http_audit_log.sql | 27 +
rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InventoryAdjustReportParam.java | 18
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java | 8
rsf-server/src/main/java/com/vincent/rsf/server/system/service/HttpAuditLogService.java | 7
version/db/http_audit_menu.sql | 22
rsf-server/src/main/java/com/vincent/rsf/server/api/config/RemotesInfoProperties.java | 21
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/HttpAuditLogController.java | 43 +
37 files changed, 1,259 insertions(+), 74 deletions(-)
diff --git a/pom.xml b/pom.xml
index 722b109..dab0ee9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,6 +19,7 @@
<modules>
<module>rsf-common</module>
<module>rsf-framework</module>
+ <module>rsf-http-audit</module>
<module>rsf-server</module>
<module>rsf-open-api</module>
</modules>
diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index 11e16ef..02b05c1 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -3,6 +3,8 @@
const customEnglishMessages = {
...englishMessages,
hello: 'Hello World',
+ 'menu.httpAuditLog': 'HTTP audit',
+ 'resources.httpAuditLog.name': 'HTTP audit',
common: {
response: {
success: "Success",
@@ -148,6 +150,7 @@
department: 'Department',
token: 'Token',
operation: 'Operation',
+ httpAuditLog: 'HTTP audit',
config: 'Config',
tenant: 'Tenant',
userLogin: 'Token',
@@ -336,6 +339,22 @@
unknown: 'Unknown',
}
},
+ httpAuditLog: {
+ serviceName: "service",
+ scopeType: "scope",
+ uri: "uri",
+ method: "method",
+ functionDesc: "description",
+ queryString: "query string",
+ requestBody: "request JSON",
+ responseBody: "response JSON",
+ responseTruncated: "response truncated",
+ httpStatus: "HTTP status",
+ okFlag: "ok / error",
+ spendMs: "spend ms",
+ clientIp: "client IP",
+ errorMessage: "error",
+ },
operationRecord: {
namespace: "namespace",
url: "url",
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index 140789d..7749482 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -3,8 +3,10 @@
const customChineseMessages = {
...chineseMessages,
hello: '浣犲ソ涓栫晫',
+ 'menu.httpAuditLog': 'HTTP鎺ュ彛瀹¤',
resources: {
config: { name: '閰嶇疆鍙傛暟' },
+ httpAuditLog: { name: 'HTTP鎺ュ彛瀹¤' },
asnOrderItem: { name: '鏀惰揣鏄庣粏' },
outStockItem: { name: '鍑哄簱鍗曟槑缁�' },
},
@@ -157,6 +159,7 @@
department: '閮ㄩ棬绠$悊',
token: '鐧诲綍鏃ュ織',
operation: '鎿嶄綔鏃ュ織',
+ httpAuditLog: 'HTTP鎺ュ彛瀹¤',
config: '閰嶇疆鍙傛暟',
tenant: '绉熸埛绠$悊',
userLogin: '鐧诲綍鏃ュ織',
@@ -368,6 +371,22 @@
unknown: '鏈煡',
}
},
+ httpAuditLog: {
+ serviceName: "搴旂敤",
+ scopeType: "鍐呭閮�",
+ uri: "鎺ュ彛璺緞",
+ method: "鏂规硶",
+ functionDesc: "鍔熻兘鎻忚堪",
+ queryString: "鏌ヨ涓�",
+ requestBody: "璇锋眰鍐呭(JSON)",
+ responseBody: "鍝嶅簲鍐呭(JSON)",
+ responseTruncated: "鍝嶅簲宸叉埅鏂�",
+ httpStatus: "HTTP鐘舵��",
+ okFlag: "姝e父/寮傚父",
+ spendMs: "鑰楁椂(ms)",
+ clientIp: "璇锋眰IP",
+ errorMessage: "寮傚父淇℃伅",
+ },
operationRecord: {
namespace: "鍛藉悕绌洪棿",
url: "url",
diff --git a/rsf-admin/src/page/ResourceContent.js b/rsf-admin/src/page/ResourceContent.js
index 969a2e6..3583d21 100644
--- a/rsf-admin/src/page/ResourceContent.js
+++ b/rsf-admin/src/page/ResourceContent.js
@@ -68,6 +68,7 @@
import statisticCount from './statistics/stockStatisticNum';
import rcsTest from './rcsTest';
import openApiApp from './system/openApiApp';
+import httpAuditLog from './system/httpAuditLog';
const ResourceContent = (node) => {
switch (node.component) {
@@ -199,6 +200,8 @@
return rcsTest;
case "openApiApp":
return openApiApp;
+ case "httpAuditLog":
+ return httpAuditLog;
default:
return {
list: ListGuesser,
diff --git a/rsf-admin/src/page/system/httpAuditLog/HttpAuditLogList.jsx b/rsf-admin/src/page/system/httpAuditLog/HttpAuditLogList.jsx
new file mode 100644
index 0000000..58fe66d
--- /dev/null
+++ b/rsf-admin/src/page/system/httpAuditLog/HttpAuditLogList.jsx
@@ -0,0 +1,82 @@
+import React from "react";
+import {
+ List,
+ Datagrid,
+ TextField,
+ DateField,
+ TopToolbar,
+ FilterButton,
+ TextInput,
+ SelectInput,
+ ShowButton,
+ BulkDeleteButton,
+ FunctionField,
+} from "react-admin";
+import { Chip } from "@mui/material";
+import EmptyData from "@/page/components/EmptyData";
+import { DEFAULT_PAGE_SIZE } from "@/config/setting";
+
+const filters = [
+ <TextInput source="uri" label="table.field.httpAuditLog.uri" alwaysOn />,
+ <TextInput source="clientIp" label="table.field.httpAuditLog.clientIp" />,
+ <SelectInput
+ source="okFlag"
+ label="table.field.httpAuditLog.okFlag"
+ choices={[
+ { id: 1, name: "姝e父" },
+ { id: 0, name: "寮傚父" },
+ ]}
+ />,
+ <TextInput source="serviceName" label="table.field.httpAuditLog.serviceName" />,
+ <SelectInput
+ source="scopeType"
+ label="table.field.httpAuditLog.scopeType"
+ choices={[
+ { id: "EXTERNAL", name: "澶栭儴" },
+ { id: "INTERNAL", name: "鍐呴儴" },
+ ]}
+ />,
+ <TextInput source="functionDesc" label="table.field.httpAuditLog.functionDesc" />,
+ <TextInput source="method" label="table.field.httpAuditLog.method" />,
+];
+
+const HttpAuditLogList = () => (
+ <List
+ title="menu.httpAuditLog"
+ filters={filters}
+ sort={{ field: "create_time", order: "DESC" }}
+ perPage={DEFAULT_PAGE_SIZE}
+ empty={<EmptyData />}
+ actions={
+ <TopToolbar>
+ <FilterButton />
+ </TopToolbar>
+ }
+ >
+ <Datagrid bulkActionButtons={<BulkDeleteButton />}>
+ <TextField source="id" />
+ <TextField source="serviceName" label="table.field.httpAuditLog.serviceName" />
+ <TextField source="scopeType" label="table.field.httpAuditLog.scopeType" />
+ <TextField source="uri" label="table.field.httpAuditLog.uri" />
+ <TextField source="method" label="table.field.httpAuditLog.method" />
+ <TextField source="functionDesc" label="table.field.httpAuditLog.functionDesc" />
+ <TextField source="clientIp" label="table.field.httpAuditLog.clientIp" />
+ <FunctionField
+ label="table.field.httpAuditLog.okFlag"
+ render={(record) =>
+ record.okFlag === 1 ? (
+ <Chip label="姝e父" color="success" size="small" variant="outlined" />
+ ) : (
+ <Chip label="寮傚父" color="error" size="small" variant="outlined" />
+ )
+ }
+ />
+ <TextField source="httpStatus" label="table.field.httpAuditLog.httpStatus" />
+ <TextField source="spendMs" label="table.field.httpAuditLog.spendMs" />
+ <DateField source="createTime" label="common.field.createTime" showTime />
+ <ShowButton />
+ </Datagrid>
+ </List>
+);
+
+export default HttpAuditLogList;
diff --git a/rsf-admin/src/page/system/httpAuditLog/HttpAuditLogShow.jsx b/rsf-admin/src/page/system/httpAuditLog/HttpAuditLogShow.jsx
new file mode 100644
index 0000000..1b19d5c
--- /dev/null
+++ b/rsf-admin/src/page/system/httpAuditLog/HttpAuditLogShow.jsx
@@ -0,0 +1,59 @@
+import React from "react";
+import { Show, SimpleShowLayout, TextField, DateField, FunctionField } from "react-admin";
+import { Box, Chip } from "@mui/material";
+
+const JsonBlock = ({ text }) => (
+ <Box component="pre" sx={{ whiteSpace: "pre-wrap", wordBreak: "break-all", m: 0, fontSize: 12 }}>
+ {text ?? ""}
+ </Box>
+);
+
+const HttpAuditLogShow = () => (
+ <Show>
+ <SimpleShowLayout>
+ <TextField source="id" />
+ <TextField source="serviceName" label="table.field.httpAuditLog.serviceName" />
+ <TextField source="scopeType" label="table.field.httpAuditLog.scopeType" />
+ <TextField source="uri" label="table.field.httpAuditLog.uri" />
+ <TextField source="method" label="table.field.httpAuditLog.method" />
+ <TextField source="functionDesc" label="table.field.httpAuditLog.functionDesc" />
+ <TextField source="clientIp" label="table.field.httpAuditLog.clientIp" />
+ <FunctionField
+ label="table.field.httpAuditLog.okFlag"
+ render={(record) =>
+ record.okFlag === 1 ? (
+ <Chip label="姝e父" color="success" size="small" variant="outlined" />
+ ) : (
+ <Chip label="寮傚父" color="error" size="small" variant="outlined" />
+ )
+ }
+ />
+ <TextField source="httpStatus" label="table.field.httpAuditLog.httpStatus" />
+ <TextField source="spendMs" label="table.field.httpAuditLog.spendMs" />
+ <TextField source="responseTruncated" label="table.field.httpAuditLog.responseTruncated" />
+ <DateField source="createTime" label="common.field.createTime" showTime />
+ <FunctionField
+ source="queryString"
+ label="table.field.httpAuditLog.queryString"
+ render={(record) => <JsonBlock text={record.queryString} />}
+ />
+ <FunctionField
+ source="requestBody"
+ label="table.field.httpAuditLog.requestBody"
+ render={(record) => <JsonBlock text={record.requestBody} />}
+ />
+ <FunctionField
+ source="responseBody"
+ label="table.field.httpAuditLog.responseBody"
+ render={(record) => <JsonBlock text={record.responseBody} />}
+ />
+ <FunctionField
+ source="errorMessage"
+ label="table.field.httpAuditLog.errorMessage"
+ render={(record) => <JsonBlock text={record.errorMessage} />}
+ />
+ </SimpleShowLayout>
+ </Show>
+);
+
+export default HttpAuditLogShow;
diff --git a/rsf-admin/src/page/system/httpAuditLog/index.jsx b/rsf-admin/src/page/system/httpAuditLog/index.jsx
new file mode 100644
index 0000000..1dc8217
--- /dev/null
+++ b/rsf-admin/src/page/system/httpAuditLog/index.jsx
@@ -0,0 +1,8 @@
+import HttpAuditLogList from "./HttpAuditLogList";
+import HttpAuditLogShow from "./HttpAuditLogShow";
+
+export default {
+ list: HttpAuditLogList,
+ show: HttpAuditLogShow,
+ recordRepresentation: (record) => `${record.uri || record.id}`,
+};
diff --git a/rsf-http-audit/pom.xml b/rsf-http-audit/pom.xml
new file mode 100644
index 0000000..fef4495
--- /dev/null
+++ b/rsf-http-audit/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.vincent</groupId>
+ <artifactId>rsf</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <artifactId>rsf-http-audit</artifactId>
+ <packaging>jar</packaging>
+ <name>rsf-http-audit</name>
+ <description>HTTP 鎺ュ彛瀹¤锛堝紩鍏ュ嵆娉ㄥ唽 Filter 寮傛钀藉簱锛屼笉褰卞搷涓氬姟锛�</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-autoconfigure</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-configuration-processor</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.baomidou</groupId>
+ <artifactId>mybatis-plus-boot-starter</artifactId>
+ <version>3.4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java
new file mode 100644
index 0000000..c0ff688
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java
@@ -0,0 +1,50 @@
+package com.vincent.rsf.httpaudit.config;
+
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
+import com.vincent.rsf.httpaudit.service.HttpAuditAsyncRecorder;
+import com.vincent.rsf.httpaudit.web.HttpAuditFilter;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+
+/**
+ * 寮曞叆 rsf-http-audit 鍗崇敓鏁堬紙鍙� http-audit.enabled=false 鍏抽棴锛�
+ */
+@Configuration
+@EnableAsync
+@EnableConfigurationProperties(HttpAuditProperties.class)
+@ConditionalOnProperty(prefix = "http-audit", name = "enabled", havingValue = "true", matchIfMissing = true)
+@MapperScan("com.vincent.rsf.httpaudit.mapper")
+public class HttpAuditAutoConfiguration {
+
+ @Bean(name = "httpAuditExecutor")
+ public Executor httpAuditExecutor() {
+ ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
+ ex.setCorePoolSize(2);
+ ex.setMaxPoolSize(8);
+ ex.setQueueCapacity(1000);
+ ex.setThreadNamePrefix("http-audit-");
+ ex.initialize();
+ return ex;
+ }
+
+ @Bean
+ public FilterRegistrationBean<HttpAuditFilter> httpAuditFilterRegistration(
+ HttpAuditAsyncRecorder recorder, HttpAuditProperties props, Environment env) {
+ HttpAuditFilter filter = new HttpAuditFilter(recorder, props, env);
+ FilterRegistrationBean<HttpAuditFilter> reg = new FilterRegistrationBean<>();
+ reg.setFilter(filter);
+ reg.addUrlPatterns("/*");
+ reg.setOrder(Ordered.HIGHEST_PRECEDENCE + 50);
+ return reg;
+ }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/entity/HttpAuditLog.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/entity/HttpAuditLog.java
new file mode 100644
index 0000000..6338006
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/entity/HttpAuditLog.java
@@ -0,0 +1,67 @@
+package com.vincent.rsf.httpaudit.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * HTTP 鎺ュ彛瀹¤璁板綍
+ */
+@Data
+@Accessors(chain = true)
+@TableName("sys_http_audit_log")
+public class HttpAuditLog implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @TableId(type = IdType.AUTO)
+ private Long id;
+
+ /** 搴旂敤鍚嶏紝濡� spring.application.name */
+ private String serviceName;
+
+ /** EXTERNAL-澶栭儴锛汭NTERNAL-鍐呴儴 */
+ private String scopeType;
+
+ /** 璇锋眰璺緞锛堜笉鍚煙鍚嶏級 */
+ private String uri;
+
+ private String method;
+
+ /** 鍔熻兘璇存槑锛堟潵鑷厤缃渶闀垮墠缂�鍖归厤锛� */
+ private String functionDesc;
+
+ private String queryString;
+
+ /** 璇锋眰浣� JSON/鏂囨湰锛屽叏閲� */
+ private String requestBody;
+
+ /** 鍝嶅簲浣擄紝鏌ヨ绫绘垨瓒呴暱鏃舵埅鏂� */
+ private String responseBody;
+
+ /** 1 琛ㄧず鍝嶅簲浣撳凡鎸夎鍒欐埅鏂� */
+ private Integer responseTruncated;
+
+ private Integer httpStatus;
+
+ /** 1 姝e父锛�2xx 涓旀棤鏈崟鑾峰紓甯革級锛�0 寮傚父 */
+ private Integer okFlag;
+
+ private Integer spendMs;
+
+ private String clientIp;
+
+ /** 閾捐矾涓婂紓甯告憳瑕� */
+ private String errorMessage;
+
+ private Date createTime;
+
+ @TableLogic
+ private Integer deleted;
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/mapper/HttpAuditLogMapper.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/mapper/HttpAuditLogMapper.java
new file mode 100644
index 0000000..3c006e4
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/mapper/HttpAuditLogMapper.java
@@ -0,0 +1,9 @@
+package com.vincent.rsf.httpaudit.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface HttpAuditLogMapper extends BaseMapper<HttpAuditLog> {
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java
new file mode 100644
index 0000000..a553c23
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java
@@ -0,0 +1,63 @@
+package com.vincent.rsf.httpaudit.props;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * HTTP 瀹¤閰嶇疆
+ */
+@Data
+@ConfigurationProperties(prefix = "http-audit")
+public class HttpAuditProperties {
+
+ private boolean enabled = true;
+
+ /** 鏌ヨ绫诲搷搴旀渶澶氫繚鐣欏瓧绗︽暟 */
+ private int queryResponseMaxChars = 500;
+
+ /** 闈炴煡璇㈢被鍝嶅簲鏈�澶氬叆搴撳瓧鑺傦紙瓒呭嚭鎴柇骞舵爣璁帮級 */
+ private int maxResponseStoreChars = 65535;
+
+ /** 璇锋眰浣撶紦瀛樹笂闄愶紙瀛楄妭锛� */
+ private int maxRequestCacheBytes = 2 * 1024 * 1024;
+
+ /** 鍝嶅簲浣撶紦瀛樹笂闄愶紙瀛楄妭锛� */
+ private int maxResponseCacheBytes = 2 * 1024 * 1024;
+
+ /** 涓嶈惤搴撶殑璺緞鍓嶇紑 */
+ private List<String> excludePathPrefixes = defaultExcludes();
+
+ /** 瑙嗕负澶栭儴璋冪敤鐨勮矾寰勫墠缂�锛堝叾浣欎负鍐呴儴锛� */
+ private List<String> externalPathPrefixes = defaultExternal();
+
+ /** 璺緞 -> 鍔熻兘鎻忚堪锛堟寜鏈�闀胯矾寰勫墠缂�鍖归厤锛� */
+ private Map<String, String> pathDescriptions = new LinkedHashMap<>();
+
+ private static List<String> defaultExcludes() {
+ List<String> list = new ArrayList<>();
+ list.add("/actuator");
+ list.add("/swagger");
+ list.add("/webjars");
+ list.add("/v2/api-docs");
+ list.add("/v3/api-docs");
+ list.add("/doc.html");
+ list.add("/druid");
+ list.add("/error");
+ list.add("/favicon.ico");
+ list.add("/static/");
+ list.add("/httpAuditLog");
+ return list;
+ }
+
+ private static List<String> defaultExternal() {
+ List<String> list = new ArrayList<>();
+ list.add("/erp");
+ list.add("/cloudwms");
+ return list;
+ }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java
new file mode 100644
index 0000000..1c99d59
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java
@@ -0,0 +1,57 @@
+package com.vincent.rsf.httpaudit.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import com.vincent.rsf.httpaudit.mapper.HttpAuditLogMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 寮傛钀藉簱锛涘け璐ユ椂鎵撳叏閲忔棩蹇楋紝涓嶅悜涓氬姟鎶涢敊
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class HttpAuditAsyncRecorder {
+
+ private final HttpAuditLogMapper httpAuditLogMapper;
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ @Async("httpAuditExecutor")
+ public void save(HttpAuditLog entity) {
+ try {
+ httpAuditLogMapper.insert(entity);
+ } catch (Throwable t) {
+ try {
+ Map<String, Object> dump = new LinkedHashMap<>();
+ dump.put("serviceName", entity.getServiceName());
+ dump.put("scopeType", entity.getScopeType());
+ dump.put("uri", entity.getUri());
+ dump.put("method", entity.getMethod());
+ dump.put("functionDesc", entity.getFunctionDesc());
+ dump.put("queryString", entity.getQueryString());
+ dump.put("requestBody", entity.getRequestBody());
+ dump.put("responseBody", entity.getResponseBody());
+ dump.put("httpStatus", entity.getHttpStatus());
+ dump.put("okFlag", entity.getOkFlag());
+ dump.put("spendMs", entity.getSpendMs());
+ dump.put("clientIp", entity.getClientIp());
+ dump.put("errorMessage", entity.getErrorMessage());
+ String json = objectMapper.writeValueAsString(dump);
+ log.error("http-audit 钀藉簱澶辫触锛屽叏閲廕SON濡備笅锛歿}", json, t);
+ } catch (JsonProcessingException je) {
+ log.error("http-audit 钀藉簱澶辫触涓斿簭鍒楀寲瀹¤鍐呭澶辫触锛宺equestBody.length={}, responseBody.length={}",
+ entity.getRequestBody() == null ? -1 : entity.getRequestBody().length(),
+ entity.getResponseBody() == null ? -1 : entity.getResponseBody().length(),
+ t);
+ log.error("搴忓垪鍖栧紓甯�", je);
+ }
+ }
+ }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/support/HttpAuditSupport.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/support/HttpAuditSupport.java
new file mode 100644
index 0000000..67ac455
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/support/HttpAuditSupport.java
@@ -0,0 +1,122 @@
+package com.vincent.rsf.httpaudit.support;
+
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
+
+import javax.servlet.http.HttpServletRequest;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鍐呭閮ㄥ垽瀹氥�佽矾寰勮鏄庛�佸搷搴旀埅鏂�
+ */
+public final class HttpAuditSupport {
+
+ private HttpAuditSupport() {
+ }
+
+ public static String resolveScope(HttpServletRequest request, HttpAuditProperties props) {
+ String path = safePath(request);
+ for (String p : props.getExternalPathPrefixes()) {
+ if (path.startsWith(p)) {
+ return "EXTERNAL";
+ }
+ }
+ return "INTERNAL";
+ }
+
+ public static String resolveFunctionDesc(HttpServletRequest request, HttpAuditProperties props) {
+ String path = safePath(request);
+ Map<String, String> map = props.getPathDescriptions();
+ if (map == null || map.isEmpty()) {
+ return null;
+ }
+ List<String> keys = new ArrayList<>(map.keySet());
+ keys.sort(Comparator.comparingInt(String::length).reversed());
+ for (String k : keys) {
+ if (path.startsWith(k)) {
+ return map.get(k);
+ }
+ }
+ return null;
+ }
+
+ public static String safePath(HttpServletRequest request) {
+ String ctx = request.getContextPath();
+ String uri = request.getRequestURI();
+ if (ctx != null && !ctx.isEmpty() && uri.startsWith(ctx)) {
+ return uri.substring(ctx.length());
+ }
+ return uri != null ? uri : "";
+ }
+
+ public static boolean shouldExclude(HttpServletRequest request, HttpAuditProperties props) {
+ String path = safePath(request);
+ for (String p : props.getExcludePathPrefixes()) {
+ if (p != null && !p.isEmpty() && path.startsWith(p)) {
+ return true;
+ }
+ }
+ String lower = path.toLowerCase();
+ if (lower.endsWith(".js") || lower.endsWith(".css") || lower.endsWith(".ico")
+ || lower.endsWith(".png") || lower.endsWith(".jpg") || lower.endsWith(".gif")
+ || lower.endsWith(".woff") || lower.endsWith(".woff2") || lower.endsWith(".map")) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isQueryLike(HttpServletRequest request) {
+ String m = request.getMethod();
+ if ("GET".equalsIgnoreCase(m)) {
+ return true;
+ }
+ String path = safePath(request).toLowerCase();
+ return path.contains("/page") || path.contains("/list") || path.contains("/query");
+ }
+
+ public static String clientIp(HttpServletRequest request) {
+ String xff = request.getHeader("X-Forwarded-For");
+ if (xff != null && !xff.isEmpty()) {
+ int i = xff.indexOf(',');
+ return i > 0 ? xff.substring(0, i).trim() : xff.trim();
+ }
+ String real = request.getHeader("X-Real-IP");
+ if (real != null && !real.isEmpty()) {
+ return real.trim();
+ }
+ return request.getRemoteAddr();
+ }
+
+ public static Charset resolveCharset(HttpServletRequest request) {
+ String enc = request.getCharacterEncoding();
+ if (enc == null || enc.isEmpty()) {
+ return StandardCharsets.UTF_8;
+ }
+ try {
+ return Charset.forName(enc);
+ } catch (Exception e) {
+ return StandardCharsets.UTF_8;
+ }
+ }
+
+ public static String bytesToString(byte[] buf, Charset charset) {
+ if (buf == null || buf.length == 0) {
+ return "";
+ }
+ return new String(buf, charset);
+ }
+
+ public static String truncateForStore(String s, int maxChars) {
+ if (s == null) {
+ return null;
+ }
+ if (s.length() <= maxChars) {
+ return s;
+ }
+ return s.substring(0, maxChars) + "...(truncated,len=" + s.length() + ")";
+ }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/HttpAuditFilter.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/HttpAuditFilter.java
new file mode 100644
index 0000000..1abd8f1
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/HttpAuditFilter.java
@@ -0,0 +1,126 @@
+package com.vincent.rsf.httpaudit.web;
+
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
+import com.vincent.rsf.httpaudit.service.HttpAuditAsyncRecorder;
+import com.vincent.rsf.httpaudit.support.HttpAuditSupport;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.env.Environment;
+import org.springframework.web.filter.OncePerRequestFilter;
+import org.springframework.web.util.ContentCachingRequestWrapper;
+import org.springframework.web.util.ContentCachingResponseWrapper;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Date;
+
+/**
+ * 缂撳瓨璇锋眰/鍝嶅簲浣撳苟寮傛鍐欏璁¤〃
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class HttpAuditFilter extends OncePerRequestFilter {
+
+ private final HttpAuditAsyncRecorder recorder;
+ private final HttpAuditProperties props;
+ private final Environment environment;
+
+ @Override
+ protected boolean shouldNotFilter(HttpServletRequest request) {
+ return !props.isEnabled() || HttpAuditSupport.shouldExclude(request, props);
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+ throws ServletException, IOException {
+ ContentCachingRequestWrapper reqWrapper = new ContentCachingRequestWrapper(request, props.getMaxRequestCacheBytes());
+ ContentCachingResponseWrapper resWrapper = new ContentCachingResponseWrapper(response);
+ long t0 = System.currentTimeMillis();
+ Exception chainError = null;
+ try {
+ filterChain.doFilter(reqWrapper, resWrapper);
+ } catch (IOException | ServletException e) {
+ chainError = e;
+ throw e;
+ } catch (RuntimeException e) {
+ chainError = e;
+ throw e;
+ } finally {
+ try {
+ record(reqWrapper, resWrapper, t0, chainError);
+ } catch (Throwable ignore) {
+ log.warn("http-audit record 寮傚父宸插悶鎺夛細{}", ignore.getMessage());
+ }
+ try {
+ resWrapper.copyBodyToResponse();
+ } catch (IOException io) {
+ log.debug("copyBodyToResponse: {}", io.getMessage());
+ }
+ }
+ }
+
+ private void record(ContentCachingRequestWrapper req, ContentCachingResponseWrapper res, long t0, Exception chainError) {
+ Charset charset = HttpAuditSupport.resolveCharset(req);
+ String ctReq = req.getContentType();
+ String reqBody;
+ if (ctReq != null && ctReq.toLowerCase().startsWith("multipart/")) {
+ reqBody = "[multipart omitted]";
+ } else {
+ reqBody = HttpAuditSupport.bytesToString(req.getContentAsByteArray(), charset);
+ }
+
+ String respCt = res.getContentType();
+ String resBodyRaw = HttpAuditSupport.bytesToString(res.getContentAsByteArray(), charset);
+ String resBodyToStore;
+ int truncated = 0;
+ if (respCt != null && (respCt.contains("octet-stream") || respCt.contains("application/pdf"))) {
+ resBodyToStore = "[binary response omitted]";
+ truncated = 1;
+ } else if (HttpAuditSupport.isQueryLike(req)) {
+ resBodyToStore = HttpAuditSupport.truncateForStore(resBodyRaw, props.getQueryResponseMaxChars());
+ if (resBodyRaw != null && resBodyRaw.length() > props.getQueryResponseMaxChars()) {
+ truncated = 1;
+ }
+ } else {
+ resBodyToStore = HttpAuditSupport.truncateForStore(resBodyRaw, props.getMaxResponseStoreChars());
+ if (resBodyRaw != null && resBodyRaw.length() > props.getMaxResponseStoreChars()) {
+ truncated = 1;
+ }
+ }
+
+ int status = res.getStatus();
+ int ok = (chainError == null && status >= 200 && status < 400) ? 1 : 0;
+ String errMsg = null;
+ if (chainError != null) {
+ String s = chainError.toString();
+ errMsg = s.length() > 4000 ? s.substring(0, 4000) + "..." : s;
+ }
+
+ String appName = environment.getProperty("spring.application.name", "unknown");
+
+ HttpAuditLog logEntity = new HttpAuditLog()
+ .setServiceName(appName)
+ .setScopeType(HttpAuditSupport.resolveScope(req, props))
+ .setUri(HttpAuditSupport.safePath(req))
+ .setMethod(req.getMethod())
+ .setFunctionDesc(HttpAuditSupport.resolveFunctionDesc(req, props))
+ .setQueryString(req.getQueryString())
+ .setRequestBody(reqBody)
+ .setResponseBody(resBodyToStore)
+ .setResponseTruncated(truncated)
+ .setHttpStatus(status)
+ .setOkFlag(ok)
+ .setSpendMs((int) (System.currentTimeMillis() - t0))
+ .setClientIp(HttpAuditSupport.clientIp(req))
+ .setErrorMessage(errMsg)
+ .setCreateTime(new Date())
+ .setDeleted(0);
+
+ recorder.save(logEntity);
+ }
+}
diff --git a/rsf-http-audit/src/main/resources/META-INF/spring.factories b/rsf-http-audit/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..65c20b4
--- /dev/null
+++ b/rsf-http-audit/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.vincent.rsf.httpaudit.config.HttpAuditAutoConfiguration
diff --git a/rsf-open-api/pom.xml b/rsf-open-api/pom.xml
index d8215d0..cb6f4a3 100644
--- a/rsf-open-api/pom.xml
+++ b/rsf-open-api/pom.xml
@@ -21,6 +21,11 @@
<artifactId>rsf-common</artifactId>
<version>1.0.0</version>
</dependency>
+ <dependency>
+ <groupId>com.vincent</groupId>
+ <artifactId>rsf-http-audit</artifactId>
+ <version>1.0.0</version>
+ </dependency>
<!-- OpenFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
diff --git a/rsf-open-api/src/main/resources/application-dev.yml b/rsf-open-api/src/main/resources/application-dev.yml
index 5a86c98..6148deb 100644
--- a/rsf-open-api/src/main/resources/application-dev.yml
+++ b/rsf-open-api/src/main/resources/application-dev.yml
@@ -72,3 +72,8 @@
host: http://127.0.0.1
#绔彛
port: 3741
+
+http-audit:
+ enabled: true
+ query-response-max-chars: 500
+ max-response-store-chars: 65535
diff --git a/rsf-server/pom.xml b/rsf-server/pom.xml
index a451ff6..1157cf1 100644
--- a/rsf-server/pom.xml
+++ b/rsf-server/pom.xml
@@ -26,6 +26,11 @@
<version>1.0.0</version>
</dependency>
<dependency>
+ <groupId>com.vincent</groupId>
+ <artifactId>rsf-http-audit</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/config/RemotesInfoProperties.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/config/RemotesInfoProperties.java
index 67956f6..7c022b6 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/config/RemotesInfoProperties.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/config/RemotesInfoProperties.java
@@ -35,15 +35,30 @@
*/
private String baseUrl;
+ /**
+ * 榧庢嵎 ilcwmsplus 瀹屾垚鍙嶉绛夊叕鍏卞瓧娈碉紙orgNo銆佸崟鎹被鍒�佸崟浣嶏級
+ */
+ private Dap dap = new Dap();
+
+ @Data
+ public static class Dap {
+ private String orgNo = "";
+ private String docTypeIn = "";
+ private String docTypeOut = "";
+ /** 搴撳瓨璋冩暣锛�9.2锛夊崟鎹被鍒紱绉诲簱绛� */
+ private String docTypeAdj = "";
+ private String unitNo = "PCS";
+ }
+
@Data
@Configuration
@ConfigurationProperties(prefix = "platform.erp.api")
public class ApiInfo {
/** 涓�閿笂鎶ヨ川妫�鎺ュ彛 */
private String notifyInspect;
- /** 9.1 鍏�/鍑哄簱缁撴灉涓婃姤锛堢珛搴撲晶璇锋眰浜戜粨锛� */
- private String inOutResultPath = "/api/report/inOutResult";
- /** 9.2 搴撳瓨璋冩暣涓诲姩涓婃姤锛堢珛搴撲晶璇锋眰浜戜粨锛� */
+ /** 宸叉敼涓� Feign 鍥哄畾璺緞 /dapilc/.../cusInventoryCompletionReport銆乧usOutboundCompletionReport锛屾湰椤逛粎浣滈厤缃崰浣� */
+ private String inOutResultPath = "/dapilc/restful/service/ilcwmsplus/IKWebService/cusInventoryCompletionReport";
+ /** 9.2 搴撳瓨璋冩暣锛氫粛涓� /api/report/inventoryAdjust锛屾姤鏂囦綋涓� 9.1 涓�鑷翠负 {data:[]} */
private String inventoryAdjustPath = "/api/report/inventoryAdjust";
/** 鐗╂枡鍩虹淇℃伅鍚屾锛堢珛搴撲晶璇锋眰浜戜粨锛� */
private String matSyncPath = "/api/mat/sync";
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/CloudWmsMockController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/CloudWmsMockController.java
index 4a562ba..bb3ec1d 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/CloudWmsMockController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/CloudWmsMockController.java
@@ -1,31 +1,44 @@
package com.vincent.rsf.server.api.controller;
-import com.vincent.rsf.server.api.controller.erp.params.InOutResultReportParam;
-import com.vincent.rsf.server.api.controller.erp.params.InventoryAdjustReportParam;
+import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
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.HashMap;
import java.util.Map;
/**
- * 浜戜粨WMS 妯℃嫙鎺ュ彛锛堝鎺ュ崗璁� 9.1銆�9.2銆佺墿鏂欏悓姝ワ級銆�
- * 浜戜粨鏈彁渚涚湡瀹� URL 鏃讹紝鍙皢 platform.erp.base-url 鎸囧悜鏈満璇ユ湇鍔★紙濡� http://127.0.0.1:8086/rsf-server锛夛紝
- * 绔嬪簱涓婃姤璇锋眰浼氭墦鍒版湰鎺ュ彛骞惰繑鍥炴ā鎷熸垚鍔熴��
+ * 浜戜粨妯℃嫙鎺ュ彛銆俻latform.erp.base-url 鎸囧悜鏈湇鍔℃椂锛孎eign 浼氳姹備笅鍒� DAP 椋庢牸璺緞銆�
*/
@Slf4j
@RestController
-@RequestMapping("/api")
@Api(value = "浜戜粨妯℃嫙鎺ュ彛", tags = "浜戜粨妯℃嫙锛堟棤鐪熷疄浜戜粨URL鏃朵娇鐢級")
public class CloudWmsMockController {
- private static Map<String, Object> successResponse() {
+ private static Map<String, Object> dapOkEnvelope() {
+ Map<String, Object> profile = new HashMap<>();
+ profile.put("tenantSid", 1);
+ profile.put("userSid", "SYS");
+ Map<String, Object> response = new HashMap<>();
+ response.put("code", -1);
+ response.put("success", false);
+ response.put("message", "");
+ Map<String, Object> map = new HashMap<>();
+ map.put("duration", 58);
+ map.put("statusDescription", "OK");
+ map.put("response", response);
+ map.put("profile", profile);
+ map.put("uuid", "");
+ map.put("status", 200);
+ return map;
+ }
+
+ private static Map<String, Object> successResponseLegacy() {
Map<String, Object> data = new HashMap<>();
data.put("result", "SUCCESS");
Map<String, Object> map = new HashMap<>();
@@ -35,33 +48,39 @@
return map;
}
- /** 9.1 鍏�/鍑哄簱缁撴灉涓婃姤 - 妯℃嫙 */
- @ApiOperation("鍏�/鍑哄簱缁撴灉涓婃姤锛堟ā鎷燂級")
- @PostMapping(value = "/report/inOutResult", consumes = MediaType.APPLICATION_JSON_VALUE)
- public Map<String, Object> mockInOutResult(@RequestBody InOutResultReportParam body) {
- log.info("浜戜粨妯℃嫙-鍏�/鍑哄簱缁撴灉涓婃姤锛宱rderNo={}锛宭ocId={}锛宮atNr={}",
- body != null ? body.getOrderNo() : null,
- body != null ? body.getLocId() : null,
- body != null ? body.getMatNr() : null);
- return successResponse();
+ @ApiOperation("榧庢嵎-鍏ュ簱瀹屾垚鍙嶉锛堟ā鎷燂級")
+ @PostMapping(value = "/dapilc/restful/service/ilcwmsplus/IKWebService/cusInventoryCompletionReport", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public Map<String, Object> mockInventoryCompletion(@RequestBody DapIlcwmsCompletionRequest body) {
+ log.info("浜戜粨妯℃嫙-鍏ュ簱瀹屾垚鍙嶉锛岃鏁�={}", body != null && body.getData() != null ? body.getData().size() : 0);
+ return dapOkEnvelope();
}
- /** 9.2 搴撳瓨璋冩暣涓诲姩涓婃姤 - 妯℃嫙 */
- @ApiOperation("搴撳瓨璋冩暣涓诲姩涓婃姤锛堟ā鎷燂級")
- @PostMapping(value = "/report/inventoryAdjust", consumes = MediaType.APPLICATION_JSON_VALUE)
- public Map<String, Object> mockInventoryAdjust(@RequestBody InventoryAdjustReportParam body) {
- log.info("浜戜粨妯℃嫙-搴撳瓨璋冩暣涓婃姤锛宑hangeType={}锛寃areHouseId={}锛宮atNr={}",
- body != null ? body.getChangeType() : null,
- body != null ? body.getWareHouseId() : null,
- body != null ? body.getMatNr() : null);
- return successResponse();
+ @ApiOperation("榧庢嵎-鍑哄簱瀹屾垚鍙嶉锛堟ā鎷燂級")
+ @PostMapping(value = "/dapilc/restful/service/ilcwmsplus/IKWebService/cusOutboundCompletionReport", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public Map<String, Object> mockOutboundCompletion(@RequestBody DapIlcwmsCompletionRequest body) {
+ log.info("浜戜粨妯℃嫙-鍑哄簱瀹屾垚鍙嶉锛岃鏁�={}", body != null && body.getData() != null ? body.getData().size() : 0);
+ return dapOkEnvelope();
+ }
+
+ /** 9.2 搴撳瓨璋冩暣涓诲姩涓婃姤 - 妯℃嫙锛堣矾寰勪笉鍙橈紝body 涓� {data:[]}锛� */
+ @ApiOperation("搴撳瓨璋冩暣涓婃姤锛堟ā鎷燂級")
+ @PostMapping(value = "/api/report/inventoryAdjust", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public Map<String, Object> mockInventoryAdjust(@RequestBody DapIlcwmsCompletionRequest body) {
+ log.info("浜戜粨妯℃嫙-搴撳瓨璋冩暣涓婃姤锛岃鏁�={}", body != null && body.getData() != null ? body.getData().size() : 0);
+ return successResponseLegacy();
}
/** 鐗╂枡鍩虹淇℃伅鍚屾 - 妯℃嫙 */
@ApiOperation("鐗╂枡鍚屾锛堟ā鎷燂級")
- @PostMapping(value = "/mat/sync", consumes = MediaType.APPLICATION_JSON_VALUE)
+ @PostMapping(value = "/api/mat/sync", consumes = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> mockMatSync(@RequestBody Object body) {
log.info("浜戜粨妯℃嫙-鐗╂枡鍚屾锛宐ody={}", body != null ? body.toString() : null);
- return successResponse();
+ return successResponseLegacy();
}
+
+// /** 9.1 鍏�/鍑哄簱缁撴灉涓婃姤 - 妯℃嫙锛堟棫璺緞锛屽凡鏀� DAP锛� */
+// @PostMapping(value = "/api/report/inOutResult", consumes = MediaType.APPLICATION_JSON_VALUE)
+// public Map<String, Object> mockInOutResult(@RequestBody InOutResultReportParam body) {
+// return successResponseLegacy();
+// }
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionLine.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionLine.java
new file mode 100644
index 0000000..72e8975
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionLine.java
@@ -0,0 +1,30 @@
+package com.vincent.rsf.server.api.controller.erp.params;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * 榧庢嵎 ilcwmsplus 绔嬪簱鍏�/鍑哄簱瀹屾垚鍙嶉 - data 涓崟琛�
+ */
+@Data
+@Accessors(chain = true)
+@ApiModel(value = "DapIlcwmsCompletionLine", description = "绔嬪簱瀹屾垚鍙嶉鏄庣粏琛�")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class DapIlcwmsCompletionLine {
+
+ private String orgNo;
+ private String docType;
+ private String docNo;
+ private String docSeqNo;
+ private String itemNo;
+ private Double qty;
+ private String unitNo;
+ private String inWarehouseNo;
+ private String inCellNo;
+ private String outWarehouseNo;
+ private String outCellNo;
+ private String combinationLotNo;
+ private String barcode;
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionRequest.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionRequest.java
new file mode 100644
index 0000000..899e545
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/DapIlcwmsCompletionRequest.java
@@ -0,0 +1,20 @@
+package com.vincent.rsf.server.api.controller.erp.params;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * 榧庢嵎 ilcwmsplus 绔嬪簱鍏�/鍑哄簱瀹屾垚鍙嶉 - 璇锋眰浣�
+ */
+@Data
+@Accessors(chain = true)
+@ApiModel(value = "DapIlcwmsCompletionRequest", description = "绔嬪簱瀹屾垚鍙嶉璇锋眰")
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class DapIlcwmsCompletionRequest {
+
+ private List<DapIlcwmsCompletionLine> data;
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InOutResultReportParam.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InOutResultReportParam.java
index 5cebeba..4941d95 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InOutResultReportParam.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InOutResultReportParam.java
@@ -39,4 +39,10 @@
@ApiModelProperty("鎵规")
private String batch;
+
+ @ApiModelProperty(value = "true 鍏ュ簱瀹屾垚鍙嶉锛宖alse 鍑哄簱瀹屾垚鍙嶉", required = true)
+ private Boolean inbound;
+
+ @ApiModelProperty(value = "鏉$爜锛堜簯浠撳繀濉級")
+ private String barcode;
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InventoryAdjustReportParam.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InventoryAdjustReportParam.java
index 1f152ee..10d6b64 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InventoryAdjustReportParam.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InventoryAdjustReportParam.java
@@ -34,4 +34,22 @@
@ApiModelProperty("鎵樼洏鍙�")
private String palletId;
+
+ @ApiModelProperty("浜戜粨鍗曞彿")
+ private String docNo;
+
+ @ApiModelProperty("椤规")
+ private String docSeqNo;
+
+ @ApiModelProperty("鍗曟嵁绫诲埆锛堢┖鍒欐寜 changeType 鍙栭厤缃� dap.doc-type-in/out/adj锛�")
+ private String docType;
+
+ @ApiModelProperty("鎵规")
+ private String batch;
+
+ @ApiModelProperty("鏉$爜锛堜簯浠撳繀濉級")
+ private String barcode;
+
+ @ApiModelProperty("鍗曚綅缂栫爜锛堢┖鍒欏彇閰嶇疆 dap.unit-no锛�")
+ private String unitNo;
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/CloudWmsErpFeignClient.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/CloudWmsErpFeignClient.java
index 097fc15..2d6cd63 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/CloudWmsErpFeignClient.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/CloudWmsErpFeignClient.java
@@ -1,7 +1,6 @@
package com.vincent.rsf.server.api.feign;
-import com.vincent.rsf.server.api.controller.erp.params.InOutResultReportParam;
-import com.vincent.rsf.server.api.controller.erp.params.InventoryAdjustReportParam;
+import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionRequest;
import com.vincent.rsf.server.api.feign.fallback.CloudWmsErpFeignClientFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
@@ -11,7 +10,7 @@
import java.util.Map;
/**
- * 绔嬪簱渚ч�氳繃 OpenFeign 璋冪敤浜戜粨WMS锛氬叆/鍑哄簱缁撴灉涓婃姤锛�9.1锛夈�佸簱瀛樿皟鏁翠笂鎶ワ紙9.2锛夈�佺墿鏂欏悓姝ャ��
+ * 绔嬪簱渚ч�氳繃 OpenFeign 璋冪敤浜戜粨锛�9.1 榧庢嵎 ilcwmsplus 鍏�/鍑哄簱瀹屾垚鍙嶉锛堜袱 URL锛夛紱9.2 浠嶄负 /api/report/inventoryAdjust锛岃姹備綋涓� 9.1 鐩稿悓 {data:[]}锛堢敱 Service 浠� InventoryAdjustReportParam 缁勮锛夈��
* 浣跨敤 platform.erp.base-url 浣滀负鏍瑰湴鍧�锛涘け璐ユ椂璧� Fallback锛岀粺涓�杩斿洖閿欒鍝嶅簲锛堜笉鎶涘紓甯革級銆�
*/
@FeignClient(
@@ -21,13 +20,17 @@
)
public interface CloudWmsErpFeignClient {
- /** 9.1 鍏�/鍑哄簱缁撴灉涓婃姤 */
- @PostMapping(value = "/api/report/inOutResult", consumes = MediaType.APPLICATION_JSON_VALUE)
- Map<String, Object> reportInOutResult(@RequestBody InOutResultReportParam body);
+ /**9.1.1 绔嬪簱鍏ュ簱浠诲姟瀹屾垚鍙嶉 */
+ @PostMapping(value = "/dapilc/restful/service/ilcwmsplus/IKWebService/cusInventoryCompletionReport", consumes = MediaType.APPLICATION_JSON_VALUE)
+ Map<String, Object> cusInventoryCompletionReport(@RequestBody DapIlcwmsCompletionRequest body);
- /** 9.2 搴撳瓨璋冩暣涓诲姩涓婃姤 */
+ /**9.1.2 绔嬪簱鍑哄簱浠诲姟瀹屾垚鍙嶉 */
+ @PostMapping(value = "/dapilc/restful/service/ilcwmsplus/IKWebService/cusOutboundCompletionReport", consumes = MediaType.APPLICATION_JSON_VALUE)
+ Map<String, Object> cusOutboundCompletionReport(@RequestBody DapIlcwmsCompletionRequest body);
+
+ /** 9.2 搴撳瓨璋冩暣涓诲姩涓婃姤锛堣矾寰勪笉鍙橈紱body 涓庡叆鍑哄簱涓�鑷寸殑 data 鏁扮粍缁撴瀯锛� */
@PostMapping(value = "/api/report/inventoryAdjust", consumes = MediaType.APPLICATION_JSON_VALUE)
- Map<String, Object> reportInventoryAdjust(@RequestBody InventoryAdjustReportParam body);
+ Map<String, Object> reportInventoryAdjust(@RequestBody DapIlcwmsCompletionRequest body);
/** 鐗╂枡鍩虹淇℃伅鍚屾 */
@PostMapping(value = "/api/mat/sync", consumes = MediaType.APPLICATION_JSON_VALUE)
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/fallback/CloudWmsErpFeignClientFallback.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/fallback/CloudWmsErpFeignClientFallback.java
index 14ff707..9845061 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/fallback/CloudWmsErpFeignClientFallback.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/feign/fallback/CloudWmsErpFeignClientFallback.java
@@ -1,7 +1,6 @@
package com.vincent.rsf.server.api.feign.fallback;
-import com.vincent.rsf.server.api.controller.erp.params.InOutResultReportParam;
-import com.vincent.rsf.server.api.controller.erp.params.InventoryAdjustReportParam;
+import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionRequest;
import com.vincent.rsf.server.api.feign.CloudWmsErpFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -76,14 +75,20 @@
}
@Override
- public Map<String, Object> reportInOutResult(InOutResultReportParam body) {
- log.error("璋冪敤浜戜粨WMS 鍏�/鍑哄簱缁撴灉涓婃姤鎺ュ彛澶辫触锛岃Е鍙戦檷绾�", cause);
+ public Map<String, Object> cusInventoryCompletionReport(DapIlcwmsCompletionRequest body) {
+ log.error("璋冪敤浜戜粨 鍏ュ簱瀹屾垚鍙嶉澶辫触锛岃Е鍙戦檷绾�", cause);
return errorResponse();
}
@Override
- public Map<String, Object> reportInventoryAdjust(InventoryAdjustReportParam body) {
- log.error("璋冪敤浜戜粨WMS 搴撳瓨璋冩暣涓婃姤鎺ュ彛澶辫触锛岃Е鍙戦檷绾�", cause);
+ public Map<String, Object> cusOutboundCompletionReport(DapIlcwmsCompletionRequest body) {
+ log.error("璋冪敤浜戜粨 鍑哄簱瀹屾垚鍙嶉澶辫触锛岃Е鍙戦檷绾�", cause);
+ return errorResponse();
+ }
+
+ @Override
+ public Map<String, Object> reportInventoryAdjust(DapIlcwmsCompletionRequest body) {
+ log.error("璋冪敤浜戜粨 9.2 搴撳瓨璋冩暣涓婃姤澶辫触锛岃Е鍙戦檷绾�", cause);
return errorResponse();
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/integration/dap/DapIlcwmsResponseNormalizer.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/integration/dap/DapIlcwmsResponseNormalizer.java
new file mode 100644
index 0000000..75e9e64
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/integration/dap/DapIlcwmsResponseNormalizer.java
@@ -0,0 +1,57 @@
+package com.vincent.rsf.server.api.integration.dap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 榧庢嵎 DAP 杩斿洖缁撴瀯杞簯浠撲笂鎶ュ唴閮ㄧ粺涓�鏍煎紡锛堜緵閲嶈瘯浠诲姟鍒ゆ柇 code==200锛�
+ */
+public final class DapIlcwmsResponseNormalizer {
+
+ private DapIlcwmsResponseNormalizer() {
+ }
+
+ public static Map<String, Object> toNotifyFormat(Map<String, Object> dapBody) {
+ if (dapBody == null) {
+ return resultMap(500, "浜戜粨杩斿洖绌�", null);
+ }
+ Object st = dapBody.get("status");
+ int status = 0;
+ if (st instanceof Number) {
+ status = ((Number) st).intValue();
+ }
+ if (status == 200) {
+ return resultMap(200, "OK", dapBody);
+ }
+ Object err = dapBody.get("errorMessage");
+ String msg = err != null ? String.valueOf(err) : String.valueOf(dapBody.get("statusDescription"));
+ if (msg == null || "null".equals(msg)) {
+ msg = "浜戜粨杩斿洖澶辫触";
+ }
+ return resultMap(500, msg, dapBody);
+ }
+
+ /**
+ * 9.2 绛変粛璧版棫璺緞鐨勬帴鍙o細鑻ヨ繑鍥炴棤椤跺眰 status锛屽垯鎸夊師 code/msg 閫忎紶锛堝吋瀹规棫浜戜粨 JSON锛夈��
+ */
+ public static Map<String, Object> toNotifyFormatFlexible(Map<String, Object> body) {
+ if (body == null) {
+ return toNotifyFormat(null);
+ }
+ if (body.containsKey("status")) {
+ return toNotifyFormat(body);
+ }
+ if (body.containsKey("code")) {
+ return body;
+ }
+ return toNotifyFormat(body);
+ }
+
+ private static Map<String, Object> resultMap(int code, String msg, Map<String, Object> data) {
+ Map<String, Object> map = new HashMap<>();
+ map.put("code", code);
+ map.put("msg", msg);
+ map.put("data", data);
+ return map;
+ }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/CloudWmsReportServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/CloudWmsReportServiceImpl.java
index ca1da5c..fbaa4ca 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/CloudWmsReportServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/CloudWmsReportServiceImpl.java
@@ -1,20 +1,26 @@
package com.vincent.rsf.server.api.service.impl;
import com.vincent.rsf.server.api.config.RemotesInfoProperties;
+import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionLine;
+import com.vincent.rsf.server.api.controller.erp.params.DapIlcwmsCompletionRequest;
import com.vincent.rsf.server.api.controller.erp.params.InOutResultReportParam;
import com.vincent.rsf.server.api.controller.erp.params.InventoryAdjustReportParam;
import com.vincent.rsf.server.api.feign.CloudWmsErpFeignClient;
+import com.vincent.rsf.server.api.integration.dap.DapIlcwmsResponseNormalizer;
import com.vincent.rsf.server.api.service.CloudWmsReportService;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
- * 绔嬪簱渚ц姹備簯浠擄細鍏�/鍑哄簱缁撴灉涓婃姤锛�9.1锛夈�佸簱瀛樿皟鏁翠富鍔ㄤ笂鎶ワ紙9.2锛夈�佺墿鏂欏熀纭�淇℃伅鍚屾銆�
- * 浣跨敤 OpenFeign 璋冪敤锛涘彲閫� HttpEntity(RestTemplate) 鏂瑰紡宸叉敞閲婁繚鐣欍��
+ * 绔嬪簱渚ц姹備簯浠擄細9.1 榧庢嵎 ilcwmsplus 鍏�/鍑哄簱涓ゆ帴鍙o紱9.2 浠嶄负 /api/report/inventoryAdjust锛屾姤鏂囦笌 9.1 鍚屼负 {data:[]}銆�
*/
@Slf4j
@Service
@@ -24,16 +30,7 @@
private RemotesInfoProperties erpApi;
@Autowired
- private RemotesInfoProperties.ApiInfo erpApiInfo;
-
- @Autowired
private CloudWmsErpFeignClient cloudWmsErpFeignClient;
-
- /**
- * 鍙�夛細鏀圭敤 HttpEntity(RestTemplate) 璋冪敤浜戜粨鏃跺惎鐢ㄣ��
- */
- // @Autowired
- // private RestTemplate restTemplate;
@Override
public Map<String, Object> syncMatnrsToCloud(Object body) {
@@ -53,7 +50,17 @@
log.warn("ErpApi(浜戜粨WMS) 鏈厤缃� host锛岃烦杩� 9.1 鍏�/鍑哄簱缁撴灉涓婃姤锛岃鍗曪細{}", param.getOrderNo());
return stubSuccess("浜戜粨鍦板潃鏈厤缃紝鏈疄闄呬笂鎶�");
}
- return cloudWmsErpFeignClient.reportInOutResult(param);
+ String err = validateDapBase();
+ if (err != null) {
+ return resultMap(400, err, null);
+ }
+ boolean inbound = param.getInbound() == null || Boolean.TRUE.equals(param.getInbound());
+ DapIlcwmsCompletionRequest req = new DapIlcwmsCompletionRequest()
+ .setData(Collections.singletonList(buildInOutLine(param, inbound)));
+ Map<String, Object> raw = inbound
+ ? cloudWmsErpFeignClient.cusInventoryCompletionReport(req)
+ : cloudWmsErpFeignClient.cusOutboundCompletionReport(req);
+ return DapIlcwmsResponseNormalizer.toNotifyFormat(raw);
}
@Override
@@ -65,7 +72,139 @@
log.warn("ErpApi(浜戜粨WMS) 鏈厤缃� host锛岃烦杩� 9.2 搴撳瓨璋冩暣涓婃姤锛岀墿鏂欙細{}", param.getMatNr());
return stubSuccess("浜戜粨鍦板潃鏈厤缃紝鏈疄闄呬笂鎶�");
}
- return cloudWmsErpFeignClient.reportInventoryAdjust(param);
+ String err = validateDapBase();
+ if (err != null) {
+ return resultMap(400, err, null);
+ }
+ Integer changeType = param.getChangeType();
+ if (changeType == null) {
+ return resultMap(400, "changeType 涓嶈兘涓虹┖", null);
+ }
+ DapIlcwmsCompletionRequest req = new DapIlcwmsCompletionRequest();
+ if (changeType == 3) {
+ String baseSeq = StringUtils.isNotBlank(param.getDocSeqNo()) ? param.getDocSeqNo() : "1";
+ List<DapIlcwmsCompletionLine> lines = new ArrayList<>(2);
+ lines.add(buildAdjustLine(param, false, true, baseSeq + "-O"));
+ lines.add(buildAdjustLine(param, true, false, baseSeq + "-I"));
+ req.setData(lines);
+ } else if (changeType == 1) {
+ req.setData(Collections.singletonList(buildAdjustLine(param, true, false, null)));
+ } else if (changeType == 2) {
+ req.setData(Collections.singletonList(buildAdjustLine(param, false, true, null)));
+ } else {
+ return resultMap(400, "涓嶆敮鎸佺殑 changeType锛�" + changeType, null);
+ }
+ Map<String, Object> raw = cloudWmsErpFeignClient.reportInventoryAdjust(req);
+ return DapIlcwmsResponseNormalizer.toNotifyFormatFlexible(raw);
+ }
+
+ private DapIlcwmsCompletionLine buildInOutLine(InOutResultReportParam param, boolean inbound) {
+ RemotesInfoProperties.Dap dap = erpApi.getDap();
+ DapIlcwmsCompletionLine line = new DapIlcwmsCompletionLine()
+ .setOrgNo(dap.getOrgNo())
+ .setDocType(inbound ? dap.getDocTypeIn() : dap.getDocTypeOut())
+ .setDocNo(param.getOrderNo())
+ .setDocSeqNo(StringUtils.isNotBlank(param.getLineId()) ? param.getLineId() : "1")
+ .setItemNo(param.getMatNr())
+ .setQty(parseQty(param.getQty()))
+ .setUnitNo(dap.getUnitNo())
+ .setCombinationLotNo(param.getBatch())
+ .setBarcode(resolveBarcode(param));
+ if (inbound) {
+ line.setInWarehouseNo(param.getWareHouseId()).setInCellNo(param.getLocId());
+ } else {
+ line.setOutWarehouseNo(param.getWareHouseId()).setOutCellNo(param.getLocId());
+ }
+ return line;
+ }
+
+ /**
+ * @param fillIn 鏄惁濉叆搴撳偍浣�
+ * @param fillOut 鏄惁濉嚭搴撳偍浣�
+ * @param docSeqOverride 闈炵┖鏃剁敤浣滈」娆★紙绉诲簱绗簩琛岀瓑锛�
+ */
+ private DapIlcwmsCompletionLine buildAdjustLine(InventoryAdjustReportParam param, boolean fillIn, boolean fillOut, String docSeqOverride) {
+ RemotesInfoProperties.Dap dap = erpApi.getDap();
+ String docType = resolveAdjustDocType(param, dap);
+ String docNo = StringUtils.isNotBlank(param.getDocNo()) ? param.getDocNo() : "ADJ";
+ String docSeq = docSeqOverride != null ? docSeqOverride
+ : (StringUtils.isNotBlank(param.getDocSeqNo()) ? param.getDocSeqNo() : "1");
+ String unit = StringUtils.isNotBlank(param.getUnitNo()) ? param.getUnitNo() : dap.getUnitNo();
+ DapIlcwmsCompletionLine line = new DapIlcwmsCompletionLine()
+ .setOrgNo(dap.getOrgNo())
+ .setDocType(docType)
+ .setDocNo(docNo)
+ .setDocSeqNo(docSeq)
+ .setItemNo(param.getMatNr())
+ .setQty(parseQty(param.getQty()))
+ .setUnitNo(unit)
+ .setCombinationLotNo(param.getBatch())
+ .setBarcode(resolveAdjustBarcode(param));
+ if (fillIn) {
+ line.setInWarehouseNo(param.getWareHouseId());
+ line.setInCellNo(StringUtils.isNotBlank(param.getTargetLocId()) ? param.getTargetLocId() : param.getSourceLocId());
+ }
+ if (fillOut) {
+ line.setOutWarehouseNo(param.getWareHouseId());
+ line.setOutCellNo(StringUtils.isNotBlank(param.getSourceLocId()) ? param.getSourceLocId() : param.getTargetLocId());
+ }
+ return line;
+ }
+
+ private static String resolveAdjustDocType(InventoryAdjustReportParam param, RemotesInfoProperties.Dap dap) {
+ if (StringUtils.isNotBlank(param.getDocType())) {
+ return param.getDocType();
+ }
+ Integer ct = param.getChangeType();
+ if (ct != null && ct == 2) {
+ return dap.getDocTypeOut();
+ }
+ if (ct != null && ct == 3) {
+ return dap.getDocTypeAdj();
+ }
+ return dap.getDocTypeIn();
+ }
+
+ private static String resolveBarcode(InOutResultReportParam param) {
+ if (StringUtils.isNotBlank(param.getBarcode())) {
+ return param.getBarcode();
+ }
+ if (StringUtils.isNotBlank(param.getPalletId())) {
+ return param.getPalletId();
+ }
+ if (param.getMatNr() != null && param.getLocId() != null) {
+ return param.getMatNr() + ":" + param.getLocId();
+ }
+ return param.getMatNr();
+ }
+
+ private static String resolveAdjustBarcode(InventoryAdjustReportParam param) {
+ if (StringUtils.isNotBlank(param.getBarcode())) {
+ return param.getBarcode();
+ }
+ if (StringUtils.isNotBlank(param.getPalletId())) {
+ return param.getPalletId();
+ }
+ return param.getMatNr();
+ }
+
+ private static Double parseQty(String q) {
+ if (StringUtils.isBlank(q)) {
+ return 0d;
+ }
+ try {
+ return Double.parseDouble(q.trim());
+ } catch (NumberFormatException e) {
+ return 0d;
+ }
+ }
+
+ private String validateDapBase() {
+ RemotesInfoProperties.Dap d = erpApi.getDap();
+ if (d == null || StringUtils.isBlank(d.getOrgNo())) {
+ return "鏈厤缃� platform.erp.dap.org-no";
+ }
+ return null;
}
private boolean isCloudWmsConfigured() {
@@ -86,14 +225,4 @@
map.put("data", data);
return map;
}
-
- // ========== 鍙�夛細HttpEntity(RestTemplate) 鏂瑰紡锛堝綋鍓嶆湭浣跨敤锛� ==========
- // 鍚敤姝ラ锛�1锛夊彇娑堜笂鏂� restTemplate 鐨� @Autowired 娉ㄥ叆锛�
- // 2锛夊彇娑堜笅闈㈡暣娈垫敞閲婏紝鎭㈠ buildUrl銆乸ostToCloudWms銆乸arseResponse 鏂规硶鍙� OBJECT_MAPPER锛�
- // 3锛夊湪 syncMatnrsToCloud/reportInOutResult/reportInventoryAdjust 涓敼涓猴細String url = buildUrl(erpApiInfo.getXxxPath()); if (url == null) return stubSuccess(...); return postToCloudWms(url, body);
- //
- // private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
- // private String buildUrl(String path) { ... }
- // private Map<String, Object> postToCloudWms(String url, Object body) { HttpHeaders headers = ...; HttpEntity<Object> entity = new HttpEntity<>(body, headers); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); return parseResponse(response.getBody()); }
- // private Map<String, Object> parseResponse(String json) { ... }
}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java
index 79b31c8..01f744a 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/ReviseLogServiceImpl.java
@@ -250,7 +250,13 @@
.setSourceLocId(sourceLoc.getCode())
.setTargetLocId(finalLoc.getCode())
.setMatNr(logItem.getMatnrCode())
- .setQty(logItem.getReviseQty() != null ? String.valueOf(logItem.getReviseQty()) : "0");
+ .setQty(logItem.getReviseQty() != null ? String.valueOf(logItem.getReviseQty()) : "0")
+ .setDocNo(revise.getCode())
+ .setDocSeqNo(logItem.getId() != null ? String.valueOf(logItem.getId()) : "1")
+ .setBatch(logItem.getBatch())
+ .setUnitNo(logItem.getUnit())
+ .setBarcode(logItem.getMatnrCode() != null && logItem.getLocCode() != null
+ ? logItem.getMatnrCode() + "@" + logItem.getLocCode() : logItem.getMatnrCode());
String requestBody = objectMapper.writeValueAsString(param);
Date now = new Date();
CloudWmsNotifyLog notifyLog = new CloudWmsNotifyLog()
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
index 6423c9f..9b841c4 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -2747,7 +2747,9 @@
.setLocId(locId)
.setMatNr(item.getMatnrCode())
.setQty(item.getAnfme() != null ? String.valueOf(item.getAnfme()) : "0")
- .setBatch(item.getBatch());
+ .setBatch(item.getBatch())
+ .setInbound(isInbound)
+ .setBarcode(task.getBarcode());
try {
String requestBody = om.writeValueAsString(param);
CloudWmsNotifyLog notifyLog = new CloudWmsNotifyLog()
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/HttpAuditLogController.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/HttpAuditLogController.java
new file mode 100644
index 0000000..dc962df
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/controller/HttpAuditLogController.java
@@ -0,0 +1,43 @@
+package com.vincent.rsf.server.system.controller;
+
+import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import com.vincent.rsf.server.common.domain.BaseParam;
+import com.vincent.rsf.server.common.domain.PageParam;
+import com.vincent.rsf.server.system.service.HttpAuditLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.Map;
+
+@RestController
+public class HttpAuditLogController extends BaseController {
+
+ @Autowired
+ private HttpAuditLogService httpAuditLogService;
+
+ @PreAuthorize("hasAuthority('system:httpAuditLog:list')")
+ @PostMapping("/httpAuditLog/page")
+ public R page(@RequestBody Map<String, Object> map) {
+ BaseParam baseParam = buildParam(map, BaseParam.class);
+ PageParam<HttpAuditLog, BaseParam> pageParam = new PageParam<>(baseParam, HttpAuditLog.class);
+ return R.ok().add(httpAuditLogService.page(pageParam, pageParam.buildWrapper(true)));
+ }
+
+ @PreAuthorize("hasAuthority('system:httpAuditLog:list')")
+ @GetMapping("/httpAuditLog/{id}")
+ public R get(@PathVariable("id") Long id) {
+ return R.ok().add(httpAuditLogService.getById(id));
+ }
+
+ @PreAuthorize("hasAuthority('system:httpAuditLog:remove')")
+ @PostMapping("/httpAuditLog/remove/{ids}")
+ public R remove(@PathVariable Long[] ids) {
+ if (!httpAuditLogService.removeByIds(Arrays.asList(ids))) {
+ return R.error("Delete Fail");
+ }
+ return R.ok("Delete Success");
+ }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/service/HttpAuditLogService.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/service/HttpAuditLogService.java
new file mode 100644
index 0000000..3c6cbdb
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/service/HttpAuditLogService.java
@@ -0,0 +1,7 @@
+package com.vincent.rsf.server.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+
+public interface HttpAuditLogService extends IService<HttpAuditLog> {
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/HttpAuditLogServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/HttpAuditLogServiceImpl.java
new file mode 100644
index 0000000..de929f5
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/HttpAuditLogServiceImpl.java
@@ -0,0 +1,11 @@
+package com.vincent.rsf.server.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import com.vincent.rsf.httpaudit.mapper.HttpAuditLogMapper;
+import com.vincent.rsf.server.system.service.HttpAuditLogService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class HttpAuditLogServiceImpl extends ServiceImpl<HttpAuditLogMapper, HttpAuditLog> implements HttpAuditLogService {
+}
diff --git a/rsf-server/src/main/resources/application-dev.yml b/rsf-server/src/main/resources/application-dev.yml
index 4a1f465..76ca7f2 100644
--- a/rsf-server/src/main/resources/application-dev.yml
+++ b/rsf-server/src/main/resources/application-dev.yml
@@ -81,12 +81,19 @@
port: 8080
#鎺ュ搧閾炬帴鍓嶇紑
pre-path: ""
- # Feign 璋冪敤浜戜粨鏃剁殑鏍瑰湴鍧�銆備簯浠撴湭鎻愪緵 URL 鏃跺彲鐢ㄦ湰鏈烘ā鎷燂細http://127.0.0.1:8086/rsf-server锛堟湰鏈嶅姟鎻愪緵鐨� CloudWmsMockController锛�
+ # Feign 璋冪敤浜戜粨鏃剁殑鏍瑰湴鍧�銆傛湰鏈烘ā鎷燂細http://127.0.0.1:8086/rsf-server锛圕loudWmsMockController锛�/dapilc/.../cusInventoryCompletionReport 绛夛級
base-url: http://127.0.0.1:8086/rsf-server
- #鎺ュ彛鏄庣粏锛堢珛搴撲晶璇锋眰浜戜粨鏃朵娇鐢ㄧ殑璺緞锛�
+ # 榧庢嵎 DAP ilcwmsplus 瀹屾垚鍙嶉锛�9.1/9.2 缁勫寘鐢級
+ dap:
+ org-no: ""
+ doc-type-in: ""
+ doc-type-out: ""
+ doc-type-adj: ""
+ unit-no: PCS
+ #鎺ュ彛鏄庣粏锛堣川妫�绛夛紱鍏ュ嚭搴撳畬鎴愬凡鍥哄畾涓� /dapilc/restful/service/ilcwmsplus/IKWebService/...锛�
api:
notify-inspect: /report/inspect
- in-out-result-path: /api/report/inOutResult
+ in-out-result-path: /dapilc/restful/service/ilcwmsplus/IKWebService/cusInventoryCompletionReport
inventory-adjust-path: /api/report/inventoryAdjust
mat-sync-path: /api/mat/sync
rcs:
@@ -105,4 +112,15 @@
#鍒ゆ柇鏄悗妫�楠屽悎鏍煎悗锛屾墠鍏佽涓婃灦
flagAvailable: true
#鍒ゆ柇鏄惁鏍¢獙鍚堟牸鍚庯紝鎵嶅厑璁告敹璐�
- flagReceiving: false
\ No newline at end of file
+ flagReceiving: false
+
+# HTTP 鎺ュ彛瀹¤锛坮sf-http-audit锛屽紩鍏ヤ緷璧栧嵆鐢熸晥锛屽彲 enabled=false 鍏抽棴锛�
+http-audit:
+ enabled: true
+ query-response-max-chars: 500
+ max-response-store-chars: 65535
+ path-descriptions:
+ "/erp/order": "浜戜粨-璁㈠崟鏌ヨ"
+ "/erp/order/add": "浜戜粨-鍗曟嵁涓嬪彂"
+ "/erp/order/addAll": "浜戜粨-鎵归噺鍗曟嵁涓嬪彂"
+ "/erp/order/cancel": "浜戜粨-鍙栨秷鍗曟嵁"
\ No newline at end of file
diff --git a/version/db/http_audit_menu.sql b/version/db/http_audit_menu.sql
new file mode 100644
index 0000000..9ce0b4f
--- /dev/null
+++ b/version/db/http_audit_menu.sql
@@ -0,0 +1,22 @@
+-- HTTP 鎺ュ彛瀹¤鑿滃崟锛堢郴缁熺鐞嗕笅锛屼笌鎿嶄綔鏃ュ織鍚岀骇锛夛紱鎵ц鍓嶈纭 id 210-212 鏈鍗犵敤
+SET NAMES utf8mb4;
+
+INSERT INTO `sys_menu` (`id`, `name`, `parent_id`, `parent_name`, `path`, `path_name`, `route`, `component`, `brief`, `code`, `type`, `authority`, `icon`, `sort`, `meta`, `tenant_id`, `status`, `deleted`, `create_time`, `create_by`, `update_time`, `update_by`, `memo`)
+SELECT 210, 'menu.httpAuditLog', 1, 'menu.system', '1,210', 'menu.httpAuditLog', '/system/httpAuditLog', 'httpAuditLog', NULL, NULL, 0, NULL, 'Http', 6, NULL, 1, 1, 0, NULL, NULL, NULL, NULL, NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `id` = 210);
+
+INSERT INTO `sys_menu` (`id`, `name`, `parent_id`, `parent_name`, `path`, `path_name`, `route`, `component`, `brief`, `code`, `type`, `authority`, `icon`, `sort`, `meta`, `tenant_id`, `status`, `deleted`, `create_time`, `create_by`, `update_time`, `update_by`, `memo`)
+SELECT 211, 'Query HttpAuditLog', 210, '', '1,210,211', NULL, NULL, NULL, NULL, NULL, 1, 'system:httpAuditLog:list', NULL, 0, NULL, 1, 1, 0, NULL, NULL, NULL, NULL, NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `id` = 211);
+
+INSERT INTO `sys_menu` (`id`, `name`, `parent_id`, `parent_name`, `path`, `path_name`, `route`, `component`, `brief`, `code`, `type`, `authority`, `icon`, `sort`, `meta`, `tenant_id`, `status`, `deleted`, `create_time`, `create_by`, `update_time`, `update_by`, `memo`)
+SELECT 212, 'Delete HttpAuditLog', 210, '', '1,210,212', NULL, NULL, NULL, NULL, NULL, 1, 'system:httpAuditLog:remove', NULL, 1, NULL, 1, 1, 0, NULL, NULL, NULL, NULL, NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `id` = 212);
+
+-- 瓒呯骇绠$悊鍛樿鑹�(role_id=1)鎺堟潈鑿滃崟锛堣嫢宸插瓨鍦ㄥ垯璺宠繃锛�
+INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
+SELECT 1, 210 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_menu` WHERE `role_id` = 1 AND `menu_id` = 210);
+INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
+SELECT 1, 211 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_menu` WHERE `role_id` = 1 AND `menu_id` = 211);
+INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
+SELECT 1, 212 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_menu` WHERE `role_id` = 1 AND `menu_id` = 212);
diff --git a/version/db/sys_http_audit_log.sql b/version/db/sys_http_audit_log.sql
new file mode 100644
index 0000000..afa0d8b
--- /dev/null
+++ b/version/db/sys_http_audit_log.sql
@@ -0,0 +1,27 @@
+-- HTTP 鎺ュ彛瀹¤锛坮sf-http-audit 鎻掍欢鍐欏叆锛�
+SET NAMES utf8mb4;
+
+DROP TABLE IF EXISTS `sys_http_audit_log`;
+CREATE TABLE `sys_http_audit_log` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '涓婚敭',
+ `service_name` varchar(64) DEFAULT NULL COMMENT '搴旂敤 spring.application.name',
+ `scope_type` varchar(16) NOT NULL COMMENT 'EXTERNAL 澶栭儴 / INTERNAL 鍐呴儴',
+ `uri` varchar(512) NOT NULL COMMENT '璇锋眰璺緞',
+ `method` varchar(16) DEFAULT NULL COMMENT 'HTTP 鏂规硶',
+ `function_desc` varchar(255) DEFAULT NULL COMMENT '鍔熻兘鎻忚堪',
+ `query_string` varchar(2048) DEFAULT NULL COMMENT 'QueryString',
+ `request_body` longtext COMMENT '璇锋眰浣擄紙鍏ㄩ噺锛�',
+ `response_body` longtext COMMENT '鍝嶅簲浣擄紙鏌ヨ绫绘垨瓒呴暱浼氭埅鏂級',
+ `response_truncated` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1 鍝嶅簲宸叉埅鏂�',
+ `http_status` int(11) DEFAULT NULL COMMENT 'HTTP 鐘舵�佺爜',
+ `ok_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1 姝e父 0 寮傚父',
+ `spend_ms` int(11) DEFAULT NULL COMMENT '鑰楁椂姣',
+ `client_ip` varchar(64) DEFAULT NULL COMMENT '瀹㈡埛绔� IP',
+ `error_message` text COMMENT '寮傚父鎽樿',
+ `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+ `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '閫昏緫鍒犻櫎',
+ PRIMARY KEY (`id`),
+ KEY `idx_create_time` (`create_time`),
+ KEY `idx_uri` (`uri`(191)),
+ KEY `idx_ok_client` (`ok_flag`,`client_ip`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='HTTP鎺ュ彛瀹¤';
--
Gitblit v1.9.1