Refactor Customer Entity and Forms to Use 'Companies' Field

- Updated the Customer entity to replace 'CompanyIDs' with 'Companies' for improved clarity and consistency.
- Modified CreateCustomerForm and UpdateCustomerForm to reflect the change from 'CompanyIDs' to 'Companies', ensuring proper validation and structured responses.
- Adjusted service methods to handle the new 'Companies' field, including registration and company assignment logic, enhancing the overall data model and API usability.
This commit is contained in:
n.nakhostin
2025-09-20 10:32:21 +03:30
parent dfcdef60d6
commit 6dcee0bc4b
3 changed files with 58 additions and 60 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ type Customer struct {
Type CustomerType `bson:"type"` Type CustomerType `bson:"type"`
Role CustomerRole `bson:"role"` Role CustomerRole `bson:"role"`
Phone *string `bson:"phone"` Phone *string `bson:"phone"`
CompanyIDs []string `bson:"company_ids"` Companies []string `bson:"companies"`
DeviceToken []string `bson:"device_token"` DeviceToken []string `bson:"device_token"`
LastLoginAt *int64 `bson:"last_login_at"` LastLoginAt *int64 `bson:"last_login_at"`
UpdatedAt int64 `bson:"updated_at"` UpdatedAt int64 `bson:"updated_at"`
+4 -6
View File
@@ -7,7 +7,7 @@ type CreateCustomerForm struct {
FullName *string `json:"full_name,omitempty" valid:"optional,length(2|100)" example:"User"` FullName *string `json:"full_name,omitempty" valid:"optional,length(2|100)" example:"User"`
Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"` Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"`
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"` Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
CompanyIDs []string `json:"company_ids,omitempty" valid:"optional"` Companies []string `json:"companies,omitempty" valid:"optional"`
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"` Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
Email string `json:"email" valid:"required,email" example:"user@opplens.com"` Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"` Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
@@ -19,7 +19,7 @@ type UpdateCustomerForm struct {
FullName *string `json:"full_name,omitempty" valid:"optional,length(2|100)" example:"User"` FullName *string `json:"full_name,omitempty" valid:"optional,length(2|100)" example:"User"`
Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"` Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"`
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"` Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
CompanyIDs []string `json:"company_ids,omitempty" valid:"optional"` Companies []string `json:"companies,omitempty" valid:"optional"`
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"` Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
Email string `json:"email" valid:"required,email" example:"user@opplens.com"` Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"` Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
@@ -56,7 +56,6 @@ type CustomerResponse struct {
Type string `json:"type"` Type string `json:"type"`
Role string `json:"role"` Role string `json:"role"`
Phone *string `json:"phone"` Phone *string `json:"phone"`
CompanyIDs []string `json:"company_ids"`
UpdatedAt int64 `json:"updated_at"` UpdatedAt int64 `json:"updated_at"`
CreatedAt int64 `json:"created_at"` CreatedAt int64 `json:"created_at"`
LastLoginAt *int64 `json:"last_login_at"` LastLoginAt *int64 `json:"last_login_at"`
@@ -74,7 +73,6 @@ func (c *Customer) ToResponse(companies []*CompanySummary) *CustomerResponse {
Status: string(c.Status), Status: string(c.Status),
Role: string(c.Role), Role: string(c.Role),
Phone: c.Phone, Phone: c.Phone,
CompanyIDs: c.CompanyIDs,
UpdatedAt: c.UpdatedAt, UpdatedAt: c.UpdatedAt,
CreatedAt: c.CreatedAt, CreatedAt: c.CreatedAt,
LastLoginAt: c.LastLoginAt, LastLoginAt: c.LastLoginAt,
@@ -117,11 +115,11 @@ type AuthResponse struct {
} }
type AssignCompaniesForm struct { type AssignCompaniesForm struct {
CompanyIDs []string `json:"company_ids" valid:"required"` Companies []string `json:"companies" valid:"required"`
} }
type RemoveCompaniesForm struct { type RemoveCompaniesForm struct {
CompanyIDs []string `json:"company_ids" valid:"required"` Companies []string `json:"companies" valid:"required"`
} }
// RequestResetPasswordForm represents the form for requesting password reset // RequestResetPasswordForm represents the form for requesting password reset
+31 -31
View File
@@ -79,9 +79,9 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
} }
// Verify that all company IDs exist // Verify that all company IDs exist
var companyIDs []string var Companies []string
if len(form.CompanyIDs) > 0 { if len(form.Companies) > 0 {
for _, companyID := range form.CompanyIDs { for _, companyID := range form.Companies {
_, err := s.companyService.GetByID(ctx, companyID) _, err := s.companyService.GetByID(ctx, companyID)
if err != nil { if err != nil {
s.logger.Error("Invalid company ID provided", map[string]interface{}{ s.logger.Error("Invalid company ID provided", map[string]interface{}{
@@ -91,7 +91,7 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
return nil, errors.New("invalid company ID: " + companyID) return nil, errors.New("invalid company ID: " + companyID)
} }
} }
companyIDs = form.CompanyIDs Companies = form.Companies
} }
// Hash password // Hash password
@@ -108,7 +108,7 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
Type: CustomerType(form.Type), Type: CustomerType(form.Type),
Role: CustomerRole(form.Role), Role: CustomerRole(form.Role),
Status: CustomerStatusActive, Status: CustomerStatusActive,
CompanyIDs: companyIDs, Companies: Companies,
FullName: form.FullName, FullName: form.FullName,
Username: form.Username, Username: form.Username,
Email: form.Email, Email: form.Email,
@@ -131,7 +131,7 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
"customer_id": customer.ID, "customer_id": customer.ID,
"email": customer.Email, "email": customer.Email,
"type": customer.Type, "type": customer.Type,
"company_ids": companyIDs, "company_ids": Companies,
}) })
go s.notification.SendEmail(ctx, customer.Email, fmt.Sprintf("Welcome to Tender Management\nUsername: %s\nPassword: %s", customer.Username, form.Password), customer.ID.Hex()) go s.notification.SendEmail(ctx, customer.Email, fmt.Sprintf("Welcome to Tender Management\nUsername: %s\nPassword: %s", customer.Username, form.Password), customer.ID.Hex())
@@ -151,7 +151,7 @@ func (s *customerService) GetByID(ctx context.Context, id string) (*CustomerResp
} }
var companies []*CompanySummary var companies []*CompanySummary
if len(customer.CompanyIDs) > 0 { if len(customer.Companies) > 0 {
companies, err = s.loadCompaniesForCustomer(ctx, customer) companies, err = s.loadCompaniesForCustomer(ctx, customer)
if err != nil { if err != nil {
s.logger.Error("Failed to load companies for customer", map[string]interface{}{ s.logger.Error("Failed to load companies for customer", map[string]interface{}{
@@ -229,10 +229,10 @@ func (s *customerService) Update(ctx context.Context, id string, form *UpdateCus
} }
// Handle company assignments // Handle company assignments
if len(form.CompanyIDs) > 0 { if len(form.Companies) > 0 {
// Verify that all company IDs exist // Verify that all company IDs exist
var validCompanyIDs []string var validCompanies []string
for _, companyID := range form.CompanyIDs { for _, companyID := range form.Companies {
_, err := s.companyService.GetByID(ctx, companyID) _, err := s.companyService.GetByID(ctx, companyID)
if err != nil { if err != nil {
s.logger.Error("Invalid company ID provided in update", map[string]interface{}{ s.logger.Error("Invalid company ID provided in update", map[string]interface{}{
@@ -241,9 +241,9 @@ func (s *customerService) Update(ctx context.Context, id string, form *UpdateCus
}) })
return nil, errors.New("invalid company ID: " + companyID) return nil, errors.New("invalid company ID: " + companyID)
} }
validCompanyIDs = append(validCompanyIDs, companyID) validCompanies = append(validCompanies, companyID)
} }
customer.CompanyIDs = validCompanyIDs customer.Companies = validCompanies
} }
if form.FullName != nil { if form.FullName != nil {
@@ -337,7 +337,7 @@ func (s *customerService) UpdateStatus(ctx context.Context, id string, form *Upd
} }
// AssignCompanies assigns companies to a customer // AssignCompanies assigns companies to a customer
func (s *customerService) AssignCompanies(ctx context.Context, customerID string, companyIDs []string) error { func (s *customerService) AssignCompanies(ctx context.Context, customerID string, Companies []string) error {
// Get customer to check if exists // Get customer to check if exists
customer, err := s.repository.GetByID(ctx, customerID) customer, err := s.repository.GetByID(ctx, customerID)
if err != nil { if err != nil {
@@ -345,8 +345,8 @@ func (s *customerService) AssignCompanies(ctx context.Context, customerID string
} }
// Verify companies exist and update customer's company IDs // Verify companies exist and update customer's company IDs
var validCompanyIDs []string var validCompanies []string
for _, companyID := range companyIDs { for _, companyID := range Companies {
_, err = s.companyService.GetByID(ctx, companyID) _, err = s.companyService.GetByID(ctx, companyID)
if err != nil { if err != nil {
s.logger.Error("Company not found during assignment", map[string]interface{}{ s.logger.Error("Company not found during assignment", map[string]interface{}{
@@ -356,11 +356,11 @@ func (s *customerService) AssignCompanies(ctx context.Context, customerID string
}) })
continue // Skip invalid company IDs continue // Skip invalid company IDs
} }
validCompanyIDs = append(validCompanyIDs, companyID) validCompanies = append(validCompanies, companyID)
} }
// Update customer's company IDs // Update customer's company IDs
customer.CompanyIDs = append(customer.CompanyIDs, validCompanyIDs...) customer.Companies = append(customer.Companies, validCompanies...)
customer.UpdatedAt = time.Now().Unix() customer.UpdatedAt = time.Now().Unix()
err = s.repository.Update(ctx, customer) err = s.repository.Update(ctx, customer)
@@ -374,14 +374,14 @@ func (s *customerService) AssignCompanies(ctx context.Context, customerID string
s.logger.Info("Companies assigned to customer successfully", map[string]interface{}{ s.logger.Info("Companies assigned to customer successfully", map[string]interface{}{
"customer_id": customerID, "customer_id": customerID,
"company_ids": validCompanyIDs, "company_ids": validCompanies,
}) })
return nil return nil
} }
// RemoveCompaniesFromCustomer removes companies from a customer // RemoveCompaniesFromCustomer removes companies from a customer
func (s *customerService) RemoveCompanies(ctx context.Context, customerID string, companyIDs []string) error { func (s *customerService) RemoveCompanies(ctx context.Context, customerID string, Companies []string) error {
// Get customer to check if exists // Get customer to check if exists
customer, err := s.repository.GetByID(ctx, customerID) customer, err := s.repository.GetByID(ctx, customerID)
if err != nil { if err != nil {
@@ -389,22 +389,22 @@ func (s *customerService) RemoveCompanies(ctx context.Context, customerID string
} }
// Remove company IDs from customer's list // Remove company IDs from customer's list
var updatedCompanyIDs []string var updatedCompanies []string
for _, existingID := range customer.CompanyIDs { for _, existingID := range customer.Companies {
shouldRemove := false shouldRemove := false
for _, removeID := range companyIDs { for _, removeID := range Companies {
if existingID == removeID { if existingID == removeID {
shouldRemove = true shouldRemove = true
break break
} }
} }
if !shouldRemove { if !shouldRemove {
updatedCompanyIDs = append(updatedCompanyIDs, existingID) updatedCompanies = append(updatedCompanies, existingID)
} }
} }
// Update customer's company IDs // Update customer's company IDs
customer.CompanyIDs = updatedCompanyIDs customer.Companies = updatedCompanies
customer.UpdatedAt = time.Now().Unix() customer.UpdatedAt = time.Now().Unix()
err = s.repository.Update(ctx, customer) err = s.repository.Update(ctx, customer)
@@ -418,7 +418,7 @@ func (s *customerService) RemoveCompanies(ctx context.Context, customerID string
s.logger.Info("Companies removed from customer successfully", map[string]interface{}{ s.logger.Info("Companies removed from customer successfully", map[string]interface{}{
"customer_id": customerID, "customer_id": customerID,
"company_ids": companyIDs, "company_ids": Companies,
}) })
return nil return nil
@@ -512,8 +512,8 @@ func (s *customerService) Login(ctx context.Context, form *LoginForm) (*AuthResp
// Generate JWT tokens using authorization service // Generate JWT tokens using authorization service
companyID := "" companyID := ""
if len(customer.CompanyIDs) > 0 { if len(customer.Companies) > 0 {
companyID = customer.CompanyIDs[0] // Use first company ID for JWT token companyID = customer.Companies[0] // Use first company ID for JWT token
} }
tokenPair, err := s.authService.GenerateTokenPair( tokenPair, err := s.authService.GenerateTokenPair(
@@ -1038,17 +1038,17 @@ func (s *customerService) isValidPassword(password string) bool {
// loadCompaniesForCustomer loads company summaries for a customer // loadCompaniesForCustomer loads company summaries for a customer
func (s *customerService) loadCompaniesForCustomer(ctx context.Context, customer *Customer) ([]*CompanySummary, error) { func (s *customerService) loadCompaniesForCustomer(ctx context.Context, customer *Customer) ([]*CompanySummary, error) {
if len(customer.CompanyIDs) == 0 { if len(customer.Companies) == 0 {
return []*CompanySummary{}, nil return []*CompanySummary{}, nil
} }
// Load companies in batch using the new GetCompaniesByIDs method // Load companies in batch using the new GetCompaniesByIDs method
companies, err := s.companyService.GetByIDs(ctx, customer.CompanyIDs) companies, err := s.companyService.GetByIDs(ctx, customer.Companies)
if err != nil { if err != nil {
s.logger.Error("Failed to load companies for customer", map[string]interface{}{ s.logger.Error("Failed to load companies for customer", map[string]interface{}{
"error": err.Error(), "error": err.Error(),
"customer_id": customer.ID, "customer_id": customer.ID,
"company_ids": customer.CompanyIDs, "company_ids": customer.Companies,
}) })
return []*CompanySummary{}, err return []*CompanySummary{}, err
} }
@@ -1064,7 +1064,7 @@ func (s *customerService) loadCompaniesForCustomer(ctx context.Context, customer
s.logger.Info("Companies loaded for customer", map[string]interface{}{ s.logger.Info("Companies loaded for customer", map[string]interface{}{
"customer_id": customer.ID, "customer_id": customer.ID,
"requested_count": len(customer.CompanyIDs), "requested_count": len(customer.Companies),
"loaded_count": len(companySummaries), "loaded_count": len(companySummaries),
}) })