예제 #1
0
        public async Task Handle(DomainEventNotification <ObservationAddedEvent> notification, CancellationToken token)
        {
            var @event      = notification.DomainEvent;
            var observation = await _context.Observations.SingleAsync(e => e.Id == @event.ObservationId, token);

            if (observation.User.Kind == ProfileKind.Producer)
            {
                return;
            }

            var observationId = _idSerializer.Serialize("Query", nameof(Observation), observation.Id);
            var producerId    = _idSerializer.Serialize("Query", nameof(Producer), observation.ProducerId);

            var url = $"{_configuration.GetValue<string>("Portal:url")}/#/traceability/?observationId={observationId}&refresh={Guid.NewGuid():N}";

            await _signalrService.SendNotificationToUserAsync(observation.ProducerId, nameof(ObservationAddedEvent),
                                                              observation.GetNotificationContent(observationId, url, producerId));

            await _emailService.SendTemplatedEmailAsync(
                observation.Producer.Email,
                observation.Producer.Name,
                $"{observation.User.Name} a ajouté une observation concernant un de vos produits ou lot.",
                nameof(ObservationAddedEvent),
                observation.GetNotificationData(observationId, url, observation.Comment, producerId),
                true,
                token);
        }
예제 #2
0
        private static void AddSerializerToObjectField(
            ITypeCompletionContext completionContext,
            ObjectFieldDefinition definition,
            FieldMiddleware placeholder,
            NameString typeName)
        {
            ITypeInspector typeInspector = completionContext.TypeInspector;
            IExtendedType? resultType;

            if (definition.ResultType is not null)
            {
                resultType = typeInspector.GetType(definition.ResultType);
            }
            else if (definition.Type is ExtendedTypeReference typeReference)
            {
                resultType = typeReference.Type;
            }
            else
            {
                throw new SchemaException(SchemaErrorBuilder.New()
                                          .SetMessage("Unable to resolve type from field `{0}`.", definition.Name)
                                          .SetTypeSystemObject(completionContext.Type)
                                          .Build());
            }

            NameString schemaName = default;

            completionContext.DescriptorContext.SchemaCompleted += (sender, args) =>
                                                                   schemaName = args.Schema.Name;

            IIdSerializer serializer =
                completionContext.Services.GetService <IIdSerializer>() ??
                new IdSerializer();
            var index = definition.MiddlewareComponents.IndexOf(placeholder);

            definition.MiddlewareComponents[index] = next => async context =>
            {
                await next(context).ConfigureAwait(false);

                if (context.Result is not null)
                {
                    if (resultType.IsArrayOrList)
                    {
                        var list = new List <object?>();
                        foreach (object?element in (IEnumerable)context.Result)
                        {
                            list.Add(element is null
                                ? element
                                : serializer.Serialize(schemaName, typeName, element));
                        }
                        context.Result = list;
                    }
                    else
                    {
                        context.Result = serializer.Serialize(schemaName, typeName, context.Result);
                    }
                }
            };
        }
예제 #3
0
        public async Task Handle(DomainEventNotification <ObservationRepliedEvent> notification, CancellationToken token)
        {
            var @event      = notification.DomainEvent;
            var observation = await _context.Set <Domain.Observation>().SingleAsync(e => e.Id == @event.ObservationId, token);

            var reply = await _context.Set <Domain.Observation>().SingleAsync(e => e.Id == @event.ReplyId, token);

            if (reply.User.Kind == ProfileKind.Producer && observation.User.Kind == ProfileKind.Producer)
            {
                return;
            }

            var targets = new List <Tuple <Guid, string, string> >();

            if (reply.User.Kind != ProfileKind.Producer)
            {
                targets.Add(new Tuple <Guid, string, string>(observation.Producer.Id, observation.Producer.Name, observation.Producer.Email));
            }
            else
            {
                targets.Add(new Tuple <Guid, string, string>(observation.User.Id, observation.User.Name, observation.User.Email));
                targets.AddRange(observation.Replies.Where(r => r.UserId != observation.ProducerId).Select(r =>
                                                                                                           new Tuple <Guid, string, string>(r.User.Id, r.User.Name, r.User.Email)));

                targets = targets.Distinct().ToList();
            }

            foreach (var target in targets)
            {
                var observationId = _idSerializer.Serialize("Query", nameof(Observation), observation.Id);
                var producerId    = _idSerializer.Serialize("Query", nameof(Producer), observation.ProducerId);

                var url = reply.User.Kind == ProfileKind.Producer
                    ? $"{_configuration.GetValue<string>("Portal:url")}/#/store-traceability/?observationId={observationId}&producerId={producerId}&refresh={Guid.NewGuid():N}"
                    : $"{_configuration.GetValue<string>("Portal:url")}/#/traceability/?observationId={observationId}&refresh={Guid.NewGuid():N}";

                await _signalrService.SendNotificationToUserAsync(target.Item1, nameof(ObservationRepliedEvent), reply.GetNotificationContent(observationId, url, producerId));

                await _emailService.SendTemplatedEmailAsync(
                    target.Item3,
                    target.Item2,
                    $"{reply.User.Name} a répondu à votre remarque",
                    nameof(ObservationRepliedEvent),
                    reply.GetNotificationData(observationId, url, reply.Comment, producerId),
                    true,
                    token);
            }
        }
