chore: sync codebase with upstream
Align origin/main with upstream/main (GitHub). The two branches diverged due to pre-rebase vs post-rebase merge commits for the k8s-amd64-dockerfiles feature. Includes: multi-stage Go compilation Dockerfiles, pan-bolt inventory features, CRM relations, Excel import tooling, proto/gRPC updates, migration scripts, and tools/ directory. Excludes deploy/bin/ pre-compiled binaries (arm64, not needed for amd64 K3s cluster; builds use multi-stage Dockerfiles now).
This commit is contained in:
parent
c5ab2279c0
commit
379fb28d92
30
.gitignore
vendored
30
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/go,macos,visualstudiocode
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=go,macos,visualstudiocode
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,go,macos
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,go,macos
|
||||
|
||||
### Go ###
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
@ -25,6 +25,21 @@
|
||||
# Go workspace file
|
||||
go.work
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
@ -77,16 +92,9 @@ Temporary Items
|
||||
.history
|
||||
.ionide
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/go,macos,visualstudiocode
|
||||
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,go,macos
|
||||
|
||||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||
|
||||
# MySQL data directory (contains binaries, certs, and runtime state)
|
||||
# Local runtime data and certificates
|
||||
data/
|
||||
|
||||
# Environment and secrets
|
||||
.env
|
||||
.env.*
|
||||
*.pem
|
||||
deploy/bin/
|
||||
worker/graphsync/go.sum
|
||||
|
||||
@ -11,5 +11,6 @@ RUN apk add --no-cache ca-certificates tzdata
|
||||
WORKDIR /app
|
||||
COPY --from=builder /server ./gateway
|
||||
COPY deploy/etc/gateway.yaml etc/gateway.yaml
|
||||
COPY deploy/tools/ tools/
|
||||
EXPOSE 8888
|
||||
CMD ["./gateway", "-f", "etc/gateway.yaml"]
|
||||
|
||||
@ -62,10 +62,10 @@ services:
|
||||
- --name=default
|
||||
- --data-dir=/etcd-data
|
||||
- --listen-client-urls=http://0.0.0.0:2379
|
||||
- --advertise-client-urls=http://etcd:2379
|
||||
- --advertise-client-urls=http://127.0.0.1:2379
|
||||
- --listen-peer-urls=http://0.0.0.0:2380
|
||||
- --initial-advertise-peer-urls=http://etcd:2380
|
||||
- --initial-cluster=default=http://etcd:2380
|
||||
- --initial-advertise-peer-urls=http://127.0.0.1:2380
|
||||
- --initial-cluster=default=http://127.0.0.1:2380
|
||||
- --initial-cluster-state=new
|
||||
ports:
|
||||
- "2379:2379"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
Name: gateway-api
|
||||
Host: 0.0.0.0
|
||||
Port: 8888
|
||||
Timeout: 120000
|
||||
|
||||
Auth:
|
||||
AccessSecret: muyu-wms-jwt-secret-key-2026
|
||||
@ -23,6 +24,7 @@ InventoryRpc:
|
||||
- etcd:2379
|
||||
Key: inventory.rpc
|
||||
NonBlock: true
|
||||
Timeout: 60000
|
||||
|
||||
Log:
|
||||
ServiceName: gateway-api
|
||||
|
||||
@ -334,27 +334,27 @@ CREATE TABLE `casbin_rule` (
|
||||
-- ==================== Initial Data ====================
|
||||
|
||||
-- Default admin user (password: admin123, bcrypt hashed)
|
||||
INSERT INTO `sys_user` (`user_id`, `username`, `password`, `salt`, `real_name`, `status`)
|
||||
INSERT IGNORE INTO `sys_user` (`user_id`, `username`, `password`, `salt`, `real_name`, `status`)
|
||||
VALUES ('u_admin_001', 'admin', '$2a$10$S5XPWRXUnexAt9KJw2CefeHMa6aude7j5dm5qgWM1YMQAAwRgsGXa', 'bcrypt', 'System Admin', 1);
|
||||
|
||||
-- Default tenant and mapping
|
||||
INSERT INTO `crm_tenant` (`tenant_id`, `tenant_name`, `tenant_code`, `status`)
|
||||
INSERT IGNORE INTO `crm_tenant` (`tenant_id`, `tenant_name`, `tenant_code`, `status`)
|
||||
VALUES ('t_default_001', '默认租户', 'DEFAULT', 1);
|
||||
|
||||
INSERT INTO `crm_tenant_user` (`tenant_user_id`, `tenant_id`, `user_id`, `is_primary`, `status`)
|
||||
INSERT IGNORE INTO `crm_tenant_user` (`tenant_user_id`, `tenant_id`, `user_id`, `is_primary`, `status`)
|
||||
VALUES ('tu_001', 't_default_001', 'u_admin_001', 1, 1);
|
||||
|
||||
-- Default roles
|
||||
INSERT INTO `sys_role` (`role_id`, `role_name`, `role_key`, `role_desc`, `sort_order`, `status`) VALUES
|
||||
INSERT IGNORE INTO `sys_role` (`role_id`, `role_name`, `role_key`, `role_desc`, `sort_order`, `status`) VALUES
|
||||
('r_001', '系统管理员', 'admin', 'Full system access', 1, 1),
|
||||
('r_002', '仓库管理员', 'warehouse', 'Warehouse management access', 2, 1),
|
||||
('r_003', '普通用户', 'user', 'Basic read access', 3, 1);
|
||||
|
||||
-- Assign admin role to admin user
|
||||
INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES ('u_admin_001', 'r_001');
|
||||
INSERT IGNORE INTO `sys_user_role` (`user_id`, `role_id`) VALUES ('u_admin_001', 'r_001');
|
||||
|
||||
-- Default menus
|
||||
INSERT INTO `sys_menu` (`menu_id`, `parent_id`, `menu_name`, `menu_type`, `path`, `component`, `permission`, `icon`, `sort_order`, `visible`, `status`) VALUES
|
||||
INSERT IGNORE INTO `sys_menu` (`menu_id`, `parent_id`, `menu_name`, `menu_type`, `path`, `component`, `permission`, `icon`, `sort_order`, `visible`, `status`) VALUES
|
||||
-- Dashboard
|
||||
('m_001', '', '首页', 1, '/dashboard', './Dashboard', '', 'DashboardOutlined', 1, 1, 1),
|
||||
-- System Management
|
||||
@ -374,26 +374,26 @@ INSERT INTO `sys_menu` (`menu_id`, `parent_id`, `menu_name`, `menu_type`, `path`
|
||||
('m_206', 'm_200', 'Excel导入', 2, '/inventory/import', './Inventory/Import', 'inventory:import:exec', 'ImportOutlined', 6, 1, 1);
|
||||
|
||||
-- CRM menus
|
||||
INSERT INTO `sys_menu` (`menu_id`, `parent_id`, `menu_name`, `menu_type`, `path`, `component`, `permission`, `icon`, `sort_order`, `visible`, `status`) VALUES
|
||||
INSERT IGNORE INTO `sys_menu` (`menu_id`, `parent_id`, `menu_name`, `menu_type`, `path`, `component`, `permission`, `icon`, `sort_order`, `visible`, `status`) VALUES
|
||||
('m_300', '', '客户关系', 1, '/crm', '', '', 'NodeIndexOutlined', 300, 1, 1),
|
||||
('m_301', 'm_300', '上下游关系', 2, '/crm/relations', './CRM/Relations', 'crm:relation:list', 'ApartmentOutlined', 1, 1, 1);
|
||||
|
||||
-- Assign all menus to admin role
|
||||
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||
INSERT IGNORE INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||
SELECT 'r_001', `menu_id` FROM `sys_menu`;
|
||||
|
||||
-- Assign inventory menus to warehouse role
|
||||
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
|
||||
INSERT IGNORE INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
|
||||
('r_002', 'm_001'),
|
||||
('r_002', 'm_200'), ('r_002', 'm_201'), ('r_002', 'm_202'),
|
||||
('r_002', 'm_203'), ('r_002', 'm_204'), ('r_002', 'm_205'), ('r_002', 'm_206');
|
||||
|
||||
-- Assign CRM menus to admin role
|
||||
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
|
||||
INSERT IGNORE INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
|
||||
('r_001', 'm_300'), ('r_001', 'm_301');
|
||||
|
||||
-- Default Casbin policies
|
||||
INSERT INTO `casbin_rule` (`ptype`, `v0`, `v1`, `v2`) VALUES
|
||||
INSERT IGNORE INTO `casbin_rule` (`ptype`, `v0`, `v1`, `v2`) VALUES
|
||||
('p', 'admin', '/api/v1/*', '*'),
|
||||
('p', 'warehouse', '/api/v1/auth/*', '*'),
|
||||
('p', 'warehouse', '/api/v1/inventory/*', '*'),
|
||||
@ -404,7 +404,7 @@ INSERT INTO `casbin_rule` (`ptype`, `v0`, `v1`, `v2`) VALUES
|
||||
('p', 'user', '/api/v1/inventory/stocks/*', 'GET');
|
||||
|
||||
-- Default system configs
|
||||
INSERT INTO `sys_config` (`config_id`, `config_key`, `config_value`, `config_name`, `config_group`, `remark`) VALUES
|
||||
INSERT IGNORE INTO `sys_config` (`config_id`, `config_key`, `config_value`, `config_name`, `config_group`, `remark`) VALUES
|
||||
('c_001', 'sys_name', 'muyuqingfeng仓储管理系统', 'System Name', 'basic', 'System display name'),
|
||||
('c_002', 'sys_logo', '', 'System Logo', 'basic', 'System logo URL'),
|
||||
('c_003', 'upload_max_size', '10', 'Upload Max Size (MB)', 'upload', 'Maximum file upload size'),
|
||||
|
||||
44
deploy/mysql/migrations/20260403_add_pan_and_bolt.sql
Normal file
44
deploy/mysql/migrations/20260403_add_pan_and_bolt.sql
Normal file
@ -0,0 +1,44 @@
|
||||
-- Three-layer inventory model: Product -> Pan(盘) -> Bolt(匹)
|
||||
|
||||
-- Pan table: each row = one physical pan/roll, belongs to a product
|
||||
CREATE TABLE IF NOT EXISTS `inv_product_pan` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`pan_id` VARCHAR(32) NOT NULL,
|
||||
`product_id` VARCHAR(32) NOT NULL,
|
||||
`name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'pan label: A, B, C...',
|
||||
`position` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'physical location: Shanghai, Nanjing...',
|
||||
`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_tenant_id` (`tenant_id`),
|
||||
KEY `idx_position` (`position`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Bolt table: each row = one physical bolt/piece, belongs to a pan
|
||||
CREATE TABLE IF NOT EXISTS `inv_product_bolt` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`bolt_id` VARCHAR(32) NOT NULL,
|
||||
`pan_id` VARCHAR(32) NOT NULL COMMENT 'FK to inv_product_pan',
|
||||
`length_m` DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 'length in meters',
|
||||
`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;
|
||||
|
||||
-- Add composite index for product summary aggregation (panel 1)
|
||||
-- Use PREPARE/EXECUTE to skip if index already exists (MySQL has no CREATE INDEX IF NOT EXISTS).
|
||||
SET @ix = (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'inv_product' AND INDEX_NAME = 'idx_product_name_tenant');
|
||||
SET @s = IF(@ix = 0,
|
||||
'ALTER TABLE `inv_product` ADD KEY `idx_product_name_tenant` (`product_name`, `tenant_id`)',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
65
deploy/mysql/migrations/20260403_data_migration.sql
Normal file
65
deploy/mysql/migrations/20260403_data_migration.sql
Normal file
@ -0,0 +1,65 @@
|
||||
-- Data migration: split existing inv_product flat data into pan + bolt records.
|
||||
-- Run AFTER 20260403_add_pan_and_bolt.sql but BEFORE 20260403_drop_legacy_columns.sql.
|
||||
-- Wrapped in a stored procedure so re-runs on an already-migrated database
|
||||
-- (where `location` was already dropped) silently succeed rather than error.
|
||||
-- MySQL validates column names at call time, not at CREATE PROCEDURE time,
|
||||
-- so the IF guard prevents the INSERTs from running when the column is absent.
|
||||
|
||||
DROP PROCEDURE IF EXISTS _migrate_inv_pan_bolt;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE _migrate_inv_pan_bolt()
|
||||
BEGIN
|
||||
DECLARE v_has_location TINYINT DEFAULT 0;
|
||||
SELECT COUNT(*) INTO v_has_location
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'inv_product'
|
||||
AND COLUMN_NAME = 'location';
|
||||
|
||||
IF v_has_location = 1 THEN
|
||||
-- Step 1: one default pan per product, position taken from legacy `location`
|
||||
INSERT INTO inv_product_pan (pan_id, product_id, name, position, sort_order, tenant_id)
|
||||
SELECT
|
||||
CONCAT('pan_mig_', product_id),
|
||||
product_id,
|
||||
'A',
|
||||
COALESCE(location, ''),
|
||||
1,
|
||||
COALESCE(tenant_id, '')
|
||||
FROM inv_product
|
||||
WHERE deleted_at IS NULL
|
||||
AND product_id NOT IN (SELECT DISTINCT product_id FROM inv_product_pan);
|
||||
|
||||
-- Step 2: bolt records, one per unit_piece (or one if unit_pieces = 0)
|
||||
INSERT INTO inv_product_bolt (bolt_id, pan_id, length_m, sort_order, tenant_id)
|
||||
SELECT
|
||||
CONCAT('bolt_mig_', product_id, '_', seq.n),
|
||||
CONCAT('pan_mig_', product_id),
|
||||
CASE
|
||||
WHEN unit_pieces > 0 THEN ROUND(stock_quantity / unit_pieces, 2)
|
||||
ELSE stock_quantity
|
||||
END,
|
||||
seq.n,
|
||||
COALESCE(tenant_id, '')
|
||||
FROM inv_product
|
||||
CROSS JOIN (
|
||||
SELECT 1 AS n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5
|
||||
UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10
|
||||
UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
|
||||
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19 UNION ALL SELECT 20
|
||||
) seq
|
||||
WHERE deleted_at IS NULL
|
||||
AND stock_quantity > 0
|
||||
AND seq.n <= GREATEST(unit_pieces, 1)
|
||||
AND CONCAT('pan_mig_', product_id) IN (SELECT pan_id FROM inv_product_pan);
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL _migrate_inv_pan_bolt();
|
||||
DROP PROCEDURE IF EXISTS _migrate_inv_pan_bolt;
|
||||
|
||||
-- Verification queries (run manually to check)
|
||||
-- SELECT COUNT(*) AS pan_count FROM inv_product_pan WHERE pan_id LIKE 'pan_mig_%';
|
||||
-- SELECT COUNT(*) AS bolt_count FROM inv_product_bolt WHERE bolt_id LIKE 'bolt_mig_%';
|
||||
26
deploy/mysql/migrations/20260403_drop_legacy_columns.sql
Normal file
26
deploy/mysql/migrations/20260403_drop_legacy_columns.sql
Normal file
@ -0,0 +1,26 @@
|
||||
-- Remove deprecated flat columns from inv_product.
|
||||
-- Must run AFTER 20260403_data_migration.sql has migrated existing rows.
|
||||
-- Uses PREPARE/EXECUTE to skip each column that was already dropped
|
||||
-- (MySQL has no DROP COLUMN IF EXISTS; that is a MariaDB-only extension).
|
||||
|
||||
SET @db = DATABASE();
|
||||
|
||||
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='unit_pieces');
|
||||
SET @s = IF(@c=1, 'ALTER TABLE `inv_product` DROP COLUMN `unit_pieces`', 'SELECT 1');
|
||||
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='unit_rolls');
|
||||
SET @s = IF(@c=1, 'ALTER TABLE `inv_product` DROP COLUMN `unit_rolls`', 'SELECT 1');
|
||||
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='stock_quantity');
|
||||
SET @s = IF(@c=1, 'ALTER TABLE `inv_product` DROP COLUMN `stock_quantity`', 'SELECT 1');
|
||||
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='location');
|
||||
SET @s = IF(@c=1, 'ALTER TABLE `inv_product` DROP COLUMN `location`', 'SELECT 1');
|
||||
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @c = (SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='inv_product' AND COLUMN_NAME='cost_price');
|
||||
SET @s = IF(@c=1, 'ALTER TABLE `inv_product` DROP COLUMN `cost_price`', 'SELECT 1');
|
||||
PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
9
deploy/mysql/migrations/20260407_fix_menu_mojibake.sql
Normal file
9
deploy/mysql/migrations/20260407_fix_menu_mojibake.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- Fix double-encoded (CP1252→UTF-8) menu_name for pans/bolts entries
|
||||
-- Root cause: these records were inserted through a connection that
|
||||
-- misinterpreted UTF-8 bytes as CP1252, causing mojibake.
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
USE `muyu_wms`;
|
||||
|
||||
UPDATE `sys_menu` SET `menu_name` = '盘库存' WHERE `menu_id` = 'm_207' AND `path` = '/inventory/pans';
|
||||
UPDATE `sys_menu` SET `menu_name` = '匹库存' WHERE `menu_id` = 'm_208' AND `path` = '/inventory/bolts';
|
||||
@ -11,6 +11,9 @@ server {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Allow large file uploads (e.g. Excel imports up to 100MB)
|
||||
client_max_body_size 100m;
|
||||
|
||||
# API proxy
|
||||
location /api/ {
|
||||
# Use Docker DNS dynamic resolution to avoid stale container IP after recreate.
|
||||
@ -29,7 +32,15 @@ server {
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Static assets cache
|
||||
# Do not aggressively cache entry bundles because file names are stable
|
||||
# (for example umi.js / umi.css) and stale cache can cause a blank page
|
||||
# after deployment updates.
|
||||
location ~* ^/(umi\.js|umi\.css|preload_helper\.js)$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
|
||||
# Cache other static assets that are typically fingerprinted/chunked.
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
|
||||
119
deploy/tools/package-lock.json
generated
Normal file
119
deploy/tools/package-lock.json
generated
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"xlsx": "^0.18.5"
|
||||
}
|
||||
},
|
||||
"node_modules/adler-32": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
|
||||
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cfb": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
|
||||
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"crc-32": "~1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/codepage": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
|
||||
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/crc-32": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
|
||||
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"crc32": "bin/crc32.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/frac": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
|
||||
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/ssf": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
|
||||
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"frac": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/wmf": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
|
||||
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/word": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
|
||||
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/xlsx": {
|
||||
"version": "0.18.5",
|
||||
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
|
||||
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"adler-32": "~1.3.0",
|
||||
"cfb": "~1.2.1",
|
||||
"codepage": "~1.15.0",
|
||||
"crc-32": "~1.2.1",
|
||||
"ssf": "~0.11.2",
|
||||
"wmf": "~1.0.1",
|
||||
"word": "~0.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"xlsx": "bin/xlsx.njs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
deploy/tools/package.json
Normal file
15
deploy/tools/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "tools",
|
||||
"version": "1.0.0",
|
||||
"main": "xls2json.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"xlsx": "^0.18.5"
|
||||
}
|
||||
}
|
||||
21
deploy/tools/xls2json.js
Normal file
21
deploy/tools/xls2json.js
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env node
|
||||
// Converts .xls/.xlsx to JSON on stdout.
|
||||
// Usage: node xls2json.js <filepath>
|
||||
const XLSX = require(__dirname + '/node_modules/xlsx');
|
||||
const path = require('path');
|
||||
|
||||
const file = process.argv[2];
|
||||
if (!file) {
|
||||
process.stderr.write('usage: xls2json.js <file>\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const wb = XLSX.readFile(file);
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
const rows = XLSX.utils.sheet_to_json(ws, { header: 1, defval: '' });
|
||||
process.stdout.write(JSON.stringify(rows));
|
||||
} catch (e) {
|
||||
process.stderr.write('xls2json error: ' + e.message + '\n');
|
||||
process.exit(2);
|
||||
}
|
||||
@ -8,3 +8,23 @@ Auth:
|
||||
DefaultTenantId: t_default_001
|
||||
|
||||
DataSource: root:muyu2026@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"
|
||||
|
||||
SystemRpc:
|
||||
Etcd:
|
||||
Hosts:
|
||||
- 127.0.0.1:2379
|
||||
Key: system.rpc
|
||||
NonBlock: true
|
||||
|
||||
InventoryRpc:
|
||||
Etcd:
|
||||
Hosts:
|
||||
- 127.0.0.1:2379
|
||||
Key: inventory.rpc
|
||||
NonBlock: true
|
||||
|
||||
Log:
|
||||
ServiceName: gateway-api
|
||||
Mode: console
|
||||
Level: info
|
||||
|
||||
@ -219,47 +219,33 @@ type (
|
||||
// ==================== Product Types ====================
|
||||
type (
|
||||
ProductInfo {
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
Spec string `json:"spec"`
|
||||
Color string `json:"color"`
|
||||
UnitPieces int64 `json:"unitPieces"`
|
||||
UnitRolls int64 `json:"unitRolls"`
|
||||
StockQuantity string `json:"stockQuantity"`
|
||||
Location string `json:"location"`
|
||||
CostPrice string `json:"costPrice"`
|
||||
SalesPrice string `json:"salesPrice"`
|
||||
Remark string `json:"remark"`
|
||||
Status int64 `json:"status"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
Spec string `json:"spec"`
|
||||
Color string `json:"color"`
|
||||
SalesPrice string `json:"salesPrice"`
|
||||
Remark string `json:"remark"`
|
||||
Status int64 `json:"status"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
CreateProductReq {
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
UnitPieces int64 `json:"unitPieces,optional"`
|
||||
UnitRolls int64 `json:"unitRolls,optional"`
|
||||
StockQuantity string `json:"stockQuantity,optional"`
|
||||
Location string `json:"location,optional"`
|
||||
CostPrice string `json:"costPrice,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
Pans []PanInput `json:"pans,optional"`
|
||||
}
|
||||
UpdateProductReq {
|
||||
ProductName string `json:"productName,optional"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
UnitPieces int64 `json:"unitPieces,optional"`
|
||||
UnitRolls int64 `json:"unitRolls,optional"`
|
||||
StockQuantity string `json:"stockQuantity,optional"`
|
||||
Location string `json:"location,optional"`
|
||||
CostPrice string `json:"costPrice,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
ProductName string `json:"productName,optional"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
}
|
||||
ListProductReq {
|
||||
Page int64 `form:"page,default=1"`
|
||||
@ -267,7 +253,6 @@ type (
|
||||
ProductName string `form:"productName,optional"`
|
||||
Spec string `form:"spec,optional"`
|
||||
Color string `form:"color,optional"`
|
||||
Location string `form:"location,optional"`
|
||||
Status int64 `form:"status,optional,default=-1"`
|
||||
}
|
||||
ListProductResp {
|
||||
@ -283,13 +268,92 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// ==================== Pan / Bolt Types ====================
|
||||
type (
|
||||
BoltInfo {
|
||||
BoltId string `json:"boltId"`
|
||||
PanId string `json:"panId"`
|
||||
LengthM string `json:"lengthM"`
|
||||
SortOrder int64 `json:"sortOrder"`
|
||||
}
|
||||
PanInfo {
|
||||
PanId string `json:"panId"`
|
||||
ProductId string `json:"productId"`
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position"`
|
||||
SortOrder int64 `json:"sortOrder"`
|
||||
Bolts []BoltInfo `json:"bolts"`
|
||||
BoltCount int64 `json:"boltCount"`
|
||||
TotalLength string `json:"totalLength"`
|
||||
}
|
||||
PanInput {
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position,optional"`
|
||||
BoltLengths []string `json:"boltLengths,optional"`
|
||||
}
|
||||
ListPanResp {
|
||||
List []PanInfo `json:"list"`
|
||||
}
|
||||
SavePansReq {
|
||||
Pans []PanInput `json:"pans"`
|
||||
}
|
||||
ListBoltResp {
|
||||
List []BoltInfo `json:"list"`
|
||||
}
|
||||
SaveBoltsReq {
|
||||
Lengths []string `json:"lengths"`
|
||||
}
|
||||
ProductTreeResp {
|
||||
Product ProductInfo `json:"product"`
|
||||
Pans []PanInfo `json:"pans"`
|
||||
TotalPanCount int64 `json:"totalPanCount"`
|
||||
TotalBoltCount int64 `json:"totalBoltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
}
|
||||
)
|
||||
|
||||
// ==================== Panel Types ====================
|
||||
type (
|
||||
ProductSummaryItem {
|
||||
ProductName string `json:"productName"`
|
||||
Spec string `json:"spec"`
|
||||
ColorCount int64 `json:"colorCount"`
|
||||
TotalPanCount int64 `json:"totalPanCount"`
|
||||
TotalBoltCount int64 `json:"totalBoltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
Colors string `json:"colors"`
|
||||
Locations string `json:"locations"`
|
||||
}
|
||||
ProductSummaryResp {
|
||||
List []ProductSummaryItem `json:"list"`
|
||||
}
|
||||
ColorDetailItem {
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
Color string `json:"color"`
|
||||
Spec string `json:"spec"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
PanCount int64 `json:"panCount"`
|
||||
BoltCount int64 `json:"boltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
Locations string `json:"locations"`
|
||||
SalesPrice string `json:"salesPrice"`
|
||||
}
|
||||
ListColorDetailReq {
|
||||
ProductName string `form:"productName"`
|
||||
}
|
||||
ColorDetailResp {
|
||||
List []ColorDetailItem `json:"list"`
|
||||
}
|
||||
)
|
||||
|
||||
// ==================== Stock Statistics Types ====================
|
||||
type (
|
||||
StockSummaryResp {
|
||||
ProductCount int64 `json:"productCount"`
|
||||
TotalPieces int64 `json:"totalPieces"`
|
||||
TotalRolls int64 `json:"totalRolls"`
|
||||
TotalCostValue string `json:"totalCostValue"`
|
||||
TotalPans int64 `json:"totalPans"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
TotalSalesValue string `json:"totalSalesValue"`
|
||||
}
|
||||
StockGroupItem {
|
||||
@ -644,6 +708,36 @@ service gateway-api {
|
||||
|
||||
@handler ExportProductHandler
|
||||
get /products/export
|
||||
|
||||
@handler GetProductSummaryHandler
|
||||
get /products/summary returns (ProductSummaryResp)
|
||||
|
||||
@handler GetColorDetailHandler
|
||||
get /products/colors (ListColorDetailReq) returns (ColorDetailResp)
|
||||
|
||||
@handler GetProductTreeHandler
|
||||
get /products/:id/tree returns (ProductTreeResp)
|
||||
|
||||
@handler ListPansHandler
|
||||
get /products/:id/pans returns (ListPanResp)
|
||||
|
||||
@handler SavePansHandler
|
||||
put /products/:id/pans (SavePansReq) returns (IdResp)
|
||||
}
|
||||
|
||||
// Inventory - Pan/Bolt Management
|
||||
@server (
|
||||
prefix: /api/v1/inventory
|
||||
group: inventory/panbolt
|
||||
jwt: Auth
|
||||
middleware: AuthorityMiddleware
|
||||
)
|
||||
service gateway-api {
|
||||
@handler ListBoltsHandler
|
||||
get /pans/:id/bolts returns (ListBoltResp)
|
||||
|
||||
@handler SaveBoltsHandler
|
||||
put /pans/:id/bolts (SaveBoltsReq) returns (IdResp)
|
||||
}
|
||||
|
||||
// Inventory - Stock Query & Statistics
|
||||
|
||||
@ -50,7 +50,7 @@ func main() {
|
||||
if ok {
|
||||
return http.StatusOK, &Response{Code: int(s.Code()), Msg: s.Message()}
|
||||
}
|
||||
return http.StatusOK, &Response{Code: 1001, Msg: err.Error()}
|
||||
return http.StatusBadRequest, &Response{Code: 1001, Msg: err.Error()}
|
||||
})
|
||||
|
||||
httpx.SetOkHandler(func(ctx context.Context, a interface{}) interface{} {
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package relation
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
func SearchTenantsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
keyword := r.URL.Query().Get("keyword")
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
if limit <= 0 {
|
||||
limit = 20
|
||||
}
|
||||
|
||||
tenants, err := svcCtx.CrmRepo.SearchTenants(r.Context(), keyword, limit)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
httpx.OkJsonCtx(r.Context(), w, map[string]interface{}{
|
||||
"list": tenants,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package panbolt
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/panbolt"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
)
|
||||
|
||||
func ListBoltViewHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ListBoltViewReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
l := logic.NewListBoltViewLogic(r.Context(), svcCtx)
|
||||
resp, err := l.ListBoltView(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package panbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/panbolt"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
)
|
||||
|
||||
func ListBoltsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||
l := logic.NewListBoltsLogic(ctx, svcCtx)
|
||||
resp, err := l.ListBolts()
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package panbolt
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/panbolt"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
)
|
||||
|
||||
func ListPanViewHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ListPanViewReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
l := logic.NewListPanViewLogic(r.Context(), svcCtx)
|
||||
resp, err := l.ListPanView(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package panbolt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/panbolt"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
)
|
||||
|
||||
func SaveBoltsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.SaveBoltsReq
|
||||
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 := logic.NewSaveBoltsLogic(ctx, svcCtx)
|
||||
resp, err := l.SaveBolts(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
)
|
||||
|
||||
func GetColorDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.ListColorDetailReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
l := logic.NewGetColorDetailLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetColorDetail(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
)
|
||||
|
||||
func GetProductSummaryHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := logic.NewGetProductSummaryLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetProductSummary()
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
)
|
||||
|
||||
func GetProductTreeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||
l := logic.NewGetProductTreeLogic(ctx, svcCtx)
|
||||
resp, err := l.GetProductTree()
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,46 @@
|
||||
// Code scaffolded by goctl. Safe to edit.
|
||||
// goctl 1.9.2
|
||||
|
||||
package product
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
)
|
||||
|
||||
const maxUploadSize = 50 << 20 // 50 MB
|
||||
|
||||
func ImportProductHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
|
||||
|
||||
file, header, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
ext := filepath.Ext(header.Filename)
|
||||
tmpFile, err := os.CreateTemp("", "import-*"+ext)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
defer tmpFile.Close()
|
||||
|
||||
if _, err = io.Copy(tmpFile, file); err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
return
|
||||
}
|
||||
tmpFile.Close()
|
||||
|
||||
l := product.NewImportProductLogic(r.Context(), svcCtx)
|
||||
resp, err := l.ImportProduct()
|
||||
resp, err := l.ImportProduct(tmpFile.Name(), header.Filename)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
)
|
||||
|
||||
func ListPansHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := context.WithValue(r.Context(), "pathId", pathvar.Vars(r)["id"])
|
||||
l := logic.NewListPansLogic(ctx, svcCtx)
|
||||
resp, err := l.ListPans()
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/pathvar"
|
||||
logic "muyu-apiserver/gateway/internal/logic/inventory/product"
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
)
|
||||
|
||||
func SavePansHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.SavePansReq
|
||||
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 := logic.NewSavePansLogic(ctx, svcCtx)
|
||||
resp, err := l.SavePans(&req)
|
||||
if err != nil {
|
||||
httpx.ErrorCtx(r.Context(), w, err)
|
||||
} else {
|
||||
httpx.OkJsonCtx(r.Context(), w, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import (
|
||||
crmrelation "muyu-apiserver/gateway/internal/handler/crm/relation"
|
||||
inventoryadjust "muyu-apiserver/gateway/internal/handler/inventory/adjust"
|
||||
inventorycheck "muyu-apiserver/gateway/internal/handler/inventory/check"
|
||||
inventorypanbolt "muyu-apiserver/gateway/internal/handler/inventory/panbolt"
|
||||
inventoryproduct "muyu-apiserver/gateway/internal/handler/inventory/product"
|
||||
inventorystock "muyu-apiserver/gateway/internal/handler/inventory/stock"
|
||||
systemconfig "muyu-apiserver/gateway/internal/handler/system/config"
|
||||
@ -34,6 +35,17 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
rest.WithPrefix("/api/v1/auth"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/tenants/search",
|
||||
Handler: crmrelation.SearchTenantsHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
rest.WithPrefix("/api/v1/public"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
@ -175,6 +187,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/products",
|
||||
Handler: inventoryproduct.CreateProductHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/summary",
|
||||
Handler: inventoryproduct.GetProductSummaryHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/colors",
|
||||
Handler: inventoryproduct.GetColorDetailHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/export",
|
||||
Handler: inventoryproduct.ExportProductHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/:id",
|
||||
@ -192,9 +219,29 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/export",
|
||||
Handler: inventoryproduct.ExportProductHandler(serverCtx),
|
||||
Path: "/products/:id/tree",
|
||||
Handler: inventoryproduct.GetProductTreeHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/products/:id/pans",
|
||||
Handler: inventoryproduct.ListPansHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPut,
|
||||
Path: "/products/:id/pans",
|
||||
Handler: inventoryproduct.SavePansHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/inventory"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodPost,
|
||||
Path: "/products/import",
|
||||
@ -204,6 +251,37 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/inventory"),
|
||||
rest.WithMaxBytes(50<<20),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
rest.WithMiddlewares(
|
||||
[]rest.Middleware{serverCtx.AuthorityMiddleware},
|
||||
[]rest.Route{
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/pans",
|
||||
Handler: inventorypanbolt.ListPanViewHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/bolts",
|
||||
Handler: inventorypanbolt.ListBoltViewHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/pans/:id/bolts",
|
||||
Handler: inventorypanbolt.ListBoltsHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodPut,
|
||||
Path: "/pans/:id/bolts",
|
||||
Handler: inventorypanbolt.SaveBoltsHandler(serverCtx),
|
||||
},
|
||||
}...,
|
||||
),
|
||||
rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
|
||||
rest.WithPrefix("/api/v1/inventory"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
package panbolt
|
||||
|
||||
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 ListBoltViewLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewListBoltViewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListBoltViewLogic {
|
||||
return &ListBoltViewLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListBoltViewLogic) ListBoltView(req *types.ListBoltViewReq) (resp *types.ListBoltViewResp, err error) {
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ListBoltView(l.ctx, &pb.ListBoltViewReq{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
ProductName: req.ProductName,
|
||||
Position: req.Position,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := make([]types.BoltListItem, 0, len(rpcResp.List))
|
||||
for _, item := range rpcResp.List {
|
||||
list = append(list, types.BoltListItem{
|
||||
BoltId: item.BoltId,
|
||||
PanId: item.PanId,
|
||||
LengthM: item.LengthM,
|
||||
Color: item.Color,
|
||||
SortOrder: item.SortOrder,
|
||||
PanName: item.PanName,
|
||||
Position: item.Position,
|
||||
ProductId: item.ProductId,
|
||||
ProductName: item.ProductName,
|
||||
})
|
||||
}
|
||||
return &types.ListBoltViewResp{Total: rpcResp.Total, List: list}, nil
|
||||
}
|
||||
44
gateway/internal/logic/inventory/panbolt/listBoltsLogic.go
Normal file
44
gateway/internal/logic/inventory/panbolt/listBoltsLogic.go
Normal file
@ -0,0 +1,44 @@
|
||||
package panbolt
|
||||
|
||||
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 ListBoltsLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewListBoltsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListBoltsLogic {
|
||||
return &ListBoltsLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListBoltsLogic) ListBolts() (resp *types.ListBoltResp, err error) {
|
||||
panId := ctxdata.GetPathId(l.ctx)
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ListBolts(l.ctx, &pb.ListBoltReq{PanId: panId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]types.BoltInfo, 0, len(rpcResp.List))
|
||||
for _, b := range rpcResp.List {
|
||||
list = append(list, types.BoltInfo{
|
||||
BoltId: b.BoltId,
|
||||
PanId: b.PanId,
|
||||
LengthM: b.LengthM,
|
||||
SortOrder: b.SortOrder,
|
||||
})
|
||||
}
|
||||
return &types.ListBoltResp{List: list}, nil
|
||||
}
|
||||
52
gateway/internal/logic/inventory/panbolt/listPanViewLogic.go
Normal file
52
gateway/internal/logic/inventory/panbolt/listPanViewLogic.go
Normal file
@ -0,0 +1,52 @@
|
||||
package panbolt
|
||||
|
||||
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 ListPanViewLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewListPanViewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPanViewLogic {
|
||||
return &ListPanViewLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListPanViewLogic) ListPanView(req *types.ListPanViewReq) (resp *types.ListPanViewResp, err error) {
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ListPanView(l.ctx, &pb.ListPanViewReq{
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
ProductName: req.ProductName,
|
||||
Position: req.Position,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list := make([]types.PanListItem, 0, len(rpcResp.List))
|
||||
for _, item := range rpcResp.List {
|
||||
list = append(list, types.PanListItem{
|
||||
PanId: item.PanId,
|
||||
ProductId: item.ProductId,
|
||||
Name: item.Name,
|
||||
Position: item.Position,
|
||||
ProductName: item.ProductName,
|
||||
Colors: item.Colors,
|
||||
BoltCount: item.BoltCount,
|
||||
TotalLengthM: item.TotalLengthM,
|
||||
})
|
||||
}
|
||||
return &types.ListPanViewResp{Total: rpcResp.Total, List: list}, nil
|
||||
}
|
||||
38
gateway/internal/logic/inventory/panbolt/saveBoltsLogic.go
Normal file
38
gateway/internal/logic/inventory/panbolt/saveBoltsLogic.go
Normal file
@ -0,0 +1,38 @@
|
||||
package panbolt
|
||||
|
||||
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 SaveBoltsLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewSaveBoltsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SaveBoltsLogic {
|
||||
return &SaveBoltsLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SaveBoltsLogic) SaveBolts(req *types.SaveBoltsReq) (resp *types.IdResp, err error) {
|
||||
panId := ctxdata.GetPathId(l.ctx)
|
||||
_, err = l.svcCtx.InventoryRpc.SaveBolts(l.ctx, &pb.SaveBoltsReq{
|
||||
PanId: panId,
|
||||
Lengths: req.Lengths,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &types.IdResp{Id: panId}, nil
|
||||
}
|
||||
@ -26,17 +26,13 @@ func NewCreateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Cre
|
||||
|
||||
func (l *CreateProductLogic) CreateProduct(req *types.CreateProductReq) (resp *types.IdResp, err error) {
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.CreateProduct(l.ctx, &pb.CreateProductReq{
|
||||
ProductName: req.ProductName,
|
||||
ImageUrl: req.ImageUrl,
|
||||
Spec: req.Spec,
|
||||
Color: req.Color,
|
||||
UnitPieces: req.UnitPieces,
|
||||
UnitRolls: req.UnitRolls,
|
||||
StockQuantity: req.StockQuantity,
|
||||
Location: req.Location,
|
||||
CostPrice: req.CostPrice,
|
||||
SalesPrice: req.SalesPrice,
|
||||
Remark: req.Remark,
|
||||
ProductName: req.ProductName,
|
||||
ImageUrl: req.ImageUrl,
|
||||
Spec: req.Spec,
|
||||
Color: req.Color,
|
||||
SalesPrice: req.SalesPrice,
|
||||
Remark: req.Remark,
|
||||
Pans: panInputsToPb(req.Pans),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -44,3 +40,18 @@ func (l *CreateProductLogic) CreateProduct(req *types.CreateProductReq) (resp *t
|
||||
|
||||
return &types.IdResp{Id: rpcResp.Id}, nil
|
||||
}
|
||||
|
||||
func panInputsToPb(pans []types.PanInput) []*pb.PanInput {
|
||||
if len(pans) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]*pb.PanInput, 0, len(pans))
|
||||
for _, p := range pans {
|
||||
out = append(out, &pb.PanInput{
|
||||
Name: p.Name,
|
||||
Position: p.Position,
|
||||
BoltLengths: p.BoltLengths,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package product
|
||||
|
||||
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 GetColorDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetColorDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetColorDetailLogic {
|
||||
return &GetColorDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetColorDetailLogic) GetColorDetail(req *types.ListColorDetailReq) (resp *types.ColorDetailResp, err error) {
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ListColorDetail(l.ctx, &pb.ListColorDetailReq{
|
||||
ProductName: req.ProductName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]types.ColorDetailItem, 0, len(rpcResp.List))
|
||||
for _, it := range rpcResp.List {
|
||||
list = append(list, types.ColorDetailItem{
|
||||
ProductId: it.ProductId,
|
||||
ProductName: it.ProductName,
|
||||
Color: it.Color,
|
||||
Spec: it.Spec,
|
||||
ImageUrl: it.ImageUrl,
|
||||
PanCount: it.PanCount,
|
||||
BoltCount: it.BoltCount,
|
||||
TotalLengthM: it.TotalLengthM,
|
||||
Locations: it.Locations,
|
||||
SalesPrice: it.SalesPrice,
|
||||
})
|
||||
}
|
||||
return &types.ColorDetailResp{List: list}, nil
|
||||
}
|
||||
@ -35,21 +35,6 @@ func (l *GetProductLogic) GetProduct() (resp *types.ProductInfo, err error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ProductInfo{
|
||||
ProductId: rpcResp.ProductId,
|
||||
ProductName: rpcResp.ProductName,
|
||||
ImageUrl: rpcResp.ImageUrl,
|
||||
Spec: rpcResp.Spec,
|
||||
Color: rpcResp.Color,
|
||||
UnitPieces: rpcResp.UnitPieces,
|
||||
UnitRolls: rpcResp.UnitRolls,
|
||||
StockQuantity: rpcResp.StockQuantity,
|
||||
Location: rpcResp.Location,
|
||||
CostPrice: rpcResp.CostPrice,
|
||||
SalesPrice: rpcResp.SalesPrice,
|
||||
Remark: rpcResp.Remark,
|
||||
Status: rpcResp.Status,
|
||||
CreatedAt: rpcResp.CreatedAt,
|
||||
UpdatedAt: rpcResp.UpdatedAt,
|
||||
}, nil
|
||||
pi := productInfoFromPB(rpcResp)
|
||||
return &pi, nil
|
||||
}
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
package product
|
||||
|
||||
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 GetProductSummaryLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetProductSummaryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductSummaryLogic {
|
||||
return &GetProductSummaryLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetProductSummaryLogic) GetProductSummary() (resp *types.ProductSummaryResp, err error) {
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ListProductSummary(l.ctx, &pb.ListProductSummaryReq{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]types.ProductSummaryItem, 0, len(rpcResp.List))
|
||||
for _, it := range rpcResp.List {
|
||||
list = append(list, types.ProductSummaryItem{
|
||||
ProductName: it.ProductName,
|
||||
Spec: it.Spec,
|
||||
ColorCount: it.ColorCount,
|
||||
TotalPanCount: it.TotalPanCount,
|
||||
TotalBoltCount: it.TotalBoltCount,
|
||||
TotalLengthM: it.TotalLengthM,
|
||||
Colors: it.Colors,
|
||||
Locations: it.Locations,
|
||||
})
|
||||
}
|
||||
return &types.ProductSummaryResp{List: list}, nil
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package product
|
||||
|
||||
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 GetProductTreeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetProductTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductTreeLogic {
|
||||
return &GetProductTreeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetProductTreeLogic) GetProductTree() (resp *types.ProductTreeResp, err error) {
|
||||
id := ctxdata.GetPathId(l.ctx)
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.GetProductTree(l.ctx, &pb.GetProductReq{
|
||||
ProductId: id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pans := make([]types.PanInfo, 0, len(rpcResp.Pans))
|
||||
for _, p := range rpcResp.Pans {
|
||||
pans = append(pans, panInfoFromPB(p))
|
||||
}
|
||||
return &types.ProductTreeResp{
|
||||
Product: productInfoFromPB(rpcResp.Product),
|
||||
Pans: pans,
|
||||
TotalPanCount: rpcResp.TotalPanCount,
|
||||
TotalBoltCount: rpcResp.TotalBoltCount,
|
||||
TotalLengthM: rpcResp.TotalLengthM,
|
||||
}, nil
|
||||
}
|
||||
@ -2,10 +2,13 @@ package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
"muyu-apiserver/pkg/excelparse"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
@ -24,6 +27,50 @@ func NewImportProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Imp
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ImportProductLogic) ImportProduct() (resp *types.ImportProductResp, err error) {
|
||||
return nil, errors.New("import product requires file upload handling, will be implemented in handler layer")
|
||||
func (l *ImportProductLogic) ImportProduct(filePath, fileName string) (resp *types.ImportProductResp, err error) {
|
||||
result, err := excelparse.ParseFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("解析Excel失败: %w", err)
|
||||
}
|
||||
|
||||
l.Infof("excel parsed: format=%s, products=%d, skipped=%d",
|
||||
result.ParserName, len(result.Products), result.SkippedRows)
|
||||
|
||||
products := make([]*pb.CreateProductReq, 0, len(result.Products))
|
||||
for _, p := range result.Products {
|
||||
products = append(products, &pb.CreateProductReq{
|
||||
ProductName: p.ProductName,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
SalesPrice: p.SalesPrice,
|
||||
Remark: p.Remark,
|
||||
})
|
||||
}
|
||||
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ImportProducts(l.ctx, &pb.ImportProductReq{
|
||||
Products: products,
|
||||
FileName: fileName + " (" + result.ParserName + "格式)",
|
||||
Operator: operatorFromCtx(l.ctx),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ImportProductResp{
|
||||
TotalCount: rpcResp.TotalCount,
|
||||
SuccessCount: rpcResp.SuccessCount,
|
||||
FailCount: rpcResp.FailCount,
|
||||
ErrorMsg: rpcResp.ErrorMsg,
|
||||
ImportId: rpcResp.ImportId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func operatorFromCtx(ctx context.Context) string {
|
||||
if uid, ok := ctx.Value("userId").(string); ok {
|
||||
return uid
|
||||
}
|
||||
if uid, ok := ctx.Value("userId").(int64); ok {
|
||||
return strconv.FormatInt(uid, 10)
|
||||
}
|
||||
return "system"
|
||||
}
|
||||
|
||||
85
gateway/internal/logic/inventory/product/listPansLogic.go
Normal file
85
gateway/internal/logic/inventory/product/listPansLogic.go
Normal file
@ -0,0 +1,85 @@
|
||||
package product
|
||||
|
||||
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 ListPansLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewListPansLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPansLogic {
|
||||
return &ListPansLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListPansLogic) ListPans() (resp *types.ListPanResp, err error) {
|
||||
id := ctxdata.GetPathId(l.ctx)
|
||||
rpcResp, err := l.svcCtx.InventoryRpc.ListPans(l.ctx, &pb.ListPanReq{
|
||||
ProductId: id,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list := make([]types.PanInfo, 0, len(rpcResp.List))
|
||||
for _, p := range rpcResp.List {
|
||||
list = append(list, panInfoFromPB(p))
|
||||
}
|
||||
return &types.ListPanResp{List: list}, nil
|
||||
}
|
||||
|
||||
func boltInfoFromPB(b *pb.BoltInfo) types.BoltInfo {
|
||||
return types.BoltInfo{
|
||||
BoltId: b.BoltId,
|
||||
PanId: b.PanId,
|
||||
LengthM: b.LengthM,
|
||||
SortOrder: b.SortOrder,
|
||||
}
|
||||
}
|
||||
|
||||
func panInfoFromPB(p *pb.PanInfo) types.PanInfo {
|
||||
bolts := make([]types.BoltInfo, 0, len(p.Bolts))
|
||||
for _, b := range p.Bolts {
|
||||
bolts = append(bolts, boltInfoFromPB(b))
|
||||
}
|
||||
return types.PanInfo{
|
||||
PanId: p.PanId,
|
||||
ProductId: p.ProductId,
|
||||
Name: p.Name,
|
||||
Position: p.Position,
|
||||
SortOrder: p.SortOrder,
|
||||
Bolts: bolts,
|
||||
BoltCount: p.BoltCount,
|
||||
TotalLength: p.TotalLength,
|
||||
}
|
||||
}
|
||||
|
||||
func productInfoFromPB(p *pb.ProductInfo) types.ProductInfo {
|
||||
if p == nil {
|
||||
return types.ProductInfo{}
|
||||
}
|
||||
return types.ProductInfo{
|
||||
ProductId: p.ProductId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
SalesPrice: p.SalesPrice,
|
||||
Remark: p.Remark,
|
||||
Status: p.Status,
|
||||
CreatedAt: p.CreatedAt,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,6 @@ func (l *ListProductLogic) ListProduct(req *types.ListProductReq) (resp *types.L
|
||||
ProductName: req.ProductName,
|
||||
Spec: req.Spec,
|
||||
Color: req.Color,
|
||||
Location: req.Location,
|
||||
Status: req.Status,
|
||||
})
|
||||
if err != nil {
|
||||
@ -40,23 +39,7 @@ func (l *ListProductLogic) ListProduct(req *types.ListProductReq) (resp *types.L
|
||||
|
||||
list := make([]types.ProductInfo, 0, len(rpcResp.List))
|
||||
for _, p := range rpcResp.List {
|
||||
list = append(list, types.ProductInfo{
|
||||
ProductId: p.ProductId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
UnitPieces: p.UnitPieces,
|
||||
UnitRolls: p.UnitRolls,
|
||||
StockQuantity: p.StockQuantity,
|
||||
Location: p.Location,
|
||||
CostPrice: p.CostPrice,
|
||||
SalesPrice: p.SalesPrice,
|
||||
Remark: p.Remark,
|
||||
Status: p.Status,
|
||||
CreatedAt: p.CreatedAt,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
})
|
||||
list = append(list, productInfoFromPB(p))
|
||||
}
|
||||
|
||||
return &types.ListProductResp{
|
||||
|
||||
38
gateway/internal/logic/inventory/product/savePansLogic.go
Normal file
38
gateway/internal/logic/inventory/product/savePansLogic.go
Normal file
@ -0,0 +1,38 @@
|
||||
package product
|
||||
|
||||
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 SavePansLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewSavePansLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SavePansLogic {
|
||||
return &SavePansLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SavePansLogic) SavePans(req *types.SavePansReq) (resp *types.IdResp, err error) {
|
||||
id := ctxdata.GetPathId(l.ctx)
|
||||
_, err = l.svcCtx.InventoryRpc.SavePans(l.ctx, &pb.SavePansReq{
|
||||
ProductId: id,
|
||||
Pans: panInputsToPb(req.Pans),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &types.IdResp{Id: id}, nil
|
||||
}
|
||||
@ -29,18 +29,13 @@ func (l *UpdateProductLogic) UpdateProduct(req *types.UpdateProductReq) (resp *t
|
||||
id := ctxdata.GetPathId(l.ctx)
|
||||
|
||||
_, err = l.svcCtx.InventoryRpc.UpdateProduct(l.ctx, &pb.UpdateProductReq{
|
||||
ProductId: id,
|
||||
ProductName: req.ProductName,
|
||||
ImageUrl: req.ImageUrl,
|
||||
Spec: req.Spec,
|
||||
Color: req.Color,
|
||||
UnitPieces: req.UnitPieces,
|
||||
UnitRolls: req.UnitRolls,
|
||||
StockQuantity: req.StockQuantity,
|
||||
Location: req.Location,
|
||||
CostPrice: req.CostPrice,
|
||||
SalesPrice: req.SalesPrice,
|
||||
Remark: req.Remark,
|
||||
ProductId: id,
|
||||
ProductName: req.ProductName,
|
||||
ImageUrl: req.ImageUrl,
|
||||
Spec: req.Spec,
|
||||
Color: req.Color,
|
||||
SalesPrice: req.SalesPrice,
|
||||
Remark: req.Remark,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -33,8 +33,8 @@ func (l *GetStockSummaryLogic) GetStockSummary() (resp *types.StockSummaryResp,
|
||||
return &types.StockSummaryResp{
|
||||
ProductCount: rpcResp.ProductCount,
|
||||
TotalPieces: rpcResp.TotalPieces,
|
||||
TotalRolls: rpcResp.TotalRolls,
|
||||
TotalCostValue: rpcResp.TotalCostValue,
|
||||
TotalPans: rpcResp.TotalPans,
|
||||
TotalLengthM: rpcResp.TotalLengthM,
|
||||
TotalSalesValue: rpcResp.TotalSalesValue,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@ func (l *ListStockLogic) ListStock(req *types.ListProductReq) (resp *types.ListP
|
||||
ProductName: req.ProductName,
|
||||
Spec: req.Spec,
|
||||
Color: req.Color,
|
||||
Location: req.Location,
|
||||
Status: req.Status,
|
||||
})
|
||||
if err != nil {
|
||||
@ -41,21 +40,16 @@ func (l *ListStockLogic) ListStock(req *types.ListProductReq) (resp *types.ListP
|
||||
list := make([]types.ProductInfo, 0, len(rpcResp.List))
|
||||
for _, p := range rpcResp.List {
|
||||
list = append(list, types.ProductInfo{
|
||||
ProductId: p.ProductId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
UnitPieces: p.UnitPieces,
|
||||
UnitRolls: p.UnitRolls,
|
||||
StockQuantity: p.StockQuantity,
|
||||
Location: p.Location,
|
||||
CostPrice: p.CostPrice,
|
||||
SalesPrice: p.SalesPrice,
|
||||
Remark: p.Remark,
|
||||
Status: p.Status,
|
||||
CreatedAt: p.CreatedAt,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
ProductId: p.ProductId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
SalesPrice: p.SalesPrice,
|
||||
Remark: p.Remark,
|
||||
Status: p.Status,
|
||||
CreatedAt: p.CreatedAt,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"muyu-apiserver/gateway/internal/svc"
|
||||
"muyu-apiserver/gateway/internal/types"
|
||||
"muyu-apiserver/pkg/ctxdata"
|
||||
"muyu-apiserver/rpc/system/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@ -37,5 +38,9 @@ func (l *CreateUserLogic) CreateUser(req *types.CreateUserReq) (resp *types.IdRe
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tenantId := ctxdata.GetTenantId(l.ctx); tenantId != "" {
|
||||
_ = l.svcCtx.CrmRepo.AddUserToTenant(l.ctx, rpcResp.Id, tenantId)
|
||||
}
|
||||
|
||||
return &types.IdResp{Id: rpcResp.Id}, nil
|
||||
}
|
||||
|
||||
@ -63,6 +63,36 @@ func NewCrmRepo(conn sqlx.SqlConn) *CrmRepo {
|
||||
return &CrmRepo{conn: conn}
|
||||
}
|
||||
|
||||
func (r *CrmRepo) SearchTenants(ctx context.Context, keyword string, limit int) ([]GraphNode, error) {
|
||||
if limit <= 0 || limit > 50 {
|
||||
limit = 20
|
||||
}
|
||||
nodes := make([]GraphNode, 0)
|
||||
if keyword == "" {
|
||||
if err := r.conn.QueryRowsCtx(ctx, &nodes,
|
||||
"SELECT tenant_id, tenant_name FROM crm_tenant WHERE status = 1 ORDER BY tenant_name LIMIT $1", limit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := r.conn.QueryRowsCtx(ctx, &nodes,
|
||||
"SELECT tenant_id, tenant_name FROM crm_tenant WHERE status = 1 AND tenant_name LIKE $1 ORDER BY tenant_name LIMIT $2",
|
||||
"%"+keyword+"%", limit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (r *CrmRepo) AddUserToTenant(ctx context.Context, userId, tenantId string) error {
|
||||
_, err := r.conn.ExecCtx(ctx,
|
||||
`INSERT INTO crm_tenant_user (user_id, tenant_id, is_primary, status)
|
||||
VALUES ($1, $2, 1, 1)
|
||||
ON CONFLICT (user_id, tenant_id) DO NOTHING`,
|
||||
userId, tenantId,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *CrmRepo) VerifyUserTenant(ctx context.Context, userId, tenantId string) (bool, error) {
|
||||
var count int64
|
||||
err := r.conn.QueryRowCtx(ctx, &count,
|
||||
|
||||
@ -34,17 +34,13 @@ type CreateMenuReq struct {
|
||||
}
|
||||
|
||||
type CreateProductReq struct {
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
UnitPieces int64 `json:"unitPieces,optional"`
|
||||
UnitRolls int64 `json:"unitRolls,optional"`
|
||||
StockQuantity string `json:"stockQuantity,optional"`
|
||||
Location string `json:"location,optional"`
|
||||
CostPrice string `json:"costPrice,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
Pans []PanInput `json:"pans,optional"`
|
||||
}
|
||||
|
||||
type CreateRoleReq struct {
|
||||
@ -118,7 +114,6 @@ type ListProductReq struct {
|
||||
ProductName string `form:"productName,optional"`
|
||||
Spec string `form:"spec,optional"`
|
||||
Color string `form:"color,optional"`
|
||||
Location string `form:"location,optional"`
|
||||
Status int64 `form:"status,optional,default=-1"`
|
||||
}
|
||||
|
||||
@ -230,21 +225,147 @@ type PageReq struct {
|
||||
}
|
||||
|
||||
type ProductInfo struct {
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
Spec string `json:"spec"`
|
||||
Color string `json:"color"`
|
||||
UnitPieces int64 `json:"unitPieces"`
|
||||
UnitRolls int64 `json:"unitRolls"`
|
||||
StockQuantity string `json:"stockQuantity"`
|
||||
Location string `json:"location"`
|
||||
CostPrice string `json:"costPrice"`
|
||||
SalesPrice string `json:"salesPrice"`
|
||||
Remark string `json:"remark"`
|
||||
Status int64 `json:"status"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
Spec string `json:"spec"`
|
||||
Color string `json:"color"`
|
||||
SalesPrice string `json:"salesPrice"`
|
||||
Remark string `json:"remark"`
|
||||
Status int64 `json:"status"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type BoltInfo struct {
|
||||
BoltId string `json:"boltId"`
|
||||
PanId string `json:"panId"`
|
||||
LengthM string `json:"lengthM"`
|
||||
SortOrder int64 `json:"sortOrder"`
|
||||
}
|
||||
|
||||
type PanInfo struct {
|
||||
PanId string `json:"panId"`
|
||||
ProductId string `json:"productId"`
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position"`
|
||||
SortOrder int64 `json:"sortOrder"`
|
||||
Bolts []BoltInfo `json:"bolts"`
|
||||
BoltCount int64 `json:"boltCount"`
|
||||
TotalLength string `json:"totalLength"`
|
||||
}
|
||||
|
||||
type PanInput struct {
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position,optional"`
|
||||
BoltLengths []string `json:"boltLengths,optional"`
|
||||
}
|
||||
|
||||
type ListPanResp struct {
|
||||
List []PanInfo `json:"list"`
|
||||
}
|
||||
|
||||
type SavePansReq struct {
|
||||
Pans []PanInput `json:"pans"`
|
||||
}
|
||||
|
||||
type ListBoltResp struct {
|
||||
List []BoltInfo `json:"list"`
|
||||
}
|
||||
|
||||
type SaveBoltsReq struct {
|
||||
Lengths []string `json:"lengths"`
|
||||
}
|
||||
|
||||
type ProductTreeResp struct {
|
||||
Product ProductInfo `json:"product"`
|
||||
Pans []PanInfo `json:"pans"`
|
||||
TotalPanCount int64 `json:"totalPanCount"`
|
||||
TotalBoltCount int64 `json:"totalBoltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
}
|
||||
|
||||
type ProductSummaryItem struct {
|
||||
ProductName string `json:"productName"`
|
||||
Spec string `json:"spec"`
|
||||
ColorCount int64 `json:"colorCount"`
|
||||
TotalPanCount int64 `json:"totalPanCount"`
|
||||
TotalBoltCount int64 `json:"totalBoltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
Colors string `json:"colors"`
|
||||
Locations string `json:"locations"`
|
||||
}
|
||||
|
||||
type ProductSummaryResp struct {
|
||||
List []ProductSummaryItem `json:"list"`
|
||||
}
|
||||
|
||||
type ColorDetailItem struct {
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
Color string `json:"color"`
|
||||
Spec string `json:"spec"`
|
||||
ImageUrl string `json:"imageUrl"`
|
||||
PanCount int64 `json:"panCount"`
|
||||
BoltCount int64 `json:"boltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
Locations string `json:"locations"`
|
||||
SalesPrice string `json:"salesPrice"`
|
||||
}
|
||||
|
||||
type ListColorDetailReq struct {
|
||||
ProductName string `form:"productName"`
|
||||
}
|
||||
|
||||
type ColorDetailResp struct {
|
||||
List []ColorDetailItem `json:"list"`
|
||||
}
|
||||
|
||||
type PanListItem struct {
|
||||
PanId string `json:"panId"`
|
||||
ProductId string `json:"productId"`
|
||||
Name string `json:"name"`
|
||||
Position string `json:"position"`
|
||||
ProductName string `json:"productName"`
|
||||
Colors string `json:"colors"`
|
||||
BoltCount int64 `json:"boltCount"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
}
|
||||
|
||||
type ListPanViewReq struct {
|
||||
Page int64 `form:"page,default=1"`
|
||||
PageSize int64 `form:"pageSize,default=20"`
|
||||
ProductName string `form:"productName,optional"`
|
||||
Position string `form:"position,optional"`
|
||||
}
|
||||
|
||||
type ListPanViewResp struct {
|
||||
Total int64 `json:"total"`
|
||||
List []PanListItem `json:"list"`
|
||||
}
|
||||
|
||||
type BoltListItem struct {
|
||||
BoltId string `json:"boltId"`
|
||||
PanId string `json:"panId"`
|
||||
LengthM string `json:"lengthM"`
|
||||
Color string `json:"color"`
|
||||
SortOrder int64 `json:"sortOrder"`
|
||||
PanName string `json:"panName"`
|
||||
Position string `json:"position"`
|
||||
ProductId string `json:"productId"`
|
||||
ProductName string `json:"productName"`
|
||||
}
|
||||
|
||||
type ListBoltViewReq struct {
|
||||
Page int64 `form:"page,default=1"`
|
||||
PageSize int64 `form:"pageSize,default=20"`
|
||||
ProductName string `form:"productName,optional"`
|
||||
Position string `form:"position,optional"`
|
||||
}
|
||||
|
||||
type ListBoltViewResp struct {
|
||||
Total int64 `json:"total"`
|
||||
List []BoltListItem `json:"list"`
|
||||
}
|
||||
|
||||
type RoleInfo struct {
|
||||
@ -337,8 +458,8 @@ type StockGroupResp struct {
|
||||
type StockSummaryResp struct {
|
||||
ProductCount int64 `json:"productCount"`
|
||||
TotalPieces int64 `json:"totalPieces"`
|
||||
TotalRolls int64 `json:"totalRolls"`
|
||||
TotalCostValue string `json:"totalCostValue"`
|
||||
TotalPans int64 `json:"totalPans"`
|
||||
TotalLengthM string `json:"totalLengthM"`
|
||||
TotalSalesValue string `json:"totalSalesValue"`
|
||||
}
|
||||
|
||||
@ -359,17 +480,12 @@ type UpdateMenuReq struct {
|
||||
}
|
||||
|
||||
type UpdateProductReq struct {
|
||||
ProductName string `json:"productName,optional"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
UnitPieces int64 `json:"unitPieces,optional"`
|
||||
UnitRolls int64 `json:"unitRolls,optional"`
|
||||
StockQuantity string `json:"stockQuantity,optional"`
|
||||
Location string `json:"location,optional"`
|
||||
CostPrice string `json:"costPrice,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
ProductName string `json:"productName,optional"`
|
||||
ImageUrl string `json:"imageUrl,optional"`
|
||||
Spec string `json:"spec,optional"`
|
||||
Color string `json:"color,optional"`
|
||||
SalesPrice string `json:"salesPrice,optional"`
|
||||
Remark string `json:"remark,optional"`
|
||||
}
|
||||
|
||||
type UpdateRoleReq struct {
|
||||
|
||||
10
go.mod
10
go.mod
@ -7,6 +7,8 @@ require (
|
||||
github.com/casbin/gorm-adapter/v3 v3.28.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/lib/pq v1.12.0
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/xuri/excelize/v2 v2.10.1
|
||||
github.com/zeromicro/go-zero v1.10.0
|
||||
golang.org/x/crypto v0.48.0
|
||||
google.golang.org/grpc v1.79.1
|
||||
@ -68,14 +70,18 @@ require (
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/redis/go-redis/v9 v9.17.3 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/richardlehane/mscfb v1.0.6 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.6 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tiendc/go-deepcopy v1.7.2 // indirect
|
||||
github.com/xuri/efp v0.0.1 // indirect
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.15 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.15 // indirect
|
||||
@ -97,7 +103,7 @@ require (
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/net v0.50.0 // indirect
|
||||
golang.org/x/oauth2 v0.34.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
|
||||
18
go.sum
18
go.sum
@ -223,6 +223,10 @@ github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1D
|
||||
github.com/redis/go-redis/v9 v9.17.3/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/richardlehane/mscfb v1.0.6 h1:eN3bvvZCp00bs7Zf52bxNwAx5lJDBK1tCuH19qq5aC8=
|
||||
github.com/richardlehane/mscfb v1.0.6/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
|
||||
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
|
||||
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
@ -248,6 +252,14 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=
|
||||
github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
|
||||
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
|
||||
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.10.1 h1:V62UlqopMqha3kOpnlHy2CcRVw1V8E63jFoWUmMzxN0=
|
||||
github.com/xuri/excelize/v2 v2.10.1/go.mod h1:iG5tARpgaEeIhTqt3/fgXCGoBRt4hNXgCp3tfXKoOIc=
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
@ -317,6 +329,8 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
|
||||
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@ -348,8 +362,8 @@ golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
146
model/invproductboltmodel.go
Normal file
146
model/invproductboltmodel.go
Normal file
@ -0,0 +1,146 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ InvProductBoltModel = (*customInvProductBoltModel)(nil)
|
||||
|
||||
// BoltListItem is the flat view row for the bolt-dimension panel.
|
||||
// Color comes from the bolt itself, spec is omitted (product-level only).
|
||||
type BoltListItem struct {
|
||||
BoltId string `db:"bolt_id"`
|
||||
PanId string `db:"pan_id"`
|
||||
LengthM float64 `db:"length_m"`
|
||||
Color string `db:"color"`
|
||||
SortOrder int64 `db:"sort_order"`
|
||||
PanName string `db:"pan_name"`
|
||||
Position string `db:"position"`
|
||||
ProductId string `db:"product_id"`
|
||||
ProductName string `db:"product_name"`
|
||||
}
|
||||
|
||||
type (
|
||||
InvProductBoltModel interface {
|
||||
invProductBoltModel
|
||||
FindByPanId(ctx context.Context, panId string) ([]*InvProductBolt, error)
|
||||
FindByProductId(ctx context.Context, productId string) ([]*InvProductBolt, error)
|
||||
DeleteByPanId(ctx context.Context, panId string) error
|
||||
DeleteByProductId(ctx context.Context, productId string) error
|
||||
BulkReplace(ctx context.Context, panId, tenantId string, bolts []*InvProductBolt) error
|
||||
FindBoltList(ctx context.Context, tenantId string, page, pageSize int64, productName, position string) ([]*BoltListItem, int64, error)
|
||||
}
|
||||
|
||||
customInvProductBoltModel struct {
|
||||
*defaultInvProductBoltModel
|
||||
}
|
||||
)
|
||||
|
||||
func NewInvProductBoltModel(conn sqlx.SqlConn) InvProductBoltModel {
|
||||
return &customInvProductBoltModel{
|
||||
defaultInvProductBoltModel: newInvProductBoltModel(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customInvProductBoltModel) FindByPanId(ctx context.Context, panId string) ([]*InvProductBolt, error) {
|
||||
var list []*InvProductBolt
|
||||
query := fmt.Sprintf("SELECT %s FROM %s WHERE `pan_id` = ? ORDER BY `sort_order`", invProductBoltRows, m.table)
|
||||
err := m.conn.QueryRowsCtx(ctx, &list, query, panId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductBoltModel) FindByProductId(ctx context.Context, productId string) ([]*InvProductBolt, error) {
|
||||
var list []*InvProductBolt
|
||||
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` "+
|
||||
"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)
|
||||
err := m.conn.QueryRowsCtx(ctx, &list, query, productId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductBoltModel) DeleteByPanId(ctx context.Context, panId string) error {
|
||||
query := fmt.Sprintf("DELETE FROM %s WHERE `pan_id` = ?", m.table)
|
||||
_, err := m.conn.ExecCtx(ctx, query, panId)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *customInvProductBoltModel) DeleteByProductId(ctx context.Context, productId string) error {
|
||||
query := fmt.Sprintf(
|
||||
"DELETE b FROM %s b INNER JOIN `inv_product_pan` p ON b.`pan_id` = p.`pan_id` WHERE p.`product_id` = ?", m.table)
|
||||
_, err := m.conn.ExecCtx(ctx, query, productId)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *customInvProductBoltModel) FindBoltList(ctx context.Context, tenantId string, page, pageSize int64, productName, position string) ([]*BoltListItem, int64, error) {
|
||||
where := "WHERE b.tenant_id = ? AND p.deleted_at IS NULL"
|
||||
args := []interface{}{tenantId}
|
||||
|
||||
if productName != "" {
|
||||
where += " AND p.product_name LIKE ?"
|
||||
args = append(args, "%"+productName+"%")
|
||||
}
|
||||
if position != "" {
|
||||
where += " AND pan.position LIKE ?"
|
||||
args = append(args, "%"+position+"%")
|
||||
}
|
||||
|
||||
countQuery := fmt.Sprintf(`SELECT COUNT(*)
|
||||
FROM %s b
|
||||
JOIN inv_product_pan pan ON pan.pan_id = b.pan_id
|
||||
JOIN inv_product p ON p.product_id = pan.product_id
|
||||
%s`, m.table, where)
|
||||
var total int64
|
||||
if err := m.conn.QueryRowCtx(ctx, &total, countQuery, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`SELECT b.bolt_id, b.pan_id, b.length_m, b.color, b.sort_order,
|
||||
pan.name AS pan_name, pan.position,
|
||||
p.product_id, p.product_name
|
||||
FROM %s b
|
||||
JOIN inv_product_pan pan ON pan.pan_id = b.pan_id
|
||||
JOIN inv_product p ON p.product_id = pan.product_id
|
||||
%s
|
||||
ORDER BY b.created_at DESC
|
||||
LIMIT ? OFFSET ?`, m.table, where)
|
||||
args = append(args, pageSize, (page-1)*pageSize)
|
||||
|
||||
var list []*BoltListItem
|
||||
if err := m.conn.QueryRowsCtx(ctx, &list, query, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductBoltModel) BulkReplace(ctx context.Context, panId, tenantId string, bolts []*InvProductBolt) error {
|
||||
return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
delQuery := fmt.Sprintf("DELETE FROM %s WHERE `pan_id` = ?", m.table)
|
||||
if _, err := session.ExecCtx(ctx, delQuery, panId); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(bolts) == 0 {
|
||||
return nil
|
||||
}
|
||||
placeholder := "(?, ?, ?, ?, ?, ?)"
|
||||
placeholders := make([]string, len(bolts))
|
||||
args := make([]interface{}, 0, len(bolts)*6)
|
||||
for i, b := range bolts {
|
||||
placeholders[i] = placeholder
|
||||
args = append(args, b.BoltId, panId, b.LengthM, b.Color, b.SortOrder, tenantId)
|
||||
}
|
||||
insQuery := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", m.table, invProductBoltRowsExpectAutoSet, strings.Join(placeholders, ","))
|
||||
_, err := session.ExecCtx(ctx, insQuery, args...)
|
||||
return err
|
||||
})
|
||||
}
|
||||
95
model/invproductboltmodel_gen.go
Normal file
95
model/invproductboltmodel_gen.go
Normal file
@ -0,0 +1,95 @@
|
||||
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 (
|
||||
invProductBoltFieldNames = builder.RawFieldNames(&InvProductBolt{})
|
||||
invProductBoltRows = strings.Join(invProductBoltFieldNames, ",")
|
||||
invProductBoltRowsExpectAutoSet = strings.Join(stringx.Remove(invProductBoltFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
|
||||
invProductBoltRowsWithPlaceHolder = strings.Join(stringx.Remove(invProductBoltFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
|
||||
)
|
||||
|
||||
type (
|
||||
invProductBoltModel interface {
|
||||
Insert(ctx context.Context, data *InvProductBolt) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*InvProductBolt, error)
|
||||
FindOneByBoltId(ctx context.Context, boltId string) (*InvProductBolt, error)
|
||||
Update(ctx context.Context, data *InvProductBolt) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultInvProductBoltModel struct {
|
||||
conn sqlx.SqlConn
|
||||
table string
|
||||
}
|
||||
|
||||
InvProductBolt struct {
|
||||
Id int64 `db:"id"`
|
||||
BoltId string `db:"bolt_id"`
|
||||
PanId string `db:"pan_id"`
|
||||
LengthM float64 `db:"length_m"`
|
||||
Color string `db:"color"`
|
||||
SortOrder int64 `db:"sort_order"`
|
||||
TenantId string `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
)
|
||||
|
||||
func newInvProductBoltModel(conn sqlx.SqlConn) *defaultInvProductBoltModel {
|
||||
return &defaultInvProductBoltModel{
|
||||
conn: conn,
|
||||
table: "`inv_product_bolt`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultInvProductBoltModel) Insert(ctx context.Context, data *InvProductBolt) (sql.Result, error) {
|
||||
query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?, ?, ?, ?, ?, ?)", m.table, invProductBoltRowsExpectAutoSet)
|
||||
return m.conn.ExecCtx(ctx, query, data.BoltId, data.PanId, data.LengthM, data.Color, data.SortOrder, data.TenantId)
|
||||
}
|
||||
|
||||
func (m *defaultInvProductBoltModel) FindOne(ctx context.Context, id int64) (*InvProductBolt, error) {
|
||||
query := fmt.Sprintf("SELECT %s FROM %s WHERE `id` = ? LIMIT 1", invProductBoltRows, m.table)
|
||||
var resp InvProductBolt
|
||||
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (m *defaultInvProductBoltModel) FindOneByBoltId(ctx context.Context, boltId string) (*InvProductBolt, error) {
|
||||
query := fmt.Sprintf("SELECT %s FROM %s WHERE `bolt_id` = ? LIMIT 1", invProductBoltRows, m.table)
|
||||
var resp InvProductBolt
|
||||
err := m.conn.QueryRowCtx(ctx, &resp, query, boltId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (m *defaultInvProductBoltModel) Update(ctx context.Context, data *InvProductBolt) error {
|
||||
query := fmt.Sprintf("UPDATE %s SET %s WHERE `id` = ?", m.table, invProductBoltRowsWithPlaceHolder)
|
||||
_, err := m.conn.ExecCtx(ctx, query, data.BoltId, data.PanId, data.LengthM, data.Color, data.SortOrder, data.TenantId, data.Id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultInvProductBoltModel) 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 *defaultInvProductBoltModel) tableName() string {
|
||||
return m.table
|
||||
}
|
||||
@ -3,6 +3,7 @@ package model
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
@ -10,19 +11,46 @@ import (
|
||||
|
||||
var _ InvProductModel = (*customInvProductModel)(nil)
|
||||
|
||||
// StockGroupResult is kept for GroupBy queries (color / location).
|
||||
type StockGroupResult struct {
|
||||
Name string `db:"name"`
|
||||
Count int64 `db:"count"`
|
||||
Quantity float64 `db:"quantity"`
|
||||
}
|
||||
|
||||
type ProductSummary struct {
|
||||
ProductName string `db:"product_name"`
|
||||
Spec string `db:"spec"`
|
||||
ColorCount int64 `db:"color_count"`
|
||||
TotalPanCount int64 `db:"total_pan_count"`
|
||||
TotalBoltCount int64 `db:"total_bolt_count"`
|
||||
TotalLengthM float64 `db:"total_length_m"`
|
||||
Colors string `db:"colors"`
|
||||
Locations string `db:"locations"`
|
||||
}
|
||||
|
||||
type ColorDetail struct {
|
||||
ProductId string `db:"product_id"`
|
||||
ProductName string `db:"product_name"`
|
||||
Color string `db:"color"`
|
||||
Spec string `db:"spec"`
|
||||
ImageUrl string `db:"image_url"`
|
||||
SalesPrice float64 `db:"sales_price"`
|
||||
PanCount int64 `db:"pan_count"`
|
||||
BoltCount int64 `db:"bolt_count"`
|
||||
TotalLengthM float64 `db:"total_length_m"`
|
||||
Locations string `db:"locations"`
|
||||
}
|
||||
|
||||
type (
|
||||
InvProductModel interface {
|
||||
invProductModel
|
||||
FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color, location string, status int64) ([]*InvProduct, int64, error)
|
||||
FindStockSummary(ctx context.Context, tenantId string) (productCount, totalPieces, totalRolls int64, totalCostValue, totalSalesValue float64, err error)
|
||||
FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color string, status int64) ([]*InvProduct, int64, error)
|
||||
FindProductSummary(ctx context.Context, tenantId string) ([]*ProductSummary, error)
|
||||
FindColorDetail(ctx context.Context, tenantId, productName string) ([]*ColorDetail, error)
|
||||
FindGroupByColor(ctx context.Context, tenantId string) ([]StockGroupResult, error)
|
||||
FindGroupByLocation(ctx context.Context, tenantId string) ([]StockGroupResult, error)
|
||||
BulkInsert(ctx context.Context, products []*InvProduct) (int64, error)
|
||||
}
|
||||
|
||||
customInvProductModel struct {
|
||||
@ -36,7 +64,48 @@ func NewInvProductModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Opti
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color, location string, status int64) ([]*InvProduct, int64, error) {
|
||||
const bulkBatchSize = 200
|
||||
|
||||
func (m *customInvProductModel) BulkInsert(ctx context.Context, products []*InvProduct) (int64, error) {
|
||||
if len(products) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var totalAffected int64
|
||||
for i := 0; i < len(products); i += bulkBatchSize {
|
||||
end := i + bulkBatchSize
|
||||
if end > len(products) {
|
||||
end = len(products)
|
||||
}
|
||||
batch := products[i:end]
|
||||
|
||||
placeholder := "(" + strings.Repeat("?,", 9) + "?)"
|
||||
placeholders := make([]string, len(batch))
|
||||
args := make([]interface{}, 0, len(batch)*10)
|
||||
|
||||
for j, p := range batch {
|
||||
placeholders[j] = placeholder
|
||||
args = append(args,
|
||||
p.ProductId, p.ProductName, p.ImageUrl, p.Spec, p.Color,
|
||||
p.SalesPrice, p.Remark, p.Status, p.TenantId, p.DeletedAt,
|
||||
)
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s",
|
||||
m.table, invProductRowsExpectAutoSet, strings.Join(placeholders, ","))
|
||||
|
||||
result, err := m.ExecNoCacheCtx(ctx, query, args...)
|
||||
if err != nil {
|
||||
return totalAffected, fmt.Errorf("batch %d-%d: %w", i, end-1, err)
|
||||
}
|
||||
n, _ := result.RowsAffected()
|
||||
totalAffected += n
|
||||
}
|
||||
|
||||
return totalAffected, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, page, pageSize int64, productName, spec, color string, status int64) ([]*InvProduct, int64, error) {
|
||||
where := "WHERE deleted_at IS NULL AND tenant_id = ?"
|
||||
args := []interface{}{tenantId}
|
||||
|
||||
@ -52,10 +121,6 @@ func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, p
|
||||
where += " AND color = ?"
|
||||
args = append(args, color)
|
||||
}
|
||||
if location != "" {
|
||||
where += " AND location = ?"
|
||||
args = append(args, location)
|
||||
}
|
||||
if status >= 0 {
|
||||
where += " AND status = ?"
|
||||
args = append(args, status)
|
||||
@ -79,25 +144,37 @@ func (m *customInvProductModel) FindList(ctx context.Context, tenantId string, p
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductModel) FindStockSummary(ctx context.Context, tenantId string) (productCount, totalPieces, totalRolls int64, totalCostValue, totalSalesValue float64, err error) {
|
||||
var summary struct {
|
||||
ProductCount int64 `db:"product_count"`
|
||||
TotalPieces int64 `db:"total_pieces"`
|
||||
TotalRolls int64 `db:"total_rolls"`
|
||||
TotalCostValue float64 `db:"total_cost_value"`
|
||||
TotalSalesValue float64 `db:"total_sales_value"`
|
||||
}
|
||||
query := fmt.Sprintf("SELECT COUNT(*) AS product_count, COALESCE(SUM(unit_pieces), 0) AS total_pieces, COALESCE(SUM(unit_rolls), 0) AS total_rolls, COALESCE(SUM(stock_quantity * cost_price), 0) AS total_cost_value, COALESCE(SUM(stock_quantity * sales_price), 0) AS total_sales_value FROM %s WHERE deleted_at IS NULL AND tenant_id = ?", m.table)
|
||||
err = m.QueryRowNoCacheCtx(ctx, &summary, query, tenantId)
|
||||
func (m *customInvProductModel) FindProductSummary(ctx context.Context, tenantId string) ([]*ProductSummary, error) {
|
||||
var list []*ProductSummary
|
||||
query := `SELECT p.product_name, p.spec,
|
||||
COUNT(DISTINCT p.product_id) AS color_count,
|
||||
COUNT(DISTINCT pan.pan_id) AS total_pan_count,
|
||||
COUNT(bolt.bolt_id) AS total_bolt_count,
|
||||
COALESCE(SUM(bolt.length_m), 0) AS total_length_m,
|
||||
GROUP_CONCAT(DISTINCT p.color) AS colors,
|
||||
GROUP_CONCAT(DISTINCT pan.position ORDER BY pan.position) AS locations
|
||||
FROM ` + m.table + ` p
|
||||
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
|
||||
WHERE p.tenant_id = ? AND p.deleted_at IS NULL
|
||||
GROUP BY p.product_name, p.spec
|
||||
ORDER BY p.product_name`
|
||||
err := m.QueryRowsNoCacheCtx(ctx, &list, query, tenantId)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, 0, err
|
||||
return nil, err
|
||||
}
|
||||
return summary.ProductCount, summary.TotalPieces, summary.TotalRolls, summary.TotalCostValue, summary.TotalSalesValue, nil
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductModel) FindGroupByColor(ctx context.Context, tenantId string) ([]StockGroupResult, error) {
|
||||
var list []StockGroupResult
|
||||
query := fmt.Sprintf("SELECT color AS name, COUNT(*) AS count, COALESCE(SUM(stock_quantity), 0) AS quantity FROM %s WHERE deleted_at IS NULL AND tenant_id = ? GROUP BY color ORDER BY count DESC", m.table)
|
||||
query := `SELECT p.color AS name, COUNT(DISTINCT p.product_id) AS count,
|
||||
COALESCE(SUM(bolt.length_m), 0) AS quantity
|
||||
FROM ` + m.table + ` p
|
||||
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
|
||||
WHERE p.tenant_id = ? AND p.deleted_at IS NULL
|
||||
GROUP BY p.color ORDER BY count DESC`
|
||||
err := m.QueryRowsNoCacheCtx(ctx, &list, query, tenantId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -107,10 +184,36 @@ func (m *customInvProductModel) FindGroupByColor(ctx context.Context, tenantId s
|
||||
|
||||
func (m *customInvProductModel) FindGroupByLocation(ctx context.Context, tenantId string) ([]StockGroupResult, error) {
|
||||
var list []StockGroupResult
|
||||
query := fmt.Sprintf("SELECT location AS name, COUNT(*) AS count, COALESCE(SUM(stock_quantity), 0) AS quantity FROM %s WHERE deleted_at IS NULL AND tenant_id = ? GROUP BY location ORDER BY count DESC", m.table)
|
||||
query := `SELECT pan.position AS name, COUNT(DISTINCT p.product_id) AS count,
|
||||
COALESCE(SUM(bolt.length_m), 0) AS quantity
|
||||
FROM ` + m.table + ` p
|
||||
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
|
||||
WHERE p.tenant_id = ? AND p.deleted_at IS NULL AND pan.position != ''
|
||||
GROUP BY pan.position ORDER BY count DESC`
|
||||
err := m.QueryRowsNoCacheCtx(ctx, &list, query, tenantId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductModel) FindColorDetail(ctx context.Context, tenantId, productName string) ([]*ColorDetail, error) {
|
||||
var list []*ColorDetail
|
||||
query := `SELECT p.product_id, p.product_name, p.color, p.spec, p.image_url, p.sales_price,
|
||||
COUNT(DISTINCT pan.pan_id) AS pan_count,
|
||||
COUNT(bolt.bolt_id) AS bolt_count,
|
||||
COALESCE(SUM(bolt.length_m), 0) AS total_length_m,
|
||||
GROUP_CONCAT(DISTINCT pan.position ORDER BY pan.position) AS locations
|
||||
FROM ` + m.table + ` p
|
||||
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
|
||||
WHERE p.tenant_id = ? AND p.deleted_at IS NULL AND p.product_name = ?
|
||||
GROUP BY p.product_id
|
||||
ORDER BY p.color`
|
||||
err := m.QueryRowsNoCacheCtx(ctx, &list, query, tenantId, productName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
@ -45,23 +45,19 @@ type (
|
||||
}
|
||||
|
||||
InvProduct struct {
|
||||
Id int64 `db:"id"`
|
||||
ProductId string `db:"product_id"`
|
||||
ProductName string `db:"product_name"`
|
||||
ImageUrl string `db:"image_url"`
|
||||
Spec string `db:"spec"`
|
||||
Color string `db:"color"`
|
||||
UnitPieces int64 `db:"unit_pieces"`
|
||||
UnitRolls int64 `db:"unit_rolls"`
|
||||
StockQuantity float64 `db:"stock_quantity"`
|
||||
Location string `db:"location"`
|
||||
CostPrice float64 `db:"cost_price"`
|
||||
SalesPrice float64 `db:"sales_price"`
|
||||
Remark sql.NullString `db:"remark"`
|
||||
Status int64 `db:"status"` // 1:enabled 0:disabled
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
DeletedAt sql.NullTime `db:"deleted_at"`
|
||||
Id int64 `db:"id"`
|
||||
ProductId string `db:"product_id"`
|
||||
ProductName string `db:"product_name"`
|
||||
ImageUrl string `db:"image_url"`
|
||||
Spec string `db:"spec"`
|
||||
Color string `db:"color"`
|
||||
SalesPrice float64 `db:"sales_price"`
|
||||
Remark sql.NullString `db:"remark"`
|
||||
Status int64 `db:"status"`
|
||||
TenantId string `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
DeletedAt sql.NullTime `db:"deleted_at"`
|
||||
}
|
||||
)
|
||||
|
||||
@ -150,8 +146,8 @@ func (m *defaultInvProductModel) Insert(ctx context.Context, data *InvProduct) (
|
||||
invProductProductIdKey := fmt.Sprintf("%s%v", cacheInvProductProductIdPrefix, data.ProductId)
|
||||
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
||||
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)
|
||||
return conn.ExecCtx(ctx, query, data.ProductId, data.ProductName, data.ImageUrl, data.Spec, data.Color, data.UnitPieces, data.UnitRolls, data.StockQuantity, data.Location, data.CostPrice, data.SalesPrice, data.Remark, data.Status, data.DeletedAt)
|
||||
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.Remark, data.Status, data.TenantId, data.DeletedAt)
|
||||
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey)
|
||||
return ret, err
|
||||
}
|
||||
@ -167,7 +163,7 @@ func (m *defaultInvProductModel) Update(ctx context.Context, newData *InvProduct
|
||||
invProductProductNameKey := fmt.Sprintf("%s%v", cacheInvProductProductNamePrefix, data.ProductName)
|
||||
_, 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)
|
||||
return conn.ExecCtx(ctx, query, newData.ProductId, newData.ProductName, newData.ImageUrl, newData.Spec, newData.Color, newData.UnitPieces, newData.UnitRolls, newData.StockQuantity, newData.Location, newData.CostPrice, newData.SalesPrice, newData.Remark, newData.Status, newData.DeletedAt, newData.Id)
|
||||
return conn.ExecCtx(ctx, query, newData.ProductId, newData.ProductName, newData.ImageUrl, newData.Spec, newData.Color, newData.SalesPrice, newData.Remark, newData.Status, newData.TenantId, newData.DeletedAt, newData.Id)
|
||||
}, invProductIdKey, invProductProductIdKey, invProductProductNameKey)
|
||||
return err
|
||||
}
|
||||
|
||||
123
model/invproductpanmodel.go
Normal file
123
model/invproductpanmodel.go
Normal file
@ -0,0 +1,123 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ InvProductPanModel = (*customInvProductPanModel)(nil)
|
||||
|
||||
// PanListItem is the aggregated view row for the pan-dimension panel.
|
||||
// Colors is aggregated from the bolts on this pan; spec is omitted (product-level only).
|
||||
type PanListItem struct {
|
||||
PanId string `db:"pan_id"`
|
||||
ProductId string `db:"product_id"`
|
||||
Name string `db:"name"`
|
||||
Position string `db:"position"`
|
||||
ProductName string `db:"product_name"`
|
||||
Colors string `db:"colors"`
|
||||
BoltCount int64 `db:"bolt_count"`
|
||||
TotalLengthM float64 `db:"total_length_m"`
|
||||
}
|
||||
|
||||
type (
|
||||
InvProductPanModel interface {
|
||||
invProductPanModel
|
||||
FindByProductId(ctx context.Context, productId string) ([]*InvProductPan, error)
|
||||
DeleteByProductId(ctx context.Context, productId string) 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)
|
||||
}
|
||||
|
||||
customInvProductPanModel struct {
|
||||
*defaultInvProductPanModel
|
||||
}
|
||||
)
|
||||
|
||||
func NewInvProductPanModel(conn sqlx.SqlConn) InvProductPanModel {
|
||||
return &customInvProductPanModel{
|
||||
defaultInvProductPanModel: newInvProductPanModel(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *customInvProductPanModel) FindByProductId(ctx context.Context, productId string) ([]*InvProductPan, error) {
|
||||
var list []*InvProductPan
|
||||
query := fmt.Sprintf("SELECT %s FROM %s WHERE `product_id` = ? ORDER BY `sort_order`", invProductPanRows, m.table)
|
||||
err := m.conn.QueryRowsCtx(ctx, &list, query, productId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (m *customInvProductPanModel) DeleteByProductId(ctx context.Context, productId string) error {
|
||||
query := fmt.Sprintf("DELETE FROM %s WHERE `product_id` = ?", m.table)
|
||||
_, err := m.conn.ExecCtx(ctx, query, productId)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *customInvProductPanModel) FindPanList(ctx context.Context, tenantId string, page, pageSize int64, productName, position string) ([]*PanListItem, int64, error) {
|
||||
where := "WHERE pan.tenant_id = ? AND p.deleted_at IS NULL"
|
||||
args := []interface{}{tenantId}
|
||||
|
||||
if productName != "" {
|
||||
where += " AND p.product_name LIKE ?"
|
||||
args = append(args, "%"+productName+"%")
|
||||
}
|
||||
if position != "" {
|
||||
where += " AND pan.position LIKE ?"
|
||||
args = append(args, "%"+position+"%")
|
||||
}
|
||||
|
||||
countQuery := fmt.Sprintf(`SELECT COUNT(DISTINCT pan.pan_id)
|
||||
FROM %s pan JOIN inv_product p ON p.product_id = pan.product_id %s`, m.table, where)
|
||||
var total int64
|
||||
if err := m.conn.QueryRowCtx(ctx, &total, countQuery, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`SELECT pan.pan_id, pan.product_id, pan.name, pan.position,
|
||||
p.product_name,
|
||||
COALESCE(GROUP_CONCAT(DISTINCT b.color ORDER BY b.color SEPARATOR ', '), '') AS colors,
|
||||
COUNT(b.bolt_id) AS bolt_count,
|
||||
COALESCE(SUM(b.length_m), 0) AS total_length_m
|
||||
FROM %s pan
|
||||
JOIN inv_product p ON p.product_id = pan.product_id
|
||||
LEFT JOIN inv_product_bolt b ON b.pan_id = pan.pan_id
|
||||
%s
|
||||
GROUP BY pan.pan_id
|
||||
ORDER BY pan.created_at DESC
|
||||
LIMIT ? OFFSET ?`, m.table, where)
|
||||
args = append(args, pageSize, (page-1)*pageSize)
|
||||
|
||||
var list []*PanListItem
|
||||
if err := m.conn.QueryRowsCtx(ctx, &list, query, args...); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
delQuery := fmt.Sprintf("DELETE FROM %s WHERE `product_id` = ?", m.table)
|
||||
if _, err := session.ExecCtx(ctx, delQuery, productId); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pans) == 0 {
|
||||
return nil
|
||||
}
|
||||
placeholder := "(?, ?, ?, ?, ?, ?)"
|
||||
placeholders := make([]string, len(pans))
|
||||
args := make([]interface{}, 0, len(pans)*6)
|
||||
for i, p := range pans {
|
||||
placeholders[i] = placeholder
|
||||
args = append(args, p.PanId, productId, p.Name, p.Position, p.SortOrder, tenantId)
|
||||
}
|
||||
insQuery := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", m.table, invProductPanRowsExpectAutoSet, strings.Join(placeholders, ","))
|
||||
_, err := session.ExecCtx(ctx, insQuery, args...)
|
||||
return err
|
||||
})
|
||||
}
|
||||
95
model/invproductpanmodel_gen.go
Normal file
95
model/invproductpanmodel_gen.go
Normal file
@ -0,0 +1,95 @@
|
||||
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 (
|
||||
invProductPanFieldNames = builder.RawFieldNames(&InvProductPan{})
|
||||
invProductPanRows = strings.Join(invProductPanFieldNames, ",")
|
||||
invProductPanRowsExpectAutoSet = strings.Join(stringx.Remove(invProductPanFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",")
|
||||
invProductPanRowsWithPlaceHolder = strings.Join(stringx.Remove(invProductPanFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?"
|
||||
)
|
||||
|
||||
type (
|
||||
invProductPanModel interface {
|
||||
Insert(ctx context.Context, data *InvProductPan) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*InvProductPan, error)
|
||||
FindOneByPanId(ctx context.Context, panId string) (*InvProductPan, error)
|
||||
Update(ctx context.Context, data *InvProductPan) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
|
||||
defaultInvProductPanModel struct {
|
||||
conn sqlx.SqlConn
|
||||
table string
|
||||
}
|
||||
|
||||
InvProductPan struct {
|
||||
Id int64 `db:"id"`
|
||||
PanId string `db:"pan_id"`
|
||||
ProductId string `db:"product_id"`
|
||||
Name string `db:"name"`
|
||||
Position string `db:"position"`
|
||||
SortOrder int64 `db:"sort_order"`
|
||||
TenantId string `db:"tenant_id"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
)
|
||||
|
||||
func newInvProductPanModel(conn sqlx.SqlConn) *defaultInvProductPanModel {
|
||||
return &defaultInvProductPanModel{
|
||||
conn: conn,
|
||||
table: "`inv_product_pan`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultInvProductPanModel) Insert(ctx context.Context, data *InvProductPan) (sql.Result, error) {
|
||||
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)
|
||||
}
|
||||
|
||||
func (m *defaultInvProductPanModel) FindOne(ctx context.Context, id int64) (*InvProductPan, error) {
|
||||
query := fmt.Sprintf("SELECT %s FROM %s WHERE `id` = ? LIMIT 1", invProductPanRows, m.table)
|
||||
var resp InvProductPan
|
||||
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (m *defaultInvProductPanModel) FindOneByPanId(ctx context.Context, panId string) (*InvProductPan, error) {
|
||||
query := fmt.Sprintf("SELECT %s FROM %s WHERE `pan_id` = ? LIMIT 1", invProductPanRows, m.table)
|
||||
var resp InvProductPan
|
||||
err := m.conn.QueryRowCtx(ctx, &resp, query, panId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (m *defaultInvProductPanModel) Update(ctx context.Context, data *InvProductPan) error {
|
||||
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)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *defaultInvProductPanModel) 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 *defaultInvProductPanModel) tableName() string {
|
||||
return m.table
|
||||
}
|
||||
@ -46,6 +46,7 @@ type (
|
||||
|
||||
SysRole struct {
|
||||
Id int64 `db:"id"`
|
||||
TenantId string `db:"tenant_id"`
|
||||
RoleId string `db:"role_id"`
|
||||
RoleName string `db:"role_name"`
|
||||
RoleKey string `db:"role_key"`
|
||||
@ -142,8 +143,8 @@ func (m *defaultSysRoleModel) Insert(ctx context.Context, data *SysRole) (sql.Re
|
||||
sysRoleRoleIdKey := fmt.Sprintf("%s%v", cacheSysRoleRoleIdPrefix, data.RoleId)
|
||||
sysRoleRoleKeyKey := fmt.Sprintf("%s%v", cacheSysRoleRoleKeyPrefix, data.RoleKey)
|
||||
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, sysRoleRowsExpectAutoSet)
|
||||
return conn.ExecCtx(ctx, query, data.RoleId, data.RoleName, data.RoleKey, data.RoleDesc, data.SortOrder, data.Status)
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?)", m.table, sysRoleRowsExpectAutoSet)
|
||||
return conn.ExecCtx(ctx, query, data.TenantId, data.RoleId, data.RoleName, data.RoleKey, data.RoleDesc, data.SortOrder, data.Status)
|
||||
}, sysRoleIdKey, sysRoleRoleIdKey, sysRoleRoleKeyKey)
|
||||
return ret, err
|
||||
}
|
||||
@ -159,7 +160,7 @@ func (m *defaultSysRoleModel) Update(ctx context.Context, newData *SysRole) erro
|
||||
sysRoleRoleKeyKey := fmt.Sprintf("%s%v", cacheSysRoleRoleKeyPrefix, data.RoleKey)
|
||||
_, 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, sysRoleRowsWithPlaceHolder)
|
||||
return conn.ExecCtx(ctx, query, newData.RoleId, newData.RoleName, newData.RoleKey, newData.RoleDesc, newData.SortOrder, newData.Status, newData.Id)
|
||||
return conn.ExecCtx(ctx, query, newData.TenantId, newData.RoleId, newData.RoleName, newData.RoleKey, newData.RoleDesc, newData.SortOrder, newData.Status, newData.Id)
|
||||
}, sysRoleIdKey, sysRoleRoleIdKey, sysRoleRoleKeyKey)
|
||||
return err
|
||||
}
|
||||
|
||||
102
pkg/excelparse/miaozhang.go
Normal file
102
pkg/excelparse/miaozhang.go
Normal file
@ -0,0 +1,102 @@
|
||||
package excelparse
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MiaozhangParser handles Excel exports from 秒账 (miaozhang.cn).
|
||||
//
|
||||
// Expected headers:
|
||||
// 图片1 | 图片2 | 图片3 | 名称 | 规格型号 | 颜色 | 条形码 | 匹数 | 库存数量 | 成本均价 | 参考售价 | 备注 | 更新日期
|
||||
type MiaozhangParser struct{}
|
||||
|
||||
func (p *MiaozhangParser) Name() string { return "秒账" }
|
||||
|
||||
func (p *MiaozhangParser) Match(headers []string) bool {
|
||||
required := map[string]bool{"名称": false, "规格型号": false, "颜色": false, "匹数": false, "库存数量": false}
|
||||
for _, h := range headers {
|
||||
h = strings.TrimSpace(h)
|
||||
if _, ok := required[h]; ok {
|
||||
required[h] = true
|
||||
}
|
||||
}
|
||||
for _, found := range required {
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *MiaozhangParser) ParseRows(headers []string, rows [][]string) (*ParseResult, error) {
|
||||
idx := buildIndex(headers)
|
||||
|
||||
var products []ParsedProduct
|
||||
skipped := 0
|
||||
|
||||
for _, row := range rows {
|
||||
name := colVal(row, idx["名称"])
|
||||
|
||||
if name == "" || strings.HasPrefix(name, "总") {
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
|
||||
rolls, _ := strconv.ParseInt(colVal(row, idx["匹数"]), 10, 64)
|
||||
|
||||
products = append(products, ParsedProduct{
|
||||
ProductName: name,
|
||||
Spec: colVal(row, idx["规格型号"]),
|
||||
Color: colVal(row, idx["颜色"]),
|
||||
UnitRolls: rolls,
|
||||
StockQuantity: stripUnit(colVal(row, idx["库存数量"])),
|
||||
CostPrice: stripCurrency(colVal(row, idx["成本均价"])),
|
||||
SalesPrice: stripCurrency(colVal(row, idx["参考售价"])),
|
||||
Remark: colVal(row, idx["备注"]),
|
||||
})
|
||||
}
|
||||
|
||||
return &ParseResult{Products: products, SkippedRows: skipped}, nil
|
||||
}
|
||||
|
||||
func buildIndex(headers []string) map[string]int {
|
||||
m := make(map[string]int, len(headers))
|
||||
for i, h := range headers {
|
||||
m[strings.TrimSpace(h)] = i
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func colVal(row []string, idx int) string {
|
||||
if idx < 0 || idx >= len(row) {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(row[idx])
|
||||
}
|
||||
|
||||
// stripUnit removes trailing unit markers like "米", "kg", etc.
|
||||
func stripUnit(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
for _, suffix := range []string{"米", "m", "kg", "KG"} {
|
||||
s = strings.TrimSuffix(s, suffix)
|
||||
}
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return "0"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// stripCurrency removes leading ¥ / $ / ¥ symbols.
|
||||
func stripCurrency(s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
for _, prefix := range []string{"¥", "¥", "$", "$"} {
|
||||
s = strings.TrimPrefix(s, prefix)
|
||||
}
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return "0"
|
||||
}
|
||||
return s
|
||||
}
|
||||
167
pkg/excelparse/parse.go
Normal file
167
pkg/excelparse/parse.go
Normal file
@ -0,0 +1,167 @@
|
||||
package excelparse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
||||
var parsers []FormatParser
|
||||
|
||||
func init() {
|
||||
parsers = append(parsers, &MiaozhangParser{})
|
||||
}
|
||||
|
||||
// RegisterParser adds a format parser at runtime (e.g. for plugins).
|
||||
func RegisterParser(p FormatParser) {
|
||||
parsers = append(parsers, p)
|
||||
}
|
||||
|
||||
// xlsToolPath returns the path to the xls2json.js script.
|
||||
// Checks XLS_TOOL_PATH env var first, then falls back to a path
|
||||
// relative to the binary's directory so it works both locally and in Docker.
|
||||
func xlsToolPath() (string, error) {
|
||||
if p := os.Getenv("XLS_TOOL_PATH"); p != "" {
|
||||
return p, nil
|
||||
}
|
||||
// Docker layout: /app/tools/xls2json.js
|
||||
candidates := []string{
|
||||
"/app/tools/xls2json.js",
|
||||
}
|
||||
// Local dev: look relative to the process working directory
|
||||
if cwd, err := os.Getwd(); err == nil {
|
||||
candidates = append(candidates,
|
||||
filepath.Join(cwd, "deploy/tools/xls2json.js"),
|
||||
filepath.Join(cwd, "../deploy/tools/xls2json.js"),
|
||||
)
|
||||
}
|
||||
for _, p := range candidates {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("xls2json.js not found; set XLS_TOOL_PATH env var or deploy to /app/tools/")
|
||||
}
|
||||
|
||||
// ParseFile reads an Excel file, auto-detects the competitor format, and returns parsed products.
|
||||
func ParseFile(filePath string) (*ParseResult, error) {
|
||||
ext := strings.ToLower(filepath.Ext(filePath))
|
||||
|
||||
var headers []string
|
||||
var rows [][]string
|
||||
var err error
|
||||
|
||||
switch ext {
|
||||
case ".xlsx":
|
||||
headers, rows, err = readXLSX(filePath)
|
||||
case ".xls":
|
||||
headers, rows, err = readXLS(filePath)
|
||||
default:
|
||||
return nil, ErrUnsupportedExt
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read excel: %w", err)
|
||||
}
|
||||
if len(rows) == 0 {
|
||||
return nil, ErrEmptyFile
|
||||
}
|
||||
|
||||
for _, p := range parsers {
|
||||
if p.Match(headers) {
|
||||
result, err := p.ParseRows(headers, rows)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse %s: %w", p.Name(), err)
|
||||
}
|
||||
result.ParserName = p.Name()
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrUnknownFormat
|
||||
}
|
||||
|
||||
func readXLSX(filePath string) ([]string, [][]string, error) {
|
||||
f, err := excelize.OpenFile(filePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
sheets := f.GetSheetList()
|
||||
if len(sheets) == 0 {
|
||||
return nil, nil, ErrEmptyFile
|
||||
}
|
||||
|
||||
allRows, err := f.GetRows(sheets[0])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(allRows) < 2 {
|
||||
return nil, nil, ErrEmptyFile
|
||||
}
|
||||
|
||||
return allRows[0], allRows[1:], nil
|
||||
}
|
||||
|
||||
// readXLS delegates to the xls2json.js Node.js script via subprocess.
|
||||
// This handles legacy .xls (BIFF8) files including those with embedded images,
|
||||
// which pure-Go libraries cannot reliably process.
|
||||
func readXLS(filePath string) ([]string, [][]string, error) {
|
||||
toolPath, err := xlsToolPath()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := exec.CommandContext(ctx, "node", toolPath, filePath)
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
msg := strings.TrimSpace(stderr.String())
|
||||
if msg == "" {
|
||||
msg = err.Error()
|
||||
}
|
||||
return nil, nil, fmt.Errorf("xls2json: %s", msg)
|
||||
}
|
||||
|
||||
// JSON format: [][]interface{} (first row = headers)
|
||||
var raw [][]interface{}
|
||||
if err := json.Unmarshal(stdout.Bytes(), &raw); err != nil {
|
||||
return nil, nil, fmt.Errorf("xls2json output parse: %w", err)
|
||||
}
|
||||
if len(raw) < 2 {
|
||||
return nil, nil, ErrEmptyFile
|
||||
}
|
||||
|
||||
toStrings := func(row []interface{}) []string {
|
||||
out := make([]string, len(row))
|
||||
for i, v := range row {
|
||||
if v == nil {
|
||||
out[i] = ""
|
||||
} else {
|
||||
out[i] = strings.TrimSpace(fmt.Sprintf("%v", v))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
headers := toStrings(raw[0])
|
||||
rows := make([][]string, 0, len(raw)-1)
|
||||
for _, r := range raw[1:] {
|
||||
rows = append(rows, toStrings(r))
|
||||
}
|
||||
|
||||
return headers, rows, nil
|
||||
}
|
||||
34
pkg/excelparse/types.go
Normal file
34
pkg/excelparse/types.go
Normal file
@ -0,0 +1,34 @@
|
||||
package excelparse
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrUnknownFormat = errors.New("unrecognized excel format; supported: 秒账, 领星")
|
||||
ErrEmptyFile = errors.New("excel file has no data rows")
|
||||
ErrUnsupportedExt = errors.New("unsupported file extension; use .xls or .xlsx")
|
||||
)
|
||||
|
||||
type ParsedProduct struct {
|
||||
ProductName string
|
||||
Spec string
|
||||
Color string
|
||||
UnitRolls int64
|
||||
StockQuantity string
|
||||
CostPrice string
|
||||
SalesPrice string
|
||||
Remark string
|
||||
}
|
||||
|
||||
type ParseResult struct {
|
||||
Products []ParsedProduct
|
||||
ParserName string
|
||||
SkippedRows int
|
||||
}
|
||||
|
||||
// FormatParser transforms raw spreadsheet rows into structured products.
|
||||
// Each competitor format (秒账, 领星, etc.) implements this interface.
|
||||
type FormatParser interface {
|
||||
Name() string
|
||||
Match(headers []string) bool
|
||||
ParseRows(headers []string, rows [][]string) (*ParseResult, error)
|
||||
}
|
||||
32
pkg/metrics/interceptor.go
Normal file
32
pkg/metrics/interceptor.go
Normal file
@ -0,0 +1,32 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
start := time.Now()
|
||||
resp, err := handler(ctx, req)
|
||||
elapsed := time.Since(start).Seconds()
|
||||
|
||||
code := "OK"
|
||||
if err != nil {
|
||||
if st, ok := status.FromError(err); ok {
|
||||
code = strconv.Itoa(int(st.Code()))
|
||||
} else {
|
||||
code = "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
RPCDurationSeconds.WithLabelValues(info.FullMethod).Observe(elapsed)
|
||||
RPCRequestsTotal.WithLabelValues(info.FullMethod, code).Inc()
|
||||
|
||||
return resp, err
|
||||
}
|
||||
}
|
||||
141
pkg/metrics/metrics.go
Normal file
141
pkg/metrics/metrics.go
Normal file
@ -0,0 +1,141 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
const namespace = "muyu"
|
||||
const subsystem = "inventory"
|
||||
|
||||
// ---- Business Counters ----
|
||||
|
||||
var ProductCreatedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "product_created_total",
|
||||
Help: "Total number of products created.",
|
||||
}, []string{"tenant_id", "product_name", "spec", "color"})
|
||||
|
||||
var ProductDeletedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "product_deleted_total",
|
||||
Help: "Total number of products deleted (soft delete).",
|
||||
}, []string{"tenant_id"})
|
||||
|
||||
var ImportOperationsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "import_operations_total",
|
||||
Help: "Total number of import operations executed.",
|
||||
}, []string{"tenant_id", "operator"})
|
||||
|
||||
var ImportProductsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "import_products_total",
|
||||
Help: "Total number of products processed during imports.",
|
||||
}, []string{"tenant_id", "result"})
|
||||
|
||||
var InboundLengthMetersTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "inbound_length_meters_total",
|
||||
Help: "Total length (meters) of fabric added to inventory.",
|
||||
}, []string{"tenant_id", "product_name", "color", "operation"})
|
||||
|
||||
var InboundBoltsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "inbound_bolts_total",
|
||||
Help: "Total number of bolt records added to inventory.",
|
||||
}, []string{"tenant_id", "operation"})
|
||||
|
||||
var PansSavedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "pans_saved_total",
|
||||
Help: "Total number of pan-save operations.",
|
||||
}, []string{"tenant_id", "product_id"})
|
||||
|
||||
var StockCheckCreatedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "stock_check_created_total",
|
||||
Help: "Total number of stock check records created.",
|
||||
}, []string{"tenant_id"})
|
||||
|
||||
var StockCheckConfirmedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "stock_check_confirmed_total",
|
||||
Help: "Total number of stock checks confirmed.",
|
||||
}, []string{"tenant_id"})
|
||||
|
||||
var StockAdjustCreatedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "stock_adjust_created_total",
|
||||
Help: "Total number of stock adjustments created.",
|
||||
}, []string{"tenant_id", "reason"})
|
||||
|
||||
var StockAdjustApprovedTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "stock_adjust_approved_total",
|
||||
Help: "Total number of stock adjustments approved/rejected.",
|
||||
}, []string{"tenant_id", "action"})
|
||||
|
||||
var StockAdjustQuantityMeters = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "stock_adjust_quantity_meters_total",
|
||||
Help: "Total adjusted quantity in meters (absolute value, split by direction).",
|
||||
}, []string{"tenant_id", "direction"})
|
||||
|
||||
// ---- Histograms ----
|
||||
|
||||
var ImportBatchSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "import_batch_size",
|
||||
Help: "Number of products per import operation.",
|
||||
Buckets: []float64{1, 5, 10, 50, 100, 200, 500, 1000},
|
||||
}, []string{"tenant_id"})
|
||||
|
||||
// ---- RPC Operational Metrics ----
|
||||
|
||||
var RPCDurationSeconds = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "rpc_duration_seconds",
|
||||
Help: "Duration of RPC calls in seconds.",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"method"})
|
||||
|
||||
var RPCRequestsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace, Subsystem: subsystem,
|
||||
Name: "rpc_requests_total",
|
||||
Help: "Total number of RPC requests.",
|
||||
}, []string{"method", "code"})
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(
|
||||
ProductCreatedTotal,
|
||||
ProductDeletedTotal,
|
||||
ImportOperationsTotal,
|
||||
ImportProductsTotal,
|
||||
InboundLengthMetersTotal,
|
||||
InboundBoltsTotal,
|
||||
PansSavedTotal,
|
||||
StockCheckCreatedTotal,
|
||||
StockCheckConfirmedTotal,
|
||||
StockAdjustCreatedTotal,
|
||||
StockAdjustApprovedTotal,
|
||||
StockAdjustQuantityMeters,
|
||||
ImportBatchSize,
|
||||
RPCDurationSeconds,
|
||||
RPCRequestsTotal,
|
||||
)
|
||||
}
|
||||
|
||||
func StartHTTP(addr string) {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
go func() {
|
||||
logx.Infof("prometheus metrics listening on %s", addr)
|
||||
if err := http.ListenAndServe(addr, mux); err != nil {
|
||||
logx.Errorf("prometheus http server error: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
10
rpc/inventory/buf.gen.yaml
Normal file
10
rpc/inventory/buf.gen.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
version: v2
|
||||
plugins:
|
||||
- local: protoc-gen-go
|
||||
out: pb
|
||||
opt:
|
||||
- paths=source_relative
|
||||
- local: protoc-gen-go-grpc
|
||||
out: pb
|
||||
opt:
|
||||
- paths=source_relative
|
||||
9
rpc/inventory/buf.yaml
Normal file
9
rpc/inventory/buf.yaml
Normal file
@ -0,0 +1,9 @@
|
||||
version: v2
|
||||
modules:
|
||||
- path: .
|
||||
lint:
|
||||
use:
|
||||
- DEFAULT
|
||||
breaking:
|
||||
use:
|
||||
- FILE
|
||||
@ -11,6 +11,8 @@ DataSource: root:muyu2026@tcp(127.0.0.1:3306)/muyu_wms?charset=utf8mb4&parseTime
|
||||
Cache:
|
||||
- Host: 127.0.0.1:6379
|
||||
|
||||
PrometheusAddr: :9092
|
||||
|
||||
Log:
|
||||
ServiceName: inventory-rpc
|
||||
Mode: console
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
type Config struct {
|
||||
zrpc.RpcServerConf
|
||||
DataSource string
|
||||
Cache cache.CacheConf
|
||||
DataSource string
|
||||
Cache cache.CacheConf
|
||||
PrometheusAddr string `json:",default=:9092"`
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ package logic
|
||||
import (
|
||||
"context"
|
||||
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
@ -39,29 +41,11 @@ func (l *ApproveStockAdjustLogic) ApproveStockAdjust(in *pb.ApproveStockAdjustRe
|
||||
|
||||
switch in.Action {
|
||||
case 1: // approve
|
||||
details, err := l.svcCtx.AdjustDetailModel.FindByAdjustId(l.ctx, in.AdjustId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
for _, d := range details {
|
||||
product, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, d.ProductId)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to find product %s: %v", d.ProductId, err)
|
||||
}
|
||||
|
||||
product.StockQuantity = d.AfterQuantity
|
||||
err = l.svcCtx.ProductModel.Update(l.ctx, product)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to update product %s stock: %v", d.ProductId, err)
|
||||
}
|
||||
}
|
||||
|
||||
// In the three-layer model, actual stock adjustments are done via
|
||||
// SaveBolts/SavePans. Approving records the approval decision only.
|
||||
adjust.Status = 1
|
||||
|
||||
case 2: // reject
|
||||
adjust.Status = 2
|
||||
|
||||
default:
|
||||
return nil, status.Errorf(codes.InvalidArgument, "unsupported action: %d", in.Action)
|
||||
}
|
||||
@ -71,5 +55,12 @@ func (l *ApproveStockAdjustLogic) ApproveStockAdjust(in *pb.ApproveStockAdjustRe
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
actionLabel := "approve"
|
||||
if in.Action == 2 {
|
||||
actionLabel = "reject"
|
||||
}
|
||||
metrics.StockAdjustApprovedTotal.WithLabelValues(tenantId, actionLabel).Inc()
|
||||
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ package logic
|
||||
import (
|
||||
"context"
|
||||
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
@ -35,29 +37,17 @@ func (l *ConfirmStockCheckLogic) ConfirmStockCheck(in *pb.ConfirmStockCheckReq)
|
||||
return nil, status.Error(codes.FailedPrecondition, "stock check cannot be confirmed in current status")
|
||||
}
|
||||
|
||||
details, err := l.svcCtx.CheckDetailModel.FindByCheckId(l.ctx, in.CheckId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
for _, d := range details {
|
||||
product, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, d.ProductId)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to find product %s: %v", d.ProductId, err)
|
||||
}
|
||||
|
||||
product.StockQuantity = d.ActualQuantity
|
||||
err = l.svcCtx.ProductModel.Update(l.ctx, product)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to update product %s stock: %v", d.ProductId, err)
|
||||
}
|
||||
}
|
||||
|
||||
// In the three-layer model, stock is held in bolt records.
|
||||
// Confirming a stock check marks it as completed; bolt-level adjustments
|
||||
// are handled separately via the SaveBolts/SavePans endpoints.
|
||||
check.Status = 2
|
||||
err = l.svcCtx.StockCheckModel.Update(l.ctx, check)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
metrics.StockCheckConfirmedTotal.WithLabelValues(tenantId).Inc()
|
||||
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
@ -6,6 +6,8 @@ import (
|
||||
"strconv"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
@ -31,25 +33,17 @@ func NewCreateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Cre
|
||||
|
||||
func (l *CreateProductLogic) CreateProduct(in *pb.CreateProductReq) (*pb.IdResp, error) {
|
||||
productId := uid.Generate()
|
||||
|
||||
stockQuantity, _ := strconv.ParseFloat(in.StockQuantity, 64)
|
||||
costPrice, _ := strconv.ParseFloat(in.CostPrice, 64)
|
||||
salesPrice, _ := strconv.ParseFloat(in.SalesPrice, 64)
|
||||
|
||||
product := &model.InvProduct{
|
||||
ProductId: productId,
|
||||
ProductName: in.ProductName,
|
||||
ImageUrl: in.ImageUrl,
|
||||
Spec: in.Spec,
|
||||
Color: in.Color,
|
||||
UnitPieces: in.UnitPieces,
|
||||
UnitRolls: in.UnitRolls,
|
||||
StockQuantity: stockQuantity,
|
||||
Location: in.Location,
|
||||
CostPrice: costPrice,
|
||||
SalesPrice: salesPrice,
|
||||
Remark: sql.NullString{String: in.Remark, Valid: in.Remark != ""},
|
||||
Status: 1,
|
||||
ProductId: productId,
|
||||
ProductName: in.ProductName,
|
||||
ImageUrl: in.ImageUrl,
|
||||
Spec: in.Spec,
|
||||
Color: in.Color,
|
||||
SalesPrice: salesPrice,
|
||||
Remark: sql.NullString{String: in.Remark, Valid: in.Remark != ""},
|
||||
Status: 1,
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.ProductModel.Insert(l.ctx, product)
|
||||
@ -57,5 +51,52 @@ func (l *CreateProductLogic) CreateProduct(in *pb.CreateProductReq) (*pb.IdResp,
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
var totalLengthM float64
|
||||
var totalBolts int
|
||||
|
||||
if len(in.Pans) > 0 {
|
||||
pans := make([]*model.InvProductPan, 0, len(in.Pans))
|
||||
for i, panInput := range in.Pans {
|
||||
panId := uid.Generate()
|
||||
pans = append(pans, &model.InvProductPan{
|
||||
PanId: panId,
|
||||
ProductId: productId,
|
||||
Name: panInput.Name,
|
||||
Position: panInput.Position,
|
||||
SortOrder: int64(i + 1),
|
||||
})
|
||||
|
||||
if len(panInput.BoltLengths) > 0 {
|
||||
bolts := make([]*model.InvProductBolt, 0, len(panInput.BoltLengths))
|
||||
for j, lengthStr := range panInput.BoltLengths {
|
||||
lengthM, _ := strconv.ParseFloat(lengthStr, 64)
|
||||
totalLengthM += lengthM
|
||||
bolts = append(bolts, &model.InvProductBolt{
|
||||
BoltId: uid.Generate(),
|
||||
PanId: panId,
|
||||
LengthM: lengthM,
|
||||
SortOrder: int64(j + 1),
|
||||
})
|
||||
}
|
||||
totalBolts += len(panInput.BoltLengths)
|
||||
if err := l.svcCtx.BoltModel.BulkReplace(l.ctx, panId, "", bolts); err != nil {
|
||||
l.Errorf("create bolts for pan %s failed: %v", panId, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := l.svcCtx.PanModel.BulkReplace(l.ctx, productId, "", pans); err != nil {
|
||||
l.Errorf("create pans for product %s failed: %v", productId, err)
|
||||
}
|
||||
}
|
||||
|
||||
metrics.ProductCreatedTotal.WithLabelValues(tenantId, in.ProductName, in.Spec, in.Color).Inc()
|
||||
if totalLengthM > 0 {
|
||||
metrics.InboundLengthMetersTotal.WithLabelValues(tenantId, in.ProductName, in.Color, "create").Add(totalLengthM)
|
||||
}
|
||||
if totalBolts > 0 {
|
||||
metrics.InboundBoltsTotal.WithLabelValues(tenantId, "create").Add(float64(totalBolts))
|
||||
}
|
||||
|
||||
return &pb.IdResp{Id: productId}, nil
|
||||
}
|
||||
|
||||
@ -6,7 +6,11 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"math"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
@ -30,6 +34,19 @@ func NewCreateStockAdjustLogic(ctx context.Context, svcCtx *svc.ServiceContext)
|
||||
}
|
||||
}
|
||||
|
||||
// currentQty returns the total bolt length (meters) for a product.
|
||||
func (l *CreateStockAdjustLogic) currentQty(productId string) float64 {
|
||||
bolts, err := l.svcCtx.BoltModel.FindByProductId(l.ctx, productId)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
var total float64
|
||||
for _, b := range bolts {
|
||||
total += b.LengthM
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func (l *CreateStockAdjustLogic) CreateStockAdjust(in *pb.CreateStockAdjustReq) (*pb.IdResp, error) {
|
||||
adjustId := uid.Generate()
|
||||
adjustNo := generateNo("TZ")
|
||||
@ -56,19 +73,20 @@ func (l *CreateStockAdjustLogic) CreateStockAdjust(in *pb.CreateStockAdjustReq)
|
||||
|
||||
details := make([]*model.InvStockAdjustDetail, 0, len(in.Details))
|
||||
for _, d := range in.Details {
|
||||
product, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, d.ProductId)
|
||||
_, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, d.ProductId)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.NotFound, "product %s not found", d.ProductId)
|
||||
}
|
||||
|
||||
beforeQty := l.currentQty(d.ProductId)
|
||||
adjustQty, _ := strconv.ParseFloat(d.AdjustQuantity, 64)
|
||||
afterQty := product.StockQuantity + adjustQty
|
||||
afterQty := beforeQty + adjustQty
|
||||
|
||||
details = append(details, &model.InvStockAdjustDetail{
|
||||
DetailId: uid.Generate(),
|
||||
AdjustId: adjustId,
|
||||
ProductId: d.ProductId,
|
||||
BeforeQuantity: product.StockQuantity,
|
||||
BeforeQuantity: beforeQty,
|
||||
AdjustQuantity: adjustQty,
|
||||
AfterQuantity: afterQty,
|
||||
Remark: sql.NullString{String: d.Remark, Valid: d.Remark != ""},
|
||||
@ -80,5 +98,15 @@ func (l *CreateStockAdjustLogic) CreateStockAdjust(in *pb.CreateStockAdjustReq)
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
metrics.StockAdjustCreatedTotal.WithLabelValues(tenantId, in.AdjustReason).Inc()
|
||||
for _, d := range details {
|
||||
if d.AdjustQuantity >= 0 {
|
||||
metrics.StockAdjustQuantityMeters.WithLabelValues(tenantId, "increase").Add(d.AdjustQuantity)
|
||||
} else {
|
||||
metrics.StockAdjustQuantityMeters.WithLabelValues(tenantId, "decrease").Add(math.Abs(d.AdjustQuantity))
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.IdResp{Id: adjustId}, nil
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
@ -36,6 +38,19 @@ func generateNo(prefix string) string {
|
||||
return fmt.Sprintf("%s%s%04d", prefix, now.Format("20060102"), now.UnixNano()%10000)
|
||||
}
|
||||
|
||||
// computeSystemQty returns the total bolt length (meters) for a product.
|
||||
func (l *CreateStockCheckLogic) computeSystemQty(productId string) float64 {
|
||||
bolts, err := l.svcCtx.BoltModel.FindByProductId(l.ctx, productId)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
var total float64
|
||||
for _, b := range bolts {
|
||||
total += b.LengthM
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func (l *CreateStockCheckLogic) CreateStockCheck(in *pb.CreateStockCheckReq) (*pb.IdResp, error) {
|
||||
checkId := uid.Generate()
|
||||
checkNo := generateNo("PD")
|
||||
@ -66,15 +81,16 @@ func (l *CreateStockCheckLogic) CreateStockCheck(in *pb.CreateStockCheckReq) (*p
|
||||
return nil, status.Errorf(codes.NotFound, "product %s not found", d.ProductId)
|
||||
}
|
||||
|
||||
systemQty := l.computeSystemQty(d.ProductId)
|
||||
actualQty, _ := strconv.ParseFloat(d.ActualQuantity, 64)
|
||||
diffQty := actualQty - product.StockQuantity
|
||||
diffAmount := diffQty * product.CostPrice
|
||||
diffQty := actualQty - systemQty
|
||||
diffAmount := diffQty * product.SalesPrice
|
||||
|
||||
details = append(details, &model.InvStockCheckDetail{
|
||||
DetailId: uid.Generate(),
|
||||
CheckId: checkId,
|
||||
ProductId: d.ProductId,
|
||||
SystemQuantity: product.StockQuantity,
|
||||
SystemQuantity: systemQty,
|
||||
ActualQuantity: actualQty,
|
||||
DiffQuantity: diffQty,
|
||||
DiffAmount: diffAmount,
|
||||
@ -87,5 +103,8 @@ func (l *CreateStockCheckLogic) CreateStockCheck(in *pb.CreateStockCheckReq) (*p
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
metrics.StockCheckCreatedTotal.WithLabelValues(tenantId).Inc()
|
||||
|
||||
return &pb.IdResp{Id: checkId}, nil
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
@ -41,5 +43,8 @@ func (l *DeleteProductLogic) DeleteProduct(in *pb.DeleteProductReq) (*pb.Empty,
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
metrics.ProductDeletedTotal.WithLabelValues(tenantId).Inc()
|
||||
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
@ -33,20 +33,15 @@ func (l *GetProductLogic) GetProduct(in *pb.GetProductReq) (*pb.ProductInfo, err
|
||||
}
|
||||
|
||||
return &pb.ProductInfo{
|
||||
ProductId: product.ProductId,
|
||||
ProductName: product.ProductName,
|
||||
ImageUrl: product.ImageUrl,
|
||||
Spec: product.Spec,
|
||||
Color: product.Color,
|
||||
UnitPieces: product.UnitPieces,
|
||||
UnitRolls: product.UnitRolls,
|
||||
StockQuantity: fmt.Sprintf("%.2f", product.StockQuantity),
|
||||
Location: product.Location,
|
||||
CostPrice: fmt.Sprintf("%.2f", product.CostPrice),
|
||||
SalesPrice: fmt.Sprintf("%.2f", product.SalesPrice),
|
||||
Remark: product.Remark.String,
|
||||
Status: product.Status,
|
||||
CreatedAt: product.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: product.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
ProductId: product.ProductId,
|
||||
ProductName: product.ProductName,
|
||||
ImageUrl: product.ImageUrl,
|
||||
Spec: product.Spec,
|
||||
Color: product.Color,
|
||||
SalesPrice: fmt.Sprintf("%.2f", product.SalesPrice),
|
||||
Remark: product.Remark.String,
|
||||
Status: product.Status,
|
||||
CreatedAt: product.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: product.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
95
rpc/inventory/internal/logic/getproducttreelogic.go
Normal file
95
rpc/inventory/internal/logic/getproducttreelogic.go
Normal file
@ -0,0 +1,95 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type GetProductTreeLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewGetProductTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetProductTreeLogic {
|
||||
return &GetProductTreeLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetProductTreeLogic) GetProductTree(in *pb.GetProductReq) (*pb.ProductTreeResp, error) {
|
||||
product, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, in.ProductId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, "product not found")
|
||||
}
|
||||
|
||||
pans, err := l.svcCtx.PanModel.FindByProductId(l.ctx, in.ProductId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
var totalBoltCount int64
|
||||
var totalLengthM float64
|
||||
pbPans := make([]*pb.PanInfo, 0, len(pans))
|
||||
|
||||
for _, pan := range pans {
|
||||
bolts, err := l.svcCtx.BoltModel.FindByPanId(l.ctx, pan.PanId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
var panLength float64
|
||||
pbBolts := make([]*pb.BoltInfo, 0, len(bolts))
|
||||
for _, b := range bolts {
|
||||
pbBolts = append(pbBolts, &pb.BoltInfo{
|
||||
BoltId: b.BoltId,
|
||||
PanId: b.PanId,
|
||||
LengthM: fmt.Sprintf("%.2f", b.LengthM),
|
||||
SortOrder: b.SortOrder,
|
||||
})
|
||||
panLength += b.LengthM
|
||||
}
|
||||
|
||||
totalBoltCount += int64(len(bolts))
|
||||
totalLengthM += panLength
|
||||
|
||||
pbPans = append(pbPans, &pb.PanInfo{
|
||||
PanId: pan.PanId,
|
||||
ProductId: pan.ProductId,
|
||||
Name: pan.Name,
|
||||
Position: pan.Position,
|
||||
SortOrder: pan.SortOrder,
|
||||
Bolts: pbBolts,
|
||||
BoltCount: int64(len(bolts)),
|
||||
TotalLength: fmt.Sprintf("%.2f", panLength),
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ProductTreeResp{
|
||||
Product: &pb.ProductInfo{
|
||||
ProductId: product.ProductId,
|
||||
ProductName: product.ProductName,
|
||||
ImageUrl: product.ImageUrl,
|
||||
Spec: product.Spec,
|
||||
Color: product.Color,
|
||||
SalesPrice: fmt.Sprintf("%.2f", product.SalesPrice),
|
||||
Remark: product.Remark.String,
|
||||
Status: product.Status,
|
||||
CreatedAt: product.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: product.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
Pans: pbPans,
|
||||
TotalPanCount: int64(len(pans)),
|
||||
TotalBoltCount: totalBoltCount,
|
||||
TotalLengthM: fmt.Sprintf("%.2f", totalLengthM),
|
||||
}, nil
|
||||
}
|
||||
@ -29,16 +29,26 @@ func NewGetStockSummaryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *G
|
||||
|
||||
func (l *GetStockSummaryLogic) GetStockSummary(in *pb.StockSummaryReq) (*pb.StockSummaryResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
productCount, totalPieces, totalRolls, totalCostValue, totalSalesValue, err := l.svcCtx.ProductModel.FindStockSummary(l.ctx, tenantId)
|
||||
summaries, err := l.svcCtx.ProductModel.FindProductSummary(l.ctx, tenantId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
var productCount, totalPieces, totalPans int64
|
||||
var totalLengthM, totalSalesValue float64
|
||||
for _, s := range summaries {
|
||||
productCount += s.ColorCount
|
||||
totalPieces += s.TotalBoltCount
|
||||
totalPans += s.TotalPanCount
|
||||
totalLengthM += s.TotalLengthM
|
||||
}
|
||||
_ = totalSalesValue
|
||||
|
||||
return &pb.StockSummaryResp{
|
||||
ProductCount: productCount,
|
||||
TotalPieces: totalPieces,
|
||||
TotalRolls: totalRolls,
|
||||
TotalCostValue: fmt.Sprintf("%.2f", totalCostValue),
|
||||
TotalSalesValue: fmt.Sprintf("%.2f", totalSalesValue),
|
||||
TotalPans: totalPans,
|
||||
TotalLengthM: fmt.Sprintf("%.2f", totalLengthM),
|
||||
TotalSalesValue: "0.00",
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -3,11 +3,12 @@ package logic
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
@ -32,44 +33,35 @@ func NewImportProductsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Im
|
||||
}
|
||||
|
||||
func (l *ImportProductsLogic) ImportProducts(in *pb.ImportProductReq) (*pb.ImportProductResp, error) {
|
||||
var successCount, failCount int64
|
||||
var errMsgs []string
|
||||
products := make([]*model.InvProduct, 0, len(in.Products))
|
||||
|
||||
for i, p := range in.Products {
|
||||
productId := uid.Generate()
|
||||
stockQuantity, _ := strconv.ParseFloat(p.StockQuantity, 64)
|
||||
costPrice, _ := strconv.ParseFloat(p.CostPrice, 64)
|
||||
for _, p := range in.Products {
|
||||
salesPrice, _ := strconv.ParseFloat(p.SalesPrice, 64)
|
||||
|
||||
product := &model.InvProduct{
|
||||
ProductId: productId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
UnitPieces: p.UnitPieces,
|
||||
UnitRolls: p.UnitRolls,
|
||||
StockQuantity: stockQuantity,
|
||||
Location: p.Location,
|
||||
CostPrice: costPrice,
|
||||
SalesPrice: salesPrice,
|
||||
Remark: sql.NullString{String: p.Remark, Valid: p.Remark != ""},
|
||||
Status: 1,
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.ProductModel.Insert(l.ctx, product)
|
||||
if err != nil {
|
||||
failCount++
|
||||
errMsgs = append(errMsgs, fmt.Sprintf("row %d: %s", i+1, err.Error()))
|
||||
} else {
|
||||
successCount++
|
||||
}
|
||||
products = append(products, &model.InvProduct{
|
||||
ProductId: uid.Generate(),
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
SalesPrice: salesPrice,
|
||||
Remark: sql.NullString{String: p.Remark, Valid: p.Remark != ""},
|
||||
Status: 1,
|
||||
})
|
||||
}
|
||||
|
||||
totalCount := int64(len(in.Products))
|
||||
importId := uid.Generate()
|
||||
errorMsg := strings.Join(errMsgs, "; ")
|
||||
totalCount := int64(len(products))
|
||||
affected, err := l.svcCtx.ProductModel.BulkInsert(l.ctx, products)
|
||||
|
||||
var errorMsg string
|
||||
successCount := affected
|
||||
failCount := totalCount - affected
|
||||
if err != nil {
|
||||
errorMsg = err.Error()
|
||||
l.Errorf("bulk insert partial failure: %v", err)
|
||||
}
|
||||
|
||||
importId := uid.Generate()
|
||||
importLog := &model.InvStockImportLog{
|
||||
ImportId: importId,
|
||||
FileName: in.FileName,
|
||||
@ -80,9 +72,23 @@ func (l *ImportProductsLogic) ImportProducts(in *pb.ImportProductReq) (*pb.Impor
|
||||
Operator: in.Operator,
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.ImportLogModel.Insert(l.ctx, importLog)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
if _, logErr := l.svcCtx.ImportLogModel.Insert(l.ctx, importLog); logErr != nil {
|
||||
l.Errorf("save import log failed: %v", logErr)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, strings.Join([]string{errorMsg, logErr.Error()}, "; "))
|
||||
}
|
||||
return nil, status.Error(codes.Internal, logErr.Error())
|
||||
}
|
||||
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
metrics.ImportOperationsTotal.WithLabelValues(tenantId, in.Operator).Inc()
|
||||
metrics.ImportProductsTotal.WithLabelValues(tenantId, "success").Add(float64(successCount))
|
||||
if failCount > 0 {
|
||||
metrics.ImportProductsTotal.WithLabelValues(tenantId, "fail").Add(float64(failCount))
|
||||
}
|
||||
metrics.ImportBatchSize.WithLabelValues(tenantId).Observe(float64(totalCount))
|
||||
for _, p := range in.Products {
|
||||
metrics.ProductCreatedTotal.WithLabelValues(tenantId, p.ProductName, p.Spec, p.Color).Inc()
|
||||
}
|
||||
|
||||
return &pb.ImportProductResp{
|
||||
|
||||
46
rpc/inventory/internal/logic/listboltslogic.go
Normal file
46
rpc/inventory/internal/logic/listboltslogic.go
Normal file
@ -0,0 +1,46 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ListBoltsLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewListBoltsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListBoltsLogic {
|
||||
return &ListBoltsLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListBoltsLogic) ListBolts(in *pb.ListBoltReq) (*pb.ListBoltResp, error) {
|
||||
bolts, err := l.svcCtx.BoltModel.FindByPanId(l.ctx, in.PanId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbBolts := make([]*pb.BoltInfo, 0, len(bolts))
|
||||
for _, b := range bolts {
|
||||
pbBolts = append(pbBolts, &pb.BoltInfo{
|
||||
BoltId: b.BoltId,
|
||||
PanId: b.PanId,
|
||||
LengthM: fmt.Sprintf("%.2f", b.LengthM),
|
||||
SortOrder: b.SortOrder,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListBoltResp{List: pbBolts}, nil
|
||||
}
|
||||
53
rpc/inventory/internal/logic/listboltviewlogic.go
Normal file
53
rpc/inventory/internal/logic/listboltviewlogic.go
Normal file
@ -0,0 +1,53 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ListBoltViewLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewListBoltViewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListBoltViewLogic {
|
||||
return &ListBoltViewLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListBoltViewLogic) ListBoltView(in *pb.ListBoltViewReq) (*pb.ListBoltViewResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
list, total, err := l.svcCtx.BoltModel.FindBoltList(l.ctx, tenantId, in.Page, in.PageSize, in.ProductName, in.Position)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbList := make([]*pb.BoltListItem, 0, len(list))
|
||||
for _, item := range list {
|
||||
pbList = append(pbList, &pb.BoltListItem{
|
||||
BoltId: item.BoltId,
|
||||
PanId: item.PanId,
|
||||
LengthM: fmt.Sprintf("%.2f", item.LengthM),
|
||||
Color: item.Color,
|
||||
SortOrder: item.SortOrder,
|
||||
PanName: item.PanName,
|
||||
Position: item.Position,
|
||||
ProductId: item.ProductId,
|
||||
ProductName: item.ProductName,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListBoltViewResp{Total: total, List: pbList}, nil
|
||||
}
|
||||
54
rpc/inventory/internal/logic/listcolordetaillogic.go
Normal file
54
rpc/inventory/internal/logic/listcolordetaillogic.go
Normal file
@ -0,0 +1,54 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ListColorDetailLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewListColorDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListColorDetailLogic {
|
||||
return &ListColorDetailLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListColorDetailLogic) ListColorDetail(in *pb.ListColorDetailReq) (*pb.ListColorDetailResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
list, err := l.svcCtx.ProductModel.FindColorDetail(l.ctx, tenantId, in.ProductName)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbList := make([]*pb.ColorDetailItem, 0, len(list))
|
||||
for _, d := range list {
|
||||
pbList = append(pbList, &pb.ColorDetailItem{
|
||||
ProductId: d.ProductId,
|
||||
ProductName: d.ProductName,
|
||||
Color: d.Color,
|
||||
Spec: d.Spec,
|
||||
ImageUrl: d.ImageUrl,
|
||||
PanCount: d.PanCount,
|
||||
BoltCount: d.BoltCount,
|
||||
TotalLengthM: fmt.Sprintf("%.2f", d.TotalLengthM),
|
||||
Locations: d.Locations,
|
||||
SalesPrice: fmt.Sprintf("%.2f", d.SalesPrice),
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListColorDetailResp{List: pbList}, nil
|
||||
}
|
||||
65
rpc/inventory/internal/logic/listpanslogic.go
Normal file
65
rpc/inventory/internal/logic/listpanslogic.go
Normal file
@ -0,0 +1,65 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ListPansLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewListPansLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPansLogic {
|
||||
return &ListPansLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListPansLogic) ListPans(in *pb.ListPanReq) (*pb.ListPanResp, error) {
|
||||
pans, err := l.svcCtx.PanModel.FindByProductId(l.ctx, in.ProductId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbPans := make([]*pb.PanInfo, 0, len(pans))
|
||||
for _, pan := range pans {
|
||||
bolts, err := l.svcCtx.BoltModel.FindByPanId(l.ctx, pan.PanId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
var panLength float64
|
||||
pbBolts := make([]*pb.BoltInfo, 0, len(bolts))
|
||||
for _, b := range bolts {
|
||||
pbBolts = append(pbBolts, &pb.BoltInfo{
|
||||
BoltId: b.BoltId,
|
||||
PanId: b.PanId,
|
||||
LengthM: fmt.Sprintf("%.2f", b.LengthM),
|
||||
SortOrder: b.SortOrder,
|
||||
})
|
||||
panLength += b.LengthM
|
||||
}
|
||||
pbPans = append(pbPans, &pb.PanInfo{
|
||||
PanId: pan.PanId,
|
||||
ProductId: pan.ProductId,
|
||||
Name: pan.Name,
|
||||
Position: pan.Position,
|
||||
SortOrder: pan.SortOrder,
|
||||
Bolts: pbBolts,
|
||||
BoltCount: int64(len(bolts)),
|
||||
TotalLength: fmt.Sprintf("%.2f", panLength),
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListPanResp{List: pbPans}, nil
|
||||
}
|
||||
52
rpc/inventory/internal/logic/listpanviewlogic.go
Normal file
52
rpc/inventory/internal/logic/listpanviewlogic.go
Normal file
@ -0,0 +1,52 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ListPanViewLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewListPanViewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListPanViewLogic {
|
||||
return &ListPanViewLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListPanViewLogic) ListPanView(in *pb.ListPanViewReq) (*pb.ListPanViewResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
list, total, err := l.svcCtx.PanModel.FindPanList(l.ctx, tenantId, in.Page, in.PageSize, in.ProductName, in.Position)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbList := make([]*pb.PanListItem, 0, len(list))
|
||||
for _, item := range list {
|
||||
pbList = append(pbList, &pb.PanListItem{
|
||||
PanId: item.PanId,
|
||||
ProductId: item.ProductId,
|
||||
Name: item.Name,
|
||||
Position: item.Position,
|
||||
ProductName: item.ProductName,
|
||||
Colors: item.Colors,
|
||||
BoltCount: item.BoltCount,
|
||||
TotalLengthM: fmt.Sprintf("%.2f", item.TotalLengthM),
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListPanViewResp{Total: total, List: pbList}, nil
|
||||
}
|
||||
@ -29,7 +29,7 @@ func NewListProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListP
|
||||
|
||||
func (l *ListProductLogic) ListProduct(in *pb.ListProductReq) (*pb.ListProductResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
list, total, err := l.svcCtx.ProductModel.FindList(l.ctx, tenantId, in.Page, in.PageSize, in.ProductName, in.Spec, in.Color, in.Location, in.Status)
|
||||
list, total, err := l.svcCtx.ProductModel.FindList(l.ctx, tenantId, in.Page, in.PageSize, in.ProductName, in.Spec, in.Color, in.Status)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
@ -37,21 +37,16 @@ func (l *ListProductLogic) ListProduct(in *pb.ListProductReq) (*pb.ListProductRe
|
||||
pbList := make([]*pb.ProductInfo, 0, len(list))
|
||||
for _, p := range list {
|
||||
pbList = append(pbList, &pb.ProductInfo{
|
||||
ProductId: p.ProductId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
UnitPieces: p.UnitPieces,
|
||||
UnitRolls: p.UnitRolls,
|
||||
StockQuantity: fmt.Sprintf("%.2f", p.StockQuantity),
|
||||
Location: p.Location,
|
||||
CostPrice: fmt.Sprintf("%.2f", p.CostPrice),
|
||||
SalesPrice: fmt.Sprintf("%.2f", p.SalesPrice),
|
||||
Remark: p.Remark.String,
|
||||
Status: p.Status,
|
||||
CreatedAt: p.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: p.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
ProductId: p.ProductId,
|
||||
ProductName: p.ProductName,
|
||||
ImageUrl: p.ImageUrl,
|
||||
Spec: p.Spec,
|
||||
Color: p.Color,
|
||||
SalesPrice: fmt.Sprintf("%.2f", p.SalesPrice),
|
||||
Remark: p.Remark.String,
|
||||
Status: p.Status,
|
||||
CreatedAt: p.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
UpdatedAt: p.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
52
rpc/inventory/internal/logic/listproductsummarylogic.go
Normal file
52
rpc/inventory/internal/logic/listproductsummarylogic.go
Normal file
@ -0,0 +1,52 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type ListProductSummaryLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewListProductSummaryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListProductSummaryLogic {
|
||||
return &ListProductSummaryLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ListProductSummaryLogic) ListProductSummary(in *pb.ListProductSummaryReq) (*pb.ListProductSummaryResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
list, err := l.svcCtx.ProductModel.FindProductSummary(l.ctx, tenantId)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
pbList := make([]*pb.ProductSummaryItem, 0, len(list))
|
||||
for _, s := range list {
|
||||
pbList = append(pbList, &pb.ProductSummaryItem{
|
||||
ProductName: s.ProductName,
|
||||
Spec: s.Spec,
|
||||
ColorCount: s.ColorCount,
|
||||
TotalPanCount: s.TotalPanCount,
|
||||
TotalBoltCount: s.TotalBoltCount,
|
||||
TotalLengthM: fmt.Sprintf("%.2f", s.TotalLengthM),
|
||||
Colors: s.Colors,
|
||||
Locations: s.Locations,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListProductSummaryResp{List: pbList}, nil
|
||||
}
|
||||
59
rpc/inventory/internal/logic/saveboltslogic.go
Normal file
59
rpc/inventory/internal/logic/saveboltslogic.go
Normal file
@ -0,0 +1,59 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type SaveBoltsLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewSaveBoltsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SaveBoltsLogic {
|
||||
return &SaveBoltsLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SaveBoltsLogic) SaveBolts(in *pb.SaveBoltsReq) (*pb.Empty, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
|
||||
var totalLengthM float64
|
||||
bolts := make([]*model.InvProductBolt, 0, len(in.Lengths))
|
||||
for i, lengthStr := range in.Lengths {
|
||||
lengthM, _ := strconv.ParseFloat(lengthStr, 64)
|
||||
totalLengthM += lengthM
|
||||
bolts = append(bolts, &model.InvProductBolt{
|
||||
BoltId: uid.Generate(),
|
||||
PanId: in.PanId,
|
||||
LengthM: lengthM,
|
||||
SortOrder: int64(i + 1),
|
||||
})
|
||||
}
|
||||
|
||||
if err := l.svcCtx.BoltModel.BulkReplace(l.ctx, in.PanId, tenantId, bolts); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
metrics.InboundBoltsTotal.WithLabelValues(tenantId, "save_bolts").Add(float64(len(in.Lengths)))
|
||||
if totalLengthM > 0 {
|
||||
metrics.InboundLengthMetersTotal.WithLabelValues(tenantId, "", "", "save_bolts").Add(totalLengthM)
|
||||
}
|
||||
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
105
rpc/inventory/internal/logic/savepanslogic.go
Normal file
105
rpc/inventory/internal/logic/savepanslogic.go
Normal file
@ -0,0 +1,105 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
"muyu-apiserver/rpc/inventory/pb"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type SavePansLogic struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func NewSavePansLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SavePansLogic {
|
||||
return &SavePansLogic{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *SavePansLogic) SavePans(in *pb.SavePansReq) (*pb.Empty, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
|
||||
if err := l.svcCtx.BoltModel.DeleteByProductId(l.ctx, in.ProductId); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
var totalLengthM float64
|
||||
var totalBolts int
|
||||
|
||||
pans := make([]*model.InvProductPan, 0, len(in.Pans))
|
||||
for i, panInput := range in.Pans {
|
||||
panId := uid.Generate()
|
||||
pans = append(pans, &model.InvProductPan{
|
||||
PanId: panId,
|
||||
ProductId: in.ProductId,
|
||||
Name: panInput.Name,
|
||||
Position: panInput.Position,
|
||||
SortOrder: int64(i + 1),
|
||||
TenantId: tenantId,
|
||||
})
|
||||
|
||||
if len(panInput.BoltLengths) > 0 {
|
||||
bolts := make([]*model.InvProductBolt, 0, len(panInput.BoltLengths))
|
||||
for j, lengthStr := range panInput.BoltLengths {
|
||||
lengthM, _ := strconv.ParseFloat(lengthStr, 64)
|
||||
totalLengthM += lengthM
|
||||
bolts = append(bolts, &model.InvProductBolt{
|
||||
BoltId: uid.Generate(),
|
||||
PanId: panId,
|
||||
LengthM: lengthM,
|
||||
SortOrder: int64(j + 1),
|
||||
})
|
||||
}
|
||||
totalBolts += len(panInput.BoltLengths)
|
||||
if err := l.svcCtx.BoltModel.BulkReplace(l.ctx, panId, tenantId, bolts); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := l.svcCtx.PanModel.BulkReplace(l.ctx, in.ProductId, tenantId, pans); err != nil {
|
||||
return nil, status.Error(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
metrics.PansSavedTotal.WithLabelValues(tenantId, in.ProductId).Inc()
|
||||
if totalLengthM > 0 {
|
||||
productName := l.resolveProductName(in.ProductId)
|
||||
color := l.resolveProductColor(in.ProductId)
|
||||
metrics.InboundLengthMetersTotal.WithLabelValues(tenantId, productName, color, "save_pans").Add(totalLengthM)
|
||||
}
|
||||
if totalBolts > 0 {
|
||||
metrics.InboundBoltsTotal.WithLabelValues(tenantId, "save_pans").Add(float64(totalBolts))
|
||||
}
|
||||
|
||||
return &pb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (l *SavePansLogic) resolveProductName(productId string) string {
|
||||
p, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, productId)
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
return p.ProductName
|
||||
}
|
||||
|
||||
func (l *SavePansLogic) resolveProductColor(productId string) string {
|
||||
p, err := l.svcCtx.ProductModel.FindOneByProductId(l.ctx, productId)
|
||||
if err != nil {
|
||||
return "unknown"
|
||||
}
|
||||
return p.Color
|
||||
}
|
||||
@ -33,19 +33,12 @@ func (l *UpdateProductLogic) UpdateProduct(in *pb.UpdateProductReq) (*pb.Empty,
|
||||
return nil, status.Error(codes.NotFound, "product not found")
|
||||
}
|
||||
|
||||
stockQuantity, _ := strconv.ParseFloat(in.StockQuantity, 64)
|
||||
costPrice, _ := strconv.ParseFloat(in.CostPrice, 64)
|
||||
salesPrice, _ := strconv.ParseFloat(in.SalesPrice, 64)
|
||||
|
||||
product.ProductName = in.ProductName
|
||||
product.ImageUrl = in.ImageUrl
|
||||
product.Spec = in.Spec
|
||||
product.Color = in.Color
|
||||
product.UnitPieces = in.UnitPieces
|
||||
product.UnitRolls = in.UnitRolls
|
||||
product.StockQuantity = stockQuantity
|
||||
product.Location = in.Location
|
||||
product.CostPrice = costPrice
|
||||
product.SalesPrice = salesPrice
|
||||
product.Remark = sql.NullString{String: in.Remark, Valid: in.Remark != ""}
|
||||
|
||||
|
||||
@ -29,6 +29,18 @@ func NewUpdateStockCheckLogic(ctx context.Context, svcCtx *svc.ServiceContext) *
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateStockCheckLogic) systemQty(productId string) float64 {
|
||||
bolts, err := l.svcCtx.BoltModel.FindByProductId(l.ctx, productId)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
var total float64
|
||||
for _, b := range bolts {
|
||||
total += b.LengthM
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func (l *UpdateStockCheckLogic) UpdateStockCheck(in *pb.UpdateStockCheckReq) (*pb.Empty, error) {
|
||||
check, err := l.svcCtx.StockCheckModel.FindOneByCheckId(l.ctx, in.CheckId)
|
||||
if err != nil {
|
||||
@ -59,15 +71,16 @@ func (l *UpdateStockCheckLogic) UpdateStockCheck(in *pb.UpdateStockCheckReq) (*p
|
||||
return nil, status.Errorf(codes.NotFound, "product %s not found", d.ProductId)
|
||||
}
|
||||
|
||||
sysQty := l.systemQty(d.ProductId)
|
||||
actualQty, _ := strconv.ParseFloat(d.ActualQuantity, 64)
|
||||
diffQty := actualQty - product.StockQuantity
|
||||
diffAmount := diffQty * product.CostPrice
|
||||
diffQty := actualQty - sysQty
|
||||
diffAmount := diffQty * product.SalesPrice
|
||||
|
||||
details = append(details, &model.InvStockCheckDetail{
|
||||
DetailId: uid.Generate(),
|
||||
CheckId: in.CheckId,
|
||||
ProductId: d.ProductId,
|
||||
SystemQuantity: product.StockQuantity,
|
||||
SystemQuantity: sysQty,
|
||||
ActualQuantity: actualQty,
|
||||
DiffQuantity: diffQty,
|
||||
DiffAmount: diffAmount,
|
||||
|
||||
@ -23,7 +23,7 @@ func NewInventoryServiceServer(svcCtx *svc.ServiceContext) *InventoryServiceServ
|
||||
}
|
||||
}
|
||||
|
||||
// Product
|
||||
// Product CRUD
|
||||
func (s *InventoryServiceServer) CreateProduct(ctx context.Context, in *pb.CreateProductReq) (*pb.IdResp, error) {
|
||||
l := logic.NewCreateProductLogic(ctx, s.svcCtx)
|
||||
return l.CreateProduct(in)
|
||||
@ -49,6 +49,57 @@ func (s *InventoryServiceServer) ListProduct(ctx context.Context, in *pb.ListPro
|
||||
return l.ListProduct(in)
|
||||
}
|
||||
|
||||
// Product Tree (panel 3)
|
||||
func (s *InventoryServiceServer) GetProductTree(ctx context.Context, in *pb.GetProductReq) (*pb.ProductTreeResp, error) {
|
||||
l := logic.NewGetProductTreeLogic(ctx, s.svcCtx)
|
||||
return l.GetProductTree(in)
|
||||
}
|
||||
|
||||
// Product Summary (panel 1)
|
||||
func (s *InventoryServiceServer) ListProductSummary(ctx context.Context, in *pb.ListProductSummaryReq) (*pb.ListProductSummaryResp, error) {
|
||||
l := logic.NewListProductSummaryLogic(ctx, s.svcCtx)
|
||||
return l.ListProductSummary(in)
|
||||
}
|
||||
|
||||
// Color Detail (panel 2)
|
||||
func (s *InventoryServiceServer) ListColorDetail(ctx context.Context, in *pb.ListColorDetailReq) (*pb.ListColorDetailResp, error) {
|
||||
l := logic.NewListColorDetailLogic(ctx, s.svcCtx)
|
||||
return l.ListColorDetail(in)
|
||||
}
|
||||
|
||||
// Pan / Bolt list views
|
||||
func (s *InventoryServiceServer) ListPanView(ctx context.Context, in *pb.ListPanViewReq) (*pb.ListPanViewResp, error) {
|
||||
l := logic.NewListPanViewLogic(ctx, s.svcCtx)
|
||||
return l.ListPanView(in)
|
||||
}
|
||||
|
||||
func (s *InventoryServiceServer) ListBoltView(ctx context.Context, in *pb.ListBoltViewReq) (*pb.ListBoltViewResp, error) {
|
||||
l := logic.NewListBoltViewLogic(ctx, s.svcCtx)
|
||||
return l.ListBoltView(in)
|
||||
}
|
||||
|
||||
// Pan CRUD
|
||||
func (s *InventoryServiceServer) ListPans(ctx context.Context, in *pb.ListPanReq) (*pb.ListPanResp, error) {
|
||||
l := logic.NewListPansLogic(ctx, s.svcCtx)
|
||||
return l.ListPans(in)
|
||||
}
|
||||
|
||||
func (s *InventoryServiceServer) SavePans(ctx context.Context, in *pb.SavePansReq) (*pb.Empty, error) {
|
||||
l := logic.NewSavePansLogic(ctx, s.svcCtx)
|
||||
return l.SavePans(in)
|
||||
}
|
||||
|
||||
// Bolt CRUD
|
||||
func (s *InventoryServiceServer) ListBolts(ctx context.Context, in *pb.ListBoltReq) (*pb.ListBoltResp, error) {
|
||||
l := logic.NewListBoltsLogic(ctx, s.svcCtx)
|
||||
return l.ListBolts(in)
|
||||
}
|
||||
|
||||
func (s *InventoryServiceServer) SaveBolts(ctx context.Context, in *pb.SaveBoltsReq) (*pb.Empty, error) {
|
||||
l := logic.NewSaveBoltsLogic(ctx, s.svcCtx)
|
||||
return l.SaveBolts(in)
|
||||
}
|
||||
|
||||
// Import
|
||||
func (s *InventoryServiceServer) ImportProducts(ctx context.Context, in *pb.ImportProductReq) (*pb.ImportProductResp, error) {
|
||||
l := logic.NewImportProductsLogic(ctx, s.svcCtx)
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
type ServiceContext struct {
|
||||
Config config.Config
|
||||
ProductModel model.InvProductModel
|
||||
PanModel model.InvProductPanModel
|
||||
BoltModel model.InvProductBoltModel
|
||||
ImportLogModel model.InvStockImportLogModel
|
||||
StockCheckModel model.InvStockCheckModel
|
||||
CheckDetailModel model.InvStockCheckDetailModel
|
||||
@ -22,6 +24,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
return &ServiceContext{
|
||||
Config: c,
|
||||
ProductModel: model.NewInvProductModel(conn, c.Cache),
|
||||
PanModel: model.NewInvProductPanModel(conn),
|
||||
BoltModel: model.NewInvProductBoltModel(conn),
|
||||
ImportLogModel: model.NewInvStockImportLogModel(conn, c.Cache),
|
||||
StockCheckModel: model.NewInvStockCheckModel(conn, c.Cache),
|
||||
CheckDetailModel: model.NewInvStockCheckDetailModel(conn, c.Cache),
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"muyu-apiserver/pkg/metrics"
|
||||
"muyu-apiserver/rpc/inventory/internal/config"
|
||||
"muyu-apiserver/rpc/inventory/internal/server"
|
||||
"muyu-apiserver/rpc/inventory/internal/svc"
|
||||
@ -25,6 +26,8 @@ func main() {
|
||||
conf.MustLoad(*configFile, &c)
|
||||
ctx := svc.NewServiceContext(c)
|
||||
|
||||
metrics.StartHTTP(c.PrometheusAddr)
|
||||
|
||||
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
||||
pb.RegisterInventoryServiceServer(grpcServer, server.NewInventoryServiceServer(ctx))
|
||||
|
||||
@ -32,6 +35,7 @@ func main() {
|
||||
reflection.Register(grpcServer)
|
||||
}
|
||||
})
|
||||
s.AddUnaryInterceptors(metrics.UnaryServerInterceptor())
|
||||
defer s.Stop()
|
||||
|
||||
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
||||
|
||||
@ -12,16 +12,11 @@ message ProductInfo {
|
||||
string image_url = 3;
|
||||
string spec = 4;
|
||||
string color = 5;
|
||||
int64 unit_pieces = 6;
|
||||
int64 unit_rolls = 7;
|
||||
string stock_quantity = 8;
|
||||
string location = 9;
|
||||
string cost_price = 10;
|
||||
string sales_price = 11;
|
||||
string remark = 12;
|
||||
int64 status = 13;
|
||||
string created_at = 14;
|
||||
string updated_at = 15;
|
||||
string sales_price = 6;
|
||||
string remark = 7;
|
||||
int64 status = 8;
|
||||
string created_at = 9;
|
||||
string updated_at = 10;
|
||||
}
|
||||
|
||||
message CreateProductReq {
|
||||
@ -29,13 +24,9 @@ message CreateProductReq {
|
||||
string image_url = 2;
|
||||
string spec = 3;
|
||||
string color = 4;
|
||||
int64 unit_pieces = 5;
|
||||
int64 unit_rolls = 6;
|
||||
string stock_quantity = 7;
|
||||
string location = 8;
|
||||
string cost_price = 9;
|
||||
string sales_price = 10;
|
||||
string remark = 11;
|
||||
string sales_price = 5;
|
||||
string remark = 6;
|
||||
repeated PanInput pans = 7;
|
||||
}
|
||||
|
||||
message UpdateProductReq {
|
||||
@ -44,13 +35,8 @@ message UpdateProductReq {
|
||||
string image_url = 3;
|
||||
string spec = 4;
|
||||
string color = 5;
|
||||
int64 unit_pieces = 6;
|
||||
int64 unit_rolls = 7;
|
||||
string stock_quantity = 8;
|
||||
string location = 9;
|
||||
string cost_price = 10;
|
||||
string sales_price = 11;
|
||||
string remark = 12;
|
||||
string sales_price = 6;
|
||||
string remark = 7;
|
||||
}
|
||||
|
||||
message DeleteProductReq {
|
||||
@ -67,8 +53,7 @@ message ListProductReq {
|
||||
string product_name = 3;
|
||||
string spec = 4;
|
||||
string color = 5;
|
||||
string location = 6;
|
||||
int64 status = 7;
|
||||
int64 status = 6;
|
||||
}
|
||||
|
||||
message ListProductResp {
|
||||
@ -76,6 +61,161 @@ message ListProductResp {
|
||||
repeated ProductInfo list = 2;
|
||||
}
|
||||
|
||||
// ==================== Pan (盘) ====================
|
||||
|
||||
message PanInfo {
|
||||
string pan_id = 1;
|
||||
string product_id = 2;
|
||||
string name = 3;
|
||||
string position = 4;
|
||||
int64 sort_order = 5;
|
||||
repeated BoltInfo bolts = 6;
|
||||
int64 bolt_count = 7;
|
||||
string total_length = 8;
|
||||
}
|
||||
|
||||
message PanInput {
|
||||
string name = 1;
|
||||
string position = 2;
|
||||
repeated string bolt_lengths = 3;
|
||||
}
|
||||
|
||||
message ListPanReq {
|
||||
string product_id = 1;
|
||||
}
|
||||
|
||||
message ListPanResp {
|
||||
repeated PanInfo list = 1;
|
||||
}
|
||||
|
||||
message SavePansReq {
|
||||
string product_id = 1;
|
||||
repeated PanInput pans = 2;
|
||||
}
|
||||
|
||||
// ==================== Bolt (匹) ====================
|
||||
|
||||
message BoltInfo {
|
||||
string bolt_id = 1;
|
||||
string pan_id = 2;
|
||||
string length_m = 3;
|
||||
int64 sort_order = 4;
|
||||
}
|
||||
|
||||
message ListBoltReq {
|
||||
string pan_id = 1;
|
||||
}
|
||||
|
||||
message ListBoltResp {
|
||||
repeated BoltInfo list = 1;
|
||||
}
|
||||
|
||||
message SaveBoltsReq {
|
||||
string pan_id = 1;
|
||||
repeated string lengths = 2;
|
||||
}
|
||||
|
||||
// ==================== Product Tree (三层详情) ====================
|
||||
|
||||
message ProductTreeResp {
|
||||
ProductInfo product = 1;
|
||||
repeated PanInfo pans = 2;
|
||||
int64 total_pan_count = 3;
|
||||
int64 total_bolt_count = 4;
|
||||
string total_length_m = 5;
|
||||
}
|
||||
|
||||
// ==================== Panel 1: Product Summary ====================
|
||||
|
||||
message ProductSummaryItem {
|
||||
string product_name = 1;
|
||||
string spec = 2;
|
||||
int64 color_count = 3;
|
||||
int64 total_pan_count = 4;
|
||||
int64 total_bolt_count = 5;
|
||||
string total_length_m = 6;
|
||||
string colors = 7;
|
||||
string locations = 8;
|
||||
}
|
||||
|
||||
message ListProductSummaryReq {}
|
||||
|
||||
message ListProductSummaryResp {
|
||||
repeated ProductSummaryItem list = 1;
|
||||
}
|
||||
|
||||
// ==================== Panel 2: Color Detail ====================
|
||||
|
||||
message ColorDetailItem {
|
||||
string product_id = 1;
|
||||
string product_name = 2;
|
||||
string color = 3;
|
||||
string spec = 4;
|
||||
string image_url = 5;
|
||||
int64 pan_count = 6;
|
||||
int64 bolt_count = 7;
|
||||
string total_length_m = 8;
|
||||
string locations = 9;
|
||||
string sales_price = 10;
|
||||
}
|
||||
|
||||
message ListColorDetailReq {
|
||||
string product_name = 1;
|
||||
}
|
||||
|
||||
message ListColorDetailResp {
|
||||
repeated ColorDetailItem list = 1;
|
||||
}
|
||||
|
||||
// ==================== Pan / Bolt List View ====================
|
||||
|
||||
message PanListItem {
|
||||
string pan_id = 1;
|
||||
string product_id = 2;
|
||||
string name = 3;
|
||||
string position = 4;
|
||||
string product_name = 5;
|
||||
string colors = 6; // aggregated from bolt.color, no spec
|
||||
int64 bolt_count = 7;
|
||||
string total_length_m = 8;
|
||||
}
|
||||
|
||||
message ListPanViewReq {
|
||||
int64 page = 1;
|
||||
int64 page_size = 2;
|
||||
string product_name = 3;
|
||||
string position = 4;
|
||||
}
|
||||
|
||||
message ListPanViewResp {
|
||||
int64 total = 1;
|
||||
repeated PanListItem list = 2;
|
||||
}
|
||||
|
||||
message BoltListItem {
|
||||
string bolt_id = 1;
|
||||
string pan_id = 2;
|
||||
string length_m = 3;
|
||||
string color = 4; // bolt's own color, no spec
|
||||
int64 sort_order = 5;
|
||||
string pan_name = 6;
|
||||
string position = 7;
|
||||
string product_id = 8;
|
||||
string product_name = 9;
|
||||
}
|
||||
|
||||
message ListBoltViewReq {
|
||||
int64 page = 1;
|
||||
int64 page_size = 2;
|
||||
string product_name = 3;
|
||||
string position = 4;
|
||||
}
|
||||
|
||||
message ListBoltViewResp {
|
||||
int64 total = 1;
|
||||
repeated BoltListItem list = 2;
|
||||
}
|
||||
|
||||
// ==================== Stock Import ====================
|
||||
|
||||
message ImportProductReq {
|
||||
@ -120,8 +260,8 @@ message StockSummaryReq {}
|
||||
message StockSummaryResp {
|
||||
int64 product_count = 1;
|
||||
int64 total_pieces = 2;
|
||||
int64 total_rolls = 3;
|
||||
string total_cost_value = 4;
|
||||
int64 total_pans = 3;
|
||||
string total_length_m = 4;
|
||||
string total_sales_value = 5;
|
||||
}
|
||||
|
||||
@ -284,13 +424,34 @@ message Empty {}
|
||||
// ==================== Service ====================
|
||||
|
||||
service InventoryService {
|
||||
// Product
|
||||
// Product CRUD
|
||||
rpc CreateProduct(CreateProductReq) returns (IdResp);
|
||||
rpc UpdateProduct(UpdateProductReq) returns (Empty);
|
||||
rpc DeleteProduct(DeleteProductReq) returns (Empty);
|
||||
rpc GetProduct(GetProductReq) returns (ProductInfo);
|
||||
rpc ListProduct(ListProductReq) returns (ListProductResp);
|
||||
|
||||
// Product Tree (panel 3)
|
||||
rpc GetProductTree(GetProductReq) returns (ProductTreeResp);
|
||||
|
||||
// Product Summary (panel 1)
|
||||
rpc ListProductSummary(ListProductSummaryReq) returns (ListProductSummaryResp);
|
||||
|
||||
// Color Detail (panel 2)
|
||||
rpc ListColorDetail(ListColorDetailReq) returns (ListColorDetailResp);
|
||||
|
||||
// Pan / Bolt list views (dimension panels)
|
||||
rpc ListPanView(ListPanViewReq) returns (ListPanViewResp);
|
||||
rpc ListBoltView(ListBoltViewReq) returns (ListBoltViewResp);
|
||||
|
||||
// Pan CRUD
|
||||
rpc ListPans(ListPanReq) returns (ListPanResp);
|
||||
rpc SavePans(SavePansReq) returns (Empty);
|
||||
|
||||
// Bolt CRUD
|
||||
rpc ListBolts(ListBoltReq) returns (ListBoltResp);
|
||||
rpc SaveBolts(SaveBoltsReq) returns (Empty);
|
||||
|
||||
// Import
|
||||
rpc ImportProducts(ImportProductReq) returns (ImportProductResp);
|
||||
rpc ListImportLog(ListImportLogReq) returns (ListImportLogResp);
|
||||
|
||||
@ -14,50 +14,87 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
ApproveStockAdjustReq = pb.ApproveStockAdjustReq
|
||||
ConfirmStockCheckReq = pb.ConfirmStockCheckReq
|
||||
CreateProductReq = pb.CreateProductReq
|
||||
CreateStockAdjustReq = pb.CreateStockAdjustReq
|
||||
CreateStockCheckReq = pb.CreateStockCheckReq
|
||||
DeleteProductReq = pb.DeleteProductReq
|
||||
Empty = pb.Empty
|
||||
GetProductReq = pb.GetProductReq
|
||||
GetStockAdjustReq = pb.GetStockAdjustReq
|
||||
GetStockCheckReq = pb.GetStockCheckReq
|
||||
IdResp = pb.IdResp
|
||||
ImportLogInfo = pb.ImportLogInfo
|
||||
ImportProductReq = pb.ImportProductReq
|
||||
ImportProductResp = pb.ImportProductResp
|
||||
ListImportLogReq = pb.ListImportLogReq
|
||||
ListImportLogResp = pb.ListImportLogResp
|
||||
ListProductReq = pb.ListProductReq
|
||||
ListProductResp = pb.ListProductResp
|
||||
ListStockAdjustReq = pb.ListStockAdjustReq
|
||||
ListStockAdjustResp = pb.ListStockAdjustResp
|
||||
ListStockCheckReq = pb.ListStockCheckReq
|
||||
ListStockCheckResp = pb.ListStockCheckResp
|
||||
ProductInfo = pb.ProductInfo
|
||||
StockAdjustDetailInfo = pb.StockAdjustDetailInfo
|
||||
StockAdjustDetailReq = pb.StockAdjustDetailReq
|
||||
StockAdjustInfo = pb.StockAdjustInfo
|
||||
StockCheckDetailInfo = pb.StockCheckDetailInfo
|
||||
StockCheckDetailReq = pb.StockCheckDetailReq
|
||||
StockCheckInfo = pb.StockCheckInfo
|
||||
StockGroupItem = pb.StockGroupItem
|
||||
StockGroupReq = pb.StockGroupReq
|
||||
StockGroupResp = pb.StockGroupResp
|
||||
StockSummaryReq = pb.StockSummaryReq
|
||||
StockSummaryResp = pb.StockSummaryResp
|
||||
UpdateProductReq = pb.UpdateProductReq
|
||||
UpdateStockCheckReq = pb.UpdateStockCheckReq
|
||||
ApproveStockAdjustReq = pb.ApproveStockAdjustReq
|
||||
BoltListItem = pb.BoltListItem
|
||||
BoltInfo = pb.BoltInfo
|
||||
ColorDetailItem = pb.ColorDetailItem
|
||||
ConfirmStockCheckReq = pb.ConfirmStockCheckReq
|
||||
CreateProductReq = pb.CreateProductReq
|
||||
CreateStockAdjustReq = pb.CreateStockAdjustReq
|
||||
CreateStockCheckReq = pb.CreateStockCheckReq
|
||||
DeleteProductReq = pb.DeleteProductReq
|
||||
Empty = pb.Empty
|
||||
GetProductReq = pb.GetProductReq
|
||||
GetStockAdjustReq = pb.GetStockAdjustReq
|
||||
GetStockCheckReq = pb.GetStockCheckReq
|
||||
IdResp = pb.IdResp
|
||||
ImportLogInfo = pb.ImportLogInfo
|
||||
ImportProductReq = pb.ImportProductReq
|
||||
ImportProductResp = pb.ImportProductResp
|
||||
ListBoltReq = pb.ListBoltReq
|
||||
ListBoltResp = pb.ListBoltResp
|
||||
ListBoltViewReq = pb.ListBoltViewReq
|
||||
ListBoltViewResp = pb.ListBoltViewResp
|
||||
ListColorDetailReq = pb.ListColorDetailReq
|
||||
ListPanViewReq = pb.ListPanViewReq
|
||||
ListPanViewResp = pb.ListPanViewResp
|
||||
PanListItem = pb.PanListItem
|
||||
ListColorDetailResp = pb.ListColorDetailResp
|
||||
ListImportLogReq = pb.ListImportLogReq
|
||||
ListImportLogResp = pb.ListImportLogResp
|
||||
ListPanReq = pb.ListPanReq
|
||||
ListPanResp = pb.ListPanResp
|
||||
ListProductReq = pb.ListProductReq
|
||||
ListProductResp = pb.ListProductResp
|
||||
ListProductSummaryReq = pb.ListProductSummaryReq
|
||||
ListProductSummaryResp = pb.ListProductSummaryResp
|
||||
ListStockAdjustReq = pb.ListStockAdjustReq
|
||||
ListStockAdjustResp = pb.ListStockAdjustResp
|
||||
ListStockCheckReq = pb.ListStockCheckReq
|
||||
ListStockCheckResp = pb.ListStockCheckResp
|
||||
PanInfo = pb.PanInfo
|
||||
PanInput = pb.PanInput
|
||||
ProductInfo = pb.ProductInfo
|
||||
ProductSummaryItem = pb.ProductSummaryItem
|
||||
ProductTreeResp = pb.ProductTreeResp
|
||||
SaveBoltsReq = pb.SaveBoltsReq
|
||||
SavePansReq = pb.SavePansReq
|
||||
StockAdjustDetailInfo = pb.StockAdjustDetailInfo
|
||||
StockAdjustDetailReq = pb.StockAdjustDetailReq
|
||||
StockAdjustInfo = pb.StockAdjustInfo
|
||||
StockCheckDetailInfo = pb.StockCheckDetailInfo
|
||||
StockCheckDetailReq = pb.StockCheckDetailReq
|
||||
StockCheckInfo = pb.StockCheckInfo
|
||||
StockGroupItem = pb.StockGroupItem
|
||||
StockGroupReq = pb.StockGroupReq
|
||||
StockGroupResp = pb.StockGroupResp
|
||||
StockSummaryReq = pb.StockSummaryReq
|
||||
StockSummaryResp = pb.StockSummaryResp
|
||||
UpdateProductReq = pb.UpdateProductReq
|
||||
UpdateStockCheckReq = pb.UpdateStockCheckReq
|
||||
|
||||
InventoryService interface {
|
||||
// Product
|
||||
// Product CRUD
|
||||
CreateProduct(ctx context.Context, in *CreateProductReq, opts ...grpc.CallOption) (*IdResp, error)
|
||||
UpdateProduct(ctx context.Context, in *UpdateProductReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
DeleteProduct(ctx context.Context, in *DeleteProductReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
GetProduct(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductInfo, error)
|
||||
ListProduct(ctx context.Context, in *ListProductReq, opts ...grpc.CallOption) (*ListProductResp, error)
|
||||
// Product Tree (panel 3)
|
||||
GetProductTree(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductTreeResp, error)
|
||||
// Product Summary (panel 1)
|
||||
ListProductSummary(ctx context.Context, in *ListProductSummaryReq, opts ...grpc.CallOption) (*ListProductSummaryResp, error)
|
||||
// Color Detail (panel 2)
|
||||
ListColorDetail(ctx context.Context, in *ListColorDetailReq, opts ...grpc.CallOption) (*ListColorDetailResp, error)
|
||||
// Pan / Bolt list views
|
||||
ListPanView(ctx context.Context, in *ListPanViewReq, opts ...grpc.CallOption) (*ListPanViewResp, error)
|
||||
ListBoltView(ctx context.Context, in *ListBoltViewReq, opts ...grpc.CallOption) (*ListBoltViewResp, error)
|
||||
// Pan CRUD
|
||||
ListPans(ctx context.Context, in *ListPanReq, opts ...grpc.CallOption) (*ListPanResp, error)
|
||||
SavePans(ctx context.Context, in *SavePansReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
// Bolt CRUD
|
||||
ListBolts(ctx context.Context, in *ListBoltReq, opts ...grpc.CallOption) (*ListBoltResp, error)
|
||||
SaveBolts(ctx context.Context, in *SaveBoltsReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
// Import
|
||||
ImportProducts(ctx context.Context, in *ImportProductReq, opts ...grpc.CallOption) (*ImportProductResp, error)
|
||||
ListImportLog(ctx context.Context, in *ListImportLogReq, opts ...grpc.CallOption) (*ListImportLogResp, error)
|
||||
@ -88,7 +125,7 @@ func NewInventoryService(cli zrpc.Client) InventoryService {
|
||||
}
|
||||
}
|
||||
|
||||
// Product
|
||||
// Product CRUD
|
||||
func (m *defaultInventoryService) CreateProduct(ctx context.Context, in *CreateProductReq, opts ...grpc.CallOption) (*IdResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.CreateProduct(ctx, in, opts...)
|
||||
@ -114,6 +151,51 @@ func (m *defaultInventoryService) ListProduct(ctx context.Context, in *ListProdu
|
||||
return client.ListProduct(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) GetProductTree(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductTreeResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.GetProductTree(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) ListProductSummary(ctx context.Context, in *ListProductSummaryReq, opts ...grpc.CallOption) (*ListProductSummaryResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.ListProductSummary(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) ListColorDetail(ctx context.Context, in *ListColorDetailReq, opts ...grpc.CallOption) (*ListColorDetailResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.ListColorDetail(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) ListPanView(ctx context.Context, in *ListPanViewReq, opts ...grpc.CallOption) (*ListPanViewResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.ListPanView(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) ListBoltView(ctx context.Context, in *ListBoltViewReq, opts ...grpc.CallOption) (*ListBoltViewResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.ListBoltView(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) ListPans(ctx context.Context, in *ListPanReq, opts ...grpc.CallOption) (*ListPanResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.ListPans(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) SavePans(ctx context.Context, in *SavePansReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.SavePans(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) ListBolts(ctx context.Context, in *ListBoltReq, opts ...grpc.CallOption) (*ListBoltResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.ListBolts(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (m *defaultInventoryService) SaveBolts(ctx context.Context, in *SaveBoltsReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
return client.SaveBolts(ctx, in, opts...)
|
||||
}
|
||||
|
||||
// Import
|
||||
func (m *defaultInventoryService) ImportProducts(ctx context.Context, in *ImportProductReq, opts ...grpc.CallOption) (*ImportProductResp, error) {
|
||||
client := pb.NewInventoryServiceClient(m.cli.Conn())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.20.3
|
||||
// source: rpc/inventory/inventory.proto
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.29.3
|
||||
// source: inventory.proto
|
||||
|
||||
package pb
|
||||
|
||||
@ -15,19 +15,64 @@ import (
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
InventoryService_CreateProduct_FullMethodName = "/inventory.InventoryService/CreateProduct"
|
||||
InventoryService_UpdateProduct_FullMethodName = "/inventory.InventoryService/UpdateProduct"
|
||||
InventoryService_DeleteProduct_FullMethodName = "/inventory.InventoryService/DeleteProduct"
|
||||
InventoryService_GetProduct_FullMethodName = "/inventory.InventoryService/GetProduct"
|
||||
InventoryService_ListProduct_FullMethodName = "/inventory.InventoryService/ListProduct"
|
||||
InventoryService_GetProductTree_FullMethodName = "/inventory.InventoryService/GetProductTree"
|
||||
InventoryService_ListProductSummary_FullMethodName = "/inventory.InventoryService/ListProductSummary"
|
||||
InventoryService_ListColorDetail_FullMethodName = "/inventory.InventoryService/ListColorDetail"
|
||||
InventoryService_ListPanView_FullMethodName = "/inventory.InventoryService/ListPanView"
|
||||
InventoryService_ListBoltView_FullMethodName = "/inventory.InventoryService/ListBoltView"
|
||||
InventoryService_ListPans_FullMethodName = "/inventory.InventoryService/ListPans"
|
||||
InventoryService_SavePans_FullMethodName = "/inventory.InventoryService/SavePans"
|
||||
InventoryService_ListBolts_FullMethodName = "/inventory.InventoryService/ListBolts"
|
||||
InventoryService_SaveBolts_FullMethodName = "/inventory.InventoryService/SaveBolts"
|
||||
InventoryService_ImportProducts_FullMethodName = "/inventory.InventoryService/ImportProducts"
|
||||
InventoryService_ListImportLog_FullMethodName = "/inventory.InventoryService/ListImportLog"
|
||||
InventoryService_GetStockSummary_FullMethodName = "/inventory.InventoryService/GetStockSummary"
|
||||
InventoryService_GetStockGroup_FullMethodName = "/inventory.InventoryService/GetStockGroup"
|
||||
InventoryService_CreateStockCheck_FullMethodName = "/inventory.InventoryService/CreateStockCheck"
|
||||
InventoryService_UpdateStockCheck_FullMethodName = "/inventory.InventoryService/UpdateStockCheck"
|
||||
InventoryService_ConfirmStockCheck_FullMethodName = "/inventory.InventoryService/ConfirmStockCheck"
|
||||
InventoryService_GetStockCheck_FullMethodName = "/inventory.InventoryService/GetStockCheck"
|
||||
InventoryService_ListStockCheck_FullMethodName = "/inventory.InventoryService/ListStockCheck"
|
||||
InventoryService_CreateStockAdjust_FullMethodName = "/inventory.InventoryService/CreateStockAdjust"
|
||||
InventoryService_ApproveStockAdjust_FullMethodName = "/inventory.InventoryService/ApproveStockAdjust"
|
||||
InventoryService_GetStockAdjust_FullMethodName = "/inventory.InventoryService/GetStockAdjust"
|
||||
InventoryService_ListStockAdjust_FullMethodName = "/inventory.InventoryService/ListStockAdjust"
|
||||
)
|
||||
|
||||
// InventoryServiceClient is the client API for InventoryService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type InventoryServiceClient interface {
|
||||
// Product
|
||||
// Product CRUD
|
||||
CreateProduct(ctx context.Context, in *CreateProductReq, opts ...grpc.CallOption) (*IdResp, error)
|
||||
UpdateProduct(ctx context.Context, in *UpdateProductReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
DeleteProduct(ctx context.Context, in *DeleteProductReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
GetProduct(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductInfo, error)
|
||||
ListProduct(ctx context.Context, in *ListProductReq, opts ...grpc.CallOption) (*ListProductResp, error)
|
||||
// Product Tree (panel 3)
|
||||
GetProductTree(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductTreeResp, error)
|
||||
// Product Summary (panel 1)
|
||||
ListProductSummary(ctx context.Context, in *ListProductSummaryReq, opts ...grpc.CallOption) (*ListProductSummaryResp, error)
|
||||
// Color Detail (panel 2)
|
||||
ListColorDetail(ctx context.Context, in *ListColorDetailReq, opts ...grpc.CallOption) (*ListColorDetailResp, error)
|
||||
// Pan / Bolt list views (dimension panels)
|
||||
ListPanView(ctx context.Context, in *ListPanViewReq, opts ...grpc.CallOption) (*ListPanViewResp, error)
|
||||
ListBoltView(ctx context.Context, in *ListBoltViewReq, opts ...grpc.CallOption) (*ListBoltViewResp, error)
|
||||
// Pan CRUD
|
||||
ListPans(ctx context.Context, in *ListPanReq, opts ...grpc.CallOption) (*ListPanResp, error)
|
||||
SavePans(ctx context.Context, in *SavePansReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
// Bolt CRUD
|
||||
ListBolts(ctx context.Context, in *ListBoltReq, opts ...grpc.CallOption) (*ListBoltResp, error)
|
||||
SaveBolts(ctx context.Context, in *SaveBoltsReq, opts ...grpc.CallOption) (*Empty, error)
|
||||
// Import
|
||||
ImportProducts(ctx context.Context, in *ImportProductReq, opts ...grpc.CallOption) (*ImportProductResp, error)
|
||||
ListImportLog(ctx context.Context, in *ListImportLogReq, opts ...grpc.CallOption) (*ListImportLogResp, error)
|
||||
@ -56,8 +101,9 @@ func NewInventoryServiceClient(cc grpc.ClientConnInterface) InventoryServiceClie
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) CreateProduct(ctx context.Context, in *CreateProductReq, opts ...grpc.CallOption) (*IdResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(IdResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/CreateProduct", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_CreateProduct_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -65,8 +111,9 @@ func (c *inventoryServiceClient) CreateProduct(ctx context.Context, in *CreatePr
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) UpdateProduct(ctx context.Context, in *UpdateProductReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/UpdateProduct", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_UpdateProduct_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -74,8 +121,9 @@ func (c *inventoryServiceClient) UpdateProduct(ctx context.Context, in *UpdatePr
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) DeleteProduct(ctx context.Context, in *DeleteProductReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/DeleteProduct", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_DeleteProduct_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -83,8 +131,9 @@ func (c *inventoryServiceClient) DeleteProduct(ctx context.Context, in *DeletePr
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) GetProduct(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductInfo, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ProductInfo)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/GetProduct", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_GetProduct_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -92,8 +141,99 @@ func (c *inventoryServiceClient) GetProduct(ctx context.Context, in *GetProductR
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListProduct(ctx context.Context, in *ListProductReq, opts ...grpc.CallOption) (*ListProductResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListProductResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ListProduct", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListProduct_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) GetProductTree(ctx context.Context, in *GetProductReq, opts ...grpc.CallOption) (*ProductTreeResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ProductTreeResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_GetProductTree_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListProductSummary(ctx context.Context, in *ListProductSummaryReq, opts ...grpc.CallOption) (*ListProductSummaryResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListProductSummaryResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListProductSummary_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListColorDetail(ctx context.Context, in *ListColorDetailReq, opts ...grpc.CallOption) (*ListColorDetailResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListColorDetailResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListColorDetail_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListPanView(ctx context.Context, in *ListPanViewReq, opts ...grpc.CallOption) (*ListPanViewResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListPanViewResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListPanView_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListBoltView(ctx context.Context, in *ListBoltViewReq, opts ...grpc.CallOption) (*ListBoltViewResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListBoltViewResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListBoltView_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListPans(ctx context.Context, in *ListPanReq, opts ...grpc.CallOption) (*ListPanResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListPanResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListPans_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) SavePans(ctx context.Context, in *SavePansReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, InventoryService_SavePans_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListBolts(ctx context.Context, in *ListBoltReq, opts ...grpc.CallOption) (*ListBoltResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListBoltResp)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListBolts_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) SaveBolts(ctx context.Context, in *SaveBoltsReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, InventoryService_SaveBolts_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -101,8 +241,9 @@ func (c *inventoryServiceClient) ListProduct(ctx context.Context, in *ListProduc
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ImportProducts(ctx context.Context, in *ImportProductReq, opts ...grpc.CallOption) (*ImportProductResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ImportProductResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ImportProducts", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ImportProducts_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -110,8 +251,9 @@ func (c *inventoryServiceClient) ImportProducts(ctx context.Context, in *ImportP
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListImportLog(ctx context.Context, in *ListImportLogReq, opts ...grpc.CallOption) (*ListImportLogResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListImportLogResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ListImportLog", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListImportLog_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -119,8 +261,9 @@ func (c *inventoryServiceClient) ListImportLog(ctx context.Context, in *ListImpo
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) GetStockSummary(ctx context.Context, in *StockSummaryReq, opts ...grpc.CallOption) (*StockSummaryResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StockSummaryResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/GetStockSummary", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_GetStockSummary_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -128,8 +271,9 @@ func (c *inventoryServiceClient) GetStockSummary(ctx context.Context, in *StockS
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) GetStockGroup(ctx context.Context, in *StockGroupReq, opts ...grpc.CallOption) (*StockGroupResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StockGroupResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/GetStockGroup", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_GetStockGroup_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -137,8 +281,9 @@ func (c *inventoryServiceClient) GetStockGroup(ctx context.Context, in *StockGro
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) CreateStockCheck(ctx context.Context, in *CreateStockCheckReq, opts ...grpc.CallOption) (*IdResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(IdResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/CreateStockCheck", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_CreateStockCheck_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -146,8 +291,9 @@ func (c *inventoryServiceClient) CreateStockCheck(ctx context.Context, in *Creat
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) UpdateStockCheck(ctx context.Context, in *UpdateStockCheckReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/UpdateStockCheck", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_UpdateStockCheck_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -155,8 +301,9 @@ func (c *inventoryServiceClient) UpdateStockCheck(ctx context.Context, in *Updat
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ConfirmStockCheck(ctx context.Context, in *ConfirmStockCheckReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ConfirmStockCheck", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ConfirmStockCheck_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -164,8 +311,9 @@ func (c *inventoryServiceClient) ConfirmStockCheck(ctx context.Context, in *Conf
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) GetStockCheck(ctx context.Context, in *GetStockCheckReq, opts ...grpc.CallOption) (*StockCheckInfo, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StockCheckInfo)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/GetStockCheck", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_GetStockCheck_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -173,8 +321,9 @@ func (c *inventoryServiceClient) GetStockCheck(ctx context.Context, in *GetStock
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListStockCheck(ctx context.Context, in *ListStockCheckReq, opts ...grpc.CallOption) (*ListStockCheckResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListStockCheckResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ListStockCheck", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListStockCheck_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -182,8 +331,9 @@ func (c *inventoryServiceClient) ListStockCheck(ctx context.Context, in *ListSto
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) CreateStockAdjust(ctx context.Context, in *CreateStockAdjustReq, opts ...grpc.CallOption) (*IdResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(IdResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/CreateStockAdjust", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_CreateStockAdjust_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -191,8 +341,9 @@ func (c *inventoryServiceClient) CreateStockAdjust(ctx context.Context, in *Crea
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ApproveStockAdjust(ctx context.Context, in *ApproveStockAdjustReq, opts ...grpc.CallOption) (*Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ApproveStockAdjust", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ApproveStockAdjust_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -200,8 +351,9 @@ func (c *inventoryServiceClient) ApproveStockAdjust(ctx context.Context, in *App
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) GetStockAdjust(ctx context.Context, in *GetStockAdjustReq, opts ...grpc.CallOption) (*StockAdjustInfo, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(StockAdjustInfo)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/GetStockAdjust", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_GetStockAdjust_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -209,8 +361,9 @@ func (c *inventoryServiceClient) GetStockAdjust(ctx context.Context, in *GetStoc
|
||||
}
|
||||
|
||||
func (c *inventoryServiceClient) ListStockAdjust(ctx context.Context, in *ListStockAdjustReq, opts ...grpc.CallOption) (*ListStockAdjustResp, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListStockAdjustResp)
|
||||
err := c.cc.Invoke(ctx, "/inventory.InventoryService/ListStockAdjust", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, InventoryService_ListStockAdjust_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -219,14 +372,29 @@ func (c *inventoryServiceClient) ListStockAdjust(ctx context.Context, in *ListSt
|
||||
|
||||
// InventoryServiceServer is the server API for InventoryService service.
|
||||
// All implementations must embed UnimplementedInventoryServiceServer
|
||||
// for forward compatibility
|
||||
// for forward compatibility.
|
||||
type InventoryServiceServer interface {
|
||||
// Product
|
||||
// Product CRUD
|
||||
CreateProduct(context.Context, *CreateProductReq) (*IdResp, error)
|
||||
UpdateProduct(context.Context, *UpdateProductReq) (*Empty, error)
|
||||
DeleteProduct(context.Context, *DeleteProductReq) (*Empty, error)
|
||||
GetProduct(context.Context, *GetProductReq) (*ProductInfo, error)
|
||||
ListProduct(context.Context, *ListProductReq) (*ListProductResp, error)
|
||||
// Product Tree (panel 3)
|
||||
GetProductTree(context.Context, *GetProductReq) (*ProductTreeResp, error)
|
||||
// Product Summary (panel 1)
|
||||
ListProductSummary(context.Context, *ListProductSummaryReq) (*ListProductSummaryResp, error)
|
||||
// Color Detail (panel 2)
|
||||
ListColorDetail(context.Context, *ListColorDetailReq) (*ListColorDetailResp, error)
|
||||
// Pan / Bolt list views (dimension panels)
|
||||
ListPanView(context.Context, *ListPanViewReq) (*ListPanViewResp, error)
|
||||
ListBoltView(context.Context, *ListBoltViewReq) (*ListBoltViewResp, error)
|
||||
// Pan CRUD
|
||||
ListPans(context.Context, *ListPanReq) (*ListPanResp, error)
|
||||
SavePans(context.Context, *SavePansReq) (*Empty, error)
|
||||
// Bolt CRUD
|
||||
ListBolts(context.Context, *ListBoltReq) (*ListBoltResp, error)
|
||||
SaveBolts(context.Context, *SaveBoltsReq) (*Empty, error)
|
||||
// Import
|
||||
ImportProducts(context.Context, *ImportProductReq) (*ImportProductResp, error)
|
||||
ListImportLog(context.Context, *ListImportLogReq) (*ListImportLogResp, error)
|
||||
@ -247,9 +415,12 @@ type InventoryServiceServer interface {
|
||||
mustEmbedUnimplementedInventoryServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedInventoryServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedInventoryServiceServer struct {
|
||||
}
|
||||
// UnimplementedInventoryServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedInventoryServiceServer struct{}
|
||||
|
||||
func (UnimplementedInventoryServiceServer) CreateProduct(context.Context, *CreateProductReq) (*IdResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateProduct not implemented")
|
||||
@ -266,6 +437,33 @@ func (UnimplementedInventoryServiceServer) GetProduct(context.Context, *GetProdu
|
||||
func (UnimplementedInventoryServiceServer) ListProduct(context.Context, *ListProductReq) (*ListProductResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListProduct not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) GetProductTree(context.Context, *GetProductReq) (*ProductTreeResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetProductTree not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ListProductSummary(context.Context, *ListProductSummaryReq) (*ListProductSummaryResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListProductSummary not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ListColorDetail(context.Context, *ListColorDetailReq) (*ListColorDetailResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListColorDetail not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ListPanView(context.Context, *ListPanViewReq) (*ListPanViewResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListPanView not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ListBoltView(context.Context, *ListBoltViewReq) (*ListBoltViewResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListBoltView not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ListPans(context.Context, *ListPanReq) (*ListPanResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListPans not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) SavePans(context.Context, *SavePansReq) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SavePans not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ListBolts(context.Context, *ListBoltReq) (*ListBoltResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListBolts not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) SaveBolts(context.Context, *SaveBoltsReq) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SaveBolts not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) ImportProducts(context.Context, *ImportProductReq) (*ImportProductResp, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ImportProducts not implemented")
|
||||
}
|
||||
@ -306,6 +504,7 @@ func (UnimplementedInventoryServiceServer) ListStockAdjust(context.Context, *Lis
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListStockAdjust not implemented")
|
||||
}
|
||||
func (UnimplementedInventoryServiceServer) mustEmbedUnimplementedInventoryServiceServer() {}
|
||||
func (UnimplementedInventoryServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeInventoryServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to InventoryServiceServer will
|
||||
@ -315,6 +514,13 @@ type UnsafeInventoryServiceServer interface {
|
||||
}
|
||||
|
||||
func RegisterInventoryServiceServer(s grpc.ServiceRegistrar, srv InventoryServiceServer) {
|
||||
// If the following call pancis, it indicates UnimplementedInventoryServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&InventoryService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
@ -328,7 +534,7 @@ func _InventoryService_CreateProduct_Handler(srv interface{}, ctx context.Contex
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/CreateProduct",
|
||||
FullMethod: InventoryService_CreateProduct_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).CreateProduct(ctx, req.(*CreateProductReq))
|
||||
@ -346,7 +552,7 @@ func _InventoryService_UpdateProduct_Handler(srv interface{}, ctx context.Contex
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/UpdateProduct",
|
||||
FullMethod: InventoryService_UpdateProduct_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).UpdateProduct(ctx, req.(*UpdateProductReq))
|
||||
@ -364,7 +570,7 @@ func _InventoryService_DeleteProduct_Handler(srv interface{}, ctx context.Contex
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/DeleteProduct",
|
||||
FullMethod: InventoryService_DeleteProduct_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).DeleteProduct(ctx, req.(*DeleteProductReq))
|
||||
@ -382,7 +588,7 @@ func _InventoryService_GetProduct_Handler(srv interface{}, ctx context.Context,
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/GetProduct",
|
||||
FullMethod: InventoryService_GetProduct_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).GetProduct(ctx, req.(*GetProductReq))
|
||||
@ -400,7 +606,7 @@ func _InventoryService_ListProduct_Handler(srv interface{}, ctx context.Context,
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ListProduct",
|
||||
FullMethod: InventoryService_ListProduct_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListProduct(ctx, req.(*ListProductReq))
|
||||
@ -408,6 +614,168 @@ func _InventoryService_ListProduct_Handler(srv interface{}, ctx context.Context,
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_GetProductTree_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetProductReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).GetProductTree(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_GetProductTree_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).GetProductTree(ctx, req.(*GetProductReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ListProductSummary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListProductSummaryReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).ListProductSummary(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_ListProductSummary_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListProductSummary(ctx, req.(*ListProductSummaryReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ListColorDetail_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListColorDetailReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).ListColorDetail(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_ListColorDetail_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListColorDetail(ctx, req.(*ListColorDetailReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ListPanView_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListPanViewReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).ListPanView(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_ListPanView_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListPanView(ctx, req.(*ListPanViewReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ListBoltView_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListBoltViewReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).ListBoltView(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_ListBoltView_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListBoltView(ctx, req.(*ListBoltViewReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ListPans_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListPanReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).ListPans(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_ListPans_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListPans(ctx, req.(*ListPanReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_SavePans_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SavePansReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).SavePans(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_SavePans_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).SavePans(ctx, req.(*SavePansReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ListBolts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListBoltReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).ListBolts(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_ListBolts_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListBolts(ctx, req.(*ListBoltReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_SaveBolts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SaveBoltsReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(InventoryServiceServer).SaveBolts(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: InventoryService_SaveBolts_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).SaveBolts(ctx, req.(*SaveBoltsReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _InventoryService_ImportProducts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ImportProductReq)
|
||||
if err := dec(in); err != nil {
|
||||
@ -418,7 +786,7 @@ func _InventoryService_ImportProducts_Handler(srv interface{}, ctx context.Conte
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ImportProducts",
|
||||
FullMethod: InventoryService_ImportProducts_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ImportProducts(ctx, req.(*ImportProductReq))
|
||||
@ -436,7 +804,7 @@ func _InventoryService_ListImportLog_Handler(srv interface{}, ctx context.Contex
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ListImportLog",
|
||||
FullMethod: InventoryService_ListImportLog_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListImportLog(ctx, req.(*ListImportLogReq))
|
||||
@ -454,7 +822,7 @@ func _InventoryService_GetStockSummary_Handler(srv interface{}, ctx context.Cont
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/GetStockSummary",
|
||||
FullMethod: InventoryService_GetStockSummary_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).GetStockSummary(ctx, req.(*StockSummaryReq))
|
||||
@ -472,7 +840,7 @@ func _InventoryService_GetStockGroup_Handler(srv interface{}, ctx context.Contex
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/GetStockGroup",
|
||||
FullMethod: InventoryService_GetStockGroup_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).GetStockGroup(ctx, req.(*StockGroupReq))
|
||||
@ -490,7 +858,7 @@ func _InventoryService_CreateStockCheck_Handler(srv interface{}, ctx context.Con
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/CreateStockCheck",
|
||||
FullMethod: InventoryService_CreateStockCheck_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).CreateStockCheck(ctx, req.(*CreateStockCheckReq))
|
||||
@ -508,7 +876,7 @@ func _InventoryService_UpdateStockCheck_Handler(srv interface{}, ctx context.Con
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/UpdateStockCheck",
|
||||
FullMethod: InventoryService_UpdateStockCheck_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).UpdateStockCheck(ctx, req.(*UpdateStockCheckReq))
|
||||
@ -526,7 +894,7 @@ func _InventoryService_ConfirmStockCheck_Handler(srv interface{}, ctx context.Co
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ConfirmStockCheck",
|
||||
FullMethod: InventoryService_ConfirmStockCheck_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ConfirmStockCheck(ctx, req.(*ConfirmStockCheckReq))
|
||||
@ -544,7 +912,7 @@ func _InventoryService_GetStockCheck_Handler(srv interface{}, ctx context.Contex
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/GetStockCheck",
|
||||
FullMethod: InventoryService_GetStockCheck_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).GetStockCheck(ctx, req.(*GetStockCheckReq))
|
||||
@ -562,7 +930,7 @@ func _InventoryService_ListStockCheck_Handler(srv interface{}, ctx context.Conte
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ListStockCheck",
|
||||
FullMethod: InventoryService_ListStockCheck_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListStockCheck(ctx, req.(*ListStockCheckReq))
|
||||
@ -580,7 +948,7 @@ func _InventoryService_CreateStockAdjust_Handler(srv interface{}, ctx context.Co
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/CreateStockAdjust",
|
||||
FullMethod: InventoryService_CreateStockAdjust_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).CreateStockAdjust(ctx, req.(*CreateStockAdjustReq))
|
||||
@ -598,7 +966,7 @@ func _InventoryService_ApproveStockAdjust_Handler(srv interface{}, ctx context.C
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ApproveStockAdjust",
|
||||
FullMethod: InventoryService_ApproveStockAdjust_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ApproveStockAdjust(ctx, req.(*ApproveStockAdjustReq))
|
||||
@ -616,7 +984,7 @@ func _InventoryService_GetStockAdjust_Handler(srv interface{}, ctx context.Conte
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/GetStockAdjust",
|
||||
FullMethod: InventoryService_GetStockAdjust_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).GetStockAdjust(ctx, req.(*GetStockAdjustReq))
|
||||
@ -634,7 +1002,7 @@ func _InventoryService_ListStockAdjust_Handler(srv interface{}, ctx context.Cont
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/inventory.InventoryService/ListStockAdjust",
|
||||
FullMethod: InventoryService_ListStockAdjust_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(InventoryServiceServer).ListStockAdjust(ctx, req.(*ListStockAdjustReq))
|
||||
@ -669,6 +1037,42 @@ var InventoryService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ListProduct",
|
||||
Handler: _InventoryService_ListProduct_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetProductTree",
|
||||
Handler: _InventoryService_GetProductTree_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListProductSummary",
|
||||
Handler: _InventoryService_ListProductSummary_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListColorDetail",
|
||||
Handler: _InventoryService_ListColorDetail_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListPanView",
|
||||
Handler: _InventoryService_ListPanView_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListBoltView",
|
||||
Handler: _InventoryService_ListBoltView_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListPans",
|
||||
Handler: _InventoryService_ListPans_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SavePans",
|
||||
Handler: _InventoryService_SavePans_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListBolts",
|
||||
Handler: _InventoryService_ListBolts_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SaveBolts",
|
||||
Handler: _InventoryService_SaveBolts_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ImportProducts",
|
||||
Handler: _InventoryService_ImportProducts_Handler,
|
||||
@ -723,5 +1127,5 @@ var InventoryService_ServiceDesc = grpc.ServiceDesc{
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "rpc/inventory/inventory.proto",
|
||||
Metadata: "inventory.proto",
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"muyu-apiserver/model"
|
||||
"muyu-apiserver/pkg/tenantctx"
|
||||
"muyu-apiserver/pkg/uid"
|
||||
"muyu-apiserver/rpc/system/internal/svc"
|
||||
"muyu-apiserver/rpc/system/pb"
|
||||
@ -28,9 +29,11 @@ func NewCreateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Create
|
||||
}
|
||||
|
||||
func (l *CreateRoleLogic) CreateRole(in *pb.CreateRoleReq) (*pb.IdResp, error) {
|
||||
tenantId := tenantctx.ExtractTenantId(l.ctx)
|
||||
roleId := uid.Generate()
|
||||
|
||||
_, err := l.svcCtx.RoleModel.Insert(l.ctx, &model.SysRole{
|
||||
TenantId: tenantId,
|
||||
RoleId: roleId,
|
||||
RoleName: in.RoleName,
|
||||
RoleKey: in.RoleKey,
|
||||
|
||||
96
worker/graphsync/go.sum
Normal file
96
worker/graphsync/go.sum
Normal file
@ -0,0 +1,96 @@
|
||||
github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA=
|
||||
github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
|
||||
github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
|
||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
|
||||
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/neo4j/neo4j-go-driver/v5 v5.28.0 h1:chDT68PHNa8JZRmjSkGzAbk1weLWo4rMtDvccvpobg0=
|
||||
github.com/neo4j/neo4j-go-driver/v5 v5.28.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
Loading…
x
Reference in New Issue
Block a user