updated for bulk update

This commit is contained in:
areeqakbr 2025-06-15 08:19:29 +07:00
parent 8afca3054a
commit 1aee7e2bda
4 changed files with 604 additions and 19 deletions

View File

@ -1,11 +1,16 @@
package controller package controller
import ( import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http" "net/http"
"users_management/m/middleware" "users_management/m/middleware"
"users_management/m/model/dto/req" "users_management/m/model/dto/req"
"users_management/m/usecase" "users_management/m/usecase"
"users_management/m/utils/common" "users_management/m/utils/common"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
) )
@ -35,9 +40,87 @@ func (c *DeviceDetailsController) Route() {
deviceDetails.POST("/:id/assign-customer", c.assignCustomer) deviceDetails.POST("/:id/assign-customer", c.assignCustomer)
deviceDetails.PUT("/:id/port-usage", c.updatePortUsage) // New endpoint deviceDetails.PUT("/:id/port-usage", c.updatePortUsage) // New endpoint
deviceDetails.PUT("/:id/port-assignments", c.updatePortAssignments) // New endpoint deviceDetails.PUT("/:id/port-assignments", c.updatePortAssignments) // New endpoint
deviceDetails.PUT("/:id/update-customer-by-port", c.updateCustomerByPort) // Updated endpoint name
deviceDetails.PUT("/:id/bulk-update-customers-by-port", c.bulkUpdateCustomersByPort) // Updated endpoint name
deviceDetails.DELETE("/:id/remove-customer-by-port", c.removeCustomerByPort)
} }
} }
func (c *DeviceDetailsController) updateCustomerByPort(ctx *gin.Context) {
id := ctx.Param("id")
deviceID, err := uuid.Parse(id)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid device ID")
return
}
var request req.UpdateCustomerByPortDTO
if err := ctx.ShouldBindJSON(&request); err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return
}
err = c.deviceDetailsUC.UpdateCustomerByPort(deviceID, request)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return
}
if request.NewCustomerName == nil {
common.SingleResponses(ctx, fmt.Sprintf("Customer removed from port %d successfully", request.PortNumber), nil)
} else {
common.SingleResponses(ctx, fmt.Sprintf("Customer assigned to port %d successfully", request.PortNumber), nil)
}
}
func (c *DeviceDetailsController) bulkUpdateCustomersByPort(ctx *gin.Context) {
id := ctx.Param("id")
deviceID, err := uuid.Parse(id)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid device ID")
return
}
var request req.BulkUpdateCustomersByPortDTO
if err := ctx.ShouldBindJSON(&request); err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return
}
err = c.deviceDetailsUC.BulkUpdateCustomersByPort(deviceID, request.Updates)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(ctx, fmt.Sprintf("%d port assignments updated successfully", len(request.Updates)), nil)
}
func (c *DeviceDetailsController) removeCustomerByPort(ctx *gin.Context) {
id := ctx.Param("id")
deviceID, err := uuid.Parse(id)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid device ID")
return
}
var request req.RemoveCustomerByPortDTO
if err := ctx.ShouldBindJSON(&request); err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return
}
err = c.deviceDetailsUC.RemoveCustomerByPort(deviceID, request.PortNumber)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return
}
common.SingleResponses(ctx, fmt.Sprintf("Customer removed from port %d successfully", request.PortNumber), nil)
}
func (c *DeviceDetailsController) assignCustomer(ctx *gin.Context) { func (c *DeviceDetailsController) assignCustomer(ctx *gin.Context) {
id := ctx.Param("id") id := ctx.Param("id")
deviceID, err := uuid.Parse(id) deviceID, err := uuid.Parse(id)
@ -46,23 +129,58 @@ func (c *DeviceDetailsController) assignCustomer(ctx *gin.Context) {
return return
} }
var request struct { // Try to parse as array first
CustomerName string `json:"customer_name"` var arrayRequest []req.AssignMultipleCustomersDTO
PortNumber *int `json:"port_number"`
// Try to parse as single object
var singleRequest struct {
CustomerName string `json:"customer_name" binding:"required"`
PortNumber *int `json:"port_number,omitempty"`
} }
if err := ctx.ShouldBindJSON(&request); err != nil { // Get raw JSON to determine the structure
rawData, err := ctx.GetRawData()
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid JSON data")
return
}
// Reset the request body for subsequent parsing
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(rawData))
// Check if it's an array by looking at the first character
trimmed := bytes.TrimSpace(rawData)
if len(trimmed) > 0 && trimmed[0] == '[' {
// It's an array
if err := json.Unmarshal(rawData, &arrayRequest); err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid array format: "+err.Error())
return
}
// Process array of assignments
err = c.deviceDetailsUC.AssignMultipleCustomersToPort(deviceID, arrayRequest)
if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return return
} }
err = c.deviceDetailsUC.AssignCustomerToPort(deviceID, request.CustomerName, request.PortNumber) common.SingleResponses(ctx, fmt.Sprintf("%d customers assigned successfully", len(arrayRequest)), nil)
} else {
// It's a single object
if err := json.Unmarshal(rawData, &singleRequest); err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, "Invalid object format: "+err.Error())
return
}
// Process single assignment
err = c.deviceDetailsUC.AssignCustomerToPort(deviceID, singleRequest.CustomerName, singleRequest.PortNumber)
if err != nil { if err != nil {
common.ErrorResponses(ctx, http.StatusBadRequest, err.Error()) common.ErrorResponses(ctx, http.StatusBadRequest, err.Error())
return return
} }
common.SingleResponses(ctx, "Customer assigned successfully", nil) common.SingleResponses(ctx, "Customer assigned successfully", nil)
}
} }

