a342da193e
- Updated feedback repository and service methods to use a consistent naming convention, changing `NewTenderRepository` and similar methods to `NewRepository`. - Refactored feedback handler methods to improve clarity by renaming methods such as `ListFeedback` to `Search` and `GetFeedback` to `Get`. - Enhanced feedback response structures to include detailed company and tender information, improving the clarity of feedback data returned to API consumers. - Updated Swagger documentation to reflect changes in feedback response structures and endpoint paths, ensuring accurate representation of the API for consumers.
305 lines
9.2 KiB
Go
305 lines
9.2 KiB
Go
package feedback
|
|
|
|
import (
|
|
"context"
|
|
"tm/internal/company"
|
|
"tm/internal/tender"
|
|
"tm/pkg/logger"
|
|
"tm/pkg/response"
|
|
)
|
|
|
|
// FeedbackService interface defines feedback business logic methods
|
|
type Service interface {
|
|
Toggle(ctx context.Context, req ToggleFeedbackForm, customerID *string, companyID *string) (*FeedbackResponse, error)
|
|
Search(ctx context.Context, criteria SearchForm, pagination *response.Pagination) (*FeedbackListResponse, error)
|
|
Get(ctx context.Context, id string) (*FeedbackResponse, error)
|
|
GetByTenderID(ctx context.Context, tenderID, companyID string) (*FeedbackResponse, error)
|
|
Delete(ctx context.Context, id string) error
|
|
CompanyStats(ctx context.Context, companyID string) (*StatsResponse, error)
|
|
getDetails(ctx context.Context, tenderID, companyID string) (*tenderResponse, *companyResponse, error)
|
|
}
|
|
|
|
// feedbackService implements FeedbackService interface
|
|
type feedbackService struct {
|
|
feedbackRepo Repository
|
|
tenderService tender.Service
|
|
companyService company.Service
|
|
logger logger.Logger
|
|
}
|
|
|
|
// NewService creates a new feedback service
|
|
func NewService(feedbackRepo Repository, tenderService tender.Service, companyService company.Service, logger logger.Logger) Service {
|
|
return &feedbackService{
|
|
feedbackRepo: feedbackRepo,
|
|
tenderService: tenderService,
|
|
companyService: companyService,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (s *feedbackService) Toggle(ctx context.Context, req ToggleFeedbackForm, customerID *string, companyID *string) (*FeedbackResponse, error) {
|
|
existing, err := s.feedbackRepo.GetByCompanyID(ctx, *companyID, req.Tender)
|
|
|
|
if err != nil {
|
|
feedback := &Feedback{
|
|
TenderID: req.Tender,
|
|
FeedbackType: req.Type,
|
|
CompanyID: companyID,
|
|
CustomerID: customerID,
|
|
}
|
|
|
|
err = s.feedbackRepo.Create(ctx, feedback)
|
|
if err != nil {
|
|
s.logger.Error("Failed to create new feedback", map[string]interface{}{
|
|
"tender_id": req.Tender,
|
|
"company_id": *companyID,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
tender, company, err := s.getDetails(ctx, req.Tender, *companyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get details", map[string]interface{}{
|
|
"tender_id": req.Tender,
|
|
"company_id": *companyID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return feedback.ToResponse(tender, company), nil
|
|
}
|
|
|
|
if existing.FeedbackType == req.Type {
|
|
err = s.feedbackRepo.Delete(ctx, existing.GetID())
|
|
if err != nil {
|
|
s.logger.Error("Failed to update existing feedback", map[string]interface{}{
|
|
"feedback_id": existing.GetID(),
|
|
"tender_id": req.Tender,
|
|
"company_id": *companyID,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
if req.Type == FeedbackTypeLike {
|
|
existing.FeedbackType = "unlike"
|
|
} else {
|
|
existing.FeedbackType = "undislike"
|
|
}
|
|
|
|
tender, company, err := s.getDetails(ctx, req.Tender, *companyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get details", map[string]interface{}{
|
|
"tender_id": req.Tender,
|
|
"company_id": *companyID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return existing.ToResponse(tender, company), nil
|
|
}
|
|
|
|
if existing.FeedbackType == FeedbackTypeLike {
|
|
existing.FeedbackType = FeedbackTypeDislike
|
|
} else {
|
|
existing.FeedbackType = FeedbackTypeLike
|
|
}
|
|
|
|
err = s.feedbackRepo.Update(ctx, existing)
|
|
if err != nil {
|
|
s.logger.Error("Failed to update existing feedback", map[string]interface{}{
|
|
"feedback_id": existing.GetID(),
|
|
"tender_id": req.Tender,
|
|
"company_id": *companyID,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
tender, company, err := s.getDetails(ctx, req.Tender, *companyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get details", map[string]interface{}{
|
|
"tender_id": req.Tender,
|
|
"company_id": *companyID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return existing.ToResponse(tender, company), nil
|
|
}
|
|
|
|
func (s *feedbackService) Get(ctx context.Context, id string) (*FeedbackResponse, error) {
|
|
feedback, err := s.feedbackRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get feedback", map[string]interface{}{
|
|
"id": id,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
tender, company, err := s.getDetails(ctx, feedback.TenderID, *feedback.CompanyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get details", map[string]interface{}{
|
|
"tender_id": feedback.TenderID,
|
|
"company_id": *feedback.CompanyID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return feedback.ToResponse(tender, company), nil
|
|
}
|
|
|
|
func (s *feedbackService) Search(ctx context.Context, criteria SearchForm, pagination *response.Pagination) (*FeedbackListResponse, error) {
|
|
feedbacks, total, err := s.feedbackRepo.Search(ctx, criteria, pagination)
|
|
if err != nil {
|
|
s.logger.Error("Failed to list feedback", map[string]interface{}{
|
|
"criteria": criteria,
|
|
"limit": pagination.Limit,
|
|
"offset": pagination.Offset,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
meta := &response.Meta{
|
|
Total: int(total),
|
|
Limit: pagination.Limit,
|
|
Offset: pagination.Offset,
|
|
Page: (pagination.Offset / pagination.Limit) + 1,
|
|
Pages: int((total + int64(pagination.Limit) - 1) / int64(pagination.Limit)),
|
|
}
|
|
|
|
result := make([]*FeedbackResponse, len(feedbacks))
|
|
for i, feedback := range feedbacks {
|
|
tender, company, _ := s.getDetails(ctx, feedback.TenderID, *feedback.CompanyID)
|
|
result[i] = feedback.ToResponse(tender, company)
|
|
}
|
|
|
|
return &FeedbackListResponse{
|
|
Feedback: result,
|
|
Meta: meta,
|
|
}, nil
|
|
}
|
|
|
|
func (s *feedbackService) Delete(ctx context.Context, id string) error {
|
|
return s.feedbackRepo.Delete(ctx, id)
|
|
}
|
|
|
|
func (s *feedbackService) GetByTenderID(ctx context.Context, tenderID, companyID string) (*FeedbackResponse, error) {
|
|
feedback, err := s.feedbackRepo.GetByTenderID(ctx, tenderID, companyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get feedback by tender ID", map[string]interface{}{
|
|
"tender_id": tenderID,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
tender, err := s.tenderService.GetByID(ctx, feedback.TenderID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get tender", map[string]interface{}{
|
|
"tender_id": feedback.TenderID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
company, err := s.companyService.GetByID(ctx, *feedback.CompanyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get company", map[string]interface{}{
|
|
"company_id": feedback.CompanyID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return feedback.ToResponse(
|
|
&tenderResponse{
|
|
ID: tender.ID,
|
|
NoticePublicationID: tender.NoticePublicationID,
|
|
PublicationDate: tender.PublicationDate,
|
|
Title: tender.Title,
|
|
Description: tender.Description,
|
|
ProcurementTypeCode: tender.ProcurementTypeCode,
|
|
ProcedureCode: tender.ProcedureCode,
|
|
EstimatedValue: tender.EstimatedValue,
|
|
Currency: tender.Currency,
|
|
Duration: tender.Duration,
|
|
DurationUnit: tender.DurationUnit,
|
|
TenderDeadline: tender.TenderDeadline,
|
|
SubmissionDeadline: tender.SubmissionDeadline,
|
|
CountryCode: tender.CountryCode,
|
|
BuyerOrganization: &organizationResponse{Name: tender.BuyerOrganization.Name},
|
|
Status: string(tender.Status),
|
|
},
|
|
&companyResponse{
|
|
ID: company.ID,
|
|
Name: company.Name,
|
|
},
|
|
), nil
|
|
}
|
|
|
|
func (s *feedbackService) getDetails(ctx context.Context, tenderID, companyID string) (*tenderResponse, *companyResponse, error) {
|
|
tender, err := s.tenderService.GetByID(ctx, tenderID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get tender", map[string]interface{}{
|
|
"tender_id": tenderID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
company, err := s.companyService.GetByID(ctx, companyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get company", map[string]interface{}{
|
|
"company_id": companyID,
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
return &tenderResponse{
|
|
ID: tender.ID,
|
|
NoticePublicationID: tender.NoticePublicationID,
|
|
PublicationDate: tender.PublicationDate,
|
|
Title: tender.Title,
|
|
Description: tender.Description,
|
|
ProcurementTypeCode: tender.ProcurementTypeCode,
|
|
ProcedureCode: tender.ProcedureCode,
|
|
EstimatedValue: tender.EstimatedValue,
|
|
Currency: tender.Currency,
|
|
Duration: tender.Duration,
|
|
DurationUnit: tender.DurationUnit,
|
|
TenderDeadline: tender.TenderDeadline,
|
|
SubmissionDeadline: tender.SubmissionDeadline,
|
|
CountryCode: tender.CountryCode,
|
|
BuyerOrganization: &organizationResponse{Name: tender.BuyerOrganization.Name},
|
|
Status: string(tender.Status),
|
|
}, &companyResponse{
|
|
ID: company.ID,
|
|
Name: company.Name,
|
|
}, nil
|
|
}
|
|
|
|
func (s *feedbackService) CompanyStats(ctx context.Context, companyID string) (*StatsResponse, error) {
|
|
s.logger.Info("Getting company feedback statistics", map[string]interface{}{
|
|
"company_id": companyID,
|
|
})
|
|
|
|
stats, err := s.feedbackRepo.CompanyStats(ctx, companyID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get company stats", map[string]interface{}{
|
|
"company_id": companyID,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
s.logger.Info("Company stats retrieved successfully", map[string]interface{}{
|
|
"company_id": companyID,
|
|
"total_feedback": stats.TotalFeedback,
|
|
"total_likes": stats.TotalLikes,
|
|
"total_dislikes": stats.TotalDislikes,
|
|
})
|
|
|
|
return stats, nil
|
|
}
|