Compare commits
10 Commits
7a8df1f0d4
...
e3f6fa236d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3f6fa236d | ||
|
|
bb212aff36 | ||
|
|
e9cdad0063 | ||
|
|
e7e5bc2386 | ||
|
|
4c427672a3 | ||
|
|
4733677334 | ||
|
|
4759295ce1 | ||
|
|
541dd5e4c8 | ||
|
|
a5b1b406ea | ||
|
|
ec8ae6a73b |
8
.gitignore
vendored
8
.gitignore
vendored
@ -99,3 +99,11 @@ Temporary Items
|
|||||||
# Local runtime data and certificates
|
# Local runtime data and certificates
|
||||||
data/
|
data/
|
||||||
deploy/bin/
|
deploy/bin/
|
||||||
|
|
||||||
|
# Node modules — install via `cd deploy/tools && npm ci`
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Environment secrets
|
||||||
|
.env
|
||||||
|
deploy/.env
|
||||||
|
!deploy/.env.example
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
stages:
|
stages:
|
||||||
- build-1
|
- build-1
|
||||||
- build-2
|
- build-2
|
||||||
|
- build-3
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
HARBOR_REGISTRY: harbor-in-k3s.cheverjohn.me
|
HARBOR_REGISTRY: harbor-in-k3s.cheverjohn.me
|
||||||
@ -13,7 +14,8 @@ variables:
|
|||||||
.build-template: &build-template
|
.build-template: &build-template
|
||||||
image: docker:27
|
image: docker:27
|
||||||
services:
|
services:
|
||||||
- docker:27-dind
|
- name: docker:27-dind
|
||||||
|
command: ["--dns", "10.43.0.10", "--dns", "223.5.5.5"]
|
||||||
retry: 2
|
retry: 2
|
||||||
before_script:
|
before_script:
|
||||||
- until docker info >/dev/null 2>&1; do echo "Waiting for Docker daemon..."; sleep 2; done
|
- until docker info >/dev/null 2>&1; do echo "Waiting for Docker daemon..."; sleep 2; done
|
||||||
@ -22,14 +24,18 @@ variables:
|
|||||||
- |
|
- |
|
||||||
if [ -n "$CI_COMMIT_TAG" ]; then
|
if [ -n "$CI_COMMIT_TAG" ]; then
|
||||||
TAG="$CI_COMMIT_TAG"
|
TAG="$CI_COMMIT_TAG"
|
||||||
else
|
elif [ "$CI_COMMIT_BRANCH" = "main" ]; then
|
||||||
TAG="main-${CI_COMMIT_SHORT_SHA}"
|
TAG="main-${CI_COMMIT_SHORT_SHA}"
|
||||||
|
else
|
||||||
|
TAG="feat-${CI_COMMIT_SHORT_SHA}"
|
||||||
fi
|
fi
|
||||||
- docker build -t $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$TAG -f $DOCKERFILE_PATH .
|
- docker build --network host -t $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$TAG -f $DOCKERFILE_PATH .
|
||||||
- docker push $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$TAG
|
- docker push $HARBOR_REGISTRY/$HARBOR_PROJECT/$IMAGE_NAME:$TAG
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == "main"
|
- if: $CI_COMMIT_BRANCH == "main"
|
||||||
- if: $CI_COMMIT_TAG =~ /^v/
|
- if: $CI_COMMIT_TAG =~ /^v/
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||||
|
- if: $CI_COMMIT_BRANCH =~ /^feat\//
|
||||||
|
|
||||||
build-muyu-gateway:
|
build-muyu-gateway:
|
||||||
<<: *build-template
|
<<: *build-template
|
||||||
@ -51,3 +57,17 @@ build-muyu-inventory-rpc:
|
|||||||
variables:
|
variables:
|
||||||
IMAGE_NAME: muyu-inventory-rpc
|
IMAGE_NAME: muyu-inventory-rpc
|
||||||
DOCKERFILE_PATH: deploy/Dockerfile.inventory
|
DOCKERFILE_PATH: deploy/Dockerfile.inventory
|
||||||
|
|
||||||
|
build-muyu-purchase-rpc:
|
||||||
|
<<: *build-template
|
||||||
|
stage: build-2
|
||||||
|
variables:
|
||||||
|
IMAGE_NAME: muyu-purchase-rpc
|
||||||
|
DOCKERFILE_PATH: deploy/Dockerfile.purchase
|
||||||
|
|
||||||
|
build-muyu-production-rpc:
|
||||||
|
<<: *build-template
|
||||||
|
stage: build-3
|
||||||
|
variables:
|
||||||
|
IMAGE_NAME: muyu-production-rpc
|
||||||
|
DOCKERFILE_PATH: deploy/Dockerfile.production
|
||||||
|
|||||||
13
deploy/.env.example
Normal file
13
deploy/.env.example
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Copy this file to .env and fill in real values
|
||||||
|
# NEVER commit .env to git
|
||||||
|
|
||||||
|
# Database passwords (REQUIRED)
|
||||||
|
MYSQL_ROOT_PASSWORD=your_mysql_password_here
|
||||||
|
POSTGRES_PASSWORD=your_postgres_password_here
|
||||||
|
|
||||||
|
# JWT secret for gateway auth (REQUIRED)
|
||||||
|
ACCESS_SECRET=your_jwt_secret_here
|
||||||
|
|
||||||
|
# Neo4j (only needed for graph stack: docker-compose.graph.yaml)
|
||||||
|
NEO4J_AUTH=neo4j/your_neo4j_password_here
|
||||||
|
NEO4J_PASS=your_neo4j_password_here
|
||||||
@ -11,10 +11,12 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /server ./gateway/gateway.
|
|||||||
|
|
||||||
FROM ${BASE_REGISTRY}/alpine:3.20
|
FROM ${BASE_REGISTRY}/alpine:3.20
|
||||||
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
RUN apk add --no-cache ca-certificates tzdata
|
RUN apk add --no-cache ca-certificates tzdata gettext
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /server ./gateway
|
COPY --from=builder /server ./gateway
|
||||||
COPY deploy/etc/gateway.yaml etc/gateway.yaml
|
COPY deploy/etc/gateway.yaml etc/gateway.yaml
|
||||||
COPY deploy/tools/ tools/
|
COPY deploy/tools/ tools/
|
||||||
|
COPY deploy/entrypoint.sh /entrypoint.sh
|
||||||
EXPOSE 8888
|
EXPOSE 8888
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["./gateway", "-f", "etc/gateway.yaml"]
|
CMD ["./gateway", "-f", "etc/gateway.yaml"]
|
||||||
|
|||||||
@ -11,9 +11,11 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /server ./rpc/inventory/in
|
|||||||
|
|
||||||
FROM ${BASE_REGISTRY}/alpine:3.20
|
FROM ${BASE_REGISTRY}/alpine:3.20
|
||||||
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
RUN apk add --no-cache ca-certificates tzdata
|
RUN apk add --no-cache ca-certificates tzdata gettext
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /server ./inventory
|
COPY --from=builder /server ./inventory
|
||||||
COPY deploy/etc/inventory.yaml etc/inventory.yaml
|
COPY deploy/etc/inventory.yaml etc/inventory.yaml
|
||||||
|
COPY deploy/entrypoint.sh /entrypoint.sh
|
||||||
EXPOSE 9002
|
EXPOSE 9002
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["./inventory", "-f", "etc/inventory.yaml"]
|
CMD ["./inventory", "-f", "etc/inventory.yaml"]
|
||||||
|
|||||||
21
deploy/Dockerfile.production
Normal file
21
deploy/Dockerfile.production
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
ARG BASE_REGISTRY=harbor-in-k3s.cheverjohn.me/library
|
||||||
|
FROM ${BASE_REGISTRY}/golang:1.24-alpine AS builder
|
||||||
|
ENV GOPROXY=https://goproxy.cn,direct
|
||||||
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
|
RUN apk add --no-cache git
|
||||||
|
WORKDIR /app
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /server ./rpc/production/production.go
|
||||||
|
|
||||||
|
FROM ${BASE_REGISTRY}/alpine:3.20
|
||||||
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
|
RUN apk add --no-cache ca-certificates tzdata gettext
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /server ./production
|
||||||
|
COPY deploy/etc/production.yaml etc/production.yaml
|
||||||
|
COPY deploy/entrypoint.sh /entrypoint.sh
|
||||||
|
EXPOSE 9004
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
CMD ["./production", "-f", "etc/production.yaml"]
|
||||||
@ -1,7 +1,21 @@
|
|||||||
FROM alpine:3.19
|
ARG BASE_REGISTRY=harbor-in-k3s.cheverjohn.me/library
|
||||||
RUN apk add --no-cache ca-certificates tzdata
|
FROM ${BASE_REGISTRY}/golang:1.24-alpine AS builder
|
||||||
|
ENV GOPROXY=https://goproxy.cn,direct
|
||||||
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
|
RUN apk add --no-cache git
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY deploy/bin/purchase .
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /server ./rpc/purchase/purchase.go
|
||||||
|
|
||||||
|
FROM ${BASE_REGISTRY}/alpine:3.20
|
||||||
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
|
RUN apk add --no-cache ca-certificates tzdata gettext
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /server ./purchase
|
||||||
COPY deploy/etc/purchase.yaml etc/purchase.yaml
|
COPY deploy/etc/purchase.yaml etc/purchase.yaml
|
||||||
|
COPY deploy/entrypoint.sh /entrypoint.sh
|
||||||
EXPOSE 9003
|
EXPOSE 9003
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["./purchase", "-f", "etc/purchase.yaml"]
|
CMD ["./purchase", "-f", "etc/purchase.yaml"]
|
||||||
|
|||||||
@ -11,9 +11,11 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /server ./rpc/system/syste
|
|||||||
|
|
||||||
FROM ${BASE_REGISTRY}/alpine:3.20
|
FROM ${BASE_REGISTRY}/alpine:3.20
|
||||||
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
RUN sed -i "s|dl-cdn.alpinelinux.org|mirrors.aliyun.com|g" /etc/apk/repositories
|
||||||
RUN apk add --no-cache ca-certificates tzdata
|
RUN apk add --no-cache ca-certificates tzdata gettext
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /server ./system
|
COPY --from=builder /server ./system
|
||||||
COPY deploy/etc/system.yaml etc/system.yaml
|
COPY deploy/etc/system.yaml etc/system.yaml
|
||||||
|
COPY deploy/entrypoint.sh /entrypoint.sh
|
||||||
EXPOSE 9001
|
EXPOSE 9001
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
CMD ["./system", "-f", "etc/system.yaml"]
|
CMD ["./system", "-f", "etc/system.yaml"]
|
||||||
|
|||||||
@ -5,7 +5,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: muyu
|
POSTGRES_USER: muyu
|
||||||
POSTGRES_PASSWORD: muyu2026
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
|
||||||
POSTGRES_DB: muyu_crm
|
POSTGRES_DB: muyu_crm
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
ports:
|
ports:
|
||||||
@ -70,7 +70,7 @@ services:
|
|||||||
container_name: muyu-neo4j
|
container_name: muyu-neo4j
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
NEO4J_AUTH: neo4j/muyu2026
|
NEO4J_AUTH: ${NEO4J_AUTH:?Set NEO4J_AUTH in .env (e.g. neo4j/yourpassword)}
|
||||||
NEO4J_server_memory_heap_initial__size: 512m
|
NEO4J_server_memory_heap_initial__size: 512m
|
||||||
NEO4J_server_memory_heap_max__size: 1024m
|
NEO4J_server_memory_heap_max__size: 1024m
|
||||||
NEO4J_server_default__listen__address: 0.0.0.0
|
NEO4J_server_default__listen__address: 0.0.0.0
|
||||||
@ -103,7 +103,7 @@ services:
|
|||||||
KAFKA_GROUP: graphsync
|
KAFKA_GROUP: graphsync
|
||||||
NEO4J_URI: bolt://neo4j:7687
|
NEO4J_URI: bolt://neo4j:7687
|
||||||
NEO4J_USER: neo4j
|
NEO4J_USER: neo4j
|
||||||
NEO4J_PASS: muyu2026
|
NEO4J_PASS: ${NEO4J_PASS:?Set NEO4J_PASS in .env}
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
|
||||||
kafka-ui:
|
kafka-ui:
|
||||||
|
|||||||
@ -4,7 +4,7 @@ services:
|
|||||||
container_name: muyu-mysql
|
container_name: muyu-mysql
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: muyu2026
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?Set MYSQL_ROOT_PASSWORD in .env}
|
||||||
MYSQL_DATABASE: muyu_wms
|
MYSQL_DATABASE: muyu_wms
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
ports:
|
ports:
|
||||||
@ -39,7 +39,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: muyu
|
POSTGRES_USER: muyu
|
||||||
POSTGRES_PASSWORD: muyu2026
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
|
||||||
POSTGRES_DB: muyu_crm
|
POSTGRES_DB: muyu_crm
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
ports:
|
ports:
|
||||||
@ -90,6 +90,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_DSN: "root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
|
||||||
|
|
||||||
inventory-rpc:
|
inventory-rpc:
|
||||||
build:
|
build:
|
||||||
@ -106,6 +107,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_DSN: "root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
|
||||||
|
|
||||||
purchase-rpc:
|
purchase-rpc:
|
||||||
build:
|
build:
|
||||||
@ -122,6 +124,28 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_DSN: "root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
|
||||||
|
|
||||||
|
production-rpc:
|
||||||
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: deploy/Dockerfile.production
|
||||||
|
container_name: muyu-production-rpc
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "9004:9004"
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
etcd:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- ./etc/production.yaml:/etc/muyu/production.yaml
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_DSN: "root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
|
||||||
|
|
||||||
gateway:
|
gateway:
|
||||||
build:
|
build:
|
||||||
@ -138,10 +162,15 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
purchase-rpc:
|
purchase-rpc:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
|
production-rpc:
|
||||||
|
condition: service_started
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
TZ: Asia/Shanghai
|
TZ: Asia/Shanghai
|
||||||
|
MYSQL_DSN: "root:${MYSQL_ROOT_PASSWORD}@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
|
||||||
|
POSTGRES_DSN: "postgres://muyu:${POSTGRES_PASSWORD}@postgres:5432/muyu_crm?sslmode=disable"
|
||||||
|
ACCESS_SECRET: ${ACCESS_SECRET:?Set ACCESS_SECRET in .env}
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
|
|||||||
28
deploy/entrypoint.sh
Executable file
28
deploy/entrypoint.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Substitute environment variables in YAML config templates before starting the service.
|
||||||
|
# Usage: entrypoint.sh <binary> -f <config.yaml>
|
||||||
|
#
|
||||||
|
# The YAML file is treated as a template with ${VAR} placeholders.
|
||||||
|
# envsubst replaces them with actual environment variable values at container start time.
|
||||||
|
# The rendered config is written to /tmp to avoid read-only filesystem issues (e.g. ConfigMap mounts).
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BINARY="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
# Scan args for -f <config> and render to /tmp
|
||||||
|
ARGS=""
|
||||||
|
PREV=""
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [ "$PREV" = "-f" ] && [ -f "$arg" ]; then
|
||||||
|
RENDERED="/tmp/$(basename "$arg")"
|
||||||
|
envsubst < "$arg" > "$RENDERED"
|
||||||
|
ARGS="$ARGS $RENDERED"
|
||||||
|
else
|
||||||
|
ARGS="$ARGS $arg"
|
||||||
|
fi
|
||||||
|
PREV="$arg"
|
||||||
|
done
|
||||||
|
|
||||||
|
exec "$BINARY" $ARGS
|
||||||
@ -4,12 +4,12 @@ Port: 8888
|
|||||||
Timeout: 120000
|
Timeout: 120000
|
||||||
|
|
||||||
Auth:
|
Auth:
|
||||||
AccessSecret: muyu-wms-jwt-secret-key-2026
|
AccessSecret: ${ACCESS_SECRET}
|
||||||
AccessExpire: 7200
|
AccessExpire: 7200
|
||||||
DefaultTenantId: t_default_001
|
DefaultTenantId: t_default_001
|
||||||
|
|
||||||
DataSource: root:muyu2026@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
DataSource: ${MYSQL_DSN}
|
||||||
PostgresDataSource: "postgres://muyu:muyu2026@postgres:5432/muyu_crm?sslmode=disable"
|
PostgresDataSource: ${POSTGRES_DSN}
|
||||||
|
|
||||||
SystemRpc:
|
SystemRpc:
|
||||||
Etcd:
|
Etcd:
|
||||||
@ -34,6 +34,14 @@ PurchaseRpc:
|
|||||||
NonBlock: true
|
NonBlock: true
|
||||||
Timeout: 60000
|
Timeout: 60000
|
||||||
|
|
||||||
|
ProductionRpc:
|
||||||
|
Etcd:
|
||||||
|
Hosts:
|
||||||
|
- etcd:2379
|
||||||
|
Key: production.rpc
|
||||||
|
NonBlock: true
|
||||||
|
Timeout: 60000
|
||||||
|
|
||||||
Log:
|
Log:
|
||||||
ServiceName: gateway-api
|
ServiceName: gateway-api
|
||||||
Mode: console
|
Mode: console
|
||||||
|
|||||||
@ -6,7 +6,7 @@ Etcd:
|
|||||||
- etcd:2379
|
- etcd:2379
|
||||||
Key: inventory.rpc
|
Key: inventory.rpc
|
||||||
|
|
||||||
DataSource: root:muyu2026@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
DataSource: ${MYSQL_DSN}
|
||||||
|
|
||||||
Cache:
|
Cache:
|
||||||
- Host: redis:6379
|
- Host: redis:6379
|
||||||
|
|||||||
17
deploy/etc/production.yaml
Normal file
17
deploy/etc/production.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Name: production.rpc
|
||||||
|
ListenOn: 0.0.0.0:9004
|
||||||
|
|
||||||
|
Etcd:
|
||||||
|
Hosts:
|
||||||
|
- etcd:2379
|
||||||
|
Key: production.rpc
|
||||||
|
|
||||||
|
DataSource: ${MYSQL_DSN}
|
||||||
|
|
||||||
|
Cache:
|
||||||
|
- Host: redis:6379
|
||||||
|
|
||||||
|
Log:
|
||||||
|
ServiceName: production-rpc
|
||||||
|
Mode: console
|
||||||
|
Level: info
|
||||||
@ -6,7 +6,7 @@ Etcd:
|
|||||||
- etcd:2379
|
- etcd:2379
|
||||||
Key: purchase.rpc
|
Key: purchase.rpc
|
||||||
|
|
||||||
DataSource: root:muyu2026@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
DataSource: ${MYSQL_DSN}
|
||||||
|
|
||||||
Cache:
|
Cache:
|
||||||
- Host: redis:6379
|
- Host: redis:6379
|
||||||
|
|||||||
@ -6,7 +6,7 @@ Etcd:
|
|||||||
- etcd:2379
|
- etcd:2379
|
||||||
Key: system.rpc
|
Key: system.rpc
|
||||||
|
|
||||||
DataSource: root:muyu2026@tcp(mysql:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
DataSource: ${MYSQL_DSN}
|
||||||
|
|
||||||
Cache:
|
Cache:
|
||||||
- Host: redis:6379
|
- Host: redis:6379
|
||||||
|
|||||||
@ -210,16 +210,14 @@ CREATE TABLE `crm_data_migration_log` (
|
|||||||
|
|
||||||
CREATE TABLE `inv_product` (
|
CREATE TABLE `inv_product` (
|
||||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT 't_default_001',
|
||||||
`product_id` VARCHAR(32) NOT NULL,
|
`product_id` VARCHAR(32) NOT NULL,
|
||||||
`product_name` VARCHAR(100) NOT NULL,
|
`product_name` VARCHAR(100) NOT NULL,
|
||||||
`image_url` VARCHAR(255) NOT NULL DEFAULT '',
|
`image_url` VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
`spec` VARCHAR(100) NOT NULL DEFAULT '',
|
`spec` VARCHAR(100) NOT NULL DEFAULT '',
|
||||||
`color` VARCHAR(50) NOT NULL DEFAULT '',
|
`color` VARCHAR(50) NOT NULL DEFAULT '本色',
|
||||||
`unit_pieces` INT NOT NULL DEFAULT 0,
|
`color_no` VARCHAR(20) NOT NULL DEFAULT '',
|
||||||
`unit_rolls` INT NOT NULL DEFAULT 0,
|
`product_code` VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
`stock_quantity` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
|
||||||
`location` VARCHAR(100) NOT NULL DEFAULT '',
|
|
||||||
`cost_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
|
||||||
`sales_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
`sales_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||||
`remark` TEXT,
|
`remark` TEXT,
|
||||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1:enabled 0:disabled',
|
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1:enabled 0:disabled',
|
||||||
@ -228,12 +226,96 @@ CREATE TABLE `inv_product` (
|
|||||||
`deleted_at` DATETIME DEFAULT NULL,
|
`deleted_at` DATETIME DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `uk_product_id` (`product_id`),
|
UNIQUE KEY `uk_product_id` (`product_id`),
|
||||||
UNIQUE KEY `uk_product_name_spec_color` (`product_name`, `spec`, `color`),
|
UNIQUE KEY `uk_tenant_product_code` (`tenant_id`, `product_code`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_product_name_tenant` (`product_name`, `tenant_id`),
|
||||||
KEY `idx_color` (`color`),
|
KEY `idx_color` (`color`),
|
||||||
KEY `idx_location` (`location`),
|
|
||||||
KEY `idx_status` (`status`),
|
KEY `idx_status` (`status`),
|
||||||
KEY `idx_deleted_at` (`deleted_at`)
|
KEY `idx_deleted_at` (`deleted_at`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品档案';
|
||||||
|
|
||||||
|
CREATE TABLE `inv_yarn` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`yarn_id` VARCHAR(32) NOT NULL,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`yarn_name` VARCHAR(100) NOT NULL,
|
||||||
|
`color` VARCHAR(50) NOT NULL DEFAULT '原纱本色',
|
||||||
|
`weight_g_m` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`supplier_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`dye_factory` VARCHAR(100) NOT NULL DEFAULT '无',
|
||||||
|
`image_url` VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
|
`remark` TEXT,
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1:enabled 0:disabled',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted_at` DATETIME DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_yarn_id` (`yarn_id`),
|
||||||
|
UNIQUE KEY `uk_tenant_yarn_name_color_supplier` (`tenant_id`, `yarn_name`, `color`, `supplier_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_supplier_id` (`supplier_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_deleted_at` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='原料纱档案';
|
||||||
|
|
||||||
|
CREATE TABLE `inv_product_batch` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`batch_id` VARCHAR(32) NOT NULL,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`product_id` VARCHAR(32) NOT NULL,
|
||||||
|
`batch_no` VARCHAR(64) NOT NULL DEFAULT '',
|
||||||
|
`yarn_ratio` JSON DEFAULT NULL,
|
||||||
|
`warp_weight_g_m` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`weft_weight_g_m` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`production_process` TEXT,
|
||||||
|
`remark` TEXT,
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1:enabled 0:disabled',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted_at` DATETIME DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_batch_id` (`batch_id`),
|
||||||
|
UNIQUE KEY `uk_tenant_batch_no` (`tenant_id`, `batch_no`),
|
||||||
|
KEY `idx_product_id` (`product_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_deleted_at` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品批次表';
|
||||||
|
|
||||||
|
CREATE TABLE `inv_product_pan` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`pan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`product_id` VARCHAR(32) NOT NULL,
|
||||||
|
`batch_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`name` VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
|
`position` VARCHAR(100) NOT NULL DEFAULT '',
|
||||||
|
`sort_order` INT NOT NULL DEFAULT 0,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_pan_id` (`pan_id`),
|
||||||
|
KEY `idx_product_id` (`product_id`),
|
||||||
|
KEY `idx_batch_id` (`batch_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_position` (`position`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品盘库存';
|
||||||
|
|
||||||
|
CREATE TABLE `inv_product_bolt` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`bolt_id` VARCHAR(32) NOT NULL,
|
||||||
|
`pan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`length_m` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||||
|
`color` VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
|
`sort_order` INT NOT NULL DEFAULT 0,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_bolt_id` (`bolt_id`),
|
||||||
|
KEY `idx_pan_id` (`pan_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品匹库存';
|
||||||
|
|
||||||
CREATE TABLE `inv_stock_import_log` (
|
CREATE TABLE `inv_stock_import_log` (
|
||||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
|||||||
79
deploy/mysql/migrations/20260629_phase3_e2e_validation.sql
Normal file
79
deploy/mysql/migrations/20260629_phase3_e2e_validation.sql
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
-- End-to-End Validation Queries for Production Plan Collaboration
|
||||||
|
-- Run these after testing the full flow to verify data consistency
|
||||||
|
|
||||||
|
-- 1. Verify production plan exists and has correct structure
|
||||||
|
SELECT p.plan_id, p.plan_code, p.product_name, p.target_quantity,
|
||||||
|
p.completed_quantity, p.status,
|
||||||
|
ROUND(p.completed_quantity * 100.0 / NULLIF(p.target_quantity, 0), 1) as progress_pct
|
||||||
|
FROM pro_production_plan p
|
||||||
|
WHERE p.tenant_id = 'TEST_TENANT'
|
||||||
|
ORDER BY p.created_at DESC LIMIT 5;
|
||||||
|
|
||||||
|
-- 2. Verify yarn ratios sum to 100%
|
||||||
|
SELECT yr.plan_id,
|
||||||
|
COUNT(*) as ratio_count,
|
||||||
|
SUM(yr.ratio) as total_ratio,
|
||||||
|
CASE WHEN ABS(SUM(yr.ratio) - 1.0) < 0.01 THEN 'OK' ELSE 'MISMATCH' END as check_result
|
||||||
|
FROM pro_plan_yarn_ratio yr
|
||||||
|
GROUP BY yr.plan_id;
|
||||||
|
|
||||||
|
-- 3. Verify process steps — each plan should have exactly 5 steps
|
||||||
|
SELECT ps.plan_id,
|
||||||
|
COUNT(*) as step_count,
|
||||||
|
SUM(CASE WHEN ps.status = 2 THEN 1 ELSE 0 END) as completed_steps,
|
||||||
|
CASE WHEN COUNT(*) = 5 THEN 'OK' ELSE 'MISSING_STEPS' END as check_result
|
||||||
|
FROM pro_plan_process_step ps
|
||||||
|
GROUP BY ps.plan_id;
|
||||||
|
|
||||||
|
-- 4. Verify share link lifecycle
|
||||||
|
SELECT sl.short_code, sl.status, sl.click_count,
|
||||||
|
sl.expires_at, NOW() as current_time,
|
||||||
|
CASE WHEN sl.expires_at > NOW() THEN 'VALID' ELSE 'EXPIRED' END as expiry_check,
|
||||||
|
pf.factory_tenant_id
|
||||||
|
FROM pro_share_link sl
|
||||||
|
LEFT JOIN pro_plan_factory pf ON pf.plan_id = sl.plan_id
|
||||||
|
ORDER BY sl.created_at DESC LIMIT 5;
|
||||||
|
|
||||||
|
-- 5. CRITICAL: Verify data consistency — completed_quantity must equal SUM(inbound)
|
||||||
|
SELECT p.plan_id, p.plan_code,
|
||||||
|
p.completed_quantity as plan_completed,
|
||||||
|
COALESCE(SUM(ir.quantity), 0) as inbound_sum,
|
||||||
|
CASE
|
||||||
|
WHEN ABS(p.completed_quantity - COALESCE(SUM(ir.quantity), 0)) < 0.01 THEN 'CONSISTENT'
|
||||||
|
ELSE 'DRIFT_DETECTED'
|
||||||
|
END as consistency_check
|
||||||
|
FROM pro_production_plan p
|
||||||
|
LEFT JOIN pro_inbound_record ir ON ir.plan_id = p.plan_id
|
||||||
|
GROUP BY p.plan_id, p.plan_code, p.completed_quantity;
|
||||||
|
|
||||||
|
-- 6. Verify auto-completion: plans with completed_quantity >= target_quantity should be status=3
|
||||||
|
SELECT p.plan_id, p.plan_code,
|
||||||
|
p.target_quantity, p.completed_quantity, p.status,
|
||||||
|
CASE
|
||||||
|
WHEN p.completed_quantity >= p.target_quantity AND p.status != 3 THEN 'SHOULD_BE_COMPLETED'
|
||||||
|
WHEN p.completed_quantity < p.target_quantity AND p.status = 3 THEN 'PREMATURE_COMPLETION'
|
||||||
|
ELSE 'OK'
|
||||||
|
END as auto_complete_check
|
||||||
|
FROM pro_production_plan p
|
||||||
|
WHERE p.status IN (2, 3);
|
||||||
|
|
||||||
|
-- 7. Verify inventory logs match inbound records
|
||||||
|
SELECT ir.record_id, ir.quantity,
|
||||||
|
il.change_qty, il.ref_type, il.ref_id,
|
||||||
|
CASE
|
||||||
|
WHEN il.log_id IS NULL THEN 'MISSING_LOG'
|
||||||
|
WHEN ABS(ir.quantity - il.change_qty) < 0.01 THEN 'OK'
|
||||||
|
ELSE 'QUANTITY_MISMATCH'
|
||||||
|
END as log_check
|
||||||
|
FROM pro_inbound_record ir
|
||||||
|
LEFT JOIN inv_inventory_log il ON il.ref_id = ir.record_id AND il.ref_type = 'PRODUCTION';
|
||||||
|
|
||||||
|
-- 8. Summary report
|
||||||
|
SELECT
|
||||||
|
(SELECT COUNT(*) FROM pro_production_plan) as total_plans,
|
||||||
|
(SELECT COUNT(*) FROM pro_production_plan WHERE status = 3) as completed_plans,
|
||||||
|
(SELECT COUNT(*) FROM pro_share_link) as total_links,
|
||||||
|
(SELECT COUNT(*) FROM pro_share_link WHERE status = 2) as confirmed_links,
|
||||||
|
(SELECT COUNT(*) FROM pro_inbound_record) as total_inbound_records,
|
||||||
|
(SELECT COALESCE(SUM(quantity), 0) FROM pro_inbound_record) as total_inbound_meters,
|
||||||
|
(SELECT COUNT(*) FROM inv_inventory_log WHERE ref_type = 'PRODUCTION') as production_inv_logs;
|
||||||
@ -0,0 +1,133 @@
|
|||||||
|
-- Phase 3: Production Plan Collaboration + Batch Inbound
|
||||||
|
|
||||||
|
-- ==================== Production Plan ====================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pro_production_plan` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`plan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`plan_code` VARCHAR(32) NOT NULL COMMENT 'PP-YYYYMMDD-XXXX',
|
||||||
|
`product_id` VARCHAR(32) NOT NULL,
|
||||||
|
`product_name` VARCHAR(100) NOT NULL DEFAULT '',
|
||||||
|
`color` VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
|
`fabric_code` VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
|
`color_code` VARCHAR(20) NOT NULL DEFAULT '',
|
||||||
|
`target_quantity` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT 'target meters',
|
||||||
|
`completed_quantity` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT 'completed meters = SUM(inbound)',
|
||||||
|
`yarn_usage_per_meter` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'grams per meter',
|
||||||
|
`production_price` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'yuan per meter',
|
||||||
|
`supplier_id` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'pur_supplier.supplier_id as textile factory',
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '0:draft 1:pending 2:producing 3:completed 4:cancelled',
|
||||||
|
`remark` TEXT,
|
||||||
|
`start_time` DATETIME DEFAULT NULL,
|
||||||
|
`creator` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`operator` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_plan_id` (`plan_id`),
|
||||||
|
UNIQUE KEY `uk_plan_code_tenant` (`plan_code`, `tenant_id`),
|
||||||
|
KEY `idx_tenant_status` (`tenant_id`, `status`),
|
||||||
|
KEY `idx_product` (`product_id`),
|
||||||
|
KEY `idx_supplier` (`supplier_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='生产计划';
|
||||||
|
|
||||||
|
-- ==================== Yarn Ratio ====================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pro_plan_yarn_ratio` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`ratio_id` VARCHAR(32) NOT NULL,
|
||||||
|
`plan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`yarn_name` VARCHAR(100) NOT NULL DEFAULT '',
|
||||||
|
`ratio` DECIMAL(5,2) NOT NULL DEFAULT 0.00 COMMENT '0.00-1.00',
|
||||||
|
`amount_per_meter` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'grams',
|
||||||
|
`total_amount` DECIMAL(14,2) NOT NULL DEFAULT 0.00 COMMENT 'grams',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_ratio_id` (`ratio_id`),
|
||||||
|
KEY `idx_plan` (`plan_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='纱线配比';
|
||||||
|
|
||||||
|
-- ==================== Process Step ====================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pro_plan_process_step` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`step_id` VARCHAR(32) NOT NULL,
|
||||||
|
`plan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`step_type` VARCHAR(30) NOT NULL COMMENT 'confirm|yarn_purchase|dyeing|machine_start|fabric_warehouse',
|
||||||
|
`step_order` TINYINT NOT NULL DEFAULT 0,
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '0:pending 1:in_progress 2:completed',
|
||||||
|
`operator_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`completed_at` DATETIME DEFAULT NULL,
|
||||||
|
`remark` TEXT,
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_step_id` (`step_id`),
|
||||||
|
UNIQUE KEY `uk_plan_step` (`plan_id`, `step_type`),
|
||||||
|
KEY `idx_plan` (`plan_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='生产流程节点';
|
||||||
|
|
||||||
|
-- ==================== Share Link ====================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pro_share_link` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`link_id` VARCHAR(32) NOT NULL,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`plan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`short_code` VARCHAR(16) NOT NULL,
|
||||||
|
`token` VARCHAR(512) NOT NULL DEFAULT '',
|
||||||
|
`factory_type` VARCHAR(20) NOT NULL DEFAULT 'textile',
|
||||||
|
`hide_sensitive` TINYINT NOT NULL DEFAULT 0,
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 0 COMMENT '0:pending 1:clicked 2:confirmed 3:rejected 4:expired',
|
||||||
|
`click_count` INT NOT NULL DEFAULT 0,
|
||||||
|
`clicked_at` DATETIME DEFAULT NULL,
|
||||||
|
`responded_at` DATETIME DEFAULT NULL,
|
||||||
|
`reject_reason` VARCHAR(500) NOT NULL DEFAULT '',
|
||||||
|
`expires_at` DATETIME NOT NULL,
|
||||||
|
`created_by` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_link_id` (`link_id`),
|
||||||
|
UNIQUE KEY `uk_short_code` (`short_code`),
|
||||||
|
KEY `idx_plan` (`plan_id`),
|
||||||
|
KEY `idx_tenant` (`tenant_id`),
|
||||||
|
KEY `idx_status_expires` (`status`, `expires_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='分享链接';
|
||||||
|
|
||||||
|
-- ==================== Plan Factory ====================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pro_plan_factory` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`plan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`factory_tenant_id` VARCHAR(32) NOT NULL,
|
||||||
|
`factory_type` VARCHAR(20) NOT NULL DEFAULT 'textile',
|
||||||
|
`share_link_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_plan_factory` (`plan_id`, `factory_tenant_id`),
|
||||||
|
KEY `idx_factory` (`factory_tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='计划-工厂关联';
|
||||||
|
|
||||||
|
-- ==================== Inbound Record ====================
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pro_inbound_record` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`record_id` VARCHAR(32) NOT NULL,
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`plan_id` VARCHAR(32) NOT NULL,
|
||||||
|
`product_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`batch_no` VARCHAR(50) NOT NULL DEFAULT '',
|
||||||
|
`quantity` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT 'meters',
|
||||||
|
`rolls` INT NOT NULL DEFAULT 0,
|
||||||
|
`price_per_meter` DECIMAL(10,2) NOT NULL DEFAULT 0.00,
|
||||||
|
`operator_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`remark` TEXT,
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_record_id` (`record_id`),
|
||||||
|
KEY `idx_plan` (`plan_id`),
|
||||||
|
KEY `idx_tenant` (`tenant_id`),
|
||||||
|
KEY `idx_product` (`product_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='按计划分批入库';
|
||||||
174
deploy/mysql/migrations/20260703_add_product_yarn_batch.sql
Normal file
174
deploy/mysql/migrations/20260703_add_product_yarn_batch.sql
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
-- Product/yarn/batch model migration.
|
||||||
|
-- Adds yarn master data, product batches, frozen product codes, and pan batch ownership.
|
||||||
|
-- Run after the pan/bolt and purchase-management migrations.
|
||||||
|
|
||||||
|
SET @db = DATABASE();
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `inv_yarn` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`yarn_id` VARCHAR(32) NOT NULL COMMENT 'business key, UUID',
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`yarn_name` VARCHAR(100) NOT NULL,
|
||||||
|
`color` VARCHAR(50) NOT NULL DEFAULT '原纱本色',
|
||||||
|
`weight_g_m` DECIMAL(10,4) NOT NULL DEFAULT 0.0000 COMMENT 'yarn weight (g/m)',
|
||||||
|
`supplier_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`dye_factory` VARCHAR(100) NOT NULL DEFAULT '无',
|
||||||
|
`image_url` VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
|
`remark` TEXT,
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1:enabled 0:disabled',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted_at` DATETIME DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_yarn_id` (`yarn_id`),
|
||||||
|
UNIQUE KEY `uk_tenant_yarn_name_color_supplier` (`tenant_id`, `yarn_name`, `color`, `supplier_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_supplier_id` (`supplier_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_deleted_at` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='原料纱档案';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `inv_product_batch` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`batch_id` VARCHAR(32) NOT NULL COMMENT 'business key, UUID',
|
||||||
|
`tenant_id` VARCHAR(32) NOT NULL DEFAULT '',
|
||||||
|
`product_id` VARCHAR(32) NOT NULL,
|
||||||
|
`batch_no` VARCHAR(64) NOT NULL DEFAULT '' COMMENT 'format: {product_code}-B001',
|
||||||
|
`yarn_ratio` JSON DEFAULT NULL,
|
||||||
|
`warp_weight_g_m` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`weft_weight_g_m` DECIMAL(10,4) NOT NULL DEFAULT 0.0000,
|
||||||
|
`production_process` TEXT,
|
||||||
|
`remark` TEXT,
|
||||||
|
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '1:enabled 0:disabled',
|
||||||
|
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
`deleted_at` DATETIME DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_batch_id` (`batch_id`),
|
||||||
|
UNIQUE KEY `uk_tenant_batch_no` (`tenant_id`, `batch_no`),
|
||||||
|
KEY `idx_product_id` (`product_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_deleted_at` (`deleted_at`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='产品批次表';
|
||||||
|
|
||||||
|
-- inv_product.color_no
|
||||||
|
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='color_no');
|
||||||
|
SET @s = IF(@c=0, 'ALTER TABLE `inv_product` ADD COLUMN `color_no` VARCHAR(20) NOT NULL DEFAULT '''' COMMENT ''色号'' AFTER `color`', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- inv_product.product_code
|
||||||
|
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='product_code');
|
||||||
|
SET @s = IF(@c=0, 'ALTER TABLE `inv_product` ADD COLUMN `product_code` VARCHAR(50) NOT NULL DEFAULT '''' COMMENT ''产品码,创建后冻结'' AFTER `color_no`', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- inv_product_pan.batch_id
|
||||||
|
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product_pan' AND COLUMN_NAME='batch_id');
|
||||||
|
SET @s = IF(@c=0, 'ALTER TABLE `inv_product_pan` ADD COLUMN `batch_id` VARCHAR(32) NOT NULL DEFAULT '''' COMMENT ''FK inv_product_batch.batch_id'' AFTER `product_id`', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @i = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product_pan' AND INDEX_NAME='idx_batch_id');
|
||||||
|
SET @s = IF(@i=0, 'ALTER TABLE `inv_product_pan` ADD KEY `idx_batch_id` (`batch_id`)', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- Align older pan/bolt installations with the current model.
|
||||||
|
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product_bolt' AND COLUMN_NAME='color');
|
||||||
|
SET @s = IF(@c=0, 'ALTER TABLE `inv_product_bolt` ADD COLUMN `color` VARCHAR(50) NOT NULL DEFAULT '''' AFTER `length_m`', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- Backfill product defaults.
|
||||||
|
UPDATE `inv_product`
|
||||||
|
SET `color` = '本色'
|
||||||
|
WHERE `deleted_at` IS NULL AND TRIM(COALESCE(`color`, '')) = '';
|
||||||
|
|
||||||
|
UPDATE `inv_product` p
|
||||||
|
JOIN (
|
||||||
|
SELECT id, LPAD(ROW_NUMBER() OVER (PARTITION BY tenant_id, product_name ORDER BY created_at, id), 2, '0') AS generated_color_no
|
||||||
|
FROM `inv_product`
|
||||||
|
WHERE `deleted_at` IS NULL
|
||||||
|
) x ON x.id = p.id
|
||||||
|
SET p.`color_no` = x.generated_color_no
|
||||||
|
WHERE TRIM(COALESCE(p.`color_no`, '')) = '';
|
||||||
|
|
||||||
|
-- Historical SQL cannot reliably derive pinyin initials. For migrated rows with
|
||||||
|
-- non-latin product names, use a stable P{id} prefix; new writes use backend pinyin.
|
||||||
|
UPDATE `inv_product` p
|
||||||
|
JOIN (
|
||||||
|
SELECT id,
|
||||||
|
UPPER(CONCAT(
|
||||||
|
CASE
|
||||||
|
WHEN REGEXP_REPLACE(product_name, '[^0-9A-Za-z]', '') = '' THEN CONCAT('P', id)
|
||||||
|
ELSE REGEXP_REPLACE(product_name, '[^0-9A-Za-z]', '')
|
||||||
|
END,
|
||||||
|
color_no
|
||||||
|
)) AS raw_code
|
||||||
|
FROM `inv_product`
|
||||||
|
WHERE `deleted_at` IS NULL
|
||||||
|
) b ON b.id = p.id
|
||||||
|
SET p.`product_code` = LEFT(b.raw_code, 50)
|
||||||
|
WHERE TRIM(COALESCE(p.`product_code`, '')) = '';
|
||||||
|
|
||||||
|
UPDATE `inv_product` p
|
||||||
|
JOIN (
|
||||||
|
SELECT id,
|
||||||
|
CASE
|
||||||
|
WHEN rn = 1 THEN raw_code
|
||||||
|
ELSE LEFT(CONCAT(raw_code, '-', id), 50)
|
||||||
|
END AS unique_code
|
||||||
|
FROM (
|
||||||
|
SELECT id, tenant_id, product_code AS raw_code,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY tenant_id, product_code ORDER BY id) AS rn
|
||||||
|
FROM `inv_product`
|
||||||
|
WHERE `deleted_at` IS NULL
|
||||||
|
) d
|
||||||
|
) u ON u.id = p.id
|
||||||
|
SET p.`product_code` = u.unique_code;
|
||||||
|
|
||||||
|
-- Default B001 batch for every historical product.
|
||||||
|
INSERT INTO `inv_product_batch` (
|
||||||
|
`batch_id`, `tenant_id`, `product_id`, `batch_no`,
|
||||||
|
`yarn_ratio`, `warp_weight_g_m`, `weft_weight_g_m`,
|
||||||
|
`production_process`, `remark`, `status`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
MD5(CONCAT('B001:', p.`tenant_id`, ':', p.`product_id`)),
|
||||||
|
p.`tenant_id`,
|
||||||
|
p.`product_id`,
|
||||||
|
CONCAT(p.`product_code`, '-B001'),
|
||||||
|
NULL,
|
||||||
|
0.0000,
|
||||||
|
0.0000,
|
||||||
|
'无',
|
||||||
|
NULL,
|
||||||
|
1
|
||||||
|
FROM `inv_product` p
|
||||||
|
WHERE p.`deleted_at` IS NULL
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1 FROM `inv_product_batch` b
|
||||||
|
WHERE b.`tenant_id` = p.`tenant_id`
|
||||||
|
AND b.`product_id` = p.`product_id`
|
||||||
|
AND b.`batch_no` = CONCAT(p.`product_code`, '-B001')
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE `inv_product_pan` pan
|
||||||
|
JOIN `inv_product` p ON p.`product_id` = pan.`product_id`
|
||||||
|
JOIN `inv_product_batch` b ON b.`product_id` = p.`product_id`
|
||||||
|
AND b.`tenant_id` = p.`tenant_id`
|
||||||
|
AND b.`batch_no` = CONCAT(p.`product_code`, '-B001')
|
||||||
|
SET pan.`batch_id` = b.`batch_id`
|
||||||
|
WHERE TRIM(COALESCE(pan.`batch_id`, '')) = '';
|
||||||
|
|
||||||
|
-- Replace the old natural key after product_code has been populated.
|
||||||
|
SET @i = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND INDEX_NAME='uk_product_name_spec_color');
|
||||||
|
SET @s = IF(@i>0, 'ALTER TABLE `inv_product` DROP INDEX `uk_product_name_spec_color`', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @i = (SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND INDEX_NAME='uk_tenant_product_code');
|
||||||
|
SET @s = IF(@i=0, 'ALTER TABLE `inv_product` ADD UNIQUE KEY `uk_tenant_product_code` (`tenant_id`, `product_code`)', 'SELECT 1');
|
||||||
|
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- Verification queries for release runbooks:
|
||||||
|
-- SELECT COUNT(*) AS empty_product_code FROM inv_product WHERE deleted_at IS NULL AND product_code = '';
|
||||||
|
-- SELECT tenant_id, product_code, COUNT(*) FROM inv_product WHERE deleted_at IS NULL GROUP BY tenant_id, product_code HAVING COUNT(*) > 1;
|
||||||
|
-- SELECT p.product_id FROM inv_product p LEFT JOIN inv_product_batch b ON b.product_id = p.product_id AND b.batch_no = CONCAT(p.product_code, '-B001') WHERE p.deleted_at IS NULL AND b.batch_id IS NULL;
|
||||||
|
-- SELECT pan.pan_id FROM inv_product_pan pan WHERE pan.batch_id = '';
|
||||||
@ -1,14 +1,15 @@
|
|||||||
|
# Local development config — fill in credentials before running locally.
|
||||||
Name: gateway-api
|
Name: gateway-api
|
||||||
Host: 0.0.0.0
|
Host: 0.0.0.0
|
||||||
Port: 8888
|
Port: 8888
|
||||||
|
|
||||||
Auth:
|
Auth:
|
||||||
AccessSecret: muyu-wms-jwt-secret-key-2026
|
AccessSecret: your_jwt_secret_here
|
||||||
AccessExpire: 7200
|
AccessExpire: 7200
|
||||||
DefaultTenantId: t_default_001
|
DefaultTenantId: t_default_001
|
||||||
|
|
||||||
DataSource: root:muyu2026@tcp(127.0.0.1:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
DataSource: root:your_password@tcp(127.0.0.1:3306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
|
||||||
PostgresDataSource: "postgres://muyu:muyu2026@127.0.0.1:5432/muyu_crm?sslmode=disable"
|
PostgresDataSource: "postgres://muyu:your_password@127.0.0.1:5432/muyu_crm?sslmode=disable"
|
||||||
|
|
||||||
SystemRpc:
|
SystemRpc:
|
||||||
Etcd:
|
Etcd:
|
||||||
|
|||||||
@ -224,6 +224,8 @@ type (
|
|||||||
ImageUrl string `json:"imageUrl"`
|
ImageUrl string `json:"imageUrl"`
|
||||||
Spec string `json:"spec"`
|
Spec string `json:"spec"`
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
|
ColorNo string `json:"colorNo"`
|
||||||
|
ProductCode string `json:"productCode"`
|
||||||
SalesPrice string `json:"salesPrice"`
|
SalesPrice string `json:"salesPrice"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
Status int64 `json:"status"`
|
Status int64 `json:"status"`
|
||||||
@ -235,15 +237,19 @@ type (
|
|||||||
ImageUrl string `json:"imageUrl,optional"`
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
Spec string `json:"spec,optional"`
|
Spec string `json:"spec,optional"`
|
||||||
Color string `json:"color,optional"`
|
Color string `json:"color,optional"`
|
||||||
|
ColorNo string `json:"colorNo,optional"`
|
||||||
|
ProductCode string `json:"productCode,optional"`
|
||||||
SalesPrice string `json:"salesPrice,optional"`
|
SalesPrice string `json:"salesPrice,optional"`
|
||||||
Remark string `json:"remark,optional"`
|
Remark string `json:"remark,optional"`
|
||||||
Pans []PanInput `json:"pans,optional"`
|
Pans []PanInput `json:"pans,optional"`
|
||||||
|
InitialBatch ProductBatchInput `json:"initialBatch,optional"`
|
||||||
}
|
}
|
||||||
UpdateProductReq {
|
UpdateProductReq {
|
||||||
ProductName string `json:"productName,optional"`
|
ProductName string `json:"productName,optional"`
|
||||||
ImageUrl string `json:"imageUrl,optional"`
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
Spec string `json:"spec,optional"`
|
Spec string `json:"spec,optional"`
|
||||||
Color string `json:"color,optional"`
|
Color string `json:"color,optional"`
|
||||||
|
ColorNo string `json:"colorNo,optional"`
|
||||||
SalesPrice string `json:"salesPrice,optional"`
|
SalesPrice string `json:"salesPrice,optional"`
|
||||||
Remark string `json:"remark,optional"`
|
Remark string `json:"remark,optional"`
|
||||||
}
|
}
|
||||||
@ -253,6 +259,8 @@ type (
|
|||||||
ProductName string `form:"productName,optional"`
|
ProductName string `form:"productName,optional"`
|
||||||
Spec string `form:"spec,optional"`
|
Spec string `form:"spec,optional"`
|
||||||
Color string `form:"color,optional"`
|
Color string `form:"color,optional"`
|
||||||
|
ColorNo string `form:"colorNo,optional"`
|
||||||
|
ProductCode string `form:"productCode,optional"`
|
||||||
Status int64 `form:"status,optional,default=-1"`
|
Status int64 `form:"status,optional,default=-1"`
|
||||||
}
|
}
|
||||||
ListProductResp {
|
ListProductResp {
|
||||||
@ -279,6 +287,8 @@ type (
|
|||||||
PanInfo {
|
PanInfo {
|
||||||
PanId string `json:"panId"`
|
PanId string `json:"panId"`
|
||||||
ProductId string `json:"productId"`
|
ProductId string `json:"productId"`
|
||||||
|
BatchId string `json:"batchId"`
|
||||||
|
BatchNo string `json:"batchNo"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Position string `json:"position"`
|
Position string `json:"position"`
|
||||||
SortOrder int64 `json:"sortOrder"`
|
SortOrder int64 `json:"sortOrder"`
|
||||||
@ -290,6 +300,7 @@ type (
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Position string `json:"position,optional"`
|
Position string `json:"position,optional"`
|
||||||
BoltLengths []string `json:"boltLengths,optional"`
|
BoltLengths []string `json:"boltLengths,optional"`
|
||||||
|
BatchId string `json:"batchId,optional"`
|
||||||
}
|
}
|
||||||
ListPanResp {
|
ListPanResp {
|
||||||
List []PanInfo `json:"list"`
|
List []PanInfo `json:"list"`
|
||||||
@ -331,6 +342,8 @@ type (
|
|||||||
ProductId string `json:"productId"`
|
ProductId string `json:"productId"`
|
||||||
ProductName string `json:"productName"`
|
ProductName string `json:"productName"`
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
|
ColorNo string `json:"colorNo"`
|
||||||
|
ProductCode string `json:"productCode"`
|
||||||
Spec string `json:"spec"`
|
Spec string `json:"spec"`
|
||||||
ImageUrl string `json:"imageUrl"`
|
ImageUrl string `json:"imageUrl"`
|
||||||
PanCount int64 `json:"panCount"`
|
PanCount int64 `json:"panCount"`
|
||||||
@ -338,6 +351,7 @@ type (
|
|||||||
TotalLengthM string `json:"totalLengthM"`
|
TotalLengthM string `json:"totalLengthM"`
|
||||||
Locations string `json:"locations"`
|
Locations string `json:"locations"`
|
||||||
SalesPrice string `json:"salesPrice"`
|
SalesPrice string `json:"salesPrice"`
|
||||||
|
BatchCount int64 `json:"batchCount"`
|
||||||
}
|
}
|
||||||
ListColorDetailReq {
|
ListColorDetailReq {
|
||||||
ProductName string `form:"productName"`
|
ProductName string `form:"productName"`
|
||||||
@ -347,6 +361,85 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ==================== Yarn & Batch Types ====================
|
||||||
|
type (
|
||||||
|
YarnInfo {
|
||||||
|
YarnId string `json:"yarnId"`
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
WeightGM string `json:"weightGM"`
|
||||||
|
SupplierId string `json:"supplierId"`
|
||||||
|
SupplierName string `json:"supplierName"`
|
||||||
|
DyeFactory string `json:"dyeFactory"`
|
||||||
|
ImageUrl string `json:"imageUrl"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
CreateYarnReq {
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Color string `json:"color,optional"`
|
||||||
|
WeightGM string `json:"weightGM"`
|
||||||
|
SupplierId string `json:"supplierId"`
|
||||||
|
DyeFactory string `json:"dyeFactory,optional"`
|
||||||
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
}
|
||||||
|
UpdateYarnReq {
|
||||||
|
YarnName string `json:"yarnName,optional"`
|
||||||
|
Color string `json:"color,optional"`
|
||||||
|
WeightGM string `json:"weightGM,optional"`
|
||||||
|
SupplierId string `json:"supplierId,optional"`
|
||||||
|
DyeFactory string `json:"dyeFactory,optional"`
|
||||||
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
Status int64 `json:"status,optional,default=1"`
|
||||||
|
}
|
||||||
|
ListYarnReq {
|
||||||
|
Page int64 `form:"page,default=1"`
|
||||||
|
PageSize int64 `form:"pageSize,default=20"`
|
||||||
|
YarnName string `form:"yarnName,optional"`
|
||||||
|
SupplierId string `form:"supplierId,optional"`
|
||||||
|
Status int64 `form:"status,optional,default=-1"`
|
||||||
|
}
|
||||||
|
ListYarnResp {
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
List []YarnInfo `json:"list"`
|
||||||
|
}
|
||||||
|
ProductBatchInput {
|
||||||
|
BatchNo string `json:"batchNo,optional"`
|
||||||
|
YarnRatio string `json:"yarnRatio,optional"`
|
||||||
|
WarpWeightGM string `json:"warpWeightGM,optional"`
|
||||||
|
WeftWeightGM string `json:"weftWeightGM,optional"`
|
||||||
|
ProductionProcess string `json:"productionProcess,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
}
|
||||||
|
ProductBatchInfo {
|
||||||
|
BatchId string `json:"batchId"`
|
||||||
|
ProductId string `json:"productId"`
|
||||||
|
BatchNo string `json:"batchNo"`
|
||||||
|
YarnRatio string `json:"yarnRatio"`
|
||||||
|
WarpWeightGM string `json:"warpWeightGM"`
|
||||||
|
WeftWeightGM string `json:"weftWeightGM"`
|
||||||
|
ProductionProcess string `json:"productionProcess"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
CreateProductBatchReq {
|
||||||
|
Batch ProductBatchInput `json:"batch"`
|
||||||
|
}
|
||||||
|
UpdateProductBatchReq {
|
||||||
|
Batch ProductBatchInput `json:"batch"`
|
||||||
|
Status int64 `json:"status,optional,default=1"`
|
||||||
|
}
|
||||||
|
ListProductBatchResp {
|
||||||
|
List []ProductBatchInfo `json:"list"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// ==================== Stock Statistics Types ====================
|
// ==================== Stock Statistics Types ====================
|
||||||
type (
|
type (
|
||||||
StockSummaryResp {
|
StockSummaryResp {
|
||||||
@ -725,6 +818,51 @@ service gateway-api {
|
|||||||
put /products/:id/pans (SavePansReq) returns (IdResp)
|
put /products/:id/pans (SavePansReq) returns (IdResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inventory - Yarn Management
|
||||||
|
@server (
|
||||||
|
prefix: /api/v1/inventory
|
||||||
|
group: inventory/yarn
|
||||||
|
jwt: Auth
|
||||||
|
middleware: AuthorityMiddleware
|
||||||
|
)
|
||||||
|
service gateway-api {
|
||||||
|
@handler ListYarnHandler
|
||||||
|
get /yarns (ListYarnReq) returns (ListYarnResp)
|
||||||
|
|
||||||
|
@handler GetYarnHandler
|
||||||
|
get /yarns/:id returns (YarnInfo)
|
||||||
|
|
||||||
|
@handler CreateYarnHandler
|
||||||
|
post /yarns (CreateYarnReq) returns (IdResp)
|
||||||
|
|
||||||
|
@handler UpdateYarnHandler
|
||||||
|
put /yarns/:id (UpdateYarnReq) returns (IdResp)
|
||||||
|
|
||||||
|
@handler DeleteYarnHandler
|
||||||
|
delete /yarns/:id returns (IdResp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inventory - Product Batch Management
|
||||||
|
@server (
|
||||||
|
prefix: /api/v1/inventory
|
||||||
|
group: inventory/productbatch
|
||||||
|
jwt: Auth
|
||||||
|
middleware: AuthorityMiddleware
|
||||||
|
)
|
||||||
|
service gateway-api {
|
||||||
|
@handler ListProductBatchHandler
|
||||||
|
get /products/:id/batches returns (ListProductBatchResp)
|
||||||
|
|
||||||
|
@handler CreateProductBatchHandler
|
||||||
|
post /products/:id/batches (CreateProductBatchReq) returns (IdResp)
|
||||||
|
|
||||||
|
@handler UpdateProductBatchHandler
|
||||||
|
put /products/:id/batches/:batchId (UpdateProductBatchReq) returns (IdResp)
|
||||||
|
|
||||||
|
@handler DeleteProductBatchHandler
|
||||||
|
delete /products/:id/batches/:batchId returns (IdResp)
|
||||||
|
}
|
||||||
|
|
||||||
// Inventory - Pan/Bolt Management
|
// Inventory - Pan/Bolt Management
|
||||||
@server (
|
@server (
|
||||||
prefix: /api/v1/inventory
|
prefix: /api/v1/inventory
|
||||||
@ -805,4 +943,3 @@ service gateway-api {
|
|||||||
@handler ApproveStockAdjustHandler
|
@handler ApproveStockAdjustHandler
|
||||||
post /adjusts/:id/approve (ApproveStockAdjustReq) returns (IdResp)
|
post /adjusts/:id/approve (ApproveStockAdjustReq) returns (IdResp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,4 +20,5 @@ type Config struct {
|
|||||||
SystemRpc zrpc.RpcClientConf
|
SystemRpc zrpc.RpcClientConf
|
||||||
InventoryRpc zrpc.RpcClientConf
|
InventoryRpc zrpc.RpcClientConf
|
||||||
PurchaseRpc zrpc.RpcClientConf
|
PurchaseRpc zrpc.RpcClientConf
|
||||||
|
ProductionRpc zrpc.RpcClientConf
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ package product
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
"muyu-apiserver/gateway/internal/logic/inventory/product"
|
"muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||||
@ -14,11 +15,14 @@ import (
|
|||||||
func ExportProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func ExportProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := product.NewExportProductLogic(r.Context(), svcCtx)
|
l := product.NewExportProductLogic(r.Context(), svcCtx)
|
||||||
err := l.ExportProduct()
|
data, filename, err := l.ExportProduct()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
} else {
|
} else {
|
||||||
httpx.Ok(w)
|
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+url.PathEscape(filename))
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/productbatch"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateProductBatchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.CreateProductBatchReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := productbatch.NewCreateProductBatchLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.CreateProductBatch(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/productbatch"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteProductBatchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := pathvar.Vars(r)
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", vars["id"])
|
||||||
|
ctx = context.WithValue(ctx, "batchId", vars["batchId"])
|
||||||
|
l := productbatch.NewDeleteProductBatchLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.DeleteProductBatch()
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/productbatch"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ListProductBatchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := productbatch.NewListProductBatchLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.ListProductBatch()
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/productbatch"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateProductBatchHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.UpdateProductBatchReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vars := pathvar.Vars(r)
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", vars["id"])
|
||||||
|
ctx = context.WithValue(ctx, "batchId", vars["batchId"])
|
||||||
|
l := productbatch.NewUpdateProductBatchLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.UpdateProductBatch(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
gateway/internal/handler/inventory/yarn/createYarnHandler.go
Normal file
29
gateway/internal/handler/inventory/yarn/createYarnHandler.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/yarn"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateYarnHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.CreateYarnReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l := yarn.NewCreateYarnLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.CreateYarn(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
gateway/internal/handler/inventory/yarn/deleteYarnHandler.go
Normal file
26
gateway/internal/handler/inventory/yarn/deleteYarnHandler.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/yarn"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteYarnHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := yarn.NewDeleteYarnLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.DeleteYarn()
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
gateway/internal/handler/inventory/yarn/getYarnHandler.go
Normal file
26
gateway/internal/handler/inventory/yarn/getYarnHandler.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/yarn"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetYarnHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := yarn.NewGetYarnLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.GetYarn()
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
gateway/internal/handler/inventory/yarn/listYarnHandler.go
Normal file
29
gateway/internal/handler/inventory/yarn/listYarnHandler.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/yarn"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ListYarnHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.ListYarnReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l := yarn.NewListYarnLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.ListYarn(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
gateway/internal/handler/inventory/yarn/updateYarnHandler.go
Normal file
32
gateway/internal/handler/inventory/yarn/updateYarnHandler.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Code scaffolded by goctl. Safe to edit.
|
||||||
|
|
||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/inventory/yarn"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateYarnHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.UpdateYarnReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := yarn.NewUpdateYarnLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.UpdateYarn(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/inbound"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateInboundHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayCreateInboundReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := inbound.NewCreateInboundLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.CreateInbound(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/inbound"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ListInboundHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayListInboundReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := inbound.NewListInboundLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.ListInbound(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/plan"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConfirmPlanHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.ConfirmPlanReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := plan.NewConfirmPlanLogic(r.Context(), svcCtx)
|
||||||
|
err := l.ConfirmPlan(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, types.IdResp{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/plan"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateProductionPlanHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.CreateProductionPlanReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := plan.NewCreateProductionPlanLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.CreateProductionPlan(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/plan"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetProductionPlanHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["planId"])
|
||||||
|
l := plan.NewGetProductionPlanLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.GetProductionPlan()
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/plan"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ListProductionPlanHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.ListProductionPlanReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := plan.NewListProductionPlanLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.ListProductionPlan(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/process"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CompleteStepHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayCompleteStepReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := process.NewCompleteStepLogic(r.Context(), svcCtx)
|
||||||
|
err := l.CompleteStep(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, types.IdResp{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/share"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ClickShareLinkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayClickShareLinkReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := share.NewClickShareLinkLogic(r.Context(), svcCtx)
|
||||||
|
err := l.ClickShareLink(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, types.IdResp{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/share"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConfirmShareLinkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayConfirmShareLinkReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := share.NewConfirmShareLinkLogic(r.Context(), svcCtx)
|
||||||
|
err := l.ConfirmShareLink(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, types.IdResp{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/share"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateShareLinkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayCreateShareLinkReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := share.NewCreateShareLinkLogic(r.Context(), svcCtx)
|
||||||
|
resp, err := l.CreateShareLink(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/share"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetShareLinkPlanViewHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["shortCode"])
|
||||||
|
l := share.NewGetShareLinkPlanViewLogic(ctx, svcCtx)
|
||||||
|
resp, err := l.GetShareLinkPlanView()
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"muyu-apiserver/gateway/internal/logic/production/share"
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RejectShareLinkHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req types.GatewayRejectShareLinkReq
|
||||||
|
if err := httpx.Parse(r, &req); err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := share.NewRejectShareLinkLogic(r.Context(), svcCtx)
|
||||||
|
err := l.RejectShareLink(&req)
|
||||||
|
if err != nil {
|
||||||
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
} else {
|
||||||
|
httpx.OkJsonCtx(r.Context(), w, types.IdResp{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,19 @@
|
|||||||
package order
|
package order
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CancelPurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func CancelPurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := order.NewCancelPurchaseOrderLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := order.NewCancelPurchaseOrderLogic(ctx, svcCtx)
|
||||||
err := l.CancelPurchaseOrder()
|
err := l.CancelPurchaseOrder()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package order
|
package order
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConfirmPurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func ConfirmPurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := order.NewConfirmPurchaseOrderLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := order.NewConfirmPurchaseOrderLogic(ctx, svcCtx)
|
||||||
err := l.ConfirmPurchaseOrder()
|
err := l.ConfirmPurchaseOrder()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package order
|
package order
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func GetPurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := order.NewGetPurchaseOrderLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := order.NewGetPurchaseOrderLogic(ctx, svcCtx)
|
||||||
resp, err := l.GetPurchaseOrder()
|
resp, err := l.GetPurchaseOrder()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package order
|
package order
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
"muyu-apiserver/gateway/internal/logic/purchase/order"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
"muyu-apiserver/gateway/internal/types"
|
"muyu-apiserver/gateway/internal/types"
|
||||||
@ -17,7 +19,8 @@ func UpdatePurchaseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l := order.NewUpdatePurchaseOrderLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := order.NewUpdatePurchaseOrderLogic(ctx, svcCtx)
|
||||||
err := l.UpdatePurchaseOrder(&req)
|
err := l.UpdatePurchaseOrder(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package receipt
|
package receipt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/receipt"
|
"muyu-apiserver/gateway/internal/logic/purchase/receipt"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConfirmPurchaseReceiptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func ConfirmPurchaseReceiptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := receipt.NewConfirmPurchaseReceiptLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := receipt.NewConfirmPurchaseReceiptLogic(ctx, svcCtx)
|
||||||
err := l.ConfirmPurchaseReceipt()
|
err := l.ConfirmPurchaseReceipt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package receipt
|
package receipt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/receipt"
|
"muyu-apiserver/gateway/internal/logic/purchase/receipt"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPurchaseReceiptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func GetPurchaseReceiptHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := receipt.NewGetPurchaseReceiptLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := receipt.NewGetPurchaseReceiptLogic(ctx, svcCtx)
|
||||||
resp, err := l.GetPurchaseReceipt()
|
resp, err := l.GetPurchaseReceipt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package supplier
|
package supplier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/supplier"
|
"muyu-apiserver/gateway/internal/logic/purchase/supplier"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DeleteSupplierHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func DeleteSupplierHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := supplier.NewDeleteSupplierLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := supplier.NewDeleteSupplierLogic(ctx, svcCtx)
|
||||||
err := l.DeleteSupplier()
|
err := l.DeleteSupplier()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
package supplier
|
package supplier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/supplier"
|
"muyu-apiserver/gateway/internal/logic/purchase/supplier"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetSupplierHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
func GetSupplierHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
l := supplier.NewGetSupplierLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := supplier.NewGetSupplierLogic(ctx, svcCtx)
|
||||||
resp, err := l.GetSupplier()
|
resp, err := l.GetSupplier()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
package supplier
|
package supplier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/rest/httpx"
|
"github.com/zeromicro/go-zero/rest/httpx"
|
||||||
|
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||||
"muyu-apiserver/gateway/internal/logic/purchase/supplier"
|
"muyu-apiserver/gateway/internal/logic/purchase/supplier"
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
"muyu-apiserver/gateway/internal/types"
|
"muyu-apiserver/gateway/internal/types"
|
||||||
@ -17,7 +19,8 @@ func UpdateSupplierHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l := supplier.NewUpdateSupplierLogic(r.Context(), svcCtx)
|
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||||
|
l := supplier.NewUpdateSupplierLogic(ctx, svcCtx)
|
||||||
err := l.UpdateSupplier(&req)
|
err := l.UpdateSupplier(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
httpx.ErrorCtx(r.Context(), w, err)
|
httpx.ErrorCtx(r.Context(), w, err)
|
||||||
|
|||||||
@ -13,7 +13,13 @@ import (
|
|||||||
inventorylog "muyu-apiserver/gateway/internal/handler/inventory/log"
|
inventorylog "muyu-apiserver/gateway/internal/handler/inventory/log"
|
||||||
inventorypanbolt "muyu-apiserver/gateway/internal/handler/inventory/panbolt"
|
inventorypanbolt "muyu-apiserver/gateway/internal/handler/inventory/panbolt"
|
||||||
inventoryproduct "muyu-apiserver/gateway/internal/handler/inventory/product"
|
inventoryproduct "muyu-apiserver/gateway/internal/handler/inventory/product"
|
||||||
|
inventoryproductbatch "muyu-apiserver/gateway/internal/handler/inventory/productbatch"
|
||||||
inventorystock "muyu-apiserver/gateway/internal/handler/inventory/stock"
|
inventorystock "muyu-apiserver/gateway/internal/handler/inventory/stock"
|
||||||
|
inventoryyarn "muyu-apiserver/gateway/internal/handler/inventory/yarn"
|
||||||
|
productioninbound "muyu-apiserver/gateway/internal/handler/production/inbound"
|
||||||
|
productionplan "muyu-apiserver/gateway/internal/handler/production/plan"
|
||||||
|
productionprocess "muyu-apiserver/gateway/internal/handler/production/process"
|
||||||
|
productionshare "muyu-apiserver/gateway/internal/handler/production/share"
|
||||||
purchaseorder "muyu-apiserver/gateway/internal/handler/purchase/order"
|
purchaseorder "muyu-apiserver/gateway/internal/handler/purchase/order"
|
||||||
purchasepayment "muyu-apiserver/gateway/internal/handler/purchase/payment"
|
purchasepayment "muyu-apiserver/gateway/internal/handler/purchase/payment"
|
||||||
purchasereceipt "muyu-apiserver/gateway/internal/handler/purchase/receipt"
|
purchasereceipt "muyu-apiserver/gateway/internal/handler/purchase/receipt"
|
||||||
@ -144,6 +150,71 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
rest.WithPrefix("/api/v1/inventory"),
|
rest.WithPrefix("/api/v1/inventory"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
rest.WithMiddlewares(
|
||||||
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/yarns",
|
||||||
|
Handler: inventoryyarn.ListYarnHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/yarns/:id",
|
||||||
|
Handler: inventoryyarn.GetYarnHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/yarns",
|
||||||
|
Handler: inventoryyarn.CreateYarnHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPut,
|
||||||
|
Path: "/yarns/:id",
|
||||||
|
Handler: inventoryyarn.UpdateYarnHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodDelete,
|
||||||
|
Path: "/yarns/:id",
|
||||||
|
Handler: inventoryyarn.DeleteYarnHandler(serverCtx),
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
),
|
||||||
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
|
rest.WithPrefix("/api/v1/inventory"),
|
||||||
|
)
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
rest.WithMiddlewares(
|
||||||
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/products/:id/batches",
|
||||||
|
Handler: inventoryproductbatch.ListProductBatchHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/products/:id/batches",
|
||||||
|
Handler: inventoryproductbatch.CreateProductBatchHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPut,
|
||||||
|
Path: "/products/:id/batches/:batchId",
|
||||||
|
Handler: inventoryproductbatch.UpdateProductBatchHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodDelete,
|
||||||
|
Path: "/products/:id/batches/:batchId",
|
||||||
|
Handler: inventoryproductbatch.DeleteProductBatchHandler(serverCtx),
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
),
|
||||||
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
|
rest.WithPrefix("/api/v1/inventory"),
|
||||||
|
)
|
||||||
|
|
||||||
server.AddRoutes(
|
server.AddRoutes(
|
||||||
rest.WithMiddlewares(
|
rest.WithMiddlewares(
|
||||||
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
@ -634,4 +705,120 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
|||||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
rest.WithPrefix("/api/v1/inventory"),
|
rest.WithPrefix("/api/v1/inventory"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ─── Production Plan (JWT + Authority) ──────────────────────────────────
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
rest.WithMiddlewares(
|
||||||
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/plan",
|
||||||
|
Handler: productionplan.CreateProductionPlanHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/plan",
|
||||||
|
Handler: productionplan.ListProductionPlanHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/plan/:planId",
|
||||||
|
Handler: productionplan.GetProductionPlanHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/plan/confirm",
|
||||||
|
Handler: productionplan.ConfirmPlanHandler(serverCtx),
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
),
|
||||||
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
|
rest.WithPrefix("/api/v1/production"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// ─── Production Share (JWT + Authority) ─────────────────────────────────
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
rest.WithMiddlewares(
|
||||||
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/share",
|
||||||
|
Handler: productionshare.CreateShareLinkHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/share/confirm",
|
||||||
|
Handler: productionshare.ConfirmShareLinkHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/share/reject",
|
||||||
|
Handler: productionshare.RejectShareLinkHandler(serverCtx),
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
),
|
||||||
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
|
rest.WithPrefix("/api/v1/production"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// ─── Production Process (JWT + Authority) ───────────────────────────────
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
rest.WithMiddlewares(
|
||||||
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/process/step",
|
||||||
|
Handler: productionprocess.CompleteStepHandler(serverCtx),
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
),
|
||||||
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
|
rest.WithPrefix("/api/v1/production"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// ─── Production Inbound (JWT + Authority) ───────────────────────────────
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
rest.WithMiddlewares(
|
||||||
|
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/inbound",
|
||||||
|
Handler: productioninbound.CreateInboundHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/inbound",
|
||||||
|
Handler: productioninbound.ListInboundHandler(serverCtx),
|
||||||
|
},
|
||||||
|
}...,
|
||||||
|
),
|
||||||
|
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||||
|
rest.WithPrefix("/api/v1/production"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// ─── Production Public Share (NO JWT) ───────────────────────────────────
|
||||||
|
|
||||||
|
server.AddRoutes(
|
||||||
|
[]rest.Route{
|
||||||
|
{
|
||||||
|
Method: http.MethodGet,
|
||||||
|
Path: "/share/:shortCode",
|
||||||
|
Handler: productionshare.GetShareLinkPlanViewHandler(serverCtx),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Path: "/share/click",
|
||||||
|
Handler: productionshare.ClickShareLinkHandler(serverCtx),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rest.WithPrefix("/api/v1/public/production"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,8 @@ func (l *ListPanViewLogic) ListPanView(req *types.ListPanViewReq) (resp *types.L
|
|||||||
list = append(list, types.PanListItem{
|
list = append(list, types.PanListItem{
|
||||||
PanId: item.PanId,
|
PanId: item.PanId,
|
||||||
ProductId: item.ProductId,
|
ProductId: item.ProductId,
|
||||||
|
BatchId: item.BatchId,
|
||||||
|
BatchNo: item.BatchNo,
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
Position: item.Position,
|
Position: item.Position,
|
||||||
ProductName: item.ProductName,
|
ProductName: item.ProductName,
|
||||||
|
|||||||
@ -30,9 +30,12 @@ func (l *CreateProductLogic) CreateProduct(req *types.CreateProductReq) (resp *t
|
|||||||
ImageUrl: req.ImageUrl,
|
ImageUrl: req.ImageUrl,
|
||||||
Spec: req.Spec,
|
Spec: req.Spec,
|
||||||
Color: req.Color,
|
Color: req.Color,
|
||||||
|
ColorNo: req.ColorNo,
|
||||||
|
ProductCode: req.ProductCode,
|
||||||
SalesPrice: req.SalesPrice,
|
SalesPrice: req.SalesPrice,
|
||||||
Remark: req.Remark,
|
Remark: req.Remark,
|
||||||
Pans: panInputsToPb(req.Pans),
|
Pans: panInputsToPb(req.Pans),
|
||||||
|
InitialBatch: productBatchInputToPb(req.InitialBatch),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -51,7 +54,22 @@ func panInputsToPb(pans []types.PanInput) []*pb.PanInput {
|
|||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
Position: p.Position,
|
Position: p.Position,
|
||||||
BoltLengths: p.BoltLengths,
|
BoltLengths: p.BoltLengths,
|
||||||
|
BatchId: p.BatchId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func productBatchInputToPb(input types.ProductBatchInput) *pb.ProductBatchInput {
|
||||||
|
if input == (types.ProductBatchInput{}) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &pb.ProductBatchInput{
|
||||||
|
BatchNo: input.BatchNo,
|
||||||
|
YarnRatio: input.YarnRatio,
|
||||||
|
WarpWeightGM: input.WarpWeightGM,
|
||||||
|
WeftWeightGM: input.WeftWeightGM,
|
||||||
|
ProductionProcess: input.ProductionProcess,
|
||||||
|
Remark: input.Remark,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,10 +2,13 @@ package product
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"muyu-apiserver/gateway/internal/svc"
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/xuri/excelize/v2"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,6 +26,99 @@ func NewExportProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Exp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ExportProductLogic) ExportProduct() error {
|
func (l *ExportProductLogic) ExportProduct() ([]byte, string, error) {
|
||||||
return errors.New("export product requires response writer, will be implemented in handler layer")
|
products, err := l.listAllProducts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
f := excelize.NewFile()
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
sheet := "产品"
|
||||||
|
if err := f.SetSheetName("Sheet1", sheet); err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
headers := []interface{}{"产品名称", "规格型号", "颜色", "色号", "产品码", "销售价", "批次号", "纱线配比", "经线克重(g/m)", "纬线克重(g/m)", "生产工艺", "备注"}
|
||||||
|
if err := f.SetSheetRow(sheet, "A1", &headers); err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
row := 2
|
||||||
|
for _, product := range products {
|
||||||
|
batchResp, err := l.svcCtx.InventoryRpc.ListProductBatch(l.ctx, &pb.ListProductBatchReq{ProductId: product.ProductId})
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
if len(batchResp.List) == 0 {
|
||||||
|
if err := setProductExportRow(f, sheet, row, product, nil); err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
row++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, batch := range batchResp.List {
|
||||||
|
if err := setProductExportRow(f, sheet, row, product, batch); err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
row++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.SetColWidth(sheet, "A", "L", 18); err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
buf, err := f.WriteToBuffer()
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
filename := fmt.Sprintf("products-%s.xlsx", time.Now().Format("20060102150405"))
|
||||||
|
return buf.Bytes(), filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ExportProductLogic) listAllProducts() ([]*pb.ProductInfo, error) {
|
||||||
|
const pageSize int64 = 500
|
||||||
|
var all []*pb.ProductInfo
|
||||||
|
for page := int64(1); ; page++ {
|
||||||
|
resp, err := l.svcCtx.InventoryRpc.ListProduct(l.ctx, &pb.ListProductReq{Page: page, PageSize: pageSize, Status: -1})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
all = append(all, resp.List...)
|
||||||
|
if int64(len(all)) >= resp.Total || len(resp.List) == 0 {
|
||||||
|
return all, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setProductExportRow(f *excelize.File, sheet string, row int, product *pb.ProductInfo, batch *pb.ProductBatchInfo) error {
|
||||||
|
values := []interface{}{
|
||||||
|
product.ProductName,
|
||||||
|
product.Spec,
|
||||||
|
product.Color,
|
||||||
|
product.ColorNo,
|
||||||
|
product.ProductCode,
|
||||||
|
product.SalesPrice,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
product.Remark,
|
||||||
|
}
|
||||||
|
if batch != nil {
|
||||||
|
values[6] = batch.BatchNo
|
||||||
|
values[7] = batch.YarnRatio
|
||||||
|
values[8] = batch.WarpWeightGM
|
||||||
|
values[9] = batch.WeftWeightGM
|
||||||
|
values[10] = batch.ProductionProcess
|
||||||
|
if batch.Remark != "" {
|
||||||
|
values[11] = batch.Remark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cell, err := excelize.CoordinatesToCellName(1, row)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return f.SetSheetRow(sheet, cell, &values)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,8 @@ func (l *GetColorDetailLogic) GetColorDetail(req *types.ListColorDetailReq) (res
|
|||||||
ProductId: it.ProductId,
|
ProductId: it.ProductId,
|
||||||
ProductName: it.ProductName,
|
ProductName: it.ProductName,
|
||||||
Color: it.Color,
|
Color: it.Color,
|
||||||
|
ColorNo: it.ColorNo,
|
||||||
|
ProductCode: it.ProductCode,
|
||||||
Spec: it.Spec,
|
Spec: it.Spec,
|
||||||
ImageUrl: it.ImageUrl,
|
ImageUrl: it.ImageUrl,
|
||||||
PanCount: it.PanCount,
|
PanCount: it.PanCount,
|
||||||
@ -44,6 +46,7 @@ func (l *GetColorDetailLogic) GetColorDetail(req *types.ListColorDetailReq) (res
|
|||||||
TotalLengthM: it.TotalLengthM,
|
TotalLengthM: it.TotalLengthM,
|
||||||
Locations: it.Locations,
|
Locations: it.Locations,
|
||||||
SalesPrice: it.SalesPrice,
|
SalesPrice: it.SalesPrice,
|
||||||
|
BatchCount: it.BatchCount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return &types.ColorDetailResp{List: list}, nil
|
return &types.ColorDetailResp{List: list}, nil
|
||||||
|
|||||||
@ -42,8 +42,17 @@ func (l *ImportProductLogic) ImportProduct(filePath, fileName string) (resp *typ
|
|||||||
ProductName: p.ProductName,
|
ProductName: p.ProductName,
|
||||||
Spec: p.Spec,
|
Spec: p.Spec,
|
||||||
Color: p.Color,
|
Color: p.Color,
|
||||||
|
ColorNo: p.ColorNo,
|
||||||
|
ProductCode: p.ProductCode,
|
||||||
SalesPrice: p.SalesPrice,
|
SalesPrice: p.SalesPrice,
|
||||||
Remark: p.Remark,
|
Remark: p.Remark,
|
||||||
|
InitialBatch: &pb.ProductBatchInput{
|
||||||
|
BatchNo: p.BatchNo,
|
||||||
|
YarnRatio: p.YarnRatio,
|
||||||
|
WarpWeightGM: p.WarpWeightGM,
|
||||||
|
WeftWeightGM: p.WeftWeightGM,
|
||||||
|
ProductionProcess: p.ProductionProcess,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,8 @@ func panInfoFromPB(p *pb.PanInfo) types.PanInfo {
|
|||||||
return types.PanInfo{
|
return types.PanInfo{
|
||||||
PanId: p.PanId,
|
PanId: p.PanId,
|
||||||
ProductId: p.ProductId,
|
ProductId: p.ProductId,
|
||||||
|
BatchId: p.BatchId,
|
||||||
|
BatchNo: p.BatchNo,
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
Position: p.Position,
|
Position: p.Position,
|
||||||
SortOrder: p.SortOrder,
|
SortOrder: p.SortOrder,
|
||||||
@ -76,6 +78,8 @@ func productInfoFromPB(p *pb.ProductInfo) types.ProductInfo {
|
|||||||
ImageUrl: p.ImageUrl,
|
ImageUrl: p.ImageUrl,
|
||||||
Spec: p.Spec,
|
Spec: p.Spec,
|
||||||
Color: p.Color,
|
Color: p.Color,
|
||||||
|
ColorNo: p.ColorNo,
|
||||||
|
ProductCode: p.ProductCode,
|
||||||
SalesPrice: p.SalesPrice,
|
SalesPrice: p.SalesPrice,
|
||||||
Remark: p.Remark,
|
Remark: p.Remark,
|
||||||
Status: p.Status,
|
Status: p.Status,
|
||||||
|
|||||||
@ -31,6 +31,8 @@ func (l *ListProductLogic) ListProduct(req *types.ListProductReq) (resp *types.L
|
|||||||
ProductName: req.ProductName,
|
ProductName: req.ProductName,
|
||||||
Spec: req.Spec,
|
Spec: req.Spec,
|
||||||
Color: req.Color,
|
Color: req.Color,
|
||||||
|
ColorNo: req.ColorNo,
|
||||||
|
ProductCode: req.ProductCode,
|
||||||
Status: req.Status,
|
Status: req.Status,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -34,6 +34,7 @@ func (l *UpdateProductLogic) UpdateProduct(req *types.UpdateProductReq) (resp *t
|
|||||||
ImageUrl: req.ImageUrl,
|
ImageUrl: req.ImageUrl,
|
||||||
Spec: req.Spec,
|
Spec: req.Spec,
|
||||||
Color: req.Color,
|
Color: req.Color,
|
||||||
|
ColorNo: req.ColorNo,
|
||||||
SalesPrice: req.SalesPrice,
|
SalesPrice: req.SalesPrice,
|
||||||
Remark: req.Remark,
|
Remark: req.Remark,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateProductBatchLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreateProductBatchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateProductBatchLogic {
|
||||||
|
return &CreateProductBatchLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CreateProductBatchLogic) CreateProductBatch(req *types.CreateProductBatchReq) (*types.IdResp, error) {
|
||||||
|
productId := ctxdata.GetPathId(l.ctx)
|
||||||
|
resp, err := l.svcCtx.InventoryRpc.CreateProductBatch(l.ctx, &pb.CreateProductBatchReq{
|
||||||
|
ProductId: productId,
|
||||||
|
Batch: batchInputToPB(req.Batch),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: resp.Id}, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteProductBatchLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDeleteProductBatchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteProductBatchLogic {
|
||||||
|
return &DeleteProductBatchLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *DeleteProductBatchLogic) DeleteProductBatch() (*types.IdResp, error) {
|
||||||
|
productId := ctxdata.GetPathId(l.ctx)
|
||||||
|
batchId, _ := l.ctx.Value("batchId").(string)
|
||||||
|
if _, err := l.svcCtx.InventoryRpc.DeleteProductBatch(l.ctx, &pb.DeleteProductBatchReq{ProductId: productId, BatchId: batchId}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: batchId}, nil
|
||||||
|
}
|
||||||
36
gateway/internal/logic/inventory/productbatch/helpers.go
Normal file
36
gateway/internal/logic/inventory/productbatch/helpers.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func batchInputToPB(input types.ProductBatchInput) *pb.ProductBatchInput {
|
||||||
|
return &pb.ProductBatchInput{
|
||||||
|
BatchNo: input.BatchNo,
|
||||||
|
YarnRatio: input.YarnRatio,
|
||||||
|
WarpWeightGM: input.WarpWeightGM,
|
||||||
|
WeftWeightGM: input.WeftWeightGM,
|
||||||
|
ProductionProcess: input.ProductionProcess,
|
||||||
|
Remark: input.Remark,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func batchInfoFromPB(b *pb.ProductBatchInfo) types.ProductBatchInfo {
|
||||||
|
if b == nil {
|
||||||
|
return types.ProductBatchInfo{}
|
||||||
|
}
|
||||||
|
return types.ProductBatchInfo{
|
||||||
|
BatchId: b.BatchId,
|
||||||
|
ProductId: b.ProductId,
|
||||||
|
BatchNo: b.BatchNo,
|
||||||
|
YarnRatio: b.YarnRatio,
|
||||||
|
WarpWeightGM: b.WarpWeightGM,
|
||||||
|
WeftWeightGM: b.WeftWeightGM,
|
||||||
|
ProductionProcess: b.ProductionProcess,
|
||||||
|
Remark: b.Remark,
|
||||||
|
Status: b.Status,
|
||||||
|
CreatedAt: b.CreatedAt,
|
||||||
|
UpdatedAt: b.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListProductBatchLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListProductBatchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListProductBatchLogic {
|
||||||
|
return &ListProductBatchLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListProductBatchLogic) ListProductBatch() (*types.ListProductBatchResp, error) {
|
||||||
|
productId := ctxdata.GetPathId(l.ctx)
|
||||||
|
resp, err := l.svcCtx.InventoryRpc.ListProductBatch(l.ctx, &pb.ListProductBatchReq{ProductId: productId})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list := make([]types.ProductBatchInfo, 0, len(resp.List))
|
||||||
|
for _, item := range resp.List {
|
||||||
|
list = append(list, batchInfoFromPB(item))
|
||||||
|
}
|
||||||
|
return &types.ListProductBatchResp{List: list}, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package productbatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateProductBatchLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpdateProductBatchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateProductBatchLogic {
|
||||||
|
return &UpdateProductBatchLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *UpdateProductBatchLogic) UpdateProductBatch(req *types.UpdateProductBatchReq) (*types.IdResp, error) {
|
||||||
|
productId := ctxdata.GetPathId(l.ctx)
|
||||||
|
batchId, _ := l.ctx.Value("batchId").(string)
|
||||||
|
_, err := l.svcCtx.InventoryRpc.UpdateProductBatch(l.ctx, &pb.UpdateProductBatchReq{
|
||||||
|
ProductId: productId,
|
||||||
|
BatchId: batchId,
|
||||||
|
Batch: batchInputToPB(req.Batch),
|
||||||
|
Status: req.Status,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: batchId}, nil
|
||||||
|
}
|
||||||
37
gateway/internal/logic/inventory/yarn/createYarnLogic.go
Normal file
37
gateway/internal/logic/inventory/yarn/createYarnLogic.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateYarnLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreateYarnLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateYarnLogic {
|
||||||
|
return &CreateYarnLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CreateYarnLogic) CreateYarn(req *types.CreateYarnReq) (*types.IdResp, error) {
|
||||||
|
resp, err := l.svcCtx.InventoryRpc.CreateYarn(l.ctx, &pb.CreateYarnReq{
|
||||||
|
YarnName: req.YarnName,
|
||||||
|
Color: req.Color,
|
||||||
|
WeightGM: req.WeightGM,
|
||||||
|
SupplierId: req.SupplierId,
|
||||||
|
DyeFactory: req.DyeFactory,
|
||||||
|
ImageUrl: req.ImageUrl,
|
||||||
|
Remark: req.Remark,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: resp.Id}, nil
|
||||||
|
}
|
||||||
30
gateway/internal/logic/inventory/yarn/deleteYarnLogic.go
Normal file
30
gateway/internal/logic/inventory/yarn/deleteYarnLogic.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteYarnLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDeleteYarnLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteYarnLogic {
|
||||||
|
return &DeleteYarnLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *DeleteYarnLogic) DeleteYarn() (*types.IdResp, error) {
|
||||||
|
id := ctxdata.GetPathId(l.ctx)
|
||||||
|
if _, err := l.svcCtx.InventoryRpc.DeleteYarn(l.ctx, &pb.DeleteYarnReq{YarnId: id}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: id}, nil
|
||||||
|
}
|
||||||
32
gateway/internal/logic/inventory/yarn/getYarnLogic.go
Normal file
32
gateway/internal/logic/inventory/yarn/getYarnLogic.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetYarnLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetYarnLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetYarnLogic {
|
||||||
|
return &GetYarnLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *GetYarnLogic) GetYarn() (*types.YarnInfo, error) {
|
||||||
|
id := ctxdata.GetPathId(l.ctx)
|
||||||
|
resp, err := l.svcCtx.InventoryRpc.GetYarn(l.ctx, &pb.GetYarnReq{YarnId: id})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out := yarnInfoFromPB(resp)
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
26
gateway/internal/logic/inventory/yarn/helpers.go
Normal file
26
gateway/internal/logic/inventory/yarn/helpers.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func yarnInfoFromPB(y *pb.YarnInfo) types.YarnInfo {
|
||||||
|
if y == nil {
|
||||||
|
return types.YarnInfo{}
|
||||||
|
}
|
||||||
|
return types.YarnInfo{
|
||||||
|
YarnId: y.YarnId,
|
||||||
|
YarnName: y.YarnName,
|
||||||
|
Color: y.Color,
|
||||||
|
WeightGM: y.WeightGM,
|
||||||
|
SupplierId: y.SupplierId,
|
||||||
|
SupplierName: y.SupplierName,
|
||||||
|
DyeFactory: y.DyeFactory,
|
||||||
|
ImageUrl: y.ImageUrl,
|
||||||
|
Remark: y.Remark,
|
||||||
|
Status: y.Status,
|
||||||
|
CreatedAt: y.CreatedAt,
|
||||||
|
UpdatedAt: y.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
39
gateway/internal/logic/inventory/yarn/listYarnLogic.go
Normal file
39
gateway/internal/logic/inventory/yarn/listYarnLogic.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListYarnLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListYarnLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListYarnLogic {
|
||||||
|
return &ListYarnLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListYarnLogic) ListYarn(req *types.ListYarnReq) (*types.ListYarnResp, error) {
|
||||||
|
resp, err := l.svcCtx.InventoryRpc.ListYarn(l.ctx, &pb.ListYarnReq{
|
||||||
|
Page: req.Page,
|
||||||
|
PageSize: req.PageSize,
|
||||||
|
YarnName: req.YarnName,
|
||||||
|
SupplierId: req.SupplierId,
|
||||||
|
Status: req.Status,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list := make([]types.YarnInfo, 0, len(resp.List))
|
||||||
|
for _, item := range resp.List {
|
||||||
|
list = append(list, yarnInfoFromPB(item))
|
||||||
|
}
|
||||||
|
return &types.ListYarnResp{Total: resp.Total, List: list}, nil
|
||||||
|
}
|
||||||
41
gateway/internal/logic/inventory/yarn/updateYarnLogic.go
Normal file
41
gateway/internal/logic/inventory/yarn/updateYarnLogic.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package yarn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/inventory/pb"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateYarnLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUpdateYarnLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateYarnLogic {
|
||||||
|
return &UpdateYarnLogic{Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *UpdateYarnLogic) UpdateYarn(req *types.UpdateYarnReq) (*types.IdResp, error) {
|
||||||
|
id := ctxdata.GetPathId(l.ctx)
|
||||||
|
_, err := l.svcCtx.InventoryRpc.UpdateYarn(l.ctx, &pb.UpdateYarnReq{
|
||||||
|
YarnId: id,
|
||||||
|
YarnName: req.YarnName,
|
||||||
|
Color: req.Color,
|
||||||
|
WeightGM: req.WeightGM,
|
||||||
|
SupplierId: req.SupplierId,
|
||||||
|
DyeFactory: req.DyeFactory,
|
||||||
|
ImageUrl: req.ImageUrl,
|
||||||
|
Remark: req.Remark,
|
||||||
|
Status: req.Status,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: id}, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateInboundLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreateInboundLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateInboundLogic {
|
||||||
|
return &CreateInboundLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CreateInboundLogic) CreateInbound(req *types.GatewayCreateInboundReq) (*types.IdResp, error) {
|
||||||
|
resp, err := l.svcCtx.ProductionRpc.CreateInbound(l.ctx, &productionservice.CreateInboundReq{
|
||||||
|
PlanId: req.PlanId,
|
||||||
|
ProductId: req.ProductId,
|
||||||
|
BatchNo: req.BatchNo,
|
||||||
|
Quantity: req.Quantity,
|
||||||
|
Rolls: req.Rolls,
|
||||||
|
PricePerMeter: req.PricePerMeter,
|
||||||
|
OperatorId: ctxdata.GetUserId(l.ctx),
|
||||||
|
Remark: req.Remark,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: resp.Id}, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package inbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListInboundLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListInboundLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListInboundLogic {
|
||||||
|
return &ListInboundLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListInboundLogic) ListInbound(req *types.GatewayListInboundReq) (*types.ListInboundResp, error) {
|
||||||
|
rpcResp, err := l.svcCtx.ProductionRpc.ListInbound(l.ctx, &productionservice.ListInboundReq{
|
||||||
|
PlanId: req.PlanId,
|
||||||
|
Page: req.Page,
|
||||||
|
PageSize: req.PageSize,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
list := make([]types.InboundRecordInfo, 0, len(rpcResp.List))
|
||||||
|
for _, ir := range rpcResp.List {
|
||||||
|
list = append(list, types.InboundRecordInfo{
|
||||||
|
RecordId: ir.RecordId,
|
||||||
|
TenantId: ir.TenantId,
|
||||||
|
PlanId: ir.PlanId,
|
||||||
|
ProductId: ir.ProductId,
|
||||||
|
BatchNo: ir.BatchNo,
|
||||||
|
Quantity: ir.Quantity,
|
||||||
|
Rolls: ir.Rolls,
|
||||||
|
PricePerMeter: ir.PricePerMeter,
|
||||||
|
OperatorId: ir.OperatorId,
|
||||||
|
Remark: ir.Remark,
|
||||||
|
CreatedAt: ir.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return &types.ListInboundResp{Total: rpcResp.Total, List: list}, nil
|
||||||
|
}
|
||||||
34
gateway/internal/logic/production/plan/confirmplanlogic.go
Normal file
34
gateway/internal/logic/production/plan/confirmplanlogic.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfirmPlanLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfirmPlanLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ConfirmPlanLogic {
|
||||||
|
return &ConfirmPlanLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ConfirmPlanLogic) ConfirmPlan(req *types.ConfirmPlanReq) error {
|
||||||
|
_, err := l.svcCtx.ProductionRpc.ConfirmPlan(l.ctx, &productionservice.ConfirmPlanReq{
|
||||||
|
PlanId: req.PlanId,
|
||||||
|
Operator: ctxdata.GetUserId(l.ctx),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateProductionPlanLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreateProductionPlanLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateProductionPlanLogic {
|
||||||
|
return &CreateProductionPlanLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CreateProductionPlanLogic) CreateProductionPlan(req *types.CreateProductionPlanReq) (*types.IdResp, error) {
|
||||||
|
yarnRatios := make([]*productionservice.YarnRatioReq, 0, len(req.YarnRatios))
|
||||||
|
for _, yr := range req.YarnRatios {
|
||||||
|
yarnRatios = append(yarnRatios, &productionservice.YarnRatioReq{
|
||||||
|
YarnName: yr.YarnName,
|
||||||
|
Ratio: yr.Ratio,
|
||||||
|
AmountPerMeter: yr.AmountPerMeter,
|
||||||
|
TotalAmount: yr.TotalAmount,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
processSteps := make([]*productionservice.ProcessStepReq, 0, len(req.ProcessSteps))
|
||||||
|
for _, ps := range req.ProcessSteps {
|
||||||
|
processSteps = append(processSteps, &productionservice.ProcessStepReq{
|
||||||
|
StepType: ps.StepType,
|
||||||
|
StepOrder: ps.StepOrder,
|
||||||
|
Remark: ps.Remark,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := l.svcCtx.ProductionRpc.CreateProductionPlan(l.ctx, &productionservice.CreateProductionPlanReq{
|
||||||
|
ProductId: req.ProductId,
|
||||||
|
ProductName: req.ProductName,
|
||||||
|
Color: req.Color,
|
||||||
|
FabricCode: req.FabricCode,
|
||||||
|
ColorCode: req.ColorCode,
|
||||||
|
TargetQuantity: req.TargetQuantity,
|
||||||
|
YarnUsagePerMeter: req.YarnUsagePerMeter,
|
||||||
|
ProductionPrice: req.ProductionPrice,
|
||||||
|
SupplierId: req.SupplierId,
|
||||||
|
Remark: req.Remark,
|
||||||
|
StartTime: req.StartTime,
|
||||||
|
Creator: ctxdata.GetUserId(l.ctx),
|
||||||
|
YarnRatios: yarnRatios,
|
||||||
|
ProcessSteps: processSteps,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &types.IdResp{Id: resp.Id}, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetProductionPlanLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetProductionPlanLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductionPlanLogic {
|
||||||
|
return &GetProductionPlanLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *GetProductionPlanLogic) GetProductionPlan() (*types.ProductionPlanInfo, error) {
|
||||||
|
planId := ctxdata.GetPathId(l.ctx)
|
||||||
|
resp, err := l.svcCtx.ProductionRpc.GetProductionPlan(l.ctx, &productionservice.GetProductionPlanReq{
|
||||||
|
PlanId: planId,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return productionPlanInfoFromPB(resp), nil
|
||||||
|
}
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
package plan
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListProductionPlanLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListProductionPlanLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListProductionPlanLogic {
|
||||||
|
return &ListProductionPlanLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ListProductionPlanLogic) ListProductionPlan(req *types.ListProductionPlanReq) (*types.ListProductionPlanResp, error) {
|
||||||
|
rpcResp, err := l.svcCtx.ProductionRpc.ListProductionPlan(l.ctx, &productionservice.ListProductionPlanReq{
|
||||||
|
Page: req.Page,
|
||||||
|
PageSize: req.PageSize,
|
||||||
|
Status: req.Status,
|
||||||
|
ProductName: req.ProductName,
|
||||||
|
PlanCode: req.PlanCode,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
list := make([]types.ProductionPlanInfo, 0, len(rpcResp.List))
|
||||||
|
for _, p := range rpcResp.List {
|
||||||
|
list = append(list, *productionPlanInfoFromPB(p))
|
||||||
|
}
|
||||||
|
return &types.ListProductionPlanResp{Total: rpcResp.Total, List: list}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func productionPlanInfoFromPB(p *productionservice.ProductionPlanInfo) *types.ProductionPlanInfo {
|
||||||
|
if p == nil {
|
||||||
|
return &types.ProductionPlanInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
yarnRatios := make([]types.YarnRatioInfo, 0, len(p.YarnRatios))
|
||||||
|
for _, yr := range p.YarnRatios {
|
||||||
|
yarnRatios = append(yarnRatios, types.YarnRatioInfo{
|
||||||
|
RatioId: yr.RatioId,
|
||||||
|
PlanId: yr.PlanId,
|
||||||
|
YarnName: yr.YarnName,
|
||||||
|
Ratio: yr.Ratio,
|
||||||
|
AmountPerMeter: yr.AmountPerMeter,
|
||||||
|
TotalAmount: yr.TotalAmount,
|
||||||
|
CreatedAt: yr.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
processSteps := make([]types.ProcessStepInfo, 0, len(p.ProcessSteps))
|
||||||
|
for _, ps := range p.ProcessSteps {
|
||||||
|
processSteps = append(processSteps, types.ProcessStepInfo{
|
||||||
|
StepId: ps.StepId,
|
||||||
|
PlanId: ps.PlanId,
|
||||||
|
StepType: ps.StepType,
|
||||||
|
StepOrder: ps.StepOrder,
|
||||||
|
Status: ps.Status,
|
||||||
|
OperatorId: ps.OperatorId,
|
||||||
|
CompletedAt: ps.CompletedAt,
|
||||||
|
Remark: ps.Remark,
|
||||||
|
CreatedAt: ps.CreatedAt,
|
||||||
|
UpdatedAt: ps.UpdatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
inboundRecords := make([]types.InboundRecordInfo, 0, len(p.InboundRecords))
|
||||||
|
for _, ir := range p.InboundRecords {
|
||||||
|
inboundRecords = append(inboundRecords, types.InboundRecordInfo{
|
||||||
|
RecordId: ir.RecordId,
|
||||||
|
TenantId: ir.TenantId,
|
||||||
|
PlanId: ir.PlanId,
|
||||||
|
ProductId: ir.ProductId,
|
||||||
|
BatchNo: ir.BatchNo,
|
||||||
|
Quantity: ir.Quantity,
|
||||||
|
Rolls: ir.Rolls,
|
||||||
|
PricePerMeter: ir.PricePerMeter,
|
||||||
|
OperatorId: ir.OperatorId,
|
||||||
|
Remark: ir.Remark,
|
||||||
|
CreatedAt: ir.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ProductionPlanInfo{
|
||||||
|
PlanId: p.PlanId,
|
||||||
|
TenantId: p.TenantId,
|
||||||
|
PlanCode: p.PlanCode,
|
||||||
|
ProductId: p.ProductId,
|
||||||
|
ProductName: p.ProductName,
|
||||||
|
Color: p.Color,
|
||||||
|
FabricCode: p.FabricCode,
|
||||||
|
ColorCode: p.ColorCode,
|
||||||
|
TargetQuantity: p.TargetQuantity,
|
||||||
|
CompletedQuantity: p.CompletedQuantity,
|
||||||
|
YarnUsagePerMeter: p.YarnUsagePerMeter,
|
||||||
|
ProductionPrice: p.ProductionPrice,
|
||||||
|
SupplierId: p.SupplierId,
|
||||||
|
Status: p.Status,
|
||||||
|
Remark: p.Remark,
|
||||||
|
StartTime: p.StartTime,
|
||||||
|
Creator: p.Creator,
|
||||||
|
Operator: p.Operator,
|
||||||
|
CreatedAt: p.CreatedAt,
|
||||||
|
UpdatedAt: p.UpdatedAt,
|
||||||
|
YarnRatios: yarnRatios,
|
||||||
|
ProcessSteps: processSteps,
|
||||||
|
InboundRecords: inboundRecords,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package process
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CompleteStepLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCompleteStepLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CompleteStepLogic {
|
||||||
|
return &CompleteStepLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CompleteStepLogic) CompleteStep(req *types.GatewayCompleteStepReq) error {
|
||||||
|
_, err := l.svcCtx.ProductionRpc.CompleteStep(l.ctx, &productionservice.CompleteStepReq{
|
||||||
|
PlanId: req.PlanId,
|
||||||
|
StepType: req.StepType,
|
||||||
|
OperatorId: ctxdata.GetUserId(l.ctx),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClickShareLinkLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClickShareLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ClickShareLinkLogic {
|
||||||
|
return &ClickShareLinkLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ClickShareLinkLogic) ClickShareLink(req *types.GatewayClickShareLinkReq) error {
|
||||||
|
_, err := l.svcCtx.ProductionRpc.ClickShareLink(l.ctx, &productionservice.ClickShareLinkReq{
|
||||||
|
ShortCode: req.ShortCode,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfirmShareLinkLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfirmShareLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ConfirmShareLinkLogic {
|
||||||
|
return &ConfirmShareLinkLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *ConfirmShareLinkLogic) ConfirmShareLink(req *types.GatewayConfirmShareLinkReq) error {
|
||||||
|
_, err := l.svcCtx.ProductionRpc.ConfirmShareLink(l.ctx, &productionservice.ConfirmShareLinkReq{
|
||||||
|
ShortCode: req.ShortCode,
|
||||||
|
Token: req.Token,
|
||||||
|
FactoryTenantId: ctxdata.GetTenantId(l.ctx),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
108
gateway/internal/logic/production/share/convert.go
Normal file
108
gateway/internal/logic/production/share/convert.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
)
|
||||||
|
|
||||||
|
func productionPlanInfoFromPB(p *productionservice.ProductionPlanInfo) *types.ProductionPlanInfo {
|
||||||
|
if p == nil {
|
||||||
|
return &types.ProductionPlanInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
|
yarnRatios := make([]types.YarnRatioInfo, 0, len(p.YarnRatios))
|
||||||
|
for _, yr := range p.YarnRatios {
|
||||||
|
yarnRatios = append(yarnRatios, types.YarnRatioInfo{
|
||||||
|
RatioId: yr.RatioId,
|
||||||
|
PlanId: yr.PlanId,
|
||||||
|
YarnName: yr.YarnName,
|
||||||
|
Ratio: yr.Ratio,
|
||||||
|
AmountPerMeter: yr.AmountPerMeter,
|
||||||
|
TotalAmount: yr.TotalAmount,
|
||||||
|
CreatedAt: yr.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
processSteps := make([]types.ProcessStepInfo, 0, len(p.ProcessSteps))
|
||||||
|
for _, ps := range p.ProcessSteps {
|
||||||
|
processSteps = append(processSteps, types.ProcessStepInfo{
|
||||||
|
StepId: ps.StepId,
|
||||||
|
PlanId: ps.PlanId,
|
||||||
|
StepType: ps.StepType,
|
||||||
|
StepOrder: ps.StepOrder,
|
||||||
|
Status: ps.Status,
|
||||||
|
OperatorId: ps.OperatorId,
|
||||||
|
CompletedAt: ps.CompletedAt,
|
||||||
|
Remark: ps.Remark,
|
||||||
|
CreatedAt: ps.CreatedAt,
|
||||||
|
UpdatedAt: ps.UpdatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
inboundRecords := make([]types.InboundRecordInfo, 0, len(p.InboundRecords))
|
||||||
|
for _, ir := range p.InboundRecords {
|
||||||
|
inboundRecords = append(inboundRecords, types.InboundRecordInfo{
|
||||||
|
RecordId: ir.RecordId,
|
||||||
|
TenantId: ir.TenantId,
|
||||||
|
PlanId: ir.PlanId,
|
||||||
|
ProductId: ir.ProductId,
|
||||||
|
BatchNo: ir.BatchNo,
|
||||||
|
Quantity: ir.Quantity,
|
||||||
|
Rolls: ir.Rolls,
|
||||||
|
PricePerMeter: ir.PricePerMeter,
|
||||||
|
OperatorId: ir.OperatorId,
|
||||||
|
Remark: ir.Remark,
|
||||||
|
CreatedAt: ir.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ProductionPlanInfo{
|
||||||
|
PlanId: p.PlanId,
|
||||||
|
TenantId: p.TenantId,
|
||||||
|
PlanCode: p.PlanCode,
|
||||||
|
ProductId: p.ProductId,
|
||||||
|
ProductName: p.ProductName,
|
||||||
|
Color: p.Color,
|
||||||
|
FabricCode: p.FabricCode,
|
||||||
|
ColorCode: p.ColorCode,
|
||||||
|
TargetQuantity: p.TargetQuantity,
|
||||||
|
CompletedQuantity: p.CompletedQuantity,
|
||||||
|
YarnUsagePerMeter: p.YarnUsagePerMeter,
|
||||||
|
ProductionPrice: p.ProductionPrice,
|
||||||
|
SupplierId: p.SupplierId,
|
||||||
|
Status: p.Status,
|
||||||
|
Remark: p.Remark,
|
||||||
|
StartTime: p.StartTime,
|
||||||
|
Creator: p.Creator,
|
||||||
|
Operator: p.Operator,
|
||||||
|
CreatedAt: p.CreatedAt,
|
||||||
|
UpdatedAt: p.UpdatedAt,
|
||||||
|
YarnRatios: yarnRatios,
|
||||||
|
ProcessSteps: processSteps,
|
||||||
|
InboundRecords: inboundRecords,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shareLinkInfoFromPB(s *productionservice.ShareLinkInfo) *types.ShareLinkInfoResp {
|
||||||
|
if s == nil {
|
||||||
|
return &types.ShareLinkInfoResp{}
|
||||||
|
}
|
||||||
|
return &types.ShareLinkInfoResp{
|
||||||
|
LinkId: s.LinkId,
|
||||||
|
TenantId: s.TenantId,
|
||||||
|
PlanId: s.PlanId,
|
||||||
|
ShortCode: s.ShortCode,
|
||||||
|
Token: s.Token,
|
||||||
|
FactoryType: s.FactoryType,
|
||||||
|
HideSensitive: s.HideSensitive,
|
||||||
|
Status: s.Status,
|
||||||
|
ClickCount: s.ClickCount,
|
||||||
|
ClickedAt: s.ClickedAt,
|
||||||
|
RespondedAt: s.RespondedAt,
|
||||||
|
RejectReason: s.RejectReason,
|
||||||
|
ExpiresAt: s.ExpiresAt,
|
||||||
|
CreatedBy: s.CreatedBy,
|
||||||
|
CreatedAt: s.CreatedAt,
|
||||||
|
UpdatedAt: s.UpdatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateShareLinkLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCreateShareLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateShareLinkLogic {
|
||||||
|
return &CreateShareLinkLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *CreateShareLinkLogic) CreateShareLink(req *types.GatewayCreateShareLinkReq) (*types.ShareLinkInfoResp, error) {
|
||||||
|
resp, err := l.svcCtx.ProductionRpc.CreateShareLink(l.ctx, &productionservice.CreateShareLinkReq{
|
||||||
|
PlanId: req.PlanId,
|
||||||
|
FactoryType: req.FactoryType,
|
||||||
|
HideSensitive: req.HideSensitive,
|
||||||
|
ExpiresHours: req.ExpiresHours,
|
||||||
|
CreatedBy: ctxdata.GetUserId(l.ctx),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return shareLinkInfoFromPB(resp), nil
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/pkg/ctxdata"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetShareLinkPlanViewLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGetShareLinkPlanViewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetShareLinkPlanViewLogic {
|
||||||
|
return &GetShareLinkPlanViewLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *GetShareLinkPlanViewLogic) GetShareLinkPlanView() (*types.ShareLinkPlanViewResp, error) {
|
||||||
|
shortCode := ctxdata.GetPathId(l.ctx)
|
||||||
|
resp, err := l.svcCtx.ProductionRpc.GetShareLinkPlanView(l.ctx, &productionservice.GetShareLinkReq{
|
||||||
|
ShortCode: shortCode,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &types.ShareLinkPlanViewResp{}
|
||||||
|
if resp.Plan != nil {
|
||||||
|
plan := productionPlanInfoFromPB(resp.Plan)
|
||||||
|
result.Plan = plan
|
||||||
|
}
|
||||||
|
if resp.Link != nil {
|
||||||
|
result.Link = shareLinkInfoFromPB(resp.Link)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package share
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"muyu-apiserver/gateway/internal/svc"
|
||||||
|
"muyu-apiserver/gateway/internal/types"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RejectShareLinkLogic struct {
|
||||||
|
logx.Logger
|
||||||
|
ctx context.Context
|
||||||
|
svcCtx *svc.ServiceContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRejectShareLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RejectShareLinkLogic {
|
||||||
|
return &RejectShareLinkLogic{
|
||||||
|
Logger: logx.WithContext(ctx),
|
||||||
|
ctx: ctx,
|
||||||
|
svcCtx: svcCtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *RejectShareLinkLogic) RejectShareLink(req *types.GatewayRejectShareLinkReq) error {
|
||||||
|
_, err := l.svcCtx.ProductionRpc.RejectShareLink(l.ctx, &productionservice.RejectShareLinkReq{
|
||||||
|
ShortCode: req.ShortCode,
|
||||||
|
Token: req.Token,
|
||||||
|
RejectReason: req.RejectReason,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@ import (
|
|||||||
pkgcasbin "muyu-apiserver/pkg/casbin"
|
pkgcasbin "muyu-apiserver/pkg/casbin"
|
||||||
"muyu-apiserver/pkg/tenantctx"
|
"muyu-apiserver/pkg/tenantctx"
|
||||||
"muyu-apiserver/rpc/inventory/inventoryservice"
|
"muyu-apiserver/rpc/inventory/inventoryservice"
|
||||||
|
"muyu-apiserver/rpc/production/productionservice"
|
||||||
"muyu-apiserver/rpc/purchase/purchaseservice"
|
"muyu-apiserver/rpc/purchase/purchaseservice"
|
||||||
"muyu-apiserver/rpc/system/systemservice"
|
"muyu-apiserver/rpc/system/systemservice"
|
||||||
)
|
)
|
||||||
@ -25,6 +26,7 @@ type ServiceContext struct {
|
|||||||
SystemRpc systemservice.SystemService
|
SystemRpc systemservice.SystemService
|
||||||
InventoryRpc inventoryservice.InventoryService
|
InventoryRpc inventoryservice.InventoryService
|
||||||
PurchaseRpc purchaseservice.PurchaseService
|
PurchaseRpc purchaseservice.PurchaseService
|
||||||
|
ProductionRpc productionservice.ProductionService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config) *ServiceContext {
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
@ -62,5 +64,6 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
SystemRpc: systemservice.NewSystemService(zrpc.MustNewClient(c.SystemRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
SystemRpc: systemservice.NewSystemService(zrpc.MustNewClient(c.SystemRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
||||||
InventoryRpc: inventoryservice.NewInventoryService(zrpc.MustNewClient(c.InventoryRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
InventoryRpc: inventoryservice.NewInventoryService(zrpc.MustNewClient(c.InventoryRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
||||||
PurchaseRpc: purchaseservice.NewPurchaseService(zrpc.MustNewClient(c.PurchaseRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
PurchaseRpc: purchaseservice.NewPurchaseService(zrpc.MustNewClient(c.PurchaseRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
||||||
|
ProductionRpc: productionservice.NewProductionService(zrpc.MustNewClient(c.ProductionRpc, zrpc.WithUnaryClientInterceptor(tenantctx.UnaryClientInterceptor()))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,9 +38,12 @@ type CreateProductReq struct {
|
|||||||
ImageUrl string `json:"imageUrl,optional"`
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
Spec string `json:"spec,optional"`
|
Spec string `json:"spec,optional"`
|
||||||
Color string `json:"color,optional"`
|
Color string `json:"color,optional"`
|
||||||
|
ColorNo string `json:"colorNo,optional"`
|
||||||
|
ProductCode string `json:"productCode,optional"`
|
||||||
SalesPrice string `json:"salesPrice,optional"`
|
SalesPrice string `json:"salesPrice,optional"`
|
||||||
Remark string `json:"remark,optional"`
|
Remark string `json:"remark,optional"`
|
||||||
Pans []PanInput `json:"pans,optional"`
|
Pans []PanInput `json:"pans,optional"`
|
||||||
|
InitialBatch ProductBatchInput `json:"initialBatch,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateRoleReq struct {
|
type CreateRoleReq struct {
|
||||||
@ -114,6 +117,8 @@ type ListProductReq struct {
|
|||||||
ProductName string `form:"productName,optional"`
|
ProductName string `form:"productName,optional"`
|
||||||
Spec string `form:"spec,optional"`
|
Spec string `form:"spec,optional"`
|
||||||
Color string `form:"color,optional"`
|
Color string `form:"color,optional"`
|
||||||
|
ColorNo string `form:"colorNo,optional"`
|
||||||
|
ProductCode string `form:"productCode,optional"`
|
||||||
Status int64 `form:"status,optional,default=-1"`
|
Status int64 `form:"status,optional,default=-1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,6 +235,8 @@ type ProductInfo struct {
|
|||||||
ImageUrl string `json:"imageUrl"`
|
ImageUrl string `json:"imageUrl"`
|
||||||
Spec string `json:"spec"`
|
Spec string `json:"spec"`
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
|
ColorNo string `json:"colorNo"`
|
||||||
|
ProductCode string `json:"productCode"`
|
||||||
SalesPrice string `json:"salesPrice"`
|
SalesPrice string `json:"salesPrice"`
|
||||||
Remark string `json:"remark"`
|
Remark string `json:"remark"`
|
||||||
Status int64 `json:"status"`
|
Status int64 `json:"status"`
|
||||||
@ -247,6 +254,8 @@ type BoltInfo struct {
|
|||||||
type PanInfo struct {
|
type PanInfo struct {
|
||||||
PanId string `json:"panId"`
|
PanId string `json:"panId"`
|
||||||
ProductId string `json:"productId"`
|
ProductId string `json:"productId"`
|
||||||
|
BatchId string `json:"batchId"`
|
||||||
|
BatchNo string `json:"batchNo"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Position string `json:"position"`
|
Position string `json:"position"`
|
||||||
SortOrder int64 `json:"sortOrder"`
|
SortOrder int64 `json:"sortOrder"`
|
||||||
@ -259,6 +268,7 @@ type PanInput struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Position string `json:"position,optional"`
|
Position string `json:"position,optional"`
|
||||||
BoltLengths []string `json:"boltLengths,optional"`
|
BoltLengths []string `json:"boltLengths,optional"`
|
||||||
|
BatchId string `json:"batchId,optional"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListPanResp struct {
|
type ListPanResp struct {
|
||||||
@ -304,6 +314,8 @@ type ColorDetailItem struct {
|
|||||||
ProductId string `json:"productId"`
|
ProductId string `json:"productId"`
|
||||||
ProductName string `json:"productName"`
|
ProductName string `json:"productName"`
|
||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
|
ColorNo string `json:"colorNo"`
|
||||||
|
ProductCode string `json:"productCode"`
|
||||||
Spec string `json:"spec"`
|
Spec string `json:"spec"`
|
||||||
ImageUrl string `json:"imageUrl"`
|
ImageUrl string `json:"imageUrl"`
|
||||||
PanCount int64 `json:"panCount"`
|
PanCount int64 `json:"panCount"`
|
||||||
@ -311,6 +323,7 @@ type ColorDetailItem struct {
|
|||||||
TotalLengthM string `json:"totalLengthM"`
|
TotalLengthM string `json:"totalLengthM"`
|
||||||
Locations string `json:"locations"`
|
Locations string `json:"locations"`
|
||||||
SalesPrice string `json:"salesPrice"`
|
SalesPrice string `json:"salesPrice"`
|
||||||
|
BatchCount int64 `json:"batchCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListColorDetailReq struct {
|
type ListColorDetailReq struct {
|
||||||
@ -321,9 +334,96 @@ type ColorDetailResp struct {
|
|||||||
List []ColorDetailItem `json:"list"`
|
List []ColorDetailItem `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type YarnInfo struct {
|
||||||
|
YarnId string `json:"yarnId"`
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
WeightGM string `json:"weightGM"`
|
||||||
|
SupplierId string `json:"supplierId"`
|
||||||
|
SupplierName string `json:"supplierName"`
|
||||||
|
DyeFactory string `json:"dyeFactory"`
|
||||||
|
ImageUrl string `json:"imageUrl"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateYarnReq struct {
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Color string `json:"color,optional"`
|
||||||
|
WeightGM string `json:"weightGM"`
|
||||||
|
SupplierId string `json:"supplierId"`
|
||||||
|
DyeFactory string `json:"dyeFactory,optional"`
|
||||||
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateYarnReq struct {
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Color string `json:"color,optional"`
|
||||||
|
WeightGM string `json:"weightGM"`
|
||||||
|
SupplierId string `json:"supplierId"`
|
||||||
|
DyeFactory string `json:"dyeFactory,optional"`
|
||||||
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
Status int64 `json:"status,optional,default=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListYarnReq struct {
|
||||||
|
Page int64 `form:"page,default=1"`
|
||||||
|
PageSize int64 `form:"pageSize,default=20"`
|
||||||
|
YarnName string `form:"yarnName,optional"`
|
||||||
|
SupplierId string `form:"supplierId,optional"`
|
||||||
|
Status int64 `form:"status,optional,default=-1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListYarnResp struct {
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
List []YarnInfo `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductBatchInput struct {
|
||||||
|
BatchNo string `json:"batchNo,optional"`
|
||||||
|
YarnRatio string `json:"yarnRatio,optional"`
|
||||||
|
WarpWeightGM string `json:"warpWeightGM,optional"`
|
||||||
|
WeftWeightGM string `json:"weftWeightGM,optional"`
|
||||||
|
ProductionProcess string `json:"productionProcess,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductBatchInfo struct {
|
||||||
|
BatchId string `json:"batchId"`
|
||||||
|
ProductId string `json:"productId"`
|
||||||
|
BatchNo string `json:"batchNo"`
|
||||||
|
YarnRatio string `json:"yarnRatio"`
|
||||||
|
WarpWeightGM string `json:"warpWeightGM"`
|
||||||
|
WeftWeightGM string `json:"weftWeightGM"`
|
||||||
|
ProductionProcess string `json:"productionProcess"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateProductBatchReq struct {
|
||||||
|
Batch ProductBatchInput `json:"batch"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateProductBatchReq struct {
|
||||||
|
Batch ProductBatchInput `json:"batch"`
|
||||||
|
Status int64 `json:"status,optional,default=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListProductBatchResp struct {
|
||||||
|
List []ProductBatchInfo `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
type PanListItem struct {
|
type PanListItem struct {
|
||||||
PanId string `json:"panId"`
|
PanId string `json:"panId"`
|
||||||
ProductId string `json:"productId"`
|
ProductId string `json:"productId"`
|
||||||
|
BatchId string `json:"batchId"`
|
||||||
|
BatchNo string `json:"batchNo"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Position string `json:"position"`
|
Position string `json:"position"`
|
||||||
ProductName string `json:"productName"`
|
ProductName string `json:"productName"`
|
||||||
@ -484,6 +584,7 @@ type UpdateProductReq struct {
|
|||||||
ImageUrl string `json:"imageUrl,optional"`
|
ImageUrl string `json:"imageUrl,optional"`
|
||||||
Spec string `json:"spec,optional"`
|
Spec string `json:"spec,optional"`
|
||||||
Color string `json:"color,optional"`
|
Color string `json:"color,optional"`
|
||||||
|
ColorNo string `json:"colorNo,optional"`
|
||||||
SalesPrice string `json:"salesPrice,optional"`
|
SalesPrice string `json:"salesPrice,optional"`
|
||||||
Remark string `json:"remark,optional"`
|
Remark string `json:"remark,optional"`
|
||||||
}
|
}
|
||||||
@ -859,3 +960,192 @@ type PurchaseStatsByProductItem struct {
|
|||||||
type PurchaseStatsByProductResp struct {
|
type PurchaseStatsByProductResp struct {
|
||||||
List []PurchaseStatsByProductItem `json:"list"`
|
List []PurchaseStatsByProductItem `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Production Plan ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
type GatewayYarnRatioReq struct {
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Ratio string `json:"ratio"`
|
||||||
|
AmountPerMeter string `json:"amountPerMeter,optional"`
|
||||||
|
TotalAmount string `json:"totalAmount,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayProcessStepReq struct {
|
||||||
|
StepType string `json:"stepType"`
|
||||||
|
StepOrder int64 `json:"stepOrder"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateProductionPlanReq struct {
|
||||||
|
ProductId string `json:"productId"`
|
||||||
|
ProductName string `json:"productName"`
|
||||||
|
Color string `json:"color,optional"`
|
||||||
|
FabricCode string `json:"fabricCode,optional"`
|
||||||
|
ColorCode string `json:"colorCode,optional"`
|
||||||
|
TargetQuantity string `json:"targetQuantity"`
|
||||||
|
YarnUsagePerMeter string `json:"yarnUsagePerMeter,optional"`
|
||||||
|
ProductionPrice string `json:"productionPrice,optional"`
|
||||||
|
SupplierId string `json:"supplierId,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
StartTime string `json:"startTime,optional"`
|
||||||
|
YarnRatios []GatewayYarnRatioReq `json:"yarnRatios,optional"`
|
||||||
|
ProcessSteps []GatewayProcessStepReq `json:"processSteps,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListProductionPlanReq struct {
|
||||||
|
Page int64 `form:"page,default=1"`
|
||||||
|
PageSize int64 `form:"pageSize,default=20"`
|
||||||
|
Status int64 `form:"status,optional,default=-1"`
|
||||||
|
ProductName string `form:"productName,optional"`
|
||||||
|
PlanCode string `form:"planCode,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type YarnRatioInfo struct {
|
||||||
|
RatioId string `json:"ratioId"`
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
YarnName string `json:"yarnName"`
|
||||||
|
Ratio string `json:"ratio"`
|
||||||
|
AmountPerMeter string `json:"amountPerMeter"`
|
||||||
|
TotalAmount string `json:"totalAmount"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessStepInfo struct {
|
||||||
|
StepId string `json:"stepId"`
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
StepType string `json:"stepType"`
|
||||||
|
StepOrder int64 `json:"stepOrder"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
OperatorId string `json:"operatorId"`
|
||||||
|
CompletedAt string `json:"completedAt"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InboundRecordInfo struct {
|
||||||
|
RecordId string `json:"recordId"`
|
||||||
|
TenantId string `json:"tenantId"`
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
ProductId string `json:"productId"`
|
||||||
|
BatchNo string `json:"batchNo"`
|
||||||
|
Quantity string `json:"quantity"`
|
||||||
|
Rolls int64 `json:"rolls"`
|
||||||
|
PricePerMeter string `json:"pricePerMeter"`
|
||||||
|
OperatorId string `json:"operatorId"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProductionPlanInfo struct {
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
TenantId string `json:"tenantId"`
|
||||||
|
PlanCode string `json:"planCode"`
|
||||||
|
ProductId string `json:"productId"`
|
||||||
|
ProductName string `json:"productName"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
FabricCode string `json:"fabricCode"`
|
||||||
|
ColorCode string `json:"colorCode"`
|
||||||
|
TargetQuantity string `json:"targetQuantity"`
|
||||||
|
CompletedQuantity string `json:"completedQuantity"`
|
||||||
|
YarnUsagePerMeter string `json:"yarnUsagePerMeter"`
|
||||||
|
ProductionPrice string `json:"productionPrice"`
|
||||||
|
SupplierId string `json:"supplierId"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
Remark string `json:"remark"`
|
||||||
|
StartTime string `json:"startTime"`
|
||||||
|
Creator string `json:"creator"`
|
||||||
|
Operator string `json:"operator"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
YarnRatios []YarnRatioInfo `json:"yarnRatios"`
|
||||||
|
ProcessSteps []ProcessStepInfo `json:"processSteps"`
|
||||||
|
InboundRecords []InboundRecordInfo `json:"inboundRecords"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListProductionPlanResp struct {
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
List []ProductionPlanInfo `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfirmPlanReq struct {
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Share Link ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
type GatewayCreateShareLinkReq struct {
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
FactoryType string `json:"factoryType,optional"`
|
||||||
|
HideSensitive int64 `json:"hideSensitive,optional"`
|
||||||
|
ExpiresHours int64 `json:"expiresHours,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShareLinkInfoResp struct {
|
||||||
|
LinkId string `json:"linkId"`
|
||||||
|
TenantId string `json:"tenantId"`
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
ShortCode string `json:"shortCode"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
FactoryType string `json:"factoryType"`
|
||||||
|
HideSensitive int64 `json:"hideSensitive"`
|
||||||
|
Status int64 `json:"status"`
|
||||||
|
ClickCount int64 `json:"clickCount"`
|
||||||
|
ClickedAt string `json:"clickedAt"`
|
||||||
|
RespondedAt string `json:"respondedAt"`
|
||||||
|
RejectReason string `json:"rejectReason"`
|
||||||
|
ExpiresAt string `json:"expiresAt"`
|
||||||
|
CreatedBy string `json:"createdBy"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
UpdatedAt string `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShareLinkPlanViewResp struct {
|
||||||
|
Plan *ProductionPlanInfo `json:"plan"`
|
||||||
|
Link *ShareLinkInfoResp `json:"link"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayConfirmShareLinkReq struct {
|
||||||
|
ShortCode string `json:"shortCode"`
|
||||||
|
Token string `json:"token,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayRejectShareLinkReq struct {
|
||||||
|
ShortCode string `json:"shortCode"`
|
||||||
|
Token string `json:"token,optional"`
|
||||||
|
RejectReason string `json:"rejectReason,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayClickShareLinkReq struct {
|
||||||
|
ShortCode string `json:"shortCode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Process Step ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
type GatewayCompleteStepReq struct {
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
StepType string `json:"stepType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── Inbound ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
type GatewayCreateInboundReq struct {
|
||||||
|
PlanId string `json:"planId"`
|
||||||
|
ProductId string `json:"productId"`
|
||||||
|
BatchNo string `json:"batchNo,optional"`
|
||||||
|
Quantity string `json:"quantity"`
|
||||||
|
Rolls int64 `json:"rolls,optional"`
|
||||||
|
PricePerMeter string `json:"pricePerMeter,optional"`
|
||||||
|
Remark string `json:"remark,optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayListInboundReq struct {
|
||||||
|
PlanId string `form:"planId,optional"`
|
||||||
|
Page int64 `form:"page,default=1"`
|
||||||
|
PageSize int64 `form:"pageSize,default=20"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListInboundResp struct {
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
List []InboundRecordInfo `json:"list"`
|
||||||
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -66,6 +66,7 @@ require (
|
|||||||
github.com/microsoft/go-mssqldb v1.9.5 // indirect
|
github.com/microsoft/go-mssqldb v1.9.5 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/mozillazg/go-pinyin v0.21.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||||
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -189,6 +189,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/mozillazg/go-pinyin v0.21.0 h1:Wo8/NT45z7P3er/9YSLHA3/kjZzbLz5hR7i+jGeIGao=
|
||||||
|
github.com/mozillazg/go-pinyin v0.21.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||||
|
|||||||
81
model/invproductbatchmodel.go
Normal file
81
model/invproductbatchmodel.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ InvProductBatchModel = (*customInvProductBatchModel)(nil)
|
||||||
|
|
||||||
|
type (
|
||||||
|
InvProductBatchModel interface {
|
||||||
|
invProductBatchModel
|
||||||
|
FindByProductId(ctx context.Context, tenantId, productId string) ([]*InvProductBatch, error)
|
||||||
|
FindLatestByProductId(ctx context.Context, tenantId, productId string) (*InvProductBatch, error)
|
||||||
|
FindOneByProductAndBatchId(ctx context.Context, tenantId, productId, batchId string) (*InvProductBatch, error)
|
||||||
|
NextBatchNo(ctx context.Context, tenantId, productCode string) (string, error)
|
||||||
|
SoftDeleteByBatchId(ctx context.Context, batchId string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
customInvProductBatchModel struct {
|
||||||
|
*defaultInvProductBatchModel
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewInvProductBatchModel(conn sqlx.SqlConn) InvProductBatchModel {
|
||||||
|
return &customInvProductBatchModel{
|
||||||
|
defaultInvProductBatchModel: newInvProductBatchModel(conn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductBatchModel) FindByProductId(ctx context.Context, tenantId, productId string) ([]*InvProductBatch, error) {
|
||||||
|
var list []*InvProductBatch
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE tenant_id = ? AND product_id = ? AND deleted_at IS NULL ORDER BY batch_no", invProductBatchRows, m.table)
|
||||||
|
if err := m.conn.QueryRowsCtx(ctx, &list, query, tenantId, productId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductBatchModel) FindLatestByProductId(ctx context.Context, tenantId, productId string) (*InvProductBatch, error) {
|
||||||
|
var resp InvProductBatch
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE tenant_id = ? AND product_id = ? AND deleted_at IS NULL AND status = 1 ORDER BY batch_no DESC LIMIT 1", invProductBatchRows, m.table)
|
||||||
|
if err := m.conn.QueryRowCtx(ctx, &resp, query, tenantId, productId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductBatchModel) FindOneByProductAndBatchId(ctx context.Context, tenantId, productId, batchId string) (*InvProductBatch, error) {
|
||||||
|
var resp InvProductBatch
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE tenant_id = ? AND product_id = ? AND batch_id = ? AND deleted_at IS NULL LIMIT 1", invProductBatchRows, m.table)
|
||||||
|
if err := m.conn.QueryRowCtx(ctx, &resp, query, tenantId, productId, batchId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductBatchModel) NextBatchNo(ctx context.Context, tenantId, productCode string) (string, error) {
|
||||||
|
var next int64
|
||||||
|
query := fmt.Sprintf(`SELECT COALESCE(MAX(CAST(SUBSTRING(batch_no, CHAR_LENGTH(?) + 3) AS UNSIGNED)), 0) + 1
|
||||||
|
FROM %s
|
||||||
|
WHERE tenant_id = ? AND batch_no LIKE CONCAT(?, '-B%%')`, m.table)
|
||||||
|
if err := m.conn.QueryRowCtx(ctx, &next, query, productCode, tenantId, productCode); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s-B%03d", productCode, next), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductBatchModel) SoftDeleteByBatchId(ctx context.Context, batchId string) error {
|
||||||
|
batch, err := m.FindOneByBatchId(ctx, batchId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
batch.Status = 0
|
||||||
|
batch.DeletedAt.Time = time.Now()
|
||||||
|
batch.DeletedAt.Valid = true
|
||||||
|
return m.Update(ctx, batch)
|
||||||
|
}
|
||||||
100
model/invproductbatchmodel_gen.go
Normal file
100
model/invproductbatchmodel_gen.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
|
"github.com/zeromicro/go-zero/core/stringx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
invProductBatchFieldNames = builder.RawFieldNames(&InvProductBatch{})
|
||||||
|
invProductBatchRows = strings.Join(invProductBatchFieldNames, ",")
|
||||||
|
invProductBatchRowsExpectAutoSet = strings.Join(stringx.Remove(invProductBatchFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
|
||||||
|
invProductBatchRowsWithPlaceHolder = strings.Join(stringx.Remove(invProductBatchFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
invProductBatchModel interface {
|
||||||
|
Insert(ctx context.Context, data *InvProductBatch) (sql.Result, error)
|
||||||
|
FindOne(ctx context.Context, id int64) (*InvProductBatch, error)
|
||||||
|
FindOneByBatchId(ctx context.Context, batchId string) (*InvProductBatch, error)
|
||||||
|
Update(ctx context.Context, data *InvProductBatch) error
|
||||||
|
Delete(ctx context.Context, id int64) error
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultInvProductBatchModel struct {
|
||||||
|
conn sqlx.SqlConn
|
||||||
|
table string
|
||||||
|
}
|
||||||
|
|
||||||
|
InvProductBatch struct {
|
||||||
|
Id int64 `db:"id"`
|
||||||
|
BatchId string `db:"batch_id"`
|
||||||
|
TenantId string `db:"tenant_id"`
|
||||||
|
ProductId string `db:"product_id"`
|
||||||
|
BatchNo string `db:"batch_no"`
|
||||||
|
YarnRatio sql.NullString `db:"yarn_ratio"`
|
||||||
|
WarpWeightGM float64 `db:"warp_weight_g_m"`
|
||||||
|
WeftWeightGM float64 `db:"weft_weight_g_m"`
|
||||||
|
ProductionProcess sql.NullString `db:"production_process"`
|
||||||
|
Remark sql.NullString `db:"remark"`
|
||||||
|
Status int64 `db:"status"`
|
||||||
|
CreatedAt time.Time `db:"created_at"`
|
||||||
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
|
DeletedAt sql.NullTime `db:"deleted_at"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func newInvProductBatchModel(conn sqlx.SqlConn) *defaultInvProductBatchModel {
|
||||||
|
return &defaultInvProductBatchModel{
|
||||||
|
conn: conn,
|
||||||
|
table: "`inv_product_batch`",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductBatchModel) Insert(ctx context.Context, data *InvProductBatch) (sql.Result, error) {
|
||||||
|
query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, invProductBatchRowsExpectAutoSet)
|
||||||
|
return m.conn.ExecCtx(ctx, query, data.BatchId, data.TenantId, data.ProductId, data.BatchNo, data.YarnRatio, data.WarpWeightGM, data.WeftWeightGM, data.ProductionProcess, data.Remark, data.Status, data.DeletedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductBatchModel) FindOne(ctx context.Context, id int64) (*InvProductBatch, error) {
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE `id` = ? LIMIT 1", invProductBatchRows, m.table)
|
||||||
|
var resp InvProductBatch
|
||||||
|
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductBatchModel) FindOneByBatchId(ctx context.Context, batchId string) (*InvProductBatch, error) {
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE `batch_id` = ? AND `deleted_at` IS NULL LIMIT 1", invProductBatchRows, m.table)
|
||||||
|
var resp InvProductBatch
|
||||||
|
err := m.conn.QueryRowCtx(ctx, &resp, query, batchId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductBatchModel) Update(ctx context.Context, data *InvProductBatch) error {
|
||||||
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE `id` = ?", m.table, invProductBatchRowsWithPlaceHolder)
|
||||||
|
_, err := m.conn.ExecCtx(ctx, query, data.BatchId, data.TenantId, data.ProductId, data.BatchNo, data.YarnRatio, data.WarpWeightGM, data.WeftWeightGM, data.ProductionProcess, data.Remark, data.Status, data.DeletedAt, data.Id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductBatchModel) Delete(ctx context.Context, id int64) error {
|
||||||
|
query := fmt.Sprintf("DELETE FROM %s WHERE `id` = ?", m.table)
|
||||||
|
_, err := m.conn.ExecCtx(ctx, query, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductBatchModel) tableName() string {
|
||||||
|
return m.table
|
||||||
|
}
|
||||||
@ -59,7 +59,7 @@ func (m *customInvProductBoltModel) FindByPanId(ctx context.Context, panId strin
|
|||||||
func (m *customInvProductBoltModel) FindByProductId(ctx context.Context, productId string) ([]*InvProductBolt, error) {
|
func (m *customInvProductBoltModel) FindByProductId(ctx context.Context, productId string) ([]*InvProductBolt, error) {
|
||||||
var list []*InvProductBolt
|
var list []*InvProductBolt
|
||||||
query := fmt.Sprintf(
|
query := fmt.Sprintf(
|
||||||
"SELECT b.`id`, b.`bolt_id`, b.`pan_id`, b.`length_m`, b.`sort_order`, b.`tenant_id`, b.`created_at`, b.`updated_at` "+
|
"SELECT b.`id`, b.`bolt_id`, b.`pan_id`, b.`length_m`, b.`color`, b.`sort_order`, b.`tenant_id`, b.`created_at`, b.`updated_at` "+
|
||||||
"FROM %s b INNER JOIN `inv_product_pan` p ON b.`pan_id` = p.`pan_id` "+
|
"FROM %s b INNER JOIN `inv_product_pan` p ON b.`pan_id` = p.`pan_id` "+
|
||||||
"WHERE p.`product_id` = ? ORDER BY p.`sort_order`, b.`sort_order`", m.table)
|
"WHERE p.`product_id` = ? ORDER BY p.`sort_order`, b.`sort_order`", m.table)
|
||||||
err := m.conn.QueryRowsCtx(ctx, &list, query, productId)
|
err := m.conn.QueryRowsCtx(ctx, &list, query, productId)
|
||||||
|
|||||||
@ -33,11 +33,14 @@ type ColorDetail struct {
|
|||||||
ProductId string `db:"product_id"`
|
ProductId string `db:"product_id"`
|
||||||
ProductName string `db:"product_name"`
|
ProductName string `db:"product_name"`
|
||||||
Color string `db:"color"`
|
Color string `db:"color"`
|
||||||
|
ColorNo string `db:"color_no"`
|
||||||
|
ProductCode string `db:"product_code"`
|
||||||
Spec string `db:"spec"`
|
Spec string `db:"spec"`
|
||||||
ImageUrl string `db:"image_url"`
|
ImageUrl string `db:"image_url"`
|
||||||
SalesPrice float64 `db:"sales_price"`
|
SalesPrice float64 `db:"sales_price"`
|
||||||
PanCount int64 `db:"pan_count"`
|
PanCount int64 `db:"pan_count"`
|
||||||
BoltCount int64 `db:"bolt_count"`
|
BoltCount int64 `db:"bolt_count"`
|
||||||
|
BatchCount int64 `db:"batch_count"`
|
||||||
TotalLengthM float64 `db:"total_length_m"`
|
TotalLengthM float64 `db:"total_length_m"`
|
||||||
Locations string `db:"locations"`
|
Locations string `db:"locations"`
|
||||||
}
|
}
|
||||||
@ -45,11 +48,13 @@ type ColorDetail struct {
|
|||||||
type (
|
type (
|
||||||
InvProductModel interface {
|
InvProductModel interface {
|
||||||
invProductModel
|
invProductModel
|
||||||
FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color string, status int64) ([]*InvProduct, int64, error)
|
FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color, colorNo, productCode string, status int64) ([]*InvProduct, int64, error)
|
||||||
FindProductSummary(ctx context.Context, tenantId string) ([]*ProductSummary, error)
|
FindProductSummary(ctx context.Context, tenantId string) ([]*ProductSummary, error)
|
||||||
FindColorDetail(ctx context.Context, tenantId, productName string) ([]*ColorDetail, error)
|
FindColorDetail(ctx context.Context, tenantId, productName string) ([]*ColorDetail, error)
|
||||||
|
FindOneByTenantProductCode(ctx context.Context, tenantId, productCode string) (*InvProduct, error)
|
||||||
FindGroupByColor(ctx context.Context, tenantId string) ([]StockGroupResult, error)
|
FindGroupByColor(ctx context.Context, tenantId string) ([]StockGroupResult, error)
|
||||||
FindGroupByLocation(ctx context.Context, tenantId string) ([]StockGroupResult, error)
|
FindGroupByLocation(ctx context.Context, tenantId string) ([]StockGroupResult, error)
|
||||||
|
NextColorNo(ctx context.Context, tenantId, productName string) (string, error)
|
||||||
BulkInsert(ctx context.Context, products []*InvProduct) (int64, error)
|
BulkInsert(ctx context.Context, products []*InvProduct) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,15 +84,16 @@ func (m *customInvProductModel) BulkInsert(ctx context.Context, products []*InvP
|
|||||||
}
|
}
|
||||||
batch := products[i:end]
|
batch := products[i:end]
|
||||||
|
|
||||||
placeholder := "(" + strings.Repeat("?,", 9) + "?)"
|
placeholder := "(" + strings.Repeat("?,", 11) + "?)"
|
||||||
placeholders := make([]string, len(batch))
|
placeholders := make([]string, len(batch))
|
||||||
args := make([]interface{}, 0, len(batch)*10)
|
args := make([]interface{}, 0, len(batch)*12)
|
||||||
|
|
||||||
for j, p := range batch {
|
for j, p := range batch {
|
||||||
placeholders[j] = placeholder
|
placeholders[j] = placeholder
|
||||||
args = append(args,
|
args = append(args,
|
||||||
p.ProductId, p.ProductName, p.ImageUrl, p.Spec, p.Color,
|
p.ProductId, p.ProductName, p.ImageUrl, p.Spec, p.Color,
|
||||||
p.SalesPrice, p.Remark, p.Status, p.TenantId, p.DeletedAt,
|
p.ColorNo, p.ProductCode, p.SalesPrice, p.Remark, p.Status,
|
||||||
|
p.TenantId, p.DeletedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +111,7 @@ func (m *customInvProductModel) BulkInsert(ctx context.Context, products []*InvP
|
|||||||
return totalAffected, nil
|
return totalAffected, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color string, status int64) ([]*InvProduct, int64, error) {
|
func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color, colorNo, productCode string, status int64) ([]*InvProduct, int64, error) {
|
||||||
where := "WHERE deleted_at IS NULL AND tenant_id = ?"
|
where := "WHERE deleted_at IS NULL AND tenant_id = ?"
|
||||||
args := []interface{}{tenantId}
|
args := []interface{}{tenantId}
|
||||||
|
|
||||||
@ -121,6 +127,14 @@ func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, p
|
|||||||
where += " AND color = ?"
|
where += " AND color = ?"
|
||||||
args = append(args, color)
|
args = append(args, color)
|
||||||
}
|
}
|
||||||
|
if colorNo != "" {
|
||||||
|
where += " AND color_no LIKE ?"
|
||||||
|
args = append(args, "%"+colorNo+"%")
|
||||||
|
}
|
||||||
|
if productCode != "" {
|
||||||
|
where += " AND product_code LIKE ?"
|
||||||
|
args = append(args, "%"+productCode+"%")
|
||||||
|
}
|
||||||
if status >= 0 {
|
if status >= 0 {
|
||||||
where += " AND status = ?"
|
where += " AND status = ?"
|
||||||
args = append(args, status)
|
args = append(args, status)
|
||||||
@ -144,6 +158,27 @@ func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, p
|
|||||||
return list, total, nil
|
return list, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductModel) FindOneByTenantProductCode(ctx context.Context, tenantId, productCode string) (*InvProduct, error) {
|
||||||
|
var resp InvProduct
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE tenant_id = ? AND product_code = ? AND deleted_at IS NULL LIMIT 1", invProductRows, m.table)
|
||||||
|
err := m.QueryRowNoCacheCtx(ctx, &resp, query, tenantId, productCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductModel) NextColorNo(ctx context.Context, tenantId, productName string) (string, error) {
|
||||||
|
var next int64
|
||||||
|
query := fmt.Sprintf(`SELECT COALESCE(MAX(CAST(color_no AS UNSIGNED)), 0) + 1
|
||||||
|
FROM %s
|
||||||
|
WHERE tenant_id = ? AND product_name = ? AND deleted_at IS NULL AND color_no REGEXP '^[0-9]+$'`, m.table)
|
||||||
|
if err := m.QueryRowNoCacheCtx(ctx, &next, query, tenantId, productName); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%02d", next), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *customInvProductModel) FindProductSummary(ctx context.Context, tenantId string) ([]*ProductSummary, error) {
|
func (m *customInvProductModel) FindProductSummary(ctx context.Context, tenantId string) ([]*ProductSummary, error) {
|
||||||
var list []*ProductSummary
|
var list []*ProductSummary
|
||||||
query := `SELECT p.product_name, p.spec,
|
query := `SELECT p.product_name, p.spec,
|
||||||
@ -151,8 +186,8 @@ func (m *customInvProductModel) FindProductSummary(ctx context.Context, tenantId
|
|||||||
COUNT(DISTINCT pan.pan_id) AS total_pan_count,
|
COUNT(DISTINCT pan.pan_id) AS total_pan_count,
|
||||||
COUNT(bolt.bolt_id) AS total_bolt_count,
|
COUNT(bolt.bolt_id) AS total_bolt_count,
|
||||||
COALESCE(SUM(bolt.length_m), 0) AS total_length_m,
|
COALESCE(SUM(bolt.length_m), 0) AS total_length_m,
|
||||||
GROUP_CONCAT(DISTINCT p.color) AS colors,
|
COALESCE(GROUP_CONCAT(DISTINCT p.color), '') AS colors,
|
||||||
GROUP_CONCAT(DISTINCT pan.position ORDER BY pan.position) AS locations
|
COALESCE(GROUP_CONCAT(DISTINCT pan.position ORDER BY pan.position), '') AS locations
|
||||||
FROM ` + m.table + ` p
|
FROM ` + m.table + ` p
|
||||||
LEFT JOIN ` + "`inv_product_pan`" + ` pan ON pan.product_id = p.product_id
|
LEFT JOIN ` + "`inv_product_pan`" + ` pan ON pan.product_id = p.product_id
|
||||||
LEFT JOIN ` + "`inv_product_bolt`" + ` bolt ON bolt.pan_id = pan.pan_id
|
LEFT JOIN ` + "`inv_product_bolt`" + ` bolt ON bolt.pan_id = pan.pan_id
|
||||||
@ -200,11 +235,18 @@ func (m *customInvProductModel) FindGroupByLocation(ctx context.Context, tenantI
|
|||||||
|
|
||||||
func (m *customInvProductModel) FindColorDetail(ctx context.Context, tenantId, productName string) ([]*ColorDetail, error) {
|
func (m *customInvProductModel) FindColorDetail(ctx context.Context, tenantId, productName string) ([]*ColorDetail, error) {
|
||||||
var list []*ColorDetail
|
var list []*ColorDetail
|
||||||
query := `SELECT p.product_id, p.product_name, p.color, p.spec, p.image_url, p.sales_price,
|
query := `SELECT p.product_id, p.product_name, p.color, p.color_no, p.product_code, p.spec, p.image_url, p.sales_price,
|
||||||
COUNT(DISTINCT pan.pan_id) AS pan_count,
|
COUNT(DISTINCT pan.pan_id) AS pan_count,
|
||||||
COUNT(bolt.bolt_id) AS bolt_count,
|
COUNT(bolt.bolt_id) AS bolt_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(DISTINCT batch.batch_id)
|
||||||
|
FROM ` + "`inv_product_batch`" + ` batch
|
||||||
|
WHERE batch.product_id = p.product_id
|
||||||
|
AND batch.tenant_id = p.tenant_id
|
||||||
|
AND batch.deleted_at IS NULL
|
||||||
|
) AS batch_count,
|
||||||
COALESCE(SUM(bolt.length_m), 0) AS total_length_m,
|
COALESCE(SUM(bolt.length_m), 0) AS total_length_m,
|
||||||
GROUP_CONCAT(DISTINCT pan.position ORDER BY pan.position) AS locations
|
COALESCE(GROUP_CONCAT(DISTINCT pan.position ORDER BY pan.position), '') AS locations
|
||||||
FROM ` + m.table + ` p
|
FROM ` + m.table + ` p
|
||||||
LEFT JOIN ` + "`inv_product_pan`" + ` pan ON pan.product_id = p.product_id
|
LEFT JOIN ` + "`inv_product_pan`" + ` pan ON pan.product_id = p.product_id
|
||||||
LEFT JOIN ` + "`inv_product_bolt`" + ` bolt ON bolt.pan_id = pan.pan_id
|
LEFT JOIN ` + "`inv_product_bolt`" + ` bolt ON bolt.pan_id = pan.pan_id
|
||||||
|
|||||||
@ -27,6 +27,7 @@ var (
|
|||||||
cacheInvProductIdPrefix = "cache:invProduct:id:"
|
cacheInvProductIdPrefix = "cache:invProduct:id:"
|
||||||
cacheInvProductProductIdPrefix = "cache:invProduct:productId:"
|
cacheInvProductProductIdPrefix = "cache:invProduct:productId:"
|
||||||
cacheInvProductProductNamePrefix = "cache:invProduct:productName:"
|
cacheInvProductProductNamePrefix = "cache:invProduct:productName:"
|
||||||
|
cacheInvProductProductCodePrefix = "cache:invProduct:productCode:"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -35,6 +36,7 @@ type (
|
|||||||
FindOne(ctx context.Context, id int64) (*InvProduct, error)
|
FindOne(ctx context.Context, id int64) (*InvProduct, error)
|
||||||
FindOneByProductId(ctx context.Context, productId string) (*InvProduct, error)
|
FindOneByProductId(ctx context.Context, productId string) (*InvProduct, error)
|
||||||
FindOneByProductName(ctx context.Context, productName string) (*InvProduct, error)
|
FindOneByProductName(ctx context.Context, productName string) (*InvProduct, error)
|
||||||
|
FindOneByProductCode(ctx context.Context, productCode string) (*InvProduct, error)
|
||||||
Update(ctx context.Context, data *InvProduct) error
|
Update(ctx context.Context, data *InvProduct) error
|
||||||
Delete(ctx context.Context, id int64) error
|
Delete(ctx context.Context, id int64) error
|
||||||
}
|
}
|
||||||
@ -51,8 +53,9 @@ type (
|
|||||||
ImageUrl string `db:"image_url"`
|
ImageUrl string `db:"image_url"`
|
||||||
Spec string `db:"spec"`
|
Spec string `db:"spec"`
|
||||||
Color string `db:"color"`
|
Color string `db:"color"`
|
||||||
|
ColorNo string `db:"color_no"`
|
||||||
|
ProductCode string `db:"product_code"`
|
||||||
SalesPrice float64 `db:"sales_price"`
|
SalesPrice float64 `db:"sales_price"`
|
||||||
CostPrice float64 `db:"cost_price"`
|
|
||||||
Remark sql.NullString `db:"remark"`
|
Remark sql.NullString `db:"remark"`
|
||||||
Status int64 `db:"status"`
|
Status int64 `db:"status"`
|
||||||
TenantId string `db:"tenant_id"`
|
TenantId string `db:"tenant_id"`
|
||||||
@ -78,10 +81,11 @@ func (m *defaultInvProductModel) Delete(ctx context.Context, id int64) error {
|
|||||||
invProductIdKey := fmt.Sprintf("%s%v", cacheInvProductIdPrefix, id)
|
invProductIdKey := fmt.Sprintf("%s%v", cacheInvProductIdPrefix, id)
|
||||||
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
||||||
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
||||||
|
invProductProductCodeKey := fmt.Sprintf("%s%v", cacheInvProductProductCodePrefix, data.ProductCode)
|
||||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||||
return conn.ExecCtx(ctx, query, id)
|
return conn.ExecCtx(ctx, query, id)
|
||||||
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey)
|
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey, invProductProductCodeKey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,6 +126,26 @@ func (m *defaultInvProductModel) FindOneByProductId(ctx context.Context, product
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *defaultInvProductModel) FindOneByProductCode(ctx context.Context, productCode string) (*InvProduct, error) {
|
||||||
|
invProductProductCodeKey := fmt.Sprintf("%s%v", cacheInvProductProductCodePrefix, productCode)
|
||||||
|
var resp InvProduct
|
||||||
|
err := m.QueryRowIndexCtx(ctx, &resp, invProductProductCodeKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) {
|
||||||
|
query := fmt.Sprintf("select %s from %s where `product_code` = ? limit 1", invProductRows, m.table)
|
||||||
|
if err := conn.QueryRowCtx(ctx, &resp, query, productCode); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Id, nil
|
||||||
|
}, m.queryPrimary)
|
||||||
|
switch err {
|
||||||
|
case nil:
|
||||||
|
return &resp, nil
|
||||||
|
case sqlc.ErrNotFound:
|
||||||
|
return nil, ErrNotFound
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *defaultInvProductModel) FindOneByProductName(ctx context.Context, productName string) (*InvProduct, error) {
|
func (m *defaultInvProductModel) FindOneByProductName(ctx context.Context, productName string) (*InvProduct, error) {
|
||||||
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, productName)
|
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, productName)
|
||||||
var resp InvProduct
|
var resp InvProduct
|
||||||
@ -146,10 +170,11 @@ func (m *defaultInvProductModel) Insert(ctx context.Context, data *InvProduct) (
|
|||||||
invProductIdKey := fmt.Sprintf("%s%v", cacheInvProductIdPrefix, data.Id)
|
invProductIdKey := fmt.Sprintf("%s%v", cacheInvProductIdPrefix, data.Id)
|
||||||
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
||||||
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
||||||
|
invProductProductCodeKey := fmt.Sprintf("%s%v", cacheInvProductProductCodePrefix, data.ProductCode)
|
||||||
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, invProductRowsExpectAutoSet)
|
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, invProductRowsExpectAutoSet)
|
||||||
return conn.ExecCtx(ctx, query, data.ProductId, data.ProductName, data.ImageUrl, data.Spec, data.Color, data.SalesPrice, data.CostPrice, data.Remark, data.Status, data.TenantId, data.DeletedAt)
|
return conn.ExecCtx(ctx, query, data.ProductId, data.ProductName, data.ImageUrl, data.Spec, data.Color, data.ColorNo, data.ProductCode, data.SalesPrice, data.Remark, data.Status, data.TenantId, data.DeletedAt)
|
||||||
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey)
|
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey, invProductProductCodeKey)
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,10 +187,11 @@ func (m *defaultInvProductModel) Update(ctx context.Context, newData *InvProduct
|
|||||||
invProductIdKey := fmt.Sprintf("%s%v", cacheInvProductIdPrefix, data.Id)
|
invProductIdKey := fmt.Sprintf("%s%v", cacheInvProductIdPrefix, data.Id)
|
||||||
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
||||||
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
||||||
|
invProductProductCodeKey := fmt.Sprintf("%s%v", cacheInvProductProductCodePrefix, data.ProductCode)
|
||||||
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, invProductRowsWithPlaceHolder)
|
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, invProductRowsWithPlaceHolder)
|
||||||
return conn.ExecCtx(ctx, query, newData.ProductId, newData.ProductName, newData.ImageUrl, newData.Spec, newData.Color, newData.SalesPrice, newData.CostPrice, newData.Remark, newData.Status, newData.TenantId, newData.DeletedAt, newData.Id)
|
return conn.ExecCtx(ctx, query, newData.ProductId, newData.ProductName, newData.ImageUrl, newData.Spec, newData.Color, newData.ColorNo, newData.ProductCode, newData.SalesPrice, newData.Remark, newData.Status, newData.TenantId, newData.DeletedAt, newData.Id)
|
||||||
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey)
|
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey, invProductProductCodeKey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
451
model/invproductmodel_test.go
Normal file
451
model/invproductmodel_test.go
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
// Integration tests for InvProduct model against the real dev database.
|
||||||
|
// These tests guard against model/schema drift (e.g. missing or extra columns).
|
||||||
|
//
|
||||||
|
// Run with the dev DB reachable:
|
||||||
|
// go test ./model/ -run TestInvProduct -v
|
||||||
|
// Skip in CI where DB is unavailable:
|
||||||
|
// go test ./model/ -short
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
const testDSN = "root:muyu2026@tcp(127.0.0.1:13306)/muyu_wms?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"
|
||||||
|
|
||||||
|
func newTestProductModel(t *testing.T) InvProductModel {
|
||||||
|
t.Helper()
|
||||||
|
conn := sqlx.NewMysql(testDSN)
|
||||||
|
cacheConf := cache.CacheConf{{RedisConf: redis.RedisConf{Host: "127.0.0.1:6379", Type: "node"}, Weight: 100}}
|
||||||
|
return NewInvProductModel(conn, cacheConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func uniqueID(prefix string) string {
|
||||||
|
return fmt.Sprintf("%s_%d", prefix, time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvProductInsert verifies that Insert succeeds against the live DB schema.
|
||||||
|
// This catches model/schema drift like the cost_price column removal.
|
||||||
|
func TestInvProductInsert(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
p := &InvProduct{
|
||||||
|
ProductId: uniqueID("pid"),
|
||||||
|
ProductName: uniqueID("test_product"),
|
||||||
|
ImageUrl: "",
|
||||||
|
Spec: "100cm",
|
||||||
|
Color: "red",
|
||||||
|
ColorNo: "01",
|
||||||
|
ProductCode: uniqueID("TPC"),
|
||||||
|
SalesPrice: 99.9,
|
||||||
|
Remark: sql.NullString{String: "test remark", Valid: true},
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := m.Insert(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert failed: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := result.LastInsertId()
|
||||||
|
if id == 0 {
|
||||||
|
t.Fatal("expected non-zero LastInsertId")
|
||||||
|
}
|
||||||
|
t.Logf("inserted product id=%d", id)
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
t.Cleanup(func() { _ = m.Delete(ctx, id) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvProductFindOne verifies Insert + FindOne round-trip.
|
||||||
|
func TestInvProductFindOne(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
p := &InvProduct{
|
||||||
|
ProductId: uniqueID("pid"),
|
||||||
|
ProductName: uniqueID("test_product"),
|
||||||
|
Spec: "200cm",
|
||||||
|
Color: "blue",
|
||||||
|
ColorNo: "01",
|
||||||
|
ProductCode: uniqueID("TPC"),
|
||||||
|
SalesPrice: 49.5,
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := m.Insert(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = m.Delete(ctx, id) })
|
||||||
|
|
||||||
|
got, err := m.FindOne(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("FindOne: %v", err)
|
||||||
|
}
|
||||||
|
if got.ProductName != p.ProductName {
|
||||||
|
t.Errorf("ProductName: got %q, want %q", got.ProductName, p.ProductName)
|
||||||
|
}
|
||||||
|
if got.SalesPrice != p.SalesPrice {
|
||||||
|
t.Errorf("SalesPrice: got %v, want %v", got.SalesPrice, p.SalesPrice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvProductUpdate verifies Update writes back correctly.
|
||||||
|
func TestInvProductUpdate(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
p := &InvProduct{
|
||||||
|
ProductId: uniqueID("pid"),
|
||||||
|
ProductName: uniqueID("test_product"),
|
||||||
|
Spec: "50cm",
|
||||||
|
Color: "green",
|
||||||
|
ColorNo: "01",
|
||||||
|
ProductCode: uniqueID("TPC"),
|
||||||
|
SalesPrice: 10.0,
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
res, err := m.Insert(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = m.Delete(ctx, id) })
|
||||||
|
|
||||||
|
got, err := m.FindOne(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("FindOne: %v", err)
|
||||||
|
}
|
||||||
|
got.SalesPrice = 25.0
|
||||||
|
got.Remark = sql.NullString{String: "updated", Valid: true}
|
||||||
|
|
||||||
|
if err := m.Update(ctx, got); err != nil {
|
||||||
|
t.Fatalf("Update: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
updated, err := m.FindOne(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("FindOne after Update: %v", err)
|
||||||
|
}
|
||||||
|
if updated.SalesPrice != 25.0 {
|
||||||
|
t.Errorf("SalesPrice after update: got %v, want 25.0", updated.SalesPrice)
|
||||||
|
}
|
||||||
|
if updated.Remark.String != "updated" {
|
||||||
|
t.Errorf("Remark after update: got %q, want \"updated\"", updated.Remark.String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvProductBulkInsert verifies BulkInsert (used by the import flow).
|
||||||
|
func TestInvProductBulkInsert(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
ids := make([]int64, 0, 3)
|
||||||
|
products := make([]*InvProduct, 3)
|
||||||
|
for i := range products {
|
||||||
|
products[i] = &InvProduct{
|
||||||
|
ProductId: uniqueID(fmt.Sprintf("bulk_pid_%d", i)),
|
||||||
|
ProductName: uniqueID(fmt.Sprintf("bulk_product_%d", i)),
|
||||||
|
Spec: "10cm",
|
||||||
|
Color: "white",
|
||||||
|
ColorNo: fmt.Sprintf("%02d", i+1),
|
||||||
|
ProductCode: uniqueID(fmt.Sprintf("BTPC%d", i)),
|
||||||
|
SalesPrice: float64(i+1) * 5.0,
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
affected, err := m.BulkInsert(ctx, products)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BulkInsert: %v", err)
|
||||||
|
}
|
||||||
|
if affected != 3 {
|
||||||
|
t.Errorf("BulkInsert: affected=%d, want 3", affected)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
for _, p := range products {
|
||||||
|
row, err := m.FindOneByProductId(ctx, p.ProductId)
|
||||||
|
if err == nil {
|
||||||
|
_ = m.Delete(ctx, row.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestInvProductSchemaColumns queries information_schema to assert the DB columns
|
||||||
|
// match what the InvProduct struct declares. Fails immediately on any mismatch.
|
||||||
|
func TestInvProductSchemaColumns(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open("mysql", testDSN)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open db: %v", err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
rows, err := db.QueryContext(context.Background(),
|
||||||
|
"SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='inv_product' ORDER BY ORDINAL_POSITION")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("query schema: %v", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
dbCols := map[string]bool{}
|
||||||
|
for rows.Next() {
|
||||||
|
var col string
|
||||||
|
if err := rows.Scan(&col); err != nil {
|
||||||
|
t.Fatalf("scan: %v", err)
|
||||||
|
}
|
||||||
|
dbCols[col] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Columns that the InvProduct struct declares (via db tags).
|
||||||
|
structCols := []string{
|
||||||
|
"id", "product_id", "product_name", "image_url", "spec", "color",
|
||||||
|
"color_no", "product_code", "sales_price", "remark", "status", "tenant_id",
|
||||||
|
"created_at", "updated_at", "deleted_at",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, col := range structCols {
|
||||||
|
if !dbCols[col] {
|
||||||
|
t.Errorf("struct declares column %q but it does NOT exist in inv_product", col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check for DB columns not in the struct (forward-drift guard).
|
||||||
|
structSet := map[string]bool{}
|
||||||
|
for _, c := range structCols {
|
||||||
|
structSet[c] = true
|
||||||
|
}
|
||||||
|
for col := range dbCols {
|
||||||
|
if !structSet[col] {
|
||||||
|
t.Logf("WARNING: DB column %q exists but is not in the InvProduct struct", col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFindProductSummaryNoPans guards against the GROUP_CONCAT NULL scan bug:
|
||||||
|
// when a product has no pans, the LEFT JOIN produces NULL for pan.position and
|
||||||
|
// GROUP_CONCAT over all-NULL values returns NULL, which cannot be scanned into a
|
||||||
|
// Go string. The fix wraps both GROUP_CONCAT calls with COALESCE(..., '').
|
||||||
|
func TestFindProductSummaryNoPans(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
p := &InvProduct{
|
||||||
|
ProductId: uniqueID("pid_nopan"),
|
||||||
|
ProductName: uniqueID("nopan_product"),
|
||||||
|
Spec: "50cm",
|
||||||
|
Color: "red",
|
||||||
|
ColorNo: "01",
|
||||||
|
ProductCode: uniqueID("TPC"),
|
||||||
|
SalesPrice: 99.0,
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
res, err := m.Insert(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = m.Delete(ctx, id) })
|
||||||
|
|
||||||
|
list, err := m.FindProductSummary(ctx, "t_default_001")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("FindProductSummary returned error for product with no pans: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var found *ProductSummary
|
||||||
|
for _, s := range list {
|
||||||
|
if s.ProductName == p.ProductName {
|
||||||
|
found = s
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if found == nil {
|
||||||
|
t.Fatalf("product %q not found in summary (len=%d)", p.ProductName, len(list))
|
||||||
|
}
|
||||||
|
if found.ColorCount != 1 {
|
||||||
|
t.Errorf("ColorCount: got %d, want 1", found.ColorCount)
|
||||||
|
}
|
||||||
|
if found.TotalPanCount != 0 {
|
||||||
|
t.Errorf("TotalPanCount: got %d, want 0", found.TotalPanCount)
|
||||||
|
}
|
||||||
|
if found.Locations != "" {
|
||||||
|
t.Errorf("Locations: got %q, want empty string", found.Locations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFindColorDetailNoPans is the same NULL guard for the color-detail query.
|
||||||
|
func TestFindColorDetailNoPans(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
p := &InvProduct{
|
||||||
|
ProductId: uniqueID("pid_color"),
|
||||||
|
ProductName: uniqueID("color_nopan_product"),
|
||||||
|
Spec: "80cm",
|
||||||
|
Color: "blue",
|
||||||
|
ColorNo: "01",
|
||||||
|
ProductCode: uniqueID("TPC"),
|
||||||
|
SalesPrice: 50.0,
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
res, err := m.Insert(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = m.Delete(ctx, id) })
|
||||||
|
|
||||||
|
list, err := m.FindColorDetail(ctx, "t_default_001", p.ProductName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("FindColorDetail returned error for product with no pans: %v", err)
|
||||||
|
}
|
||||||
|
if len(list) != 1 {
|
||||||
|
t.Fatalf("expected 1 color detail row, got %d", len(list))
|
||||||
|
}
|
||||||
|
if list[0].Color != "blue" {
|
||||||
|
t.Errorf("Color: got %q, want %q", list[0].Color, "blue")
|
||||||
|
}
|
||||||
|
if list[0].Locations != "" {
|
||||||
|
t.Errorf("Locations: got %q, want empty string", list[0].Locations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindColorDetailBatchCountDoesNotDuplicateStock(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := sqlx.NewMysql(testDSN)
|
||||||
|
m := newTestProductModel(t)
|
||||||
|
panM := newInvProductPanModel(conn)
|
||||||
|
boltM := newInvProductBoltModel(conn)
|
||||||
|
batchM := newInvProductBatchModel(conn)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
productId := uniqueID("pcb")
|
||||||
|
p := &InvProduct{
|
||||||
|
ProductId: productId,
|
||||||
|
ProductName: uniqueID("color_batch_product"),
|
||||||
|
Spec: "120cm",
|
||||||
|
Color: "natural",
|
||||||
|
ColorNo: "01",
|
||||||
|
ProductCode: uniqueID("TPC"),
|
||||||
|
SalesPrice: 20.0,
|
||||||
|
Status: 1,
|
||||||
|
TenantId: "t_default_001",
|
||||||
|
}
|
||||||
|
res, err := m.Insert(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert product: %v", err)
|
||||||
|
}
|
||||||
|
productRowId, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = m.Delete(ctx, productRowId) })
|
||||||
|
|
||||||
|
batchAId := uniqueID("b1")
|
||||||
|
batchBId := uniqueID("b2")
|
||||||
|
for _, batch := range []*InvProductBatch{
|
||||||
|
{BatchId: batchAId, TenantId: p.TenantId, ProductId: productId, BatchNo: p.ProductCode + "-B001", Status: 1},
|
||||||
|
{BatchId: batchBId, TenantId: p.TenantId, ProductId: productId, BatchNo: p.ProductCode + "-B002", Status: 1},
|
||||||
|
} {
|
||||||
|
res, err := batchM.Insert(ctx, batch)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert batch: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = batchM.Delete(ctx, id) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pans := []*InvProductPan{
|
||||||
|
{PanId: uniqueID("pa"), ProductId: productId, BatchId: batchAId, Name: "A", Position: "A-01", SortOrder: 1, TenantId: p.TenantId},
|
||||||
|
{PanId: uniqueID("pb"), ProductId: productId, BatchId: batchBId, Name: "B", Position: "B-02", SortOrder: 2, TenantId: p.TenantId},
|
||||||
|
}
|
||||||
|
for _, pan := range pans {
|
||||||
|
res, err := panM.Insert(ctx, pan)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert pan: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = panM.Delete(ctx, id) })
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, bolt := range []*InvProductBolt{
|
||||||
|
{BoltId: uniqueID("ba1"), PanId: pans[0].PanId, LengthM: 10.5, Color: p.Color, SortOrder: 1, TenantId: p.TenantId},
|
||||||
|
{BoltId: uniqueID("ba2"), PanId: pans[0].PanId, LengthM: 11.5, Color: p.Color, SortOrder: 2, TenantId: p.TenantId},
|
||||||
|
{BoltId: uniqueID("bb1"), PanId: pans[1].PanId, LengthM: 12.0, Color: p.Color, SortOrder: 1, TenantId: p.TenantId},
|
||||||
|
} {
|
||||||
|
res, err := boltM.Insert(ctx, bolt)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Insert bolt: %v", err)
|
||||||
|
}
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
t.Cleanup(func() { _ = boltM.Delete(ctx, id) })
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := m.FindColorDetail(ctx, p.TenantId, p.ProductName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("FindColorDetail: %v", err)
|
||||||
|
}
|
||||||
|
if len(list) != 1 {
|
||||||
|
t.Fatalf("expected 1 color detail row, got %d", len(list))
|
||||||
|
}
|
||||||
|
got := list[0]
|
||||||
|
if got.PanCount != 2 {
|
||||||
|
t.Errorf("PanCount: got %d, want 2", got.PanCount)
|
||||||
|
}
|
||||||
|
if got.BoltCount != 3 {
|
||||||
|
t.Errorf("BoltCount: got %d, want 3", got.BoltCount)
|
||||||
|
}
|
||||||
|
if got.BatchCount != 2 {
|
||||||
|
t.Errorf("BatchCount: got %d, want 2", got.BatchCount)
|
||||||
|
}
|
||||||
|
if got.TotalLengthM != 34.0 {
|
||||||
|
t.Errorf("TotalLengthM: got %.2f, want 34.00", got.TotalLengthM)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,8 @@ var _ InvProductPanModel = (*customInvProductPanModel)(nil)
|
|||||||
type PanListItem struct {
|
type PanListItem struct {
|
||||||
PanId string `db:"pan_id"`
|
PanId string `db:"pan_id"`
|
||||||
ProductId string `db:"product_id"`
|
ProductId string `db:"product_id"`
|
||||||
|
BatchId string `db:"batch_id"`
|
||||||
|
BatchNo string `db:"batch_no"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
Position string `db:"position"`
|
Position string `db:"position"`
|
||||||
ProductName string `db:"product_name"`
|
ProductName string `db:"product_name"`
|
||||||
@ -30,6 +32,7 @@ type (
|
|||||||
DeleteByProductId(ctx context.Context, productId string) error
|
DeleteByProductId(ctx context.Context, productId string) error
|
||||||
BulkReplace(ctx context.Context, productId, tenantId string, pans []*InvProductPan) error
|
BulkReplace(ctx context.Context, productId, tenantId string, pans []*InvProductPan) error
|
||||||
FindPanList(ctx context.Context, tenantId string, page, pageSize int64, productName, position string) ([]*PanListItem, int64, error)
|
FindPanList(ctx context.Context, tenantId string, page, pageSize int64, productName, position string) ([]*PanListItem, int64, error)
|
||||||
|
CountByBatchId(ctx context.Context, batchId string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
customInvProductPanModel struct {
|
customInvProductPanModel struct {
|
||||||
@ -79,13 +82,14 @@ func (m *customInvProductPanModel) FindPanList(ctx context.Context, tenantId str
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
query := fmt.Sprintf(`SELECT pan.pan_id, pan.product_id, pan.name, pan.position,
|
query := fmt.Sprintf(`SELECT pan.pan_id, pan.product_id, pan.batch_id, COALESCE(batch.batch_no, '') AS batch_no,
|
||||||
p.product_name,
|
pan.name, pan.position, p.product_name,
|
||||||
COALESCE(GROUP_CONCAT(DISTINCT b.color ORDER BY b.color SEPARATOR ', '), '') AS colors,
|
COALESCE(GROUP_CONCAT(DISTINCT b.color ORDER BY b.color SEPARATOR ', '), '') AS colors,
|
||||||
COUNT(b.bolt_id) AS bolt_count,
|
COUNT(b.bolt_id) AS bolt_count,
|
||||||
COALESCE(SUM(b.length_m), 0) AS total_length_m
|
COALESCE(SUM(b.length_m), 0) AS total_length_m
|
||||||
FROM %s pan
|
FROM %s pan
|
||||||
JOIN inv_product p ON p.product_id = pan.product_id
|
JOIN inv_product p ON p.product_id = pan.product_id
|
||||||
|
LEFT JOIN inv_product_batch batch ON batch.batch_id = pan.batch_id AND batch.deleted_at IS NULL
|
||||||
LEFT JOIN inv_product_bolt b ON b.pan_id = pan.pan_id
|
LEFT JOIN inv_product_bolt b ON b.pan_id = pan.pan_id
|
||||||
%s
|
%s
|
||||||
GROUP BY pan.pan_id
|
GROUP BY pan.pan_id
|
||||||
@ -100,6 +104,15 @@ func (m *customInvProductPanModel) FindPanList(ctx context.Context, tenantId str
|
|||||||
return list, total, nil
|
return list, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *customInvProductPanModel) CountByBatchId(ctx context.Context, batchId string) (int64, error) {
|
||||||
|
var total int64
|
||||||
|
query := fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE `batch_id` = ?", m.table)
|
||||||
|
if err := m.conn.QueryRowCtx(ctx, &total, query, batchId); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *customInvProductPanModel) BulkReplace(ctx context.Context, productId, tenantId string, pans []*InvProductPan) error {
|
func (m *customInvProductPanModel) BulkReplace(ctx context.Context, productId, tenantId string, pans []*InvProductPan) error {
|
||||||
return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
|
return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||||
delQuery := fmt.Sprintf("DELETE FROM %s WHERE `product_id` = ?", m.table)
|
delQuery := fmt.Sprintf("DELETE FROM %s WHERE `product_id` = ?", m.table)
|
||||||
@ -109,12 +122,12 @@ func (m *customInvProductPanModel) BulkReplace(ctx context.Context, productId, t
|
|||||||
if len(pans) == 0 {
|
if len(pans) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
placeholder := "(?, ?, ?, ?, ?, ?)"
|
placeholder := "(?, ?, ?, ?, ?, ?, ?)"
|
||||||
placeholders := make([]string, len(pans))
|
placeholders := make([]string, len(pans))
|
||||||
args := make([]interface{}, 0, len(pans)*6)
|
args := make([]interface{}, 0, len(pans)*7)
|
||||||
for i, p := range pans {
|
for i, p := range pans {
|
||||||
placeholders[i] = placeholder
|
placeholders[i] = placeholder
|
||||||
args = append(args, p.PanId, productId, p.Name, p.Position, p.SortOrder, tenantId)
|
args = append(args, p.PanId, productId, p.BatchId, p.Name, p.Position, p.SortOrder, tenantId)
|
||||||
}
|
}
|
||||||
insQuery := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", m.table, invProductPanRowsExpectAutoSet, strings.Join(placeholders, ","))
|
insQuery := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", m.table, invProductPanRowsExpectAutoSet, strings.Join(placeholders, ","))
|
||||||
_, err := session.ExecCtx(ctx, insQuery, args...)
|
_, err := session.ExecCtx(ctx, insQuery, args...)
|
||||||
|
|||||||
@ -37,6 +37,7 @@ type (
|
|||||||
Id int64 `db:"id"`
|
Id int64 `db:"id"`
|
||||||
PanId string `db:"pan_id"`
|
PanId string `db:"pan_id"`
|
||||||
ProductId string `db:"product_id"`
|
ProductId string `db:"product_id"`
|
||||||
|
BatchId string `db:"batch_id"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
Position string `db:"position"`
|
Position string `db:"position"`
|
||||||
SortOrder int64 `db:"sort_order"`
|
SortOrder int64 `db:"sort_order"`
|
||||||
@ -54,8 +55,8 @@ func newInvProductPanModel(conn sqlx.SqlConn) *defaultInvProductPanModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultInvProductPanModel) Insert(ctx context.Context, data *InvProductPan) (sql.Result, error) {
|
func (m *defaultInvProductPanModel) Insert(ctx context.Context, data *InvProductPan) (sql.Result, error) {
|
||||||
query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?)", m.table, invProductPanRowsExpectAutoSet)
|
query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?, ?)", m.table, invProductPanRowsExpectAutoSet)
|
||||||
return m.conn.ExecCtx(ctx, query, data.PanId, data.ProductId, data.Name, data.Position, data.SortOrder, data.TenantId)
|
return m.conn.ExecCtx(ctx, query, data.PanId, data.ProductId, data.BatchId, data.Name, data.Position, data.SortOrder, data.TenantId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *defaultInvProductPanModel) FindOne(ctx context.Context, id int64) (*InvProductPan, error) {
|
func (m *defaultInvProductPanModel) FindOne(ctx context.Context, id int64) (*InvProductPan, error) {
|
||||||
@ -80,7 +81,7 @@ func (m *defaultInvProductPanModel) FindOneByPanId(ctx context.Context, panId st
|
|||||||
|
|
||||||
func (m *defaultInvProductPanModel) Update(ctx context.Context, data *InvProductPan) error {
|
func (m *defaultInvProductPanModel) Update(ctx context.Context, data *InvProductPan) error {
|
||||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE `id` = ?", m.table, invProductPanRowsWithPlaceHolder)
|
query := fmt.Sprintf("UPDATE %s SET %s WHERE `id` = ?", m.table, invProductPanRowsWithPlaceHolder)
|
||||||
_, err := m.conn.ExecCtx(ctx, query, data.PanId, data.ProductId, data.Name, data.Position, data.SortOrder, data.TenantId, data.Id)
|
_, err := m.conn.ExecCtx(ctx, query, data.PanId, data.ProductId, data.BatchId, data.Name, data.Position, data.SortOrder, data.TenantId, data.Id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
82
model/invyarnmodel.go
Normal file
82
model/invyarnmodel.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ InvYarnModel = (*customInvYarnModel)(nil)
|
||||||
|
|
||||||
|
type (
|
||||||
|
InvYarnModel interface {
|
||||||
|
invYarnModel
|
||||||
|
FindList(ctx context.Context, tenantId string, page, pageSize int64, yarnName, supplierId string, status int64) ([]*InvYarn, int64, error)
|
||||||
|
FindOneByUnique(ctx context.Context, tenantId, yarnName, color, supplierId string) (*InvYarn, error)
|
||||||
|
SoftDeleteByYarnId(ctx context.Context, yarnId string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
customInvYarnModel struct {
|
||||||
|
*defaultInvYarnModel
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewInvYarnModel(conn sqlx.SqlConn) InvYarnModel {
|
||||||
|
return &customInvYarnModel{
|
||||||
|
defaultInvYarnModel: newInvYarnModel(conn),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvYarnModel) FindList(ctx context.Context, tenantId string, page, pageSize int64, yarnName, supplierId string, status int64) ([]*InvYarn, int64, error) {
|
||||||
|
where := "WHERE tenant_id = ? AND deleted_at IS NULL"
|
||||||
|
args := []interface{}{tenantId}
|
||||||
|
|
||||||
|
if yarnName != "" {
|
||||||
|
where += " AND yarn_name LIKE ?"
|
||||||
|
args = append(args, "%"+yarnName+"%")
|
||||||
|
}
|
||||||
|
if supplierId != "" {
|
||||||
|
where += " AND supplier_id = ?"
|
||||||
|
args = append(args, supplierId)
|
||||||
|
}
|
||||||
|
if status >= 0 {
|
||||||
|
where += " AND status = ?"
|
||||||
|
args = append(args, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
var total int64
|
||||||
|
countQuery := fmt.Sprintf("SELECT COUNT(*) FROM %s %s", m.table, where)
|
||||||
|
if err := m.conn.QueryRowCtx(ctx, &total, countQuery, args...); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var list []*InvYarn
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s %s ORDER BY created_at DESC LIMIT ? OFFSET ?", invYarnRows, m.table, where)
|
||||||
|
args = append(args, pageSize, (page-1)*pageSize)
|
||||||
|
if err := m.conn.QueryRowsCtx(ctx, &list, query, args...); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return list, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvYarnModel) FindOneByUnique(ctx context.Context, tenantId, yarnName, color, supplierId string) (*InvYarn, error) {
|
||||||
|
var resp InvYarn
|
||||||
|
query := fmt.Sprintf("SELECT %s FROM %s WHERE tenant_id = ? AND yarn_name = ? AND color = ? AND supplier_id = ? AND deleted_at IS NULL LIMIT 1", invYarnRows, m.table)
|
||||||
|
if err := m.conn.QueryRowCtx(ctx, &resp, query, tenantId, yarnName, color, supplierId); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *customInvYarnModel) SoftDeleteByYarnId(ctx context.Context, yarnId string) error {
|
||||||
|
yarn, err := m.FindOneByYarnId(ctx, yarnId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
yarn.Status = 0
|
||||||
|
yarn.DeletedAt.Time = time.Now()
|
||||||
|
yarn.DeletedAt.Valid = true
|
||||||
|
return m.Update(ctx, yarn)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user