feat: add import

This commit is contained in:
Donghuang 2024-10-10 21:20:48 +08:00
parent d5043a3141
commit 00a5bce427
95 changed files with 3159 additions and 671 deletions

View File

@ -20,7 +20,6 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>

View File

@ -19,19 +19,17 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>junit</groupId>
@ -39,13 +37,8 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -1,7 +1,8 @@
package com.pudonghot.yo.util;
import lombok.val;
import java.io.File;
import org.bson.types.ObjectId;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
/**
@ -27,7 +28,7 @@ public class FileUtils {
* @return temp file
*/
public static File tempFile(final File dir, final String suffix) {
return new File(dir, ObjectId.get() + suffix);
return new File(dir, uuid() + suffix);
}
/**
@ -37,6 +38,12 @@ public class FileUtils {
* @return temp file
*/
public static File tempFile(final String dir, final String suffix) {
return new File(dir, ObjectId.get() + suffix);
return new File(dir, uuid() + suffix);
}
static String uuid() {
val uuid = UUID.randomUUID();
return Long.toHexString(uuid.getMostSignificantBits())
+ Long.toHexString(uuid.getLeastSignificantBits());
}
}

View File

@ -0,0 +1,203 @@
package com.pudonghot.yo.util;
import lombok.val;
import lombok.Getter;
import java.util.Map;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Pattern;
import java.text.ParseException;
import lombok.extern.slf4j.Slf4j;
import lombok.RequiredArgsConstructor;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
/**
* @author Donghuang
* @date Oct 08, 2024 16:31:49
*/
@Slf4j
@UtilityClass
public class IdCardUtils {
private static final int[] FACTORS = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
private static final char[] VERIFY_CODES = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
private static final Map<String, String> AREA_CODES = new HashMap<>();
static {
AREA_CODES.put("11", "北京");
AREA_CODES.put("12", "天津");
AREA_CODES.put("13", "河北");
AREA_CODES.put("14", "山西");
AREA_CODES.put("15", "内蒙古");
AREA_CODES.put("21", "辽宁");
AREA_CODES.put("22", "吉林");
AREA_CODES.put("23", "黑龙江");
AREA_CODES.put("31", "上海");
AREA_CODES.put("32", "江苏");
AREA_CODES.put("33", "浙江");
AREA_CODES.put("34", "安徽");
AREA_CODES.put("35", "福建");
AREA_CODES.put("36", "江西");
AREA_CODES.put("37", "山东");
AREA_CODES.put("41", "河南");
AREA_CODES.put("42", "湖北");
AREA_CODES.put("43", "湖南");
AREA_CODES.put("44", "广东");
AREA_CODES.put("45", "广西");
AREA_CODES.put("46", "海南");
AREA_CODES.put("50", "重庆");
AREA_CODES.put("51", "四川");
AREA_CODES.put("52", "贵州");
AREA_CODES.put("53", "云南");
AREA_CODES.put("54", "西藏");
AREA_CODES.put("61", "陕西");
AREA_CODES.put("62", "甘肃");
AREA_CODES.put("63", "青海");
AREA_CODES.put("64", "宁夏");
AREA_CODES.put("65", "新疆");
AREA_CODES.put("71", "台湾");
AREA_CODES.put("81", "香港");
AREA_CODES.put("82", "澳门");
AREA_CODES.put("91", "国外");
}
private static final Pattern PATTERN15 = Pattern.compile("^(" + StringUtils.join(AREA_CODES.keySet(), "|") + ")\\d{13}$");
private static final Pattern PATTERN18 = Pattern.compile("^(" + StringUtils.join(AREA_CODES.keySet(), "|") + ")\\d{15}[X\\d]$", Pattern.CASE_INSENSITIVE);
public record IdCard(String number, Gender gender, Date birthdate, String province) {
@Getter
@RequiredArgsConstructor
public enum Gender {
M(""),
F("");
private final String text;
}
}
/**
* validate id card number, 18 digits only
*
* @param idCard id card
* @return true if valid
*/
public static boolean validate(final String idCard) {
return parse(idCard) != null;
}
/**
* parse id card number
*
* @param idCard id card
* @return id card if valid
*/
public static IdCard parse(final String idCard) {
val card = parse18(idCard);
return card != null ? card : parse15(idCard);
}
/**
* parse id card number, 15 digits only
*
* @param idCard id card
* @return id card if valid
*/
public static IdCard parse15(final String idCard) {
val idCard18 = convertTo18(idCard);
if (StringUtils.isBlank(idCard18)) {
return null;
}
return parse18(idCard18);
}
/**
* parse id card number, 18 digits only
*
* @param idCard id card
* @return id card if valid
*/
public static IdCard parse18(final String idCard) {
if (StringUtils.isBlank(idCard)) {
return null;
}
val m = PATTERN18.matcher(idCard);
if (!m.find()) {
return null;
}
val chars = idCard.toCharArray();
// 身份证号码校验公式 RESULT = ( A[i] * W[i] ) mod 11
val verifyChar = getVerifyChar(idCard);
if (chars[17] != verifyChar) {
return null;
}
val birthDate = getBirthdate(idCard);
if (birthDate == null) {
return null;
}
return new IdCard(idCard, idCard.charAt(16) % 2 == 0 ?
IdCard.Gender.F : IdCard.Gender.M,
birthDate,
AREA_CODES.get(idCard.substring(0, 2)));
}
static char getVerifyChar(final String idCard) {
val chars = idCard.toCharArray();
// 身份证号码校验公式 RESULT = ( A[i] * W[i] ) mod 11
int sumFactor = 0;
for (int i = 0; i < FACTORS.length; ++i) {
// Number ASCII range 48-57
// number char to int
sumFactor += FACTORS[i] * (chars[i] - 48);
}
return VERIFY_CODES[sumFactor % 11];
}
public static String convertTo18(final String idCard) {
if (StringUtils.isBlank(idCard)) {
return null;
}
val m = PATTERN15.matcher(idCard);
if (!m.find()) {
return null;
}
val sbIdCard = new StringBuilder(idCard).insert(6, "19");
sbIdCard.append(getVerifyChar(sbIdCard.toString()));
return sbIdCard.toString();
}
Date getBirthdate(final String idCard) {
try {
val birthDate = DateUtils.parseDate(idCard.substring(6, 14), "yyyyMMdd");
if (birthDate.after(new Date())) {
return null;
}
if (birthDate.before(DateUtils.addYears(new Date(), -150))) {
return null;
}
return birthDate;
}
catch (final ParseException e) {
log.debug("Parse id card [{}] birthdate error caused.", idCard, e);
return null;
}
}
}

View File

@ -1,7 +1,6 @@
package com.pudonghot.yo.util;
import lombok.val;
import java.util.List;
import java.util.function.Consumer;

View File

@ -0,0 +1,94 @@
package com.pudonghot.yo.util;
import lombok.val;
import org.junit.Test;
import org.junit.Assert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
/**
* @author Donghuang
* @date Oct 08, 2024 20:47:01
*/
@Slf4j
public class IdCardUtilsTest {
@Test
public void testIdCardParse() {
val tests = new String[] {
"32132320180313094X,2018-03-13,女,江苏省",
"469002200404173681,2004-04-17,女,海南省",
"13062619971210987X,1997-12-10,男,河北省",
"350825197011242498,1970-11-24,男,福建省",
"34162119771106746X,1977-11-06,女,安徽省",
"421022196705153723,1967-05-15,女,湖北省",
"232722196502125275,1965-02-12,男,黑龙江省",
"370302199006090558,1990-06-09,男,山东省",
"450722200506035072,2005-06-03,男,广西壮族自治区",
"411424202201311100,2022-01-31,女,河南省",
"310151200206201735,2002-06-20,男,上海市",
"37052320151206956X,2015-12-06,女,山东省",
"540422200511215671,2005-11-21,男,西藏自治区",
"140302202111241487,2021-11-24,女,山西省",
"540628199907012743,1999-07-01,女,西藏自治区",
"130706198612205966,1986-12-20,女,河北省",
"371523194505061525,1945-05-06,女,山东省",
"340822198204221830,1982-04-22,男,安徽省",
"371321195707292584,1957-07-29,女,山东省",
"610118196110182977,1961-10-18,男,陕西省",
"610628198805103242,1988-05-10,女,陕西省",
"540423199504286405,1995-04-28,女,西藏自治区",
"140925196611145247,1966-11-14,女,山西省",
"41032720200106171X,2020-01-06,男,河南省",
"140581199202057417,1992-02-05,男,山西省",
"130708201206214389,2012-06-21,女,河北省",
"511421195310212381,1953-10-21,女,四川省",
"62302619740725180X,1974-07-25,女,甘肃省",
"621228196507163898,1965-07-16,男,甘肃省",
"23088119940427141X,1994-04-27,男,黑龙江省",
"320830200508227437,2005-08-22,男,江苏省",
"431026200105283395,2001-05-28,男,湖南省",
"150404197401183875,1974-01-18,男,内蒙古自治区",
"370214201806246397,2018-06-24,男,山东省",
"230206199705137713,1997-05-13,男,黑龙江省",
"451031196907165601,1969-07-16,女,广西壮族自治区",
"230902197804115046,1978-04-11,女,黑龙江省",
"522629197506082092,1975-06-08,男,贵州省",
"211002199110058160,1991-10-05,女,辽宁省",
"440604198011196050,1980-11-19,男,广东省",
"350430200911129742,2009-11-12,女,福建省",
"440402202304014631,2023-04-01,男,广东省",
"120110200407284386,2004-07-28,女,天津市",
"620524199801109159,1998-01-10,男,甘肃省",
"421281197301147218,1973-01-14,男,湖北省",
"511703194802076143,1948-02-07,女,四川省",
"320585195711062856,1957-11-06,男,江苏省",
"320116202203028887,2022-03-02,女,江苏省",
"130534201606221029,2016-06-22,女,河北省",
"520523196410296088,1964-10-29,女,贵州省",
"511181200202015835,2002-02-01,男,四川省",
"370322196112127651,1961-12-12,男,山东省",
"652825197509187548,1975-09-18,女,新疆维吾尔自治区",
"52052119510706309X,1951-07-06,男,贵州省",
"230718195112153413,1951-12-15,男,黑龙江省",
"513326195006228977,1950-06-22,男,四川省",
"632823198705212593,1987-05-21,男,青海省",
"130527200703145269,2007-03-14,女,河北省",
"340406198811062251,1988-11-06,男,安徽省",
"533423199403280734,1994-03-28,男,云南省",
"620825199601131565,1996-01-13,女,甘肃省",
"330603197906266965,1979-06-26,女,浙江省",
"210381198812245194,1988-12-24,男,辽宁省",
"533102201110282332,2011-10-28,男,云南省",
"533423940328073,1994-03-28,男,云南省",
};
for (val test : tests) {
val rec = test.split(",");
val resp = IdCardUtils.parse(rec[0]);
Assert.assertNotNull(resp);
Assert.assertEquals(DateFormatUtils.format(resp.birthdate(), "yyyy-MM-dd"), rec[1]);
Assert.assertEquals(rec[2], resp.gender().getText());
}
}
}

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="180 seconds">>
<property name="log.level" value="TRACE" />
<property name="log.dir" value="target/logs" />
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%magenta(%d{"yyyy-MM-dd HH:mm:ss,SSS"}) [%thread][%X{traceId}] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.dir}/app.log</file>
<encoder>
<pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"} [%thread][%X{traceId}] %-5level %logger{15} %msg %n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/%d{yyyy-MM, aux}/app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>32MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="org.springframework" level="INFO" additivity="false">
<appender-ref ref="Console" />
<appender-ref ref="File" />
</logger>
<logger name="org.apache" level="WARN" additivity="false">
<appender-ref ref="File" />
</logger>
<logger name="org.hibernate.validator" level="WARN" additivity="false">
<appender-ref ref="File" />
</logger>
<root level="${log.level}">
<appender-ref ref="Console" />
<appender-ref ref="File" />
</root>
</configuration>

View File

@ -0,0 +1 @@
# TJ Operation Common

47
operation/common/pom.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>yo-tj-operation-common</artifactId>
<name>Yo Tiaojie Operation Common</name>
<description>Yo Tiaojie Operation Common</description>
<parent>
<groupId>com.pudonghot.yo</groupId>
<artifactId>yo-tj-operation</artifactId>
<version>${revision}</version>
</parent>
<dependencies>
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-common</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,12 @@
package com.pudonghot.yo.operation.common;
/**
* @author Donghuang
* @date Oct 10, 2024 11:06:40
*/
public interface Constants {
String GENDER_MALE = "M";
String GENDER_FEMALE = "F";
String GENDER_REGEXP = "^M|F$";
}

View File

@ -0,0 +1,22 @@
package com.pudonghot.yo.operation.enumeration.customer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.pudonghot.tigon.enumuration.LabelEnum;
/**
* @author Donghuang
* @date Oct 10, 2024 11:05:03
*/
@Getter
@RequiredArgsConstructor
public enum GenderEnum implements LabelEnum {
M(""),
F(""),
U("未知"),
;
private final String label;
}

