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"
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
CreatedBy *string `bson:"created_by,omitempty" json:"created_by,omitempty"`
UpdatedBy *string `bson:"updated_by,omitempty" json:"updated_by,omitempty"`
@@ -167,7 +164,6 @@ type CompanyResponse struct {
Language string `json:"language"`
Currency string `json:"currency"`
Timezone string `json:"timezone"`
OwnerCustomerID *string `json:"owner_customer_id,omitempty"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
CreatedBy *string `json:"created_by,omitempty"`
@@ -200,7 +196,6 @@ func (c *Company) ToResponse() *CompanyResponse {
Language: c.Language,
Currency: c.Currency,
Timezone: c.Timezone,
OwnerCustomerID: c.OwnerCustomerID,
CreatedAt: c.CreatedAt,
UpdatedAt: c.UpdatedAt,
CreatedBy: c.CreatedBy,
+8 -18
View File
@@ -26,9 +26,6 @@ type CreateCompanyForm struct {
// Tags for categorization and search
Tags *CompanyTagsForm `json:"tags,omitempty"`
// Customer assignment (for login credentials)
CustomerID *string `json:"customer_id,omitempty" valid:"optional,uuid"`
// Settings
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)"`
@@ -81,7 +78,6 @@ type ListCompaniesForm struct {
Categories []string `query:"categories" valid:"optional"`
Keywords []string `query:"keywords" 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)"`
EmployeeCountMax *int `query:"employee_count_max" valid:"optional,min(1)"`
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)"`
}
// 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
type UpdateCompanyTagsForm struct {
Tags *CompanyTagsForm `json:"tags" valid:"required"`
@@ -199,15 +190,14 @@ type CompanySearchForm struct {
// Company statistics DTOs
type CompanyStatsResponse struct {
TotalCompanies int64 `json:"total_companies"`
ActiveCompanies int64 `json:"active_companies"`
VerifiedCompanies int64 `json:"verified_companies"`
CompaniesWithCustomer int64 `json:"companies_with_customer"`
CompaniesByType map[string]int64 `json:"companies_by_type"`
CompaniesByIndustry map[string]int64 `json:"companies_by_industry"`
CompaniesByStatus map[string]int64 `json:"companies_by_status"`
TopCategories []CategoryCount `json:"top_categories"`
TopCPVCodes []CPVCodeCount `json:"top_cpv_codes"`
TotalCompanies int64 `json:"total_companies"`
ActiveCompanies int64 `json:"active_companies"`
VerifiedCompanies int64 `json:"verified_companies"`
CompaniesByType map[string]int64 `json:"companies_by_type"`
CompaniesByIndustry map[string]int64 `json:"companies_by_industry"`
CompaniesByStatus map[string]int64 `json:"companies_by_status"`
TopCategories []CategoryCount `json:"top_categories"`
TopCPVCodes []CPVCodeCount `json:"top_cpv_codes"`
}
type CategoryCount struct {
-1
View File
@@ -183,7 +183,6 @@ func (h *Handler) DeleteCompany(c echo.Context) error {
// @Param industry query string false "Filter by industry"
// @Param is_verified query boolean false "Filter by verification 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 categories query array false "Filter by categories"
// @Param keywords query array false "Filter by keywords"
+10 -59
View File
@@ -17,17 +17,15 @@ 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)
GetByCustomerID(ctx context.Context, customerID 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)
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)
CountByType(ctx context.Context, companyType CompanyType) (int64, error)
CountByStatus(ctx context.Context, status CompanyStatus) (int64, error)
CountByIndustry(ctx context.Context, industry string) (int64, error)
CountVerified(ctx context.Context) (int64, error)
CountWithCustomer(ctx context.Context) (int64, error)
UpdateStatus(ctx context.Context, id string, status CompanyStatus) error
UpdateVerification(ctx context.Context, id string, isVerified, isCompliant bool, complianceNotes *string) 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("registration_number_idx", bson.D{{Key: "registration_number", 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("status_idx", bson.D{{Key: "status", 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
}
// 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
func (r *companyRepository) Update(ctx context.Context, company *Company) error {
// 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
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
filter := bson.M{}
@@ -326,14 +305,6 @@ func (r *companyRepository) Search(ctx context.Context, search string, companyTy
filter["currency"] = *currency
}
if hasCustomer != nil {
if *hasCustomer {
filter["customer_id"] = bson.M{"$ne": nil}
} else {
filter["customer_id"] = nil
}
}
// Tag filters
if len(cpvCodes) > 0 {
filter["tags.cpv_codes"] = bson.M{"$in": cpvCodes}
@@ -507,24 +478,6 @@ func (r *companyRepository) CountVerified(ctx context.Context) (int64, error) {
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
func (r *companyRepository) UpdateStatus(ctx context.Context, id string, status CompanyStatus) error {
// Get company first
@@ -704,20 +657,18 @@ func (r *companyRepository) GetCompanyStats(ctx context.Context) (*CompanyStatsR
totalCompanies, _ := r.Count(ctx)
activeCompanies, _ := r.CountByStatus(ctx, CompanyStatusActive)
verifiedCompanies, _ := r.CountVerified(ctx)
companiesWithCustomer, _ := r.CountWithCustomer(ctx)
// For this implementation, we'll return basic stats
// In a real implementation, you'd use MongoDB aggregation pipelines
stats := &CompanyStatsResponse{
TotalCompanies: totalCompanies,
ActiveCompanies: activeCompanies,
VerifiedCompanies: verifiedCompanies,
CompaniesWithCustomer: companiesWithCustomer,
CompaniesByType: make(map[string]int64),
CompaniesByIndustry: make(map[string]int64),
CompaniesByStatus: make(map[string]int64),
TopCategories: []CategoryCount{},
TopCPVCodes: []CPVCodeCount{},
TotalCompanies: totalCompanies,
ActiveCompanies: activeCompanies,
VerifiedCompanies: verifiedCompanies,
CompaniesByType: make(map[string]int64),
CompaniesByIndustry: make(map[string]int64),
CompaniesByStatus: make(map[string]int64),
TopCategories: []CategoryCount{},
TopCPVCodes: []CPVCodeCount{},
}
return stats, nil
+5 -24
View File
@@ -325,7 +325,7 @@ func (s *companyService) ListCompanies(ctx context.Context, form *ListCompaniesF
}
// 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 {
s.logger.Error("Failed to list companies", map[string]interface{}{
"error": err.Error(),
@@ -371,7 +371,7 @@ func (s *companyService) SearchCompanies(ctx context.Context, form *CompanySearc
}
// 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 {
s.logger.Error("Failed to search companies", map[string]interface{}{
"error": err.Error(),
@@ -469,25 +469,6 @@ func (s *companyService) UpdateCompanyVerification(ctx context.Context, id strin
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
@@ -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) {
// 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")
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 {
s.logger.Error("Failed to get companies by type", map[string]interface{}{
"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) {
// 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")
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 {
s.logger.Error("Failed to get companies by status", map[string]interface{}{
"error": err.Error(),
@@ -714,7 +695,7 @@ func (s *companyService) GetCompaniesByStatus(ctx context.Context, status Compan
// 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")
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 {
s.logger.Error("Failed to get companies by industry", map[string]interface{}{
"error": err.Error(),