Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-product
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-product
Commits
d4994eaa
Commit
d4994eaa
authored
May 12, 2026
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
push
parent
80ee4e93
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
61 additions
and
150 deletions
+61
-150
yd-product-api/src/main/java/com/yd/product/api/service/impl/ApiExpectedCommissionRatioServiceImpl.java
+61
-150
No files found.
yd-product-api/src/main/java/com/yd/product/api/service/impl/ApiExpectedCommissionRatioServiceImpl.java
View file @
d4994eaa
...
@@ -181,38 +181,50 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
...
@@ -181,38 +181,50 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
return
Result
.
success
();
return
Result
.
success
();
}
}
/**
/**
* 校验入参-来佣比率规格明细列表(年限区间和有效时间区间均不能重叠)
* 校验入参-来佣比率规格明细列表(年限区间和有效时间区间同时重叠时才禁止)
* @param ratioBatchSaveDtoList
* 规则:
* @return
* - 分组条件:费用名称、是否受汇率影响、结算币种、对账公司、销售组织 完全一致
* - 同一分组内,年限重叠 且 有效时间重叠 → 报错
* - 年限不重叠则无论如何都通过
*/
*/
public
Result
checkBatchSaveRequestPram
(
List
<
ApiExpectedCommissionRatioBatchSaveDto
>
ratioBatchSaveDtoList
)
{
public
Result
checkBatchSaveRequestPram
(
List
<
ApiExpectedCommissionRatioBatchSaveDto
>
ratioBatchSaveDtoList
)
{
// 1.
验证并准备数据(增加有效时间字段)
// 1.
准备解析后的数据
List
<
DtoWithParsedData
>
preparedDataList
=
prepareData
(
ratioBatchSaveDtoList
);
List
<
DtoWithParsedData
>
preparedDataList
=
prepareData
(
ratioBatchSaveDtoList
);
// 2. 检查所有数据对的年限重叠情况(原有逻辑,保持不变)
// 2. 检查同一分组内年限重叠且有效时间重叠的冲突
List
<
OverlapError
>
yearErrors
=
checkYearOverlap
(
preparedDataList
);
List
<
OverlapError
>
errors
=
new
ArrayList
<>();
int
n
=
preparedDataList
.
size
();
// 3. 检查所有数据对的有效时间重叠情况(新增逻辑,使用排除时间字段的业务分组)
List
<
OverlapError
>
effectiveErrors
=
checkEffectiveTimeOverlap
(
preparedDataList
);
// 4. 合并错误
for
(
int
i
=
0
;
i
<
n
-
1
;
i
++)
{
List
<
OverlapError
>
allErrors
=
new
ArrayList
<>();
DtoWithParsedData
data1
=
preparedDataList
.
get
(
i
);
allErrors
.
addAll
(
yearErrors
);
for
(
int
j
=
i
+
1
;
j
<
n
;
j
++)
{
allErrors
.
addAll
(
effectiveErrors
);
DtoWithParsedData
data2
=
preparedDataList
.
get
(
j
);
if
(
isSameBusinessGroup
(
data1
.
dto
,
data2
.
dto
))
{
boolean
yearOverlap
=
ProductCommonUtils
.
isYearRangeOverlap
(
data1
.
startYear
,
data1
.
endYear
,
data2
.
startYear
,
data2
.
endYear
);
boolean
timeOverlap
=
isTimeRangeOverlap
(
data1
.
effectiveStart
,
data1
.
effectiveEnd
,
data2
.
effectiveStart
,
data2
.
effectiveEnd
);
if
(
yearOverlap
&&
timeOverlap
)
{
if
(!
isErrorAlreadyExists
(
errors
,
data1
.
originalIndex
,
data2
.
originalIndex
,
"CONFLICT"
))
{
errors
.
add
(
new
OverlapError
(
data1
.
originalIndex
,
data2
.
originalIndex
,
"CONFLICT"
));
}
}
}
}
}
//
5. 如果有错误,返回错误信息
//
3. 有冲突则抛出异常
if
(!
allE
rrors
.
isEmpty
())
{
if
(!
e
rrors
.
isEmpty
())
{
String
errorMsg
=
build
ErrorMessage
(
allE
rrors
,
ratioBatchSaveDtoList
);
String
errorMsg
=
build
ConflictErrorMessage
(
e
rrors
,
ratioBatchSaveDtoList
);
throw
new
BusinessException
(
1004
,
errorMsg
);
throw
new
BusinessException
(
1004
,
errorMsg
);
}
}
return
Result
.
success
();
return
Result
.
success
();
}
}
/**
/**
* 准备数据:解析年限、存储有效时间,并校验基本合法性
* 准备数据:解析年限、有效时间,并校验基本合法性
* @param dtoList
* @return
*/
*/
private
List
<
DtoWithParsedData
>
prepareData
(
List
<
ApiExpectedCommissionRatioBatchSaveDto
>
dtoList
)
{
private
List
<
DtoWithParsedData
>
prepareData
(
List
<
ApiExpectedCommissionRatioBatchSaveDto
>
dtoList
)
{
List
<
DtoWithParsedData
>
preparedList
=
new
ArrayList
<>();
List
<
DtoWithParsedData
>
preparedList
=
new
ArrayList
<>();
...
@@ -220,17 +232,15 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
...
@@ -220,17 +232,15 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
for
(
int
i
=
0
;
i
<
dtoList
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
dtoList
.
size
();
i
++)
{
ApiExpectedCommissionRatioBatchSaveDto
dto
=
dtoList
.
get
(
i
);
ApiExpectedCommissionRatioBatchSaveDto
dto
=
dtoList
.
get
(
i
);
// 解析年限
Integer
startYear
=
ProductCommonUtils
.
parseYearToInt
(
dto
.
getStartPeriod
());
Integer
startYear
=
ProductCommonUtils
.
parseYearToInt
(
dto
.
getStartPeriod
());
Integer
endYear
=
ProductCommonUtils
.
parseYearToInt
(
dto
.
getEndPeriod
());
Integer
endYear
=
ProductCommonUtils
.
parseYearToInt
(
dto
.
getEndPeriod
());
if
(
startYear
>
endYear
)
{
if
(
startYear
>
endYear
)
{
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的起始年限["
+
startYear
+
"]不能大于结束年限["
+
endYear
+
"]"
);
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的起始年限["
+
startYear
+
"]不能大于结束年限["
+
endYear
+
"]"
);
}
}
// 校验有效时间起止顺序(新增)
if
(
dto
.
getEffectiveStart
().
isAfter
(
dto
.
getEffectiveEnd
()))
{
if
(
dto
.
getEffectiveStart
().
isAfter
(
dto
.
getEffectiveEnd
()))
{
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的有效开始时间不能晚于有效结束时间"
);
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的有效开始时间不能晚于有效结束时间"
);
}
}
preparedList
.
add
(
new
DtoWithParsedData
(
i
,
dto
,
startYear
,
endYear
,
preparedList
.
add
(
new
DtoWithParsedData
(
i
,
dto
,
startYear
,
endYear
,
...
@@ -241,56 +251,6 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
...
@@ -241,56 +251,6 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
}
}
/**
/**
* 检查年限重叠(原有逻辑,完全不变)
*/
private
List
<
OverlapError
>
checkYearOverlap
(
List
<
DtoWithParsedData
>
preparedDataList
)
{
List
<
OverlapError
>
errors
=
new
ArrayList
<>();
int
n
=
preparedDataList
.
size
();
for
(
int
i
=
0
;
i
<
n
-
1
;
i
++)
{
DtoWithParsedData
data1
=
preparedDataList
.
get
(
i
);
for
(
int
j
=
i
+
1
;
j
<
n
;
j
++)
{
DtoWithParsedData
data2
=
preparedDataList
.
get
(
j
);
// 使用原有的分组条件(包含 effectiveStart/end)
if
(
isSameGroupForYear
(
data1
,
data2
))
{
if
(
ProductCommonUtils
.
isYearRangeOverlap
(
data1
.
startYear
,
data1
.
endYear
,
data2
.
startYear
,
data2
.
endYear
))
{
if
(!
isErrorAlreadyExists
(
errors
,
data1
.
originalIndex
,
data2
.
originalIndex
,
"YEAR"
))
{
errors
.
add
(
new
OverlapError
(
data1
.
originalIndex
,
data2
.
originalIndex
,
"YEAR"
));
}
}
}
}
}
return
errors
;
}
/**
* 检查有效时间重叠(新增逻辑,使用排除时间字段的业务分组)
*/
private
List
<
OverlapError
>
checkEffectiveTimeOverlap
(
List
<
DtoWithParsedData
>
preparedDataList
)
{
List
<
OverlapError
>
errors
=
new
ArrayList
<>();
int
n
=
preparedDataList
.
size
();
for
(
int
i
=
0
;
i
<
n
-
1
;
i
++)
{
DtoWithParsedData
data1
=
preparedDataList
.
get
(
i
);
for
(
int
j
=
i
+
1
;
j
<
n
;
j
++)
{
DtoWithParsedData
data2
=
preparedDataList
.
get
(
j
);
// 使用排除时间字段的分组条件(expenseName, isExchangeRate, currency, reconciliationCompany)
if
(
isSameGroupForEffectiveTime
(
data1
.
dto
,
data2
.
dto
))
{
if
(
isTimeRangeOverlap
(
data1
.
effectiveStart
,
data1
.
effectiveEnd
,
data2
.
effectiveStart
,
data2
.
effectiveEnd
))
{
if
(!
isErrorAlreadyExists
(
errors
,
data1
.
originalIndex
,
data2
.
originalIndex
,
"EFFECTIVE"
))
{
errors
.
add
(
new
OverlapError
(
data1
.
originalIndex
,
data2
.
originalIndex
,
"EFFECTIVE"
));
}
}
}
}
}
return
errors
;
}
/**
* 判断两个有效时间区间是否重叠
* 判断两个有效时间区间是否重叠
*/
*/
private
boolean
isTimeRangeOverlap
(
LocalDateTime
start1
,
LocalDateTime
end1
,
private
boolean
isTimeRangeOverlap
(
LocalDateTime
start1
,
LocalDateTime
end1
,
...
@@ -299,38 +259,19 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
...
@@ -299,38 +259,19 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
}
}
/**
/**
*
原有的分组条件(包含有效开始/结束时间),用于年限重叠校验,保持不变
*
同一业务分组判断:费用名称、是否受汇率影响、结算币种、对账公司、销售组织完全一致
*/
*/
private
boolean
isSameGroupForYear
(
DtoWithParsedData
data1
,
DtoWithParsedData
data2
)
{
private
boolean
isSameBusinessGroup
(
ApiExpectedCommissionRatioBatchSaveDto
dto1
,
return
isSameGroupExcept
(
data1
.
dto
,
data2
.
dto
);
}
/**
* 原有的 isSameGroupExcept 方法,完全不变
*/
private
boolean
isSameGroupExcept
(
ApiExpectedCommissionRatioBatchSaveDto
dto1
,
ApiExpectedCommissionRatioBatchSaveDto
dto2
)
{
ApiExpectedCommissionRatioBatchSaveDto
dto2
)
{
return
Objects
.
equals
(
dto1
.
getExpenseName
(),
dto2
.
getExpenseName
())
return
Objects
.
equals
(
dto1
.
getExpenseName
(),
dto2
.
getExpenseName
())
&&
Objects
.
equals
(
dto1
.
getEffectiveStart
(),
dto2
.
getEffectiveStart
())
&&
Objects
.
equals
(
dto1
.
getEffectiveEnd
(),
dto2
.
getEffectiveEnd
())
&&
Objects
.
equals
(
dto1
.
getIsExchangeRate
(),
dto2
.
getIsExchangeRate
())
&&
Objects
.
equals
(
dto1
.
getIsExchangeRate
(),
dto2
.
getIsExchangeRate
())
&&
Objects
.
equals
(
dto1
.
getCurrency
(),
dto2
.
getCurrency
())
&&
Objects
.
equals
(
dto1
.
getCurrency
(),
dto2
.
getCurrency
())
&&
Objects
.
equals
(
dto1
.
getReconciliationCompany
(),
dto2
.
getReconciliationCompany
());
&&
Objects
.
equals
(
dto1
.
getReconciliationCompany
(),
dto2
.
getReconciliationCompany
())
&&
Objects
.
equals
(
dto1
.
getSalesOrg
(),
dto2
.
getSalesOrg
());
}
}
/**
/**
* 新增:用于有效时间重叠校验的分组条件(排除 effectiveStart/end)
* 检查冲突是否已记录(去重)
*/
private
boolean
isSameGroupForEffectiveTime
(
ApiExpectedCommissionRatioBatchSaveDto
dto1
,
ApiExpectedCommissionRatioBatchSaveDto
dto2
)
{
return
Objects
.
equals
(
dto1
.
getExpenseName
(),
dto2
.
getExpenseName
())
&&
Objects
.
equals
(
dto1
.
getIsExchangeRate
(),
dto2
.
getIsExchangeRate
())
&&
Objects
.
equals
(
dto1
.
getCurrency
(),
dto2
.
getCurrency
())
&&
Objects
.
equals
(
dto1
.
getReconciliationCompany
(),
dto2
.
getReconciliationCompany
());
}
/**
* 检查错误是否已存在(区分类型)
*/
*/
private
boolean
isErrorAlreadyExists
(
List
<
OverlapError
>
errors
,
int
index1
,
int
index2
,
String
type
)
{
private
boolean
isErrorAlreadyExists
(
List
<
OverlapError
>
errors
,
int
index1
,
int
index2
,
String
type
)
{
for
(
OverlapError
error
:
errors
)
{
for
(
OverlapError
error
:
errors
)
{
...
@@ -344,64 +285,37 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
...
@@ -344,64 +285,37 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
}
}
/**
/**
* 构建
错误消息(区分年限重叠和有效时间重叠)
* 构建
冲突错误信息
*/
*/
private
String
buildErrorMessage
(
List
<
OverlapError
>
errors
,
private
String
build
Conflict
ErrorMessage
(
List
<
OverlapError
>
errors
,
List
<
ApiExpectedCommissionRatioBatchSaveDto
>
originalList
)
{
List
<
ApiExpectedCommissionRatioBatchSaveDto
>
originalList
)
{
if
(
errors
.
isEmpty
())
{
if
(
errors
.
isEmpty
())
{
return
"未发现
重叠
数据"
;
return
"未发现
冲突
数据"
;
}
}
// 按重叠类型分组
StringBuilder
sb
=
new
StringBuilder
(
"发现年限区间重叠且有效时间区间重叠的数据:\n"
);
Map
<
String
,
Map
<
Integer
,
List
<
Integer
>>>
typeGroupMap
=
new
LinkedHashMap
<>();
for
(
OverlapError
error
:
errors
)
{
for
(
OverlapError
error
:
errors
)
{
typeGroupMap
.
computeIfAbsent
(
error
.
type
,
k
->
new
TreeMap
<>())
int
i
=
error
.
index1
;
.
computeIfAbsent
(
error
.
index1
,
k
->
new
ArrayList
<>()).
add
(
error
.
index2
);
int
j
=
error
.
index2
;
typeGroupMap
.
get
(
error
.
type
)
ApiExpectedCommissionRatioBatchSaveDto
dto1
=
originalList
.
get
(
i
);
.
computeIfAbsent
(
error
.
index2
,
k
->
new
ArrayList
<>()).
add
(
error
.
index1
);
ApiExpectedCommissionRatioBatchSaveDto
dto2
=
originalList
.
get
(
j
);
}
sb
.
append
(
"第"
).
append
(
i
+
1
).
append
(
"行(年限 "
).
append
(
dto1
.
getStartPeriod
()).
append
(
"~"
).
append
(
dto1
.
getEndPeriod
())
.
append
(
",有效 "
).
append
(
dto1
.
getEffectiveStart
().
format
(
DATE_FORMATTER
)).
append
(
"~"
).
append
(
dto1
.
getEffectiveEnd
().
format
(
DATE_FORMATTER
))
StringBuilder
sb
=
new
StringBuilder
();
.
append
(
")与第"
).
append
(
j
+
1
).
append
(
"行(年限 "
).
append
(
dto2
.
getStartPeriod
()).
append
(
"~"
).
append
(
dto2
.
getEndPeriod
())
for
(
Map
.
Entry
<
String
,
Map
<
Integer
,
List
<
Integer
>>>
typeEntry
:
typeGroupMap
.
entrySet
())
{
.
append
(
",有效 "
).
append
(
dto2
.
getEffectiveStart
().
format
(
DATE_FORMATTER
)).
append
(
"~"
).
append
(
dto2
.
getEffectiveEnd
().
format
(
DATE_FORMATTER
))
String
overlapType
=
"YEAR"
.
equals
(
typeEntry
.
getKey
())
?
"佣金年限区间"
:
"有效时间区间"
;
.
append
(
")冲突\n"
);
sb
.
append
(
"发现"
).
append
(
overlapType
).
append
(
"重叠的数据:\n"
);
Map
<
Integer
,
List
<
Integer
>>
overlapMap
=
typeEntry
.
getValue
();
for
(
Map
.
Entry
<
Integer
,
List
<
Integer
>>
entry
:
overlapMap
.
entrySet
())
{
int
dataIndex
=
entry
.
getKey
();
List
<
Integer
>
overlapIndices
=
entry
.
getValue
();
ApiExpectedCommissionRatioBatchSaveDto
dto
=
originalList
.
get
(
dataIndex
);
if
(
"YEAR"
.
equals
(
typeEntry
.
getKey
()))
{
sb
.
append
(
"第"
).
append
(
dataIndex
+
1
).
append
(
"行数据年限区间 "
)
.
append
(
dto
.
getStartPeriod
()).
append
(
"~"
).
append
(
dto
.
getEndPeriod
())
.
append
(
" 与以下数据年限区间重叠:"
);
}
else
{
// 格式化有效时间
String
startStr
=
dto
.
getEffectiveStart
().
format
(
DATE_FORMATTER
);
String
endStr
=
dto
.
getEffectiveEnd
().
format
(
DATE_FORMATTER
);
sb
.
append
(
"第"
).
append
(
dataIndex
+
1
).
append
(
"行数据有效时间 "
)
.
append
(
startStr
).
append
(
"~"
).
append
(
endStr
)
.
append
(
" 与以下数据有效时间重叠:"
);
}
for
(
int
overlapIndex
:
overlapIndices
)
{
sb
.
append
(
" 第"
).
append
(
overlapIndex
+
1
).
append
(
"行"
);
}
sb
.
append
(
"\n"
);
}
sb
.
append
(
"\n"
);
}
}
return
sb
.
toString
();
return
sb
.
toString
();
}
}
/**
// ------------------ 内部类 ------------------
* 内部类:包含解析后数据的DTO(增加有效时间字段)
public
static
class
DtoWithParsedData
{
*/
final
int
originalIndex
;
private
static
class
DtoWithParsedData
{
final
ApiExpectedCommissionRatioBatchSaveDto
dto
;
final
int
originalIndex
;
// 在原始列表中的索引
final
int
startYear
;
final
ApiExpectedCommissionRatioBatchSaveDto
dto
;
// 原始DTO
final
int
endYear
;
final
int
startYear
;
// 解析后的起始年份
final
LocalDateTime
effectiveStart
;
final
int
endYear
;
// 解析后的结束年份
final
LocalDateTime
effectiveEnd
;
final
LocalDateTime
effectiveStart
;
// 有效开始时间
final
LocalDateTime
effectiveEnd
;
// 有效结束时间
public
DtoWithParsedData
(
int
originalIndex
,
ApiExpectedCommissionRatioBatchSaveDto
dto
,
public
DtoWithParsedData
(
int
originalIndex
,
ApiExpectedCommissionRatioBatchSaveDto
dto
,
int
startYear
,
int
endYear
,
int
startYear
,
int
endYear
,
...
@@ -415,13 +329,10 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
...
@@ -415,13 +329,10 @@ public class ApiExpectedCommissionRatioServiceImpl implements ApiExpectedCommiss
}
}
}
}
/**
public
static
class
OverlapError
{
* 内部类:重叠错误(增加类型字段)
*/
private
static
class
OverlapError
{
private
final
int
index1
;
private
final
int
index1
;
private
final
int
index2
;
private
final
int
index2
;
private
final
String
type
;
// "YEAR" 或 "EFFECTIVE"
private
final
String
type
;
public
OverlapError
(
int
index1
,
int
index2
,
String
type
)
{
public
OverlapError
(
int
index1
,
int
index2
,
String
type
)
{
this
.
index1
=
index1
;
this
.
index1
=
index1
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment