Wrote tests for most services, applied EF core optimisations
This commit is contained in:
@@ -0,0 +1,81 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.Authors;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Authors.Models;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.MidrandBooks.Tests;
|
||||||
|
|
||||||
|
public class AuthorServiceFeatureTests(Fixture fixture, ITestOutputHelper output) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
private readonly AuthorService authorService = fixture.Services.GetRequiredService<AuthorService>();
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateAuthorAsync_ShouldReturn_ResultWithAuthorId()
|
||||||
|
{
|
||||||
|
var request = new CreateAuthor
|
||||||
|
{
|
||||||
|
Name = "John",
|
||||||
|
LastName = "Doe",
|
||||||
|
Company = "Solo Publishers",
|
||||||
|
Email = "solo@publishers.co.za",
|
||||||
|
PublisherType = PublisherTypes.Independent,
|
||||||
|
ImageUrl = ""
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await authorService.CreateAuthorAsync(request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.True(result.Value > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateAuthorAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var request = new UpdateAuthor
|
||||||
|
{
|
||||||
|
Name = "Jane",
|
||||||
|
LastName = "Doe",
|
||||||
|
Company = "Solo Publishers",
|
||||||
|
Email = "solo@publishers.co.za",
|
||||||
|
PublisherType = PublisherTypes.Independent,
|
||||||
|
ImageUrl = ""
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await authorService.UpdateAuthorAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetAuthors_ShouldReturn_ResultWithAuthorList()
|
||||||
|
{
|
||||||
|
var range = new DateRange
|
||||||
|
{
|
||||||
|
From = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(-7)),
|
||||||
|
To = DateOnly.FromDateTime(DateTime.UtcNow),
|
||||||
|
MaxRecords = 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await authorService.GetAuthorsAsync(range, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetAuthorAsync_ShouldReturn_ResultWithAuthor()
|
||||||
|
{
|
||||||
|
var result = await authorService.GetAuthorAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateAuthorStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await authorService.UpdateAuthorStatusAsync(1, true, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.AuthorBooks;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.MidrandBooks.Tests;
|
||||||
|
|
||||||
|
public class BooksServiceFeatureTests(Fixture fixture) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
private readonly BooksService bookService = fixture.Services.GetRequiredService<BooksService>();
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateBookAsync_ShouldReturn_ResultWithBookId()
|
||||||
|
{
|
||||||
|
var result = await bookService.CreateBookAsync(1, 2, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetBookAsync_ShouldReturn_ResultWithBook()
|
||||||
|
{
|
||||||
|
var result = await bookService.GetBookAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetBooksByAuthorAsync_ShouldReturn_ResultWithAuthorBooks()
|
||||||
|
{
|
||||||
|
var result = await bookService.GetBooksByAuthorAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetPublishedBooksAsync_ShouldReturn_ResultWithBublishedBooks()
|
||||||
|
{
|
||||||
|
var result = await bookService.GetPublishedBooksAsync(0, 1000, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateBookStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await bookService.UpdateBookStatusAsync(1, true, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
using LiteCharms.Features.MidrandBooks.Abstractions;
|
using LiteCharms.Features.MidrandBooks.Abstractions;
|
||||||
using LiteCharms.Features.MidrandBooks.Extensions;
|
using LiteCharms.Features.MidrandBooks.Extensions;
|
||||||
|
|
||||||
namespace LiteCharms.Features.MidrandBooks.Tests;
|
namespace LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
|
||||||
public class Fixture : IDisposable
|
public class Fixture : IDisposable
|
||||||
{
|
{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Tests;
|
namespace LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
|
||||||
public class IntegrationFactAttribute : FactAttribute
|
public class IntegrationFactAttribute : FactAttribute
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.Customers;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Customers.Models;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.MidrandBooks.Tests;
|
||||||
|
|
||||||
|
public class CustomerServiceFeatureTests(Fixture fixture) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
private readonly CustomerService customerService = fixture.Services.GetRequiredService<CustomerService>();
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateCustomerAsync_ShouldReturn_ResultWithCustomerId()
|
||||||
|
{
|
||||||
|
var request = new CreateCustomer
|
||||||
|
{
|
||||||
|
Company = "Book Lovers",
|
||||||
|
Email = "hank@booklovers.com",
|
||||||
|
Phone = "555 1245 8577",
|
||||||
|
Website = "https://www.booklovers.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await customerService.CreateCustomerAsync(request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.True(result.Value > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateCustomerContactAsync_ShouldReturn_ResultWithCustomerContactId()
|
||||||
|
{
|
||||||
|
var request = new CreateCustomerContact
|
||||||
|
{
|
||||||
|
Name = "Sipho",
|
||||||
|
LastName = "Madlanga",
|
||||||
|
Phone = "0710857365",
|
||||||
|
Email = "sipho@madlanga.africa",
|
||||||
|
Type = ContactTypes.Business
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await customerService.CreateCustomerContactAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.True(result.Value > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateCustomerAddressAsync_ShouldReturn_ResultWithCustomerAddressId()
|
||||||
|
{
|
||||||
|
var request = new CreateCustomerAddress
|
||||||
|
{
|
||||||
|
Name = "Business",
|
||||||
|
BuildingType = AddressBuildingTypes.MixedUse,
|
||||||
|
Type = AddressType.Shipping,
|
||||||
|
Street = "123 Building 4, XYZ Suburb, Some Region",
|
||||||
|
City = "Johannesburg",
|
||||||
|
State = "Gauteng",
|
||||||
|
Country = "South Africa",
|
||||||
|
IsPrimary = true,
|
||||||
|
Enabled = true,
|
||||||
|
PostalCode = "12345"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await customerService.CreateCustomerAddressAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.True(result.Value > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateCustomerAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var request = new UpdateCustomer
|
||||||
|
{
|
||||||
|
Company = "Book Lovers",
|
||||||
|
Email = "hank@booklovers.com",
|
||||||
|
Phone = "555 1245 8578",
|
||||||
|
Website = "https://www.booklovers.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await customerService.UpdateCustomerAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateCustomerContactAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var request = new UpdateCustomerContact
|
||||||
|
{
|
||||||
|
Name = "Sipho",
|
||||||
|
LastName = "Madlanga",
|
||||||
|
Phone = "0710857366",
|
||||||
|
Email = "sipho@madlanga.africa",
|
||||||
|
Type = ContactTypes.Business
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await customerService.UpdateCustomerContactAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateCustomerAddressAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var request = new UpdateCustomerAddress
|
||||||
|
{
|
||||||
|
Name = "Business",
|
||||||
|
BuildingType = AddressBuildingTypes.MixedUse,
|
||||||
|
Type = AddressType.Shipping,
|
||||||
|
Street = "123 Building 4, XYZ Suburb, Some Region",
|
||||||
|
City = "Johannesburg",
|
||||||
|
State = "Gauteng",
|
||||||
|
Country = "South Africa",
|
||||||
|
IsPrimary = true,
|
||||||
|
Enabled = true,
|
||||||
|
PostalCode = "12346"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await customerService.UpdateCustomerAddressAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateCustomerStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await customerService.UpdateCustomerStatusAsync(1, true, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateCustomerContactStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await customerService.UpdateCustomerContactStatusAsync(1, true, true, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateCustomerAddressStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await customerService.UpdateCustomerAddressStatusAsync(1, true, true, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetCustomersAsync_ShouldReturn_ResultWithCustomerList()
|
||||||
|
{
|
||||||
|
var result = await customerService.GetCustomersAsync(fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetCustomerContactsAsync_ShouldReturn_ResultWithCustomerContactList()
|
||||||
|
{
|
||||||
|
var result = await customerService.GetCustomerContactsAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetCustomerAddressesAsync_ShouldReturn_ResultWithCustomerAddressList()
|
||||||
|
{
|
||||||
|
var result = await customerService.GetCustomerAddressesAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetCustomerAsync_ShouldReturn_ResultWithCustomer()
|
||||||
|
{
|
||||||
|
var result = await customerService.GetCustomerAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetCustomerContactAsync_ShouldReturn_ResultWithCustomerContact()
|
||||||
|
{
|
||||||
|
var result = await customerService.GetCustomerContactsAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetCustomerAddressAsync_ShouldReturn_ResultWithCustomerAddress()
|
||||||
|
{
|
||||||
|
var result = await customerService.GetCustomerAddressAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.Orders;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Orders.Models;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
using LiteCharms.Features.Models;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.MidrandBooks.Tests;
|
||||||
|
|
||||||
|
public class OrderServiceFeatureTests(Fixture fixture) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
private readonly OrderService orderService = fixture.Services.GetRequiredService<OrderService>();
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateOrderAsync_ShouldReturn_ResultWithOrderId()
|
||||||
|
{
|
||||||
|
var request = new CreateOrder(250, "At the intercomm, dial 1 then option 2");
|
||||||
|
|
||||||
|
var result = await orderService.CreateOrderAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.True(result.Value > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task AddItemToOrderAsync_ShouldReturn_ResultWithOrderItemId()
|
||||||
|
{
|
||||||
|
var request = new CreateOrderItem(1, 1, 2);
|
||||||
|
|
||||||
|
var result = await orderService.AddItemToOrderAsync(1, request, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.True(result.Value > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task AddItemsToOrderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var requests = new List<CreateOrderItem>
|
||||||
|
{
|
||||||
|
new(1, 1, 1),
|
||||||
|
new(1, 1, 3)
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await orderService.AddItemsToOrderAsync(1, [.. requests], fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task RemoveItemFromOrderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await orderService.RemoveItemFromOrderAsync(1, 5, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task ClearOrderItemsAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await orderService.ClearOrderItemsAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CancelOrderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await orderService.CancelOrderAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetOrderAsync_ShouldReturn_ResultWithOrder()
|
||||||
|
{
|
||||||
|
var result = await orderService.GetOrderAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotNull(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetOrdersByCustomerAsync_ShouldReturn_ResultWithOrderList()
|
||||||
|
{
|
||||||
|
var result = await orderService.GetOrdersByCustomerAsync(1, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetOrdersAsync_ShouldReturn_ResultWithOrderList()
|
||||||
|
{
|
||||||
|
var range = new DateRange
|
||||||
|
{
|
||||||
|
From = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(-7)),
|
||||||
|
To = DateOnly.FromDateTime(DateTime.UtcNow),
|
||||||
|
MaxRecords = 1000
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await orderService.GetOrdersAsync(range, 0, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.NotEmpty(result.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateOrderStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
var result = await orderService.UpdateOrderStatusAsync(1, OrderStatus.Pending, fixture.CancellationToken);
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task AddShippingToOrderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateShippingStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetShippingByOrderIdAsync_ShouldReturn_ResultWithShipping()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task RemoveShippingFromOrderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateShippingTrackingNumberAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreateShippingProviderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetShippingProvidersAsync_ShouldReturn_ResultWithShippingProviderList()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetShippingProviderAsync_ShouldReturn_ResultWithShippingProvider()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdateShippingProviderAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using LiteCharms.Features.MidrandBooks.Pages;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
|
|
||||||
|
namespace LiteCharms.Features.MidrandBooks.Tests;
|
||||||
|
|
||||||
|
public class PageServiceFeatureTests(Fixture fixture) : IClassFixture<Fixture>
|
||||||
|
{
|
||||||
|
private readonly PageService pageService = fixture.Services.GetRequiredService<PageService>();
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task CreatePageAsync_ShouldReturn_ResultWithPageId()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetPagesAsync_ByBookId_ShouldReturn_ResultWithPageList()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetPageAsync_ShouldReturn_ResultWithPage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task GetPageByNumberAsync_ById_And_BookPageNumber_ShouldReturn_ResultWithPage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdatePageAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task DeletePageAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task DeleteByPageTypeAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task DeleteAllAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[IntegrationFact]
|
||||||
|
public async Task UpdatePageStatusAsync_ShouldReturn_ResultWithSuccess()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -1,10 +1,11 @@
|
|||||||
using LiteCharms.Features.MidrandBooks.Products;
|
using LiteCharms.Features.MidrandBooks.Products;
|
||||||
using LiteCharms.Features.MidrandBooks.Products.Models;
|
using LiteCharms.Features.MidrandBooks.Products.Models;
|
||||||
|
using LiteCharms.Features.MidrandBooks.Tests.Common;
|
||||||
using LiteCharms.Features.Models;
|
using LiteCharms.Features.Models;
|
||||||
|
|
||||||
namespace LiteCharms.Features.MidrandBooks.Tests;
|
namespace LiteCharms.Features.MidrandBooks.Tests;
|
||||||
|
|
||||||
public class ProductServiceFeatureTest(Fixture fixture, ITestOutputHelper output) : IClassFixture<Fixture>
|
public class ProductServiceFeatureTests(Fixture fixture, ITestOutputHelper output) : IClassFixture<Fixture>
|
||||||
{
|
{
|
||||||
private readonly ProductService productService = fixture.Services.GetRequiredService<ProductService>();
|
private readonly ProductService productService = fixture.Services.GetRequiredService<ProductService>();
|
||||||
|
|
||||||
@@ -7,23 +7,21 @@ namespace LiteCharms.Features.MidrandBooks.AuthorBooks;
|
|||||||
|
|
||||||
public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contextFactory) : IService
|
public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contextFactory) : IService
|
||||||
{
|
{
|
||||||
public async ValueTask<Result> UpdateBookStatusAsync(long bookId, bool isEnabled, CancellationToken cancellationToken)
|
public async ValueTask<Result> UpdateBookStatusAsync(long bookId, bool isEnabled, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var book = await context.Books.FirstOrDefaultAsync(b => b.Id == bookId, cancellationToken);
|
var rowsUpdated = await context.Books
|
||||||
|
.Where(b => b.Id == bookId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(b => b.Enabled, isEnabled)
|
||||||
|
.SetProperty(b => b.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (book is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Book with ID {bookId} not found"));
|
|
||||||
|
|
||||||
book.UpdatedAt = DateTime.UtcNow;
|
|
||||||
book.Enabled = isEnabled;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error($"Failed to change status of book with ID {bookId}"));
|
: Result.Fail(new Error($"Book with ID {bookId} not found"));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -45,8 +43,9 @@ public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
|
|
||||||
var book = context.Books.Add(new Entities.AuthorBook
|
var book = context.Books.Add(new Entities.AuthorBook
|
||||||
{
|
{
|
||||||
|
CreatedAt = DateTime.UtcNow,
|
||||||
AuthorId = authorId,
|
AuthorId = authorId,
|
||||||
ProductId = productId,
|
ProductId = productId
|
||||||
});
|
});
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
@@ -68,7 +67,8 @@ public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
var book = await context.Books
|
var book = await context.Books
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(b => b.Author)
|
.Include(b => b.Author)
|
||||||
.Include(b => b.Product!.Price)
|
.Include(b => b.Product)
|
||||||
|
.ThenInclude(b => b!.Prices)
|
||||||
.Include(b => b.Pages)
|
.Include(b => b.Pages)
|
||||||
.FirstOrDefaultAsync(b => b.Id == bookId, cancellationToken);
|
.FirstOrDefaultAsync(b => b.Id == bookId, cancellationToken);
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
if(!await context.Authors.AnyAsync(a => a.Id == authorId, cancellationToken))
|
if(!await context.Authors.AnyAsync(a => a.Id == authorId, cancellationToken))
|
||||||
return Result.Fail<AuthorBook[]>(new Error($"Author with ID {authorId} not found"));
|
return Result.Fail<AuthorBook[]>(new Error($"Author with ID {authorId} not found"));
|
||||||
@@ -94,7 +94,8 @@ public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
var books = await context.Books
|
var books = await context.Books
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(b => b.Author)
|
.Include(b => b.Author)
|
||||||
.Include(b => b.Product!.Price)
|
.Include(b => b.Product)
|
||||||
|
.ThenInclude(b => b.Prices)
|
||||||
.OrderByDescending(b => b.CreatedAt)
|
.OrderByDescending(b => b.CreatedAt)
|
||||||
.Where(b => b.AuthorId == authorId)
|
.Where(b => b.AuthorId == authorId)
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
@@ -118,9 +119,10 @@ public sealed class BooksService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
var books = await context.Books
|
var books = await context.Books
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(b => b.Author)
|
.Include(b => b.Author)
|
||||||
.Include(b => b.Product!.Price)
|
.Include(b => b.Product)
|
||||||
|
.ThenInclude(b => b!.Prices)
|
||||||
.Include(b => b.Pages)
|
.Include(b => b.Pages)
|
||||||
.Where(b => b.Enabled && b.Product!.Enabled && b.Author.Enabled)
|
.Where(b => b.Enabled && b.Product!.Enabled && b.Author!.Enabled)
|
||||||
.OrderByDescending(b => b.Ranking)
|
.OrderByDescending(b => b.Ranking)
|
||||||
.ThenByDescending(b => b.Ranking)
|
.ThenByDescending(b => b.Ranking)
|
||||||
.ThenByDescending(b => b.CreatedAt)
|
.ThenByDescending(b => b.CreatedAt)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace LiteCharms.Features.MidrandBooks.AuthorBooks.Entities;
|
|||||||
|
|
||||||
public class AuthorBook : Models.AuthorBook
|
public class AuthorBook : Models.AuthorBook
|
||||||
{
|
{
|
||||||
public virtual Author Author { get; set; } = new();
|
public virtual Author? Author { get; set; }
|
||||||
|
|
||||||
public new virtual Product? Product { get; set; }
|
public new virtual Product? Product { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using LiteCharms.Features.MidrandBooks.Abstractions;
|
using LiteCharms.Features.MidrandBooks.Abstractions;
|
||||||
using LiteCharms.Features.MidrandBooks.AuthorBooks.Models;
|
|
||||||
using LiteCharms.Features.MidrandBooks.Authors.Models;
|
using LiteCharms.Features.MidrandBooks.Authors.Models;
|
||||||
using LiteCharms.Features.MidrandBooks.Extensions;
|
using LiteCharms.Features.MidrandBooks.Extensions;
|
||||||
using LiteCharms.Features.MidrandBooks.Postgres;
|
using LiteCharms.Features.MidrandBooks.Postgres;
|
||||||
@@ -9,53 +8,21 @@ namespace LiteCharms.Features.MidrandBooks.Authors;
|
|||||||
|
|
||||||
public sealed class AuthorService(IDbContextFactory<MidrandBooksDbContext> contextFactory) : IService
|
public sealed class AuthorService(IDbContextFactory<MidrandBooksDbContext> contextFactory) : IService
|
||||||
{
|
{
|
||||||
public async ValueTask<Result<AuthorBook[]>> GetAuthorBooksAsync(long authorId, CancellationToken cancellationToken)
|
public async ValueTask<Result> UpdateAuthorStatusAsync(long authorId, bool isEnabled, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var author = await context.Authors.FirstOrDefaultAsync(a => a.Id == authorId, cancellationToken);
|
var rowsUpdated = await context.Authors
|
||||||
|
.Where(a => a.Id == authorId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(a => a.Enabled, isEnabled)
|
||||||
|
.SetProperty(a => a.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (author is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail<AuthorBook[]>(new Error($"Author with ID {authorId} not found"));
|
|
||||||
|
|
||||||
var books = await context.Books
|
|
||||||
.AsNoTracking()
|
|
||||||
.Include(b => b.Author)
|
|
||||||
.Include(b => b.Product!.Price)
|
|
||||||
.OrderByDescending(b => b.CreatedAt)
|
|
||||||
.Where(p => p.AuthorId == authorId)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.ToArrayAsync(cancellationToken);
|
|
||||||
|
|
||||||
return books?.Length > 0
|
|
||||||
? Result.Ok(books.Select(b => b.ToModel()).ToArray())
|
|
||||||
: Result.Fail<AuthorBook[]>(new Error($"No books found for author with ID {authorId}"));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return Result.Fail<AuthorBook[]>(new Error(ex.Message).CausedBy(ex));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask<Result> UpdateAuthorStatusAsync(long authorId, bool isEnabled, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
|
||||||
|
|
||||||
var author = await context.Authors.FirstOrDefaultAsync(a => a.Id == authorId, cancellationToken);
|
|
||||||
|
|
||||||
if (author is null)
|
|
||||||
return Result.Fail(new Error($"Author with ID {authorId} not found"));
|
|
||||||
|
|
||||||
author.UpdatedAt = DateTime.UtcNow;
|
|
||||||
author.Enabled = isEnabled;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error($"Failed to change status of author with ID {authorId}"));
|
: Result.Fail(new Error($"Author with ID {authorId} not found"));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -81,12 +48,12 @@ public sealed class AuthorService(IDbContextFactory<MidrandBooksDbContext> conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<Result<Author[]>> GetAuthors(DateRange range, CancellationToken cancellationToken)
|
public async ValueTask<Result<Author[]>> GetAuthorsAsync(DateRange range, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var fromDate = range.From.ToDateTime(TimeOnly.MinValue);
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
|
||||||
var toDate = range.To.ToDateTime(TimeOnly.MaxValue);
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc);
|
||||||
|
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
@@ -107,18 +74,12 @@ public sealed class AuthorService(IDbContextFactory<MidrandBooksDbContext> conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<Result> UpdateAuthorAsync(long authorId, UpdateAuthor request, CancellationToken cancellationToken)
|
public async ValueTask<Result> UpdateAuthorAsync(long authorId, UpdateAuthor request, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
if (await context.Authors.AnyAsync(a => a.Name == request.Name && a.LastName == request.LastName, cancellationToken))
|
|
||||||
return Result.Fail(new Error($"An author with the name {request.Name} {request.LastName} already exists"));
|
|
||||||
|
|
||||||
if (await context.Authors.AnyAsync(a => a.Email == request.Email, cancellationToken))
|
|
||||||
return Result.Fail(new Error($"An author with the email {request.Email} already exists"));
|
|
||||||
|
|
||||||
var author = await context.Authors.FirstOrDefaultAsync(a => a.Id == authorId, cancellationToken);
|
var author = await context.Authors.FirstOrDefaultAsync(a => a.Id == authorId, cancellationToken);
|
||||||
|
|
||||||
if (author is null)
|
if (author is null)
|
||||||
@@ -151,12 +112,12 @@ public sealed class AuthorService(IDbContextFactory<MidrandBooksDbContext> conte
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
if(await context.Authors.AnyAsync(a => a.Name == request.Name && a.LastName == request.LastName, cancellationToken))
|
if (await context.Authors.AnyAsync(a => a.Name == request.Name && a.LastName == request.LastName, cancellationToken))
|
||||||
return Result.Fail<long>(new Error($"An author with the name {request.Name} {request.LastName} already exists"));
|
return Result.Fail<long>(new Error($"An author with the name {request.Name} {request.LastName} already exists"));
|
||||||
|
|
||||||
if(await context.Authors.AnyAsync(a => a.Email == request.Email, cancellationToken))
|
if (await context.Authors.AnyAsync(a => a.Email == request.Email, cancellationToken))
|
||||||
return Result.Fail<long>(new Error($"An author with the email {request.Email} already exists"));
|
return Result.Fail<long>(new Error($"An author with the email {request.Email} already exists"));
|
||||||
|
|
||||||
var newAuthor = context.Authors.Add(new Entities.Author
|
var newAuthor = context.Authors.Add(new Entities.Author
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class Author
|
|||||||
|
|
||||||
public string? ThumbnailImageUrl { get; set; }
|
public string? ThumbnailImageUrl { get; set; }
|
||||||
|
|
||||||
public SocialMedia[]? SocialMedia { get; set; }
|
public ICollection<SocialMedia>? SocialMedia { get; set; }
|
||||||
|
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
if (await context.Customers.AnyAsync(c => c.Email!.Equals(request.Email, StringComparison.OrdinalIgnoreCase), cancellationToken))
|
if (await context.Customers.AnyAsync(c => EF.Functions.ILike(c.Email!, $"%{request.Email}%"), cancellationToken))
|
||||||
return Result.Fail<long>(new Error($"Customer with email '{request.Email}' already exists."));
|
return Result.Fail<long>(new Error($"Customer with email '{request.Email}' already exists."));
|
||||||
|
|
||||||
var customer = context.Customers.Add(new Entities.Customer
|
var customer = context.Customers.Add(new Entities.Customer
|
||||||
@@ -46,7 +46,7 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
if (!await context.Customers.AnyAsync(c => c.Id == customerId, cancellationToken))
|
||||||
return Result.Fail<long>(new Error($"Customer with ID '{customerId}' does not exist."));
|
return Result.Fail<long>(new Error($"Customer with ID '{customerId}' does not exist."));
|
||||||
|
|
||||||
if (await context.Contacts.AnyAsync(cc => cc.CustomerId == customerId && cc.Email!.Equals(request.Email, StringComparison.OrdinalIgnoreCase), cancellationToken))
|
if (await context.Contacts.AnyAsync(cc => cc.CustomerId == customerId && EF.Functions.ILike(cc.Email!, $"%{request.Email}%"), cancellationToken))
|
||||||
return Result.Fail<long>(new Error($"Contact with email '{request.Email}' already exists for this customer."));
|
return Result.Fail<long>(new Error($"Contact with email '{request.Email}' already exists for this customer."));
|
||||||
|
|
||||||
var contact = context.Contacts.Add(new Entities.Contact
|
var contact = context.Contacts.Add(new Entities.Contact
|
||||||
@@ -139,21 +139,19 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var contact = await context.Contacts.FirstOrDefaultAsync(cc => cc.Id == contactId, cancellationToken);
|
var rowsUpdated = await context.Contacts
|
||||||
|
.Where(cc => cc.Id == contactId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(cc => cc.Name, request.Name)
|
||||||
|
.SetProperty(cc => cc.LastName, request.LastName)
|
||||||
|
.SetProperty(cc => cc.Email, request.Email)
|
||||||
|
.SetProperty(cc => cc.Phone, request.Phone)
|
||||||
|
.SetProperty(cc => cc.Type, request.Type)
|
||||||
|
.SetProperty(cc => cc.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (contact is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Contact with ID '{contactId}' does not exist."));
|
|
||||||
|
|
||||||
contact.UpdatedAt = DateTime.UtcNow;
|
|
||||||
contact.Name = request.Name;
|
|
||||||
contact.LastName = request.LastName;
|
|
||||||
contact.Email = request.Email;
|
|
||||||
contact.Phone = request.Phone;
|
|
||||||
contact.Type = request.Type;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error("Failed to update customer contact."));
|
: Result.Fail(new Error($"Contact with ID '{contactId}' does not exist."));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -167,25 +165,23 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var address = await context.Addresses.FirstOrDefaultAsync(a => a.Id == addressId, cancellationToken);
|
var rowsUpdated = await context.Addresses
|
||||||
|
.Where(a => a.Id == addressId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(a => a.Street, request.Street)
|
||||||
|
.SetProperty(a => a.City, request.City)
|
||||||
|
.SetProperty(a => a.State, request.State)
|
||||||
|
.SetProperty(a => a.PostalCode, request.PostalCode)
|
||||||
|
.SetProperty(a => a.Country, request.Country)
|
||||||
|
.SetProperty(a => a.Type, request.Type)
|
||||||
|
.SetProperty(a => a.BuildingType, request.BuildingType)
|
||||||
|
.SetProperty(a => a.IsPrimary, request.IsPrimary)
|
||||||
|
.SetProperty(a => a.Name, request.Name)
|
||||||
|
.SetProperty(a => a.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (address is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Address with ID '{addressId}' does not exist."));
|
|
||||||
|
|
||||||
address.UpdatedAt = DateTime.UtcNow;
|
|
||||||
address.Street = request.Street;
|
|
||||||
address.City = request.City;
|
|
||||||
address.State = request.State;
|
|
||||||
address.PostalCode = request.PostalCode;
|
|
||||||
address.Country = request.Country;
|
|
||||||
address.Type = request.Type;
|
|
||||||
address.BuildingType = request.BuildingType;
|
|
||||||
address.IsPrimary = request.IsPrimary;
|
|
||||||
address.Name = request.Name;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error("Failed to update customer address."));
|
: Result.Fail(new Error($"Address with ID '{addressId}' does not exist."));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -199,17 +195,15 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == customerId, cancellationToken);
|
var rowsUpdated = await context.Customers
|
||||||
|
.Where(c => c.Id == customerId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(c => c.Enabled, enabled)
|
||||||
|
.SetProperty(c => c.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (customer is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Customer with ID '{customerId}' does not exist."));
|
|
||||||
|
|
||||||
customer.Enabled = enabled;
|
|
||||||
customer.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error("Failed to update customer status."));
|
: Result.Fail(new Error($"Customer with ID '{customerId}' does not exist."));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -223,18 +217,16 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var contact = await context.Contacts.FirstOrDefaultAsync(cc => cc.Id == contactId, cancellationToken);
|
var rowsUpdated = await context.Contacts
|
||||||
|
.Where(cc => cc.Id == contactId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(cc => cc.Enabled, enabled)
|
||||||
|
.SetProperty(cc => cc.IsPrimary, isPrimary)
|
||||||
|
.SetProperty(cc => cc.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (contact is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Contact with ID '{contactId}' does not exist."));
|
|
||||||
|
|
||||||
contact.Enabled = enabled;
|
|
||||||
contact.IsPrimary = isPrimary;
|
|
||||||
contact.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error("Failed to update customer contact status."));
|
: Result.Fail(new Error($"Contact with ID '{contactId}' does not exist."));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -248,18 +240,16 @@ public sealed class CustomerService(IDbContextFactory<MidrandBooksDbContext> con
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var address = await context.Addresses.FirstOrDefaultAsync(a => a.Id == addressId, cancellationToken);
|
var rowsUpdated = await context.Addresses
|
||||||
|
.Where(a => a.Id == addressId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(a => a.Enabled, enabled)
|
||||||
|
.SetProperty(a => a.IsPrimary, isPrimary)
|
||||||
|
.SetProperty(a => a.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (address is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Address with ID '{addressId}' does not exist."));
|
|
||||||
|
|
||||||
address.Enabled = enabled;
|
|
||||||
address.IsPrimary = isPrimary;
|
|
||||||
address.UpdatedAt = DateTime.UtcNow;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error("Failed to update customer address status."));
|
: Result.Fail(new Error($"Address with ID '{addressId}' does not exist."));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class Customer
|
|||||||
|
|
||||||
public string? Phone { get; set; }
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
public SocialMedia[]? SocialMedia { get; set; }
|
public ICollection<SocialMedia>? SocialMedia { get; set; }
|
||||||
|
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public record CreateCustomer
|
|||||||
|
|
||||||
public string? Phone { get; set; }
|
public string? Phone { get; set; }
|
||||||
|
|
||||||
public SocialMedia[]? SocialMedia { get; set; }
|
public ICollection<SocialMedia>? SocialMedia { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed record UpdateCustomer : CreateCustomer;
|
public sealed record UpdateCustomer : CreateCustomer;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace LiteCharms.Features.MidrandBooks.Orders.Models;
|
namespace LiteCharms.Features.MidrandBooks.Orders.Models;
|
||||||
|
|
||||||
public sealed record CreateOrder(long CustomerId, decimal TotalPrice, string? Notes);
|
public sealed record CreateOrder(decimal TotalPrice, string? Notes);
|
||||||
|
|
||||||
public sealed record CreateOrderItem(long AuthorBookId, long ProductPriceId, int Quantity);
|
public sealed record CreateOrderItem(long AuthorBookId, long ProductPriceId, int Quantity);
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,17 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
if (!await context.Prices.AnyAsync(pp => pp.Id == request.ProductPriceId, cancellationToken))
|
if (!await context.Prices.AnyAsync(pp => pp.Id == request.ProductPriceId, cancellationToken))
|
||||||
return Result.Fail<long>("Product price not found.");
|
return Result.Fail<long>("Product price not found.");
|
||||||
|
|
||||||
|
var existingItem = await context.OrderItems.FirstOrDefaultAsync(i => i.ProductPriceId == request.ProductPriceId && i.OrderId == orderId, cancellationToken);
|
||||||
|
|
||||||
|
if(existingItem is not null)
|
||||||
|
{
|
||||||
|
existingItem.Quantity += request.Quantity;
|
||||||
|
|
||||||
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
|
? Result.Ok(existingItem.Id)
|
||||||
|
: Result.Fail<long>("Update existing order item.");
|
||||||
|
}
|
||||||
|
|
||||||
var orderItem = context.OrderItems.Add(new Entities.OrderItem
|
var orderItem = context.OrderItems.Add(new Entities.OrderItem
|
||||||
{
|
{
|
||||||
OrderId = orderId,
|
OrderId = orderId,
|
||||||
@@ -78,9 +89,6 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
|
|
||||||
if (!await context.Orders.AnyAsync(o => o.Id == orderId, cancellationToken))
|
if (!await context.Orders.AnyAsync(o => o.Id == orderId, cancellationToken))
|
||||||
return Result.Fail("Order not found.");
|
return Result.Fail("Order not found.");
|
||||||
|
|
||||||
var existingItems = context.OrderItems.Where(oi => oi.OrderId == orderId);
|
|
||||||
context.OrderItems.RemoveRange(existingItems);
|
|
||||||
|
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
@@ -90,18 +98,23 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
if (!await context.Prices.AnyAsync(pp => pp.Id == item.ProductPriceId, cancellationToken))
|
if (!await context.Prices.AnyAsync(pp => pp.Id == item.ProductPriceId, cancellationToken))
|
||||||
return Result.Fail($"Product price with ID {item.ProductPriceId} not found.");
|
return Result.Fail($"Product price with ID {item.ProductPriceId} not found.");
|
||||||
|
|
||||||
context.OrderItems.Add(new Entities.OrderItem
|
var existingItem = await context.OrderItems.FirstOrDefaultAsync(i => i.ProductPriceId == item.ProductPriceId && i.OrderId == orderId, cancellationToken);
|
||||||
{
|
|
||||||
OrderId = orderId,
|
if (existingItem is not null)
|
||||||
AuthorBookId = item.AuthorBookId,
|
existingItem.Quantity += item.Quantity;
|
||||||
ProductPriceId = item.ProductPriceId,
|
else
|
||||||
Quantity = item.Quantity
|
context.OrderItems.Add(new Entities.OrderItem
|
||||||
});
|
{
|
||||||
|
OrderId = orderId,
|
||||||
|
AuthorBookId = item.AuthorBookId,
|
||||||
|
ProductPriceId = item.ProductPriceId,
|
||||||
|
Quantity = item.Quantity
|
||||||
|
});
|
||||||
|
|
||||||
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
return Result.Ok();
|
||||||
? Result.Ok()
|
|
||||||
: Result.Fail("Failed to add items to order.");
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -115,16 +128,13 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var orderItem = await context.OrderItems.FirstOrDefaultAsync(oi => oi.Id == orderItemId && oi.OrderId == orderId, cancellationToken);
|
var rowsDeleted = await context.OrderItems
|
||||||
|
.Where(oi => oi.Id == orderItemId && oi.OrderId == orderId)
|
||||||
|
.ExecuteDeleteAsync(cancellationToken);
|
||||||
|
|
||||||
if (orderItem is null)
|
return rowsDeleted > 0
|
||||||
return Result.Fail("Order item not found.");
|
|
||||||
|
|
||||||
context.OrderItems.Remove(orderItem);
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to remove item from order.");
|
: Result.Fail("Order item not found or failed to remove.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -132,15 +142,14 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<Result> ClearOrderItemasAsync(long orderId, CancellationToken cancellationToken = default)
|
public async ValueTask<Result> ClearOrderItemsAsync(long orderId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var orderItems = context.OrderItems.Where(oi => oi.OrderId == orderId);
|
var deletedItems = await context.OrderItems.Where(oi => oi.OrderId == orderId)
|
||||||
|
.ExecuteDeleteAsync(cancellationToken);
|
||||||
context.OrderItems.RemoveRange(orderItems);
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
return await context.SaveChangesAsync(cancellationToken) > 0
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
@@ -199,12 +208,15 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var fromDate = range.From.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc);
|
||||||
|
var toDate = range.To.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc);
|
||||||
|
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var orders = await context.Orders
|
var orders = await context.Orders
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(o => o.CreatedAt >= range.From.ToDateTime(TimeOnly.MinValue) && o.CreatedAt <= range.To.ToDateTime(TimeOnly.MaxValue))
|
.Where(o => o.CreatedAt >= fromDate && o.CreatedAt <= toDate)
|
||||||
.Skip(index * range.MaxRecords)
|
.Skip(index).Take(range.MaxRecords)
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
return Result.Ok(orders.Select(o => o.ToModel()).ToArray());
|
return Result.Ok(orders.Select(o => o.ToModel()).ToArray());
|
||||||
@@ -221,17 +233,15 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var order = await context.Orders.FirstOrDefaultAsync(o => o.Id == orderId, cancellationToken);
|
var rowsUpdated = await context.Orders
|
||||||
|
.Where(o => o.Id == orderId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(o => o.Status, newStatus)
|
||||||
|
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (order is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail("Order not found.");
|
|
||||||
|
|
||||||
order.UpdatedAt = DateTime.UtcNow;
|
|
||||||
order.Status = newStatus;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to update order status.");
|
: Result.Fail("Order not found or status update failed.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -282,17 +292,16 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var shipping = await context.Shippings.FirstOrDefaultAsync(s => s.OrderId == orderId, cancellationToken);
|
var rowsUpdated = await context.Shippings
|
||||||
|
.Where(s => s.OrderId == orderId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(s => s.Status, newStatus)
|
||||||
|
.SetProperty(s => s.UpdatedAt, DateTime.UtcNow),
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
if (shipping is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail("Shipping not found for this order.");
|
|
||||||
|
|
||||||
shipping.UpdatedAt = DateTime.UtcNow;
|
|
||||||
shipping.Status = newStatus;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to update shipping status.");
|
: Result.Fail("Shipping not found for this order or status update failed.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -325,21 +334,14 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
var rowsDeleted = await context.Shippings
|
||||||
|
.Where(s => s.Id == shippingId && s.OrderId == orderId)
|
||||||
|
.ExecuteDeleteAsync(cancellationToken);
|
||||||
|
|
||||||
if(!await context.Orders.AnyAsync(o => o.Id == orderId, cancellationToken))
|
return rowsDeleted > 0
|
||||||
return Result.Fail("Order not found.");
|
|
||||||
|
|
||||||
var shipping = await context.Shippings.AsNoTracking()
|
|
||||||
.FirstOrDefaultAsync(s => s.OrderId == orderId && s.Id == shippingId, cancellationToken);
|
|
||||||
|
|
||||||
if (shipping is null)
|
|
||||||
return Result.Fail("Shipping not found for this order.");
|
|
||||||
|
|
||||||
context.Shippings.Remove(shipping);
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to remove shipping from order.");
|
: Result.Fail("Shipping record not found for this order.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -353,17 +355,15 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var shipping = await context.Shippings.FirstOrDefaultAsync(s => s.OrderId == orderId && s.Id == shippingId, cancellationToken);
|
var rowsUpdated = await context.Shippings
|
||||||
|
.Where(s => s.Id == shippingId && s.OrderId == orderId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(s => s.TrackingNumber, trackingNumber)
|
||||||
|
.SetProperty(s => s.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (shipping is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail("Shipping not found for this order.");
|
|
||||||
|
|
||||||
shipping.UpdatedAt = DateTime.UtcNow;
|
|
||||||
shipping.TrackingNumber = trackingNumber;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to update shipping tracking number.");
|
: Result.Fail("Shipping record not found for this order.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -440,24 +440,22 @@ public sealed class OrderService(IDbContextFactory<MidrandBooksDbContext> contex
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var provider = await context.ShippingProviders.FirstOrDefaultAsync(sp => sp.Id == request.ProviderId, cancellationToken);
|
var rowsUpdated = await context.ShippingProviders
|
||||||
|
.Where(sp => sp.Id == request.ProviderId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(sp => sp.Name, request.Name)
|
||||||
|
.SetProperty(sp => sp.Price, request.Price)
|
||||||
|
.SetProperty(sp => sp.TrackingUrl, request.TrackingUrl)
|
||||||
|
.SetProperty(sp => sp.Enabled, request.Enabled)
|
||||||
|
.SetProperty(sp => sp.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (provider is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail("Shipping provider not found.");
|
|
||||||
|
|
||||||
provider.UpdatedAt = DateTime.UtcNow;
|
|
||||||
provider.Enabled = request.Enabled;
|
|
||||||
provider.Name = request.Name;
|
|
||||||
provider.Price = request.Price;
|
|
||||||
provider.TrackingUrl = request.TrackingUrl;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to update shipping provider status.");
|
: Result.Fail("Shipping provider not found.");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
return Result.Fail(new Error(ex.Message).CausedBy(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class BookPage
|
|||||||
|
|
||||||
public string[]? Notes { get; set; }
|
public string[]? Notes { get; set; }
|
||||||
|
|
||||||
public PageReference[]? References { get; set; }
|
public ICollection<PageReference>? References { get; set; }
|
||||||
|
|
||||||
public bool Enabled { get; set; }
|
public bool Enabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ public class CreateBookPage
|
|||||||
|
|
||||||
public string[]? Notes { get; set; }
|
public string[]? Notes { get; set; }
|
||||||
|
|
||||||
public PageReference[]? References { get; set; }
|
public ICollection<PageReference>? References { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,19 +13,13 @@ public sealed class PageService(IDbContextFactory<MidrandBooksDbContext> context
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
if (!await context.Books.AnyAsync(b => b.Id == authorBookId, cancellationToken))
|
var rowsDeleted = await context.Pages
|
||||||
return Result.Fail("Book not found");
|
.Where(p => p.AuthorBookId == authorBookId)
|
||||||
|
.ExecuteDeleteAsync(cancellationToken);
|
||||||
|
|
||||||
var pages = await context.Pages.Where(p => p.AuthorBookId == authorBookId).ToListAsync(cancellationToken);
|
return rowsDeleted > 0
|
||||||
|
? Result.Ok()
|
||||||
if (pages.Count == 0)
|
: Result.Fail("No pages found for the specified book");
|
||||||
return Result.Fail("No pages found for the specified book");
|
|
||||||
|
|
||||||
context.Pages.RemoveRange(pages);
|
|
||||||
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
|
||||||
|
|
||||||
return Result.Ok();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -39,16 +33,13 @@ public sealed class PageService(IDbContextFactory<MidrandBooksDbContext> context
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var page = await context.Pages.FirstOrDefaultAsync(p => p.AuthorBookId == authorBookId && p.Number == pageNumber && p.Type == pageType, cancellationToken);
|
var rowsDeleted = await context.Pages
|
||||||
|
.Where(p => p.AuthorBookId == authorBookId && p.Number == pageNumber && p.Type == pageType)
|
||||||
|
.ExecuteDeleteAsync(cancellationToken);
|
||||||
|
|
||||||
if (page is null)
|
return rowsDeleted > 0
|
||||||
return Result.Fail("Page not found");
|
|
||||||
|
|
||||||
context.Pages.Remove(page);
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to delete page");
|
: Result.Fail("Page not found");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -62,17 +53,15 @@ public sealed class PageService(IDbContextFactory<MidrandBooksDbContext> context
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var page = await context.Pages.FirstOrDefaultAsync(p => p.Id == bookPageId, cancellationToken);
|
var rowsUpdated = await context.Pages
|
||||||
|
.Where(p => p.Id == bookPageId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(p => p.Enabled, enabled)
|
||||||
|
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (page is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail("Page not found");
|
|
||||||
|
|
||||||
page.UpdatedAt = DateTime.UtcNow;
|
|
||||||
page.Enabled = enabled;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to update page status");
|
: Result.Fail("Page not found");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -86,16 +75,13 @@ public sealed class PageService(IDbContextFactory<MidrandBooksDbContext> context
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var page = await context.Pages.FirstOrDefaultAsync(p => p.Id == bookPageId, cancellationToken);
|
var rowsDeleted = await context.Pages
|
||||||
|
.Where(p => p.Id == bookPageId)
|
||||||
|
.ExecuteDeleteAsync(cancellationToken);
|
||||||
|
|
||||||
if (page is null)
|
return rowsDeleted > 0
|
||||||
return Result.Fail("Page not found");
|
|
||||||
|
|
||||||
context.Pages.Remove(page);
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to delete page");
|
: Result.Fail("Page not found");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -109,22 +95,20 @@ public sealed class PageService(IDbContextFactory<MidrandBooksDbContext> context
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var page = await context.Pages.FirstOrDefaultAsync(p => p.Id == bookPageId, cancellationToken);
|
var rowsUpdated = await context.Pages
|
||||||
|
.Where(p => p.Id == bookPageId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(p => p.Type, request.Type)
|
||||||
|
.SetProperty(p => p.ContentType, request.ContentType)
|
||||||
|
.SetProperty(p => p.Number, request.Number)
|
||||||
|
.SetProperty(p => p.Content, request.Content)
|
||||||
|
.SetProperty(p => p.Notes, request.Notes)
|
||||||
|
.SetProperty(p => p.References, request.References)
|
||||||
|
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (page is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail("Page not found");
|
|
||||||
|
|
||||||
page.UpdatedAt = DateTime.UtcNow;
|
|
||||||
page.Type = request.Type;
|
|
||||||
page.ContentType = request.ContentType;
|
|
||||||
page.Number = request.Number;
|
|
||||||
page.Content = request.Content;
|
|
||||||
page.Notes = request.Notes;
|
|
||||||
page.References = request.References;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail("Failed to update page");
|
: Result.Fail("Page not found");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
+7
-7
@@ -57,7 +57,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProductId");
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
b.ToTable("Books");
|
b.ToTable("Books", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Authors.Entities.Author", b =>
|
||||||
@@ -454,7 +454,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("ShippingProviders");
|
b.ToTable("ShippingProviders", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Pages.Entities.BookPage", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.Pages.Entities.BookPage", b =>
|
||||||
@@ -677,7 +677,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
b.HasIndex("ProductId")
|
b.HasIndex("ProductId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("ProductPrice");
|
b.ToTable("ProductPrice", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
modelBuilder.Entity("LiteCharms.Features.MidrandBooks.AuthorBooks.Entities.AuthorBook", b =>
|
||||||
@@ -718,7 +718,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("AuthorId", "__synthesizedOrdinal");
|
b1.HasKey("AuthorId", "__synthesizedOrdinal");
|
||||||
|
|
||||||
b1.ToTable("Authors");
|
b1.ToTable("Authors", (string)null);
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("SocialMedia")
|
.ToJson("SocialMedia")
|
||||||
@@ -772,7 +772,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("CustomerId", "__synthesizedOrdinal");
|
b1.HasKey("CustomerId", "__synthesizedOrdinal");
|
||||||
|
|
||||||
b1.ToTable("Customers");
|
b1.ToTable("Customers", (string)null);
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("SocialMedia")
|
.ToJson("SocialMedia")
|
||||||
@@ -862,7 +862,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("BookPageId", "__synthesizedOrdinal");
|
b1.HasKey("BookPageId", "__synthesizedOrdinal");
|
||||||
|
|
||||||
b1.ToTable("BookPages");
|
b1.ToTable("BookPages", (string)null);
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("References")
|
.ToJson("References")
|
||||||
@@ -904,7 +904,7 @@ namespace LiteCharms.Features.MidrandBooks.Postgres.Migrations
|
|||||||
|
|
||||||
b1.HasKey("ProductId");
|
b1.HasKey("ProductId");
|
||||||
|
|
||||||
b1.ToTable("Products");
|
b1.ToTable("Products", (string)null);
|
||||||
|
|
||||||
b1
|
b1
|
||||||
.ToJson("Metadata")
|
.ToJson("Metadata")
|
||||||
|
|||||||
@@ -14,17 +14,15 @@ public sealed class ProductService(IDbContextFactory<MidrandBooksDbContext> cont
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var productPrice = await context.Prices.FirstOrDefaultAsync(p => p.Id == productPriceId, cancellationToken);
|
var rowsUpdated = await context.Prices
|
||||||
|
.Where(p => p.Id == productPriceId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(p => p.Enabled, isEnabled)
|
||||||
|
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (productPrice is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Product price with ID {productPriceId} not found"));
|
|
||||||
|
|
||||||
productPrice.UpdatedAt = DateTime.UtcNow;
|
|
||||||
productPrice.Enabled = isEnabled;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error($"Failed to change status of product price with ID {productPriceId}"));
|
: Result.Fail(new Error($"Product price with ID {productPriceId} not found"));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -38,17 +36,15 @@ public sealed class ProductService(IDbContextFactory<MidrandBooksDbContext> cont
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var product = await context.Products.FirstOrDefaultAsync(p => p.Id == productId, cancellationToken);
|
var rowsUpdated = await context.Products
|
||||||
|
.Where(p => p.Id == productId)
|
||||||
|
.ExecuteUpdateAsync(setters => setters
|
||||||
|
.SetProperty(p => p.Enabled, isEnabled)
|
||||||
|
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow), cancellationToken);
|
||||||
|
|
||||||
if (product is null)
|
return rowsUpdated > 0
|
||||||
return Result.Fail(new Error($"Product with ID {productId} not found"));
|
|
||||||
|
|
||||||
product.UpdatedAt = DateTime.UtcNow;
|
|
||||||
product.Enabled = isEnabled;
|
|
||||||
|
|
||||||
return await context.SaveChangesAsync(cancellationToken) > 0
|
|
||||||
? Result.Ok()
|
? Result.Ok()
|
||||||
: Result.Fail(new Error($"Failed to change status of product with ID {productId}"));
|
: Result.Fail(new Error($"Product with ID {productId} not found"));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user