feat(业务用户组): AUG26-003 业务用户组与店铺负责人分组导入
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Failing after 1h43m42s
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Failing after 1h43m42s
- 迁移 000221:新增 tb_business_user_group、tb_business_user_group_member、tb_shop_business_owner_import_task,成员一账号一行由部分唯一索引保证,店铺所属组按当前负责人实时推导,不回填历史分组。 - 用户组 CRUD、成员改组/清空归属、店铺批量交接(原子失败不部分写入)。 - 店铺负责人 CSV 导入任务:逐行独立事务、逐行明细、任务级与行级失败分离。 - 读侧推导与筛选:未分组、业务线、停用组可筛出并带停用标记。 - 补齐操作审计动作与资源、openapi 清单、发布门禁巡检表清单。 - 归档 add-shop-salesperson-groups 变更并同步 openspec/specs/business-user-group,补齐 AUG26-003 验证证据链。
This commit is contained in:
@@ -1164,7 +1164,8 @@
|
||||
"entry": "GET /api/admin/shops",
|
||||
"capability": "identity-access",
|
||||
"requirements": [
|
||||
"identity-access::数据范围拒绝"
|
||||
"identity-access::数据范围拒绝",
|
||||
"business-user-group::店铺负责人和所属组实时推导"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
@@ -1201,7 +1202,8 @@
|
||||
"entry": "GET /api/admin/shops/{id}",
|
||||
"capability": "identity-access",
|
||||
"requirements": [
|
||||
"identity-access::数据范围拒绝"
|
||||
"identity-access::数据范围拒绝",
|
||||
"business-user-group::店铺负责人和所属组实时推导"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
@@ -1223,6 +1225,16 @@
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "GET /api/admin/shops/{shop_id}/commission-records/{id}",
|
||||
"capability": "agent-funds-commission",
|
||||
"requirements": [
|
||||
"agent-funds-commission::回溯明细关联查询与导出",
|
||||
"identity-access::数据范围拒绝"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "GET /api/admin/shops/{shop_id}/commission-stats",
|
||||
@@ -3585,6 +3597,7 @@
|
||||
"requirements": [
|
||||
"agent-funds-commission::退款佣金回扣可靠完成",
|
||||
"agent-funds-commission::退款后处理可补偿",
|
||||
"agent-funds-commission::套餐退款佣金回溯",
|
||||
"order-refund-exchange::退款终态事实与失败分类"
|
||||
],
|
||||
"classification": "route_index_or_infrastructure"
|
||||
@@ -4010,5 +4023,114 @@
|
||||
"agent-distribution-withdrawal::提现冻结与企业微信终审"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "POST /api/admin/business-user-groups",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "GET /api/admin/business-user-groups",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "GET /api/admin/business-user-groups/{id}",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "PUT /api/admin/business-user-groups/{id}",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "DELETE /api/admin/business-user-groups/{id}",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "PUT /api/admin/business-user-groups/{id}/members",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "DELETE /api/admin/business-user-groups/members",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::业务用户组生命周期与成员归属"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "PUT /api/admin/shops/business-owner/batch",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::店铺负责人批量交接",
|
||||
"identity-access::数据范围拒绝"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "POST /api/admin/shops/business-owner-imports",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::店铺负责人 CSV 导入"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "GET /api/admin/shops/business-owner-imports",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::店铺负责人 CSV 导入"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "http",
|
||||
"entry": "GET /api/admin/shops/business-owner-imports/{id}",
|
||||
"capability": "business-user-group",
|
||||
"requirements": [
|
||||
"business-user-group::店铺负责人 CSV 导入"
|
||||
],
|
||||
"classification": "behavior"
|
||||
},
|
||||
{
|
||||
"entry_type": "async",
|
||||
"entry": "constants.TaskTypeShopBusinessOwnerImport",
|
||||
"capability": "infrastructure",
|
||||
"requirements": [
|
||||
"business-user-group::店铺负责人 CSV 导入"
|
||||
],
|
||||
"classification": "route_index_or_infrastructure"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3358,5 +3358,213 @@
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"capability": "agent-funds-commission",
|
||||
"requirement": "套餐退款佣金回溯",
|
||||
"spec": "openspec/specs/agent-funds-commission/spec.md",
|
||||
"entries": [
|
||||
"constants.TaskTypeRefundCommissionRecovery"
|
||||
],
|
||||
"handler_consumer_job": [
|
||||
"internal/service/refund/approval_decision.go",
|
||||
"internal/infrastructure/commissiondelivery/event.go",
|
||||
"cmd/worker/main.go"
|
||||
],
|
||||
"application_service_query": [
|
||||
"internal/service/refund/clawback.go"
|
||||
],
|
||||
"domain_state_amount": [
|
||||
"internal/model/commission_clawback.go",
|
||||
"pkg/constants/iot.go"
|
||||
],
|
||||
"store_migration_config": [
|
||||
"internal/store/postgres/commission_record_store.go",
|
||||
"migrations/000220_add_commission_clawback_record.up.sql"
|
||||
],
|
||||
"verification": {
|
||||
"command": "grep -nE 'uk_commission_clawback_refund_original|chk_commission_clawback_amount|chk_commission_clawback_withdrawable|chk_commission_clawback_status' migrations/000220_add_commission_clawback_record.up.sql",
|
||||
"literal_output": [
|
||||
"23: CONSTRAINT uk_commission_clawback_refund_original UNIQUE (refund_id, original_commission_id),",
|
||||
"25: CONSTRAINT chk_commission_clawback_amount CHECK (amount < 0),",
|
||||
"26: CONSTRAINT chk_commission_clawback_withdrawable CHECK (withdrawable = FALSE),",
|
||||
"27: CONSTRAINT chk_commission_clawback_status CHECK (status = 5)"
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"capability": "agent-funds-commission",
|
||||
"requirement": "回溯明细关联查询与导出",
|
||||
"spec": "openspec/specs/agent-funds-commission/spec.md",
|
||||
"entries": [
|
||||
"/api/admin/shops/{shop_id}/commission-records",
|
||||
"/api/admin/shops/{shop_id}/commission-records/{id}"
|
||||
],
|
||||
"handler_consumer_job": [
|
||||
"internal/routes/shop.go",
|
||||
"internal/handler/admin/shop_commission.go"
|
||||
],
|
||||
"application_service_query": [
|
||||
"internal/service/shop_commission/service.go"
|
||||
],
|
||||
"domain_state_amount": [
|
||||
"internal/model/dto/shop_commission_dto.go"
|
||||
],
|
||||
"store_migration_config": [
|
||||
"internal/store/postgres/commission_record_store.go",
|
||||
"internal/exporter/commission_record_scene.go"
|
||||
],
|
||||
"verification": {
|
||||
"command": "grep -n 'ledger_clawback' internal/store/postgres/commission_record_store.go internal/exporter/commission_record_scene.go",
|
||||
"literal_output": [
|
||||
"internal/store/postgres/commission_record_store.go:118:\t\tRaw(\"SELECT * FROM (?) AS ledger_original UNION ALL SELECT * FROM (?) AS ledger_clawback\", original, clawback)",
|
||||
"internal/exporter/commission_record_scene.go:60:\t\tRaw(\"SELECT * FROM (?) AS ledger_original UNION ALL SELECT * FROM (?) AS ledger_clawback\","
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"capability": "business-user-group",
|
||||
"requirement": "业务用户组生命周期与成员归属",
|
||||
"spec": "openspec/specs/business-user-group/spec.md",
|
||||
"entries": [
|
||||
"/api/admin/business-user-groups",
|
||||
"/api/admin/business-user-groups/{id}",
|
||||
"/api/admin/business-user-groups/{id}/members",
|
||||
"/api/admin/business-user-groups/members"
|
||||
],
|
||||
"handler_consumer_job": [
|
||||
"internal/routes/business_user_group.go",
|
||||
"internal/handler/admin/business_user_group.go"
|
||||
],
|
||||
"application_service_query": [
|
||||
"internal/application/businessusergroup/service.go"
|
||||
],
|
||||
"domain_state_amount": [
|
||||
"internal/model/business_user_group.go",
|
||||
"pkg/constants/business_user_group.go"
|
||||
],
|
||||
"store_migration_config": [
|
||||
"internal/store/postgres/business_user_group_store.go",
|
||||
"migrations/000221_add_business_user_group_and_shop_owner_import.up.sql"
|
||||
],
|
||||
"verification": {
|
||||
"command": "grep -nE '用户组仍有成员|目标用户组已停用|uk_business_user_group_code|IsAvailablePlatformBusinessOwner' internal/application/businessusergroup/service.go",
|
||||
"literal_output": [
|
||||
"170:\t\t\treturn errors.New(errors.CodeInvalidStatus, \"用户组仍有成员,只能停用或先移走成员\")",
|
||||
"202:\t\t\treturn errors.New(errors.CodeInvalidStatus, \"目标用户组已停用,不能作为成员归属目标\")",
|
||||
"316:\t\tif constants.IsAvailablePlatformBusinessOwner(account.UserType, account.Status, account.DeletedAt.Valid) {",
|
||||
"338:\tif strings.Contains(strings.ToLower(err.Error()), \"uk_business_user_group_code\") {"
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"capability": "business-user-group",
|
||||
"requirement": "店铺负责人和所属组实时推导",
|
||||
"spec": "openspec/specs/business-user-group/spec.md",
|
||||
"entries": [
|
||||
"/api/admin/shops",
|
||||
"/api/admin/shops/{id}"
|
||||
],
|
||||
"handler_consumer_job": [
|
||||
"internal/routes/shop.go",
|
||||
"internal/query/shop/business_owner.go"
|
||||
],
|
||||
"application_service_query": [
|
||||
"internal/query/shop/business_owner.go"
|
||||
],
|
||||
"domain_state_amount": [
|
||||
"internal/model/dto/shop_dto.go",
|
||||
"internal/model/business_user_group.go"
|
||||
],
|
||||
"store_migration_config": [
|
||||
"migrations/000221_add_business_user_group_and_shop_owner_import.up.sql"
|
||||
],
|
||||
"verification": {
|
||||
"command": "grep -nE 'EXISTS \\(SELECT 1 FROM tb_business_user_group_member|ungroupedCondition' internal/query/shop/business_owner.go",
|
||||
"literal_output": [
|
||||
"126:\t\t\t\"EXISTS (SELECT 1 FROM tb_business_user_group_member m WHERE m.account_id = tb_shop.business_owner_account_id AND m.deleted_at IS NULL AND m.business_user_group_id = ?)\",",
|
||||
"131:\t\t\t\"EXISTS (SELECT 1 FROM tb_business_user_group_member m WHERE m.account_id = tb_shop.business_owner_account_id AND m.deleted_at IS NULL AND EXISTS (SELECT 1 FROM tb_business_user_group g WHERE g.id = m.business_user_group_id AND g.deleted_at IS NULL AND g.business_line = ?))\",",
|
||||
"136:\t\tconst ungroupedCondition = \"(tb_shop.business_owner_account_id IS NULL OR NOT EXISTS (SELECT 1 FROM tb_business_user_group_member m WHERE m.account_id = tb_shop.business_owner_account_id AND m.deleted_at IS NULL))\"",
|
||||
"138:\t\t\tdb = db.Where(ungroupedCondition)",
|
||||
"140:\t\t\tdb = db.Where(\"NOT \" + ungroupedCondition)"
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"capability": "business-user-group",
|
||||
"requirement": "店铺负责人批量交接",
|
||||
"spec": "openspec/specs/business-user-group/spec.md",
|
||||
"entries": [
|
||||
"/api/admin/shops/business-owner/batch"
|
||||
],
|
||||
"handler_consumer_job": [
|
||||
"internal/routes/business_user_group.go",
|
||||
"internal/handler/admin/business_user_group.go"
|
||||
],
|
||||
"application_service_query": [
|
||||
"internal/application/shop/batch_business_owner.go"
|
||||
],
|
||||
"domain_state_amount": [
|
||||
"internal/model/dto/shop_dto.go"
|
||||
],
|
||||
"store_migration_config": [
|
||||
"internal/infrastructure/audit/business_user_group.go"
|
||||
],
|
||||
"verification": {
|
||||
"command": "grep -nE 'batchBusinessOwnerFailureMessage' internal/application/shop/batch_business_owner.go",
|
||||
"literal_output": [
|
||||
"102:\t\t\treturn errors.New(errors.CodeForbidden, batchBusinessOwnerFailureMessage)",
|
||||
"122:\t\t\treturn errors.New(errors.CodeForbidden, batchBusinessOwnerFailureMessage)",
|
||||
"203:// batchBusinessOwnerFailureMessage 复用平台维护入口的统一失败文案,不区分无权、不存在与已删除。",
|
||||
"204:const batchBusinessOwnerFailureMessage = constants.PlatformManagementForbiddenMessage",
|
||||
"243:\t\treturn nil, errors.New(errors.CodeForbidden, batchBusinessOwnerFailureMessage)",
|
||||
"249:\t\treturn nil, errors.New(errors.CodeForbidden, batchBusinessOwnerFailureMessage)"
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"capability": "business-user-group",
|
||||
"requirement": "店铺负责人 CSV 导入",
|
||||
"spec": "openspec/specs/business-user-group/spec.md",
|
||||
"entries": [
|
||||
"/api/admin/shops/business-owner-imports",
|
||||
"/api/admin/shops/business-owner-imports/{id}",
|
||||
"constants.TaskTypeShopBusinessOwnerImport"
|
||||
],
|
||||
"handler_consumer_job": [
|
||||
"internal/routes/business_user_group.go",
|
||||
"internal/handler/admin/shop_business_owner_import.go"
|
||||
],
|
||||
"application_service_query": [
|
||||
"internal/task/shop_business_owner_import.go",
|
||||
"pkg/utils/encoding.go"
|
||||
],
|
||||
"domain_state_amount": [
|
||||
"internal/model/shop_business_owner_import_task.go",
|
||||
"pkg/constants/shop_business_owner_import.go"
|
||||
],
|
||||
"store_migration_config": [
|
||||
"internal/store/postgres/shop_business_owner_import_task_store.go",
|
||||
"migrations/000221_add_business_user_group_and_shop_owner_import.up.sql"
|
||||
],
|
||||
"verification": {
|
||||
"command": "grep -nE 'ShopBusinessOwnerImportColumns|ShopBusinessOwnerImportErrorFileFormat|ShopBusinessOwnerImportRowErrorOwnerForbidden|ShopOwnerImportAccessDescription' pkg/constants/shop_business_owner_import.go",
|
||||
"literal_output": [
|
||||
"29:// ShopBusinessOwnerImportColumns 表示导入文件首行必须完全一致的固定列序。",
|
||||
"30:var ShopBusinessOwnerImportColumns = []string{\"店铺编码\", \"操作类型\", \"业务员登录账号\", \"备注\"}",
|
||||
"34:\t// ShopBusinessOwnerImportErrorFileFormat 表示文件格式或表头与固定列序不符。",
|
||||
"35:\tShopBusinessOwnerImportErrorFileFormat = \"文件格式或表头与固定列序不符\"",
|
||||
"50:\t// ShopBusinessOwnerImportRowErrorOwnerForbidden 表示清空却填写了业务员登录账号。",
|
||||
"51:\tShopBusinessOwnerImportRowErrorOwnerForbidden = \"清空不得填写业务员登录账号\"",
|
||||
"59:\t// ShopOwnerImportAccessDescription 表示店铺负责人导入入口的角色说明。",
|
||||
"60:\tShopOwnerImportAccessDescription = \"仅超级管理员和平台账号可访问,代理与企业账号返回 403。\""
|
||||
],
|
||||
"exit_status": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user