Skip to content

買い物かごの取得にカタログから削除済みのアイテムのリストを含める #2756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ public ShoppingApplicationService(
/// <returns>
/// BasketResult : <paramref name="buyerId"/> に対応する買い物かご。
/// CatalogItems : 買い物かごアイテムの一覧。
/// DeletedItemIds : 削除済みのカタログアイテム Id のリスト。
/// </returns>
public async Task<(Basket BasketResult, IReadOnlyList<CatalogItem> CatalogItems)> GetBasketItemsAsync(string buyerId, CancellationToken cancellationToken = default)
public async Task<(Basket BasketResult, IReadOnlyList<CatalogItem> CatalogItems, IReadOnlyList<long> DeletedItemIds)> GetBasketItemsAsync(string buyerId, CancellationToken cancellationToken = default)
{
this.logger.LogDebug(Events.DebugEvent, LogMessages.ShoppingApplicationService_GetBasketItemsAsyncStart, buyerId);

Expand All @@ -75,8 +76,10 @@ public ShoppingApplicationService(
scope.Complete();
}

var deletedCatalogItemIds = catalogItems.Where(item => item.IsDeleted == true).Select(item => item.Id).ToList();

this.logger.LogDebug(Events.DebugEvent, LogMessages.ShoppingApplicationService_GetBasketItemsAsyncEnd, buyerId);
return (BasketResult: basket, CatalogItems: catalogItems);
return (BasketResult: basket, CatalogItems: catalogItems, DeletedItemIds: deletedCatalogItemIds);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,9 @@ public class BasketResponse
/// 買い物かごアイテムのリストを取得または設定します。
/// </summary>
public IList<BasketItemResponse> BasketItems { get; set; } = [];

/// <summary>
/// 削除済みカタログアイテムの Id のリストを取得または設定します。
/// </summary>
public IList<long> DeletedItemIds { get; set; } = [];
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,16 @@ public async Task<IActionResult> GetBasketItemsAsync()
{
var buyerId = this.HttpContext.GetBuyerId();

var (basket, catalogItems) = await this.service.GetBasketItemsAsync(buyerId);
var (basket, catalogItems, deletedCatalogItemIds) = await this.service.GetBasketItemsAsync(buyerId);

var basketResponse = this.basketMapper.Convert(basket);
foreach (var basketItem in basketResponse.BasketItems)
{
basketItem.CatalogItem = this.GetCatalogItemSummary(basketItem.CatalogItemId, catalogItems);
}

basketResponse.DeletedItemIds = deletedCatalogItemIds.ToList();

return this.Ok(basketResponse);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,14 @@
"items": {
"$ref": "#/components/schemas/BasketItemResponse"
}
},
"deletedItemIds": {
"type": "array",
"description": "削除済みカタログアイテムの Id のリストを取得または設定します。\n ",
"items": {
"type": "integer",
"format": "int64"
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,208 @@ public async Task GetBasketItemsAsync_購入者Idに対応する買い物かご
basketRepo.Verify(r => r.AddAsync(It.Is<Basket>(b => b.BuyerId == dummyBuyerId), AnyToken), Times.Once);
}

[Fact]
public async Task GetBasketItemsAsync_買い物かごアイテムに対応するカタログアイテムが削除されている_削除済みアイテムのIDが返却される()
{
// Arrange
var dummyBuyerId = "dummyId";
var deletedCatalogItem1 = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明1", Name = "ダミー商品1", Price = 1000m, ProductCode = "C000000001", Id = 10L, IsDeleted = true };
var deletedCatalogItem2 = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明2", Name = "ダミー商品2", Price = 1000m, ProductCode = "C000000002", Id = 11L, IsDeleted = true };
var existingCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明3", Name = "ダミー商品3", Price = 1000m, ProductCode = "C000000003", Id = 12L };
var catalogItems = new List<CatalogItem>
{
deletedCatalogItem1, deletedCatalogItem2, existingCatalogItem,
};
var basket = new Basket { BuyerId = dummyBuyerId };

var basketRepo = new Mock<IBasketRepository>();
basketRepo
.Setup(r => r.AddAsync(It.IsAny<Basket>(), AnyToken))
.ReturnsAsync(basket);
var orderRepo = Mock.Of<IOrderRepository>();
var orderFactory = Mock.Of<IOrderFactory>();
var catalogRepo = new Mock<ICatalogRepository>();
catalogRepo
.Setup(r => r.FindAsync(It.IsAny<Expression<Func<CatalogItem, bool>>>(), AnyToken))
.ReturnsAsync(catalogItems.AsReadOnly());
var catalogDomainService = Mock.Of<ICatalogDomainService>();
var logger = this.CreateTestLogger<ShoppingApplicationService>();
var service = new ShoppingApplicationService(basketRepo.Object, orderRepo, orderFactory, catalogRepo.Object, catalogDomainService, logger);
var cancellationToken = TestContext.Current.CancellationToken;

// Act
var (basketResult, catalogItemList, deletedItemIds) = await service.GetBasketItemsAsync(dummyBuyerId, cancellationToken);

// Assert
Assert.Collection(
deletedItemIds,
id => Assert.Equal(deletedCatalogItem1.Id, id),
id => Assert.Equal(deletedCatalogItem2.Id, id));
}

[Fact]
public async Task GetBasketItemsAsync_既存の買い物かごの一覧を取得_正しく買い物かごの情報が取得できる()
{
// Arrange
var dummyBuyerId = "dummyId";
var deletedCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明1", Name = "ダミー商品1", Price = 1000m, ProductCode = "C000000001", Id = 10L, IsDeleted = true };
var existingCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明2", Name = "ダミー商品2", Price = 1000m, ProductCode = "C000000002", Id = 11L };
var catalogItems = new List<CatalogItem>
{
deletedCatalogItem, existingCatalogItem,
};
var basket = new Basket { BuyerId = dummyBuyerId };
basket.AddItem(deletedCatalogItem.Id, deletedCatalogItem.Price, 1);
basket.AddItem(existingCatalogItem.Id, existingCatalogItem.Price, 1);
var basketItemList = basket.Items.ToList();

var basketRepo = new Mock<IBasketRepository>();
basketRepo
.Setup(r => r.AddAsync(It.IsAny<Basket>(), AnyToken))
.ReturnsAsync(basket);
var orderRepo = Mock.Of<IOrderRepository>();
var orderFactory = Mock.Of<IOrderFactory>();
var catalogRepo = new Mock<ICatalogRepository>();
catalogRepo
.Setup(r => r.FindAsync(It.IsAny<Expression<Func<CatalogItem, bool>>>(), AnyToken))
.ReturnsAsync(catalogItems.AsReadOnly());
var catalogDomainService = Mock.Of<ICatalogDomainService>();
var logger = this.CreateTestLogger<ShoppingApplicationService>();
var service = new ShoppingApplicationService(basketRepo.Object, orderRepo, orderFactory, catalogRepo.Object, catalogDomainService, logger);
var cancellationToken = TestContext.Current.CancellationToken;

// Act
var (basketResult, catalogItemList, deletedItemIds) = await service.GetBasketItemsAsync(dummyBuyerId, cancellationToken);

// Assert
Assert.Equal(basket.BuyerId, basketResult.BuyerId);
Assert.Collection(
basketResult.Items,
basketItem =>
{
Assert.Equal(basketItemList[0].CatalogItemId, basketItem.CatalogItemId);
Assert.Equal(basketItemList[0].Quantity, basketItem.Quantity);
},
basketItem =>
{
Assert.Equal(basketItemList[1].CatalogItemId, basketItem.CatalogItemId);
Assert.Equal(basketItemList[1].Quantity, basketItem.Quantity);
});
}

[Fact]
public async Task GetBasketItemsAsync_既存の買い物かごの一覧を取得_正しくカタログアイテムの一覧が取得できる()
{
// Arrange
var dummyBuyerId = "dummyId";
var deletedCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明1", Name = "ダミー商品1", Price = 1000m, ProductCode = "C000000001", Id = 10L, IsDeleted = true };
var existingCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明2", Name = "ダミー商品2", Price = 1000m, ProductCode = "C000000002", Id = 11L };
var catalogItems = new List<CatalogItem>
{
deletedCatalogItem, existingCatalogItem,
};
var basket = new Basket { BuyerId = dummyBuyerId };
basket.AddItem(deletedCatalogItem.Id, deletedCatalogItem.Price, 1);
basket.AddItem(existingCatalogItem.Id, existingCatalogItem.Price, 1);

var basketRepo = new Mock<IBasketRepository>();
basketRepo
.Setup(r => r.AddAsync(It.IsAny<Basket>(), AnyToken))
.ReturnsAsync(basket);
var orderRepo = Mock.Of<IOrderRepository>();
var orderFactory = Mock.Of<IOrderFactory>();
var catalogRepo = new Mock<ICatalogRepository>();
catalogRepo
.Setup(r => r.FindAsync(It.IsAny<Expression<Func<CatalogItem, bool>>>(), AnyToken))
.ReturnsAsync(catalogItems.AsReadOnly());
var catalogDomainService = Mock.Of<ICatalogDomainService>();
var logger = this.CreateTestLogger<ShoppingApplicationService>();
var service = new ShoppingApplicationService(basketRepo.Object, orderRepo, orderFactory, catalogRepo.Object, catalogDomainService, logger);
var cancellationToken = TestContext.Current.CancellationToken;

// Act
var (basketResult, catalogItemList, deletedItemIds) = await service.GetBasketItemsAsync(dummyBuyerId, cancellationToken);

// Assert
Assert.Collection(
catalogItemList,
catalogItem =>
{
Assert.Equal(deletedCatalogItem.Id, catalogItem.Id);
Assert.Equal(deletedCatalogItem.IsDeleted, catalogItem.IsDeleted);
},
catalogItem =>
{
Assert.Equal(existingCatalogItem.Id, catalogItem.Id);
Assert.Equal(existingCatalogItem.IsDeleted, catalogItem.IsDeleted);
});
}

[Fact]
public async Task GetBasketItemsAsync_買い物かごの一覧取得時に買い物かごを新規作成_正しく買い物かごの情報が取得できる()
{
// Arrange
var dummyBuyerId = "dummyId";
var deletedCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明1", Name = "ダミー商品1", Price = 1000m, ProductCode = "C000000001", Id = 10L, IsDeleted = true };
var existingCatalogItem = new CatalogItem() { CatalogCategoryId = 100L, CatalogBrandId = 110L, Description = "説明2", Name = "ダミー商品2", Price = 1000m, ProductCode = "C000000002", Id = 11L };
var catalogItems = new List<CatalogItem>
{
deletedCatalogItem, existingCatalogItem,
};
var basket = new Basket { BuyerId = dummyBuyerId };

var basketRepo = new Mock<IBasketRepository>();
basketRepo
.Setup(r => r.AddAsync(It.IsAny<Basket>(), AnyToken))
.ReturnsAsync(basket);
var orderRepo = Mock.Of<IOrderRepository>();
var orderFactory = Mock.Of<IOrderFactory>();
var catalogRepo = new Mock<ICatalogRepository>();
catalogRepo
.Setup(r => r.FindAsync(It.IsAny<Expression<Func<CatalogItem, bool>>>(), AnyToken))
.ReturnsAsync(catalogItems.AsReadOnly());
var catalogDomainService = Mock.Of<ICatalogDomainService>();
var logger = this.CreateTestLogger<ShoppingApplicationService>();
var service = new ShoppingApplicationService(basketRepo.Object, orderRepo, orderFactory, catalogRepo.Object, catalogDomainService, logger);
var cancellationToken = TestContext.Current.CancellationToken;

// Act
var (basketResult, catalogItemList, deletedItemIds) = await service.GetBasketItemsAsync(dummyBuyerId, cancellationToken);

// Assert
Assert.Equal(basket.BuyerId, basketResult.BuyerId);
Assert.Empty(basketResult.Items);
}

[Fact]
public async Task GetBasketItemsAsync_既存の買い物かごの一覧を取得_カタログアイテムの一覧が空のリストになる()
{
// Arrange
var dummyBuyerId = "dummyId";
var basket = new Basket { BuyerId = dummyBuyerId };

var basketRepo = new Mock<IBasketRepository>();
basketRepo
.Setup(r => r.AddAsync(It.IsAny<Basket>(), AnyToken))
.ReturnsAsync(basket);
var orderRepo = Mock.Of<IOrderRepository>();
var orderFactory = Mock.Of<IOrderFactory>();
var catalogRepo = new Mock<ICatalogRepository>();
catalogRepo
.Setup(r => r.FindAsync(It.IsAny<Expression<Func<CatalogItem, bool>>>(), AnyToken))
.ReturnsAsync(new List<CatalogItem>());
var catalogDomainService = Mock.Of<ICatalogDomainService>();
var logger = this.CreateTestLogger<ShoppingApplicationService>();
var service = new ShoppingApplicationService(basketRepo.Object, orderRepo, orderFactory, catalogRepo.Object, catalogDomainService, logger);
var cancellationToken = TestContext.Current.CancellationToken;

// Act
var (basketResult, catalogItemList, deletedItemIds) = await service.GetBasketItemsAsync(dummyBuyerId, cancellationToken);

// Assert
Assert.Empty(catalogItemList);
}

[Theory]
[InlineData(null)]
[InlineData("")]
Expand Down