Commit fa6e00c3 authored by terrfly's avatar terrfly
Browse files

完成订单的分账逻辑

parent ad2afc15
......@@ -5,7 +5,7 @@
-- 权限表
DROP TABLE IF EXISTS `t_sys_entitlement`;
CREATE TABLE `t_sys_entitlement` (
`ent_id` VARCHAR(32) NOT NULL COMMENT '权限ID[ENT_功能模块_子模块_操作], eg: ENT_ROLE_LIST_ADD',
`ent_id` VARCHAR(64) NOT NULL COMMENT '权限ID[ENT_功能模块_子模块_操作], eg: ENT_ROLE_LIST_ADD',
`ent_name` VARCHAR(32) NOT NULL COMMENT '权限名称',
`menu_icon` VARCHAR(32) COMMENT '菜单图标',
`menu_uri` VARCHAR(128) COMMENT '菜单uri/路由地址',
......@@ -261,7 +261,6 @@ CREATE TABLE `t_pay_order` (
`amount` BIGINT(20) NOT NULL COMMENT '支付金额,单位分',
`mch_fee_rate` decimal(20,6) NOT NULL COMMENT '商户手续费费率快照',
`mch_fee_amount` BIGINT(20) NOT NULL COMMENT '商户手续费,单位分',
`mch_income_amount` BIGINT(20) NOT NULL COMMENT '商户入账金额(支付金额-手续费),单位分',
`currency` VARCHAR(3) NOT NULL DEFAULT 'cny' COMMENT '三位货币代码,人民币:cny',
`state` TINYINT(6) NOT NULL DEFAULT '0' COMMENT '支付状态: 0-订单生成, 1-支付中, 2-支付成功, 3-支付失败, 4-已撤销, 5-已退款, 6-订单关闭',
`notify_state` TINYINT(6) NOT NULL DEFAULT '0' COMMENT '向下游回调状态, 0-未发送, 1-已发送',
......@@ -403,13 +402,27 @@ CREATE TABLE `t_transfer_order` (
INDEX(`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='转账订单表';
-- 商户分账接收者账号组
DROP TABLE IF EXISTS `t_mch_division_receiver_group`;
CREATE TABLE `t_mch_division_receiver_group` (
`receiver_group_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '组ID',
`receiver_group_name` VARCHAR(64) NOT NULL COMMENT '组名称',
`mch_no` VARCHAR(64) NOT NULL COMMENT '商户号',
`auto_division_flag` TINYINT(6) NOT NULL DEFAULT 0 COMMENT '自动分账组(当订单分账模式为自动分账,改组将完成分账逻辑) 0-否 1-是',
`created_uid` BIGINT(20) NOT NULL COMMENT '创建者用户ID',
`created_by` VARCHAR(64) NOT NULL COMMENT '创建者姓名',
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
PRIMARY KEY (`receiver_group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8mb4 COMMENT='分账账号组';
-- 商户分账接收者账号绑定关系表
DROP TABLE IF EXISTS `t_mch_division_receiver`;
CREATE TABLE `t_mch_division_receiver` (
`receiver_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '分账接收者ID',
`receiver_group_id` BIGINT(20) NOT NULL COMMENT '多渠道组合ID(便于商户接口使用)',
`receiver_name` VARCHAR(64) NOT NULL COMMENT '接收者账号别名',
`receiver_alias` VARCHAR(64) NOT NULL COMMENT '接收者账号别名',
`receiver_group_id` BIGINT(20) COMMENT '组ID(便于商户接口使用)',
`receiver_group_name` VARCHAR(64) COMMENT '组名称',
`mch_no` VARCHAR(64) NOT NULL COMMENT '商户号',
`isv_no` VARCHAR(64) COMMENT '服务商号',
`app_id` VARCHAR(64) NOT NULL COMMENT '应用ID',
......@@ -421,14 +434,13 @@ CREATE TABLE `t_mch_division_receiver` (
`relation_type_name` VARCHAR(30) NOT NULL COMMENT '当选择自定义时,需要录入该字段。 否则为对应的名称',
`division_profit` DECIMAL(20,6) COMMENT '分账比例',
`state` TINYINT(6) NOT NULL COMMENT '分账状态(本系统状态,并不调用上游关联关系): 1-正常分账, 0-暂停分账',
`channel_bind_state` TINYINT(6) NOT NULL COMMENT '上游绑定状态: 1-绑定成功, 2-绑定异常',
`channel_bind_result` TEXT COMMENT '上游绑定返回信息,一般用作查询绑定异常时的记录',
`channel_bind_result` TEXT COMMENT '上游绑定返回信息,一般用作查询账号异常时的记录',
`channel_ext_info` TEXT COMMENT '渠道特殊信息',
`bind_success_time` DATETIME DEFAULT NULL COMMENT '绑定成功时间',
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
PRIMARY KEY (`receiver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COMMENT='商户分账接收者账号绑定关系表';
) ENGINE=InnoDB AUTO_INCREMENT=800001 DEFAULT CHARSET=utf8mb4 COMMENT='商户分账接收者账号绑定关系表';
-- 分账记录表
DROP TABLE IF EXISTS `t_pay_order_division_record`;
......@@ -449,7 +461,8 @@ CREATE TABLE `t_pay_order_division_record` (
`state` TINYINT(6) NOT NULL COMMENT '状态: 0-待分账 1-分账成功, 2-分账失败',
`channel_resp_result` TEXT COMMENT '上游返回数据包',
`receiver_id` BIGINT(20) NOT NULL COMMENT '账号快照》 分账接收者ID',
`receiver_group_id` BIGINT(20) NOT NULL COMMENT '账号快照》 多渠道组合ID(便于商户存储)',
`receiver_group_id` BIGINT(20) COMMENT '账号快照》 组ID(便于商户接口使用)',
`receiver_alias` VARCHAR(64) COMMENT '接收者账号别名',
`acc_type` TINYINT(6) NOT NULL COMMENT '账号快照》 分账接收账号类型: 0-个人 1-商户',
`acc_no` VARCHAR(50) NOT NULL COMMENT '账号快照》 分账接收账号',
`acc_name` VARCHAR(30) NOT NULL DEFAULT '' COMMENT '账号快照》 分账接收账号名称',
......@@ -630,6 +643,24 @@ insert into t_sys_entitlement values('ENT_ORDER', '订单中心', 'transaction',
insert into t_sys_entitlement values('ENT_TRANSFER_ORDER_LIST', '页面:转账订单列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_TRANSFER_ORDER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_TRANSFER_ORDER_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_TRANSFER_ORDER', '0', 'MCH', now(), now());
-- 【商户系统】 分账管理
insert into t_sys_entitlement values('ENT_DIVISION', '分账管理', 'apartment', '', 'RouteView', 'ML', 0, 1, 'ROOT', '30', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP', '账号组管理', 'team', '/divisionReceiverGroup', 'DivisionReceiverGroupPage', 'ML', 0, 1, 'ENT_DIVISION', '10', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_LIST', '页面:数据列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_ADD', '按钮:新增', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_EDIT', '按钮:修改', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_DELETE', '按钮:删除', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER', '收款账号管理', 'trademark', '/divisionReceiver', 'DivisionReceiverPage', 'ML', 0, 1, 'ENT_DIVISION', '20', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_LIST', '页面:数据列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_ADD', '按钮:新增收款账号', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_DELETE', '按钮:删除收款账号', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_EDIT', '按钮:修改账号信息', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECORD', '分账记录', 'unordered-list', '/divisionRecord', 'DivisionRecordPage', 'ML', 0, 1, 'ENT_DIVISION', '30', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECORD_LIST', '页面:数据列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECORD', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECORD_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECORD', '0', 'MCH', now(), now());
-- 【商户系统】 系统管理
insert into t_sys_entitlement values('ENT_SYS_CONFIG', '系统管理', 'setting', '', 'RouteView', 'ML', 0, 1, 'ROOT', '200', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_UR', '用户角色管理', 'team', '', 'RouteView', 'ML', 0, 1, 'ENT_SYS_CONFIG', '10', 'MCH', now(), now());
......
......@@ -95,7 +95,7 @@ insert into t_sys_entitlement values('ENT_MCH_TRANSFER_DO', '按钮:发起转
## -- ++++ ++++
## -- ++++ [v1.6.0] ===> [未确定] ++++
## -- ++++ [v1.6.0] ===> [v1.7.0] ++++
-- 订单页的支付方式筛选项添加权限并可分配: 避免API权限导致页面出现异常
insert into t_sys_entitlement values('ENT_PAY_ORDER_SEARCH_PAY_WAY', '筛选项:支付方式', 'no-icon', '', '', 'PB', 0, 1, 'ENT_PAY_ORDER', '0', 'MGR', now(), now());
......@@ -105,10 +105,8 @@ insert into t_sys_entitlement values('ENT_PAY_ORDER_SEARCH_PAY_WAY', '筛选项
-- 插入表结构,并插入默认数据(默认费率 0)
alter table `t_pay_order` add column `mch_fee_rate` decimal(20,6) NOT NULL COMMENT '商户手续费费率快照' after `amount`;
alter table `t_pay_order` add column `mch_fee_amount` BIGINT(20) NOT NULL COMMENT '商户手续费,单位分' after `mch_fee_rate`;
alter table `t_pay_order` add column `mch_income_amount` BIGINT(20) NOT NULL COMMENT '商户入账金额(支付金额-手续费),单位分' after `mch_fee_amount`;
update `t_pay_order` set mch_fee_rate = 0;
update `t_pay_order` set mch_fee_amount = 0;
update `t_pay_order` set mch_income_amount = amount - mch_fee_amount;
alter table `t_pay_order` drop column `division_flag`;
alter table `t_pay_order` drop column `division_time`;
......@@ -117,7 +115,100 @@ alter table `t_pay_order` add column `division_mode` TINYINT(6) DEFAULT 0 COMMEN
alter table `t_pay_order` add column `division_state` TINYINT(6) DEFAULT 0 COMMENT '订单分账状态:0-未发生分账, 1-等待分账任务处理, 2-分账处理中, 3-分账任务已结束(不体现状态)' after `division_mode`;
alter table `t_pay_order` add column `division_last_time` DATETIME COMMENT '最新分账时间' after `division_state`;
-- TODO 分账的两张表
-- 商户分账接收者账号组
DROP TABLE IF EXISTS `t_mch_division_receiver_group`;
CREATE TABLE `t_mch_division_receiver_group` (
`receiver_group_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '组ID',
`receiver_group_name` VARCHAR(64) NOT NULL COMMENT '组名称',
`mch_no` VARCHAR(64) NOT NULL COMMENT '商户号',
`auto_division_flag` TINYINT(6) NOT NULL DEFAULT 0 COMMENT '自动分账组(当订单分账模式为自动分账,改组将完成分账逻辑) 0-否 1-是',
`created_uid` BIGINT(20) NOT NULL COMMENT '创建者用户ID',
`created_by` VARCHAR(64) NOT NULL COMMENT '创建者姓名',
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
PRIMARY KEY (`receiver_group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8mb4 COMMENT='分账账号组';
-- 商户分账接收者账号绑定关系表
DROP TABLE IF EXISTS `t_mch_division_receiver`;
CREATE TABLE `t_mch_division_receiver` (
`receiver_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '分账接收者ID',
`receiver_alias` VARCHAR(64) NOT NULL COMMENT '接收者账号别名',
`receiver_group_id` BIGINT(20) COMMENT '组ID(便于商户接口使用)',
`receiver_group_name` VARCHAR(64) COMMENT '组名称',
`mch_no` VARCHAR(64) NOT NULL COMMENT '商户号',
`isv_no` VARCHAR(64) COMMENT '服务商号',
`app_id` VARCHAR(64) NOT NULL COMMENT '应用ID',
`if_code` VARCHAR(20) NOT NULL COMMENT '支付接口代码',
`acc_type` TINYINT(6) NOT NULL COMMENT '分账接收账号类型: 0-个人(对私) 1-商户(对公)',
`acc_no` VARCHAR(50) NOT NULL COMMENT '分账接收账号',
`acc_name` VARCHAR(30) NOT NULL DEFAULT '' COMMENT '分账接收账号名称',
`relation_type` VARCHAR(30) NOT NULL COMMENT '分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等',
`relation_type_name` VARCHAR(30) NOT NULL COMMENT '当选择自定义时,需要录入该字段。 否则为对应的名称',
`division_profit` DECIMAL(20,6) COMMENT '分账比例',
`state` TINYINT(6) NOT NULL COMMENT '分账状态(本系统状态,并不调用上游关联关系): 1-正常分账, 0-暂停分账',
`channel_bind_result` TEXT COMMENT '上游绑定返回信息,一般用作查询账号异常时的记录',
`channel_ext_info` TEXT COMMENT '渠道特殊信息',
`bind_success_time` DATETIME DEFAULT NULL COMMENT '绑定成功时间',
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
PRIMARY KEY (`receiver_id`)
) ENGINE=InnoDB AUTO_INCREMENT=800001 DEFAULT CHARSET=utf8mb4 COMMENT='商户分账接收者账号绑定关系表';
-- 分账记录表
DROP TABLE IF EXISTS `t_pay_order_division_record`;
CREATE TABLE `t_pay_order_division_record` (
`record_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分账记录ID',
`mch_no` VARCHAR(64) NOT NULL COMMENT '商户号',
`isv_no` VARCHAR(64) COMMENT '服务商号',
`app_id` VARCHAR(64) NOT NULL COMMENT '应用ID',
`mch_name` VARCHAR(30) NOT NULL COMMENT '商户名称',
`mch_type` TINYINT(6) NOT NULL COMMENT '类型: 1-普通商户, 2-特约商户(服务商模式)',
`if_code` VARCHAR(20) NOT NULL COMMENT '支付接口代码',
`pay_order_id` VARCHAR(30) NOT NULL COMMENT '系统支付订单号',
`pay_order_channel_order_no` VARCHAR(64) COMMENT '支付订单渠道支付订单号',
`pay_order_amount` BIGINT(20) NOT NULL COMMENT '订单金额,单位分',
`pay_order_division_amount` BIGINT(20) NOT NULL COMMENT '订单实际分账金额, 单位:分(订单金额 - 商户手续费 - 已退款金额)',
`batch_order_id` VARCHAR(30) NOT NULL COMMENT '系统分账批次号',
`channel_batch_order_id` VARCHAR(64) COMMENT '上游分账批次号',
`state` TINYINT(6) NOT NULL COMMENT '状态: 0-待分账 1-分账成功, 2-分账失败',
`channel_resp_result` TEXT COMMENT '上游返回数据包',
`receiver_id` BIGINT(20) NOT NULL COMMENT '账号快照》 分账接收者ID',
`receiver_group_id` BIGINT(20) COMMENT '账号快照》 组ID(便于商户接口使用)',
`receiver_alias` VARCHAR(64) COMMENT '接收者账号别名',
`acc_type` TINYINT(6) NOT NULL COMMENT '账号快照》 分账接收账号类型: 0-个人 1-商户',
`acc_no` VARCHAR(50) NOT NULL COMMENT '账号快照》 分账接收账号',
`acc_name` VARCHAR(30) NOT NULL DEFAULT '' COMMENT '账号快照》 分账接收账号名称',
`relation_type` VARCHAR(30) NOT NULL COMMENT '账号快照》 分账关系类型(参考微信), 如: SERVICE_PROVIDER 服务商等',
`relation_type_name` VARCHAR(30) NOT NULL COMMENT '账号快照》 当选择自定义时,需要录入该字段。 否则为对应的名称',
`division_profit` DECIMAL(20,6) NOT NULL COMMENT '账号快照》 配置的实际分账比例',
`cal_division_amount` BIGINT(20) NOT NULL COMMENT '计算该接收方的分账金额,单位分',
`created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
PRIMARY KEY (`record_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8mb4 COMMENT='分账记录表';
-- 权限表扩容
alter table `t_sys_entitlement` modify column `ent_id` VARCHAR(64) NOT NULL COMMENT '权限ID[ENT_功能模块_子模块_操作], eg: ENT_ROLE_LIST_ADD';
-- 【商户系统】 分账管理
insert into t_sys_entitlement values('ENT_DIVISION', '分账管理', 'apartment', '', 'RouteView', 'ML', 0, 1, 'ROOT', '30', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP', '账号组管理', 'team', '/divisionReceiverGroup', 'DivisionReceiverGroupPage', 'ML', 0, 1, 'ENT_DIVISION', '10', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_LIST', '页面:数据列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_ADD', '按钮:新增', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_EDIT', '按钮:修改', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_GROUP_DELETE', '按钮:删除', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER_GROUP', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER', '收款账号管理', 'trademark', '/divisionReceiver', 'DivisionReceiverPage', 'ML', 0, 1, 'ENT_DIVISION', '20', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_LIST', '页面:数据列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_ADD', '按钮:新增收款账号', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_DELETE', '按钮:删除收款账号', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECEIVER_EDIT', '按钮:修改账号信息', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECEIVER', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECORD', '分账记录', 'unordered-list', '/divisionRecord', 'DivisionRecordPage', 'ML', 0, 1, 'ENT_DIVISION', '30', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECORD_LIST', '页面:数据列表', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECORD', '0', 'MCH', now(), now());
insert into t_sys_entitlement values('ENT_DIVISION_RECORD_VIEW', '按钮:详情', 'no-icon', '', '', 'PB', 0, 1, 'ENT_DIVISION_RECORD', '0', 'MCH', now(), now());
......
......@@ -108,7 +108,7 @@ public class PayOrderDivisionMQ extends AbstractMQ {
private Long receiverId;
/**
* 多渠道组合ID(便于商户接口使用) (与 receiverId 二选一)
* ID(便于商户接口使用) (与 receiverId 二选一)
*/
private Long receiverGroupId;
......
......@@ -28,11 +28,6 @@ public class MchDivisionReceiver implements Serializable {
private static final long serialVersionUID=1L;
public static final byte STATE_WAIT = 0; // 待分账
public static final byte STATE_SUCCESS = 1; // 分账成功
public static final byte STATE_FAIL = 2; // 分账失败
//gw
public static final LambdaQueryWrapper<MchDivisionReceiver> gw(){
return new LambdaQueryWrapper<>();
......@@ -45,14 +40,19 @@ public class MchDivisionReceiver implements Serializable {
private Long receiverId;
/**
* 多渠道组合ID(便于商户接口使用)
* 接收者账号别名
*/
private String receiverAlias;
/**
* 组ID(便于商户接口使用)
*/
private Long receiverGroupId;
/**
* 接收者账号别名
* 组名称
*/
private String receiverName;
private String receiverGroupName;
/**
* 商户号
......@@ -109,11 +109,6 @@ public class MchDivisionReceiver implements Serializable {
*/
private Byte state;
/**
* 上游绑定状态: 1-绑定成功, 2-绑定异常
*/
private Byte channelBindState;
/**
* 上游绑定返回信息,一般用作查询绑定异常时的记录
*/
......
package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 分账账号组
* </p>
*
* @author [mybatis plus generator]
* @since 2021-08-23
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_mch_division_receiver_group")
public class MchDivisionReceiverGroup implements Serializable {
//gw
public static final LambdaQueryWrapper<MchDivisionReceiverGroup> gw(){
return new LambdaQueryWrapper<>();
}
private static final long serialVersionUID=1L;
/**
* 组ID
*/
@TableId(value = "receiver_group_id", type = IdType.AUTO)
private Long receiverGroupId;
/**
* 组名称
*/
private String receiverGroupName;
/**
* 商户号
*/
private String mchNo;
/**
* 自动分账组(当订单分账模式为自动分账,改组将完成分账逻辑) 0-否 1-是
*/
private Byte autoDivisionFlag;
/**
* 创建者用户ID
*/
private Long createdUid;
/**
* 创建者姓名
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
}
......@@ -132,11 +132,6 @@ public class PayOrder extends BaseModel implements Serializable {
*/
private Long mchFeeAmount;
/**
* 商户入账金额(支付金额-手续费),单位分
*/
private Long mchIncomeAmount;
/**
* 三位货币代码,人民币:cny
*/
......@@ -203,7 +198,7 @@ public class PayOrder extends BaseModel implements Serializable {
private Byte divisionMode;
/**
* 订单分账状态:0-未发生分账, 1-等待分账任务处理, 2-分账成功, 3-分账失败
* 0-未发生分账, 1-等待分账任务处理, 2-分账处理中, 3-分账任务已结束(不体现状态)
*/
private Byte divisionState;
......
......@@ -3,6 +3,7 @@ package com.jeequan.jeepay.core.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
......@@ -25,8 +26,16 @@ import java.util.Date;
@TableName("t_pay_order_division_record")
public class PayOrderDivisionRecord implements Serializable {
public static final byte STATE_WAIT = 0; // 待分账
public static final byte STATE_SUCCESS = 1; // 分账成功
public static final byte STATE_FAIL = 2; // 分账失败
private static final long serialVersionUID=1L;
public static final LambdaQueryWrapper<PayOrderDivisionRecord> gw(){
return new LambdaQueryWrapper<>();
}
/**
* 分账记录ID
*/
......@@ -109,10 +118,15 @@ public class PayOrderDivisionRecord implements Serializable {
private Long receiverId;
/**
* 账号快照》 多渠道组合ID(便于商户存储
* 账号快照》 ID(便于商户接口使用
*/
private Long receiverGroupId;
/**
* 账号快照》 分账接收者别名
*/
private String receiverAlias;
/**
* 账号快照》 分账接收账号类型: 0-个人 1-商户
*/
......
......@@ -51,12 +51,12 @@ public class DBApplicationConfig implements Serializable {
/** 生成 【jsapi统一收银台】oauth2获取用户ID回调地址 **/
public String genOauth2RedirectUrlEncode(String payOrderId){
return URLUtil.encode(getPaySiteUrl() + "/cashier/index.html#/oauth2Callback/" + JeepayKit.aesEncode(payOrderId));
return URLUtil.encodeAll(getPaySiteUrl() + "/cashier/index.html#/oauth2Callback/" + JeepayKit.aesEncode(payOrderId));
}
/** 生成 【商户获取渠道用户ID接口】oauth2获取用户ID回调地址 **/
public String genMchChannelUserIdApiOauth2RedirectUrlEncode(JSONObject param){
return URLUtil.encode(getPaySiteUrl() + "/api/channelUserId/oauth2Callback/" + JeepayKit.aesEncode(param.toJSONString()));
return URLUtil.encodeAll(getPaySiteUrl() + "/api/channelUserId/oauth2Callback/" + JeepayKit.aesEncode(param.toJSONString()));
}
/** 生成 【jsapi统一收银台二维码图片地址】 **/
......
......@@ -62,7 +62,6 @@ public class JeeUserDetails implements UserDetails {
this.setSysUser(sysUser);
this.setCredential(credential);
//TODO ....
//做一些初始化操作
}
......
......@@ -131,8 +131,22 @@ public class AmountUtil {
* @param rate 费率 (保持与数据库的格式一致 ,真实费率值,如费率为0.55%,则传入 0.0055)
*/
public static Long calPercentageFee(Long amount, BigDecimal rate){
return calPercentageFee(amount, rate, BigDecimal.ROUND_HALF_UP);
}
/**
* 计算百分比类型的各种费用值 (订单金额 * 真实费率 结果四舍五入并保留0位小数 )
*
* @author terrfly
* @site https://www.jeepay.vip
* @date 2021/8/20 14:53
* @param amount 订单金额 (保持与数据库的格式一致 ,单位:分)
* @param rate 费率 (保持与数据库的格式一致 ,真实费率值,如费率为0.55%,则传入 0.0055)
* @param mode 模式 参考:BigDecimal.ROUND_HALF_UP(四舍五入) BigDecimal.ROUND_FLOOR(向下取整)
*/
public static Long calPercentageFee(Long amount, BigDecimal rate, int mode){
//费率乘以订单金额 结果四舍五入并保留0位小数
return new BigDecimal(amount).multiply(rate).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
return new BigDecimal(amount).multiply(rate).setScale(0, mode).longValue();
}
}
......@@ -25,10 +25,16 @@ package com.jeequan.jeepay.core.utils;
public class RegKit {
public static final String REG_MOBILE = "^1\\d{10}$"; //判断是否是手机号
public static final String REG_ALIPAY_USER_ID = "^2088\\d{12}$"; //判断是支付宝用户Id 以2088开头的纯16位数字
public static boolean isMobile(String str){
return match(str, REG_MOBILE);
}
public static boolean isAlipayUserId(String str){
return match(str, REG_ALIPAY_USER_ID);
}
/** 正则验证 */
public static boolean match(String text, String reg){
......
......@@ -100,6 +100,9 @@ public class PayOrderController extends CommonCtrl {
if (StringUtils.isNotEmpty(payOrder.getAppId())) {
wrapper.eq(PayOrder::getAppId, payOrder.getAppId());
}
if (payOrder.getDivisionState() != null) {
wrapper.eq(PayOrder::getDivisionState, payOrder.getDivisionState());
}
if (paramJSON != null) {
if (StringUtils.isNotEmpty(paramJSON.getString("createdStart"))) {
wrapper.ge(PayOrder::getCreatedAt, paramJSON.getString("createdStart"));
......
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.mch.ctrl.division;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchDivisionReceiver;
import com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.mch.ctrl.CommonCtrl;
import com.jeequan.jeepay.model.DivisionReceiverBindReqModel;
import com.jeequan.jeepay.request.DivisionReceiverBindRequest;
import com.jeequan.jeepay.response.DivisionReceiverBindResponse;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchDivisionReceiverGroupService;
import com.jeequan.jeepay.service.impl.MchDivisionReceiverService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
/**
* 商户分账接收者账号关系维护
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021-08-23 11:50
*/
@RestController
@RequestMapping("api/divisionReceivers")
public class MchDivisionReceiverController extends CommonCtrl {
@Autowired private MchDivisionReceiverService mchDivisionReceiverService;
@Autowired private MchDivisionReceiverGroupService mchDivisionReceiverGroupService;
@Autowired private MchAppService mchAppService;
@Autowired private SysConfigService sysConfigService;
/** list */
@PreAuthorize("hasAnyAuthority( 'ENT_DIVISION_RECEIVER_LIST' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
MchDivisionReceiver queryObject = getObject(MchDivisionReceiver.class);
LambdaQueryWrapper<MchDivisionReceiver> condition = MchDivisionReceiver.gw();
condition.eq(MchDivisionReceiver::getMchNo, getCurrentMchNo());
if(queryObject.getReceiverId() != null){
condition.eq(MchDivisionReceiver::getReceiverId, queryObject.getReceiverId());
}
if(StringUtils.isNotEmpty(queryObject.getReceiverAlias())){
condition.like(MchDivisionReceiver::getReceiverAlias, queryObject.getReceiverAlias());
}
if(queryObject.getReceiverGroupId() != null){
condition.eq(MchDivisionReceiver::getReceiverGroupId, queryObject.getReceiverGroupId());
}
if(StringUtils.isNotEmpty(queryObject.getReceiverGroupName())){
condition.like(MchDivisionReceiver::getReceiverGroupName, queryObject.getReceiverGroupName());
}
if(StringUtils.isNotEmpty(queryObject.getAppId())){
condition.like(MchDivisionReceiver::getAppId, queryObject.getAppId());
}
if(queryObject.getState() != null){
condition.eq(MchDivisionReceiver::getState, queryObject.getState());
}
condition.orderByDesc(MchDivisionReceiver::getCreatedAt); //时间倒序
IPage<MchDivisionReceiver> pages = mchDivisionReceiverService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_VIEW' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") Long recordId) {
MchDivisionReceiver record = mchDivisionReceiverService
.getOne(MchDivisionReceiver.gw()
.eq(MchDivisionReceiver::getMchNo, getCurrentMchNo())
.eq(MchDivisionReceiver::getReceiverId, recordId));
if (record == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SELETE);
}
return ApiRes.ok(record);
}
/** add */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_ADD' )")
@RequestMapping(value="", method = RequestMethod.POST)
@MethodLog(remark = "新增分账接收账号")
public ApiRes add() {
DivisionReceiverBindReqModel model = getObject(DivisionReceiverBindReqModel.class);
MchApp mchApp = mchAppService.getById(model.getAppId());
if(mchApp == null || mchApp.getState() != CS.PUB_USABLE || !mchApp.getMchNo().equals(getCurrentMchNo()) ){
throw new BizException("商户应用不存在或不可用");
}
DivisionReceiverBindRequest request = new DivisionReceiverBindRequest();
request.setBizModel(model);
model.setMchNo(this.getCurrentMchNo());
model.setAppId(mchApp.getAppId());
model.setDivisionProfit(new BigDecimal(model.getDivisionProfit()).divide(new BigDecimal(100)).toPlainString());
JeepayClient jeepayClient = new JeepayClient(sysConfigService.getDBApplicationConfig().getPaySiteUrl(), mchApp.getAppSecret());
try {
DivisionReceiverBindResponse response = jeepayClient.execute(request);
if(response.getCode() != 0){
throw new BizException(response.getMsg());
}
return ApiRes.ok(response.get());
} catch (JeepayException e) {
throw new BizException(e.getMessage());
}
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.PUT)
@MethodLog(remark = "更新分账接收账号")
public ApiRes update(@PathVariable("recordId") Long recordId) {
// 请求参数
MchDivisionReceiver reqReceiver = getObject(MchDivisionReceiver.class);
MchDivisionReceiver record = new MchDivisionReceiver();
record.setReceiverAlias(reqReceiver.getReceiverAlias());
record.setReceiverGroupId(reqReceiver.getReceiverGroupId());
record.setState(reqReceiver.getState());
// 改为真实比例
if(reqReceiver.getDivisionProfit() != null){
record.setDivisionProfit(reqReceiver.getDivisionProfit().divide(new BigDecimal(100)));
}
if(record.getReceiverGroupId() != null){
MchDivisionReceiverGroup groupRecord = mchDivisionReceiverGroupService.findByIdAndMchNo(record.getReceiverGroupId(), getCurrentMchNo());
if (record == null) {
throw new BizException("账号组不存在");
}
record.setReceiverGroupId(groupRecord.getReceiverGroupId());
record.setReceiverGroupName(groupRecord.getReceiverGroupName());
}
LambdaUpdateWrapper<MchDivisionReceiver> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(MchDivisionReceiver::getReceiverId, recordId);
updateWrapper.eq(MchDivisionReceiver::getMchNo, getCurrentMchNo());
mchDivisionReceiverService.update(record, updateWrapper);
return ApiRes.ok();
}
/** delete */
@PreAuthorize("hasAuthority('ENT_DIVISION_RECEIVER_DELETE')")
@RequestMapping(value="/{recordId}", method = RequestMethod.DELETE)
@MethodLog(remark = "删除分账接收账号")
public ApiRes del(@PathVariable("recordId") Long recordId) {
MchDivisionReceiver record = mchDivisionReceiverService.getOne(MchDivisionReceiver.gw()
.eq(MchDivisionReceiver::getReceiverGroupId, recordId).eq(MchDivisionReceiver::getMchNo, getCurrentMchNo()));
if (record == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SELETE);
}
mchDivisionReceiverService.removeById(recordId);
return ApiRes.ok();
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.mch.ctrl.division;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchDivisionReceiver;
import com.jeequan.jeepay.core.entity.MchDivisionReceiverGroup;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.mch.ctrl.CommonCtrl;
import com.jeequan.jeepay.service.impl.MchDivisionReceiverGroupService;
import com.jeequan.jeepay.service.impl.MchDivisionReceiverService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 商户分账接收者账号组
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021-08-23 11:50
*/
@RestController
@RequestMapping("api/divisionReceiverGroups")
public class MchDivisionReceiverGroupController extends CommonCtrl {
@Autowired private MchDivisionReceiverGroupService mchDivisionReceiverGroupService;
@Autowired private MchDivisionReceiverService mchDivisionReceiverService;
/** list */
@PreAuthorize("hasAnyAuthority( 'ENT_DIVISION_RECEIVER_GROUP_LIST' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
MchDivisionReceiverGroup queryObject = getObject(MchDivisionReceiverGroup.class);
LambdaQueryWrapper<MchDivisionReceiverGroup> condition = MchDivisionReceiverGroup.gw();
condition.eq(MchDivisionReceiverGroup::getMchNo, getCurrentMchNo());
if(StringUtils.isNotEmpty(queryObject.getReceiverGroupName())){
condition.like(MchDivisionReceiverGroup::getReceiverGroupName, queryObject.getReceiverGroupName());
}
if(queryObject.getReceiverGroupId() != null){
condition.eq(MchDivisionReceiverGroup::getReceiverGroupId, queryObject.getReceiverGroupId());
}
condition.orderByDesc(MchDivisionReceiverGroup::getCreatedAt); //时间倒序
IPage<MchDivisionReceiverGroup> pages = mchDivisionReceiverGroupService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_GROUP_VIEW' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") Long recordId) {
MchDivisionReceiverGroup record = mchDivisionReceiverGroupService
.getOne(MchDivisionReceiverGroup.gw()
.eq(MchDivisionReceiverGroup::getMchNo, getCurrentMchNo())
.eq(MchDivisionReceiverGroup::getReceiverGroupId, recordId));
if (record == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SELETE);
}
return ApiRes.ok(record);
}
/** add */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_GROUP_ADD' )")
@RequestMapping(value="", method = RequestMethod.POST)
@MethodLog(remark = "新增分账账号组")
public ApiRes add() {
MchDivisionReceiverGroup record = getObject(MchDivisionReceiverGroup.class);
record.setMchNo(getCurrentMchNo());
record.setCreatedUid(getCurrentUser().getSysUser().getSysUserId());
record.setCreatedBy(getCurrentUser().getSysUser().getRealname());
if(mchDivisionReceiverGroupService.save(record)){
//更新其他组为非默认分账组
if(record.getAutoDivisionFlag() == CS.YES){
mchDivisionReceiverGroupService.update(new LambdaUpdateWrapper<MchDivisionReceiverGroup>()
.set(MchDivisionReceiverGroup::getAutoDivisionFlag, CS.NO)
.eq(MchDivisionReceiverGroup::getMchNo, getCurrentMchNo())
.ne(MchDivisionReceiverGroup::getReceiverGroupId, record.getReceiverGroupId())
);
}
}
return ApiRes.ok();
}
/** update */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_GROUP_EDIT' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.PUT)
@MethodLog(remark = "更新分账账号组")
public ApiRes update(@PathVariable("recordId") Long recordId) {
MchDivisionReceiverGroup reqRecord = getObject(MchDivisionReceiverGroup.class);
MchDivisionReceiverGroup record = new MchDivisionReceiverGroup();
record.setReceiverGroupName(reqRecord.getReceiverGroupName());
record.setAutoDivisionFlag(reqRecord.getAutoDivisionFlag());
LambdaUpdateWrapper<MchDivisionReceiverGroup> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(MchDivisionReceiverGroup::getReceiverGroupId, recordId);
updateWrapper.eq(MchDivisionReceiverGroup::getMchNo, getCurrentMchNo());
if(mchDivisionReceiverGroupService.update(record, updateWrapper)){
//更新其他组为非默认分账组
if(record.getAutoDivisionFlag() == CS.YES){
mchDivisionReceiverGroupService.update(new LambdaUpdateWrapper<MchDivisionReceiverGroup>()
.set(MchDivisionReceiverGroup::getAutoDivisionFlag, CS.NO)
.eq(MchDivisionReceiverGroup::getMchNo, getCurrentMchNo())
.ne(MchDivisionReceiverGroup::getReceiverGroupId, recordId)
);
}
}
return ApiRes.ok();
}
/** delete */
@PreAuthorize("hasAuthority('ENT_DIVISION_RECEIVER_GROUP_DELETE')")
@RequestMapping(value="/{recordId}", method = RequestMethod.DELETE)
@MethodLog(remark = "删除分账账号组")
public ApiRes del(@PathVariable("recordId") Long recordId) {
MchDivisionReceiverGroup record = mchDivisionReceiverGroupService.getOne(MchDivisionReceiverGroup.gw()
.eq(MchDivisionReceiverGroup::getReceiverGroupId, recordId).eq(MchDivisionReceiverGroup::getMchNo, getCurrentMchNo()));
if (record == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SELETE);
}
if( mchDivisionReceiverService.count(MchDivisionReceiver.gw().eq(MchDivisionReceiver::getReceiverGroupId, recordId)) > 0){
throw new BizException("该组存在账号,无法删除");
}
mchDivisionReceiverGroupService.removeById(recordId);
return ApiRes.ok();
}
}
/*
* Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeequan.jeepay.mch.ctrl.division;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.mch.ctrl.CommonCtrl;
import com.jeequan.jeepay.service.impl.PayOrderDivisionRecordService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 分账记录
*
* @author terrfly
* @site https://www.jeequan.com
* @date 2021-08-25 11:50
*/
@RestController
@RequestMapping("api/division/records")
public class PayOrderDivisionRecordController extends CommonCtrl {
@Autowired private PayOrderDivisionRecordService payOrderDivisionRecordService;
/** list */
@PreAuthorize("hasAnyAuthority( 'ENT_DIVISION_RECORD_LIST' )")
@RequestMapping(value="", method = RequestMethod.GET)
public ApiRes list() {
PayOrderDivisionRecord queryObject = getObject(PayOrderDivisionRecord.class);
JSONObject paramJSON = getReqParamJSON();
LambdaQueryWrapper<PayOrderDivisionRecord> condition = PayOrderDivisionRecord.gw();
condition.eq(PayOrderDivisionRecord::getMchNo, getCurrentMchNo());
if(queryObject.getReceiverId() != null){
condition.eq(PayOrderDivisionRecord::getReceiverId, queryObject.getReceiverId());
}
if(queryObject.getReceiverGroupId() != null){
condition.eq(PayOrderDivisionRecord::getReceiverGroupId, queryObject.getReceiverGroupId());
}
if(StringUtils.isNotEmpty(queryObject.getAppId())){
condition.like(PayOrderDivisionRecord::getAppId, queryObject.getAppId());
}
if(queryObject.getState() != null){
condition.eq(PayOrderDivisionRecord::getState, queryObject.getState());
}
if(StringUtils.isNotEmpty(queryObject.getPayOrderId())){
condition.eq(PayOrderDivisionRecord::getPayOrderId, queryObject.getPayOrderId());
}
if(StringUtils.isNotEmpty(queryObject.getAccNo())){
condition.eq(PayOrderDivisionRecord::getAccNo, queryObject.getAccNo());
}
if (paramJSON != null) {
if (StringUtils.isNotEmpty(paramJSON.getString("createdStart"))) {
condition.ge(PayOrderDivisionRecord::getCreatedAt, paramJSON.getString("createdStart"));
}
if (StringUtils.isNotEmpty(paramJSON.getString("createdEnd"))) {
condition.le(PayOrderDivisionRecord::getCreatedAt, paramJSON.getString("createdEnd"));
}
}
condition.orderByDesc(PayOrderDivisionRecord::getCreatedAt); //时间倒序
IPage<PayOrderDivisionRecord> pages = payOrderDivisionRecordService.page(getIPage(true), condition);
return ApiRes.page(pages);
}
/** detail */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECORD_VIEW' )")
@RequestMapping(value="/{recordId}", method = RequestMethod.GET)
public ApiRes detail(@PathVariable("recordId") Long recordId) {
PayOrderDivisionRecord record = payOrderDivisionRecordService
.getOne(PayOrderDivisionRecord.gw()
.eq(PayOrderDivisionRecord::getMchNo, getCurrentMchNo())
.eq(PayOrderDivisionRecord::getRecordId, recordId));
if (record == null) {
throw new BizException(ApiCodeEnum.SYS_OPERATION_FAIL_SELETE);
}
return ApiRes.ok(record);
}
}
......@@ -21,26 +21,22 @@ import com.jeequan.jeepay.components.mq.vender.IMQSender;
import com.jeequan.jeepay.core.aop.MethodLog;
import com.jeequan.jeepay.core.constants.ApiCodeEnum;
import com.jeequan.jeepay.core.constants.CS;
import com.jeequan.jeepay.core.entity.MchApp;
import com.jeequan.jeepay.core.entity.MchInfo;
import com.jeequan.jeepay.core.entity.PayInterfaceConfig;
import com.jeequan.jeepay.core.entity.PayInterfaceDefine;
import com.jeequan.jeepay.core.entity.*;
import com.jeequan.jeepay.core.exception.BizException;
import com.jeequan.jeepay.core.model.ApiRes;
import com.jeequan.jeepay.core.model.params.NormalMchParams;
import com.jeequan.jeepay.core.utils.StringKit;
import com.jeequan.jeepay.mch.ctrl.CommonCtrl;
import com.jeequan.jeepay.service.impl.MchAppService;
import com.jeequan.jeepay.service.impl.MchInfoService;
import com.jeequan.jeepay.service.impl.PayInterfaceConfigService;
import com.jeequan.jeepay.service.impl.SysConfigService;
import com.jeequan.jeepay.service.impl.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 商户支付接口配置类
......@@ -180,4 +176,25 @@ public class MchPayInterfaceConfigController extends CommonCtrl {
}
/** 查询当前应用支持的支付接口 */
@PreAuthorize("hasAuthority( 'ENT_DIVISION_RECEIVER_ADD' )")
@RequestMapping(value="ifCodes/{appId}", method = RequestMethod.GET)
public ApiRes getIfCodeByAppId(@PathVariable("appId") String appId) {
if(mchAppService.count(MchApp.gw().eq(MchApp::getMchNo, getCurrentMchNo()).eq(MchApp::getAppId, appId)) <= 0){
throw new BizException("商户应用不存在");
}
Set<String> result = new HashSet<>();
payInterfaceConfigService.list(PayInterfaceConfig.gw().select(PayInterfaceConfig::getIfCode)
.eq(PayInterfaceConfig::getState, CS.PUB_USABLE)
.eq(PayInterfaceConfig::getInfoId, appId)
.eq(PayInterfaceConfig::getInfoType, CS.INFO_TYPE_MCH_APP)
).stream().forEach(r -> result.add(r.getIfCode()));
return ApiRes.ok(result);
}
}
......@@ -85,6 +85,9 @@ public class PayOrderController extends CommonCtrl {
if (StringUtils.isNotEmpty(payOrder.getAppId())) {
wrapper.eq(PayOrder::getAppId, payOrder.getAppId());
}
if (payOrder.getDivisionState() != null) {
wrapper.eq(PayOrder::getDivisionState, payOrder.getDivisionState());
}
if (paramJSON != null) {
if (StringUtils.isNotEmpty(paramJSON.getString("createdStart"))) {
wrapper.ge(PayOrder::getCreatedAt, paramJSON.getString("createdStart"));
......
......@@ -81,6 +81,13 @@ public class PaytestController extends CommonCtrl {
String mchOrderNo = getValStringRequired("mchOrderNo");
String wayCode = getValStringRequired("wayCode");
Byte divisionMode = getValByteRequired("divisionMode");
String orderTitle = getValStringRequired("orderTitle");
if(StringUtils.isEmpty(orderTitle)){
throw new BizException("订单标题不能为空");
}
// 前端明确了支付参数的类型 payDataType
String payDataType = getValString("payDataType");
String authCode = getValString("authCode");
......@@ -102,9 +109,10 @@ public class PaytestController extends CommonCtrl {
model.setAmount(amount);
model.setCurrency("CNY");
model.setClientIp(getClientIp());
model.setSubject(getCurrentMchNo() + "商户联调");
model.setBody(getCurrentMchNo() + "商户联调");
model.setSubject(orderTitle + "[" + getCurrentMchNo() + "商户联调]");
model.setBody(orderTitle + "[" + getCurrentMchNo() + "商户联调]");
model.setNotifyUrl(sysConfigService.getDBApplicationConfig().getMchSiteUrl() + "/api/anon/paytestNotify/payOrder"); //回调地址
model.setDivisionMode(divisionMode); //分账模式
//设置扩展参数
JSONObject extParams = new JSONObject();
......
......@@ -16,6 +16,7 @@
package com.jeequan.jeepay.pay.channel;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.pay.util.ChannelCertConfigKitBean;
import com.jeequan.jeepay.service.impl.SysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -32,6 +33,15 @@ public abstract class AbstractPaymentService implements IPaymentService{
@Autowired protected SysConfigService sysConfigService;
@Autowired protected ChannelCertConfigKitBean channelCertConfigKitBean;
/** 订单分账(一般用作 如微信订单将在下单处做标记) */
protected boolean isDivisionOrder(PayOrder payOrder){
//订单分账, 将冻结商户资金。
if(payOrder.getDivisionMode() != null && (PayOrder.DIVISION_MODE_AUTO == payOrder.getDivisionMode() || PayOrder.DIVISION_MODE_MANUAL == payOrder.getDivisionMode() )){
return true;
}
return false;
}
protected String getNotifyUrl(){
return sysConfigService.getDBApplicationConfig().getPaySiteUrl() + "/api/pay/notify/" + getIfCode();
}
......
......@@ -16,6 +16,7 @@
package com.jeequan.jeepay.pay.channel;
import com.jeequan.jeepay.core.entity.MchDivisionReceiver;
import com.jeequan.jeepay.core.entity.PayOrder;
import com.jeequan.jeepay.core.entity.PayOrderDivisionRecord;
import com.jeequan.jeepay.core.entity.TransferOrder;
import com.jeequan.jeepay.pay.model.MchAppConfigContext;
......@@ -40,9 +41,9 @@ public interface IDivisionService {
boolean isSupport();
/** 绑定关系 **/
boolean bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext);
ChannelRetMsg bind(MchDivisionReceiver mchDivisionReceiver, MchAppConfigContext mchAppConfigContext);
/** 单次分账 (无需调用完结接口,或自动解冻商户资金) **/
boolean singleDivision(List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
ChannelRetMsg singleDivision(PayOrder payOrder, List<PayOrderDivisionRecord> recordList, MchAppConfigContext mchAppConfigContext);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment