301 lines
8.7 KiB
Go
301 lines
8.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/oklog/ulid/v2"
|
|
"github.com/timetracker/backend/internal/api/utils"
|
|
dto "github.com/timetracker/backend/internal/dtos"
|
|
"github.com/timetracker/backend/internal/models"
|
|
)
|
|
|
|
// CustomerHandler handles customer-related API endpoints
|
|
type CustomerHandler struct{}
|
|
|
|
// NewCustomerHandler creates a new CustomerHandler
|
|
func NewCustomerHandler() *CustomerHandler {
|
|
return &CustomerHandler{}
|
|
}
|
|
|
|
// GetCustomers handles GET /customers
|
|
//
|
|
// @Summary Get all customers
|
|
// @Description Get a list of all customers
|
|
// @Tags customers
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Success 200 {object} utils.Response{data=[]dto.CustomerDto}
|
|
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Router /customers [get]
|
|
func (h *CustomerHandler) GetCustomers(c *gin.Context) {
|
|
// Get customers from the database
|
|
customers, err := models.GetAllCustomers(c.Request.Context())
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error retrieving customers: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Convert to DTOs
|
|
customerDTOs := make([]dto.CustomerDto, len(customers))
|
|
for i, customer := range customers {
|
|
customerDTOs[i] = convertCustomerToDTO(&customer)
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, customerDTOs)
|
|
}
|
|
|
|
// GetCustomerByID handles GET /customers/:id
|
|
//
|
|
// @Summary Get customer by ID
|
|
// @Description Get a customer by its ID
|
|
// @Tags customers
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Customer ID"
|
|
// @Success 200 {object} utils.Response{data=dto.CustomerDto}
|
|
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 404 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Router /customers/{id} [get]
|
|
func (h *CustomerHandler) GetCustomerByID(c *gin.Context) {
|
|
// Parse ID from URL
|
|
idStr := c.Param("id")
|
|
id, err := ulid.Parse(idStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid customer ID format")
|
|
return
|
|
}
|
|
|
|
// Get customer from the database
|
|
customer, err := models.GetCustomerByID(c.Request.Context(), id)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error retrieving customer: "+err.Error())
|
|
return
|
|
}
|
|
|
|
if customer == nil {
|
|
utils.NotFoundResponse(c, "Customer not found")
|
|
return
|
|
}
|
|
|
|
// Convert to DTO
|
|
customerDTO := convertCustomerToDTO(customer)
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, customerDTO)
|
|
}
|
|
|
|
// GetCustomersByCompanyID handles GET /customers/company/:companyId
|
|
//
|
|
// @Summary Get customers by company ID
|
|
// @Description Get a list of customers for a specific company
|
|
// @Tags customers
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param companyId path int true "Company ID"
|
|
// @Success 200 {object} utils.Response{data=[]dto.CustomerDto}
|
|
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Router /customers/company/{companyId} [get]
|
|
func (h *CustomerHandler) GetCustomersByCompanyID(c *gin.Context) {
|
|
// Parse company ID from URL
|
|
companyIDStr := c.Param("companyId")
|
|
companyID, err := parseCompanyID(companyIDStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid company ID format")
|
|
return
|
|
}
|
|
|
|
// Get customers from the database
|
|
customers, err := models.GetCustomersByCompanyID(c.Request.Context(), companyID)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error retrieving customers: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Convert to DTOs
|
|
customerDTOs := make([]dto.CustomerDto, len(customers))
|
|
for i, customer := range customers {
|
|
customerDTOs[i] = convertCustomerToDTO(&customer)
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, customerDTOs)
|
|
}
|
|
|
|
// CreateCustomer handles POST /customers
|
|
//
|
|
// @Summary Create a new customer
|
|
// @Description Create a new customer
|
|
// @Tags customers
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param customer body dto.CustomerCreateDto true "Customer data"
|
|
// @Success 201 {object} utils.Response{data=dto.CustomerDto}
|
|
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Router /customers [post]
|
|
func (h *CustomerHandler) CreateCustomer(c *gin.Context) {
|
|
// Parse request body
|
|
var customerCreateDTO dto.CustomerCreateDto
|
|
if err := c.ShouldBindJSON(&customerCreateDTO); err != nil {
|
|
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Convert DTO to model
|
|
customerCreate := convertCreateCustomerDTOToModel(customerCreateDTO)
|
|
|
|
// Create customer in the database
|
|
customer, err := models.CreateCustomer(c.Request.Context(), customerCreate)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error creating customer: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Convert to DTO
|
|
customerDTO := convertCustomerToDTO(customer)
|
|
|
|
utils.SuccessResponse(c, http.StatusCreated, customerDTO)
|
|
}
|
|
|
|
// UpdateCustomer handles PUT /customers/:id
|
|
//
|
|
// @Summary Update a customer
|
|
// @Description Update an existing customer
|
|
// @Tags customers
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Customer ID"
|
|
// @Param customer body dto.CustomerUpdateDto true "Customer data"
|
|
// @Success 200 {object} utils.Response{data=dto.CustomerDto}
|
|
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 404 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Router /customers/{id} [put]
|
|
func (h *CustomerHandler) UpdateCustomer(c *gin.Context) {
|
|
// Parse ID from URL
|
|
idStr := c.Param("id")
|
|
id, err := ulid.Parse(idStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid customer ID format")
|
|
return
|
|
}
|
|
|
|
// Parse request body
|
|
var customerUpdateDTO dto.CustomerUpdateDto
|
|
if err := c.ShouldBindJSON(&customerUpdateDTO); err != nil {
|
|
utils.BadRequestResponse(c, "Invalid request body: "+err.Error())
|
|
return
|
|
}
|
|
|
|
// Set ID from URL
|
|
customerUpdateDTO.ID = id.String()
|
|
|
|
// Convert DTO to model
|
|
customerUpdate := convertUpdateCustomerDTOToModel(customerUpdateDTO)
|
|
|
|
// Update customer in the database
|
|
customer, err := models.UpdateCustomer(c.Request.Context(), customerUpdate)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error updating customer: "+err.Error())
|
|
return
|
|
}
|
|
|
|
if customer == nil {
|
|
utils.NotFoundResponse(c, "Customer not found")
|
|
return
|
|
}
|
|
|
|
// Convert to DTO
|
|
customerDTO := convertCustomerToDTO(customer)
|
|
|
|
utils.SuccessResponse(c, http.StatusOK, customerDTO)
|
|
}
|
|
|
|
// DeleteCustomer handles DELETE /customers/:id
|
|
//
|
|
// @Summary Delete a customer
|
|
// @Description Delete a customer by its ID
|
|
// @Tags customers
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param id path string true "Customer ID"
|
|
// @Success 204 {object} utils.Response
|
|
// @Failure 400 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 401 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Failure 500 {object} utils.Response{error=utils.ErrorInfo}
|
|
// @Router /customers/{id} [delete]
|
|
func (h *CustomerHandler) DeleteCustomer(c *gin.Context) {
|
|
// Parse ID from URL
|
|
idStr := c.Param("id")
|
|
id, err := ulid.Parse(idStr)
|
|
if err != nil {
|
|
utils.BadRequestResponse(c, "Invalid customer ID format")
|
|
return
|
|
}
|
|
|
|
// Delete customer from the database
|
|
err = models.DeleteCustomer(c.Request.Context(), id)
|
|
if err != nil {
|
|
utils.InternalErrorResponse(c, "Error deleting customer: "+err.Error())
|
|
return
|
|
}
|
|
|
|
utils.SuccessResponse(c, http.StatusNoContent, nil)
|
|
}
|
|
|
|
// Helper functions for DTO conversion
|
|
|
|
func convertCustomerToDTO(customer *models.Customer) dto.CustomerDto {
|
|
return dto.CustomerDto{
|
|
ID: customer.ID.String(),
|
|
CreatedAt: customer.CreatedAt,
|
|
UpdatedAt: customer.UpdatedAt,
|
|
Name: customer.Name,
|
|
CompanyID: customer.CompanyID,
|
|
}
|
|
}
|
|
|
|
func convertCreateCustomerDTOToModel(dto dto.CustomerCreateDto) models.CustomerCreate {
|
|
return models.CustomerCreate{
|
|
Name: dto.Name,
|
|
CompanyID: dto.CompanyID,
|
|
}
|
|
}
|
|
|
|
func convertUpdateCustomerDTOToModel(dto dto.CustomerUpdateDto) models.CustomerUpdate {
|
|
id, _ := ulid.Parse(dto.ID)
|
|
update := models.CustomerUpdate{
|
|
ID: id,
|
|
}
|
|
|
|
if dto.Name != nil {
|
|
update.Name = dto.Name
|
|
}
|
|
|
|
if dto.CompanyID != nil {
|
|
update.CompanyID = dto.CompanyID
|
|
}
|
|
|
|
return update
|
|
}
|
|
|
|
// Helper function to parse company ID from string
|
|
func parseCompanyID(idStr string) (int, error) {
|
|
var id int
|
|
_, err := fmt.Sscanf(idStr, "%d", &id)
|
|
return id, err
|
|
}
|