package tender import "tm/pkg/response" // UpdateTenderRequest represents a request to update an existing tender type UpdateTenderRequest struct { ID string `json:"id" valid:"required~Tender ID is required"` Title *string `json:"title,omitempty" valid:"stringlength(1|500)~Title must be between 1 and 500 characters"` Description *string `json:"description,omitempty" valid:"stringlength(0|5000)~Description must not exceed 5000 characters"` Status *TenderStatus `json:"status,omitempty"` EstimatedValue *float64 `json:"estimated_value,omitempty" valid:"range(0|999999999999)~Estimated value must be between 0 and 999999999999"` Currency *string `json:"currency,omitempty" valid:"stringlength(3|3)~Currency must be 3 characters"` TenderDeadline *int64 `json:"tender_deadline,omitempty"` // Unix milliseconds } // SearchForm represents a request to list tenders with pagination and filtering type SearchForm struct { Search *string `query:"q" valid:"optional"` Title *string `query:"title" valid:"optional"` Description *string `query:"description" valid:"optional"` NoticeType *string `query:"notice_type" valid:"optional"` NoticeTypes []string `query:"notice_types" valid:"optional"` FormTypes []string `query:"form_types" valid:"optional"` ProcurementType *string `query:"procurement_type" valid:"optional"` Country *string `query:"country" valid:"optional"` CountryCode *string `query:"country_code" valid:"optional"` CountryCodes []string `query:"country_codes" valid:"optional"` RegionCodes []string `query:"region_codes" valid:"optional"` CompanyID *string `query:"company_id" valid:"optional"` CustomerID *string `query:"customer_id" valid:"optional"` Status []string `query:"status" valid:"optional"` MainClassification *string `query:"main_classification" valid:"optional"` Classifications []string `query:"classifications" valid:"optional"` CpvCodes []string `query:"cpv_codes" valid:"optional"` MinEstimatedValue *float64 `query:"min_estimated_value" valid:"optional"` MaxEstimatedValue *float64 `query:"max_estimated_value" valid:"optional"` Currency string `query:"currency" valid:"optional"` CreatedAt *int64 `query:"created_at" valid:"optional"` CreatedAtFrom *int64 `query:"created_at_from" valid:"optional"` CreatedAtTo *int64 `query:"created_at_to" valid:"optional"` TenderDeadline *int64 `query:"tender_deadline" valid:"optional"` TenderDeadlineFrom *int64 `query:"tender_deadline_from" valid:"optional"` TenderDeadlineTo *int64 `query:"tender_deadline_to" valid:"optional"` DeadlineFrom *int64 `query:"deadline_from" valid:"optional"` DeadlineTo *int64 `query:"deadline_to" valid:"optional"` PublicationDate *int64 `query:"publication_date" valid:"optional"` PublicationDateFrom *int64 `query:"publication_date_from" valid:"optional"` PublicationDateTo *int64 `query:"publication_date_to" valid:"optional"` SubmissionDeadline *int64 `query:"submission_deadline" valid:"optional"` SubmissionDateAliasFrom *int64 `query:"submission_deadline_from" valid:"optional"` SubmissionDateAliasTo *int64 `query:"submission_deadline_to" valid:"optional"` SubmissionDateFrom *int64 `query:"submission_date_from" valid:"optional"` SubmissionDateTo *int64 `query:"submission_date_to" valid:"optional"` Source []string `query:"source" valid:"optional"` BuyerOrganizationID *string `query:"buyer_organization_id" valid:"optional"` Languages []string `query:"languages" valid:"optional"` OnlyActiveDeadlines bool `query:"-" valid:"optional"` Language *string `query:"lang" valid:"optional"` } // SearchResponse represents the response for listing tenders type SearchResponse struct { Tenders []TenderResponse `json:"tenders"` Metadata *response.Meta `json:"-"` } // TenderResponse represents a tender in API responses type TenderResponse struct { ID string `json:"id"` NoticePublicationID string `json:"notice_publication_id"` NoticeTypeCode string `json:"notice_type_code"` Title string `json:"title"` Description string `json:"description"` ProcurementTypeCode string `json:"procurement_type_code"` ProcedureCode string `json:"procedure_code"` MainClassification string `json:"main_classification"` EstimatedValue float64 `json:"estimated_value"` Currency string `json:"currency"` Duration string `json:"duration"` DurationUnit string `json:"duration_unit"` PublicationDate int64 `json:"publication_date"` TenderDeadline int64 `json:"tender_deadline"` SubmissionDeadline int64 `json:"submission_deadline"` ApplicationDeadline int64 `json:"application_deadline"` SubmissionURL string `json:"submission_url"` CountryCode string `json:"country_code"` BuyerOrganization *OrganizationResponse `json:"buyer_organization"` Status TenderStatus `json:"status"` TenderID string `json:"tender_id"` CreatedAt int64 `json:"created_at"` OverallSummary string `json:"overall_summary,omitempty"` // AI-generated summary from the pipeline Language string `json:"language,omitempty"` } // TenderDocumentResponse represents a scraped tender document available for download. type TenderDocumentResponse struct { Filename string `json:"filename"` Size int64 `json:"size"` LastModified int64 `json:"last_modified"` DocumentType string `json:"document_type,omitempty"` } // TenderDocumentsResponse represents scraped documents for a tender. type TenderDocumentsResponse struct { TenderID string `json:"tender_id"` Documents []TenderDocumentResponse `json:"documents"` } type OrganizationResponse struct { Name string `json:"name"` } // ToTenderResponse converts a Tender entity to TenderResponse func (t *Tender) ToResponse() *TenderResponse { return t.ToResponseWithLanguage("") } // ToResponseWithLanguage converts a Tender entity to TenderResponse using a preferred language. // When language is provided and translation exists, translated title/description are returned. func (t *Tender) ToResponseWithLanguage(language string) *TenderResponse { org := &OrganizationResponse{} if t.BuyerOrganization != nil { org.Name = t.BuyerOrganization.Name } title := t.Title description := t.Description usedLanguage := "" if language != "" { if entry, ok := t.Translations[language]; ok { title = entry.Title description = entry.Description usedLanguage = language } } response := &TenderResponse{ ID: t.ID.Hex(), NoticePublicationID: t.NoticePublicationID, NoticeTypeCode: t.NoticeTypeCode, Title: title, Description: description, ProcurementTypeCode: t.ProcurementTypeCode, ProcedureCode: t.ProcedureCode, MainClassification: t.MainClassification, EstimatedValue: t.EstimatedValue, Currency: t.Currency, Duration: t.Duration, DurationUnit: t.DurationUnit, PublicationDate: t.PublicationDate, TenderDeadline: t.TenderDeadline, SubmissionDeadline: t.SubmissionDeadline, ApplicationDeadline: t.ApplicationDeadline, CountryCode: t.CountryCode, SubmissionURL: t.SubmissionURL, BuyerOrganization: org, Status: t.Status, TenderID: t.TenderID, CreatedAt: t.CreatedAt, Language: usedLanguage, } return response } // AITranslateRequest represents a request for on-demand AI translation. type AITranslateRequest struct { Language string `json:"language" valid:"required,stringlength(2|5)~Language must be between 2 and 5 characters"` } // AITranslateResponse represents the response for AI translation trigger. type AITranslateResponse struct { NoticeID string `json:"notice_id"` Language string `json:"language"` TranslatedTitle string `json:"translated_title"` TranslatedDescription string `json:"translated_description"` } // AISummaryResponse represents the response for getting an AI-generated summary type AISummaryResponse struct { NoticeID string `json:"notice_id"` OverallSummary string `json:"overall_summary"` Source string `json:"source"` // "storage" or "on_demand" } // AISummarizeResponse represents the response for triggering on-demand AI summarization type AISummarizeResponse struct { NoticeID string `json:"notice_id"` Summaries []AIDocumentSummary `json:"summaries"` OverallSummary *string `json:"overall_summary"` } // AIDocumentSummary represents a single document summary from the AI service type AIDocumentSummary struct { DocumentName string `json:"document_name"` DocumentType string `json:"document_type"` Summary string `json:"summary"` SummaryModel string `json:"summary_model"` Error string `json:"error,omitempty"` }