fix minor issue
This commit is contained in:
parent
ece05cee18
commit
8afca3054a
|
|
@ -16,10 +16,10 @@ type DeviceDetailsDTO struct {
|
|||
|
||||
type UpdateDeviceDetailsDTO struct {
|
||||
DeviceCode *string `json:"device_code,omitempty" validate:"omitempty,min=3"`
|
||||
DeviceType *string `json:"device_type,omitempty" validate:"omitempty,oneof=OTB ODP"`
|
||||
DeviceType *string `json:"device_type,omitempty" validate:"omitempty,oneof=OTB ODP CLOSURE"`
|
||||
Longitude *float64 `json:"longitude,omitempty" validate:"omitempty,longitude"`
|
||||
Latitude *float64 `json:"latitude,omitempty" validate:"omitempty,latitude"`
|
||||
PortAmount *int `json:"port_amount,omitempty" validate:"omitempty,min=1,max=100"`
|
||||
PortAmount *int `json:"port_amount,omitempty" validate:"omitempty,min=0,max=100"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=active inactive maintenance"`
|
||||
Region *string `json:"region,omitempty" validate:"omitempty,min=3"`
|
||||
Province *string `json:"province,omitempty" validate:"omitempty,min=3"`
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ type DeviceDTO struct {
|
|||
DeviceType string `json:"device_type" validate:"required"`
|
||||
Longitude float64 `json:"longitude" validate:"required"`
|
||||
Latitude float64 `json:"latitude" validate:"required"`
|
||||
PortAmount int `json:"port_amount" validate:"required"`
|
||||
PortAmount int `json:"port_amount"`
|
||||
Status string `json:"status" validate:"required,oneof=active inactive maintenance"`
|
||||
Province *string `json:"province,omitempty" validate:"omitempty,min=3"`
|
||||
City *string `json:"city,omitempty" validate:"omitempty,min=3"`
|
||||
|
|
@ -17,7 +17,7 @@ type UpdateDeviceDTO struct {
|
|||
DeviceType *string `json:"device_type,omitempty" validate:"omitempty,min=3"`
|
||||
Longitude *float64 `json:"longitude,omitempty" validate:"omitempty,longitude"`
|
||||
Latitude *float64 `json:"latitude,omitempty" validate:"omitempty,latitude"`
|
||||
PortAmount *int `json:"port_amount,omitempty" validate:"omitempty,min=1"`
|
||||
PortAmount *int `json:"port_amount,omitempty" validate:"omitempty"`
|
||||
Status *string `json:"status,omitempty" validate:"omitempty,oneof=active inactive maintenance"`
|
||||
Province *string `json:"province,omitempty" validate:"omitempty,min=3"`
|
||||
City *string `json:"city,omitempty" validate:"omitempty,min=3"`
|
||||
|
|
|
|||
|
|
@ -141,13 +141,7 @@ func (dp *DevicePort) GetCustomerNames() []string {
|
|||
}
|
||||
|
||||
func (dp *DevicePort) GetPortAssignmentsWithDetails() []PortAssignmentResponse {
|
||||
// If both port_used and port_available are 0, return empty array
|
||||
if dp.PortUsed == 0 && dp.PortAvailable == 0 {
|
||||
return []PortAssignmentResponse{}
|
||||
}
|
||||
|
||||
// If port_used is 0 but port_available > 0, still return empty array
|
||||
// This means the device has capacity but no ports are currently used
|
||||
// If port_used is 0, return empty array
|
||||
if dp.PortUsed == 0 {
|
||||
return []PortAssignmentResponse{}
|
||||
}
|
||||
|
|
@ -166,19 +160,20 @@ func (dp *DevicePort) GetPortAssignmentsWithDetails() []PortAssignmentResponse {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: use CustomerNames array
|
||||
// Fallback: use CustomerNames array if PortAssignments is empty
|
||||
for i, name := range dp.CustomerNames {
|
||||
portNum := i + 1
|
||||
if name != "" {
|
||||
portMap[i+1] = &name
|
||||
}
|
||||
if i+1 > maxPort {
|
||||
maxPort = i + 1
|
||||
portMap[portNum] = &name
|
||||
if portNum > maxPort {
|
||||
maxPort = portNum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no ports have assignments and port_used > 0, create empty assignments up to port_used
|
||||
if maxPort == 0 && dp.PortUsed > 0 {
|
||||
// Ensure maxPort is at least equal to port_used
|
||||
if maxPort < dp.PortUsed {
|
||||
maxPort = dp.PortUsed
|
||||
}
|
||||
|
||||
|
|
@ -212,30 +207,20 @@ func (dp *DevicePort) GetPortAssignmentsWithDetails() []PortAssignmentResponse {
|
|||
occupiedCount++
|
||||
}
|
||||
}
|
||||
|
||||
// If we still haven't reached port_used, extend maxPort
|
||||
for i := maxPort + 1; occupiedCount < dp.PortUsed; i++ {
|
||||
occupiedPorts[i] = true
|
||||
occupiedCount++
|
||||
maxPort = i
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Create the result only for ports that are either occupied or have customers
|
||||
// Step 4: Create the result for ALL ports up to maxPort
|
||||
for i := 1; i <= maxPort; i++ {
|
||||
// Only include ports that are occupied or have customers
|
||||
if occupiedPorts[i] || (portMap[i] != nil && *portMap[i] != "") {
|
||||
var customerName *string
|
||||
if portMap[i] != nil {
|
||||
customerName = portMap[i]
|
||||
}
|
||||
|
||||
result = append(result, PortAssignmentResponse{
|
||||
PortNumber: i,
|
||||
CustomerName: customerName,
|
||||
IsOccupied: occupiedPorts[i],
|
||||
})
|
||||
var customerName *string
|
||||
if portMap[i] != nil {
|
||||
customerName = portMap[i]
|
||||
}
|
||||
|
||||
result = append(result, PortAssignmentResponse{
|
||||
PortNumber: i,
|
||||
CustomerName: customerName,
|
||||
IsOccupied: occupiedPorts[i],
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"users_management/m/model/dto/req"
|
||||
|
|
@ -33,6 +32,8 @@ type DeviceDetailsRepo interface {
|
|||
RemoveCustomerFromPort(deviceID uuid.UUID, customerName string) error
|
||||
UpdatePortUsage(deviceID uuid.UUID, portUsed int) error
|
||||
UpdatePortAssignments(deviceID uuid.UUID, assignments []req.PortAssignmentDTO) error
|
||||
MigrateCustomerNamesToPortAssignments(devicePort *entity.DevicePort, devicePortAmount int) error
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -222,17 +223,45 @@ func (r *deviceDetailsRepo) updatePortAmountCascade(tx *gorm.DB, deviceID uuid.U
|
|||
|
||||
// Check if new port amount is sufficient for current usage
|
||||
if newPortAmount < devicePort.PortUsed {
|
||||
return errors.New("cannot reduce port amount below current usage")
|
||||
return fmt.Errorf("cannot reduce port amount to %d, currently using %d ports", newPortAmount, devicePort.PortUsed)
|
||||
}
|
||||
|
||||
// Update port available
|
||||
newPortAvailable := newPortAmount - devicePort.PortUsed
|
||||
return tx.Model(&entity.DevicePort{}).
|
||||
Where("device_id = ?", deviceID).
|
||||
Updates(map[string]interface{}{
|
||||
"port_available": newPortAvailable,
|
||||
"updated_at": gorm.Expr("NOW()"),
|
||||
}).Error
|
||||
// Special case: if port_amount is set to 0, clear all assignments
|
||||
if newPortAmount == 0 {
|
||||
devicePort.PortUsed = 0
|
||||
devicePort.PortAvailable = 0
|
||||
devicePort.CustomerCount = 0
|
||||
devicePort.CustomerNames = []string{}
|
||||
devicePort.PortAssignments = entity.PortAssignments{}
|
||||
devicePort.UpdatedAt = time.Now()
|
||||
} else {
|
||||
// Calculate new port available
|
||||
newPortAvailable := newPortAmount - devicePort.PortUsed
|
||||
|
||||
// Update port assignments to match new port amount
|
||||
if len(devicePort.PortAssignments) > 0 {
|
||||
// Resize port assignments array
|
||||
newPortAssignments := make(entity.PortAssignments, newPortAmount)
|
||||
|
||||
// Copy existing assignments up to the new port amount
|
||||
for i := 0; i < newPortAmount; i++ {
|
||||
if i < len(devicePort.PortAssignments) {
|
||||
newPortAssignments[i] = devicePort.PortAssignments[i]
|
||||
} else {
|
||||
newPortAssignments[i] = entity.PortAssignment{
|
||||
PortNumber: i + 1,
|
||||
CustomerName: nil,
|
||||
}
|
||||
}
|
||||
}
|
||||
devicePort.PortAssignments = newPortAssignments
|
||||
}
|
||||
|
||||
devicePort.PortAvailable = newPortAvailable
|
||||
devicePort.UpdatedAt = time.Now()
|
||||
}
|
||||
|
||||
return tx.Save(&devicePort).Error
|
||||
}
|
||||
|
||||
func (r *deviceDetailsRepo) UpdatePortUsage(deviceID uuid.UUID, portUsed int) error {
|
||||
|
|
@ -253,13 +282,19 @@ func (r *deviceDetailsRepo) UpdatePortUsage(deviceID uuid.UUID, portUsed int) er
|
|||
return fmt.Errorf("device port record not found: %w", err)
|
||||
}
|
||||
|
||||
// Initialize port assignments if empty
|
||||
if len(devicePort.PortAssignments) == 0 {
|
||||
// Initialize port assignments if empty and we have customers or port_used > 0
|
||||
if len(devicePort.PortAssignments) == 0 && (len(devicePort.CustomerNames) > 0 || portUsed > 0) {
|
||||
devicePort.PortAssignments = make(entity.PortAssignments, device.PortAmount)
|
||||
for i := 0; i < device.PortAmount; i++ {
|
||||
var customerName *string
|
||||
// Map existing customer names to ports
|
||||
if i < len(devicePort.CustomerNames) && devicePort.CustomerNames[i] != "" {
|
||||
customerName = &devicePort.CustomerNames[i]
|
||||
}
|
||||
|
||||
devicePort.PortAssignments[i] = entity.PortAssignment{
|
||||
PortNumber: i + 1,
|
||||
CustomerName: nil,
|
||||
CustomerName: customerName,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -296,6 +331,26 @@ func (r *deviceDetailsRepo) UpdatePortUsage(deviceID uuid.UUID, portUsed int) er
|
|||
})
|
||||
}
|
||||
|
||||
func (r *deviceDetailsRepo) MigrateCustomerNamesToPortAssignments(devicePort *entity.DevicePort, devicePortAmount int) error {
|
||||
// Only migrate if PortAssignments is empty but CustomerNames has data
|
||||
if len(devicePort.PortAssignments) == 0 && len(devicePort.CustomerNames) > 0 {
|
||||
devicePort.PortAssignments = make(entity.PortAssignments, devicePortAmount)
|
||||
|
||||
for i := 0; i < devicePortAmount; i++ {
|
||||
var customerName *string
|
||||
if i < len(devicePort.CustomerNames) && devicePort.CustomerNames[i] != "" {
|
||||
customerName = &devicePort.CustomerNames[i]
|
||||
}
|
||||
|
||||
devicePort.PortAssignments[i] = entity.PortAssignment{
|
||||
PortNumber: i + 1,
|
||||
CustomerName: customerName,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// func (r *deviceDetailsRepo) ValidatePortAvailability(deviceID uuid.UUID, requiredPorts int) error {
|
||||
// var devicePort entity.DevicePort
|
||||
// if err := r.db.Where("device_id = ?", deviceID).First(&devicePort).Error; err != nil {
|
||||
|
|
|
|||
|
|
@ -118,8 +118,6 @@ func (u *deviceDetailsUseCase) UpdateDeviceDetails(id uuid.UUID, deviceDTO req.U
|
|||
return fmt.Errorf("validation error: %w", err)
|
||||
}
|
||||
|
||||
// Check if device exists
|
||||
|
||||
updates := map[string]interface{}{}
|
||||
|
||||
if deviceDTO.DeviceCode != nil {
|
||||
|
|
@ -136,13 +134,21 @@ func (u *deviceDetailsUseCase) UpdateDeviceDetails(id uuid.UUID, deviceDTO req.U
|
|||
}
|
||||
if deviceDTO.PortAmount != nil {
|
||||
// Validate port amount change
|
||||
currentUsed, _, err := u.deviceDetailsRepo.GetPortUsageByDevice(id)
|
||||
if err != nil {
|
||||
return err
|
||||
if *deviceDTO.PortAmount < 0 {
|
||||
return fmt.Errorf("port amount cannot be negative")
|
||||
}
|
||||
if *deviceDTO.PortAmount < currentUsed {
|
||||
return fmt.Errorf("cannot reduce port amount to %d, currently using %d ports", *deviceDTO.PortAmount, currentUsed)
|
||||
|
||||
// If not setting to 0, check current usage
|
||||
if *deviceDTO.PortAmount > 0 {
|
||||
currentUsed, _, err := u.deviceDetailsRepo.GetPortUsageByDevice(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *deviceDTO.PortAmount < currentUsed {
|
||||
return fmt.Errorf("cannot reduce port amount to %d, currently using %d ports", *deviceDTO.PortAmount, currentUsed)
|
||||
}
|
||||
}
|
||||
|
||||
updates["port_amount"] = *deviceDTO.PortAmount
|
||||
}
|
||||
if deviceDTO.Status != nil {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ func (u *deviceUseCase) CreateDevice(device req.DeviceDTO) error {
|
|||
return fmt.Errorf("validation error: %w", err)
|
||||
}
|
||||
|
||||
if device.DeviceType == "OTB" || device.DeviceType == "ODP" && device.PortAmount <= 0 {
|
||||
return fmt.Errorf("port amount must be greater than 0 for OTB or ODP devices")
|
||||
}
|
||||
|
||||
newDevice := entity.Device{
|
||||
ID: uuid.New(),
|
||||
DeviceCode: device.DeviceCode,
|
||||
|
|
@ -92,7 +96,6 @@ func (u *deviceUseCase) UpdateDevice(id uuid.UUID, device req.UpdateDeviceDTO) e
|
|||
if err != nil {
|
||||
return fmt.Errorf("validation error: %w", err)
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{}
|
||||
|
||||
if device.DeviceCode != nil {
|
||||
|
|
@ -122,6 +125,9 @@ func (u *deviceUseCase) UpdateDevice(id uuid.UUID, device req.UpdateDeviceDTO) e
|
|||
if device.District != nil {
|
||||
updates["District"] = *device.District
|
||||
}
|
||||
if device.DeviceType != nil && (*device.DeviceType == "OTB" || *device.DeviceType == "ODP") && device.PortAmount != nil && *device.PortAmount <= 0 {
|
||||
return fmt.Errorf("port amount must be greater than 0 for OTB or ODP devices")
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
return fmt.Errorf("no update data")
|
||||
|
|
@ -129,6 +135,8 @@ func (u *deviceUseCase) UpdateDevice(id uuid.UUID, device req.UpdateDeviceDTO) e
|
|||
|
||||
updates["UpdatedAt"] = time.Now()
|
||||
|
||||
|
||||
|
||||
return u.deviceRepo.Update(id, updates)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,10 +168,17 @@ func ConvertToDeviceDetailsResponse(device entity.DeviceDetails, geocoder servic
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
var customerNames []string
|
||||
|
||||
// If port_used is 0, return empty port assignments
|
||||
if device.DevicePort.PortUsed == 0 {
|
||||
if device.PortAmount == 0 {
|
||||
finalPortAssignments = []res.PortAssignmentResponse{}
|
||||
customerNames = []string{}
|
||||
} else if device.DevicePort.PortUsed == 0 {
|
||||
// If port_used is 0, return empty port assignments but keep port_amount structure
|
||||
finalPortAssignments = []res.PortAssignmentResponse{}
|
||||
customerNames = []string{}
|
||||
} else {
|
||||
// Get port assignments with details
|
||||
portAssignments := device.DevicePort.GetPortAssignmentsWithDetails()
|
||||
|
|
@ -185,6 +192,9 @@ func ConvertToDeviceDetailsResponse(device entity.DeviceDetails, geocoder servic
|
|||
IsOccupied: pa.IsOccupied,
|
||||
}
|
||||
}
|
||||
|
||||
// Get customer names
|
||||
customerNames = device.DevicePort.GetCustomerNamesOnly()
|
||||
}
|
||||
|
||||
response := res.DeviceDetailsResponse{
|
||||
|
|
@ -198,7 +208,7 @@ func ConvertToDeviceDetailsResponse(device entity.DeviceDetails, geocoder servic
|
|||
PortAmount: device.PortAmount,
|
||||
PortUsed: device.DevicePort.PortUsed,
|
||||
PortAvailable: device.DevicePort.PortAvailable,
|
||||
CustomerNames: device.DevicePort.GetCustomerNamesOnly(), // Just customer names
|
||||
CustomerNames: customerNames, // Just customer names
|
||||
PortAssignments: finalPortAssignments, // Use finalPortAssignments instead of resPortAssignments
|
||||
Region: device.Region,
|
||||
Province: device.Province,
|
||||
|
|
|
|||
Loading…
Reference in New Issue