Merge branch 'test' into feauture-20261104
# Conflicts: # bms-back/bms-system/src/main/java/com/bms/price/mapper/PrcOrderBillMapper.java
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
-- 应收账单毛利分析:增量结构与历史客户归属快照。
|
||||
-- MySQL 5.7+;停用后端写入并备份数据库,再执行本文件,最后部署新版本并重新登录。
|
||||
-- DDL 自动提交;数据与菜单授权使用事务。失败后检查已创建对象并修复结构,再重试完整文件。
|
||||
-- 历史区域及销售员来自当前客户资料,不代表能还原历史真实归属。
|
||||
-- 已有快照不会覆盖。账单来源订单销售员与当前客户销售员不一致时不自动回填销售员。
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
DROP PROCEDURE IF EXISTS bms_ar_profit_upgrade_20261105_v1;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE bms_ar_profit_upgrade_20261105_v1()
|
||||
BEGIN
|
||||
DECLARE n INT DEFAULT 0;
|
||||
DECLARE report_id BIGINT DEFAULT NULL;
|
||||
DECLARE page_id BIGINT DEFAULT NULL;
|
||||
DECLARE export_id BIGINT DEFAULT NULL;
|
||||
DECLARE commission_id BIGINT DEFAULT NULL;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
ROLLBACK;
|
||||
RESIGNAL;
|
||||
END;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.tables
|
||||
WHERE table_schema = DATABASE() AND table_name IN ('ar_bill','ar_bill_detail','ar_bill_detail_fee','ar_balance_writeoff','ctr_customer','prc_order_bill','sys_user','sys_dept','sys_role','sys_menu','sys_role_menu');
|
||||
IF n <> 11 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '应收毛利升级前置表缺失'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM sys_menu WHERE parent_id = 0 AND menu_type = 'M' AND menu_name = '报表中心';
|
||||
IF n > 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '报表中心目录不唯一'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM (SELECT perms FROM sys_menu WHERE perms IN
|
||||
('report:arProfit:list','report:arProfit:export','report:arProfit:commission') GROUP BY perms HAVING COUNT(*) > 1) conflicts;
|
||||
IF n > 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '应收毛利菜单权限重复'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM (SELECT role_key FROM sys_role WHERE role_key IN
|
||||
('ORA_6040','ORA_6041','ORA_6042','ORA_6043') AND del_flag = '0' GROUP BY role_key HAVING COUNT(*) > 1) conflicts;
|
||||
IF n > 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '应收毛利角色标识重复'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'ar_bill' AND column_name = 'profit_customer_area';
|
||||
IF n = 0 THEN ALTER TABLE ar_bill ADD COLUMN profit_customer_area VARCHAR(50) NULL COMMENT '账单客户区域快照'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'ar_bill' AND column_name = 'profit_sales_user_id';
|
||||
IF n = 0 THEN ALTER TABLE ar_bill ADD COLUMN profit_sales_user_id BIGINT NULL COMMENT '账单销售员用户ID快照'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'ar_bill' AND column_name = 'profit_sales_user_code';
|
||||
IF n = 0 THEN ALTER TABLE ar_bill ADD COLUMN profit_sales_user_code VARCHAR(64) NULL COMMENT '账单销售员工号快照'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'ar_bill' AND column_name = 'profit_sales_user_name';
|
||||
IF n = 0 THEN ALTER TABLE ar_bill ADD COLUMN profit_sales_user_name VARCHAR(64) NULL COMMENT '账单销售员姓名快照'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = 'ar_bill' AND column_name = 'profit_snapshot_source';
|
||||
IF n = 0 THEN ALTER TABLE ar_bill ADD COLUMN profit_snapshot_source VARCHAR(16) NULL COMMENT 'NEW生成时快照/BACKFILLED历史补录'; END IF;
|
||||
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'ar_bill'
|
||||
AND is_nullable = 'YES'
|
||||
AND ((column_name = 'profit_customer_area' AND data_type = 'varchar' AND character_maximum_length = 50)
|
||||
OR (column_name = 'profit_sales_user_id' AND data_type = 'bigint')
|
||||
OR (column_name IN ('profit_sales_user_code','profit_sales_user_name') AND data_type = 'varchar' AND character_maximum_length = 64)
|
||||
OR (column_name = 'profit_snapshot_source' AND data_type = 'varchar' AND character_maximum_length = 16));
|
||||
IF n <> 5 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '账单快照字段结构冲突'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'ar_bill' AND index_name = 'idx_ar_profit_sales_date';
|
||||
IF n = 0 THEN ALTER TABLE ar_bill ADD INDEX idx_ar_profit_sales_date (profit_sales_user_id, bill_date, ar_bill_id); END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND table_name = 'ar_bill' AND index_name = 'idx_ar_profit_sales_date'
|
||||
AND ((seq_in_index = 1 AND column_name = 'profit_sales_user_id')
|
||||
OR (seq_in_index = 2 AND column_name = 'bill_date')
|
||||
OR (seq_in_index = 3 AND column_name = 'ar_bill_id'));
|
||||
IF n <> 3 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '账单毛利索引结构冲突'; END IF;
|
||||
|
||||
-- 提成比例版本及每次核销时的比例快照;历史核销未录入比例时保留空值待财务确认。
|
||||
CREATE TABLE IF NOT EXISTS ar_profit_commission_rate (
|
||||
rate_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '提成比例记录ID',
|
||||
sales_user_id BIGINT NOT NULL COMMENT '销售员用户ID',
|
||||
rate DECIMAL(7,4) NOT NULL COMMENT '提成比例,百分数,例如10表示10%',
|
||||
effective_at DATETIME NOT NULL COMMENT '比例生效时间',
|
||||
create_by VARCHAR(64) NOT NULL COMMENT '创建人',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间',
|
||||
remark VARCHAR(500) NULL COMMENT '备注',
|
||||
PRIMARY KEY (rate_id),
|
||||
KEY idx_ar_profit_rate_effective (sales_user_id, effective_at, rate_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='账单毛利销售员提成比例版本';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ar_profit_writeoff_rate (
|
||||
writeoff_id BIGINT NOT NULL COMMENT '核销记录ID',
|
||||
sales_user_id BIGINT NULL COMMENT '销售员用户ID',
|
||||
rate_id BIGINT NULL COMMENT '提成比例记录ID',
|
||||
rate DECIMAL(7,4) NULL COMMENT '提成比例,百分数,例如10表示10%',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间',
|
||||
confirmed_by VARCHAR(64) NULL COMMENT '历史比例确认人',
|
||||
confirmed_time DATETIME NULL COMMENT '历史比例确认时间',
|
||||
confirm_remark VARCHAR(500) NULL COMMENT '历史比例确认说明',
|
||||
PRIMARY KEY (writeoff_id),
|
||||
KEY idx_ar_profit_writeoff_rate_sales (sales_user_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='账单核销时提成比例快照';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ar_profit_commission_result (
|
||||
result_id BIGINT NOT NULL AUTO_INCREMENT COMMENT '提成结果ID',
|
||||
ar_bill_id BIGINT NOT NULL COMMENT '应收账单ID',
|
||||
detail_id BIGINT NOT NULL COMMENT '应收账单明细ID',
|
||||
sales_user_id BIGINT NULL COMMENT '销售员用户ID',
|
||||
currency VARCHAR(10) NOT NULL COMMENT '币种',
|
||||
gross_profit DECIMAL(18,4) NULL COMMENT '销售毛利',
|
||||
commission_amount DECIMAL(18,2) NULL COMMENT '提成金额',
|
||||
result_status VARCHAR(24) NOT NULL COMMENT 'READY/MISSING_RATE/MISSING_PRICE/MISSING_SNAPSHOT/WRITEOFF_MISMATCH/REVERSED',
|
||||
create_by VARCHAR(64) NOT NULL COMMENT '创建人',
|
||||
create_time DATETIME NOT NULL COMMENT '创建时间',
|
||||
reversed_by VARCHAR(64) NULL COMMENT '冲回操作人',
|
||||
reversed_time DATETIME NULL COMMENT '冲回时间',
|
||||
PRIMARY KEY (result_id),
|
||||
KEY idx_ar_profit_result_bill (ar_bill_id, result_status, detail_id),
|
||||
KEY idx_ar_profit_result_sales (sales_user_id, result_status, create_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='账单完全核销时逐单正式提成及冲回记录';
|
||||
|
||||
-- 检查已有表结构,避免 IF NOT EXISTS 掩盖不兼容的旧结构。
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'ar_profit_commission_rate'
|
||||
AND column_name IN ('rate_id','sales_user_id','rate','effective_at','create_by','create_time','remark');
|
||||
IF n <> 7 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成比例表结构不完整'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'ar_profit_writeoff_rate'
|
||||
AND column_name IN ('writeoff_id','sales_user_id','rate_id','rate','create_time','confirmed_by','confirmed_time','confirm_remark');
|
||||
IF n <> 8 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '核销比例表结构不完整'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'ar_profit_commission_result'
|
||||
AND column_name IN ('result_id','ar_bill_id','detail_id','sales_user_id','currency','gross_profit','commission_amount','result_status','create_by','create_time','reversed_by','reversed_time');
|
||||
IF n <> 12 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '逐单提成表结构不完整'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.tables WHERE table_schema = DATABASE()
|
||||
AND table_name IN ('ar_profit_commission_rate','ar_profit_writeoff_rate','ar_profit_commission_result') AND engine = 'InnoDB';
|
||||
IF n <> 3 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成相关表必须使用 InnoDB'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE()
|
||||
AND table_name IN ('ar_profit_commission_rate','ar_profit_writeoff_rate') AND column_name = 'rate' AND column_type = 'decimal(7,4)';
|
||||
IF n <> 2 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成比例字段类型不匹配'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE()
|
||||
AND ((table_name = 'ar_profit_commission_rate' AND column_name IN ('rate_id','sales_user_id') AND data_type = 'bigint' AND is_nullable = 'NO')
|
||||
OR (table_name = 'ar_profit_commission_rate' AND column_name = 'effective_at' AND data_type = 'datetime' AND is_nullable = 'NO')
|
||||
OR (table_name = 'ar_profit_writeoff_rate' AND column_name = 'writeoff_id' AND data_type = 'bigint' AND is_nullable = 'NO')
|
||||
OR (table_name = 'ar_profit_writeoff_rate' AND column_name IN ('sales_user_id','rate_id') AND data_type = 'bigint' AND is_nullable = 'YES')
|
||||
OR (table_name = 'ar_profit_writeoff_rate' AND column_name = 'rate' AND is_nullable = 'YES'));
|
||||
IF n <> 7 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成比例关键字段类型或空值约束不匹配'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'ar_profit_commission_result'
|
||||
AND ((column_name = 'gross_profit' AND column_type = 'decimal(18,4)')
|
||||
OR (column_name = 'commission_amount' AND column_type = 'decimal(18,2)')
|
||||
OR (column_name = 'result_status' AND data_type = 'varchar' AND character_maximum_length = 24)
|
||||
OR (column_name IN ('result_id','ar_bill_id','detail_id','sales_user_id') AND data_type = 'bigint'));
|
||||
IF n <> 7 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '逐单提成字段类型不匹配'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'ar_profit_writeoff_rate'
|
||||
AND index_name = 'PRIMARY' AND column_name = 'writeoff_id' AND seq_in_index = 1;
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '核销比例表主键不匹配'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'ar_profit_writeoff_rate' AND index_name = 'PRIMARY';
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '核销比例表主键必须仅包含 writeoff_id'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'ar_profit_commission_rate'
|
||||
AND index_name = 'PRIMARY' AND column_name = 'rate_id' AND seq_in_index = 1;
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成比例表主键不匹配'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE() AND table_name = 'ar_profit_commission_result'
|
||||
AND index_name = 'PRIMARY' AND column_name = 'result_id' AND seq_in_index = 1;
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '逐单提成表主键不匹配'; END IF;
|
||||
SELECT COUNT(*) INTO n FROM information_schema.statistics WHERE table_schema = DATABASE()
|
||||
AND ((table_name = 'ar_profit_commission_rate' AND index_name = 'PRIMARY')
|
||||
OR (table_name = 'ar_profit_commission_result' AND index_name = 'PRIMARY'));
|
||||
IF n <> 2 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成表主键结构不匹配'; END IF;
|
||||
|
||||
-- 旧版本已经建表时,只补充空注释;按实际元数据保留字段类型、字符集和空值约束。
|
||||
-- 对无法安全重建的默认值、生成列或其他额外属性先中止,不擅自改写字段定义。
|
||||
SELECT COUNT(*) INTO n FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND column_comment = ''
|
||||
AND ((table_name = 'ar_profit_commission_rate' AND column_name IN ('rate_id','sales_user_id','rate','effective_at','create_by','create_time','remark'))
|
||||
OR (table_name = 'ar_profit_writeoff_rate' AND column_name IN ('writeoff_id','sales_user_id','rate_id','rate','create_time','confirmed_by','confirmed_time','confirm_remark'))
|
||||
OR (table_name = 'ar_profit_commission_result' AND column_name IN ('result_id','ar_bill_id','detail_id','sales_user_id','currency','gross_profit','commission_amount','result_status','create_by','create_time','reversed_by','reversed_time')))
|
||||
AND (column_default IS NOT NULL OR extra NOT IN ('','auto_increment') OR data_type NOT IN ('bigint','decimal','datetime','varchar'));
|
||||
IF n > 0 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '提成表待补注释字段存在特殊定义,请检查后再执行'; END IF;
|
||||
|
||||
BEGIN
|
||||
DECLARE v_table VARCHAR(64);
|
||||
DECLARE v_table_index INT DEFAULT 1;
|
||||
DECLARE v_old_concat_limit BIGINT UNSIGNED;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||
BEGIN
|
||||
SET SESSION group_concat_max_len = v_old_concat_limit;
|
||||
RESIGNAL;
|
||||
END;
|
||||
SET v_old_concat_limit = @@SESSION.group_concat_max_len;
|
||||
SET SESSION group_concat_max_len = 65535;
|
||||
WHILE v_table_index <= 3 DO
|
||||
SET v_table = CASE v_table_index
|
||||
WHEN 1 THEN 'ar_profit_commission_rate'
|
||||
WHEN 2 THEN 'ar_profit_writeoff_rate'
|
||||
ELSE 'ar_profit_commission_result' END;
|
||||
SELECT GROUP_CONCAT(CONCAT(
|
||||
'MODIFY COLUMN `', REPLACE(column_name, '`', '``'), '` ', column_type,
|
||||
IF(character_set_name IS NULL, '', CONCAT(' CHARACTER SET ', character_set_name, ' COLLATE ', collation_name)),
|
||||
IF(is_nullable = 'YES', ' NULL DEFAULT NULL', ' NOT NULL'),
|
||||
IF(extra = 'auto_increment', ' AUTO_INCREMENT', ''),
|
||||
' COMMENT ', QUOTE(CASE column_name
|
||||
WHEN 'rate_id' THEN '提成比例记录ID'
|
||||
WHEN 'sales_user_id' THEN '销售员用户ID'
|
||||
WHEN 'rate' THEN '提成比例,百分数,例如10表示10%'
|
||||
WHEN 'effective_at' THEN '比例生效时间'
|
||||
WHEN 'create_by' THEN '创建人'
|
||||
WHEN 'create_time' THEN '创建时间'
|
||||
WHEN 'remark' THEN '备注'
|
||||
WHEN 'writeoff_id' THEN '核销记录ID'
|
||||
WHEN 'confirmed_by' THEN '历史比例确认人'
|
||||
WHEN 'confirmed_time' THEN '历史比例确认时间'
|
||||
WHEN 'confirm_remark' THEN '历史比例确认说明'
|
||||
WHEN 'result_id' THEN '提成结果ID'
|
||||
WHEN 'ar_bill_id' THEN '应收账单ID'
|
||||
WHEN 'detail_id' THEN '应收账单明细ID'
|
||||
WHEN 'currency' THEN '币种'
|
||||
WHEN 'gross_profit' THEN '销售毛利'
|
||||
WHEN 'commission_amount' THEN '提成金额'
|
||||
WHEN 'result_status' THEN 'READY/MISSING_RATE/MISSING_PRICE/MISSING_SNAPSHOT/WRITEOFF_MISMATCH/REVERSED'
|
||||
WHEN 'reversed_by' THEN '冲回操作人'
|
||||
WHEN 'reversed_time' THEN '冲回时间'
|
||||
END)) ORDER BY ordinal_position SEPARATOR ', ')
|
||||
INTO @bms_ar_profit_comment_columns
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE() AND table_name = v_table AND column_comment = ''
|
||||
AND ((table_name = 'ar_profit_commission_rate' AND column_name IN ('rate_id','sales_user_id','rate','effective_at','create_by','create_time','remark'))
|
||||
OR (table_name = 'ar_profit_writeoff_rate' AND column_name IN ('writeoff_id','sales_user_id','rate_id','rate','create_time','confirmed_by','confirmed_time','confirm_remark'))
|
||||
OR (table_name = 'ar_profit_commission_result' AND column_name IN ('result_id','ar_bill_id','detail_id','sales_user_id','currency','gross_profit','commission_amount','result_status','create_by','create_time','reversed_by','reversed_time')));
|
||||
IF @bms_ar_profit_comment_columns IS NOT NULL THEN
|
||||
SET @bms_ar_profit_comment_ddl = CONCAT('ALTER TABLE `', REPLACE(v_table, '`', '``'), '` ', @bms_ar_profit_comment_columns);
|
||||
PREPARE bms_ar_profit_comment_stmt FROM @bms_ar_profit_comment_ddl;
|
||||
EXECUTE bms_ar_profit_comment_stmt;
|
||||
DEALLOCATE PREPARE bms_ar_profit_comment_stmt;
|
||||
END IF;
|
||||
SET v_table_index = v_table_index + 1;
|
||||
END WHILE;
|
||||
SET SESSION group_concat_max_len = v_old_concat_limit;
|
||||
END;
|
||||
|
||||
SELECT MAX(menu_id) INTO report_id FROM sys_menu WHERE parent_id = 0 AND menu_type = 'M' AND menu_name = '报表中心';
|
||||
SELECT MAX(menu_id) INTO page_id FROM sys_menu WHERE perms = 'report:arProfit:list';
|
||||
IF page_id IS NOT NULL THEN
|
||||
SELECT COUNT(*) INTO n FROM sys_menu WHERE menu_id = page_id AND parent_id = report_id AND component = 'report/arProfit/index' AND menu_type = 'C';
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有应收毛利菜单与预期不符'; END IF;
|
||||
END IF;
|
||||
SELECT MAX(menu_id) INTO export_id FROM sys_menu WHERE perms = 'report:arProfit:export';
|
||||
IF export_id IS NOT NULL THEN
|
||||
SELECT COUNT(*) INTO n FROM sys_menu WHERE menu_id = export_id AND parent_id = page_id AND menu_type = 'F';
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有应收毛利导出权限与预期不符'; END IF;
|
||||
END IF;
|
||||
SELECT MAX(menu_id) INTO commission_id FROM sys_menu WHERE perms = 'report:arProfit:commission';
|
||||
IF commission_id IS NOT NULL THEN
|
||||
SELECT COUNT(*) INTO n FROM sys_menu WHERE menu_id = commission_id AND parent_id = page_id AND menu_type = 'F';
|
||||
IF n <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '现有应收毛利提成权限与预期不符'; END IF;
|
||||
END IF;
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
-- 只读检查:不能关联客户、区域为空或销售员无效的历史账单。
|
||||
SELECT b.ar_bill_id, b.bill_no, b.customer_id, c.customer_area, c.sales_user_id
|
||||
FROM ar_bill b LEFT JOIN ctr_customer c ON c.customer_id = b.customer_id
|
||||
LEFT JOIN sys_user u ON CONVERT(CAST(u.user_id AS CHAR) USING utf8mb4) COLLATE utf8mb4_unicode_ci = c.sales_user_id AND u.del_flag = '0'
|
||||
WHERE (b.profit_customer_area IS NULL AND (c.customer_area IS NULL OR TRIM(c.customer_area) = ''))
|
||||
OR (b.profit_sales_user_id IS NULL AND u.user_id IS NULL);
|
||||
|
||||
-- 检查来源订单销售员与当前客户负责人不一致的账单;下方不自动回填这些销售归属。
|
||||
SELECT DISTINCT b.ar_bill_id, b.bill_no, p.belong_saler_code AS order_saler_code,
|
||||
u.user_id AS customer_sales_user_id, u.user_name AS customer_sales_code
|
||||
FROM ar_bill b
|
||||
JOIN ctr_customer c ON c.customer_id = b.customer_id
|
||||
JOIN sys_user u ON CONVERT(CAST(u.user_id AS CHAR) USING utf8mb4) COLLATE utf8mb4_unicode_ci = c.sales_user_id AND u.del_flag = '0'
|
||||
JOIN ar_bill_detail d ON d.ar_bill_id = b.ar_bill_id
|
||||
JOIN prc_order_bill p ON p.bill_id = d.prc_order_bill_id
|
||||
WHERE b.profit_sales_user_id IS NULL AND (b.profit_snapshot_source IS NULL OR b.profit_snapshot_source = 'BACKFILLED')
|
||||
AND p.belong_saler_code IS NOT NULL
|
||||
AND TRIM(p.belong_saler_code) <> ''
|
||||
AND TRIM(p.belong_saler_code) <> u.user_name COLLATE utf8mb4_unicode_ci
|
||||
AND TRIM(p.belong_saler_code) <> CONVERT(CAST(u.user_id AS CHAR) USING utf8mb4) COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 此处仅补空值。客户区域来自客户当前资料,并非出账时的历史事实。
|
||||
UPDATE ar_bill b JOIN ctr_customer c ON c.customer_id = b.customer_id
|
||||
SET b.profit_customer_area = c.customer_area
|
||||
WHERE b.profit_customer_area IS NULL AND (b.profit_snapshot_source IS NULL OR b.profit_snapshot_source = 'BACKFILLED')
|
||||
AND c.customer_area IS NOT NULL AND TRIM(c.customer_area) <> '';
|
||||
|
||||
UPDATE ar_bill b
|
||||
JOIN ctr_customer c ON c.customer_id = b.customer_id
|
||||
JOIN sys_user u ON CONVERT(CAST(u.user_id AS CHAR) USING utf8mb4) COLLATE utf8mb4_unicode_ci = c.sales_user_id AND u.del_flag = '0'
|
||||
SET b.profit_sales_user_id = u.user_id,
|
||||
b.profit_sales_user_code = u.user_name,
|
||||
b.profit_sales_user_name = u.nick_name
|
||||
WHERE b.profit_sales_user_id IS NULL AND (b.profit_snapshot_source IS NULL OR b.profit_snapshot_source = 'BACKFILLED')
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM ar_bill_detail d JOIN prc_order_bill p ON p.bill_id = d.prc_order_bill_id
|
||||
WHERE d.ar_bill_id = b.ar_bill_id AND p.belong_saler_code IS NOT NULL
|
||||
AND TRIM(p.belong_saler_code) <> ''
|
||||
AND TRIM(p.belong_saler_code) <> u.user_name COLLATE utf8mb4_unicode_ci
|
||||
AND TRIM(p.belong_saler_code) <> CONVERT(CAST(u.user_id AS CHAR) USING utf8mb4) COLLATE utf8mb4_unicode_ci
|
||||
);
|
||||
|
||||
UPDATE ar_bill SET profit_snapshot_source = 'BACKFILLED'
|
||||
WHERE profit_snapshot_source IS NULL AND (profit_customer_area IS NOT NULL OR profit_sales_user_id IS NOT NULL);
|
||||
|
||||
-- 历史核销比例不可追溯,不能使用当前比例替代。
|
||||
INSERT INTO ar_profit_writeoff_rate (writeoff_id, sales_user_id, rate_id, rate, create_time)
|
||||
SELECT w.writeoff_id, b.profit_sales_user_id, NULL, NULL, NOW()
|
||||
FROM ar_balance_writeoff w JOIN ar_bill b ON b.ar_bill_id = w.ar_bill_id
|
||||
LEFT JOIN ar_profit_writeoff_rate s ON s.writeoff_id = w.writeoff_id
|
||||
WHERE s.writeoff_id IS NULL;
|
||||
|
||||
IF report_id IS NULL THEN
|
||||
INSERT INTO sys_menu (menu_name,parent_id,order_num,path,component,is_frame,is_cache,menu_type,visible,status,perms,icon,create_by,create_time)
|
||||
VALUES ('报表中心',0,8,'report',NULL,1,0,'M','0','0','','chart','admin',NOW());
|
||||
SET report_id = LAST_INSERT_ID();
|
||||
END IF;
|
||||
IF page_id IS NULL THEN
|
||||
INSERT INTO sys_menu (menu_name,parent_id,order_num,path,component,route_name,is_frame,is_cache,menu_type,visible,status,perms,icon,create_by,create_time)
|
||||
VALUES ('应收账单毛利分析',report_id,2,'arProfit','report/arProfit/index','ArProfitReport',1,0,'C','0','0','report:arProfit:list','chart','admin',NOW());
|
||||
SET page_id = LAST_INSERT_ID();
|
||||
END IF;
|
||||
IF export_id IS NULL THEN
|
||||
INSERT INTO sys_menu (menu_name,parent_id,order_num,path,component,is_frame,is_cache,menu_type,visible,status,perms,icon,create_by,create_time)
|
||||
VALUES ('导出',page_id,1,'',NULL,1,0,'F','0','0','report:arProfit:export','#','admin',NOW());
|
||||
SET export_id = LAST_INSERT_ID();
|
||||
END IF;
|
||||
IF commission_id IS NULL THEN
|
||||
INSERT INTO sys_menu (menu_name,parent_id,order_num,path,component,is_frame,is_cache,menu_type,visible,status,perms,icon,create_by,create_time)
|
||||
VALUES ('提成管理',page_id,2,'',NULL,1,0,'F','0','0','report:arProfit:commission','#','admin',NOW());
|
||||
SET commission_id = LAST_INSERT_ID();
|
||||
END IF;
|
||||
INSERT INTO sys_role_menu (role_id,menu_id)
|
||||
SELECT r.role_id, m.menu_id FROM sys_role r JOIN sys_menu m ON m.menu_id IN (report_id,page_id,export_id)
|
||||
WHERE r.del_flag = '0' AND r.status = '0' AND (r.role_id = 1 OR r.role_key IN ('ORA_6040','ORA_6041','ORA_6042','ORA_6043'))
|
||||
AND NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = r.role_id AND rm.menu_id = m.menu_id);
|
||||
INSERT INTO sys_role_menu (role_id,menu_id)
|
||||
SELECT r.role_id, commission_id FROM sys_role r
|
||||
WHERE r.del_flag = '0' AND r.status = '0' AND (r.role_id = 1 OR r.role_key IN ('ORA_6042','ORA_6043'))
|
||||
AND NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = r.role_id AND rm.menu_id = commission_id);
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT 'AR_PROFIT_UPGRADE_COMPLETED' AS upgrade_status,
|
||||
(SELECT COUNT(*) FROM ar_bill WHERE profit_customer_area IS NULL) AS missing_area,
|
||||
(SELECT COUNT(*) FROM ar_bill WHERE profit_sales_user_id IS NULL) AS missing_sales,
|
||||
(SELECT COUNT(*) FROM ar_bill WHERE generation_status IS NULL AND status IN ('CONFIRMED','PARTIAL_WRITTEN_OFF','WRITTEN_OFF')) AS unknown_generation_status,
|
||||
(SELECT COUNT(*) FROM ar_profit_writeoff_rate r JOIN ar_balance_writeoff w ON w.writeoff_id = r.writeoff_id
|
||||
JOIN ar_bill b ON b.ar_bill_id = w.ar_bill_id
|
||||
WHERE (r.rate IS NULL OR r.rate < 0 OR r.rate > 100) AND w.status = 'EFFECTIVE' AND b.generation_status = 'READY' AND b.status IN ('CONFIRMED','PARTIAL_WRITTEN_OFF','WRITTEN_OFF')) AS missing_writeoff_rates,
|
||||
(SELECT COUNT(*) FROM ar_bill b WHERE b.status = 'WRITTEN_OFF' AND NOT EXISTS
|
||||
(SELECT 1 FROM ar_balance_writeoff w WHERE w.ar_bill_id = b.ar_bill_id AND w.status = 'EFFECTIVE')) AS paid_bills_without_writeoffs;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
CALL bms_ar_profit_upgrade_20261105_v1();
|
||||
DROP PROCEDURE IF EXISTS bms_ar_profit_upgrade_20261105_v1;
|
||||
@@ -1,29 +1,75 @@
|
||||
-- Exclusive quote module menus
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- Top-level directory
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
SELECT 2600, N'专属报价', 0, 55, 'exclusive', NULL, '', '', 1, 0, 'M', '0', '0', '', 'money', 'admin', sysdate(), N'老板客户专属报价'
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2600 OR (path = 'exclusive' AND parent_id = 0 AND menu_type = 'M'));
|
||||
-- Exclusive package menus under package management (套餐管理).
|
||||
-- Idempotent: create if missing, rename/reparent if already present, drop obsolete top directory 专属报价.
|
||||
|
||||
SET @exParentId := (SELECT menu_id FROM sys_menu WHERE menu_id = 2600 LIMIT 1);
|
||||
SET @exParentId := IFNULL(@exParentId, (
|
||||
SELECT menu_id FROM sys_menu WHERE path = 'exclusive' AND menu_type = 'M' AND parent_id = 0 ORDER BY menu_id ASC LIMIT 1
|
||||
));
|
||||
SET @pkgParentId := (
|
||||
SELECT menu_id FROM sys_menu
|
||||
WHERE menu_id = 2200
|
||||
OR (menu_name = N'套餐管理' AND parent_id = 0 AND menu_type = 'M')
|
||||
ORDER BY CASE WHEN menu_id = 2200 THEN 0 ELSE 1 END, menu_id
|
||||
LIMIT 1
|
||||
);
|
||||
|
||||
-- List page
|
||||
-- Drop obsolete top-level directory (and role links)
|
||||
DELETE FROM sys_role_menu WHERE menu_id = 2600;
|
||||
DELETE FROM sys_menu
|
||||
WHERE menu_id = 2600
|
||||
OR (path = 'exclusive' AND parent_id = 0 AND menu_type = 'M' AND menu_name = N'专属报价');
|
||||
|
||||
-- List: 专属套餐
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
SELECT 2601, N'报价列表', @exParentId, 1, 'quote', 'price/exclusive/exclusiveQuote', '', 'ExclusiveQuote', 1, 0, 'C', '0', '0', 'price:exclusive:list', 'list', 'admin', sysdate(), N'专属报价列表'
|
||||
FROM DUAL WHERE @exParentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2601 OR perms = 'price:exclusive:list');
|
||||
SELECT 2601, N'专属套餐', @pkgParentId, 2, 'quote', 'price/exclusive/exclusiveQuote', '', 'ExclusiveQuote', 1, 0, 'C', '0', '0', 'price:exclusive:list', 'list', 'admin', sysdate(), N'专属套餐列表'
|
||||
FROM DUAL WHERE @pkgParentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2601 OR perms = 'price:exclusive:list');
|
||||
|
||||
UPDATE sys_menu
|
||||
SET menu_name = N'专属套餐',
|
||||
parent_id = @pkgParentId,
|
||||
order_num = 2,
|
||||
path = 'quote',
|
||||
component = 'price/exclusive/exclusiveQuote',
|
||||
route_name = 'ExclusiveQuote',
|
||||
remark = N'专属套餐列表',
|
||||
update_by = 'admin',
|
||||
update_time = sysdate()
|
||||
WHERE @pkgParentId IS NOT NULL AND (menu_id = 2601 OR perms = 'price:exclusive:list');
|
||||
|
||||
-- Hidden create / detail
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
SELECT 2609, N'报价新建', @exParentId, 2, 'quoteCreate', 'price/exclusive/create', '', 'ExclusiveQuoteCreate', 1, 0, 'C', '1', '0', 'price:exclusive:add', '#', 'admin', sysdate(), N'专属报价新建/编辑'
|
||||
FROM DUAL WHERE @exParentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2609 OR path = 'quoteCreate');
|
||||
SELECT 2609, N'专属套餐新建', @pkgParentId, 5, 'quoteCreate', 'price/exclusive/create', '', 'ExclusiveQuoteCreate', 1, 0, 'C', '1', '0', 'price:exclusive:add', '#', 'admin', sysdate(), N'专属套餐新建/编辑'
|
||||
FROM DUAL WHERE @pkgParentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2609 OR path = 'quoteCreate');
|
||||
|
||||
UPDATE sys_menu
|
||||
SET menu_name = N'专属套餐新建',
|
||||
parent_id = @pkgParentId,
|
||||
order_num = 5,
|
||||
path = 'quoteCreate',
|
||||
component = 'price/exclusive/create',
|
||||
route_name = 'ExclusiveQuoteCreate',
|
||||
remark = N'专属套餐新建/编辑',
|
||||
update_by = 'admin',
|
||||
update_time = sysdate()
|
||||
WHERE @pkgParentId IS NOT NULL AND (menu_id = 2609 OR path = 'quoteCreate');
|
||||
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
SELECT 2610, N'报价详情', @exParentId, 3, 'quoteDetail', 'price/exclusive/detail', '', 'ExclusiveQuoteDetail', 1, 0, 'C', '1', '0', 'price:exclusive:query', '#', 'admin', sysdate(), N'专属报价详情'
|
||||
FROM DUAL WHERE @exParentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2610 OR path = 'quoteDetail');
|
||||
SELECT 2610, N'专属套餐详情', @pkgParentId, 6, 'quoteDetail', 'price/exclusive/detail', '', 'ExclusiveQuoteDetail', 1, 0, 'C', '1', '0', 'price:exclusive:query', '#', 'admin', sysdate(), N'专属套餐详情'
|
||||
FROM DUAL WHERE @pkgParentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2610 OR path = 'quoteDetail');
|
||||
|
||||
UPDATE sys_menu
|
||||
SET menu_name = N'专属套餐详情',
|
||||
parent_id = @pkgParentId,
|
||||
order_num = 6,
|
||||
path = 'quoteDetail',
|
||||
component = 'price/exclusive/detail',
|
||||
route_name = 'ExclusiveQuoteDetail',
|
||||
remark = N'专属套餐详情',
|
||||
update_by = 'admin',
|
||||
update_time = sysdate()
|
||||
WHERE @pkgParentId IS NOT NULL AND (menu_id = 2610 OR path = 'quoteDetail');
|
||||
|
||||
-- Keep ordinary set create/detail order after list pages
|
||||
UPDATE sys_menu SET order_num = 3, update_by = 'admin', update_time = sysdate() WHERE menu_id = 2208;
|
||||
UPDATE sys_menu SET order_num = 4, update_by = 'admin', update_time = sysdate() WHERE menu_id = 2209;
|
||||
|
||||
-- Buttons under list
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
@@ -52,7 +98,7 @@ FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2607 OR (pare
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT 1, m.menu_id FROM (
|
||||
SELECT 2600 AS menu_id UNION SELECT 2601 UNION SELECT 2602 UNION SELECT 2603
|
||||
SELECT 2601 AS menu_id UNION SELECT 2602 UNION SELECT 2603
|
||||
UNION SELECT 2604 UNION SELECT 2605 UNION SELECT 2606 UNION SELECT 2607
|
||||
UNION SELECT 2609 UNION SELECT 2610
|
||||
) m
|
||||
|
||||
Reference in New Issue
Block a user