From e3ee3d64ceae9c8726e272af4ed56388108af52a Mon Sep 17 00:00:00 2001 From: "n.nakhostin" Date: Mon, 11 Aug 2025 19:12:31 +0330 Subject: [PATCH] Remove obsolete customer endpoint and update related documentation - Deleted the `/admin/v1/customers/{id}/with-companies` endpoint from the API documentation and Swagger files to streamline the API structure. - Updated the router to remove the corresponding route registration for the deprecated endpoint. - Enhanced the company repository and service to support batch retrieval of companies by IDs, improving efficiency in data handling. - Adjusted customer service methods to utilize the new batch retrieval functionality for loading companies associated with customers. - Improved logging practices to provide better traceability for company retrieval operations. --- cmd/web/docs/docs.go | 67 ---------------------------------- cmd/web/docs/swagger.json | 67 ---------------------------------- cmd/web/docs/swagger.yaml | 41 --------------------- cmd/web/router/routes.go | 2 - internal/company/repository.go | 50 +++++++++++++++++++++++++ internal/company/service.go | 24 ++++++++++++ internal/customer/handler.go | 29 +-------------- internal/customer/service.go | 39 +++++++++++++------- 8 files changed, 100 insertions(+), 219 deletions(-) diff --git a/cmd/web/docs/docs.go b/cmd/web/docs/docs.go index ea9e811..cc18805 100644 --- a/cmd/web/docs/docs.go +++ b/cmd/web/docs/docs.go @@ -2840,73 +2840,6 @@ const docTemplate = `{ } } }, - "/admin/v1/customers/{id}/with-companies": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve detailed customer information by customer ID including assigned companies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Admin-Customers" - ], - "summary": "Get customer by ID with companies", - "parameters": [ - { - "type": "string", - "description": "Customer ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Customer retrieved successfully", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.APIResponse" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/customer.CustomerResponse" - } - } - } - ] - } - }, - "400": { - "description": "Bad request - Invalid customer ID", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "404": { - "description": "Not found - Customer not found", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/admin/v1/health": { "get": { "description": "Get comprehensive server health status including system information, dependencies status, and performance metrics. This endpoint is used for monitoring and load balancer health checks.", diff --git a/cmd/web/docs/swagger.json b/cmd/web/docs/swagger.json index 1ecbc8f..8544250 100644 --- a/cmd/web/docs/swagger.json +++ b/cmd/web/docs/swagger.json @@ -2834,73 +2834,6 @@ } } }, - "/admin/v1/customers/{id}/with-companies": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve detailed customer information by customer ID including assigned companies", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Admin-Customers" - ], - "summary": "Get customer by ID with companies", - "parameters": [ - { - "type": "string", - "description": "Customer ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Customer retrieved successfully", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.APIResponse" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/customer.CustomerResponse" - } - } - } - ] - } - }, - "400": { - "description": "Bad request - Invalid customer ID", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "404": { - "description": "Not found - Customer not found", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal server error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/admin/v1/health": { "get": { "description": "Get comprehensive server health status including system information, dependencies status, and performance metrics. This endpoint is used for monitoring and load balancer health checks.", diff --git a/cmd/web/docs/swagger.yaml b/cmd/web/docs/swagger.yaml index 91d967a..749bc50 100644 --- a/cmd/web/docs/swagger.yaml +++ b/cmd/web/docs/swagger.yaml @@ -2546,47 +2546,6 @@ paths: summary: Verify customer tags: - Admin-Customers - /admin/v1/customers/{id}/with-companies: - get: - consumes: - - application/json - description: Retrieve detailed customer information by customer ID including - assigned companies - parameters: - - description: Customer ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: Customer retrieved successfully - schema: - allOf: - - $ref: '#/definitions/response.APIResponse' - - properties: - data: - $ref: '#/definitions/customer.CustomerResponse' - type: object - "400": - description: Bad request - Invalid customer ID - schema: - $ref: '#/definitions/response.APIResponse' - "404": - description: Not found - Customer not found - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal server error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - BearerAuth: [] - summary: Get customer by ID with companies - tags: - - Admin-Customers /admin/v1/customers/company/{companyId}: get: consumes: diff --git a/cmd/web/router/routes.go b/cmd/web/router/routes.go index 6b74093..bc39c5b 100644 --- a/cmd/web/router/routes.go +++ b/cmd/web/router/routes.go @@ -73,9 +73,7 @@ func RegisterAdminRoutes(e *echo.Echo, userHandler *user.Handler, companyHandler customersGP.Use(userHandler.AuthMiddleware()) customersGP.POST("", customerHandler.CreateCustomer) customersGP.GET("", customerHandler.ListCustomers) - customersGP.GET("/with-companies", customerHandler.ListCustomersWithCompanies) customersGP.GET("/:id", customerHandler.GetCustomerByID) - customersGP.GET("/:id/with-companies", customerHandler.GetCustomerByIDWithCompanies) customersGP.PUT("/:id", customerHandler.UpdateCustomer) customersGP.DELETE("/:id", customerHandler.DeleteCustomer) customersGP.PATCH("/:id/status", customerHandler.UpdateCustomerStatus) diff --git a/internal/company/repository.go b/internal/company/repository.go index d22cd3c..06257aa 100644 --- a/internal/company/repository.go +++ b/internal/company/repository.go @@ -8,6 +8,7 @@ import ( mongopkg "tm/pkg/mongo" "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" ) // Repository defines the interface for company data operations @@ -17,6 +18,7 @@ type Repository interface { GetByName(ctx context.Context, name string) (*Company, error) GetByRegistrationNumber(ctx context.Context, registrationNumber string) (*Company, error) GetByTaxID(ctx context.Context, taxID string) (*Company, error) + GetByIDs(ctx context.Context, ids []string) ([]*Company, error) Update(ctx context.Context, company *Company) error Delete(ctx context.Context, id string) error List(ctx context.Context, limit, offset int) ([]*Company, error) @@ -184,6 +186,54 @@ func (r *companyRepository) GetByTaxID(ctx context.Context, taxID string) (*Comp return company, nil } +// GetByIDs retrieves multiple companies by their IDs +func (r *companyRepository) GetByIDs(ctx context.Context, ids []string) ([]*Company, error) { + if len(ids) == 0 { + return []*Company{}, nil + } + + // Convert string IDs to ObjectIDs for MongoDB query + objectIDs := make([]interface{}, len(ids)) + for i, id := range ids { + objectID, err := primitive.ObjectIDFromHex(id) + if err != nil { + r.logger.Warn("Invalid company ID format", map[string]interface{}{ + "id": id, + "error": err.Error(), + }) + continue + } + objectIDs[i] = objectID + } + + if len(objectIDs) == 0 { + return []*Company{}, nil + } + + filter := bson.M{"_id": bson.M{"$in": objectIDs}} + companies, err := r.ormRepo.FindMany(ctx, filter, len(ids)) + if err != nil { + r.logger.Error("Failed to get companies by IDs", map[string]interface{}{ + "error": err.Error(), + "ids": ids, + }) + return nil, err + } + + // Convert to pointer slice + result := make([]*Company, len(companies)) + for i := range companies { + result[i] = &companies[i] + } + + r.logger.Info("Retrieved companies by IDs", map[string]interface{}{ + "requested_count": len(ids), + "found_count": len(result), + }) + + return result, nil +} + // Update updates a company func (r *companyRepository) Update(ctx context.Context, company *Company) error { // Set updated timestamp using Unix timestamp diff --git a/internal/company/service.go b/internal/company/service.go index e38ba39..04b5b56 100644 --- a/internal/company/service.go +++ b/internal/company/service.go @@ -13,6 +13,7 @@ type Service interface { // Core company operations CreateCompany(ctx context.Context, form *CreateCompanyForm, createdBy *string) (*Company, error) GetCompanyByID(ctx context.Context, id string) (*Company, error) + GetCompaniesByIDs(ctx context.Context, ids []string) ([]*Company, error) UpdateCompany(ctx context.Context, id string, form *UpdateCompanyForm, updatedBy *string) (*Company, error) DeleteCompany(ctx context.Context, id string, deletedBy *string) error @@ -144,6 +145,29 @@ func (s *companyService) GetCompanyByID(ctx context.Context, id string) (*Compan return company, nil } +// GetCompaniesByIDs retrieves multiple companies by their IDs +func (s *companyService) GetCompaniesByIDs(ctx context.Context, ids []string) ([]*Company, error) { + if len(ids) == 0 { + return []*Company{}, nil + } + + companies, err := s.repository.GetByIDs(ctx, ids) + if err != nil { + s.logger.Error("Failed to get companies by IDs", map[string]interface{}{ + "error": err.Error(), + "ids": ids, + }) + return nil, err + } + + s.logger.Info("Companies retrieved successfully", map[string]interface{}{ + "requested_count": len(ids), + "found_count": len(companies), + }) + + return companies, nil +} + // UpdateCompany updates a company func (s *companyService) UpdateCompany(ctx context.Context, id string, form *UpdateCompanyForm, updatedBy *string) (*Company, error) { // Get existing company diff --git a/internal/customer/handler.go b/internal/customer/handler.go index e9bf648..6ee07bc 100644 --- a/internal/customer/handler.go +++ b/internal/customer/handler.go @@ -84,33 +84,6 @@ func (h *Handler) CreateCustomer(c echo.Context) error { func (h *Handler) GetCustomerByID(c echo.Context) error { idStr := c.Param("id") - customer, err := h.service.GetCustomerByID(c.Request().Context(), idStr) - if err != nil { - if err.Error() == "customer not found" { - return response.NotFound(c, "Customer not found") - } - return response.InternalServerError(c, "Failed to get customer") - } - - return response.Success(c, customer.ToResponse(), "Customer retrieved successfully") -} - -// GetCustomerByIDWithCompanies retrieves a customer by ID with companies (Web Panel) -// @Summary Get customer by ID with companies -// @Description Retrieve detailed customer information by customer ID including assigned companies -// @Tags Admin-Customers -// @Accept json -// @Produce json -// @Param id path string true "Customer ID" -// @Success 200 {object} response.APIResponse{data=CustomerResponse} "Customer retrieved successfully" -// @Failure 400 {object} response.APIResponse "Bad request - Invalid customer ID" -// @Failure 404 {object} response.APIResponse "Not found - Customer not found" -// @Failure 500 {object} response.APIResponse "Internal server error" -// @Security BearerAuth -// @Router /admin/v1/customers/{id}/with-companies [get] -func (h *Handler) GetCustomerByIDWithCompanies(c echo.Context) error { - idStr := c.Param("id") - customer, err := h.service.GetCustomerByIDWithCompanies(c.Request().Context(), idStr) if err != nil { if err.Error() == "customer not found" { @@ -234,7 +207,7 @@ func (h *Handler) ListCustomers(c echo.Context) error { return response.ValidationError(c, "Invalid request data", err.Error()) } - result, err := h.service.ListCustomers(c.Request().Context(), form) + result, err := h.service.ListCustomersWithCompanies(c.Request().Context(), form) if err != nil { return response.InternalServerError(c, "Failed to list customers") } diff --git a/internal/customer/service.go b/internal/customer/service.go index 381814b..ebf1710 100644 --- a/internal/customer/service.go +++ b/internal/customer/service.go @@ -1280,24 +1280,35 @@ func (s *customerService) getDefaultTimezone(timezone *string) string { // loadCompaniesForCustomer loads company summaries for a customer func (s *customerService) loadCompaniesForCustomer(ctx context.Context, customer *Customer) ([]*CompanySummary, error) { - var companies []*CompanySummary + if len(customer.CompanyIDs) == 0 { + return []*CompanySummary{}, nil + } - // Load companies from CompanyIDs - for _, companyID := range customer.CompanyIDs { - company, err := s.companyService.GetCompanyByID(ctx, companyID) - if err != nil { - s.logger.Warn("Failed to load company for customer", map[string]interface{}{ - "error": err.Error(), - "customer_id": customer.ID, - "company_id": companyID, - }) - continue // Skip companies that can't be loaded - } - companies = append(companies, &CompanySummary{ + // Load companies in batch using the new GetCompaniesByIDs method + companies, err := s.companyService.GetCompaniesByIDs(ctx, customer.CompanyIDs) + if err != nil { + s.logger.Error("Failed to load companies for customer", map[string]interface{}{ + "error": err.Error(), + "customer_id": customer.ID, + "company_ids": customer.CompanyIDs, + }) + return []*CompanySummary{}, err + } + + // Convert to CompanySummary format + var companySummaries []*CompanySummary + for _, company := range companies { + companySummaries = append(companySummaries, &CompanySummary{ ID: company.ID.Hex(), Name: company.Name, }) } - return companies, nil + s.logger.Info("Companies loaded for customer", map[string]interface{}{ + "customer_id": customer.ID, + "requested_count": len(customer.CompanyIDs), + "loaded_count": len(companySummaries), + }) + + return companySummaries, nil }