package delivery import ( "time" "git.apinb.com/bsm-sdk/core/errcode" "git.apinb.com/bsm-sdk/core/infra" "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common" "git.apinb.com/heqiapp/platforms/backend/api/internal/models" "github.com/gin-gonic/gin" "gorm.io/gorm" ) func scopedStaff(ctx *gin.Context, identity string, point models.DeliveryBasic) (models.StaffAccount, bool) { var staff models.StaffAccount if err := common.ActiveRecords(db()).Where("identity = ? AND gas_basic_id = ? AND delivery_basic_id = ?", identity, point.GasBasicID, point.ID).First(&staff).Error; err != nil { common.RespondRecordError(ctx, err) return staff, false } return staff, true } func ListStaff(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } query := common.ActiveRecords(db().Model(&models.StaffAccount{})). Where("gas_basic_id = ? AND delivery_basic_id = ? AND role_code = ?", point.GasBasicID, point.ID, "delivery") listScoped(ctx, &models.StaffAccount{}, query, "staff_account.created_at desc") } func GetStaff(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var staff models.StaffAccount respondRecord(ctx, common.ActiveRecords(db()).Where("identity = ? AND gas_basic_id = ? AND delivery_basic_id = ? AND role_code = ?", ctx.Param("identity"), point.GasBasicID, point.ID, "delivery"), &staff) } type staffRequest struct { Username string `json:"username"` Password string `json:"password"` Name string `json:"name" binding:"required,max=64"` Phone string `json:"phone" binding:"max=32"` Avatar string `json:"avatar" binding:"max=512"` WorkStatus string `json:"work_status" binding:"required"` } func CreateStaff(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var request staffRequest if err := ctx.ShouldBindJSON(&request); err != nil || request.Username == "" || !common.IsValidAccountPassword(request.Password) || (request.WorkStatus != "on_duty" && request.WorkStatus != "off_duty") { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } hash, err := common.PasswordHash(request.Password) if err != nil { infra.Response.Error(ctx, err) return } staff := models.StaffAccount{ Entity: common.NewEntity(common.StatusEnable), Username: request.Username, PasswordHash: hash, Name: request.Name, Phone: request.Phone, Avatar: request.Avatar, RoleCode: "delivery", GasBasicID: point.GasBasicID, DeliveryBasicID: point.ID, WorkStatus: request.WorkStatus, } if err := db().Create(&staff).Error; err != nil { infra.Response.Error(ctx, err) return } common.RespondCreatedResource(ctx, staff) } func UpdateStaff(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } if _, ok := scopedStaff(ctx, ctx.Param("identity"), point); !ok { return } var request staffRequest if err := ctx.ShouldBindJSON(&request); err != nil || (request.WorkStatus != "on_duty" && request.WorkStatus != "off_duty") { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } common.UpdateAllowedByIdentity(ctx, &models.StaffAccount{}, gin.H{ "name": request.Name, "phone": request.Phone, "avatar": request.Avatar, "work_status": request.WorkStatus, }, []string{"name", "phone", "avatar", "work_status"}) } func ResetStaffPassword(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } staff, ok := scopedStaff(ctx, ctx.Param("identity"), point) if !ok { return } var request struct { Password string `json:"password" binding:"required"` } if err := ctx.ShouldBindJSON(&request); err != nil || !common.IsValidAccountPassword(request.Password) { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } hash, _ := common.PasswordHash(request.Password) if err := db().Model(&staff).Update("password_hash", hash).Error; err != nil { infra.Response.Error(ctx, err) return } infra.Response.Success(ctx, gin.H{"changed": true}) } func UpdateStaffStatus(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } if _, ok := scopedStaff(ctx, ctx.Param("identity"), point); ok { common.UpdateRecordStatus(ctx, &models.StaffAccount{}) } } func ArchiveStaff(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } staff, ok := scopedStaff(ctx, ctx.Param("identity"), point) if !ok { return } var count int64 if err := db().Model(&models.GasorderBasic{}). Where("staff_account_id = ? AND order_status NOT IN ?", staff.ID, []int{common.StatusCompleted, common.StatusCancelled}). Count(&count).Error; err != nil || count > 0 { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } if err := db().Transaction(func(tx *gorm.DB) error { if err := tx.Model(&models.StaffCredential{}).Where("staff_account_id = ?", staff.ID). Update("status", common.StatusArchived).Error; err != nil { return err } return tx.Model(&staff).Update("status", common.StatusArchived).Error }); err != nil { infra.Response.Error(ctx, err) return } infra.Response.Success(ctx, gin.H{"archived": true}) } func credentialQuery(point models.DeliveryBasic) *gorm.DB { return common.ActiveRecords(db().Model(&models.StaffCredential{})). Joins("JOIN staff_account ON staff_account.id = staff_credential.staff_account_id"). Where("staff_account.delivery_basic_id = ? AND staff_account.gas_basic_id = ? AND staff_account.role_code = ?", point.ID, point.GasBasicID, "delivery") } func ListCredential(ctx *gin.Context) { point, _, ok := currentScope(ctx) if ok { listScoped(ctx, &models.StaffCredential{}, credentialQuery(point), "staff_credential.created_at desc") } } func GetCredential(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var credential models.StaffCredential respondRecord(ctx, credentialQuery(point).Where("staff_credential.identity = ?", ctx.Param("identity")), &credential) } type credentialRequest struct { StaffIdentity string `json:"staff_account_identity" binding:"required"` CredentialType string `json:"credential_type" binding:"required,max=64"` CredentialNo string `json:"credential_no" binding:"max=128"` ExpiredAt *time.Time `json:"expired_at"` } func CreateCredential(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var request credentialRequest if err := ctx.ShouldBindJSON(&request); err != nil { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } staff, ok := scopedStaff(ctx, request.StaffIdentity, point) if !ok { return } item := models.StaffCredential{ Entity: common.NewEntity(common.StatusEnable), StaffAccountID: staff.ID, CredentialType: request.CredentialType, CredentialNo: request.CredentialNo, ExpiredAt: request.ExpiredAt, } if err := db().Create(&item).Error; err != nil { infra.Response.Error(ctx, err) return } common.RespondCreatedResource(ctx, item) } func UpdateCredential(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var existing models.StaffCredential if err := credentialQuery(point).Where("staff_credential.identity = ?", ctx.Param("identity")).First(&existing).Error; err != nil { common.RespondRecordError(ctx, err) return } var request credentialRequest if err := ctx.ShouldBindJSON(&request); err != nil { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } staff, ok := scopedStaff(ctx, request.StaffIdentity, point) if !ok { return } if err := db().Model(&existing).Updates(map[string]any{ "staff_account_id": staff.ID, "credential_type": request.CredentialType, "credential_no": request.CredentialNo, "expired_at": request.ExpiredAt, }).Error; err != nil { infra.Response.Error(ctx, err) return } infra.Response.Success(ctx, gin.H{"updated": true}) } func UpdateCredentialStatus(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var count int64 if err := credentialQuery(point).Where("staff_credential.identity = ?", ctx.Param("identity")).Count(&count).Error; err != nil || count != 1 { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } common.UpdateRecordStatus(ctx, &models.StaffCredential{}) } func ArchiveCredential(ctx *gin.Context) { point, _, ok := currentScope(ctx) if !ok { return } var count int64 if err := credentialQuery(point).Where("staff_credential.identity = ?", ctx.Param("identity")).Count(&count).Error; err != nil || count != 1 { infra.Response.Error(ctx, errcode.ErrInvalidArgument) return } common.ArchiveRecord(ctx, &models.StaffCredential{}) }