Added shared projects
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
PROPRIETARY LICENSE
|
||||||
|
|
||||||
|
Copyright (c) 2026 Lite Charms (PTY) Ltd. All rights reserved.
|
||||||
|
|
||||||
|
This software and its associated documentation (the "Software") are the
|
||||||
|
proprietary property of Lite Charms (PTY) Ltd.
|
||||||
|
|
||||||
|
The Software is provided for internal use only. Unauthorized copying,
|
||||||
|
distribution, modification, or use of this file via any medium is
|
||||||
|
strictly prohibited.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
namespace LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Customer> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(Customer));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
||||||
|
builder.Property(f => f.Company);
|
||||||
|
builder.Property(f => f.Name).IsRequired();
|
||||||
|
builder.Property(f => f.LastName).IsRequired();
|
||||||
|
builder.Property(f => f.Email).IsRequired();
|
||||||
|
builder.Property(f => f.Tax);
|
||||||
|
builder.Property(f => f.Discord);
|
||||||
|
builder.Property(f => f.Slack);
|
||||||
|
builder.Property(f => f.LinkedIn);
|
||||||
|
builder.Property(f => f.Whatsapp);
|
||||||
|
builder.Property(f => f.Website);
|
||||||
|
builder.Property(f => f.Phone);
|
||||||
|
builder.Property(f => f.Address);
|
||||||
|
builder.Property(f => f.City);
|
||||||
|
builder.Property(f => f.Region);
|
||||||
|
builder.Property(f => f.Country);
|
||||||
|
builder.Property(f => f.PostalCode);
|
||||||
|
builder.Property(f => f.Active).HasDefaultValue(true);
|
||||||
|
|
||||||
|
builder.HasMany(f => f.Leads)
|
||||||
|
.WithOne(f => f.Customer)
|
||||||
|
.HasForeignKey(f => f.CustomerId)
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
public class LeadConfiguration : IEntityTypeConfiguration<Lead>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Lead> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(Lead));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
||||||
|
builder.Property(f => f.CustomerId).IsRequired(false);
|
||||||
|
builder.Property(f => f.GoogleClickId);
|
||||||
|
builder.Property(f => f.WebClickId);
|
||||||
|
builder.Property(f => f.AppClickId);
|
||||||
|
builder.Property(f => f.CampaignId);
|
||||||
|
builder.Property(f => f.AdGroupId);
|
||||||
|
builder.Property(f => f.AdName);
|
||||||
|
builder.Property(f => f.TargetId);
|
||||||
|
builder.Property(f => f.FeedItemId);
|
||||||
|
builder.Property(f => f.ClickLocation);
|
||||||
|
builder.Property(f => f.Status).IsRequired();
|
||||||
|
builder.Property(f => f.AttributionHash).IsRequired(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
public class OrderConfiguration : IEntityTypeConfiguration<Order>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Order> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(Order));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
||||||
|
builder.Property(f => f.CustomerId).IsRequired();
|
||||||
|
builder.Property(f => f.RefundId).IsRequired(false);
|
||||||
|
builder.Property(f => f.ProductPriceId).IsRequired();
|
||||||
|
builder.Property(f => f.Status).HasConversion<int>().IsRequired();
|
||||||
|
builder.Property(f => f.Notes).HasColumnType("jsonb").IsRequired(false);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.ProductPrice)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(f => f.ProductPriceId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.Customer)
|
||||||
|
.WithMany(f => f.Orders)
|
||||||
|
.HasForeignKey(f => f.CustomerId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
namespace LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
public class OrderRefundConfiguration : IEntityTypeConfiguration<OrderRefund>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<OrderRefund> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(OrderRefund));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
||||||
|
builder.Property(f => f.OrderId).IsRequired();
|
||||||
|
builder.Property(f => f.Reason).IsRequired();
|
||||||
|
builder.Property(f => f.Amount).IsRequired().HasPrecision(18, 2);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.Order)
|
||||||
|
.WithOne(o => o.Refund)
|
||||||
|
.HasForeignKey<OrderRefund>(o => o.OrderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
public class ProductConfiguration : IEntityTypeConfiguration<Product>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Product> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(Product));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.Name).IsRequired();
|
||||||
|
builder.Property(f => f.Description).IsRequired();
|
||||||
|
builder.Property(f => f.Active).HasDefaultValue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
namespace LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
public class ProductPriceConfiguration : IEntityTypeConfiguration<ProductPrice>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<ProductPrice> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable(nameof(ProductPrice));
|
||||||
|
|
||||||
|
builder.HasKey(f => f.Id);
|
||||||
|
builder.Property(f => f.CreatedAt).ValueGeneratedOnAdd();
|
||||||
|
builder.Property(f => f.UpdatedAt).IsRequired(false).ValueGeneratedOnUpdate();
|
||||||
|
builder.Property(f => f.ProductId).IsRequired();
|
||||||
|
builder.Property(f => f.Price).IsRequired().HasPrecision(18, 2);
|
||||||
|
builder.Property(f => f.Discount).HasPrecision(18, 2);
|
||||||
|
builder.Property(f => f.Active);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.Product)
|
||||||
|
.WithMany(p => p.ProductPrices)
|
||||||
|
.HasForeignKey(f => f.ProductId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<CustomerConfiguration, Customer>]
|
||||||
|
public class Customer : Models.Customer
|
||||||
|
{
|
||||||
|
public virtual ICollection<Lead>? Leads { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<Order>? Orders { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<LeadConfiguration, Lead>]
|
||||||
|
public class Lead : Models.Lead
|
||||||
|
{
|
||||||
|
public virtual Customer? Customer { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<SignAssembly>True</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Nuget Package Details -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageId>LiteCharms.Entities</PackageId>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
|
<Authors>Khwezi Mngoma</Authors>
|
||||||
|
<Company>Lite Charms (PTY) Ltd</Company>
|
||||||
|
<Description>Shared entities for Lite Charms applications.</Description>
|
||||||
|
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator.git</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<PackageTags>utility;dotnet</PackageTags>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\LICENSE" Pack="true" PackagePath="\"/>
|
||||||
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Database -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Models\LiteCharms.Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<OrderConfiguration, Order>]
|
||||||
|
public class Order : Models.Order
|
||||||
|
{
|
||||||
|
public virtual OrderRefund? Refund { get; set; }
|
||||||
|
|
||||||
|
public virtual Customer? Customer { get; set; }
|
||||||
|
|
||||||
|
public virtual ProductPrice? ProductPrice { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<OrderRefundConfiguration, OrderRefund>]
|
||||||
|
public class OrderRefund : Models.OrderRefund
|
||||||
|
{
|
||||||
|
public virtual Order? Order { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<ProductConfiguration, Product>]
|
||||||
|
public class Product : Models.Product
|
||||||
|
{
|
||||||
|
public virtual ICollection<ProductPrice>? ProductPrices { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using LiteCharms.Entities.Configuration;
|
||||||
|
|
||||||
|
namespace LiteCharms.Entities;
|
||||||
|
|
||||||
|
[EntityTypeConfiguration<ProductPriceConfiguration, ProductPrice>]
|
||||||
|
public class ProductPrice : Models.ProductPrice
|
||||||
|
{
|
||||||
|
public virtual Product? Product { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Extensions;
|
||||||
|
|
||||||
|
public static class EntityModeMappers
|
||||||
|
{
|
||||||
|
public static Customer ToModel(this Entities.Customer entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
Active = entity.Active,
|
||||||
|
Address = entity.Address,
|
||||||
|
City = entity.City,
|
||||||
|
Company = entity.Company,
|
||||||
|
Country = entity.Country,
|
||||||
|
Discord = entity.Discord,
|
||||||
|
Email = entity.Email,
|
||||||
|
LastName = entity.LastName,
|
||||||
|
LinkedIn = entity.LinkedIn,
|
||||||
|
Name = entity.Name,
|
||||||
|
Phone = entity.Phone,
|
||||||
|
PostalCode = entity.PostalCode,
|
||||||
|
Region = entity.Region,
|
||||||
|
Slack = entity.Slack,
|
||||||
|
Tax = entity.Tax,
|
||||||
|
Website = entity.Website,
|
||||||
|
Whatsapp = entity.Whatsapp
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Lead ToModel(this Entities.Lead entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
AdGroupId = entity.AdGroupId,
|
||||||
|
AdName = entity.AdName,
|
||||||
|
AppClickId = entity.AppClickId,
|
||||||
|
AttributionHash = entity.AttributionHash,
|
||||||
|
CampaignId = entity.CampaignId,
|
||||||
|
ClickLocation = entity.ClickLocation,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
FeedItemId = entity.FeedItemId,
|
||||||
|
GoogleClickId = entity.GoogleClickId,
|
||||||
|
TargetId = entity.TargetId,
|
||||||
|
WebClickId = entity.WebClickId,
|
||||||
|
Status = entity.Status
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Order ToModel(this Entities.Order entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
UpdatedAt = entity.UpdatedAt,
|
||||||
|
CustomerId = entity.CustomerId,
|
||||||
|
ProductPriceId = entity.ProductPriceId,
|
||||||
|
Notes = entity.Notes,
|
||||||
|
RefundId = entity.RefundId
|
||||||
|
};
|
||||||
|
|
||||||
|
public static OrderRefund ToModel(this Entities.OrderRefund entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
OrderId = entity.OrderId,
|
||||||
|
Reason = entity.Reason,
|
||||||
|
Amount = entity.Amount
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Product ToModel(this Entities.Product entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
Name = entity.Name,
|
||||||
|
Description = entity.Description,
|
||||||
|
Active = entity.Active
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ProductPrice ToModel(this Entities.ProductPrice entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Id = entity.Id,
|
||||||
|
ProductId = entity.ProductId,
|
||||||
|
Price = entity.Price,
|
||||||
|
Active = entity.Active,
|
||||||
|
CreatedAt = entity.CreatedAt,
|
||||||
|
Discount = entity.Discount,
|
||||||
|
UpdatedAt = entity.UpdatedAt
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<SignAssembly>True</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Nuget Package Details -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageId>LiteCharms.Extensions</PackageId>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
|
<Authors>Khwezi Mngoma</Authors>
|
||||||
|
<Company>Lite Charms (PTY) Ltd</Company>
|
||||||
|
<Description>Extension components for Lite Charms applications.</Description>
|
||||||
|
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator.git</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<PackageTags>utility;dotnet</PackageTags>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\LICENSE" Pack="true" PackagePath="\"/>
|
||||||
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Shared Usings -->
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Microsoft.AspNetCore.Builder" />
|
||||||
|
<Using Include="Microsoft.Extensions.Configuration" />
|
||||||
|
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||||
|
<Using Include="Microsoft.Extensions.Logging" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Health Checks -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Core" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Data" Version="9.0.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.SQLite.Storage" Version="9.0.0" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
|
||||||
|
<Using Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Open Telemetry -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.3" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.15.2" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.15.1" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.15.1" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="OpenTelemetry.Resources" />
|
||||||
|
<Using Include="OpenTelemetry.Exporter" />
|
||||||
|
<Using Include="OpenTelemetry.Logs" />
|
||||||
|
<Using Include="OpenTelemetry.Metrics" />
|
||||||
|
<Using Include="OpenTelemetry.Trace" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Database -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Npgsql" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Design" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Entities\LiteCharms.Entities.csproj" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Infrastructure\LiteCharms.Infrastructure.csproj" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Models\LiteCharms.Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Infrastructure.HealthChecks;
|
||||||
|
|
||||||
|
namespace LiteCharms.Extensions;
|
||||||
|
|
||||||
|
public static class Services
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddHealthChecksSupport(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddHealthChecks()
|
||||||
|
.AddCheck("Self", () => HealthCheckResult.Healthy())
|
||||||
|
.AddCheck<PostgresHealthCheck>("PostgreSQL");
|
||||||
|
|
||||||
|
//services.AddHealthChecksUI(setup =>
|
||||||
|
//{
|
||||||
|
// setup.AddHealthCheckEndpoint("Lead Generator", $"{configuration["ASPNETCORE_URLS"]}/healthui");
|
||||||
|
// setup.SetEvaluationTimeInSeconds(15);
|
||||||
|
//}).AddSqliteStorage($"Data Source=health_history.db");
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddLeadGeneratorDatabase(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddPooledDbContextFactory<LeadGeneratorDbContext>(options =>
|
||||||
|
options.UseNpgsql(configuration.GetConnectionString("PostgresLeadGenerator")));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WebApplicationBuilder AddMonitoring(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
var serviceName = builder.Configuration.GetValue<string>("Monitoring:ServiceName") ?? "LiteCharms.Capture";
|
||||||
|
var endpoint = builder.Configuration.GetValue<string>("Monitoring:Address")!;
|
||||||
|
var apiKey = builder.Configuration.GetValue<string>("Monitoring:ApiKey");
|
||||||
|
|
||||||
|
var resourceBuilder = ResourceBuilder.CreateDefault()
|
||||||
|
.AddService(serviceName);
|
||||||
|
|
||||||
|
var otlpHeaders = !string.IsNullOrEmpty(apiKey) ? $"x-otlp-api-key={apiKey}" : null;
|
||||||
|
|
||||||
|
builder.Logging.AddOpenTelemetry(logging =>
|
||||||
|
{
|
||||||
|
logging.SetResourceBuilder(resourceBuilder);
|
||||||
|
logging.AddOtlpExporter(opt =>
|
||||||
|
{
|
||||||
|
opt.Endpoint = new Uri(endpoint);
|
||||||
|
opt.Protocol = OtlpExportProtocol.Grpc;
|
||||||
|
opt.Headers = otlpHeaders;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddOpenTelemetry()
|
||||||
|
.WithTracing(tracing => tracing
|
||||||
|
.SetResourceBuilder(resourceBuilder)
|
||||||
|
.AddAspNetCoreInstrumentation()
|
||||||
|
.AddHttpClientInstrumentation()
|
||||||
|
.AddOtlpExporter(opt =>
|
||||||
|
{
|
||||||
|
opt.Endpoint = new Uri(endpoint);
|
||||||
|
opt.Protocol = OtlpExportProtocol.Grpc;
|
||||||
|
opt.Headers = otlpHeaders;
|
||||||
|
}))
|
||||||
|
.WithMetrics(metrics => metrics
|
||||||
|
.SetResourceBuilder(resourceBuilder)
|
||||||
|
.AddMeter(serviceName)
|
||||||
|
.AddAspNetCoreInstrumentation()
|
||||||
|
.AddRuntimeInstrumentation()
|
||||||
|
.AddOtlpExporter(opt =>
|
||||||
|
{
|
||||||
|
opt.Endpoint = new Uri(endpoint);
|
||||||
|
opt.Protocol = OtlpExportProtocol.Grpc;
|
||||||
|
opt.Headers = otlpHeaders;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
namespace LiteCharms.Features.Customers.Commands;
|
||||||
|
|
||||||
|
public class CreateCustomerCommand : IRequest<Result<Guid>>
|
||||||
|
{
|
||||||
|
public string? Company { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string LastName { get; set; }
|
||||||
|
|
||||||
|
public string? Tax { get; set; }
|
||||||
|
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
public string? Discord { get; set; }
|
||||||
|
|
||||||
|
public string? Slack { get; set; }
|
||||||
|
|
||||||
|
public string? LinkedIn { get; set; }
|
||||||
|
|
||||||
|
public string? Whatsapp { get; set; }
|
||||||
|
|
||||||
|
public string? Website { get; set; }
|
||||||
|
|
||||||
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
|
public string? Address { get; set; }
|
||||||
|
|
||||||
|
public string? City { get; set; }
|
||||||
|
|
||||||
|
public string? Region { get; set; }
|
||||||
|
|
||||||
|
public string? Country { get; set; }
|
||||||
|
|
||||||
|
public string? PostalCode { get; set; }
|
||||||
|
|
||||||
|
private CreateCustomerCommand(string name, string lastName, string? company, string? tax, string email, string? discord, string? slack, string? linkedIn, string? whatsapp, string? website, string? phone, string? address, string? city, string? region, string? country, string? postalCode)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
LastName = lastName;
|
||||||
|
Company = company;
|
||||||
|
Tax = tax;
|
||||||
|
Email = email;
|
||||||
|
Discord = discord;
|
||||||
|
Slack = slack;
|
||||||
|
LinkedIn = linkedIn;
|
||||||
|
Whatsapp = whatsapp;
|
||||||
|
Website = website;
|
||||||
|
Phone = phone;
|
||||||
|
Address = address;
|
||||||
|
City = city;
|
||||||
|
Region = region;
|
||||||
|
Country = country;
|
||||||
|
PostalCode = postalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CreateCustomerCommand Create(string name, string lastName, string? company, string? tax, string email, string? discord, string? slack, string? linkedIn, string? whatsapp, string? website, string? phone, string? address, string? city, string? region, string? country, string? postalCode)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name) && string.IsNullOrWhiteSpace(lastName) && string.IsNullOrWhiteSpace(email))
|
||||||
|
throw new ArgumentException("At the following fields must be provided: Name, LastName, Email");
|
||||||
|
|
||||||
|
return new(name, lastName, company, tax, email, discord, slack, linkedIn, whatsapp, website, phone, address, city, region, country, postalCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Commands.Handlers;
|
||||||
|
|
||||||
|
public class CreateCustomerCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<CreateCustomerCommand, Result<Guid>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> Handle(CreateCustomerCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customerEmail = request.Email.ToLower().Trim();
|
||||||
|
|
||||||
|
if (await context.Customers.AnyAsync(c => c.Email == customerEmail, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"A customer with the email {customerEmail} already exists"));
|
||||||
|
|
||||||
|
var newCustomer = context.Customers.Add(new Entities.Customer
|
||||||
|
{
|
||||||
|
Company = request.Company,
|
||||||
|
Name = request.Name,
|
||||||
|
LastName = request.LastName,
|
||||||
|
Tax = request.Tax,
|
||||||
|
Email = customerEmail,
|
||||||
|
Discord = request.Discord,
|
||||||
|
Slack = request.Slack,
|
||||||
|
LinkedIn = request.LinkedIn,
|
||||||
|
Whatsapp = request.Whatsapp,
|
||||||
|
Website = request.Website,
|
||||||
|
Phone = request.Phone,
|
||||||
|
Address = request.Address,
|
||||||
|
City = request.City,
|
||||||
|
Region = request.Region,
|
||||||
|
Country = request.Country,
|
||||||
|
PostalCode = request.PostalCode,
|
||||||
|
Active = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newCustomer.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create customer {customerEmail}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Commands.Handlers;
|
||||||
|
|
||||||
|
public class RefundCustomerCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<RefundCustomerCommand, Result<Guid>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> Handle(RefundCustomerCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if(!await context.Orders.AnyAsync(o => o.Id == request.OrderId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Order with Id: {request.OrderId} does not exist"));
|
||||||
|
|
||||||
|
if (!await context.Customers.AnyAsync(c => c.Id == request.CustomerId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Customer with Id: {request.CustomerId} does not exist"));
|
||||||
|
|
||||||
|
if(!await context.Orders.AnyAsync(o => o.Id == request.OrderId && o.CustomerId == request.CustomerId, cancellationToken))
|
||||||
|
return Result.Fail<Guid>(new Error($"Order with Id: {request.OrderId} does not belong to Customer with Id: {request.CustomerId}"));
|
||||||
|
|
||||||
|
var refund = context.OrderRefunds.Add(new Entities.OrderRefund
|
||||||
|
{
|
||||||
|
OrderId = request.OrderId,
|
||||||
|
Reason = request.Reason,
|
||||||
|
Amount = request.Amount
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(refund.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create refund for OrderId: {request.OrderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Commands.Handlers;
|
||||||
|
|
||||||
|
public class UpdateCustomerCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<UpdateCustomerCommand, Result>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result> Handle(UpdateCustomerCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == request.CustomerId, cancellationToken);
|
||||||
|
|
||||||
|
if (customer is null)
|
||||||
|
return Result.Fail(new Error($"Customer with ID {request.CustomerId} not found."));
|
||||||
|
|
||||||
|
customer.Name = request.Name;
|
||||||
|
customer.LastName = request.LastName;
|
||||||
|
customer.Email = request.Email;
|
||||||
|
customer.Company = request.Company;
|
||||||
|
customer.Address = request.Address;
|
||||||
|
customer.City = request.City;
|
||||||
|
customer.Region = request.Region;
|
||||||
|
customer.Country = request.Country;
|
||||||
|
customer.PostalCode = request.PostalCode;
|
||||||
|
customer.Phone = request.Phone;
|
||||||
|
customer.Tax = request.Tax;
|
||||||
|
customer.City = request.City;
|
||||||
|
customer.Discord = request.Discord;
|
||||||
|
customer.Slack = request.Slack;
|
||||||
|
customer.LinkedIn = request.LinkedIn;
|
||||||
|
customer.Whatsapp = request.Whatsapp;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update the customer {request.CustomerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
namespace LiteCharms.Features.Customers.Commands;
|
||||||
|
|
||||||
|
public class RefundCustomerCommand : IRequest<Result<Guid>>
|
||||||
|
{
|
||||||
|
public Guid OrderId { get; set; }
|
||||||
|
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public string? Reason { get; set; }
|
||||||
|
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
|
||||||
|
private RefundCustomerCommand(Guid orderId, Guid customerId, string? reason, decimal amount)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
CustomerId = customerId;
|
||||||
|
Reason = reason;
|
||||||
|
Amount = amount;
|
||||||
|
CustomerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RefundCustomerCommand Create(Guid orderId, Guid customerId, string? reason, decimal amount)
|
||||||
|
{
|
||||||
|
if (orderId == Guid.Empty)
|
||||||
|
throw new ArgumentException("OrderId is required", nameof(orderId));
|
||||||
|
|
||||||
|
if (customerId == Guid.Empty)
|
||||||
|
throw new ArgumentException("CustomerId is required", nameof(customerId));
|
||||||
|
|
||||||
|
if (amount <= 0)
|
||||||
|
throw new ArgumentException("Amount must be greater than zero", nameof(amount));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
|
throw new ArgumentException("Reason is required", nameof(reason));
|
||||||
|
|
||||||
|
return new(orderId, customerId, reason, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
namespace LiteCharms.Features.Customers.Commands;
|
||||||
|
|
||||||
|
public class UpdateCustomerCommand : IRequest<Result>
|
||||||
|
{
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public string? Company { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? LastName { get; set; }
|
||||||
|
|
||||||
|
public string? Tax { get; set; }
|
||||||
|
|
||||||
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
public string? Discord { get; set; }
|
||||||
|
|
||||||
|
public string? Slack { get; set; }
|
||||||
|
|
||||||
|
public string? LinkedIn { get; set; }
|
||||||
|
|
||||||
|
public string? Whatsapp { get; set; }
|
||||||
|
|
||||||
|
public string? Website { get; set; }
|
||||||
|
|
||||||
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
|
public string? Address { get; set; }
|
||||||
|
|
||||||
|
public string? City { get; set; }
|
||||||
|
|
||||||
|
public string? Region { get; set; }
|
||||||
|
|
||||||
|
public string? Country { get; set; }
|
||||||
|
|
||||||
|
public string? PostalCode { get; set; }
|
||||||
|
|
||||||
|
private UpdateCustomerCommand(Guid customerId, string name, string lastName, string? company, string? tax, string email, string? discord, string? slack, string? linkedIn, string? whatsapp, string? website, string? phone, string? address, string? city, string? region, string? country, string? postalCode)
|
||||||
|
{
|
||||||
|
CustomerId = customerId;
|
||||||
|
Name = name;
|
||||||
|
LastName = lastName;
|
||||||
|
Company = company;
|
||||||
|
Tax = tax;
|
||||||
|
Email = email;
|
||||||
|
Discord = discord;
|
||||||
|
Slack = slack;
|
||||||
|
LinkedIn = linkedIn;
|
||||||
|
Whatsapp = whatsapp;
|
||||||
|
Website = website;
|
||||||
|
Phone = phone;
|
||||||
|
Address = address;
|
||||||
|
City = city;
|
||||||
|
Region = region;
|
||||||
|
Country = country;
|
||||||
|
PostalCode = postalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateCustomerCommand Create(Guid customerId, string name, string lastName, string? company, string? tax, string email, string? discord, string? slack, string? linkedIn, string? whatsapp, string? website, string? phone, string? address, string? city, string? region, string? country, string? postalCode)
|
||||||
|
{
|
||||||
|
if (customerId == Guid.Empty)
|
||||||
|
throw new ArgumentException("Customer ID is required.", nameof(customerId));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(name) && string.IsNullOrWhiteSpace(lastName) && string.IsNullOrWhiteSpace(email))
|
||||||
|
throw new ArgumentException("At the following fields must be provided: Name, LastName, Email");
|
||||||
|
|
||||||
|
return new(customerId, name, lastName, company, tax, email, discord, slack, linkedIn, whatsapp, website, phone, address, city, region, country, postalCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Queries;
|
||||||
|
|
||||||
|
public class GetCustomerOrdersQuery : IRequest<Result<Order[]>>
|
||||||
|
{
|
||||||
|
public Guid CustomerId { get; }
|
||||||
|
|
||||||
|
private GetCustomerOrdersQuery(Guid customerId) => CustomerId = customerId;
|
||||||
|
|
||||||
|
public static GetCustomerOrdersQuery Create(Guid customerId)
|
||||||
|
{
|
||||||
|
if (customerId == Guid.Empty)
|
||||||
|
throw new ArgumentException("CustomerId is required.", nameof(customerId));
|
||||||
|
|
||||||
|
return new(customerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Queries;
|
||||||
|
|
||||||
|
public class GetCustomerRefundsQuery : IRequest<Result<OrderRefund[]>>
|
||||||
|
{
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
private GetCustomerRefundsQuery(Guid customerId) => CustomerId = customerId;
|
||||||
|
|
||||||
|
public static GetCustomerRefundsQuery Create(Guid customerId)
|
||||||
|
{
|
||||||
|
if (customerId == Guid.Empty)
|
||||||
|
throw new ArgumentException("CustomerId is required.", nameof(customerId));
|
||||||
|
|
||||||
|
return new(customerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Queries;
|
||||||
|
|
||||||
|
public class GetCustomersQuery : IRequest<Result<Customer[]>>
|
||||||
|
{
|
||||||
|
public DateOnly From { get; set; }
|
||||||
|
|
||||||
|
public DateOnly To { get; set; }
|
||||||
|
|
||||||
|
private GetCustomersQuery(DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
From = from;
|
||||||
|
To = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetCustomersQuery Create(DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
if (from > to)
|
||||||
|
throw new ArgumentException("From date cannot be greater than To date.");
|
||||||
|
|
||||||
|
return new(from, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetCustomerOrdersQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetCustomerOrdersQuery, Result<Order[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Order[]>> Handle(GetCustomerOrdersQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var orders = await context.Orders.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(o => o.CustomerId == request.CustomerId)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return orders?.Length > 0
|
||||||
|
? Result.Ok(orders.Select(o => o.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Order[]>(new Error($"No orders found for customer with Id {request.CustomerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Order[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetCustomerRefundsQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetCustomerRefundsQuery, Result<OrderRefund[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<OrderRefund[]>> Handle(GetCustomerRefundsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if(!await context.Customers.AnyAsync(c => c.Id == request.CustomerId, cancellationToken))
|
||||||
|
return Result.Fail<OrderRefund[]>(new Error($"Customer with Id {request.CustomerId} does not exist."));
|
||||||
|
|
||||||
|
var refunds = await context.OrderRefunds.AsNoTracking().AsSplitQuery()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(r => r.Order!.CustomerId == request.CustomerId).ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return refunds?.Length > 0
|
||||||
|
? Result.Ok(refunds.Select(r => r.ToModel()).ToArray())
|
||||||
|
: Result.Fail<OrderRefund[]>(new Error($"No refunds found for customer with Id {request.CustomerId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<OrderRefund[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Customers.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetCustomersQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetCustomersQuery, Result<Customer[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Customer[]>> Handle(GetCustomersQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = request.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = request.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var customers = await context.Customers.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(c => c.CreatedAt >= fromDate && c.CreatedAt <= toDate)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return customers?.Length > 0
|
||||||
|
? Result.Ok(customers.Select(c => c.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Customer[]>(new Error("No customers found in the specified date range."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Customer[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
namespace LiteCharms.Features.Leads.Commands;
|
||||||
|
|
||||||
|
public class CreateLeadCommand : IRequest<Result<Guid>>
|
||||||
|
{
|
||||||
|
public Guid? CustomerId { get; set; }
|
||||||
|
|
||||||
|
public string? GoogleClickId { get; set; }
|
||||||
|
|
||||||
|
public string? WebClickId { get; set; }
|
||||||
|
|
||||||
|
public string? AppClickId { get; set; }
|
||||||
|
|
||||||
|
public long? CampaignId { get; set; }
|
||||||
|
|
||||||
|
public long? AdGroupId { get; set; }
|
||||||
|
|
||||||
|
public long? AdName { get; set; }
|
||||||
|
|
||||||
|
public long? TargetId { get; set; }
|
||||||
|
|
||||||
|
public long? FeedItemId { get; set; }
|
||||||
|
|
||||||
|
public string? ClickLocation { get; set; }
|
||||||
|
|
||||||
|
public string? AttribusionHash { get; set; }
|
||||||
|
|
||||||
|
private CreateLeadCommand(Guid? customerId, string googleClickId, string webClickId, string appClickId, long? campaignId, long? adGroupId, long? adName, long? targetId, long? feedItemId, string? clickLocation, string? attribusionHash)
|
||||||
|
{
|
||||||
|
CustomerId = customerId;
|
||||||
|
GoogleClickId = googleClickId;
|
||||||
|
WebClickId = webClickId;
|
||||||
|
AppClickId = appClickId;
|
||||||
|
CampaignId = campaignId;
|
||||||
|
AdGroupId = adGroupId;
|
||||||
|
AdName = adName;
|
||||||
|
TargetId = targetId;
|
||||||
|
FeedItemId = feedItemId;
|
||||||
|
ClickLocation = clickLocation;
|
||||||
|
AttribusionHash = attribusionHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CreateLeadCommand Create(Guid? customerId, string googleClickId, string webClickId, string appClickId, long? campaignId, long? adGroupId, long? adName, long? targetId, long? feedItemId, string? clickLocation, string? attribusionHash)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(googleClickId) || string.IsNullOrWhiteSpace(appClickId) || string.IsNullOrWhiteSpace(webClickId))
|
||||||
|
throw new ArgumentException("Google ClickId, App ClickId and Web ClickId are required to create a lead.");
|
||||||
|
|
||||||
|
return new(customerId, googleClickId, webClickId, appClickId, campaignId, adGroupId, adName, targetId, feedItemId, clickLocation, attribusionHash);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using LiteCharms.Features.Utilities.Commands;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Commands.Handlers;
|
||||||
|
|
||||||
|
public class CreateLeadCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory, ISender mediator) : IRequestHandler<CreateLeadCommand, Result<Guid>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> Handle(CreateLeadCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var hashCommand = ComputeHashCommand.Create($"{request.GoogleClickId}{request.AppClickId}{request.WebClickId}");
|
||||||
|
var hashResult = await mediator.Send(hashCommand, cancellationToken);
|
||||||
|
|
||||||
|
if(hashResult.IsFailed)
|
||||||
|
return Result.Fail<Guid>(new Error($"Failed to compute hash for lead -> Google ClickId: {request.GoogleClickId}, App ClickId: {request.AppClickId}, Web ClickId: {request.WebClickId}")
|
||||||
|
.CausedBy(hashResult.Errors));
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var newLead = context.Leads.Add(new Entities.Lead
|
||||||
|
{
|
||||||
|
WebClickId = request.WebClickId,
|
||||||
|
AppClickId = request.AppClickId,
|
||||||
|
GoogleClickId = request.GoogleClickId,
|
||||||
|
AdGroupId = request.AdGroupId,
|
||||||
|
AdName = request.AdName,
|
||||||
|
CampaignId = request.CampaignId,
|
||||||
|
ClickLocation = request.ClickLocation,
|
||||||
|
CustomerId = request.CustomerId,
|
||||||
|
FeedItemId = request.FeedItemId,
|
||||||
|
Status = Models.LeadStatus.New,
|
||||||
|
TargetId = request.TargetId,
|
||||||
|
AttributionHash = hashResult.Value
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newLead.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create lead -> Google ClickId: {request.GoogleClickId}, App ClickId: {request.AppClickId}, Web ClickId: {request.WebClickId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Commands.Handlers;
|
||||||
|
|
||||||
|
public class UpdateLeadCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<UpdateLeadCommand, Result>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result> Handle(UpdateLeadCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var lead = await context.Leads.FirstOrDefaultAsync(l => l.Id == request.LeadId, cancellationToken);
|
||||||
|
|
||||||
|
if (lead is null)
|
||||||
|
return Result.Fail(new Error($"Lead with ID {request.LeadId} not found."));
|
||||||
|
|
||||||
|
lead.Status = request.Status;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update the lead {request.LeadId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Commands;
|
||||||
|
|
||||||
|
public class UpdateLeadCommand : IRequest<Result>
|
||||||
|
{
|
||||||
|
public Guid LeadId { get; set; }
|
||||||
|
|
||||||
|
public LeadStatus Status { get; set; }
|
||||||
|
|
||||||
|
private UpdateLeadCommand(Guid leadId, LeadStatus status)
|
||||||
|
{
|
||||||
|
LeadId = leadId;
|
||||||
|
Status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateLeadCommand Create(Guid leadId, LeadStatus status)
|
||||||
|
{
|
||||||
|
if (leadId == Guid.Empty)
|
||||||
|
throw new ArgumentException("Lead ID cannot be empty.", nameof(leadId));
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(LeadStatus), status))
|
||||||
|
throw new ArgumentException("Invalid lead status.", nameof(status));
|
||||||
|
|
||||||
|
return new(leadId, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Queries;
|
||||||
|
|
||||||
|
public class GetCustomerLeadsQuery : IRequest<Result<Lead[]>>
|
||||||
|
{
|
||||||
|
public Guid CustomerId { get; }
|
||||||
|
|
||||||
|
public DateOnly From { get; set; }
|
||||||
|
|
||||||
|
public DateOnly To { get; set; }
|
||||||
|
|
||||||
|
private GetCustomerLeadsQuery(Guid customerId, DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
CustomerId = customerId;
|
||||||
|
From = from;
|
||||||
|
To = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetCustomerLeadsQuery Create(Guid customerId, DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
if(customerId == Guid.Empty)
|
||||||
|
throw new ArgumentException("Customer ID cannot be empty.", nameof(customerId));
|
||||||
|
|
||||||
|
if(from > to)
|
||||||
|
throw new ArgumentException("The 'From' date cannot be later than the 'To' date.");
|
||||||
|
|
||||||
|
return new(customerId, from, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Queries;
|
||||||
|
|
||||||
|
public class GetLeadsQuery : IRequest<Result<Lead[]>>
|
||||||
|
{
|
||||||
|
public DateOnly From { get; set; }
|
||||||
|
|
||||||
|
public DateOnly To { get; set; }
|
||||||
|
|
||||||
|
private GetLeadsQuery(DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
From = from;
|
||||||
|
To = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetLeadsQuery Create(DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
if (from > to)
|
||||||
|
throw new ArgumentException("From date cannot be greater than To date.");
|
||||||
|
|
||||||
|
return new(from, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetCustomerLeadsQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetCustomerLeadsQuery, Result<Lead[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Lead[]>> Handle(GetCustomerLeadsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = request.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = request.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var leads = await context.Leads.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(lead => lead.CustomerId == request.CustomerId)
|
||||||
|
.Where(lead => lead.CreatedAt.Date >= fromDate && lead.CreatedAt.Date <= toDate)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return leads?.Length > 0
|
||||||
|
? Result.Ok(leads.Select(l => l.ToModel()).ToArray())
|
||||||
|
: Result.Fail(new Error($"No customer {request.CustomerId} leads found for the specified date range {request.From} to {request.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Lead[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Leads.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetLeadsQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetLeadsQuery, Result<Lead[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Lead[]>> Handle(GetLeadsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = request.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = request.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var leads = await context.Leads.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(l => l.CreatedAt.Date >= fromDate && l.CreatedAt.Date <= toDate)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return leads?.Length > 0
|
||||||
|
? Result.Ok(leads.Select(l => l.ToModel()).ToArray())
|
||||||
|
: Result.Fail(new Error($"No leads found for the specified date range {request.From} to {request.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<SignAssembly>True</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Nuget Package Details -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageId>LiteCharms.Features</PackageId>
|
||||||
|
<Version>1.0.2</Version>
|
||||||
|
<Authors>Khwezi Mngoma</Authors>
|
||||||
|
<Company>Lite Charms (PTY) Ltd</Company>
|
||||||
|
<Description>Feature components for Lite Charms applications.</Description>
|
||||||
|
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator.git</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<PackageTags>utility;dotnet</PackageTags>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\LICENSE" Pack="true" PackagePath="\" />
|
||||||
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- CQRS -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentResults" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Mediator.Abstractions" Version="3.0.2" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="FluentResults" />
|
||||||
|
<Using Include="Mediator" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Shared Usings -->
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="System.Text" />
|
||||||
|
<Using Include="System.Security.Cryptography" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Extensions\LiteCharms.Extensions.csproj" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Infrastructure\LiteCharms.Infrastructure.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace LiteCharms.Features.Orders.Commands;
|
||||||
|
|
||||||
|
public class CreateOrderCommand : IRequest<Result<Guid>>
|
||||||
|
{
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public Guid ProductPriceId { get; set; }
|
||||||
|
|
||||||
|
private CreateOrderCommand(Guid customerId, Guid productPriceId)
|
||||||
|
{
|
||||||
|
CustomerId = customerId;
|
||||||
|
ProductPriceId = productPriceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CreateOrderCommand Create(Guid customerId, Guid productPriceId)
|
||||||
|
{
|
||||||
|
if (customerId == Guid.Empty)
|
||||||
|
throw new ArgumentException("CustomerId is required.", nameof(customerId));
|
||||||
|
|
||||||
|
if (productPriceId == Guid.Empty)
|
||||||
|
throw new ArgumentException("ProductPriceId is required.", nameof(productPriceId));
|
||||||
|
|
||||||
|
return new(customerId, productPriceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Commands.Handlers;
|
||||||
|
|
||||||
|
public class CreateOrderCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<CreateOrderCommand, Result<Guid>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Guid>> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var newOrder = context.Orders.Add(new Entities.Order
|
||||||
|
{
|
||||||
|
CustomerId = request.CustomerId,
|
||||||
|
ProductPriceId = request.ProductPriceId,
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(newOrder.Entity.Id)
|
||||||
|
: Result.Fail<Guid>(new Error($"Failed to create customer {request.CustomerId} order using product price {request.ProductPriceId}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Guid>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Commands.Handlers;
|
||||||
|
|
||||||
|
public class UpdateOrderCommandHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<UpdateOrderCommand, Result>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result> Handle(UpdateOrderCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var order = await context.Orders.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);
|
||||||
|
|
||||||
|
if (order is null)
|
||||||
|
return Result.Fail(new Error($"Order {request.OrderId} not found"));
|
||||||
|
|
||||||
|
order.Status = request.Status;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok()
|
||||||
|
: Result.Fail(new Error($"Failed to update order {request.OrderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Commands;
|
||||||
|
|
||||||
|
public class UpdateOrderCommand : IRequest<Result>
|
||||||
|
{
|
||||||
|
public Guid OrderId { get; set; }
|
||||||
|
|
||||||
|
public OrderStatus Status { get; set; }
|
||||||
|
|
||||||
|
public string? Note { get; set; }
|
||||||
|
|
||||||
|
private UpdateOrderCommand(Guid orderId, OrderStatus status, string? note)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
Status = status;
|
||||||
|
Note = note;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateOrderCommand Create(Guid orderId, OrderStatus status, string? note)
|
||||||
|
{
|
||||||
|
if (orderId == Guid.Empty)
|
||||||
|
throw new ArgumentException("OrderId is required.", nameof(orderId));
|
||||||
|
|
||||||
|
if (!Enum.IsDefined(typeof(OrderStatus), status))
|
||||||
|
throw new ArgumentException("Invalid order status.", nameof(status));
|
||||||
|
|
||||||
|
return new(orderId, status, note);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Queries;
|
||||||
|
|
||||||
|
public class GetOrderRefundQuery : IRequest<Result<OrderRefund>>
|
||||||
|
{
|
||||||
|
public Guid OrderId { get; set; }
|
||||||
|
|
||||||
|
public Guid OrderRefundId { get; set; }
|
||||||
|
|
||||||
|
private GetOrderRefundQuery(Guid orderId, Guid orderRefundId)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
OrderRefundId = orderRefundId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetOrderRefundQuery Create(Guid orderId, Guid orderRefundId)
|
||||||
|
{
|
||||||
|
if (orderId == Guid.Empty)
|
||||||
|
throw new ArgumentException("OrderId is required.", nameof(orderId));
|
||||||
|
|
||||||
|
if (orderRefundId == Guid.Empty)
|
||||||
|
throw new ArgumentException("OrderRefundId is required.", nameof(orderRefundId));
|
||||||
|
|
||||||
|
return new(orderId, orderRefundId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Queries;
|
||||||
|
|
||||||
|
public class GetOrdersQuery : IRequest<Result<Order[]>>
|
||||||
|
{
|
||||||
|
public DateOnly From { get; set; }
|
||||||
|
|
||||||
|
public DateOnly To { get; set; }
|
||||||
|
|
||||||
|
private GetOrdersQuery(DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
From = from;
|
||||||
|
To = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetOrdersQuery Create(DateOnly from, DateOnly to)
|
||||||
|
{
|
||||||
|
if (from > to)
|
||||||
|
throw new ArgumentException("From date cannot be greater than To date.");
|
||||||
|
|
||||||
|
return new(from, to);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetOrderRefundQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetOrderRefundQuery, Result<OrderRefund>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<OrderRefund>> Handle(GetOrderRefundQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var refund = await context.OrderRefunds.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(r => r.OrderId == request.OrderId && r.Id == request.OrderRefundId, cancellationToken);
|
||||||
|
|
||||||
|
return refund is not null
|
||||||
|
? Result.Ok(refund.ToModel())
|
||||||
|
: Result.Fail<OrderRefund>(new Error($"Refund {request.OrderRefundId} not found for the given OrderId: {request.OrderId}"));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<OrderRefund>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Orders.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetOrdersQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetOrdersQuery, Result<Order[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Order[]>> Handle(GetOrdersQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fromDate = request.From.ToDateTime(TimeOnly.MinValue);
|
||||||
|
var toDate = request.To.ToDateTime(TimeOnly.MaxValue);
|
||||||
|
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var orders = await context.Orders
|
||||||
|
.OrderByDescending(o => o.CreatedAt)
|
||||||
|
.Where(o => o.CreatedAt >= fromDate && o.CreatedAt <= toDate)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return orders?.Length > 0
|
||||||
|
? Result.Ok(orders.Select(o => o.ToModel()).ToArray())
|
||||||
|
: Result.Fail<Order[]>(new Error($"No orders found for the specified date range {request.From} - {request.To}."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Order[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Products.Queries;
|
||||||
|
|
||||||
|
public class GetProductPriceQuery : IRequest<Result<ProductPrice>>
|
||||||
|
{
|
||||||
|
public Guid ProductId { get; set; }
|
||||||
|
|
||||||
|
private GetProductPriceQuery(Guid productId) => ProductId = productId;
|
||||||
|
|
||||||
|
public static GetProductPriceQuery Create(Guid productId)
|
||||||
|
{
|
||||||
|
if (productId == Guid.Empty)
|
||||||
|
throw new ArgumentException("ProductId is required.", nameof(productId));
|
||||||
|
|
||||||
|
return new(productId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Products.Queries;
|
||||||
|
|
||||||
|
public class GetProductQuery : IRequest<Result<Product>>
|
||||||
|
{
|
||||||
|
public Guid ProductId { get; set; }
|
||||||
|
|
||||||
|
private GetProductQuery(Guid productId) => ProductId = productId;
|
||||||
|
|
||||||
|
public static GetProductQuery Create(Guid productId)
|
||||||
|
{
|
||||||
|
if(productId == Guid.Empty)
|
||||||
|
throw new ArgumentException("Product ID is required.", nameof(productId));
|
||||||
|
|
||||||
|
return new(productId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Products.Queries;
|
||||||
|
|
||||||
|
public class GetProductsQuery : IRequest<Result<Product[]>>
|
||||||
|
{
|
||||||
|
public static GetProductsQuery Create() => new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Products.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetProductPriceQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetProductPriceQuery, Result<ProductPrice>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<ProductPrice>> Handle(GetProductPriceQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var productPrice = await context.ProductPrices.AsNoTracking()
|
||||||
|
.Where(pp => pp.ProductId == request.ProductId && pp.Active)
|
||||||
|
.OrderByDescending(pp => pp.CreatedAt)
|
||||||
|
.FirstOrDefaultAsync(cancellationToken);
|
||||||
|
|
||||||
|
return productPrice is not null
|
||||||
|
? Result.Ok(productPrice.ToModel())
|
||||||
|
: Result.Fail<ProductPrice>(new Error($"Product price {request.ProductId} not found."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<ProductPrice>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Products.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetProductQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetProductQuery, Result<Product>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Product>> Handle(GetProductQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var product = await context.Products.FirstOrDefaultAsync(p => p.Id == request.ProductId, cancellationToken);
|
||||||
|
|
||||||
|
return product is not null
|
||||||
|
? Result.Ok(product.ToModel())
|
||||||
|
: Result.Fail<Product>(new Error($"Product with ID {request.ProductId} not found."));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Product>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using LiteCharms.Extensions;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using LiteCharms.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.Products.Queries.Handlers;
|
||||||
|
|
||||||
|
public class GetProductsQueryHandler(IDbContextFactory<LeadGeneratorDbContext> contextFactory) : IRequestHandler<GetProductsQuery, Result<Product[]>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<Product[]>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var products = await context.Products.AsNoTracking()
|
||||||
|
.OrderByDescending(o => o.Id)
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return Result.Ok(products.Select(p => p.ToModel()).ToArray());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<Product[]>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace LiteCharms.Features.Utilities.Commands;
|
||||||
|
|
||||||
|
public class ComputeHashCommand : IRequest<Result<string>>
|
||||||
|
{
|
||||||
|
public string? Input { get; set; }
|
||||||
|
|
||||||
|
private ComputeHashCommand(string input) => Input = input;
|
||||||
|
|
||||||
|
public static ComputeHashCommand Create(string input)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(input))
|
||||||
|
throw new ArgumentException("Input is required", nameof(input));
|
||||||
|
|
||||||
|
return new(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace LiteCharms.Features.Utilities.Commands.Handlers;
|
||||||
|
|
||||||
|
public class ComputeHashCommandHandler : IRequestHandler<ComputeHashCommand, Result<string>>
|
||||||
|
{
|
||||||
|
public async ValueTask<Result<string>> Handle(ComputeHashCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(request.Input!));
|
||||||
|
|
||||||
|
return Result.Ok(Convert.ToHexString(bytes));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return Result.Fail<string>(new Error(ex.Message).CausedBy(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using LiteCharms.Entities;
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
public class LeadGeneratorDbContext(DbContextOptions<LeadGeneratorDbContext> options) : DbContext(options)
|
||||||
|
{
|
||||||
|
public DbSet<Customer> Customers { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Lead> Leads { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Order> Orders { get; set; }
|
||||||
|
|
||||||
|
public DbSet<OrderRefund> OrderRefunds { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Product> Products { get; set; }
|
||||||
|
|
||||||
|
public DbSet<ProductPrice> ProductPrices { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
namespace LiteCharms.Infrastructure.Database;
|
||||||
|
|
||||||
|
public class LeadGeneratorDbContextFactory : IDesignTimeDbContextFactory<LeadGeneratorDbContext>
|
||||||
|
{
|
||||||
|
public LeadGeneratorDbContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var configuration = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddUserSecrets(typeof(LeadGeneratorDbContext).Assembly)
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.AddEnvironmentVariables()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<LeadGeneratorDbContext>();
|
||||||
|
optionsBuilder.UseNpgsql(configuration.GetConnectionString("PostgresLeadGenerator"));
|
||||||
|
|
||||||
|
return new LeadGeneratorDbContext(optionsBuilder.Options);
|
||||||
|
}
|
||||||
|
}
|
||||||
+272
@@ -0,0 +1,272 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LeadGeneratorDbContext))]
|
||||||
|
[Migration("20260502231708_Init")]
|
||||||
|
partial class Init
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttribusionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("LeadId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Init : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Customer",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
Company = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
LastName = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Tax = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Email = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Discord = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Slack = table.Column<string>(type: "text", nullable: true),
|
||||||
|
LinkedIn = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Whatsapp = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Website = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Phone = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Address = table.Column<string>(type: "text", nullable: true),
|
||||||
|
City = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Region = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Country = table.Column<string>(type: "text", nullable: true),
|
||||||
|
PostalCode = table.Column<string>(type: "text", nullable: true),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Customer", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Lead",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
GoogleClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
WebClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AppClickId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
CampaignId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdGroupId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
AdName = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
TargetId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
FeedItemId = table.Column<long>(type: "bigint", nullable: true),
|
||||||
|
ClickLocation = table.Column<string>(type: "text", nullable: true),
|
||||||
|
AttribusionHash = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Lead", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Order",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
LeadId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ProductId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
ProductPriceId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
Notes = table.Column<string>(type: "jsonb", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Order", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "OrderRefund",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Reason = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Amount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_OrderRefund", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Product",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "text", nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Product", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ProductPrice",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
|
ProductId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
Price = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Discount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "boolean", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ProductPrice", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Customer");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "OrderRefund");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Product");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ProductPrice");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+357
@@ -0,0 +1,357 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LeadGeneratorDbContext))]
|
||||||
|
[Migration("20260503002123_DefinedEntityRelationships")]
|
||||||
|
partial class DefinedEntityRelationships
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttribusionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("LeadId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("RefundId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Order", "Order")
|
||||||
|
.WithOne("Refund")
|
||||||
|
.HasForeignKey("LeadGenerator.Database.Entities.OrderRefund", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Refund");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+175
@@ -0,0 +1,175 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class DefinedEntityRelationships : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LeadId",
|
||||||
|
table: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "ProductId",
|
||||||
|
table: "Order",
|
||||||
|
newName: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "RefundId",
|
||||||
|
table: "Order",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "CustomerId",
|
||||||
|
table: "Lead",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "LeadId",
|
||||||
|
table: "Lead",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ProductPrice_ProductId",
|
||||||
|
table: "ProductPrice",
|
||||||
|
column: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_OrderRefund_OrderId",
|
||||||
|
table: "OrderRefund",
|
||||||
|
column: "OrderId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Order_CustomerId",
|
||||||
|
table: "Order",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Order_ProductPriceId",
|
||||||
|
table: "Order",
|
||||||
|
column: "ProductPriceId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Lead_CustomerId",
|
||||||
|
table: "Lead",
|
||||||
|
column: "CustomerId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Lead_Customer_CustomerId",
|
||||||
|
table: "Lead",
|
||||||
|
column: "CustomerId",
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Order_Customer_CustomerId",
|
||||||
|
table: "Order",
|
||||||
|
column: "CustomerId",
|
||||||
|
principalTable: "Customer",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Order_ProductPrice_ProductPriceId",
|
||||||
|
table: "Order",
|
||||||
|
column: "ProductPriceId",
|
||||||
|
principalTable: "ProductPrice",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_OrderRefund_Order_OrderId",
|
||||||
|
table: "OrderRefund",
|
||||||
|
column: "OrderId",
|
||||||
|
principalTable: "Order",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ProductPrice_Product_ProductId",
|
||||||
|
table: "ProductPrice",
|
||||||
|
column: "ProductId",
|
||||||
|
principalTable: "Product",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Lead_Customer_CustomerId",
|
||||||
|
table: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Order_Customer_CustomerId",
|
||||||
|
table: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Order_ProductPrice_ProductPriceId",
|
||||||
|
table: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_OrderRefund_Order_OrderId",
|
||||||
|
table: "OrderRefund");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ProductPrice_Product_ProductId",
|
||||||
|
table: "ProductPrice");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_ProductPrice_ProductId",
|
||||||
|
table: "ProductPrice");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_OrderRefund_OrderId",
|
||||||
|
table: "OrderRefund");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Order_CustomerId",
|
||||||
|
table: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Order_ProductPriceId",
|
||||||
|
table: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Lead_CustomerId",
|
||||||
|
table: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "RefundId",
|
||||||
|
table: "Order");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "CustomerId",
|
||||||
|
table: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LeadId",
|
||||||
|
table: "Lead");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "CustomerId",
|
||||||
|
table: "Order",
|
||||||
|
newName: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "LeadId",
|
||||||
|
table: "Order",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+354
@@ -0,0 +1,354 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LeadGeneratorDbContext))]
|
||||||
|
[Migration("20260503003624_RemovedLeadIdFromLead")]
|
||||||
|
partial class RemovedLeadIdFromLead
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttribusionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("RefundId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Order", "Order")
|
||||||
|
.WithOne("Refund")
|
||||||
|
.HasForeignKey("LeadGenerator.Database.Entities.OrderRefund", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Refund");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class RemovedLeadIdFromLead : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LeadId",
|
||||||
|
table: "Lead");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "LeadId",
|
||||||
|
table: "Lead",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+357
@@ -0,0 +1,357 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LeadGeneratorDbContext))]
|
||||||
|
[Migration("20260503012708_AddedStatusToLead")]
|
||||||
|
partial class AddedStatusToLead
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttribusionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("RefundId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Order", "Order")
|
||||||
|
.WithOne("Refund")
|
||||||
|
.HasForeignKey("LeadGenerator.Database.Entities.OrderRefund", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LeadGenerator.Database.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Refund");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LeadGenerator.Database.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedStatusToLead : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "Status",
|
||||||
|
table: "Lead",
|
||||||
|
type: "integer",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Status",
|
||||||
|
table: "Lead");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+357
@@ -0,0 +1,357 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LeadGeneratorDbContext))]
|
||||||
|
[Migration("20260503133855_CorrectedAttributionHashColumnOnLead")]
|
||||||
|
partial class CorrectedAttributionHashColumnOnLead
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("RefundId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Order", "Order")
|
||||||
|
.WithOne("Refund")
|
||||||
|
.HasForeignKey("LiteCharms.Entities.OrderRefund", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Refund");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class CorrectedAttributionHashColumnOnLead : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "AttribusionHash",
|
||||||
|
table: "Lead",
|
||||||
|
newName: "AttributionHash");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "AttributionHash",
|
||||||
|
table: "Lead",
|
||||||
|
newName: "AttribusionHash");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,354 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using LiteCharms.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace LiteCharms.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(LeadGeneratorDbContext))]
|
||||||
|
partial class LeadGeneratorDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "10.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("City")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Company")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Country")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Discord")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LinkedIn")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Phone")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PostalCode")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Region")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Slack")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Tax")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Website")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Whatsapp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Customer", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("AdGroupId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<long?>("AdName")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("AppClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AttributionHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<long?>("CampaignId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ClickLocation")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long?>("FeedItemId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("GoogleClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<long?>("TargetId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("WebClickId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.ToTable("Lead", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("CustomerId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("Notes")
|
||||||
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductPriceId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<Guid?>("RefundId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CustomerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductPriceId");
|
||||||
|
|
||||||
|
b.ToTable("Order", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<decimal>("Amount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("OrderId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OrderRefund", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Product", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedAt")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("numeric(18,2)");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProductId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("UpdatedAt")
|
||||||
|
.ValueGeneratedOnUpdate()
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("ProductPrice", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Lead", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Leads")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Customer", "Customer")
|
||||||
|
.WithMany("Orders")
|
||||||
|
.HasForeignKey("CustomerId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("LiteCharms.Entities.ProductPrice", "ProductPrice")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductPriceId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Customer");
|
||||||
|
|
||||||
|
b.Navigation("ProductPrice");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.OrderRefund", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Order", "Order")
|
||||||
|
.WithOne("Refund")
|
||||||
|
.HasForeignKey("LiteCharms.Entities.OrderRefund", "OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Order");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.ProductPrice", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("LiteCharms.Entities.Product", "Product")
|
||||||
|
.WithMany("ProductPrices")
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Customer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Leads");
|
||||||
|
|
||||||
|
b.Navigation("Orders");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Order", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Refund");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("LiteCharms.Entities.Product", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ProductPrices");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace LiteCharms.Infrastructure.HealthChecks;
|
||||||
|
|
||||||
|
public class PostgresHealthCheck(IConfiguration configuration) : IHealthCheck
|
||||||
|
{
|
||||||
|
private readonly string connectionString = configuration.GetConnectionString("PostgresLeadGenerator")!;
|
||||||
|
|
||||||
|
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var dataSource = NpgsqlDataSource.Create(connectionString);
|
||||||
|
await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);
|
||||||
|
|
||||||
|
await using var command = connection.CreateCommand();
|
||||||
|
command.CommandText = "SELECT 1";
|
||||||
|
|
||||||
|
await command.ExecuteScalarAsync(cancellationToken);
|
||||||
|
|
||||||
|
return HealthCheckResult.Healthy("PostgreSQL is responsive.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return HealthCheckResult.Unhealthy("PostgreSQL is unreachable.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UserSecretsId>7770ab3b-72ee-4897-8e06-57d6613e050a</UserSecretsId>
|
||||||
|
<SignAssembly>True</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Nuget Package Details -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageId>LiteCharms.Infrastructure</PackageId>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
|
<Authors>Khwezi Mngoma</Authors>
|
||||||
|
<Company>Lite Charms (PTY) Ltd</Company>
|
||||||
|
<Description>Infrastructure components for Lite Charms applications.</Description>
|
||||||
|
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator.git</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\LICENSE" Pack="true" PackagePath="\" />
|
||||||
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Configuration -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.7" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Microsoft.Extensions.Configuration" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Health Checks -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.7" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Database -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.7">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="10.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.1" />
|
||||||
|
|
||||||
|
<!-- Global Usings -->
|
||||||
|
<Using Include="Npgsql" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Design" />
|
||||||
|
<Using Include="Microsoft.EntityFrameworkCore.Metadata.Builders" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Project References -->
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiteCharms.Entities\LiteCharms.Entities.csproj" />
|
||||||
|
<ProjectReference Include="..\LiteCharms.Models\LiteCharms.Models.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public class Customer
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public string? Company { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? LastName { get; set; }
|
||||||
|
|
||||||
|
public string? Tax { get; set; }
|
||||||
|
|
||||||
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
public string? Discord { get; set; }
|
||||||
|
|
||||||
|
public string? Slack { get; set; }
|
||||||
|
|
||||||
|
public string? LinkedIn { get; set; }
|
||||||
|
|
||||||
|
public string? Whatsapp { get; set; }
|
||||||
|
|
||||||
|
public string? Website { get; set; }
|
||||||
|
|
||||||
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
|
public string? Address { get; set; }
|
||||||
|
|
||||||
|
public string? City { get; set; }
|
||||||
|
|
||||||
|
public string? Region { get; set; }
|
||||||
|
|
||||||
|
public string? Country { get; set; }
|
||||||
|
|
||||||
|
public string? PostalCode { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public enum OrderStatus : int
|
||||||
|
{
|
||||||
|
Pending = 0,
|
||||||
|
Completed = 1,
|
||||||
|
Cancelled = 2,
|
||||||
|
Failed = 3,
|
||||||
|
Refunded = 4,
|
||||||
|
Error = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LeadStatus : int
|
||||||
|
{
|
||||||
|
New = 0,
|
||||||
|
Contacted = 1,
|
||||||
|
Qualified = 2,
|
||||||
|
Unqualified = 3,
|
||||||
|
Converted = 4,
|
||||||
|
Lost = 5
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public class Lead
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid? CustomerId { get; set; }
|
||||||
|
|
||||||
|
public string? GoogleClickId { get; set; }
|
||||||
|
|
||||||
|
public string? WebClickId { get; set; }
|
||||||
|
|
||||||
|
public string? AppClickId { get; set; }
|
||||||
|
|
||||||
|
public long? CampaignId { get; set; }
|
||||||
|
|
||||||
|
public long? AdGroupId { get; set; }
|
||||||
|
|
||||||
|
public long? AdName { get; set; }
|
||||||
|
|
||||||
|
public long? TargetId { get; set; }
|
||||||
|
|
||||||
|
public long? FeedItemId { get; set; }
|
||||||
|
|
||||||
|
public string? ClickLocation { get; set; }
|
||||||
|
|
||||||
|
public string? AttributionHash { get; set; }
|
||||||
|
|
||||||
|
public LeadStatus Status { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AssemblyOriginatorKeyFile>..\LiteCharms.snk</AssemblyOriginatorKeyFile>
|
||||||
|
<SignAssembly>True</SignAssembly>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Nuget Package Details -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<PackageId>LiteCharms.Models</PackageId>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
|
<Authors>Khwezi Mngoma</Authors>
|
||||||
|
<Company>Lite Charms (PTY) Ltd</Company>
|
||||||
|
<Description>Shared models for Lite Charms applications.</Description>
|
||||||
|
<PackageProjectUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator</PackageProjectUrl>
|
||||||
|
<RepositoryUrl>https://gitea.khongisa.co.za/litecharms/leadgenerator.git</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<PackageTags>utility;dotnet</PackageTags>
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="..\LICENSE" Pack="true" PackagePath="\"/>
|
||||||
|
<None Include="..\icon.png" Pack="true" PackagePath="\" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public class Order
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid CustomerId { get; set; }
|
||||||
|
|
||||||
|
public Guid ProductPriceId { get; set; }
|
||||||
|
|
||||||
|
public Guid? RefundId { get; set; }
|
||||||
|
|
||||||
|
public OrderStatus Status { get; set; }
|
||||||
|
|
||||||
|
public string[]? Notes { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public class OrderRefund
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid OrderId { get; set; }
|
||||||
|
|
||||||
|
public string? Reason { get; set; }
|
||||||
|
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public class Product
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace LiteCharms.Models;
|
||||||
|
|
||||||
|
public class ProductPrice
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset CreatedAt { get; set; }
|
||||||
|
|
||||||
|
public DateTimeOffset? UpdatedAt { get; set; }
|
||||||
|
|
||||||
|
public Guid ProductId { get; set; }
|
||||||
|
|
||||||
|
public decimal Price { get; set; }
|
||||||
|
|
||||||
|
public decimal Discount { get; set; }
|
||||||
|
|
||||||
|
public bool Active { get; set; }
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -1 +1,7 @@
|
|||||||
<Solution />
|
<Solution>
|
||||||
|
<Project Path="LiteCharms.Entities/LiteCharms.Entities.csproj" />
|
||||||
|
<Project Path="LiteCharms.Extensions/LiteCharms.Extensions.csproj" />
|
||||||
|
<Project Path="LiteCharms.Features/LiteCharms.Features.csproj" />
|
||||||
|
<Project Path="LiteCharms.Infrastructure/LiteCharms.Infrastructure.csproj" />
|
||||||
|
<Project Path="LiteCharms.Models/LiteCharms.Models.csproj" />
|
||||||
|
</Solution>
|
||||||
|
|||||||
Reference in New Issue
Block a user