Beispiel #1
0
        private async Task SendCheckoutConfirmationMail(BookingDataModel booking)
        {
            TemplateDataModel template = await TemplateProvider.GetTemplateByName("slutafregningskvittering");

            string mailText = TemplateProvider.MergeText(template.Text, booking);

            MailAddress to      = new MailAddress(booking.ContactEMail, booking.ContactName);
            MailMessage message = new MailMessage
            {
                To       = to,
                Subject  = template.Subject,
                HtmlBody = mailText
            };

            await MailDispatchService.DispatchAsync(message);

            byte[] mailBody           = System.Text.Encoding.UTF8.GetBytes(message.HtmlBody);
            var    addDcoumentCommand = new AddDocumentCommand
            {
                Title    = message.Subject,
                MimeType = "text/html",
                Body     = mailBody
            };

            await CommandExecutor.ExecuteAsync(addDcoumentCommand);

            booking.AddDocument(message.Subject, addDcoumentCommand.OutputDocumentId);
        }
Beispiel #2
0
        public async Task ExecuteAsync(AnonymizeBookingsCommand command, IExecutionContext executionContext)
        {
            PermissionValidationService.EnforceCustomEntityPermission <CustomEntityDeletePermission>(BookingCustomEntityDefinition.DefinitionCode, executionContext.UserContext);

            var query = new SearchBookingSummariesQuery
            {
                BookingState = new BookingDataModel.BookingStateType[] { BookingDataModel.BookingStateType.Closed },
                Start        = new DateTime(2000, 1, 1),
                End          = DateTime.Now.AddYears(-3)
            };

            command.AnonymizedCount = 0;

            foreach (KeyValuePair <int, BookingDataModel> bookingEntry in (await BookingProvider.FindBookingDataInInterval(query)).ToList())
            {
                BookingDataModel booking = bookingEntry.Value;

                // Protected agains mistakes in the query by checking values again
                if (!booking.IsArchived &&
                    booking.BookingState == BookingDataModel.BookingStateType.Closed &&
                    booking.DepartureDate.Value.AddYears(3) < DateTime.Now)
                {
                    booking.TenantName     = "---";
                    booking.Purpose        = "---";
                    booking.ContactName    = "---";
                    booking.ContactEMail   = "ukendt@ukendte-mailmodtagere";
                    booking.ContactPhone   = "---";
                    booking.ContactAddress = "---";
                    booking.ContactCity    = "---";
                    booking.Comments       = "---";

                    foreach (var document in booking.Documents)
                    {
                        var deleteDocumentCommand = new DeleteDocumentCommand {
                            Id = document.DocumentId
                        };
                        await CommandExecutor.ExecuteAsync(deleteDocumentCommand);
                    }

                    booking.LogEntries.Clear();
                    booking.Documents.Clear();

                    booking.IsArchived = true;
                    command.AnonymizedCount++;

                    UpdateCustomEntityDraftVersionCommand updateCmd = new UpdateCustomEntityDraftVersionCommand
                    {
                        CustomEntityDefinitionCode = BookingCustomEntityDefinition.DefinitionCode,
                        CustomEntityId             = bookingEntry.Key,
                        Title   = booking.MakeTitle(),
                        Publish = true,
                        Model   = booking
                    };

                    await DomainRepository.CustomEntities().Versions().UpdateDraftAsync(updateCmd);
                }
            }
        }
Beispiel #3
0
        public async Task ExecuteAsync(BookingRequestCommand command, IExecutionContext executionContext)
        {
            using (var scope = DomainRepository.Transactions().CreateScope())
            {
                var tenantCategory = await TenantCategoryProvider.GetTenantCategoryById(command.TenantCategoryId.Value);

                DateTime lastAllowedArrivalDate = DateTime.Now.AddMonths(tenantCategory.AllowedBookingFutureMonths);
                if (command.ArrivalDate.Value >= lastAllowedArrivalDate || command.DepartureDate.Value >= lastAllowedArrivalDate)
                {
                    throw new ValidationErrorException(new ValidationError($"Den valgte lejertype kan ikke reservere mere end {tenantCategory.AllowedBookingFutureMonths} måneder ud i fremtiden. Dvs. senest {lastAllowedArrivalDate.ToShortDateString()}.", nameof(command.ArrivalDate)));
                }

                int bookingNumber = await SequenceNumberGenerator.NextNumber("BookingNumber");

                var booking = new BookingDataModel
                {
                    BookingNumber        = bookingNumber,
                    ArrivalDate          = command.ArrivalDate.Value,
                    DepartureDate        = command.DepartureDate.Value,
                    OnlySelectedWeekdays = command.OnlySelectedWeekdays,
                    SelectedWeekdays     = command.SelectedWeekdays,
                    TenantCategoryId     = command.TenantCategoryId.Value,
                    TenantName           = command.TenantName,
                    Purpose        = command.Purpose,
                    ContactName    = command.ContactName,
                    ContactPhone   = command.ContactPhone,
                    ContactAddress = command.ContactAddress,
                    ContactCity    = command.ContactCity,
                    ContactEMail   = command.ContactEMail,
                    Comments       = command.Comments,
                    RentalPrice    = null, // To be set later
                    Deposit        = BookingSettings.StandardDeposit,
                    BookingState   = BookingDataModel.BookingStateType.Requested
                };

                await booking.AddLogEntry(CurrentUserProvider, "Reservationen blev indsendt af lejer.");

                await SendConfirmationMail(booking);
                await SendNotificationMail(booking);

                var addCommand = new AddCustomEntityCommand
                {
                    CustomEntityDefinitionCode = BookingCustomEntityDefinition.DefinitionCode,
                    Model   = booking,
                    Title   = booking.MakeTitle(),
                    Publish = true,
                };

                await DomainRepository.WithElevatedPermissions().CustomEntities().AddAsync(addCommand);

                await scope.CompleteAsync();
            }
        }
Beispiel #4
0
        public async Task ExecuteAsync(CheckoutBookingCommand command, IExecutionContext executionContext)
        {
            using (var scope = DomainRepository.Transactions().CreateScope())
            {
                BookingDataModel booking = await BookingProvider.GetBookingById(command.Id);

                if (command.Token != booking.TenantSelfServiceToken)
                {
                    throw new AuthenticationFailedException("Ugyldigt eller manglende adgangsnøgle");
                }

                if (booking.BookingState == BookingDataModel.BookingStateType.Requested)
                {
                    throw new ValidationErrorException("Det er ikke muligt at indberette slutafregning, da reservationen endnu ikke er godkendt.");
                }
                else if (booking.BookingState == BookingDataModel.BookingStateType.Closed)
                {
                    throw new ValidationErrorException("Det er ikke muligt at indberette slutafregning, da reservationen allerede er afsluttet.");
                }

                booking.IsCheckedOut            = true;
                booking.ElectricityReadingStart = command.StartReading;
                booking.ElectricityReadingEnd   = command.EndReading;
                booking.ElectricityPriceUnit    = BookingSettings.ElectricityPrice;

                if (!string.IsNullOrEmpty(command.Comments))
                {
                    booking.Comments += $"\n\n=== Kommentarer til slutregnskab [{DateTime.Now}] ===\n{command.Comments}";
                }

                await booking.AddLogEntry(CurrentUserProvider, "Elforbrug blev indmeldt af lejer.");

                // Do not use BookingSummary for mails as it will be the old version of the booking, from before readings were updated.
                // Also make sure mails are sent before updating the entity, as sent mail will be refered by the model.
                await SendCheckoutConfirmationMail(booking);
                await SendAdminNotificationMail(booking);

                UpdateCustomEntityDraftVersionCommand updateCmd = new UpdateCustomEntityDraftVersionCommand
                {
                    CustomEntityDefinitionCode = BookingCustomEntityDefinition.DefinitionCode,
                    CustomEntityId             = command.Id,
                    Title   = booking.MakeTitle(),
                    Publish = true,
                    Model   = booking
                };

                await DomainRepository.WithElevatedPermissions().CustomEntities().Versions().UpdateDraftAsync(updateCmd);

                await scope.CompleteAsync();
            }
        }
Beispiel #5
0
        public async Task ExecuteAsync(UpdateBookingCommand command, IExecutionContext executionContext)
        {
            PermissionValidationService.EnforceCustomEntityPermission <CustomEntityUpdatePermission>(BookingCustomEntityDefinition.DefinitionCode, executionContext.UserContext);

            using (var scope = DomainRepository.Transactions().CreateScope())
            {
                // Verify teneant category
                await TenantCategoryProvider.GetTenantCategoryById(command.TenantCategoryId.Value);

                BookingDataModel booking = await BookingProvider.GetBookingById(command.BookingId);

                booking.ArrivalDate          = command.ArrivalDate.Value;
                booking.DepartureDate        = command.DepartureDate.Value;
                booking.OnlySelectedWeekdays = command.OnlySelectedWeekdays;
                booking.SelectedWeekdays     = command.SelectedWeekdays;
                booking.TenantCategoryId     = command.TenantCategoryId;
                booking.TenantName           = command.TenantName;
                booking.Purpose                 = command.Purpose;
                booking.ContactName             = command.ContactName;
                booking.ContactPhone            = command.ContactPhone;
                booking.ContactAddress          = command.ContactAddress;
                booking.ContactCity             = command.ContactCity;
                booking.ContactEMail            = command.ContactEMail;
                booking.Comments                = command.Comments;
                booking.RentalPrice             = command.RentalPrice;
                booking.BookingState            = command.BookingState;
                booking.IsApproved              = command.IsApproved;
                booking.IsCancelled             = command.IsCancelled;
                booking.IsCheckedOut            = command.IsCheckedOut;
                booking.IsArchived              = command.IsArchived;
                booking.WelcomeLetterIsSent     = command.WelcomeLetterIsSent;
                booking.Deposit                 = command.Deposit;
                booking.DepositReceived         = command.DepositReceived;
                booking.ElectricityReadingStart = command.ElectricityReadingStart;
                booking.ElectricityReadingEnd   = command.ElectricityReadingEnd;
                booking.ElectricityPriceUnit    = command.ElectricityPriceUnit;

                UpdateCustomEntityDraftVersionCommand updateCmd = new UpdateCustomEntityDraftVersionCommand
                {
                    CustomEntityDefinitionCode = BookingCustomEntityDefinition.DefinitionCode,
                    CustomEntityId             = command.BookingId,
                    Title   = booking.MakeTitle(),
                    Publish = true,
                    Model   = booking
                };

                await DomainRepository.CustomEntities().Versions().UpdateDraftAsync(updateCmd);

                await scope.CompleteAsync();
            }
        }
        public async Task ExecuteAsync(SendBookingMailCommand command, IExecutionContext executionContext)
        {
            PermissionValidationService.EnforceCustomEntityPermission <CustomEntityUpdatePermission>(BookingCustomEntityDefinition.DefinitionCode, executionContext.UserContext);

            using (var scope = DomainRepository.Transactions().CreateScope())
            {
                BookingDataModel booking = await BookingProvider.GetBookingById(command.BookingId);

                await booking.AddLogEntry(CurrentUserProvider, $"Sendt: {command.Subject}.");

                byte[] mailBody           = System.Text.Encoding.UTF8.GetBytes(command.Message);
                var    addDcoumentCommand = new AddDocumentCommand
                {
                    Title    = command.Subject,
                    MimeType = "text/html",
                    Body     = mailBody
                };

                await CommandExecutor.ExecuteAsync(addDcoumentCommand);

                booking.AddDocument(command.Subject, addDcoumentCommand.OutputDocumentId);

                UpdateCustomEntityDraftVersionCommand updateCmd = new UpdateCustomEntityDraftVersionCommand
                {
                    CustomEntityDefinitionCode = BookingCustomEntityDefinition.DefinitionCode,
                    CustomEntityId             = command.BookingId,
                    Title   = booking.MakeTitle(),
                    Publish = true,
                    Model   = booking
                };

                await DomainRepository.CustomEntities().Versions().UpdateDraftAsync(updateCmd);

                MailAddress to      = new MailAddress(booking.ContactEMail, booking.ContactName);
                MailMessage message = new MailMessage
                {
                    To       = to,
                    Subject  = command.Subject,
                    HtmlBody = command.Message
                };

                // It is not really a good idea to contact a mail server during a transaction, but ...
                // 1) I really don't want the mail being registered in the database as "sent" if the mail sending fails.
                // 2) One can hope that the dispatcher simply adds the message to an outgoing mail queue.
                // (and, yes, sending mails may fail much later with an "unknown recipient" or similar)

                await MailDispatchService.DispatchAsync(message);

                await scope.CompleteAsync();
            }
        }
Beispiel #7
0
        private async Task SendAdminNotificationMail(BookingDataModel booking)
        {
            TemplateDataModel template = await TemplateProvider.GetTemplateByName("slutafregningsnotifikation");

            string mailText = TemplateProvider.MergeText(template.Text, booking);

            MailAddress to      = new MailAddress(BookingSettings.AdminEmail);
            MailMessage message = new MailMessage
            {
                To       = to,
                Subject  = template.Subject,
                HtmlBody = mailText
            };

            await MailDispatchService.DispatchAsync(message);
        }
