Toggle navigation
Toggle navigation
This project
Loading...
Sign in
jiujian
/
client-customer-order-api
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
zhuyifan
2025-10-27 18:58:59 +0800
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
2f8b7a62b4d6a61e638bcbe74454be7991160993
2f8b7a62
2 parents
4c308216
f36ed61c
Merge branch 'feature/2025-10-23' into 'master'
Feature/2025 10 23 See merge request
!11
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
1185 additions
and
45 deletions
src/main/java/com/infoloop/tianting/context/LoginContextHolder.java
src/main/java/com/infoloop/tianting/controller/KdsController.java
src/main/java/com/infoloop/tianting/enums/SettlementDimensionEnum.java
src/main/java/com/infoloop/tianting/intercepter/LoginInterceptor.java
src/main/java/com/infoloop/tianting/model/dto/KdsDTO.java
src/main/java/com/infoloop/tianting/model/dto/OrderDbDTO.java
src/main/java/com/infoloop/tianting/model/dto/SettlementDTO.java
src/main/java/com/infoloop/tianting/model/enums/desc/OnlinePayDescEnum.java
src/main/java/com/infoloop/tianting/service/KdsService.java
src/main/java/com/infoloop/tianting/service/SettlementService.java
src/main/java/com/infoloop/tianting/service/client/OrderServiceRpcClient.java
src/main/java/com/infoloop/tianting/service/impl/KdsServiceImpl.java
src/main/java/com/infoloop/tianting/service/impl/OrderServiceImpl.java
src/main/java/com/infoloop/tianting/service/impl/SettlementServiceImpl.java
src/main/java/com/infoloop/tianting/streamController/SettlementController.java
src/main/proto/ClientCustomerOrderService.proto
src/main/java/com/infoloop/tianting/context/LoginContextHolder.java
View file @
2f8b7a6
...
...
@@ -57,6 +57,8 @@ public class LoginContextHolder {
private
Integer
enterpriseId
;
private
Integer
clientId
;
private
String
name
;
@Builder
.
Default
...
...
src/main/java/com/infoloop/tianting/controller/KdsController.java
View file @
2f8b7a6
...
...
@@ -48,8 +48,8 @@ public class KdsController {
@ApiOperation
(
value
=
"kds获取餐别详情"
)
@PostMapping
(
"/kds/mealDetails"
)
@ResponseStatus
(
HttpStatus
.
OK
)
public
List
<
KdsMealDetailDto
>
getMealDetail
()
{
return
kdsService
.
getMealDetail
();
public
List
<
KdsMealDetailDto
>
getMealDetail
(
@Valid
@RequestBody
KdsDTO
.
KdsMealDetailQueryDto
queryDto
)
{
return
kdsService
.
getMealDetail
(
queryDto
);
}
}
...
...
src/main/java/com/infoloop/tianting/enums/SettlementDimensionEnum.java
View file @
2f8b7a6
...
...
@@ -8,6 +8,7 @@ import lombok.Getter;
public
enum
SettlementDimensionEnum
{
BY_SKU
(
1
,
"菜品"
),
BY_MEAL
(
2
,
"餐别"
),
BY_ORDER
(
3
,
"订单"
)
;
/**
...
...
src/main/java/com/infoloop/tianting/intercepter/LoginInterceptor.java
View file @
2f8b7a6
...
...
@@ -93,7 +93,7 @@ public class LoginInterceptor implements HandlerInterceptor {
ResponseUtil
.
write
(
response
,
ResponseResult
.
failed
(
ErrorCodeEnum
.
FORBIDDEN
));
return
false
;
}
builder
.
id
(
loginId
).
enterpriseId
(
enterpriseId
).
name
(
customer
.
getResponse
().
getName
()).
openId
(
openId
).
loginSource
(
LoginSourceEnum
.
CUSTOMER
);
builder
.
id
(
loginId
).
enterpriseId
(
enterpriseId
).
clientId
(
customer
.
getResponse
().
getClientId
()).
name
(
customer
.
getResponse
().
getName
()).
openId
(
openId
).
loginSource
(
LoginSourceEnum
.
CUSTOMER
);
return
true
;
}
else
if
(
loginSource
.
equals
(
LoginSourceEnum
.
OPERATOR
.
getValue
())){
final
var
loginId
=
StpUtil
.
getLoginIdAsInt
();
...
...
@@ -103,7 +103,7 @@ public class LoginInterceptor implements HandlerInterceptor {
ResponseUtil
.
write
(
response
,
ResponseResult
.
failed
(
ErrorCodeEnum
.
FORBIDDEN
));
return
false
;
}
builder
.
id
(
loginId
).
enterpriseId
(
enterpriseId
).
name
(
opeartor
.
getName
()).
loginSource
(
LoginSourceEnum
.
OPERATOR
);
builder
.
id
(
loginId
).
enterpriseId
(
enterpriseId
).
clientId
(
opeartor
.
getClientId
()).
name
(
opeartor
.
getName
()).
loginSource
(
LoginSourceEnum
.
OPERATOR
);
return
true
;
}
else
if
(
loginSource
.
equals
(
LoginSourceEnum
.
KDS
.
getValue
()))
{
final
var
loginId
=
StpUtil
.
getLoginIdAsInt
();
...
...
src/main/java/com/infoloop/tianting/model/dto/KdsDTO.java
View file @
2f8b7a6
...
...
@@ -30,6 +30,7 @@ public class KdsDTO {
private
Integer
price
;
private
String
roomNo
;
private
String
remark
;
private
String
avoidRemark
;
private
CustomerNotice
customerNotice
;
private
String
adjustSkuRemark
;
private
String
mealTime
;
...
...
@@ -38,6 +39,8 @@ public class KdsDTO {
private
ClientDto
client
;
private
ClientDto
stall
;
private
CustomerDetailDto
customer
;
private
Integer
menuId
;
private
String
menuName
;
}
@Data
...
...
@@ -77,6 +80,7 @@ public class KdsDTO {
private
String
tableCode
;
private
Integer
totalCount
;
private
String
remark
;
private
String
avoidRemark
;
private
String
mealTime
;
private
CustomerNotice
customerNotice
;
private
Integer
totalPrice
;
...
...
@@ -87,6 +91,8 @@ public class KdsDTO {
private
ClientDto
client
;
private
CustomerDetailDto
customer
;
private
List
<
KdsOrderLocationDetailDto
>
orderDetailList
;
private
Integer
menuId
;
private
String
menuName
;
}
@Data
...
...
@@ -97,6 +103,7 @@ public class KdsDTO {
public
static
class
KdsOrderSkuQueryDto
{
private
ServeStatusEnum
serveStatus
;
private
Integer
mealId
;
private
String
mealTime
;
}
@Data
...
...
@@ -107,12 +114,22 @@ public class KdsDTO {
public
static
class
KdsOrderLocationQueryDto
{
private
OrderStatusEnum
orderStatus
;
private
Integer
mealId
;
private
String
mealTime
;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel
(
description
=
"KdsMealDetailQueryDto"
)
public
static
class
KdsMealDetailQueryDto
{
private
String
mealTime
;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ApiModel
(
description
=
"KdsMealDetailDto"
)
public
static
class
KdsMealDetailDto
{
private
Integer
mealId
;
...
...
src/main/java/com/infoloop/tianting/model/dto/OrderDbDTO.java
View file @
2f8b7a6
...
...
@@ -64,6 +64,16 @@ public class OrderDbDTO {
}
@Data
@ApiModel
(
description
=
"查询订单Dto"
)
public
static
class
QueryOrderDto
{
private
Integer
enterpriseId
;
private
Integer
clientId
;
private
OrderStatusEnum
status
;
private
String
keyword
;
private
List
<
Integer
>
stallIds
;
}
@Data
@ApiModel
(
description
=
"查询已撤销订单Dto"
)
public
static
class
QueryRefundOrderByPaginationDto
{
private
Integer
enterpriseId
;
...
...
@@ -155,6 +165,7 @@ public class OrderDbDTO {
private
String
tableCode
;
private
Integer
updatedBy
;
private
OrderSourceEnum
updatedSource
;
private
String
avoidRemark
;
}
...
...
@@ -440,6 +451,9 @@ public class OrderDbDTO {
@ApiModelProperty
(
value
=
"备注"
)
private
String
remark
;
@ApiModelProperty
(
value
=
"忌口备注"
)
private
String
avoidRemark
;
@ApiModelProperty
(
value
=
"下单客户当时的忌口、医嘱"
)
private
CustomerNotice
customerNoticeJson
;
...
...
src/main/java/com/infoloop/tianting/model/dto/SettlementDTO.java
View file @
2f8b7a6
...
...
@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel;
import
lombok.Builder
;
import
lombok.Data
;
import
java.math.BigDecimal
;
import
java.time.LocalDateTime
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -75,7 +76,55 @@ public class SettlementDTO {
private
Map
<
String
,
Map
<
String
,
Map
<
String
,
List
<
SettlementMenuMealDto
>>>>
classifyOrders
;
}
}
@Data
@Builder
@ApiModel
(
description
=
"SettlementDataByOrderDto"
)
public
static
class
SettlementDataByOrderDto
{
private
List
<
SettlementOrderDetail
>
classifyOrders
;
}
@Data
@Builder
@ApiModel
(
description
=
"SettlementOrderDetail"
)
public
static
class
SettlementOrderDetail
{
private
String
mealTime
;
private
String
code
;
private
String
mealName
;
private
String
roomNo
;
private
String
customerName
;
private
String
HISCustomerNo
;
private
List
<
String
>
avoids
;
private
List
<
String
>
doctors
;
private
String
menuName
;
private
String
skuName
;
private
Integer
count
;
private
BigDecimal
price
;
private
BigDecimal
totalPrice
;
private
String
remark
;
private
String
avoidRemark
;
private
String
onlinePay
;
}
@Data
@Builder
@ApiModel
(
description
=
"SeparateMealDetail"
)
public
static
class
SeparateMealDetail
{
private
Integer
orderId
;
private
String
mealName
;
private
String
roomNo
;
private
String
customerName
;
private
String
menuName
;
private
String
skuName
;
private
Integer
count
;
private
String
avoids
;
private
String
remark
;
}
\ No newline at end of file
@Data
@Builder
@ApiModel
(
description
=
"SeparateMealDataDto"
)
public
static
class
SeparateMealDataDto
{
private
List
<
SeparateMealDetail
>
mealDetails
;
}
}
...
...
src/main/java/com/infoloop/tianting/model/enums/desc/OnlinePayDescEnum.java
0 → 100644
View file @
2f8b7a6
package
com
.
infoloop
.
tianting
.
model
.
enums
.
desc
;
import
com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum
;
public
enum
OnlinePayDescEnum
implements
BaseProtoDescEnum
<
OnlinePayEnum
>
{
UNKNOWN
(
OnlinePayEnum
.
UNKNOWN
,
""
),
ONLINE
(
OnlinePayEnum
.
ONLINE
,
"线上支付"
),
OFFLINE
(
OnlinePayEnum
.
OFFLINE
,
"线下支付"
),
LEAVE_HOSPITAL
(
OnlinePayEnum
.
LEAVE_HOSPITAL
,
"出院支付"
),
EMPLOYEE_CARD
(
OnlinePayEnum
.
EMPLOYEE_CARD
,
"员工卡支付"
),
PAPER_VERIFICATION
(
OnlinePayEnum
.
PAPER_VERIFICATION
,
"纸质核销"
),
CASH
(
OnlinePayEnum
.
CASH
,
"现金支付"
),
MEAL_CARD
(
OnlinePayEnum
.
MEAL_CARD
,
"餐卡结算"
),
BAND_CARD
(
OnlinePayEnum
.
BAND_CARD
,
"POS-银行卡"
),
ALIPAY
(
OnlinePayEnum
.
ALIPAY
,
"POS-支付宝"
),
WECHATPAY
(
OnlinePayEnum
.
WECHATPAY
,
"POS-微信"
);
private
final
OnlinePayEnum
protoEnum
;
private
final
String
desc
;
OnlinePayDescEnum
(
OnlinePayEnum
protoEnum
,
String
desc
)
{
this
.
protoEnum
=
protoEnum
;
this
.
desc
=
desc
;
}
@Override
public
OnlinePayEnum
getProtoEnum
()
{
return
protoEnum
;
}
@Override
public
String
getDesc
()
{
return
desc
;
}
}
src/main/java/com/infoloop/tianting/service/KdsService.java
View file @
2f8b7a6
package
com
.
infoloop
.
tianting
.
service
;
import
com.infoloop.tianting.model.dto.KdsDTO
;
import
com.infoloop.tianting.model.dto.KdsDTO.KdsMealDetailDto
;
import
com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDto
;
import
com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationQueryDto
;
...
...
@@ -14,5 +15,5 @@ public interface KdsService {
List
<
KdsOrderLocationDto
>
getOrderDetailByLocation
(
KdsOrderLocationQueryDto
queryDto
);
List
<
KdsMealDetailDto
>
getMealDetail
();
List
<
KdsMealDetailDto
>
getMealDetail
(
KdsDTO
.
KdsMealDetailQueryDto
queryDto
);
}
...
...
src/main/java/com/infoloop/tianting/service/SettlementService.java
View file @
2f8b7a6
package
com
.
infoloop
.
tianting
.
service
;
import
com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto
;
import
java.io.ByteArrayOutputStream
;
public
interface
SettlementService
{
ByteArrayOutputStream
generateOrderSettlementExcel
(
SettlementRequestDto
settlementRequest
);
ByteArrayOutputStream
exportSeparateMealsExcel
(
QueryOrderDto
queryOrderDto
);
}
...
...
src/main/java/com/infoloop/tianting/service/client/OrderServiceRpcClient.java
View file @
2f8b7a6
...
...
@@ -31,6 +31,7 @@ import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
import
com.infoloop.tianting.clientcustomerorderservice.OrderTypeEnum
;
import
com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum
;
import
com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcRequest
;
import
com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcResponse
;
import
com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcRequest
;
import
com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcResponse
;
import
com.infoloop.tianting.clientcustomerorderservice.QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest
;
...
...
@@ -57,6 +58,7 @@ import com.infoloop.tianting.model.bo.AddSkusSellQuantityBO;
import
com.infoloop.tianting.model.bo.SkuSellQuantityBO
;
import
com.infoloop.tianting.model.dto.OperationDTO.BatchOperationDto
;
import
com.infoloop.tianting.model.dto.OperationDTO.SingleOperationDto
;
import
com.infoloop.tianting.model.dto.OrderDbDTO
;
import
com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDetailDto
;
import
com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto
;
import
com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderResponse
;
...
...
@@ -180,6 +182,8 @@ public class OrderServiceRpcClient {
.
setTableCode
(
tableCode
)
.
setShouldUpdateRoomNo
(
updateOrderDto
.
isShouldUpdateRoomNo
())
.
setRoomNo
(
roomNo
)
.
setShouldUpdateAvoidRemark
(
updateOrderDto
.
getAvoidRemark
()
!=
null
)
.
setAvoidRemark
(
updateOrderDto
.
getAvoidRemark
()
==
null
?
""
:
updateOrderDto
.
getAvoidRemark
())
.
build
();
final
var
request
=
UpdateClientCustomerOrderRpcRequest
.
newBuilder
()
.
setEnterpriseId
(
updateOrderDto
.
getEnterpriseId
())
...
...
@@ -188,7 +192,7 @@ public class OrderServiceRpcClient {
.
setModification
(
modification
)
.
build
();
final
UpdateClientCustomerOrderRpcResponse
updateClientCustomerOrderRpcResponse
=
orderServiceRpcBlockingStub
.
updateClientCustomerOrder
(
request
);
if
(
updateClientCustomerOrderRpcResponse
.
getIsUpdated
()
&&
updateOrderDto
.
getStatus
()
==
OrderStatusEnum
.
ORDER_CANCELED
)
{
if
(
updateClientCustomerOrderRpcResponse
.
getIsUpdated
()
&&
updateOrderDto
.
getStatus
()
!=
null
&&
updateOrderDto
.
getStatus
()
==
OrderStatusEnum
.
ORDER_CANCELED
)
{
final
var
orderById
=
getOrderById
(
updateOrderDto
.
getId
());
if
(
orderById
!=
null
&&
orderById
.
getCloseTimeType
()
==
CloseTimeType
.
IMMEDIATELY
)
{
final
var
orderDetails
=
getOrderDetailsByOrderId
(
orderById
.
getId
());
...
...
@@ -484,6 +488,17 @@ public class OrderServiceRpcClient {
return
orderServiceRpcBlockingStub
.
queryClientCustomerOrdersByPagination
(
request
);
}
public
QueryClientCustomerOrdersByConditionRpcResponse
queryClientCustomerOrdersByCondition
(
OrderDbDTO
.
QueryOrderDto
queryOrderDto
)
{
final
var
request
=
QueryClientCustomerOrdersByConditionRpcRequest
.
newBuilder
()
.
setShouldFilterStatus
(
true
)
.
setStatus
(
queryOrderDto
.
getStatus
())
.
setEnterpriseId
(
queryOrderDto
.
getEnterpriseId
())
.
setShouldFilterClientIds
(
true
).
addClientIds
(
queryOrderDto
.
getClientId
())
.
setShouldFilterStallIds
(
true
).
addAllStallIds
(
queryOrderDto
.
getStallIds
())
.
build
();
return
orderServiceRpcBlockingStub
.
queryClientCustomerOrdersByCondition
(
request
);
}
public
QueryClientCustomerOrdersByPaginationRpcResponse
queryRefundClientCustomerOrdersByPagination
(
QueryRefundOrderByPaginationDto
queryOrderDto
)
{
final
var
request
=
QueryClientCustomerOrdersByPaginationRpcRequest
.
newBuilder
()
...
...
src/main/java/com/infoloop/tianting/service/impl/KdsServiceImpl.java
View file @
2f8b7a6
...
...
@@ -6,7 +6,9 @@ import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
import
com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse
;
import
com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse
;
import
com.infoloop.tianting.context.LoginContextHolder
;
import
com.infoloop.tianting.menuservice.SingleMenuRpcResponse
;
import
com.infoloop.tianting.model.dto.ClientInventoryDbDTO.ClientDto
;
import
com.infoloop.tianting.model.dto.KdsDTO
;
import
com.infoloop.tianting.model.dto.KdsDTO.KdsMealDetailDto
;
import
com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDetailDto
;
import
com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDto
;
...
...
@@ -22,6 +24,7 @@ import com.infoloop.tianting.service.client.ClientCustomerServiceRpcClient;
import
com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient
;
import
com.infoloop.tianting.service.client.EnterpriseResourceServiceRpcClient
;
import
com.infoloop.tianting.service.client.MealServiceRpcClient
;
import
com.infoloop.tianting.service.client.MenuServiceRpcClient
;
import
com.infoloop.tianting.service.client.OrderServiceRpcClient
;
import
com.infoloop.tianting.service.client.SkuServiceRpcClient
;
import
com.infoloop.tianting.service.client.WOperatorServiceRpcClient
;
...
...
@@ -33,8 +36,10 @@ import org.springframework.stereotype.Service;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.LocalTime
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
@Slf4j
...
...
@@ -49,14 +54,14 @@ public class KdsServiceImpl implements KdsService {
private
final
SkuServiceRpcClient
skuServiceRpcClient
;
private
final
ClientInventoryServiceRpcClient
clientInventoryServiceRpcClient
;
private
final
ClientCustomerServiceRpcClient
clientCustomerServiceRpcClient
;
private
final
MenuServiceRpcClient
menuServiceRpcClient
;
@Override
public
List
<
KdsOrderSkuDto
>
getOrderDetailBySku
(
KdsOrderSkuQueryDto
queryDto
)
{
// 获取当日所有的订单 和 订单明细
LocalDate
today
=
LocalDate
.
now
(
);
LocalDate
today
=
LocalDate
.
parse
(
queryDto
.
getMealTime
(),
DateUtil
.
YYYY_MM_DD
);
LocalDateTime
todayZero
=
today
.
atStartOfDay
();
LocalDate
tomorrow
=
today
.
plusDays
(
1
);
LocalDateTime
tomorrowZero
=
tomorrow
.
atStartOfDay
();
LocalDateTime
todayEnd
=
today
.
atTime
(
LocalTime
.
MAX
);
final
var
operatorLoginInfo
=
LoginContextHolder
.
getLoginInfo
();
boolean
shouldFilterStallIds
=
false
;
List
<
Integer
>
stallIds
=
new
ArrayList
<>();
...
...
@@ -73,7 +78,7 @@ public class KdsServiceImpl implements KdsService {
.
shouldFilterMealTimeStart
(
true
)
.
mealTimeStart
(
todayZero
)
.
shouldFilterMealTimeEnd
(
true
)
.
mealTimeEnd
(
to
morrowZero
)
.
mealTimeEnd
(
to
dayEnd
)
.
shouldFilterPayStatus
(
true
)
.
payStatus
(
PayStatusEnum
.
SUCCEED
)
.
build
();
...
...
@@ -118,6 +123,9 @@ public class KdsServiceImpl implements KdsService {
.
collect
(
Collectors
.
toList
());
final
var
skus
=
skuServiceRpcClient
.
getDishSkusByIds
(
skuIds
).
getResponseList
();
final
var
menuIds
=
orderList
.
stream
().
map
(
SingleClientCustomerOrderRpcResponse:
:
getMenuId
).
distinct
().
toList
();
final
var
menuMap
=
menuServiceRpcClient
.
getMenusByIds
(
operator
.
getEnterpriseId
(),
menuIds
).
getResponsesList
().
stream
().
collect
(
Collectors
.
toMap
(
SingleMenuRpcResponse:
:
getId
,
Function
.
identity
()));
List
<
KdsOrderSkuDto
>
kdsOrderSkuList
=
new
ArrayList
<>();
for
(
Integer
menuDetailId
:
menuDetailIds
)
{
// 找出该menuDetailId 的所有orderDetail
...
...
@@ -168,8 +176,11 @@ public class KdsServiceImpl implements KdsService {
.
count
(
detail
.
getCount
())
.
orderDetailId
(
detail
.
getId
())
.
remark
(
order
.
get
().
getRemark
())
.
avoidRemark
(
order
.
get
().
getAvoidRemark
())
.
orderId
(
order
.
get
().
getId
())
.
roomNo
(
order
.
get
().
getSyncRoomNo
().
isEmpty
()
?
order
.
get
().
getRoomNo
()
:
order
.
get
().
getSyncRoomNo
())
.
menuId
(
order
.
get
().
getMenuId
())
.
menuName
(
menuMap
.
get
(
order
.
get
().
getMenuId
())
==
null
?
""
:
menuMap
.
get
(
order
.
get
().
getMenuId
()).
getName
())
.
tableCode
(
order
.
get
().
getTableCode
())
.
customerNotice
(
CustomerNotice
.
builder
()
.
doctors
(
order
.
get
().
getCustomerNoticeJson
().
getDoctorsList
())
...
...
@@ -208,9 +219,9 @@ public class KdsServiceImpl implements KdsService {
}
@Override
public
List
<
KdsMealDetailDto
>
getMealDetail
()
{
public
List
<
KdsMealDetailDto
>
getMealDetail
(
KdsDTO
.
KdsMealDetailQueryDto
queryDto
)
{
// 获取当日用餐的所有的订单 和 订单明细
LocalDate
today
=
LocalDate
.
now
(
);
LocalDate
today
=
LocalDate
.
parse
(
queryDto
.
getMealTime
(),
DateUtil
.
YYYY_MM_DD
);
LocalDateTime
todayZero
=
today
.
atStartOfDay
();
LocalDate
tomorrow
=
today
.
plusDays
(
1
);
LocalDateTime
tomorrowZero
=
tomorrow
.
atStartOfDay
().
minusMinutes
(
1
);
...
...
@@ -235,6 +246,8 @@ public class KdsServiceImpl implements KdsService {
.
mealTimeStart
(
todayZero
)
.
shouldFilterMealTimeEnd
(
true
)
.
mealTimeEnd
(
tomorrowZero
)
.
shouldFilterPayStatus
(
true
)
.
payStatus
(
PayStatusEnum
.
SUCCEED
)
.
build
();
final
var
orderList
=
orderServiceRpcClient
.
getOrdersByCondition
(
queryOrderDto
);
...
...
@@ -281,10 +294,9 @@ public class KdsServiceImpl implements KdsService {
@Override
public
List
<
KdsOrderLocationDto
>
getOrderDetailByLocation
(
KdsOrderLocationQueryDto
queryDto
)
{
// 获取当日用餐的所有的订单 和 订单明细
LocalDate
today
=
LocalDate
.
now
(
);
LocalDate
today
=
LocalDate
.
parse
(
queryDto
.
getMealTime
(),
DateUtil
.
YYYY_MM_DD
);
LocalDateTime
todayZero
=
today
.
atStartOfDay
();
LocalDate
tomorrow
=
today
.
plusDays
(
1
);
LocalDateTime
tomorrowZero
=
tomorrow
.
atStartOfDay
().
minusMinutes
(
1
);
LocalDateTime
todayEnd
=
today
.
atTime
(
LocalTime
.
MAX
);
final
var
operatorLoginInfo
=
LoginContextHolder
.
getLoginInfo
();
...
...
@@ -305,7 +317,7 @@ public class KdsServiceImpl implements KdsService {
.
shouldFilterMealTimeStart
(
true
)
.
mealTimeStart
(
todayZero
)
.
shouldFilterMealTimeEnd
(
true
)
.
mealTimeEnd
(
to
morrowZero
)
.
mealTimeEnd
(
to
dayEnd
)
.
shouldFilterStatus
(
true
)
.
status
(
queryDto
.
getOrderStatus
())
.
shouldFilterPayStatus
(
true
)
...
...
@@ -339,6 +351,12 @@ public class KdsServiceImpl implements KdsService {
final
var
filteredOrderDetailList
=
orderDetailList
.
stream
()
.
filter
(
od
->
od
.
getMealId
()
==
queryDto
.
getMealId
()
&&
od
.
getServeStatus
()
!=
ServeStatusEnum
.
SERVE_REJECT
)
.
collect
(
Collectors
.
toList
());
final
var
menuIds
=
orderList
.
stream
().
map
(
SingleClientCustomerOrderRpcResponse:
:
getMenuId
).
distinct
().
toList
();
final
var
menuMap
=
menuServiceRpcClient
.
getMenusByIds
(
operator
.
getEnterpriseId
(),
menuIds
).
getResponsesList
().
stream
().
collect
(
Collectors
.
toMap
(
SingleMenuRpcResponse:
:
getId
,
Function
.
identity
()));
List
<
KdsOrderLocationDto
>
kdsOrderLocationList
=
new
ArrayList
<>();
for
(
SingleClientCustomerOrderRpcResponse
order
:
orderList
)
{
...
...
@@ -395,9 +413,12 @@ public class KdsServiceImpl implements KdsService {
final
var
kdsOrder
=
KdsOrderLocationDto
.
builder
()
.
totalCount
(
order
.
getTotalNum
())
.
remark
(
order
.
getRemark
())
.
avoidRemark
(
order
.
getAvoidRemark
())
.
orderId
(
order
.
getId
())
.
roomNo
(
order
.
getSyncRoomNo
().
isEmpty
()
?
order
.
getRoomNo
()
:
order
.
getSyncRoomNo
())
.
tableCode
(
order
.
getTableCode
())
.
menuId
(
order
.
getMenuId
())
.
menuName
(
menuMap
.
get
(
order
.
getMenuId
())
==
null
?
""
:
menuMap
.
get
(
order
.
getMenuId
()).
getName
())
.
customerNotice
(
CustomerNotice
.
builder
()
.
doctors
(
order
.
getCustomerNoticeJson
().
getDoctorsList
())
.
avoids
(
order
.
getCustomerNoticeJson
().
getAvoidsList
())
...
...
src/main/java/com/infoloop/tianting/service/impl/OrderServiceImpl.java
View file @
2f8b7a6
...
...
@@ -487,6 +487,7 @@ public class OrderServiceImpl implements OrderService {
.
mealTime
(
DateUtil
.
formatDate
(
r
.
getMealTime
()))
.
orderType
(
r
.
getOrderTypeValue
())
.
remark
(
r
.
getRemark
())
.
avoidRemark
(
r
.
getAvoidRemark
())
.
isDeleted
(
r
.
getIsDeleted
())
.
isRead
(
r
.
getIsRead
())
.
creationSource
(
r
.
getCreationSource
().
getNumber
())
...
...
src/main/java/com/infoloop/tianting/service/impl/SettlementServiceImpl.java
View file @
2f8b7a6
package
com
.
infoloop
.
tianting
.
service
.
impl
;
import
cn.hutool.core.collection.CollectionUtil
;
import
cn.hutool.core.date.LocalDateTimeUtil
;
import
com.infoloop.tianting.SingleDishSkuByIdsRpcResponse
;
import
com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum
;
import
com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum
;
import
com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum
;
import
com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum
;
import
com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse
;
import
com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse
;
import
com.infoloop.tianting.clientcustomerservice.SingleClientCustomerRpcResponse
;
import
com.infoloop.tianting.clientinventoryservice.SingleClientRpcResponse
;
import
com.infoloop.tianting.context.LoginContextHolder
;
import
com.infoloop.tianting.enums.SettlementDimensionEnum
;
...
...
@@ -12,35 +18,55 @@ import com.infoloop.tianting.exception.ErrorCodeEnum;
import
com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse
;
import
com.infoloop.tianting.menuservice.SingleMenuRpcResponse
;
import
com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto
;
import
com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SeparateMealDataDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SeparateMealDetail
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataByMealDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuMealDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuSkuDto
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto
;
import
com.infoloop.tianting.model.enums.desc.BaseProtoDescEnum
;
import
com.infoloop.tianting.model.enums.desc.OnlinePayDescEnum
;
import
com.infoloop.tianting.service.SettlementService
;
import
com.infoloop.tianting.service.client.ClientCustomerServiceRpcClient
;
import
com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient
;
import
com.infoloop.tianting.service.client.ClientResourceTagServiceRpcClient
;
import
com.infoloop.tianting.service.client.MealServiceRpcClient
;
import
com.infoloop.tianting.service.client.MenuServiceRpcClient
;
import
com.infoloop.tianting.service.client.OrderServiceRpcClient
;
import
com.infoloop.tianting.service.client.SkuServiceRpcClient
;
import
com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse
;
import
com.infoloop.tianting.utils.DateUtil
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.poi.ss.usermodel.BorderStyle
;
import
org.apache.poi.ss.usermodel.Cell
;
import
org.apache.poi.ss.usermodel.CellStyle
;
import
org.apache.poi.ss.usermodel.Font
;
import
org.apache.poi.ss.usermodel.HorizontalAlignment
;
import
org.apache.poi.ss.usermodel.IndexedColors
;
import
org.apache.poi.ss.usermodel.Row
;
import
org.apache.poi.ss.usermodel.Sheet
;
import
org.apache.poi.ss.usermodel.VerticalAlignment
;
import
org.apache.poi.ss.usermodel.Workbook
;
import
org.apache.poi.ss.util.CellRangeAddress
;
import
org.apache.poi.ss.util.RegionUtil
;
import
org.apache.poi.xssf.usermodel.XSSFWorkbook
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Service
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.ZoneId
;
import
java.time.temporal.ChronoUnit
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.Comparator
;
import
java.util.HashMap
;
import
java.util.List
;
...
...
@@ -57,6 +83,8 @@ public class SettlementServiceImpl implements SettlementService {
private
final
SkuServiceRpcClient
skuServiceRpcClient
;
private
final
ClientInventoryServiceRpcClient
clientInventoryServiceRpcClient
;
private
final
MealServiceRpcClient
mealServiceRpcClient
;
private
final
ClientCustomerServiceRpcClient
clientCustomerServiceRpcClient
;
private
final
ClientResourceTagServiceRpcClient
clientResourceTagServiceRpcClient
;
public
static
ByteArrayOutputStream
writeToExcelBySku
(
SettlementDataDto
settlementDataDto
)
throws
IOException
{
...
...
@@ -272,9 +300,567 @@ public class SettlementServiceImpl implements SettlementService {
public
ByteArrayOutputStream
generateOrderSettlementExcel
(
SettlementRequestDto
settlementRequest
)
{
if
(
settlementRequest
.
getDimension
().
equals
(
SettlementDimensionEnum
.
BY_SKU
))
{
return
generateOrderSettlementExcelBySku
(
settlementRequest
);
}
else
{
}
else
if
(
settlementRequest
.
getDimension
().
equals
(
SettlementDimensionEnum
.
BY_MEAL
))
{
return
generateOrderSettlementExcelByMeal
(
settlementRequest
);
}
else
if
(
settlementRequest
.
getDimension
().
equals
(
SettlementDimensionEnum
.
BY_ORDER
))
{
return
generateOrderSettlementExcelByOrder
(
settlementRequest
);
}
return
null
;
}
private
ByteArrayOutputStream
generateOrderSettlementExcelByOrder
(
SettlementRequestDto
settlementRequest
)
{
// 参数校验
if
(
settlementRequest
==
null
||
settlementRequest
.
getTimeStart
()
==
null
||
settlementRequest
.
getTimeEnd
()
==
null
)
{
throw
BusinessException
.
build
(
ErrorCodeEnum
.
GENERATE_EXCEL_ERROR
);
}
final
var
loginInfo
=
LoginContextHolder
.
getLoginInfo
();
final
var
userResources
=
clientResourceTagServiceRpcClient
.
getUserResources
(
loginInfo
.
getEnterpriseId
(),
loginInfo
.
getClientId
(),
loginInfo
.
getId
());
// 计算日期范围
final
var
startDate
=
settlementRequest
.
getTimeStart
().
plusHours
(
8
).
toLocalDate
().
atStartOfDay
();
final
var
endDate
=
settlementRequest
.
getTimeEnd
()
.
plusHours
(
8
)
.
toLocalDate
()
.
atTime
(
23
,
59
,
59
,
999_000_000
);
// 获取企业ID
final
var
operatorLoginInfo
=
LoginContextHolder
.
getLoginInfo
();
final
int
enterpriseId
=
LoginContextHolder
.
hasLogin
()
?
operatorLoginInfo
.
getEnterpriseId
()
:
settlementRequest
.
getEnterpriseId
();
final
var
stallIds
=
new
ArrayList
<
Integer
>();
if
(
CollectionUtil
.
isEmpty
(
settlementRequest
.
getStallIds
()))
{
stallIds
.
addAll
(
userResources
.
getStallIdsList
());
}
else
{
stallIds
.
addAll
(
settlementRequest
.
getStallIds
());
}
// 构建查询条件
final
var
queryOrderDto
=
QueryOrderByConditionDto
.
builder
()
.
enterpriseId
(
enterpriseId
)
.
shouldFilterMealTimeStart
(
true
)
.
mealTimeStart
(
startDate
)
.
shouldFilterMealTimeEnd
(
true
)
.
mealTimeEnd
(
endDate
)
.
shouldFilterStallIds
(
true
)
.
stallIds
(
stallIds
)
.
build
();
// 查询订单列表
final
var
orderList
=
orderServiceRpcClient
.
getOrdersByCondition
(
queryOrderDto
);
if
(
orderList
==
null
||
orderList
.
isEmpty
())
{
log
.
warn
(
"未查询到订单数据,enterpriseId: {}, startDate: {}, endDate: {}"
,
enterpriseId
,
startDate
,
endDate
);
return
createEmptyExcelByOrder
();
}
// 筛选有效订单ID
List
<
Integer
>
orderIds
=
orderList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
o
->
{
// 在线支付订单需要支付成功
if
(
o
.
getOnlinePay
()
==
OnlinePayEnum
.
ONLINE
)
{
return
o
.
getPayStatus
()
==
PayStatusEnum
.
SUCCEED
;
}
else
{
// 非在线支付订单需要未取消
return
o
.
getStatus
()
!=
OrderStatusEnum
.
ORDER_CANCELED
;
}
})
.
map
(
SingleClientCustomerOrderRpcResponse:
:
getId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
if
(
orderIds
.
isEmpty
())
{
log
.
warn
(
"筛选后无有效订单,enterpriseId: {}"
,
enterpriseId
);
return
createEmptyExcelByOrder
();
}
// 构建订单映射
final
var
orderMap
=
orderList
.
stream
()
.
filter
(
o
->
o
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleClientCustomerOrderRpcResponse:
:
getId
,
o
->
o
,
(
o1
,
o2
)
->
o1
));
// 查询订单详情
final
var
orderDetailList
=
orderServiceRpcClient
.
getOrderDetailsByOrderIds
(
orderIds
);
if
(
orderDetailList
==
null
||
orderDetailList
.
isEmpty
())
{
log
.
warn
(
"未查询到订单详情数据,orderIds: {}"
,
orderIds
);
return
createEmptyExcelByOrder
();
}
// 订单详情按订单ID分组
final
var
orderDetailGroupByOrderId
=
orderDetailList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
d
->
!
d
.
getServeStatus
().
equals
(
ServeStatusEnum
.
SERVE_REJECT
))
.
collect
(
Collectors
.
groupingBy
(
SingleClientCustomerOrderDetailRpcResponse:
:
getOrderId
));
// 获取SKU数据
List
<
Integer
>
skuIds
=
orderDetailList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
d
->
!
d
.
getServeStatus
().
equals
(
ServeStatusEnum
.
SERVE_REJECT
))
.
map
(
SingleClientCustomerOrderDetailRpcResponse:
:
getSkuId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
final
var
skuResponse
=
skuServiceRpcClient
.
getDishSkusByIds
(
skuIds
);
final
List
<
SingleDishSkuByIdsRpcResponse
>
skus
=
skuResponse
!=
null
?
skuResponse
.
getResponseList
()
:
new
ArrayList
<>();
final
var
skuMap
=
skus
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
s
->
s
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleDishSkuByIdsRpcResponse:
:
getId
,
s
->
s
,
(
s1
,
s2
)
->
s1
));
// 获取餐别数据
final
var
mealResponse
=
mealServiceRpcClient
.
getAllMeals
(
enterpriseId
);
final
List
<
SingleMealRpcResponse
>
meals
=
mealResponse
!=
null
?
mealResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
mealMap
=
meals
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
m
->
m
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleMealRpcResponse:
:
getId
,
m
->
m
,
(
m1
,
m2
)
->
m1
));
// 获取菜单数据
List
<
Integer
>
menuIds
=
orderList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
map
(
SingleClientCustomerOrderRpcResponse:
:
getMenuId
)
.
filter
(
id
->
id
!=
0
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
final
var
menuResponse
=
menuServiceRpcClient
.
getMenusByIds
(
enterpriseId
,
menuIds
);
final
List
<
SingleMenuRpcResponse
>
menuList
=
menuResponse
!=
null
?
menuResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
menuMap
=
menuList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
m
->
m
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleMenuRpcResponse:
:
getId
,
m
->
m
,
(
m1
,
m2
)
->
m1
));
// 获取菜单详情数据
final
var
menuDetailResponse
=
menuServiceRpcClient
.
queryMenuDetailsByMenuIds
(
enterpriseId
,
menuIds
);
final
List
<
SingleMenuDetailRpcResponse
>
menuDetailList
=
menuDetailResponse
!=
null
?
menuDetailResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
menuDetailMap
=
menuDetailList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
m
->
m
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleMenuDetailRpcResponse:
:
getId
,
m
->
m
,
(
m1
,
m2
)
->
m1
));
// 获取客户数据
List
<
Integer
>
customerIds
=
orderList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
map
(
SingleClientCustomerOrderRpcResponse:
:
getCustomerId
)
.
filter
(
id
->
id
!=
0
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
final
var
customerResponse
=
clientCustomerServiceRpcClient
.
getClientCustomersByIds
(
enterpriseId
,
customerIds
);
final
List
<
SingleClientCustomerRpcResponse
>
customers
=
customerResponse
!=
null
?
customerResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
customerMap
=
customers
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
c
->
c
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleClientCustomerRpcResponse:
:
getId
,
c
->
c
,
(
c1
,
c2
)
->
c1
));
// 构建结算订单明细
final
var
classifyOrders
=
new
ArrayList
<
SettlementDTO
.
SettlementOrderDetail
>();
for
(
Integer
orderId
:
orderIds
)
{
final
var
orderDetails
=
orderDetailGroupByOrderId
.
getOrDefault
(
orderId
,
Collections
.
emptyList
());
final
var
order
=
orderMap
.
get
(
orderId
);
// 订单为空则跳过
if
(
order
==
null
)
{
log
.
warn
(
"订单不存在,orderId: {}"
,
orderId
);
continue
;
}
// 获取菜单信息
final
var
menu
=
menuMap
.
get
(
order
.
getMenuId
());
final
String
menuName
=
menu
!=
null
?
menu
.
getName
()
:
""
;
// 获取客户信息
final
var
customer
=
customerMap
.
get
(
order
.
getCustomerId
());
final
String
customerName
=
customer
!=
null
?
customer
.
getName
()
:
""
;
final
String
hisCustomerNo
=
customer
!=
null
?
customer
.
getHISCustomerNo
()
:
""
;
// 处理每个订单详情
for
(
SingleClientCustomerOrderDetailRpcResponse
orderDetail
:
orderDetails
)
{
if
(
orderDetail
==
null
)
{
continue
;
}
// 安全获取餐别名称
String
mealName
=
getMealNameSafely
(
orderDetail
,
menuDetailMap
,
mealMap
);
// 安全获取SKU名称
String
skuName
=
getSkuNameSafely
(
orderDetail
,
skuMap
);
// 安全获取房间号
String
roomNo
=
getRoomNoSafely
(
order
);
// 安全获取忌口和医嘱
List
<
String
>
avoids
=
getAvoidsSafely
(
order
);
List
<
String
>
doctors
=
getDoctorsSafely
(
order
);
// 安全获取在线支付描述
String
onlinePayDesc
=
getOnlinePayDescSafely
(
order
);
// 构建订单详情
order
.
getOrderCode
();
order
.
getRemark
();
order
.
getAvoidRemark
();
SettlementDTO
.
SettlementOrderDetail
settlementOrderDetail
=
SettlementDTO
.
SettlementOrderDetail
.
builder
()
.
mealTime
(
order
.
getMealTime
()
!=
0L
?
LocalDateTimeUtil
.
of
(
order
.
getMealTime
()).
format
(
DateUtil
.
YYYY_MM_DD_LEFT_SYMBOL
)
:
""
)
.
code
(
order
.
getOrderCode
())
.
mealName
(
mealName
)
.
roomNo
(
roomNo
)
.
customerName
(
customerName
)
.
HISCustomerNo
(
hisCustomerNo
)
.
avoids
(
avoids
)
.
doctors
(
doctors
)
.
menuName
(
menuName
)
.
skuName
(
skuName
)
.
count
(
orderDetail
.
getCount
()
!=
0
?
orderDetail
.
getCount
()
:
0
)
.
price
(
calculatePrice
(
orderDetail
.
getPrice
()))
.
totalPrice
(
calculateTotalPrice
(
orderDetail
.
getPrice
(),
orderDetail
.
getCount
()))
.
remark
(
order
.
getRemark
())
.
avoidRemark
(
order
.
getAvoidRemark
())
.
onlinePay
(
onlinePayDesc
)
.
build
();
classifyOrders
.
add
(
settlementOrderDetail
);
}
}
// 构建结算数据
final
var
settlementDataByOrderDto
=
SettlementDTO
.
SettlementDataByOrderDto
.
builder
()
.
classifyOrders
(
classifyOrders
)
.
build
();
// 生成Excel
try
{
return
writeToExcelByOrder
(
settlementDataByOrderDto
);
}
catch
(
IOException
e
)
{
log
.
error
(
"生成按订单结算Excel失败"
,
e
);
throw
BusinessException
.
build
(
ErrorCodeEnum
.
GENERATE_EXCEL_ERROR
);
}
}
/**
* 安全获取餐别名称
*/
private
String
getMealNameSafely
(
SingleClientCustomerOrderDetailRpcResponse
orderDetail
,
Map
<
Integer
,
SingleMenuDetailRpcResponse
>
menuDetailMap
,
Map
<
Integer
,
SingleMealRpcResponse
>
mealMap
)
{
if
(
orderDetail
==
null
||
orderDetail
.
getMenuDetailId
()
==
0
)
{
return
""
;
}
final
var
menuDetail
=
menuDetailMap
.
get
(
orderDetail
.
getMenuDetailId
());
if
(
menuDetail
==
null
||
menuDetail
.
getMealId
()
==
0
)
{
return
""
;
}
final
var
meal
=
mealMap
.
get
(
menuDetail
.
getMealId
());
return
meal
!=
null
?
meal
.
getName
()
:
""
;
}
/**
* 安全获取SKU名称
*/
private
String
getSkuNameSafely
(
SingleClientCustomerOrderDetailRpcResponse
orderDetail
,
Map
<
Integer
,
SingleDishSkuByIdsRpcResponse
>
skuMap
)
{
if
(
orderDetail
==
null
||
orderDetail
.
getSkuId
()
==
0
)
{
return
""
;
}
final
var
sku
=
skuMap
.
get
(
orderDetail
.
getSkuId
());
return
sku
!=
null
?
sku
.
getName
()
:
""
;
}
/**
* 安全获取房间号
*/
private
String
getRoomNoSafely
(
SingleClientCustomerOrderRpcResponse
order
)
{
if
(
order
==
null
)
{
return
""
;
}
String
syncRoomNo
=
order
.
getSyncRoomNo
();
if
(!
syncRoomNo
.
isEmpty
())
{
return
syncRoomNo
;
}
return
order
.
getRoomNo
();
}
/**
* 安全获取忌口列表
*/
private
List
<
String
>
getAvoidsSafely
(
SingleClientCustomerOrderRpcResponse
order
)
{
if
(
order
==
null
)
{
return
Collections
.
emptyList
();
}
return
order
.
getCustomerNoticeJson
().
getAvoidsList
();
}
/**
* 安全获取医嘱列表
*/
private
List
<
String
>
getDoctorsSafely
(
SingleClientCustomerOrderRpcResponse
order
)
{
if
(
order
==
null
)
{
return
Collections
.
emptyList
();
}
return
order
.
getCustomerNoticeJson
().
getDoctorsList
();
}
/**
* 安全获取在线支付描述
*/
private
String
getOnlinePayDescSafely
(
SingleClientCustomerOrderRpcResponse
order
)
{
if
(
order
==
null
)
{
return
""
;
}
try
{
String
desc
=
BaseProtoDescEnum
.
getDescByProtoEnum
(
order
.
getOnlinePay
(),
OnlinePayDescEnum
.
class
);
return
desc
!=
null
?
desc
:
""
;
}
catch
(
Exception
e
)
{
log
.
warn
(
"获取在线支付描述失败,orderId: {}"
,
order
.
getId
(),
e
);
return
""
;
}
}
/**
* 计算单价
*/
private
BigDecimal
calculatePrice
(
Integer
price
)
{
if
(
price
==
null
)
{
return
BigDecimal
.
ZERO
;
}
return
new
BigDecimal
(
price
).
divide
(
new
BigDecimal
(
100
),
2
,
RoundingMode
.
HALF_UP
);
}
/**
* 计算总价
*/
private
BigDecimal
calculateTotalPrice
(
Integer
price
,
Integer
count
)
{
if
(
price
==
null
||
count
==
null
)
{
return
BigDecimal
.
ZERO
;
}
return
new
BigDecimal
(
price
)
.
multiply
(
new
BigDecimal
(
count
))
.
divide
(
new
BigDecimal
(
100
),
2
,
RoundingMode
.
HALF_UP
);
}
/**
* 创建空的订单Excel
*/
private
ByteArrayOutputStream
createEmptyExcelByOrder
()
{
try
{
final
var
emptyData
=
SettlementDTO
.
SettlementDataByOrderDto
.
builder
()
.
classifyOrders
(
Collections
.
emptyList
())
.
build
();
return
writeToExcelByOrder
(
emptyData
);
}
catch
(
IOException
e
)
{
log
.
error
(
"创建空Excel失败"
,
e
);
throw
BusinessException
.
build
(
ErrorCodeEnum
.
GENERATE_EXCEL_ERROR
);
}
}
/**
* 按订单维度生成Excel
*/
private
static
ByteArrayOutputStream
writeToExcelByOrder
(
SettlementDTO
.
SettlementDataByOrderDto
settlementDataDto
)
throws
IOException
{
Workbook
workbook
=
new
XSSFWorkbook
();
Sheet
sheet
=
workbook
.
createSheet
(
"客人结算"
);
// 创建表头样式(黑色边框)
CellStyle
headerStyle
=
workbook
.
createCellStyle
();
headerStyle
.
setBorderTop
(
BorderStyle
.
THIN
);
headerStyle
.
setBorderBottom
(
BorderStyle
.
THIN
);
headerStyle
.
setBorderLeft
(
BorderStyle
.
THIN
);
headerStyle
.
setBorderRight
(
BorderStyle
.
THIN
);
headerStyle
.
setTopBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
headerStyle
.
setBottomBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
headerStyle
.
setLeftBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
headerStyle
.
setRightBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
// 创建数据行样式(浅灰色边框)
CellStyle
dataStyle
=
workbook
.
createCellStyle
();
dataStyle
.
setBorderTop
(
BorderStyle
.
THIN
);
dataStyle
.
setBorderBottom
(
BorderStyle
.
THIN
);
dataStyle
.
setBorderLeft
(
BorderStyle
.
THIN
);
dataStyle
.
setBorderRight
(
BorderStyle
.
THIN
);
dataStyle
.
setTopBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
dataStyle
.
setBottomBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
dataStyle
.
setLeftBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
dataStyle
.
setRightBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
int
rowNum
=
0
;
// 创建表头
Row
titleRow
=
sheet
.
createRow
(
rowNum
++);
int
columnNum
=
0
;
Cell
cell0
=
titleRow
.
createCell
(
columnNum
++);
cell0
.
setCellValue
(
"用餐时间"
);
cell0
.
setCellStyle
(
headerStyle
);
Cell
cell1
=
titleRow
.
createCell
(
columnNum
++);
cell1
.
setCellValue
(
"订单号"
);
cell1
.
setCellStyle
(
headerStyle
);
Cell
cell2
=
titleRow
.
createCell
(
columnNum
++);
cell2
.
setCellValue
(
"餐别"
);
cell2
.
setCellStyle
(
headerStyle
);
Cell
cell3
=
titleRow
.
createCell
(
columnNum
++);
cell3
.
setCellValue
(
"房间号"
);
cell3
.
setCellStyle
(
headerStyle
);
Cell
cell4
=
titleRow
.
createCell
(
columnNum
++);
cell4
.
setCellValue
(
"客户姓名"
);
cell4
.
setCellStyle
(
headerStyle
);
Cell
cell5
=
titleRow
.
createCell
(
columnNum
++);
cell5
.
setCellValue
(
"客户腕带号"
);
cell5
.
setCellStyle
(
headerStyle
);
Cell
cell6
=
titleRow
.
createCell
(
columnNum
++);
cell6
.
setCellValue
(
"忌口信息"
);
cell6
.
setCellStyle
(
headerStyle
);
Cell
cell7
=
titleRow
.
createCell
(
columnNum
++);
cell7
.
setCellValue
(
"医嘱信息"
);
cell7
.
setCellStyle
(
headerStyle
);
Cell
cell8
=
titleRow
.
createCell
(
columnNum
++);
cell8
.
setCellValue
(
"餐单名称"
);
cell8
.
setCellStyle
(
headerStyle
);
Cell
cell9
=
titleRow
.
createCell
(
columnNum
++);
cell9
.
setCellValue
(
"菜品名称"
);
cell9
.
setCellStyle
(
headerStyle
);
Cell
cell10
=
titleRow
.
createCell
(
columnNum
++);
cell10
.
setCellValue
(
"菜品份数"
);
cell10
.
setCellStyle
(
headerStyle
);
Cell
cell11
=
titleRow
.
createCell
(
columnNum
++);
cell11
.
setCellValue
(
"菜品单价"
);
cell11
.
setCellStyle
(
headerStyle
);
Cell
cell12
=
titleRow
.
createCell
(
columnNum
++);
cell12
.
setCellValue
(
"菜品金额"
);
cell12
.
setCellStyle
(
headerStyle
);
Cell
cell13
=
titleRow
.
createCell
(
columnNum
++);
cell13
.
setCellValue
(
"备注"
);
cell13
.
setCellStyle
(
headerStyle
);
Cell
cell14
=
titleRow
.
createCell
(
columnNum
++);
cell14
.
setCellValue
(
"支付方式"
);
cell14
.
setCellStyle
(
headerStyle
);
// 填充数据
final
var
classifyOrders
=
settlementDataDto
.
getClassifyOrders
();
if
(
classifyOrders
!=
null
)
{
for
(
SettlementDTO
.
SettlementOrderDetail
orderDetail
:
classifyOrders
)
{
Row
dataRow
=
sheet
.
createRow
(
rowNum
++);
columnNum
=
0
;
Cell
dataCell0
=
dataRow
.
createCell
(
columnNum
++);
dataCell0
.
setCellValue
(
orderDetail
.
getMealTime
()
!=
null
?
orderDetail
.
getMealTime
()
:
""
);
dataCell0
.
setCellStyle
(
dataStyle
);
Cell
dataCell1
=
dataRow
.
createCell
(
columnNum
++);
dataCell1
.
setCellValue
(
orderDetail
.
getCode
()
!=
null
?
orderDetail
.
getCode
()
:
""
);
dataCell1
.
setCellStyle
(
dataStyle
);
Cell
dataCell2
=
dataRow
.
createCell
(
columnNum
++);
dataCell2
.
setCellValue
(
orderDetail
.
getMealName
()
!=
null
?
orderDetail
.
getMealName
()
:
""
);
dataCell2
.
setCellStyle
(
dataStyle
);
Cell
dataCell3
=
dataRow
.
createCell
(
columnNum
++);
dataCell3
.
setCellValue
(
orderDetail
.
getRoomNo
()
!=
null
?
orderDetail
.
getRoomNo
()
:
""
);
dataCell3
.
setCellStyle
(
dataStyle
);
Cell
dataCell4
=
dataRow
.
createCell
(
columnNum
++);
dataCell4
.
setCellValue
(
orderDetail
.
getCustomerName
()
!=
null
?
orderDetail
.
getCustomerName
()
:
""
);
dataCell4
.
setCellStyle
(
dataStyle
);
Cell
dataCell5
=
dataRow
.
createCell
(
columnNum
++);
dataCell5
.
setCellValue
(
orderDetail
.
getHISCustomerNo
()
!=
null
?
orderDetail
.
getHISCustomerNo
()
:
""
);
dataCell5
.
setCellStyle
(
dataStyle
);
// 忌口列表转字符串
String
avoidsStr
=
orderDetail
.
getAvoids
()
!=
null
?
String
.
join
(
", "
,
orderDetail
.
getAvoids
())
:
""
;
Cell
dataCell6
=
dataRow
.
createCell
(
columnNum
++);
dataCell6
.
setCellValue
(
avoidsStr
);
dataCell6
.
setCellStyle
(
dataStyle
);
// 医嘱列表转字符串
String
doctorsStr
=
orderDetail
.
getDoctors
()
!=
null
?
String
.
join
(
", "
,
orderDetail
.
getDoctors
())
:
""
;
Cell
dataCell7
=
dataRow
.
createCell
(
columnNum
++);
dataCell7
.
setCellValue
(
doctorsStr
);
dataCell7
.
setCellStyle
(
dataStyle
);
Cell
dataCell8
=
dataRow
.
createCell
(
columnNum
++);
dataCell8
.
setCellValue
(
orderDetail
.
getMenuName
()
!=
null
?
orderDetail
.
getMenuName
()
:
""
);
dataCell8
.
setCellStyle
(
dataStyle
);
Cell
dataCell9
=
dataRow
.
createCell
(
columnNum
++);
dataCell9
.
setCellValue
(
orderDetail
.
getSkuName
()
!=
null
?
orderDetail
.
getSkuName
()
:
""
);
dataCell9
.
setCellStyle
(
dataStyle
);
Cell
dataCell10
=
dataRow
.
createCell
(
columnNum
++);
dataCell10
.
setCellValue
(
orderDetail
.
getCount
()
!=
null
?
orderDetail
.
getCount
()
:
0
);
dataCell10
.
setCellStyle
(
dataStyle
);
// 价格
Cell
dataCell11
=
dataRow
.
createCell
(
columnNum
++);
if
(
orderDetail
.
getPrice
()
!=
null
)
{
dataCell11
.
setCellValue
(
orderDetail
.
getPrice
().
doubleValue
());
}
else
{
dataCell11
.
setCellValue
(
0.0
);
}
dataCell11
.
setCellStyle
(
dataStyle
);
// 总价
Cell
dataCell12
=
dataRow
.
createCell
(
columnNum
++);
if
(
orderDetail
.
getTotalPrice
()
!=
null
)
{
dataCell12
.
setCellValue
(
orderDetail
.
getTotalPrice
().
doubleValue
());
}
else
{
dataCell12
.
setCellValue
(
0.0
);
}
dataCell12
.
setCellStyle
(
dataStyle
);
// 合并备注和忌口备注,用分号分割,备注在前
String
remark
=
orderDetail
.
getRemark
()
!=
null
?
orderDetail
.
getRemark
()
:
""
;
String
avoidRemark
=
orderDetail
.
getAvoidRemark
()
!=
null
?
orderDetail
.
getAvoidRemark
()
:
""
;
String
combinedRemark
=
""
;
if
(!
remark
.
isEmpty
()
&&
!
avoidRemark
.
isEmpty
())
{
combinedRemark
=
remark
+
";"
+
avoidRemark
;
}
else
if
(!
remark
.
isEmpty
())
{
combinedRemark
=
remark
;
}
else
if
(!
avoidRemark
.
isEmpty
())
{
combinedRemark
=
avoidRemark
;
}
Cell
dataCell13
=
dataRow
.
createCell
(
columnNum
++);
dataCell13
.
setCellValue
(
combinedRemark
);
dataCell13
.
setCellStyle
(
dataStyle
);
Cell
dataCell14
=
dataRow
.
createCell
(
columnNum
++);
dataCell14
.
setCellValue
(
orderDetail
.
getOnlinePay
()
!=
null
?
orderDetail
.
getOnlinePay
()
:
""
);
dataCell14
.
setCellStyle
(
dataStyle
);
}
}
// 自动调整列宽
for
(
int
i
=
0
;
i
<
15
;
i
++)
{
sheet
.
autoSizeColumn
(
i
);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream
outputStream
=
new
ByteArrayOutputStream
();
workbook
.
write
(
outputStream
);
workbook
.
close
();
return
outputStream
;
}
public
ByteArrayOutputStream
generateOrderSettlementExcelBySku
(
SettlementRequestDto
settlementRequest
)
{
...
...
@@ -541,4 +1127,364 @@ public class SettlementServiceImpl implements SettlementService {
}
@Override
public
ByteArrayOutputStream
exportSeparateMealsExcel
(
QueryOrderDto
queryOrderDto
)
{
// 参数校验
if
(
queryOrderDto
==
null
)
{
throw
BusinessException
.
build
(
ErrorCodeEnum
.
GENERATE_EXCEL_ERROR
);
}
final
int
enterpriseId
=
queryOrderDto
.
getEnterpriseId
();
// 查询订单列表
final
var
queryClientCustomerOrdersByConditionRpcResponse
=
orderServiceRpcClient
.
queryClientCustomerOrdersByCondition
(
queryOrderDto
);
// 今天开始时间的时间戳(毫秒)
final
long
todayStartTimestamp
=
LocalDate
.
now
().
atStartOfDay
()
.
atZone
(
ZoneId
.
systemDefault
())
.
toInstant
()
.
toEpochMilli
();
final
var
orderList
=
queryClientCustomerOrdersByConditionRpcResponse
.
getResponsesList
()
.
stream
()
.
filter
(
e
->
{
boolean
payStatusMatch
=
e
.
getPayStatus
()
==
PayStatusEnum
.
SUCCEED
||
e
.
getPayStatus
()
==
PayStatusEnum
.
PAY_CANCELED
;
// 过滤时间:只查询今天和以后的订单
boolean
timeMatch
=
e
.
getMealTime
()
>=
todayStartTimestamp
;
return
payStatusMatch
&&
timeMatch
;
})
.
toList
();
if
(
orderList
.
isEmpty
())
{
log
.
warn
(
"未查询到订单数据,enterpriseId: {}"
,
enterpriseId
);
return
createEmptyExcelBySeparateMeal
();
}
// 获取订单IDs
List
<
Integer
>
orderIds
=
orderList
.
stream
()
.
map
(
SingleClientCustomerOrderRpcResponse:
:
getId
)
.
collect
(
Collectors
.
toList
());
// 构建订单映射
final
var
orderMap
=
orderList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
o
->
o
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleClientCustomerOrderRpcResponse:
:
getId
,
o
->
o
,
(
o1
,
o2
)
->
o1
));
// 查询订单详情
final
var
orderDetailList
=
orderServiceRpcClient
.
getOrderDetailsByOrderIds
(
orderIds
);
if
(
orderDetailList
==
null
||
orderDetailList
.
isEmpty
())
{
log
.
warn
(
"未查询到订单详情数据,orderIds: {}"
,
orderIds
);
return
createEmptyExcelBySeparateMeal
();
}
// 订单详情按订单ID分组
final
var
orderDetailGroupByOrderId
=
orderDetailList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
d
->
!
d
.
getServeStatus
().
equals
(
ServeStatusEnum
.
SERVE_REJECT
))
.
collect
(
Collectors
.
groupingBy
(
SingleClientCustomerOrderDetailRpcResponse:
:
getOrderId
));
// 获取SKU数据
List
<
Integer
>
skuIds
=
orderDetailList
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
d
->
!
d
.
getServeStatus
().
equals
(
ServeStatusEnum
.
SERVE_REJECT
))
.
map
(
SingleClientCustomerOrderDetailRpcResponse:
:
getSkuId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
final
var
skuResponse
=
skuServiceRpcClient
.
getDishSkusByIds
(
skuIds
);
final
List
<
SingleDishSkuByIdsRpcResponse
>
skus
=
skuResponse
!=
null
?
skuResponse
.
getResponseList
()
:
new
ArrayList
<>();
final
var
skuMap
=
skus
.
stream
()
.
collect
(
Collectors
.
toMap
(
SingleDishSkuByIdsRpcResponse:
:
getId
,
s
->
s
,
(
s1
,
s2
)
->
s1
));
// 获取餐别数据
final
var
mealResponse
=
mealServiceRpcClient
.
getAllMeals
(
enterpriseId
);
final
List
<
SingleMealRpcResponse
>
meals
=
mealResponse
!=
null
?
mealResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
mealMap
=
meals
.
stream
()
.
filter
(
Objects:
:
nonNull
)
.
filter
(
m
->
m
.
getId
()
!=
0
)
.
collect
(
Collectors
.
toMap
(
SingleMealRpcResponse:
:
getId
,
m
->
m
,
(
m1
,
m2
)
->
m1
));
// 获取菜单数据
List
<
Integer
>
menuIds
=
orderList
.
stream
()
.
map
(
SingleClientCustomerOrderRpcResponse:
:
getMenuId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
final
var
menuResponse
=
menuServiceRpcClient
.
getMenusByIds
(
enterpriseId
,
menuIds
);
final
List
<
SingleMenuRpcResponse
>
menuList
=
menuResponse
!=
null
?
menuResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
menuMap
=
menuList
.
stream
()
.
collect
(
Collectors
.
toMap
(
SingleMenuRpcResponse:
:
getId
,
m
->
m
,
(
m1
,
m2
)
->
m1
));
// 获取菜单详情数据
final
var
menuDetailResponse
=
menuServiceRpcClient
.
queryMenuDetailsByMenuIds
(
enterpriseId
,
menuIds
);
final
List
<
SingleMenuDetailRpcResponse
>
menuDetailList
=
menuDetailResponse
!=
null
?
menuDetailResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
menuDetailMap
=
menuDetailList
.
stream
()
.
collect
(
Collectors
.
toMap
(
SingleMenuDetailRpcResponse:
:
getId
,
m
->
m
,
(
m1
,
m2
)
->
m1
));
// 获取客户数据
List
<
Integer
>
customerIds
=
orderList
.
stream
()
.
map
(
SingleClientCustomerOrderRpcResponse:
:
getCustomerId
)
.
filter
(
id
->
id
!=
0
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
final
var
customerResponse
=
clientCustomerServiceRpcClient
.
getClientCustomersByIds
(
enterpriseId
,
customerIds
);
final
List
<
SingleClientCustomerRpcResponse
>
customers
=
customerResponse
!=
null
?
customerResponse
.
getResponsesList
()
:
new
ArrayList
<>();
final
var
customerMap
=
customers
.
stream
()
.
collect
(
Collectors
.
toMap
(
SingleClientCustomerRpcResponse:
:
getId
,
c
->
c
,
(
c1
,
c2
)
->
c1
));
// 构建分餐表明细
final
var
mealDetails
=
new
ArrayList
<
SeparateMealDetail
>();
for
(
Integer
orderId
:
orderIds
)
{
final
var
orderDetails
=
orderDetailGroupByOrderId
.
getOrDefault
(
orderId
,
Collections
.
emptyList
());
final
var
order
=
orderMap
.
get
(
orderId
);
// 订单为空则跳过
if
(
order
==
null
)
{
log
.
warn
(
"订单不存在,orderId: {}"
,
orderId
);
continue
;
}
// 获取菜单信息
final
var
menu
=
menuMap
.
get
(
order
.
getMenuId
());
final
String
menuName
=
menu
!=
null
?
menu
.
getName
()
:
""
;
// 获取客户信息
final
var
customer
=
customerMap
.
get
(
order
.
getCustomerId
());
final
String
customerName
=
customer
!=
null
?
customer
.
getName
()
:
""
;
// 安全获取房间号
String
roomNo
=
getRoomNoSafely
(
order
);
// 处理每个订单详情
for
(
SingleClientCustomerOrderDetailRpcResponse
orderDetail
:
orderDetails
)
{
if
(
orderDetail
==
null
)
{
continue
;
}
// 安全获取餐别名称
String
mealName
=
getMealNameSafely
(
orderDetail
,
menuDetailMap
,
mealMap
);
// 安全获取SKU名称
String
skuName
=
getSkuNameSafely
(
orderDetail
,
skuMap
);
// 安全获取忌口信息(列表转字符串)
List
<
String
>
avoidsList
=
getAvoidsSafely
(
order
);
String
avoidsStr
=
String
.
join
(
", "
,
avoidsList
);
String
remark
=
order
.
getRemark
();
String
avoidRemark
=
order
.
getAvoidRemark
();
String
combinedRemark
=
""
;
if
(!
remark
.
isEmpty
()
&&
!
avoidRemark
.
isEmpty
())
{
combinedRemark
=
remark
+
";"
+
avoidRemark
;
}
else
if
(!
remark
.
isEmpty
())
{
combinedRemark
=
remark
;
}
else
if
(!
avoidRemark
.
isEmpty
())
{
combinedRemark
=
avoidRemark
;
}
// 构建分餐表明细
SeparateMealDetail
mealDetail
=
SeparateMealDetail
.
builder
()
.
orderId
(
orderId
)
.
mealName
(
mealName
)
.
roomNo
(
roomNo
)
.
customerName
(
customerName
)
.
menuName
(
menuName
)
.
skuName
(
skuName
)
.
count
(
orderDetail
.
getCount
()
!=
0
?
orderDetail
.
getCount
()
:
0
)
.
avoids
(
avoidsStr
)
.
remark
(
combinedRemark
)
.
build
();
mealDetails
.
add
(
mealDetail
);
}
}
// 构建分餐表数据
final
var
separateMealDataDto
=
SeparateMealDataDto
.
builder
()
.
mealDetails
(
mealDetails
)
.
build
();
// 生成Excel
try
{
return
writeToExcelBySeparateMeal
(
separateMealDataDto
);
}
catch
(
IOException
e
)
{
log
.
error
(
"生成分餐表Excel失败"
,
e
);
throw
BusinessException
.
build
(
ErrorCodeEnum
.
GENERATE_EXCEL_ERROR
);
}
}
/**
* 生成分餐表Excel
*/
private
static
ByteArrayOutputStream
writeToExcelBySeparateMeal
(
SeparateMealDataDto
separateMealDataDto
)
throws
IOException
{
Workbook
workbook
=
new
XSSFWorkbook
();
Sheet
sheet
=
workbook
.
createSheet
(
"分餐表"
);
// 创建标题样式(合并单元格标题)
CellStyle
titleStyle
=
workbook
.
createCellStyle
();
titleStyle
.
setAlignment
(
HorizontalAlignment
.
CENTER
);
titleStyle
.
setVerticalAlignment
(
VerticalAlignment
.
CENTER
);
titleStyle
.
setBorderTop
(
BorderStyle
.
THIN
);
titleStyle
.
setBorderBottom
(
BorderStyle
.
THIN
);
titleStyle
.
setBorderLeft
(
BorderStyle
.
THIN
);
titleStyle
.
setBorderRight
(
BorderStyle
.
THIN
);
titleStyle
.
setTopBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
titleStyle
.
setBottomBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
titleStyle
.
setLeftBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
titleStyle
.
setRightBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
Font
titleFont
=
workbook
.
createFont
();
titleFont
.
setBold
(
true
);
titleFont
.
setFontHeightInPoints
((
short
)
16
);
titleStyle
.
setFont
(
titleFont
);
// 创建表头样式(黑色边框)
CellStyle
headerStyle
=
workbook
.
createCellStyle
();
headerStyle
.
setBorderTop
(
BorderStyle
.
THIN
);
headerStyle
.
setBorderBottom
(
BorderStyle
.
THIN
);
headerStyle
.
setBorderLeft
(
BorderStyle
.
THIN
);
headerStyle
.
setBorderRight
(
BorderStyle
.
THIN
);
headerStyle
.
setTopBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
headerStyle
.
setBottomBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
headerStyle
.
setLeftBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
headerStyle
.
setRightBorderColor
(
IndexedColors
.
BLACK
.
getIndex
());
// 创建数据行样式(浅灰色边框)
CellStyle
dataStyle
=
workbook
.
createCellStyle
();
dataStyle
.
setBorderTop
(
BorderStyle
.
THIN
);
dataStyle
.
setBorderBottom
(
BorderStyle
.
THIN
);
dataStyle
.
setBorderLeft
(
BorderStyle
.
THIN
);
dataStyle
.
setBorderRight
(
BorderStyle
.
THIN
);
dataStyle
.
setTopBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
dataStyle
.
setBottomBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
dataStyle
.
setLeftBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
dataStyle
.
setRightBorderColor
(
IndexedColors
.
GREY_25_PERCENT
.
getIndex
());
int
rowNum
=
0
;
// 第一行:创建合并单元格标题
Row
mainTitleRow
=
sheet
.
createRow
(
rowNum
++);
Cell
mainTitleCell
=
mainTitleRow
.
createCell
(
0
);
mainTitleCell
.
setCellValue
(
"住院客户分餐表"
);
mainTitleCell
.
setCellStyle
(
titleStyle
);
// 合并第一行的8列
CellRangeAddress
titleRegion
=
new
CellRangeAddress
(
0
,
0
,
0
,
7
);
sheet
.
addMergedRegion
(
titleRegion
);
// 为合并区域设置边框
RegionUtil
.
setBorderTop
(
BorderStyle
.
THIN
,
titleRegion
,
sheet
);
RegionUtil
.
setBorderBottom
(
BorderStyle
.
THIN
,
titleRegion
,
sheet
);
RegionUtil
.
setBorderLeft
(
BorderStyle
.
THIN
,
titleRegion
,
sheet
);
RegionUtil
.
setBorderRight
(
BorderStyle
.
THIN
,
titleRegion
,
sheet
);
RegionUtil
.
setTopBorderColor
(
IndexedColors
.
BLACK
.
getIndex
(),
titleRegion
,
sheet
);
RegionUtil
.
setBottomBorderColor
(
IndexedColors
.
BLACK
.
getIndex
(),
titleRegion
,
sheet
);
RegionUtil
.
setLeftBorderColor
(
IndexedColors
.
BLACK
.
getIndex
(),
titleRegion
,
sheet
);
RegionUtil
.
setRightBorderColor
(
IndexedColors
.
BLACK
.
getIndex
(),
titleRegion
,
sheet
);
// 第二行:创建表头
Row
titleRow
=
sheet
.
createRow
(
rowNum
++);
int
columnNum
=
0
;
Cell
cell0
=
titleRow
.
createCell
(
columnNum
++);
cell0
.
setCellValue
(
"餐别"
);
cell0
.
setCellStyle
(
headerStyle
);
Cell
cell1
=
titleRow
.
createCell
(
columnNum
++);
cell1
.
setCellValue
(
"房间号"
);
cell1
.
setCellStyle
(
headerStyle
);
Cell
cell2
=
titleRow
.
createCell
(
columnNum
++);
cell2
.
setCellValue
(
"客户姓名"
);
cell2
.
setCellStyle
(
headerStyle
);
Cell
cell3
=
titleRow
.
createCell
(
columnNum
++);
cell3
.
setCellValue
(
"餐单名称"
);
cell3
.
setCellStyle
(
headerStyle
);
Cell
cell4
=
titleRow
.
createCell
(
columnNum
++);
cell4
.
setCellValue
(
"菜品名称"
);
cell4
.
setCellStyle
(
headerStyle
);
Cell
cell5
=
titleRow
.
createCell
(
columnNum
++);
cell5
.
setCellValue
(
"菜品数量"
);
cell5
.
setCellStyle
(
headerStyle
);
Cell
cell6
=
titleRow
.
createCell
(
columnNum
++);
cell6
.
setCellValue
(
"忌口信息"
);
cell6
.
setCellStyle
(
headerStyle
);
Cell
cell7
=
titleRow
.
createCell
(
columnNum
++);
cell7
.
setCellValue
(
"备注"
);
cell7
.
setCellStyle
(
headerStyle
);
// 填充数据
final
var
mealDetails
=
separateMealDataDto
.
getMealDetails
();
if
(
mealDetails
!=
null
)
{
for
(
SeparateMealDetail
mealDetail
:
mealDetails
)
{
Row
dataRow
=
sheet
.
createRow
(
rowNum
++);
columnNum
=
0
;
Cell
dataCell0
=
dataRow
.
createCell
(
columnNum
++);
dataCell0
.
setCellValue
(
mealDetail
.
getMealName
()
!=
null
?
mealDetail
.
getMealName
()
:
""
);
dataCell0
.
setCellStyle
(
dataStyle
);
Cell
dataCell1
=
dataRow
.
createCell
(
columnNum
++);
dataCell1
.
setCellValue
(
mealDetail
.
getRoomNo
()
!=
null
?
mealDetail
.
getRoomNo
()
:
""
);
dataCell1
.
setCellStyle
(
dataStyle
);
Cell
dataCell2
=
dataRow
.
createCell
(
columnNum
++);
dataCell2
.
setCellValue
(
mealDetail
.
getCustomerName
()
!=
null
?
mealDetail
.
getCustomerName
()
:
""
);
dataCell2
.
setCellStyle
(
dataStyle
);
Cell
dataCell3
=
dataRow
.
createCell
(
columnNum
++);
dataCell3
.
setCellValue
(
mealDetail
.
getMenuName
()
!=
null
?
mealDetail
.
getMenuName
()
:
""
);
dataCell3
.
setCellStyle
(
dataStyle
);
Cell
dataCell4
=
dataRow
.
createCell
(
columnNum
++);
dataCell4
.
setCellValue
(
mealDetail
.
getSkuName
()
!=
null
?
mealDetail
.
getSkuName
()
:
""
);
dataCell4
.
setCellStyle
(
dataStyle
);
Cell
dataCell5
=
dataRow
.
createCell
(
columnNum
++);
dataCell5
.
setCellValue
(
mealDetail
.
getCount
()
!=
null
?
mealDetail
.
getCount
()
:
0
);
dataCell5
.
setCellStyle
(
dataStyle
);
Cell
dataCell6
=
dataRow
.
createCell
(
columnNum
++);
dataCell6
.
setCellValue
(
mealDetail
.
getAvoids
()
!=
null
?
mealDetail
.
getAvoids
()
:
""
);
dataCell6
.
setCellStyle
(
dataStyle
);
Cell
dataCell7
=
dataRow
.
createCell
(
columnNum
++);
dataCell7
.
setCellValue
(
mealDetail
.
getRemark
()
!=
null
?
mealDetail
.
getRemark
()
:
""
);
dataCell7
.
setCellStyle
(
dataStyle
);
}
}
// 自动调整列宽
for
(
int
i
=
0
;
i
<
8
;
i
++)
{
sheet
.
autoSizeColumn
(
i
);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream
outputStream
=
new
ByteArrayOutputStream
();
workbook
.
write
(
outputStream
);
workbook
.
close
();
return
outputStream
;
}
/**
* 创建空的分餐表Excel(无数据)
*/
private
static
ByteArrayOutputStream
createEmptyExcelBySeparateMeal
()
{
try
{
SeparateMealDataDto
emptyData
=
SeparateMealDataDto
.
builder
()
.
mealDetails
(
new
ArrayList
<>())
.
build
();
return
writeToExcelBySeparateMeal
(
emptyData
);
}
catch
(
IOException
e
)
{
log
.
error
(
"创建空分餐表Excel失败"
,
e
);
throw
BusinessException
.
build
(
ErrorCodeEnum
.
GENERATE_EXCEL_ERROR
);
}
}
}
...
...
src/main/java/com/infoloop/tianting/streamController/SettlementController.java
View file @
2f8b7a6
...
...
@@ -2,6 +2,8 @@ package com.infoloop.tianting.streamController;
import
cn.dev33.satoken.annotation.SaIgnore
;
import
com.github.xiaoymin.knife4j.annotations.ApiSupport
;
import
com.infoloop.tianting.enums.SettlementDimensionEnum
;
import
com.infoloop.tianting.model.dto.OrderDbDTO
;
import
com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto
;
import
com.infoloop.tianting.service.SettlementService
;
import
io.swagger.annotations.Api
;
...
...
@@ -21,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
import
javax.validation.Valid
;
import
java.io.ByteArrayOutputStream
;
import
java.time.format.DateTimeFormatter
;
@Api
(
tags
=
"结算"
)
@ApiSupport
(
order
=
0
)
...
...
@@ -29,35 +32,59 @@ import java.io.ByteArrayOutputStream;
@RestController
@RequiredArgsConstructor
(
onConstructor
=
@__
(
@Autowired
))
public
class
SettlementController
{
private
final
SettlementService
settlementService
;
@SaIgnore
@ApiOperation
(
value
=
"企业端结算账单生成excel"
)
@PostMapping
(
"/enterprise/settlement/generate-excel"
)
@ResponseStatus
(
HttpStatus
.
OK
)
public
ResponseEntity
<
byte
[]>
enterpriseSettlementGenerateExcel
(
@Valid
@RequestBody
SettlementRequestDto
settlementRequestDto
)
{
ByteArrayOutputStream
outputStream
=
settlementService
.
generateOrderSettlementExcel
(
settlementRequestDto
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM
);
headers
.
setContentDispositionFormData
(
"attachment"
,
"订单数据.xlsx"
);
return
ResponseEntity
.
ok
()
.
headers
(
headers
)
.
body
(
outputStream
.
toByteArray
());
}
private
final
SettlementService
settlementService
;
@SaIgnore
@ApiOperation
(
value
=
"企业端结算账单生成excel"
)
@PostMapping
(
"/enterprise/settlement/generate-excel"
)
@ResponseStatus
(
HttpStatus
.
OK
)
public
ResponseEntity
<
byte
[]>
enterpriseSettlementGenerateExcel
(
@Valid
@RequestBody
SettlementRequestDto
settlementRequestDto
)
{
ByteArrayOutputStream
outputStream
=
settlementService
.
generateOrderSettlementExcel
(
settlementRequestDto
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM
);
headers
.
setContentDispositionFormData
(
"attachment"
,
"订单数据.xlsx"
);
return
ResponseEntity
.
ok
()
.
headers
(
headers
)
.
body
(
outputStream
.
toByteArray
());
}
@ApiOperation
(
value
=
"结算账单生成excel"
)
@PostMapping
(
"/settlement/generate-excel"
)
@ResponseStatus
(
HttpStatus
.
OK
)
public
ResponseEntity
<
byte
[]>
settlementGenerateExcel
(
@Valid
@RequestBody
SettlementRequestDto
settlementRequestDto
)
{
ByteArrayOutputStream
outputStream
=
settlementService
.
generateOrderSettlementExcel
(
settlementRequestDto
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM
);
headers
.
setContentDispositionFormData
(
"attachment"
,
"订单数据.xlsx"
);
return
ResponseEntity
.
ok
()
.
headers
(
headers
)
.
body
(
outputStream
.
toByteArray
());
public
ResponseEntity
<
byte
[]>
settlementGenerateExcel
(
@Valid
@RequestBody
SettlementRequestDto
settlementRequestDto
)
{
ByteArrayOutputStream
outputStream
=
settlementService
.
generateOrderSettlementExcel
(
settlementRequestDto
);
String
fileName
;
if
(
settlementRequestDto
.
getDimension
()
==
SettlementDimensionEnum
.
BY_ORDER
)
{
DateTimeFormatter
formatter
=
DateTimeFormatter
.
ofPattern
(
"yyyyMMdd"
);
String
startDate
=
settlementRequestDto
.
getTimeStart
().
format
(
formatter
);
String
endDate
=
settlementRequestDto
.
getTimeEnd
().
format
(
formatter
);
fileName
=
String
.
format
(
"结算报表_%s_%s.xlsx"
,
startDate
,
endDate
);
}
else
{
fileName
=
"订单数据.xlsx"
;
}
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM
);
headers
.
setContentDispositionFormData
(
"attachment"
,
fileName
);
return
ResponseEntity
.
ok
()
.
headers
(
headers
)
.
body
(
outputStream
.
toByteArray
());
}
@ApiOperation
(
value
=
"院区端订单导出"
)
@PostMapping
(
"/separateMeals/export"
)
@ResponseStatus
(
HttpStatus
.
OK
)
public
ResponseEntity
<
byte
[]>
exportSeparateMeals
(
@Valid
@RequestBody
OrderDbDTO
.
QueryOrderDto
queryOrderDto
)
{
ByteArrayOutputStream
outputStream
=
settlementService
.
exportSeparateMealsExcel
(
queryOrderDto
);
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM
);
headers
.
setContentDispositionFormData
(
"attachment"
,
"分餐表.xlsx"
);
return
ResponseEntity
.
ok
()
.
headers
(
headers
)
.
body
(
outputStream
.
toByteArray
());
}
}
...
...
src/main/proto/ClientCustomerOrderService.proto
View file @
2f8b7a6
...
...
@@ -89,6 +89,11 @@ enum OnlinePayEnum {
LEAVE_HOSPITAL
=
3
;
//出院
EMPLOYEE_CARD
=
4
;
//员工卡
PAPER_VERIFICATION
=
5
;
//纸质核销
CASH
=
6
;
//现金
MEAL_CARD
=
7
;
//餐卡
BAND_CARD
=
8
;
//银行卡
ALIPAY
=
9
;
//支付宝
WECHATPAY
=
10
;
//微信支付
}
enum
ServeStatusEnum
{
...
...
@@ -141,6 +146,7 @@ message SingleClientCustomerOrderRpcResponse {
bool
isAllocation
=
35
;
string
syncRoomNo
=
36
;
bool
isCanceled
=
37
;
string
avoidRemark
=
38
;
}
message
GetClientCustomerOrderByIdRpcRequest
{
...
...
@@ -385,6 +391,8 @@ message ClientCustomerOrderModification {
string
syncRoomNo
=
55
;
bool
shouldUpdateIsCanceled
=
56
;
bool
isCanceled
=
57
;
bool
shouldUpdateAvoidRemark
=
58
;
string
avoidRemark
=
59
;
}
message
UpdateClientCustomerOrderRpcRequest
{
...
...
Please
register
or
login
to post a comment