Add company management domain with CRUD operations and API enhancements
- Introduced a new company management domain, including entities, services, handlers, and forms for company operations. - Implemented CRUD functionality for companies, allowing for creation, retrieval, updating, and deletion of company records. - Enhanced API endpoints for company management, including search and filtering capabilities based on various criteria. - Integrated JWT-based user authorization for company management operations. - Updated Swagger documentation to include new company-related endpoints and detailed request/response structures. - Established MongoDB ORM integration for efficient data handling and repository management. - Added comprehensive validation rules for company forms to ensure data integrity and consistency. - Implemented logging for key operations within the company service and repository for better traceability.
This commit is contained in:
@@ -0,0 +1,874 @@
|
||||
package company
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"tm/pkg/logger"
|
||||
)
|
||||
|
||||
// Service defines business logic for company operations
|
||||
type Service interface {
|
||||
// Core company operations
|
||||
CreateCompany(ctx context.Context, form *CreateCompanyForm, createdBy *string) (*Company, error)
|
||||
GetCompanyByID(ctx context.Context, id string) (*Company, error)
|
||||
UpdateCompany(ctx context.Context, id string, form *UpdateCompanyForm, updatedBy *string) (*Company, error)
|
||||
DeleteCompany(ctx context.Context, id string, deletedBy *string) error
|
||||
|
||||
// Company listing and search
|
||||
ListCompanies(ctx context.Context, form *ListCompaniesForm) (*CompanyListResponse, error)
|
||||
SearchCompanies(ctx context.Context, form *CompanySearchForm) (*CompanyListResponse, error)
|
||||
SearchCompaniesByTags(ctx context.Context, cpvCodes []string, categories []string, keywords []string, specializations []string, limit, offset int) ([]*Company, error)
|
||||
|
||||
// Company management
|
||||
UpdateCompanyStatus(ctx context.Context, id string, form *UpdateCompanyStatusForm, updatedBy *string) error
|
||||
UpdateCompanyVerification(ctx context.Context, id string, form *UpdateCompanyVerificationForm, updatedBy *string) error
|
||||
|
||||
// Customer assignment
|
||||
AssignCustomer(ctx context.Context, id string, form *AssignCustomerForm, assignedBy *string) error
|
||||
UnassignCustomer(ctx context.Context, id string, unassignedBy *string) error
|
||||
GetCompanyByCustomerID(ctx context.Context, customerID string) (*Company, error)
|
||||
|
||||
// Tag management
|
||||
UpdateCompanyTags(ctx context.Context, id string, form *UpdateCompanyTagsForm, updatedBy *string) error
|
||||
AddTags(ctx context.Context, id string, form *AddTagsForm, updatedBy *string) error
|
||||
RemoveTags(ctx context.Context, id string, form *RemoveTagsForm, updatedBy *string) error
|
||||
|
||||
// Business operations
|
||||
VerifyCompany(ctx context.Context, id string, verifiedBy *string) error
|
||||
SuspendCompany(ctx context.Context, id string, reason string, suspendedBy *string) error
|
||||
ActivateCompany(ctx context.Context, id string, activatedBy *string) error
|
||||
|
||||
// Statistics and analytics
|
||||
GetCompanyStats(ctx context.Context) (*CompanyStatsResponse, error)
|
||||
|
||||
// Search and filtering helpers
|
||||
GetCompaniesByType(ctx context.Context, companyType CompanyType, limit, offset int) ([]*Company, int64, error)
|
||||
GetCompaniesByStatus(ctx context.Context, status CompanyStatus, limit, offset int) ([]*Company, int64, error)
|
||||
GetCompaniesByIndustry(ctx context.Context, industry string, limit, offset int) ([]*Company, int64, error)
|
||||
}
|
||||
|
||||
// companyService implements the Service interface
|
||||
type companyService struct {
|
||||
repository Repository
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// NewCompanyService creates a new company service
|
||||
func NewCompanyService(repository Repository, logger logger.Logger) Service {
|
||||
return &companyService{
|
||||
repository: repository,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateCompany creates a new company
|
||||
func (s *companyService) CreateCompany(ctx context.Context, form *CreateCompanyForm, createdBy *string) (*Company, error) {
|
||||
// Check if company name already exists
|
||||
existingCompany, _ := s.repository.GetByName(ctx, form.Name)
|
||||
if existingCompany != nil {
|
||||
return nil, errors.New("company with this name already exists")
|
||||
}
|
||||
|
||||
// Check if registration number already exists
|
||||
existingCompany, _ = s.repository.GetByRegistrationNumber(ctx, form.RegistrationNumber)
|
||||
if existingCompany != nil {
|
||||
return nil, errors.New("company with this registration number already exists")
|
||||
}
|
||||
|
||||
// Check if tax ID already exists
|
||||
existingCompany, _ = s.repository.GetByTaxID(ctx, form.TaxID)
|
||||
if existingCompany != nil {
|
||||
return nil, errors.New("company with this tax ID already exists")
|
||||
}
|
||||
|
||||
// Create company
|
||||
company := &Company{
|
||||
Name: form.Name,
|
||||
Type: CompanyType(form.Type),
|
||||
Status: CompanyStatusPending,
|
||||
RegistrationNumber: form.RegistrationNumber,
|
||||
TaxID: form.TaxID,
|
||||
Industry: form.Industry,
|
||||
Description: form.Description,
|
||||
Website: form.Website,
|
||||
EmployeeCount: form.EmployeeCount,
|
||||
AnnualRevenue: form.AnnualRevenue,
|
||||
FoundedYear: form.FoundedYear,
|
||||
Address: s.convertAddressForm(form.Address),
|
||||
ContactPerson: s.convertContactPersonForm(form.ContactPerson),
|
||||
Phone: form.Phone,
|
||||
Email: form.Email,
|
||||
Tags: s.convertCompanyTagsForm(form.Tags),
|
||||
CustomerID: form.CustomerID,
|
||||
IsVerified: false,
|
||||
IsCompliant: false,
|
||||
Language: s.getDefaultLanguage(form.Language),
|
||||
Currency: s.getDefaultCurrency(form.Currency),
|
||||
Timezone: s.getDefaultTimezone(form.Timezone),
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
|
||||
// Save to database
|
||||
err := s.repository.Create(ctx, company)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to create company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"name": form.Name,
|
||||
"registration_number": form.RegistrationNumber,
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.logger.Info("Company created successfully", map[string]interface{}{
|
||||
"company_id": company.ID,
|
||||
"name": company.Name,
|
||||
"type": company.Type,
|
||||
"created_by": createdBy,
|
||||
})
|
||||
|
||||
return company, nil
|
||||
}
|
||||
|
||||
// GetCompanyByID retrieves a company by ID
|
||||
func (s *companyService) GetCompanyByID(ctx context.Context, id string) (*Company, error) {
|
||||
company, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get company by ID", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.logger.Info("Company retrieved successfully", map[string]interface{}{
|
||||
"company_id": company.ID,
|
||||
"name": company.Name,
|
||||
})
|
||||
|
||||
return company, nil
|
||||
}
|
||||
|
||||
// UpdateCompany updates a company
|
||||
func (s *companyService) UpdateCompany(ctx context.Context, id string, form *UpdateCompanyForm, updatedBy *string) (*Company, error) {
|
||||
// Get existing company
|
||||
company, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get company for update", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return nil, errors.New("company not found")
|
||||
}
|
||||
|
||||
// Check if name already exists (if changing name)
|
||||
if form.Name != nil && *form.Name != company.Name {
|
||||
existingCompany, _ := s.repository.GetByName(ctx, *form.Name)
|
||||
if existingCompany != nil {
|
||||
return nil, errors.New("company with this name already exists")
|
||||
}
|
||||
company.Name = *form.Name
|
||||
}
|
||||
|
||||
// Check if registration number already exists (if changing)
|
||||
if form.RegistrationNumber != nil && *form.RegistrationNumber != company.RegistrationNumber {
|
||||
existingCompany, _ := s.repository.GetByRegistrationNumber(ctx, *form.RegistrationNumber)
|
||||
if existingCompany != nil {
|
||||
return nil, errors.New("company with this registration number already exists")
|
||||
}
|
||||
company.RegistrationNumber = *form.RegistrationNumber
|
||||
}
|
||||
|
||||
// Check if tax ID already exists (if changing)
|
||||
if form.TaxID != nil && *form.TaxID != company.TaxID {
|
||||
existingCompany, _ := s.repository.GetByTaxID(ctx, *form.TaxID)
|
||||
if existingCompany != nil {
|
||||
return nil, errors.New("company with this tax ID already exists")
|
||||
}
|
||||
company.TaxID = *form.TaxID
|
||||
}
|
||||
|
||||
// Update fields if provided
|
||||
if form.Type != nil {
|
||||
company.Type = CompanyType(*form.Type)
|
||||
}
|
||||
|
||||
if form.Industry != nil {
|
||||
company.Industry = *form.Industry
|
||||
}
|
||||
|
||||
if form.Description != nil {
|
||||
company.Description = form.Description
|
||||
}
|
||||
|
||||
if form.Website != nil {
|
||||
company.Website = form.Website
|
||||
}
|
||||
|
||||
if form.EmployeeCount != nil {
|
||||
company.EmployeeCount = form.EmployeeCount
|
||||
}
|
||||
|
||||
if form.AnnualRevenue != nil {
|
||||
company.AnnualRevenue = form.AnnualRevenue
|
||||
}
|
||||
|
||||
if form.FoundedYear != nil {
|
||||
company.FoundedYear = form.FoundedYear
|
||||
}
|
||||
|
||||
if form.Address != nil {
|
||||
company.Address = s.convertAddressForm(form.Address)
|
||||
}
|
||||
|
||||
if form.ContactPerson != nil {
|
||||
company.ContactPerson = s.convertContactPersonForm(form.ContactPerson)
|
||||
}
|
||||
|
||||
if form.Phone != nil {
|
||||
company.Phone = form.Phone
|
||||
}
|
||||
|
||||
if form.Email != nil {
|
||||
company.Email = form.Email
|
||||
}
|
||||
|
||||
if form.Tags != nil {
|
||||
company.Tags = s.convertCompanyTagsForm(form.Tags)
|
||||
}
|
||||
|
||||
if form.CustomerID != nil {
|
||||
company.CustomerID = form.CustomerID
|
||||
}
|
||||
|
||||
if form.Language != nil {
|
||||
company.Language = *form.Language
|
||||
}
|
||||
|
||||
if form.Currency != nil {
|
||||
company.Currency = *form.Currency
|
||||
}
|
||||
|
||||
if form.Timezone != nil {
|
||||
company.Timezone = *form.Timezone
|
||||
}
|
||||
|
||||
// Set updated by
|
||||
company.UpdatedBy = updatedBy
|
||||
company.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// Update in database
|
||||
err = s.repository.Update(ctx, company)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to update company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return nil, errors.New("failed to update company")
|
||||
}
|
||||
|
||||
s.logger.Info("Company updated successfully", map[string]interface{}{
|
||||
"company_id": company.ID,
|
||||
"name": company.Name,
|
||||
"updated_by": updatedBy,
|
||||
})
|
||||
|
||||
return company, nil
|
||||
}
|
||||
|
||||
// DeleteCompany deletes a company (soft delete)
|
||||
func (s *companyService) DeleteCompany(ctx context.Context, id string, deletedBy *string) error {
|
||||
// Get company to check if exists
|
||||
company, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Set updated by before deletion
|
||||
company.UpdatedBy = deletedBy
|
||||
|
||||
// Delete company (soft delete)
|
||||
err = s.repository.Delete(ctx, id)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to delete company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to delete company")
|
||||
}
|
||||
|
||||
s.logger.Info("Company deleted successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"deleted_by": deletedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListCompanies lists companies with search and filters
|
||||
func (s *companyService) ListCompanies(ctx context.Context, form *ListCompaniesForm) (*CompanyListResponse, error) {
|
||||
// Set defaults
|
||||
limit := 20
|
||||
if form.Limit != nil {
|
||||
limit = *form.Limit
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if form.Offset != nil {
|
||||
offset = *form.Offset
|
||||
}
|
||||
|
||||
search := ""
|
||||
if form.Search != nil {
|
||||
search = *form.Search
|
||||
}
|
||||
|
||||
sortBy := "created_at"
|
||||
if form.SortBy != nil {
|
||||
sortBy = *form.SortBy
|
||||
}
|
||||
|
||||
sortOrder := "desc"
|
||||
if form.SortOrder != nil {
|
||||
sortOrder = *form.SortOrder
|
||||
}
|
||||
|
||||
// Get companies
|
||||
companies, err := s.repository.Search(ctx, search, form.Type, form.Status, form.Industry, form.IsVerified, form.IsCompliant, form.Language, form.Currency, form.HasCustomer, form.CPVCodes, form.Categories, form.Keywords, form.Specializations, form.EmployeeCountMin, form.EmployeeCountMax, form.AnnualRevenueMin, form.AnnualRevenueMax, form.FoundedYearMin, form.FoundedYearMax, limit, offset, sortBy, sortOrder)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to list companies", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return nil, errors.New("failed to list companies")
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
var companyResponses []*CompanyResponse
|
||||
for _, company := range companies {
|
||||
companyResponses = append(companyResponses, company.ToResponse())
|
||||
}
|
||||
|
||||
// TODO: Implement proper count for pagination metadata
|
||||
total := int64(len(companies)) // This should be a separate count query
|
||||
totalPages := (total + int64(limit) - 1) / int64(limit)
|
||||
|
||||
return &CompanyListResponse{
|
||||
Companies: companyResponses,
|
||||
Total: total,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
TotalPages: int(totalPages),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SearchCompanies searches companies with advanced filters
|
||||
func (s *companyService) SearchCompanies(ctx context.Context, form *CompanySearchForm) (*CompanyListResponse, error) {
|
||||
// Set defaults
|
||||
limit := 20
|
||||
if form.Limit != nil {
|
||||
limit = *form.Limit
|
||||
}
|
||||
|
||||
offset := 0
|
||||
if form.Offset != nil {
|
||||
offset = *form.Offset
|
||||
}
|
||||
|
||||
query := ""
|
||||
if form.Query != nil {
|
||||
query = *form.Query
|
||||
}
|
||||
|
||||
// Get companies using search
|
||||
companies, err := s.repository.Search(ctx, query, nil, nil, form.Industry, form.IsVerified, form.IsCompliant, nil, nil, nil, form.CPVCodes, form.Categories, form.Keywords, form.Specializations, form.MinEmployees, form.MaxEmployees, form.MinRevenue, form.MaxRevenue, nil, nil, limit, offset, "created_at", "desc")
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to search companies", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"query": query,
|
||||
})
|
||||
return nil, errors.New("failed to search companies")
|
||||
}
|
||||
|
||||
// Convert to responses
|
||||
var companyResponses []*CompanyResponse
|
||||
for _, company := range companies {
|
||||
companyResponses = append(companyResponses, company.ToResponse())
|
||||
}
|
||||
|
||||
// TODO: Implement proper count for pagination metadata
|
||||
total := int64(len(companies)) // This should be a separate count query
|
||||
totalPages := (total + int64(limit) - 1) / int64(limit)
|
||||
|
||||
return &CompanyListResponse{
|
||||
Companies: companyResponses,
|
||||
Total: total,
|
||||
Limit: limit,
|
||||
Offset: offset,
|
||||
TotalPages: int(totalPages),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SearchCompaniesByTags searches companies by tags
|
||||
func (s *companyService) SearchCompaniesByTags(ctx context.Context, cpvCodes []string, categories []string, keywords []string, specializations []string, limit, offset int) ([]*Company, error) {
|
||||
companies, err := s.repository.SearchByTags(ctx, cpvCodes, categories, keywords, specializations, limit, offset)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to search companies by tags", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return nil, errors.New("failed to search companies by tags")
|
||||
}
|
||||
|
||||
return companies, nil
|
||||
}
|
||||
|
||||
// UpdateCompanyStatus updates company status
|
||||
func (s *companyService) UpdateCompanyStatus(ctx context.Context, id string, form *UpdateCompanyStatusForm, updatedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Update status
|
||||
status := CompanyStatus(form.Status)
|
||||
err = s.repository.UpdateStatus(ctx, id, status)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to update company status", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
"status": form.Status,
|
||||
})
|
||||
return errors.New("failed to update company status")
|
||||
}
|
||||
|
||||
s.logger.Info("Company status updated successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"status": form.Status,
|
||||
"updated_by": updatedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateCompanyVerification updates company verification status
|
||||
func (s *companyService) UpdateCompanyVerification(ctx context.Context, id string, form *UpdateCompanyVerificationForm, updatedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Update verification
|
||||
err = s.repository.UpdateVerification(ctx, id, form.IsVerified, form.IsCompliant, form.ComplianceNotes)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to update company verification", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to update company verification")
|
||||
}
|
||||
|
||||
s.logger.Info("Company verification updated successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"is_verified": form.IsVerified,
|
||||
"is_compliant": form.IsCompliant,
|
||||
"updated_by": updatedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssignCustomer assigns a customer to a company
|
||||
func (s *companyService) AssignCustomer(ctx context.Context, id string, form *AssignCustomerForm, assignedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Check if customer is already assigned to another company
|
||||
existingCompany, _ := s.repository.GetByCustomerID(ctx, form.CustomerID)
|
||||
if existingCompany != nil {
|
||||
return errors.New("customer is already assigned to another company")
|
||||
}
|
||||
|
||||
// Assign customer
|
||||
err = s.repository.AssignCustomer(ctx, id, form.CustomerID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to assign customer to company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
"customer_id": form.CustomerID,
|
||||
})
|
||||
return errors.New("failed to assign customer to company")
|
||||
}
|
||||
|
||||
s.logger.Info("Customer assigned to company successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"customer_id": form.CustomerID,
|
||||
"assigned_by": assignedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnassignCustomer unassigns a customer from a company
|
||||
func (s *companyService) UnassignCustomer(ctx context.Context, id string, unassignedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Unassign customer
|
||||
err = s.repository.UnassignCustomer(ctx, id)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to unassign customer from company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to unassign customer from company")
|
||||
}
|
||||
|
||||
s.logger.Info("Customer unassigned from company successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"unassigned_by": unassignedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCompanyByCustomerID retrieves a company by customer ID
|
||||
func (s *companyService) GetCompanyByCustomerID(ctx context.Context, customerID string) (*Company, error) {
|
||||
company, err := s.repository.GetByCustomerID(ctx, customerID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get company by customer ID", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"customer_id": customerID,
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.logger.Info("Company retrieved by customer ID successfully", map[string]interface{}{
|
||||
"company_id": company.ID,
|
||||
"customer_id": customerID,
|
||||
})
|
||||
|
||||
return company, nil
|
||||
}
|
||||
|
||||
// UpdateCompanyTags updates company tags
|
||||
func (s *companyService) UpdateCompanyTags(ctx context.Context, id string, form *UpdateCompanyTagsForm, updatedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Update tags
|
||||
tags := s.convertCompanyTagsForm(form.Tags)
|
||||
err = s.repository.UpdateTags(ctx, id, tags)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to update company tags", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to update company tags")
|
||||
}
|
||||
|
||||
s.logger.Info("Company tags updated successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"updated_by": updatedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddTags adds tags to a company
|
||||
func (s *companyService) AddTags(ctx context.Context, id string, form *AddTagsForm, updatedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Add tags
|
||||
err = s.repository.AddTags(ctx, id, form.CPVCodes, form.Categories, form.Keywords, form.Specializations, form.Certifications)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to add tags to company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to add tags to company")
|
||||
}
|
||||
|
||||
s.logger.Info("Tags added to company successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"updated_by": updatedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveTags removes tags from a company
|
||||
func (s *companyService) RemoveTags(ctx context.Context, id string, form *RemoveTagsForm, updatedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Remove tags
|
||||
err = s.repository.RemoveTags(ctx, id, form.CPVCodes, form.Categories, form.Keywords, form.Specializations, form.Certifications)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to remove tags from company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to remove tags from company")
|
||||
}
|
||||
|
||||
s.logger.Info("Tags removed from company successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"updated_by": updatedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyCompany verifies a company
|
||||
func (s *companyService) VerifyCompany(ctx context.Context, id string, verifiedBy *string) error {
|
||||
// Get company to check if exists
|
||||
company, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Update verification
|
||||
err = s.repository.UpdateVerification(ctx, id, true, company.IsCompliant, company.ComplianceNotes)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to verify company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to verify company")
|
||||
}
|
||||
|
||||
s.logger.Info("Company verified successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"verified_by": verifiedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SuspendCompany suspends a company
|
||||
func (s *companyService) SuspendCompany(ctx context.Context, id string, reason string, suspendedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Update status to suspended
|
||||
err = s.repository.UpdateStatus(ctx, id, CompanyStatusSuspended)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to suspend company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to suspend company")
|
||||
}
|
||||
|
||||
s.logger.Info("Company suspended successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"reason": reason,
|
||||
"suspended_by": suspendedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActivateCompany activates a company
|
||||
func (s *companyService) ActivateCompany(ctx context.Context, id string, activatedBy *string) error {
|
||||
// Get company to check if exists
|
||||
_, err := s.repository.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return errors.New("company not found")
|
||||
}
|
||||
|
||||
// Update status to active
|
||||
err = s.repository.UpdateStatus(ctx, id, CompanyStatusActive)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to activate company", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_id": id,
|
||||
})
|
||||
return errors.New("failed to activate company")
|
||||
}
|
||||
|
||||
s.logger.Info("Company activated successfully", map[string]interface{}{
|
||||
"company_id": id,
|
||||
"activated_by": activatedBy,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCompanyStats returns company statistics
|
||||
func (s *companyService) GetCompanyStats(ctx context.Context) (*CompanyStatsResponse, error) {
|
||||
stats, err := s.repository.GetCompanyStats(ctx)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get company stats", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return nil, errors.New("failed to get company statistics")
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// GetCompaniesByType retrieves companies by type with pagination
|
||||
func (s *companyService) GetCompaniesByType(ctx context.Context, companyType CompanyType, limit, offset int) ([]*Company, int64, error) {
|
||||
// Use search method with type filter
|
||||
typeStr := string(companyType)
|
||||
companies, err := s.repository.Search(ctx, "", &typeStr, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get companies by type", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_type": companyType,
|
||||
})
|
||||
return nil, 0, errors.New("failed to get companies by type")
|
||||
}
|
||||
|
||||
// Get total count
|
||||
total, err := s.repository.CountByType(ctx, companyType)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to count companies by type", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"company_type": companyType,
|
||||
})
|
||||
return companies, 0, nil // Return companies even if count fails
|
||||
}
|
||||
|
||||
return companies, total, nil
|
||||
}
|
||||
|
||||
// GetCompaniesByStatus retrieves companies by status with pagination
|
||||
func (s *companyService) GetCompaniesByStatus(ctx context.Context, status CompanyStatus, limit, offset int) ([]*Company, int64, error) {
|
||||
// Use search method with status filter
|
||||
statusStr := string(status)
|
||||
companies, err := s.repository.Search(ctx, "", nil, &statusStr, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get companies by status", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"status": status,
|
||||
})
|
||||
return nil, 0, errors.New("failed to get companies by status")
|
||||
}
|
||||
|
||||
// Get total count
|
||||
total, err := s.repository.CountByStatus(ctx, status)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to count companies by status", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"status": status,
|
||||
})
|
||||
return companies, 0, nil
|
||||
}
|
||||
|
||||
return companies, total, nil
|
||||
}
|
||||
|
||||
// GetCompaniesByIndustry retrieves companies by industry with pagination
|
||||
func (s *companyService) GetCompaniesByIndustry(ctx context.Context, industry string, limit, offset int) ([]*Company, int64, error) {
|
||||
// Use search method with industry filter
|
||||
companies, err := s.repository.Search(ctx, "", nil, nil, &industry, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to get companies by industry", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"industry": industry,
|
||||
})
|
||||
return nil, 0, errors.New("failed to get companies by industry")
|
||||
}
|
||||
|
||||
// Get total count
|
||||
total, err := s.repository.CountByIndustry(ctx, industry)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to count companies by industry", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"industry": industry,
|
||||
})
|
||||
return companies, 0, nil
|
||||
}
|
||||
|
||||
return companies, total, nil
|
||||
}
|
||||
|
||||
// Helper methods for converting forms to domain objects
|
||||
func (s *companyService) convertAddressForm(form *AddressForm) *Address {
|
||||
if form == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &Address{
|
||||
Street: form.Street,
|
||||
City: form.City,
|
||||
State: form.State,
|
||||
PostalCode: form.PostalCode,
|
||||
Country: form.Country,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *companyService) convertContactPersonForm(form *ContactPersonForm) *ContactPerson {
|
||||
if form == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ContactPerson{
|
||||
FirstName: form.FirstName,
|
||||
LastName: form.LastName,
|
||||
FullName: form.FullName,
|
||||
Position: form.Position,
|
||||
Email: form.Email,
|
||||
Phone: form.Phone,
|
||||
Mobile: form.Mobile,
|
||||
IsPrimary: form.IsPrimary,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *companyService) convertCompanyTagsForm(form *CompanyTagsForm) *CompanyTags {
|
||||
if form == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &CompanyTags{
|
||||
CPVCodes: form.CPVCodes,
|
||||
Categories: form.Categories,
|
||||
Keywords: form.Keywords,
|
||||
Specializations: form.Specializations,
|
||||
Certifications: form.Certifications,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *companyService) getDefaultLanguage(language *string) string {
|
||||
if language != nil {
|
||||
return *language
|
||||
}
|
||||
return "en"
|
||||
}
|
||||
|
||||
func (s *companyService) getDefaultCurrency(currency *string) string {
|
||||
if currency != nil {
|
||||
return *currency
|
||||
}
|
||||
return "USD"
|
||||
}
|
||||
|
||||
func (s *companyService) getDefaultTimezone(timezone *string) string {
|
||||
if timezone != nil {
|
||||
return *timezone
|
||||
}
|
||||
return "UTC"
|
||||
}
|
||||
Reference in New Issue
Block a user