结算初始化
This commit is contained in:
parent
acd37d0e19
commit
890846057f
60
b/account_config.sql
Normal file
60
b/account_config.sql
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : kbossdev
|
||||
Source Server Type : MariaDB
|
||||
Source Server Version : 100622
|
||||
Source Host : db:3306
|
||||
Source Schema : kboss_dev
|
||||
|
||||
Target Server Type : MariaDB
|
||||
Target Server Version : 100622
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 18/06/2026 17:11:12
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for account_config
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `account_config`;
|
||||
CREATE TABLE `account_config` (
|
||||
`id` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'id',
|
||||
`partytype` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '参与方类型',
|
||||
`subjectname` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '科目名称',
|
||||
`del_flg` varchar(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '创建时间戳',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '账户配置表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of account_config
|
||||
-- ----------------------------
|
||||
INSERT INTO `account_config` VALUES ('acc001', '本机构', '资金账号', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc002', '本机构', '折扣收入', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc003', '本机构', '底价收入', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc004', '本机构', '客户折扣支出', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc005', '本机构', '存放供应商资金', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc006', '本机构', '分销商代付费销售', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc007', '本机构', '支付宝手续费', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc008', '客户', '业务账', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc009', '供应商', '待结转折扣销售收入', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc010', '供应商', '待结转代付费销售收入', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc011', '供应商', '待结转底价销售收入', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc012', '分销商', '分销商存放资金', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc013', '分销商', '待结转折扣支出', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc014', '分销商', '待结转代付费支出', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc015', '分销商', '待结转底价支出', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc016', '分销商', '代付费销售', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `account_config` VALUES ('acc017', '客户', '算力券', '0', '2025-03-31 11:36:11');
|
||||
INSERT INTO `account_config` VALUES ('acc019', '算力券发行方', '算力券发放', '0', '2025-04-08 11:21:33');
|
||||
INSERT INTO `account_config` VALUES ('acc020', '算力券发行方', '算力券消费', '0', '2025-04-08 11:21:43');
|
||||
INSERT INTO `account_config` VALUES ('acc021', '算力券承销方', '待结算算力券', '0', '2025-04-08 11:29:56');
|
||||
INSERT INTO `account_config` VALUES ('acc022', '本机构', '算力劵临时账户', '0', '2025-04-10 16:34:46');
|
||||
INSERT INTO `account_config` VALUES ('acc023', '分销商', '算力劵临时账户', '0', '2025-04-10 16:34:55');
|
||||
INSERT INTO `account_config` VALUES ('acc024', '供应商', '算力劵临时账户', '0', '2025-04-10 16:35:03');
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
131
b/accounting_config.sql
Normal file
131
b/accounting_config.sql
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : kbossdev
|
||||
Source Server Type : MariaDB
|
||||
Source Server Version : 100622
|
||||
Source Host : db:3306
|
||||
Source Schema : kboss_dev
|
||||
|
||||
Target Server Type : MariaDB
|
||||
Target Server Version : 100622
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 18/06/2026 17:11:43
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for accounting_config
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `accounting_config`;
|
||||
CREATE TABLE `accounting_config` (
|
||||
`id` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'id',
|
||||
`action` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '交易',
|
||||
`specstr` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '特性',
|
||||
`accounting_orgtype` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '账务机构',
|
||||
`accounting_dir` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '记账方向',
|
||||
`orgtype` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '机构类型',
|
||||
`subjectname` varchar(21) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '科目名',
|
||||
`amt_pattern` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '金额模板',
|
||||
`del_flg` varchar(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '创建时间戳',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '记账配置表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of accounting_config
|
||||
-- ----------------------------
|
||||
INSERT INTO `accounting_config` VALUES ('accc-01', '充值', '充值', '客户所在机构', '借', '本机构', '资金账号', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-02', '充值', '充值', '客户所在机构', '贷', '客户', '业务账', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-03', '充值', '充值', '分销商机构', '借', '本机构', '资金账号', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-04', '充值', '充值', '分销商机构', '贷', '分销商', '分销商存放资金', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-05', '交易', '付费-折扣', '客户所在机构', '借', '客户', '业务账', '${交易金额}$ * ${客户折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-06', '交易', '付费-折扣', '客户所在机构', '贷', '本机构', '折扣收入', '${交易金额}$ * (${客户折扣}$ - ${本方折扣}$)', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-07', '交易', '付费-折扣', '客户所在机构', '贷', '供应商', '待结转折扣销售收入', '${交易金额}$ * ${本方折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-08', '交易', '付费-折扣-折扣', '分销商机构', '借', '分销商', '分销商存放资金', '${交易金额}$ * ${分销商折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-09', '交易', '付费-折扣-折扣', '分销商机构', '贷', '本机构', '折扣收入', '${交易金额}$ * (${分销商折扣}$ - ${本方折扣}$)', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-10', '交易', '付费-折扣-折扣', '分销商机构', '贷', '供应商', '待结转折扣销售收入', '${交易金额}$ * ${本方折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-11', '交易', '付费-折扣-代付费', '分销商机构', '借', '分销商', '分销商存放资金', '${交易金额}$ * ${客户折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-12', '交易', '付费-折扣-代付费', '分销商机构', '贷', '本机构', '折扣收入', '${交易金额}$ * (${客户折扣}$ - ${本方折扣}$)', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-13', '交易', '付费-折扣-代付费', '分销商机构', '贷', '供应商', '待结转折扣销售收入', '${交易金额}$ * ${本方折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-14', '交易', '付费-折扣-代付费', '分销商机构', '借', '本机构', '分销商代付费销售', '${交易金额}$ * ${客户折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-15', '交易', '付费-折扣-代付费', '分销商机构', '贷', '分销商', '代付费销售', '${交易金额}$ * ${客户折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-16', '交易', '付费-代付费', '客户所在机构', '借', '客户', '业务账', '${交易金额}$ * ${客户折扣}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-17', '交易', '付费-代付费', '客户所在机构', '借', '本机构', '客户折扣支出', '${交易金额}$ * (1 - ${客户折扣}$)', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-18', '交易', '付费-代付费', '客户所在机构', '贷', '供应商', '待结转代付费销售收入', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-19', '交易', '付费-代付费-代付费', '分销商机构', '借', '分销商', '分销商存放资金', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-20', '交易', '付费-代付费-代付费', '分销商机构', '贷', '供应商', '待结转代付费销售收入', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-21', '交易', '付费-代付费-代付费', '分销商机构', '借', '本机构', '分销商代付费销售', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-22', '交易', '付费-代付费-代付费', '分销商机构', '贷', '分销商', '代付费销售', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-23', '交易', '付费-底价', '客户所在机构', '借', '客户', '业务账', '${客户售价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-24', '交易', '付费-底价', '客户所在机构', '贷', '本机构', '底价收入', '${客户售价}$ - ${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-25', '交易', '付费-底价', '客户所在机构', '贷', '供应商', '待结转底价销售收入', '${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-26', '交易', '付费-底价-底价', '分销商机构', '借', '分销商', '分销商存放资金', '${分销商售价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-27', '交易', '付费-底价-底价', '分销商机构', '贷', '本机构', '底价收入', '${分销商售价}$ - ${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-28', '交易', '付费-底价-底价', '分销商机构', '贷', '供应商', '待结转底价销售收入', '${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-29', '交易', '付费-底价-底价', '分销商机构', '借', '分销商', '分销商存放资金', '${客户售价}$ * ${分销商售价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-30', '交易', '付费-底价-底价', '分销商机构', '贷', '本机构', '底价收入', '${客户售价}$ * ${分销商售价}$ - ${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-31', '交易', '付费-底价-底价', '分销商机构', '贷', '供应商', '待结转底价销售收入', '${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-32', '交易', '付费-底价-代付费', '分销商机构', '借', '分销商', '分销商存放资金', '${客户售价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-33', '交易', '付费-底价-代付费', '分销商机构', '贷', '本机构', '底价收入', '${客户售价}$ - ${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-34', '交易', '付费-底价-代付费', '分销商机构', '贷', '供应商', '待结转底价销售收入', '${进价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-35', '交易', '付费-底价-代付费', '分销商机构', '借', '本机构', '分销商代付费销售', '${客户售价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-36', '交易', '付费-底价-代付费', '分销商机构', '贷', '分销商', '代付费销售', '${客户售价}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-37', '结算', '结算-折扣-实时', NULL, '借', '供应商', '待结转折扣销售收入', '${贷-供应商-待结转折扣销售收入}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-38', '结算', '结算-折扣-实时', NULL, '贷', '本机构', '资金账号', '${贷-供应商-待结转折扣销售收入}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-39', '结算', '结算-代付费-实时', NULL, '借', '供应商', '待结转代付费销售收入', '${贷-供应商-待结转代付费销售收入}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-40', '结算', '结算-代付费-实时', NULL, '贷', '本机构', '资金账号', '${贷-供应商-待结转代付费销售收入}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-41', '结算', '结算-底价-实时', NULL, '借', '供应商', '待结转底价销售收入', '${贷-供应商-待结转底价销售收入}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-42', '结算', '结算-底价-实时', NULL, '贷', '本机构', '资金账号', '${贷-供应商-待结转底价销售收入}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-43', '结算', '结算-折扣', NULL, '借', '供应商', '待结转折扣销售收入', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-44', '结算', '结算-折扣', NULL, '贷', '本机构', '资金账号', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-45', '结算', '结算-代付费', NULL, '借', '供应商', '待结转代付费销售收入', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-46', '结算', '结算-代付费', NULL, '贷', '本机构', '资金账号', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-47', '结算', '结算-底价', NULL, '借', '供应商', '待结转底价销售收入', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-48', '结算', '结算-底价', NULL, '贷', '本机构', '资金账号', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-49', '充值', '支付宝充值', '客户所在机构', '借', '本机构', '资金账号', '${交易金额}$ - ${手续费}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-50', '充值', '支付宝充值', '客户所在机构', '借', '本机构', '支付宝手续费', '${手续费}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-51', '充值', '支付宝充值', '客户所在机构', '贷', '客户', '业务账', '${交易金额}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-52', '充值', '支付宝充值', '分销商机构', '借', '本机构', '资金账号', '${交易金额}$ - ${手续费}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-53', '充值', '支付宝充值', '分销商机构', '贷', '分销商', '分销商存放资金', '${交易金额}$ - ${手续费}$', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-54', '算力劵发行', '算力劵充值', '算力劵承销方', '借', '算力劵发行方', '算力劵发行', '${交易金额}$', '0', '2025-04-08 17:33:03');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-55', '算力劵发行', '算力劵充值', '算力劵承销方', '贷', '本机构', '算力劵临时账户', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-56', '算力劵发放', '算力劵充值', '分销商机构', '借', '本机构', '算力劵临时账户', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-57', '算力劵发放', '算力劵充值', '分销商机构', '贷', '分销商', '算力劵临时账户', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-58', '算力劵发放', '算力劵充值', '客户所在机构', '借', '本机构', '算力劵临时账户', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-59', '算力劵发放', '算力劵充值', '客户所在机构', '贷', '客户', '算力劵', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-60', '算力劵交易', '算力券-付费-折扣', '客户所在机构', '借', '客户', '算力劵', '${交易金额}*${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-61', '算力劵交易', '算力券-付费-折扣', '客户所在机构', '贷', '本机构', '算力劵临时账户', '${交易金额}*${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-62', '算力劵交易', '算力券-付费-折扣', '客户所在机构', '借', '供应商', '算力劵临时账户', '${交易金额}*${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-63', '算力劵交易', '算力券-付费-折扣', '客户所在机构', '贷', '本机构', '折扣收入', '${交易金额}*(${客户折扣}-${本方折扣})$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-64', '算力劵交易', '算力券-付费-折扣', '客户所在机构', '贷', '供应商', '待结转折扣销售收入', '${交易金额}$*${分销商折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-65', '算力劵交易', '算力券-付费-折扣-折扣', '分销商机构', '借', '本机构', '算力劵临时账户', '${交易金额}$*${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-66', '算力劵交易', '算力券-付费-折扣-折扣', '分销商机构', '贷', '供应商', '算力劵临时账户', '${交易金额}$*${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-67', '算力劵交易', '算力券-付费-折扣-折扣', '分销商机构', '贷', '本机构', '折扣收入', '${交易金额}$*(${分销商折扣}$ -${本方折扣}$)', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-68', '算力劵交易', '算力券-付费-折扣-折扣', '分销商机构', '贷', '供应商', '待结转折扣销售收入', '${交易金额}$*${本方折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-69', '算力劵交易', '算力券-付费-折扣-折扣', '分销商机构', '借', '分销商', '分销商存放资金', '${交易金额}$*${分销商折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-70', '算力劵交易', '算力券-付费-底价', '客户所在机构', '借', '客户', '算力劵', '${客户售价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-71', '算力劵交易', '算力券-付费-底价', '客户所在机构', '贷', '本机构', '算力劵临时账户', '${客户售价}$ - ${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-72', '算力劵交易', '算力券-付费-底价', '客户所在机构', '借', '供应商', '算力劵临时账户', '${客户售价}$ - ${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-73', '算力劵交易', '算力券-付费-底价', '客户所在机构', '贷', '本机构', '底价收入', '${客户售价}$ - ${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-74', '算力劵交易', '算力券-付费-底价', '客户所在机构', '贷', '供应商', '待结转底价销售收入', '${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-75', '算力劵交易', '算力券-付费-底价-底价', '分销商机构', '借', '本机构', '算力劵临时账户', '${客户售价}$ - ${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-76', '算力劵交易', '算力券-付费-底价-底价', '分销商机构', '贷', '供应商', '算力劵临时账户', '${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-77', '算力劵交易', '算力券-付费-底价-底价', '分销商机构', '贷', '本机构', '底价收入', '${客户售价}$ - ${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-78', '算力劵交易', '算力券-付费-底价-底价', '分销商机构', '贷', '供应商', '待结转底价销售收入', '${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-79', '算力劵交易', '算力券-付费-底价-底价', '分销商机构', '借', '分销商', '分销商存放资金', '${客户售价}$ * ${分销商售价}$ - ${进价}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-80', '算力劵交易', '算力券-付费-底价', '客户所在机构', '借', '客户', '算力劵', '${交易金额}$ * ${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-81', '算力劵交易', '算力券-付费-底价', '客户所在机构', '贷', '本机构', '算力劵临时账户', '${交易金额}$ * ${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-82', '算力劵交易', '算力券-付费-代付费', '客户所在机构', '借', '供应商', '算力劵临时账户', '${交易金额}$ * ${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-83', '算力劵交易', '算力券-付费-代付费', '客户所在机构', '贷', '本机构', '底价收入', '${交易金额}$ * (1 - ${客户折扣}$)', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-84', '算力劵交易', '算力券-付费-代付费', '客户所在机构', '贷', '供应商', '待结转底价销售收入', '${交易金额}$ * ${客户折扣}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-85', '算力劵交易', '算力券-付费-代付费-代付费', '分销商机构', '借', '本机构', '算力劵临时账户', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-86', '算力劵交易', '算力券-付费-代付费-代付费', '分销商机构', '贷', '供应商', '算力劵临时账户', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-87', '算力劵交易', '算力券-付费-代付费-代付费', '分销商机构', '贷', '本机构', '底价收入', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-88', '算力劵交易', '算力券-付费-代付费-代付费', '分销商机构', '贷', '供应商', '待结转底价销售收入', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
INSERT INTO `accounting_config` VALUES ('accc-89', '算力劵交易', '算力券-付费-代付费-代付费', '分销商机构', '借', '分销商', '分销商存放资金', '${交易金额}$', '0', '2025-04-08 17:37:44');
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@ -2396,6 +2396,67 @@ CREATE TABLE `subject` (
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '科目表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for finance_settlement
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `finance_settlement`;
|
||||
CREATE TABLE `finance_settlement` (
|
||||
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id',
|
||||
`settlement_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '结算单号',
|
||||
`accounting_orgid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账本机构id',
|
||||
`counterparty_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '对手方类型 supplier/reseller',
|
||||
`counterparty_orgid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '对手方机构id',
|
||||
`counterparty_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '对手方名称',
|
||||
`period_type` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账期类型 day/month',
|
||||
`period_start` date NULL DEFAULT NULL COMMENT '账期开始日期',
|
||||
`period_end` date NULL DEFAULT NULL COMMENT '账期结束日期',
|
||||
`sales_amount` double(18, 8) NULL DEFAULT 0.00000000 COMMENT '销售金额',
|
||||
`settlement_amount` double(18, 8) NULL DEFAULT 0.00000000 COMMENT '结算金额',
|
||||
`platform_income_amount` double(18, 8) NULL DEFAULT 0.00000000 COMMENT '平台收入',
|
||||
`bill_count` int(11) NULL DEFAULT 0 COMMENT '账单数量',
|
||||
`status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'draft' COMMENT 'draft/approving/approved/rejected/settled/failed/cancelled',
|
||||
`approval_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '审批id',
|
||||
`approval_status` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '审批状态',
|
||||
`failure_reason` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '失败原因',
|
||||
`settled_at` datetime NULL DEFAULT NULL COMMENT '结算记账时间',
|
||||
`created_by` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
|
||||
`del_flg` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` datetime NULL DEFAULT current_timestamp() COMMENT '创建时间',
|
||||
`update_at` datetime NULL DEFAULT current_timestamp() COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `finance_settlement_un`(`accounting_orgid`, `counterparty_type`, `counterparty_orgid`, `period_start`, `period_end`, `del_flg`) USING BTREE,
|
||||
INDEX `finance_settlement_idx1`(`accounting_orgid`, `status`) USING BTREE,
|
||||
INDEX `finance_settlement_idx2`(`counterparty_type`, `counterparty_orgid`) USING BTREE,
|
||||
INDEX `finance_settlement_idx3`(`period_start`, `period_end`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '财务结算单主表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for finance_settlement_detail
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `finance_settlement_detail`;
|
||||
CREATE TABLE `finance_settlement_detail` (
|
||||
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id',
|
||||
`settlement_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '结算单id',
|
||||
`bill_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账单id',
|
||||
`order_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '订单id',
|
||||
`bill_date` date NULL DEFAULT NULL COMMENT '账单日期',
|
||||
`customerid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客户id',
|
||||
`providerid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '供应商机构id',
|
||||
`productid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '产品id',
|
||||
`business_op` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '业务操作',
|
||||
`sale_mode` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '销售模式 0折扣/1代付费/2底价',
|
||||
`sales_amount` double(18, 8) NULL DEFAULT 0.00000000 COMMENT '销售金额',
|
||||
`settlement_amount` double(18, 8) NULL DEFAULT 0.00000000 COMMENT '结算金额',
|
||||
`platform_income_amount` double(18, 8) NULL DEFAULT 0.00000000 COMMENT '平台收入',
|
||||
`amount_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'bill_detail' COMMENT '金额来源',
|
||||
`del_flg` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` datetime NULL DEFAULT current_timestamp() COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `finance_settlement_detail_idx1`(`settlement_id`) USING BTREE,
|
||||
INDEX `finance_settlement_detail_idx2`(`bill_id`) USING BTREE,
|
||||
INDEX `finance_settlement_detail_idx3`(`providerid`, `productid`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '财务结算单明细快照' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for transfer_record
|
||||
-- ----------------------------
|
||||
|
||||
301
b/bill/finance_settlement_apv_callback.dspy
Normal file
301
b/bill/finance_settlement_apv_callback.dspy
Normal file
@ -0,0 +1,301 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""财务结算审批回调。"""
|
||||
|
||||
import datetime
|
||||
|
||||
DBNAME = 'kboss'
|
||||
|
||||
|
||||
def _period_settle_mode(period_type):
|
||||
if period_type == 'day':
|
||||
return '1'
|
||||
if period_type == 'month':
|
||||
return '3'
|
||||
return '0'
|
||||
|
||||
|
||||
async def _business_date():
|
||||
try:
|
||||
return await get_business_date(sor=None)
|
||||
except Exception:
|
||||
return datetime.datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
|
||||
async def _settle_supplier(sor, settlement):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT sale_mode, SUM(settlement_amount) AS amount
|
||||
FROM finance_settlement_detail
|
||||
WHERE settlement_id=${settlement_id}$
|
||||
AND del_flg='0'
|
||||
GROUP BY sale_mode
|
||||
""", {'settlement_id': settlement['id']})
|
||||
settle_date = await _business_date()
|
||||
settle_mode = _period_settle_mode(settlement.get('period_type'))
|
||||
failures = []
|
||||
for row in rows:
|
||||
amount = round(float(row.get('amount') or 0), 8)
|
||||
if amount == 0:
|
||||
continue
|
||||
sale_mode = row.get('sale_mode') or '0'
|
||||
try:
|
||||
settle_log = {
|
||||
'accounting_orgid': settlement.get('accounting_orgid'),
|
||||
'providerid': settlement.get('counterparty_orgid'),
|
||||
'settle_date': settle_date,
|
||||
'settle_mode': settle_mode,
|
||||
'sale_mode': sale_mode,
|
||||
'settle_amt': amount,
|
||||
'business_op': 'SETTLE',
|
||||
}
|
||||
ai = SettleAccounting(settle_log)
|
||||
await ai.accounting(sor)
|
||||
except Exception as e:
|
||||
failures.append('sale_mode=%s: %s' % (sale_mode, str(e)))
|
||||
if failures:
|
||||
return False, '; '.join(failures)
|
||||
return True, None
|
||||
|
||||
|
||||
async def _get_account(sor, accounting_orgid, orgid, subjectname):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT a.*
|
||||
FROM account a
|
||||
INNER JOIN subject s ON a.subjectid=s.id
|
||||
WHERE a.accounting_orgid=${accounting_orgid}$
|
||||
AND a.orgid=${orgid}$
|
||||
AND s.name=${subjectname}$
|
||||
AND a.del_flg='0'
|
||||
AND s.del_flg='0'
|
||||
LIMIT 1
|
||||
""", {
|
||||
'accounting_orgid': accounting_orgid,
|
||||
'orgid': orgid,
|
||||
'subjectname': subjectname,
|
||||
})
|
||||
return rows[0] if rows else None
|
||||
|
||||
|
||||
async def _latest_balance(sor, accountid):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT balance
|
||||
FROM acc_balance
|
||||
WHERE accountid=${accountid}$ AND del_flg='0'
|
||||
ORDER BY acc_date DESC
|
||||
LIMIT 1
|
||||
""", {'accountid': accountid})
|
||||
if not rows or rows[0].get('balance') is None:
|
||||
return 0.0
|
||||
return float(rows[0].get('balance') or 0)
|
||||
|
||||
|
||||
def _next_balance(account, balance, acc_dir, amount):
|
||||
balance_at = account.get('balance_at')
|
||||
if (
|
||||
(balance_at == '0' and acc_dir == '1')
|
||||
or (balance_at == '1' and acc_dir == '0')
|
||||
):
|
||||
return balance - amount
|
||||
return balance + amount
|
||||
|
||||
|
||||
async def _write_balance(sor, accountid, acc_date, balance):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT id
|
||||
FROM acc_balance
|
||||
WHERE accountid=${accountid}$ AND acc_date=${acc_date}$ AND del_flg='0'
|
||||
LIMIT 1
|
||||
""", {'accountid': accountid, 'acc_date': acc_date})
|
||||
if rows:
|
||||
await sor.U('acc_balance', {
|
||||
'id': rows[0]['id'],
|
||||
'balance': balance,
|
||||
})
|
||||
else:
|
||||
await sor.C('acc_balance', {
|
||||
'id': uuid(),
|
||||
'accountid': accountid,
|
||||
'acc_date': acc_date,
|
||||
'balance': balance,
|
||||
'del_flg': '0',
|
||||
'create_at': datetime.datetime.now(),
|
||||
})
|
||||
|
||||
|
||||
async def _write_reseller_leg(
|
||||
sor,
|
||||
billid,
|
||||
acc_date,
|
||||
accounting_orgid,
|
||||
participantid,
|
||||
participanttype,
|
||||
subjectname,
|
||||
accounting_dir,
|
||||
amount,
|
||||
description,
|
||||
):
|
||||
account = await _get_account(sor, accounting_orgid, participantid, subjectname)
|
||||
if not account:
|
||||
raise Exception(
|
||||
'未找到账户 accounting_orgid=%s, orgid=%s, subject=%s'
|
||||
% (accounting_orgid, participantid, subjectname)
|
||||
)
|
||||
acc_dir = '0' if accounting_dir == '借' else '1'
|
||||
old_balance = await _latest_balance(sor, account['id'])
|
||||
new_balance = _next_balance(account, old_balance, acc_dir, amount)
|
||||
await _write_balance(sor, account['id'], acc_date, new_balance)
|
||||
await sor.C('bill_detail', {
|
||||
'id': uuid(),
|
||||
'accounting_orgid': accounting_orgid,
|
||||
'billid': billid,
|
||||
'description': description,
|
||||
'participantid': participantid,
|
||||
'participanttype': participanttype,
|
||||
'subjectname': subjectname,
|
||||
'accounting_dir': accounting_dir,
|
||||
'amount': amount,
|
||||
'del_flg': '0',
|
||||
'create_at': datetime.datetime.now(),
|
||||
})
|
||||
logid = uuid()
|
||||
await sor.C('accounting_log', {
|
||||
'id': logid,
|
||||
'accountid': account['id'],
|
||||
'acc_date': acc_date,
|
||||
'acc_timestamp': datetime.datetime.now(),
|
||||
'acc_dir': acc_dir,
|
||||
'summary': 'SETTLE',
|
||||
'amount': amount,
|
||||
'billid': billid,
|
||||
'del_flg': '0',
|
||||
'create_at': datetime.datetime.now(),
|
||||
})
|
||||
await sor.C('acc_detail', {
|
||||
'id': uuid(),
|
||||
'accountid': account['id'],
|
||||
'acc_date': acc_date,
|
||||
'acc_timestamp': datetime.datetime.now(),
|
||||
'acc_dir': acc_dir,
|
||||
'summary': 'SETTLE',
|
||||
'amount': amount,
|
||||
'balance': new_balance,
|
||||
'acclogid': logid,
|
||||
'del_flg': '0',
|
||||
'create_at': datetime.datetime.now(),
|
||||
})
|
||||
|
||||
|
||||
async def _settle_reseller(sor, settlement):
|
||||
amount = round(float(settlement.get('settlement_amount') or 0), 8)
|
||||
if amount == 0:
|
||||
return True, None
|
||||
if amount < 0:
|
||||
return False, '分销商结算金额为负数,需先人工确认红冲口径'
|
||||
|
||||
accounting_orgid = settlement.get('accounting_orgid')
|
||||
reseller_orgid = settlement.get('counterparty_orgid')
|
||||
settle_date = await _business_date()
|
||||
billid = uuid()
|
||||
description = '分销商结算-%s' % settlement.get('settlement_no')
|
||||
|
||||
await sor.C('bill', {
|
||||
'id': billid,
|
||||
'customerid': reseller_orgid,
|
||||
'business_op': 'SETTLE',
|
||||
'amount': amount,
|
||||
'bill_date': settle_date,
|
||||
'bill_timestamp': datetime.datetime.now(),
|
||||
'bill_state': '1',
|
||||
'del_flg': '0',
|
||||
'create_at': datetime.datetime.now(),
|
||||
})
|
||||
|
||||
# 结算分录:借记分销商存放资金,贷记本机构资金账号。
|
||||
await _write_reseller_leg(
|
||||
sor,
|
||||
billid,
|
||||
settle_date,
|
||||
accounting_orgid,
|
||||
reseller_orgid,
|
||||
'分销商',
|
||||
'分销商存放资金',
|
||||
'借',
|
||||
amount,
|
||||
description,
|
||||
)
|
||||
await _write_reseller_leg(
|
||||
sor,
|
||||
billid,
|
||||
settle_date,
|
||||
accounting_orgid,
|
||||
accounting_orgid,
|
||||
'本机构',
|
||||
'资金账号',
|
||||
'贷',
|
||||
amount,
|
||||
description,
|
||||
)
|
||||
return True, None
|
||||
|
||||
|
||||
async def finance_settlement_apv_callback(ns={}):
|
||||
approval_id = ns.get('approval_id') or ns.get('apv_id')
|
||||
status = ns.get('status')
|
||||
if not approval_id or not status:
|
||||
return {'status': False, 'msg': '缺少 approval_id/apv_id 或 status'}
|
||||
status_map = {
|
||||
'start': 'approving',
|
||||
'agree': 'approved',
|
||||
'refuse': 'rejected',
|
||||
'terminate': 'cancelled',
|
||||
}
|
||||
next_status = status_map.get(status, status)
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
rows = await sor.R('finance_settlement', {'approval_id': approval_id, 'del_flg': '0'})
|
||||
if not rows:
|
||||
return {'status': False, 'msg': '未找到结算审批数据'}
|
||||
now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
results = []
|
||||
for settlement in rows:
|
||||
update_data = {
|
||||
'id': settlement['id'],
|
||||
'approval_status': status,
|
||||
'status': next_status,
|
||||
'update_at': now_time,
|
||||
}
|
||||
if status != 'agree':
|
||||
await sor.U('finance_settlement', update_data)
|
||||
results.append({'settlement_id': settlement['id'], 'status': next_status})
|
||||
continue
|
||||
|
||||
if settlement.get('status') == 'settled':
|
||||
results.append({'settlement_id': settlement['id'], 'status': 'settled'})
|
||||
continue
|
||||
|
||||
if settlement.get('counterparty_type') == 'supplier':
|
||||
ok, err = await _settle_supplier(sor, settlement)
|
||||
else:
|
||||
ok, err = await _settle_reseller(sor, settlement)
|
||||
|
||||
if ok:
|
||||
update_data['status'] = 'settled'
|
||||
update_data['settled_at'] = now_time
|
||||
update_data['failure_reason'] = None
|
||||
results.append({'settlement_id': settlement['id'], 'status': 'settled'})
|
||||
else:
|
||||
update_data['status'] = 'failed'
|
||||
update_data['failure_reason'] = err
|
||||
results.append({
|
||||
'settlement_id': settlement['id'],
|
||||
'status': 'failed',
|
||||
'failure_reason': err,
|
||||
})
|
||||
await sor.U('finance_settlement', update_data)
|
||||
return {'status': True, 'msg': 'ok', 'data': results}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '审批回调处理失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_apv_callback(params_kw)
|
||||
return ret
|
||||
283
b/bill/finance_settlement_create.dspy
Normal file
283
b/bill/finance_settlement_create.dspy
Normal file
@ -0,0 +1,283 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""创建财务结算单并保存明细快照。"""
|
||||
|
||||
import datetime
|
||||
|
||||
DBNAME = 'kboss'
|
||||
|
||||
|
||||
def _round_money(v):
|
||||
return round(float(v or 0), 8)
|
||||
|
||||
|
||||
def _is_reverse_op(op):
|
||||
return str(op or '').upper().endswith('_REVERSE')
|
||||
|
||||
|
||||
def _sale_mode_from_subject(subjectname):
|
||||
text = str(subjectname or '')
|
||||
if '代付费' in text or '返佣' in text:
|
||||
return '1'
|
||||
if '底价' in text or '低价' in text:
|
||||
return '2'
|
||||
return '0'
|
||||
|
||||
|
||||
def _validate_params(ns):
|
||||
for key in ('accounting_orgid', 'counterparty_type', 'counterparty_orgid'):
|
||||
if not ns.get(key):
|
||||
return None, '缺少 %s' % key
|
||||
if ns.get('counterparty_type') not in ('supplier', 'reseller'):
|
||||
return None, 'counterparty_type 仅支持 supplier / reseller'
|
||||
period_type = ns.get('period_type') or 'day'
|
||||
if period_type not in ('day', 'month'):
|
||||
return None, 'period_type 仅支持 day / month'
|
||||
period_start = ns.get('period_start') or ns.get('start_date')
|
||||
period_end = ns.get('period_end') or ns.get('end_date')
|
||||
if not period_start or not period_end:
|
||||
return None, '缺少 period_start / period_end'
|
||||
return {
|
||||
'accounting_orgid': ns.get('accounting_orgid'),
|
||||
'counterparty_type': ns.get('counterparty_type'),
|
||||
'counterparty_orgid': ns.get('counterparty_orgid'),
|
||||
'period_type': period_type,
|
||||
'period_start': period_start,
|
||||
'period_end': period_end,
|
||||
'userid': ns.get('userid') or ns.get('user_id'),
|
||||
}, None
|
||||
|
||||
|
||||
async def _ensure_schema(sor):
|
||||
await sor.sqlExe("""
|
||||
CREATE TABLE IF NOT EXISTS finance_settlement (
|
||||
id varchar(32) NOT NULL,
|
||||
settlement_no varchar(64),
|
||||
accounting_orgid varchar(32),
|
||||
counterparty_type varchar(16),
|
||||
counterparty_orgid varchar(32),
|
||||
counterparty_name varchar(255),
|
||||
period_type varchar(16),
|
||||
period_start date,
|
||||
period_end date,
|
||||
sales_amount double(18,8) DEFAULT 0,
|
||||
settlement_amount double(18,8) DEFAULT 0,
|
||||
platform_income_amount double(18,8) DEFAULT 0,
|
||||
bill_count int DEFAULT 0,
|
||||
status varchar(16) DEFAULT 'draft',
|
||||
approval_id varchar(64),
|
||||
approval_status varchar(16),
|
||||
failure_reason varchar(1000),
|
||||
settled_at datetime,
|
||||
created_by varchar(32),
|
||||
del_flg varchar(1) DEFAULT '0',
|
||||
create_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
update_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY finance_settlement_un (accounting_orgid, counterparty_type, counterparty_orgid, period_start, period_end, del_flg)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
""", {})
|
||||
await sor.sqlExe("""
|
||||
CREATE TABLE IF NOT EXISTS finance_settlement_detail (
|
||||
id varchar(32) NOT NULL,
|
||||
settlement_id varchar(32),
|
||||
bill_id varchar(32),
|
||||
order_id varchar(32),
|
||||
bill_date date,
|
||||
customerid varchar(32),
|
||||
providerid varchar(32),
|
||||
productid varchar(32),
|
||||
business_op varchar(64),
|
||||
sale_mode varchar(1),
|
||||
sales_amount double(18,8) DEFAULT 0,
|
||||
settlement_amount double(18,8) DEFAULT 0,
|
||||
platform_income_amount double(18,8) DEFAULT 0,
|
||||
amount_source varchar(32) DEFAULT 'bill_detail',
|
||||
del_flg varchar(1) DEFAULT '0',
|
||||
create_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY finance_settlement_detail_idx1 (settlement_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
""", {})
|
||||
|
||||
|
||||
async def _existing_settlement(sor, args):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT id, settlement_no, status
|
||||
FROM finance_settlement
|
||||
WHERE accounting_orgid=${accounting_orgid}$
|
||||
AND counterparty_type=${counterparty_type}$
|
||||
AND counterparty_orgid=${counterparty_orgid}$
|
||||
AND period_start=${period_start}$
|
||||
AND period_end=${period_end}$
|
||||
AND del_flg='0'
|
||||
LIMIT 1
|
||||
""", args)
|
||||
return rows[0] if rows else None
|
||||
|
||||
|
||||
async def _counterparty_name(sor, args):
|
||||
if args['counterparty_type'] == 'supplier':
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT COALESCE(p.name, o.orgname) AS name
|
||||
FROM organization o
|
||||
LEFT JOIN provider p ON p.orgid=o.id AND p.del_flg='0'
|
||||
WHERE o.id=${counterparty_orgid}$ AND o.del_flg='0'
|
||||
LIMIT 1
|
||||
""", args)
|
||||
else:
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT orgname AS name FROM organization
|
||||
WHERE id=${counterparty_orgid}$ AND del_flg='0'
|
||||
LIMIT 1
|
||||
""", args)
|
||||
return rows[0].get('name') if rows else None
|
||||
|
||||
|
||||
async def _fetch_source_rows(sor, args):
|
||||
filters = [
|
||||
"b.del_flg='0'",
|
||||
"b.bill_state='1'",
|
||||
"b.bill_date >= ${period_start}$",
|
||||
"b.bill_date <= ${period_end}$",
|
||||
]
|
||||
if args['counterparty_type'] == 'supplier':
|
||||
filters.append('b.providerid=${counterparty_orgid}$')
|
||||
settlement_join = """
|
||||
LEFT JOIN bill_detail sd ON sd.billid=b.id
|
||||
AND sd.accounting_orgid=${accounting_orgid}$
|
||||
AND sd.del_flg='0'
|
||||
AND sd.accounting_dir='贷'
|
||||
AND sd.subjectname LIKE '待结转%'
|
||||
"""
|
||||
else:
|
||||
filters.append('cust.parentid=${counterparty_orgid}$')
|
||||
settlement_join = """
|
||||
LEFT JOIN bill_detail sd ON sd.billid=b.id
|
||||
AND sd.accounting_orgid=${accounting_orgid}$
|
||||
AND sd.del_flg='0'
|
||||
AND sd.accounting_dir='借'
|
||||
AND sd.subjectname='分销商存放资金'
|
||||
AND sd.participantid=cust.parentid
|
||||
"""
|
||||
|
||||
sql = """
|
||||
SELECT b.id AS bill_id, b.orderid AS order_id, b.bill_date,
|
||||
b.customerid, b.providerid, b.productid, b.business_op,
|
||||
b.amount AS sales_amount,
|
||||
COALESCE(sd.amount, 0) AS settlement_amount,
|
||||
sd.subjectname AS settlement_subject,
|
||||
COALESCE((
|
||||
SELECT SUM(bd.amount)
|
||||
FROM bill_detail bd
|
||||
WHERE bd.billid=b.id
|
||||
AND bd.accounting_orgid=${accounting_orgid}$
|
||||
AND bd.del_flg='0'
|
||||
AND bd.accounting_dir='贷'
|
||||
AND bd.subjectname IN ('折扣收入', '底价收入')
|
||||
), 0) AS platform_income_amount
|
||||
FROM bill b
|
||||
INNER JOIN organization cust ON cust.id=b.customerid AND cust.del_flg='0'
|
||||
%s
|
||||
WHERE %s
|
||||
ORDER BY b.bill_date DESC, b.create_at DESC
|
||||
""" % (settlement_join, ' AND '.join(filters))
|
||||
rows = await sor.sqlExe(sql, args)
|
||||
items = []
|
||||
seen_platform_bill = set()
|
||||
for row in rows:
|
||||
sign = -1 if _is_reverse_op(row.get('business_op')) else 1
|
||||
bill_id = row.get('bill_id')
|
||||
platform_income = float(row.get('platform_income_amount') or 0)
|
||||
if bill_id in seen_platform_bill:
|
||||
platform_income = 0
|
||||
seen_platform_bill.add(bill_id)
|
||||
items.append({
|
||||
'bill_id': bill_id,
|
||||
'order_id': row.get('order_id'),
|
||||
'bill_date': str(row.get('bill_date'))[:10] if row.get('bill_date') else None,
|
||||
'customerid': row.get('customerid'),
|
||||
'providerid': row.get('providerid'),
|
||||
'productid': row.get('productid'),
|
||||
'business_op': row.get('business_op'),
|
||||
'sale_mode': _sale_mode_from_subject(row.get('settlement_subject')),
|
||||
'sales_amount': _round_money(sign * float(row.get('sales_amount') or 0)),
|
||||
'settlement_amount': _round_money(sign * float(row.get('settlement_amount') or 0)),
|
||||
'platform_income_amount': _round_money(sign * platform_income),
|
||||
'amount_source': 'bill_detail',
|
||||
})
|
||||
return items
|
||||
|
||||
|
||||
def _summary(items):
|
||||
return {
|
||||
'sales_amount': _round_money(sum(i.get('sales_amount') or 0 for i in items)),
|
||||
'settlement_amount': _round_money(sum(i.get('settlement_amount') or 0 for i in items)),
|
||||
'platform_income_amount': _round_money(sum(i.get('platform_income_amount') or 0 for i in items)),
|
||||
'bill_count': len({i.get('bill_id') for i in items if i.get('bill_id')}),
|
||||
}
|
||||
|
||||
|
||||
async def finance_settlement_create(ns={}):
|
||||
args, err = _validate_params(ns)
|
||||
if err:
|
||||
return {'status': False, 'msg': err}
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
await _ensure_schema(sor)
|
||||
existing = await _existing_settlement(sor, args)
|
||||
if existing:
|
||||
return {'status': False, 'msg': '该账期已存在结算单', 'data': existing}
|
||||
items = await _fetch_source_rows(sor, args)
|
||||
if not items:
|
||||
return {'status': False, 'msg': '该账期无可结算已记账账单'}
|
||||
summary = _summary(items)
|
||||
settlement_id = uuid()
|
||||
settlement_no = 'FS%s%s' % (
|
||||
datetime.datetime.now().strftime('%Y%m%d%H%M%S'),
|
||||
str(settlement_id)[-6:],
|
||||
)
|
||||
master = {
|
||||
'id': settlement_id,
|
||||
'settlement_no': settlement_no,
|
||||
'accounting_orgid': args['accounting_orgid'],
|
||||
'counterparty_type': args['counterparty_type'],
|
||||
'counterparty_orgid': args['counterparty_orgid'],
|
||||
'counterparty_name': await _counterparty_name(sor, args),
|
||||
'period_type': args['period_type'],
|
||||
'period_start': args['period_start'],
|
||||
'period_end': args['period_end'],
|
||||
'sales_amount': summary['sales_amount'],
|
||||
'settlement_amount': summary['settlement_amount'],
|
||||
'platform_income_amount': summary['platform_income_amount'],
|
||||
'bill_count': summary['bill_count'],
|
||||
'status': 'draft',
|
||||
'created_by': args.get('userid'),
|
||||
'del_flg': '0',
|
||||
'create_at': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'update_at': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
}
|
||||
await sor.C('finance_settlement', master)
|
||||
for item in items:
|
||||
detail = dict(item)
|
||||
detail['id'] = uuid()
|
||||
detail['settlement_id'] = settlement_id
|
||||
detail['del_flg'] = '0'
|
||||
detail['create_at'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
await sor.C('finance_settlement_detail', detail)
|
||||
return {
|
||||
'status': True,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'settlement_id': settlement_id,
|
||||
'settlement_no': settlement_no,
|
||||
'status': 'draft',
|
||||
'summary': summary,
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '创建结算单失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_create(params_kw)
|
||||
return ret
|
||||
61
b/bill/finance_settlement_detail.dspy
Normal file
61
b/bill/finance_settlement_detail.dspy
Normal file
@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""财务结算单详情查询。"""
|
||||
|
||||
DBNAME = 'kboss'
|
||||
|
||||
|
||||
def _parse_page(ns, default_page=1, default_size=100, max_size=500):
|
||||
try:
|
||||
current_page = int(ns.get('current_page', default_page) or default_page)
|
||||
except (TypeError, ValueError):
|
||||
current_page = default_page
|
||||
try:
|
||||
page_size = int(ns.get('page_size', default_size) or default_size)
|
||||
except (TypeError, ValueError):
|
||||
page_size = default_size
|
||||
current_page = max(1, current_page)
|
||||
page_size = max(1, min(page_size, max_size))
|
||||
return current_page, page_size, (current_page - 1) * page_size
|
||||
|
||||
|
||||
async def finance_settlement_detail(ns={}):
|
||||
settlement_id = ns.get('settlement_id') or ns.get('id')
|
||||
if not settlement_id:
|
||||
return {'status': False, 'msg': '缺少 settlement_id'}
|
||||
current_page, page_size, offset = _parse_page(ns)
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
rows = await sor.R('finance_settlement', {'id': settlement_id, 'del_flg': '0'})
|
||||
if not rows:
|
||||
return {'status': False, 'msg': '结算单不存在'}
|
||||
count_rows = await sor.sqlExe("""
|
||||
SELECT COUNT(*) AS total_count
|
||||
FROM finance_settlement_detail
|
||||
WHERE settlement_id=${settlement_id}$ AND del_flg='0'
|
||||
""", {'settlement_id': settlement_id})
|
||||
total_count = count_rows[0]['total_count'] if count_rows else 0
|
||||
detail_rows = await sor.sqlExe("""
|
||||
SELECT *
|
||||
FROM finance_settlement_detail
|
||||
WHERE settlement_id=${settlement_id}$ AND del_flg='0'
|
||||
ORDER BY bill_date DESC, create_at DESC
|
||||
LIMIT %d OFFSET %d
|
||||
""" % (page_size, offset), {'settlement_id': settlement_id})
|
||||
return {
|
||||
'status': True,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'settlement': rows[0],
|
||||
'detail_total_count': total_count,
|
||||
'current_page': current_page,
|
||||
'page_size': page_size,
|
||||
'items': detail_rows,
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '查询结算单详情失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_detail(params_kw)
|
||||
return ret
|
||||
70
b/bill/finance_settlement_list.dspy
Normal file
70
b/bill/finance_settlement_list.dspy
Normal file
@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""财务结算单列表查询。"""
|
||||
|
||||
DBNAME = 'kboss'
|
||||
|
||||
|
||||
def _parse_page(ns, default_page=1, default_size=20, max_size=200):
|
||||
try:
|
||||
current_page = int(ns.get('current_page', default_page) or default_page)
|
||||
except (TypeError, ValueError):
|
||||
current_page = default_page
|
||||
try:
|
||||
page_size = int(ns.get('page_size', default_size) or default_size)
|
||||
except (TypeError, ValueError):
|
||||
page_size = default_size
|
||||
current_page = max(1, current_page)
|
||||
page_size = max(1, min(page_size, max_size))
|
||||
return current_page, page_size, (current_page - 1) * page_size
|
||||
|
||||
|
||||
async def finance_settlement_list(ns={}):
|
||||
accounting_orgid = ns.get('accounting_orgid')
|
||||
if not accounting_orgid:
|
||||
return {'status': False, 'msg': '缺少 accounting_orgid'}
|
||||
current_page, page_size, offset = _parse_page(ns)
|
||||
conditions = ["accounting_orgid=${accounting_orgid}$", "del_flg='0'"]
|
||||
params = {'accounting_orgid': accounting_orgid}
|
||||
for key in ('counterparty_type', 'counterparty_orgid', 'status', 'period_type'):
|
||||
if ns.get(key):
|
||||
conditions.append('%s=${%s}$' % (key, key))
|
||||
params[key] = ns[key]
|
||||
if ns.get('start_date'):
|
||||
conditions.append('period_end >= ${start_date}$')
|
||||
params['start_date'] = ns['start_date']
|
||||
if ns.get('end_date'):
|
||||
conditions.append('period_start <= ${end_date}$')
|
||||
params['end_date'] = ns['end_date']
|
||||
where_sql = ' AND '.join(conditions)
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
count_rows = await sor.sqlExe(
|
||||
'SELECT COUNT(*) AS total_count FROM finance_settlement WHERE %s' % where_sql,
|
||||
params,
|
||||
)
|
||||
total_count = count_rows[0]['total_count'] if count_rows else 0
|
||||
sql = """
|
||||
SELECT *
|
||||
FROM finance_settlement
|
||||
WHERE %s
|
||||
ORDER BY period_end DESC, create_at DESC
|
||||
LIMIT %d OFFSET %d
|
||||
""" % (where_sql, page_size, offset)
|
||||
rows = await sor.sqlExe(sql, params)
|
||||
return {
|
||||
'status': True,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'total_count': total_count,
|
||||
'current_page': current_page,
|
||||
'page_size': page_size,
|
||||
'items': rows,
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '查询结算单失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_list(params_kw)
|
||||
return ret
|
||||
89
b/bill/finance_settlement_migration.sql
Normal file
89
b/bill/finance_settlement_migration.sql
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
财务结算接口手动迁移 SQL。
|
||||
|
||||
执行范围:
|
||||
1. 新增统一结算主表 finance_settlement。
|
||||
2. 新增统一结算明细表 finance_settlement_detail。
|
||||
3. 如果表已经由接口自动创建,补齐 sale_mode 字段。
|
||||
|
||||
注意:
|
||||
- 不修改旧 provider_settle_data 流程。
|
||||
- 分销商结算记账依赖既有账户:
|
||||
account(accounting_orgid=上级机构, orgid=分销商机构, subject=分销商存放资金)
|
||||
account(accounting_orgid=上级机构, orgid=上级机构, subject=资金账号)
|
||||
*/
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `finance_settlement` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'id',
|
||||
`settlement_no` varchar(64) DEFAULT NULL COMMENT '结算单号',
|
||||
`accounting_orgid` varchar(32) DEFAULT NULL COMMENT '账本机构id',
|
||||
`counterparty_type` varchar(16) DEFAULT NULL COMMENT '对手方类型 supplier/reseller',
|
||||
`counterparty_orgid` varchar(32) DEFAULT NULL COMMENT '对手方机构id',
|
||||
`counterparty_name` varchar(255) DEFAULT NULL COMMENT '对手方名称',
|
||||
`period_type` varchar(16) DEFAULT NULL COMMENT '账期类型 day/month',
|
||||
`period_start` date DEFAULT NULL COMMENT '账期开始日期',
|
||||
`period_end` date DEFAULT NULL COMMENT '账期结束日期',
|
||||
`sales_amount` double(18,8) DEFAULT 0.00000000 COMMENT '销售金额',
|
||||
`settlement_amount` double(18,8) DEFAULT 0.00000000 COMMENT '结算金额',
|
||||
`platform_income_amount` double(18,8) DEFAULT 0.00000000 COMMENT '平台收入',
|
||||
`bill_count` int(11) DEFAULT 0 COMMENT '账单数量',
|
||||
`status` varchar(16) DEFAULT 'draft' COMMENT 'draft/approving/approved/rejected/settled/failed/cancelled',
|
||||
`approval_id` varchar(64) DEFAULT NULL COMMENT '审批id',
|
||||
`approval_status` varchar(16) DEFAULT NULL COMMENT '审批状态',
|
||||
`failure_reason` varchar(1000) DEFAULT NULL COMMENT '失败原因',
|
||||
`settled_at` datetime DEFAULT NULL COMMENT '结算记账时间',
|
||||
`created_by` varchar(32) DEFAULT NULL COMMENT '创建人',
|
||||
`del_flg` varchar(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` datetime DEFAULT current_timestamp() COMMENT '创建时间',
|
||||
`update_at` datetime DEFAULT current_timestamp() COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `finance_settlement_un` (`accounting_orgid`, `counterparty_type`, `counterparty_orgid`, `period_start`, `period_end`, `del_flg`),
|
||||
KEY `finance_settlement_idx1` (`accounting_orgid`, `status`),
|
||||
KEY `finance_settlement_idx2` (`counterparty_type`, `counterparty_orgid`),
|
||||
KEY `finance_settlement_idx3` (`period_start`, `period_end`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='财务结算单主表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `finance_settlement_detail` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'id',
|
||||
`settlement_id` varchar(32) DEFAULT NULL COMMENT '结算单id',
|
||||
`bill_id` varchar(32) DEFAULT NULL COMMENT '账单id',
|
||||
`order_id` varchar(32) DEFAULT NULL COMMENT '订单id',
|
||||
`bill_date` date DEFAULT NULL COMMENT '账单日期',
|
||||
`customerid` varchar(32) DEFAULT NULL COMMENT '客户id',
|
||||
`providerid` varchar(32) DEFAULT NULL COMMENT '供应商机构id',
|
||||
`productid` varchar(32) DEFAULT NULL COMMENT '产品id',
|
||||
`business_op` varchar(64) DEFAULT NULL COMMENT '业务操作',
|
||||
`sale_mode` varchar(1) DEFAULT NULL COMMENT '销售模式 0折扣/1代付费/2底价',
|
||||
`sales_amount` double(18,8) DEFAULT 0.00000000 COMMENT '销售金额',
|
||||
`settlement_amount` double(18,8) DEFAULT 0.00000000 COMMENT '结算金额',
|
||||
`platform_income_amount` double(18,8) DEFAULT 0.00000000 COMMENT '平台收入',
|
||||
`amount_source` varchar(32) DEFAULT 'bill_detail' COMMENT '金额来源',
|
||||
`del_flg` varchar(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` datetime DEFAULT current_timestamp() COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `finance_settlement_detail_idx1` (`settlement_id`),
|
||||
KEY `finance_settlement_detail_idx2` (`bill_id`),
|
||||
KEY `finance_settlement_detail_idx3` (`providerid`, `productid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='财务结算单明细快照';
|
||||
|
||||
ALTER TABLE `finance_settlement_detail`
|
||||
ADD COLUMN IF NOT EXISTS `sale_mode` varchar(1) DEFAULT NULL COMMENT '销售模式 0折扣/1代付费/2底价' AFTER `business_op`;
|
||||
|
||||
-- 执行分销商结算前,可用以下 SQL 检查目标账户是否存在:
|
||||
-- SELECT a.*
|
||||
-- FROM account a
|
||||
-- JOIN subject s ON a.subjectid=s.id
|
||||
-- WHERE a.accounting_orgid='<上级机构orgid>'
|
||||
-- AND a.orgid='<分销商orgid>'
|
||||
-- AND s.name='分销商存放资金'
|
||||
-- AND a.del_flg='0'
|
||||
-- AND s.del_flg='0';
|
||||
--
|
||||
-- SELECT a.*
|
||||
-- FROM account a
|
||||
-- JOIN subject s ON a.subjectid=s.id
|
||||
-- WHERE a.accounting_orgid='<上级机构orgid>'
|
||||
-- AND a.orgid='<上级机构orgid>'
|
||||
-- AND s.name='资金账号'
|
||||
-- AND a.del_flg='0'
|
||||
-- AND s.del_flg='0';
|
||||
281
b/bill/finance_settlement_preview.dspy
Normal file
281
b/bill/finance_settlement_preview.dspy
Normal file
@ -0,0 +1,281 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""财务结算单生成前预览。"""
|
||||
|
||||
DBNAME = 'kboss'
|
||||
|
||||
|
||||
def _round_money(v):
|
||||
return round(float(v or 0), 8)
|
||||
|
||||
|
||||
def _is_reverse_op(op):
|
||||
return str(op or '').upper().endswith('_REVERSE')
|
||||
|
||||
|
||||
def _sale_mode_from_subject(subjectname):
|
||||
text = str(subjectname or '')
|
||||
if '代付费' in text or '返佣' in text:
|
||||
return '1'
|
||||
if '底价' in text or '低价' in text:
|
||||
return '2'
|
||||
return '0'
|
||||
|
||||
|
||||
def _parse_page(ns, default_page=1, default_size=50, max_size=500):
|
||||
try:
|
||||
current_page = int(ns.get('current_page', default_page) or default_page)
|
||||
except (TypeError, ValueError):
|
||||
current_page = default_page
|
||||
try:
|
||||
page_size = int(ns.get('page_size', default_size) or default_size)
|
||||
except (TypeError, ValueError):
|
||||
page_size = default_size
|
||||
current_page = max(1, current_page)
|
||||
page_size = max(1, min(page_size, max_size))
|
||||
return current_page, page_size, (current_page - 1) * page_size
|
||||
|
||||
|
||||
def _validate_params(ns):
|
||||
required = ('accounting_orgid', 'counterparty_type', 'counterparty_orgid')
|
||||
for key in required:
|
||||
if not ns.get(key):
|
||||
return None, '缺少 %s' % key
|
||||
counterparty_type = ns.get('counterparty_type')
|
||||
if counterparty_type not in ('supplier', 'reseller'):
|
||||
return None, 'counterparty_type 仅支持 supplier / reseller'
|
||||
period_type = ns.get('period_type') or 'day'
|
||||
if period_type not in ('day', 'month'):
|
||||
return None, 'period_type 仅支持 day / month'
|
||||
period_start = ns.get('period_start') or ns.get('start_date')
|
||||
period_end = ns.get('period_end') or ns.get('end_date')
|
||||
if not period_start or not period_end:
|
||||
return None, '缺少 period_start / period_end'
|
||||
return {
|
||||
'accounting_orgid': ns.get('accounting_orgid'),
|
||||
'counterparty_type': counterparty_type,
|
||||
'counterparty_orgid': ns.get('counterparty_orgid'),
|
||||
'period_type': period_type,
|
||||
'period_start': period_start,
|
||||
'period_end': period_end,
|
||||
}, None
|
||||
|
||||
|
||||
async def _ensure_schema(sor):
|
||||
await sor.sqlExe("""
|
||||
CREATE TABLE IF NOT EXISTS finance_settlement (
|
||||
id varchar(32) NOT NULL,
|
||||
settlement_no varchar(64),
|
||||
accounting_orgid varchar(32),
|
||||
counterparty_type varchar(16),
|
||||
counterparty_orgid varchar(32),
|
||||
counterparty_name varchar(255),
|
||||
period_type varchar(16),
|
||||
period_start date,
|
||||
period_end date,
|
||||
sales_amount double(18,8) DEFAULT 0,
|
||||
settlement_amount double(18,8) DEFAULT 0,
|
||||
platform_income_amount double(18,8) DEFAULT 0,
|
||||
bill_count int DEFAULT 0,
|
||||
status varchar(16) DEFAULT 'draft',
|
||||
approval_id varchar(64),
|
||||
approval_status varchar(16),
|
||||
failure_reason varchar(1000),
|
||||
settled_at datetime,
|
||||
created_by varchar(32),
|
||||
del_flg varchar(1) DEFAULT '0',
|
||||
create_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
update_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY finance_settlement_un (accounting_orgid, counterparty_type, counterparty_orgid, period_start, period_end, del_flg)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
""", {})
|
||||
await sor.sqlExe("""
|
||||
CREATE TABLE IF NOT EXISTS finance_settlement_detail (
|
||||
id varchar(32) NOT NULL,
|
||||
settlement_id varchar(32),
|
||||
bill_id varchar(32),
|
||||
order_id varchar(32),
|
||||
bill_date date,
|
||||
customerid varchar(32),
|
||||
providerid varchar(32),
|
||||
productid varchar(32),
|
||||
business_op varchar(64),
|
||||
sale_mode varchar(1),
|
||||
sales_amount double(18,8) DEFAULT 0,
|
||||
settlement_amount double(18,8) DEFAULT 0,
|
||||
platform_income_amount double(18,8) DEFAULT 0,
|
||||
amount_source varchar(32) DEFAULT 'bill_detail',
|
||||
del_flg varchar(1) DEFAULT '0',
|
||||
create_at datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
KEY finance_settlement_detail_idx1 (settlement_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
""", {})
|
||||
|
||||
|
||||
async def _existing_settlement(sor, args):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT id, settlement_no, status
|
||||
FROM finance_settlement
|
||||
WHERE accounting_orgid=${accounting_orgid}$
|
||||
AND counterparty_type=${counterparty_type}$
|
||||
AND counterparty_orgid=${counterparty_orgid}$
|
||||
AND period_start=${period_start}$
|
||||
AND period_end=${period_end}$
|
||||
AND del_flg='0'
|
||||
LIMIT 1
|
||||
""", args)
|
||||
return rows[0] if rows else None
|
||||
|
||||
|
||||
async def _counterparty_name(sor, args):
|
||||
if args['counterparty_type'] == 'supplier':
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT COALESCE(p.name, o.orgname) AS name
|
||||
FROM organization o
|
||||
LEFT JOIN provider p ON p.orgid=o.id AND p.del_flg='0'
|
||||
WHERE o.id=${counterparty_orgid}$ AND o.del_flg='0'
|
||||
LIMIT 1
|
||||
""", args)
|
||||
else:
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT orgname AS name FROM organization
|
||||
WHERE id=${counterparty_orgid}$ AND del_flg='0'
|
||||
LIMIT 1
|
||||
""", args)
|
||||
return rows[0].get('name') if rows else None
|
||||
|
||||
|
||||
async def _fetch_source_rows(sor, args):
|
||||
params = dict(args)
|
||||
filters = [
|
||||
"b.del_flg='0'",
|
||||
"b.bill_state='1'",
|
||||
"b.bill_date >= ${period_start}$",
|
||||
"b.bill_date <= ${period_end}$",
|
||||
]
|
||||
if args['counterparty_type'] == 'supplier':
|
||||
filters.append('b.providerid=${counterparty_orgid}$')
|
||||
settlement_join = """
|
||||
LEFT JOIN bill_detail sd ON sd.billid=b.id
|
||||
AND sd.accounting_orgid=${accounting_orgid}$
|
||||
AND sd.del_flg='0'
|
||||
AND sd.accounting_dir='贷'
|
||||
AND sd.subjectname LIKE '待结转%'
|
||||
"""
|
||||
settlement_expr = 'COALESCE(sd.amount, 0)'
|
||||
sale_mode_expr = 'sd.subjectname'
|
||||
else:
|
||||
filters.append('cust.parentid=${counterparty_orgid}$')
|
||||
settlement_join = """
|
||||
LEFT JOIN bill_detail sd ON sd.billid=b.id
|
||||
AND sd.accounting_orgid=${accounting_orgid}$
|
||||
AND sd.del_flg='0'
|
||||
AND sd.accounting_dir='借'
|
||||
AND sd.subjectname='分销商存放资金'
|
||||
AND sd.participantid=cust.parentid
|
||||
"""
|
||||
settlement_expr = 'COALESCE(sd.amount, 0)'
|
||||
sale_mode_expr = 'sd.subjectname'
|
||||
|
||||
where_sql = ' AND '.join(filters)
|
||||
sql = """
|
||||
SELECT b.id AS bill_id,
|
||||
b.orderid AS order_id,
|
||||
b.bill_date,
|
||||
b.customerid,
|
||||
b.providerid,
|
||||
b.productid,
|
||||
b.business_op,
|
||||
b.amount AS sales_amount,
|
||||
%s AS settlement_amount,
|
||||
%s AS settlement_subject,
|
||||
COALESCE((
|
||||
SELECT SUM(bd.amount)
|
||||
FROM bill_detail bd
|
||||
WHERE bd.billid=b.id
|
||||
AND bd.accounting_orgid=${accounting_orgid}$
|
||||
AND bd.del_flg='0'
|
||||
AND bd.accounting_dir='贷'
|
||||
AND bd.subjectname IN ('折扣收入', '底价收入')
|
||||
), 0) AS platform_income_amount
|
||||
FROM bill b
|
||||
INNER JOIN organization cust ON cust.id=b.customerid AND cust.del_flg='0'
|
||||
%s
|
||||
WHERE %s
|
||||
ORDER BY b.bill_date DESC, b.create_at DESC
|
||||
""" % (settlement_expr, sale_mode_expr, settlement_join, where_sql)
|
||||
rows = await sor.sqlExe(sql, params)
|
||||
items = []
|
||||
seen_platform_bill = set()
|
||||
for row in rows:
|
||||
sign = -1 if _is_reverse_op(row.get('business_op')) else 1
|
||||
bill_id = row.get('bill_id')
|
||||
platform_income = float(row.get('platform_income_amount') or 0)
|
||||
if bill_id in seen_platform_bill:
|
||||
platform_income = 0
|
||||
seen_platform_bill.add(bill_id)
|
||||
items.append({
|
||||
'bill_id': bill_id,
|
||||
'order_id': row.get('order_id'),
|
||||
'bill_date': str(row.get('bill_date'))[:10] if row.get('bill_date') else None,
|
||||
'customerid': row.get('customerid'),
|
||||
'providerid': row.get('providerid'),
|
||||
'productid': row.get('productid'),
|
||||
'business_op': row.get('business_op'),
|
||||
'sale_mode': _sale_mode_from_subject(row.get('settlement_subject')),
|
||||
'sales_amount': _round_money(sign * float(row.get('sales_amount') or 0)),
|
||||
'settlement_amount': _round_money(sign * float(row.get('settlement_amount') or 0)),
|
||||
'platform_income_amount': _round_money(sign * platform_income),
|
||||
'amount_source': 'bill_detail',
|
||||
})
|
||||
return items
|
||||
|
||||
|
||||
def _summary(items):
|
||||
return {
|
||||
'sales_amount': _round_money(sum(i.get('sales_amount') or 0 for i in items)),
|
||||
'settlement_amount': _round_money(sum(i.get('settlement_amount') or 0 for i in items)),
|
||||
'platform_income_amount': _round_money(sum(i.get('platform_income_amount') or 0 for i in items)),
|
||||
'bill_count': len({i.get('bill_id') for i in items if i.get('bill_id')}),
|
||||
}
|
||||
|
||||
|
||||
async def finance_settlement_preview(ns={}):
|
||||
args, err = _validate_params(ns)
|
||||
if err:
|
||||
return {'status': False, 'msg': err}
|
||||
current_page, page_size, offset = _parse_page(ns)
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
await _ensure_schema(sor)
|
||||
existing = await _existing_settlement(sor, args)
|
||||
items = await _fetch_source_rows(sor, args)
|
||||
total_count = len(items)
|
||||
return {
|
||||
'status': True,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'accounting_orgid': args['accounting_orgid'],
|
||||
'counterparty_type': args['counterparty_type'],
|
||||
'counterparty_orgid': args['counterparty_orgid'],
|
||||
'counterparty_name': await _counterparty_name(sor, args),
|
||||
'period_type': args['period_type'],
|
||||
'period_start': args['period_start'],
|
||||
'period_end': args['period_end'],
|
||||
'existing_settlement': existing,
|
||||
'can_create': existing is None and total_count > 0,
|
||||
'summary': _summary(items),
|
||||
'total_count': total_count,
|
||||
'current_page': current_page,
|
||||
'page_size': page_size,
|
||||
'items': items[offset:offset + page_size],
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '预览失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_preview(params_kw)
|
||||
return ret
|
||||
100
b/bill/finance_settlement_submit.dspy
Normal file
100
b/bill/finance_settlement_submit.dspy
Normal file
@ -0,0 +1,100 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""财务结算单提交审批。"""
|
||||
|
||||
import datetime
|
||||
import json
|
||||
|
||||
DBNAME = 'kboss'
|
||||
|
||||
|
||||
async def _finance_phone(sor, orgid):
|
||||
rows = await sor.sqlExe("""
|
||||
SELECT u.mobile
|
||||
FROM users u
|
||||
LEFT JOIN userrole ur ON u.id=ur.userid
|
||||
LEFT JOIN role r ON ur.roleid=r.id
|
||||
WHERE r.role='财务'
|
||||
AND u.orgid=${orgid}$
|
||||
AND ur.del_flg='0'
|
||||
AND r.del_flg='0'
|
||||
AND u.del_flg='0'
|
||||
LIMIT 1
|
||||
""", {'orgid': orgid})
|
||||
return rows[0]['mobile'] if rows else None
|
||||
|
||||
|
||||
async def finance_settlement_submit(ns={}):
|
||||
settlement_id = ns.get('settlement_id') or ns.get('id')
|
||||
userid = ns.get('userid') or ns.get('user_id')
|
||||
business_name = ns.get('business_name') or '财务结算'
|
||||
if not settlement_id or not userid:
|
||||
return {'status': False, 'msg': '缺少 settlement_id 或 userid'}
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
rows = await sor.R('finance_settlement', {'id': settlement_id, 'del_flg': '0'})
|
||||
if not rows:
|
||||
return {'status': False, 'msg': '结算单不存在'}
|
||||
settlement = rows[0]
|
||||
if settlement.get('status') not in ('draft', 'rejected', 'failed'):
|
||||
return {'status': False, 'msg': '当前状态不可提交审批'}
|
||||
phone = await _finance_phone(sor, settlement.get('accounting_orgid'))
|
||||
if not phone:
|
||||
return {'status': False, 'msg': '未找到当前机构财务审批人'}
|
||||
business_rows = await sor.R('apv_business', {'business_name': business_name, 'del_flg': '0'})
|
||||
if not business_rows:
|
||||
return {'status': False, 'msg': '审批业务不存在: %s' % business_name}
|
||||
form_component = {
|
||||
'title': '财务结算审批',
|
||||
'detail': {
|
||||
'data': '%s %s-%s %s 金额:%s' % (
|
||||
settlement.get('counterparty_name'),
|
||||
settlement.get('period_start'),
|
||||
settlement.get('period_end'),
|
||||
settlement.get('counterparty_type'),
|
||||
settlement.get('settlement_amount'),
|
||||
)
|
||||
},
|
||||
}
|
||||
apv_json = json.dumps({
|
||||
'table': 'finance_settlement',
|
||||
'settlement_id': settlement_id,
|
||||
'settlement_no': settlement.get('settlement_no'),
|
||||
}, ensure_ascii=False)
|
||||
resp = await issue_approve(
|
||||
phone,
|
||||
settlement.get('accounting_orgid'),
|
||||
userid,
|
||||
business_rows[0]['id'],
|
||||
form_component,
|
||||
settlement.get('counterparty_orgid'),
|
||||
settlement_id,
|
||||
apv_json,
|
||||
)
|
||||
if not resp.get('status'):
|
||||
return {'status': False, 'msg': '发起审批失败, %s' % resp.get('msg')}
|
||||
now_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
await sor.U('finance_settlement', {
|
||||
'id': settlement_id,
|
||||
'status': 'approving',
|
||||
'approval_status': 'start',
|
||||
'approval_id': resp.get('instanceId'),
|
||||
'created_by': userid,
|
||||
'failure_reason': None,
|
||||
'update_at': now_time,
|
||||
})
|
||||
return {
|
||||
'status': True,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'settlement_id': settlement_id,
|
||||
'approval_id': resp.get('instanceId'),
|
||||
'status': 'approving',
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '提交审批失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_submit(params_kw)
|
||||
return ret
|
||||
225
b/bill/finance_settlement_summary.dspy
Normal file
225
b/bill/finance_settlement_summary.dspy
Normal file
@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
财务结算汇总查询。
|
||||
|
||||
按供应商或分销商聚合日结/月结应结金额、平台收入和销售额。
|
||||
金额以已记账 bill_detail 为准,不使用未记账估算。
|
||||
"""
|
||||
|
||||
DBNAME = 'kboss'
|
||||
INCOME_SUBJECTS = ('折扣收入', '底价收入')
|
||||
PARENT_SETTLE_SUBJECT = '分销商存放资金'
|
||||
|
||||
|
||||
def _round_money(v):
|
||||
return round(float(v or 0), 8)
|
||||
|
||||
|
||||
def _is_reverse_op(op):
|
||||
return str(op or '').upper().endswith('_REVERSE')
|
||||
|
||||
|
||||
def _parse_page(ns, default_page=1, default_size=20, max_size=200):
|
||||
try:
|
||||
current_page = int(ns.get('current_page', default_page) or default_page)
|
||||
except (TypeError, ValueError):
|
||||
current_page = default_page
|
||||
try:
|
||||
page_size = int(ns.get('page_size', default_size) or default_size)
|
||||
except (TypeError, ValueError):
|
||||
page_size = default_size
|
||||
current_page = max(1, current_page)
|
||||
page_size = max(1, min(page_size, max_size))
|
||||
return current_page, page_size, (current_page - 1) * page_size
|
||||
|
||||
|
||||
def _period_key(bill_date, period_type):
|
||||
text = str(bill_date or '')[:10]
|
||||
if period_type == 'month':
|
||||
return text[:7]
|
||||
return text
|
||||
|
||||
|
||||
def _validate_params(ns):
|
||||
debug(ns)
|
||||
accounting_orgid = ns.get('accounting_orgid')
|
||||
counterparty_type = ns.get('counterparty_type')
|
||||
period_type = ns.get('period_type') or 'day'
|
||||
start_date = ns.get('start_date') or ns.get('period_start')
|
||||
end_date = ns.get('end_date') or ns.get('period_end')
|
||||
if not accounting_orgid:
|
||||
return None, '缺少 accounting_orgid'
|
||||
if counterparty_type not in ('supplier', 'reseller'):
|
||||
return None, 'counterparty_type 仅支持 supplier / reseller'
|
||||
if period_type not in ('day', 'month'):
|
||||
return None, 'period_type 仅支持 day / month'
|
||||
if not start_date or not end_date:
|
||||
return None, '缺少 start_date / end_date'
|
||||
return {
|
||||
'accounting_orgid': accounting_orgid,
|
||||
'counterparty_type': counterparty_type,
|
||||
'period_type': period_type,
|
||||
'start_date': start_date,
|
||||
'end_date': end_date,
|
||||
'counterparty_orgid': ns.get('counterparty_orgid'),
|
||||
}, None
|
||||
|
||||
|
||||
async def _fetch_source_rows(sor, args):
|
||||
params = {
|
||||
'accounting_orgid': args['accounting_orgid'],
|
||||
'start_date': args['start_date'],
|
||||
'end_date': args['end_date'],
|
||||
}
|
||||
filters = [
|
||||
"b.del_flg = '0'",
|
||||
"b.bill_state = '1'",
|
||||
"b.bill_date >= ${start_date}$",
|
||||
"b.bill_date <= ${end_date}$",
|
||||
]
|
||||
if args['counterparty_type'] == 'supplier':
|
||||
counterparty_expr = 'b.providerid'
|
||||
name_expr = 'COALESCE(pv.name, cp.orgname)'
|
||||
join_sql = """
|
||||
LEFT JOIN provider pv ON pv.orgid = b.providerid AND pv.del_flg = '0'
|
||||
LEFT JOIN organization cp ON cp.id = b.providerid AND cp.del_flg = '0'
|
||||
"""
|
||||
settlement_expr = """
|
||||
SELECT SUM(bd.amount)
|
||||
FROM bill_detail bd
|
||||
WHERE bd.billid = b.id
|
||||
AND bd.accounting_orgid = ${accounting_orgid}$
|
||||
AND bd.del_flg = '0'
|
||||
AND bd.accounting_dir = '贷'
|
||||
AND bd.subjectname LIKE '待结转%'
|
||||
"""
|
||||
if args.get('counterparty_orgid'):
|
||||
filters.append('b.providerid = ${counterparty_orgid}$')
|
||||
params['counterparty_orgid'] = args['counterparty_orgid']
|
||||
else:
|
||||
counterparty_expr = 'cust.parentid'
|
||||
name_expr = 'cp.orgname'
|
||||
join_sql = "LEFT JOIN organization cp ON cp.id = cust.parentid AND cp.del_flg = '0'"
|
||||
settlement_expr = """
|
||||
SELECT SUM(bd.amount)
|
||||
FROM bill_detail bd
|
||||
WHERE bd.billid = b.id
|
||||
AND bd.accounting_orgid = ${accounting_orgid}$
|
||||
AND bd.del_flg = '0'
|
||||
AND bd.accounting_dir = '借'
|
||||
AND bd.subjectname = '分销商存放资金'
|
||||
AND bd.participantid = cust.parentid
|
||||
"""
|
||||
filters.append("cust.parentid IS NOT NULL AND cust.parentid != ''")
|
||||
if args.get('counterparty_orgid'):
|
||||
filters.append('cust.parentid = ${counterparty_orgid}$')
|
||||
params['counterparty_orgid'] = args['counterparty_orgid']
|
||||
|
||||
where_sql = ' AND '.join(filters)
|
||||
sql = """
|
||||
SELECT b.id AS bill_id,
|
||||
b.orderid AS order_id,
|
||||
b.bill_date,
|
||||
b.customerid,
|
||||
b.providerid,
|
||||
b.productid,
|
||||
b.business_op,
|
||||
b.amount AS sales_amount,
|
||||
%s AS counterparty_orgid,
|
||||
%s AS counterparty_name,
|
||||
COALESCE((%s), 0) AS settlement_amount,
|
||||
COALESCE((
|
||||
SELECT SUM(bd.amount)
|
||||
FROM bill_detail bd
|
||||
WHERE bd.billid = b.id
|
||||
AND bd.accounting_orgid = ${accounting_orgid}$
|
||||
AND bd.del_flg = '0'
|
||||
AND bd.accounting_dir = '贷'
|
||||
AND bd.subjectname IN ('折扣收入', '底价收入')
|
||||
), 0) AS platform_income_amount
|
||||
FROM bill b
|
||||
INNER JOIN organization cust ON cust.id = b.customerid AND cust.del_flg = '0'
|
||||
%s
|
||||
WHERE %s
|
||||
ORDER BY b.bill_date DESC, b.create_at DESC
|
||||
""" % (counterparty_expr, name_expr, settlement_expr, join_sql, where_sql)
|
||||
return await sor.sqlExe(sql, params)
|
||||
|
||||
|
||||
def _aggregate_rows(rows, period_type):
|
||||
buckets = {}
|
||||
for row in rows:
|
||||
counterparty_orgid = row.get('counterparty_orgid')
|
||||
if not counterparty_orgid:
|
||||
continue
|
||||
period = _period_key(row.get('bill_date'), period_type)
|
||||
key = (period, counterparty_orgid)
|
||||
if key not in buckets:
|
||||
buckets[key] = {
|
||||
'period': period,
|
||||
'counterparty_orgid': counterparty_orgid,
|
||||
'counterparty_name': row.get('counterparty_name'),
|
||||
'sales_amount': 0.0,
|
||||
'settlement_amount': 0.0,
|
||||
'platform_income_amount': 0.0,
|
||||
'bill_count': 0,
|
||||
}
|
||||
sign = -1 if _is_reverse_op(row.get('business_op')) else 1
|
||||
bucket = buckets[key]
|
||||
bucket['sales_amount'] += sign * float(row.get('sales_amount') or 0)
|
||||
bucket['settlement_amount'] += sign * float(row.get('settlement_amount') or 0)
|
||||
bucket['platform_income_amount'] += sign * float(row.get('platform_income_amount') or 0)
|
||||
bucket['bill_count'] += 1
|
||||
|
||||
items = []
|
||||
for item in buckets.values():
|
||||
item['sales_amount'] = _round_money(item['sales_amount'])
|
||||
item['settlement_amount'] = _round_money(item['settlement_amount'])
|
||||
item['platform_income_amount'] = _round_money(item['platform_income_amount'])
|
||||
items.append(item)
|
||||
return sorted(items, key=lambda x: (x['period'], x['settlement_amount']), reverse=True)
|
||||
|
||||
|
||||
def _summary(items):
|
||||
return {
|
||||
'sales_amount': _round_money(sum(i.get('sales_amount') or 0 for i in items)),
|
||||
'settlement_amount': _round_money(sum(i.get('settlement_amount') or 0 for i in items)),
|
||||
'platform_income_amount': _round_money(sum(i.get('platform_income_amount') or 0 for i in items)),
|
||||
'bill_count': sum(i.get('bill_count') or 0 for i in items),
|
||||
}
|
||||
|
||||
|
||||
async def finance_settlement_summary(ns={}):
|
||||
args, err = _validate_params(ns)
|
||||
if err:
|
||||
return {'status': False, 'msg': err}
|
||||
current_page, page_size, offset = _parse_page(ns)
|
||||
db = DBPools()
|
||||
async with db.sqlorContext(DBNAME) as sor:
|
||||
try:
|
||||
rows = await _fetch_source_rows(sor, args)
|
||||
items = _aggregate_rows(rows, args['period_type'])
|
||||
total_count = len(items)
|
||||
page_items = items[offset:offset + page_size]
|
||||
return {
|
||||
'status': True,
|
||||
'msg': 'ok',
|
||||
'data': {
|
||||
'accounting_orgid': args['accounting_orgid'],
|
||||
'counterparty_type': args['counterparty_type'],
|
||||
'period_type': args['period_type'],
|
||||
'start_date': args['start_date'],
|
||||
'end_date': args['end_date'],
|
||||
'summary': _summary(items),
|
||||
'total_count': total_count,
|
||||
'current_page': current_page,
|
||||
'page_size': page_size,
|
||||
'items': page_items,
|
||||
},
|
||||
}
|
||||
except Exception as e:
|
||||
return {'status': False, 'msg': '查询失败, %s' % str(e)}
|
||||
|
||||
|
||||
ret = await finance_settlement_summary(params_kw)
|
||||
return ret
|
||||
58
b/subject.sql
Normal file
58
b/subject.sql
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
Navicat Premium Data Transfer
|
||||
|
||||
Source Server : kbossdev
|
||||
Source Server Type : MariaDB
|
||||
Source Server Version : 100622
|
||||
Source Host : db:3306
|
||||
Source Schema : kboss_dev
|
||||
|
||||
Target Server Type : MariaDB
|
||||
Target Server Version : 100622
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 18/06/2026 17:12:02
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for subject
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `subject`;
|
||||
CREATE TABLE `subject` (
|
||||
`id` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT 'id',
|
||||
`name` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '科目名称',
|
||||
`balance_side` varchar(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL COMMENT '余额方向',
|
||||
`del_flg` varchar(1) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '创建时间戳',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '科目表' ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of subject
|
||||
-- ----------------------------
|
||||
INSERT INTO `subject` VALUES ('subject001', '资金账号', '0', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject002', '折扣收入', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject003', '底价收入', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject004', '客户折扣支出', '0', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject005', '存放供应商资金', '0', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject006', '分销商代付费销售', '0', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject007', '支付宝手续费', '0', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject008', '业务账', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject009', '待结转折扣销售收入', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject010', '待结转代付费销售收入', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject011', '待结转底价销售收入', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject012', '分销商存放资金', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject013', '待结转折扣支出', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject014', '待结转代付费支出', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject015', '待结转底价支出', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject016', '代付费销售', '1', '0', '2023-08-03 17:40:34');
|
||||
INSERT INTO `subject` VALUES ('subject017', '算力券', '1', '0', '2025-03-31 11:50:49');
|
||||
INSERT INTO `subject` VALUES ('subject018', '算力券发放', '0', '0', '2025-04-08 11:20:16');
|
||||
INSERT INTO `subject` VALUES ('subject019', '算力券消费', '1', '0', '2025-04-08 11:20:32');
|
||||
INSERT INTO `subject` VALUES ('subject020', '待结算算力券', '0', '0', '2025-04-08 11:29:02');
|
||||
INSERT INTO `subject` VALUES ('subject021', '算力劵临时账户', '0', '0', '2025-04-08 17:24:30');
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
Loading…
x
Reference in New Issue
Block a user