Enhance tender approval and submission handling

- Added a new error for submission sync failures, improving error handling in the tender approval process.
- Updated the `ToggleTenderApproval` method to handle the new error, providing clearer responses for sync issues.
- Introduced a method to reopen terminal submissions when tender approvals are resubmitted, enhancing submission state management.
- Implemented optimistic locking in the repository to prevent concurrent updates, improving data integrity.
- Added unit tests for new submission handling logic, ensuring robust functionality and error management.

This update strengthens the tender approval workflow and submission handling, ensuring better error reporting and state management.
This commit is contained in:
Mazyar
2026-07-12 21:41:53 +03:30
parent 0cce9ef1b5
commit fa3d466579
9 changed files with 436 additions and 21 deletions
+1
View File
@@ -14,4 +14,5 @@ var (
ErrInvalidCompanyID = errors.New("invalid company ID")
ErrUnauthorized = errors.New("unauthorized to perform this action")
ErrInvalidData = errors.New("invalid tender approval data")
ErrSubmissionSyncFailed = errors.New("failed to sync tender submission workflow")
)
+3
View File
@@ -66,6 +66,9 @@ func (h *Handler) ToggleTenderApproval(c echo.Context) error {
if errors.Is(err, ErrTenderNotFound) {
return response.NotFound(c, "Tender not found")
}
if errors.Is(err, ErrSubmissionSyncFailed) {
return response.InternalServerError(c, "Failed to sync tender submission workflow")
}
if err.Error() == "tender approval already exists for this tender and company" {
return response.Conflict(c, err.Error())
}
+18 -5
View File
@@ -908,7 +908,15 @@ func (s *tenderApprovalService) ToggleTenderApproval(ctx context.Context, req *T
return nil, err
}
s.syncSubmissionAfterToggle(ctx, tenderID, companyID, customerID, req.Status, true)
if err := s.syncSubmissionAfterToggle(ctx, tenderID, companyID, customerID, req.Status, true); err != nil {
if deleteErr := s.repository.Delete(ctx, approval.GetID()); deleteErr != nil {
s.logger.Error("Failed to rollback tender approval after submission sync failure", map[string]interface{}{
"tender_approval_id": approval.GetID(),
"error": deleteErr.Error(),
})
}
return nil, ErrSubmissionSyncFailed
}
return s.toggleResponseWithTender(ctx, approval)
}
@@ -927,7 +935,9 @@ func (s *tenderApprovalService) ToggleTenderApproval(ctx context.Context, req *T
existing.Status = "unrejected"
}
s.syncSubmissionAfterToggle(ctx, tenderID, companyID, customerID, req.Status, false)
if err := s.syncSubmissionAfterToggle(ctx, tenderID, companyID, customerID, req.Status, false); err != nil {
return nil, ErrSubmissionSyncFailed
}
return existing.ToResponseWithTender(nil), nil
}
@@ -950,13 +960,15 @@ func (s *tenderApprovalService) ToggleTenderApproval(ctx context.Context, req *T
return nil, err
}
s.syncSubmissionAfterToggle(ctx, tenderID, companyID, customerID, req.Status, true)
if err := s.syncSubmissionAfterToggle(ctx, tenderID, companyID, customerID, req.Status, true); err != nil {
return nil, ErrSubmissionSyncFailed
}
return s.toggleResponseWithTender(ctx, existing)
}
func (s *tenderApprovalService) syncSubmissionAfterToggle(ctx context.Context, tenderID, companyID, customerID string, status ApprovalStatus, active bool) {
func (s *tenderApprovalService) syncSubmissionAfterToggle(ctx context.Context, tenderID, companyID, customerID string, status ApprovalStatus, active bool) error {
if s.submissionHook == nil {
return
return nil
}
var err error
@@ -977,6 +989,7 @@ func (s *tenderApprovalService) syncSubmissionAfterToggle(ctx context.Context, t
"error": err.Error(),
})
}
return err
}
func (s *tenderApprovalService) toggleResponseWithTender(ctx context.Context, approval *TenderApproval) (*TenderApprovalWithTenderResponse, error) {