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"`
Role CustomerRole `bson:"role"`
Phone *string `bson:"phone"`
CompanyIDs []string `bson:"company_ids"`
Companies []string `bson:"companies"`
DeviceToken []string `bson:"device_token"`
LastLoginAt *int64 `bson:"last_login_at"`
UpdatedAt int64 `bson:"updated_at"`
+18 -20
View File
@@ -4,26 +4,26 @@ import "tm/pkg/response"
// CreateCustomerForm represents the form for creating a new customer
type CreateCustomerForm struct {
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"`
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
CompanyIDs []string `json:"company_ids,omitempty" valid:"optional"`
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
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"`
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
Companies []string `json:"companies,omitempty" valid:"optional"`
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
}
// UpdateCustomerForm represents the form for updating a customer
type UpdateCustomerForm struct {
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"`
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
CompanyIDs []string `json:"company_ids,omitempty" valid:"optional"`
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
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"`
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
Companies []string `json:"companies,omitempty" valid:"optional"`
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
}
// CustomerStatusForm represents the form for suspending a customer
@@ -56,7 +56,6 @@ type CustomerResponse struct {
Type string `json:"type"`
Role string `json:"role"`
Phone *string `json:"phone"`
CompanyIDs []string `json:"company_ids"`
UpdatedAt int64 `json:"updated_at"`
CreatedAt int64 `json:"created_at"`
LastLoginAt *int64 `json:"last_login_at"`
@@ -74,7 +73,6 @@ func (c *Customer) ToResponse(companies []*CompanySummary) *CustomerResponse {
Status: string(c.Status),
Role: string(c.Role),
Phone: c.Phone,
CompanyIDs: c.CompanyIDs,
UpdatedAt: c.UpdatedAt,
CreatedAt: c.CreatedAt,
LastLoginAt: c.LastLoginAt,
@@ -117,11 +115,11 @@ type AuthResponse struct {
}
type AssignCompaniesForm struct {
CompanyIDs []string `json:"company_ids" valid:"required"`
Companies []string `json:"companies" valid:"required"`
}
type RemoveCompaniesForm struct {
CompanyIDs []string `json:"company_ids" valid:"required"`
Companies []string `json:"companies" valid:"required"`
}
// RequestResetPasswordForm represents the form for requesting password reset
+39 -39
View File
@@ -79,9 +79,9 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
}
// Verify that all company IDs exist
var companyIDs []string
if len(form.CompanyIDs) > 0 {
for _, companyID := range form.CompanyIDs {
var Companies []string
if len(form.Companies) > 0 {
for _, companyID := range form.Companies {
_, err := s.companyService.GetByID(ctx, companyID)
if err != nil {
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)
}
}
companyIDs = form.CompanyIDs
Companies = form.Companies
}
// Hash password
@@ -105,15 +105,15 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
// Create customer
customer := &Customer{
Type: CustomerType(form.Type),
Role: CustomerRole(form.Role),
Status: CustomerStatusActive,
CompanyIDs: companyIDs,
FullName: form.FullName,
Username: form.Username,
Email: form.Email,
Password: string(hashedPassword),
Phone: form.Phone,
Type: CustomerType(form.Type),
Role: CustomerRole(form.Role),
Status: CustomerStatusActive,
Companies: Companies,
FullName: form.FullName,
Username: form.Username,
Email: form.Email,
Password: string(hashedPassword),
Phone: form.Phone,
}
// Save to database
@@ -131,7 +131,7 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
"customer_id": customer.ID,
"email": customer.Email,
"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())
@@ -151,7 +151,7 @@ func (s *customerService) GetByID(ctx context.Context, id string) (*CustomerResp
}
var companies []*CompanySummary
if len(customer.CompanyIDs) > 0 {
if len(customer.Companies) > 0 {
companies, err = s.loadCompaniesForCustomer(ctx, customer)
if err != nil {
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
if len(form.CompanyIDs) > 0 {
if len(form.Companies) > 0 {
// Verify that all company IDs exist
var validCompanyIDs []string
for _, companyID := range form.CompanyIDs {
var validCompanies []string
for _, companyID := range form.Companies {
_, err := s.companyService.GetByID(ctx, companyID)
if err != nil {
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)
}
validCompanyIDs = append(validCompanyIDs, companyID)
validCompanies = append(validCompanies, companyID)
}
customer.CompanyIDs = validCompanyIDs
customer.Companies = validCompanies
}
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
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
customer, err := s.repository.GetByID(ctx, customerID)
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
var validCompanyIDs []string
for _, companyID := range companyIDs {
var validCompanies []string
for _, companyID := range Companies {
_, err = s.companyService.GetByID(ctx, companyID)
if err != nil {
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
}
validCompanyIDs = append(validCompanyIDs, companyID)
validCompanies = append(validCompanies, companyID)
}
// Update customer's company IDs
customer.CompanyIDs = append(customer.CompanyIDs, validCompanyIDs...)
customer.Companies = append(customer.Companies, validCompanies...)
customer.UpdatedAt = time.Now().Unix()
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{}{
"customer_id": customerID,
"company_ids": validCompanyIDs,
"company_ids": validCompanies,
})
return nil
}
// 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
customer, err := s.repository.GetByID(ctx, customerID)
if err != nil {
@@ -389,22 +389,22 @@ func (s *customerService) RemoveCompanies(ctx context.Context, customerID string
}
// Remove company IDs from customer's list
var updatedCompanyIDs []string
for _, existingID := range customer.CompanyIDs {
var updatedCompanies []string
for _, existingID := range customer.Companies {
shouldRemove := false
for _, removeID := range companyIDs {
for _, removeID := range Companies {
if existingID == removeID {
shouldRemove = true
break
}
}
if !shouldRemove {
updatedCompanyIDs = append(updatedCompanyIDs, existingID)
updatedCompanies = append(updatedCompanies, existingID)
}
}
// Update customer's company IDs
customer.CompanyIDs = updatedCompanyIDs
customer.Companies = updatedCompanies
customer.UpdatedAt = time.Now().Unix()
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{}{
"customer_id": customerID,
"company_ids": companyIDs,
"company_ids": Companies,
})
return nil
@@ -512,8 +512,8 @@ func (s *customerService) Login(ctx context.Context, form *LoginForm) (*AuthResp
// Generate JWT tokens using authorization service
companyID := ""
if len(customer.CompanyIDs) > 0 {
companyID = customer.CompanyIDs[0] // Use first company ID for JWT token
if len(customer.Companies) > 0 {
companyID = customer.Companies[0] // Use first company ID for JWT token
}
tokenPair, err := s.authService.GenerateTokenPair(
@@ -1038,17 +1038,17 @@ func (s *customerService) isValidPassword(password string) bool {
// loadCompaniesForCustomer loads company summaries for a customer
func (s *customerService) loadCompaniesForCustomer(ctx context.Context, customer *Customer) ([]*CompanySummary, error) {
if len(customer.CompanyIDs) == 0 {
if len(customer.Companies) == 0 {
return []*CompanySummary{}, nil
}
// 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 {
s.logger.Error("Failed to load companies for customer", map[string]interface{}{
"error": err.Error(),
"customer_id": customer.ID,
"company_ids": customer.CompanyIDs,
"company_ids": customer.Companies,
})
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{}{
"customer_id": customer.ID,
"requested_count": len(customer.CompanyIDs),
"requested_count": len(customer.Companies),
"loaded_count": len(companySummaries),
})