View File

@ -0,0 +1,22 @@
package com.pudonghot.yo.operation.enumeration.repayment;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.pudonghot.tigon.enumuration.LabelEnum;
/**
* @author Donghuang
* @date Oct 10, 2024 11:05:03
*/
@Getter
@RequiredArgsConstructor
public enum RepaymentStatusEnum implements LabelEnum {
UNPAID("未还款"),
FULLY_PAID("已还款"),
PARTIALLY_PAID("部分还款"),
;
private final String label;
}

View File

@ -0,0 +1,35 @@
package com.pudonghot.yo.operation.event;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import lombok.RequiredArgsConstructor;
/**
* @author Donghuang
* @date Jun 18, 2023 12:26:40
*/
@Getter
@Setter
@ToString
@RequiredArgsConstructor
public class WebSocketPushEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final String topic;
private final WebSocketPushEventPayload payload;
public static WebSocketPushEvent of(final String topic,
final WebSocketPushEventPayload payload) {
return new WebSocketPushEvent(topic, payload);
}
@Getter
@ToString
@RequiredArgsConstructor
public static class WebSocketPushEventPayload implements Serializable {
private static final long serialVersionUID = 1L;
private final String type;
}
}

View File

@ -0,0 +1,17 @@
package com.pudonghot.yo.operation.common;
import org.junit.Test;
import lombok.extern.slf4j.Slf4j;
/**
* @author Donghuang
* @date Oct 10, 2024 11:02:33
*/
@Slf4j
public class TestDriver {
@Test
public void testRun() {
log.info("Run.");
}
}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="180 seconds">>
<property name="log.level" value="DEBUG" />
<property name="log.dir" value="target/.logs" />
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%magenta(%d{"yyyy-MM-dd HH:mm:ss,SSS"}) [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.dir}/${project.artifactId}.log</file>
<encoder>
<pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"} [%thread] %-5level %logger{15} %msg %n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/%d{yyyy-MM, aux}/${project.artifactId}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>32MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
</appender>
<logger name="org.springframework" level="${log.level}" additivity="false">
<appender-ref ref="Console" />
<appender-ref ref="File" />
</logger>
<root level="${log.level}">
<appender-ref ref="Console" />
<appender-ref ref="File" />
</root>
</configuration>

View File

@ -20,7 +20,6 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@ -37,6 +36,18 @@
<!--/三方依赖-->
<!--二方依赖-->
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-kit</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-dal</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.yo</groupId>
<artifactId>yo-basic-model</artifactId>
@ -50,16 +61,8 @@
<artifactId>yo-util</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-kit</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-dal</artifactId>
<groupId>com.pudonghot.yo</groupId>
<artifactId>yo-tj-operation-common</artifactId>
</dependency>
<!--/二方依赖-->

View File

@ -2,6 +2,7 @@ package com.pudonghot.yo.operation.dal.application;
import com.pudonghot.yo.operation.dal.application.model.ApplicationDO;
import com.pudonghot.tigon.dal.BaseDal;
import jakarta.validation.constraints.NotNull;
/**
* 案件原始信息表
@ -10,4 +11,12 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:19:20
*/
public interface ApplicationDal extends BaseDal<Long, ApplicationDO> {
/**
* find app by loan id
*
* @param loanId loan id
* @return application
*/
ApplicationDO findByLoanId(Long loanId);
}

View File

@ -2,6 +2,7 @@ package com.pudonghot.yo.operation.dal.application;
import com.pudonghot.yo.operation.dal.application.model.ApplicationExtDO;
import com.pudonghot.tigon.dal.BaseDal;
import jakarta.validation.constraints.NotNull;
/**
* 案件申请扩展表
@ -10,4 +11,20 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 02, 2024 11:30:55
*/
public interface ApplicationExtDal extends BaseDal<Long, ApplicationExtDO> {
/**
* find app ext by loan id
*
* @param loanId loan id
* @return app ext
*/
ApplicationExtDO findByLoanId(Long loanId);
/**
* remove app ext by loan id
*
* @param loanId loan id
* @return rows
*/
Integer removeByLoanId(Long loanId);
}

View File

@ -1,10 +1,11 @@
package com.pudonghot.yo.operation.dal.application.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import com.pudonghot.yo.operation.dal.application.ApplicationDal;
import com.pudonghot.yo.operation.dal.application.model.ApplicationDO;
import com.pudonghot.yo.operation.dal.application.mapper.ApplicationMapper;
import com.pudonghot.yo.operation.dal.application.ApplicationDal;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
/**
* 案件原始信息表
@ -16,4 +17,12 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class ApplicationDalImpl
extends BaseDalImpl<Long, ApplicationDO, ApplicationMapper>
implements ApplicationDal {
/**
* {@inheritDoc}
*/
@Override
public ApplicationDO findByLoanId(final Long loanId) {
return find(Search.of(ApplicationDO.Fields.loanId, loanId));
}
}

View File

@ -1,10 +1,11 @@
package com.pudonghot.yo.operation.dal.application.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import com.pudonghot.yo.operation.dal.application.ApplicationExtDal;
import com.pudonghot.yo.operation.dal.application.model.ApplicationExtDO;
import com.pudonghot.yo.operation.dal.application.mapper.ApplicationExtMapper;
import com.pudonghot.yo.operation.dal.application.ApplicationExtDal;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
/**
* 案件申请扩展表
@ -16,4 +17,20 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class ApplicationExtDalImpl
extends BaseDalImpl<Long, ApplicationExtDO, ApplicationExtMapper>
implements ApplicationExtDal {
/**
* {@inheritDoc}
*/
@Override
public ApplicationExtDO findByLoanId(final Long loanId) {
return find(Search.of(ApplicationExtDO.Fields.loanId, loanId));
}
/**
* {@inheritDoc}
*/
@Override
public Integer removeByLoanId(final Long loanId) {
return mapper.delete(Search.of(ApplicationExtDO.Fields.loanId, loanId));
}
}

View File

@ -8,6 +8,7 @@ import com.pudonghot.tigon.mybatis.NotUpdate;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
import com.pudonghot.tigon.mybatis.NotUpdateWhenNull;
/**
* 案件原始信息表
@ -31,86 +32,103 @@ public class ApplicationDO extends BaseDbEntity {
/**
* 总期数
*/
@NotUpdateWhenNull
private Integer totalInstallments;
/**
* 当前期数
*/
@NotUpdateWhenNull
private Integer currentInstallment;
/**
* 已还期数
*/
@NotUpdateWhenNull
private Integer repaidInstallments;
/**
* 逾期期数
*/
@NotUpdateWhenNull
private Integer overdueInstallments;
/**
* 申请时间
*/
@NotUpdateWhenNull
private Date applyDate;
/**
* 批核时间
*/
@NotUpdateWhenNull
private Date approveDate;
/**
* 放款时间
*/
@NotUpdateWhenNull
private Date loanDate;
/**
* 当期账单日
*/
@NotUpdateWhenNull
private Date dueDate;
/**
* 利率
*/
@NotUpdateWhenNull
private BigDecimal interestRate;
/**
* 服务费率
*/
@NotUpdateWhenNull
private BigDecimal serviceInterestRate;
/**
* 罚息利率
*/
@NotUpdateWhenNull
private BigDecimal penaltyInterestRate;
/**
* 合同(申请)金额
*/
@NotUpdateWhenNull
private Long applyAmount;
/**
* 放款金额
*/
@NotUpdateWhenNull
private Long loanAmount;
/**
* 违约金,罚金
*/
@NotUpdateWhenNull
private Long defaultFineAmount;
/**
* 逾期金额
*/
@NotUpdateWhenNull
private Long overdueAmount;
/**
* 剩余本金
*/
@NotUpdateWhenNull
private Long principalRemain;
/**
* 提前清贷金额
*/
@NotUpdateWhenNull
private Long prepaymentAmount;
/**

View File

@ -6,6 +6,7 @@ import com.pudonghot.tigon.mybatis.NotUpdate;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
import com.pudonghot.tigon.dal.model.EntityJsonField;
/**
* 案件申请扩展表
@ -29,50 +30,50 @@ public class ApplicationExtDO extends BaseDbEntity {
/**
* 附加字段1
*/
private String extData1;
private EntityJsonField extData1;
/**
* 附加字段2
*/
private String extData2;
private EntityJsonField extData2;
/**
* 附加字段3
*/
private String extData3;
private EntityJsonField extData3;
/**
* 附加字段4
*/
private String extData4;
private EntityJsonField extData4;
/**
* 附加字段5
*/
private String extData5;
private EntityJsonField extData5;
/**
* 附加字段6
*/
private String extData6;
private EntityJsonField extData6;
/**
* 附加字段7
*/
private String extData7;
private EntityJsonField extData7;
/**
* 附加字段8
*/
private String extData8;
private EntityJsonField extData8;
/**
* 附加字段9
*/
private String extData9;
private EntityJsonField extData9;
/**
* 附加字段10
*/
private String extData10;
private EntityJsonField extData10;
}

View File

@ -1,5 +1,6 @@
package com.pudonghot.yo.operation.dal.dept;
import java.util.Collection;
import java.util.List;
import com.pudonghot.tigon.dal.BaseDal;
import com.pudonghot.yo.operation.dal.dept.model.DeptDO;
@ -18,4 +19,20 @@ public interface DeptDal extends BaseDal<Long, DeptDO> {
* @return top depts
*/
List<DeptDO> listTop();
/**
* find by name
*
* @param name name
* @return dept
*/
DeptDO findByName(String name);
/**
* list by names
*
* @param names names
* @return depts
*/
List<DeptDO> listByNames(Collection<String> names);
}

View File

@ -1,5 +1,6 @@
package com.pudonghot.yo.operation.dal.dept.impl;
import java.util.Collection;
import java.util.List;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
@ -26,7 +27,26 @@ public class DeptDalImpl
@Override
public List<DeptDO> listTop() {
return list(Search.of(DeptDO.Fields.parentId, 0L)
.isFalse(BaseDbEntity.Fields.deleted)
.isTrue(BaseDbEntity.Fields.active));
}
/**
* {@inheritDoc}
*/
@Override
public DeptDO findByName(final String name) {
return find(Search.of(DeptDO.Fields.parentId, 0L)
.eq(DeptDO.Fields.name, name)
.isTrue(BaseDbEntity.Fields.active));
}
/**
* {@inheritDoc}
*/
@Override
public List<DeptDO> listByNames(final Collection<String> names) {
return list(Search.of(DeptDO.Fields.parentId, 0L)
.in(DeptDO.Fields.name, names)
.isTrue(BaseDbEntity.Fields.active));
}
}

View File

@ -1,7 +1,7 @@
package com.pudonghot.yo.operation.dal.loan;
import com.pudonghot.yo.operation.dal.loan.model.BankCardDO;
import com.pudonghot.tigon.dal.BaseDal;
import com.pudonghot.yo.operation.dal.loan.model.BankCardDO;
/**
* 银行卡绑定信息表
@ -10,4 +10,12 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:20:47
*/
public interface BankCardDal extends BaseDal<Long, BankCardDO> {
/**
* remove by loan id
*
* @param loanId loan id
* @return rows
*/
Integer removeByLoanId(Long loanId);
}

View File

@ -1,7 +1,7 @@
package com.pudonghot.yo.operation.dal.loan;
import com.pudonghot.yo.operation.dal.loan.model.ContactDO;
import com.pudonghot.tigon.dal.BaseDal;
import com.pudonghot.yo.operation.dal.loan.model.ContactDO;
/**
* 客户联系人表
@ -10,4 +10,12 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:20:47
*/
public interface ContactDal extends BaseDal<Long, ContactDO> {
/**
* remove by loan id
*
* @param loanId loan id
* @return rows
*/
Integer removeByLoanId(Long loanId);
}

View File

@ -2,6 +2,7 @@ package com.pudonghot.yo.operation.dal.loan;
import com.pudonghot.yo.operation.dal.loan.model.CustomerDO;
import com.pudonghot.tigon.dal.BaseDal;
import jakarta.validation.constraints.NotNull;
/**
* 客户表
@ -10,4 +11,12 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:20:47
*/
public interface CustomerDal extends BaseDal<Long, CustomerDO> {
/**
* find by loan id
*
* @param loanId loan id
* @return customer
*/
CustomerDO findByLoanId(Long loanId);
}

View File

@ -1,7 +1,7 @@
package com.pudonghot.yo.operation.dal.loan;
import com.pudonghot.yo.operation.dal.loan.model.LoanDO;
import com.pudonghot.tigon.dal.BaseDal;
import com.pudonghot.yo.operation.dal.loan.model.LoanDO;
/**
* 信贷案件表
@ -10,4 +10,21 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:20:47
*/
public interface LoanDal extends BaseDal<Long, LoanDO> {
/**
* update loan repayment
*
* @param loanId loan id
* @return update rows
*/
Integer updateRepayment(Long loanId);
/**
* find by source id and biz key
*
* @param sourceId source id
* @param bizKey biz key
* @return loan
*/
LoanDO findBySourceIdAndBizKey(Long sourceId, String bizKey);
}

