Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Spd.Manager.Printing/Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ namespace Spd.Manager.Printing;
public interface IPrintingManager
{
public Task<ResultResponse> Handle(StartPrintJobCommand cmd, CancellationToken ct);
public Task<ResultResponse> Handle(PrintCardsInBatchCommand cmd, CancellationToken ct);
public Task<ResultResponse> Handle(PrintJobStatusQuery cmd, CancellationToken ct);
public Task<PreviewDocumentResp> Handle(PreviewDocumentCommand request, CancellationToken ct);
public Task<PreviewDocumentResp> Handle(PrintingEventImageQuery request, CancellationToken ct);
}
public record StartPrintJobCommand(Guid EventId) : IRequest<ResultResponse>;
public record PrintCardsInBatchCommand() : IRequest<ResultResponse>;
public record PrintJobStatusQuery(Guid EventId) : IRequest<ResultResponse>;
public record PreviewDocumentCommand(Guid LicenceId) : IRequest<PreviewDocumentResp>;
public record PrintingEventImageQuery(Guid EventId) : IRequest<PreviewDocumentResp>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
using AutoMapper;
using Spd.Resource.Repository.Licence;
using Spd.Utilities.Printing.BCMailPlus;
using Spd.Utilities.Shared.Exceptions;
using System.Text.Json.Serialization;

namespace Spd.Manager.Printing.Documents.TransformationStrategies;

internal class PersonalLicencePrintingTransformStrategy(
ILicenceRepository licenceRepository,
IMapper mapper)
: BcMailPlusTransformStrategyBase<PersonalLicencePrintingTransformRequest, PersonalLicencePrinting>(Jobs.PersonalLicenseRelease)
: BcMailPlusTransformStrategyBase<PersonalLicenceBatchPrintingTransformRequest, PersonalLicencePrinting>(Jobs.PersonalLicenseRelease)
{
protected override async Task<PersonalLicencePrinting> CreateDocument(PersonalLicencePrintingTransformRequest request, CancellationToken cancellationToken)
protected override async Task<PersonalLicencePrinting> CreateDocument(PersonalLicenceBatchPrintingTransformRequest request, CancellationToken cancellationToken)
{
LicenceResp? licence = await licenceRepository.GetAsync(request.LicenceId, cancellationToken);

if (licence?.PrintingPreviewJobId == null)
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "Cannot find the preview job id");

return new PersonalLicencePrinting()
if (request.CardPrintEvents.Any())
{
Jobs = new List<string> { licence?.PrintingPreviewJobId }
};
var result = new PersonalLicencePrinting()
{
Jobs = request.CardPrintEvents.Where(p => p.PrintingPreviewJobId != null)
.Select(p => p.PrintingPreviewJobId)
.ToList(),
};
if (result.Jobs.Any()) return result;
}
return null;
}

}

public record PersonalLicencePrintingTransformRequest(Guid LicenceId) : DocumentTransformRequest;

public record PersonalLicenceBatchPrintingTransformRequest(List<CardPrintEvent> CardPrintEvents) : DocumentTransformRequest;
public record CardPrintEvent
{
public Guid EventQueueId { get; set; }
public string? PrintingPreviewJobId { get; set; }
public bool? IsSuccess { get; set; }
public string? ErrMsg { get; set; }
}
public record PersonalLicencePrinting
{
[JsonPropertyName("Jobs")]
Expand Down
136 changes: 112 additions & 24 deletions src/Spd.Manager.Printing/PrintingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Spd.Manager.Printing;

internal class PrintingManager
: IRequestHandler<StartPrintJobCommand, ResultResponse>,
IRequestHandler<PrintCardsInBatchCommand, ResultResponse>,
IRequestHandler<PrintJobStatusQuery, ResultResponse>,
IRequestHandler<PreviewDocumentCommand, PreviewDocumentResp>,
IRequestHandler<PrintingEventImageQuery, PreviewDocumentResp>,
Expand Down Expand Up @@ -81,6 +82,44 @@ public async Task<ResultResponse> Handle(StartPrintJobCommand request, Cancellat
return null;
}

public async Task<ResultResponse> Handle(PrintCardsInBatchCommand request, CancellationToken cancellationToken)
{
PersonalLicenceBatchPrintingTransformRequest transformRequest = await CreatePersonalLicenceBatchPrintingTransformRequest(cancellationToken);

if (transformRequest.CardPrintEvents.Any())
{
try
{
var transformResponse = await _documentTransformationEngine.Transform(
transformRequest,
cancellationToken);
if (transformResponse is BcMailPlusTransformResponse)
{
BcMailPlusTransformResponse transformResult = (BcMailPlusTransformResponse)transformResponse;
var printResponse = await _printer.Send(
new BCMailPlusPrintRequest(transformResult.JobTemplateId, transformResult.Document),
cancellationToken);
ResultResponse result = _mapper.Map<ResultResponse>(printResponse);
await UpdateResultInEvents(result, transformRequest.CardPrintEvents, cancellationToken);
return result;
}
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message, null);
ResultResponse result = new()
{
PrintJobId = null,
Status = JobStatusCode.Error,
Error = $"{ex.Message} {ex.InnerException?.Message}"
};
await UpdateResultInEvents(result, transformRequest.CardPrintEvents, cancellationToken);
return result;
}
}
return null;
}

