- Changed JSON naming policy from CamelCase to SnakeCaseLower for SilverPay API compatibility - Fixed field name from 'fiat_amount' to 'amount' in request body - Used unique payment ID instead of order ID to avoid duplicate external_id conflicts - Modified SilverPayApiResponse to handle string amounts from API - Added [JsonIgnore] attributes to computed properties to prevent JSON serialization conflicts - Fixed test compilation errors (mock service and enum casting issues) - Updated SilverPay endpoint to http://10.0.0.52:8001/ 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
373 lines
12 KiB
C#
373 lines
12 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using System.Text.Json;
|
|
using FluentAssertions;
|
|
using LittleShop.DTOs;
|
|
using LittleShop.Models;
|
|
using LittleShop.Tests.Infrastructure;
|
|
using Microsoft.AspNetCore.Mvc.Testing;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Xunit;
|
|
|
|
namespace LittleShop.Tests.Integration;
|
|
|
|
public class OrdersWithVariantsTests : IClassFixture<TestWebApplicationFactory>
|
|
{
|
|
private readonly HttpClient _client;
|
|
private readonly TestWebApplicationFactory _factory;
|
|
|
|
public OrdersWithVariantsTests(TestWebApplicationFactory factory)
|
|
{
|
|
_factory = factory;
|
|
_client = _factory.CreateClient(new WebApplicationFactoryClientOptions
|
|
{
|
|
AllowAutoRedirect = false
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateOrder_WithVariants_ShouldStoreVariantInfo()
|
|
{
|
|
// Arrange
|
|
var product = await CreateProductWithVariants();
|
|
|
|
var orderRequest = new CreateOrderDto
|
|
{
|
|
IdentityReference = "test_user_" + Guid.NewGuid(),
|
|
ShippingName = "John Doe",
|
|
ShippingAddress = "123 Test St",
|
|
ShippingCity = "Test City",
|
|
ShippingPostCode = "TE1 1ST",
|
|
ShippingCountry = "United Kingdom",
|
|
Items = new List<CreateOrderItemDto>
|
|
{
|
|
new()
|
|
{
|
|
ProductId = product.Id,
|
|
Quantity = 1,
|
|
SelectedVariant = "Red"
|
|
},
|
|
new()
|
|
{
|
|
ProductId = product.Id,
|
|
Quantity = 2,
|
|
SelectedVariant = "Blue"
|
|
}
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
|
|
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
|
|
order.Should().NotBeNull();
|
|
order!.Items.Should().HaveCount(2);
|
|
order.Items.Should().Contain(i => i.SelectedVariant == "Red" && i.Quantity == 1);
|
|
order.Items.Should().Contain(i => i.SelectedVariant == "Blue" && i.Quantity == 2);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateOrder_WithMultiBuy_ShouldApplyMultiBuyPricing()
|
|
{
|
|
// Arrange
|
|
var product = await CreateProductWithMultiBuys();
|
|
var multiBuy = product.MultiBuys.First(mb => mb.Quantity == 3);
|
|
|
|
var orderRequest = new CreateOrderDto
|
|
{
|
|
IdentityReference = "test_user_" + Guid.NewGuid(),
|
|
ShippingName = "Jane Doe",
|
|
ShippingAddress = "456 Test Ave",
|
|
ShippingCity = "Test Town",
|
|
ShippingPostCode = "TT2 2ST",
|
|
ShippingCountry = "United Kingdom",
|
|
Items = new List<CreateOrderItemDto>
|
|
{
|
|
new()
|
|
{
|
|
ProductId = product.Id,
|
|
ProductMultiBuyId = multiBuy.Id,
|
|
Quantity = 3
|
|
}
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
|
|
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
|
|
order.Should().NotBeNull();
|
|
order!.Items.Should().HaveCount(1);
|
|
|
|
var item = order.Items.First();
|
|
item.Quantity.Should().Be(3);
|
|
item.ProductMultiBuyId.Should().Be(multiBuy.Id);
|
|
item.UnitPrice.Should().Be(multiBuy.PricePerUnit);
|
|
item.TotalPrice.Should().Be(multiBuy.Price);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateOrder_WithMultiBuyAndVariant_ShouldStoreBoth()
|
|
{
|
|
// Arrange
|
|
var product = await CreateProductWithMultiBuysAndVariants();
|
|
var multiBuy = product.MultiBuys.First(mb => mb.Quantity == 2);
|
|
|
|
var orderRequest = new CreateOrderDto
|
|
{
|
|
IdentityReference = "test_user_" + Guid.NewGuid(),
|
|
ShippingName = "Bob Smith",
|
|
ShippingAddress = "789 Test Rd",
|
|
ShippingCity = "Testville",
|
|
ShippingPostCode = "TV3 3ST",
|
|
ShippingCountry = "United Kingdom",
|
|
Items = new List<CreateOrderItemDto>
|
|
{
|
|
new()
|
|
{
|
|
ProductId = product.Id,
|
|
ProductMultiBuyId = multiBuy.Id,
|
|
Quantity = 2,
|
|
SelectedVariant = "Vanilla"
|
|
}
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
|
|
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
|
|
order.Should().NotBeNull();
|
|
|
|
var item = order.Items.First();
|
|
item.ProductMultiBuyId.Should().Be(multiBuy.Id);
|
|
item.SelectedVariant.Should().Be("Vanilla");
|
|
item.Quantity.Should().Be(2);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateOrder_MixedItems_ShouldCalculateTotalCorrectly()
|
|
{
|
|
// Arrange
|
|
var regularProduct = await CreateRegularProduct();
|
|
var variantProduct = await CreateProductWithVariants();
|
|
var multiBuyProduct = await CreateProductWithMultiBuys();
|
|
|
|
var multiBuy = multiBuyProduct.MultiBuys.First(mb => mb.Quantity == 3);
|
|
|
|
var orderRequest = new CreateOrderDto
|
|
{
|
|
IdentityReference = "test_user_" + Guid.NewGuid(),
|
|
ShippingName = "Alice Johnson",
|
|
ShippingAddress = "321 Mixed St",
|
|
ShippingCity = "Complex City",
|
|
ShippingPostCode = "CC4 4ST",
|
|
ShippingCountry = "United Kingdom",
|
|
Items = new List<CreateOrderItemDto>
|
|
{
|
|
// Regular product
|
|
new()
|
|
{
|
|
ProductId = regularProduct.Id,
|
|
Quantity = 2
|
|
},
|
|
// Product with variant
|
|
new()
|
|
{
|
|
ProductId = variantProduct.Id,
|
|
Quantity = 1,
|
|
SelectedVariant = "Blue"
|
|
},
|
|
// Product with multi-buy
|
|
new()
|
|
{
|
|
ProductId = multiBuyProduct.Id,
|
|
ProductMultiBuyId = multiBuy.Id,
|
|
Quantity = 3
|
|
}
|
|
}
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
|
|
|
|
// Assert
|
|
response.StatusCode.Should().Be(HttpStatusCode.Created);
|
|
|
|
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
|
|
order.Should().NotBeNull();
|
|
order!.Items.Should().HaveCount(3);
|
|
|
|
// Verify total calculation
|
|
var expectedTotal = (regularProduct.Price * 2) +
|
|
variantProduct.Price +
|
|
multiBuy.Price;
|
|
order.TotalAmount.Should().Be(expectedTotal);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetOrder_ShouldIncludeVariantAndMultiBuyInfo()
|
|
{
|
|
// Arrange
|
|
var product = await CreateProductWithMultiBuysAndVariants();
|
|
var multiBuy = product.MultiBuys.First();
|
|
|
|
var orderRequest = new CreateOrderDto
|
|
{
|
|
IdentityReference = "test_user_" + Guid.NewGuid(),
|
|
ShippingName = "Test User",
|
|
ShippingAddress = "Test Address",
|
|
ShippingCity = "Test City",
|
|
ShippingPostCode = "TE1 1ST",
|
|
ShippingCountry = "United Kingdom",
|
|
Items = new List<CreateOrderItemDto>
|
|
{
|
|
new()
|
|
{
|
|
ProductId = product.Id,
|
|
ProductMultiBuyId = multiBuy.Id,
|
|
Quantity = multiBuy.Quantity,
|
|
SelectedVariant = "Chocolate"
|
|
}
|
|
}
|
|
};
|
|
|
|
var createResponse = await _client.PostAsJsonAsync("/api/orders", orderRequest);
|
|
var createdOrder = await createResponse.Content.ReadFromJsonAsync<OrderDto>();
|
|
|
|
// Act
|
|
var getResponse = await _client.GetAsync($"/api/orders/by-identity/{orderRequest.IdentityReference}/{createdOrder!.Id}");
|
|
|
|
// Assert
|
|
getResponse.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
|
|
var retrievedOrder = await getResponse.Content.ReadFromJsonAsync<OrderDto>();
|
|
retrievedOrder.Should().NotBeNull();
|
|
|
|
var item = retrievedOrder!.Items.First();
|
|
item.ProductMultiBuyId.Should().Be(multiBuy.Id);
|
|
item.SelectedVariant.Should().Be("Chocolate");
|
|
}
|
|
|
|
private async Task<ProductDto> CreateRegularProduct()
|
|
{
|
|
var category = await CreateTestCategory();
|
|
|
|
var productDto = new CreateProductDto
|
|
{
|
|
Name = "Regular Product",
|
|
Description = "A regular product without variants",
|
|
Price = 15.00m,
|
|
CategoryId = category.Id,
|
|
Weight = 1.0m,
|
|
WeightUnit = LittleShop.Enums.ProductWeightUnit.Kilograms
|
|
};
|
|
|
|
var response = await _client.PostAsJsonAsync("/api/admin/products", productDto);
|
|
response.EnsureSuccessStatusCode();
|
|
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
|
|
}
|
|
|
|
private async Task<ProductDto> CreateProductWithVariants()
|
|
{
|
|
var product = await CreateRegularProduct();
|
|
|
|
// Add variants
|
|
var variants = new[] { "Red", "Blue", "Green" };
|
|
foreach (var variantName in variants)
|
|
{
|
|
var variantDto = new CreateProductVariantDto
|
|
{
|
|
ProductId = product.Id,
|
|
Name = variantName,
|
|
VariantType = "Color",
|
|
StockLevel = 100
|
|
};
|
|
|
|
await _client.PostAsJsonAsync($"/api/admin/products/{product.Id}/variants", variantDto);
|
|
}
|
|
|
|
// Refresh product to get variants
|
|
var response = await _client.GetAsync($"/api/catalog/products/{product.Id}");
|
|
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
|
|
}
|
|
|
|
private async Task<ProductDto> CreateProductWithMultiBuys()
|
|
{
|
|
var product = await CreateRegularProduct();
|
|
|
|
// Add multi-buys
|
|
var multiBuys = new[]
|
|
{
|
|
new CreateProductMultiBuyDto
|
|
{
|
|
ProductId = product.Id,
|
|
Name = "Twin Pack",
|
|
Quantity = 2,
|
|
Price = 25.00m
|
|
},
|
|
new CreateProductMultiBuyDto
|
|
{
|
|
ProductId = product.Id,
|
|
Name = "Triple Pack",
|
|
Quantity = 3,
|
|
Price = 35.00m
|
|
}
|
|
};
|
|
|
|
foreach (var multiBuyDto in multiBuys)
|
|
{
|
|
await _client.PostAsJsonAsync($"/api/admin/products/{product.Id}/multibuys", multiBuyDto);
|
|
}
|
|
|
|
// Refresh product to get multi-buys
|
|
var response = await _client.GetAsync($"/api/catalog/products/{product.Id}");
|
|
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
|
|
}
|
|
|
|
private async Task<ProductDto> CreateProductWithMultiBuysAndVariants()
|
|
{
|
|
var product = await CreateProductWithMultiBuys();
|
|
|
|
// Add variants
|
|
var variants = new[] { "Vanilla", "Chocolate", "Strawberry" };
|
|
foreach (var variantName in variants)
|
|
{
|
|
var variantDto = new CreateProductVariantDto
|
|
{
|
|
ProductId = product.Id,
|
|
Name = variantName,
|
|
VariantType = "Flavor",
|
|
StockLevel = 50
|
|
};
|
|
|
|
await _client.PostAsJsonAsync($"/api/admin/products/{product.Id}/variants", variantDto);
|
|
}
|
|
|
|
// Refresh product
|
|
var response = await _client.GetAsync($"/api/catalog/products/{product.Id}");
|
|
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
|
|
}
|
|
|
|
private async Task<CategoryDto> CreateTestCategory()
|
|
{
|
|
var categoryDto = new CreateCategoryDto
|
|
{
|
|
Name = "Test Category " + Guid.NewGuid(),
|
|
Description = "Test category for integration tests"
|
|
};
|
|
|
|
var response = await _client.PostAsJsonAsync("/api/admin/categories", categoryDto);
|
|
response.EnsureSuccessStatusCode();
|
|
return (await response.Content.ReadFromJsonAsync<CategoryDto>())!;
|
|
}
|
|
} |