예제 #4
0
        private async Task NotifyProducerAsync(DomainEventNotification <PurchaseOrderCreatedEvent> notification,
                                               CancellationToken token)
        {
            var orderEvent    = notification.DomainEvent;
            var purchaseOrder =
                await _context.PurchaseOrders.SingleAsync(e => e.Id == orderEvent.PurchaseOrderId, token);

            if (!purchaseOrder.OrderId.HasValue)
            {
                return;
            }

            var purchaseOrderIdentifier = _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrder.Id);
            await _signalrService.SendNotificationToUserAsync(purchaseOrder.ProducerId, "PurchaseOrderReceivedEvent",
                                                              purchaseOrder.GetPurchaseNotifModelAsString(purchaseOrderIdentifier));

            await _emailService.SendTemplatedEmailAsync(
                purchaseOrder.VendorInfo.Email,
                purchaseOrder.VendorInfo.Name,
                $"{purchaseOrder.SenderInfo.Name} a envoyé une commande pour le {purchaseOrder.ExpectedDelivery.ExpectedDeliveryDate:dd/MM/yyyy}",
                "PurchaseOrderReceivedEvent",
                purchaseOrder.GetTemplateData(purchaseOrderIdentifier,
                                              $"{_configuration.GetValue<string>("Portal:url")}/#/purchase-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}"),
                true,
                token);
        }
예제 #5
0
        public async Task Handle(DomainEventNotification <PurchaseOrderWithdrawnedEvent> notification,
                                 CancellationToken token)
        {
            var orderEvent    = notification.DomainEvent;
            var purchaseOrder =
                await _context.PurchaseOrders.SingleAsync(e => e.Id == orderEvent.PurchaseOrderId, token);

            var purchaseOrderIdentifier = _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrder.Id);
            await _signalrService.SendNotificationToUserAsync(purchaseOrder.ProducerId,
                                                              nameof(PurchaseOrderWithdrawnedEvent), purchaseOrder.GetPurchaseNotifModelAsString(purchaseOrderIdentifier));

            await _emailService.SendTemplatedEmailAsync(
                purchaseOrder.SenderInfo.Email,
                purchaseOrder.SenderInfo.Name,
                $"Votre commande pour {purchaseOrder.VendorInfo.Name} prévue pour le {purchaseOrder.ExpectedDelivery.ExpectedDeliveryDate:dd/MM/yyyy} a bien été annulée",
                nameof(PurchaseOrderWithdrawnedEvent),
                purchaseOrder.GetTemplateData(purchaseOrderIdentifier,
                                              $"{_configuration.GetValue<string>("Portal:url")}/#/my-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}"),
                true,
                token);

            await _emailService.SendTemplatedEmailAsync(
                purchaseOrder.VendorInfo.Email,
                purchaseOrder.VendorInfo.Name,
                $"{purchaseOrder.SenderInfo.Name} a annulé sa commande pour le {purchaseOrder.ExpectedDelivery.ExpectedDeliveryDate:dd/MM/yyyy}",
                nameof(PurchaseOrderWithdrawnedEvent),
                purchaseOrder.GetTemplateData(purchaseOrderIdentifier,
                                              $"{_configuration.GetValue<string>("Portal:url")}/#/purchase-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}"),
                true,
                token);
        }
        private async Task NotifyConsumerAsync(Domain.PurchaseOrder purchaseOrder, CancellationToken token)
        {
            var purchaseOrderIdentifier = _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrder.Id);
            await _signalrService.SendNotificationToUserAsync(purchaseOrder.ClientId,
                                                              nameof(PurchaseOrderExpiredEvent),
                                                              purchaseOrder.GetPurchaseNotifModelAsString(purchaseOrderIdentifier));

            await _emailService.SendTemplatedEmailAsync(
                purchaseOrder.SenderInfo.Email,
                purchaseOrder.SenderInfo.Name,
                $"Votre commande a expirée",
                nameof(PurchaseOrderExpiredEvent),
                purchaseOrder.GetTemplateData(purchaseOrderIdentifier,
                                              $"{_configuration.GetValue<string>("Portal:url")}/#/my-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}"),
                true,
                token);
        }
예제 #7
0
        public async Task InvokeAsync(IMiddlewareContext context)
        {
            await _next(context).ConfigureAwait(false);

            context.Result = _serializer.Serialize(
                context.Schema.Name,
                context.ObjectType.Name,
                context.Result);
        }
예제 #8
0
 internal StoreListItem(Domain.Store user, IIdSerializer serializer)
 {
     Address      = new AddressItem(user.Address);
     Id           = serializer.Serialize("Query", nameof(Store), user.Id);
     Name         = user.Name;
     Picture      = user.Picture;
     HasProducers = user.ProducersCount > 0;
     Producers    = user.ProducersCount;
 }
예제 #9
0
        public async Task Handle(DomainEventNotification <PickingOrderExportProcessingEvent> notification,
                                 CancellationToken token)
        {
            var pickingOrderEvent = notification.DomainEvent;
            var job = await _context.Jobs.SingleAsync(e => e.Id == pickingOrderEvent.JobId, token);

            var jobIdentifier = _idSerializer.Serialize("Query", nameof(Job), job.Id);
            await _signalrService.SendNotificationToUserAsync(job.UserId, nameof(PickingOrderExportProcessingEvent),
                                                              new { JobId = jobIdentifier, Name = job.Name, UserId = job.UserId });
        }
예제 #10
0
        public async Task Handle(DomainEventNotification <RecallSentEvent> notification, CancellationToken token)
        {
            var @event = notification.DomainEvent;
            var recall = await _context.Recalls.SingleAsync(e => e.Id == @event.RecallId, token);

            var clientRecall = await _context.Set <RecallClient>()
                               .SingleAsync(c => c.ClientId == @event.ClientId && c.RecallId == @event.RecallId, token);

            if (clientRecall.RecallSent)
            {
                return;
            }

            await _signalrService.SendNotificationToUserAsync(clientRecall.Client.Id, nameof(RecallSentEvent),
                                                              recall.GetNotificationContent(
                                                                  _idSerializer.Serialize("Query", nameof(Domain.Recall), recall.Id),
                                                                  _configuration.GetValue <string>("Portal:url"),
                                                                  recall.Producer.Name));

            try
            {
                await _emailService.SendTemplatedEmailAsync(
                    clientRecall.Client.Email,
                    clientRecall.Client.Name,
                    $"{recall.Producer.Name} procède au rappel de certains produits.",
                    nameof(RecallSentEvent),
                    recall.GetNotificationData(
                        _idSerializer.Serialize("Query", nameof(Domain.Recall), recall.Id),
                        _configuration.GetValue <string>("Portal:url"),
                        recall.Comment,
                        clientRecall.Client.FirstName),
                    true,
                    token);

                clientRecall.SetRecallAsSent();
                await _context.SaveChangesAsync(token);
            }
            catch (Exception e)
            {
                clientRecall.SetRecallAsSent(false);
                await _context.SaveChangesAsync(token);
            }
        }