public async Task<ResultResponse> Handle(PrintJobStatusQuery request, CancellationToken cancellationToken)
{
//get event
Expand Down Expand Up @@ -144,41 +183,90 @@ private static DocumentTransformRequest CreateDocumentTransformRequest(EventResp
if (eventResp.EventTypeEnum == EventTypeEnum.BCMPScreeningFingerprintPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_application"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "ApplicationId cannot be null if it is BCMPScreeningFingerprintPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPSecurityWorkerLicencePrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPSecurityWorkerLicencePrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPArmouredVehiclePermitPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPArmouredVehiclePermitPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPBodyArmourPermitPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPBodyArmourPermitPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPGuideDogServiceDogTeamPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPGuideDogServiceDogTeamPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPDogTrainerPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPDogTrainerPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPRetiredServiceDogPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPRetiredServiceDogPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPBusinessLicencePrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPBusinessLicencePrinting");

return eventResp.EventTypeEnum switch
{
EventTypeEnum.BCMPScreeningFingerprintPrinting => new FingerprintLetterTransformRequest(eventResp.RegardingObjectId.Value),
EventTypeEnum.BCMPSecurityWorkerLicencePrinting => new PersonalLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
EventTypeEnum.BCMPBodyArmourPermitPrinting => new PersonalLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
EventTypeEnum.BCMPArmouredVehiclePermitPrinting => new PersonalLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
EventTypeEnum.BCMPGuideDogServiceDogTeamPrinting => new PersonalLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
EventTypeEnum.BCMPDogTrainerPrinting => new PersonalLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
EventTypeEnum.BCMPRetiredServiceDogPrinting => new PersonalLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
EventTypeEnum.BCMPBusinessLicencePrinting => new BizLicencePrintingTransformRequest((Guid)eventResp.RegardingObjectId),
_ => throw new NotImplementedException()
};
}

private async Task<PersonalLicenceBatchPrintingTransformRequest> CreatePersonalLicenceBatchPrintingTransformRequest(CancellationToken ct)
{
IEnumerable<EventResp?> eventResps = await _eventRepo.QueryAsync(
new EventQuery()
{
EventStatusReasonEnum = EventStatusReasonEnum.Ready,
EventTypeEnums = new List<EventTypeEnum>()
{
EventTypeEnum.BCMPSecurityWorkerLicencePrinting,
EventTypeEnum.BCMPArmouredVehiclePermitPrinting,
EventTypeEnum.BCMPBodyArmourPermitPrinting,
//EventTypeEnum.BCMPRetiredServiceDogPrinting,
//EventTypeEnum.BCMPDogTrainerPrinting,
//EventTypeEnum.BCMPGuideDogServiceDogTeamPrinting
},
CutOffDateTime = DateTimeOffset.UtcNow,
}, ct);

List<CardPrintEvent> cardPrints = new List<CardPrintEvent>();
foreach (var eventResp in eventResps)
{
if (eventResp.EventTypeEnum == EventTypeEnum.BCMPSecurityWorkerLicencePrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPSecurityWorkerLicencePrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPArmouredVehiclePermitPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPArmouredVehiclePermitPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPBodyArmourPermitPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPBodyArmourPermitPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPGuideDogServiceDogTeamPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPGuideDogServiceDogTeamPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPDogTrainerPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPDogTrainerPrinting");

if (eventResp.EventTypeEnum == EventTypeEnum.BCMPRetiredServiceDogPrinting && (eventResp.RegardingObjectId == null || eventResp.RegardingObjectName != "spd_licence"))
throw new ApiException(System.Net.HttpStatusCode.BadRequest, "LicenceId cannot be null if it is BCMPRetiredServiceDogPrinting");
var licence = await _licenceRepository.GetBasicAsync((Guid)eventResp.RegardingObjectId, ct);
var cardPrint = new CardPrintEvent
{
EventQueueId = eventResp.Id,
PrintingPreviewJobId = licence?.PrintingPreviewJobId,
IsSuccess = licence?.PrintingPreviewJobId == null ? false : null,
ErrMsg = licence?.PrintingPreviewJobId == null ? "Cannot find the preview job id" : null
};
cardPrints.Add(cardPrint);
}
return new PersonalLicenceBatchPrintingTransformRequest(cardPrints);
}

private async Task UpdateResultInEvents(ResultResponse resultResponse, List<CardPrintEvent> events, CancellationToken cancellationToken)
{
//update event queues
List<EventUpdateCmd> cmds = new List<EventUpdateCmd>();
foreach (var e in events)
{
var cmd = _mapper.Map<EventUpdateCmd>(resultResponse);
if (e.IsSuccess == false) //those events has data issue, even though it is supposed to be in print batch, but as there is error, it does not go to print batch.
{
cmd.JobId = null;
cmd.ErrorDescription = e.ErrMsg;
cmd.StateCode = 1;
cmd.EventStatusReasonEnum = EventStatusReasonEnum.Fail;
}
cmd.Id = e.EventQueueId;
cmds.Add(cmd);
}

await _eventRepo.ManageInBatchAsync(cmds, cancellationToken);
return;
}

private async Task UpdateResultInEvent(ResultResponse resultResponse, Guid eventId, CancellationToken cancellationToken)
{
//update event queue
Expand Down
14 changes: 13 additions & 1 deletion src/Spd.Presentation.Dynamics/Controllers/PrintingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class PrintingController(IMediator mediator, IMapper mapper) : SpdControl
/// a GET request that takes an event id. It should be like
/// GET /api/printjobs/{eventid}
/// where eventid is the GUID for spd_eventqueue record.
/// Now, it will exe the event according to the eventype (now, only finger print), and update the event according to the response from bcMail plus.
/// Now, it will exe the event according to the eventype (now, only finger print. sbl and msdr), and update the event according to the response from bcMail plus.
/// </summary>
/// <param name="eventId"></param>
/// <param name="ct"></param>
Expand All @@ -26,6 +26,18 @@ public async Task<ResultResponse> GetPrintJob([FromRoute] Guid eventId, Cancella
return await mediator.Send(new StartPrintJobCommand(eventId), ct);
}

/// <summary>
/// a GET request that will print all cards (swl, permit) in event queue
/// Now, it will find all previous event queues which is for printing swl, permit and gdsd card printing, and create batch job, then update the events according to the response from bcMail plus.
/// </summary>
/// <param name="eventId"></param>
/// <param name="ct"></param>
/// <returns></returns>
[HttpGet("api/print-cards-in-batch")]
public async Task<ResultResponse> PrintCardsInBatch(CancellationToken ct)
{
return await mediator.Send(new PrintCardsInBatchCommand(), ct);
}
/// <summary>
/// return the preview picture of licence.
/// The bcmp job id will be returned in the http header as "bcmp-personal-licence-preview-jobid"
Expand Down
9 changes: 9 additions & 0 deletions src/Spd.Resource.Repository/Event/Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public interface IEventRepository
{
public Task<EventResp> GetAsync(Guid eventId, CancellationToken cancellationToken);
public Task<Unit> ManageAsync(EventUpdateCmd cmd, CancellationToken ct);
public Task<Unit> ManageInBatchAsync(List<EventUpdateCmd> cmd, CancellationToken ct);
public Task<IEnumerable<EventResp>> QueryAsync(EventQuery qry, CancellationToken cancellationToken);
}

public record EventResp()
Expand All @@ -28,6 +30,13 @@ public record EventUpdateCmd()
public EventStatusReasonEnum EventStatusReasonEnum { get; set; }
}

public record EventQuery()
{
public IEnumerable<EventTypeEnum> EventTypeEnums { get; set; }
public EventStatusReasonEnum EventStatusReasonEnum { get; set; }
public DateTimeOffset? CutOffDateTime { get; set; }
}

public enum EventTypeEnum
{
BCMPScreeningFingerprintPrinting,
Expand Down
50 changes: 49 additions & 1 deletion src/Spd.Resource.Repository/Event/EventRepository.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
using AutoMapper;
using MediatR;
using Microsoft.Dynamics.CRM;
using Microsoft.Extensions.Logging;
using Microsoft.OData.Client;
using Spd.Utilities.Dynamics;

namespace Spd.Resource.Repository.Event;
internal class EventRepository : IEventRepository
{
private readonly DynamicsContext _context;
private readonly IMapper _mapper;
private readonly ILogger<IEventRepository> _logger;

public EventRepository(IDynamicsContextFactory ctx,
IMapper mapper)
IMapper mapper,
ILogger<IEventRepository> logger)
{
_context = ctx.Create();
_mapper = mapper;
_logger = logger;
}

public async Task<EventResp?> GetAsync(Guid eventId, CancellationToken ct)
Expand All @@ -21,6 +27,28 @@ public EventRepository(IDynamicsContextFactory ctx,
return _mapper.Map<EventResp>(eventQueue);
}

public async Task<IEnumerable<EventResp>?> QueryAsync(EventQuery qry, CancellationToken ct)
{
IQueryable<spd_eventqueue> eventQueues = _context.spd_eventqueues;
if (qry.EventStatusReasonEnum != null)
{
int status = (int)SharedMappingFuncs.GetOptionset<EventStatusReasonEnum, EventStatusReasonOptionSet>(qry.EventStatusReasonEnum);
eventQueues = eventQueues.Where(i => i.statuscode == status);
}

if (qry.CutOffDateTime != null)
eventQueues = eventQueues.Where(e => e.spd_eventdate < qry.CutOffDateTime);

var eventQueuesList = eventQueues.ToList();
if (qry.EventTypeEnums != null && qry.EventTypeEnums.Any())
{
int[] types = qry.EventTypeEnums.Select(e => (int)SharedMappingFuncs.GetOptionset<EventTypeEnum, EventTypeOptionSet>(e)).ToArray();
eventQueuesList = eventQueuesList.Where(e => types.Any(t => t == e.spd_eventtype)).ToList();
}

return _mapper.Map<IEnumerable<EventResp>>(eventQueuesList);
}

public async Task<Unit> ManageAsync(EventUpdateCmd cmd, CancellationToken ct)
{
spd_eventqueue? eventQueue = await _context.GetEventById(cmd.Id, ct);
Expand All @@ -29,4 +57,24 @@ public async Task<Unit> ManageAsync(EventUpdateCmd cmd, CancellationToken ct)
await _context.SaveChangesAsync(ct);
return default;
}
public async Task<Unit> ManageInBatchAsync(List<EventUpdateCmd> cmds, CancellationToken ct)
{
try
{
foreach (var cmd in cmds)
{
spd_eventqueue? eventQueue = await _context.spd_eventqueues
.Where(l => l.spd_eventqueueid == cmd.Id)
.FirstOrDefaultAsync(ct);
_mapper.Map<EventUpdateCmd, spd_eventqueue>(cmd, eventQueue);
_context.UpdateObject(eventQueue);
}
await _context.SaveChangesAsync(SaveChangesOptions.BatchWithSingleChangeset, ct);
}
catch (Exception e)
{
_logger.LogError(e.ToString());
}
return default;
}
}
Loading