View File

@ -3,6 +3,9 @@ package com.pudonghot.yo.operation.dal.loan;
import com.pudonghot.yo.operation.dal.loan.model.LoanSourceDO;
import com.pudonghot.tigon.dal.BaseDal;
import java.util.Collection;
import java.util.List;
/**
* 案件来源表
*
@ -10,4 +13,28 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:20:47
*/
public interface LoanSourceDal extends BaseDal<Long, LoanSourceDO> {
/**
* find by code
*
* @param code code
* @return loan source
*/
LoanSourceDO findByCode(String code);
/**
* find by name
*
* @param name name
* @return loan source
*/
LoanSourceDO findByName(String name);
/**
* list by names
*
* @param names name
* @return loan sources
*/
List<LoanSourceDO> listByNames(Collection<String> names);
}

View File

@ -1,7 +1,9 @@
package com.pudonghot.yo.operation.dal.loan;
import com.pudonghot.yo.operation.dal.loan.model.RepaymentDO;
import com.pudonghot.tigon.dal.BaseDal;
import com.pudonghot.yo.operation.dal.loan.model.RepaymentDO;
import java.util.List;
/**
* 还款计划表
@ -10,4 +12,29 @@ import com.pudonghot.tigon.dal.BaseDal;
* @date Oct 01, 2024 14:20:47
*/
public interface RepaymentDal extends BaseDal<Long, RepaymentDO> {
/**
* remove repayment by loan id
*
* @param loanId loan id
* @return rows
*/
Integer removeByLoanId(Long loanId);
/**
* list repayments by loan id
*
* @param loanId loan id
* @return repayments
*/
List<RepaymentDO> listByLoanId(Long loanId);
/**
* find repayment and installment
*
* @param loanId loan id
* @param installment installment
* @return repayment
*/
RepaymentDO findByLoanIdAndInstallment(Long loanId, Integer installment);
}

View File

@ -1,5 +1,6 @@
package com.pudonghot.yo.operation.dal.loan.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.yo.operation.dal.loan.model.BankCardDO;
import com.pudonghot.yo.operation.dal.loan.mapper.BankCardMapper;
@ -16,4 +17,12 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class BankCardDalImpl
extends BaseDalImpl<Long, BankCardDO, BankCardMapper>
implements BankCardDal {
/**
* {@inheritDoc}
*/
@Override
public Integer removeByLoanId(final Long loanId) {
return mapper.delete(Search.of(BankCardDO.Fields.loanId, loanId));
}
}

View File

@ -1,5 +1,6 @@
package com.pudonghot.yo.operation.dal.loan.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.yo.operation.dal.loan.model.ContactDO;
import com.pudonghot.yo.operation.dal.loan.mapper.ContactMapper;
@ -16,4 +17,12 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class ContactDalImpl
extends BaseDalImpl<Long, ContactDO, ContactMapper>
implements ContactDal {
/**
* {@inheritDoc}
*/
@Override
public Integer removeByLoanId(final Long loanId) {
return mapper.delete(Search.of(ContactDO.Fields.loanId, loanId));
}
}

View File

@ -1,5 +1,6 @@
package com.pudonghot.yo.operation.dal.loan.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.yo.operation.dal.loan.model.CustomerDO;
import com.pudonghot.yo.operation.dal.loan.mapper.CustomerMapper;
@ -16,4 +17,12 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class CustomerDalImpl
extends BaseDalImpl<Long, CustomerDO, CustomerMapper>
implements CustomerDal {
/**
* {@inheritDoc}
*/
@Override
public CustomerDO findByLoanId(final Long loanId) {
return find(Search.of(CustomerDO.Fields.loanId, loanId));
}
}

View File

@ -1,10 +1,11 @@
package com.pudonghot.yo.operation.dal.loan.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import com.pudonghot.yo.operation.dal.loan.LoanDal;
import com.pudonghot.yo.operation.dal.loan.model.LoanDO;
import com.pudonghot.yo.operation.dal.loan.mapper.LoanMapper;
import com.pudonghot.yo.operation.dal.loan.LoanDal;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
/**
* 信贷案件表
@ -16,4 +17,21 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class LoanDalImpl
extends BaseDalImpl<Long, LoanDO, LoanMapper>
implements LoanDal {
/**
* {@inheritDoc}
*/
@Override
public Integer updateRepayment(final Long loanId) {
return mapper.updateRepayment(loanId);
}
/**
* {@inheritDoc}
*/
@Override
public LoanDO findBySourceIdAndBizKey(final Long sourceId, final String bizKey) {
return find(Search.of(LoanDO.Fields.loanSourceId, sourceId)
.eq(LoanDO.Fields.contractNumber, bizKey));
}
}

View File

@ -1,10 +1,15 @@
package com.pudonghot.yo.operation.dal.loan.impl;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.yo.operation.dal.loan.LoanSourceDal;
import com.pudonghot.yo.operation.dal.loan.model.LoanSourceDO;
import com.pudonghot.yo.operation.dal.loan.mapper.LoanSourceMapper;
import com.pudonghot.yo.operation.dal.loan.LoanSourceDal;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import java.util.Collection;
import java.util.List;
/**
* 案件来源表
@ -16,4 +21,31 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class LoanSourceDalImpl
extends BaseDalImpl<Long, LoanSourceDO, LoanSourceMapper>
implements LoanSourceDal {
/**
* {@inheritDoc}
*/
@Override
public LoanSourceDO findByCode(final String code) {
return find(Search.of(LoanSourceDO.Fields.loanSourceCode, code)
.isTrue(BaseDbEntity.Fields.active));
}
/**
* {@inheritDoc}
*/
@Override
public LoanSourceDO findByName(final String name) {
return find(Search.of(LoanSourceDO.Fields.loanSourceName, name)
.isTrue(BaseDbEntity.Fields.active));
}
/**
* {@inheritDoc}
*/
@Override
public List<LoanSourceDO> listByNames(final Collection<String> names) {
return list(Search.of(LoanSourceDO.Fields.loanSourceName, names)
.isTrue(BaseDbEntity.Fields.active));
}
}

View File

@ -1,10 +1,14 @@
package com.pudonghot.yo.operation.dal.loan.impl;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.Search;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import org.springframework.stereotype.Component;
import com.pudonghot.yo.operation.dal.loan.RepaymentDal;
import com.pudonghot.yo.operation.dal.loan.model.RepaymentDO;
import com.pudonghot.yo.operation.dal.loan.mapper.RepaymentMapper;
import com.pudonghot.yo.operation.dal.loan.RepaymentDal;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import java.util.List;
/**
* 还款计划表
@ -16,4 +20,31 @@ import com.pudonghot.tigon.dal.impl.BaseDalImpl;
public class RepaymentDalImpl
extends BaseDalImpl<Long, RepaymentDO, RepaymentMapper>
implements RepaymentDal {
/**
* {@inheritDoc}
*/
@Override
public Integer removeByLoanId(final Long loanId) {
return mapper.delete(Search.of(RepaymentDO.Fields.loanId, loanId));
}
/**
* {@inheritDoc}
*/
@Override
public List<RepaymentDO> listByLoanId(final Long loanId) {
return list(Search.of(RepaymentDO.Fields.loanId, loanId)
.isTrue(BaseDbEntity.Fields.active)
.asc(RepaymentDO.Fields.installment));
}
/**
* {@inheritDoc}
*/
@Override
public RepaymentDO findByLoanIdAndInstallment(final Long loanId, final Integer installment) {
return find(Search.of(RepaymentDO.Fields.loanId, loanId)
.eq(RepaymentDO.Fields.installment, installment));
}
}

View File

@ -14,4 +14,12 @@ import com.pudonghot.yo.operation.dal.loan.model.LoanDO;
@Mapper
@Table("loan")
public interface LoanMapper extends BaseMapper<Long, LoanDO> {
/**
* update repayment info
*
* @param loanId loan id
* @return rows
*/
int updateRepayment(Long loanId);
}

View File

@ -10,4 +10,60 @@
* @date Oct 01, 2024 14:20:47
*/
-->
<update id="updateRepayment">
update <include refid="com.pudonghot.yo.operation.dal.application.mapper.ApplicationMapper.table" /> a
join (
select loan_id,
sum(expect_principal_amount) expect_principal_amount,
sum(actual_principal_amount) actual_principal_amount,
sum(expect_interest_amount) expect_interest_amount,
sum(actual_interest_amount) actual_interest_amount,
sum(expect_service_amount) expect_service_amount,
sum(actual_service_amount) actual_service_amount,
sum(expect_penalty_amount) expect_penalty_amount,
sum(actual_penalty_amount) actual_penalty_amount,
sum(reduction_amount) reduction_amount,
sum(expect_total_amount) expect_total_amount,
sum(actual_total_amount) actual_total_amount,
sum(overdue_amount) overdue_amount,
count(id) total_installments,
count(if (overdue_amount = 0, 1, null)) paid_installments,
count(if (overdue_amount > 0, 1, null)) overdue_installments,
ifnull(min(if (overdue_amount > 0, installment, if (date_format(expect_repay_time, '%Y%m') = date_format(now(), '%Y%m'), installment, null))), 0) current_installment,
min(if (overdue_amount > 0, date(expect_repay_time), if (date_format(expect_repay_time, '%Y%m') = date_format(now(), '%Y%m'), date(expect_repay_time), null))) current_due_date,
ifnull(datediff(now(), min(if (overdue_amount > 0, expect_repay_time, null))), 0) overdue_days,
ifnull(max(if (overdue_amount > 0, status, null)), 'PAID') status,
ifnull(sum(if (expect_repay_time > now(), actual_total_amount, null)), 0) prepayment_amount
from <include refid="com.pudonghot.yo.operation.dal.loan.mapper.RepaymentMapper.table" />
where loan_id = #{loanId}
group by loan_id
) p
on a.loan_id = p.loan_id
join <include refid="table" /> l
on a.loan_id = l.id
set
a.current_installment = p.current_installment,
a.total_installments = p.total_installments,
a.repaid_installments = p.paid_installments,
a.overdue_installments = p.overdue_installments,
a.due_date = p.current_due_date,
a.loan_amount = p.expect_total_amount,
a.overdue_amount = p.overdue_amount,
a.principal_remain = greatest(p.expect_principal_amount - p.actual_principal_amount, 0),
a.prepayment_amount = p.prepayment_amount,
a.default_fine_amount = p.expect_penalty_amount,
l.overdue_amount = p.expect_total_amount,
l.principal_amount = p.expect_principal_amount,
l.interest_amount = p.expect_interest_amount,
l.service_amount = p.expect_service_amount,
l.penalty_amount = p.expect_penalty_amount,
l.repayment_status = p.status,
l.overdue_days = p.overdue_days
</update>
</mapper>

View File

