mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-04 21:52:12 +00:00
fix(vendors): return completion documents in portal detail
This commit is contained in:
parent
5ecb377613
commit
36d0a638a2
5 changed files with 183 additions and 4 deletions
|
|
@ -35,6 +35,11 @@ public sealed class VendorPortalDocumentTests : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
private VendorPortalController NewController(ApplicationDbContext context)
|
private VendorPortalController NewController(ApplicationDbContext context)
|
||||||
|
{
|
||||||
|
return NewController(NewService(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
private VendorPortalService NewService(ApplicationDbContext context)
|
||||||
{
|
{
|
||||||
var vendorData = new VendorDataService(context);
|
var vendorData = new VendorDataService(context);
|
||||||
var tokenService = new VendorPortalTokenService(
|
var tokenService = new VendorPortalTokenService(
|
||||||
|
|
@ -45,11 +50,18 @@ public sealed class VendorPortalDocumentTests : IDisposable
|
||||||
storageEnvironment.SetupGet(item => item.ContentRootPath).Returns(_contentRoot);
|
storageEnvironment.SetupGet(item => item.ContentRootPath).Returns(_contentRoot);
|
||||||
var storage = new VendorDocumentStorageAdapter(storageEnvironment.Object);
|
var storage = new VendorDocumentStorageAdapter(storageEnvironment.Object);
|
||||||
|
|
||||||
var service = new VendorPortalService(
|
var upliftData = new Mock<IUpliftDataService>();
|
||||||
|
upliftData.Setup(u => u.GetForVendorDispatchAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||||
|
.ReturnsAsync(new List<PortalUpliftData>());
|
||||||
|
var commentData = new Mock<ICommentDataService>();
|
||||||
|
commentData.Setup(c => c.GetVendorViewableForDispatchAsync(It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||||
|
.ReturnsAsync(new List<PortalCommentData>());
|
||||||
|
|
||||||
|
return new VendorPortalService(
|
||||||
tokenService,
|
tokenService,
|
||||||
new DispatchDataService(context),
|
new DispatchDataService(context),
|
||||||
Mock.Of<IUpliftDataService>(),
|
upliftData.Object,
|
||||||
Mock.Of<ICommentDataService>(),
|
commentData.Object,
|
||||||
Mock.Of<IUserDataService>(),
|
Mock.Of<IUserDataService>(),
|
||||||
Mock.Of<IEmailSender>(),
|
Mock.Of<IEmailSender>(),
|
||||||
documentData,
|
documentData,
|
||||||
|
|
@ -57,7 +69,10 @@ public sealed class VendorPortalDocumentTests : IDisposable
|
||||||
Microsoft.Extensions.Options.Options.Create(new FrontendOptions()),
|
Microsoft.Extensions.Options.Options.Create(new FrontendOptions()),
|
||||||
Microsoft.Extensions.Options.Options.Create(new ApprovalsOptions()),
|
Microsoft.Extensions.Options.Options.Create(new ApprovalsOptions()),
|
||||||
Microsoft.Extensions.Options.Options.Create(new VendorDocumentsOptions()));
|
Microsoft.Extensions.Options.Options.Create(new VendorDocumentsOptions()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VendorPortalController NewController(VendorPortalService service)
|
||||||
|
{
|
||||||
var controller = new VendorPortalController(service, Mock.Of<ILogger<VendorPortalController>>());
|
var controller = new VendorPortalController(service, Mock.Of<ILogger<VendorPortalController>>());
|
||||||
controller.ControllerContext = new ControllerContext
|
controller.ControllerContext = new ControllerContext
|
||||||
{
|
{
|
||||||
|
|
@ -292,6 +307,122 @@ public sealed class VendorPortalDocumentTests : IDisposable
|
||||||
context.VendorCompletionDocuments.Should().HaveCount(1);
|
context.VendorCompletionDocuments.Should().HaveCount(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDispatchDetail_ReturnsUploadedDocumentWithQuarantineAndReplacementMetadata()
|
||||||
|
{
|
||||||
|
using var context = NewContext();
|
||||||
|
var (_, dispatch) = await SeedDispatch(context);
|
||||||
|
var service = NewService(context);
|
||||||
|
var pdf = "%PDF-1.4\nvendor completion"u8.ToArray();
|
||||||
|
|
||||||
|
await NewController(service).UploadCompletionDocument(
|
||||||
|
dispatch.Id,
|
||||||
|
FormFile(pdf, "completion-v1.pdf", "application/pdf"));
|
||||||
|
|
||||||
|
var session = await service.ResolveSessionAsync(Token, CancellationToken.None);
|
||||||
|
var firstDetail = await service.GetDispatchDetailAsync(session!, dispatch.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
firstDetail.Should().NotBeNull();
|
||||||
|
var firstDoc = firstDetail!.Documents.Should().ContainSingle().Subject;
|
||||||
|
firstDoc.OriginalFileName.Should().Be("completion-v1.pdf");
|
||||||
|
firstDoc.ContentType.Should().Be("application/pdf");
|
||||||
|
firstDoc.SizeBytes.Should().Be(pdf.Length);
|
||||||
|
firstDoc.ScanStatus.Should().Be("Pending");
|
||||||
|
firstDoc.ReviewStatus.Should().Be("Processing");
|
||||||
|
firstDoc.Version.Should().Be(1);
|
||||||
|
firstDoc.ReplacesDocumentId.Should().BeNull();
|
||||||
|
firstDoc.CanDownload.Should().BeFalse();
|
||||||
|
firstDoc.CreatedDate.Should().NotBeNull();
|
||||||
|
|
||||||
|
var first = await context.VendorCompletionDocuments.SingleAsync();
|
||||||
|
await NewController(service).UploadCompletionDocument(
|
||||||
|
dispatch.Id,
|
||||||
|
FormFile(pdf, "completion-v2.pdf", "application/pdf"),
|
||||||
|
first.Id);
|
||||||
|
|
||||||
|
var secondDetail = await service.GetDispatchDetailAsync(session!, dispatch.Id, CancellationToken.None);
|
||||||
|
var ordered = secondDetail!.Documents.OrderByDescending(d => d.Version).ToList();
|
||||||
|
ordered.Should().HaveCount(2);
|
||||||
|
ordered[0].Version.Should().Be(2);
|
||||||
|
ordered[0].ReplacesDocumentId.Should().Be(first.Id);
|
||||||
|
ordered[0].OriginalFileName.Should().Be("completion-v2.pdf");
|
||||||
|
ordered[1].Version.Should().Be(1);
|
||||||
|
ordered[1].ReplacesDocumentId.Should().BeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDispatchDetail_EnablesDownloadOnlyWhenScanPasses()
|
||||||
|
{
|
||||||
|
using var context = NewContext();
|
||||||
|
var (_, dispatch) = await SeedDispatch(context);
|
||||||
|
var service = NewService(context);
|
||||||
|
var pdf = "%PDF-1.4\nvendor completion"u8.ToArray();
|
||||||
|
|
||||||
|
await NewController(service).UploadCompletionDocument(
|
||||||
|
dispatch.Id,
|
||||||
|
FormFile(pdf, "completion.pdf", "application/pdf"));
|
||||||
|
|
||||||
|
var document = await context.VendorCompletionDocuments.SingleAsync();
|
||||||
|
document.ScanStatus = "Passed";
|
||||||
|
document.ScannedAt = DateTime.UtcNow;
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var session = await service.ResolveSessionAsync(Token, CancellationToken.None);
|
||||||
|
var detail = await service.GetDispatchDetailAsync(session!, dispatch.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
var doc = detail!.Documents.Should().ContainSingle().Subject;
|
||||||
|
doc.ScanStatus.Should().Be("Passed");
|
||||||
|
doc.CanDownload.Should().BeTrue();
|
||||||
|
doc.ScannedAt.Should().NotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Verified")]
|
||||||
|
[InlineData("Cancelled")]
|
||||||
|
public async Task GetDispatchDetail_DisablesDownloadForLockedDispatches(string status)
|
||||||
|
{
|
||||||
|
using var context = NewContext();
|
||||||
|
var (_, dispatch) = await SeedDispatch(context);
|
||||||
|
var service = NewService(context);
|
||||||
|
var pdf = "%PDF-1.4\nvendor completion"u8.ToArray();
|
||||||
|
|
||||||
|
await NewController(service).UploadCompletionDocument(
|
||||||
|
dispatch.Id,
|
||||||
|
FormFile(pdf, "completion.pdf", "application/pdf"));
|
||||||
|
|
||||||
|
var document = await context.VendorCompletionDocuments.SingleAsync();
|
||||||
|
document.ScanStatus = "Passed";
|
||||||
|
dispatch.Status = status;
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var session = await service.ResolveSessionAsync(Token, CancellationToken.None);
|
||||||
|
var detail = await service.GetDispatchDetailAsync(session!, dispatch.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
detail!.Documents.Should().ContainSingle().Which.CanDownload.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetDispatchDetail_ExcludesSoftDeletedDocuments()
|
||||||
|
{
|
||||||
|
using var context = NewContext();
|
||||||
|
var (_, dispatch) = await SeedDispatch(context);
|
||||||
|
var service = NewService(context);
|
||||||
|
var pdf = "%PDF-1.4\nvendor completion"u8.ToArray();
|
||||||
|
|
||||||
|
await NewController(service).UploadCompletionDocument(
|
||||||
|
dispatch.Id,
|
||||||
|
FormFile(pdf, "completion.pdf", "application/pdf"));
|
||||||
|
|
||||||
|
var document = await context.VendorCompletionDocuments.SingleAsync();
|
||||||
|
document.IsDeleted = true;
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var session = await service.ResolveSessionAsync(Token, CancellationToken.None);
|
||||||
|
var detail = await service.GetDispatchDetailAsync(session!, dispatch.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
detail!.Documents.Should().BeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Directory.Exists(_contentRoot))
|
if (Directory.Exists(_contentRoot))
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,16 @@ namespace SeaHaven.DataServices.Implementation
|
||||||
&& (document.IsDeleted == null || document.IsDeleted == false), cancellationToken);
|
&& (document.IsDeleted == null || document.IsDeleted == false), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<List<VendorCompletionDocument>> ListForVendorDispatchAsync(int dispatchId, int vendorId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return _context.VendorCompletionDocuments
|
||||||
|
.Where(document => document.DispatchId == dispatchId
|
||||||
|
&& document.VendorId == vendorId
|
||||||
|
&& (document.IsDeleted == null || document.IsDeleted == false))
|
||||||
|
.OrderByDescending(document => document.Version)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task AddAsync(VendorCompletionDocument document, CancellationToken cancellationToken)
|
public async Task AddAsync(VendorCompletionDocument document, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
await _context.VendorCompletionDocuments.AddAsync(document, cancellationToken);
|
await _context.VendorCompletionDocuments.AddAsync(document, cancellationToken);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ namespace SeaHaven.DataServices.Interfaces
|
||||||
{
|
{
|
||||||
Task<VendorCompletionDocument?> GetLatestForDispatchAsync(int dispatchId, CancellationToken cancellationToken);
|
Task<VendorCompletionDocument?> GetLatestForDispatchAsync(int dispatchId, CancellationToken cancellationToken);
|
||||||
Task<VendorCompletionDocument?> GetForVendorDispatchAsync(int documentId, int dispatchId, int vendorId, CancellationToken cancellationToken);
|
Task<VendorCompletionDocument?> GetForVendorDispatchAsync(int documentId, int dispatchId, int vendorId, CancellationToken cancellationToken);
|
||||||
|
Task<List<VendorCompletionDocument>> ListForVendorDispatchAsync(int dispatchId, int vendorId, CancellationToken cancellationToken);
|
||||||
Task AddAsync(VendorCompletionDocument document, CancellationToken cancellationToken);
|
Task AddAsync(VendorCompletionDocument document, CancellationToken cancellationToken);
|
||||||
Task SaveChangesAsync(CancellationToken cancellationToken);
|
Task SaveChangesAsync(CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,24 @@ namespace SeaHaven.Services.DTOs
|
||||||
public IEnumerable<PortalSignoffDTO> Signoffs { get; set; } = Enumerable.Empty<PortalSignoffDTO>();
|
public IEnumerable<PortalSignoffDTO> Signoffs { get; set; } = Enumerable.Empty<PortalSignoffDTO>();
|
||||||
public IEnumerable<PortalCommentDTO> Comments { get; set; } = Enumerable.Empty<PortalCommentDTO>();
|
public IEnumerable<PortalCommentDTO> Comments { get; set; } = Enumerable.Empty<PortalCommentDTO>();
|
||||||
public IEnumerable<PortalUpliftDTO> UpliftRequests { get; set; } = Enumerable.Empty<PortalUpliftDTO>();
|
public IEnumerable<PortalUpliftDTO> UpliftRequests { get; set; } = Enumerable.Empty<PortalUpliftDTO>();
|
||||||
|
public IEnumerable<VendorPortalDocumentDTO> Documents { get; set; } = Enumerable.Empty<VendorPortalDocumentDTO>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VendorPortalDocumentDTO
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string? OriginalFileName { get; set; }
|
||||||
|
public string? ContentType { get; set; }
|
||||||
|
public long SizeBytes { get; set; }
|
||||||
|
public string? ScanStatus { get; set; }
|
||||||
|
public string? ReviewStatus { get; set; }
|
||||||
|
public string? RejectionReason { get; set; }
|
||||||
|
public int Version { get; set; }
|
||||||
|
public int? ReplacesDocumentId { get; set; }
|
||||||
|
public DateTime? CreatedDate { get; set; }
|
||||||
|
public DateTime? ScannedAt { get; set; }
|
||||||
|
public DateTime? ReviewedAt { get; set; }
|
||||||
|
public bool CanDownload { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AcceptDispatchResultDTO
|
public class AcceptDispatchResultDTO
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ namespace SeaHaven.Services.Implementation
|
||||||
var signoffs = await _dispatchData.GetPortalSignoffsAsync(id, cancellationToken);
|
var signoffs = await _dispatchData.GetPortalSignoffsAsync(id, cancellationToken);
|
||||||
var rawUplifts = await _upliftData.GetForVendorDispatchAsync(id, cancellationToken);
|
var rawUplifts = await _upliftData.GetForVendorDispatchAsync(id, cancellationToken);
|
||||||
var rawComments = await _commentData.GetVendorViewableForDispatchAsync(id, cancellationToken);
|
var rawComments = await _commentData.GetVendorViewableForDispatchAsync(id, cancellationToken);
|
||||||
|
var rawDocuments = await _documentData.ListForVendorDispatchAsync(id, session.Id, cancellationToken);
|
||||||
|
|
||||||
var upliftRequests = rawUplifts.Select(u => new PortalUpliftDTO
|
var upliftRequests = rawUplifts.Select(u => new PortalUpliftDTO
|
||||||
{
|
{
|
||||||
|
|
@ -192,7 +193,25 @@ namespace SeaHaven.Services.Implementation
|
||||||
SignedAt = s.SignedAt
|
SignedAt = s.SignedAt
|
||||||
}),
|
}),
|
||||||
Comments = comments,
|
Comments = comments,
|
||||||
UpliftRequests = upliftRequests
|
UpliftRequests = upliftRequests,
|
||||||
|
Documents = rawDocuments.Select(document => new VendorPortalDocumentDTO
|
||||||
|
{
|
||||||
|
Id = document.Id,
|
||||||
|
OriginalFileName = document.OriginalFileName,
|
||||||
|
ContentType = document.ContentType,
|
||||||
|
SizeBytes = document.SizeBytes,
|
||||||
|
ScanStatus = document.ScanStatus,
|
||||||
|
ReviewStatus = document.ReviewStatus,
|
||||||
|
RejectionReason = document.RejectionReason,
|
||||||
|
Version = document.Version,
|
||||||
|
ReplacesDocumentId = document.ReplacesDocumentId,
|
||||||
|
CreatedDate = document.CreatedDate,
|
||||||
|
ScannedAt = document.ScannedAt,
|
||||||
|
ReviewedAt = document.ReviewedAt,
|
||||||
|
CanDownload = string.Equals(document.ScanStatus, "Passed", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& dispatch.Status != "Verified"
|
||||||
|
&& dispatch.Status != "Cancelled"
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue