组织初始化接口 GET /api/auth/organizations 现在为每项授权公司附带
warehouse 摘要({id, name, status, location: {id, name, status} | null} | null),
结构与切换接口一致,供普通用户在公司切换器直接展示,无需放开管理员仓库配置接口。
- model:新增 WarehouseSummary/LocationSummary/OrganizationSummary,
OrganizationAccess 每项改为内嵌公司资料再加 warehouse 摘要。
- repository:新增 WarehouseRepository.Summary 复用切换接口的解析规则;
ListAccessible 逐公司补齐摘要,仓库或库位配置不唯一时报错而非随意取第一条,
无仓库、无库位或已停用如实返回,不回退旧公司数据。
- service:Switch 复用 List 已解析的摘要,响应格式保持不变。
- 测试:新增服务层 sqlmock 用例与仓储层 MySQL 集成用例,
覆盖启用唯一仓库加启用库位、无仓库、仓库停用三类。
72 lines
3.2 KiB
Go
72 lines
3.2 KiB
Go
package service
|
||
|
||
import (
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/DATA-DOG/go-sqlmock"
|
||
"github.com/wmms/wmms/pkg/database"
|
||
)
|
||
|
||
func organizationAccessMock(t *testing.T) sqlmock.Sqlmock {
|
||
t.Helper()
|
||
db, mock, err := sqlmock.New()
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
previous := database.DB
|
||
database.DB = db
|
||
t.Cleanup(func() { database.DB = previous; db.Close() })
|
||
return mock
|
||
}
|
||
|
||
// 组织初始化列表要为每家公司附带与切换接口一致的仓库摘要。这里覆盖
|
||
// 无仓库(null)、仓库停用(如实返回停用状态)、启用唯一仓库加启用库位三类。
|
||
func TestOrganizationAccessListIncludesWarehouseSummary(t *testing.T) {
|
||
mock := organizationAccessMock(t)
|
||
now := time.Now()
|
||
organizationRows := sqlmock.NewRows([]string{"id", "code", "name", "status", "default_timezone", "created_at", "updated_at", "is_default"}).
|
||
AddRow(2, "TWO", "无仓库公司", "active", "Asia/Shanghai", now, now, false).
|
||
AddRow(3, "THREE", "停用仓库公司", "active", "Asia/Shanghai", now, now, false).
|
||
AddRow(4, "FOUR", "启用仓库公司", "active", "Asia/Shanghai", now, now, true)
|
||
mock.ExpectQuery("SELECT o.id,o.code,o.name,o.status").WithArgs(int64(7), int64(7)).WillReturnRows(organizationRows)
|
||
|
||
warehouseColumns := []string{"id", "organization_id", "code", "name", "status", "location_id", "location_code", "location_name", "location_status"}
|
||
// 无仓库:查询返回空集,摘要为 null。
|
||
mock.ExpectQuery("SELECT w.id, w.organization_id").WithArgs(int64(2)).WillReturnRows(sqlmock.NewRows(warehouseColumns))
|
||
// 仓库停用:仍返回该公司自己的仓库与库位,状态为停用。
|
||
mock.ExpectQuery("SELECT w.id, w.organization_id").WithArgs(int64(3)).
|
||
WillReturnRows(sqlmock.NewRows(warehouseColumns).AddRow(30, 3, "D3", "停用仓库", "inactive", 31, "L3", "停用仓库的库位", "active"))
|
||
// 启用唯一仓库加启用库位。
|
||
mock.ExpectQuery("SELECT w.id, w.organization_id").WithArgs(int64(4)).
|
||
WillReturnRows(sqlmock.NewRows(warehouseColumns).AddRow(40, 4, "D4", "启用仓库", "active", 41, "L4", "启用仓库的库位", "active"))
|
||
|
||
access, err := NewOrganizationAccessService().List(7)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(access.Organizations) != 3 || access.DefaultOrganizationID == nil || *access.DefaultOrganizationID != 4 {
|
||
t.Fatalf("公司列表错误 %+v", access)
|
||
}
|
||
byID := make(map[int64]int, len(access.Organizations))
|
||
for i, item := range access.Organizations {
|
||
byID[item.ID] = i
|
||
}
|
||
if warehouse := access.Organizations[byID[2]].Warehouse; warehouse != nil {
|
||
t.Fatalf("无仓库公司应返回空摘要,实际 %+v", warehouse)
|
||
}
|
||
disabled := access.Organizations[byID[3]].Warehouse
|
||
if disabled == nil || disabled.ID != 30 || disabled.Status != "inactive" ||
|
||
disabled.Location == nil || disabled.Location.ID != 31 || disabled.Location.Status != "active" {
|
||
t.Fatalf("停用仓库摘要错误 %+v", disabled)
|
||
}
|
||
enabled := access.Organizations[byID[4]].Warehouse
|
||
if enabled == nil || enabled.ID != 40 || enabled.Status != "active" ||
|
||
enabled.Location == nil || enabled.Location.ID != 41 || enabled.Location.Status != "active" {
|
||
t.Fatalf("启用仓库摘要错误 %+v", enabled)
|
||
}
|
||
if err := mock.ExpectationsWereMet(); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|