@ -1,11 +1,11 @@
package com.pudonghot.yo.operation.dal.loan.model;
import com.pudonghot.tigon.mybatis.NotUpdate;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
import com.pudonghot.tigon.mybatis.NotUpdate;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
/**
* 客户联系人表

View File

@ -2,10 +2,11 @@ package com.pudonghot.yo.operation.dal.loan.model;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.mybatis.NotUpdate;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
import com.pudonghot.yo.operation.enumeration.customer.GenderEnum;
/**
* 客户表
@ -49,7 +50,7 @@ public class CustomerDO extends BaseDbEntity {
/**
* 性别
*/
private String gender;
private GenderEnum gender;
/**
* 民族

View File

@ -3,8 +3,9 @@ package com.pudonghot.yo.operation.dal.loan.model;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.mybatis.NotUpdate;
import lombok.experimental.FieldNameConstants;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
@ -37,6 +38,7 @@ public class LoanDO extends BaseDbEntity {
* 外部合同号
*/
@NotUpdate
@JsonAlias("bizKey")
private String contractNumber;
/**

View File

@ -8,10 +8,13 @@ import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;
import com.pudonghot.tigon.mybatis.NotUpdateWhenNull;
import com.pudonghot.yo.operation.enumeration.repayment.RepaymentStatusEnum;
/**
* 还款计划表
*
* 注意该表字段需要做加减计算且字段不允许为空因此使用原生intlong类型避免NPE
*
* @author Donghuang
* @date Oct 01, 2024 14:20:47
*/
@ -31,15 +34,17 @@ public class RepaymentDO extends BaseDbEntity {
/**
* 期数
*/
private Integer installment;
@NotUpdate
private int installment;
/**
* 还款状态 UNPAID未还款 PARTIALLY_PAID 部分还款 FULLY_PAID全部还款
*/
private String status;
@NotUpdateWhenNull
private RepaymentStatusEnum status;
/**
* 计还款时间
* 还款时间
*/
@NotUpdateWhenNull
private Date expectRepayTime;
@ -52,47 +57,47 @@ public class RepaymentDO extends BaseDbEntity {
/**
* 应还本金单位
*/
private Long expectPrincipalAmount;
private long expectPrincipalAmount;
/**
* 已还本金单位
*/
private Long actualPrincipalAmount;
private long actualPrincipalAmount;
/**
* 应还利息单位
*/
private Long expectInterestAmount;
private long expectInterestAmount;
/**
* 已还利息单位
*/
private Long actualInterestAmount;
private long actualInterestAmount;
/**
* 应还平台服务费单位
*/
private Long expectServiceAmount;
private long expectServiceAmount;
/**
* 已还平台服务费单位
*/
private Long actualServiceAmount;
private long actualServiceAmount;
/**
* 应还罚息,单位:
*/
private Long expectPenaltyAmount;
private long expectPenaltyAmount;
/**
* 已还罚息,单位:
*/
private Long actualPenaltyAmount;
private long actualPenaltyAmount;
/**
* 减免金额
*/
private Long reductionAmount;
private long reductionAmount;
/**
* 减免原因
@ -102,15 +107,15 @@ public class RepaymentDO extends BaseDbEntity {
/**
* 应还总金额,单位:
*/
private Long expectTotalAmount;
private long expectTotalAmount;
/**
* 已还总金额,单位:
*/
private Long actualTotalAmount;
private long actualTotalAmount;
/**
* 逾期金额单位
*/
private Long overdueAmount;
private long overdueAmount;
}

View File

@ -1,9 +1,8 @@
package com.pudonghot.yo.operation.dal.loanimport;
import com.pudonghot.yo.operation.dal.loanimport.model.BatchNumberDO;
import com.pudonghot.tigon.dal.BaseDal;
import java.util.List;
import com.pudonghot.tigon.dal.BaseDal;
import com.pudonghot.yo.operation.dal.loanimport.model.BatchNumberDO;
/**
* 导入批次号
@ -13,6 +12,13 @@ import java.util.List;
*/
public interface BatchNumberDal extends BaseDal<Long, BatchNumberDO> {
/**
* find by batch number
*
* @return batch number
*/
BatchNumberDO findByNumber(String batchNumber);
/**
* commission org list
*

View File

@ -1,6 +1,7 @@
package com.pudonghot.yo.operation.dal.loanimport.impl;
import java.util.List;
import com.pudonghot.tigon.mybatis.Search;
import org.springframework.stereotype.Component;
import com.pudonghot.tigon.dal.impl.BaseDalImpl;
import com.pudonghot.yo.operation.dal.loanimport.BatchNumberDal;
@ -18,6 +19,14 @@ public class BatchNumberDalImpl
extends BaseDalImpl<Long, BatchNumberDO, BatchNumberMapper>
implements BatchNumberDal {
/**
* {@inheritDoc}
*/
@Override
public BatchNumberDO findByNumber(final String batchNumber) {
return find(Search.of(BatchNumberDO.Fields.batchNumber, batchNumber));
}
/**
* {@inheritDoc}
*/

View File

@ -43,6 +43,7 @@ public class BatchNumberDO extends BaseDbEntity {
/**
* 委案日期
*/
@NotUpdate
private Date commissionDate;
/**

View File

@ -2,8 +2,8 @@ package com.pudonghot.yo.operation.dal.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.mybatis.NotUpdate;
import lombok.experimental.FieldNameConstants;
import com.pudonghot.tigon.dal.model.BaseDbEntity;
import com.pudonghot.tigon.mybatis.UseGeneratedKeys;

View File

@ -19,4 +19,9 @@ public class LoanDalTest extends TestBase {
public void testLoanList() {
dal.list(Arrays.asList(1L, 2L));
}
@Test
public void testUpdateRepayment() {
dal.updateRepayment(2L);
}
}

View File

@ -17,6 +17,7 @@
</parent>
<modules>
<module>common</module>
<module>dal</module>
<module>service</module>
<module>web</module>
@ -24,6 +25,11 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.pudonghot.yo</groupId>
<artifactId>yo-tj-operation-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.pudonghot.yo</groupId>
<artifactId>yo-tj-operation-dal</artifactId>

View File

@ -48,6 +48,10 @@
<groupId>com.pudonghot.tigon</groupId>
<artifactId>tigon-file-oss</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.yo</groupId>
<artifactId>yo-util</artifactId>
</dependency>
<!-- Provided Dependencies -->
<dependency>

View File

@ -36,7 +36,7 @@ public class HomeServiceImpl implements HomeService {
@Autowired
private DeptDal deptDal;
@Value("${yo.sip.webrtc.endpoint:wss://cc.ideasfin.com:4443/ws}")
@Value("${yo.webrtc.endpoint}")
private String webRtcEndpoint;
@Autowired
private AuthHook<Long> authHook;

View File

@ -0,0 +1,36 @@
package com.pudonghot.yo.operation.service.loanimport;
import com.pudonghot.yo.operation.service.loanimport.model.DeptBO;
import java.util.Collection;
import java.util.List;
/**
* @author Donghuang
* @date Oct 01, 2024 20:00:10
*/
public interface DeptService {
/**
* find default dept
*
* @return dept
*/
DeptBO findDefault();
/**
* find dept
*
* @param name name
* @return dept
*/
DeptBO find(String name);
/**
* depts
*
* @param names names
* @return depts
*/
List<DeptBO> list(Collection<String> names);
}

View File

@ -0,0 +1,36 @@
package com.pudonghot.yo.operation.service.loanimport;
import com.pudonghot.yo.operation.service.loanimport.model.LoanSourceBO;
import java.util.Collection;
import java.util.List;
/**
* @author Donghuang
* @date Oct 01, 2024 20:00:10
*/
public interface LoanSourceService {
/**
* find default loan source
*
* @return loan source
*/
LoanSourceBO findDefault();
/**
* find loan source
*
* @param name name
* @return loan source
*/
LoanSourceBO find(String name);
/**
* list loan source
*
* @param names names
* @return loan sources
*/
List<LoanSourceBO> list(Collection<String> names);
}

View File

@ -0,0 +1,59 @@
package com.pudonghot.yo.operation.service.loanimport.annotation;
import java.io.IOException;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
/**
* 性别序列化
*
* @author Donghuang
* @date Oct 08, 2024 15:55:52
*/
@Documented
@JacksonAnnotationsInside
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = Gender.ValueSerializer.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface Gender {
/**
* @author Donghuang
* @date Apr 24, 2022 09:58:02
*/
class ValueSerializer extends JsonSerializer<String> {
/**
* {@inheritDoc}
*/
@Override
public void serialize(final String value,
final JsonGenerator gen,
final SerializerProvider serializers) throws IOException {
if (value == null) {
//write the word 'null' if there's no value available
gen.writeNull();
return;
}
if (value.contains("")) {
gen.writeString("M");
return;
}
if (value.contains("")) {
gen.writeString("F");
return;
}
}
}
}

View File

@ -0,0 +1,82 @@
package com.pudonghot.yo.operation.service.loanimport.annotation;
import java.io.IOException;
import com.pudonghot.tigon.kit.spring.ApplicationContextProvider;
import com.pudonghot.yo.operation.service.loanimport.DeptService;
import jakarta.validation.Payload;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import jakarta.validation.ConstraintValidator;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import jakarta.validation.ConstraintValidatorContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
/**
* 处置部门
*
* @author Donghuang
* @date Oct 08, 2024 16:29:08
*/
@Documented
@JacksonAnnotationsInside
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = HandleDept.Validator.class)
@JsonSerialize(using = HandleDept.ValueSerializer.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface HandleDept {
String message() default "无效处置部门";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
class Validator implements ConstraintValidator<HandleDept, String> {
/**
* {@inheritDoc}
*/
@Override
public boolean isValid(final String value, final ConstraintValidatorContext context) {
if (StringUtils.isBlank(value)) {
return true;
}
val dept = ApplicationContextProvider.getApplicationContext().getBean(DeptService.class).find(value);
return dept != null;
}
}
class ValueSerializer extends JsonSerializer<String> {
/**
* {@inheritDoc}
*/
@Override
public void serialize(final String value,
final JsonGenerator gen,
final SerializerProvider serializers) throws IOException {
val deptService = ApplicationContextProvider.getApplicationContext().getBean(DeptService.class);
if (StringUtils.isBlank(value)) {
gen.writeNumber(deptService.findDefault().getId());
return;
}
gen.writeNumber(deptService.find(value).getId());
}
}
}

View File

@ -0,0 +1,68 @@
package com.pudonghot.yo.operation.service.loanimport.annotation;
import java.io.IOException;
import jakarta.validation.Payload;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import com.pudonghot.yo.util.IdCardUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.RetentionPolicy;
import jakarta.validation.ConstraintValidator;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import jakarta.validation.ConstraintValidatorContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
/**
* @author Donghuang
* @date Oct 08, 2024 16:29:08
*/
@Documented
@JacksonAnnotationsInside
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCard.Validator.class)
@JsonSerialize(using = IdCard.ValueSerializer.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface IdCard {
String message() default "无效身份证号码";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
class Validator implements ConstraintValidator<IdCard, String> {
/**
* {@inheritDoc}
*/
@Override
public boolean isValid(final String value, final ConstraintValidatorContext context) {
return StringUtils.isBlank(value) || IdCardUtils.validate(value);
}
}
class ValueSerializer extends JsonSerializer<String> {
/**
* {@inheritDoc}
*/
@Override
public void serialize(final String value,
final JsonGenerator gen,
final SerializerProvider serializers) throws IOException {
if (value == null) {
gen.writeNull();
return;
}
gen.writeString(value.toUpperCase());
}
}
}

View File

@ -0,0 +1,79 @@
package com.pudonghot.yo.operation.service.loanimport.annotation;
import lombok.val;
import java.io.IOException;
import jakarta.validation.Payload;
import java.lang.annotation.Target;
import jakarta.validation.Constraint;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import org.apache.commons.lang3.StringUtils;
import java.lang.annotation.RetentionPolicy;
import jakarta.validation.ConstraintValidator;
import com.fasterxml.jackson.core.JsonGenerator;
import jakarta.validation.ConstraintValidatorContext;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.pudonghot.tigon.kit.spring.ApplicationContextProvider;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.pudonghot.yo.operation.service.loanimport.LoanSourceService;
/**
* 案件来源
*
* @author Donghuang
* @date Oct 08, 2024 16:29:08
*/
@Documented
@JacksonAnnotationsInside
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = LoanSource.Validator.class)
@JsonSerialize(using = LoanSource.ValueSerializer.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface LoanSource {
String message() default "无效案件来源";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
class Validator implements ConstraintValidator<LoanSource, String> {
/**
* {@inheritDoc}
*/
@Override
public boolean isValid(final String value, final ConstraintValidatorContext context) {
if (StringUtils.isBlank(value)) {
return true;
}
val loanSource = ApplicationContextProvider.getApplicationContext().getBean(LoanSourceService.class).find(value);
return loanSource != null;
}
}
class ValueSerializer extends JsonSerializer<String> {
/**
* {@inheritDoc}
*/
@Override
public void serialize(final String value,
final JsonGenerator gen,
final SerializerProvider serializers) throws IOException {
val loanSourceService = ApplicationContextProvider.getApplicationContext().getBean(LoanSourceService.class);
if (StringUtils.isBlank(value)) {
gen.writeNumber(loanSourceService.findDefault().getId());
return;
}
gen.writeNumber(loanSourceService.find(value).getId());
}
}
}

View File

@ -0,0 +1,51 @@
package com.pudonghot.yo.operation.service.loanimport.annotation;
import java.io.IOException;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
/**
* 金额序列化元转换为分
*
* @author Donghuang
* @date Oct 08, 2024 09:40:46
*/
@Documented
@JacksonAnnotationsInside
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = MoneyAmount.ValueSerializer.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface MoneyAmount {
/**
* @author Donghuang
* @date Apr 24, 2022 09:58:02
*/
class ValueSerializer extends JsonSerializer<Double> {
/**
* {@inheritDoc}
*/
@Override
public void serialize(final Double value,
final JsonGenerator gen,
final SerializerProvider serializers) throws IOException {
if (value == null) {
//write the word 'null' if there's no value available
gen.writeNumber(0L);
return;
}
gen.writeNumber(Double.valueOf(value * 1000).longValue());
}
}
}

View File

@ -0,0 +1,51 @@
package com.pudonghot.yo.operation.service.loanimport.impl;
import org.springframework.stereotype.Service;
import com.pudonghot.tigon.kit.bean.BeanService;
import com.pudonghot.yo.operation.dal.dept.DeptDal;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import com.pudonghot.yo.operation.service.loanimport.DeptService;
import com.pudonghot.yo.operation.service.loanimport.model.DeptBO;
import java.util.Collection;
import java.util.List;
/**
* @author Donghuang
* @date Oct 09, 2024 15:58:37
*/
@Service("deptImportServiceImpl")
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDal deptDal;
@Autowired
private BeanService beanService;
@Value("${yo.default-dept:创易广州分公司}")
private String defaultDept;
/**
* {@inheritDoc}
*/
@Override
public DeptBO findDefault() {
return beanService.convert(deptDal.findByName(defaultDept), DeptBO.class);
}
/**
* {@inheritDoc}
*/
@Override
public DeptBO find(final String name) {
return beanService.convert(deptDal.findByName(name), DeptBO.class);
}
/**
* {@inheritDoc}
*/
@Override
public List<DeptBO> list(Collection<String> names) {
return beanService.convert(deptDal.listByNames(names), DeptBO.class);
}
}

View File

@ -1,18 +1,61 @@
package com.pudonghot.yo.operation.service.loanimport.impl;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import java.util.Date;
import java.util.Map;
import java.util.List;
import java.util.HashSet;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Comparator;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.excel.EasyExcel;
import java.util.stream.Collectors;
import com.pudonghot.yo.util.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.alibaba.excel.read.metadata.ReadSheet;
import org.apache.commons.lang3.math.NumberUtils;
import com.pudonghot.tigon.file.util.StreamUtils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.pudonghot.tigon.kit.bean.BeanService;
import com.pudonghot.yo.operation.dal.loan.LoanDal;
import org.apache.commons.lang3.time.DateFormatUtils;
import com.pudonghot.yo.operation.dal.loan.ContactDal;
import com.pudonghot.yo.operation.dal.loan.BankCardDal;
import com.pudonghot.tigon.cms.service.seq.SeqService;
import com.pudonghot.yo.operation.dal.loan.CustomerDal;
import com.pudonghot.yo.operation.dal.loan.RepaymentDal;
import com.pudonghot.yo.operation.dal.loan.model.LoanDO;
import com.pudonghot.yo.operation.dal.loan.model.ContactDO;
import com.pudonghot.yo.operation.dal.loan.model.CustomerDO;
import com.pudonghot.yo.operation.dal.loan.model.BankCardDO;
import com.pudonghot.yo.operation.dal.loan.model.RepaymentDO;
import com.alibaba.excel.exception.ExcelDataConvertException;
import org.springframework.beans.factory.annotation.Autowired;
import com.pudonghot.yo.operation.dal.loanimport.BatchNumberDal;
import com.pudonghot.tigon.cms.service.seq.request.SeqGenReqBO;
import com.pudonghot.yo.operation.dal.application.ApplicationDal;
import com.pudonghot.tigon.cms.service.seq.response.SeqGenRespBO;
import com.pudonghot.yo.operation.service.loanimport.DeptService;
import com.pudonghot.yo.operation.service.loanimport.model.DeptBO;
import com.pudonghot.yo.operation.dal.application.ApplicationExtDal;
import com.pudonghot.yo.operation.dal.loanimport.model.BatchNumberDO;
import com.pudonghot.yo.operation.dal.application.model.ApplicationDO;
import com.pudonghot.yo.operation.service.loanimport.LoanImportService;
import com.pudonghot.yo.operation.service.loanimport.LoanSourceService;
import com.pudonghot.yo.operation.service.loanimport.model.LoanSourceBO;
import com.pudonghot.yo.operation.dal.application.model.ApplicationExtDO;
import com.pudonghot.yo.operation.service.loanimport.impl.reader.BaseReader;
import com.pudonghot.yo.operation.service.loanimport.request.LoanImportReqBO;
import com.pudonghot.yo.operation.service.loanimport.model.ApplicationImportBO;
import com.pudonghot.yo.operation.service.loanimport.impl.reader.ImportItemBO;
import com.pudonghot.yo.operation.service.loanimport.impl.reader.ReadContext;
import static com.pudonghot.yo.operation.service.util.ExcelUtil.getCellValue;
import com.pudonghot.yo.operation.enumeration.repayment.RepaymentStatusEnum;
import com.pudonghot.yo.operation.service.loanimport.response.LoanImportRespBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ImportBatchBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.RepaymentImportBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ApplicationImportBO;
/**
* @author Donghuang
@ -21,47 +64,317 @@ import com.pudonghot.yo.operation.service.loanimport.response.LoanImportRespBO;
@Slf4j
@Service
public class LoanImportServiceImpl implements LoanImportService {
@Autowired
private Map<String, BaseReader<?>> readers;
@Autowired
private BeanService beanService;
@Autowired
private SeqService seqService;
@Autowired
private BatchNumberDal batchNumberDal;
@Autowired
private LoanDal loanDal;
@Autowired
private ApplicationDal applicationDal;
@Autowired
private ApplicationExtDal applicationExtDal;
@Autowired
private CustomerDal customerDal;
@Autowired
private ContactDal contactDal;
@Autowired
private BankCardDal bankCardDal;
@Autowired
private RepaymentDal repaymentDal;
@Autowired
private LoanSourceService loanSourceService;
@Autowired
private DeptService deptService;
/**
* {@inheritDoc}
*/
@Override
public LoanImportRespBO loanImport(final LoanImportReqBO req) {
val resp = new LoanImportRespBO();
StreamUtils.openStream(req.getFile(), inputStream -> {
val readContext = new ReadContext();
val excelReader = EasyExcel.read(inputStream).build();
val sheets = excelReader.excelExecutor().sheetList();
try (val excelReader = EasyExcel.read(inputStream).customObject(readContext).build()) {
val readSheets = new ArrayList<ReadSheet>();
for (val sheet : sheets) {
val sheetName = sheet.getSheetName();
ReadSheet readSheet1 =
EasyExcel.readSheet(0).head(ApplicationImportBO.class).registerReadListener(
new ReadListener<ApplicationImportBO>() {
@Override
public void invoke(ApplicationImportBO data, AnalysisContext context) {
for (val sheet : excelReader.excelExecutor().sheetList()) {
val sheetName = sheet.getSheetName();
val reader = readers.get(sheetName);
readSheets.add(EasyExcel.readSheet(sheetName).head(reader.getModelType()).registerReadListener(reader).build());
}
}
try {
excelReader.read(readSheets);
}
catch (final ExcelDataConvertException e) {
log.error("Excel data convert exception caused.", e);
throw new IllegalStateException("Excel数据类型转换错误"
+ e.getRowIndex()
+ ",列:" + e.getColumnIndex()
+ ",数据:" + getCellValue(e.getCellData()));
}
finally {
excelReader.finish();
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// validate
val records = readContext.getRecords();
records.forEach((k, rec) -> {
val app = rec.getApplication();
if (app == null) {
readContext.addError("合同号[" + k + "]申请单信息缺失");
}
}
}
).build();
// excelReader.read(sheet1);
if (rec.getRepayments().isEmpty()) {
readContext.addError("合同号[" + k + "]还款计划信息缺失");
}
});
// 案件来源处置方
val loanSourceNames = new HashSet<String>();
val handleDeptNames = new HashSet<String>();
records.forEach((k, rec) -> {
val app = rec.getApplication();
val loanSource = app.getLoanSource();
if (StringUtils.isNotBlank(loanSource)) {
loanSourceNames.add(loanSource);
}
val handleDept = app.getHandleDept();
if (StringUtils.isNotBlank(handleDept)) {
handleDeptNames.add(handleDept);
}
});
val defaultKey = "__DEFAULT";
val mapLoanSources = new HashMap<String, LoanSourceBO>();
mapLoanSources.put(defaultKey, loanSourceService.findDefault());
if (!loanSourceNames.isEmpty()) {
mapLoanSources.putAll(loanSourceService.list(loanSourceNames).stream().collect(Collectors.toMap(LoanSourceBO::getName, item -> item)));
}
if (!mapLoanSources.keySet().containsAll(loanSourceNames)) {
loanSourceNames.removeAll(mapLoanSources.keySet());
readContext.addError("未知案件来源:[" + StringUtils.join(loanSourceNames, ", ") + "]");
}
else {
records.forEach((k, rec) -> {
val app = rec.getApplication();
val loanSource = app.getLoanSource();
app.setLoanSourceId(mapLoanSources.get(StringUtils.defaultIfBlank(loanSource, defaultKey)).getId());
});
}
val mapHandleDepts = new HashMap<String, DeptBO>();
mapHandleDepts.put(defaultKey, deptService.findDefault());
if (!handleDeptNames.isEmpty()) {
mapHandleDepts.putAll(deptService.list(handleDeptNames).stream().collect(Collectors.toMap(DeptBO::getName, item -> item)));
}
if (!mapHandleDepts.keySet().containsAll(handleDeptNames)) {
handleDeptNames.removeAll(mapHandleDepts.keySet());
readContext.addError("未知处置方:[" + StringUtils.join(handleDeptNames, ", ") + "]");
}
else {
records.forEach((k, rec) -> {
val app = rec.getApplication();
app.setDeptId(mapHandleDepts.get(StringUtils.defaultIfBlank(app.getHandleDept(), defaultKey)).getId());
});
}
if (readContext.hasError()) {
resp.setTotal(0);
resp.setErrors(readContext.getErrors());
return;
}
resp.setTotal(saveData(records.values().stream().toList()));
}
// try {
// EasyExcel.read(inputStream, modelClass, reader).customObject(metaData).sheet(0).doRead();
// }
// catch (final ExcelDataConvertException e) {
// log.error("Excel data convert exception caused.", e);
// throw new IllegalStateException("Excel数据类型转换错误"
// + e.getRowIndex()
// + ",列:" + e.getColumnIndex()
// + ",数据:" + getCellValue(e.getCellData()));
// }
});
return null;
return resp;
}
Integer saveData(final List<ImportItemBO> records) {
if (CollectionUtils.isEmpty(records)) {
return 0;
}
val mapBizKeyBatchBO = new HashMap<String, ImportBatchBO>();
val mapBatchNumDO = new HashMap<ImportBatchBO, BatchNumberDO>();
// 保存批次号
for (val record : records) {
val application = record.getApplication();
// 做HashCode区分
val batch = beanService.convert(application, ImportBatchBO.class);
mapBizKeyBatchBO.put(record.getBizKey(), batch);
// 相同分类的batchNum共用同一个Number
mapBatchNumDO.put(batch, beanService.convert(batch, BatchNumberDO.class));
}
val numbers = genBatchNumbers(mapBatchNumDO.size());
val ii = new int[]{ 0 };
mapBatchNumDO.forEach((k, v) -> v.setBatchNumber(numbers.get(ii[0]++)));
ListUtils.eachBatch(mapBatchNumDO.values().stream().toList(), 32, batchNumberDal::insert);
records.forEach(record -> {
val bizKey = record.getBizKey();
val application = record.getApplication();
// batch number
val loanDO = findOrCreateLoan(application, mapBatchNumDO.get(mapBizKeyBatchBO.get(bizKey)).getId());
val loanId = loanDO.getId();
val appExisted = applicationDal.findByLoanId(loanId);
if (appExisted != null) {
beanService.assign(appExisted, application);
val applicationRemark = application.getApplicationRemark();
if (StringUtils.isNotBlank(applicationRemark)) {
appExisted.setRemark(applicationRemark);
}
applicationDal.update(appExisted);
}
else {
val newApp = beanService.convert(application, ApplicationDO.class);
newApp.setLoanId(loanId);
val applicationRemark = application.getApplicationRemark();
if (StringUtils.isNotBlank(applicationRemark)) {
newApp.setRemark(applicationRemark);
}
applicationDal.insert(newApp);
}
val customerExisted = customerDal.findByLoanId(loanId);
if (customerExisted != null) {
beanService.assign(customerExisted, application);
customerDal.update(customerExisted);
}
else {
val newCustomer = beanService.convert(application, CustomerDO.class);
newCustomer.setLoanId(loanId);
customerDal.insert(newCustomer);
}
val applicationExt = record.getApplicationExt();
if (applicationExt != null) {
val appExtExisted = applicationExtDal.findByLoanId(loanId);
if (appExtExisted != null) {
beanService.assign(appExtExisted, applicationExt);
applicationExtDal.update(appExtExisted);
}
else {
val newAppExt = beanService.convert(applicationExt, ApplicationExtDO.class);
newAppExt.setLoanId(loanId);
applicationExtDal.insert(newAppExt);
}
}
else {
applicationExtDal.removeByLoanId(loanId);
}
contactDal.removeByLoanId(loanId);
val contacts = beanService.convert(record.getContacts(), ContactDO.class);
if (!CollectionUtils.isEmpty(contacts)) {
contacts.forEach(it -> it.setLoanId(loanId));
ListUtils.eachBatch(contacts, 24, contactDal::insert);
}
bankCardDal.removeByLoanId(loanId);
val bankCardList = beanService.convert(record.getBankCards(), BankCardDO.class);
if (CollectionUtils.isEmpty(bankCardList)) {
bankCardList.forEach(it -> it.setLoanId(loanId));
ListUtils.eachBatch(bankCardList, 24, bankCardDal::insert);
}
repaymentDal.removeByLoanId(loanId);
val repayments = record.getRepayments().stream().sorted(Comparator.comparing(RepaymentImportBO::getInstallment)).map(it -> {
val newRepayment = beanService.convert(it, RepaymentDO.class);
newRepayment.setLoanId(loanId);
calcRepayment(newRepayment);
return newRepayment;
}).collect(Collectors.toList());
ListUtils.eachBatch(repayments, 24, repaymentDal::insert);
// 更新逾期天数逾期金额剩余本金罚息
loanDal.updateRepayment(loanId);
});
return records.size();
}
LoanDO findOrCreateLoan(final ApplicationImportBO appBO, final Long importBatchId) {
val newLoanDO = beanService.convert(appBO, LoanDO.class);
val loanExisted = loanDal.findBySourceIdAndBizKey(newLoanDO.getLoanSourceId(), appBO.getBizKey());
if (loanExisted == null) {
newLoanDO.setImportBatchId(importBatchId);
loanDal.insert(newLoanDO);
return newLoanDO;
}
return loanExisted;
}
void calcRepayment(final RepaymentDO repayment) {
// 计划总金额
val expectTotalAmount = repayment.getExpectPrincipalAmount()
+ repayment.getExpectInterestAmount()
+ repayment.getExpectServiceAmount()
+ repayment.getExpectPenaltyAmount();
repayment.setExpectTotalAmount(expectTotalAmount);
// 实际总金额
val actualTotalAmount = repayment.getActualPrincipalAmount()
+ repayment.getActualInterestAmount()
+ repayment.getActualServiceAmount()
+ repayment.getActualPenaltyAmount();
repayment.setActualTotalAmount(actualTotalAmount);
// 逾期金额
val overdueAmount = NumberUtils.max(expectTotalAmount
- actualTotalAmount
- repayment.getReductionAmount(), 0);
// 已逾期
if (repayment.getExpectRepayTime().before(new Date())) {
repayment.setOverdueAmount(overdueAmount);
}
if (overdueAmount > 0) {
repayment.setStatus(actualTotalAmount > 0 ?
RepaymentStatusEnum.PARTIALLY_PAID : RepaymentStatusEnum.UNPAID);
}
else {
repayment.setStatus(RepaymentStatusEnum.FULLY_PAID);
}
}
/**
* {@inheritDoc}
*/
public List<String> genBatchNumbers(final Integer size) {
val today = DateFormatUtils.format(new Date(), "yyyyMMdd");
val seqKey = "LOAN_IMPORT_BATCH_NUMBER_" + today;
val req = new SeqGenReqBO();
req.setSeqKey(seqKey);
req.setPrefix(today + "_");
req.setLength(today.length() + 4);
req.setSize(size);
return seqService.gen(req).getValues().stream().map(SeqGenRespBO.SeqValue::text).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,50 @@
package com.pudonghot.yo.operation.service.loanimport.impl;
import java.util.List;
import java.util.Collection;
import org.springframework.stereotype.Service;
import com.pudonghot.tigon.kit.bean.BeanService;
import com.pudonghot.yo.operation.dal.loan.LoanSourceDal;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import com.pudonghot.yo.operation.service.loanimport.LoanSourceService;
import com.pudonghot.yo.operation.service.loanimport.model.LoanSourceBO;
/**
* @author Donghuang
* @date Oct 09, 2024 12:11:33
*/
@Service("loanSourceImportServiceImpl")
public class LoanSourceServiceImpl implements LoanSourceService {
@Autowired
private LoanSourceDal loanSourceDal;
@Autowired
private BeanService beanService;
@Value("${yo.default-loan-source:DEFAULT}")
private String defaultLoanSourceCode;
/**
* {@inheritDoc}
*/
@Override
public LoanSourceBO findDefault() {
return beanService.convert(loanSourceDal.findByCode(defaultLoanSourceCode), LoanSourceBO.class);
}
/**
* {@inheritDoc}
*/
@Override
public LoanSourceBO find(final String name) {
return beanService.convert(loanSourceDal.findByName(name), LoanSourceBO.class);
}
/**
* {@inheritDoc}
*/
@Override
public List<LoanSourceBO> list(final Collection<String> names) {
return beanService.convert(loanSourceDal.listByNames(names), LoanSourceBO.class);
}
}

View File

@ -0,0 +1,58 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.val;
import java.util.Map;
import java.lang.reflect.Field;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.excel.util.ConverterUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ApplicationExtImportBO;
/**
* @author Donghuang
* @date Oct 07, 2024 16:01:32
*/
@Slf4j
@Component("附加信息")
public class ApplicationExtReader extends BaseReader<ApplicationExtImportBO> {
/**
* {@inheritDoc}
*/
@Override
public void invokeHead(final Map<Integer, ReadCellData<?>> mapHeaders, final AnalysisContext context) {
getCtx(context).setAppExtHeaders(ConverterUtils.convertToStringMap(mapHeaders, context));
}
/**
* {@inheritDoc}
*/
@Override
protected void doInvoke(final ApplicationExtImportBO record, final AnalysisContext context) {
val ctx = getCtx(context);
val appExtHeaders = ctx.getAppExtHeaders();
val rec = ctx.getRecord(record.getBizKey());
ReflectionUtils.doWithFields(ApplicationExtImportBO.class, field -> {
field.setAccessible(true);
val extField = (ApplicationExtImportBO.ExtField) field.get(record);
if (extField != null) {
extField.setLabel(appExtHeaders.get(extField.getIndex()));
}
}, new ReflectionUtils.FieldFilter() {
/**
* {@inheritDoc}
*/
@Override
public boolean matches(final Field field) {
return ApplicationExtImportBO.ExtField.class.isAssignableFrom(field.getType());
}
});
rec.setApplicationExt(record);
}
}

View File

@ -0,0 +1,24 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.val;
import org.springframework.stereotype.Component;
import com.alibaba.excel.context.AnalysisContext;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ApplicationImportBO;
/**
* @author Donghuang
* @date Oct 07, 2024 16:01:32
*/
@Component("申请单信息")
public class ApplicationReader extends BaseReader<ApplicationImportBO> {
/**
* {@inheritDoc}
*/
@Override
protected void doInvoke(final ApplicationImportBO record, final AnalysisContext context) {
val ctx = getCtx(context);
val rec = ctx.getRecord(record.getBizKey());
rec.setApplication(record);
}
}

View File

@ -0,0 +1,24 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import com.alibaba.excel.context.AnalysisContext;
import lombok.val;
import org.springframework.stereotype.Component;
import com.pudonghot.yo.operation.service.loanimport.model.excel.BankCardImportBO;
/**
* @author Donghuang
* @date Oct 07, 2024 16:01:32
*/
@Component("银行卡信息")
public class BankCardReader extends BaseReader<BankCardImportBO> {
/**
* {@inheritDoc}
*/
@Override
protected void doInvoke(final BankCardImportBO record, final AnalysisContext context) {
val ctx = getCtx(context);
val rec = ctx.getRecord(record.getBizKey());
rec.getBankCards().add(record);
}
}

View File

@ -0,0 +1,96 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.val;
import lombok.Getter;
import java.util.ArrayList;
import jakarta.validation.Validator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import org.springframework.core.GenericTypeResolver;
import org.springframework.beans.factory.annotation.Autowired;
import com.pudonghot.yo.operation.service.loanimport.model.excel.BaseImportBO;
/**
* @author Donghuang
* @date Oct 07, 2024 16:03:07
*/
public abstract class BaseReader<T extends BaseImportBO> implements ReadListener<T> {
@Getter
private final Class<T> modelType;
@Autowired
private Validator validator;
public BaseReader() {
val clazzArr = GenericTypeResolver.resolveTypeArguments(getClass(), BaseReader.class);
modelType = (Class<T>) clazzArr[0];
}
/**
* {@inheritDoc}
*/
@Override
public void invoke(final T record, final AnalysisContext context) {
// validate
if (!validate(record, context)) {
return;
}
getCtx(context).addRecord(record.getBizKey());
doInvoke(record, context);
}
/**
* {@inheritDoc}
*/
@Override
public void doAfterAllAnalysed(final AnalysisContext context) {
// ignore
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext(final AnalysisContext context) {
val ctx = getCtx(context);
if (ctx.getErrors().size() > 10) {
return false;
}
return true;
}
protected abstract void doInvoke(final T record, final AnalysisContext context);
protected boolean validate(final T record, final AnalysisContext context) {
val validationResult = validator.validate(record);
if (CollectionUtils.isEmpty(validationResult)) {
return true;
}
val rowIndex = context.readRowHolder().getRowIndex();
val messages = new ArrayList<String>(validationResult.size());
for (val v : validationResult) {
messages.add(v.getMessage());
}
val sheetName = context.readSheetHolder().getSheetName();
getCtx(context).addError("Sheet" + sheetName + ",行:" + rowIndex + ",错误:" + StringUtils.join(messages, ""));
return false;
}
/**
* get context
*
* @param context
* @return context
*/
protected ReadContext getCtx(final AnalysisContext context) {
return (ReadContext) context.getCustom();
}
}

View File

@ -0,0 +1,24 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.val;
import org.springframework.stereotype.Component;
import com.alibaba.excel.context.AnalysisContext;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ContactImportBO;
/**
* @author Donghuang
* @date Oct 07, 2024 16:01:32
*/
@Component("联系人信息")
public class ContactReader extends BaseReader<ContactImportBO> {
/**
* {@inheritDoc}
*/
@Override
protected void doInvoke(final ContactImportBO record, final AnalysisContext context) {
val ctx = getCtx(context);
val rec = ctx.getRecord(record.getBizKey());
rec.getContacts().add(record);
}
}

View File

@ -0,0 +1,36 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.Getter;
import lombok.Setter;
import java.util.Set;
import lombok.ToString;
import java.util.HashSet;
import java.io.Serializable;
import lombok.RequiredArgsConstructor;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ContactImportBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.BankCardImportBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.RepaymentImportBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ApplicationImportBO;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ApplicationExtImportBO;
/**
* @author Donghuang
* @date Oct 08, 2024 21:52:14
*/
@Getter
@Setter
@ToString
@RequiredArgsConstructor
public class ImportItemBO implements Serializable {
private static final long serialVersionUID = 1L;
private final String bizKey;
private ApplicationImportBO application;
private ApplicationExtImportBO applicationExt;
private final Set<BankCardImportBO> bankCards = new HashSet<>();
private final Set<ContactImportBO> contacts = new HashSet<>();
private final Set<RepaymentImportBO> repayments = new HashSet<>();
}

View File

@ -0,0 +1,42 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
import java.util.List;
import lombok.ToString;
import java.util.HashMap;
import java.util.ArrayList;
import java.io.Serializable;
/**
* @author Donghuang
* @date Sep 27, 2024 20:51:56
*/
@Getter
@Setter
@ToString
public class ReadContext implements Serializable {
private static final long serialVersionUID = 1L;
private final List<String> errors = new ArrayList<>();
private Integer total;
private Map<Integer, String> appExtHeaders;
private final Map<String, ImportItemBO> records = new HashMap<>();
public boolean hasError() {
return !errors.isEmpty();
}
public void addError(final String error) {
errors.add(error);
}
public void addRecord(final String bizKey) {
records.putIfAbsent(bizKey, new ImportItemBO(bizKey));
}
public ImportItemBO getRecord(final String bizKey) {
return records.get(bizKey);
}
}

View File

@ -0,0 +1,25 @@
package com.pudonghot.yo.operation.service.loanimport.impl.reader;
import lombok.val;
import org.springframework.stereotype.Component;
import com.alibaba.excel.context.AnalysisContext;
import com.pudonghot.yo.operation.service.loanimport.model.excel.RepaymentImportBO;
/**
* @author Donghuang
* @date Oct 07, 2024 16:01:32
*/
@Component("还款计划信息")
public class RepaymentReader extends BaseReader<RepaymentImportBO> {
/**
* {@inheritDoc}
*/
@Override
protected void doInvoke(final RepaymentImportBO record, final AnalysisContext context) {
val ctx = getCtx(context);
val rec = ctx.getRecord(record.getBizKey());
rec.getRepayments().add(record);
}
}

View File

@ -1,67 +0,0 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class ApplicationExtImportBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 附加字段1
*/
private String extData1;
/**
* 附加字段2
*/
private String extData2;
/**
* 附加字段3
*/
private String extData3;
/**
* 附加字段4
*/
private String extData4;
/**
* 附加字段5
*/
private String extData5;
/**
* 附加字段6
*/
private String extData6;
/**
* 附加字段7
*/
private String extData7;
/**
* 附加字段8
*/
private String extData8;
/**
* 附加字段9
*/
private String extData9;
/**
* 附加字段10
*/
private String extData10;
}

View File

@ -1,149 +0,0 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import lombok.ToString;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class ApplicationImportBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总期数
*/
private Integer totalInstallments;
/**
* 当前期数
*/
private Integer currentInstallment;
/**
* 已还期数
*/
private Integer repaidInstallments;
/**
* 逾期期数
*/
private Integer overdueInstallments;
/**
* 申请时间
*/
private Date applyDate;
/**
* 批核时间
*/
private Date approveDate;
/**
* 放款时间
*/
private Date loanDate;
/**
* 当期账单日
*/
private Date dueDate;
/**
* 利率
*/
private BigDecimal interestRate;
/**
* 服务费率
*/
private BigDecimal serviceInterestRate;
/**
* 罚息利率
*/
private BigDecimal penaltyInterestRate;
/**
* 合同(申请)金额
*/
private Long applyAmount;
/**
* 放款金额
*/
private Long loanAmount;
/**
* 违约金,罚金
*/
private Long defaultFineAmount;
/**
* 逾期金额
*/
private Long overdueAmount;
/**
* 剩余本金
*/
private Long principalRemain;
/**
* 提前清贷金额
*/
private Long prepaymentAmount;
/**
* 募资方
*/
private String fundraiser;
/**
* 产品名称
*/
private String productName;
/**
* 还款方式
*/
private String repaymentType;
/**
* 贷款平台名称
*/
private String platformName;
/**
* 募资方名称
*/
private String fundraiserName;
/**
* 助贷机构名称
*/
private String loanAgencyName;
/**
* 紧急联系人关系
*/
private String emergencyContactRelation;
/**
* 紧急联系人备注名
*/
private String emergencyContactName;
/**
* 紧急联系人号码
*/
private String emergencyContactMobile;
}

View File

@ -1,47 +0,0 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class BankCardImportBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 开户名
*/
private String name;
/**
* 银行预留手机号
*/
private String mobile;
/**
* 银行ID
*/
private Long bankId;
/**
* 银行卡卡号
*/
private String bankCardNo;
/**
* 银行卡开户行
*/
private String bankName;
/**
* 绑定优先级
*/
private Boolean priority;
}

View File

@ -1,43 +0,0 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class ContactImportBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
private String name;
/**
* 手机
*/
private String mobile;
/**
* 关系
*/
private String relationType;
/**
* 联系频率
*/
private String frequency;
/**
* 联系人来源
*/
private String source;
}

View File

@ -1,140 +0,0 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class CustomerImportBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
private String name;
/**
* 身份证号
*/
private String idNo;
/**
* 手机
*/
private String mobile;
/**
* 邮箱
*/
private String email;
/**
* 性别
*/
private String gender;
/**
* 民族
*/
private String nation;
/**
* 出生日期
*/
private String birthday;
/**
* 户籍地址
*/
private String censusRegisterAddress;
/**
* 学历
*/
private String educational;
/**
* 婚姻状态
*/
private String marriage;
/**
* 居住省
*/
private String residenceProvince;
/**
* 居住市
*/
private String residenceCity;
/**
* 居住区
*/
private String residenceDistrict;
/**
* 常住地址
*/
private String residenceAddress;
/**
* 居住时长
*/
private String residenceTime;
/**
* qq
*/
private String qq;
/**
* 职业
*/
private String profession;
/**
* 月收入
*/
private String salary;
/**
* 单位名称
*/
private String workCompany;
/**
* 最近工作年限
*/
private String recentlyWorkDuration;
/**
* 单位所在省
*/
private String companyProvince;
/**
* 单位所在市
*/
private String companyCity;
/**
* 单位所在区
*/
private String companyDistrict;
/**
* 单位详细地址
*/
private String companyAddress;
}

