281 lines
7.8 KiB
Go
281 lines
7.8 KiB
Go
package inquiry
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
"tm/pkg/logger"
|
|
orm "tm/pkg/mongo"
|
|
"tm/pkg/response"
|
|
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
)
|
|
|
|
// Repository defines methods for inquiry data access
|
|
type Repository interface {
|
|
Create(ctx context.Context, inquiry *Inquiry) error
|
|
GetByID(ctx context.Context, id string) (*Inquiry, error)
|
|
UpdateStatus(ctx context.Context, id string, status, reason, changedBy, description string) error
|
|
Search(ctx context.Context, form *SearchInquiriesForm, pagination *response.Pagination) (*orm.PaginatedResult[Inquiry], error)
|
|
Delete(ctx context.Context, id string) error
|
|
CheckPendingInquiry(ctx context.Context, email string) (*Inquiry, error)
|
|
CheckPendingInquiryByPhone(ctx context.Context, phone string) (*Inquiry, error)
|
|
}
|
|
|
|
// inquiryRepository implements the Repository interface using the MongoDB ORM
|
|
type inquiryRepository struct {
|
|
ormRepo orm.Repository[Inquiry]
|
|
logger logger.Logger
|
|
}
|
|
|
|
// NewInquiryRepository creates a new inquiry repository
|
|
func NewRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Repository {
|
|
// Create indexes using the ORM's index management
|
|
indexes := []orm.Index{
|
|
*orm.CreateTextIndex("search_idx", "full_name", "company_name", "work_email"),
|
|
*orm.NewIndex("company_name_idx", bson.D{bson.E{Key: "company_name", Value: 1}}),
|
|
*orm.NewIndex("work_email_idx", bson.D{bson.E{Key: "work_email", Value: 1}}),
|
|
*orm.NewIndex("phone_number_idx", bson.D{bson.E{Key: "phone_number", Value: 1}}),
|
|
*orm.NewIndex("status_idx", bson.D{bson.E{Key: "status", Value: 1}}),
|
|
*orm.NewIndex("created_at_idx", bson.D{bson.E{Key: "created_at", Value: -1}}),
|
|
// Compound index for duplicate prevention
|
|
*orm.NewIndex("email_status_idx", bson.D{
|
|
bson.E{Key: "work_email", Value: 1},
|
|
bson.E{Key: "status", Value: 1},
|
|
}),
|
|
*orm.NewIndex("phone_status_idx", bson.D{
|
|
bson.E{Key: "phone_number", Value: 1},
|
|
bson.E{Key: "status", Value: 1},
|
|
}),
|
|
}
|
|
|
|
// Create indexes
|
|
err := mongoManager.CreateIndexes("inquiries", indexes)
|
|
if err != nil {
|
|
logger.Warn("Failed to create inquiry indexes", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
// Create ORM repository
|
|
ormRepo := orm.NewRepository[Inquiry](mongoManager.GetCollection("inquiries"), logger)
|
|
|
|
return &inquiryRepository{
|
|
ormRepo: ormRepo,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Create creates a new inquiry
|
|
func (r *inquiryRepository) Create(ctx context.Context, inquiry *Inquiry) error {
|
|
// Set created timestamp using Unix timestamp
|
|
now := time.Now().Unix()
|
|
inquiry.SetCreatedAt(now)
|
|
inquiry.SetUpdatedAt(now)
|
|
|
|
// Set initial status to pending
|
|
inquiry.Status = StatusPending
|
|
|
|
// Add initial status change to history
|
|
inquiry.AddStatusChange(StatusPending, "Inquiry submitted", "system", "Initial inquiry submission")
|
|
|
|
// Use ORM to create inquiry
|
|
err := r.ormRepo.Create(ctx, inquiry)
|
|
if err != nil {
|
|
r.logger.Error("Failed to create inquiry", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"work_email": inquiry.WorkEmail,
|
|
"company_name": inquiry.CompanyName,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("Inquiry created successfully", map[string]interface{}{
|
|
"inquiry_id": inquiry.ID,
|
|
"work_email": inquiry.WorkEmail,
|
|
"company_name": inquiry.CompanyName,
|
|
"status": inquiry.Status,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetByID retrieves an inquiry by ID
|
|
func (r *inquiryRepository) GetByID(ctx context.Context, id string) (*Inquiry, error) {
|
|
inquiry, err := r.ormRepo.FindByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
|
return nil, errors.New("inquiry not found")
|
|
}
|
|
r.logger.Error("Failed to get inquiry by ID", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"inquiry_id": id,
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
return inquiry, nil
|
|
}
|
|
|
|
// UpdateStatus updates the status of an inquiry
|
|
func (r *inquiryRepository) UpdateStatus(ctx context.Context, id string, status, reason, changedBy, description string) error {
|
|
// Get inquiry first
|
|
inquiry, err := r.GetByID(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Add status change to history
|
|
inquiry.AddStatusChange(status, reason, changedBy, description)
|
|
|
|
// Update in database - use the correct Update method signature
|
|
err = r.ormRepo.Update(ctx, inquiry)
|
|
if err != nil {
|
|
r.logger.Error("Failed to update inquiry status", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"inquiry_id": id,
|
|
"new_status": status,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("Inquiry status updated successfully", map[string]interface{}{
|
|
"inquiry_id": id,
|
|
"old_status": inquiry.StatusHistory[len(inquiry.StatusHistory)-2].Status, // Previous status
|
|
"new_status": status,
|
|
"changed_by": changedBy,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// CheckPendingInquiry checks if there's a pending inquiry for the given email
|
|
func (r *inquiryRepository) CheckPendingInquiry(ctx context.Context, email string) (*Inquiry, error) {
|
|
filter := bson.M{
|
|
"work_email": email,
|
|
"status": bson.M{"$in": []string{StatusPending, StatusReviewed}},
|
|
}
|
|
|
|
pagination := orm.NewPaginationBuilder().
|
|
Limit(1).
|
|
SortBy("created_at", "desc").
|
|
Build()
|
|
|
|
result, err := r.ormRepo.FindAll(ctx, filter, pagination)
|
|
if err != nil {
|
|
r.logger.Error("Failed to check pending inquiry by email", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"work_email": email,
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
if len(result.Items) > 0 {
|
|
return &result.Items[0], nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// CheckPendingInquiryByPhone checks if there's a pending inquiry for the given phone number
|
|
func (r *inquiryRepository) CheckPendingInquiryByPhone(ctx context.Context, phone string) (*Inquiry, error) {
|
|
filter := bson.M{
|
|
"phone_number": phone,
|
|
"status": bson.M{"$in": []string{StatusPending, StatusReviewed}},
|
|
}
|
|
|
|
pagination := orm.NewPaginationBuilder().
|
|
Limit(1).
|
|
SortBy("created_at", "desc").
|
|
Build()
|
|
|
|
result, err := r.ormRepo.FindAll(ctx, filter, pagination)
|
|
if err != nil {
|
|
r.logger.Error("Failed to check pending inquiry by phone", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"phone_number": phone,
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
if len(result.Items) > 0 {
|
|
return &result.Items[0], nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// Search retrieves inquiries with pagination and filters
|
|
func (r *inquiryRepository) Search(ctx context.Context, form *SearchInquiriesForm, pagination *response.Pagination) (*orm.PaginatedResult[Inquiry], error) {
|
|
filter := bson.M{}
|
|
|
|
// Add search filter
|
|
if form.Search != nil {
|
|
filter["$or"] = bson.A{
|
|
bson.M{"full_name": bson.M{"$regex": form.Search, "$options": "i"}},
|
|
bson.M{"company_name": bson.M{"$regex": form.Search, "$options": "i"}},
|
|
bson.M{"work_email": bson.M{"$regex": form.Search, "$options": "i"}},
|
|
}
|
|
}
|
|
|
|
// Add status filter
|
|
if form.Status != nil {
|
|
filter["status"] = *form.Status
|
|
}
|
|
|
|
mongoPagination, err := orm.BuildListPagination(
|
|
pagination.Limit,
|
|
pagination.Offset,
|
|
pagination.Cursor,
|
|
pagination.SortBy,
|
|
pagination.SortOrder,
|
|
filter,
|
|
orm.ListPaginationOptions{},
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result, err := r.ormRepo.FindAll(ctx, filter, mongoPagination)
|
|
if err != nil {
|
|
r.logger.Error("Failed to search inquiries", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Delete deletes an inquiry
|
|
func (r *inquiryRepository) Delete(ctx context.Context, id string) error {
|
|
// Get inquiry first to ensure it exists
|
|
_, err := r.GetByID(ctx, id)
|
|
if err != nil {
|
|
r.logger.Error("Failed to delete inquiry", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"inquiry_id": id,
|
|
})
|
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
|
return errors.New("inquiry not found")
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Delete in database
|
|
err = r.ormRepo.Delete(ctx, id)
|
|
if err != nil {
|
|
r.logger.Error("Failed to delete inquiry", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"inquiry_id": id,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("Inquiry deleted successfully", map[string]interface{}{
|
|
"inquiry_id": id,
|
|
})
|
|
|
|
return nil
|
|
}
|