예제 #11
0
        public async Task Handle(DomainEventNotification <PurchaseOrderProcessingEvent> notification,
                                 CancellationToken token)
        {
            var orderEvent    = notification.DomainEvent;
            var purchaseOrder =
                await _context.PurchaseOrders.SingleAsync(e => e.Id == orderEvent.PurchaseOrderId, token);

            var purchaseOrderIdentifier = _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrder.Id);
            await _signalrService.SendNotificationToUserAsync(purchaseOrder.ClientId,
                                                              nameof(PurchaseOrderProcessingEvent), purchaseOrder.GetPurchaseNotifModelAsString(purchaseOrderIdentifier));
        }
예제 #12
0
        public async Task InvokeAsync(IMiddlewareContext context)
        {
            await _next(context).ConfigureAwait(false);

            if (context.Result != null &&
                context.Field.Type.NamedType() is IdType &&
                context.Field.Name.Equals(_idFieldName))
            {
                context.Result = _serializer.Serialize(
                    context.ObjectType.Name,
                    context.Result);
            }
        }
예제 #13
0
        public async Task Handle(DomainEventNotification <OrderConfirmedEvent> notification, CancellationToken token)
        {
            var orderEvent = notification.DomainEvent;
            var order      = await _context.Orders.SingleAsync(e => e.Id == orderEvent.OrderId, token);

            var purchaseOrderId         = order.PurchaseOrders.Count() == 1 ? order.PurchaseOrders.FirstOrDefault()?.Id : (Guid?)null;
            var purchaseOrderIdentifier = purchaseOrderId.HasValue ? _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrderId): string.Empty;
            await _signalrService.SendNotificationToUserAsync(order.UserId.Value, nameof(OrderConfirmedEvent),
                                                              new
            {
                PurchaseOrderId = order.GetOrderNotifModelAsString(purchaseOrderIdentifier),
                PortalUrl       = $"{_configuration.GetValue<string>("Portal:url")}/#/my-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}",
            });

            await _emailService.SendTemplatedEmailAsync(
                order.User.Email,
                order.User.Name,
                $"Votre commande de {order.TotalPrice}€ a été prise en compte",
                nameof(OrderConfirmedEvent),
                order.GetTemplateData(_idSerializer.Serialize("Query", nameof(Order), orderEvent.OrderId),
                                      $"{_configuration.GetValue<string>("Portal:url")}/#/my-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}"),
                true,
                token);
        }
        public async Task Handle(DomainEventNotification <DeliveryBatchPendingEvent> notification,
                                 CancellationToken token)
        {
            var @event        = notification.DomainEvent;
            var deliveryBatch = await _context.DeliveryBatches.SingleAsync(d => d.Id == @event.DeliveryBatchId, token);

            if (deliveryBatch.Status is DeliveryBatchStatus.Completed or DeliveryBatchStatus.Cancelled or
                DeliveryBatchStatus.Partial)
            {
                return;
            }

            var deliveryBatchIdentifier =
                _idSerializer.Serialize("Query", nameof(Domain.DeliveryBatch), deliveryBatch.Id);

            await _signalrService.SendNotificationToUserAsync(deliveryBatch.AssignedToId,
                                                              nameof(DeliveryBatchPendingEvent),
                                                              new
            {
                Id           = deliveryBatchIdentifier,
                Firstname    = deliveryBatch.AssignedTo.FirstName,
                ScheduledOn  = deliveryBatch.ScheduledOn,
                ProducerName = deliveryBatch.AssignedTo.Name,
                Name         = deliveryBatch.Name,
                Url          =
                    $"{_configuration.GetValue<string>("Portal:url")}/#/delivery-batches/{deliveryBatchIdentifier}?refresh={Guid.NewGuid():N}"
            });

            await _emailService.SendTemplatedEmailAsync(
                deliveryBatch.AssignedTo.Email,
                deliveryBatch.AssignedTo.Name,
                $"Votre livraison {deliveryBatch.Name} du {deliveryBatch.ScheduledOn.ToString("dd/MM/yyyy")} est toujours en attente",
                nameof(DeliveryBatchPendingEvent),
                new DeliveryBatchMailerModel
            {
                Id           = deliveryBatchIdentifier,
                Firstname    = deliveryBatch.AssignedTo.FirstName,
                ScheduledOn  = deliveryBatch.ScheduledOn,
                ProducerName = deliveryBatch.AssignedTo.Name,
                Name         = deliveryBatch.Name,
                Url          =
                    $"{_configuration.GetValue<string>("Portal:url")}/#/delivery-batches/{deliveryBatchIdentifier}?refresh={Guid.NewGuid():N}"
            },
                true,
                token);
        }
        public async Task Handle(DomainEventNotification <PickingOrderExportFailedEvent> notification, CancellationToken token)
        {
            var pickingOrderEvent = notification.DomainEvent;
            var job = await _context.Jobs.SingleAsync(e => e.Id == pickingOrderEvent.JobId, token);

            var jobIdentifier = _idSerializer.Serialize("Query", nameof(Job), job.Id);
            await _signalrService.SendNotificationToUserAsync(job.User.Id, nameof(PickingOrderExportFailedEvent), new { JobId = jobIdentifier, Name = job.Name, UserId = job.User.Id });

            var url = $"{_configuration.GetValue<string>("Portal:url")}/#/jobs/{jobIdentifier}?refresh={Guid.NewGuid():N}";
            await _emailService.SendTemplatedEmailAsync(
                job.User.Email,
                job.User.Name,
                $"La création de votre bon de préparation a échouée",
                nameof(PickingOrderExportFailedEvent),
                new PickingOrderExportMailerModel { JobId = jobIdentifier, UserName = job.User.Name, Name = job.Name, CreatedOn = job.CreatedOn, JobUrl = url },
                true,
                token);
        }