View File

@ -0,0 +1,22 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import com.pudonghot.tigon.service.model.BaseServModel;
/**
* 部门
*
* @author Donghuang
* @date Oct 09, 2024 15:53:55
*/
@Getter
@Setter
public class DeptBO extends BaseServModel {
private static final long serialVersionUID = 1L;
/**
* 部门名称
*/
private String name;
}

View File

@ -0,0 +1,30 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.pudonghot.tigon.service.model.BaseServModel;
/**
* 案件来源表
*
* @author Donghuang
* @date Oct 09, 2024 12:09:08
*/
@Getter
@Setter
public class LoanSourceBO extends BaseServModel {
private static final long serialVersionUID = 1L;
/**
* 渠道数据源代码
*/
@JsonAlias("loanSourceCode")
private String code;
/**
* 渠道数据源名称
*/
@JsonAlias("loanSourceName")
private String name;
}

View File

@ -1,104 +0,0 @@
package com.pudonghot.yo.operation.service.loanimport.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import java.util.Date;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class RepaymentImportBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 期数
*/
private Integer installment;
/**
* 还款状态 UNPAID未还款 PARTIALLY_PAID 部分还款 FULLY_PAID全部还款
*/
private String status;
/**
* 预计还款时间
*/
private Date expectRepayTime;
/**
* 实际还款时间
*/
private Date actualRepayTime;
/**
* 应还本金单位
*/
private Long expectPrincipalAmount;
/**
* 已还本金单位
*/
private Long actualPrincipalAmount;
/**
* 应还利息单位
*/
private Long expectInterestAmount;
/**
* 已还利息单位
*/
private Long actualInterestAmount;
/**
* 应还平台服务费单位
*/
private Long expectServiceAmount;
/**
* 已还平台服务费单位
*/
private Long actualServiceAmount;
/**
* 应还罚息,单位:
*/
private Long expectPenaltyAmount;
/**
* 已还罚息,单位:
*/
private Long actualPenaltyAmount;
/**
* 减免金额
*/
private Long reductionAmount;
/**
* 减免原因
*/
private String reductionReason;
/**
* 应还总金额,单位:
*/
private Long expectTotalAmount;
/**
* 已还总金额,单位:
*/
private Long actualTotalAmount;
/**
* 逾期金额单位
*/
private Long overdueAmount;
}

