1.返回userlist
2.通过use_id,product_id 返回关联信息
This commit is contained in:
parent
0eb07eec03
commit
fafac05570
@ -327,3 +327,28 @@ func (r *EmployeeApi) GetUserList(c *gin.Context) {
|
||||
"data": result,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateEmployeeSplitAccountConfigByAboutId 根据about_id更新员工分账配置ID
|
||||
func (r *EmployeeApi) UpdateEmployeeSplitAccountConfigByAboutId(c *gin.Context) {
|
||||
var req systemReq.UpdateEmployeeSplitAccountConfigRequest
|
||||
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
ValidAndFail(constant.LoggerChannelRequest, "更新员工分账配置请求参数异常", "参数错误: "+err.Error(), c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
userInfo := utils.GetUserInfo(c)
|
||||
|
||||
result, err := employeeService.UpdateEmployeeSplitAccountConfigByAboutId(req, userInfo.Username)
|
||||
if err != nil {
|
||||
utils.ErrorLog(constant.LoggerChannelWork, logrus.Fields{
|
||||
"source": "更新员工分账配置异常",
|
||||
"err_msg": err.Error(),
|
||||
})
|
||||
systemRes.FailWithMessage(err.Error(), c)
|
||||
return
|
||||
}
|
||||
|
||||
systemRes.OkWithDetailed(result, "更新成功", c)
|
||||
}
|
||||
|
||||
@ -25,6 +25,19 @@ type Employee struct {
|
||||
ExpireTime int64 `json:"expire_time" gorm:"not null;default:0;comment:过期时间"`
|
||||
}
|
||||
|
||||
// UpdateEmployeeSplitAccountConfigResponse 更新员工分账配置响应
|
||||
type UpdateEmployeeSplitAccountConfigResponse struct {
|
||||
ID int64 `json:"id"`
|
||||
EmployeeIDStr string `json:"employee_id_str"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
AboutId int64 `json:"about_id"`
|
||||
SplitAccountConfigId int64 `json:"split_account_config_id"`
|
||||
Status int8 `json:"status"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (Employee) TableName() string {
|
||||
return "employees"
|
||||
}
|
||||
|
||||
@ -65,8 +65,25 @@ type SetEmployeeLevelRequest struct {
|
||||
|
||||
// GetUserListRequest 获取用户列表请求
|
||||
type GetUserListRequest struct {
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"page_size"`
|
||||
Keyword string `form:"keyword"`
|
||||
Status string `form:"status"`
|
||||
Page int `form:"page"` // 页码
|
||||
PageSize int `form:"page_size"` // 页大小
|
||||
Username string `form:"username"` // 用户名
|
||||
Tel string `form:"tel"` // 手机号
|
||||
//Keyword string `form:"keyword"` // 关键词 注释将keyword改为 username 和 tel
|
||||
Status string `form:"status"` // 状态
|
||||
}
|
||||
|
||||
// GetUserListRequest 获取用户列表请求
|
||||
/*type GetUserListRequest struct {
|
||||
Page int `form:"page"` // 页码
|
||||
PageSize int `form:"page_size"` // 页大小
|
||||
Username string `form:"username"` // 用户名
|
||||
Tel string `form:"tel"` // 手机号
|
||||
Status string `form:"status"` // 状态
|
||||
}*/
|
||||
|
||||
// UpdateEmployeeSplitAccountConfigRequest 根据about_id更新员工分账配置请求
|
||||
type UpdateEmployeeSplitAccountConfigRequest struct {
|
||||
AboutId int64 `form:"about_id" binding:"required"`
|
||||
SplitAccountConfigId int64 `form:"split_account_config_id" binding:"required"`
|
||||
}
|
||||
|
||||
@ -154,6 +154,7 @@ type DeleteProductLogRequest struct {
|
||||
type GetProductInventoryRequest struct {
|
||||
UserID int64 `form:"user_id" binding:"required"` // 用户ID
|
||||
ProductID int64 `form:"product_id" binding:"required"` // 商品ID
|
||||
Type int8 `form:"type"` // 类型: 0=原始数据, 1=按商品名称+ISBN+仓库聚合
|
||||
}
|
||||
|
||||
type GetShopProductDetailRequest struct {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"psi/models"
|
||||
)
|
||||
|
||||
@ -109,6 +110,7 @@ type UserListItem struct {
|
||||
Role int64 `json:"role"`
|
||||
Status int8 `json:"status"`
|
||||
SplitAccountConfigId int64 `json:"split_account_config_id"`
|
||||
SplitAccountConfig *SplitAccountConfigInfo `json:"split_account_config,omitempty"` // 分账配置详情
|
||||
}
|
||||
|
||||
// GetUserListResponse 用户列表响应
|
||||
@ -118,3 +120,47 @@ type GetUserListResponse struct {
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// UpdateEmployeeSplitAccountConfigResponse 更新员工分账配置响应
|
||||
type UpdateEmployeeSplitAccountConfigResponse struct {
|
||||
ID int64 `json:"id"`
|
||||
EmployeeIDStr string `json:"employee_id_str"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
AboutId int64 `json:"about_id"`
|
||||
SplitAccountConfigId int64 `json:"split_account_config_id"`
|
||||
Status int8 `json:"status"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
// CurrentUserResponse 当前用户信息响应(包含分账配置)
|
||||
type CurrentUserResponse struct {
|
||||
ID int64 `json:"id"`
|
||||
EmployeeIDStr string `json:"employee_id_str"`
|
||||
Username string `json:"username"`
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
Role int64 `json:"role"`
|
||||
Fid int64 `json:"fid"`
|
||||
AboutId int64 `json:"about_id"`
|
||||
Status int8 `json:"status"`
|
||||
Score int64 `json:"score"`
|
||||
SplitAccountConfigId int64 `json:"split_account_config_id"`
|
||||
SplitAccountConfig *SplitAccountConfigInfo `json:"split_account_config,omitempty"` // 分账配置详情
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
// SplitAccountConfigInfo 分账配置信息
|
||||
type SplitAccountConfigInfo struct {
|
||||
ID int64 `json:"id"`
|
||||
RuleName string `json:"rule_name"`
|
||||
RuleValue json.RawMessage `json:"rule_value"`
|
||||
Status int8 `json:"status"`
|
||||
Description string `json:"description"`
|
||||
CreatedBy string `json:"created_by"`
|
||||
UpdatedBy string `json:"updated_by"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
@ -146,7 +146,8 @@ type ProductLogListResponse struct {
|
||||
|
||||
// ProductInventoryResponse 商品库存响应
|
||||
type ProductInventoryResponse struct {
|
||||
Quantity int64 `json:"quantity"`
|
||||
Quantity int64 `json:"quantity"` // 总库存数量(type=0时使用)
|
||||
Warehouses []ProductInventoryWarehouse `json:"warehouses,omitempty"` // 仓库列表(type=1时使用)
|
||||
}
|
||||
|
||||
// ShopProductDetailResponse 店铺商品详情响应
|
||||
@ -199,3 +200,14 @@ type ProductInShop struct {
|
||||
CreatedAt int64 `json:"created_at"` // 创建时间
|
||||
UpdatedAt int64 `json:"updated_at"` // 更新时间
|
||||
}
|
||||
|
||||
// ProductInventoryWarehouse 商品库存仓库信息
|
||||
type ProductInventoryWarehouse struct {
|
||||
WarehouseID int64 `json:"warehouse_id"` // 仓库ID
|
||||
WarehouseName string `json:"warehouse_name"` // 仓库名称
|
||||
WarehouseCode string `json:"warehouse_code"` // 仓库编码
|
||||
ProductName string `json:"product_name"` // 商品名称
|
||||
ISBN string `json:"isbn"` // ISBN/条码
|
||||
Appearance int64 `json:"appearance"` // 品相
|
||||
TotalQuantity int64 `json:"total_quantity"` // 该仓库下该商品的总库存
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ func initRouter() (r *gin.Engine) {
|
||||
// 管理员
|
||||
auth.GET("/user/current", employeeApi.GetCurrentUser) // 获取当前用户信息
|
||||
auth.POST("/logout", employeeApi.Logout) // 登出
|
||||
auth.POST("/userList", employeeApi.GetUserList) // 获取用户列表
|
||||
auth.GET("/userList", employeeApi.GetUserList) // 获取用户列表
|
||||
// 配置管理
|
||||
auth.GET("/config/list", configApi.GetConfigList) // 获取配置列表
|
||||
auth.GET("/config/detail/:id", configApi.GetConfigDetail) // 获取配置详情
|
||||
@ -261,6 +261,7 @@ func initRouter() (r *gin.Engine) {
|
||||
admin.GET("/employee/check_expire_time", employeeApi.CheckExpireTimeEmployee) // 检查员工到期时间
|
||||
admin.POST("/employee/set_level", employeeApi.SetEmployeeLevel) // 设置员工等级
|
||||
admin.GET("/employee/level_config", employeeApi.GetLevelConfigList) // 获取员工等级配置列表
|
||||
admin.POST("/employee/update-split-account-config", employeeApi.UpdateEmployeeSplitAccountConfigByAboutId) // 根据about_id更新员工分账配置ID
|
||||
// 用户类型管理
|
||||
admin.GET("/user-type/list", userTypeApi.GetUserTypeList) // 获取用户类型列表
|
||||
admin.GET("/user-type/detail/:id", userTypeApi.GetUserTypeDetail) // 获取用户类型详情
|
||||
|
||||
@ -839,7 +839,7 @@ func (s *EmployeeService) createEmployeeLevelLog(empId int64, operationType int8
|
||||
}
|
||||
|
||||
// GetUserList 获取用户列表(主库)
|
||||
func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*systemRes.GetUserListResponse, error) {
|
||||
/*func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*systemRes.GetUserListResponse, error) {
|
||||
if req.Page < 1 {
|
||||
req.Page = 1
|
||||
}
|
||||
@ -888,3 +888,149 @@ func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*system
|
||||
PageSize: req.PageSize,
|
||||
}, nil
|
||||
}
|
||||
*/
|
||||
func (s *EmployeeService) GetUserList(req systemReq.GetUserListRequest) (*systemRes.GetUserListResponse, error) {
|
||||
if req.Page < 1 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize < 1 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
query := database.DB.Model(&models.Employee{}).Where("deleted_at = ?", 0)
|
||||
|
||||
if req.Status != "" {
|
||||
query = query.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.Username != "" {
|
||||
query = query.Where("username LIKE ?", "%"+req.Username+"%")
|
||||
}
|
||||
if req.Tel != "" {
|
||||
query = query.Where("phone LIKE ?", "%"+req.Tel+"%")
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := query.Count(&total).Error; err != nil {
|
||||
return nil, utils.NewError("查询总数失败")
|
||||
}
|
||||
|
||||
var employees []models.Employee
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
if err := query.Order("created_at DESC").Offset(offset).Limit(req.PageSize).Find(&employees).Error; err != nil {
|
||||
return nil, utils.NewError("查询用户列表失败")
|
||||
}
|
||||
|
||||
// 收集所有需要查询的分账配置ID
|
||||
splitConfigIDs := make([]int64, 0)
|
||||
for _, emp := range employees {
|
||||
if emp.SplitAccountConfigId > 0 {
|
||||
splitConfigIDs = append(splitConfigIDs, emp.SplitAccountConfigId)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量查询分账配置
|
||||
splitConfigMap := make(map[int64]*systemRes.SplitAccountConfigInfo)
|
||||
if len(splitConfigIDs) > 0 {
|
||||
var splitConfigs []models.SplitAccountConfig
|
||||
database.DB.Where("id IN ? AND deleted_at = ?", splitConfigIDs, 0).Find(&splitConfigs)
|
||||
|
||||
for _, config := range splitConfigs {
|
||||
splitConfigMap[config.ID] = &systemRes.SplitAccountConfigInfo{
|
||||
ID: config.ID,
|
||||
RuleName: config.RuleName,
|
||||
RuleValue: json.RawMessage(config.RuleValue),
|
||||
Status: config.Status,
|
||||
Description: config.Description,
|
||||
CreatedBy: config.CreatedBy,
|
||||
UpdatedBy: config.UpdatedBy,
|
||||
CreatedAt: config.CreatedAt,
|
||||
UpdatedAt: config.UpdatedAt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var items []systemRes.UserListItem
|
||||
for _, emp := range employees {
|
||||
item := systemRes.UserListItem{
|
||||
ID: emp.ID,
|
||||
EmployeeIDStr: emp.EmployeeIDStr,
|
||||
Username: emp.Username,
|
||||
Name: emp.Name,
|
||||
Role: emp.Role,
|
||||
Status: emp.Status,
|
||||
SplitAccountConfigId: emp.SplitAccountConfigId,
|
||||
}
|
||||
|
||||
// 如果有关联的分账配置,添加详情
|
||||
if emp.SplitAccountConfigId > 0 {
|
||||
if config, exists := splitConfigMap[emp.SplitAccountConfigId]; exists {
|
||||
item.SplitAccountConfig = config
|
||||
}
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &systemRes.GetUserListResponse{
|
||||
List: items,
|
||||
Total: total,
|
||||
Page: req.Page,
|
||||
PageSize: req.PageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateEmployeeSplitAccountConfigByAboutId 根据about_id更新员工分账配置ID
|
||||
func (s *EmployeeService) UpdateEmployeeSplitAccountConfigByAboutId(req systemReq.UpdateEmployeeSplitAccountConfigRequest, username string) (*systemRes.UpdateEmployeeSplitAccountConfigResponse, error) {
|
||||
var employee models.Employee
|
||||
result := database.DB.Where("about_id = ? AND deleted_at = ?", req.AboutId, 0).First(&employee)
|
||||
if result.Error != nil {
|
||||
return nil, utils.NewError("员工不存在")
|
||||
}
|
||||
|
||||
updateData := map[string]interface{}{
|
||||
"split_account_config_id": req.SplitAccountConfigId,
|
||||
"updated_at": time.Now().Unix(),
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&employee).Updates(updateData).Error; err != nil {
|
||||
return nil, utils.NewError("更新员工分账配置失败: " + err.Error())
|
||||
}
|
||||
|
||||
// 重新查询更新后的员工数据
|
||||
if err := database.DB.Where("id = ? AND deleted_at = ?", employee.ID, 0).First(&employee).Error; err != nil {
|
||||
return nil, utils.NewError("查询更新后的员工数据失败")
|
||||
}
|
||||
|
||||
return &systemRes.UpdateEmployeeSplitAccountConfigResponse{
|
||||
ID: employee.ID,
|
||||
EmployeeIDStr: employee.EmployeeIDStr,
|
||||
Username: employee.Username,
|
||||
Name: employee.Name,
|
||||
Phone: employee.Phone,
|
||||
AboutId: employee.AboutId,
|
||||
SplitAccountConfigId: employee.SplitAccountConfigId,
|
||||
Status: employee.Status,
|
||||
UpdatedAt: employee.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ... existing code ...
|
||||
/*func (s *EmployeeService) UpdateEmployeeSplitAccountConfigByAboutId(req systemReq.UpdateEmployeeSplitAccountConfigRequest, username string) error {
|
||||
var employee models.Employee
|
||||
result := database.DB.Where("about_id = ? AND deleted_at = ?", req.AboutId, 0).First(&employee)
|
||||
if result.Error != nil {
|
||||
return utils.NewError("员工不存在")
|
||||
}
|
||||
|
||||
updateData := map[string]interface{}{
|
||||
"split_account_config_id": req.SplitAccountConfigId,
|
||||
"updated_at": time.Now().Unix(),
|
||||
}
|
||||
|
||||
if err := database.DB.Model(&employee).Updates(updateData).Error; err != nil {
|
||||
return utils.NewError("更新员工分账配置失败: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
@ -3974,12 +3974,7 @@ func (s *ProcessService) syncProductsToExternal(receivingOrderID, waveTaskID, us
|
||||
group.totalQty += item.quantity
|
||||
} else {
|
||||
// 新建ISBN组
|
||||
var imgList []string
|
||||
if product.LiveImage != nil && len(product.LiveImage) > 0 {
|
||||
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil {
|
||||
return fmt.Errorf("解析json失败: %v", err)
|
||||
}
|
||||
}
|
||||
imgList := parseImageList(product.LiveImage)
|
||||
|
||||
skuCode := warehouse.Code
|
||||
if item.locationID > 0 {
|
||||
@ -4046,12 +4041,7 @@ func (s *ProcessService) syncProductsToExternal(receivingOrderID, waveTaskID, us
|
||||
}
|
||||
|
||||
isbn := product.Barcode
|
||||
var imgList []string
|
||||
if product.LiveImage != nil && len(product.LiveImage) > 0 {
|
||||
if err := json.Unmarshal(product.LiveImage, &imgList); err != nil {
|
||||
return fmt.Errorf("解析json失败: %v", err)
|
||||
}
|
||||
}
|
||||
imgList := parseImageList(product.LiveImage)
|
||||
|
||||
skuCode := warehouse.Code
|
||||
if item.locationID > 0 {
|
||||
@ -4379,3 +4369,34 @@ func getSalesStatusText(status int8) string {
|
||||
return "未知状态"
|
||||
}
|
||||
}
|
||||
|
||||
// parseImageList 解析图片列表,支持JSON数组和逗号分隔字符串两种格式
|
||||
func parseImageList(liveImage datatypes.JSON) []string {
|
||||
if liveImage == nil || len(liveImage) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// 尝试解析为字符串数组
|
||||
var imgList []string
|
||||
if err := json.Unmarshal(liveImage, &imgList); err == nil {
|
||||
return imgList
|
||||
}
|
||||
|
||||
// 如果解析失败,尝试解析为字符串,然后按逗号分割
|
||||
var imgStr string
|
||||
if err := json.Unmarshal(liveImage, &imgStr); err == nil {
|
||||
// 去除空格并按逗号分割
|
||||
parts := strings.Split(imgStr, ",")
|
||||
result := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
trimmed := strings.TrimSpace(part)
|
||||
if trimmed != "" {
|
||||
result = append(result, trimmed)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 都不成功,返回空数组
|
||||
return []string{}
|
||||
}
|
||||
|
||||
@ -651,18 +651,123 @@ func (s *ProductService) UpdatePrice(req systemReq.UpdatePriceRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetProductInventory 获取商品库存数量
|
||||
//// GetProductInventory 获取商品库存数量
|
||||
//func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRequest) (*systemRes.ProductInventoryResponse, error) {
|
||||
// databaseConn, err := database.GetTenantDB(req.UserID)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("获取数据库连接失败: %v", err)
|
||||
// }
|
||||
//
|
||||
// // 验证商品是否存在
|
||||
// var product models.Product
|
||||
// if err := databaseConn.Where("id = ? AND is_del = ?", req.ProductID, 0).First(&product).Error; err != nil {
|
||||
// return nil, fmt.Errorf("商品不存在")
|
||||
// }
|
||||
//
|
||||
// //// type=1: 按品相+ISBN+仓库聚合
|
||||
// //if req.Type == 1 {
|
||||
// // type warehouseStock struct {
|
||||
// // WarehouseID int64 `gorm:"column:warehouse_id"`
|
||||
// // WarehouseName string `gorm:"column:warehouse_name"`
|
||||
// // WarehouseCode string `gorm:"column:warehouse_code"`
|
||||
// // ProductName string `gorm:"column:product_name"`
|
||||
// // ISBN string `gorm:"column:isbn"`
|
||||
// // Appearance int64 `gorm:"column:appearance"`
|
||||
// // TotalQuantity int64 `gorm:"column:total_quantity"`
|
||||
// // }
|
||||
// //
|
||||
// // var warehouseList []warehouseStock
|
||||
// // databaseConn.Table("inventory").
|
||||
// // Select(`
|
||||
// // inventory.warehouse_id,
|
||||
// // w.name as warehouse_name,
|
||||
// // w.code as warehouse_code,
|
||||
// // p.name as product_name,
|
||||
// // p.barcode as isbn,
|
||||
// // p.appearance as appearance,
|
||||
// // COALESCE(SUM(inventory.quantity), 0) as total_quantity
|
||||
// // `).
|
||||
// // Joins("LEFT JOIN warehouse w ON inventory.warehouse_id = w.id AND w.is_del = ?", 0).
|
||||
// // Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
|
||||
// // Where("inventory.product_id = ? AND inventory.is_del = ?", req.ProductID, 0).
|
||||
// // Group("inventory.warehouse_id, w.name, w.code, p.name, p.barcode, p.appearance").
|
||||
// // Scan(&warehouseList)
|
||||
// //
|
||||
// // warehouses := make([]systemRes.ProductInventoryWarehouse, 0, len(warehouseList))
|
||||
// // totalQuantity := int64(0)
|
||||
// // for _, ws := range warehouseList {
|
||||
// // warehouses = append(warehouses, systemRes.ProductInventoryWarehouse{
|
||||
// // WarehouseID: ws.WarehouseID,
|
||||
// // WarehouseName: ws.WarehouseName,
|
||||
// // WarehouseCode: ws.WarehouseCode,
|
||||
// // ProductName: ws.ProductName,
|
||||
// // ISBN: ws.ISBN,
|
||||
// // Appearance: ws.Appearance,
|
||||
// // TotalQuantity: ws.TotalQuantity,
|
||||
// // })
|
||||
// // totalQuantity += ws.TotalQuantity
|
||||
// // }
|
||||
//
|
||||
// return &systemRes.ProductInventoryResponse{
|
||||
// Quantity: totalQuantity,
|
||||
// //Warehouses: warehouses,
|
||||
// }, nil
|
||||
// }
|
||||
//
|
||||
// // type=0: 返回原始数据(总库存)
|
||||
// var totalQuantity int64
|
||||
// //databaseConn.Table("inventory").
|
||||
// // Select("COALESCE(SUM(quantity), 0)").
|
||||
// // Where("product_id = ? AND is_del = ?", req.ProductID, 0).
|
||||
// // Scan(&totalQuantity)
|
||||
//
|
||||
// return &systemRes.ProductInventoryResponse{
|
||||
// Quantity: totalQuantity,
|
||||
// }, nil
|
||||
//}
|
||||
|
||||
func (s *ProductService) GetProductInventory(req systemReq.GetProductInventoryRequest) (*systemRes.ProductInventoryResponse, error) {
|
||||
databaseConn, err := database.GetTenantDB(req.UserID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("获取数据库连接失败: %v", err)
|
||||
}
|
||||
|
||||
// 验证商品是否存在,并获取商品信息
|
||||
var product models.Product
|
||||
if err := databaseConn.Where("id = ? AND is_del = ?", req.ProductID, 0).First(&product).Error; err != nil {
|
||||
return nil, fmt.Errorf("商品不存在")
|
||||
}
|
||||
|
||||
var totalQuantity int64
|
||||
|
||||
// type=1: 按品相+ISBN+仓库分组后统计总数量
|
||||
if req.Type == 1 {
|
||||
type GroupStock struct {
|
||||
TotalQuantity int64 `gorm:"column:total_quantity"`
|
||||
}
|
||||
|
||||
var groupList []GroupStock
|
||||
// 先根据商品的 ISBN 和品相,查询所有匹配的库存记录,再按仓库分组统计
|
||||
databaseConn.Table("inventory").
|
||||
Select(`
|
||||
COALESCE(SUM(inventory.quantity), 0) as total_quantity
|
||||
`).
|
||||
Joins("LEFT JOIN product p ON inventory.product_id = p.id AND p.is_del = ?", 0).
|
||||
Where("p.barcode = ? AND p.appearance = ? AND inventory.warehouse_id IS NOT NULL AND inventory.is_del = ?",
|
||||
product.Barcode, product.Appearance, 0).
|
||||
Group("inventory.warehouse_id").
|
||||
Scan(&groupList)
|
||||
|
||||
// 累加所有分组的数量
|
||||
for _, group := range groupList {
|
||||
totalQuantity += group.TotalQuantity
|
||||
}
|
||||
} else {
|
||||
databaseConn.Table("inventory").
|
||||
Select("COALESCE(SUM(quantity), 0)").
|
||||
Where("product_id = ? AND is_del = ?", req.ProductID, 0).
|
||||
Scan(&totalQuantity)
|
||||
}
|
||||
|
||||
return &systemRes.ProductInventoryResponse{
|
||||
Quantity: totalQuantity,
|
||||
@ -1443,7 +1548,8 @@ func (s *ProductService) PushProductToShop(req systemReq.PushProductToShopReques
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTask, product models.Product, stock, salePrice, cost, now, userID int64, warehouseCode string, locationCode string, condition int64) {
|
||||
// 批量上架
|
||||
/*func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTask, product models.Product, stock, salePrice, cost, now, userID int64, warehouseCode string, locationCode string, condition int64) {
|
||||
isbn := product.Barcode
|
||||
var imgList []string
|
||||
if product.LiveImage != nil && len(product.LiveImage) > 0 {
|
||||
@ -1527,6 +1633,89 @@ func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTas
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// batchPushProductBody 批量上架商品到外部任务
|
||||
func (s *ProductService) batchPushProductBody(db *gorm.DB, outTask models.OutTask, product models.Product, stock, salePrice, cost, now, userID int64, warehouseCode string, locationCode string, condition int64) {
|
||||
isbn := product.Barcode
|
||||
|
||||
// 使用 parseImageList 解析图片列表,支持多种格式
|
||||
imgList := s.parseImageList(product.LiveImage)
|
||||
|
||||
msgData := map[string]interface{}{
|
||||
"product_id": product.ID,
|
||||
"user_id": strconv.FormatInt(userID, 10),
|
||||
"is_distribution": "1",
|
||||
}
|
||||
msgJSON, _ := json.Marshal(msgData)
|
||||
|
||||
bodyData := map[string]interface{}{
|
||||
"book_info": map[string]interface{}{
|
||||
"isbn": isbn,
|
||||
"image_object": map[string]interface{}{
|
||||
"carousel_url_array": imgList,
|
||||
},
|
||||
},
|
||||
"detail": map[string]interface{}{
|
||||
"stock": stock,
|
||||
"price": salePrice,
|
||||
"shipping_cost": cost,
|
||||
"msg": string(msgJSON),
|
||||
"sku_code": warehouseCode + "##" + locationCode,
|
||||
"condition": condition,
|
||||
},
|
||||
}
|
||||
|
||||
bodyDataJSON, err := json.Marshal(bodyData)
|
||||
if err != nil {
|
||||
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("序列化请求体失败: %v", err), db)
|
||||
return
|
||||
}
|
||||
|
||||
bodyList := []string{string(bodyDataJSON)}
|
||||
taskID := fmt.Sprintf("%d", outTask.OutTaskID)
|
||||
allBody := strings.Join(bodyList, "")
|
||||
|
||||
signParams := map[string]string{
|
||||
"task_id": taskID,
|
||||
"body": allBody,
|
||||
}
|
||||
|
||||
sign := utils.SignParams(signParams)
|
||||
|
||||
url := config.AppConfig.ExternalAPI.SyncTaskBodyURL
|
||||
resp, err := utils.SubmitMultiBody(url, taskID, bodyList, sign)
|
||||
if err != nil {
|
||||
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("请求外部接口失败: %v", err), db)
|
||||
return
|
||||
}
|
||||
|
||||
var resData systemRes.ExternalAPIResponse
|
||||
if err := json.Unmarshal([]byte(resp), &resData); err != nil {
|
||||
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("解析响应失败: %v", err), db)
|
||||
return
|
||||
}
|
||||
|
||||
if resData.Code != "200" {
|
||||
s.saveOutTaskLogWithStock(outTask, product.ID, isbn, product.LiveImage, stock, salePrice, cost, fmt.Sprintf("外部接口返回错误: code=%s, msg=%s", resData.Code, resData.Msg), db)
|
||||
return
|
||||
}
|
||||
|
||||
if updateErr := db.Model(&models.OutTaskLog{}).
|
||||
Where("shop_id = ? AND product_id = ? AND is_del = ?", outTask.ShopID, product.ID, 0).
|
||||
Updates(map[string]interface{}{
|
||||
"status": 1,
|
||||
"msg": "成功",
|
||||
"updated_at": now,
|
||||
}).Error; updateErr != nil {
|
||||
utils.ErrorLog(constant.LoggerChannelWork, map[string]interface{}{
|
||||
"source": "批量推送-更新历史日志状态失败",
|
||||
"shop_id": outTask.ShopID,
|
||||
"product_id": product.ID,
|
||||
"error": fmt.Sprintf("更新失败: %v", updateErr),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// saveRetryLog 保存重试任务日志
|
||||
func (s *ProductService) saveRetryLog(shopID, outTaskID, productID int64, product models.Product, waveTaskDetail models.WaveTaskDetail, hasWaveTask bool, msg string, db *gorm.DB) {
|
||||
@ -1765,7 +1954,7 @@ func (s *ProductService) syncPriceToExternal(waveTaskDetail models.WaveTaskDetai
|
||||
}
|
||||
|
||||
// syncPriceToExternalTask 同步售价到单个外部任务
|
||||
func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product models.Product, waveTaskDetail models.WaveTaskDetail, salePrice, cost, userId int64, db *gorm.DB) error {
|
||||
/*func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product models.Product, waveTaskDetail models.WaveTaskDetail, salePrice, cost, userId int64, db *gorm.DB) error {
|
||||
isbn := product.Barcode
|
||||
var imgList []string
|
||||
if product.LiveImage != nil && len(product.LiveImage) > 0 {
|
||||
@ -1837,6 +2026,78 @@ func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product
|
||||
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
|
||||
// syncPriceToExternalTask 同步售价到单个外部任务
|
||||
func (s *ProductService) syncPriceToExternalTask(outTask models.OutTask, product models.Product, waveTaskDetail models.WaveTaskDetail, salePrice, cost, userId int64, db *gorm.DB) error {
|
||||
isbn := product.Barcode
|
||||
|
||||
// 使用 parseImageList 解析图片列表,支持多种格式
|
||||
imgList := s.parseImageList(product.LiveImage)
|
||||
|
||||
msgData := map[string]interface{}{
|
||||
"product_id": product.ID,
|
||||
"user_id": fmt.Sprintf("%d", userId),
|
||||
}
|
||||
msgJSON, _ := json.Marshal(msgData)
|
||||
|
||||
bodyData := map[string]interface{}{
|
||||
"book_info": map[string]interface{}{
|
||||
"isbn": isbn,
|
||||
"image_object": map[string]interface{}{
|
||||
"carousel_url_array": imgList,
|
||||
},
|
||||
},
|
||||
"detail": map[string]interface{}{
|
||||
"stock": waveTaskDetail.PlannedQuantity,
|
||||
"price": salePrice,
|
||||
"shipping_cost": cost,
|
||||
"msg": string(msgJSON),
|
||||
},
|
||||
}
|
||||
|
||||
bodyDataJSON, err := json.Marshal(bodyData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("序列化请求体失败: %v", err)
|
||||
}
|
||||
|
||||
bodyList := []string{
|
||||
string(bodyDataJSON),
|
||||
}
|
||||
|
||||
taskID := fmt.Sprintf("%d", outTask.OutTaskID)
|
||||
|
||||
allBody := strings.Join(bodyList, "") // 直接无缝拼接(和服务端一致)
|
||||
|
||||
signParams := map[string]string{
|
||||
"task_id": taskID,
|
||||
"body": allBody,
|
||||
}
|
||||
|
||||
sign := utils.SignParams(signParams)
|
||||
|
||||
// 发送请求
|
||||
url := config.AppConfig.ExternalAPI.SyncTaskBodyURL
|
||||
resp, err := utils.SubmitMultiBody(url, taskID, bodyList, sign)
|
||||
if err != nil {
|
||||
s.saveOutTaskLog(outTask, product.ID, isbn, product.LiveImage, waveTaskDetail.PlannedQuantity, salePrice, cost, fmt.Sprintf("请求外部接口失败: %v", err), db)
|
||||
return fmt.Errorf("请求外部接口失败: %v", err)
|
||||
}
|
||||
|
||||
var resData systemRes.ExternalAPIResponse
|
||||
if err := json.Unmarshal([]byte(resp), &resData); err != nil {
|
||||
return fmt.Errorf("解析响应失败: %v", err)
|
||||
}
|
||||
|
||||
if resData.Code != "200" {
|
||||
s.saveOutTaskLog(outTask, product.ID, isbn, product.LiveImage, waveTaskDetail.PlannedQuantity, salePrice, cost, fmt.Sprintf("外部接口返回错误: code=%s, msg=%s", resData.Code, resData.Msg), db)
|
||||
return fmt.Errorf("外部接口返回错误: code=%s, msg=%s", resData.Code, resData.Msg)
|
||||
}
|
||||
|
||||
s.saveOutTaskLog(outTask, product.ID, isbn, product.LiveImage, waveTaskDetail.PlannedQuantity, salePrice, cost, "成功", db)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveOutTaskLog 保存外部任务日志
|
||||
func (s *ProductService) saveOutTaskLog(outTask models.OutTask, productID int64, isbn string, liveImage []byte, stock, salePrice, cost int64, msg string, db *gorm.DB) {
|
||||
@ -2687,6 +2948,45 @@ func (s *ProductService) convertProductLogToItem(log models.ProductLog) systemRe
|
||||
}
|
||||
}
|
||||
|
||||
// parseImageList 解析图片列表,支持JSON数组和逗号分隔字符串两种格式
|
||||
func (s *ProductService) parseImageList(liveImage datatypes.JSON) []string {
|
||||
if liveImage == nil || len(liveImage) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// 尝试解析为字符串数组
|
||||
var imgList []string
|
||||
if err := json.Unmarshal(liveImage, &imgList); err == nil {
|
||||
// 成功解析为数组,过滤空字符串后返回
|
||||
result := make([]string, 0, len(imgList))
|
||||
for _, img := range imgList {
|
||||
trimmed := strings.TrimSpace(img)
|
||||
if trimmed != "" {
|
||||
result = append(result, trimmed)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 如果解析失败,尝试解析为字符串,然后按逗号分割
|
||||
var imgStr string
|
||||
if err := json.Unmarshal(liveImage, &imgStr); err == nil {
|
||||
// 去除空格并按逗号分割
|
||||
parts := strings.Split(imgStr, ",")
|
||||
result := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
trimmed := strings.TrimSpace(part)
|
||||
if trimmed != "" {
|
||||
result = append(result, trimmed)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 都不成功,返回空数组
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (s *ProductService) getShopTypeName(shopType int8) string {
|
||||
switch shopType {
|
||||
case 1:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user