예제 #16
0
        public async Task Handle(DomainEventNotification <UserDataExportFailedEvent> notification, CancellationToken token)
        {
            var userEvent = notification.DomainEvent;
            var job       = await _context.Jobs.SingleAsync(e => e.Id == userEvent.JobId, token);

            var jobIdentifier = _idSerializer.Serialize("Query", nameof(Job), job.Id);

            await _signalrService.SendNotificationToUserAsync(job.User.Id, nameof(UserDataExportFailedEvent), new { JobId = jobIdentifier, UserId = job.UserId });

            var url = $"{_configuration.GetValue<string>("Portal:url")}/#/jobs/{jobIdentifier}";
            await _emailService.SendTemplatedEmailAsync(
                job.User.Email,
                job.User.Name,
                $"Votre export de données a échoué",
                nameof(UserDataExportFailedEvent),
                new RgpdExportMailerModel { JobId = jobIdentifier, UserName = job.User.Name, Name = job.Name, CreatedOn = job.CreatedOn, PortalUrl = url },
                true,
                token);
        }
예제 #17
0
        public async Task Handle(DomainEventNotification <ProductImportSucceededEvent> notification, CancellationToken token)
        {
            var productEvent = notification.DomainEvent;
            var job          = await _context.Jobs.SingleAsync(e => e.Id == productEvent.JobId, token);

            await _signalrService.SendNotificationToUserAsync(job.UserId, nameof(ProductImportSucceededEvent), new { JobId = job.Id, UserId = job.UserId });

            var jobIdentifier = _idSerializer.Serialize("Query", nameof(Job), job.Id);
            var url           = $"{_configuration.GetValue<string>("Portal:url")}/#/jobs/{jobIdentifier}?refresh={Guid.NewGuid():N}";

            await _emailService.SendTemplatedEmailAsync(
                job.User.Email,
                job.User.Name,
                $"Votre catalogue produit a bien été importé",
                nameof(ProductImportSucceededEvent),
                new ProductImportMailerModel { JobId = jobIdentifier, UserName = job.User.Name, Name = job.Name, CreatedOn = job.CreatedOn, PortalUrl = url },
                true,
                token);
        }
