提交
This commit is contained in:
parent
9d9a94aac6
commit
2d00956212
@ -163,3 +163,55 @@ func (r *SplitAccountDeductionLogApi) DeleteSplitAccountDeductionLog(c *gin.Cont
|
|||||||
|
|
||||||
systemRes.OkWithMessage("删除成功", c)
|
systemRes.OkWithMessage("删除成功", c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSplitAccountDeductionLogSummary 获取分账扣钱日志汇总
|
||||||
|
func (r *SplitAccountDeductionLogApi) GetSplitAccountDeductionLogSummary(c *gin.Context) {
|
||||||
|
var req systemReq.GetSplitAccountDeductionLogSummaryRequest
|
||||||
|
|
||||||
|
if err := c.ShouldBindQuery(&req); err != nil {
|
||||||
|
ValidAndFail(constant.LoggerChannelRequest, "分账扣钱日志汇总请求参数异常", "参数错误: "+err.Error(), c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdBy := req.AboutId
|
||||||
|
if createdBy == "0" || createdBy == "1" {
|
||||||
|
createdBy = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := splitAccountDeductionLogService.GetSplitAccountDeductionLogSummary(req, createdBy, database.GetDB(c))
|
||||||
|
if err != nil {
|
||||||
|
utils.FailWithRequestLog(constant.LoggerChannelWork, "分账扣钱日志汇总异常", err, c, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code": 200,
|
||||||
|
"data": result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSplitAccountDeductionLogDetailList 获取分账扣钱日志详情列表
|
||||||
|
func (r *SplitAccountDeductionLogApi) GetSplitAccountDeductionLogDetailList(c *gin.Context) {
|
||||||
|
var req systemReq.GetSplitAccountDeductionLogDetailListRequest
|
||||||
|
|
||||||
|
if err := c.ShouldBindQuery(&req); err != nil {
|
||||||
|
ValidAndFail(constant.LoggerChannelRequest, "分账扣钱日志详情列表请求参数异常", "参数错误: "+err.Error(), c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
createdBy := req.AboutId
|
||||||
|
if createdBy == "0" || createdBy == "1" {
|
||||||
|
createdBy = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := splitAccountDeductionLogService.GetSplitAccountDeductionLogDetailList(req, createdBy, database.GetDB(c))
|
||||||
|
if err != nil {
|
||||||
|
utils.FailWithRequestLog(constant.LoggerChannelWork, "分账扣钱日志详情列表异常", err, c, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"code": 200,
|
||||||
|
"data": result,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ type BookInfo struct {
|
|||||||
Author string `json:"author" gorm:"size:100;not null;default:'';comment:作者"`
|
Author string `json:"author" gorm:"size:100;not null;default:'';comment:作者"`
|
||||||
Publishing string `json:"publishing" gorm:"size:50;not null;default:'';comment:出版社"`
|
Publishing string `json:"publishing" gorm:"size:50;not null;default:'';comment:出版社"`
|
||||||
PublicationTime int64 `json:"publication_time" gorm:"type:bigint;not null;default:0;comment:出版日期时间戳"`
|
PublicationTime int64 `json:"publication_time" gorm:"type:bigint;not null;default:0;comment:出版日期时间戳"`
|
||||||
|
PublicationDate string `json:"publication_date" gorm:"size:10;not null;default:'';comment:出版日期年-月"`
|
||||||
Binding string `json:"binding" gorm:"size:10;not null;default:'';comment:装帧"`
|
Binding string `json:"binding" gorm:"size:10;not null;default:'';comment:装帧"`
|
||||||
PagesCount int64 `json:"pages_count" gorm:"not null;default:0;comment:页数"`
|
PagesCount int64 `json:"pages_count" gorm:"not null;default:0;comment:页数"`
|
||||||
WordsCount int64 `json:"words_count" gorm:"not null;default:0;comment:字数"`
|
WordsCount int64 `json:"words_count" gorm:"not null;default:0;comment:字数"`
|
||||||
|
|||||||
@ -6,6 +6,7 @@ type OutboundOrder struct {
|
|||||||
OutNo string `json:"out_no" gorm:"size:100;not null;default:'';uniqueIndex;comment:出库单号"`
|
OutNo string `json:"out_no" gorm:"size:100;not null;default:'';uniqueIndex;comment:出库单号"`
|
||||||
WaveTaskID int64 `json:"wave_task_id" gorm:"not null;default:0;index;comment:波次任务ID"`
|
WaveTaskID int64 `json:"wave_task_id" gorm:"not null;default:0;index;comment:波次任务ID"`
|
||||||
WarehouseID int64 `json:"warehouse_id" gorm:"not null;default:0;comment:仓库ID"`
|
WarehouseID int64 `json:"warehouse_id" gorm:"not null;default:0;comment:仓库ID"`
|
||||||
|
ShopId int64 `json:"shop_id" gorm:"type:bigint(20);default:0;comment:店铺ID"`
|
||||||
CustomerID int64 `json:"customer_id" gorm:"not null;default:0;comment:客户ID"`
|
CustomerID int64 `json:"customer_id" gorm:"not null;default:0;comment:客户ID"`
|
||||||
TotalQuantity int64 `json:"total_quantity" gorm:"not null;default:0;comment:出库总数量"`
|
TotalQuantity int64 `json:"total_quantity" gorm:"not null;default:0;comment:出库总数量"`
|
||||||
TotalAmount int64 `json:"total_amount" gorm:"not null;default:0;comment:出库总金额(分)"`
|
TotalAmount int64 `json:"total_amount" gorm:"not null;default:0;comment:出库总金额(分)"`
|
||||||
|
|||||||
@ -7,6 +7,7 @@ type ReceivingOrder struct {
|
|||||||
PurchaseOrderID int64 `json:"purchase_order_id" gorm:"not null;default:0;index;comment:关联采购单ID(可为空,支持无来源入库)"`
|
PurchaseOrderID int64 `json:"purchase_order_id" gorm:"not null;default:0;index;comment:关联采购单ID(可为空,支持无来源入库)"`
|
||||||
WaveTaskID int64 `json:"wave_task_id" gorm:"not null;default:0;index;comment:关联波次任务ID"`
|
WaveTaskID int64 `json:"wave_task_id" gorm:"not null;default:0;index;comment:关联波次任务ID"`
|
||||||
WarehouseID int64 `json:"warehouse_id" gorm:"not null;default:0;index;comment:入库仓库ID"`
|
WarehouseID int64 `json:"warehouse_id" gorm:"not null;default:0;index;comment:入库仓库ID"`
|
||||||
|
ShopId int64 `json:"shop_id" gorm:"type:bigint(20);default:0;comment:店铺ID"`
|
||||||
SupplierID int64 `json:"supplier_id" gorm:"not null;default:0;comment:供应商ID"`
|
SupplierID int64 `json:"supplier_id" gorm:"not null;default:0;comment:供应商ID"`
|
||||||
ReceivingDate int64 `json:"receiving_date" gorm:"not null;default:0;comment:入库日期时间戳(秒)"`
|
ReceivingDate int64 `json:"receiving_date" gorm:"not null;default:0;comment:入库日期时间戳(秒)"`
|
||||||
Status int8 `json:"status" gorm:"not null;default:1;index;comment:状态(1:待收货/pending, 2:验收中/checking, 3:已完成/completed, 4:已取消/cancelled)"`
|
Status int8 `json:"status" gorm:"not null;default:1;index;comment:状态(1:待收货/pending, 2:验收中/checking, 3:已完成/completed, 4:已取消/cancelled)"`
|
||||||
|
|||||||
@ -39,3 +39,16 @@ type UpdateSplitAccountDeductionLogRequest struct {
|
|||||||
type DeleteSplitAccountDeductionLogRequest struct {
|
type DeleteSplitAccountDeductionLogRequest struct {
|
||||||
ID int64 `form:"id" binding:"required"`
|
ID int64 `form:"id" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSplitAccountDeductionLogSummaryRequest 获取分账扣钱日志汇总请求
|
||||||
|
type GetSplitAccountDeductionLogSummaryRequest struct {
|
||||||
|
AboutId string `form:"about_id"` // 用户about_id,作为created_by
|
||||||
|
PageNum int `form:"page_num"` // 页码
|
||||||
|
PageSize int `form:"page_size"` // 每页数量
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSplitAccountDeductionLogDetailListRequest 获取分账扣钱日志详情列表请求
|
||||||
|
type GetSplitAccountDeductionLogDetailListRequest struct {
|
||||||
|
AboutId string `form:"about_id"` // 用户about_id,作为created_by
|
||||||
|
BusinessNo string `form:"business_no"` // 订单号
|
||||||
|
}
|
||||||
|
|||||||
@ -210,6 +210,9 @@ type ProductInventoryWarehouse struct {
|
|||||||
WarehouseID int64 `json:"warehouse_id"` // 仓库ID
|
WarehouseID int64 `json:"warehouse_id"` // 仓库ID
|
||||||
WarehouseName string `json:"warehouse_name"` // 仓库名称
|
WarehouseName string `json:"warehouse_name"` // 仓库名称
|
||||||
WarehouseCode string `json:"warehouse_code"` // 仓库编码
|
WarehouseCode string `json:"warehouse_code"` // 仓库编码
|
||||||
|
LocationID int64 `json:"location_id"` // 库位ID
|
||||||
|
LocationName string `json:"location_name"` // 库位名称
|
||||||
|
Logistics *LogisticsResponse `json:"logistics,omitempty"` // 物流模板信息
|
||||||
ProductName string `json:"product_name"` // 商品名称
|
ProductName string `json:"product_name"` // 商品名称
|
||||||
ISBN string `json:"isbn"` // ISBN/条码
|
ISBN string `json:"isbn"` // ISBN/条码
|
||||||
Appearance int64 `json:"appearance"` // 品相
|
Appearance int64 `json:"appearance"` // 品相
|
||||||
|
|||||||
@ -29,6 +29,24 @@ type SplitAccountDeductionLogItem struct {
|
|||||||
UpdatedAt int64 `json:"updated_at"`
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SplitAccountDeductionLogSummaryItem 分账扣钱日志汇总项
|
||||||
|
type SplitAccountDeductionLogSummaryItem struct {
|
||||||
|
BusinessNo string `json:"business_no"`
|
||||||
|
ConfigName string `json:"config_name"`
|
||||||
|
DeductionDetails interface{} `json:"deduction_details"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitAccountDeductionLogSummaryResponse 分账扣钱日志汇总响应
|
||||||
|
type SplitAccountDeductionLogSummaryResponse struct {
|
||||||
|
List []SplitAccountDeductionLogSummaryItem `json:"list"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"page_size"`
|
||||||
|
}
|
||||||
|
|
||||||
// ConvertSplitAccountDeductionLogToItem 将模型转换为响应项
|
// ConvertSplitAccountDeductionLogToItem 将模型转换为响应项
|
||||||
func ConvertSplitAccountDeductionLogToItem(log models.SplitAccountDeductionLog) SplitAccountDeductionLogItem {
|
func ConvertSplitAccountDeductionLogToItem(log models.SplitAccountDeductionLog) SplitAccountDeductionLogItem {
|
||||||
var deductionDetails interface{}
|
var deductionDetails interface{}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ package response
|
|||||||
type DashboardStatistResponse struct {
|
type DashboardStatistResponse struct {
|
||||||
TotalReceivingCount int64 `json:"total_receiving_count"` // 总入库次数
|
TotalReceivingCount int64 `json:"total_receiving_count"` // 总入库次数
|
||||||
TotalOutboundCount int64 `json:"total_outbound_count"` // 总出库次数
|
TotalOutboundCount int64 `json:"total_outbound_count"` // 总出库次数
|
||||||
TotalSaleCount int64 `json:"total_sale_count"` // 今日商品总数
|
TotalSaleCount int64 `json:"total_sale_count"` // 今日销售数
|
||||||
UserStats []UserStatItem `json:"user_stats"` // 个人统计数据
|
UserStats []UserStatItem `json:"user_stats"` // 个人统计数据
|
||||||
ProductTotal int64 `json:"product_total"` // 商品总量
|
ProductTotal int64 `json:"product_total"` // 商品总量
|
||||||
InventoryTotal int64 `json:"inventory_total"` // 库存量
|
InventoryTotal int64 `json:"inventory_total"` // 库存量
|
||||||
|
|||||||
@ -5,6 +5,7 @@ type ShippingOrder struct {
|
|||||||
ID int64 `json:"id" gorm:"primarykey;comment:主键ID"`
|
ID int64 `json:"id" gorm:"primarykey;comment:主键ID"`
|
||||||
ShippingNo string `json:"shipping_no" gorm:"size:64;not null;default:'';uniqueIndex;comment:发货单号"`
|
ShippingNo string `json:"shipping_no" gorm:"size:64;not null;default:'';uniqueIndex;comment:发货单号"`
|
||||||
CustomerID int64 `json:"customer_id" gorm:"not null;default:0;index;comment:客户ID"`
|
CustomerID int64 `json:"customer_id" gorm:"not null;default:0;index;comment:客户ID"`
|
||||||
|
ShopId int64 `json:"shop_id" gorm:"type:bigint(20);default:0;comment:店铺ID"`
|
||||||
Status int8 `json:"status" gorm:"not null;default:1;index;comment:状态:1=待发货 2=已发货 3=已签收 4=已取消"`
|
Status int8 `json:"status" gorm:"not null;default:1;index;comment:状态:1=待发货 2=已发货 3=已签收 4=已取消"`
|
||||||
ShippingTime *int64 `json:"shipping_time" gorm:"type:bigint;comment:发货时间(时间戳秒)"`
|
ShippingTime *int64 `json:"shipping_time" gorm:"type:bigint;comment:发货时间(时间戳秒)"`
|
||||||
ExpectedArriveTime *int64 `json:"expected_arrive_time" gorm:"type:bigint;comment:预计到达时间(时间戳秒)"`
|
ExpectedArriveTime *int64 `json:"expected_arrive_time" gorm:"type:bigint;comment:预计到达时间(时间戳秒)"`
|
||||||
|
|||||||
@ -35,6 +35,7 @@ var locationImportApi = &controllers.LocationImportApi{}
|
|||||||
var outTaskApi = &controllers.OutTaskApi{}
|
var outTaskApi = &controllers.OutTaskApi{}
|
||||||
var logisticsApi = &controllers.LogisticsApi{}
|
var logisticsApi = &controllers.LogisticsApi{}
|
||||||
var statistApi = &controllers.StatistApi{}
|
var statistApi = &controllers.StatistApi{}
|
||||||
|
var storeInfoApi = &controllers.StoreInfoApi{}
|
||||||
var userTypeApi = &controllers.UserTypeApi{}
|
var userTypeApi = &controllers.UserTypeApi{}
|
||||||
var splitAccountConfigApi = &controllers.SplitAccountConfigApi{}
|
var splitAccountConfigApi = &controllers.SplitAccountConfigApi{}
|
||||||
var splitAccountDeductionLogApi = &controllers.SplitAccountDeductionLogApi{}
|
var splitAccountDeductionLogApi = &controllers.SplitAccountDeductionLogApi{}
|
||||||
@ -112,6 +113,14 @@ func initRouter() (r *gin.Engine) {
|
|||||||
sign.POST("/logistics/cancel", cancelLogisticsApi.CancelLogistics) // 取消物流单号
|
sign.POST("/logistics/cancel", cancelLogisticsApi.CancelLogistics) // 取消物流单号
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分账扣款日志签名查询接口(仅签名认证,无需JWT)
|
||||||
|
splitAccountSign := api.Group("")
|
||||||
|
splitAccountSign.Use(middleware.APISign())
|
||||||
|
{
|
||||||
|
splitAccountSign.GET("/split-account-deduction-log/summary", splitAccountDeductionLogApi.GetSplitAccountDeductionLogSummary) // 获取分账扣钱日志汇总
|
||||||
|
splitAccountSign.GET("/split-account-deduction-log/detail-list", splitAccountDeductionLogApi.GetSplitAccountDeductionLogDetailList) // 获取分账扣钱日志详情列表
|
||||||
|
}
|
||||||
|
|
||||||
// 需要认证(JWT)但不签名验证的接口
|
// 需要认证(JWT)但不签名验证的接口
|
||||||
authOnly := api.Group("")
|
authOnly := api.Group("")
|
||||||
authOnly.Use(middleware.JWTAuth())
|
authOnly.Use(middleware.JWTAuth())
|
||||||
@ -295,6 +304,7 @@ func initRouter() (r *gin.Engine) {
|
|||||||
auth.GET("/dashboard/statist", statistApi.DashboardStatist) // 仪表盘统计
|
auth.GET("/dashboard/statist", statistApi.DashboardStatist) // 仪表盘统计
|
||||||
auth.GET("/dashboard/warehouse", statistApi.GetWarehouseStatist) // 获取仓库统计
|
auth.GET("/dashboard/warehouse", statistApi.GetWarehouseStatist) // 获取仓库统计
|
||||||
auth.GET("/dashboard/order", statistApi.GetOrderStatist) // 获取订单统计
|
auth.GET("/dashboard/order", statistApi.GetOrderStatist) // 获取订单统计
|
||||||
|
auth.GET("/dashboard/store-info", storeInfoApi.StoreInfo) // 店铺统计
|
||||||
|
|
||||||
// 管理员接口
|
// 管理员接口
|
||||||
admin := auth.Group("/admin")
|
admin := auth.Group("/admin")
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
systemRes "psi/models/response"
|
systemRes "psi/models/response"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BookService struct{}
|
type BookService struct{}
|
||||||
@ -159,6 +160,16 @@ func (s *BookService) doBook(data systemReq.AddBookRequest) (int64, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// publication_time 兼容秒级和毫秒级时间戳,格式化为 "年-月"
|
||||||
|
var publicationDate string
|
||||||
|
if data.PublicationTime > 0 {
|
||||||
|
ts := data.PublicationTime
|
||||||
|
if ts > 1e12 { // 毫秒级时间戳
|
||||||
|
ts /= 1000
|
||||||
|
}
|
||||||
|
publicationDate = time.Unix(ts, 0).Format("2006-01")
|
||||||
|
}
|
||||||
|
|
||||||
book := models.BookInfo{
|
book := models.BookInfo{
|
||||||
Fid: data.Fid,
|
Fid: data.Fid,
|
||||||
Type: data.Type,
|
Type: data.Type,
|
||||||
@ -169,6 +180,7 @@ func (s *BookService) doBook(data systemReq.AddBookRequest) (int64, error) {
|
|||||||
Author: data.Author,
|
Author: data.Author,
|
||||||
Publishing: data.Publisher,
|
Publishing: data.Publisher,
|
||||||
PublicationTime: data.PublicationTime,
|
PublicationTime: data.PublicationTime,
|
||||||
|
PublicationDate: publicationDate,
|
||||||
Binding: data.BindingLayout,
|
Binding: data.BindingLayout,
|
||||||
PagesCount: data.PageCount,
|
PagesCount: data.PageCount,
|
||||||
WordsCount: data.WordCount,
|
WordsCount: data.WordCount,
|
||||||
|
|||||||
@ -1419,27 +1419,121 @@ func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
var totalQuantity int64
|
var totalQuantity int64
|
||||||
|
var warehouses []systemRes.ProductInventoryWarehouse
|
||||||
|
|
||||||
// type=1: 按品相+ISBN+仓库分组后统计总数量
|
// type=1: 按品相+ISBN+仓库分组后统计总数量
|
||||||
if req.Type == 1 {
|
if req.Type == 1 {
|
||||||
type GroupStock struct {
|
type GroupStock struct {
|
||||||
|
WarehouseID int64 `gorm:"column:warehouse_id"`
|
||||||
|
WarehouseName string `gorm:"column:warehouse_name"`
|
||||||
|
WarehouseCode string `gorm:"column:warehouse_code"`
|
||||||
|
LocationID int64 `gorm:"column:location_id"`
|
||||||
|
LocationCode string `gorm:"column:location_code"`
|
||||||
TotalQuantity int64 `gorm:"column:total_quantity"`
|
TotalQuantity int64 `gorm:"column:total_quantity"`
|
||||||
|
LgID uint64 `gorm:"column:lg_id"`
|
||||||
|
LgTemplateName string `gorm:"column:lg_template_name"`
|
||||||
|
LgDeliveryProvince string `gorm:"column:lg_delivery_province"`
|
||||||
|
LgDeliveryCity string `gorm:"column:lg_delivery_city"`
|
||||||
|
LgDeliveryArea string `gorm:"column:lg_delivery_area"`
|
||||||
|
LgDeliveryAddress string `gorm:"column:lg_delivery_address"`
|
||||||
|
LgPricingMethod string `gorm:"column:lg_pricing_method"`
|
||||||
|
LgShipping string `gorm:"column:lg_shipping"`
|
||||||
|
LgFirWbv float64 `gorm:"column:lg_fir_wbv"`
|
||||||
|
LgFirPrice float64 `gorm:"column:lg_fir_price"`
|
||||||
|
LgContinueWbv float64 `gorm:"column:lg_continue_wbv"`
|
||||||
|
LgContinuePrice float64 `gorm:"column:lg_continue_price"`
|
||||||
|
LgContact string `gorm:"column:lg_contact"`
|
||||||
|
LgPhoneNumber uint64 `gorm:"column:lg_phone_number"`
|
||||||
|
LgFullAddress string `gorm:"column:lg_full_address"`
|
||||||
|
LgShippingRange string `gorm:"column:lg_shipping_range"`
|
||||||
|
LgWarehouseID uint64 `gorm:"column:lg_warehouse_id"`
|
||||||
|
LgRemark string `gorm:"column:lg_remark"`
|
||||||
|
LgStatus string `gorm:"column:lg_status"`
|
||||||
|
LgCreateTime *time.Time `gorm:"column:lg_create_time"`
|
||||||
|
LgUpdateTime *time.Time `gorm:"column:lg_update_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var groupList []GroupStock
|
var groupList []GroupStock
|
||||||
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计(可用量 = 总量 - 锁定量)
|
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计(可用量 = 总量 - 锁定量)
|
||||||
|
// 仓库和库位信息从 inventory_detail 表关联获取
|
||||||
databaseConn.Table("inventory").
|
databaseConn.Table("inventory").
|
||||||
Select(`
|
Select(`
|
||||||
COALESCE(SUM(inventory.quantity - inventory.locked_quantity), 0) as total_quantity
|
inventory.warehouse_id,
|
||||||
|
COALESCE(w.name, '') as warehouse_name,
|
||||||
|
COALESCE(w.code, '') as warehouse_code,
|
||||||
|
COALESCE(MIN(l.id), 0) as location_id,
|
||||||
|
COALESCE(MIN(l.code), '') as location_code,
|
||||||
|
COALESCE(SUM(inventory.quantity - inventory.locked_quantity), 0) as total_quantity,
|
||||||
|
COALESCE(logistics.id, 0) as lg_id,
|
||||||
|
COALESCE(logistics.template_name, '') as lg_template_name,
|
||||||
|
COALESCE(logistics.delivery_province, '') as lg_delivery_province,
|
||||||
|
COALESCE(logistics.delivery_city, '') as lg_delivery_city,
|
||||||
|
COALESCE(logistics.delivery_area, '') as lg_delivery_area,
|
||||||
|
COALESCE(logistics.delivery_address, '') as lg_delivery_address,
|
||||||
|
COALESCE(logistics.pricing_method, '') as lg_pricing_method,
|
||||||
|
COALESCE(logistics.shipping, '') as lg_shipping,
|
||||||
|
COALESCE(logistics.fir_wbv, 0) as lg_fir_wbv,
|
||||||
|
COALESCE(logistics.fir_price, 0) as lg_fir_price,
|
||||||
|
COALESCE(logistics.continue_wbv, 0) as lg_continue_wbv,
|
||||||
|
COALESCE(logistics.continue_price, 0) as lg_continue_price,
|
||||||
|
COALESCE(logistics.contact, '') as lg_contact,
|
||||||
|
COALESCE(logistics.phone_number, 0) as lg_phone_number,
|
||||||
|
COALESCE(logistics.full_address, '') as lg_full_address,
|
||||||
|
COALESCE(logistics.shipping_range, '') as lg_shipping_range,
|
||||||
|
COALESCE(logistics.warehouse_id, 0) as lg_warehouse_id,
|
||||||
|
COALESCE(logistics.remark, '') as lg_remark,
|
||||||
|
COALESCE(logistics.status, '') as lg_status,
|
||||||
|
logistics.create_time as lg_create_time,
|
||||||
|
logistics.update_time as lg_update_time
|
||||||
`).
|
`).
|
||||||
Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
|
Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
|
||||||
|
Joins("LEFT JOIN warehouse w ON inventory.warehouse_id = w.id AND w.is_del = 0").
|
||||||
|
Joins("LEFT JOIN logistics ON w.logistics_id = logistics.id AND logistics.del_flag = '0'").
|
||||||
|
Joins("LEFT JOIN inventory_detail d ON d.product_id = inventory.product_id AND d.warehouse_id = inventory.warehouse_id AND d.is_del = 0").
|
||||||
|
Joins("LEFT JOIN location l ON d.location_id = l.id AND l.is_del = 0").
|
||||||
Where("p.barcode = ? AND p.appearance = ? AND inventory.warehouse_id IS NOT NULL AND inventory.is_del = ?",
|
Where("p.barcode = ? AND p.appearance = ? AND inventory.warehouse_id IS NOT NULL AND inventory.is_del = ?",
|
||||||
product.Barcode, product.Appearance, 0).
|
product.Barcode, product.Appearance, 0).
|
||||||
Group("inventory.warehouse_id").
|
Group("inventory.warehouse_id, w.name, w.code").
|
||||||
Scan(&groupList)
|
Scan(&groupList)
|
||||||
|
|
||||||
// 累加所有分组的可用数量
|
// 累加所有分组的可用数量
|
||||||
for _, group := range groupList {
|
for _, group := range groupList {
|
||||||
totalQuantity += group.TotalQuantity
|
totalQuantity += group.TotalQuantity
|
||||||
|
var lg *systemRes.LogisticsResponse
|
||||||
|
if group.LgID > 0 {
|
||||||
|
lg = &systemRes.LogisticsResponse{
|
||||||
|
Id: group.LgID,
|
||||||
|
TemplateName: group.LgTemplateName,
|
||||||
|
DeliveryProvince: group.LgDeliveryProvince,
|
||||||
|
DeliveryCity: group.LgDeliveryCity,
|
||||||
|
DeliveryArea: group.LgDeliveryArea,
|
||||||
|
DeliveryAddress: group.LgDeliveryAddress,
|
||||||
|
PricingMethod: group.LgPricingMethod,
|
||||||
|
Shipping: group.LgShipping,
|
||||||
|
FirWbv: group.LgFirWbv,
|
||||||
|
FirPrice: group.LgFirPrice,
|
||||||
|
ContinueWbv: group.LgContinueWbv,
|
||||||
|
ContinuePrice: group.LgContinuePrice,
|
||||||
|
Contact: group.LgContact,
|
||||||
|
PhoneNumber: group.LgPhoneNumber,
|
||||||
|
FullAddress: group.LgFullAddress,
|
||||||
|
ShippingRange: group.LgShippingRange,
|
||||||
|
WarehouseId: group.LgWarehouseID,
|
||||||
|
Remark: group.LgRemark,
|
||||||
|
Status: group.LgStatus,
|
||||||
|
CreateTime: group.LgCreateTime,
|
||||||
|
UpdateTime: group.LgUpdateTime,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warehouses = append(warehouses, systemRes.ProductInventoryWarehouse{
|
||||||
|
WarehouseID: group.WarehouseID,
|
||||||
|
WarehouseName: group.WarehouseName,
|
||||||
|
WarehouseCode: group.WarehouseCode,
|
||||||
|
LocationID: group.LocationID,
|
||||||
|
LocationName: group.LocationCode,
|
||||||
|
Logistics: lg,
|
||||||
|
TotalQuantity: group.TotalQuantity,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
databaseConn.Table("inventory").
|
databaseConn.Table("inventory").
|
||||||
@ -1449,6 +1543,7 @@ func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRe
|
|||||||
}
|
}
|
||||||
return &systemRes.ProductInventoryResponse{
|
return &systemRes.ProductInventoryResponse{
|
||||||
Quantity: totalQuantity,
|
Quantity: totalQuantity,
|
||||||
|
Warehouses: warehouses,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"psi/database"
|
"psi/database"
|
||||||
"psi/models"
|
"psi/models"
|
||||||
systemReq "psi/models/request"
|
systemReq "psi/models/request"
|
||||||
@ -179,3 +180,124 @@ func (s *SplitAccountDeductionLogService) DeleteSplitAccountDeductionLog(req sys
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSplitAccountDeductionLogSummary 获取分账扣钱日志汇总
|
||||||
|
func (s *SplitAccountDeductionLogService) GetSplitAccountDeductionLogSummary(req systemReq.GetSplitAccountDeductionLogSummaryRequest, createdBy string, db ...*gorm.DB) (*systemRes.SplitAccountDeductionLogSummaryResponse, error) {
|
||||||
|
databaseConn := database.OptionalDB(db...)
|
||||||
|
|
||||||
|
if req.PageNum < 1 {
|
||||||
|
req.PageNum = 1
|
||||||
|
}
|
||||||
|
if req.PageSize < 1 || req.PageSize > 100 {
|
||||||
|
req.PageSize = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 createdBy 决定是否过滤
|
||||||
|
hasFilter := createdBy != ""
|
||||||
|
|
||||||
|
// 先查询分组总数
|
||||||
|
var total int64
|
||||||
|
var countArgs []interface{}
|
||||||
|
if hasFilter {
|
||||||
|
countSQL := "SELECT COUNT(*) FROM (SELECT business_no FROM split_account_deduction_log WHERE created_by = ? GROUP BY business_no) AS t"
|
||||||
|
countArgs = []interface{}{createdBy}
|
||||||
|
fmt.Printf("[SQL] summary-count: %s | args: %v\n", countSQL, countArgs)
|
||||||
|
if err := databaseConn.Raw(countSQL, countArgs...).Scan(&total).Error; err != nil {
|
||||||
|
return nil, utils.NewError("查询汇总总数失败")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
countSQL := "SELECT COUNT(*) FROM (SELECT business_no FROM split_account_deduction_log GROUP BY business_no) AS t"
|
||||||
|
fmt.Printf("[SQL] summary-count: %s\n", countSQL)
|
||||||
|
if err := databaseConn.Raw(countSQL).Scan(&total).Error; err != nil {
|
||||||
|
return nil, utils.NewError("查询汇总总数失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询分页数据
|
||||||
|
offset := (req.PageNum - 1) * req.PageSize
|
||||||
|
|
||||||
|
type rawResult struct {
|
||||||
|
BusinessNo string `gorm:"column:business_no"`
|
||||||
|
ConfigName string `gorm:"column:config_name"`
|
||||||
|
DeductionDetails datatypes.JSON `gorm:"column:deduction_details"`
|
||||||
|
Total int64 `gorm:"column:total"`
|
||||||
|
CreatedAt int64 `gorm:"column:created_at"`
|
||||||
|
UpdatedAt int64 `gorm:"column:updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []rawResult
|
||||||
|
if hasFilter {
|
||||||
|
dataSQL := `SELECT MAX(business_no) AS business_no, MAX(config_name) AS config_name,
|
||||||
|
MAX(deduction_details) AS deduction_details, COUNT(*) AS total,
|
||||||
|
MIN(created_at) AS created_at, MIN(updated_at) AS updated_at
|
||||||
|
FROM split_account_deduction_log
|
||||||
|
WHERE created_by = ?
|
||||||
|
GROUP BY business_no
|
||||||
|
ORDER BY business_no DESC
|
||||||
|
LIMIT ? OFFSET ?`
|
||||||
|
fmt.Printf("[SQL] summary-data: WHERE created_by = '%s' GROUP BY business_no ORDER BY business_no DESC LIMIT %d OFFSET %d\n", createdBy, req.PageSize, offset)
|
||||||
|
if err := databaseConn.Raw(dataSQL, createdBy, req.PageSize, offset).Scan(&results).Error; err != nil {
|
||||||
|
return nil, utils.NewError("查询分账扣钱日志汇总失败")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dataSQL := `SELECT MAX(business_no) AS business_no, MAX(config_name) AS config_name,
|
||||||
|
MAX(deduction_details) AS deduction_details, COUNT(*) AS total,
|
||||||
|
MIN(created_at) AS created_at, MIN(updated_at) AS updated_at
|
||||||
|
FROM split_account_deduction_log
|
||||||
|
GROUP BY business_no
|
||||||
|
ORDER BY business_no DESC
|
||||||
|
LIMIT ? OFFSET ?`
|
||||||
|
fmt.Printf("[SQL] summary-data: GROUP BY business_no ORDER BY business_no DESC LIMIT %d OFFSET %d\n", req.PageSize, offset)
|
||||||
|
if err := databaseConn.Raw(dataSQL, req.PageSize, offset).Scan(&results).Error; err != nil {
|
||||||
|
return nil, utils.NewError("查询分账扣钱日志汇总失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []systemRes.SplitAccountDeductionLogSummaryItem
|
||||||
|
for _, r := range results {
|
||||||
|
var deductionDetails interface{}
|
||||||
|
if r.DeductionDetails != nil {
|
||||||
|
json.Unmarshal(r.DeductionDetails, &deductionDetails)
|
||||||
|
}
|
||||||
|
items = append(items, systemRes.SplitAccountDeductionLogSummaryItem{
|
||||||
|
BusinessNo: r.BusinessNo,
|
||||||
|
ConfigName: r.ConfigName,
|
||||||
|
DeductionDetails: deductionDetails,
|
||||||
|
Total: r.Total,
|
||||||
|
CreatedAt: r.CreatedAt,
|
||||||
|
UpdatedAt: r.UpdatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &systemRes.SplitAccountDeductionLogSummaryResponse{
|
||||||
|
List: items,
|
||||||
|
Total: total,
|
||||||
|
Page: req.PageNum,
|
||||||
|
PageSize: req.PageSize,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSplitAccountDeductionLogDetailList 获取分账扣钱日志详情列表
|
||||||
|
func (s *SplitAccountDeductionLogService) GetSplitAccountDeductionLogDetailList(req systemReq.GetSplitAccountDeductionLogDetailListRequest, createdBy string, db ...*gorm.DB) ([]systemRes.SplitAccountDeductionLogItem, error) {
|
||||||
|
databaseConn := database.OptionalDB(db...)
|
||||||
|
|
||||||
|
query := databaseConn.Where("business_no = ?", req.BusinessNo)
|
||||||
|
if createdBy != "" {
|
||||||
|
query = query.Where("created_by = ?", createdBy)
|
||||||
|
fmt.Printf("[SQL] detail-list: SELECT * FROM split_account_deduction_log WHERE business_no = '%s' AND created_by = '%s' ORDER BY id ASC\n", req.BusinessNo, createdBy)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("[SQL] detail-list: SELECT * FROM split_account_deduction_log WHERE business_no = '%s' ORDER BY id ASC\n", req.BusinessNo)
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs []models.SplitAccountDeductionLog
|
||||||
|
if err := query.Order("id ASC").Find(&logs).Error; err != nil {
|
||||||
|
return nil, utils.NewError("查询分账扣钱日志详情列表失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []systemRes.SplitAccountDeductionLogItem
|
||||||
|
for _, log := range logs {
|
||||||
|
items = append(items, systemRes.ConvertSplitAccountDeductionLogToItem(log))
|
||||||
|
}
|
||||||
|
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -159,6 +159,8 @@ func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest,
|
|||||||
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()
|
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()
|
||||||
endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()).Unix()
|
endOfDay := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()).Unix()
|
||||||
|
|
||||||
|
hasExplicitDate := req.EndDate != 0
|
||||||
|
|
||||||
if req.StartDate == 0 {
|
if req.StartDate == 0 {
|
||||||
req.StartDate = startOfDay
|
req.StartDate = startOfDay
|
||||||
}
|
}
|
||||||
@ -166,7 +168,12 @@ func (s *StatistService) DashboardStatist(req systemReq.DashboardStatistRequest,
|
|||||||
req.EndDate = endOfDay
|
req.EndDate = endOfDay
|
||||||
}
|
}
|
||||||
|
|
||||||
statDateStr := now.Format("20060102")
|
var statDateStr string
|
||||||
|
if hasExplicitDate {
|
||||||
|
statDateStr = time.Unix(req.EndDate, 0).Format("20060102")
|
||||||
|
} else {
|
||||||
|
statDateStr = now.Format("20060102")
|
||||||
|
}
|
||||||
var statDate int64
|
var statDate int64
|
||||||
if _, err := fmt.Sscanf(statDateStr, "%d", &statDate); err != nil {
|
if _, err := fmt.Sscanf(statDateStr, "%d", &statDate); err != nil {
|
||||||
return s.getDashboardStatRealtime(databaseConn, req.StartDate, req.EndDate)
|
return s.getDashboardStatRealtime(databaseConn, req.StartDate, req.EndDate)
|
||||||
@ -213,9 +220,13 @@ func (s *StatistService) getDashboardStatRealtime(databaseConn *gorm.DB, startDa
|
|||||||
Where("created_at >= ? AND created_at <= ? AND is_del = ?", startDate, endDate, 0)
|
Where("created_at >= ? AND created_at <= ? AND is_del = ?", startDate, endDate, 0)
|
||||||
saleOrderQuery.Count(&totalSaleCount)
|
saleOrderQuery.Count(&totalSaleCount)
|
||||||
|
|
||||||
|
endTime := time.Unix(endDate, 0)
|
||||||
|
singleDayStart := time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, endTime.Location()).Unix()
|
||||||
|
singleDayEnd := time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 23, 59, 59, 0, endTime.Location()).Unix()
|
||||||
|
|
||||||
var totalReceivingCount, totalOutboundCount int64
|
var totalReceivingCount, totalOutboundCount int64
|
||||||
statistQuery := databaseConn.Model(&models.Statist{}).
|
statistQuery := databaseConn.Model(&models.Statist{}).
|
||||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0)
|
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", singleDayStart, singleDayEnd, 0)
|
||||||
|
|
||||||
var statistList []models.Statist
|
var statistList []models.Statist
|
||||||
if err := statistQuery.Find(&statistList).Error; err != nil {
|
if err := statistQuery.Find(&statistList).Error; err != nil {
|
||||||
@ -247,13 +258,13 @@ func (s *StatistService) getDashboardStatRealtime(databaseConn *gorm.DB, startDa
|
|||||||
var userStatGroups []UserStatGroup
|
var userStatGroups []UserStatGroup
|
||||||
databaseConn.Model(&models.Statist{}).
|
databaseConn.Model(&models.Statist{}).
|
||||||
Select("create_by, SUM(receiving_num) as total_receiving, SUM(outbound_num) as total_outbound").
|
Select("create_by, SUM(receiving_num) as total_receiving, SUM(outbound_num) as total_outbound").
|
||||||
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", startDate, endDate, 0).
|
Where("stat_date >= ? AND stat_date <= ? AND is_del = ?", singleDayStart, singleDayEnd, 0).
|
||||||
Group("create_by").
|
Group("create_by").
|
||||||
Scan(&userStatGroups)
|
Scan(&userStatGroups)
|
||||||
|
|
||||||
for _, group := range userStatGroups {
|
for _, group := range userStatGroups {
|
||||||
var employee models.Employee
|
var employee models.Employee
|
||||||
if err := database.DB.Where("id = ?", group.CreateBy).First(&employee).Error; err == nil {
|
if err := databaseConn.Where("id = ?", group.CreateBy).First(&employee).Error; err == nil {
|
||||||
userStats = append(userStats, systemRes.UserStatItem{
|
userStats = append(userStats, systemRes.UserStatItem{
|
||||||
UserID: employee.ID,
|
UserID: employee.ID,
|
||||||
UserName: employee.Username,
|
UserName: employee.Username,
|
||||||
@ -315,18 +326,11 @@ func (s *StatistService) GetWarehouseStatist(req systemReq.WarehouseStatistReque
|
|||||||
req.EndDate = endOfDay
|
req.EndDate = endOfDay
|
||||||
}
|
}
|
||||||
|
|
||||||
type WarehouseStat struct {
|
var productTotal int64
|
||||||
ProductTotal int64 `gorm:"column:product_total"`
|
databaseConn.Model(&models.Product{}).Where("is_del = ?", 0).Count(&productTotal)
|
||||||
InventoryTotal int64 `gorm:"column:inventory_total"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var warehouseStat WarehouseStat
|
var inventoryTotal int64
|
||||||
databaseConn.Table("(?) as p", databaseConn.Model(&models.Product{}).Where("is_del = ?", 0).Select("COUNT(*) as product_total")).
|
databaseConn.Model(&models.Inventory{}).Where("is_del = ?", 0).Select("COALESCE(SUM(quantity), 0)").Row().Scan(&inventoryTotal)
|
||||||
Select(`
|
|
||||||
p.product_total,
|
|
||||||
COALESCE((SELECT SUM(quantity) FROM inventory WHERE is_del = ?), 0) as inventory_total
|
|
||||||
`, 0).
|
|
||||||
Scan(&warehouseStat)
|
|
||||||
|
|
||||||
type DailyStat struct {
|
type DailyStat struct {
|
||||||
TodayInbound int64 `gorm:"column:today_inbound"`
|
TodayInbound int64 `gorm:"column:today_inbound"`
|
||||||
@ -347,8 +351,8 @@ func (s *StatistService) GetWarehouseStatist(req systemReq.WarehouseStatistReque
|
|||||||
Scan(&dailyStat)
|
Scan(&dailyStat)
|
||||||
|
|
||||||
return &systemRes.WarehouseStatistResponse{
|
return &systemRes.WarehouseStatistResponse{
|
||||||
ProductTotal: warehouseStat.ProductTotal,
|
ProductTotal: productTotal,
|
||||||
InventoryTotal: warehouseStat.InventoryTotal,
|
InventoryTotal: inventoryTotal,
|
||||||
TodayInbound: dailyStat.TodayInbound,
|
TodayInbound: dailyStat.TodayInbound,
|
||||||
TodayOutbound: dailyStat.TodayOutbound,
|
TodayOutbound: dailyStat.TodayOutbound,
|
||||||
YesterdayInbound: dailyStat.YesterdayInbound,
|
YesterdayInbound: dailyStat.YesterdayInbound,
|
||||||
@ -408,7 +412,7 @@ func (s *StatistService) GetOrderStatist(req systemReq.OrderStatistRequest, db .
|
|||||||
COALESCE(SUM(CASE WHEN created_at >= ? AND created_at <= ? AND status IN (?, ?) THEN 1 ELSE 0 END), 0) as yesterday_pending
|
COALESCE(SUM(CASE WHEN created_at >= ? AND created_at <= ? AND status IN (?, ?) THEN 1 ELSE 0 END), 0) as yesterday_pending
|
||||||
`, req.StartDate, req.EndDate, req.StartDate, req.EndDate, req.StartDate, req.EndDate, StatusShipped, req.StartDate, req.EndDate, StatusShipped, StatusCancelled, req.StartDate, req.EndDate, StatusDraft, StatusConfirmed,
|
`, req.StartDate, req.EndDate, req.StartDate, req.EndDate, req.StartDate, req.EndDate, StatusShipped, req.StartDate, req.EndDate, StatusShipped, StatusCancelled, req.StartDate, req.EndDate, StatusDraft, StatusConfirmed,
|
||||||
yesterdayStart, yesterdayEnd, yesterdayStart, yesterdayEnd, yesterdayStart, yesterdayEnd, StatusShipped, yesterdayStart, yesterdayEnd, StatusShipped, StatusCancelled, yesterdayStart, yesterdayEnd, StatusDraft, StatusConfirmed).
|
yesterdayStart, yesterdayEnd, yesterdayStart, yesterdayEnd, yesterdayStart, yesterdayEnd, StatusShipped, yesterdayStart, yesterdayEnd, StatusShipped, StatusCancelled, yesterdayStart, yesterdayEnd, StatusDraft, StatusConfirmed).
|
||||||
Where("is_del = ?", 0).
|
Where("is_del = ? AND created_at >= ? AND created_at <= ?", 0, yesterdayStart, req.EndDate).
|
||||||
Scan(&orderStat)
|
Scan(&orderStat)
|
||||||
|
|
||||||
return &systemRes.OrderStatistResponse{
|
return &systemRes.OrderStatistResponse{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user