package service import ( "errors" "fmt" "time" "gorm.io/gorm" "sql-platform/internal/model" ) type TicketService struct { DB *gorm.DB } func NewTicketService(db *gorm.DB) *TicketService { return &TicketService{DB: db} } // CreateTicket creates a new ticket func (s *TicketService) CreateTicket(ticket *model.Ticket) error { if ticket.TicketNo == "" { ticket.TicketNo = s.generateTicketNo() } if ticket.CreateTime.IsZero() { ticket.CreateTime = time.Now() } if ticket.Status == "" { ticket.Status = "pending" } return s.DB.Create(ticket).Error } // GetTicketByID retrieves a ticket by ID func (s *TicketService) GetTicketByID(id uint) (*model.Ticket, error) { var ticket model.Ticket if err := s.DB.First(&ticket, id).Error; err != nil { return nil, errors.New("ticket not found") } return &ticket, nil } // ListTickets returns paginated tickets with filters func (s *TicketService) ListTickets(page, pageSize int, status, priority string, applicantID uint) ([]model.Ticket, int64, error) { var tickets []model.Ticket var total int64 db := s.DB.Model(&model.Ticket{}) if status != "" { db = db.Where("status = ?", status) } if priority != "" { db = db.Where("priority = ?", priority) } if applicantID > 0 { db = db.Where("applicant_id = ?", applicantID) } db.Count(&total) offset := (page - 1) * pageSize if err := db.Offset(offset).Limit(pageSize).Order("create_time DESC").Find(&tickets).Error; err != nil { return nil, 0, err } return tickets, total, nil } // UpdateTicketStatus updates a ticket's status func (s *TicketService) UpdateTicketStatus(id uint, status string, updaterID uint) error { updates := map[string]interface{}{ "status": status, } now := time.Now() switch status { case "approved": updates["approver_id"] = updaterID updates["review_time"] = now case "executing", "completed", "failed": updates["execute_time"] = now } result := s.DB.Model(&model.Ticket{}).Where("id = ?", id).Updates(updates) if result.RowsAffected == 0 { return errors.New("ticket not found") } return result.Error } // ApproveTicket approves a ticket func (s *TicketService) ApproveTicket(id, approverID uint, comment string) error { return s.UpdateTicketStatus(id, "approved", approverID) } // RejectTicket rejects a ticket func (s *TicketService) RejectTicket(id, approverID uint, comment string) error { return s.UpdateTicketStatus(id, "rejected", approverID) } // GetTicketSQLItems returns SQL items for a ticket func (s *TicketService) GetTicketSQLItems(ticketID uint) ([]model.TicketSQLItem, error) { var items []model.TicketSQLItem err := s.DB.Where("ticket_id = ?", ticketID).Order("seq ASC").Find(&items).Error return items, err } // CreateTicketSQLItem creates a SQL item for a ticket func (s *TicketService) CreateTicketSQLItem(item *model.TicketSQLItem) error { return s.DB.Create(item).Error } // GetTicketApprovals returns approval records for a ticket func (s *TicketService) GetTicketApprovals(ticketID uint) ([]model.TicketApproval, error) { var approvals []model.TicketApproval err := s.DB.Where("ticket_id = ?", ticketID).Order("step_number ASC").Find(&approvals).Error return approvals, err } // DeleteTicket soft-deletes a ticket func (s *TicketService) DeleteTicket(id uint) error { return s.DB.Delete(&model.Ticket{}, id).Error } // generateTicketNo generates a unique ticket number func (s *TicketService) generateTicketNo() string { now := time.Now() var count int64 s.DB.Model(&model.Ticket{}).Where("DATE(create_time) = DATE(?)", now).Count(&count) return fmt.Sprintf("TK-%s-%04d", now.Format("20060102"), count+1) }