修正了运险模板保存失败问题
This commit is contained in:
parent
2d00956212
commit
8ffe485fa2
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@ fonts/
|
|||||||
|
|
||||||
# Runtime logs
|
# Runtime logs
|
||||||
runtime/logs/
|
runtime/logs/
|
||||||
|
|
||||||
|
# Test directory (temporarily excluded from git)
|
||||||
|
_test/
|
||||||
|
|||||||
76
config.yaml
76
config.yaml
@ -1,76 +0,0 @@
|
|||||||
server:
|
|
||||||
port: "9090"
|
|
||||||
# host: "https://psi.api.buzhiyushu.cn/"
|
|
||||||
host: "http://192.168.101.213:9090/"
|
|
||||||
|
|
||||||
database:
|
|
||||||
host: 175.27.224.66
|
|
||||||
port: "3306"
|
|
||||||
user: root
|
|
||||||
password: 5e07c0eec1770c94
|
|
||||||
name: psi
|
|
||||||
encrypt_key: "0123456789abcdef0123456789abcdef"
|
|
||||||
|
|
||||||
task_database:
|
|
||||||
host: 36.212.7.35
|
|
||||||
port: "3306"
|
|
||||||
user: zhishu
|
|
||||||
password: KSwx1MDcRW
|
|
||||||
name: task
|
|
||||||
|
|
||||||
jwt:
|
|
||||||
secret: "0123456789abcdef0123456789abcdef"
|
|
||||||
expire_hours: 24
|
|
||||||
|
|
||||||
api_sign:
|
|
||||||
app_key: "psi"
|
|
||||||
app_secret: "psi_api_sign_secret"
|
|
||||||
client_id: "psi"
|
|
||||||
sign_method: "md5"
|
|
||||||
timestamp_tolerance: 300
|
|
||||||
|
|
||||||
log:
|
|
||||||
max_age: 600
|
|
||||||
rotate_time: 600
|
|
||||||
root_path: "./runtime/logs"
|
|
||||||
channel:
|
|
||||||
sql: "/sql/err.log"
|
|
||||||
work: "/work/err.log"
|
|
||||||
request: "/request/err.log"
|
|
||||||
es: "/es/err.log"
|
|
||||||
redis: "/redis/err.log"
|
|
||||||
|
|
||||||
es:
|
|
||||||
host: "http://36.212.12.92:9527"
|
|
||||||
index: "books-from-mysql-v2"
|
|
||||||
username: "elastic"
|
|
||||||
password: "+Tz5qR_KushZ-bPgZ_H-"
|
|
||||||
|
|
||||||
ocr:
|
|
||||||
service_url: "http://127.0.0.1:35569/ocr"
|
|
||||||
exe_url: "./ocr/OCRService.exe"
|
|
||||||
|
|
||||||
external_api:
|
|
||||||
# sync_product_url: "http://192.168.101.127:8080/zhishu/filterSet/save"
|
|
||||||
sync_product_url: "https://api.buzhiyushu.cn/zhishu/filterSet/save"
|
|
||||||
es_update_book_url: "https://book.center.yushutx.com/api/es/updateBookFieldsByISBN"
|
|
||||||
# sync_task_url: "http://192.168.101.156:8080/task/create"
|
|
||||||
sync_task_url: "http://36.212.7.246:8283/task/create"
|
|
||||||
# sync_task_body_url: "http://192.168.101.156:8080/task/setTaskBody"
|
|
||||||
sync_task_body_url: "http://36.212.7.246:8283/task/setTaskBody"
|
|
||||||
timeout: 30
|
|
||||||
|
|
||||||
wangdian:
|
|
||||||
url: "https://api.wangdian.cn/openapi2/purchase_order_push.php"
|
|
||||||
sandbox_url: "https://sandbox.wangdian.cn/openapi2/purchase_order_push.php"
|
|
||||||
provider_query_url: "https://api.wangdian.cn/openapi2/purchase_provider_query.php"
|
|
||||||
provider_query_sandbox: "https://sandbox.wangdian.cn/openapi2/purchase_provider_query.php"
|
|
||||||
warehouse_query_url: "https://api.wangdian.cn/openapi2/warehouse_query.php"
|
|
||||||
warehouse_query_sandbox: "https://sandbox.wangdian.cn/openapi2/warehouse_query.php"
|
|
||||||
goods_query_url: "https://api.wangdian.cn/openapi2/goods_query.php"
|
|
||||||
goods_query_sandbox: "https://sandbox.wangdian.cn/openapi2/goods_query.php"
|
|
||||||
sandbox: true
|
|
||||||
sid: "apidevnew2"
|
|
||||||
appkey: "skxz2-test"
|
|
||||||
appsecret: "85bf423bb"
|
|
||||||
timeout: 30
|
|
||||||
@ -322,6 +322,16 @@ func migrateTenantTables(db *gorm.DB) {
|
|||||||
log.Printf("Config表迁移警告: %v", err)
|
log.Printf("Config表迁移警告: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='仪表盘每日统计表'").AutoMigrate(&models.DashboardDailyStat{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("DashboardDailyStat表迁移警告: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户每日统计表'").AutoMigrate(&models.UserDailyStat{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("UserDailyStat表迁移警告: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
log.Println("租户业务表迁移完成")
|
log.Println("租户业务表迁移完成")
|
||||||
//tableOptions := "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
//tableOptions := "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
|
||||||
//
|
//
|
||||||
@ -412,4 +422,22 @@ func migrateIncrementalTenantTables(db *gorm.DB) {
|
|||||||
log.Println("Config表增量迁移成功")
|
log.Println("Config表增量迁移成功")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !db.Migrator().HasTable(&models.DashboardDailyStat{}) {
|
||||||
|
err := db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='仪表盘每日统计表'").AutoMigrate(&models.DashboardDailyStat{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("DashboardDailyStat表增量迁移警告: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("DashboardDailyStat表增量迁移成功")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !db.Migrator().HasTable(&models.UserDailyStat{}) {
|
||||||
|
err := db.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户每日统计表'").AutoMigrate(&models.UserDailyStat{})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("UserDailyStat表增量迁移警告: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("UserDailyStat表增量迁移成功")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,7 +81,7 @@ func (s *StatistTaskService) GenerateDailyStat(db ...*gorm.DB) error {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.generateUserDailyStat(tx, aboutID, statDate, yesterdayStart, yesterdayEnd); err != nil {
|
if err := s.generateUserDailyStat(tx, mainDB, aboutID, statDate, yesterdayStart, yesterdayEnd); err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
utils.ErrorLog("work", map[string]interface{}{
|
utils.ErrorLog("work", map[string]interface{}{
|
||||||
"source": "定时任务-生成每日统计",
|
"source": "定时任务-生成每日统计",
|
||||||
@ -198,49 +198,66 @@ func (s *StatistTaskService) generateDashboardDailyStat(tx *gorm.DB, statDate in
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generateUserDailyStat 生成用户每日统计
|
// generateUserDailyStat 生成用户每日统计
|
||||||
func (s *StatistTaskService) generateUserDailyStat(tx *gorm.DB, aboutID int64, statDate int64, startDate, endDate int64) error {
|
// mainDB: 主库连接(查询 employee 表),tx: 租户事务(查询 statist/sales_order,写入 user_daily_stat)
|
||||||
type UserStatGroup struct {
|
func (s *StatistTaskService) generateUserDailyStat(tx *gorm.DB, mainDB *gorm.DB, aboutID int64, statDate int64, startDate, endDate int64) error {
|
||||||
|
// 1. 从主库查询该租户下的所有员工
|
||||||
|
type EmployeeBrief struct {
|
||||||
UserID int64 `gorm:"column:user_id"`
|
UserID int64 `gorm:"column:user_id"`
|
||||||
UserName string `gorm:"column:user_name"`
|
UserName string `gorm:"column:user_name"`
|
||||||
ReceivingNum int64 `gorm:"column:receiving_num"`
|
}
|
||||||
OutboundNum int64 `gorm:"column:outbound_num"`
|
var employees []EmployeeBrief
|
||||||
SalesCount int64 `gorm:"column:sales_count"`
|
if err := mainDB.Model(&models.Employee{}).
|
||||||
|
Where("about_id = ? AND deleted_at = ?", aboutID, 0).
|
||||||
|
Select("id as user_id, username as user_name").
|
||||||
|
Find(&employees).Error; err != nil {
|
||||||
|
return fmt.Errorf("查询员工列表失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var userStats []UserStatGroup
|
if len(employees) == 0 {
|
||||||
tx.Table("employee").
|
|
||||||
Select(`
|
|
||||||
employee.id as user_id,
|
|
||||||
employee.username as user_name,
|
|
||||||
COALESCE((SELECT SUM(receiving_num) FROM statist WHERE create_by = employee.id AND stat_date >= ? AND stat_date <= ? AND is_del = ?), 0) as receiving_num,
|
|
||||||
COALESCE((SELECT SUM(outbound_num) FROM statist WHERE create_by = employee.id AND stat_date >= ? AND stat_date <= ? AND is_del = ?), 0) as outbound_num,
|
|
||||||
COALESCE((SELECT COUNT(*) FROM sales_order WHERE create_by = employee.id AND created_at >= ? AND created_at <= ? AND is_del = ?), 0) as sales_count
|
|
||||||
`, startDate, endDate, 0, startDate, endDate, 0, startDate, endDate, 0).
|
|
||||||
Where("employee.about_id = ? AND employee.is_del = ?", aboutID, 0).
|
|
||||||
Scan(&userStats)
|
|
||||||
|
|
||||||
if len(userStats) == 0 {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().Unix()
|
// 2. 提取员工ID列表
|
||||||
for _, userStat := range userStats {
|
userIDs := make([]int64, len(employees))
|
||||||
var existingStat models.UserDailyStat
|
for i, emp := range employees {
|
||||||
err := tx.Where("user_id = ? AND stat_date = ? AND is_del = ?", userStat.UserID, statDate, 0).First(&existingStat).Error
|
userIDs[i] = emp.UserID
|
||||||
|
}
|
||||||
|
|
||||||
if err == nil {
|
// 3. 批量查询租户库的入库/出库统计
|
||||||
if err := tx.Model(&models.UserDailyStat{}).Where("id = ?", existingStat.ID).Update("is_del", 1).Error; err != nil {
|
type UserReceivingStat struct {
|
||||||
continue
|
CreateBy int64 `gorm:"column:create_by"`
|
||||||
|
ReceivingNum int64 `gorm:"column:receiving_num"`
|
||||||
|
OutboundNum int64 `gorm:"column:outbound_num"`
|
||||||
}
|
}
|
||||||
|
var receivingStats []UserReceivingStat
|
||||||
|
tx.Model(&models.Statist{}).
|
||||||
|
Where("create_by IN ? AND stat_date >= ? AND stat_date <= ? AND is_del = ?", userIDs, startDate, endDate, 0).
|
||||||
|
Select("create_by, COALESCE(SUM(receiving_num), 0) as receiving_num, COALESCE(SUM(outbound_num), 0) as outbound_num").
|
||||||
|
Group("create_by").
|
||||||
|
Find(&receivingStats)
|
||||||
|
|
||||||
|
receivingMap := make(map[int64]UserReceivingStat, len(receivingStats))
|
||||||
|
for _, rs := range receivingStats {
|
||||||
|
receivingMap[rs.CreateBy] = rs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4. 写入 user_daily_stat(注:SalesCount=0,sales_order 表无 create_by 字段无法归因到员工)
|
||||||
|
now := time.Now().Unix()
|
||||||
|
for _, emp := range employees {
|
||||||
|
// 软删除已有记录
|
||||||
|
tx.Model(&models.UserDailyStat{}).
|
||||||
|
Where("user_id = ? AND stat_date = ? AND is_del = ?", emp.UserID, statDate, 0).
|
||||||
|
Update("is_del", 1)
|
||||||
|
|
||||||
|
receiving := receivingMap[emp.UserID]
|
||||||
|
|
||||||
newStat := &models.UserDailyStat{
|
newStat := &models.UserDailyStat{
|
||||||
UserID: userStat.UserID,
|
UserID: emp.UserID,
|
||||||
UserName: userStat.UserName,
|
UserName: emp.UserName,
|
||||||
StatDate: statDate,
|
StatDate: statDate,
|
||||||
ReceivingNum: userStat.ReceivingNum,
|
ReceivingNum: receiving.ReceivingNum,
|
||||||
OutboundNum: userStat.OutboundNum,
|
OutboundNum: receiving.OutboundNum,
|
||||||
SalesCount: userStat.SalesCount,
|
SalesCount: 0,
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: now,
|
UpdatedAt: now,
|
||||||
IsDel: 0,
|
IsDel: 0,
|
||||||
@ -249,7 +266,7 @@ func (s *StatistTaskService) generateUserDailyStat(tx *gorm.DB, aboutID int64, s
|
|||||||
if err := tx.Create(newStat).Error; err != nil {
|
if err := tx.Create(newStat).Error; err != nil {
|
||||||
utils.ErrorLog("work", map[string]interface{}{
|
utils.ErrorLog("work", map[string]interface{}{
|
||||||
"source": "生成用户统计",
|
"source": "生成用户统计",
|
||||||
"user_id": userStat.UserID,
|
"user_id": emp.UserID,
|
||||||
"error": fmt.Sprintf("创建用户统计记录失败: %v", err),
|
"error": fmt.Sprintf("创建用户统计记录失败: %v", err),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,28 +27,8 @@ func (s *LogisticsService) GetLogisticsList(req request.QueryLogisticsRequest, d
|
|||||||
req.PageSize = 20
|
req.PageSize = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果提供了 about_id,先查询该租户下的所有仓库
|
|
||||||
var warehouseIDs []int64
|
|
||||||
if req.AboutID > 0 {
|
|
||||||
if err := databaseConn.Model(&models.Warehouse{}).
|
|
||||||
Where("about_id = ? AND is_del = ?", req.AboutID, 0).
|
|
||||||
Pluck("id", &warehouseIDs).Error; err != nil {
|
|
||||||
return nil, 0, errors.New("查询仓库信息失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有找到仓库,直接返回空结果
|
|
||||||
if len(warehouseIDs) == 0 {
|
|
||||||
return []response.LogisticsResponse{}, 0, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query := databaseConn.Model(&models.Logistics{}).Where("del_flag = ?", "0")
|
query := databaseConn.Model(&models.Logistics{}).Where("del_flag = ?", "0")
|
||||||
|
|
||||||
// 如果有仓库ID列表,只查询这些仓库关联的物流模板
|
|
||||||
if len(warehouseIDs) > 0 {
|
|
||||||
query = query.Where("id IN (?)", warehouseIDs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Keyword != "" {
|
if req.Keyword != "" {
|
||||||
query = query.Where("template_name LIKE ? OR delivery_province LIKE ? OR delivery_city LIKE ?",
|
query = query.Where("template_name LIKE ? OR delivery_province LIKE ? OR delivery_city LIKE ?",
|
||||||
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
|
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
|
||||||
|
|||||||
@ -615,6 +615,33 @@ func (s *ProcessService) submitOrderOperation(orderID, waveTaskID int64, items [
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 入库时回写商品的 warehouse_id、location_id,方便前台查询
|
||||||
|
if changeType == constant.InventoryChangeInbound {
|
||||||
|
productUpdates := make(map[int64]map[string]interface{})
|
||||||
|
for _, op := range inventoryOpMap {
|
||||||
|
if _, ok := productUpdates[op.key.productID]; !ok {
|
||||||
|
productUpdates[op.key.productID] = map[string]interface{}{
|
||||||
|
"warehouse_id": op.key.warehouseID,
|
||||||
|
"location_id": op.locationID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for pid, pu := range productUpdates {
|
||||||
|
wid := pu["warehouse_id"].(int64)
|
||||||
|
lid := pu["location_id"].(int64)
|
||||||
|
// 查名称
|
||||||
|
var wh models.Warehouse
|
||||||
|
tx.Where("id = ?", wid).Select("name").First(&wh)
|
||||||
|
var loc models.Location
|
||||||
|
tx.Where("id = ?", lid).Select("code").First(&loc)
|
||||||
|
pu["warehouse_name"] = wh.Name
|
||||||
|
pu["location_name"] = loc.Code
|
||||||
|
if err := tx.Model(&models.Product{}).Where("id = ? AND is_del = 0", pid).Updates(pu).Error; err != nil {
|
||||||
|
return fmt.Errorf("回写商品仓库/库位失败(product_id=%d): %v", pid, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.batchUpdateOrderItems(tx, orderItems, changeType); err != nil {
|
if err := s.batchUpdateOrderItems(tx, orderItems, changeType); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user