diff --git a/internal/tender_approval/service.go b/internal/tender_approval/service.go index 3f196da..f0e89cf 100644 --- a/internal/tender_approval/service.go +++ b/internal/tender_approval/service.go @@ -292,40 +292,12 @@ func (s *tenderApprovalService) GetTenderApprovalsByCompanyIDWithTender(ctx cont return nil, err } - // Convert to response with tender details + tenders := s.loadTendersByIDs(ctx, uniqueTenderIDs(tenderApprovals)) + responses := &TenderApprovalWithTenderListResponse{ - Approvals: []*TenderApprovalWithTenderResponse{}, + Approvals: mapApprovalsWithTender(tenderApprovals, tenders, listTenderDetailsFromResponse), Metadata: &response.Meta{}, } - for _, approval := range tenderApprovals { - // Get tender details - tenderResponse, err := s.tenderService.GetByID(ctx, approval.TenderID, "") - if err != nil { - s.logger.Warn("Failed to get tender details", map[string]interface{}{ - "tender_id": approval.TenderID, - "error": err.Error(), - }) - // Continue without tender details rather than failing completely - responses.Approvals = append(responses.Approvals, approval.ToResponseWithTender(nil)) - continue - } - - // Convert tender response to tender details - tenderDetails := &TenderDetails{ - ID: tenderResponse.ID, - Title: tenderResponse.Title, - Description: tenderResponse.Description, - EstimatedValue: tenderResponse.EstimatedValue, - Currency: tenderResponse.Currency, - TenderDeadline: tenderResponse.TenderDeadline, - SubmissionDeadline: tenderResponse.SubmissionDeadline, - CountryCode: tenderResponse.CountryCode, - BuyerOrganization: &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name}, - Status: string(tenderResponse.Status), - } - - responses.Approvals = append(responses.Approvals, approval.ToResponseWithTender(tenderDetails)) - } responses.Metadata = &response.Meta{ Total: int(total), @@ -780,43 +752,8 @@ func (s *tenderApprovalService) GetTenderApprovalsByStatusWithTender(ctx context return nil, 0, err } - // Convert to response with tender details - var responses []*TenderApprovalWithTenderResponse - for _, approval := range tenderApprovals { - // Get tender details - tenderResponse, err := s.tenderService.GetByID(ctx, approval.TenderID, "") - if err != nil { - s.logger.Warn("Failed to get tender details", map[string]interface{}{ - "tender_id": approval.TenderID, - "error": err.Error(), - }) - // Continue without tender details rather than failing completely - responses = append(responses, approval.ToResponseWithTender(nil)) - continue - } - - // Convert tender response to tender details - tenderDetails := &TenderDetails{ - ID: tenderResponse.ID, - NoticePublicationID: tenderResponse.NoticePublicationID, - PublicationDate: tenderResponse.PublicationDate, - Title: tenderResponse.Title, - Description: tenderResponse.Description, - ProcurementTypeCode: tenderResponse.ProcurementTypeCode, - ProcedureCode: tenderResponse.ProcurementTypeCode, - EstimatedValue: tenderResponse.EstimatedValue, - Currency: tenderResponse.Currency, - Duration: tenderResponse.Duration, - DurationUnit: tenderResponse.DurationUnit, - TenderDeadline: tenderResponse.TenderDeadline, - SubmissionDeadline: tenderResponse.SubmissionDeadline, - CountryCode: tenderResponse.CountryCode, - BuyerOrganization: &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name}, - Status: string(tenderResponse.Status), - } - - responses = append(responses, approval.ToResponseWithTender(tenderDetails)) - } + tenders := s.loadTendersByIDs(ctx, uniqueTenderIDs(tenderApprovals)) + responses := mapApprovalsWithTender(tenderApprovals, tenders, fullTenderDetailsFromResponse) return responses, total, nil } @@ -828,43 +765,8 @@ func (s *tenderApprovalService) GetTenderApprovalsBySubmissionModeWithTender(ctx return nil, 0, err } - // Convert to response with tender details - var responses []*TenderApprovalWithTenderResponse - for _, approval := range tenderApprovals { - // Get tender details - tenderResponse, err := s.tenderService.GetByID(ctx, approval.TenderID, "") - if err != nil { - s.logger.Warn("Failed to get tender details", map[string]interface{}{ - "tender_id": approval.TenderID, - "error": err.Error(), - }) - // Continue without tender details rather than failing completely - responses = append(responses, approval.ToResponseWithTender(nil)) - continue - } - - // Convert tender response to tender details - tenderDetails := &TenderDetails{ - ID: tenderResponse.ID, - NoticePublicationID: tenderResponse.NoticePublicationID, - PublicationDate: tenderResponse.PublicationDate, - Title: tenderResponse.Title, - Description: tenderResponse.Description, - ProcurementTypeCode: tenderResponse.ProcurementTypeCode, - ProcedureCode: tenderResponse.ProcedureCode, - EstimatedValue: tenderResponse.EstimatedValue, - Currency: tenderResponse.Currency, - Duration: tenderResponse.Duration, - DurationUnit: tenderResponse.DurationUnit, - TenderDeadline: tenderResponse.TenderDeadline, - SubmissionDeadline: tenderResponse.SubmissionDeadline, - CountryCode: tenderResponse.CountryCode, - BuyerOrganization: &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name}, - Status: string(tenderResponse.Status), - } - - responses = append(responses, approval.ToResponseWithTender(tenderDetails)) - } + tenders := s.loadTendersByIDs(ctx, uniqueTenderIDs(tenderApprovals)) + responses := mapApprovalsWithTender(tenderApprovals, tenders, fullTenderDetailsFromResponse) return responses, total, nil } @@ -926,43 +828,8 @@ func (s *tenderApprovalService) ListTenderApprovalsWithTender(ctx context.Contex total = int64(len(tenderApprovals)) // Use actual count if total count fails } - // Convert to response with tender details - var responses []*TenderApprovalWithTenderResponse - for _, approval := range tenderApprovals { - // Get tender details - tenderResponse, err := s.tenderService.GetByID(ctx, approval.TenderID, "") - if err != nil { - s.logger.Warn("Failed to get tender details", map[string]interface{}{ - "tender_id": approval.TenderID, - "error": err.Error(), - }) - // Continue without tender details rather than failing completely - responses = append(responses, approval.ToResponseWithTender(nil)) - continue - } - - // Convert tender response to tender details - tenderDetails := &TenderDetails{ - ID: tenderResponse.ID, - NoticePublicationID: tenderResponse.NoticePublicationID, - PublicationDate: tenderResponse.PublicationDate, - Title: tenderResponse.Title, - Description: tenderResponse.Description, - ProcurementTypeCode: tenderResponse.ProcurementTypeCode, - ProcedureCode: tenderResponse.ProcedureCode, - EstimatedValue: tenderResponse.EstimatedValue, - Currency: tenderResponse.Currency, - Duration: tenderResponse.Duration, - DurationUnit: tenderResponse.DurationUnit, - TenderDeadline: tenderResponse.TenderDeadline, - SubmissionDeadline: tenderResponse.SubmissionDeadline, - CountryCode: tenderResponse.CountryCode, - BuyerOrganization: &OrganizationResponse{Name: tenderResponse.BuyerOrganization.Name}, - Status: string(tenderResponse.Status), - } - - responses = append(responses, approval.ToResponseWithTender(tenderDetails)) - } + tenders := s.loadTendersByIDs(ctx, uniqueTenderIDs(tenderApprovals)) + responses := mapApprovalsWithTender(tenderApprovals, tenders, fullTenderDetailsFromResponse) // Calculate pagination metadata pages := int(total) / limit diff --git a/internal/tender_approval/tender_details.go b/internal/tender_approval/tender_details.go new file mode 100644 index 0000000..2dcbf00 --- /dev/null +++ b/internal/tender_approval/tender_details.go @@ -0,0 +1,110 @@ +package tender_approval + +import ( + "context" + + "tm/internal/tender" +) + +func fullTenderDetailsFromResponse(resp *tender.TenderResponse) *TenderDetails { + if resp == nil { + return nil + } + + details := &TenderDetails{ + ID: resp.ID, + NoticePublicationID: resp.NoticePublicationID, + PublicationDate: resp.PublicationDate, + Title: resp.Title, + Description: resp.Description, + ProcurementTypeCode: resp.ProcurementTypeCode, + ProcedureCode: resp.ProcedureCode, + EstimatedValue: resp.EstimatedValue, + Currency: resp.Currency, + Duration: resp.Duration, + DurationUnit: resp.DurationUnit, + TenderDeadline: resp.TenderDeadline, + SubmissionDeadline: resp.SubmissionDeadline, + CountryCode: resp.CountryCode, + Status: string(resp.Status), + } + if resp.BuyerOrganization != nil && resp.BuyerOrganization.Name != "" { + details.BuyerOrganization = &OrganizationResponse{Name: resp.BuyerOrganization.Name} + } + return details +} + +func listTenderDetailsFromResponse(resp *tender.TenderResponse) *TenderDetails { + if resp == nil { + return nil + } + + details := &TenderDetails{ + ID: resp.ID, + Title: resp.Title, + Description: resp.Description, + EstimatedValue: resp.EstimatedValue, + Currency: resp.Currency, + TenderDeadline: resp.TenderDeadline, + SubmissionDeadline: resp.SubmissionDeadline, + CountryCode: resp.CountryCode, + Status: string(resp.Status), + } + if resp.BuyerOrganization != nil && resp.BuyerOrganization.Name != "" { + details.BuyerOrganization = &OrganizationResponse{Name: resp.BuyerOrganization.Name} + } + return details +} + +func uniqueTenderIDs(approvals []*TenderApproval) []string { + if len(approvals) == 0 { + return nil + } + + seen := make(map[string]struct{}, len(approvals)) + ids := make([]string, 0, len(approvals)) + for _, approval := range approvals { + if approval == nil || approval.TenderID == "" { + continue + } + if _, ok := seen[approval.TenderID]; ok { + continue + } + seen[approval.TenderID] = struct{}{} + ids = append(ids, approval.TenderID) + } + return ids +} + +func (s *tenderApprovalService) loadTendersByIDs(ctx context.Context, tenderIDs []string) map[string]*tender.TenderResponse { + if len(tenderIDs) == 0 { + return map[string]*tender.TenderResponse{} + } + + tenders, err := s.tenderService.GetByIDs(ctx, tenderIDs) + if err != nil { + s.logger.Warn("Failed to load tenders by IDs", map[string]interface{}{ + "count": len(tenderIDs), + "error": err.Error(), + }) + return map[string]*tender.TenderResponse{} + } + + return tenders +} + +func mapApprovalsWithTender( + approvals []*TenderApproval, + tenders map[string]*tender.TenderResponse, + toDetails func(*tender.TenderResponse) *TenderDetails, +) []*TenderApprovalWithTenderResponse { + responses := make([]*TenderApprovalWithTenderResponse, 0, len(approvals)) + for _, approval := range approvals { + var details *TenderDetails + if tenderResp, ok := tenders[approval.TenderID]; ok { + details = toDetails(tenderResp) + } + responses = append(responses, approval.ToResponseWithTender(details)) + } + return responses +}