Enhance Customer Service with Notification Response Structures
- Introduced CustomerNotificationResponse struct to provide a detailed response format for customer notifications, improving the clarity of notification data. - Updated the Customer service interface to include methods for searching and retrieving customers with notification-specific responses, enhancing the flexibility of customer data retrieval. - Modified the Login method to accept a device token, allowing for better tracking of customer devices during login. - Refactored existing methods to utilize the new notification response structure, ensuring consistency across customer-related API responses. - Enhanced error handling and logging in the service layer for improved traceability during customer searches and logins.
This commit is contained in:
@@ -80,6 +80,30 @@ func (c *Customer) ToResponse(companies []*CompanySummary) *CustomerResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CustomerNotificationResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
FullName *string `json:"full_name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
Phone *string `json:"phone"`
|
||||||
|
DeviceToken []string `json:"device_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Customer) ToNotificationResponse() *CustomerNotificationResponse {
|
||||||
|
return &CustomerNotificationResponse{
|
||||||
|
ID: c.ID.Hex(),
|
||||||
|
FullName: c.FullName,
|
||||||
|
Username: c.Username,
|
||||||
|
Email: c.Email,
|
||||||
|
Type: string(c.Type),
|
||||||
|
Role: string(c.Role),
|
||||||
|
Phone: c.Phone,
|
||||||
|
DeviceToken: c.DeviceToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CustomerListResponse represents the response for listing customers
|
// CustomerListResponse represents the response for listing customers
|
||||||
type CustomerListResponse struct {
|
type CustomerListResponse struct {
|
||||||
Customers []*CustomerResponse `json:"customers"`
|
Customers []*CustomerResponse `json:"customers"`
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package customer
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
"tm/pkg/logger"
|
"tm/pkg/logger"
|
||||||
orm "tm/pkg/mongo"
|
orm "tm/pkg/mongo"
|
||||||
@@ -13,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// Repository defines the interface for customer data operations
|
// Repository defines the interface for customer data operations
|
||||||
type Repository interface {
|
type Repository interface {
|
||||||
Login(ctx context.Context, id string) error
|
Login(ctx context.Context, id, deviceToken string) error
|
||||||
Register(ctx context.Context, customer *Customer) error
|
Register(ctx context.Context, customer *Customer) error
|
||||||
Update(ctx context.Context, customer *Customer) error
|
Update(ctx context.Context, customer *Customer) error
|
||||||
UpdateStatus(ctx context.Context, id string, status CustomerStatus) error
|
UpdateStatus(ctx context.Context, id string, status CustomerStatus) error
|
||||||
@@ -90,13 +91,18 @@ func (r *customerRepository) Register(ctx context.Context, customer *Customer) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login updates the last login timestamp
|
// Login updates the last login timestamp
|
||||||
func (r *customerRepository) Login(ctx context.Context, id string) error {
|
func (r *customerRepository) Login(ctx context.Context, id, deviceToken string) error {
|
||||||
// Get customer first
|
// Get customer first
|
||||||
customer, err := r.GetByID(ctx, id)
|
customer, err := r.GetByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// append device token to customer if not exists
|
||||||
|
if !slices.Contains(customer.DeviceToken, deviceToken) {
|
||||||
|
customer.DeviceToken = append(customer.DeviceToken, deviceToken)
|
||||||
|
}
|
||||||
|
|
||||||
// Update last login timestamp
|
// Update last login timestamp
|
||||||
customer.LastLoginAt = &[]int64{time.Now().Unix()}[0]
|
customer.LastLoginAt = &[]int64{time.Now().Unix()}[0]
|
||||||
customer.SetUpdatedAt(time.Now().Unix())
|
customer.SetUpdatedAt(time.Now().Unix())
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"slices"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -29,9 +28,10 @@ type Service interface {
|
|||||||
Register(ctx context.Context, form *CreateCustomerForm) (*CustomerResponse, error)
|
Register(ctx context.Context, form *CreateCustomerForm) (*CustomerResponse, error)
|
||||||
GetByID(ctx context.Context, id string) (*CustomerResponse, error)
|
GetByID(ctx context.Context, id string) (*CustomerResponse, error)
|
||||||
Search(ctx context.Context, form *SearchCustomersForm, pagination *response.Pagination) (*CustomerListResponse, error)
|
Search(ctx context.Context, form *SearchCustomersForm, pagination *response.Pagination) (*CustomerListResponse, error)
|
||||||
GetCustomersByIDs(ctx context.Context, ids []string) (*CustomerListResponse, error)
|
SearchNotification(ctx context.Context, form *SearchCustomersForm, pagination *response.Pagination) ([]*CustomerNotificationResponse, error)
|
||||||
GetCustomersByRole(ctx context.Context, role string) (*CustomerListResponse, error)
|
GetCustomersByIDs(ctx context.Context, ids []string) ([]*CustomerNotificationResponse, error)
|
||||||
GetCustomersByCompanies(ctx context.Context, companies []string) (*CustomerListResponse, error)
|
GetCustomersByRole(ctx context.Context, role string) ([]*CustomerNotificationResponse, error)
|
||||||
|
GetCustomersByCompanies(ctx context.Context, companies []string) ([]*CustomerNotificationResponse, error)
|
||||||
Update(ctx context.Context, id string, form *UpdateCustomerForm) (*CustomerResponse, error)
|
Update(ctx context.Context, id string, form *UpdateCustomerForm) (*CustomerResponse, error)
|
||||||
Delete(ctx context.Context, id string) error
|
Delete(ctx context.Context, id string) error
|
||||||
UpdateStatus(ctx context.Context, id string, form *UpdateStatusForm) error
|
UpdateStatus(ctx context.Context, id string, form *UpdateStatusForm) error
|
||||||
@@ -216,25 +216,40 @@ func (s *customerService) Search(ctx context.Context, form *SearchCustomersForm,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *customerService) SearchNotification(ctx context.Context, form *SearchCustomersForm, pagination *response.Pagination) ([]*CustomerNotificationResponse, error) {
|
||||||
|
customers, _, err := s.repository.Search(ctx, form, pagination)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("Failed to search customers", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
})
|
||||||
|
return nil, errors.New("failed to search customers")
|
||||||
|
}
|
||||||
|
|
||||||
|
var customerResponses []*CustomerNotificationResponse
|
||||||
|
for _, customer := range customers {
|
||||||
|
customerResponses = append(customerResponses, customer.ToNotificationResponse())
|
||||||
|
}
|
||||||
|
|
||||||
|
return customerResponses, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetCustomersByIDs retrieves customers by IDs
|
// GetCustomersByIDs retrieves customers by IDs
|
||||||
func (s *customerService) GetCustomersByIDs(ctx context.Context, ids []string) (*CustomerListResponse, error) {
|
func (s *customerService) GetCustomersByIDs(ctx context.Context, ids []string) ([]*CustomerNotificationResponse, error) {
|
||||||
customers, err := s.repository.GetByIDs(ctx, ids)
|
customers, err := s.repository.GetByIDs(ctx, ids)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var customerResponses []*CustomerResponse
|
var customerResponses []*CustomerNotificationResponse
|
||||||
for _, customer := range customers {
|
for _, customer := range customers {
|
||||||
customerResponses = append(customerResponses, customer.ToResponse(nil))
|
customerResponses = append(customerResponses, customer.ToNotificationResponse())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CustomerListResponse{
|
return customerResponses, nil
|
||||||
Customers: customerResponses,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCustomersByRole retrieves customers by role
|
// GetCustomersByRole retrieves customers by role
|
||||||
func (s *customerService) GetCustomersByRole(ctx context.Context, role string) (*CustomerListResponse, error) {
|
func (s *customerService) GetCustomersByRole(ctx context.Context, role string) ([]*CustomerNotificationResponse, error) {
|
||||||
customers, err := s.repository.GetByRole(ctx, CustomerRole(role))
|
customers, err := s.repository.GetByRole(ctx, CustomerRole(role))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get customers by role", map[string]interface{}{
|
s.logger.Error("Failed to get customers by role", map[string]interface{}{
|
||||||
@@ -244,18 +259,16 @@ func (s *customerService) GetCustomersByRole(ctx context.Context, role string) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var customerResponses []*CustomerResponse
|
var customerResponses []*CustomerNotificationResponse
|
||||||
for _, customer := range customers {
|
for _, customer := range customers {
|
||||||
customerResponses = append(customerResponses, customer.ToResponse(nil))
|
customerResponses = append(customerResponses, customer.ToNotificationResponse())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CustomerListResponse{
|
return customerResponses, nil
|
||||||
Customers: customerResponses,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCustomersByCompanies retrieves customers by companies
|
// GetCustomersByCompanies retrieves customers by companies
|
||||||
func (s *customerService) GetCustomersByCompanies(ctx context.Context, companies []string) (*CustomerListResponse, error) {
|
func (s *customerService) GetCustomersByCompanies(ctx context.Context, companies []string) ([]*CustomerNotificationResponse, error) {
|
||||||
customers, err := s.repository.GetByCompanies(ctx, companies)
|
customers, err := s.repository.GetByCompanies(ctx, companies)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get customers by companies", map[string]interface{}{
|
s.logger.Error("Failed to get customers by companies", map[string]interface{}{
|
||||||
@@ -265,24 +278,12 @@ func (s *customerService) GetCustomersByCompanies(ctx context.Context, companies
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var customerResponses []*CustomerResponse
|
var customerResponses []*CustomerNotificationResponse
|
||||||
for _, customer := range customers {
|
for _, customer := range customers {
|
||||||
companies := make([]*CompanySummary, 0)
|
customerResponses = append(customerResponses, customer.ToNotificationResponse())
|
||||||
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{}{
|
|
||||||
"error": err.Error(),
|
|
||||||
"customer_id": customer.ID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customerResponses = append(customerResponses, customer.ToResponse(companies))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CustomerListResponse{
|
return customerResponses, nil
|
||||||
Customers: customerResponses,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates a customer
|
// Update updates a customer
|
||||||
@@ -619,12 +620,7 @@ func (s *customerService) Login(ctx context.Context, form *LoginForm) (*AuthResp
|
|||||||
return nil, errors.New("failed to generate authentication tokens")
|
return nil, errors.New("failed to generate authentication tokens")
|
||||||
}
|
}
|
||||||
|
|
||||||
// append device token to customer if not exists
|
err = s.repository.Login(ctx, customer.ID.Hex(), form.DeviceToken)
|
||||||
if !slices.Contains(customer.DeviceToken, form.DeviceToken) {
|
|
||||||
customer.DeviceToken = append(customer.DeviceToken, form.DeviceToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.repository.Login(ctx, customer.ID.Hex())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to update customer last login", map[string]interface{}{
|
s.logger.Error("Failed to update customer last login", map[string]interface{}{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ func (s *notificationService) getCustomers(ctx context.Context, values []string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, customer := range customers.Customers {
|
for _, customer := range customers {
|
||||||
recipients = append(recipients, notificationRecipient{
|
recipients = append(recipients, notificationRecipient{
|
||||||
UserID: customer.ID,
|
UserID: customer.ID,
|
||||||
Email: customer.Email,
|
Email: customer.Email,
|
||||||
@@ -379,7 +379,7 @@ func (s *notificationService) getCustomers(ctx context.Context, values []string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, customer := range customers.Customers {
|
for _, customer := range customers {
|
||||||
recipients = append(recipients, notificationRecipient{
|
recipients = append(recipients, notificationRecipient{
|
||||||
UserID: customer.ID,
|
UserID: customer.ID,
|
||||||
Email: customer.Email,
|
Email: customer.Email,
|
||||||
@@ -391,7 +391,7 @@ func (s *notificationService) getCustomers(ctx context.Context, values []string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, customer := range customers.Customers {
|
for _, customer := range customers {
|
||||||
recipients = append(recipients, notificationRecipient{
|
recipients = append(recipients, notificationRecipient{
|
||||||
UserID: customer.ID,
|
UserID: customer.ID,
|
||||||
Email: customer.Email,
|
Email: customer.Email,
|
||||||
@@ -401,11 +401,11 @@ func (s *notificationService) getCustomers(ctx context.Context, values []string,
|
|||||||
} else {
|
} else {
|
||||||
offset := 0
|
offset := 0
|
||||||
for {
|
for {
|
||||||
customers, err := s.customerService.Search(ctx, &customer.SearchCustomersForm{}, &response.Pagination{Limit: 100, Offset: offset})
|
customers, err := s.customerService.SearchNotification(ctx, &customer.SearchCustomersForm{}, &response.Pagination{Limit: 100, Offset: offset})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, customer := range customers.Customers {
|
for _, customer := range customers {
|
||||||
recipients = append(recipients, notificationRecipient{
|
recipients = append(recipients, notificationRecipient{
|
||||||
UserID: customer.ID,
|
UserID: customer.ID,
|
||||||
Email: customer.Email,
|
Email: customer.Email,
|
||||||
@@ -413,7 +413,7 @@ func (s *notificationService) getCustomers(ctx context.Context, values []string,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
offset += 100
|
offset += 100
|
||||||
if len(customers.Customers) == 0 {
|
if len(customers) == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user