From bff07b80a77489fe1a3d7da39f862c2454105166 Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Tue, 2 Sep 2025 18:41:15 +0100 Subject: [PATCH 01/13] removed sensitive entries from config --- src/appsettings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/appsettings.json b/src/appsettings.json index 3aba6a9..61b4754 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -25,8 +25,8 @@ "ExpiryInMin": 10 }, "Cloudinary": { - "CloudName": "dowypvotw", - "ApiKey": "717696641265335", - "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" + "CloudName": "", + "ApiKey": "", + "ApiSecret": "" } } From c4e2a28b68c1a63f0d108d988a181a38884b41fa Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Thu, 25 Sep 2025 17:49:50 +0100 Subject: [PATCH 02/13] add business availability : repos --- docker-compose.yml | 6 +- .../IBusinessAvailabilityRepository.cs | 11 + .../Repository/IIndustryRepository.cs | 10 +- .../Models/BreakModel.cs | 27 ++ .../Models/BusinessAvailabilityModel.cs | 55 +++ .../Models/BusinessAvailabilitySlotModel.cs | 31 ++ .../Models/BusinessModel.cs | 1 - .../Models/UserModel.cs | 6 - .../Entities/Appointment.cs | 17 +- src/ProjectR.Backend.Domain/Entities/Break.cs | 19 + .../Entities/BusinessAvailability.cs | 11 +- .../Entities/BusinessAvailabilitySlot.cs | 11 +- .../Entities/Customer.cs | 20 + .../Providers/WhatsAppProvider.cs | 1 + .../Configurations/BreakConfiguration.cs | 28 ++ .../BusinessAvailabilityConfiguration.cs | 31 +- .../BusinessAvailabilitySlotConfiguration.cs | 36 ++ .../DatabaseContext/DatabaseContext.cs | 1 + ...250906151923_UnexpectedChanges.Designer.cs | 442 ++++++++++++++++++ .../20250906151923_UnexpectedChanges.cs | 245 ++++++++++ ...ddedBusinessAvailabilityTables.Designer.cs | 423 +++++++++++++++++ ...1160654_AddedBusinessAvailabilityTables.cs | 259 ++++++++++ .../Migrations/AppDbContextModelSnapshot.cs | 72 ++- .../BusinessAvailabilityRepository.cs | 79 ++++ .../Mappers/BusinessAvailabilityMapper.cs | 18 + src/appsettings.json | 6 +- 26 files changed, 1788 insertions(+), 78 deletions(-) create mode 100644 src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs create mode 100644 src/ProjectR.Backend.Application/Models/BreakModel.cs create mode 100644 src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs create mode 100644 src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs create mode 100644 src/ProjectR.Backend.Domain/Entities/Break.cs create mode 100644 src/ProjectR.Backend.Domain/Entities/Customer.cs create mode 100644 src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs create mode 100644 src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs create mode 100644 src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs create mode 100644 src/ProjectR.Backend.Shared/Mappers/BusinessAvailabilityMapper.cs diff --git a/docker-compose.yml b/docker-compose.yml index ad39382..7911d02 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,9 +30,9 @@ services: - WhatsApp__BusinessAccountId=${WhatsApp__BusinessAccountId} - WhatsApp__UseMock=${WhatsApp__UseMock} - - Cloudinary__CloudName=${Cloudinary__CloudName} - - Cloudinary__ApiKey=${Cloudinary__ApiKey} - - Cloudinary__ApiSecret=${Cloudinary__ApiSecret} + # - Cloudinary__CloudName=${Cloudinary__CloudName} + # - Cloudinary__ApiKey=${Cloudinary__ApiKey} + # - Cloudinary__ApiSecret=${Cloudinary__ApiSecret} # Serilog Seq config - Serilog__WriteTo__0__Name=Seq diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs new file mode 100644 index 0000000..bde437d --- /dev/null +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs @@ -0,0 +1,11 @@ +using ProjectR.Backend.Application.Models; + +namespace ProjectR.Backend.Application.Interfaces.Repository +{ + public interface IBusinessAvailabilityRepository + { + Task GetByIdAsync(Guid id); + Task AddAsync(BusinessAvailabilityModel model); + Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs index a880395..8e60d40 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs @@ -4,10 +4,10 @@ namespace ProjectR.Backend.Application.Interfaces.Repository { public interface IIndustryRepository { - Task CreateAsync(Industry industry); - Task GetByIdAsync(Guid id); - Task> GetAllAsync(); - Task UpdateAsync(Industry industry); - Task DeleteAsync(Guid id); + Task CreateAsync(Industry industry); + Task GetByIdAsync(Guid id); + Task> GetAllAsync(); + Task UpdateAsync(Industry industry); + Task DeleteAsync(Guid id); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Models/BreakModel.cs b/src/ProjectR.Backend.Application/Models/BreakModel.cs new file mode 100644 index 0000000..137a71e --- /dev/null +++ b/src/ProjectR.Backend.Application/Models/BreakModel.cs @@ -0,0 +1,27 @@ +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Domain.Entities +{ + /// + /// This is the avaibility for a business for a given period + /// + public class BreakModel : BaseObject + { + [Required] + public Guid BusinessAvailabilitySlotId { get; set; } + public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } + [Required] + public TimeOnly? StartTime { get; set; } + [Required] + public TimeOnly? EndTime { get; set; } + } + + public class AddBreakModel + { + [Required] + public TimeOnly? StartTime { get; set; } + [Required] + public TimeOnly? EndTime { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs new file mode 100644 index 0000000..e0ebd20 --- /dev/null +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs @@ -0,0 +1,55 @@ +using ProjectR.Backend.Domain.Entities; +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Application.Models +{ + + public class BusinessAvailabilityModel + { + public Guid Id { get; set; } + + [Required] + public Guid BusinessId { get; set; } + + [Required] + public DateOnly? StartDate { get; set; } + + [Required] + public DateOnly? EndDate { get; set; } + + [Required, MinLength(1, ErrorMessage = "At least one slot is required")] + public ICollection? Slots { get; set; } + } + + /// + /// This is a bucket for business availability slots for a given period + /// + public class AddBusinessAvailabilityModel + { + [Required] + public Guid BusinessId { get; set; } + + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateOnly? StartDate { get; set; } + + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateOnly? EndDate { get; set; } + + [Required, MinLength(1, ErrorMessage = "At least one slot is required")] + public List? Slots { get; set; } + + public List? Breaks { get; set; } + } + + public class UpdateBusinessAvailabilityModel + { + [Required] + public Guid BusinessId { get; set; } + + [Required, MinLength(1, ErrorMessage = "At least one slot is required")] + public List? Slots { get; set; } + + public List? Breaks { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs new file mode 100644 index 0000000..a0fcd89 --- /dev/null +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -0,0 +1,31 @@ +using ProjectR.Backend.Domain.Entities; +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Application.Models +{ + /// + /// This is the avaibility slot for a business for a given period and represents a day in the week + /// + public class BusinessAvailabilitySlotModel + { + [Required] + public Guid BusinessAvailabilityId { get; set; } + public BusinessAvailabilityModel? BusinessAvailability { get; set; } + [Required] + public TimeOnly? StartTime { get; set; } + [Required] + public TimeOnly? EndTime { get; set; } + public DayOfWeek DayOfWeek { get; set; } + + public ICollection? Breaks { get; set; } + } + + public class AddBusinessAvailabilitySlotModel + { + [Required] + public TimeOnly? StartTime { get; set; } + [Required] + public TimeOnly? EndTime { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Application/Models/BusinessModel.cs b/src/ProjectR.Backend.Application/Models/BusinessModel.cs index 11708c1..048a6d9 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessModel.cs @@ -19,7 +19,6 @@ public class BusinessModel public string? Latitude { get; set; } public string? ShortLink { get; set; } public string? Logo { get; set; } - } public class AddBusinessModel diff --git a/src/ProjectR.Backend.Application/Models/UserModel.cs b/src/ProjectR.Backend.Application/Models/UserModel.cs index ba7b889..0ee5362 100644 --- a/src/ProjectR.Backend.Application/Models/UserModel.cs +++ b/src/ProjectR.Backend.Application/Models/UserModel.cs @@ -21,14 +21,8 @@ public class UserModel public class AddUserModel { - // [Required(ErrorMessage = "Email is required")] - // [EmailAddress(ErrorMessage = "Invalid email format.")] public string Email { get; set; } = string.Empty; - // [Required(ErrorMessage = "Phone number is required")] - // [RegularExpression(@"^\d{10,15}$", ErrorMessage = "Invalid phone number format. It should be between 10 to 15 digits.")] public string PhoneNumber { get; set; } = string.Empty; - // [Required(ErrorMessage = "Phone Code is required.")] - // [RegularExpression(@"^\+\d{1,3}$", ErrorMessage = "Invalid phone code format. Use the format +[country code].")] public string PhoneCode { get; set; } = string.Empty; [Required(ErrorMessage = "Account type is required")] public AccountType AccountType { get; set; } diff --git a/src/ProjectR.Backend.Domain/Entities/Appointment.cs b/src/ProjectR.Backend.Domain/Entities/Appointment.cs index b99a8fe..93ca6e8 100644 --- a/src/ProjectR.Backend.Domain/Entities/Appointment.cs +++ b/src/ProjectR.Backend.Domain/Entities/Appointment.cs @@ -1,3 +1,4 @@ +using ProjectR.Backend.Shared; using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations; @@ -5,17 +6,11 @@ namespace ProjectR.Backend.Domain.Entities { public class Appointment : BaseObject { - // public Guid BusinessId { get; set; } - // public Business? Business { get; set; } - // public DateOnly? StartDate { get; set; } - // public DateOnly? EndDate { get; set; } - // /// - // /// This will be used in scenerios where we decide to use templating. - // /// Templating allows a business to reuse a previous availability without necessarily setting it all over again - // /// - // public DateOnly? ValidFrom { get; set; } - // public DateOnly? ValidTo { get; set; } - // public Collection? Slots { get; set; } + [Required] + public Guid CustomerId { get; set; } + public Customer? Customer { get; set; } + [Required] + public AppointmentStatus Status { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/Break.cs b/src/ProjectR.Backend.Domain/Entities/Break.cs new file mode 100644 index 0000000..85fd70c --- /dev/null +++ b/src/ProjectR.Backend.Domain/Entities/Break.cs @@ -0,0 +1,19 @@ +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Domain.Entities +{ + /// + /// This is the avaibility for a business for a given period + /// + public class Break : BaseObject + { + [Required] + public Guid BusinessAvailabilitySlotId { get; set; } + public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } + [Required] + public TimeOnly? StartTime { get; set; } + [Required] + public TimeOnly? EndTime { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs index 2c1599c..93c078a 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs @@ -3,19 +3,16 @@ namespace ProjectR.Backend.Domain.Entities { + /// + /// This is a bucket for business availability slots for a given period + /// public class BusinessAvailability : BaseObject { public Guid BusinessId { get; set; } public Business? Business { get; set; } public DateOnly? StartDate { get; set; } public DateOnly? EndDate { get; set; } - /// - /// This will be used in scenerios where we decide to use templating. - /// Templating allows a business to reuse a previous availability without necessarily setting it all over again - /// - public DateOnly? ValidFrom { get; set; } - public DateOnly? ValidTo { get; set; } - public Collection? Slots { get; set; } + public ICollection? Slots { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs index dd3a30b..952b198 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs @@ -3,7 +3,7 @@ namespace ProjectR.Backend.Domain.Entities { /// - /// This is the avaibility for a business for a given period + /// This is the avaibility slot for a business for a given period and represents a day in the week /// public class BusinessAvailabilitySlot : BaseObject { @@ -14,13 +14,8 @@ public class BusinessAvailabilitySlot : BaseObject public TimeOnly? StartTime { get; set; } [Required] public TimeOnly? EndTime { get; set; } - public DayOfWeek DayOfWeek { get; set; } - - /// - /// keeping the breaks here as a list of time(may be better to extract and compre that way) - /// This is subject to restructuring if need be in the future - /// - public List? Breaks { get; set; } + public DayOfWeek DayOfWeek { get; set; } + public ICollection? Breaks { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/Customer.cs b/src/ProjectR.Backend.Domain/Entities/Customer.cs new file mode 100644 index 0000000..2157b26 --- /dev/null +++ b/src/ProjectR.Backend.Domain/Entities/Customer.cs @@ -0,0 +1,20 @@ +using ProjectR.Backend.Shared; +using System.ComponentModel.DataAnnotations; + +namespace ProjectR.Backend.Domain.Entities +{ + /// + /// This represents a customer that has booked a business in the system. We collect this information to be able to retain customer information and contact them if need be + /// + public class Customer : BaseObject + { + public string? PhoneNumber { get; set; } + public string? PhoneCode { get; set; } + public string? Email { get; set; } + /// + /// This identifies a user type in the system [Business, Client, Admin etc] + /// + public string? Name { get; set; } + } +} + diff --git a/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs b/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs index 959a2d8..a274149 100644 --- a/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs +++ b/src/ProjectR.Backend.Infrastructure/Providers/WhatsAppProvider.cs @@ -97,6 +97,7 @@ public async Task SendInteractiveReplyButtonMessageAsync(InteractiveMessag return default; } } + public async Task SendSimpleMessageAsync(SimpleMessageModel model) { if (_settings.UseMock) diff --git a/src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs b/src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs new file mode 100644 index 0000000..0341e93 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Configurations/BreakConfiguration.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Persistence.Configurations +{ + public class BreakConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + + builder.Property(x => x.BusinessAvailabilitySlotId) + .IsRequired(); + + builder.HasOne(x => x.BusinessAvailabilitySlot) + .WithMany(x => x.Breaks) + .HasForeignKey(x => x.BusinessAvailabilitySlotId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Property(x => x.StartTime) + .IsRequired(); + + builder.Property(x => x.EndTime) + .IsRequired(); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs index eb01198..bf17da2 100644 --- a/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs +++ b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilityConfiguration.cs @@ -8,21 +8,26 @@ public class BusinessAvailabilityConfiguration : IEntityTypeConfiguration builder) { - builder.HasKey(e => e.Id); - builder.Property(e => e.BusinessId).IsRequired(); - builder.Property(e => e.StartDate).IsRequired(); - builder.Property(e => e.EndDate).IsRequired(); - builder.Property(e => e.ValidFrom); - builder.Property(e => e.ValidTo); + builder.HasKey(x => x.Id); - builder.HasOne(e => e.Business) - .WithMany() - .HasForeignKey(e => e.BusinessId) - .OnDelete(DeleteBehavior.Cascade); + builder.Property(x => x.BusinessId) + .IsRequired(); - builder.HasMany(e => e.Slots) - .WithOne() - .HasForeignKey(e => e.BusinessAvailabilityId); + builder.HasOne(x => x.Business) + .WithMany() + .HasForeignKey(x => x.BusinessId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Property(x => x.StartDate) + .IsRequired(); + + builder.Property(x => x.EndDate) + .IsRequired(); + + builder.HasMany(x => x.Slots) + .WithOne(x => x.BusinessAvailability) + .HasForeignKey(x => x.BusinessAvailabilityId) + .OnDelete(DeleteBehavior.Cascade); } } } diff --git a/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs new file mode 100644 index 0000000..f253a15 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Configurations/BusinessAvailabilitySlotConfiguration.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Persistence.Configurations +{ + public class BusinessAvailabilitySlotConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + + builder.Property(x => x.BusinessAvailabilityId) + .IsRequired(); + + builder.HasOne(x => x.BusinessAvailability) + .WithMany(x => x.Slots) + .HasForeignKey(x => x.BusinessAvailabilityId) + .OnDelete(DeleteBehavior.Cascade); + + builder.Property(x => x.StartTime) + .IsRequired(); + + builder.Property(x => x.EndTime) + .IsRequired(); + + builder.Property(x => x.DayOfWeek) + .IsRequired(); + + builder.HasMany(x => x.Breaks) + .WithOne(x => x.BusinessAvailabilitySlot) + .HasForeignKey(x => x.BusinessAvailabilitySlotId) + .OnDelete(DeleteBehavior.Cascade); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs b/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs index 2c13020..387e31c 100644 --- a/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs +++ b/src/ProjectR.Backend.Persistence/DatabaseContext/DatabaseContext.cs @@ -11,6 +11,7 @@ public class AppDbContext : DbContext public DbSet Businesses => Set(); public DbSet BusinessAvailabilities => Set(); public DbSet BusinessAvailabilitySlots => Set(); + public DbSet Breaks => Set(); public DbSet Otps => Set(); public DbSet Industries { get; set; } diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs new file mode 100644 index 0000000..bac77f9 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs @@ -0,0 +1,442 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using ProjectR.Backend.Persistence.DatabaseContext; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250906151923_UnexpectedChanges")] + partial class UnexpectedChanges + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AppThemes"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId1") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.HasIndex("BusinessAvailabilitySlotId1"); + + b.ToTable("Break"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("About") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Industry") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Latitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Location") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Logo") + .HasColumnType("text"); + + b.Property("Longitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PhoneCode") + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("ServiceType") + .HasColumnType("integer"); + + b.Property("ShortLink") + .HasColumnType("text"); + + b.Property("Type") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("businesses", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessId"); + + b.ToTable("BusinessAvailability"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilityId") + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilityId1") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilityId"); + + b.HasIndex("BusinessAvailabilityId1"); + + b.ToTable("BusinessAvailabilitySlot"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeliveryMode") + .HasColumnType("integer"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OtpType") + .HasColumnType("integer"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Otps"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("PhoneCode") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("RegistrationType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsProcessed") + .HasColumnType("boolean"); + + b.Property("LastProcessedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastProcessedResult") + .HasColumnType("text"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("WebhookMessages"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", null) + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany() + .HasForeignKey("BusinessAvailabilitySlotId1"); + + b.Navigation("BusinessAvailabilitySlot"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") + .WithMany() + .HasForeignKey("BusinessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Business"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") + .WithMany() + .HasForeignKey("BusinessAvailabilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) + .WithMany("Slots") + .HasForeignKey("BusinessAvailabilityId1") + .HasConstraintName("FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1"); + + b.Navigation("BusinessAvailability"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Navigation("Slots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs b/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs new file mode 100644 index 0000000..2c0072f --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class UnexpectedChanges : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilities_businesses_BusinessId", + table: "BusinessAvailabilities"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", + table: "BusinessAvailabilitySlots"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1", + table: "BusinessAvailabilitySlots"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailabilitySlots", + table: "BusinessAvailabilitySlots"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailabilities", + table: "BusinessAvailabilities"); + + migrationBuilder.DropColumn( + name: "Breaks", + table: "BusinessAvailabilitySlots"); + + migrationBuilder.DropColumn( + name: "ValidFrom", + table: "BusinessAvailabilities"); + + migrationBuilder.DropColumn( + name: "ValidTo", + table: "BusinessAvailabilities"); + + migrationBuilder.RenameTable( + name: "BusinessAvailabilitySlots", + newName: "BusinessAvailabilitySlot"); + + migrationBuilder.RenameTable( + name: "BusinessAvailabilities", + newName: "BusinessAvailability"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId1", + table: "BusinessAvailabilitySlot", + newName: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", + table: "BusinessAvailabilitySlot", + newName: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilities_BusinessId", + table: "BusinessAvailability", + newName: "IX_BusinessAvailability_BusinessId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailabilitySlot", + table: "BusinessAvailabilitySlot", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailability", + table: "BusinessAvailability", + column: "Id"); + + migrationBuilder.CreateTable( + name: "Break", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + BusinessAvailabilitySlotId = table.Column(type: "uuid", nullable: false), + BusinessAvailabilitySlotId1 = table.Column(type: "uuid", nullable: true), + StartTime = table.Column(type: "time without time zone", nullable: false), + EndTime = table.Column(type: "time without time zone", nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), + UpdatedBy = table.Column(type: "text", nullable: true), + RecordStatus = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Break", x => x.Id); + table.ForeignKey( + name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId", + column: x => x.BusinessAvailabilitySlotId, + principalTable: "BusinessAvailabilitySlot", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId1", + column: x => x.BusinessAvailabilitySlotId1, + principalTable: "BusinessAvailabilitySlot", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_Break_BusinessAvailabilitySlotId", + table: "Break", + column: "BusinessAvailabilitySlotId"); + + migrationBuilder.CreateIndex( + name: "IX_Break_BusinessAvailabilitySlotId1", + table: "Break", + column: "BusinessAvailabilitySlotId1"); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailability_businesses_BusinessId", + table: "BusinessAvailability", + column: "BusinessId", + principalTable: "businesses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", + table: "BusinessAvailabilitySlot", + column: "BusinessAvailabilityId", + principalTable: "BusinessAvailability", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", + table: "BusinessAvailabilitySlot", + column: "BusinessAvailabilityId1", + principalTable: "BusinessAvailability", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailability_businesses_BusinessId", + table: "BusinessAvailability"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropTable( + name: "Break"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailabilitySlot", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailability", + table: "BusinessAvailability"); + + migrationBuilder.RenameTable( + name: "BusinessAvailabilitySlot", + newName: "BusinessAvailabilitySlots"); + + migrationBuilder.RenameTable( + name: "BusinessAvailability", + newName: "BusinessAvailabilities"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1", + table: "BusinessAvailabilitySlots", + newName: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId1"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId", + table: "BusinessAvailabilitySlots", + newName: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailability_BusinessId", + table: "BusinessAvailabilities", + newName: "IX_BusinessAvailabilities_BusinessId"); + + migrationBuilder.AddColumn>( + name: "Breaks", + table: "BusinessAvailabilitySlots", + type: "time without time zone[]", + nullable: true); + + migrationBuilder.AddColumn( + name: "ValidFrom", + table: "BusinessAvailabilities", + type: "date", + nullable: true); + + migrationBuilder.AddColumn( + name: "ValidTo", + table: "BusinessAvailabilities", + type: "date", + nullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailabilitySlots", + table: "BusinessAvailabilitySlots", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailabilities", + table: "BusinessAvailabilities", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilities_businesses_BusinessId", + table: "BusinessAvailabilities", + column: "BusinessId", + principalTable: "businesses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", + table: "BusinessAvailabilitySlots", + column: "BusinessAvailabilityId", + principalTable: "BusinessAvailabilities", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1", + table: "BusinessAvailabilitySlots", + column: "BusinessAvailabilityId1", + principalTable: "BusinessAvailabilities", + principalColumn: "Id"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs new file mode 100644 index 0000000..54726b1 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs @@ -0,0 +1,423 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using ProjectR.Backend.Persistence.DatabaseContext; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250921160654_AddedBusinessAvailabilityTables")] + partial class AddedBusinessAvailabilityTables + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AppThemes"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("About") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Industry") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Latitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Location") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Logo") + .HasColumnType("text"); + + b.Property("Longitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PhoneCode") + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("ServiceType") + .HasColumnType("integer"); + + b.Property("ShortLink") + .HasColumnType("text"); + + b.Property("Type") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("businesses", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessId"); + + b.ToTable("BusinessAvailabilities"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilityId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilityId"); + + b.ToTable("BusinessAvailabilitySlots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeliveryMode") + .HasColumnType("integer"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OtpType") + .HasColumnType("integer"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Otps"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("PhoneCode") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("RegistrationType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsProcessed") + .HasColumnType("boolean"); + + b.Property("LastProcessedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastProcessedResult") + .HasColumnType("text"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("WebhookMessages"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") + .WithMany() + .HasForeignKey("BusinessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Business"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") + .WithMany("Slots") + .HasForeignKey("BusinessAvailabilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailability"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Navigation("Slots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs b/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs new file mode 100644 index 0000000..7772f46 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs @@ -0,0 +1,259 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class AddedBusinessAvailabilityTables : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId", + table: "Break"); + + migrationBuilder.DropForeignKey( + name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId1", + table: "Break"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailability_businesses_BusinessId", + table: "BusinessAvailability"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailabilitySlot", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropIndex( + name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailability", + table: "BusinessAvailability"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Break", + table: "Break"); + + migrationBuilder.DropIndex( + name: "IX_Break_BusinessAvailabilitySlotId1", + table: "Break"); + + migrationBuilder.DropColumn( + name: "BusinessAvailabilityId1", + table: "BusinessAvailabilitySlot"); + + migrationBuilder.DropColumn( + name: "BusinessAvailabilitySlotId1", + table: "Break"); + + migrationBuilder.RenameTable( + name: "BusinessAvailabilitySlot", + newName: "BusinessAvailabilitySlots"); + + migrationBuilder.RenameTable( + name: "BusinessAvailability", + newName: "BusinessAvailabilities"); + + migrationBuilder.RenameTable( + name: "Break", + newName: "Breaks"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId", + table: "BusinessAvailabilitySlots", + newName: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailability_BusinessId", + table: "BusinessAvailabilities", + newName: "IX_BusinessAvailabilities_BusinessId"); + + migrationBuilder.RenameIndex( + name: "IX_Break_BusinessAvailabilitySlotId", + table: "Breaks", + newName: "IX_Breaks_BusinessAvailabilitySlotId"); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailabilitySlots", + table: "BusinessAvailabilitySlots", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailabilities", + table: "BusinessAvailabilities", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Breaks", + table: "Breaks", + column: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Breaks_BusinessAvailabilitySlots_BusinessAvailabilitySlotId", + table: "Breaks", + column: "BusinessAvailabilitySlotId", + principalTable: "BusinessAvailabilitySlots", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilities_businesses_BusinessId", + table: "BusinessAvailabilities", + column: "BusinessId", + principalTable: "businesses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", + table: "BusinessAvailabilitySlots", + column: "BusinessAvailabilityId", + principalTable: "BusinessAvailabilities", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Breaks_BusinessAvailabilitySlots_BusinessAvailabilitySlotId", + table: "Breaks"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilities_businesses_BusinessId", + table: "BusinessAvailabilities"); + + migrationBuilder.DropForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", + table: "BusinessAvailabilitySlots"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailabilitySlots", + table: "BusinessAvailabilitySlots"); + + migrationBuilder.DropPrimaryKey( + name: "PK_BusinessAvailabilities", + table: "BusinessAvailabilities"); + + migrationBuilder.DropPrimaryKey( + name: "PK_Breaks", + table: "Breaks"); + + migrationBuilder.RenameTable( + name: "BusinessAvailabilitySlots", + newName: "BusinessAvailabilitySlot"); + + migrationBuilder.RenameTable( + name: "BusinessAvailabilities", + newName: "BusinessAvailability"); + + migrationBuilder.RenameTable( + name: "Breaks", + newName: "Break"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", + table: "BusinessAvailabilitySlot", + newName: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId"); + + migrationBuilder.RenameIndex( + name: "IX_BusinessAvailabilities_BusinessId", + table: "BusinessAvailability", + newName: "IX_BusinessAvailability_BusinessId"); + + migrationBuilder.RenameIndex( + name: "IX_Breaks_BusinessAvailabilitySlotId", + table: "Break", + newName: "IX_Break_BusinessAvailabilitySlotId"); + + migrationBuilder.AddColumn( + name: "BusinessAvailabilityId1", + table: "BusinessAvailabilitySlot", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "BusinessAvailabilitySlotId1", + table: "Break", + type: "uuid", + nullable: true); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailabilitySlot", + table: "BusinessAvailabilitySlot", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_BusinessAvailability", + table: "BusinessAvailability", + column: "Id"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Break", + table: "Break", + column: "Id"); + + migrationBuilder.CreateIndex( + name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1", + table: "BusinessAvailabilitySlot", + column: "BusinessAvailabilityId1"); + + migrationBuilder.CreateIndex( + name: "IX_Break_BusinessAvailabilitySlotId1", + table: "Break", + column: "BusinessAvailabilitySlotId1"); + + migrationBuilder.AddForeignKey( + name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId", + table: "Break", + column: "BusinessAvailabilitySlotId", + principalTable: "BusinessAvailabilitySlot", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId1", + table: "Break", + column: "BusinessAvailabilitySlotId1", + principalTable: "BusinessAvailabilitySlot", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailability_businesses_BusinessId", + table: "BusinessAvailability", + column: "BusinessId", + principalTable: "businesses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", + table: "BusinessAvailabilitySlot", + column: "BusinessAvailabilityId", + principalTable: "BusinessAvailability", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", + table: "BusinessAvailabilitySlot", + column: "BusinessAvailabilityId1", + principalTable: "BusinessAvailability", + principalColumn: "Id"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs index c3b05c1..5e7fe6d 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -1,6 +1,5 @@ // using System; -using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; @@ -37,6 +36,40 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("AppThemes"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => { b.Property("Id") @@ -137,12 +170,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("UpdatedBy") .HasColumnType("text"); - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - b.HasKey("Id"); b.HasIndex("BusinessId"); @@ -156,15 +183,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - b.Property("BusinessAvailabilityId") .HasColumnType("uuid"); - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); @@ -190,8 +211,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("BusinessAvailabilityId"); - b.HasIndex("BusinessAvailabilityId1"); - b.ToTable("BusinessAvailabilitySlots"); }); @@ -342,6 +361,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("WebhookMessages"); }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => { b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") @@ -366,17 +396,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") .WithMany("Slots") .HasForeignKey("BusinessAvailabilityId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - b.Navigation("BusinessAvailability"); }); @@ -384,6 +409,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Navigation("Slots"); }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); #pragma warning restore 612, 618 } } diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs new file mode 100644 index 0000000..e9343d0 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -0,0 +1,79 @@ +using Microsoft.EntityFrameworkCore; +using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Persistence.DatabaseContext; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Shared.Mappers; + +namespace ProjectR.Backend.Persistence.Repository +{ + public class BusinessAvailabilityRepository : IBusinessAvailabilityRepository + { + private readonly AppDbContext _appDbContext; + + public BusinessAvailabilityRepository(AppDbContext appDbContext) + { + _appDbContext = appDbContext; + } + + public async Task GetByIdAsync(Guid id) + { + BusinessAvailability? availability = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .FirstOrDefaultAsync(x => x.Id == id); + + if (availability == null) + { + return null; + } + + BusinessAvailabilityModel result = Mapper.Map(availability); + return result; + // return new BusinessAvailabilityModel + // { + // Id = availability.Id, + // BusinessId = availability.BusinessId, + // Slots = availability.Slots?.Select(slot => new BusinessAvailabilitySlotModel + // { + // BusinessAvailabilityId = availability.Id, + // DayOfWeek = slot.DayOfWeek, + // StartTime = slot.StartTime, + // EndTime = slot.EndTime, + // Breaks = slot.Breaks?.Select(b => new BreakModel + // { + // Id = b.Id, + // StartTime = b.StartTime, + // EndTime = b.EndTime + // }).ToList() + // }).ToList() + // }; + } + + public async Task AddAsync(BusinessAvailabilityModel model) + { + // Create new availability + BusinessAvailability newAvailability = Mapper.Map(model); + await _appDbContext.BusinessAvailabilities.AddAsync(newAvailability); + } + + public async Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model) + { + BusinessAvailability? availability = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .FirstOrDefaultAsync(x => x.Id == id); + + if (availability == null) + { + return null!; + } + + //remove all existing slots and breaks + _appDbContext.BusinessAvailabilitySlots.RemoveRange(availability.Slots!); + _appDbContext.AddRange(model.Slots!); + await _appDbContext.SaveChangesAsync(); + return Mapper.Map(availability); + } + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Shared/Mappers/BusinessAvailabilityMapper.cs b/src/ProjectR.Backend.Shared/Mappers/BusinessAvailabilityMapper.cs new file mode 100644 index 0000000..1a608e2 --- /dev/null +++ b/src/ProjectR.Backend.Shared/Mappers/BusinessAvailabilityMapper.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace ProjectR.Backend.Shared.Mappers +{ + public static class Mapper + { + public static TDestination Map(TSource source) + { + if (source == null) + { + return default!; + } + + string serialized = JsonConvert.SerializeObject(source); + return JsonConvert.DeserializeObject(serialized)!; + } + } +} \ No newline at end of file diff --git a/src/appsettings.json b/src/appsettings.json index 61b4754..3aba6a9 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -25,8 +25,8 @@ "ExpiryInMin": 10 }, "Cloudinary": { - "CloudName": "", - "ApiKey": "", - "ApiSecret": "" + "CloudName": "dowypvotw", + "ApiKey": "717696641265335", + "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" } } From d0d8d9a10ccde9bee92441b27dc2bf545fd360a6 Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Thu, 25 Sep 2025 18:32:41 +0100 Subject: [PATCH 03/13] business availabilty: manager --- .../Managers/IBusinessAvailabilityManager.cs | 14 ++++ .../IBusinessAvailabilityRepository.cs | 3 +- .../Models/BusinessAvailabilityModel.cs | 5 +- .../Models/BusinessAvailabilitySlotModel.cs | 13 ++- .../Entities/BusinessAvailabilitySlot.cs | 4 + .../Managers/BusinessAvailabilityManager.cs | 84 +++++++++++++++++++ .../Managers/BusinessManager.cs | 5 +- .../BusinessAvailabilityRepository.cs | 19 ++++- .../Helpers/DateTimeHelper.cs | 11 +++ ...usinessAvailabilityMapper.cs => Mapper.cs} | 0 10 files changed, 147 insertions(+), 11 deletions(-) create mode 100644 src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs create mode 100644 src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs create mode 100644 src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs rename src/ProjectR.Backend.Shared/Mappers/{BusinessAvailabilityMapper.cs => Mapper.cs} (100%) diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs new file mode 100644 index 0000000..3572673 --- /dev/null +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs @@ -0,0 +1,14 @@ +using ProjectR.Backend.Application.Models; + +namespace ProjectR.Backend.Application.Interfaces.Managers +{ + public interface IBusinessAvailabilityManager + { + Task GetByBusinessIdAsync(); + Task> GetByIdAsync(Guid id); + Task> AddAsync(AddBusinessAvailabilityModel model); + Task> UpdateAsync(UpdateBusinessAvailabilityModel user); + Task DeleteAsync(Guid Id); + Task GetByBusinessId(Guid businessId); + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs index bde437d..5e94f47 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs @@ -5,7 +5,8 @@ namespace ProjectR.Backend.Application.Interfaces.Repository public interface IBusinessAvailabilityRepository { Task GetByIdAsync(Guid id); - Task AddAsync(BusinessAvailabilityModel model); + Task GetAllByBusinessIdAsync(Guid id); + Task AddAsync(BusinessAvailabilityModel model); Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs index e0ebd20..7b976c3 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs @@ -35,10 +35,9 @@ public class AddBusinessAvailabilityModel [DataType(DataType.Date, ErrorMessage = "Invalid date format")] public DateOnly? EndDate { get; set; } - [Required, MinLength(1, ErrorMessage = "At least one slot is required")] - public List? Slots { get; set; } + public List Slots { get; set; } = []; - public List? Breaks { get; set; } + public List Breaks { get; set; } = []; } public class UpdateBusinessAvailabilityModel diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs index a0fcd89..9931105 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -10,20 +10,31 @@ public class BusinessAvailabilitySlotModel { [Required] public Guid BusinessAvailabilityId { get; set; } + public BusinessAvailabilityModel? BusinessAvailability { get; set; } + [Required] public TimeOnly? StartTime { get; set; } + [Required] public TimeOnly? EndTime { get; set; } + public DayOfWeek DayOfWeek { get; set; } - public ICollection? Breaks { get; set; } + [Required] + public DateTimeOffset Date { get; set; } + + public List? Breaks { get; set; } } public class AddBusinessAvailabilitySlotModel { + [Required] + public DateTime Date { get; set; } + [Required] public TimeOnly? StartTime { get; set; } + [Required] public TimeOnly? EndTime { get; set; } } diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs index 952b198..e5f566b 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs @@ -15,6 +15,10 @@ public class BusinessAvailabilitySlot : BaseObject [Required] public TimeOnly? EndTime { get; set; } public DayOfWeek DayOfWeek { get; set; } + /// + /// The specific date for this slot. Slots are generally recurring weekly but this date represents the specific date for this slot + /// + public DateTimeOffset Date { get; set; } public ICollection? Breaks { get; set; } } } diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs new file mode 100644 index 0000000..4efa913 --- /dev/null +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs @@ -0,0 +1,84 @@ +using ProjectR.Backend.Application.Interfaces.Managers; +using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Infrastructure.Managers +{ + public class BusinessAvailabilityManager : IBusinessAvailabilityManager + { + public readonly IBusinessAvailabilityRepository _repository; + + public BusinessAvailabilityManager(IBusinessAvailabilityRepository repository) + { + _repository = repository; + } + + public async Task> AddAsync(AddBusinessAvailabilityModel model) + { + //check if the days are more than one week apart + //check if the business exist + //check if business availability already exists for the business + + //check that slots are valid i.e One slot to One day of the week + //check that only one date is used in the slots + //check that there are not dup + + //ensure that start time of the date is before the end time + //ensure that the times in the breaks are within the time of the slot + //should we let users have breaks occupying the whole slot time? + + // Map to BusinessAvailabilityModel + + // Create new availability + + BusinessAvailabilityModel newAvailability = new() + { + BusinessId = model.BusinessId, + Slots = model.Slots?.Select(slot => new BusinessAvailabilitySlotModel + { + Date = slot.Date, + DayOfWeek = slot.Date.DayOfWeek, + StartTime = slot.StartTime, + EndTime = slot.EndTime, + Breaks = model.Breaks?.Select(b => new BreakModel + { + StartTime = b.StartTime, + EndTime = b.EndTime + }).ToList() + }).ToList() + }; + + await _repository.AddAsync(newAvailability); + return new ResponseModel(message: "Business Availability created successfully", data: newAvailability, status: true); + } + + public async Task DeleteAsync(Guid Id) + { + throw new NotImplementedException(); + } + + public async Task GetByBusinessId(Guid businessId) + { + BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(businessId); + return result; + } + + public async Task GetByBusinessIdAsync() + { + BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(Guid.Empty); + return result; + } + + public async Task> GetByIdAsync(Guid id) + { + BusinessAvailabilityModel? result = await _repository.GetByIdAsync(id); + return new ResponseModel(message: result != null ? "Business Availability retrieved successfully" : "Business Availability not found", data: result, status: result != null); + } + + public async Task> UpdateAsync(UpdateBusinessAvailabilityModel user) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs index c03f1d7..01a0cdd 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs @@ -9,13 +9,11 @@ public class BusinessManager : IBusinessManager { public readonly IBusinessRepository _businessRepository; private readonly ISlugService _slugService; - private readonly ICloudinaryService _cloudinaryService; - public BusinessManager(IBusinessRepository businessRepository, ISlugService slugService, ICloudinaryService cloudinaryService) + public BusinessManager(IBusinessRepository businessRepository, ISlugService slugService) { _businessRepository = businessRepository; _slugService = slugService; - _cloudinaryService = cloudinaryService; } public async Task> AddAsync(AddBusinessModel business) @@ -86,7 +84,6 @@ public async Task> AddAsync(AddBusinessModel[] bu BusinessModel[] result = await _businessRepository.AddAsync(models); return new ResponseModel(message: "Businesses Added Successfully", data: result, status: true); - } public async Task DeleteAsync(BusinessModel[] businesses) diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs index e9343d0..98e0c37 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -4,6 +4,7 @@ using ProjectR.Backend.Persistence.DatabaseContext; using ProjectR.Backend.Application.Models; using ProjectR.Backend.Shared.Mappers; +using Microsoft.EntityFrameworkCore.ChangeTracking; namespace ProjectR.Backend.Persistence.Repository { @@ -50,11 +51,14 @@ public BusinessAvailabilityRepository(AppDbContext appDbContext) // }; } - public async Task AddAsync(BusinessAvailabilityModel model) + public async Task AddAsync(BusinessAvailabilityModel model) { // Create new availability BusinessAvailability newAvailability = Mapper.Map(model); - await _appDbContext.BusinessAvailabilities.AddAsync(newAvailability); + EntityEntry result = await _appDbContext.BusinessAvailabilities.AddAsync(newAvailability); + await _appDbContext.SaveChangesAsync(); + model.Id = result.Entity.Id; + return model; } public async Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model) @@ -75,5 +79,16 @@ public async Task UpdateAsync(Guid id, UpdateBusiness await _appDbContext.SaveChangesAsync(); return Mapper.Map(availability); } + + public async Task GetAllByBusinessIdAsync(Guid id) + { + List availabilities = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .Where(x => x.BusinessId == id) + .ToListAsync(); + + return availabilities.Select(c => Mapper.Map(c)).ToArray(); + } } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs b/src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs new file mode 100644 index 0000000..4b01ad5 --- /dev/null +++ b/src/ProjectR.Backend.Shared/Helpers/DateTimeHelper.cs @@ -0,0 +1,11 @@ +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace ProjectR.Backend.Shared.Helpers +{ + public static class DateTimeHelper + { + + } +} diff --git a/src/ProjectR.Backend.Shared/Mappers/BusinessAvailabilityMapper.cs b/src/ProjectR.Backend.Shared/Mappers/Mapper.cs similarity index 100% rename from src/ProjectR.Backend.Shared/Mappers/BusinessAvailabilityMapper.cs rename to src/ProjectR.Backend.Shared/Mappers/Mapper.cs From 3a9968a27d1576403812e20b0dd508da2a8cc319 Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Fri, 26 Sep 2025 00:23:26 +0100 Subject: [PATCH 04/13] added business availability endpoints --- .../BusinessesAvailabilityController.cs | 69 +++ .../Managers/IBusinessAvailabilityManager.cs | 10 +- .../IBusinessAvailabilityRepository.cs | 1 + .../Models/BusinessAvailabilityModel.cs | 4 - .../Models/BusinessAvailabilitySlotModel.cs | 2 + .../Models/ResponseModel.cs | 6 +- .../ProjectR.Backend.Application.csproj | 2 + .../Settings/BusinessAvailabilitySettings.cs | 10 + .../BusinessAvailabilityValidator.cs | 214 +++++++++ .../Managers/BusinessAvailabilityManager.cs | 88 ++-- .../ProjectR.Backend.Infrastructure.csproj | 2 + .../ServiceCollectionRegistration.cs | 7 + ...25458_AddedDateTimeToSlotTable.Designer.cs | 426 ++++++++++++++++++ ...20250925225458_AddedDateTimeToSlotTable.cs | 30 ++ .../Migrations/AppDbContextModelSnapshot.cs | 3 + .../BusinessAvailabilityRepository.cs | 12 +- src/appsettings.json | 3 + 17 files changed, 835 insertions(+), 54 deletions(-) create mode 100644 src/Controllers/BusinessesAvailabilityController.cs create mode 100644 src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs create mode 100644 src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs diff --git a/src/Controllers/BusinessesAvailabilityController.cs b/src/Controllers/BusinessesAvailabilityController.cs new file mode 100644 index 0000000..07a86c9 --- /dev/null +++ b/src/Controllers/BusinessesAvailabilityController.cs @@ -0,0 +1,69 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ProjectR.Backend.Application.Interfaces.Managers; +using ProjectR.Backend.Application.Models; + +namespace ProjectR.Backend.Controllers +{ + [Authorize] + [Route("api/[controller]")] + public class BusinessAvailabilityController : BaseController + { + private readonly IBusinessAvailabilityManager _manager; + + public BusinessAvailabilityController(IBusinessAvailabilityManager manager) + { + _manager = manager; + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BusinessAvailabilityModel[]))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(BusinessAvailabilityModel[]))] + [HttpGet("GetByBusiness/{id:guid}")] + public async Task GetByBusiness(Guid Id) + { + BusinessAvailabilityModel[] result = await _manager.GetByBusinessId(Id); + return Ok(result); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] + [HttpGet("{id:guid}")] + public async Task Get(Guid id) + { + ResponseModel result = await _manager.GetByIdAsync(id); + return result.Status ? Ok(result) : BadRequest(); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [HttpPost] + public async Task Add([FromBody] AddBusinessAvailabilityModel business) + { + if (business == null || !ModelState.IsValid) + { + return BadRequest(ModelState); + } + + ResponseModel result = await _manager.AddAsync(business); + return result.Status ? Ok(result) : BadRequest(result); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [HttpPut("{id:guid}")] + public async Task Update(Guid id, [FromBody] UpdateBusinessAvailabilityModel model) + { + if (model == null || !ModelState.IsValid) + { + return BadRequest(ModelState); + } + + ResponseModel result = await _manager.UpdateAsync(id, model); + return result.Status ? Ok(result) : BadRequest(result); + } + } +} diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs index 3572673..c08918d 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs @@ -4,11 +4,15 @@ namespace ProjectR.Backend.Application.Interfaces.Managers { public interface IBusinessAvailabilityManager { - Task GetByBusinessIdAsync(); Task> GetByIdAsync(Guid id); Task> AddAsync(AddBusinessAvailabilityModel model); - Task> UpdateAsync(UpdateBusinessAvailabilityModel user); - Task DeleteAsync(Guid Id); + Task> UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); Task GetByBusinessId(Guid businessId); + /// + /// Check if the business has any availability set already within a date range + /// + /// + /// + Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs index 5e94f47..b29f74e 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs @@ -8,5 +8,6 @@ public interface IBusinessAvailabilityRepository Task GetAllByBusinessIdAsync(Guid id); Task AddAsync(BusinessAvailabilityModel model); Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); + Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs index 7b976c3..8392f54 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs @@ -36,8 +36,6 @@ public class AddBusinessAvailabilityModel public DateOnly? EndDate { get; set; } public List Slots { get; set; } = []; - - public List Breaks { get; set; } = []; } public class UpdateBusinessAvailabilityModel @@ -47,8 +45,6 @@ public class UpdateBusinessAvailabilityModel [Required, MinLength(1, ErrorMessage = "At least one slot is required")] public List? Slots { get; set; } - - public List? Breaks { get; set; } } } diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs index 9931105..6570e42 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -37,6 +37,8 @@ public class AddBusinessAvailabilitySlotModel [Required] public TimeOnly? EndTime { get; set; } + + public List Breaks { get; set; } = []; } } diff --git a/src/ProjectR.Backend.Application/Models/ResponseModel.cs b/src/ProjectR.Backend.Application/Models/ResponseModel.cs index 9112872..370e6f4 100644 --- a/src/ProjectR.Backend.Application/Models/ResponseModel.cs +++ b/src/ProjectR.Backend.Application/Models/ResponseModel.cs @@ -4,15 +4,17 @@ public class BaseResponseModel { public bool Status { get; private set; } public string? Message { get; private set; } - public BaseResponseModel(string? message = "", bool status = true) + public string[] Errors { get; private set; } + public BaseResponseModel(string? message = "", bool status = true, string[]? errors = null) { Message = message; Status = status; + Errors = errors ?? Array.Empty(); } } public class ResponseModel : BaseResponseModel { - public ResponseModel(string? message, T? data, bool status = true) : base(message, status) + public ResponseModel(string? message, T? data, bool status = true, string[]? errors = null) : base(message, status, errors) { Data = data; } diff --git a/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj b/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj index 4500a87..899ca8f 100644 --- a/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj +++ b/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj @@ -17,6 +17,8 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs b/src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs new file mode 100644 index 0000000..59abbab --- /dev/null +++ b/src/ProjectR.Backend.Application/Settings/BusinessAvailabilitySettings.cs @@ -0,0 +1,10 @@ +namespace ProjectR.Backend.Application.Settings +{ + public class BusinessAvailabilitySettings + { + /// + /// Maximum number of days in advance a booking can be made + /// + public int MaxAdvanceBookingInDays { get; set; } + } +} diff --git a/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs new file mode 100644 index 0000000..0b6d550 --- /dev/null +++ b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs @@ -0,0 +1,214 @@ +using FluentValidation; +using Microsoft.Extensions.Options; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Application.Settings; +using ProjectR.Backend.Domain.Entities; + +namespace ProjectR.Backend.Application.Validators +{ + public class BusinessAvailabilityValidator : AbstractValidator + { + private readonly BusinessAvailabilitySettings _settings; + + public BusinessAvailabilityValidator(IOptions settings) + { + #region Validation Checks + //check that the end date is after the start date + //check if the business exist + //check if business availability already exists for the business + + //check that slots are valid i.e One slot to One day of the week + //check that only one date is used in the slots + //check that there are not dup + + //ensure that start time of the date is before the end time + //ensure that the times in the breaks are within the time of the slot + //should we let users have breaks occupying the whole slot time? + #endregion + + _settings = settings.Value; + + // Rule: BusinessId required + RuleFor(x => x.BusinessId) + .NotEmpty().WithMessage("BusinessId is required."); + + // Rule: StartDate and EndDate required and valid + RuleFor(x => x.StartDate) + .NotNull().WithMessage("Start date is required."); + + RuleFor(x => x.EndDate) + .NotNull().WithMessage("End date is required."); + + // Rule: EndDate must be after StartDate + RuleFor(x => x.EndDate) + .GreaterThanOrEqualTo(x => x.StartDate) + .When(x => x.StartDate.HasValue && x.EndDate.HasValue) + .WithMessage("End date must be after or equal to start date."); + + // Rule: Gap must not exceed settings.MaxAdvanceBookingInDays + RuleFor(x => x) + .Must(x => + { + if (x.StartDate.HasValue && x.EndDate.HasValue) + { + TimeSpan diff = x.EndDate.Value.ToDateTime(TimeOnly.MinValue) + - x.StartDate.Value.ToDateTime(TimeOnly.MinValue); + return diff.Days <= _settings.MaxAdvanceBookingInDays; + } + + return true; + }) + .WithMessage($"The gap between start and end date cannot exceed {_settings.MaxAdvanceBookingInDays} days."); + + // Rule: At least one slot required + RuleFor(x => x.Slots) + .NotNull().WithMessage("At least one slot is required.") + .Must(slots => slots != null && slots.Count > 0) + .WithMessage("At least one slot is required."); + + // Rule: Each slot must have valid times and date + RuleForEach(x => x.Slots).SetValidator(new AddBusinessAvailabilitySlotValidator()); + + // Rule: No overlapping slots on the same date + RuleFor(x => x.Slots) + .Must(slots => + { + if (slots == null) + { + return true; + } + + IEnumerable> slotGroups = slots.GroupBy(s => s.Date.Date); + foreach (IGrouping group in slotGroups) + { + List slotList = group.ToList(); + for (int i = 0; i < slotList.Count; i++) + { + for (int j = i + 1; j < slotList.Count; j++) + { + AddBusinessAvailabilitySlotModel a = slotList[i]; + AddBusinessAvailabilitySlotModel b = slotList[j]; + if (a.StartTime.HasValue && a.EndTime.HasValue && b.StartTime.HasValue && b.EndTime.HasValue) + { + if (a.StartTime < b.EndTime && b.StartTime < a.EndTime) + { + return false; + } + } + } + } + } + + return true; + }) + .WithMessage("Slots must not overlap on the same date."); + + // Rule: Breaks must not overlap within the same slot + RuleFor(x => x.Slots) + .Must(slots => + { + if (slots == null) + { + return true; + } + + foreach (AddBusinessAvailabilitySlotModel? slot in slots) + { + if (slot.Breaks == null) + { + continue; + } + + List breaks = slot.Breaks; + for (int i = 0; i < breaks.Count; i++) + { + for (int j = i + 1; j < breaks.Count; j++) + { + AddBreakModel a = breaks[i]; + AddBreakModel b = breaks[j]; + if (a.StartTime.HasValue && a.EndTime.HasValue && b.StartTime.HasValue && b.EndTime.HasValue) + { + if (a.StartTime < b.EndTime && b.StartTime < a.EndTime) + { + return false; + } + } + } + } + } + + return true; + }) + .WithMessage("Breaks within a slot must not overlap."); + + // Rule: Each break must be within the slot's time range + RuleFor(x => x.Slots) + .Must(slots => + { + if (slots == null) + { + return true; + } + + foreach (AddBusinessAvailabilitySlotModel? slot in slots) + { + if (slot.Breaks == null) + { + continue; + } + + foreach (AddBreakModel brk in slot.Breaks) + { + if (slot.StartTime.HasValue && slot.EndTime.HasValue && brk.StartTime.HasValue && brk.EndTime.HasValue) + { + if (brk.StartTime < slot.StartTime || brk.EndTime > slot.EndTime) + { + return false; + } + } + } + } + + return true; + }) + .WithMessage("Breaks must be within the slot's start and end time."); + } + } + + public class AddBusinessAvailabilitySlotValidator : AbstractValidator + { + public AddBusinessAvailabilitySlotValidator() + { + RuleFor(x => x.Date) + .NotEmpty().WithMessage("Slot date is required."); + + RuleFor(x => x.StartTime) + .NotNull().WithMessage("Slot start time is required."); + + RuleFor(x => x.EndTime) + .NotNull().WithMessage("Slot end time is required."); + + RuleFor(x => x) + .Must(x => x.StartTime.HasValue && x.EndTime.HasValue && x.EndTime > x.StartTime) + .WithMessage("Slot end time must be after start time."); + + RuleForEach(x => x.Breaks).SetValidator(new AddBreakValidator()); + } + } + + public class AddBreakValidator : AbstractValidator + { + public AddBreakValidator() + { + RuleFor(x => x.StartTime) + .NotNull().WithMessage("Break start time is required."); + + RuleFor(x => x.EndTime) + .NotNull().WithMessage("Break end time is required."); + + RuleFor(x => x) + .Must(x => x.StartTime.HasValue && x.EndTime.HasValue && x.EndTime > x.StartTime) + .WithMessage("Break end time must be after start time."); + } + } +} \ No newline at end of file diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs index 4efa913..988d47d 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs @@ -1,84 +1,84 @@ +using FluentValidation; +using FluentValidation.Results; +using Microsoft.Extensions.Options; using ProjectR.Backend.Application.Interfaces.Managers; using ProjectR.Backend.Application.Interfaces.Repository; using ProjectR.Backend.Application.Models; -using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Application.Settings; +using ProjectR.Backend.Shared.Mappers; namespace ProjectR.Backend.Infrastructure.Managers { public class BusinessAvailabilityManager : IBusinessAvailabilityManager { public readonly IBusinessAvailabilityRepository _repository; + public readonly IBusinessManager _businessManager; + private readonly BusinessAvailabilitySettings _options; + private readonly IValidator _validator; - public BusinessAvailabilityManager(IBusinessAvailabilityRepository repository) + public BusinessAvailabilityManager(IBusinessAvailabilityRepository repository, IOptions options, IValidator validator, IBusinessManager businessManager) { _repository = repository; + _options = options.Value ?? throw new ArgumentNullException(nameof(options)); + _businessManager = businessManager ?? throw new ArgumentNullException(nameof(businessManager)); + _validator = validator ?? throw new ArgumentNullException(nameof(validator)); } public async Task> AddAsync(AddBusinessAvailabilityModel model) { - //check if the days are more than one week apart - //check if the business exist - //check if business availability already exists for the business - - //check that slots are valid i.e One slot to One day of the week - //check that only one date is used in the slots - //check that there are not dup - - //ensure that start time of the date is before the end time - //ensure that the times in the breaks are within the time of the slot - //should we let users have breaks occupying the whole slot time? - - // Map to BusinessAvailabilityModel + ResponseModel business = await _businessManager.GetByIdAsync(model.BusinessId); + if (business.Data == null) + { + return new ResponseModel("Business not found", null, false); + } - // Create new availability + //TODO: check if the business already has availability set for the same day and time range + //for example, if the business has availability on 12th - 19th June, it should not be able to add another availability for the same date range - BusinessAvailabilityModel newAvailability = new() + ValidationResult validate = _validator.Validate(model); + if (!validate.IsValid) { - BusinessId = model.BusinessId, - Slots = model.Slots?.Select(slot => new BusinessAvailabilitySlotModel - { - Date = slot.Date, - DayOfWeek = slot.Date.DayOfWeek, - StartTime = slot.StartTime, - EndTime = slot.EndTime, - Breaks = model.Breaks?.Select(b => new BreakModel - { - StartTime = b.StartTime, - EndTime = b.EndTime - }).ToList() - }).ToList() - }; + return new ResponseModel(message: "Validation errors occurred", data: null, status: false, errors: validate.Errors.Select(e => e.ErrorMessage).ToArray()); + } + BusinessAvailabilityModel newAvailability = Mapper.Map(model); await _repository.AddAsync(newAvailability); return new ResponseModel(message: "Business Availability created successfully", data: newAvailability, status: true); } - public async Task DeleteAsync(Guid Id) - { - throw new NotImplementedException(); - } - public async Task GetByBusinessId(Guid businessId) { BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(businessId); return result; } - public async Task GetByBusinessIdAsync() - { - BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(Guid.Empty); - return result; - } - public async Task> GetByIdAsync(Guid id) { BusinessAvailabilityModel? result = await _repository.GetByIdAsync(id); return new ResponseModel(message: result != null ? "Business Availability retrieved successfully" : "Business Availability not found", data: result, status: result != null); } - public async Task> UpdateAsync(UpdateBusinessAvailabilityModel user) + public async Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate) + { + return await _repository.HasActiveAvailabilityAsync(businessId, startDate, endDate); + } + + public async Task> UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model) { - throw new NotImplementedException(); + BusinessAvailabilityModel? existing = await _repository.GetByIdAsync(id); + if (existing == null) + { + return new ResponseModel("Business Availability not found", null, false); + } + + UpdateBusinessAvailabilityModel updatedAvailability = Mapper.Map(model); + BusinessAvailabilityModel result = await _repository.UpdateAsync(id, updatedAvailability); + + //put all notification into a table and have a background service send them out or Send them out in parallel using Task.WhenAll + //TODO: send notification to business owner about the update (via WhatsApp) + //TODO: send notification to customers who have bookings in the updated slots (WhatsApp) + //TODO: send out a SignalR notification to connected clients about the update + return new ResponseModel("Business Availability updated successfully", result, true); } } } diff --git a/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj b/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj index d256f27..0e7cd7a 100644 --- a/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj +++ b/src/ProjectR.Backend.Infrastructure/ProjectR.Backend.Infrastructure.csproj @@ -8,6 +8,8 @@ + + diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index 600bae5..d911cf0 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -1,4 +1,5 @@ using CloudinaryDotNet; +using FluentValidation; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -13,6 +14,7 @@ using ProjectR.Backend.Application.Interfaces.Repository; using ProjectR.Backend.Application.Interfaces.Utility; using ProjectR.Backend.Application.Settings; +using ProjectR.Backend.Application.Validators; using ProjectR.Backend.Infrastructure.Managers; using ProjectR.Backend.Infrastructure.Providers; using ProjectR.Backend.Infrastructure.Utility; @@ -34,6 +36,11 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.Configure(configuration.GetSection("Twilio")); services.Configure(configuration.GetSection("Otp")); services.Configure(configuration.GetSection("Cloudinary")); + services.Configure(configuration.GetSection("BusinessAvailability")); + #endregion + + #region Validators + services.AddValidatorsFromAssemblyContaining(); #endregion #region Providers diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs new file mode 100644 index 0000000..b1b07ae --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs @@ -0,0 +1,426 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using ProjectR.Backend.Persistence.DatabaseContext; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250925225458_AddedDateTimeToSlotTable")] + partial class AddedDateTimeToSlotTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AppThemes"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("About") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Industry") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Latitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Location") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Logo") + .HasColumnType("text"); + + b.Property("Longitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PhoneCode") + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("ServiceType") + .HasColumnType("integer"); + + b.Property("ShortLink") + .HasColumnType("text"); + + b.Property("Type") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("businesses", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessId"); + + b.ToTable("BusinessAvailabilities"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilityId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilityId"); + + b.ToTable("BusinessAvailabilitySlots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeliveryMode") + .HasColumnType("integer"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OtpType") + .HasColumnType("integer"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Otps"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("PhoneCode") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("RegistrationType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsProcessed") + .HasColumnType("boolean"); + + b.Property("LastProcessedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastProcessedResult") + .HasColumnType("text"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("WebhookMessages"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") + .WithMany() + .HasForeignKey("BusinessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Business"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") + .WithMany("Slots") + .HasForeignKey("BusinessAvailabilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailability"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Navigation("Slots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs new file mode 100644 index 0000000..152206a --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class AddedDateTimeToSlotTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Date", + table: "BusinessAvailabilitySlots", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Date", + table: "BusinessAvailabilitySlots"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs index 5e7fe6d..f160050 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -189,6 +189,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); + b.Property("Date") + .HasColumnType("timestamp with time zone"); + b.Property("DayOfWeek") .HasColumnType("integer"); diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs index 98e0c37..9c90393 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -5,6 +5,7 @@ using ProjectR.Backend.Application.Models; using ProjectR.Backend.Shared.Mappers; using Microsoft.EntityFrameworkCore.ChangeTracking; +using ProjectR.Backend.Shared; namespace ProjectR.Backend.Persistence.Repository { @@ -22,7 +23,7 @@ public BusinessAvailabilityRepository(AppDbContext appDbContext) BusinessAvailability? availability = await _appDbContext.BusinessAvailabilities .Include(x => x.Slots)! .ThenInclude(s => s.Breaks) - .FirstOrDefaultAsync(x => x.Id == id); + .FirstOrDefaultAsync(x => x.Id == id && x.RecordStatus == RecordStatus.Active); if (availability == null) { @@ -90,5 +91,14 @@ public async Task GetAllByBusinessIdAsync(Guid id) return availabilities.Select(c => Mapper.Map(c)).ToArray(); } + + public async Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate) + { + return await _appDbContext.BusinessAvailabilities + .AnyAsync(x => x.BusinessId == businessId + && x.RecordStatus == RecordStatus.Active + && x.StartDate <= endDate + && x.EndDate >= startDate); + } } } \ No newline at end of file diff --git a/src/appsettings.json b/src/appsettings.json index 3aba6a9..670b498 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -28,5 +28,8 @@ "CloudName": "dowypvotw", "ApiKey": "717696641265335", "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" + }, + "BusinessAvailability": { + "MaxAdvanceBookingInDays": 7 } } From 6ca24a13c7a54157d3cbb3fdac8977fe63359622 Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Fri, 26 Sep 2025 23:19:51 +0100 Subject: [PATCH 05/13] business availability: controllers --- .../Managers/IBusinessAvailabilityManager.cs | 2 +- .../IBusinessAvailabilityRepository.cs | 2 +- .../Models/BusinessAvailabilityModel.cs | 8 +- .../BusinessAvailabilityValidator.cs | 4 +- .../Entities/BusinessAvailability.cs | 7 +- .../Managers/BusinessAvailabilityManager.cs | 6 +- ...pdatedDateOnlyFieldsToDateTime.Designer.cs | 426 ++++++++++++++++++ ...6165354_UpdatedDateOnlyFieldsToDateTime.cs | 51 +++ .../Migrations/AppDbContextModelSnapshot.cs | 8 +- .../BusinessAvailabilityRepository.cs | 6 +- 10 files changed, 496 insertions(+), 24 deletions(-) create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs index c08918d..b66d566 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs @@ -13,6 +13,6 @@ public interface IBusinessAvailabilityManager /// /// /// - Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate); + Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs index b29f74e..a06acb9 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs @@ -8,6 +8,6 @@ public interface IBusinessAvailabilityRepository Task GetAllByBusinessIdAsync(Guid id); Task AddAsync(BusinessAvailabilityModel model); Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); - Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate); + Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs index 8392f54..55dbba8 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilityModel.cs @@ -12,10 +12,10 @@ public class BusinessAvailabilityModel public Guid BusinessId { get; set; } [Required] - public DateOnly? StartDate { get; set; } + public DateTime? StartDate { get; set; } [Required] - public DateOnly? EndDate { get; set; } + public DateTime? EndDate { get; set; } [Required, MinLength(1, ErrorMessage = "At least one slot is required")] public ICollection? Slots { get; set; } @@ -30,10 +30,10 @@ public class AddBusinessAvailabilityModel public Guid BusinessId { get; set; } [DataType(DataType.Date, ErrorMessage = "Invalid date format")] - public DateOnly? StartDate { get; set; } + public DateTime? StartDate { get; set; } [DataType(DataType.Date, ErrorMessage = "Invalid date format")] - public DateOnly? EndDate { get; set; } + public DateTime? EndDate { get; set; } public List Slots { get; set; } = []; } diff --git a/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs index 0b6d550..061feec 100644 --- a/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs +++ b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs @@ -51,8 +51,8 @@ public BusinessAvailabilityValidator(IOptions sett { if (x.StartDate.HasValue && x.EndDate.HasValue) { - TimeSpan diff = x.EndDate.Value.ToDateTime(TimeOnly.MinValue) - - x.StartDate.Value.ToDateTime(TimeOnly.MinValue); + TimeSpan diff = x.EndDate.Value + - x.StartDate.Value; return diff.Days <= _settings.MaxAdvanceBookingInDays; } diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs index 93c078a..262ebde 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs @@ -1,6 +1,3 @@ -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; - namespace ProjectR.Backend.Domain.Entities { /// @@ -10,8 +7,8 @@ public class BusinessAvailability : BaseObject { public Guid BusinessId { get; set; } public Business? Business { get; set; } - public DateOnly? StartDate { get; set; } - public DateOnly? EndDate { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } public ICollection? Slots { get; set; } } } diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs index 988d47d..024f685 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs @@ -13,13 +13,11 @@ public class BusinessAvailabilityManager : IBusinessAvailabilityManager { public readonly IBusinessAvailabilityRepository _repository; public readonly IBusinessManager _businessManager; - private readonly BusinessAvailabilitySettings _options; private readonly IValidator _validator; - public BusinessAvailabilityManager(IBusinessAvailabilityRepository repository, IOptions options, IValidator validator, IBusinessManager businessManager) + public BusinessAvailabilityManager(IBusinessAvailabilityRepository repository, IValidator validator, IBusinessManager businessManager) { _repository = repository; - _options = options.Value ?? throw new ArgumentNullException(nameof(options)); _businessManager = businessManager ?? throw new ArgumentNullException(nameof(businessManager)); _validator = validator ?? throw new ArgumentNullException(nameof(validator)); } @@ -58,7 +56,7 @@ public async Task> GetByIdAsync(Guid id return new ResponseModel(message: result != null ? "Business Availability retrieved successfully" : "Business Availability not found", data: result, status: result != null); } - public async Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate) + public async Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate) { return await _repository.HasActiveAvailabilityAsync(businessId, startDate, endDate); } diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs new file mode 100644 index 0000000..63f68ad --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs @@ -0,0 +1,426 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using ProjectR.Backend.Persistence.DatabaseContext; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250926165354_UpdatedDateOnlyFieldsToDateTime")] + partial class UpdatedDateOnlyFieldsToDateTime + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AppThemes"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("About") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Industry") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Latitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Location") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Logo") + .HasColumnType("text"); + + b.Property("Longitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PhoneCode") + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("ServiceType") + .HasColumnType("integer"); + + b.Property("ShortLink") + .HasColumnType("text"); + + b.Property("Type") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("businesses", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessId"); + + b.ToTable("BusinessAvailabilities"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilityId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndTime") + .HasColumnType("time without time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("time without time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilityId"); + + b.ToTable("BusinessAvailabilitySlots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeliveryMode") + .HasColumnType("integer"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OtpType") + .HasColumnType("integer"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Otps"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("PhoneCode") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("RegistrationType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsProcessed") + .HasColumnType("boolean"); + + b.Property("LastProcessedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastProcessedResult") + .HasColumnType("text"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("WebhookMessages"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") + .WithMany() + .HasForeignKey("BusinessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Business"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") + .WithMany("Slots") + .HasForeignKey("BusinessAvailabilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailability"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Navigation("Slots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs b/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs new file mode 100644 index 0000000..1774e73 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs @@ -0,0 +1,51 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class UpdatedDateOnlyFieldsToDateTime : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "StartDate", + table: "BusinessAvailabilities", + type: "timestamp with time zone", + nullable: false, + oldClrType: typeof(DateOnly), + oldType: "date"); + + migrationBuilder.AlterColumn( + name: "EndDate", + table: "BusinessAvailabilities", + type: "timestamp with time zone", + nullable: false, + oldClrType: typeof(DateOnly), + oldType: "date"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "StartDate", + table: "BusinessAvailabilities", + type: "date", + nullable: false, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "EndDate", + table: "BusinessAvailabilities", + type: "date", + nullable: false, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs index f160050..7056191 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -155,14 +155,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); - b.Property("EndDate") - .HasColumnType("date"); + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); b.Property("RecordStatus") .HasColumnType("integer"); - b.Property("StartDate") - .HasColumnType("date"); + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); b.Property("UpdatedAt") .HasColumnType("timestamp with time zone"); diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs index 9c90393..5c580db 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -92,13 +92,13 @@ public async Task GetAllByBusinessIdAsync(Guid id) return availabilities.Select(c => Mapper.Map(c)).ToArray(); } - public async Task HasActiveAvailabilityAsync(Guid businessId, DateOnly startDate, DateOnly endDate) + public async Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate) { return await _appDbContext.BusinessAvailabilities .AnyAsync(x => x.BusinessId == businessId && x.RecordStatus == RecordStatus.Active - && x.StartDate <= endDate - && x.EndDate >= startDate); + && x.StartDate!.Value.Date <= endDate + && x.EndDate!.Value.Date >= startDate); } } } \ No newline at end of file From 707e95408943251e04417a20bb0a479d3a0f5c00 Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Fri, 26 Sep 2025 23:32:25 +0100 Subject: [PATCH 06/13] added flag to fetch all busines avaiability by businessId --- .../BusinessesAvailabilityController.cs | 4 +-- .../Managers/IBusinessAvailabilityManager.cs | 2 +- .../IBusinessAvailabilityRepository.cs | 2 +- .../Managers/BusinessAvailabilityManager.cs | 2 +- .../BusinessAvailabilityRepository.cs | 25 ++++++++++++++----- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Controllers/BusinessesAvailabilityController.cs b/src/Controllers/BusinessesAvailabilityController.cs index 07a86c9..08bf194 100644 --- a/src/Controllers/BusinessesAvailabilityController.cs +++ b/src/Controllers/BusinessesAvailabilityController.cs @@ -20,9 +20,9 @@ public BusinessAvailabilityController(IBusinessAvailabilityManager manager) [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BusinessAvailabilityModel[]))] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(BusinessAvailabilityModel[]))] [HttpGet("GetByBusiness/{id:guid}")] - public async Task GetByBusiness(Guid Id) + public async Task GetByBusiness(Guid Id, [FromQuery] bool includeAll = false) { - BusinessAvailabilityModel[] result = await _manager.GetByBusinessId(Id); + BusinessAvailabilityModel[] result = await _manager.GetByBusinessId(Id, includeAll); return Ok(result); } diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs index b66d566..d23f4cc 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessAvailabilityManager.cs @@ -7,7 +7,7 @@ public interface IBusinessAvailabilityManager Task> GetByIdAsync(Guid id); Task> AddAsync(AddBusinessAvailabilityModel model); Task> UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); - Task GetByBusinessId(Guid businessId); + Task GetByBusinessId(Guid businessId, bool includeAll = false); /// /// Check if the business has any availability set already within a date range /// diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs index a06acb9..a13b89c 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessAvailabilityRepository.cs @@ -5,7 +5,7 @@ namespace ProjectR.Backend.Application.Interfaces.Repository public interface IBusinessAvailabilityRepository { Task GetByIdAsync(Guid id); - Task GetAllByBusinessIdAsync(Guid id); + Task GetAllByBusinessIdAsync(Guid id, bool includeAll = false); Task AddAsync(BusinessAvailabilityModel model); Task UpdateAsync(Guid id, UpdateBusinessAvailabilityModel model); Task HasActiveAvailabilityAsync(Guid businessId, DateTime startDate, DateTime endDate); diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs index 024f685..a203446 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs @@ -44,7 +44,7 @@ public async Task> AddAsync(AddBusiness return new ResponseModel(message: "Business Availability created successfully", data: newAvailability, status: true); } - public async Task GetByBusinessId(Guid businessId) + public async Task GetByBusinessId(Guid businessId, bool includeAll = false) { BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(businessId); return result; diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs index 5c580db..eeef08d 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -81,14 +81,27 @@ public async Task UpdateAsync(Guid id, UpdateBusiness return Mapper.Map(availability); } - public async Task GetAllByBusinessIdAsync(Guid id) + public async Task GetAllByBusinessIdAsync(Guid id, bool includeAll = false) { - List availabilities = await _appDbContext.BusinessAvailabilities - .Include(x => x.Slots)! - .ThenInclude(s => s.Breaks) - .Where(x => x.BusinessId == id) - .ToListAsync(); + IQueryable query = _appDbContext.BusinessAvailabilities; + + if (includeAll) + { + query = query.Where(x => x.BusinessId == id); + } + else + { + query = query.Where(x => x.BusinessId == id && x.RecordStatus == RecordStatus.Active); + } + + // Conditionally include related entities only if needed + if (includeAll) + { + query = query.Include(x => x.Slots!) + .ThenInclude(s => s.Breaks); + } + List availabilities = await query.ToListAsync(); return availabilities.Select(c => Mapper.Map(c)).ToArray(); } From 3e12ff04e54fc81f8790b21398998e22feb31f0a Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Sat, 27 Sep 2025 14:13:07 +0100 Subject: [PATCH 07/13] fixed model binding issues --- .../BusinessesAvailabilityController.cs | 8 +++--- src/Controllers/BusinessesController.cs | 1 + .../Models/BreakModel.cs | 21 +++++++++------ .../Models/BusinessAvailabilitySlotModel.cs | 26 ++++++++++++------- .../Models/BusinessModel.cs | 8 ++++-- .../ServiceCollectionRegistration.cs | 2 ++ .../Repository/BusinessRepository.cs | 4 ++- 7 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/Controllers/BusinessesAvailabilityController.cs b/src/Controllers/BusinessesAvailabilityController.cs index 08bf194..df03508 100644 --- a/src/Controllers/BusinessesAvailabilityController.cs +++ b/src/Controllers/BusinessesAvailabilityController.cs @@ -40,14 +40,14 @@ public async Task Get(Guid id) [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] [HttpPost] - public async Task Add([FromBody] AddBusinessAvailabilityModel business) + public async Task Add([FromBody] AddBusinessAvailabilityModel model) { - if (business == null || !ModelState.IsValid) + if (model == null || !ModelState.IsValid) { return BadRequest(ModelState); } - - ResponseModel result = await _manager.AddAsync(business); + + ResponseModel result = await _manager.AddAsync(model); return result.Status ? Ok(result) : BadRequest(result); } diff --git a/src/Controllers/BusinessesController.cs b/src/Controllers/BusinessesController.cs index 0ea5dd5..390353e 100644 --- a/src/Controllers/BusinessesController.cs +++ b/src/Controllers/BusinessesController.cs @@ -57,6 +57,7 @@ public async Task Add([FromBody] AddBusinessModel business) return BadRequest(ModelState); } + business.UserId = UserId; ResponseModel result = await _businessManager.AddAsync(business); return result.Status ? Ok(result) : BadRequest(result); } diff --git a/src/ProjectR.Backend.Application/Models/BreakModel.cs b/src/ProjectR.Backend.Application/Models/BreakModel.cs index 137a71e..3f858c0 100644 --- a/src/ProjectR.Backend.Application/Models/BreakModel.cs +++ b/src/ProjectR.Backend.Application/Models/BreakModel.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; namespace ProjectR.Backend.Domain.Entities { @@ -9,19 +10,23 @@ public class BreakModel : BaseObject { [Required] public Guid BusinessAvailabilitySlotId { get; set; } + public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } - [Required] - public TimeOnly? StartTime { get; set; } - [Required] - public TimeOnly? EndTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTime? StartTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTime? EndTime { get; set; } } public class AddBreakModel { - [Required] - public TimeOnly? StartTime { get; set; } - [Required] - public TimeOnly? EndTime { get; set; } + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? StartTime { get; set; } + + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } } } diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs index 6570e42..7206314 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -13,15 +13,15 @@ public class BusinessAvailabilitySlotModel public BusinessAvailabilityModel? BusinessAvailability { get; set; } - [Required] + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] public TimeOnly? StartTime { get; set; } - [Required] - public TimeOnly? EndTime { get; set; } + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } public DayOfWeek DayOfWeek { get; set; } - [Required] + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] public DateTimeOffset Date { get; set; } public List? Breaks { get; set; } @@ -29,14 +29,20 @@ public class BusinessAvailabilitySlotModel public class AddBusinessAvailabilitySlotModel { - [Required] - public DateTime Date { get; set; } + [DataType(DataType.Date, ErrorMessage = "Invalid date format")] + public DateTimeOffset Date { get; set; } - [Required] - public TimeOnly? StartTime { get; set; } + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? StartTime { get; set; } - [Required] - public TimeOnly? EndTime { get; set; } + [DataType(DataType.Time, ErrorMessage = "Invalid time format")] + public DateTimeOffset? EndTime { get; set; } + + // [JsonIgnore] + // public TimeOnly? StartTimeInternal => TimeOnly.FromDateTime(StartTime!.Value); + + // [JsonIgnore] + // public TimeOnly? EndTimeInternal => TimeOnly.FromDateTime(EndTime!.Value); public List Breaks { get; set; } = []; } diff --git a/src/ProjectR.Backend.Application/Models/BusinessModel.cs b/src/ProjectR.Backend.Application/Models/BusinessModel.cs index 048a6d9..8f80da0 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessModel.cs @@ -1,11 +1,11 @@ -using Microsoft.AspNetCore.Http; using System.ComponentModel.DataAnnotations; -using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; namespace ProjectR.Backend.Application.Models { public class BusinessModel { + [JsonIgnore] public Guid UserId { get; set; } public Guid Id { get; set; } public string? Name { get; set; } @@ -23,12 +23,16 @@ public class BusinessModel public class AddBusinessModel { + [JsonIgnore] public Guid UserId { get; set; } + [Required(ErrorMessage = "Name is required")] public string? Name { get; set; } public string? Type { get; set; } + [Required(ErrorMessage = "Phone Code is required")] public string? PhoneCode { get; set; } + [Required(ErrorMessage = "Phone Number is required")] public string? PhoneNumber { get; set; } public string? Industry { get; set; } diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index d911cf0..f3ab1e3 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -55,6 +55,7 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); #endregion #region Managers @@ -69,6 +70,7 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); #endregion #region Services diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs index 2f86a86..7a1b002 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using ProjectR.Backend.Application.Interfaces.Repository; using ProjectR.Backend.Application.Models; using ProjectR.Backend.Domain.Entities; @@ -69,7 +70,8 @@ public async Task AddAsync(BusinessModel businessModel) Logo = businessModel.Logo }; - await _context.Businesses.AddAsync(entity); + EntityEntry result = await _context.Businesses.AddAsync(entity); + result.Entity.Id = entity.Id; await _context.SaveChangesAsync(); return businessModel; } From cde482e2fe7df8a5cf19053c947aec79c3c4fb9c Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Sat, 27 Sep 2025 18:14:23 +0100 Subject: [PATCH 08/13] fixed datetime --- .../Models/BreakModel.cs | 4 +- .../Models/BusinessAvailabilitySlotModel.cs | 2 +- src/ProjectR.Backend.Domain/Entities/Break.cs | 4 +- .../Entities/BusinessAvailability.cs | 4 +- .../Entities/BusinessAvailabilitySlot.cs | 4 +- ..._ChangedFromTimeOnlyToDateTime.Designer.cs | 426 ++++++++++++++++++ ...927151832_ChangedFromTimeOnlyToDateTime.cs | 91 ++++ .../Migrations/AppDbContextModelSnapshot.cs | 16 +- 8 files changed, 534 insertions(+), 17 deletions(-) create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs diff --git a/src/ProjectR.Backend.Application/Models/BreakModel.cs b/src/ProjectR.Backend.Application/Models/BreakModel.cs index 3f858c0..f926e40 100644 --- a/src/ProjectR.Backend.Application/Models/BreakModel.cs +++ b/src/ProjectR.Backend.Application/Models/BreakModel.cs @@ -14,10 +14,10 @@ public class BreakModel : BaseObject public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } [DataType(DataType.Time, ErrorMessage = "Invalid time format")] - public DateTime? StartTime { get; set; } + public DateTimeOffset? StartTime { get; set; } [DataType(DataType.Time, ErrorMessage = "Invalid time format")] - public DateTime? EndTime { get; set; } + public DateTimeOffset? EndTime { get; set; } } public class AddBreakModel diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs index 7206314..12210fb 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -14,7 +14,7 @@ public class BusinessAvailabilitySlotModel public BusinessAvailabilityModel? BusinessAvailability { get; set; } [DataType(DataType.Time, ErrorMessage = "Invalid time format")] - public TimeOnly? StartTime { get; set; } + public DateTimeOffset? StartTime { get; set; } [DataType(DataType.Time, ErrorMessage = "Invalid time format")] public DateTimeOffset? EndTime { get; set; } diff --git a/src/ProjectR.Backend.Domain/Entities/Break.cs b/src/ProjectR.Backend.Domain/Entities/Break.cs index 85fd70c..b8d2579 100644 --- a/src/ProjectR.Backend.Domain/Entities/Break.cs +++ b/src/ProjectR.Backend.Domain/Entities/Break.cs @@ -11,9 +11,9 @@ public class Break : BaseObject public Guid BusinessAvailabilitySlotId { get; set; } public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } [Required] - public TimeOnly? StartTime { get; set; } + public DateTimeOffset? StartTime { get; set; } [Required] - public TimeOnly? EndTime { get; set; } + public DateTimeOffset? EndTime { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs index 262ebde..f0e4108 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs @@ -7,8 +7,8 @@ public class BusinessAvailability : BaseObject { public Guid BusinessId { get; set; } public Business? Business { get; set; } - public DateTime? StartDate { get; set; } - public DateTime? EndDate { get; set; } + public DateTimeOffset? StartDate { get; set; } + public DateTimeOffset? EndDate { get; set; } public ICollection? Slots { get; set; } } } diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs index e5f566b..417e175 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailabilitySlot.cs @@ -11,9 +11,9 @@ public class BusinessAvailabilitySlot : BaseObject public Guid BusinessAvailabilityId { get; set; } public BusinessAvailability? BusinessAvailability { get; set; } [Required] - public TimeOnly? StartTime { get; set; } + public DateTimeOffset? StartTime { get; set; } [Required] - public TimeOnly? EndTime { get; set; } + public DateTimeOffset? EndTime { get; set; } public DayOfWeek DayOfWeek { get; set; } /// /// The specific date for this slot. Slots are generally recurring weekly but this date represents the specific date for this slot diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs new file mode 100644 index 0000000..81b41b0 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs @@ -0,0 +1,426 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using ProjectR.Backend.Persistence.DatabaseContext; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250927151832_ChangedFromTimeOnlyToDateTime")] + partial class ChangedFromTimeOnlyToDateTime + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AppThemes"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilitySlotId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilitySlotId"); + + b.ToTable("Breaks"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("About") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Industry") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Latitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Location") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Logo") + .HasColumnType("text"); + + b.Property("Longitude") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PhoneCode") + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .HasMaxLength(15) + .HasColumnType("character varying(15)"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("ServiceType") + .HasColumnType("integer"); + + b.Property("ShortLink") + .HasColumnType("text"); + + b.Property("Type") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("businesses", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessId"); + + b.ToTable("BusinessAvailabilities"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BusinessAvailabilityId") + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DayOfWeek") + .HasColumnType("integer"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("BusinessAvailabilityId"); + + b.ToTable("BusinessAvailabilitySlots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Description") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.ToTable("Industries"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeliveryMode") + .HasColumnType("integer"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OtpType") + .HasColumnType("integer"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Otps"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("PhoneCode") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character varying(4)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("RegistrationType") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsProcessed") + .HasColumnType("boolean"); + + b.Property("LastProcessedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastProcessedResult") + .HasColumnType("text"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("RecordStatus") + .HasColumnType("integer"); + + b.Property("Source") + .HasColumnType("integer"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UpdatedBy") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("WebhookMessages"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") + .WithMany("Breaks") + .HasForeignKey("BusinessAvailabilitySlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailabilitySlot"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") + .WithMany() + .HasForeignKey("BusinessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Business"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") + .WithMany("Slots") + .HasForeignKey("BusinessAvailabilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("BusinessAvailability"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => + { + b.Navigation("Slots"); + }); + + modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => + { + b.Navigation("Breaks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs b/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs new file mode 100644 index 0000000..5618c5d --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs @@ -0,0 +1,91 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class ChangedFromTimeOnlyToDateTime : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "StartTime", + table: "BusinessAvailabilitySlots", + type: "timestamp with time zone", + nullable: false, + oldClrType: typeof(TimeOnly), + oldNullable: false, + oldType: "time without time zone") + .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); + + migrationBuilder.AlterColumn( + name: "EndTime", + table: "BusinessAvailabilitySlots", + type: "timestamp with time zone", + nullable: false, + oldClrType: typeof(TimeOnly), + oldNullable: false, + oldType: "time without time zone") + .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); + + migrationBuilder.AlterColumn( + name: "StartTime", + table: "Breaks", + type: "timestamp with time zone", + nullable: false, + oldClrType: typeof(TimeOnly), + oldNullable: false, + oldType: "time without time zone") + .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); + + migrationBuilder.AlterColumn( + name: "EndTime", + table: "Breaks", + type: "timestamp with time zone", + nullable: false, + oldClrType: typeof(TimeOnly), + oldNullable: false, + oldType: "time without time zone") + .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "StartTime", + table: "BusinessAvailabilitySlots", + type: "time without time zone", + nullable: false, + oldClrType: typeof(DateTimeOffset), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "EndTime", + table: "BusinessAvailabilitySlots", + type: "time without time zone", + nullable: false, + oldClrType: typeof(DateTimeOffset), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "StartTime", + table: "Breaks", + type: "time without time zone", + nullable: false, + oldClrType: typeof(DateTimeOffset), + oldType: "timestamp with time zone"); + + migrationBuilder.AlterColumn( + name: "EndTime", + table: "Breaks", + type: "time without time zone", + nullable: false, + oldClrType: typeof(DateTimeOffset), + oldType: "timestamp with time zone"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs index 7056191..d920376 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -48,14 +48,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); - b.Property("EndTime") - .HasColumnType("time without time zone"); + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); b.Property("RecordStatus") .HasColumnType("integer"); - b.Property("StartTime") - .HasColumnType("time without time zone"); + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); b.Property("UpdatedAt") .HasColumnType("timestamp with time zone"); @@ -195,14 +195,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("DayOfWeek") .HasColumnType("integer"); - b.Property("EndTime") - .HasColumnType("time without time zone"); + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); b.Property("RecordStatus") .HasColumnType("integer"); - b.Property("StartTime") - .HasColumnType("time without time zone"); + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); b.Property("UpdatedAt") .HasColumnType("timestamp with time zone"); From e8b94f7b624d08dcbf33d7888864eff868f6ba18 Mon Sep 17 00:00:00 2001 From: Faith Sodipe Date: Sun, 28 Sep 2025 22:38:22 +0100 Subject: [PATCH 09/13] fix: switched db provider for local --- docker-compose.yml | 48 +- src/Controllers/IndustryController.cs | 4 +- .../ProjectR.Backend.Application.csproj | 1 + .../ServiceCollectionRegistration.cs | 4 +- ...0250711140719_InitialMigration.Designer.cs | 271 ----------- .../20250711140719_InitialMigration.cs | 162 ------- ...0715221843_AddedNameToAppTheme.Designer.cs | 285 ----------- .../20250715221843_AddedNameToAppTheme.cs | 34 -- ...URLandShortLinkToBusinessTable.Designer.cs | 291 ------------ ...000_AddedURLandShortLinkToBusinessTable.cs | 38 -- .../20250730144416_AddedOtpTable.Designer.cs | 335 ------------- .../20250730144416_AddedOtpTable.cs | 44 -- ...14128_AddedWebhookMessageTable.Designer.cs | 373 --------------- ...20250809114128_AddedWebhookMessageTable.cs | 42 -- ...50818204545_AddedIndustryTable.Designer.cs | 355 -------------- .../20250818204545_AddedIndustryTable.cs | 35 -- ...9082107_AddIndustryDescription.Designer.cs | 355 -------------- .../20250819082107_AddIndustryDescription.cs | 22 - ...250906151923_UnexpectedChanges.Designer.cs | 442 ------------------ .../20250906151923_UnexpectedChanges.cs | 245 ---------- ...ddedBusinessAvailabilityTables.Designer.cs | 423 ----------------- ...1160654_AddedBusinessAvailabilityTables.cs | 259 ---------- ...25458_AddedDateTimeToSlotTable.Designer.cs | 426 ----------------- ...20250925225458_AddedDateTimeToSlotTable.cs | 30 -- ...pdatedDateOnlyFieldsToDateTime.Designer.cs | 426 ----------------- ...6165354_UpdatedDateOnlyFieldsToDateTime.cs | 51 -- ...927151832_ChangedFromTimeOnlyToDateTime.cs | 91 ---- ...250928213128_InitialMigration.Designer.cs} | 178 +++---- .../20250928213128_InitialMigration.cs | 261 +++++++++++ .../Migrations/AppDbContextModelSnapshot.cs | 174 +++---- .../ProjectR.Backend.Persistence.csproj | 3 +- .../ProjectR.Backend.Tests.csproj | 3 +- src/ProjectR.Backend.csproj | 3 +- src/appsettings.json | 2 +- 34 files changed, 478 insertions(+), 5238 deletions(-) delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs delete mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs rename src/ProjectR.Backend.Persistence/Migrations/{20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs => 20250928213128_InitialMigration.Designer.cs} (67%) create mode 100644 src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs diff --git a/docker-compose.yml b/docker-compose.yml index 7911d02..7cb492e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,13 +2,13 @@ services: projectr.backend: build: - context: ./src - dockerfile: Dockerfile + context: . + dockerfile: src/Dockerfile container_name: projectr-api depends_on: db: - condition: service_healthy + condition: service_started seq: condition: service_started @@ -43,25 +43,36 @@ services: - "5001:5001" db: - image: postgres:15 - container_name: postgres - restart: always + image: mcr.microsoft.com/mssql/server:2022-latest + container_name: sqlserver environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_DB: projectr - - ports: - - "4400:80" - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data + - ACCEPT_EULA=Y + - SA_PASSWORD=Test@1234 healthcheck: - test: [ "CMD-SHELL", "pg_isready -U postgres" ] + # test: ["CMD-SHELL", "timeout 5 bash -c ' Create([FromBody] IndustryModel industry) { - var id = await _manager.CreateIndustryAsync(industry.Name, industry.Description); + var id = await _manager.CreateIndustryAsync(industry.Name!, industry.Description); return CreatedAtAction(nameof(GetById), new { id }, null); } @@ -43,7 +43,7 @@ public async Task GetAll() [HttpPut("{id}")] public async Task Update(Guid id, [FromBody] IndustryModel industry) { - await _manager.UpdateIndustryAsync(id, industry.Name, industry.Description); + await _manager.UpdateIndustryAsync(id, industry.Name!, industry.Description); return NoContent(); } diff --git a/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj b/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj index 899ca8f..c33e90f 100644 --- a/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj +++ b/src/ProjectR.Backend.Application/ProjectR.Backend.Application.csproj @@ -19,6 +19,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index f3ab1e3..d454a94 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -147,9 +147,9 @@ public static void RegisterDatabaseServices(this IServiceCollection services, IC { string connectionString = configuration.GetConnectionString("DefaultConnection")!; services.AddDbContext(options => - options.UseNpgsql(connectionString, options => + options.UseSqlServer(connectionString, options => { - options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorCodesToAdd: []); + options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorNumbersToAdd: []); })); } public static void RegisterHttpClients(this IServiceCollection services, IConfiguration configuration) diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs deleted file mode 100644 index 1e2093e..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.Designer.cs +++ /dev/null @@ -1,271 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250711140719_InitialMigration")] - partial class InitialMigration - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs b/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs deleted file mode 100644 index 197477d..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250711140719_InitialMigration.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class InitialMigration : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "users", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - PhoneNumber = table.Column(type: "text", nullable: false), - PhoneCode = table.Column(type: "character varying(4)", maxLength: 4, nullable: false), - Email = table.Column(type: "text", nullable: true), - AccountType = table.Column(type: "integer", nullable: false, defaultValue: 1), - RegistrationType = table.Column(type: "integer", nullable: false, defaultValue: 1), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_users", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "businesses", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - UserId = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "character varying(200)", maxLength: 200, nullable: true), - Type = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - PhoneCode = table.Column(type: "character varying(4)", maxLength: 4, nullable: true), - PhoneNumber = table.Column(type: "character varying(15)", maxLength: 15, nullable: true), - Industry = table.Column(type: "character varying(100)", maxLength: 100, nullable: true), - About = table.Column(type: "character varying(1000)", maxLength: 1000, nullable: true), - ServiceType = table.Column(type: "integer", nullable: true), - Location = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), - Longitude = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), - Latitude = table.Column(type: "character varying(10)", maxLength: 10, nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_businesses", x => x.Id); - table.ForeignKey( - name: "FK_businesses_users_UserId", - column: x => x.UserId, - principalTable: "users", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BusinessAvailabilities", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - BusinessId = table.Column(type: "uuid", nullable: false), - StartDate = table.Column(type: "date", nullable: false), - EndDate = table.Column(type: "date", nullable: false), - ValidFrom = table.Column(type: "date", nullable: true), - ValidTo = table.Column(type: "date", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BusinessAvailabilities", x => x.Id); - table.ForeignKey( - name: "FK_BusinessAvailabilities_businesses_BusinessId", - column: x => x.BusinessId, - principalTable: "businesses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BusinessAvailabilitySlots", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - BusinessAvailabilityId = table.Column(type: "uuid", nullable: false), - BusinessAvailabilityId1 = table.Column(type: "uuid", nullable: true), - StartTime = table.Column(type: "time without time zone", nullable: false), - EndTime = table.Column(type: "time without time zone", nullable: false), - DayOfWeek = table.Column(type: "integer", nullable: false), - Breaks = table.Column>(type: "time without time zone[]", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BusinessAvailabilitySlots", x => x.Id); - table.ForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", - column: x => x.BusinessAvailabilityId, - principalTable: "BusinessAvailabilities", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1", - column: x => x.BusinessAvailabilityId1, - principalTable: "BusinessAvailabilities", - principalColumn: "Id"); - }); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilities_BusinessId", - table: "BusinessAvailabilities", - column: "BusinessId"); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId"); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId1", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId1"); - - migrationBuilder.CreateIndex( - name: "IX_businesses_UserId", - table: "businesses", - column: "UserId"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "BusinessAvailabilitySlots"); - - migrationBuilder.DropTable( - name: "BusinessAvailabilities"); - - migrationBuilder.DropTable( - name: "businesses"); - - migrationBuilder.DropTable( - name: "users"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs deleted file mode 100644 index a0eb7c1..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.Designer.cs +++ /dev/null @@ -1,285 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250715221843_AddedNameToAppTheme")] - partial class AddedNameToAppTheme - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs b/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs deleted file mode 100644 index b695934..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250715221843_AddedNameToAppTheme.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedNameToAppTheme : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "AppThemes", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AppThemes", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AppThemes"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs deleted file mode 100644 index c2b3cda..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.Designer.cs +++ /dev/null @@ -1,291 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250721134000_AddedURLandShortLinkToBusinessTable")] - partial class AddedURLandShortLinkToBusinessTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs deleted file mode 100644 index 6011c99..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250721134000_AddedURLandShortLinkToBusinessTable.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedURLandShortLinkToBusinessTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Logo", - table: "businesses", - type: "text", - nullable: true); - - migrationBuilder.AddColumn( - name: "ShortLink", - table: "businesses", - type: "text", - nullable: true); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Logo", - table: "businesses"); - - migrationBuilder.DropColumn( - name: "ShortLink", - table: "businesses"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs deleted file mode 100644 index 50be6f8..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.Designer.cs +++ /dev/null @@ -1,335 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250730144416_AddedOtpTable")] - partial class AddedOtpTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs deleted file mode 100644 index 5140bac..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250730144416_AddedOtpTable.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedOtpTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Otps", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - PhoneNumber = table.Column(type: "text", nullable: true), - CountryCode = table.Column(type: "text", nullable: true), - Email = table.Column(type: "text", nullable: true), - Code = table.Column(type: "text", nullable: true), - ExpiryDate = table.Column(type: "timestamp with time zone", nullable: false), - OtpType = table.Column(type: "integer", nullable: false), - DeliveryMode = table.Column(type: "integer", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Otps", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Otps"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs deleted file mode 100644 index 5981fcb..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.Designer.cs +++ /dev/null @@ -1,373 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250809114128_AddedWebhookMessageTable")] - partial class AddedWebhookMessageTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LastProcessedResult") - .HasColumnType("text"); - - b.Property("Payload") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("Source") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("WebhookMessages"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs deleted file mode 100644 index b3c4efd..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250809114128_AddedWebhookMessageTable.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedWebhookMessageTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "WebhookMessages", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Source = table.Column(type: "integer", nullable: false), - Payload = table.Column(type: "text", nullable: true), - IsProcessed = table.Column(type: "boolean", nullable: false), - LastProcessedDate = table.Column(type: "timestamp with time zone", nullable: true), - LastProcessedResult = table.Column(type: "text", nullable: true), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_WebhookMessages", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "WebhookMessages"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs deleted file mode 100644 index cc15775..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.Designer.cs +++ /dev/null @@ -1,355 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250818204545_AddedIndustryTable")] - partial class AddedIndustryTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs deleted file mode 100644 index 7ad2d57..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250818204545_AddedIndustryTable.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedIndustryTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Industries", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - Name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), - Description = table.Column(type: "character varying(500)", maxLength: 500, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Industries", x => x.Id); - }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Industries"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs deleted file mode 100644 index e2b96cb..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.Designer.cs +++ /dev/null @@ -1,355 +0,0 @@ -// -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250819082107_AddIndustryDescription")] - partial class AddIndustryDescription - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("ValidFrom") - .HasColumnType("date"); - - b.Property("ValidTo") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.PrimitiveCollection>("Breaks") - .HasColumnType("time without time zone[]"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs b/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs deleted file mode 100644 index a89389f..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250819082107_AddIndustryDescription.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddIndustryDescription : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs deleted file mode 100644 index bac77f9..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.Designer.cs +++ /dev/null @@ -1,442 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250906151923_UnexpectedChanges")] - partial class UnexpectedChanges - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilitySlotId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilitySlotId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilitySlotId"); - - b.HasIndex("BusinessAvailabilitySlotId1"); - - b.ToTable("Break"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId1") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.HasIndex("BusinessAvailabilityId1"); - - b.ToTable("BusinessAvailabilitySlot"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LastProcessedResult") - .HasColumnType("text"); - - b.Property("Payload") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("Source") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("WebhookMessages"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", null) - .WithMany("Breaks") - .HasForeignKey("BusinessAvailabilitySlotId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") - .WithMany() - .HasForeignKey("BusinessAvailabilitySlotId1"); - - b.Navigation("BusinessAvailabilitySlot"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany() - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", null) - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId1") - .HasConstraintName("FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1"); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Navigation("Breaks"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs b/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs deleted file mode 100644 index 2c0072f..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250906151923_UnexpectedChanges.cs +++ /dev/null @@ -1,245 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class UnexpectedChanges : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilities_businesses_BusinessId", - table: "BusinessAvailabilities"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", - table: "BusinessAvailabilitySlots"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1", - table: "BusinessAvailabilitySlots"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailabilitySlots", - table: "BusinessAvailabilitySlots"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailabilities", - table: "BusinessAvailabilities"); - - migrationBuilder.DropColumn( - name: "Breaks", - table: "BusinessAvailabilitySlots"); - - migrationBuilder.DropColumn( - name: "ValidFrom", - table: "BusinessAvailabilities"); - - migrationBuilder.DropColumn( - name: "ValidTo", - table: "BusinessAvailabilities"); - - migrationBuilder.RenameTable( - name: "BusinessAvailabilitySlots", - newName: "BusinessAvailabilitySlot"); - - migrationBuilder.RenameTable( - name: "BusinessAvailabilities", - newName: "BusinessAvailability"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId1", - table: "BusinessAvailabilitySlot", - newName: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", - table: "BusinessAvailabilitySlot", - newName: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilities_BusinessId", - table: "BusinessAvailability", - newName: "IX_BusinessAvailability_BusinessId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailabilitySlot", - table: "BusinessAvailabilitySlot", - column: "Id"); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailability", - table: "BusinessAvailability", - column: "Id"); - - migrationBuilder.CreateTable( - name: "Break", - columns: table => new - { - Id = table.Column(type: "uuid", nullable: false), - BusinessAvailabilitySlotId = table.Column(type: "uuid", nullable: false), - BusinessAvailabilitySlotId1 = table.Column(type: "uuid", nullable: true), - StartTime = table.Column(type: "time without time zone", nullable: false), - EndTime = table.Column(type: "time without time zone", nullable: false), - CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedAt = table.Column(type: "timestamp with time zone", nullable: false), - UpdatedBy = table.Column(type: "text", nullable: true), - RecordStatus = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Break", x => x.Id); - table.ForeignKey( - name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId", - column: x => x.BusinessAvailabilitySlotId, - principalTable: "BusinessAvailabilitySlot", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId1", - column: x => x.BusinessAvailabilitySlotId1, - principalTable: "BusinessAvailabilitySlot", - principalColumn: "Id"); - }); - - migrationBuilder.CreateIndex( - name: "IX_Break_BusinessAvailabilitySlotId", - table: "Break", - column: "BusinessAvailabilitySlotId"); - - migrationBuilder.CreateIndex( - name: "IX_Break_BusinessAvailabilitySlotId1", - table: "Break", - column: "BusinessAvailabilitySlotId1"); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailability_businesses_BusinessId", - table: "BusinessAvailability", - column: "BusinessId", - principalTable: "businesses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", - table: "BusinessAvailabilitySlot", - column: "BusinessAvailabilityId", - principalTable: "BusinessAvailability", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", - table: "BusinessAvailabilitySlot", - column: "BusinessAvailabilityId1", - principalTable: "BusinessAvailability", - principalColumn: "Id"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailability_businesses_BusinessId", - table: "BusinessAvailability"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropTable( - name: "Break"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailabilitySlot", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailability", - table: "BusinessAvailability"); - - migrationBuilder.RenameTable( - name: "BusinessAvailabilitySlot", - newName: "BusinessAvailabilitySlots"); - - migrationBuilder.RenameTable( - name: "BusinessAvailability", - newName: "BusinessAvailabilities"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1", - table: "BusinessAvailabilitySlots", - newName: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId1"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId", - table: "BusinessAvailabilitySlots", - newName: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailability_BusinessId", - table: "BusinessAvailabilities", - newName: "IX_BusinessAvailabilities_BusinessId"); - - migrationBuilder.AddColumn>( - name: "Breaks", - table: "BusinessAvailabilitySlots", - type: "time without time zone[]", - nullable: true); - - migrationBuilder.AddColumn( - name: "ValidFrom", - table: "BusinessAvailabilities", - type: "date", - nullable: true); - - migrationBuilder.AddColumn( - name: "ValidTo", - table: "BusinessAvailabilities", - type: "date", - nullable: true); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailabilitySlots", - table: "BusinessAvailabilitySlots", - column: "Id"); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailabilities", - table: "BusinessAvailabilities", - column: "Id"); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilities_businesses_BusinessId", - table: "BusinessAvailabilities", - column: "BusinessId", - principalTable: "businesses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId", - principalTable: "BusinessAvailabilities", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessA~1", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId1", - principalTable: "BusinessAvailabilities", - principalColumn: "Id"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs deleted file mode 100644 index 54726b1..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.Designer.cs +++ /dev/null @@ -1,423 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250921160654_AddedBusinessAvailabilityTables")] - partial class AddedBusinessAvailabilityTables - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilitySlotId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilitySlotId"); - - b.ToTable("Breaks"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LastProcessedResult") - .HasColumnType("text"); - - b.Property("Payload") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("Source") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("WebhookMessages"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") - .WithMany("Breaks") - .HasForeignKey("BusinessAvailabilitySlotId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BusinessAvailabilitySlot"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Navigation("Breaks"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs b/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs deleted file mode 100644 index 7772f46..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250921160654_AddedBusinessAvailabilityTables.cs +++ /dev/null @@ -1,259 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedBusinessAvailabilityTables : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId", - table: "Break"); - - migrationBuilder.DropForeignKey( - name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId1", - table: "Break"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailability_businesses_BusinessId", - table: "BusinessAvailability"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailabilitySlot", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropIndex( - name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailability", - table: "BusinessAvailability"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Break", - table: "Break"); - - migrationBuilder.DropIndex( - name: "IX_Break_BusinessAvailabilitySlotId1", - table: "Break"); - - migrationBuilder.DropColumn( - name: "BusinessAvailabilityId1", - table: "BusinessAvailabilitySlot"); - - migrationBuilder.DropColumn( - name: "BusinessAvailabilitySlotId1", - table: "Break"); - - migrationBuilder.RenameTable( - name: "BusinessAvailabilitySlot", - newName: "BusinessAvailabilitySlots"); - - migrationBuilder.RenameTable( - name: "BusinessAvailability", - newName: "BusinessAvailabilities"); - - migrationBuilder.RenameTable( - name: "Break", - newName: "Breaks"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId", - table: "BusinessAvailabilitySlots", - newName: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailability_BusinessId", - table: "BusinessAvailabilities", - newName: "IX_BusinessAvailabilities_BusinessId"); - - migrationBuilder.RenameIndex( - name: "IX_Break_BusinessAvailabilitySlotId", - table: "Breaks", - newName: "IX_Breaks_BusinessAvailabilitySlotId"); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailabilitySlots", - table: "BusinessAvailabilitySlots", - column: "Id"); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailabilities", - table: "BusinessAvailabilities", - column: "Id"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Breaks", - table: "Breaks", - column: "Id"); - - migrationBuilder.AddForeignKey( - name: "FK_Breaks_BusinessAvailabilitySlots_BusinessAvailabilitySlotId", - table: "Breaks", - column: "BusinessAvailabilitySlotId", - principalTable: "BusinessAvailabilitySlots", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilities_businesses_BusinessId", - table: "BusinessAvailabilities", - column: "BusinessId", - principalTable: "businesses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", - table: "BusinessAvailabilitySlots", - column: "BusinessAvailabilityId", - principalTable: "BusinessAvailabilities", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Breaks_BusinessAvailabilitySlots_BusinessAvailabilitySlotId", - table: "Breaks"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilities_businesses_BusinessId", - table: "BusinessAvailabilities"); - - migrationBuilder.DropForeignKey( - name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAv~", - table: "BusinessAvailabilitySlots"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailabilitySlots", - table: "BusinessAvailabilitySlots"); - - migrationBuilder.DropPrimaryKey( - name: "PK_BusinessAvailabilities", - table: "BusinessAvailabilities"); - - migrationBuilder.DropPrimaryKey( - name: "PK_Breaks", - table: "Breaks"); - - migrationBuilder.RenameTable( - name: "BusinessAvailabilitySlots", - newName: "BusinessAvailabilitySlot"); - - migrationBuilder.RenameTable( - name: "BusinessAvailabilities", - newName: "BusinessAvailability"); - - migrationBuilder.RenameTable( - name: "Breaks", - newName: "Break"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", - table: "BusinessAvailabilitySlot", - newName: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId"); - - migrationBuilder.RenameIndex( - name: "IX_BusinessAvailabilities_BusinessId", - table: "BusinessAvailability", - newName: "IX_BusinessAvailability_BusinessId"); - - migrationBuilder.RenameIndex( - name: "IX_Breaks_BusinessAvailabilitySlotId", - table: "Break", - newName: "IX_Break_BusinessAvailabilitySlotId"); - - migrationBuilder.AddColumn( - name: "BusinessAvailabilityId1", - table: "BusinessAvailabilitySlot", - type: "uuid", - nullable: true); - - migrationBuilder.AddColumn( - name: "BusinessAvailabilitySlotId1", - table: "Break", - type: "uuid", - nullable: true); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailabilitySlot", - table: "BusinessAvailabilitySlot", - column: "Id"); - - migrationBuilder.AddPrimaryKey( - name: "PK_BusinessAvailability", - table: "BusinessAvailability", - column: "Id"); - - migrationBuilder.AddPrimaryKey( - name: "PK_Break", - table: "Break", - column: "Id"); - - migrationBuilder.CreateIndex( - name: "IX_BusinessAvailabilitySlot_BusinessAvailabilityId1", - table: "BusinessAvailabilitySlot", - column: "BusinessAvailabilityId1"); - - migrationBuilder.CreateIndex( - name: "IX_Break_BusinessAvailabilitySlotId1", - table: "Break", - column: "BusinessAvailabilitySlotId1"); - - migrationBuilder.AddForeignKey( - name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId", - table: "Break", - column: "BusinessAvailabilitySlotId", - principalTable: "BusinessAvailabilitySlot", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_Break_BusinessAvailabilitySlot_BusinessAvailabilitySlotId1", - table: "Break", - column: "BusinessAvailabilitySlotId1", - principalTable: "BusinessAvailabilitySlot", - principalColumn: "Id"); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailability_businesses_BusinessId", - table: "BusinessAvailability", - column: "BusinessId", - principalTable: "businesses", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvail~", - table: "BusinessAvailabilitySlot", - column: "BusinessAvailabilityId", - principalTable: "BusinessAvailability", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - - migrationBuilder.AddForeignKey( - name: "FK_BusinessAvailabilitySlot_BusinessAvailability_BusinessAvai~1", - table: "BusinessAvailabilitySlot", - column: "BusinessAvailabilityId1", - principalTable: "BusinessAvailability", - principalColumn: "Id"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs deleted file mode 100644 index b1b07ae..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.Designer.cs +++ /dev/null @@ -1,426 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250925225458_AddedDateTimeToSlotTable")] - partial class AddedDateTimeToSlotTable - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilitySlotId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilitySlotId"); - - b.ToTable("Breaks"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("date"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("date"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Date") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LastProcessedResult") - .HasColumnType("text"); - - b.Property("Payload") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("Source") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("WebhookMessages"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") - .WithMany("Breaks") - .HasForeignKey("BusinessAvailabilitySlotId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BusinessAvailabilitySlot"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Navigation("Breaks"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs b/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs deleted file mode 100644 index 152206a..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250925225458_AddedDateTimeToSlotTable.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class AddedDateTimeToSlotTable : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Date", - table: "BusinessAvailabilitySlots", - type: "timestamp with time zone", - nullable: false, - defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Date", - table: "BusinessAvailabilitySlots"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs deleted file mode 100644 index 63f68ad..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.Designer.cs +++ /dev/null @@ -1,426 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using ProjectR.Backend.Persistence.DatabaseContext; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - [DbContext(typeof(AppDbContext))] - [Migration("20250926165354_UpdatedDateOnlyFieldsToDateTime")] - partial class UpdatedDateOnlyFieldsToDateTime - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("AppThemes"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilitySlotId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilitySlotId"); - - b.ToTable("Breaks"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("About") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Industry") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("Latitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Longitude") - .HasMaxLength(10) - .HasColumnType("character varying(10)"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("PhoneCode") - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .HasMaxLength(15) - .HasColumnType("character varying(15)"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("ServiceType") - .HasColumnType("integer"); - - b.Property("ShortLink") - .HasColumnType("text"); - - b.Property("Type") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("businesses", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("EndDate") - .HasColumnType("timestamp with time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartDate") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessId"); - - b.ToTable("BusinessAvailabilities"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Date") - .HasColumnType("timestamp with time zone"); - - b.Property("DayOfWeek") - .HasColumnType("integer"); - - b.Property("EndTime") - .HasColumnType("time without time zone"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("StartTime") - .HasColumnType("time without time zone"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BusinessAvailabilityId"); - - b.ToTable("BusinessAvailabilitySlots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Industry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Description") - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.HasKey("Id"); - - b.ToTable("Industries"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Otp", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("Code") - .HasColumnType("text"); - - b.Property("CountryCode") - .HasColumnType("text"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("DeliveryMode") - .HasColumnType("integer"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); - - b.Property("OtpType") - .HasColumnType("integer"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Otps"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("AccountType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Email") - .HasColumnType("text"); - - b.Property("PhoneCode") - .IsRequired() - .HasMaxLength(4) - .HasColumnType("character varying(4)"); - - b.Property("PhoneNumber") - .IsRequired() - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("RegistrationType") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(1); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("users", (string)null); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.WebhookMessage", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("IsProcessed") - .HasColumnType("boolean"); - - b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LastProcessedResult") - .HasColumnType("text"); - - b.Property("Payload") - .HasColumnType("text"); - - b.Property("RecordStatus") - .HasColumnType("integer"); - - b.Property("Source") - .HasColumnType("integer"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("UpdatedBy") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("WebhookMessages"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Break", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", "BusinessAvailabilitySlot") - .WithMany("Breaks") - .HasForeignKey("BusinessAvailabilitySlotId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BusinessAvailabilitySlot"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.Business", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.User", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.Business", "Business") - .WithMany() - .HasForeignKey("BusinessId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Business"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.HasOne("ProjectR.Backend.Domain.Entities.BusinessAvailability", "BusinessAvailability") - .WithMany("Slots") - .HasForeignKey("BusinessAvailabilityId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BusinessAvailability"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailability", b => - { - b.Navigation("Slots"); - }); - - modelBuilder.Entity("ProjectR.Backend.Domain.Entities.BusinessAvailabilitySlot", b => - { - b.Navigation("Breaks"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs b/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs deleted file mode 100644 index 1774e73..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250926165354_UpdatedDateOnlyFieldsToDateTime.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class UpdatedDateOnlyFieldsToDateTime : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "StartDate", - table: "BusinessAvailabilities", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(DateOnly), - oldType: "date"); - - migrationBuilder.AlterColumn( - name: "EndDate", - table: "BusinessAvailabilities", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(DateOnly), - oldType: "date"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "StartDate", - table: "BusinessAvailabilities", - type: "date", - nullable: false, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone"); - - migrationBuilder.AlterColumn( - name: "EndDate", - table: "BusinessAvailabilities", - type: "date", - nullable: false, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs b/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs deleted file mode 100644 index 5618c5d..0000000 --- a/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ProjectR.Backend.Persistence.Migrations -{ - /// - public partial class ChangedFromTimeOnlyToDateTime : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "StartTime", - table: "BusinessAvailabilitySlots", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(TimeOnly), - oldNullable: false, - oldType: "time without time zone") - .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); - - migrationBuilder.AlterColumn( - name: "EndTime", - table: "BusinessAvailabilitySlots", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(TimeOnly), - oldNullable: false, - oldType: "time without time zone") - .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); - - migrationBuilder.AlterColumn( - name: "StartTime", - table: "Breaks", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(TimeOnly), - oldNullable: false, - oldType: "time without time zone") - .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); - - migrationBuilder.AlterColumn( - name: "EndTime", - table: "Breaks", - type: "timestamp with time zone", - nullable: false, - oldClrType: typeof(TimeOnly), - oldNullable: false, - oldType: "time without time zone") - .Annotation("Npgsql:AlterColumnType", "USING \"StartTime\"::time AT TIME ZONE 'UTC'"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "StartTime", - table: "BusinessAvailabilitySlots", - type: "time without time zone", - nullable: false, - oldClrType: typeof(DateTimeOffset), - oldType: "timestamp with time zone"); - - migrationBuilder.AlterColumn( - name: "EndTime", - table: "BusinessAvailabilitySlots", - type: "time without time zone", - nullable: false, - oldClrType: typeof(DateTimeOffset), - oldType: "timestamp with time zone"); - - migrationBuilder.AlterColumn( - name: "StartTime", - table: "Breaks", - type: "time without time zone", - nullable: false, - oldClrType: typeof(DateTimeOffset), - oldType: "timestamp with time zone"); - - migrationBuilder.AlterColumn( - name: "EndTime", - table: "Breaks", - type: "time without time zone", - nullable: false, - oldClrType: typeof(DateTimeOffset), - oldType: "timestamp with time zone"); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs similarity index 67% rename from src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs index 81b41b0..9679eb2 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250927151832_ChangedFromTimeOnlyToDateTime.Designer.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs @@ -2,9 +2,9 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using ProjectR.Backend.Persistence.DatabaseContext; #nullable disable @@ -12,27 +12,27 @@ namespace ProjectR.Backend.Persistence.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20250927151832_ChangedFromTimeOnlyToDateTime")] - partial class ChangedFromTimeOnlyToDateTime + [Migration("20250928213128_InitialMigration")] + partial class InitialMigration { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Name") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -43,28 +43,28 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessAvailabilitySlotId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("EndTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("StartTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -77,67 +77,67 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("About") .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); + .HasColumnType("nvarchar(1000)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Industry") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("Latitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Location") .HasMaxLength(255) - .HasColumnType("character varying(255)"); + .HasColumnType("nvarchar(255)"); b.Property("Logo") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Longitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Name") .HasMaxLength(200) - .HasColumnType("character varying(200)"); + .HasColumnType("nvarchar(200)"); b.Property("PhoneCode") .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .HasMaxLength(15) - .HasColumnType("character varying(15)"); + .HasColumnType("nvarchar(15)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ServiceType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ShortLink") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Type") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("UserId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.HasKey("Id"); @@ -150,28 +150,28 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); - b.Property("EndDate") - .HasColumnType("timestamp with time zone"); + b.Property("EndDate") + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("StartDate") - .HasColumnType("timestamp with time zone"); + b.Property("StartDate") + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -184,34 +184,34 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Date") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("DayOfWeek") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("EndTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("StartTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -224,16 +224,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Description") .HasMaxLength(500) - .HasColumnType("character varying(500)"); + .HasColumnType("nvarchar(500)"); b.Property("Name") .IsRequired() .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.HasKey("Id"); @@ -244,40 +244,40 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Code") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CountryCode") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("DeliveryMode") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("OtpType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("PhoneNumber") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -288,41 +288,41 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("AccountType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("PhoneCode") .IsRequired() .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .IsRequired() - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("RegistrationType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -333,34 +333,34 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("IsProcessed") - .HasColumnType("boolean"); + .HasColumnType("bit"); b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("LastProcessedResult") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Payload") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Source") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs new file mode 100644 index 0000000..297ecf4 --- /dev/null +++ b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs @@ -0,0 +1,261 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectR.Backend.Persistence.Migrations +{ + /// + public partial class InitialMigration : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AppThemes", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AppThemes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Industries", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + Description = table.Column(type: "nvarchar(500)", maxLength: 500, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Industries", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Otps", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), + CountryCode = table.Column(type: "nvarchar(max)", nullable: true), + Email = table.Column(type: "nvarchar(max)", nullable: true), + Code = table.Column(type: "nvarchar(max)", nullable: true), + ExpiryDate = table.Column(type: "datetimeoffset", nullable: false), + OtpType = table.Column(type: "int", nullable: false), + DeliveryMode = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Otps", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "users", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false), + PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: true), + AccountType = table.Column(type: "int", nullable: false, defaultValue: 1), + RegistrationType = table.Column(type: "int", nullable: false, defaultValue: 1), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_users", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "WebhookMessages", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Source = table.Column(type: "int", nullable: false), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + IsProcessed = table.Column(type: "bit", nullable: false), + LastProcessedDate = table.Column(type: "datetimeoffset", nullable: true), + LastProcessedResult = table.Column(type: "nvarchar(max)", nullable: true), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_WebhookMessages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "businesses", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + UserId = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), + Type = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: true), + PhoneNumber = table.Column(type: "nvarchar(15)", maxLength: 15, nullable: true), + Industry = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true), + About = table.Column(type: "nvarchar(1000)", maxLength: 1000, nullable: true), + ServiceType = table.Column(type: "int", nullable: true), + Location = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), + Longitude = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: true), + Latitude = table.Column(type: "nvarchar(10)", maxLength: 10, nullable: true), + Logo = table.Column(type: "nvarchar(max)", nullable: true), + ShortLink = table.Column(type: "nvarchar(max)", nullable: true), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_businesses", x => x.Id); + table.ForeignKey( + name: "FK_businesses_users_UserId", + column: x => x.UserId, + principalTable: "users", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BusinessAvailabilities", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + BusinessId = table.Column(type: "uniqueidentifier", nullable: false), + StartDate = table.Column(type: "datetimeoffset", nullable: false), + EndDate = table.Column(type: "datetimeoffset", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BusinessAvailabilities", x => x.Id); + table.ForeignKey( + name: "FK_BusinessAvailabilities_businesses_BusinessId", + column: x => x.BusinessId, + principalTable: "businesses", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "BusinessAvailabilitySlots", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + BusinessAvailabilityId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetimeoffset", nullable: false), + EndTime = table.Column(type: "datetimeoffset", nullable: false), + DayOfWeek = table.Column(type: "int", nullable: false), + Date = table.Column(type: "datetimeoffset", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_BusinessAvailabilitySlots", x => x.Id); + table.ForeignKey( + name: "FK_BusinessAvailabilitySlots_BusinessAvailabilities_BusinessAvailabilityId", + column: x => x.BusinessAvailabilityId, + principalTable: "BusinessAvailabilities", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Breaks", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + BusinessAvailabilitySlotId = table.Column(type: "uniqueidentifier", nullable: false), + StartTime = table.Column(type: "datetimeoffset", nullable: false), + EndTime = table.Column(type: "datetimeoffset", nullable: false), + CreatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), + UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), + RecordStatus = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Breaks", x => x.Id); + table.ForeignKey( + name: "FK_Breaks_BusinessAvailabilitySlots_BusinessAvailabilitySlotId", + column: x => x.BusinessAvailabilitySlotId, + principalTable: "BusinessAvailabilitySlots", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Breaks_BusinessAvailabilitySlotId", + table: "Breaks", + column: "BusinessAvailabilitySlotId"); + + migrationBuilder.CreateIndex( + name: "IX_BusinessAvailabilities_BusinessId", + table: "BusinessAvailabilities", + column: "BusinessId"); + + migrationBuilder.CreateIndex( + name: "IX_BusinessAvailabilitySlots_BusinessAvailabilityId", + table: "BusinessAvailabilitySlots", + column: "BusinessAvailabilityId"); + + migrationBuilder.CreateIndex( + name: "IX_businesses_UserId", + table: "businesses", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AppThemes"); + + migrationBuilder.DropTable( + name: "Breaks"); + + migrationBuilder.DropTable( + name: "Industries"); + + migrationBuilder.DropTable( + name: "Otps"); + + migrationBuilder.DropTable( + name: "WebhookMessages"); + + migrationBuilder.DropTable( + name: "BusinessAvailabilitySlots"); + + migrationBuilder.DropTable( + name: "BusinessAvailabilities"); + + migrationBuilder.DropTable( + name: "businesses"); + + migrationBuilder.DropTable( + name: "users"); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs index d920376..c3a72b7 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/AppDbContextModelSnapshot.cs @@ -2,8 +2,8 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using ProjectR.Backend.Persistence.DatabaseContext; #nullable disable @@ -17,19 +17,19 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); + .HasAnnotation("ProductVersion", "9.0.9") + .HasAnnotation("Relational:MaxIdentifierLength", 128); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("ProjectR.Backend.Domain.Entities.AppTheme", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Name") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -40,28 +40,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessAvailabilitySlotId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("EndTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("StartTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -74,67 +74,67 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("About") .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); + .HasColumnType("nvarchar(1000)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Industry") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("Latitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Location") .HasMaxLength(255) - .HasColumnType("character varying(255)"); + .HasColumnType("nvarchar(255)"); b.Property("Logo") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Longitude") .HasMaxLength(10) - .HasColumnType("character varying(10)"); + .HasColumnType("nvarchar(10)"); b.Property("Name") .HasMaxLength(200) - .HasColumnType("character varying(200)"); + .HasColumnType("nvarchar(200)"); b.Property("PhoneCode") .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .HasMaxLength(15) - .HasColumnType("character varying(15)"); + .HasColumnType("nvarchar(15)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ServiceType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("ShortLink") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Type") .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("UserId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.HasKey("Id"); @@ -147,28 +147,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); - b.Property("EndDate") - .HasColumnType("timestamp with time zone"); + b.Property("EndDate") + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); - b.Property("StartDate") - .HasColumnType("timestamp with time zone"); + b.Property("StartDate") + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -181,34 +181,34 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("BusinessAvailabilityId") - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Date") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("DayOfWeek") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("EndTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("StartTime") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -221,16 +221,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Description") .HasMaxLength(500) - .HasColumnType("character varying(500)"); + .HasColumnType("nvarchar(500)"); b.Property("Name") .IsRequired() .HasMaxLength(100) - .HasColumnType("character varying(100)"); + .HasColumnType("nvarchar(100)"); b.HasKey("Id"); @@ -241,40 +241,40 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("Code") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CountryCode") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("DeliveryMode") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("OtpType") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("PhoneNumber") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -285,41 +285,41 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("AccountType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("Email") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("PhoneCode") .IsRequired() .HasMaxLength(4) - .HasColumnType("character varying(4)"); + .HasColumnType("nvarchar(4)"); b.Property("PhoneNumber") .IsRequired() - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("RegistrationType") .ValueGeneratedOnAdd() - .HasColumnType("integer") + .HasColumnType("int") .HasDefaultValue(1); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); @@ -330,34 +330,34 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("uuid"); + .HasColumnType("uniqueidentifier"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("IsProcessed") - .HasColumnType("boolean"); + .HasColumnType("bit"); b.Property("LastProcessedDate") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("LastProcessedResult") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("Payload") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.Property("RecordStatus") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("Source") - .HasColumnType("integer"); + .HasColumnType("int"); b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone"); + .HasColumnType("datetimeoffset"); b.Property("UpdatedBy") - .HasColumnType("text"); + .HasColumnType("nvarchar(max)"); b.HasKey("Id"); diff --git a/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj b/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj index 6109399..6a1d09e 100644 --- a/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj +++ b/src/ProjectR.Backend.Persistence/ProjectR.Backend.Persistence.csproj @@ -3,15 +3,16 @@ net8.0 enable + false enable + all runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj b/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj index a5d5125..546d109 100644 --- a/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj +++ b/src/ProjectR.Backend.Tests/ProjectR.Backend.Tests.csproj @@ -4,6 +4,7 @@ net8.0 enable enable + false @@ -20,4 +21,4 @@ - + \ No newline at end of file diff --git a/src/ProjectR.Backend.csproj b/src/ProjectR.Backend.csproj index 0a341ec..924c852 100644 --- a/src/ProjectR.Backend.csproj +++ b/src/ProjectR.Backend.csproj @@ -4,7 +4,7 @@ net8.0 enable enable - true + false false false e32f2d32-f168-4966-a5ff-3117e6c9adb4 @@ -49,6 +49,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/appsettings.json b/src/appsettings.json index 670b498..20f5b5b 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Host=host.docker.internal;Port=5432;Database=projectr;Username=postgres;Password=postgres" + "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=projectr-db;User Id=sa1;Password=StrongPassword123!;TrustServerCertificate=true;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { From 662c8f638e519fcc131a87292d2e955750481164 Mon Sep 17 00:00:00 2001 From: DevFinesse Date: Mon, 29 Sep 2025 06:31:02 +0100 Subject: [PATCH 10/13] Resolve merge conflicts: consolidate migration files and update configurations --- docker-compose.yml | 46 +++++++------------ src/Program.cs | 4 ++ .../ServiceCollectionRegistration.cs | 4 +- ....cs => 20250928100050_Initial.Designer.cs} | 4 +- ...Migration.cs => 20250928100050_Initial.cs} | 30 ++++++------ src/appsettings.json | 2 +- 6 files changed, 41 insertions(+), 49 deletions(-) rename src/ProjectR.Backend.Persistence/Migrations/{20250928213128_InitialMigration.Designer.cs => 20250928100050_Initial.Designer.cs} (99%) rename src/ProjectR.Backend.Persistence/Migrations/{20250928213128_InitialMigration.cs => 20250928100050_Initial.cs} (99%) diff --git a/docker-compose.yml b/docker-compose.yml index 7cb492e..7d2e380 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ - services: projectr.backend: build: @@ -12,12 +11,12 @@ services: seq: condition: service_started - networks: + networks: - mynetwork environment: - ASPNETCORE_ENVIRONMENT=Development - - ConnectionStrings__DefaultConnection=Host=db;Port=5432;Database=projectr;Username=postgres;Password=password + - ConnectionStrings__DefaultConnection= Server=sqlserver_db;Database=projectr;User Id=SA;Password=YourStrongPassword123!;TrustServerCertificate=True; # Update with your database name and password - Google__Android=${Google__Android} - Google__Ios=${Google__Ios} @@ -43,36 +42,25 @@ services: - "5001:5001" db: - image: mcr.microsoft.com/mssql/server:2022-latest - container_name: sqlserver + image: postgres:15 + container_name: postgres + restart: always environment: - - ACCEPT_EULA=Y - - SA_PASSWORD=Test@1234 + POSTGRES_USER: postgres + POSTGRES_PASSWORD: password + POSTGRES_DB: projectr + + ports: + - "4400:80" + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data healthcheck: - # test: ["CMD-SHELL", "timeout 5 bash -c ' { diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index d454a94..f3ab1e3 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -147,9 +147,9 @@ public static void RegisterDatabaseServices(this IServiceCollection services, IC { string connectionString = configuration.GetConnectionString("DefaultConnection")!; services.AddDbContext(options => - options.UseSqlServer(connectionString, options => + options.UseNpgsql(connectionString, options => { - options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorNumbersToAdd: []); + options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorCodesToAdd: []); })); } public static void RegisterHttpClients(this IServiceCollection services, IConfiguration configuration) diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.Designer.cs similarity index 99% rename from src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.Designer.cs index 9679eb2..0ba5014 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.Designer.cs @@ -12,8 +12,8 @@ namespace ProjectR.Backend.Persistence.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20250928213128_InitialMigration")] - partial class InitialMigration + [Migration("20250928100050_Initial")] + partial class Initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs b/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.cs similarity index 99% rename from src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.cs index 297ecf4..bef4921 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.cs @@ -6,7 +6,7 @@ namespace ProjectR.Backend.Persistence.Migrations { /// - public partial class InitialMigration : Migration + public partial class Initial : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -59,15 +59,15 @@ protected override void Up(MigrationBuilder migrationBuilder) }); migrationBuilder.CreateTable( - name: "users", + name: "WebhookMessages", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false), - PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), - Email = table.Column(type: "nvarchar(max)", nullable: true), - AccountType = table.Column(type: "int", nullable: false, defaultValue: 1), - RegistrationType = table.Column(type: "int", nullable: false, defaultValue: 1), + Source = table.Column(type: "int", nullable: false), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + IsProcessed = table.Column(type: "bit", nullable: false), + LastProcessedDate = table.Column(type: "datetimeoffset", nullable: true), + LastProcessedResult = table.Column(type: "nvarchar(max)", nullable: true), CreatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), @@ -75,19 +75,19 @@ protected override void Up(MigrationBuilder migrationBuilder) }, constraints: table => { - table.PrimaryKey("PK_users", x => x.Id); + table.PrimaryKey("PK_WebhookMessages", x => x.Id); }); migrationBuilder.CreateTable( - name: "WebhookMessages", + name: "users", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - Source = table.Column(type: "int", nullable: false), - Payload = table.Column(type: "nvarchar(max)", nullable: true), - IsProcessed = table.Column(type: "bit", nullable: false), - LastProcessedDate = table.Column(type: "datetimeoffset", nullable: true), - LastProcessedResult = table.Column(type: "nvarchar(max)", nullable: true), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false), + PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: true), + AccountType = table.Column(type: "int", nullable: false, defaultValue: 1), + RegistrationType = table.Column(type: "int", nullable: false, defaultValue: 1), CreatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), @@ -95,7 +95,7 @@ protected override void Up(MigrationBuilder migrationBuilder) }, constraints: table => { - table.PrimaryKey("PK_WebhookMessages", x => x.Id); + table.PrimaryKey("PK_users", x => x.Id); }); migrationBuilder.CreateTable( diff --git a/src/appsettings.json b/src/appsettings.json index 20f5b5b..670b498 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=projectr-db;User Id=sa1;Password=StrongPassword123!;TrustServerCertificate=true;MultipleActiveResultSets=true" + "DefaultConnection": "Host=host.docker.internal;Port=5432;Database=projectr;Username=postgres;Password=postgres" }, "Logging": { "LogLevel": { From 31e43eae4f42021bee0ec39fc22603bf191d02f6 Mon Sep 17 00:00:00 2001 From: DevFinesse Date: Mon, 29 Sep 2025 07:51:36 +0100 Subject: [PATCH 11/13] Revert "Resolve merge conflicts: consolidate migration files and update configurations" This reverts commit 662c8f638e519fcc131a87292d2e955750481164. --- docker-compose.yml | 46 ++++++++++++------- src/Program.cs | 4 -- .../ServiceCollectionRegistration.cs | 4 +- ...250928213128_InitialMigration.Designer.cs} | 4 +- ....cs => 20250928213128_InitialMigration.cs} | 30 ++++++------ src/appsettings.json | 2 +- 6 files changed, 49 insertions(+), 41 deletions(-) rename src/ProjectR.Backend.Persistence/Migrations/{20250928100050_Initial.Designer.cs => 20250928213128_InitialMigration.Designer.cs} (99%) rename src/ProjectR.Backend.Persistence/Migrations/{20250928100050_Initial.cs => 20250928213128_InitialMigration.cs} (99%) diff --git a/docker-compose.yml b/docker-compose.yml index 7d2e380..7cb492e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,4 @@ + services: projectr.backend: build: @@ -11,12 +12,12 @@ services: seq: condition: service_started - networks: + networks: - mynetwork environment: - ASPNETCORE_ENVIRONMENT=Development - - ConnectionStrings__DefaultConnection= Server=sqlserver_db;Database=projectr;User Id=SA;Password=YourStrongPassword123!;TrustServerCertificate=True; # Update with your database name and password + - ConnectionStrings__DefaultConnection=Host=db;Port=5432;Database=projectr;Username=postgres;Password=password - Google__Android=${Google__Android} - Google__Ios=${Google__Ios} @@ -42,25 +43,36 @@ services: - "5001:5001" db: - image: postgres:15 - container_name: postgres - restart: always + image: mcr.microsoft.com/mssql/server:2022-latest + container_name: sqlserver environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: password - POSTGRES_DB: projectr - - ports: - - "4400:80" - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data + - ACCEPT_EULA=Y + - SA_PASSWORD=Test@1234 healthcheck: - test: [ "CMD-SHELL", "pg_isready -U postgres" ] + # test: ["CMD-SHELL", "timeout 5 bash -c ' { diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index f3ab1e3..d454a94 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -147,9 +147,9 @@ public static void RegisterDatabaseServices(this IServiceCollection services, IC { string connectionString = configuration.GetConnectionString("DefaultConnection")!; services.AddDbContext(options => - options.UseNpgsql(connectionString, options => + options.UseSqlServer(connectionString, options => { - options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorCodesToAdd: []); + options.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(10), errorNumbersToAdd: []); })); } public static void RegisterHttpClients(this IServiceCollection services, IConfiguration configuration) diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs similarity index 99% rename from src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.Designer.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs index 0ba5014..9679eb2 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.Designer.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs @@ -12,8 +12,8 @@ namespace ProjectR.Backend.Persistence.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20250928100050_Initial")] - partial class Initial + [Migration("20250928213128_InitialMigration")] + partial class InitialMigration { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.cs b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs similarity index 99% rename from src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs index bef4921..297ecf4 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250928100050_Initial.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs @@ -6,7 +6,7 @@ namespace ProjectR.Backend.Persistence.Migrations { /// - public partial class Initial : Migration + public partial class InitialMigration : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -59,15 +59,15 @@ protected override void Up(MigrationBuilder migrationBuilder) }); migrationBuilder.CreateTable( - name: "WebhookMessages", + name: "users", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - Source = table.Column(type: "int", nullable: false), - Payload = table.Column(type: "nvarchar(max)", nullable: true), - IsProcessed = table.Column(type: "bit", nullable: false), - LastProcessedDate = table.Column(type: "datetimeoffset", nullable: true), - LastProcessedResult = table.Column(type: "nvarchar(max)", nullable: true), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false), + PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), + Email = table.Column(type: "nvarchar(max)", nullable: true), + AccountType = table.Column(type: "int", nullable: false, defaultValue: 1), + RegistrationType = table.Column(type: "int", nullable: false, defaultValue: 1), CreatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), @@ -75,19 +75,19 @@ protected override void Up(MigrationBuilder migrationBuilder) }, constraints: table => { - table.PrimaryKey("PK_WebhookMessages", x => x.Id); + table.PrimaryKey("PK_users", x => x.Id); }); migrationBuilder.CreateTable( - name: "users", + name: "WebhookMessages", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - PhoneNumber = table.Column(type: "nvarchar(max)", nullable: false), - PhoneCode = table.Column(type: "nvarchar(4)", maxLength: 4, nullable: false), - Email = table.Column(type: "nvarchar(max)", nullable: true), - AccountType = table.Column(type: "int", nullable: false, defaultValue: 1), - RegistrationType = table.Column(type: "int", nullable: false, defaultValue: 1), + Source = table.Column(type: "int", nullable: false), + Payload = table.Column(type: "nvarchar(max)", nullable: true), + IsProcessed = table.Column(type: "bit", nullable: false), + LastProcessedDate = table.Column(type: "datetimeoffset", nullable: true), + LastProcessedResult = table.Column(type: "nvarchar(max)", nullable: true), CreatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedAt = table.Column(type: "datetimeoffset", nullable: false), UpdatedBy = table.Column(type: "nvarchar(max)", nullable: true), @@ -95,7 +95,7 @@ protected override void Up(MigrationBuilder migrationBuilder) }, constraints: table => { - table.PrimaryKey("PK_users", x => x.Id); + table.PrimaryKey("PK_WebhookMessages", x => x.Id); }); migrationBuilder.CreateTable( diff --git a/src/appsettings.json b/src/appsettings.json index 670b498..20f5b5b 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Host=host.docker.internal;Port=5432;Database=projectr;Username=postgres;Password=postgres" + "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=projectr-db;User Id=sa1;Password=StrongPassword123!;TrustServerCertificate=true;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { From 970034d326946e915df0d78ab3c0e2816b935963 Mon Sep 17 00:00:00 2001 From: DevFinesse Date: Sat, 4 Oct 2025 13:20:21 +0100 Subject: [PATCH 12/13] BusinessAvailability fixes --- .../BusinessesAvailabilityController.cs | 2 +- src/Controllers/BusinessesController.cs | 11 + .../Interfaces/Managers/IBusinessManager.cs | 2 + .../Repository/IBusinessRepository.cs | 2 + .../Models/BreakModel.cs | 2 +- .../Models/BusinessAvailabilitySlotModel.cs | 2 +- .../BusinessAvailabilityValidator.cs | 16 ++ .../Entities/BaseObject.cs | 2 +- .../Entities/BusinessAvailability.cs | 3 + .../Managers/BusinessAvailabilityManager.cs | 2 +- .../Managers/BusinessManager.cs | 10 + .../ServiceCollectionRegistration.cs | 2 +- .../BusinessRepository.cs | 242 ++++++++++++++++++ ....cs => 20250930210149_Initial.Designer.cs} | 4 +- ...Migration.cs => 20250930210149_Initial.cs} | 2 +- .../BusinessAvailabilityRepository.cs | 50 ++-- .../Repository/BusinessRepository.cs | 26 ++ src/ProjectR.Backend.Shared/Mappers/Mapper.cs | 18 +- src/ProjectR.Backend.csproj | 1 + src/Properties/serviceDependencies.json | 3 + src/Properties/serviceDependencies.local.json | 3 + .../serviceDependencies.local.json.user | 4 + src/appsettings.json | 63 ++--- src/src.sln | 60 +++++ 24 files changed, 467 insertions(+), 65 deletions(-) create mode 100644 src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs rename src/ProjectR.Backend.Persistence/Migrations/{20250928213128_InitialMigration.Designer.cs => 20250930210149_Initial.Designer.cs} (99%) rename src/ProjectR.Backend.Persistence/Migrations/{20250928213128_InitialMigration.cs => 20250930210149_Initial.cs} (99%) create mode 100644 src/Properties/serviceDependencies.json create mode 100644 src/Properties/serviceDependencies.local.json create mode 100644 src/Properties/serviceDependencies.local.json.user create mode 100644 src/src.sln diff --git a/src/Controllers/BusinessesAvailabilityController.cs b/src/Controllers/BusinessesAvailabilityController.cs index df03508..20bb9ca 100644 --- a/src/Controllers/BusinessesAvailabilityController.cs +++ b/src/Controllers/BusinessesAvailabilityController.cs @@ -19,7 +19,7 @@ public BusinessAvailabilityController(IBusinessAvailabilityManager manager) [Produces("application/json")] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BusinessAvailabilityModel[]))] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(BusinessAvailabilityModel[]))] - [HttpGet("GetByBusiness/{id:guid}")] + [HttpGet("GetByBusiness/{Id:guid}")] public async Task GetByBusiness(Guid Id, [FromQuery] bool includeAll = false) { BusinessAvailabilityModel[] result = await _manager.GetByBusinessId(Id, includeAll); diff --git a/src/Controllers/BusinessesController.cs b/src/Controllers/BusinessesController.cs index 390353e..5fb6dd9 100644 --- a/src/Controllers/BusinessesController.cs +++ b/src/Controllers/BusinessesController.cs @@ -97,5 +97,16 @@ public async Task GetByUserId() BaseResponseModel result = await _businessManager.GetByUserId(UserId); return result.Status ? Ok(result) : BadRequest(result); } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] + [HttpGet("{id:guid}/businesses")] + public async Task GetUserBusinesses(Guid id) + { + BusinessModel[] result = await _businessManager.GetUserBusinessesAsync(id); + return Ok(result); + } + } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs index 871e6e1..8567f20 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs @@ -7,6 +7,7 @@ public interface IBusinessManager Task> GetByIdAsync(Guid id); Task> GetBySlugAsync(string slug); Task GetAllAsync(); + Task GetUserBusinessesAsync(Guid UserId); Task> AddAsync(AddBusinessModel[] businesses); Task> AddAsync(AddBusinessModel business); Task> UpdateAsync(BusinessModel business); @@ -15,5 +16,6 @@ public interface IBusinessManager Task DeleteAsync(Guid id); Task> GetByUserId(Guid userId); Task IsBusinessExist(Guid userId); + Task IsBusinessExist(Guid userId, Guid BusinessId); } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs index 31c0521..7ec4ceb 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs @@ -7,6 +7,7 @@ public interface IBusinessRepository Task GetByIdAsync(Guid id); Task GetBySlugAsync(string slug); Task GetAllAsync(); + Task GetUserBusinessesAsync(Guid UserId); Task AddAsync(BusinessModel[] businessModels); Task AddAsync(BusinessModel businessModel); Task UpdateAsync(BusinessModel[] businessModels); @@ -16,5 +17,6 @@ public interface IBusinessRepository Task SlugExistsAsync(string shortLink, Guid? excludedId = null); Task GetByUserId(Guid userId); Task IsBusinessExist(Guid userId); + Task IsBusinessExist(Guid userId, Guid BusinessId); } } diff --git a/src/ProjectR.Backend.Application/Models/BreakModel.cs b/src/ProjectR.Backend.Application/Models/BreakModel.cs index f926e40..ee0ea05 100644 --- a/src/ProjectR.Backend.Application/Models/BreakModel.cs +++ b/src/ProjectR.Backend.Application/Models/BreakModel.cs @@ -11,7 +11,7 @@ public class BreakModel : BaseObject [Required] public Guid BusinessAvailabilitySlotId { get; set; } - public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } + //public BusinessAvailabilitySlot? BusinessAvailabilitySlot { get; set; } [DataType(DataType.Time, ErrorMessage = "Invalid time format")] public DateTimeOffset? StartTime { get; set; } diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs index 12210fb..a7ef9f7 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -11,7 +11,7 @@ public class BusinessAvailabilitySlotModel [Required] public Guid BusinessAvailabilityId { get; set; } - public BusinessAvailabilityModel? BusinessAvailability { get; set; } + //public BusinessAvailabilityModel? BusinessAvailability { get; set; } [DataType(DataType.Time, ErrorMessage = "Invalid time format")] public DateTimeOffset? StartTime { get; set; } diff --git a/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs index 061feec..e9b8553 100644 --- a/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs +++ b/src/ProjectR.Backend.Application/Validators/BusinessAvailabilityValidator.cs @@ -45,6 +45,11 @@ public BusinessAvailabilityValidator(IOptions sett .When(x => x.StartDate.HasValue && x.EndDate.HasValue) .WithMessage("End date must be after or equal to start date."); + //Rule: Cannot add dates in the past + RuleFor(x => x.StartDate) + .GreaterThanOrEqualTo(x => DateTime.UtcNow) + .WithMessage("Start Date cannot be in the past"); + // Rule: Gap must not exceed settings.MaxAdvanceBookingInDays RuleFor(x => x) .Must(x => @@ -192,6 +197,12 @@ public AddBusinessAvailabilitySlotValidator() .Must(x => x.StartTime.HasValue && x.EndTime.HasValue && x.EndTime > x.StartTime) .WithMessage("Slot end time must be after start time."); + + //Rule: Cannot add times in the past + RuleFor(x => x.StartTime) + .GreaterThanOrEqualTo(x => DateTime.UtcNow) + .WithMessage("Slot StartTime cannot be in the past"); + RuleForEach(x => x.Breaks).SetValidator(new AddBreakValidator()); } } @@ -209,6 +220,11 @@ public AddBreakValidator() RuleFor(x => x) .Must(x => x.StartTime.HasValue && x.EndTime.HasValue && x.EndTime > x.StartTime) .WithMessage("Break end time must be after start time."); + + //Rule: Cannot add time in the past + RuleFor(x => x.StartTime) + .GreaterThanOrEqualTo(x => DateTime.UtcNow) + .WithMessage("Break StartTime cannot be in the past"); } } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Domain/Entities/BaseObject.cs b/src/ProjectR.Backend.Domain/Entities/BaseObject.cs index cd3f829..98ae4a8 100644 --- a/src/ProjectR.Backend.Domain/Entities/BaseObject.cs +++ b/src/ProjectR.Backend.Domain/Entities/BaseObject.cs @@ -8,6 +8,6 @@ public class BaseObject public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset UpdatedAt { get; set; } public string? UpdatedBy { get; set; } - public RecordStatus? RecordStatus { get; set; } + public RecordStatus? RecordStatus { get; set; } = Shared.RecordStatus.Active; } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs index f0e4108..f0e66ae 100644 --- a/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs +++ b/src/ProjectR.Backend.Domain/Entities/BusinessAvailability.cs @@ -1,3 +1,5 @@ +using ProjectR.Backend.Shared; + namespace ProjectR.Backend.Domain.Entities { /// @@ -10,6 +12,7 @@ public class BusinessAvailability : BaseObject public DateTimeOffset? StartDate { get; set; } public DateTimeOffset? EndDate { get; set; } public ICollection? Slots { get; set; } + //RecordStatus } } diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs index a203446..d455e30 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessAvailabilityManager.cs @@ -46,7 +46,7 @@ public async Task> AddAsync(AddBusiness public async Task GetByBusinessId(Guid businessId, bool includeAll = false) { - BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(businessId); + BusinessAvailabilityModel[] result = await _repository.GetAllByBusinessIdAsync(businessId, includeAll); return result; } diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs index 01a0cdd..dd35621 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs @@ -127,11 +127,21 @@ public async Task> GetByUserId(Guid userId) return new ResponseModel(message: result != null ? "Business retrieved successfully" : "Business not found", data: result, status: result != null); } + public async Task GetUserBusinessesAsync(Guid UserId) + { + return await _businessRepository.GetUserBusinessesAsync(UserId); + } + public async Task IsBusinessExist(Guid userId) { return await _businessRepository.IsBusinessExist(userId); } + public async Task IsBusinessExist(Guid userId, Guid BusinessId) + { + return await _businessRepository.IsBusinessExist(userId,BusinessId); + } + public async Task> UpdateAsync(BusinessModel business) { diff --git a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs index d454a94..5fc8bed 100644 --- a/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs +++ b/src/ProjectR.Backend.Infrastructure/ServiceConfigurations/ServiceCollectionRegistration.cs @@ -36,7 +36,7 @@ public static void RegisterServices(this IServiceCollection services, IConfigura services.Configure(configuration.GetSection("Twilio")); services.Configure(configuration.GetSection("Otp")); services.Configure(configuration.GetSection("Cloudinary")); - services.Configure(configuration.GetSection("BusinessAvailability")); + services.Configure(configuration.GetSection("BusinessAvailability")); #endregion #region Validators diff --git a/src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs b/src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs new file mode 100644 index 0000000..7afe79b --- /dev/null +++ b/src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs @@ -0,0 +1,242 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Persistence.DatabaseContext; + +namespace ProjectR.Backend.Persistence.Repository +{ + public class BusinessRepository : IBusinessRepository + { + private readonly AppDbContext _context; + + public BusinessRepository(AppDbContext context) + { + _context = context; + } + + public async Task SlugExistsAsync(string shortLink, Guid? excludedId = null) + { + IQueryable query = _context.Businesses.Where(p => p.ShortLink == shortLink); + + if (excludedId.HasValue) + { + query = query.Where(p => p.Id == excludedId.Value); + } + + return await query.AnyAsync(); + } + public async Task AddAsync(BusinessModel[] businessModels) + { + List entities = businessModels.Select(e => new Business + { + UserId = e.UserId, + Id = e.Id, + Name = e.Name, + Type = e.Type, + PhoneCode = e.PhoneCode, + PhoneNumber = e.PhoneNumber, + Industry = e.Industry, + About = e.About, + Location = e.Location, + Longitude = e.Longitude, + Latitude = e.Latitude, + ShortLink = e.ShortLink, + Logo = e.Logo + }).ToList(); + + await _context.Businesses.AddRangeAsync(entities); + await _context.SaveChangesAsync(); + return businessModels; + } + + public async Task AddAsync(BusinessModel businessModel) + { + Business entity = new() + { + UserId = businessModel.UserId, + Id = businessModel.Id, + Name = businessModel.Name, + Type = businessModel.Type, + PhoneCode = businessModel.PhoneCode, + PhoneNumber = businessModel.PhoneNumber, + Industry = businessModel.Industry, + About = businessModel.About, + Location = businessModel.Location, + Longitude = businessModel.Longitude, + Latitude = businessModel.Latitude, + ShortLink = businessModel.ShortLink, + Logo = businessModel.Logo + }; + + EntityEntry result = await _context.Businesses.AddAsync(entity); + result.Entity.Id = entity.Id; + await _context.SaveChangesAsync(); + return businessModel; + } + + public async Task DeleteAsync(BusinessModel[] businessModels) + { + List entities = businessModels.Select(c => new Business { Id = c.Id }).ToList(); + _context.Businesses.RemoveRange(entities); + await _context.SaveChangesAsync(); + } + + public async Task DeleteAsync(BusinessModel businessModel) + { + Business? entity = await _context.Businesses.SingleOrDefaultAsync(c => c.Id == businessModel.Id); + _context.Businesses.Remove(entity!); + await _context.SaveChangesAsync(); + } + + public async Task GetAllAsync() + { + List entities = await _context.Businesses.ToListAsync(); + return entities.Select(e => new BusinessModel + { + UserId = e.UserId, + Id = e.Id, + Name = e.Name, + Type = e.Type, + PhoneCode = e.PhoneCode, + PhoneNumber = e.PhoneNumber, + Industry = e.Industry, + About = e.About, + Location = e.Location, + Longitude = e.Longitude, + Latitude = e.Latitude, + ShortLink = e.ShortLink, + Logo = e.Logo + }).ToArray(); + } + + public async Task GetByIdAsync(Guid id) + { + Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.Id == id); + return result == null ? null : new BusinessModel + { + UserId = result!.UserId, + Id = id, + Name = result?.Name, + Type = result?.Type, + PhoneCode = result?.PhoneCode, + PhoneNumber = result?.PhoneNumber, + Industry = result?.Industry, + About = result?.About, + Location = result?.Location, + Longitude = result?.Longitude, + Latitude = result?.Latitude, + Logo = result?.Logo, + ShortLink = result?.ShortLink + }; + } + + public async Task GetBySlugAsync(string slug) + { + Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.ShortLink == slug); + return result == null ? null : new BusinessModel + { + UserId = result.UserId, + Id = result.Id, + Name = result?.Name, + Type = result?.Type, + PhoneCode = result?.PhoneCode, + PhoneNumber = result?.PhoneNumber, + Industry = result?.Industry, + About = result?.About, + Location = result?.Location, + Longitude = result?.Longitude, + Latitude = result?.Latitude, + Logo = result?.Logo, + ShortLink = result?.ShortLink + }; + } + + public async Task UpdateAsync(BusinessModel[] businessModels) + { + List entities = businessModels.Select(c => new Business + { + Id = c.Id, + Name = c.Name, + Type = c.Type, + PhoneCode = c.PhoneCode, + PhoneNumber = c.PhoneNumber, + Industry = c.Industry, + About = c.About, + Location = c.Location, + Longitude = c.Longitude, + Latitude = c.Latitude, + Logo = c.Logo + }).ToList(); + _context.Businesses.UpdateRange(entities); + await _context.SaveChangesAsync(); + return businessModels; + } + + public async Task UpdateAsync(BusinessModel businessModel) + { + Business? entity = await _context.Businesses.SingleOrDefaultAsync(c => c.Id == businessModel.Id); + entity!.Name = businessModel.Name; + entity!.Type = businessModel.Type; + entity!.PhoneCode = businessModel.PhoneCode; + entity!.PhoneNumber = businessModel.PhoneNumber; + entity!.Industry = businessModel.Industry; + entity!.About = businessModel.About; + entity!.Location = businessModel.Location; + entity!.Longitude = businessModel.Longitude; + entity!.Latitude = businessModel.Latitude; + entity!.ShortLink = businessModel.ShortLink; + entity!.Logo = businessModel.Logo; + _context.Businesses.Update(entity); + await _context.SaveChangesAsync(); + return businessModel; + } + + public async Task GetByUserId(Guid userId) + { + Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.UserId == userId); + return result == null ? null : new BusinessModel + { + UserId = result!.UserId, + Id = result.Id, + Name = result?.Name, + Type = result?.Type, + PhoneCode = result?.PhoneCode, + PhoneNumber = result?.PhoneNumber, + Industry = result?.Industry, + About = result?.About, + Location = result?.Location, + Longitude = result?.Longitude, + Latitude = result?.Latitude, + Logo = result?.Logo + }; + } + + public async Task IsBusinessExist(Guid userId) + { + return await _context.Businesses.AnyAsync(c => c.UserId == userId); + } + + public async Task GetUserBusinessesAsync(Guid UserId) + { + List entities = await _context.Businesses.Where(b => b.UserId == UserId).ToListAsync(); + return entities.Select(e => new BusinessModel + { + UserId = e.UserId, + Id = e.Id, + Name = e.Name, + Type = e.Type, + PhoneCode = e.PhoneCode, + PhoneNumber = e.PhoneNumber, + Industry = e.Industry, + About = e.About, + Location = e.Location, + Longitude = e.Longitude, + Latitude = e.Latitude, + ShortLink = e.ShortLink, + Logo = e.Logo + }).ToArray(); + } + } +} diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.Designer.cs similarity index 99% rename from src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.Designer.cs index 9679eb2..326c0c7 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.Designer.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.Designer.cs @@ -12,8 +12,8 @@ namespace ProjectR.Backend.Persistence.Migrations { [DbContext(typeof(AppDbContext))] - [Migration("20250928213128_InitialMigration")] - partial class InitialMigration + [Migration("20250930210149_Initial")] + partial class Initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.cs similarity index 99% rename from src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs rename to src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.cs index 297ecf4..1411a84 100644 --- a/src/ProjectR.Backend.Persistence/Migrations/20250928213128_InitialMigration.cs +++ b/src/ProjectR.Backend.Persistence/Migrations/20250930210149_Initial.cs @@ -6,7 +6,7 @@ namespace ProjectR.Backend.Persistence.Migrations { /// - public partial class InitialMigration : Migration + public partial class Initial : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs index eeef08d..3146ecc 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessAvailabilityRepository.cs @@ -22,7 +22,7 @@ public BusinessAvailabilityRepository(AppDbContext appDbContext) { BusinessAvailability? availability = await _appDbContext.BusinessAvailabilities .Include(x => x.Slots)! - .ThenInclude(s => s.Breaks) + .ThenInclude(s => s.Breaks) .FirstOrDefaultAsync(x => x.Id == id && x.RecordStatus == RecordStatus.Active); if (availability == null) @@ -32,24 +32,6 @@ public BusinessAvailabilityRepository(AppDbContext appDbContext) BusinessAvailabilityModel result = Mapper.Map(availability); return result; - // return new BusinessAvailabilityModel - // { - // Id = availability.Id, - // BusinessId = availability.BusinessId, - // Slots = availability.Slots?.Select(slot => new BusinessAvailabilitySlotModel - // { - // BusinessAvailabilityId = availability.Id, - // DayOfWeek = slot.DayOfWeek, - // StartTime = slot.StartTime, - // EndTime = slot.EndTime, - // Breaks = slot.Breaks?.Select(b => new BreakModel - // { - // Id = b.Id, - // StartTime = b.StartTime, - // EndTime = b.EndTime - // }).ToList() - // }).ToList() - // }; } public async Task AddAsync(BusinessAvailabilityModel model) @@ -74,11 +56,32 @@ public async Task UpdateAsync(Guid id, UpdateBusiness return null!; } - //remove all existing slots and breaks - _appDbContext.BusinessAvailabilitySlots.RemoveRange(availability.Slots!); - _appDbContext.AddRange(model.Slots!); + if (availability.Slots != null && availability.Slots.Any()) + { + _appDbContext.BusinessAvailabilitySlots.RemoveRange(availability.Slots); + } + + List newSlots = model.Slots?.Select(s => Mapper.Map(s)).ToList() + ?? new List(); + + foreach (BusinessAvailabilitySlot slot in newSlots) + { + slot.BusinessAvailabilityId = availability.Id; + } + + if (newSlots.Any()) + { + await _appDbContext.BusinessAvailabilitySlots.AddRangeAsync(newSlots); + } + await _appDbContext.SaveChangesAsync(); - return Mapper.Map(availability); + + BusinessAvailability updatedAvailability = await _appDbContext.BusinessAvailabilities + .Include(x => x.Slots)! + .ThenInclude(s => s.Breaks) + .FirstAsync(x => x.Id == id); + + return Mapper.Map(updatedAvailability); } public async Task GetAllByBusinessIdAsync(Guid id, bool includeAll = false) @@ -94,7 +97,6 @@ public async Task GetAllByBusinessIdAsync(Guid id, query = query.Where(x => x.BusinessId == id && x.RecordStatus == RecordStatus.Active); } - // Conditionally include related entities only if needed if (includeAll) { query = query.Include(x => x.Slots!) diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs index 7a1b002..fd033a5 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs @@ -217,5 +217,31 @@ public async Task IsBusinessExist(Guid userId) { return await _context.Businesses.AnyAsync(c => c.UserId == userId); } + + public async Task IsBusinessExist(Guid userId, Guid BusinessId) + { + return await _context.Businesses.AnyAsync(c => c.UserId == userId && c.Id == BusinessId) ; + } + + public async Task GetUserBusinessesAsync(Guid UserId) + { + List entities = await _context.Businesses.Where(b => b.UserId == UserId).ToListAsync(); + return entities.Select(e => new BusinessModel + { + UserId = e.UserId, + Id = e.Id, + Name = e.Name, + Type = e.Type, + PhoneCode = e.PhoneCode, + PhoneNumber = e.PhoneNumber, + Industry = e.Industry, + About = e.About, + Location = e.Location, + Longitude = e.Longitude, + Latitude = e.Latitude, + ShortLink = e.ShortLink, + Logo = e.Logo + }).ToArray(); + } } } diff --git a/src/ProjectR.Backend.Shared/Mappers/Mapper.cs b/src/ProjectR.Backend.Shared/Mappers/Mapper.cs index 1a608e2..8fd64e2 100644 --- a/src/ProjectR.Backend.Shared/Mappers/Mapper.cs +++ b/src/ProjectR.Backend.Shared/Mappers/Mapper.cs @@ -1,9 +1,23 @@ using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; namespace ProjectR.Backend.Shared.Mappers { public static class Mapper { + private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings + { + // Prevent self-referencing loop exceptions by ignoring back-references + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + // Keep property names predictable when mapping between domain and DTOs + ContractResolver = new DefaultContractResolver + { + NamingStrategy = new CamelCaseNamingStrategy() + }, + // Ignore nulls to reduce noise during mapping + NullValueHandling = NullValueHandling.Ignore + }; + public static TDestination Map(TSource source) { if (source == null) @@ -11,8 +25,8 @@ public static TDestination Map(TSource source) return default!; } - string serialized = JsonConvert.SerializeObject(source); - return JsonConvert.DeserializeObject(serialized)!; + string serialized = JsonConvert.SerializeObject(source, _settings); + return JsonConvert.DeserializeObject(serialized, _settings)!; } } } \ No newline at end of file diff --git a/src/ProjectR.Backend.csproj b/src/ProjectR.Backend.csproj index 924c852..8838ad2 100644 --- a/src/ProjectR.Backend.csproj +++ b/src/ProjectR.Backend.csproj @@ -48,6 +48,7 @@ + diff --git a/src/Properties/serviceDependencies.json b/src/Properties/serviceDependencies.json new file mode 100644 index 0000000..33703d5 --- /dev/null +++ b/src/Properties/serviceDependencies.json @@ -0,0 +1,3 @@ +{ + "dependencies": {} +} \ No newline at end of file diff --git a/src/Properties/serviceDependencies.local.json b/src/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..33703d5 --- /dev/null +++ b/src/Properties/serviceDependencies.local.json @@ -0,0 +1,3 @@ +{ + "dependencies": {} +} \ No newline at end of file diff --git a/src/Properties/serviceDependencies.local.json.user b/src/Properties/serviceDependencies.local.json.user new file mode 100644 index 0000000..1b0e055 --- /dev/null +++ b/src/Properties/serviceDependencies.local.json.user @@ -0,0 +1,4 @@ +{ + "dependencies": {}, + "parameters": {} +} \ No newline at end of file diff --git a/src/appsettings.json b/src/appsettings.json index 20f5b5b..cd66864 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -1,35 +1,38 @@ { "ConnectionStrings": { - "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=projectr-db;User Id=sa1;Password=StrongPassword123!;TrustServerCertificate=true;MultipleActiveResultSets=true" + //"DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=projectr;MultipleActiveResultSets=true", + //"DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=projectr-db;User Id=sa1;Password=StrongPassword123!;TrustServerCertificate=true;MultipleActiveResultSets=true", + "DefaultConnection": "Data Source=localhost\\SQLEXPRESS;Initial Catalog=projectr;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" + }, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "Jwt": { + "Issuer": "https://projectr.dev.com", + "Audience": "https://projectr.dev.com", + "Key": "FakeDevelopmentKeyForOurProjectRApp@12345", + "ValidityInMinutes": 43200 + }, + "Twilio": { + "AccountSID": "tEST", + "AuthToken": "tEST", + "UseMock": true, + "OtpContentSid": "tEST" + }, + "Otp": { + "UseMock": true, + "ExpiryInMin": 10 + }, + "Cloudinary": { + "CloudName": "dowypvotw", + "ApiKey": "717696641265335", + "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" + }, + "BusinessAvailability": { + "MaxAdvanceBookingInDays": 7 } - }, - "Jwt": { - "Issuer": "https://projectr.dev.com", - "Audience": "https://projectr.dev.com", - "Key": "FakeDevelopmentKeyForOurProjectRApp@12345", - "ValidityInMinutes": 43200 - }, - "Twilio": { - "AccountSID": "tEST", - "AuthToken": "tEST", - "UseMock": true, - "OtpContentSid": "tEST" - }, - "Otp": { - "UseMock": false, - "ExpiryInMin": 10 - }, - "Cloudinary": { - "CloudName": "dowypvotw", - "ApiKey": "717696641265335", - "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" - }, - "BusinessAvailability": { - "MaxAdvanceBookingInDays": 7 } -} diff --git a/src/src.sln b/src/src.sln new file mode 100644 index 0000000..53c6546 --- /dev/null +++ b/src/src.sln @@ -0,0 +1,60 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend", "ProjectR.Backend.csproj", "{9736014B-8E52-B32A-87AB-2C313CF7DDFA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend.Application", "ProjectR.Backend.Application\ProjectR.Backend.Application.csproj", "{074044BD-717E-38B2-CE7E-4F247F6FE406}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend.Domain", "ProjectR.Backend.Domain\ProjectR.Backend.Domain.csproj", "{54CD46B5-211D-519B-37EB-0E61E67FDCDE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend.Infrastructure", "ProjectR.Backend.Infrastructure\ProjectR.Backend.Infrastructure.csproj", "{92C6C20A-ACBF-C36C-AF12-1712BCAFB2EC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend.Persistence", "ProjectR.Backend.Persistence\ProjectR.Backend.Persistence.csproj", "{D76DD076-C7AA-14F1-38B3-BABB0C0FEA40}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend.Shared", "ProjectR.Backend.Shared\ProjectR.Backend.Shared.csproj", "{983190D8-70DB-169C-F7EF-BD219F3BDC3F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectR.Backend.Tests", "ProjectR.Backend.Tests\ProjectR.Backend.Tests.csproj", "{86971173-D47B-9C63-7A61-1BB93959431D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9736014B-8E52-B32A-87AB-2C313CF7DDFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9736014B-8E52-B32A-87AB-2C313CF7DDFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9736014B-8E52-B32A-87AB-2C313CF7DDFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9736014B-8E52-B32A-87AB-2C313CF7DDFA}.Release|Any CPU.Build.0 = Release|Any CPU + {074044BD-717E-38B2-CE7E-4F247F6FE406}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {074044BD-717E-38B2-CE7E-4F247F6FE406}.Debug|Any CPU.Build.0 = Debug|Any CPU + {074044BD-717E-38B2-CE7E-4F247F6FE406}.Release|Any CPU.ActiveCfg = Release|Any CPU + {074044BD-717E-38B2-CE7E-4F247F6FE406}.Release|Any CPU.Build.0 = Release|Any CPU + {54CD46B5-211D-519B-37EB-0E61E67FDCDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54CD46B5-211D-519B-37EB-0E61E67FDCDE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54CD46B5-211D-519B-37EB-0E61E67FDCDE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54CD46B5-211D-519B-37EB-0E61E67FDCDE}.Release|Any CPU.Build.0 = Release|Any CPU + {92C6C20A-ACBF-C36C-AF12-1712BCAFB2EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92C6C20A-ACBF-C36C-AF12-1712BCAFB2EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92C6C20A-ACBF-C36C-AF12-1712BCAFB2EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92C6C20A-ACBF-C36C-AF12-1712BCAFB2EC}.Release|Any CPU.Build.0 = Release|Any CPU + {D76DD076-C7AA-14F1-38B3-BABB0C0FEA40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D76DD076-C7AA-14F1-38B3-BABB0C0FEA40}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D76DD076-C7AA-14F1-38B3-BABB0C0FEA40}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D76DD076-C7AA-14F1-38B3-BABB0C0FEA40}.Release|Any CPU.Build.0 = Release|Any CPU + {983190D8-70DB-169C-F7EF-BD219F3BDC3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {983190D8-70DB-169C-F7EF-BD219F3BDC3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {983190D8-70DB-169C-F7EF-BD219F3BDC3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {983190D8-70DB-169C-F7EF-BD219F3BDC3F}.Release|Any CPU.Build.0 = Release|Any CPU + {86971173-D47B-9C63-7A61-1BB93959431D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86971173-D47B-9C63-7A61-1BB93959431D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86971173-D47B-9C63-7A61-1BB93959431D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86971173-D47B-9C63-7A61-1BB93959431D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {999A3DA5-8A82-49E9-A14A-5980485E18B6} + EndGlobalSection +EndGlobal From 4fbac1ce3c28afe7fe22141cd4d63d767d13534c Mon Sep 17 00:00:00 2001 From: DevFinesse Date: Tue, 7 Oct 2025 14:17:36 +0100 Subject: [PATCH 13/13] Refactored Industry and fixes --- src/Controllers/BusinessesController.cs | 17 +- src/Controllers/IndustryController.cs | 73 ++++-- .../Interfaces/Managers/IBusinessManager.cs | 3 +- .../Interfaces/Managers/IIndustryManager.cs | 10 +- .../Repository/IBusinessRepository.cs | 3 +- .../Repository/IIndustryRepository.cs | 13 +- .../Models/BusinessAvailabilitySlotModel.cs | 6 - .../Models/IndustryModel.cs | 10 +- .../Managers/BusinessManager.cs | 10 +- .../Managers/IndustryManager.cs | 69 ++--- .../BusinessRepository.cs | 242 ------------------ .../Repository/BusinessRepository.cs | 21 +- .../Repository/IndustryRepository.cs | 65 +++-- src/appsettings.json | 6 +- 14 files changed, 165 insertions(+), 383 deletions(-) delete mode 100644 src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs diff --git a/src/Controllers/BusinessesController.cs b/src/Controllers/BusinessesController.cs index 5fb6dd9..8346155 100644 --- a/src/Controllers/BusinessesController.cs +++ b/src/Controllers/BusinessesController.cs @@ -88,25 +88,14 @@ public async Task Delete([FromRoute] Guid id) return result.Status ? Ok(result) : BadRequest(result); } - [Produces("application/json")] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] - [HttpGet("GetByUser")] - public async Task GetByUserId() - { - BaseResponseModel result = await _businessManager.GetByUserId(UserId); - return result.Status ? Ok(result) : BadRequest(result); - } - [Produces("application/json")] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] - [HttpGet("{id:guid}/businesses")] - public async Task GetUserBusinesses(Guid id) + [HttpGet("/Userbusinesses")] + public async Task GetUserBusinesses() { - BusinessModel[] result = await _businessManager.GetUserBusinessesAsync(id); + BusinessModel[] result = await _businessManager.GetBusinessByUserAsync(UserId); return Ok(result); } - } } diff --git a/src/Controllers/IndustryController.cs b/src/Controllers/IndustryController.cs index 19a5c92..e57133a 100644 --- a/src/Controllers/IndustryController.cs +++ b/src/Controllers/IndustryController.cs @@ -1,57 +1,82 @@ using Microsoft.AspNetCore.Mvc; using ProjectR.Backend.Application.Interfaces.Managers; using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Infrastructure.Managers; namespace ProjectR.Backend.Controllers { [ApiController] [Route("api/[controller]")] - public class IndustryController : ControllerBase + public class IndustryController : BaseController { - private readonly IIndustryManager _manager; + private readonly IIndustryManager _industryManager; - public IndustryController(IIndustryManager manager) + public IndustryController(IIndustryManager industryManager) { - _manager = manager; + _industryManager = industryManager; } + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] [HttpPost] - public async Task Create([FromBody] IndustryModel industry) + public async Task Add([FromBody] AddIndustryModel industry) { - var id = await _manager.CreateIndustryAsync(industry.Name!, industry.Description); - return CreatedAtAction(nameof(GetById), new { id }, null); - } - [HttpGet("{id}")] - public async Task GetById(Guid id) - { - var industry = await _manager.GetIndustryByIdAsync(id); - if (industry == null) + if (industry == null || !ModelState.IsValid) { - return NotFound(); + return BadRequest(ModelState); } - return Ok(industry); + + ResponseModel result = await _industryManager.AddAsync(industry); + return result.Status ? Ok(result) : BadRequest(result); + } + + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] + [HttpGet("{id:guid}")] + public async Task Get(Guid id) + { + ResponseModel result = await _industryManager.GetByIdAsync(id); + return result.Status ? Ok(result) : BadRequest(); } + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ResponseModel))] [HttpGet] public async Task GetAll() { - var industries = await _manager.GetAllIndustriesAsync(); - return Ok(industries); + IndustryModel[] result = await _industryManager.GetAllAsync(); + return Ok(result); } - [HttpPut("{id}")] - public async Task Update(Guid id, [FromBody] IndustryModel industry) + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] + [HttpPut] + public async Task Update([FromBody] IndustryModel industry) { - await _manager.UpdateIndustryAsync(id, industry.Name!, industry.Description); - return NoContent(); + if (industry == null || !ModelState.IsValid) + { + return BadRequest(ModelState); + } + + ResponseModel result = await _industryManager.UpdateAsync(industry); + return result.Status ? Ok(result) : BadRequest(result); + } + [Produces("application/json")] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(ResponseModel))] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ResponseModel))] [HttpDelete("{id}")] - public async Task Delete(Guid id) + public async Task Delete([FromRoute] Guid id) { - await _manager.DeleteIndustryAsync(id); - return NoContent(); + BaseResponseModel result = await _industryManager.DeleteAsync(id); + return result.Status ? Ok(result) : BadRequest(result); } } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs index 8567f20..2d0c5e1 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IBusinessManager.cs @@ -7,14 +7,13 @@ public interface IBusinessManager Task> GetByIdAsync(Guid id); Task> GetBySlugAsync(string slug); Task GetAllAsync(); - Task GetUserBusinessesAsync(Guid UserId); + Task GetBusinessByUserAsync(Guid UserId); Task> AddAsync(AddBusinessModel[] businesses); Task> AddAsync(AddBusinessModel business); Task> UpdateAsync(BusinessModel business); Task> UpdateAsync(BusinessModel[] businesses); Task DeleteAsync(BusinessModel[] businesses); Task DeleteAsync(Guid id); - Task> GetByUserId(Guid userId); Task IsBusinessExist(Guid userId); Task IsBusinessExist(Guid userId, Guid BusinessId); } diff --git a/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs b/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs index 54b1207..2bd49b4 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Managers/IIndustryManager.cs @@ -5,10 +5,10 @@ namespace ProjectR.Backend.Application.Interfaces.Managers { public interface IIndustryManager { - Task CreateIndustryAsync(string name, string? description); - Task GetIndustryByIdAsync(Guid id); - Task> GetAllIndustriesAsync(); - Task UpdateIndustryAsync(Guid id, string name, string? description); - Task DeleteIndustryAsync(Guid id); + Task> AddAsync(AddIndustryModel industry); + Task> GetByIdAsync(Guid id); + Task GetAllAsync(); + Task> UpdateAsync(IndustryModel industry); + Task DeleteAsync(Guid id); } } diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs index 7ec4ceb..d190d0f 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IBusinessRepository.cs @@ -7,7 +7,7 @@ public interface IBusinessRepository Task GetByIdAsync(Guid id); Task GetBySlugAsync(string slug); Task GetAllAsync(); - Task GetUserBusinessesAsync(Guid UserId); + Task GetBusinessByUserAsync(Guid UserId); Task AddAsync(BusinessModel[] businessModels); Task AddAsync(BusinessModel businessModel); Task UpdateAsync(BusinessModel[] businessModels); @@ -15,7 +15,6 @@ public interface IBusinessRepository Task DeleteAsync(BusinessModel[] businessModels); Task DeleteAsync(BusinessModel businessModel); Task SlugExistsAsync(string shortLink, Guid? excludedId = null); - Task GetByUserId(Guid userId); Task IsBusinessExist(Guid userId); Task IsBusinessExist(Guid userId, Guid BusinessId); } diff --git a/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs b/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs index 8e60d40..45070f9 100644 --- a/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs +++ b/src/ProjectR.Backend.Application/Interfaces/Repository/IIndustryRepository.cs @@ -1,13 +1,14 @@ -using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; namespace ProjectR.Backend.Application.Interfaces.Repository { public interface IIndustryRepository { - Task CreateAsync(Industry industry); - Task GetByIdAsync(Guid id); - Task> GetAllAsync(); - Task UpdateAsync(Industry industry); - Task DeleteAsync(Guid id); + Task AddAsync(IndustryModel industry); + Task GetByIdAsync(Guid id); + Task GetAllAsync(); + Task UpdateAsync(IndustryModel industry); + Task DeleteAsync(IndustryModel industry); } } \ No newline at end of file diff --git a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs index a7ef9f7..a84bfa3 100644 --- a/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs +++ b/src/ProjectR.Backend.Application/Models/BusinessAvailabilitySlotModel.cs @@ -38,12 +38,6 @@ public class AddBusinessAvailabilitySlotModel [DataType(DataType.Time, ErrorMessage = "Invalid time format")] public DateTimeOffset? EndTime { get; set; } - // [JsonIgnore] - // public TimeOnly? StartTimeInternal => TimeOnly.FromDateTime(StartTime!.Value); - - // [JsonIgnore] - // public TimeOnly? EndTimeInternal => TimeOnly.FromDateTime(EndTime!.Value); - public List Breaks { get; set; } = []; } } diff --git a/src/ProjectR.Backend.Application/Models/IndustryModel.cs b/src/ProjectR.Backend.Application/Models/IndustryModel.cs index 4e79951..23fd0db 100644 --- a/src/ProjectR.Backend.Application/Models/IndustryModel.cs +++ b/src/ProjectR.Backend.Application/Models/IndustryModel.cs @@ -6,9 +6,17 @@ public class IndustryModel { public Guid Id { get; set; } - [Required(ErrorMessage = "Industry Name is Required")] public string? Name { get; set; } public string? Description { get; set; } } + + public class AddIndustryModel + { + + [Required(ErrorMessage = "Industry Name is Required")] + public string? Name { get; set; } + + public string? Description { get; set; } + } } diff --git a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs index dd35621..bee4e98 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/BusinessManager.cs @@ -121,15 +121,9 @@ public async Task> GetBySlugAsync(string slug) return new ResponseModel(message: result != null ? "Business retrieved successfully" : "Business not found", data: result, status: result != null); } - public async Task> GetByUserId(Guid userId) + public async Task GetBusinessByUserAsync(Guid UserId) { - BusinessModel? result = await _businessRepository.GetByUserId(userId); - return new ResponseModel(message: result != null ? "Business retrieved successfully" : "Business not found", data: result, status: result != null); - } - - public async Task GetUserBusinessesAsync(Guid UserId) - { - return await _businessRepository.GetUserBusinessesAsync(UserId); + return await _businessRepository.GetBusinessByUserAsync(UserId); } public async Task IsBusinessExist(Guid userId) diff --git a/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs b/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs index f8cabc3..7d6ec53 100644 --- a/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs +++ b/src/ProjectR.Backend.Infrastructure/Managers/IndustryManager.cs @@ -1,66 +1,67 @@ using ProjectR.Backend.Application.Interfaces.Managers; -using ProjectR.Backend.Application.Models; using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; using ProjectR.Backend.Domain.Entities; +using ProjectR.Backend.Persistence.Repository; namespace ProjectR.Backend.Infrastructure.Managers { public class IndustryManager : IIndustryManager { - private readonly IIndustryRepository _repository; + private readonly IIndustryRepository _industryRepository; public IndustryManager(IIndustryRepository repository) { - _repository = repository; + _industryRepository = repository; } - public async Task CreateIndustryAsync(string name, string? description) + public async Task> AddAsync(AddIndustryModel model) { - var industry = new Industry - { - Id = Guid.NewGuid(), - Name = name, - Description = description + IndustryModel entity = new() + { + Name = model.Name, + Description = model.Description, }; - return await _repository.CreateAsync(industry); + IndustryModel result = await _industryRepository.AddAsync(entity); + return new ResponseModel(message: "Business Added Successfully", data: result, status: true); } - public async Task GetIndustryByIdAsync(Guid id) + public async Task> GetByIdAsync(Guid id) { - var industry = await _repository.GetByIdAsync(id); - return industry == null ? null : new Industry - { - Id = industry.Id, - Name = industry.Name , - Description = industry.Description - }; + IndustryModel? result = await _industryRepository.GetByIdAsync(id); + return new ResponseModel(message: result != null ? "Industry retrieved successfully" : "Industry not found", data: result, status: result != null); + } - public async Task> GetAllIndustriesAsync() + public async Task GetAllAsync() { - var industries = await _repository.GetAllAsync(); - return industries.Select(i => new Industry - { - Id = i.Id, - Name = i.Name, - Description = i.Description - }).ToList(); + return await _industryRepository.GetAllAsync(); } - public async Task UpdateIndustryAsync(Guid id, string name, string? description) + public async Task DeleteAsync(Guid id) { - var industry = await _repository.GetByIdAsync(id); - if (industry != null) + IndustryModel? existingIndustry = await _industryRepository.GetByIdAsync(id); + if (existingIndustry == null) { - industry.Name = name; - industry.Description = description; - await _repository.UpdateAsync(industry); + return new BaseResponseModel(message: "Industry not found", status: false); } + + await _industryRepository.DeleteAsync(existingIndustry); + return new BaseResponseModel(message: "Industry succesfully deleted", status: true); } - public async Task DeleteIndustryAsync(Guid id) + + + public async Task> UpdateAsync(IndustryModel industry) { - await _repository.DeleteAsync(id); + IndustryModel? existingIndustry = await _industryRepository.GetByIdAsync(industry.Id); + if (existingIndustry == null) + { + return new ResponseModel(message: "Industry not found", data: default, status: false); + } + + IndustryModel result = await _industryRepository.UpdateAsync(industry); + return new ResponseModel(message: "Business updated successfully", data: result, status: true); } } } diff --git a/src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs b/src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs deleted file mode 100644 index 7afe79b..0000000 --- a/src/ProjectR.Backend.Persistence.Repository/BusinessRepository.cs +++ /dev/null @@ -1,242 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using ProjectR.Backend.Application.Interfaces.Repository; -using ProjectR.Backend.Application.Models; -using ProjectR.Backend.Domain.Entities; -using ProjectR.Backend.Persistence.DatabaseContext; - -namespace ProjectR.Backend.Persistence.Repository -{ - public class BusinessRepository : IBusinessRepository - { - private readonly AppDbContext _context; - - public BusinessRepository(AppDbContext context) - { - _context = context; - } - - public async Task SlugExistsAsync(string shortLink, Guid? excludedId = null) - { - IQueryable query = _context.Businesses.Where(p => p.ShortLink == shortLink); - - if (excludedId.HasValue) - { - query = query.Where(p => p.Id == excludedId.Value); - } - - return await query.AnyAsync(); - } - public async Task AddAsync(BusinessModel[] businessModels) - { - List entities = businessModels.Select(e => new Business - { - UserId = e.UserId, - Id = e.Id, - Name = e.Name, - Type = e.Type, - PhoneCode = e.PhoneCode, - PhoneNumber = e.PhoneNumber, - Industry = e.Industry, - About = e.About, - Location = e.Location, - Longitude = e.Longitude, - Latitude = e.Latitude, - ShortLink = e.ShortLink, - Logo = e.Logo - }).ToList(); - - await _context.Businesses.AddRangeAsync(entities); - await _context.SaveChangesAsync(); - return businessModels; - } - - public async Task AddAsync(BusinessModel businessModel) - { - Business entity = new() - { - UserId = businessModel.UserId, - Id = businessModel.Id, - Name = businessModel.Name, - Type = businessModel.Type, - PhoneCode = businessModel.PhoneCode, - PhoneNumber = businessModel.PhoneNumber, - Industry = businessModel.Industry, - About = businessModel.About, - Location = businessModel.Location, - Longitude = businessModel.Longitude, - Latitude = businessModel.Latitude, - ShortLink = businessModel.ShortLink, - Logo = businessModel.Logo - }; - - EntityEntry result = await _context.Businesses.AddAsync(entity); - result.Entity.Id = entity.Id; - await _context.SaveChangesAsync(); - return businessModel; - } - - public async Task DeleteAsync(BusinessModel[] businessModels) - { - List entities = businessModels.Select(c => new Business { Id = c.Id }).ToList(); - _context.Businesses.RemoveRange(entities); - await _context.SaveChangesAsync(); - } - - public async Task DeleteAsync(BusinessModel businessModel) - { - Business? entity = await _context.Businesses.SingleOrDefaultAsync(c => c.Id == businessModel.Id); - _context.Businesses.Remove(entity!); - await _context.SaveChangesAsync(); - } - - public async Task GetAllAsync() - { - List entities = await _context.Businesses.ToListAsync(); - return entities.Select(e => new BusinessModel - { - UserId = e.UserId, - Id = e.Id, - Name = e.Name, - Type = e.Type, - PhoneCode = e.PhoneCode, - PhoneNumber = e.PhoneNumber, - Industry = e.Industry, - About = e.About, - Location = e.Location, - Longitude = e.Longitude, - Latitude = e.Latitude, - ShortLink = e.ShortLink, - Logo = e.Logo - }).ToArray(); - } - - public async Task GetByIdAsync(Guid id) - { - Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.Id == id); - return result == null ? null : new BusinessModel - { - UserId = result!.UserId, - Id = id, - Name = result?.Name, - Type = result?.Type, - PhoneCode = result?.PhoneCode, - PhoneNumber = result?.PhoneNumber, - Industry = result?.Industry, - About = result?.About, - Location = result?.Location, - Longitude = result?.Longitude, - Latitude = result?.Latitude, - Logo = result?.Logo, - ShortLink = result?.ShortLink - }; - } - - public async Task GetBySlugAsync(string slug) - { - Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.ShortLink == slug); - return result == null ? null : new BusinessModel - { - UserId = result.UserId, - Id = result.Id, - Name = result?.Name, - Type = result?.Type, - PhoneCode = result?.PhoneCode, - PhoneNumber = result?.PhoneNumber, - Industry = result?.Industry, - About = result?.About, - Location = result?.Location, - Longitude = result?.Longitude, - Latitude = result?.Latitude, - Logo = result?.Logo, - ShortLink = result?.ShortLink - }; - } - - public async Task UpdateAsync(BusinessModel[] businessModels) - { - List entities = businessModels.Select(c => new Business - { - Id = c.Id, - Name = c.Name, - Type = c.Type, - PhoneCode = c.PhoneCode, - PhoneNumber = c.PhoneNumber, - Industry = c.Industry, - About = c.About, - Location = c.Location, - Longitude = c.Longitude, - Latitude = c.Latitude, - Logo = c.Logo - }).ToList(); - _context.Businesses.UpdateRange(entities); - await _context.SaveChangesAsync(); - return businessModels; - } - - public async Task UpdateAsync(BusinessModel businessModel) - { - Business? entity = await _context.Businesses.SingleOrDefaultAsync(c => c.Id == businessModel.Id); - entity!.Name = businessModel.Name; - entity!.Type = businessModel.Type; - entity!.PhoneCode = businessModel.PhoneCode; - entity!.PhoneNumber = businessModel.PhoneNumber; - entity!.Industry = businessModel.Industry; - entity!.About = businessModel.About; - entity!.Location = businessModel.Location; - entity!.Longitude = businessModel.Longitude; - entity!.Latitude = businessModel.Latitude; - entity!.ShortLink = businessModel.ShortLink; - entity!.Logo = businessModel.Logo; - _context.Businesses.Update(entity); - await _context.SaveChangesAsync(); - return businessModel; - } - - public async Task GetByUserId(Guid userId) - { - Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.UserId == userId); - return result == null ? null : new BusinessModel - { - UserId = result!.UserId, - Id = result.Id, - Name = result?.Name, - Type = result?.Type, - PhoneCode = result?.PhoneCode, - PhoneNumber = result?.PhoneNumber, - Industry = result?.Industry, - About = result?.About, - Location = result?.Location, - Longitude = result?.Longitude, - Latitude = result?.Latitude, - Logo = result?.Logo - }; - } - - public async Task IsBusinessExist(Guid userId) - { - return await _context.Businesses.AnyAsync(c => c.UserId == userId); - } - - public async Task GetUserBusinessesAsync(Guid UserId) - { - List entities = await _context.Businesses.Where(b => b.UserId == UserId).ToListAsync(); - return entities.Select(e => new BusinessModel - { - UserId = e.UserId, - Id = e.Id, - Name = e.Name, - Type = e.Type, - PhoneCode = e.PhoneCode, - PhoneNumber = e.PhoneNumber, - Industry = e.Industry, - About = e.About, - Location = e.Location, - Longitude = e.Longitude, - Latitude = e.Latitude, - ShortLink = e.ShortLink, - Logo = e.Logo - }).ToArray(); - } - } -} diff --git a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs index fd033a5..4048dfa 100644 --- a/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/BusinessRepository.cs @@ -193,25 +193,6 @@ public async Task UpdateAsync(BusinessModel businessModel) return businessModel; } - public async Task GetByUserId(Guid userId) - { - Business? result = await _context.Businesses.SingleOrDefaultAsync(c => c.UserId == userId); - return result == null ? null : new BusinessModel - { - UserId = result!.UserId, - Id = result.Id, - Name = result?.Name, - Type = result?.Type, - PhoneCode = result?.PhoneCode, - PhoneNumber = result?.PhoneNumber, - Industry = result?.Industry, - About = result?.About, - Location = result?.Location, - Longitude = result?.Longitude, - Latitude = result?.Latitude, - Logo = result?.Logo - }; - } public async Task IsBusinessExist(Guid userId) { @@ -223,7 +204,7 @@ public async Task IsBusinessExist(Guid userId, Guid BusinessId) return await _context.Businesses.AnyAsync(c => c.UserId == userId && c.Id == BusinessId) ; } - public async Task GetUserBusinessesAsync(Guid UserId) + public async Task GetBusinessByUserAsync(Guid UserId) { List entities = await _context.Businesses.Where(b => b.UserId == UserId).ToListAsync(); return entities.Select(e => new BusinessModel diff --git a/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs b/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs index 09de79e..e74bdc5 100644 --- a/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs +++ b/src/ProjectR.Backend.Persistence/Repository/IndustryRepository.cs @@ -1,43 +1,76 @@ using Microsoft.EntityFrameworkCore; -using ProjectR.Backend.Domain.Entities; +using Microsoft.EntityFrameworkCore.ChangeTracking; using ProjectR.Backend.Application.Interfaces.Repository; +using ProjectR.Backend.Application.Models; +using ProjectR.Backend.Domain.Entities; using ProjectR.Backend.Persistence.DatabaseContext; namespace ProjectR.Backend.Persistence.Repository { public class IndustryRepository : IIndustryRepository { - private readonly AppDbContext _appDbContext; + private readonly AppDbContext _context; public IndustryRepository(AppDbContext appDbContext) { - _appDbContext = appDbContext; + _context = appDbContext; } - public async Task CreateAsync(Industry industry) + public async Task AddAsync(IndustryModel industryModel) { - await _appDbContext.Industries.AddAsync(industry); - await _appDbContext.SaveChangesAsync(); - return industry.Id; + Industry entity = new() + { + Name = industryModel.Name, + Description = industryModel.Description + }; + + EntityEntry result = await _context.Industries.AddAsync(entity); + result.Entity.Id = entity.Id; + await _context.SaveChangesAsync(); + return industryModel; + } - public async Task GetByIdAsync(Guid id) => await _appDbContext.Industries.FindAsync(id); + public async Task GetByIdAsync(Guid id) + { + Industry? entity = await _context.Industries.SingleOrDefaultAsync(i => i.Id.Equals(id)); + return entity == null ? null : new IndustryModel + { + Id = entity.Id, + Name = entity?.Name, + Description = entity?.Description, + }; + + } - public async Task> GetAllAsync() => await _appDbContext.Industries.ToListAsync(); + public async Task GetAllAsync() + { + List entities = await _context.Industries.ToListAsync(); + return entities.Select(i => new IndustryModel + { + Id = i.Id, + Name = i.Name, + Description = i.Description, + }).ToArray(); + } - public async Task UpdateAsync(Industry industry) + public async Task UpdateAsync(IndustryModel industry) { - _appDbContext.Industries.Update(industry); - await _appDbContext.SaveChangesAsync(); + Industry? entity = await _context.Industries.SingleOrDefaultAsync(i => i.Id.Equals(industry.Id)); + entity!.Name = industry.Name; + entity!.Description = industry.Description; + _context.Industries.Update(entity); + await _context.SaveChangesAsync(); + return industry; } - public async Task DeleteAsync(Guid id) + public async Task DeleteAsync(IndustryModel model) { - var industry = await _appDbContext.Industries.FindAsync(id); + Industry? industry = await _context.Industries.FindAsync(model.Id); if (industry != null) { - _appDbContext.Industries.Remove(industry); - await _appDbContext.SaveChangesAsync(); + _context.Industries.Remove(industry); + await _context.SaveChangesAsync(); } } } diff --git a/src/appsettings.json b/src/appsettings.json index cd66864..ef06def 100644 --- a/src/appsettings.json +++ b/src/appsettings.json @@ -28,9 +28,9 @@ "ExpiryInMin": 10 }, "Cloudinary": { - "CloudName": "dowypvotw", - "ApiKey": "717696641265335", - "ApiSecret": "GQfLtDOeRdeM7dl4sYpjorgy0_8" + "CloudName": "", + "ApiKey": "", + "ApiSecret": "" }, "BusinessAvailability": { "MaxAdvanceBookingInDays": 7