View File

@ -26,3 +26,21 @@ type UpdateDeviceDetailsDTO struct {
City *string `json:"city,omitempty" validate:"omitempty,min=3"` City *string `json:"city,omitempty" validate:"omitempty,min=3"`
District *string `json:"district,omitempty" validate:"omitempty,min=3"` District *string `json:"district,omitempty" validate:"omitempty,min=3"`
} }
type AssignMultipleCustomersDTO struct {
CustomerName string `json:"customer_name" binding:"required"`
PortNumber *int `json:"port_number,omitempty"`
}
type UpdateCustomerByPortDTO struct {
PortNumber int `json:"port_number" binding:"required,min=1"`
NewCustomerName *string `json:"new_customer_name,omitempty"` // null to remove, string to update/assign
}
type BulkUpdateCustomersByPortDTO struct {
Updates []UpdateCustomerByPortDTO `json:"updates" binding:"required"`
}
type RemoveCustomerByPortDTO struct {
PortNumber int `json:"port_number" binding:"required,min=1"`
}

View File

@ -33,6 +33,10 @@ type DeviceDetailsRepo interface {
UpdatePortUsage(deviceID uuid.UUID, portUsed int) error UpdatePortUsage(deviceID uuid.UUID, portUsed int) error
UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error
MigrateCustomerNamesToPortAssignments(devicePort *entity.DevicePort, devicePortAmount int) error MigrateCustomerNamesToPortAssignments(devicePort *entity.DevicePort, devicePortAmount int) error
AssignMultipleCustomersToPort(deviceID uuid.UUID, assignments []req.AssignMultipleCustomersDTO) error
UpdateCustomerByPort(deviceID uuid.UUID, update req.UpdateCustomerByPortDTO) error
BulkUpdateCustomersByPort(deviceID uuid.UUID, updates []req.UpdateCustomerByPortDTO) error
RemoveCustomerByPort(deviceID uuid.UUID, portNumber int) error
} }
@ -47,6 +51,214 @@ func NewDeviceDetailsRepo(db *gorm.DB) DeviceDetailsRepo {
} }
} }
func (r *deviceDetailsRepo) UpdateCustomerByPort(deviceID uuid.UUID, update req.UpdateCustomerByPortDTO) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// Lock both device and device_port records
var device entity.Device
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("id = ?", deviceID).First(&device).Error; err != nil {
return err
}
// Only ODP devices can have customer assignments
if device.DeviceType != "ODP" {
return fmt.Errorf("customer assignments can only be updated for ODP devices")
}
var devicePort entity.DevicePort
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("device_id = ?", deviceID).First(&devicePort).Error; err != nil {
return fmt.Errorf("device port record not found: %w", err)
}
// Initialize port assignments if empty
if len(devicePort.PortAssignments) == 0 {
devicePort.PortAssignments = make(entity.PortAssignments, device.PortAmount)
for i := 0; i < device.PortAmount; i++ {
devicePort.PortAssignments[i] = entity.PortAssignment{
PortNumber: i + 1,
CustomerName: nil,
}
}
}
// Validate port number
if update.PortNumber > device.PortAmount {
return fmt.Errorf("port number %d exceeds device capacity (%d)", update.PortNumber, device.PortAmount)
}
portIndex := update.PortNumber - 1
// If assigning a new customer name
if update.NewCustomerName != nil && *update.NewCustomerName != "" {
// Check if customer name already exists on another port
for i, assignment := range devicePort.PortAssignments {
if i != portIndex && assignment.CustomerName != nil && *assignment.CustomerName == *update.NewCustomerName {
return fmt.Errorf("customer %s is already assigned to port %d", *update.NewCustomerName, i+1)
}
}
}
// Update the port assignment
if update.NewCustomerName == nil {
// Remove customer from port
devicePort.PortAssignments[portIndex].CustomerName = nil
} else {
// Assign/update customer on port
devicePort.PortAssignments[portIndex].CustomerName = update.NewCustomerName
}
// Update counters and backward compatibility fields
r.updateDevicePortCounters(&devicePort)
devicePort.UpdatedAt = time.Now()
return tx.Save(&devicePort).Error
})
}
func (r *deviceDetailsRepo) BulkUpdateCustomersByPort(deviceID uuid.UUID, updates []req.UpdateCustomerByPortDTO) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// Lock both device and device_port records
var device entity.Device
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("id = ?", deviceID).First(&device).Error; err != nil {
return err
}
// Only ODP devices can have customer assignments
if device.DeviceType != "ODP" {
return fmt.Errorf("customer assignments can only be updated for ODP devices")
}
var devicePort entity.DevicePort
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("device_id = ?", deviceID).First(&devicePort).Error; err != nil {
return fmt.Errorf("device port record not found: %w", err)
}
// Initialize port assignments if empty
if len(devicePort.PortAssignments) == 0 {
devicePort.PortAssignments = make(entity.PortAssignments, device.PortAmount)
for i := 0; i < device.PortAmount; i++ {
devicePort.PortAssignments[i] = entity.PortAssignment{
PortNumber: i + 1,
CustomerName: nil,
}
}
}
// Validate all port numbers first
for _, update := range updates {
if update.PortNumber > device.PortAmount {
return fmt.Errorf("port number %d exceeds device capacity (%d)", update.PortNumber, device.PortAmount)
}
}
// Create a map of final assignments to validate for duplicates
finalAssignments := make(map[int]*string)
// Start with current assignments
for i, assignment := range devicePort.PortAssignments {
finalAssignments[i+1] = assignment.CustomerName
}
// Apply updates
for _, update := range updates {
finalAssignments[update.PortNumber] = update.NewCustomerName
}
// Check for duplicate customer names
customerNames := make(map[string]int) // customer name -> port number
for portNum, customerName := range finalAssignments {
if customerName != nil && *customerName != "" {
if existingPort, exists := customerNames[*customerName]; exists {
return fmt.Errorf("customer %s would be assigned to both port %d and port %d", *customerName, existingPort, portNum)
}
customerNames[*customerName] = portNum
}
}
// Apply all updates
for _, update := range updates {
portIndex := update.PortNumber - 1
devicePort.PortAssignments[portIndex].CustomerName = update.NewCustomerName
}
// Recalculate port_used based on actual assignments
highestUsedPort := 0
customerCount := 0
for _, assignment := range devicePort.PortAssignments {
if assignment.CustomerName != nil && *assignment.CustomerName != "" {
customerCount++
if assignment.PortNumber > highestUsedPort {
highestUsedPort = assignment.PortNumber
}
}
}
// Update port_used to reflect actual usage
if customerCount == 0 {
devicePort.PortUsed = 0
} else {
// Set port_used to the highest port with a customer
// or keep current port_used if it's higher (for reserved ports)
if highestUsedPort > devicePort.PortUsed {
devicePort.PortUsed = highestUsedPort
}
}
// Recalculate port_available
devicePort.PortAvailable = device.PortAmount - devicePort.PortUsed
// Update counters and backward compatibility fields
r.updateDevicePortCounters(&devicePort)
devicePort.UpdatedAt = time.Now()
return tx.Save(&devicePort).Error
})
}
func (r *deviceDetailsRepo) RemoveCustomerByPort(deviceID uuid.UUID, portNumber int) error {
return r.db.Transaction(func(tx *gorm.DB) error {
var device entity.Device
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("id = ?", deviceID).First(&device).Error; err != nil {
return err
}
var devicePort entity.DevicePort
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("device_id = ?", deviceID).First(&devicePort).Error; err != nil {
return fmt.Errorf("device port record not found: %w", err)
}
// Validate port number
if portNumber > device.PortAmount {
return fmt.Errorf("port number %d exceeds device capacity (%d)", portNumber, device.PortAmount)
}
portIndex := portNumber - 1
// Check if port has a customer
if len(devicePort.PortAssignments) <= portIndex ||
devicePort.PortAssignments[portIndex].CustomerName == nil ||
*devicePort.PortAssignments[portIndex].CustomerName == "" {
return fmt.Errorf("port %d does not have a customer assigned", portNumber)
}
// Remove customer from port
devicePort.PortAssignments[portIndex].CustomerName = nil
// Update counters and backward compatibility fields
r.updateDevicePortCounters(&devicePort)
devicePort.UpdatedAt = time.Now()
return tx.Save(&devicePort).Error
})
}
func (r *deviceDetailsRepo) UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error { func (r *deviceDetailsRepo) UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error {
return r.db.Transaction(func(tx *gorm.DB) error { return r.db.Transaction(func(tx *gorm.DB) error {
// Lock both device and device_port records // Lock both device and device_port records
@ -536,17 +748,172 @@ func (r *deviceDetailsRepo) UpdateDevicePortUsage(deviceID uuid.UUID) error {
} }
func (r *deviceDetailsRepo) updateDevicePortCounters(devicePort *entity.DevicePort) { func (r *deviceDetailsRepo) updateDevicePortCounters(devicePort *entity.DevicePort) {
// Count actual customers and create customer names list // Get device port amount (need to load device if not loaded)
var device entity.Device
if devicePort.Device.ID == uuid.Nil {
r.db.Where("id = ?", devicePort.DeviceID).First(&device)
devicePort.Device = device
} else {
device = devicePort.Device
}
// Count actual customers and find highest used port
customerCount := 0 customerCount := 0
customerNames := make([]string, 0) customerNames := make([]string, 0)
highestCustomerPort := 0
for _, assignment := range devicePort.PortAssignments { for _, assignment := range devicePort.PortAssignments {
if assignment.CustomerName != nil && *assignment.CustomerName != "" { if assignment.CustomerName != nil && *assignment.CustomerName != "" {
customerCount++ customerCount++
customerNames = append(customerNames, *assignment.CustomerName) customerNames = append(customerNames, *assignment.CustomerName) // Just customer names, not with port numbers
if assignment.PortNumber > highestCustomerPort {
highestCustomerPort = assignment.PortNumber
}
} }
} }
// Set port_used to the highest port number that has a customer
// This ensures we don't have gaps in port usage
if customerCount == 0 {
devicePort.PortUsed = 0
} else {
devicePort.PortUsed = highestCustomerPort
}
// Calculate port_available
devicePort.PortAvailable = device.PortAmount - devicePort.PortUsed
// Update customer fields
devicePort.CustomerCount = customerCount devicePort.CustomerCount = customerCount
devicePort.CustomerNames = customerNames devicePort.CustomerNames = customerNames
} }
func (r *deviceDetailsRepo) AssignMultipleCustomersToPort(deviceID uuid.UUID, assignments []req.AssignMultipleCustomersDTO) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// Lock both device and device_port records
var device entity.Device
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("id = ?", deviceID).First(&device).Error; err != nil {
return err
}
// Only ODP devices can have customers assigned
if device.DeviceType != "ODP" {
return fmt.Errorf("customers can only be assigned to ODP devices")
}
var devicePort entity.DevicePort
if err := tx.Set("gorm:query_option", "FOR UPDATE").
Where("device_id = ?", deviceID).First(&devicePort).Error; err != nil {
return fmt.Errorf("device port record not found: %w", err)
}
// Initialize port assignments if empty
if len(devicePort.PortAssignments) == 0 {
devicePort.PortAssignments = make(entity.PortAssignments, device.PortAmount)
for i := 0; i < device.PortAmount; i++ {
devicePort.PortAssignments[i] = entity.PortAssignment{
PortNumber: i + 1,
CustomerName: nil,
}
}
}
// Check if there are enough available ports
availablePorts := 0
for _, assignment := range devicePort.PortAssignments {
if assignment.CustomerName == nil || *assignment.CustomerName == "" {
availablePorts++
}
}
portsNeeded := len(assignments)
if portsNeeded > availablePorts {
return fmt.Errorf("not enough available ports: need %d, available %d", portsNeeded, availablePorts)
}
// Process each assignment
for _, assignment := range assignments {
var targetPortNumber int
if assignment.PortNumber != nil {
targetPortNumber = *assignment.PortNumber
if targetPortNumber < 1 || targetPortNumber > device.PortAmount {
return fmt.Errorf("port number %d must be between 1 and %d", targetPortNumber, device.PortAmount)
}
} else {
// Auto-assign to first available port
targetPortNumber = -1
for i, portAssignment := range devicePort.PortAssignments {
if portAssignment.CustomerName == nil || *portAssignment.CustomerName == "" {
targetPortNumber = i + 1
break
}
}
if targetPortNumber == -1 {
return fmt.Errorf("no available ports for customer assignment")
}
}
// Check if the specified port is already occupied
portIndex := targetPortNumber - 1
if devicePort.PortAssignments[portIndex].CustomerName != nil &&
*devicePort.PortAssignments[portIndex].CustomerName != "" {
return fmt.Errorf("port %d is already occupied by %s", targetPortNumber, *devicePort.PortAssignments[portIndex].CustomerName)
}
// Check if customer is already assigned to another port
for i, portAssignment := range devicePort.PortAssignments {
if portAssignment.CustomerName != nil && *portAssignment.CustomerName == assignment.CustomerName {
return fmt.Errorf("customer %s is already assigned to port %d", assignment.CustomerName, i+1)
}
}
// Assign customer to port
devicePort.PortAssignments[portIndex].CustomerName = &assignment.CustomerName
}
// Update counters and backward compatibility fields
r.updateDevicePortCounters(&devicePort)
devicePort.UpdatedAt = time.Now()
return tx.Save(&devicePort).Error
})
}
func (r *deviceDetailsRepo) RecalculatePortUsageAfterBulkUpdate(deviceID uuid.UUID) error {
return r.db.Transaction(func(tx *gorm.DB) error {
var device entity.Device
if err := tx.Where("id = ?", deviceID).First(&device).Error; err != nil {
return err
}
var devicePort entity.DevicePort
if err := tx.Where("device_id = ?", deviceID).First(&devicePort).Error; err != nil {
return err
}
// Find the highest port number with a customer
highestUsedPort := 0
customerCount := 0
for _, assignment := range devicePort.PortAssignments {
if assignment.CustomerName != nil && *assignment.CustomerName != "" {
customerCount++
if assignment.PortNumber > highestUsedPort {
highestUsedPort = assignment.PortNumber
}
}
}
// Update port usage
devicePort.PortUsed = highestUsedPort
devicePort.PortAvailable = device.PortAmount - devicePort.PortUsed
// Update other counters
r.updateDevicePortCounters(&devicePort)
devicePort.UpdatedAt = time.Now()
return tx.Save(&devicePort).Error
})
}

View File

@ -28,6 +28,10 @@ type DeviceDetailsUseCase interface {
AssignCustomerToPort(deviceID uuid.UUID, customerName string,portNumber *int) error AssignCustomerToPort(deviceID uuid.UUID, customerName string,portNumber *int) error
UpdatePortUsage(deviceID uuid.UUID, portUsed int) error UpdatePortUsage(deviceID uuid.UUID, portUsed int) error
UpdatePortAssignments(deviceID uuid.UUID, portAssignments []req.PortAssignmentDTO) error UpdatePortAssignments(deviceID uuid.UUID, portAssignments []req.PortAssignmentDTO) error
AssignMultipleCustomersToPort(deviceID uuid.UUID, assignments []req.AssignMultipleCustomersDTO) error
UpdateCustomerByPort(deviceID uuid.UUID, update req.UpdateCustomerByPortDTO) error
BulkUpdateCustomersByPort(deviceID uuid.UUID, updates []req.UpdateCustomerByPortDTO) error
RemoveCustomerByPort(deviceID uuid.UUID, portNumber int) error
} }
type deviceDetailsUseCase struct { type deviceDetailsUseCase struct {
@ -44,6 +48,84 @@ func NewDeviceDetailsUseCase(deviceDetailsRepo repository.DeviceDetailsRepo, geo
} }
} }
func (u *deviceDetailsUseCase) UpdateCustomerByPort(deviceID uuid.UUID, update req.UpdateCustomerByPortDTO) error {
// Validate port number
if update.PortNumber < 1 {
return errors.New("port number must be greater than 0")
}
return u.deviceDetailsRepo.UpdateCustomerByPort(deviceID, update)
}
func (u *deviceDetailsUseCase) BulkUpdateCustomersByPort(deviceID uuid.UUID, updates []req.UpdateCustomerByPortDTO) error {
if len(updates) == 0 {
return errors.New("no updates provided")
}
// Validate all updates
portNumbers := make(map[int]bool)
newCustomerNames := make(map[string]bool)
for _, update := range updates {
// Check for duplicate port numbers in request
if portNumbers[update.PortNumber] {
return fmt.Errorf("duplicate port number in request: %d", update.PortNumber)
}
portNumbers[update.PortNumber] = true
// Check for duplicate new customer names in request (ignore nulls)
if update.NewCustomerName != nil && *update.NewCustomerName != "" {
if newCustomerNames[*update.NewCustomerName] {
return fmt.Errorf("duplicate new customer name in request: %s", *update.NewCustomerName)
}
newCustomerNames[*update.NewCustomerName] = true
}
// Validate port number
if update.PortNumber < 1 {
return fmt.Errorf("port number must be greater than 0: %d", update.PortNumber)
}
}
return u.deviceDetailsRepo.BulkUpdateCustomersByPort(deviceID, updates)
}
func (u *deviceDetailsUseCase) RemoveCustomerByPort(deviceID uuid.UUID, portNumber int) error {
if portNumber < 1 {
return errors.New("port number must be greater than 0")
}
return u.deviceDetailsRepo.RemoveCustomerByPort(deviceID, portNumber)
}
func (u *deviceDetailsUseCase) AssignMultipleCustomersToPort(deviceID uuid.UUID, assignments []req.AssignMultipleCustomersDTO) error {
if len(assignments) == 0 {
return errors.New("no assignments provided")
}
// Validate all assignments first
customerNames := make(map[string]bool)
portNumbers := make(map[int]bool)
for _, assignment := range assignments {
// Check for duplicate customer names in the request
if customerNames[assignment.CustomerName] {
return fmt.Errorf("duplicate customer name in request: %s", assignment.CustomerName)
}
customerNames[assignment.CustomerName] = true
// Check for duplicate port numbers in the request
if assignment.PortNumber != nil {
if portNumbers[*assignment.PortNumber] {
return fmt.Errorf("duplicate port number in request: %d", *assignment.PortNumber)
}
portNumbers[*assignment.PortNumber] = true
}
}
return u.deviceDetailsRepo.AssignMultipleCustomersToPort(deviceID, assignments)
}
func (u *deviceDetailsUseCase) UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error { func (u *deviceDetailsUseCase) UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error {
// Validate the assignments // Validate the assignments