View File

@ -0,0 +1,126 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.RequiredArgsConstructor;
import lombok.val;
import lombok.Setter;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.io.Serializable;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class ApplicationExtImportBO extends BaseImportBO {
private static final long serialVersionUID = 1L;
/**
* 附加字段1
*/
@ExcelProperty(index = 1, converter = ExtFieldConverter.class)
private ExtField extData1;
/**
* 附加字段2
*/
@ExcelProperty(index = 2, converter = ExtFieldConverter.class)
private ExtField extData2;
/**
* 附加字段3
*/
@ExcelProperty(index = 3, converter = ExtFieldConverter.class)
private ExtField extData3;
/**
* 附加字段4
*/
@ExcelProperty(index = 4, converter = ExtFieldConverter.class)
private ExtField extData4;
/**
* 附加字段5
*/
@ExcelProperty(index = 5, converter = ExtFieldConverter.class)
private ExtField extData5;
/**
* 附加字段6
*/
@ExcelProperty(index = 6, converter = ExtFieldConverter.class)
private ExtField extData6;
/**
* 附加字段7
*/
@ExcelProperty(index = 7, converter = ExtFieldConverter.class)
private ExtField extData7;
/**
* 附加字段8
*/
@ExcelProperty(index = 8, converter = ExtFieldConverter.class)
private ExtField extData8;
/**
* 附加字段9
*/
@ExcelProperty(index = 9, converter = ExtFieldConverter.class)
private ExtField extData9;
/**
* 附加字段10
*/
@ExcelProperty(index = 10, converter = ExtFieldConverter.class)
private ExtField extData10;
@Getter
@Setter
@ToString
@RequiredArgsConstructor
public static class ExtField implements Serializable {
private static final long serialVersionUID = 1L;
@JsonIgnore
private final Integer index;
private final String value;
private String label;
}
/**
* @author Donghuang
* @date Sep 27, 2024 16:46:08
*/
public static class ExtFieldConverter implements Converter<ExtField> {
/**
* {@inheritDoc}
*/
@Override
public ExtField convertToJavaData(final ReadCellData<?> cellData,
final ExcelContentProperty contentProperty,
final GlobalConfiguration globalConfiguration) {
val value = StringUtils.trimToNull(cellData.getStringValue());
if (StringUtils.isBlank(value)) {
return null;
}
val columnIndex = cellData.getColumnIndex();
return new ExtField(columnIndex, value);
}
}
}