예제 #18
0
        public async Task Handle(DomainEventNotification <OrderValidatedEvent> notification, CancellationToken token)
        {
            var orderEvent = notification.DomainEvent;
            var order      = await _context.Orders.SingleAsync(e => e.Id == orderEvent.OrderId, token);

            if (!order.UserId.HasValue)
            {
                return;
            }

            var purchaseOrderId         = order.PurchaseOrders.Count() == 1 ? order.PurchaseOrders.FirstOrDefault()?.Id : (Guid?)null;
            var purchaseOrderIdentifier = purchaseOrderId.HasValue ? _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrderId): string.Empty;
            await _signalrService.SendNotificationToUserAsync(order.UserId.Value, nameof(OrderValidatedEvent),
                                                              new
            {
                PurchaseOrderId = order.GetOrderNotifModelAsString(purchaseOrderIdentifier),
                PortalUrl       = $"{_configuration.GetValue<string>("Portal:url")}/#/my-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}",
            });
        }
        public async Task Handle(DomainEventNotification <TransactionsExportSucceededEvent> notification,
                                 CancellationToken token)
        {
            var pickingOrderEvent = notification.DomainEvent;
            var job = await _context.Jobs.SingleAsync(e => e.Id == pickingOrderEvent.JobId, token);

            var jobIdentifier = _idSerializer.Serialize("Query", nameof(Job), job.Id);
            await _signalrService.SendNotificationToUserAsync(job.UserId, nameof(TransactionsExportSucceededEvent),
                                                              new { JobId = jobIdentifier, Name = job.Name, UserId = job.UserId, Url = job.File });

            await _emailService.SendTemplatedEmailAsync(
                job.User.Email,
                job.User.Name,
                $"Votre export de virements est prêt",
                nameof(TransactionsExportSucceededEvent),
                new TransactionsExportMailerModel
                { UserName = job.User.Name, Name = job.Name, CreatedOn = job.CreatedOn, DownloadUrl = job.File },
                true,
                token);
        }
