Refactor company domain by removing customer-related fields and methods

- Removed OwnerCustomerID from Company entity and CompanyResponse to streamline ownership representation.
- Eliminated customer assignment fields from CreateCompanyForm and ListCompaniesForm for clarity.
- Updated repository and service methods to remove GetByCustomerID and CountWithCustomer, simplifying the codebase.
- Adjusted Search method parameters to exclude hasCustomer filter, enhancing search functionality.
- Improved API documentation by removing references to customer assignment in handler comments.
This commit is contained in:
n.nakhostin
2025-08-11 18:31:15 +03:30
parent 3e4831c2e7
commit f5407abbf0
5 changed files with 23 additions and 107 deletions
-5
View File
@@ -65,9 +65,6 @@ type Company struct {
Currency string `bson:"currency" json:"currency"` // Default: "USD" Currency string `bson:"currency" json:"currency"` // Default: "USD"
Timezone string `bson:"timezone" json:"timezone"` // Default: "UTC" Timezone string `bson:"timezone" json:"timezone"` // Default: "UTC"
// Company ownership - which customer owns this company
OwnerCustomerID *string `bson:"owner_customer_id,omitempty" json:"owner_customer_id,omitempty"`
// Audit fields // Audit fields
CreatedBy *string `bson:"created_by,omitempty" json:"created_by,omitempty"` CreatedBy *string `bson:"created_by,omitempty" json:"created_by,omitempty"`
UpdatedBy *string `bson:"updated_by,omitempty" json:"updated_by,omitempty"` UpdatedBy *string `bson:"updated_by,omitempty" json:"updated_by,omitempty"`
@@ -167,7 +164,6 @@ type CompanyResponse struct {
Language string `json:"language"` Language string `json:"language"`
Currency string `json:"currency"` Currency string `json:"currency"`
Timezone string `json:"timezone"` Timezone string `json:"timezone"`
OwnerCustomerID *string `json:"owner_customer_id,omitempty"`
CreatedAt int64 `json:"created_at"` CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"` UpdatedAt int64 `json:"updated_at"`
CreatedBy *string `json:"created_by,omitempty"` CreatedBy *string `json:"created_by,omitempty"`
@@ -200,7 +196,6 @@ func (c *Company) ToResponse() *CompanyResponse {
Language: c.Language, Language: c.Language,
Currency: c.Currency, Currency: c.Currency,
Timezone: c.Timezone, Timezone: c.Timezone,
OwnerCustomerID: c.OwnerCustomerID,
CreatedAt: c.CreatedAt, CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt, UpdatedAt: c.UpdatedAt,
CreatedBy: c.CreatedBy, CreatedBy: c.CreatedBy,
-10
View File
@@ -26,9 +26,6 @@ type CreateCompanyForm struct {
// Tags for categorization and search // Tags for categorization and search
Tags *CompanyTagsForm `json:"tags,omitempty"` Tags *CompanyTagsForm `json:"tags,omitempty"`
// Customer assignment (for login credentials)
CustomerID *string `json:"customer_id,omitempty" valid:"optional,uuid"`
// Settings // Settings
Language *string `json:"language,omitempty" valid:"optional,in(en|ar|fr|es|de|zh|ja|ko)"` Language *string `json:"language,omitempty" valid:"optional,in(en|ar|fr|es|de|zh|ja|ko)"`
Currency *string `json:"currency,omitempty" valid:"optional,in(USD|EUR|GBP|JPY|CAD|AUD|CHF|CNY|INR|BRL)"` Currency *string `json:"currency,omitempty" valid:"optional,in(USD|EUR|GBP|JPY|CAD|AUD|CHF|CNY|INR|BRL)"`
@@ -81,7 +78,6 @@ type ListCompaniesForm struct {
Categories []string `query:"categories" valid:"optional"` Categories []string `query:"categories" valid:"optional"`
Keywords []string `query:"keywords" valid:"optional"` Keywords []string `query:"keywords" valid:"optional"`
Specializations []string `query:"specializations" valid:"optional"` Specializations []string `query:"specializations" valid:"optional"`
HasCustomer *bool `query:"has_customer" valid:"optional"`
EmployeeCountMin *int `query:"employee_count_min" valid:"optional,min(1)"` EmployeeCountMin *int `query:"employee_count_min" valid:"optional,min(1)"`
EmployeeCountMax *int `query:"employee_count_max" valid:"optional,min(1)"` EmployeeCountMax *int `query:"employee_count_max" valid:"optional,min(1)"`
AnnualRevenueMin *float64 `query:"annual_revenue_min" valid:"optional,min(0)"` AnnualRevenueMin *float64 `query:"annual_revenue_min" valid:"optional,min(0)"`
@@ -106,11 +102,6 @@ type UpdateCompanyVerificationForm struct {
ComplianceNotes *string `json:"compliance_notes,omitempty" valid:"optional,length(0|1000)"` ComplianceNotes *string `json:"compliance_notes,omitempty" valid:"optional,length(0|1000)"`
} }
// AssignCustomerForm represents the form for assigning a customer to a company
type AssignCustomerForm struct {
CustomerID string `json:"customer_id" valid:"required,uuid"`
}
// UpdateCompanyTagsForm represents the form for updating company tags // UpdateCompanyTagsForm represents the form for updating company tags
type UpdateCompanyTagsForm struct { type UpdateCompanyTagsForm struct {
Tags *CompanyTagsForm `json:"tags" valid:"required"` Tags *CompanyTagsForm `json:"tags" valid:"required"`
@@ -202,7 +193,6 @@ type CompanyStatsResponse struct {
TotalCompanies int64 `json:"total_companies"` TotalCompanies int64 `json:"total_companies"`
ActiveCompanies int64 `json:"active_companies"` ActiveCompanies int64 `json:"active_companies"`
VerifiedCompanies int64 `json:"verified_companies"` VerifiedCompanies int64 `json:"verified_companies"`
CompaniesWithCustomer int64 `json:"companies_with_customer"`
CompaniesByType map[string]int64 `json:"companies_by_type"` CompaniesByType map[string]int64 `json:"companies_by_type"`
CompaniesByIndustry map[string]int64 `json:"companies_by_industry"` CompaniesByIndustry map[string]int64 `json:"companies_by_industry"`
CompaniesByStatus map[string]int64 `json:"companies_by_status"` CompaniesByStatus map[string]int64 `json:"companies_by_status"`
-1
View File
@@ -183,7 +183,6 @@ func (h *Handler) DeleteCompany(c echo.Context) error {
// @Param industry query string false "Filter by industry" // @Param industry query string false "Filter by industry"
// @Param is_verified query boolean false "Filter by verification status" // @Param is_verified query boolean false "Filter by verification status"
// @Param is_compliant query boolean false "Filter by compliance status" // @Param is_compliant query boolean false "Filter by compliance status"
// @Param has_customer query boolean false "Filter by customer assignment status"
// @Param cpv_codes query array false "Filter by CPV codes" // @Param cpv_codes query array false "Filter by CPV codes"
// @Param categories query array false "Filter by categories" // @Param categories query array false "Filter by categories"
// @Param keywords query array false "Filter by keywords" // @Param keywords query array false "Filter by keywords"
+2 -51
View File
@@ -17,17 +17,15 @@ type Repository interface {
GetByName(ctx context.Context, name string) (*Company, error) GetByName(ctx context.Context, name string) (*Company, error)
GetByRegistrationNumber(ctx context.Context, registrationNumber string) (*Company, error) GetByRegistrationNumber(ctx context.Context, registrationNumber string) (*Company, error)
GetByTaxID(ctx context.Context, taxID string) (*Company, error) GetByTaxID(ctx context.Context, taxID string) (*Company, error)
GetByCustomerID(ctx context.Context, customerID string) (*Company, error)
Update(ctx context.Context, company *Company) error Update(ctx context.Context, company *Company) error
Delete(ctx context.Context, id string) error Delete(ctx context.Context, id string) error
List(ctx context.Context, limit, offset int) ([]*Company, error) List(ctx context.Context, limit, offset int) ([]*Company, error)
Search(ctx context.Context, search string, companyType *string, status *string, industry *string, isVerified *bool, isCompliant *bool, language *string, currency *string, hasCustomer *bool, cpvCodes []string, categories []string, keywords []string, specializations []string, employeeCountMin *int, employeeCountMax *int, annualRevenueMin *float64, annualRevenueMax *float64, foundedYearMin *int, foundedYearMax *int, limit, offset int, sortBy, sortOrder string) ([]*Company, error) Search(ctx context.Context, search string, companyType *string, status *string, industry *string, isVerified *bool, isCompliant *bool, language *string, currency *string, cpvCodes []string, categories []string, keywords []string, specializations []string, employeeCountMin *int, employeeCountMax *int, annualRevenueMin *float64, annualRevenueMax *float64, foundedYearMin *int, foundedYearMax *int, limit, offset int, sortBy, sortOrder string) ([]*Company, error)
Count(ctx context.Context) (int64, error) Count(ctx context.Context) (int64, error)
CountByType(ctx context.Context, companyType CompanyType) (int64, error) CountByType(ctx context.Context, companyType CompanyType) (int64, error)
CountByStatus(ctx context.Context, status CompanyStatus) (int64, error) CountByStatus(ctx context.Context, status CompanyStatus) (int64, error)
CountByIndustry(ctx context.Context, industry string) (int64, error) CountByIndustry(ctx context.Context, industry string) (int64, error)
CountVerified(ctx context.Context) (int64, error) CountVerified(ctx context.Context) (int64, error)
CountWithCustomer(ctx context.Context) (int64, error)
UpdateStatus(ctx context.Context, id string, status CompanyStatus) error UpdateStatus(ctx context.Context, id string, status CompanyStatus) error
UpdateVerification(ctx context.Context, id string, isVerified, isCompliant bool, complianceNotes *string) error UpdateVerification(ctx context.Context, id string, isVerified, isCompliant bool, complianceNotes *string) error
UpdateTags(ctx context.Context, id string, tags *CompanyTags) error UpdateTags(ctx context.Context, id string, tags *CompanyTags) error
@@ -50,7 +48,6 @@ func NewCompanyRepository(mongoManager *mongopkg.ConnectionManager, logger logge
*mongopkg.CreateUniqueIndex("name_idx", bson.D{{Key: "name", Value: 1}}), *mongopkg.CreateUniqueIndex("name_idx", bson.D{{Key: "name", Value: 1}}),
*mongopkg.CreateUniqueIndex("registration_number_idx", bson.D{{Key: "registration_number", Value: 1}}), *mongopkg.CreateUniqueIndex("registration_number_idx", bson.D{{Key: "registration_number", Value: 1}}),
*mongopkg.CreateUniqueIndex("tax_id_idx", bson.D{{Key: "tax_id", Value: 1}}), *mongopkg.CreateUniqueIndex("tax_id_idx", bson.D{{Key: "tax_id", Value: 1}}),
*mongopkg.NewIndex("customer_id_idx", bson.D{{Key: "customer_id", Value: 1}}),
*mongopkg.NewIndex("type_idx", bson.D{{Key: "type", Value: 1}}), *mongopkg.NewIndex("type_idx", bson.D{{Key: "type", Value: 1}}),
*mongopkg.NewIndex("status_idx", bson.D{{Key: "status", Value: 1}}), *mongopkg.NewIndex("status_idx", bson.D{{Key: "status", Value: 1}}),
*mongopkg.NewIndex("industry_idx", bson.D{{Key: "industry", Value: 1}}), *mongopkg.NewIndex("industry_idx", bson.D{{Key: "industry", Value: 1}}),
@@ -187,24 +184,6 @@ func (r *companyRepository) GetByTaxID(ctx context.Context, taxID string) (*Comp
return company, nil return company, nil
} }
// GetByCustomerID retrieves a company by customer ID
func (r *companyRepository) GetByCustomerID(ctx context.Context, customerID string) (*Company, error) {
filter := bson.M{"customer_id": customerID}
company, err := r.ormRepo.FindOne(ctx, filter)
if err != nil {
if errors.Is(err, mongopkg.ErrDocumentNotFound) {
return nil, errors.New("company not found")
}
r.logger.Error("Failed to get company by customer ID", map[string]interface{}{
"error": err.Error(),
"customer_id": customerID,
})
return nil, err
}
return company, nil
}
// Update updates a company // Update updates a company
func (r *companyRepository) Update(ctx context.Context, company *Company) error { func (r *companyRepository) Update(ctx context.Context, company *Company) error {
// Set updated timestamp using Unix timestamp // Set updated timestamp using Unix timestamp
@@ -290,7 +269,7 @@ func (r *companyRepository) List(ctx context.Context, limit, offset int) ([]*Com
} }
// Search retrieves companies with search and filters // Search retrieves companies with search and filters
func (r *companyRepository) Search(ctx context.Context, search string, companyType *string, status *string, industry *string, isVerified *bool, isCompliant *bool, language *string, currency *string, hasCustomer *bool, cpvCodes []string, categories []string, keywords []string, specializations []string, employeeCountMin *int, employeeCountMax *int, annualRevenueMin *float64, annualRevenueMax *float64, foundedYearMin *int, foundedYearMax *int, limit, offset int, sortBy, sortOrder string) ([]*Company, error) { func (r *companyRepository) Search(ctx context.Context, search string, companyType *string, status *string, industry *string, isVerified *bool, isCompliant *bool, language *string, currency *string, cpvCodes []string, categories []string, keywords []string, specializations []string, employeeCountMin *int, employeeCountMax *int, annualRevenueMin *float64, annualRevenueMax *float64, foundedYearMin *int, foundedYearMax *int, limit, offset int, sortBy, sortOrder string) ([]*Company, error) {
// Build filter // Build filter
filter := bson.M{} filter := bson.M{}
@@ -326,14 +305,6 @@ func (r *companyRepository) Search(ctx context.Context, search string, companyTy
filter["currency"] = *currency filter["currency"] = *currency
} }
if hasCustomer != nil {
if *hasCustomer {
filter["customer_id"] = bson.M{"$ne": nil}
} else {
filter["customer_id"] = nil
}
}
// Tag filters // Tag filters
if len(cpvCodes) > 0 { if len(cpvCodes) > 0 {
filter["tags.cpv_codes"] = bson.M{"$in": cpvCodes} filter["tags.cpv_codes"] = bson.M{"$in": cpvCodes}
@@ -507,24 +478,6 @@ func (r *companyRepository) CountVerified(ctx context.Context) (int64, error) {
return count, nil return count, nil
} }
// CountWithCustomer counts companies with assigned customers
func (r *companyRepository) CountWithCustomer(ctx context.Context) (int64, error) {
filter := bson.M{
"customer_id": bson.M{"$ne": nil},
"status": bson.M{"$ne": CompanyStatusInactive},
}
count, err := r.ormRepo.Count(ctx, filter)
if err != nil {
r.logger.Error("Failed to count companies with customer", map[string]interface{}{
"error": err.Error(),
})
return 0, err
}
return count, nil
}
// UpdateStatus updates company status // UpdateStatus updates company status
func (r *companyRepository) UpdateStatus(ctx context.Context, id string, status CompanyStatus) error { func (r *companyRepository) UpdateStatus(ctx context.Context, id string, status CompanyStatus) error {
// Get company first // Get company first
@@ -704,7 +657,6 @@ func (r *companyRepository) GetCompanyStats(ctx context.Context) (*CompanyStatsR
totalCompanies, _ := r.Count(ctx) totalCompanies, _ := r.Count(ctx)
activeCompanies, _ := r.CountByStatus(ctx, CompanyStatusActive) activeCompanies, _ := r.CountByStatus(ctx, CompanyStatusActive)
verifiedCompanies, _ := r.CountVerified(ctx) verifiedCompanies, _ := r.CountVerified(ctx)
companiesWithCustomer, _ := r.CountWithCustomer(ctx)
// For this implementation, we'll return basic stats // For this implementation, we'll return basic stats
// In a real implementation, you'd use MongoDB aggregation pipelines // In a real implementation, you'd use MongoDB aggregation pipelines
@@ -712,7 +664,6 @@ func (r *companyRepository) GetCompanyStats(ctx context.Context) (*CompanyStatsR
TotalCompanies: totalCompanies, TotalCompanies: totalCompanies,
ActiveCompanies: activeCompanies, ActiveCompanies: activeCompanies,
VerifiedCompanies: verifiedCompanies, VerifiedCompanies: verifiedCompanies,
CompaniesWithCustomer: companiesWithCustomer,
CompaniesByType: make(map[string]int64), CompaniesByType: make(map[string]int64),
CompaniesByIndustry: make(map[string]int64), CompaniesByIndustry: make(map[string]int64),
CompaniesByStatus: make(map[string]int64), CompaniesByStatus: make(map[string]int64),
+5 -24
View File
@@ -325,7 +325,7 @@ func (s *companyService) ListCompanies(ctx context.Context, form *ListCompaniesF
} }
// Get companies // 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) companies, err := s.repository.Search(ctx, search, form.Type, form.Status, form.Industry, form.IsVerified, form.IsCompliant, form.Language, form.Currency, 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 { if err != nil {
s.logger.Error("Failed to list companies", map[string]interface{}{ s.logger.Error("Failed to list companies", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
@@ -371,7 +371,7 @@ func (s *companyService) SearchCompanies(ctx context.Context, form *CompanySearc
} }
// Get companies using search // 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") companies, err := s.repository.Search(ctx, query, nil, nil, form.Industry, form.IsVerified, form.IsCompliant, 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 { if err != nil {
s.logger.Error("Failed to search companies", map[string]interface{}{ s.logger.Error("Failed to search companies", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
@@ -469,25 +469,6 @@ func (s *companyService) UpdateCompanyVerification(ctx context.Context, id strin
return nil 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 // UpdateCompanyTags updates company tags
func (s *companyService) UpdateCompanyTags(ctx context.Context, id string, form *UpdateCompanyTagsForm, updatedBy *string) error { func (s *companyService) UpdateCompanyTags(ctx context.Context, id string, form *UpdateCompanyTagsForm, updatedBy *string) error {
// Get company to check if exists // Get company to check if exists
@@ -663,7 +644,7 @@ func (s *companyService) GetCompanyStats(ctx context.Context) (*CompanyStatsResp
func (s *companyService) GetCompaniesByType(ctx context.Context, companyType CompanyType, limit, offset int) ([]*Company, int64, error) { func (s *companyService) GetCompaniesByType(ctx context.Context, companyType CompanyType, limit, offset int) ([]*Company, int64, error) {
// Use search method with type filter // Use search method with type filter
typeStr := string(companyType) 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") companies, err := s.repository.Search(ctx, "", &typeStr, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
if err != nil { if err != nil {
s.logger.Error("Failed to get companies by type", map[string]interface{}{ s.logger.Error("Failed to get companies by type", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
@@ -689,7 +670,7 @@ func (s *companyService) GetCompaniesByType(ctx context.Context, companyType Com
func (s *companyService) GetCompaniesByStatus(ctx context.Context, status CompanyStatus, limit, offset int) ([]*Company, int64, error) { func (s *companyService) GetCompaniesByStatus(ctx context.Context, status CompanyStatus, limit, offset int) ([]*Company, int64, error) {
// Use search method with status filter // Use search method with status filter
statusStr := string(status) 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") companies, err := s.repository.Search(ctx, "", nil, &statusStr, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
if err != nil { if err != nil {
s.logger.Error("Failed to get companies by status", map[string]interface{}{ s.logger.Error("Failed to get companies by status", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
@@ -714,7 +695,7 @@ func (s *companyService) GetCompaniesByStatus(ctx context.Context, status Compan
// GetCompaniesByIndustry retrieves companies by industry with pagination // GetCompaniesByIndustry retrieves companies by industry with pagination
func (s *companyService) GetCompaniesByIndustry(ctx context.Context, industry string, limit, offset int) ([]*Company, int64, error) { func (s *companyService) GetCompaniesByIndustry(ctx context.Context, industry string, limit, offset int) ([]*Company, int64, error) {
// Use search method with industry filter // 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") companies, err := s.repository.Search(ctx, "", nil, nil, &industry, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, limit, offset, "created_at", "desc")
if err != nil { if err != nil {
s.logger.Error("Failed to get companies by industry", map[string]interface{}{ s.logger.Error("Failed to get companies by industry", map[string]interface{}{
"error": err.Error(), "error": err.Error(),