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
80ee4e93
Commit
80ee4e93
authored
May 12, 2026
by
zhangxingmin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
push
parent
bb32f26e
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
60 additions
and
197 deletions
+60
-197
yd-product-api/src/main/java/com/yd/product/api/service/impl/ApiAnnouncementCommissionRatioServiceImpl.java
+60
-197
No files found.
yd-product-api/src/main/java/com/yd/product/api/service/impl/ApiAnnouncementCommissionRatioServiceImpl.java
View file @
80ee4e93
...
...
@@ -47,8 +47,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 分页列表查询-公告佣比率规格明细信息
* @param request
* @return
*/
@Override
public
Result
<
IPage
<
ApiAnnouncementCommissionRatioPageResponse
>>
page
(
ApiAnnouncementCommissionRatioPageRequest
request
)
{
...
...
@@ -59,8 +57,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 列表查询-条件查询-公告佣比率规格明细信息列表
* @param request
* @return
*/
@Override
public
Result
<
List
<
ApiAnnouncementCommissionRatioListResponse
>>
list
(
ApiAnnouncementCommissionRatioListRequest
request
)
{
...
...
@@ -75,8 +71,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 批量保存-公告佣比率规格明细信息
* @param request
* @return
*/
@Override
public
Result
batchSave
(
ApiAnnouncementCommissionRatioBatchSaveRequest
request
)
{
...
...
@@ -104,8 +98,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 添加-公告佣比率规格明细信息
* @param request
* @return
*/
@Override
public
Result
add
(
ApiAnnouncementCommissionRatioAddRequest
request
)
{
...
...
@@ -122,8 +114,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 编辑-公告佣比率规格明细信息
* @param request
* @return
*/
@Override
public
Result
edit
(
ApiAnnouncementCommissionRatioEditRequest
request
)
{
...
...
@@ -141,9 +131,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 编辑-状态
* @param announcementCommissionRatioBizId
* @param status
* @return
*/
@Override
public
Result
editStatus
(
String
announcementCommissionRatioBizId
,
Integer
status
)
{
...
...
@@ -157,8 +144,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 详情-公告佣比率规格明细信息
* @param announcementCommissionRatioBizId 公告佣比率规格明细表唯一业务ID
* @return
*/
@Override
public
Result
<
ApiAnnouncementCommissionRatioDetailResponse
>
detail
(
String
announcementCommissionRatioBizId
)
{
...
...
@@ -172,8 +157,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 删除-公告佣比率规格明细信息
* @param announcementCommissionRatioBizId 公告佣比率规格明细表唯一业务ID
* @return
*/
@Override
public
Result
del
(
String
announcementCommissionRatioBizId
)
{
...
...
@@ -186,8 +169,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 复制-公告佣比率规格明细信息
* @param announcementCommissionRatioBizId 公告佣比率规格明细表唯一业务ID
* @return
*/
@Override
public
Result
copy
(
String
announcementCommissionRatioBizId
)
{
...
...
@@ -202,8 +183,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 根据条件查询是否有公告佣比率规格明细信息数据
* @param productLaunchBizId 产品上架信息表唯一业务ID不
* @return
*/
@Override
public
Result
<
Boolean
>
isData
(
String
productLaunchBizId
)
{
...
...
@@ -221,8 +200,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
/**
* 校验公告佣比率规格明细信息是否存在
* @param announcementCommissionRatioBizId
* @return
*/
@Override
public
Result
<
AnnouncementCommissionRatio
>
checkAnnouncementCommissionRatioIsExist
(
String
announcementCommissionRatioBizId
)
{
...
...
@@ -235,37 +212,45 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
}
/**
* 校验入参-公告佣比率规格明细列表(年限区间和有效时间区间均不能重叠)
* @param ratioBatchSaveDtoList
* @return
* 校验入参-公告佣比率规格明细列表(年限区间重叠 且 有效时间区间重叠 时禁止)
*/
public
Result
checkBatchSaveRequestPram
(
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
ratioBatchSaveDtoList
)
{
// 1.
验证并准备数据(增加有效时间字段)
// 1.
准备解析后的数据
List
<
DtoWithParsedData
>
preparedDataList
=
prepareData
(
ratioBatchSaveDtoList
);
// 2. 检查年限重叠(原有逻辑,保持不变)
List
<
OverlapError
>
yearErrors
=
checkYearOverlap
(
preparedDataList
);
// 3. 检查有效时间重叠(新增逻辑,使用排除 effectiveStart/end 的分组,但仍考虑 scope 交集)
List
<
OverlapError
>
effectiveErrors
=
checkEffectiveTimeOverlap
(
preparedDataList
);
// 2. 检查年限重叠且有效时间重叠的冲突(业务字段相同 + scope有交集才视为同一分组)
List
<
OverlapError
>
errors
=
new
ArrayList
<>();
int
n
=
preparedDataList
.
size
();
// 4. 合并错误
List
<
OverlapError
>
allErrors
=
new
ArrayList
<>();
allErrors
.
addAll
(
yearErrors
);
allErrors
.
addAll
(
effectiveErrors
);
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
);
// 分组条件:费用名称、是否受汇率影响、币种相同,且scope有交集
if
(
isSameBusinessAndScopeIntersect
(
data1
,
data2
))
{
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. 如果有错误,返回错误信息
if
(!
allE
rrors
.
isEmpty
())
{
String
errorMsg
=
build
ErrorMessage
(
allE
rrors
,
ratioBatchSaveDtoList
);
//
3. 有冲突则抛出异常
if
(!
e
rrors
.
isEmpty
())
{
String
errorMsg
=
build
ConflictErrorMessage
(
e
rrors
,
ratioBatchSaveDtoList
);
throw
new
BusinessException
(
1004
,
errorMsg
);
}
return
Result
.
success
();
}
/**
* 准备数据:解析年限、存储有效时间、解析scope,并校验基本合法性
* @param dtoList
* @return
* 准备数据:解析年限、有效时间、scope,并校验基本合法性
*/
private
List
<
DtoWithParsedData
>
prepareData
(
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
dtoList
)
{
List
<
DtoWithParsedData
>
preparedList
=
new
ArrayList
<>();
...
...
@@ -281,12 +266,12 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的起始年限["
+
startYear
+
"]不能大于结束年限["
+
endYear
+
"]"
);
}
// 校验有效时间起止顺序
(新增)
// 校验有效时间起止顺序
if
(
dto
.
getEffectiveStart
().
isAfter
(
dto
.
getEffectiveEnd
()))
{
throw
new
BusinessException
(
"第"
+
(
i
+
1
)
+
"条数据的有效开始时间不能晚于有效结束时间"
);
}
// 解析scope为集合
,
去重
// 解析scope为集合
,
去重
Set
<
String
>
scopeSet
=
ProductCommonUtils
.
parseScopeToSet
(
dto
.
getScope
());
preparedList
.
add
(
new
DtoWithParsedData
(
i
,
dto
,
startYear
,
endYear
,
scopeSet
,
...
...
@@ -297,56 +282,6 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
}
/**
* 检查年限重叠(原有逻辑,完全不变)
*/
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 和 scope 交集)
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
;
}
/**
* 检查有效时间重叠(新增逻辑,使用排除 effectiveStart/end 的分组,但仍考虑 scope 交集)
*/
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
);
// 使用排除 effectiveStart/end 的分组条件,但仍然检查 scope 交集
if
(
isSameGroupForEffectiveTime
(
data1
,
data2
))
{
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
,
...
...
@@ -355,66 +290,19 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
}
/**
* 原有的分组条件(包含 effectiveStart/end 和 scope 交集),用于年限重叠校验,保持不变
*/
private
boolean
isSameGroupForYear
(
DtoWithParsedData
data1
,
DtoWithParsedData
data2
)
{
// 1. 检查除scope外的其他条件是否相同(包含 effectiveStart/end)
if
(!
isSameGroupExceptScope
(
data1
.
dto
,
data2
.
dto
))
{
return
false
;
}
// 2. 检查scope是否有交集
return
ProductCommonUtils
.
hasScopeIntersection
(
data1
.
scopeSet
,
data2
.
scopeSet
);
}
/**
* 原有的 isSameGroupExceptScope 方法,完全不变
*/
private
boolean
isSameGroupExceptScope
(
ApiAnnouncementCommissionRatioBatchSaveDto
dto1
,
ApiAnnouncementCommissionRatioBatchSaveDto
dto2
)
{
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
.
getCurrency
(),
dto2
.
getCurrency
());
}
/**
* 新增:用于有效时间重叠校验的分组条件(排除 effectiveStart/end,但仍检查 scope 交集)
* 同一业务分组判断:费用名称、是否受汇率影响、币种相同,且scope有交集(忽略有效时间)
*/
private
boolean
isSameGroupForEffectiveTime
(
DtoWithParsedData
data1
,
DtoWithParsedData
data2
)
{
// 1. 检查排除 effectiveStart/end 后的其他条件是否相同
if
(!
isSameGroupExceptTimeAndScope
(
data1
.
dto
,
data2
.
dto
))
{
return
false
;
}
// 2. 检查scope是否有交集
return
ProductCommonUtils
.
hasScopeIntersection
(
data1
.
scopeSet
,
data2
.
scopeSet
);
}
/**
* 检查排除 effectiveStart/end 和 scope 后的条件是否相同(仅业务分组字段)
*/
private
boolean
isSameGroupExceptTimeAndScope
(
ApiAnnouncementCommissionRatioBatchSaveDto
dto1
,
ApiAnnouncementCommissionRatioBatchSaveDto
dto2
)
{
private
boolean
isSameBusinessAndScopeIntersect
(
DtoWithParsedData
data1
,
DtoWithParsedData
data2
)
{
ApiAnnouncementCommissionRatioBatchSaveDto
dto1
=
data1
.
dto
;
ApiAnnouncementCommissionRatioBatchSaveDto
dto2
=
data2
.
dto
;
return
Objects
.
equals
(
dto1
.
getExpenseName
(),
dto2
.
getExpenseName
())
&&
Objects
.
equals
(
dto1
.
getIsExchangeRate
(),
dto2
.
getIsExchangeRate
())
&&
Objects
.
equals
(
dto1
.
getCurrency
(),
dto2
.
getCurrency
());
&&
Objects
.
equals
(
dto1
.
getCurrency
(),
dto2
.
getCurrency
())
&&
ProductCommonUtils
.
hasScopeIntersection
(
data1
.
scopeSet
,
data2
.
scopeSet
);
}
/**
* 校验基础字段(保留,未使用)
*/
private
boolean
validateBasicFields
(
ApiAnnouncementCommissionRatioBatchSaveDto
dto
)
{
return
dto
.
getExpenseName
()
!=
null
&&
!
dto
.
getExpenseName
().
trim
().
isEmpty
()
&&
dto
.
getEffectiveStart
()
!=
null
&&
dto
.
getEffectiveEnd
()
!=
null
&&
dto
.
getEffectiveStart
().
isBefore
(
dto
.
getEffectiveEnd
())
&&
dto
.
getScope
()
!=
null
&&
!
dto
.
getScope
().
trim
().
isEmpty
()
&&
dto
.
getIsExchangeRate
()
!=
null
&&
!
dto
.
getIsExchangeRate
().
trim
().
isEmpty
()
&&
dto
.
getCurrency
()
!=
null
&&
!
dto
.
getCurrency
().
trim
().
isEmpty
();
}
/**
* 检查错误是否已存在(区分类型)
* 检查冲突是否已记录(去重)
*/
private
boolean
isErrorAlreadyExists
(
List
<
OverlapError
>
errors
,
int
index1
,
int
index2
,
String
type
)
{
for
(
OverlapError
error
:
errors
)
{
...
...
@@ -428,65 +316,40 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
}
/**
* 构建
错误消息(区分年限重叠和有效时间重叠)
* 构建
合并后的冲突错误信息
*/
private
String
buildErrorMessage
(
List
<
OverlapError
>
errors
,
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
originalList
)
{
private
String
build
Conflict
ErrorMessage
(
List
<
OverlapError
>
errors
,
List
<
ApiAnnouncementCommissionRatioBatchSaveDto
>
originalList
)
{
if
(
errors
.
isEmpty
())
{
return
"未发现
重叠
数据"
;
return
"未发现
冲突
数据"
;
}
// 按重叠类型分组
Map
<
String
,
Map
<
Integer
,
List
<
Integer
>>>
typeGroupMap
=
new
LinkedHashMap
<>();
StringBuilder
sb
=
new
StringBuilder
(
"发现年限区间重叠且有效时间区间重叠的数据:\n"
);
for
(
OverlapError
error
:
errors
)
{
typeGroupMap
.
computeIfAbsent
(
error
.
type
,
k
->
new
TreeMap
<>())
.
computeIfAbsent
(
error
.
index1
,
k
->
new
ArrayList
<>()).
add
(
error
.
index2
);
typeGroupMap
.
get
(
error
.
type
)
.
computeIfAbsent
(
error
.
index2
,
k
->
new
ArrayList
<>()).
add
(
error
.
index1
);
}
StringBuilder
sb
=
new
StringBuilder
();
for
(
Map
.
Entry
<
String
,
Map
<
Integer
,
List
<
Integer
>>>
typeEntry
:
typeGroupMap
.
entrySet
())
{
String
overlapType
=
"YEAR"
.
equals
(
typeEntry
.
getKey
())
?
"佣金年限区间"
:
"有效时间区间"
;
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
();
ApiAnnouncementCommissionRatioBatchSaveDto
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"
);
int
i
=
error
.
index1
;
int
j
=
error
.
index2
;
ApiAnnouncementCommissionRatioBatchSaveDto
dto1
=
originalList
.
get
(
i
);
ApiAnnouncementCommissionRatioBatchSaveDto
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
))
.
append
(
")与第"
).
append
(
j
+
1
).
append
(
"行(年限 "
).
append
(
dto2
.
getStartPeriod
()).
append
(
"~"
).
append
(
dto2
.
getEndPeriod
())
.
append
(
",有效 "
).
append
(
dto2
.
getEffectiveStart
().
format
(
DATE_FORMATTER
)).
append
(
"~"
).
append
(
dto2
.
getEffectiveEnd
().
format
(
DATE_FORMATTER
))
.
append
(
")冲突\n"
);
}
return
sb
.
toString
();
}
/**
* 内部类:包含解析后数据的DTO
(增加有效时间字段)
* 内部类:包含解析后数据的DTO
*/
private
static
class
DtoWithParsedData
{
final
int
originalIndex
;
// 在原始列表中的索引
final
ApiAnnouncementCommissionRatioBatchSaveDto
dto
;
// 原始DTO
final
int
startYear
;
// 解析后的起始年份
final
int
endYear
;
// 解析后的结束年份
final
Set
<
String
>
scopeSet
;
// 解析后的scope集合
final
LocalDateTime
effectiveStart
;
// 有效开始时间
final
LocalDateTime
effectiveEnd
;
// 有效结束时间
final
int
originalIndex
;
final
ApiAnnouncementCommissionRatioBatchSaveDto
dto
;
final
int
startYear
;
final
int
endYear
;
final
Set
<
String
>
scopeSet
;
final
LocalDateTime
effectiveStart
;
final
LocalDateTime
effectiveEnd
;
public
DtoWithParsedData
(
int
originalIndex
,
ApiAnnouncementCommissionRatioBatchSaveDto
dto
,
int
startYear
,
int
endYear
,
Set
<
String
>
scopeSet
,
...
...
@@ -502,12 +365,12 @@ public class ApiAnnouncementCommissionRatioServiceImpl implements ApiAnnouncemen
}
/**
* 内部类:重叠错误(
增加类型字段
)
* 内部类:重叠错误(
类型统一为"CONFLICT"
)
*/
private
static
class
OverlapError
{
private
final
int
index1
;
private
final
int
index2
;
private
final
String
type
;
// "YEAR" 或 "EFFECTIVE"
private
final
String
type
;
public
OverlapError
(
int
index1
,
int
index2
,
String
type
)
{
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