View File

@ -0,0 +1,375 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import lombok.val;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import lombok.ToString;
import com.pudonghot.yo.util.IdCardUtils;
import jakarta.validation.constraints.Email;
import org.apache.commons.lang3.StringUtils;
import jakarta.validation.constraints.Past;
import jakarta.validation.constraints.Future;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.NotBlank;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import jakarta.validation.constraints.PositiveOrZero;
import org.apache.commons.lang3.time.DateFormatUtils;
import com.pudonghot.yo.operation.service.loanimport.annotation.IdCard;
import com.pudonghot.yo.operation.service.loanimport.annotation.MoneyAmount;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class ApplicationImportBO extends BaseImportBO {
private static final long serialVersionUID = 1L;
/**
* 委案日期
*/
@ExcelProperty("委案日期")
@NotNull(message = "委案日期不能为空")
private Date commissionDate;
/**
* 委托方
*/
@ExcelProperty("委案机构")
@NotBlank(message = "委案机构不能为空")
private String commissionOrg;
/**
* 退案日期
*/
@ExcelProperty("退案日期")
@NotNull(message = "退案日期不能为空")
@Future(message = "退案日期不能提前于今天")
private Date withdrawDate;
/**
* 案件来源
*/
@ExcelProperty("案件来源")
private String loanSource;
/**
* 案件来源ID
*/
@ExcelIgnore
private Long loanSourceId;
/**
* 处置方
*/
@ExcelProperty("处置方")
private String handleDept;
/**
* 处置方ID
*/
@ExcelIgnore
private Long deptId;
/**
* 目标回款率
*/
@ExcelProperty("目标回款率")
@PositiveOrZero(message = "目标回款率不能小于0")
private Double targetReturnRate;
/**
* 佣金系数
*/
@ExcelProperty("佣金系数")
@PositiveOrZero(message = "佣金系数不能小于0")
private Double commissionRate;
/**
* 申请时间
*/
@ExcelProperty("申请时间")
@Past(message = "申请时间不能晚于今天")
private Date applyDate;
/**
* 批核时间
*/
@ExcelProperty("批核时间")
@Past(message = "批核时间不能晚于今天")
private Date approveDate;
/**
* 放款时间
*/
@ExcelProperty("放款时间")
@Past(message = "放款时间不能晚于今天")
private Date loanDate;
/**
* 利率
*/
@ExcelProperty("利率")
@PositiveOrZero(message = "利率不能小于0")
private Double interestRate;
/**
* 服务费率
*/
@ExcelProperty("服务费率")
@PositiveOrZero(message = "服务费率不能小于0")
private Double serviceInterestRate;
/**
* 罚息利率
*/
@ExcelProperty("罚息利率")
@PositiveOrZero(message = "罚息利率不能小于0")
private Double penaltyInterestRate;
/**
* 合同(申请)金额
*/
@MoneyAmount
@ExcelProperty("合同(申请)金额")
@Positive(message = "合同申请金额不能小于0")
private Double applyAmount;
/**
* 募资方
*/
@ExcelProperty("募资方")
private String fundraiser;
/**
* 产品名称
*/
@ExcelProperty("产品名称")
private String productName;
/**
* 还款方式
*/
@ExcelProperty("还款方式")
private String repaymentType;
/**
* 贷款平台名称
*/
@ExcelProperty("贷款平台名称")
private String platformName;
/**
* 募资方名称
*/
@ExcelProperty("募资方名称")
private String fundraiserName;
/**
* 助贷机构名称
*/
@ExcelProperty("助贷机构名称")
private String loanAgencyName;
/**
* 紧急联系人关系
*/
@ExcelProperty("紧急联系人关系")
private String emergencyContactRelation;
/**
* 紧急联系人姓名
*/
@ExcelProperty("紧急联系人姓名")
private String emergencyContactName;
/**
* 紧急联系人电话
*/
@ExcelProperty("紧急联系人电话")
private String emergencyContactMobile;
/**
* 备注
*/
@ExcelProperty("备注")
private String applicationRemark;
// 客户信息
/**
* 姓名
*/
@ExcelProperty("姓名")
@NotBlank(message = "姓名不能为空")
private String name;
/**
* 身份证号
*/
@IdCard
@ExcelProperty("身份证号")
@NotBlank(message = "身份证号不能为空")
private String idNo;
/**
* 民族
*/
@ExcelProperty("民族")
private String nation;
/**
* 手机
*/
@NotBlank
@ExcelProperty("手机")
@NotBlank(message = "手机号不能为空")
private String mobile;
/**
* 邮箱
*/
@ExcelProperty("邮箱")
@Email(message = "邮箱格式不正确")
private String email;
/**
* @return 性别
*/
public String getGender() {
if (StringUtils.isBlank(idNo)) {
return null;
}
val idCard = IdCardUtils.parse(idNo);
if (idCard != null) {
return idCard.gender().name();
}
return null;
}
/**
* 出生日期
*
* @return birth day
*/
public String getBirthday() {
if (StringUtils.isBlank(idNo)) {
return null;
}
val idCard = IdCardUtils.parse(idNo);
if (idCard != null) {
return DateFormatUtils.format(idCard.birthdate(), "yyyy-MM-dd");
}
return null;
}
/**
* 户籍地址
*/
@ExcelProperty("户籍地址")
private String censusRegisterAddress;
/**
* 学历
*/
@ExcelProperty("学历")
private String educational;
/**
* 婚姻状态
*/
@ExcelProperty("婚姻状态")
private String marriage;
/**
* 居住省
*/
@ExcelProperty("居住省")
private String residenceProvince;
/**
* 居住市
*/
@ExcelProperty("居住市")
private String residenceCity;
/**
* 居住区
*/
@ExcelProperty("居住区")
private String residenceDistrict;
/**
* 常住地址
*/
@ExcelProperty("常住地址")
private String residenceAddress;
/**
* 居住时长
*/
@ExcelProperty("居住时长")
private String residenceTime;
/**
* qq
*/
@ExcelProperty("QQ")
private String qq;
/**
* 职业
*/
@ExcelProperty("职业")
private String profession;
/**
* 月收入
*/
@ExcelProperty("月收入")
private String salary;
/**
* 单位名称
*/
@ExcelProperty("单位名称")
private String workCompany;
/**
* 最近工作年限
*/
@ExcelProperty("最近工作年限")
private String recentlyWorkDuration;
/**
* 单位所在省
*/
@ExcelProperty("单位所在省")
private String companyProvince;
/**
* 单位所在市
*/
@ExcelProperty("单位所在市")
private String companyCity;
/**
* 单位所在区
*/
@ExcelProperty("单位所在区")
private String companyDistrict;
/**
* 单位详细地址
*/
@ExcelProperty("单位详细地址")
private String companyAddress;
}

View File

@ -0,0 +1,47 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.NotBlank;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
@EqualsAndHashCode(of = "bankCardNo")
public class BankCardImportBO extends BaseImportBO {
private static final long serialVersionUID = 1L;
/**
* 开户名
*/
@ExcelProperty("开户名")
@NotBlank(message = "开户名不能为空")
private String name;
/**
* 银行预留手机号
*/
@ExcelProperty("银行预留手机号")
@NotBlank(message = "银行预留手机号不能为空")
private String mobile;
/**
* 银行卡卡号
*/
@ExcelProperty("银行卡卡号")
@NotBlank(message = "银行卡卡号不能为空")
private String bankCardNo;
/**
* 银行卡开户行
*/
@ExcelProperty("银行卡开户行")
private String bankName;
}

View File

@ -0,0 +1,23 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import jakarta.validation.constraints.NotBlank;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
public class BaseImportBO implements Serializable {
private static final long serialVersionUID = 1L;
@ExcelProperty("合同号")
@NotBlank(message = "合同号不能为空")
private String bizKey;
}

View File

@ -0,0 +1,52 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.NotBlank;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
@EqualsAndHashCode(of = "mobile")
public class ContactImportBO extends BaseImportBO {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
@ExcelProperty("姓名")
@NotBlank(message = "姓名不能为空")
private String name;
/**
* 手机
*/
@ExcelProperty("手机")
@NotBlank(message = "手机号不能为空")
private String mobile;
/**
* 关系
*/
@ExcelProperty("关系")
private String relationType;
/**
* 联系人来源
*/
@ExcelProperty("联系人来源")
private String source;
/**
* 联系频率
*/
@ExcelProperty("联系频率")
private String frequency;
}

View File

@ -0,0 +1,45 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import lombok.ToString;
import java.io.Serializable;
import lombok.EqualsAndHashCode;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
@EqualsAndHashCode
public class ImportBatchBO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 委托方
*/
private String commissionOrg;
/**
* 委案日期
*/
private Date commissionDate;
/**
* 退案日期
*/
private Date withdrawDate;
/**
* 案件来源ID
*/
private Long loanSourceId;
/**
* 处置部门ID
*/
private Long deptId;
}

View File

@ -0,0 +1,126 @@
package com.pudonghot.yo.operation.service.loanimport.model.excel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import lombok.ToString;
import jakarta.validation.constraints.Past;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import com.alibaba.excel.annotation.ExcelProperty;
import jakarta.validation.constraints.PositiveOrZero;
import com.pudonghot.yo.operation.service.loanimport.annotation.MoneyAmount;
/**
* @author Donghuang
* @date Oct 02, 2024 10:30:10
*/
@Getter
@Setter
@ToString
@EqualsAndHashCode(of = "installment")
public class RepaymentImportBO extends BaseImportBO {
private static final long serialVersionUID = 1L;
/**
* 期数
*/
@NotNull(message = "期数不能为空")
@Positive(message = "期数不能小于1")
@ExcelProperty("期数")
private Integer installment;
/**
* 计划还款时间
*/
@NotNull(message = "计划还款时间不能为空")
@ExcelProperty("计划还款时间")
private Date expectRepayTime;
/**
* 实际还款时间
*/
@Past(message = "实际还款时间不能晚于今天")
@ExcelProperty("实际还款时间")
private Date actualRepayTime;
/**
* 应还本金
*/
@MoneyAmount
@ExcelProperty("应还本金")
@NotNull(message = "应还本金不能为空")
@Positive(message = "应还本金须大于0")
private Double expectPrincipalAmount;
/**
* 已还本金
*/
@MoneyAmount
@ExcelProperty("已还本金")
@PositiveOrZero(message = "已还本金不能小于0")
private Double actualPrincipalAmount;
/**
* 应还利息
*/
@MoneyAmount
@ExcelProperty("应还利息")
@PositiveOrZero(message = "应还利息不能小于0")
private Double expectInterestAmount;
/**
* 已还利息
*/
@MoneyAmount
@ExcelProperty("已还利息")
@PositiveOrZero(message = "已还利息不能小于0")
private Double actualInterestAmount;
/**
* 应还平台服务费
*/
@MoneyAmount
@ExcelProperty("应还平台服务费")
@PositiveOrZero(message = "应还平台服务费不能小于0")
private Double expectServiceAmount;
/**
* 已还平台服务费
*/
@MoneyAmount
@ExcelProperty("已还平台服务费")
@PositiveOrZero(message = "已还平台服务费不能小于0")
private Double actualServiceAmount;
/**
* 应还罚息
*/
@MoneyAmount
@ExcelProperty("应还罚息")
@PositiveOrZero(message = "应还罚息不能小于0")
private Double expectPenaltyAmount;
/**
* 已还罚息
*/
@MoneyAmount
@ExcelProperty("已还罚息")
@PositiveOrZero(message = "已还罚息不能小于0")
private Double actualPenaltyAmount;
/**
* 减免金额
*/
@MoneyAmount
@ExcelProperty("减免金额")
@PositiveOrZero(message = "减免金额不能小于0")
private Double reductionAmount;
/**
* 减免原因
*/
@ExcelProperty("减免原因")
private String reductionReason;
}

View File

@ -4,6 +4,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.List;
import java.util.ArrayList;
import java.io.Serializable;
/**
@ -16,6 +17,6 @@ import java.io.Serializable;
public class LoanImportRespBO implements Serializable {
private static final long serialVersionUID = 1L;
private Integer total;
private List<String> errors;
private Integer total = 0;
private List<String> errors = new ArrayList<>();
}

View File

@ -2,7 +2,7 @@ package com.pudonghot.yo.operation.service;
import lombok.extern.slf4j.Slf4j;
import org.junit.runner.RunWith;
import org.apache.ibatis.annotations.Mapper;
import com.pudonghot.tigon.mybatis.BaseMapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.boot.test.context.SpringBootTest;
@ -19,8 +19,16 @@ public class TestBase {
}
@Slf4j
@SpringBootApplication(scanBasePackages = "com.pudonghot.yo.operation")
@MapperScan(basePackages = "com.pudonghot.yo.operation.dal", annotationClass = Mapper.class)
@SpringBootApplication(scanBasePackages = {
"com.pudonghot.yo.dal",
"com.pudonghot.yo.operation"
})
@MapperScan(basePackages = {
"com.pudonghot.yo.dal",
"com.pudonghot.yo.operation.dal"
},
markerInterface = BaseMapper.class
)
class TestDriver {
}

View File

@ -1,8 +1,15 @@
package com.pudonghot.yo.operation.service.loanimport;
import java.util.Map;
import com.pudonghot.yo.operation.service.loanimport.model.excel.ApplicationImportBO;
import lombok.val;
import org.junit.Test;
import lombok.extern.slf4j.Slf4j;
import jakarta.validation.Validator;
import com.pudonghot.yo.operation.service.TestBase;
import org.springframework.beans.factory.annotation.Autowired;
import com.pudonghot.yo.operation.service.loanimport.impl.reader.BaseReader;
/**
* @author Donghuang
@ -11,8 +18,20 @@ import com.pudonghot.yo.operation.service.TestBase;
@Slf4j
public class LoanImportServiceTest extends TestBase {
@Autowired
private Map<String, BaseReader<?>> readers;
@Autowired
private Validator validator;
@Test
public void testImport() {
log.info("Run.");
log.info("Readers: [{}].", readers);
}
@Test
public void testValidate() {
val appBO = new ApplicationImportBO();
val resp = validator.validate(appBO);
log.info("Validate: [{}].", resp);
}
}

View File

@ -43,3 +43,6 @@ tigon:
cms:
table-prefix: tj
yo:
webrtc:
endpoint: wss://cc.ideasfin.com:4443/ws

View File

@ -1,24 +1,32 @@
package com.pudonghot.yo.operation.controller.loanimport;
import jakarta.validation.Valid;
import com.pudonghot.tigon.kit.bean.BeanService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import com.pudonghot.yo.operation.service.loanimport.LoanImportService;
import com.pudonghot.yo.operation.service.loanimport.request.LoanImportReqBO;
import com.pudonghot.yo.operation.controller.loanimport.request.LoanImportReqVO;
import com.pudonghot.yo.operation.controller.loanimport.response.LoanImportRespVO;
/**
* @author Donghuang
* @date Oct 02, 2024 21:07:55
*/
@Controller
@RequestMapping("/api/loan")
public class LoanImportController {
@Autowired
private LoanImportService loanImportService;
@Autowired
private BeanService beanService;
@PostMapping("/import")
public void loanImport(@Valid final LoanImportReqVO req) {
public LoanImportRespVO loanImport(@Valid final LoanImportReqVO req) {
return beanService.convert(
loanImportService.loanImport(beanService.convert(req, LoanImportReqBO.class)), LoanImportRespVO.class);
}
}

View File

@ -71,8 +71,10 @@ tigon:
/api/**=user
yo:
webrtc:
endpoint: wss://cc.ideasfin.com:4443/ws
websocket:
allowed-origins: >
http://localhost:[*],
http://127.0.0.1:[*]
https://*.zhujiachefu.com
https://*.zhujiachefu.com

View File

@ -1,4 +1,4 @@
package com.pudonghot.yo.operation.controller;
package com.pudonghot.yo.operation.controller.auth;
import org.junit.Test;
import java.security.Principal;

View File

@ -0,0 +1,46 @@
package com.pudonghot.yo.operation.controller.loanimport;
import lombok.val;
import org.junit.Test;
import java.util.HashMap;
import java.io.InputStream;
import lombok.SneakyThrows;
import java.io.FileInputStream;
import com.pudonghot.yo.operation.TestBase;
import org.springframework.mock.web.MockMultipartFile;
import com.pudonghot.tigon.web.test.ControllerTestTool;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Donghuang
* @date Oct 09, 2024 09:19:07
*/
public class LoanImportControllerTest extends TestBase {
@Autowired
private ControllerTestTool t;
@Test
public void testImport() {
val params = new HashMap<String, Object>();
params.put("file", newFile("file", "/Users/donghuang/Downloads/调解系统-案件导入模板.xlsx"));
t.print(t.post("/api/loan/import", params));
}
@Test
public void testImport2() {
val params = new HashMap<String, Object>();
params.put("file", newFile("file", "/Users/donghuang/Documents/创易科技/PH-案件导入模板-20240313.xlsx"));
t.print(t.post("/api/loan/import", params));
}
@SneakyThrows
MockMultipartFile newFile(final String name, final String path) {
return new MockMultipartFile(name, openFile(path));
}
@SneakyThrows
InputStream openFile(final String file) {
return new FileInputStream(file);
}
}

View File

@ -27,6 +27,7 @@ spring:
mybatis:
mapper-locations:
- classpath*:com/pudonghot/yo/dal/*/mapper/*Mapper.xml
- classpath*:com/pudonghot/yo/operation/dal/*/mapper/*Mapper.xml
- classpath*:com/pudonghot/tigon/cms/dal/*/mapper/*Mapper.xml
lazy-initialization: false
@ -65,3 +66,7 @@ tigon:
/assets/**=anon
/cms/api/**=user
/api/**=user
yo:
webrtc:
endpoint: wss://cc.ideasfin.com:4443/ws

View File

@ -177,7 +177,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>

View File

@ -58,7 +58,6 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>