This commit is contained in:
wuweihua
2026-09-16 17:14:24 +08:00
45 changed files with 3786 additions and 77 deletions
+75
View File
@@ -0,0 +1,75 @@
-- =====================================================================
-- 客户余额核销应收账单 V1.0 2026-09-16
-- 1) 余额核销单表 ar_balance_writeoff(资金来源:customer_account.balance)
-- 2) 存量账单未核销金额重算 customer_account.used_credit 占用
-- 3) 菜单与授权:客户账单(2435) / 账单详情(2436) / 余额核销(2437) / 反核销(2438)
-- =====================================================================
-- 余额核销单:用客户账户余额核销应收账单(与 ar_receipt_writeoff 收款核销并列,
-- 两者共享 ar_bill.written_off_amount / unwritten_amount 缓存字段)
CREATE TABLE IF NOT EXISTS ar_balance_writeoff (
writeoff_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '余额核销ID',
writeoff_no VARCHAR(50) NOT NULL COMMENT '核销单号(BWO开头)',
ar_bill_id BIGINT(20) NOT NULL COMMENT '应收账单ID',
bill_no VARCHAR(50) NOT NULL COMMENT '账单号快照',
customer_id BIGINT(20) NOT NULL COMMENT '客户ID',
account_id BIGINT(20) DEFAULT NULL COMMENT '客户账户ID',
currency VARCHAR(10) NOT NULL DEFAULT 'CNY' COMMENT '币种',
writeoff_amount DECIMAL(18,2) NOT NULL DEFAULT 0.00 COMMENT '本次核销金额',
balance_flow_id BIGINT(20) DEFAULT NULL COMMENT '核销扣余额流水ID',
reverse_flow_id BIGINT(20) DEFAULT NULL COMMENT '反核销回补余额流水ID',
writeoff_date DATE NOT NULL COMMENT '核销日期',
status VARCHAR(30) NOT NULL COMMENT 'EFFECTIVE/CANCELLED',
remark VARCHAR(500) DEFAULT NULL COMMENT '核销备注',
create_by VARCHAR(64) NOT NULL COMMENT '创建人',
create_time DATETIME NOT NULL COMMENT '创建时间',
cancel_by VARCHAR(64) DEFAULT NULL COMMENT '反核销人',
cancel_time DATETIME DEFAULT NULL COMMENT '反核销时间',
cancel_remark VARCHAR(500) DEFAULT NULL COMMENT '反核销原因',
PRIMARY KEY (writeoff_id),
UNIQUE KEY uk_ar_balance_writeoff_no (writeoff_no),
KEY idx_abw_bill (ar_bill_id, status),
KEY idx_abw_customer (customer_id, status),
KEY idx_abw_account (account_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单余额核销表';
-- 存量数据:为仅有账单、没有账户的客户补建账户(理论上CNY账户均已自动开户)
INSERT INTO customer_account (customer_id, currency, balance, frozen_balance, total_credit, extra_credit, used_credit, tax, version, create_by, create_time, del_flag)
SELECT b.customer_id, b.currency, 0, 0, 0, 0, 0, 0, 0, 'system', NOW(), '0'
FROM (
SELECT customer_id, currency FROM ar_bill
WHERE status IN ('CONFIRMED','PARTIAL_WRITTEN_OFF')
GROUP BY customer_id, currency
) b
LEFT JOIN customer_account a
ON a.customer_id = b.customer_id
AND a.currency COLLATE utf8mb4_general_ci = b.currency
AND a.del_flag = '0'
WHERE a.id IS NULL;
-- 已用额度 = 该客户该币种 已确认/部分核销账单的未核销金额合计
UPDATE customer_account a
JOIN (
SELECT customer_id, currency, SUM(unwritten_amount) AS used_total
FROM ar_bill
WHERE status IN ('CONFIRMED','PARTIAL_WRITTEN_OFF')
GROUP BY customer_id, currency
) t ON t.customer_id = a.customer_id
AND t.currency COLLATE utf8mb4_general_ci = a.currency
SET a.used_credit = t.used_total,
a.version = a.version + 1,
a.update_by = 'system',
a.update_time = NOW()
WHERE a.del_flag = '0';
-- 菜单(父菜单 2309 = 客户/供应商管理;如环境ID不同请自行调整)
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
VALUES
(2435, '客户账单', 2309, 3, 'customerbill', 'customersuppliermanagement/customerinfo/customerbill/index', '', 1, 0, 'C', '0', '0', 'customer:bill:list', 'documentation', 'admin', NOW(), '客户应收账单只读查询'),
(2436, '账单详情', 2435, 1, '', NULL, '', 1, 0, 'F', '0', '0', 'customer:bill:query', '#', 'admin', NOW(), ''),
(2437, '余额核销', 2435, 2, '', NULL, '', 1, 0, 'F', '0', '0', 'customer:bill:writeoff', '#', 'admin', NOW(), '用客户账户余额核销应收账单'),
(2438, '取消余额核销', 2435, 3, '', NULL, '', 1, 0, 'F', '0', '0', 'customer:bill:writeoff:cancel', '#', 'admin', NOW(), '反核销');
-- 普通角色授权(按实际角色调整)
INSERT INTO sys_role_menu (role_id, menu_id) VALUES
(2, 2435), (2, 2436), (2, 2437), (2, 2438);
+6 -6
View File
@@ -43,7 +43,7 @@ CREATE TABLE IF NOT EXISTS ar_bill (
CREATE TABLE IF NOT EXISTS ar_bill_detail (
detail_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '账单订单明细ID',
ar_bill_id BIGINT(20) NOT NULL COMMENT '应收账单ID',
prc_bill_id VARCHAR(36) NOT NULL COMMENT '来源订单计费ID,保持来源类型',
prc_order_bill_id VARCHAR(36) NOT NULL COMMENT '来源计费订单ID,对应 prc_order_bill.bill_id',
detail_no INT(11) NOT NULL COMMENT '账单内顺序号',
order_no VARCHAR(64) NOT NULL COMMENT '订单号快照',
tracking_no VARCHAR(64) DEFAULT NULL COMMENT '运单号快照',
@@ -66,16 +66,16 @@ CREATE TABLE IF NOT EXISTS ar_bill_detail (
create_by VARCHAR(64) NOT NULL COMMENT '创建人',
create_time DATETIME NOT NULL COMMENT '创建时间',
PRIMARY KEY (detail_id),
UNIQUE KEY uk_ar_bill_detail_source (ar_bill_id, prc_bill_id),
UNIQUE KEY uk_ar_bill_detail_source (ar_bill_id, prc_order_bill_id),
UNIQUE KEY uk_ar_bill_detail_no (ar_bill_id, detail_no),
KEY idx_ar_bill_detail_source (prc_bill_id),
KEY idx_ar_bill_detail_source (prc_order_bill_id),
CONSTRAINT fk_ar_bill_detail_bill FOREIGN KEY (ar_bill_id) REFERENCES ar_bill (ar_bill_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单订单快照';
CREATE TABLE IF NOT EXISTS ar_bill_detail_fee (
detail_fee_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '账单费用明细ID',
detail_id BIGINT(20) NOT NULL COMMENT '账单订单明细ID',
prc_fee_id VARCHAR(36) NOT NULL COMMENT '来源费用ID,保持来源类型',
prc_income_bill_fee_id VARCHAR(36) NOT NULL COMMENT '来源收入费用ID,对应 prc_income_bill_fee.fee_id',
fee_no INT(11) NOT NULL COMMENT '订单内费用顺序号',
fee_type VARCHAR(30) NOT NULL COMMENT '费用类型快照',
fee_name VARCHAR(100) DEFAULT NULL COMMENT '费用名称快照',
@@ -91,9 +91,9 @@ CREATE TABLE IF NOT EXISTS ar_bill_detail_fee (
create_by VARCHAR(64) NOT NULL COMMENT '创建人',
create_time DATETIME NOT NULL COMMENT '创建时间',
PRIMARY KEY (detail_fee_id),
UNIQUE KEY uk_ar_detail_prc_fee (detail_id, prc_fee_id),
UNIQUE KEY uk_ar_detail_prc_income_fee (detail_id, prc_income_bill_fee_id),
KEY idx_ar_detail_fee_type (fee_type),
KEY idx_ar_detail_prc_fee (prc_fee_id),
KEY idx_ar_detail_prc_income_fee (prc_income_bill_fee_id),
KEY idx_ar_detail_fee_order (detail_id, fee_no, detail_fee_id),
CONSTRAINT fk_ar_detail_fee_detail FOREIGN KEY (detail_id) REFERENCES ar_bill_detail (detail_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='应收账单费用快照';
@@ -1,5 +1,6 @@
-- 应收账单:订单占用状态 + 单日期截止日迁移
-- 适用于已经执行过 ar/ar_bill.sql、price/bill.sql 的数据库。
-- 若数据库中的应收明细仍使用旧来源ID列名,请先执行 ar_bill_source_id_rename.sql。
-- 请在业务低峰期执行;本脚本只做字段、索引和历史状态初始化,不删除账单明细。
SET NAMES utf8mb4;
SET @db_name := DATABASE();
@@ -60,11 +61,11 @@ DEALLOCATE PREPARE stmt;
-- 3. 根据已有账单明细回填历史订单状态。作废账单不占用订单。
UPDATE prc_order_bill o
JOIN (
SELECT DISTINCT d.prc_bill_id
SELECT DISTINCT d.prc_order_bill_id
FROM ar_bill_detail d
JOIN ar_bill b ON b.ar_bill_id = d.ar_bill_id
WHERE b.status <> 'VOID'
) billed ON billed.prc_bill_id = o.bill_id
) billed ON billed.prc_order_bill_id = o.bill_id
SET o.ar_bill_status = 'BILLED'
WHERE COALESCE(o.ar_bill_status, 'UNBILLED') <> 'BILLED';
@@ -0,0 +1,95 @@
-- 应收账单来源ID字段命名迁移
--
-- 将历史字段名迁移为与当前来源表一致的名称:
-- ar_bill_detail.prc_bill_id -> prc_order_bill_id
-- ar_bill_detail_fee.prc_fee_id -> prc_income_bill_fee_id
-- 脚本可重复执行,已完成迁移的字段和索引会自动跳过。
SET NAMES utf8mb4;
SET @db_name := DATABASE();
-- 1. 应收账单订单明细:来源计费订单ID。
SET @has_old_detail_column := (
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail'
AND COLUMN_NAME = 'prc_bill_id'
);
SET @has_new_detail_column := (
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail'
AND COLUMN_NAME = 'prc_order_bill_id'
);
SET @sql := IF(@has_old_detail_column > 0 AND @has_new_detail_column = 0,
'ALTER TABLE ar_bill_detail CHANGE COLUMN prc_bill_id prc_order_bill_id VARCHAR(36) NOT NULL COMMENT ''来源计费订单ID,对应 prc_order_bill.bill_id''',
'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2. 应收账单费用明细:来源收入费用ID。
SET @has_old_fee_column := (
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail_fee'
AND COLUMN_NAME = 'prc_fee_id'
);
SET @has_new_fee_column := (
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail_fee'
AND COLUMN_NAME = 'prc_income_bill_fee_id'
);
SET @sql := IF(@has_old_fee_column > 0 AND @has_new_fee_column = 0,
'ALTER TABLE ar_bill_detail_fee CHANGE COLUMN prc_fee_id prc_income_bill_fee_id VARCHAR(36) NOT NULL COMMENT ''来源收入费用ID,对应 prc_income_bill_fee.fee_id''',
'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 3. 费用明细索引同步改名,避免数据库中继续保留旧字段命名。
SET @has_old_fee_unique := (
SELECT COUNT(*)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail_fee'
AND INDEX_NAME = 'uk_ar_detail_prc_fee'
);
SET @has_new_fee_unique := (
SELECT COUNT(*)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail_fee'
AND INDEX_NAME = 'uk_ar_detail_prc_income_fee'
);
SET @sql := IF(@has_old_fee_unique > 0 AND @has_new_fee_unique = 0,
'ALTER TABLE ar_bill_detail_fee RENAME INDEX uk_ar_detail_prc_fee TO uk_ar_detail_prc_income_fee',
'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @has_old_fee_index := (
SELECT COUNT(*)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail_fee'
AND INDEX_NAME = 'idx_ar_detail_prc_fee'
);
SET @has_new_fee_index := (
SELECT COUNT(*)
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db_name
AND TABLE_NAME = 'ar_bill_detail_fee'
AND INDEX_NAME = 'idx_ar_detail_prc_income_fee'
);
SET @sql := IF(@has_old_fee_index > 0 AND @has_new_fee_index = 0,
'ALTER TABLE ar_bill_detail_fee RENAME INDEX idx_ar_detail_prc_fee TO idx_ar_detail_prc_income_fee',
'SELECT 1');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;