예제 #20
0
        public async Task Handle(DomainEventNotification <AgreementAcceptedEvent> notification, CancellationToken token)
        {
            var agreementEvent = notification.DomainEvent;
            var agreement      = await _context.Agreements.SingleAsync(e => e.Id == agreementEvent.AgreementId, token);

            var email      = string.Empty;
            var name       = string.Empty;
            var targetName = string.Empty;
            var id         = Guid.Empty;

            var subEventName = string.Empty;

            if (agreementEvent.RequestedByKind == ProfileKind.Producer)
            {
                email        = agreement.Store.Email;
                name         = agreement.Store.Name;
                targetName   = agreement.Producer.Name;
                id           = agreement.Store.Id;
                subEventName = "ByProducer";
            }
            else
            {
                email        = agreement.Producer.Email;
                name         = agreement.Producer.Name;
                targetName   = agreement.Store.Name;
                id           = agreement.Producer.Id;
                subEventName = "ByStore";
            }

            var eventName = nameof(AgreementAcceptedEvent).Replace("Event", $"{subEventName}Event");
            await _signalrService.SendNotificationToUserAsync(id, eventName, agreement.GetNotificationContent(_idSerializer.Serialize("Query", nameof(Agreement), agreement.Id), _configuration.GetValue <string>("Portal:url"), targetName));

            await _emailService.SendTemplatedEmailAsync(
                email,
                name,
                $"{targetName} a accepté votre partenariat",
                nameof(AgreementAcceptedEvent),
                agreement.GetNotificationData(_idSerializer.Serialize("Query", nameof(Agreement), agreement.Id), _configuration.GetValue <string>("Portal:url"), targetName),
                true,
                token);
        }
        public async Task Handle(DomainEventNotification <PurchaseOrderCompletedEvent> notification,
                                 CancellationToken token)
        {
            var orderEvent    = notification.DomainEvent;
            var purchaseOrder =
                await _context.PurchaseOrders.SingleAsync(e => e.Id == orderEvent.PurchaseOrderId, token);

            var purchaseOrderIdentifier = _idSerializer.Serialize("Query", nameof(PurchaseOrder), purchaseOrder.Id);
            await _signalrService.SendNotificationToUserAsync(purchaseOrder.ClientId,
                                                              nameof(PurchaseOrderCompletedEvent), purchaseOrder.GetPurchaseNotifModelAsString(purchaseOrderIdentifier));

            await _emailService.SendTemplatedEmailAsync(
                purchaseOrder.SenderInfo.Email,
                purchaseOrder.SenderInfo.Name,
                $"Votre commande pour {purchaseOrder.VendorInfo.Name} est prête !",
                nameof(PurchaseOrderCompletedEvent),
                purchaseOrder.GetTemplateData(purchaseOrderIdentifier,
                                              $"{_configuration.GetValue<string>("Portal:url")}/#/my-orders/{purchaseOrderIdentifier}?refresh={Guid.NewGuid():N}"),
                true,
                token);
        }
        public async Task Handle(DomainEventNotification <DeliveryBatchPostponedEvent> notification, CancellationToken token)
        {
            var @event        = notification.DomainEvent;
            var deliveryBatch = await _context.DeliveryBatches.SingleAsync(d => d.Id == @event.DeliveryBatchId, token);

            if (deliveryBatch.Status != DeliveryBatchStatus.Ready && deliveryBatch.Status != DeliveryBatchStatus.Waiting)
            {
                return;
            }

            var deliveries = deliveryBatch.Deliveries
                             .Where(d => d.Status != DeliveryStatus.Delivered && d.Status != DeliveryStatus.Rejected)
                             .ToList();

            var clientIds = deliveries.Select(d => d.ClientId);
            var clients   = await _context.Users
                            .Where(u => clientIds.Contains(u.Id))
                            .ToListAsync(token);

            foreach (var delivery in deliveries)
            {
                var client = clients.Single(c => c.Id == delivery.ClientId);
                await _signalrService.SendNotificationToUserAsync(client.Id, nameof(DeliveryPostponedEvent),
                                                                  new {
                    Firstname    = client.FirstName,
                    ScheduledOn  = deliveryBatch.ScheduledOn,
                    ProducerName = deliveryBatch.AssignedTo.Name,
                    Url          = $"{_configuration.GetValue<string>("Portal:url")}/#/expected-deliveries/{_idSerializer.Serialize("Query", nameof(Delivery), delivery.Id)}?refresh={Guid.NewGuid():N}"
                });

                await _emailService.SendTemplatedEmailAsync(
                    client.Email,
                    client.Name,
                    $"{deliveryBatch.AssignedTo.Name} a décalé sa livraison au {deliveryBatch.ScheduledOn.ToString("dd/MM/yyyy")}",
                    nameof(DeliveryPostponedEvent),
                    new DeliveryMailerModel
                {
                    Firstname    = client.FirstName,
                    ScheduledOn  = deliveryBatch.ScheduledOn,
                    ProducerName = deliveryBatch.AssignedTo.Name,
                    Url          = $"{_configuration.GetValue<string>("Portal:url")}/#/expected-deliveries/{_idSerializer.Serialize("Query", nameof(Delivery), delivery.Id)}?refresh={Guid.NewGuid():N}"
                },
                    true,
                    token);
            }
        }
        private static void AddSerializerToObjectField(
            ITypeCompletionContext completionContext,
            ObjectFieldDefinition definition,
            ResultConverterDefinition placeholder,
            NameString typeName)
        {
            ITypeInspector typeInspector = completionContext.TypeInspector;
            IExtendedType? resultType;

            if (definition.ResultType is not null)
            {
                resultType = typeInspector.GetType(definition.ResultType);
            }
            else if (definition.Type is ExtendedTypeReference typeReference)
            {
                resultType = typeReference.Type;
            }
            else
            {
                throw new SchemaException(SchemaErrorBuilder.New()
                                          .SetMessage("Unable to resolve type from field `{0}`.", definition.Name)
                                          .SetTypeSystemObject(completionContext.Type)
                                          .Build());
            }

            NameString schemaName = default;

            completionContext.DescriptorContext.SchemaCompleted += (_, args) =>
                                                                   schemaName = args.Schema.Name;

            IIdSerializer serializer =
                completionContext.Services.GetService <IIdSerializer>() ??
                new IdSerializer();
            var index = definition.ResultConverters.IndexOf(placeholder);

            if (typeName.IsEmpty)
            {
                typeName = completionContext.Type.Name;
            }

            definition.ResultConverters[index] = new((_, result) =>
            {
                if (result is not null)
                {
                    if (resultType.IsArrayOrList)
                    {
                        var list = new List <object?>();

                        foreach (var element in (IEnumerable)result)
                        {
                            list.Add(element is null
                                ? element
                                : serializer.Serialize(schemaName, typeName, element));
                        }

                        return(list);
                    }

                    return(serializer.Serialize(schemaName, typeName, result));
                }

                return(result);
            }, key : WellKnownMiddleware.GlobalId, isRepeatable : false);
        }