diff --git a/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx b/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx index 384715ebc..98082c79b 100644 --- a/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx +++ b/apps/console/src/pages/organizations/documents/_components/SignatureDocumentsDialog.tsx @@ -37,6 +37,7 @@ import { graphql } from "relay-runtime"; import { z } from "zod"; import type { SignatureDocumentsDialogMutation } from "#/__generated__/core/SignatureDocumentsDialogMutation.graphql"; +import type { SignatureDocumentsDialogPeopleFragment$key } from "#/__generated__/core/SignatureDocumentsDialogPeopleFragment.graphql"; import type { SignatureDocumentsDialogPeopleQuery } from "#/__generated__/core/SignatureDocumentsDialogPeopleQuery.graphql"; import type { SignatureDocumentsDialogPeopleRefetchQuery } from "#/__generated__/core/SignatureDocumentsDialogPeopleRefetchQuery.graphql"; import { useFormWithSchema } from "#/hooks/useFormWithSchema"; @@ -203,7 +204,10 @@ function PeopleList({ hasNext, loadNext, isLoadingNext, - } = usePaginationFragment( + } = usePaginationFragment< + SignatureDocumentsDialogPeopleRefetchQuery, + SignatureDocumentsDialogPeopleFragment$key + >( signatureDocumentsDialogPeopleFragment, data.organization, ); diff --git a/pkg/probo/document_approval_service.go b/pkg/probo/document_approval_service.go index 721aaca0b..0c33e41cf 100644 --- a/pkg/probo/document_approval_service.go +++ b/pkg/probo/document_approval_service.go @@ -106,6 +106,18 @@ func (s *DocumentApprovalService) RequestApproval( err := s.svc.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { + profiles := &coredata.MembershipProfiles{} + if err := profiles.LoadByIDs(ctx, tx, s.svc.scope, req.ApproverIDs); err != nil { + return fmt.Errorf("cannot load approver profiles: %w", err) + } + + now := time.Now() + for _, p := range *profiles { + if p.ContractEndDate != nil && p.ContractEndDate.Before(now) { + return &ErrProfileContractEnded{ProfileID: p.ID} + } + } + document := &coredata.Document{} if err := document.LoadByID(ctx, tx, s.svc.scope, req.DocumentID); err != nil { return fmt.Errorf("cannot load document: %w", err) diff --git a/pkg/probo/document_service.go b/pkg/probo/document_service.go index 6706c9330..2675bfa78 100644 --- a/pkg/probo/document_service.go +++ b/pkg/probo/document_service.go @@ -80,6 +80,10 @@ type ( ErrDocumentVersionSignatureAlreadySigned struct { } + ErrProfileContractEnded struct { + ProfileID gid.GID + } + CreateDocumentRequest struct { OrganizationID gid.GID Title string @@ -217,6 +221,10 @@ func (e ErrDocumentVersionSignatureAlreadySigned) Error() string { return "document version signature already signed" } +func (e ErrProfileContractEnded) Error() string { + return fmt.Sprintf("cannot use profile %q: contract has ended", e.ProfileID) +} + func (s *DocumentService) Get( ctx context.Context, documentID gid.GID, @@ -883,6 +891,18 @@ func (s *DocumentService) BulkRequestSignatures( err := s.svc.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { + profiles := &coredata.MembershipProfiles{} + if err := profiles.LoadByIDs(ctx, tx, s.svc.scope, req.SignatoryIDs); err != nil { + return fmt.Errorf("cannot load signatory profiles: %w", err) + } + + now := time.Now() + for _, p := range *profiles { + if p.ContractEndDate != nil && p.ContractEndDate.Before(now) { + return &ErrProfileContractEnded{ProfileID: p.ID} + } + } + for _, documentID := range req.DocumentIDs { documentVersion := &coredata.DocumentVersion{} if err := documentVersion.LoadLatestVersion(ctx, tx, s.svc.scope, documentID); err != nil { @@ -984,6 +1004,15 @@ func (s *DocumentService) RequestSignature( return fmt.Errorf("cannot request signature for unpublished version") } + profile := &coredata.MembershipProfile{} + if err := profile.LoadByID(ctx, tx, s.svc.scope, req.Signatory); err != nil { + return fmt.Errorf("cannot load signatory profile: %w", err) + } + + if profile.ContractEndDate != nil && profile.ContractEndDate.Before(time.Now()) { + return &ErrProfileContractEnded{ProfileID: profile.ID} + } + var err error signature, err = s.createSignatureRequestInTx(ctx, tx, req.DocumentVersionID, req.Signatory, false) if err != nil { diff --git a/pkg/server/api/console/v1/document_resolvers.go b/pkg/server/api/console/v1/document_resolvers.go index a3b1b77f5..94af92803 100644 --- a/pkg/server/api/console/v1/document_resolvers.go +++ b/pkg/server/api/console/v1/document_resolvers.go @@ -1156,6 +1156,10 @@ func (r *mutationResolver) RequestDocumentVersionApproval(ctx context.Context, i return nil, gqlutils.Conflict(ctx, errNotDraft) } + if errContractEnded, ok := errors.AsType[*probo.ErrProfileContractEnded](err); ok { + return nil, gqlutils.Conflict(ctx, errContractEnded) + } + if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok { return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors) } @@ -1354,6 +1358,10 @@ func (r *mutationResolver) RequestSignature(ctx context.Context, input types.Req return nil, gqlutils.Conflict(ctx, errArchived) } + if errContractEnded, ok := errors.AsType[*probo.ErrProfileContractEnded](err); ok { + return nil, gqlutils.Conflict(ctx, errContractEnded) + } + r.logger.ErrorCtx(ctx, "cannot request signature", log.Error(err)) return nil, gqlutils.Internal(ctx) } @@ -1387,6 +1395,10 @@ func (r *mutationResolver) BulkRequestSignatures(ctx context.Context, input type }, ) if err != nil { + if errContractEnded, ok := errors.AsType[*probo.ErrProfileContractEnded](err); ok { + return nil, gqlutils.Conflict(ctx, errContractEnded) + } + r.logger.ErrorCtx(ctx, "cannot bulk request signatures", log.Error(err)) return nil, gqlutils.Internal(ctx) }