Beispiel #8
0
        public async Task ExecuteAsync(ImportBookingsCommand command, IExecutionContext executionContext)
        {
            PermissionValidationService.EnforceCustomEntityPermission <CustomEntityUpdatePermission>(BookingCustomEntityDefinition.DefinitionCode, executionContext.UserContext);

            DataSet bookings = new DataSet();

            bookings.ReadXml(command.ReadyToReadInput);

            var groupedBookings = bookings.Tables[0].Rows
                                  .Cast <DataRow>()
                                  .GroupBy(row => row["AftaleID"].ToString());

            int count = 0;

            foreach (var bookingGroup in groupedBookings)
            {
                try
                {
                    int bookingNumber = Convert.ToInt32(bookingGroup.Key);

                    string   startStr    = bookingGroup.Min(b => b["Dato"].ToString());
                    DateTime arrivalDate = DateTime.SpecifyKind(DateTime.Parse(startStr), DateTimeKind.Utc);

                    string   endStr        = bookingGroup.Max(b => b["Dato"].ToString());
                    DateTime departureDate = DateTime.SpecifyKind(DateTime.Parse(endStr), DateTimeKind.Utc);

                    DataRow row            = bookingGroup.First();
                    string  status         = row["Status"].ToString();
                    string  origin1        = row["HvorDuFra"].ToString();
                    string  origin2        = row["Fra"].ToString();
                    string  purpose        = row["Formaal"].ToString();
                    string  contactName    = row["KontaktPerson"].ToString();
                    string  contactEmail   = row["Email"].ToString();
                    string  contactAddress = row["Adresse"].ToString();
                    string  comments       = row["Bem"].ToString();
                    decimal.TryParse(row["AftaltLeje"].ToString(), out decimal rentalPrice);

                    int tenantCategoryId = GetTenantCategory(origin1);

                    BookingDataModel booking = new BookingDataModel
                    {
                        BookingNumber        = bookingNumber,
                        ArrivalDate          = arrivalDate,
                        DepartureDate        = departureDate,
                        OnlySelectedWeekdays = false,
                        SelectedWeekdays     = new List <WeekdayType>(),
                        TenantCategoryId     = tenantCategoryId,
                        TenantName           = origin2,
                        Purpose             = purpose,
                        ContactName         = contactName,
                        ContactPhone        = "",
                        ContactAddress      = contactAddress,
                        ContactCity         = "",
                        ContactEMail        = contactEmail,
                        Comments            = "Importeret i 2021 fra gammelt bookingsystem\n\n" + comments,
                        RentalPrice         = Math.Abs(rentalPrice),
                        Deposit             = 0,
                        BookingState        = BookingDataModel.BookingStateType.Closed,
                        IsApproved          = true,
                        IsCheckedOut        = true,
                        WelcomeLetterIsSent = true
                    };

                    if (booking.ArrivalDate.Value.Year >= 2021)
                    {
                        if (status == "Forespørgsel")
                        {
                            booking.BookingState        = BookingDataModel.BookingStateType.Requested;
                            booking.IsApproved          = false;
                            booking.WelcomeLetterIsSent = false;
                            booking.IsCheckedOut        = false;
                        }
                        else if (status == "Bekræftet")
                        {
                            booking.BookingState        = BookingDataModel.BookingStateType.Approved;
                            booking.IsApproved          = true;
                            booking.WelcomeLetterIsSent = false;
                            booking.IsCheckedOut        = false;
                        }
                        else if (status == "Nøgle sendt")
                        {
                            booking.BookingState        = BookingDataModel.BookingStateType.Approved;
                            booking.IsApproved          = true;
                            booking.WelcomeLetterIsSent = true;
                            booking.IsCheckedOut        = false;
                        }
                    }

                    var addCommand = new AddCustomEntityCommand
                    {
                        CustomEntityDefinitionCode = BookingCustomEntityDefinition.DefinitionCode,
                        Model   = booking,
                        Title   = booking.MakeTitle(),
                        Publish = true
                    };

                    await DomainRepository.WithElevatedPermissions().CustomEntities().AddAsync(addCommand);

                    if (++count >= 10000)
                    {
                        break;
                    }
                }
                catch (ValidationException ex)
                {
                    if (ex.ValidationResult is CompositeValidationResult vres)
                    {
                        throw new Exception($"Failed to validate booking number {bookingGroup.Key}: {vres.Results?.FirstOrDefault()}.", ex);
                    }
                    else
                    {
                        throw new Exception($"Failed to validate booking number {bookingGroup.Key}: {ex.ValidationResult?.ErrorMessage} ({ex.ValidationResult?.MemberNames?.FirstOrDefault()}).", ex);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception($"Failed to import booking number {bookingGroup.Key}.", ex);
                }
            }

            //return Task.CompletedTask;
        }