修复气站合同用户权限与服务关系边界

This commit is contained in:
czl231
2026-08-18 22:49:14 +08:00
parent 61a61f916b
commit 9a31cadf5f
27 changed files with 635 additions and 59 deletions

View File

@@ -1,5 +1,5 @@
// 功能描述:实现平台总后台的用户地址与服务关系管理。
// 版本v1.1
// 版本v1.2
package user
import (
@@ -176,6 +176,8 @@ type serviceRelationRequest struct {
StaffAccountIdentity string `json:"staff_account_identity"`
}
var errUserServiceTransferBlocked = errors.New("用户存在生效合同、未完成订单或未关闭工单,请处理完成后再变更所属气站")
func ListUserServiceRelation(ctx *gin.Context) { common.ListPage[models.UserServiceRelation](ctx) }
func GetUserServiceRelation(ctx *gin.Context) { common.GetByIdentity[models.UserServiceRelation](ctx) }
func CreateUserServiceRelation(ctx *gin.Context) {
@@ -206,7 +208,7 @@ func UpdateUserServiceRelation(ctx *gin.Context) {
return
}
var current models.UserServiceRelation
if err := common.ActiveRecords(impl.DBService).Select("user_account_id").
if err := common.ActiveRecords(impl.DBService).Select("user_account_id", "gas_basic_id").
Where("identity = ?", ctx.Param("identity")).First(&current).Error; err != nil {
common.RespondRecordError(ctx, err)
return
@@ -215,9 +217,88 @@ func UpdateUserServiceRelation(ctx *gin.Context) {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
if current.GasBasicID != gasBasicID {
blocked, err := userServiceTransferBlocked(impl.DBService, current)
if err != nil {
infra.Response.Error(ctx, err)
return
}
if blocked {
infra.Response.Error(ctx, errUserServiceTransferBlocked)
return
}
}
common.UpdateAllowedByIdentity(ctx, &models.UserServiceRelation{}, gin.H{"user_account_id": userAccountID, "gas_basic_id": gasBasicID, "delivery_basic_id": deliveryBasicID, "staff_account_id": staffAccountID}, []string{"user_account_id", "gas_basic_id", "delivery_basic_id", "staff_account_id"})
}
// UpdateUserServiceRelationStatus 更新服务关系状态;归档必须执行履约阻断检查。
func UpdateUserServiceRelationStatus(ctx *gin.Context) {
var request struct {
Status int `json:"status" binding:"required"`
}
if err := ctx.ShouldBindJSON(&request); err != nil || !common.IsGenericRecordStatus(request.Status) {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
if request.Status == common.StatusArchived && !allowUserServiceRelationRemoval(ctx) {
return
}
common.UpdateAllowedByIdentity(ctx, &models.UserServiceRelation{}, gin.H{"status": request.Status}, []string{"status"})
}
// ArchiveUserServiceRelation 归档服务关系;存在未完成履约业务时拒绝解除归属。
func ArchiveUserServiceRelation(ctx *gin.Context) {
if !allowUserServiceRelationRemoval(ctx) {
return
}
common.UpdateAllowedByIdentity(ctx, &models.UserServiceRelation{}, gin.H{"status": common.StatusArchived}, []string{"status"})
}
// allowUserServiceRelationRemoval 校验当前服务关系是否允许解除。
func allowUserServiceRelationRemoval(ctx *gin.Context) bool {
var current models.UserServiceRelation
if err := common.ActiveRecords(impl.DBService).Where("identity = ?", ctx.Param("identity")).First(&current).Error; err != nil {
common.RespondRecordError(ctx, err)
return false
}
blocked, err := userServiceTransferBlocked(impl.DBService, current)
if err != nil {
infra.Response.Error(ctx, err)
return false
}
if blocked {
infra.Response.Error(ctx, errUserServiceTransferBlocked)
return false
}
return true
}
// userServiceTransferBlocked 检查原气站仍在履约中的合同、订单和工单。
func userServiceTransferBlocked(databaseService *gorm.DB, relation models.UserServiceRelation) (bool, error) {
if relation.GasBasicID == 0 {
return false, nil
}
checks := []struct {
model any
where string
args []any
}{
{&models.GasorderContract{}, "user_account_id = ? AND gas_basic_id = ? AND status <> ? AND contract_status = ?", []any{relation.UserAccountID, relation.GasBasicID, common.StatusArchived, common.StatusActive}},
{&models.GasorderBasic{}, "user_account_id = ? AND gas_basic_id = ? AND status <> ? AND order_status NOT IN ?", []any{relation.UserAccountID, relation.GasBasicID, common.StatusArchived, []int{common.StatusCompleted, common.StatusCancelled}}},
{&models.CsTicket{}, "user_account_id = ? AND gas_basic_id = ? AND status <> ? AND ticket_status = ?", []any{relation.UserAccountID, relation.GasBasicID, common.StatusArchived, common.StatusOpen}},
}
for _, check := range checks {
var count int64
if err := databaseService.Model(check.model).Where(check.where, check.args...).Count(&count).Error; err != nil {
return false, err
}
if count > 0 {
return true, nil
}
}
return false, nil
}
func resolveServiceRelation(ctx *gin.Context, request serviceRelationRequest) (uint64, uint64, uint64, uint64, bool) {
userAccountID, err := common.ResolveIdentityID(&models.UserAccount{}, request.UserAccountIdentity, true)
if err != nil {