package tender_submission import ( "time" "tm/pkg/mongo" ) // SubmissionStatus represents the current step in the tender submission workflow. type SubmissionStatus string const ( StatusOpportunity SubmissionStatus = "opportunity" StatusValidating SubmissionStatus = "validating" StatusPartnerPending SubmissionStatus = "partner_pending" StatusApplying SubmissionStatus = "applying" StatusSentWaiting SubmissionStatus = "sent_waiting" StatusRejected SubmissionStatus = "rejected" StatusContract SubmissionStatus = "contract" StatusNotApplied SubmissionStatus = "not_applied" ) // SubmissionStage groups statuses into high-level workflow stages for UI display. type SubmissionStage string const ( StageOpportunity SubmissionStage = "opportunity" StageInProgress SubmissionStage = "in_progress" StageSubmitted SubmissionStage = "submitted" StageNotApplied SubmissionStage = "not_applied" ) // StatusHistory records a status change in the submission workflow. type StatusHistory struct { Status SubmissionStatus `bson:"status" json:"status"` Reason string `bson:"reason,omitempty" json:"reason,omitempty"` ChangedBy string `bson:"changed_by" json:"changed_by"` ChangedAt int64 `bson:"changed_at" json:"changed_at"` Description string `bson:"description,omitempty" json:"description,omitempty"` } // TenderSubmission tracks a company's tender submission workflow. type TenderSubmission struct { mongo.Model `bson:",inline"` TenderID string `bson:"tender_id" json:"tender_id"` CompanyID string `bson:"company_id" json:"company_id"` CustomerID string `bson:"customer_id,omitempty" json:"customer_id,omitempty"` Status SubmissionStatus `bson:"status" json:"status"` Stage SubmissionStage `bson:"stage" json:"stage"` History []StatusHistory `bson:"status_history" json:"status_history"` } func StageForStatus(status SubmissionStatus) SubmissionStage { switch status { case StatusOpportunity: return StageOpportunity case StatusValidating, StatusPartnerPending, StatusApplying: return StageInProgress case StatusSentWaiting, StatusRejected, StatusContract: return StageSubmitted case StatusNotApplied: return StageNotApplied default: return StageOpportunity } } func IsTerminalStatus(status SubmissionStatus) bool { switch status { case StatusRejected, StatusContract, StatusNotApplied: return true default: return false } } func AllowedNextStatuses(current SubmissionStatus) []SubmissionStatus { transitions := map[SubmissionStatus][]SubmissionStatus{ StatusOpportunity: {StatusValidating, StatusNotApplied}, StatusValidating: {StatusPartnerPending, StatusApplying, StatusNotApplied}, StatusPartnerPending: {StatusApplying, StatusNotApplied}, StatusApplying: {StatusSentWaiting, StatusNotApplied}, StatusSentWaiting: {StatusRejected, StatusContract}, StatusRejected: {}, StatusContract: {}, StatusNotApplied: {}, } return transitions[current] } func (ts *TenderSubmission) GetID() string { return ts.ID.Hex() } func (ts *TenderSubmission) SetCreatedAt(timestamp int64) { ts.CreatedAt = timestamp } func (ts *TenderSubmission) SetUpdatedAt(timestamp int64) { ts.UpdatedAt = timestamp } func (ts *TenderSubmission) AddStatusChange(status SubmissionStatus, reason, changedBy, description string) { ts.History = append(ts.History, StatusHistory{ Status: status, Reason: reason, ChangedBy: changedBy, ChangedAt: time.Now().Unix(), Description: description, }) ts.Status = status ts.Stage = StageForStatus(status) ts.SetUpdatedAt(time.Now().Unix()) } // ReopenForApproval resets a terminal submission when the tender is approved again. // This is only used by the approval sync path, not by user-initiated status updates. func (ts *TenderSubmission) ReopenForApproval(changedBy, description string) { ts.AddStatusChange(StatusOpportunity, "approval_resubmitted", changedBy, description) } func NewTenderSubmission(tenderID, companyID, customerID string) *TenderSubmission { now := time.Now().Unix() ts := &TenderSubmission{ TenderID: tenderID, CompanyID: companyID, CustomerID: customerID, Status: StatusOpportunity, Stage: StageOpportunity, } ts.SetCreatedAt(now) ts.SetUpdatedAt(now) ts.AddStatusChange(StatusOpportunity, "", customerID, "Submission workflow started") return ts } func (ts *TenderSubmission) ToResponse() *TenderSubmissionResponse { history := make([]StatusHistoryResponse, len(ts.History)) for i, h := range ts.History { history[i] = StatusHistoryResponse{ Status: string(h.Status), Reason: h.Reason, ChangedBy: h.ChangedBy, ChangedAt: h.ChangedAt, Description: h.Description, } } return &TenderSubmissionResponse{ ID: ts.GetID(), TenderID: ts.TenderID, CompanyID: ts.CompanyID, CustomerID: ts.CustomerID, Status: string(ts.Status), Stage: string(ts.Stage), History: history, CreatedAt: ts.CreatedAt, UpdatedAt: ts.UpdatedAt, } } func (ts *TenderSubmission) ToResponseWithTender(tender *TenderDetails) *TenderSubmissionWithTenderResponse { resp := ts.ToResponse() return &TenderSubmissionWithTenderResponse{ TenderSubmissionResponse: *resp, Tender: tender, } }