Browse Source

Added order repository tests and specifications

pull/56/head
Galip Tolga Erdem 4 years ago
parent
commit
ea97dafa44
  1. 1
      services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs
  2. 9
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs
  3. 2
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs
  4. 1
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs
  5. 2
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs
  6. 14
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/Last30DaysSpecification.cs
  7. 21
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/MonthsAgoSpecification.cs
  8. 23
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/SpecificationFactory.cs
  9. 20
      services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/YearSpecification.cs
  10. 1
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs
  11. 16
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs
  12. 22
      services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs
  13. 1
      services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs
  14. 39
      services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs
  15. 52
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs
  16. 31
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/Product.cs
  17. 20
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestData.cs
  18. 42
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestProducts.cs
  19. 902
      services/ordering/test/EShopOnAbp.OrderingService.TestBase/products.json

1
services/ordering/src/EShopOnAbp.OrderingService.Application/OrderingServiceApplicationAutoMapperProfile.cs

@ -1,5 +1,4 @@
using AutoMapper;
using EShopOnAbp.OrderingService.Buyers;
using EShopOnAbp.OrderingService.Orders;
using Volo.Abp.AutoMapper;

9
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/IOrderRepository.cs

@ -1,8 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders;
public interface IOrderRepository : IRepository<Order, Guid>
{
Task<List<Order>> GetOrdersByUserId(
Guid userId,
ISpecification<Order> spec,
bool includeDetails = false,
CancellationToken cancellationToken = default);
}

2
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Order.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using EShopOnAbp.OrderingService.Buyers;
using Volo.Abp.Domain.Entities;
namespace EShopOnAbp.OrderingService.Orders;
@ -11,7 +10,6 @@ public class Order : AggregateRoot<Guid>
private int _orderStatusId;
private int _paymentTypeId;
public DateTime OrderDate { get; private set; }
public PaymentType PaymentType { get; private set; }
public Guid? PaymentRequestId { get; private set; }
public string PaymentStatus { get; private set; }

1
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/OrderManager.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Distributed;

2
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/PaymentType.cs

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Volo.Abp;
namespace EShopOnAbp.OrderingService.Buyers;
namespace EShopOnAbp.OrderingService.Orders;
public class PaymentType : Enumeration
{

14
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/Last30DaysSpecification.cs

@ -0,0 +1,14 @@
using System;
using System.Linq.Expressions;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public class Last30DaysSpecification : Specification<Order>
{
public override Expression<Func<Order, bool>> ToExpression()
{
var daysAgo30 = DateTime.Now.AddDays(-30);
return query => query.OrderDate >= daysAgo30 && query.OrderDate <= DateTime.Now;
}
}

21
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/MonthsAgoSpecification.cs

@ -0,0 +1,21 @@
using System;
using System.Linq.Expressions;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public class MonthsAgoSpecification : Specification<Order>
{
protected int NumberOfMonths { get; set; }
public MonthsAgoSpecification(int months)
{
NumberOfMonths = months;
}
public override Expression<Func<Order, bool>> ToExpression()
{
var monthsAgo = DateTime.Now.AddMonths(NumberOfMonths);
return query => query.OrderDate >= monthsAgo && query.OrderDate <= DateTime.Now;
}
}

23
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/SpecificationFactory.cs

@ -0,0 +1,23 @@
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public static class SpecificationFactory
{
public static ISpecification<Order> Create(string filter)
{
if (filter.StartsWith("y"))
{
var year = int.Parse(filter.Split('y')[1]);
return new YearSpecification(year);
}
if (filter.StartsWith("m"))
{
var months = int.Parse(filter.Split('m')[1]);
return new MonthsAgoSpecification(months);
}
return new Last30DaysSpecification();
}
}

20
services/ordering/src/EShopOnAbp.OrderingService.Domain/Orders/Specifications/YearSpecification.cs

@ -0,0 +1,20 @@
using System;
using System.Linq.Expressions;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders.Specifications;
public class YearSpecification : Specification<Order>
{
protected int Year { get; set; }
public YearSpecification(int year)
{
Year = year;
}
public override Expression<Func<Order, bool>> ToExpression()
{
return query => query.OrderDate.Year == Year;
}
}

1
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/EntityFrameworkCore/OrderServiceDataSeedContributor.cs

@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using EShopOnAbp.OrderingService.Orders;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;

16
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/EfCoreOrderRepository.cs

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;
namespace EShopOnAbp.OrderingService.Orders;
@ -25,6 +28,19 @@ public class EfCoreOrderRepository : EfCoreRepository<OrderingServiceDbContext,
return newEntity;
}
public async Task<List<Order>> GetOrdersByUserId(
Guid userId,
ISpecification<Order> spec,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.IncludeDetails(includeDetails)
.Where(q=>q.Buyer.Id == userId)
.Where(spec.ToExpression())
.ToListAsync(GetCancellationToken(cancellationToken));
}
public override async Task<IQueryable<Order>> WithDetailsAsync()
{
return (await GetQueryableAsync())

22
services/ordering/src/EShopOnAbp.OrderingService.EntityFrameworkCore/Orders/OrderEfCoreQueryableExtensions.cs

@ -0,0 +1,22 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace EShopOnAbp.OrderingService.Orders;
public static class OrderEfCoreQueryableExtensions
{
public static IQueryable<Order> IncludeDetails(this IQueryable<Order> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.Address)
.Include(x => x.Buyer)
.Include(x => x.OrderItems)
.Include(x => x.PaymentType)
.Include(x => x.OrderStatus);
}
}

1
services/ordering/test/EShopOnAbp.OrderingService.Domain.Tests/Orders/OrderManager_Tests.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Buyers;
using Shouldly;
using Xunit;

39
services/ordering/test/EShopOnAbp.OrderingService.EntityFrameworkCore.Tests/EntityFrameworkCore/Orders/OrderRepository_Tests.cs

@ -0,0 +1,39 @@
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using EShopOnAbp.OrderingService.Orders.Specifications;
using EShopOnAbp.OrderingService.Samples;
using Microsoft.EntityFrameworkCore;
using Shouldly;
using Xunit;
namespace EShopOnAbp.OrderingService.EntityFrameworkCore.Orders;
public class OrderRepository_Tests : SampleRepository_Tests<OrderingServiceEntityFrameworkCoreTestModule>
{
private readonly TestData _testData;
private readonly IOrderRepository _orderRepository;
private readonly IOrderingServiceDbContext _dbContext;
public OrderRepository_Tests()
{
_dbContext = GetRequiredService<IOrderingServiceDbContext>();
_orderRepository = GetRequiredService<IOrderRepository>();
_testData = GetRequiredService<TestData>();
}
[Fact]
public async Task Should_Get_OrderStatus()
{
var dbSet = _dbContext.Set<OrderStatus>();
var statusList = await dbSet.ToListAsync();
statusList.Count.ShouldNotBe(0);
}
[Fact]
public async Task Should_Get_User_Orders()
{
var orders =
await _orderRepository.GetOrdersByUserId(_testData.CurrentUserId, new Last30DaysSpecification(), true);
orders.Count.ShouldBe(2);
}
}

52
services/ordering/test/EShopOnAbp.OrderingService.TestBase/OrderingServiceDataSeedContributor.cs

@ -1,33 +1,53 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EShopOnAbp.OrderingService.Orders;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
namespace EShopOnAbp.OrderingService
{
public class OrderingServiceDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly IGuidGenerator _guidGenerator;
private readonly ICurrentTenant _currentTenant;
private readonly OrderManager _orderManager;
private readonly TestData _testData;
private readonly TestProducts _testProducts;
public OrderingServiceDataSeedContributor(
IGuidGenerator guidGenerator, ICurrentTenant currentTenant)
OrderManager orderManager,
TestData testData,
TestProducts testProducts)
{
_guidGenerator = guidGenerator;
_currentTenant = currentTenant;
_orderManager = orderManager;
_testData = testData;
_testProducts = testProducts;
}
public Task SeedAsync(DataSeedContext context)
public async Task SeedAsync(DataSeedContext context)
{
/* Instead of returning the Task.CompletedTask, you can insert your test data
* at this point!
*/
await SeedTestOrdersAsync();
}
private async Task SeedTestOrdersAsync()
{
var order1 = await _orderManager.CreateOrderAsync(
1, _testData.CurrentUserId, _testData.CurrentUserName, _testData.CurrentUserEmail,
_testProducts.GetRandomProducts(0),
_testData.Address.Street,
_testData.Address.City,
_testData.Address.Country,
_testData.Address.ZipCode
);
using (_currentTenant.Change(context?.TenantId))
{
return Task.CompletedTask;
}
var order2 = await _orderManager.CreateOrderAsync(
1, _testData.CurrentUserId, _testData.CurrentUserName, _testData.CurrentUserEmail,
_testProducts.GetRandomProducts(10),
_testData.Address.Street,
_testData.Address.City,
_testData.Address.Country,
_testData.Address.ZipCode
);
}
}
}
}

31
services/ordering/test/EShopOnAbp.OrderingService.TestBase/Product.cs

@ -0,0 +1,31 @@
using System;
using System.Text.Json.Serialization;
namespace EShopOnAbp.OrderingService;
public class Product
{
[JsonPropertyName("id")] public int Id { get; set; }
public Guid ProductId
{
get
{
byte[] bytes = new byte[16];
BitConverter.GetBytes(Id).CopyTo(bytes, 0);
return new Guid(bytes);
}
}
[JsonPropertyName("productName")] public string ProductName { get; set; }
[JsonPropertyName("pictureUrl")] public string PictureUrl { get; set; }
[JsonPropertyName("productStock")] public int ProductStock { get; set; }
[JsonPropertyName("unitPrice")] public string UnitPrice { get; set; }
[JsonPropertyName("productSalePrice")] public string ProductSalePrice { get; set; }
[JsonPropertyName("units")] public int Units { get; set; }
}

20
services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestData.cs

@ -0,0 +1,20 @@
using System;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.OrderingService;
public class TestData : ISingletonDependency
{
public string CurrentUserEmail { get; set; } = "galip.erdem@volosoft.com";
public Guid CurrentUserId { get; set; } = Guid.NewGuid();
public string CurrentUserName { get; set; } = "Galip T. ERDEM";
public DemoAddress Address { get; set; } = new DemoAddress();
public class DemoAddress
{
public string Street { get; set; } = "Test Demo Street";
public string City { get; set; } = "DemoCity";
public string Country { get; set; } = "DemoLand";
public string ZipCode { get; set; } = "123-456-789";
}
}

42
services/ordering/test/EShopOnAbp.OrderingService.TestBase/TestProducts.cs

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Volo.Abp.DependencyInjection;
namespace EShopOnAbp.OrderingService;
public class TestProducts : ISingletonDependency
{
private readonly List<Product> _products;
private readonly Random _random = new();
public TestProducts()
{
_products = new List<Product>();
using (StreamReader r = new StreamReader("../../../../EShopOnAbp.OrderingService.TestBase/products.json"))
{
string json = r.ReadToEnd();
_products = JsonConvert.DeserializeObject<List<Product>>(json);
}
}
public List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int units)> GetRandomProducts(int quantity)
{
List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int units)> randomProducts =
new List<(Guid productId, string productName, string productCode, decimal unitPrice, decimal discount,
string pictureUrl, int units)>();
for (int i = 0; i < quantity; i++)
{
int num = _random.Next(_products.Count);
var product = _products[num];
randomProducts.Add((Guid.NewGuid(), product.ProductName, $"Code-{num}", decimal.Parse(product.UnitPrice),
0, product.PictureUrl, product.Units));
}
return randomProducts;
}
}

902
services/ordering/test/EShopOnAbp.OrderingService.TestBase/products.json

@ -0,0 +1,902 @@
[
{
"id": 1000,
"productName": "delightful chocolate Ilise",
"pictureUrl": "https://picsum.photos/400?image=659",
"productStock": 81,
"unitPrice": "23488.67",
"productSalePrice": "23488.67",
"units": 4
},
{
"id": 1001,
"productName": "civilian salmon Delinda",
"pictureUrl": "https://picsum.photos/400?image=261",
"productStock": 66,
"unitPrice": "42992.62",
"productSalePrice": "20636.46",
"units": 2
},
{
"id": 1002,
"productName": "northern chocolate Dagmar",
"pictureUrl": "https://picsum.photos/400?image=921",
"productStock": 58,
"unitPrice": "26956.67",
"productSalePrice": "26956.67",
"units": 4
},
{
"id": 1003,
"productName": "spatial plum Mattie",
"pictureUrl": "https://picsum.photos/400?image=753",
"productStock": 74,
"unitPrice": "32827.45",
"productSalePrice": "32827.45",
"units": 2
},
{
"id": 1004,
"productName": "arrogant tan Nelia",
"pictureUrl": "https://picsum.photos/400?image=924",
"productStock": 85,
"unitPrice": "27379.36",
"productSalePrice": "9308.98",
"units": 4
},
{
"id": 1005,
"productName": "following bronze Misti",
"pictureUrl": "https://picsum.photos/400?image=340",
"productStock": 24,
"unitPrice": "34617.96",
"productSalePrice": "34617.96",
"units": 3
},
{
"id": 1006,
"productName": "continued rose Nesta",
"pictureUrl": "https://picsum.photos/400?image=712",
"productStock": 34,
"unitPrice": "27822.85",
"productSalePrice": "27822.85",
"units": 1
},
{
"id": 1007,
"productName": "sufficient peach Georgiana",
"pictureUrl": "https://picsum.photos/400?image=860",
"productStock": 55,
"unitPrice": "15506.06",
"productSalePrice": "15506.06",
"units": 4
},
{
"id": 1008,
"productName": "frequent sapphire Petronella",
"pictureUrl": "https://picsum.photos/400?image=913",
"productStock": 36,
"unitPrice": "44132.59",
"productSalePrice": "44132.59",
"units": 5
},
{
"id": 1009,
"productName": "indirect indigo Fiona",
"pictureUrl": "https://picsum.photos/400?image=583",
"productStock": 49,
"unitPrice": "40702.21",
"productSalePrice": "4477.24",
"units": 1
},
{
"id": 1010,
"productName": "gross plum Veriee",
"pictureUrl": "https://picsum.photos/400?image=306",
"productStock": 12,
"unitPrice": "42194.21",
"productSalePrice": "42194.21",
"units": 4
},
{
"id": 1011,
"productName": "gigantic red Lissy",
"pictureUrl": "https://picsum.photos/400?image=184",
"productStock": 45,
"unitPrice": "18745.19",
"productSalePrice": "8810.24",
"units": 2
},
{
"id": 1012,
"productName": "blind copper Dionne",
"pictureUrl": "https://picsum.photos/400?image=308",
"productStock": 27,
"unitPrice": "2038.28",
"productSalePrice": "448.42",
"units": 3
},
{
"id": 1013,
"productName": "varied indigo Lizzie",
"pictureUrl": "https://picsum.photos/400?image=453",
"productStock": 97,
"unitPrice": "28245.22",
"productSalePrice": "9603.37",
"units": 4
},
{
"id": 1014,
"productName": "single amaranth Doris",
"pictureUrl": "https://picsum.photos/400?image=325",
"productStock": 21,
"unitPrice": "4200.08",
"productSalePrice": "4200.08",
"units": 2
},
{
"id": 1015,
"productName": "keen maroon Lenette",
"pictureUrl": "https://picsum.photos/400?image=92",
"productStock": 88,
"unitPrice": "2282.88",
"productSalePrice": "2282.88",
"units": 3
},
{
"id": 1016,
"productName": "conservation peach Nari",
"pictureUrl": "https://picsum.photos/400?image=798",
"productStock": 31,
"unitPrice": "45707.28",
"productSalePrice": "45707.28",
"units": 5
},
{
"id": 1017,
"productName": "loyal blush Happy",
"pictureUrl": "https://picsum.photos/400?image=163",
"productStock": 58,
"unitPrice": "40390.62",
"productSalePrice": "16560.15",
"units": 5
},
{
"id": 1018,
"productName": "awkward jade Wini",
"pictureUrl": "https://picsum.photos/400?image=475",
"productStock": 46,
"unitPrice": "4221.73",
"productSalePrice": "4221.73",
"units": 5
},
{
"id": 1019,
"productName": "uncertain cyan Tawsha",
"pictureUrl": "https://picsum.photos/400?image=18",
"productStock": 24,
"unitPrice": "6790.39",
"productSalePrice": "6790.39",
"units": 2
},
{
"id": 1020,
"productName": "partial harlequin Katlin",
"pictureUrl": "https://picsum.photos/400?image=466",
"productStock": 15,
"unitPrice": "9001.19",
"productSalePrice": "3510.47",
"units": 2
},
{
"id": 1021,
"productName": "redundant emerald Allyson",
"pictureUrl": "https://picsum.photos/400?image=110",
"productStock": 59,
"unitPrice": "25272.78",
"productSalePrice": "3032.73",
"units": 4
},
{
"id": 1022,
"productName": "far beige Megan",
"pictureUrl": "https://picsum.photos/400?image=264",
"productStock": 95,
"unitPrice": "33122.53",
"productSalePrice": "33122.53",
"units": 5
},
{
"id": 1023,
"productName": "select tomato Berty",
"pictureUrl": "https://picsum.photos/400?image=316",
"productStock": 57,
"unitPrice": "6265.37",
"productSalePrice": "2819.42",
"units": 5
},
{
"id": 1024,
"productName": "recent harlequin Kally",
"pictureUrl": "https://picsum.photos/400?image=896",
"productStock": 12,
"unitPrice": "30807.26",
"productSalePrice": "9550.25",
"units": 2
},
{
"id": 1025,
"productName": "limited emerald Alethea",
"pictureUrl": "https://picsum.photos/400?image=671",
"productStock": 85,
"unitPrice": "5782.65",
"productSalePrice": "2370.89",
"units": 2
},
{
"id": 1026,
"productName": "initial pink Riane",
"pictureUrl": "https://picsum.photos/400?image=917",
"productStock": 70,
"unitPrice": "34095.19",
"productSalePrice": "34095.19",
"units": 5
},
{
"id": 1027,
"productName": "long yellow Dorey",
"pictureUrl": "https://picsum.photos/400?image=419",
"productStock": 77,
"unitPrice": "24712.30",
"productSalePrice": "24712.30",
"units": 3
},
{
"id": 1028,
"productName": "acute brown Phaidra",
"pictureUrl": "https://picsum.photos/400?image=889",
"productStock": 15,
"unitPrice": "6488.51",
"productSalePrice": "6488.51",
"units": 4
},
{
"id": 1029,
"productName": "accepted orange Harriett",
"pictureUrl": "https://picsum.photos/400?image=719",
"productStock": 41,
"unitPrice": "19609.46",
"productSalePrice": "19609.46",
"units": 2
},
{
"id": 1030,
"productName": "creative amethyst Kali",
"pictureUrl": "https://picsum.photos/400?image=888",
"productStock": 22,
"unitPrice": "26368.88",
"productSalePrice": "12393.37",
"units": 2
},
{
"id": 1031,
"productName": "crooked indigo Karen",
"pictureUrl": "https://picsum.photos/400?image=443",
"productStock": 60,
"unitPrice": "49558.08",
"productSalePrice": "8424.87",
"units": 1
},
{
"id": 1032,
"productName": "operational orange Myrtia",
"pictureUrl": "https://picsum.photos/400?image=649",
"productStock": 61,
"unitPrice": "14925.93",
"productSalePrice": "2238.89",
"units": 3
},
{
"id": 1033,
"productName": "disturbing aqua Natalya",
"pictureUrl": "https://picsum.photos/400?image=554",
"productStock": 78,
"unitPrice": "27159.30",
"productSalePrice": "11950.09",
"units": 5
},
{
"id": 1034,
"productName": "forward green Alis",
"pictureUrl": "https://picsum.photos/400?image=746",
"productStock": 23,
"unitPrice": "27608.78",
"productSalePrice": "27608.78",
"units": 5
},
{
"id": 1035,
"productName": "complicated maroon Esmaria",
"pictureUrl": "https://picsum.photos/400?image=648",
"productStock": 69,
"unitPrice": "3128.23",
"productSalePrice": "938.47",
"units": 4
},
{
"id": 1036,
"productName": "frequent chocolate Michell",
"pictureUrl": "https://picsum.photos/400?image=439",
"productStock": 64,
"unitPrice": "39521.86",
"productSalePrice": "39521.86",
"units": 4
},
{
"id": 1037,
"productName": "inquisitive cyan Janette",
"pictureUrl": "https://picsum.photos/400?image=857",
"productStock": 35,
"unitPrice": "9689.55",
"productSalePrice": "9689.55",
"units": 4
},
{
"id": 1038,
"productName": "regional tomato Melamie",
"pictureUrl": "https://picsum.photos/400?image=48",
"productStock": 20,
"unitPrice": "5948.06",
"productSalePrice": "1605.98",
"units": 4
},
{
"id": 1039,
"productName": "notable maroon Anthe",
"pictureUrl": "https://picsum.photos/400?image=802",
"productStock": 34,
"unitPrice": "49448.68",
"productSalePrice": "49448.68",
"units": 3
},
{
"id": 1040,
"productName": "unfortunate maroon Aileen",
"pictureUrl": "https://picsum.photos/400?image=38",
"productStock": 65,
"unitPrice": "24131.28",
"productSalePrice": "24131.28",
"units": 1
},
{
"id": 1041,
"productName": "illegal black Karylin",
"pictureUrl": "https://picsum.photos/400?image=859",
"productStock": 57,
"unitPrice": "36521.61",
"productSalePrice": "16799.94",
"units": 5
},
{
"id": 1042,
"productName": "diverse crimson Chiquia",
"pictureUrl": "https://picsum.photos/400?image=928",
"productStock": 63,
"unitPrice": "30920.27",
"productSalePrice": "30920.27",
"units": 4
},
{
"id": 1043,
"productName": "coming magenta Siana",
"pictureUrl": "https://picsum.photos/400?image=54",
"productStock": 66,
"unitPrice": "41255.15",
"productSalePrice": "41255.15",
"units": 3
},
{
"id": 1044,
"productName": "psychological maroon Cesya",
"pictureUrl": "https://picsum.photos/400?image=596",
"productStock": 25,
"unitPrice": "20085.00",
"productSalePrice": "7230.60",
"units": 2
},
{
"id": 1045,
"productName": "stingy moccasin Conny",
"pictureUrl": "https://picsum.photos/400?image=399",
"productStock": 95,
"unitPrice": "30494.11",
"productSalePrice": "30494.11",
"units": 4
},
{
"id": 1046,
"productName": "voiceless emerald Sarita",
"pictureUrl": "https://picsum.photos/400?image=695",
"productStock": 48,
"unitPrice": "21625.98",
"productSalePrice": "8001.61",
"units": 3
},
{
"id": 1047,
"productName": "old lime Elvera",
"pictureUrl": "https://picsum.photos/400?image=761",
"productStock": 4,
"unitPrice": "30869.36",
"productSalePrice": "30869.36",
"units": 5
},
{
"id": 1048,
"productName": "grumpy plum Jessica",
"pictureUrl": "https://picsum.photos/400?image=570",
"productStock": 73,
"unitPrice": "35395.72",
"productSalePrice": "11326.63",
"units": 3
},
{
"id": 1049,
"productName": "unknown beige Maddalena",
"pictureUrl": "https://picsum.photos/400?image=784",
"productStock": 11,
"unitPrice": "24573.75",
"productSalePrice": "2457.37",
"units": 4
},
{
"id": 1050,
"productName": "clever rose Karoly",
"pictureUrl": "https://picsum.photos/400?image=500",
"productStock": 81,
"unitPrice": "12289.15",
"productSalePrice": "12289.15",
"units": 4
},
{
"id": 1051,
"productName": "unfortunate tan Maris",
"pictureUrl": "https://picsum.photos/400?image=622",
"productStock": 63,
"unitPrice": "39042.14",
"productSalePrice": "11322.22",
"units": 2
},
{
"id": 1052,
"productName": "statutory emerald Arlyn",
"pictureUrl": "https://picsum.photos/400?image=472",
"productStock": 50,
"unitPrice": "35325.05",
"productSalePrice": "35325.05",
"units": 1
},
{
"id": 1053,
"productName": "dynamic gold Gratiana",
"pictureUrl": "https://picsum.photos/400?image=71",
"productStock": 59,
"unitPrice": "21332.58",
"productSalePrice": "21332.58",
"units": 5
},
{
"id": 1054,
"productName": "spotty cyan Micky",
"pictureUrl": "https://picsum.photos/400?image=471",
"productStock": 78,
"unitPrice": "49952.94",
"productSalePrice": "10490.12",
"units": 2
},
{
"id": 1055,
"productName": "creative peach Loria",
"pictureUrl": "https://picsum.photos/400?image=619",
"productStock": 6,
"unitPrice": "20547.31",
"productSalePrice": "8424.40",
"units": 2
},
{
"id": 1056,
"productName": "dutch peach Em",
"pictureUrl": "https://picsum.photos/400?image=236",
"productStock": 98,
"unitPrice": "42634.53",
"productSalePrice": "19611.88",
"units": 3
},
{
"id": 1057,
"productName": "civilian fuchsia Jackelyn",
"pictureUrl": "https://picsum.photos/400?image=409",
"productStock": 62,
"unitPrice": "21268.92",
"productSalePrice": "21268.92",
"units": 1
},
{
"id": 1058,
"productName": "elderly turquoise Storm",
"pictureUrl": "https://picsum.photos/400?image=270",
"productStock": 68,
"unitPrice": "45826.03",
"productSalePrice": "9623.47",
"units": 4
},
{
"id": 1059,
"productName": "charming jade Emelia",
"pictureUrl": "https://picsum.photos/400?image=696",
"productStock": 36,
"unitPrice": "23535.56",
"productSalePrice": "23535.56",
"units": 4
},
{
"id": 1060,
"productName": "uninterested violet Lind",
"pictureUrl": "https://picsum.photos/400?image=732",
"productStock": 51,
"unitPrice": "18257.20",
"productSalePrice": "18257.20",
"units": 2
},
{
"id": 1061,
"productName": "assistant gray Regine",
"pictureUrl": "https://picsum.photos/400?image=129",
"productStock": 6,
"unitPrice": "31745.83",
"productSalePrice": "31745.83",
"units": 2
},
{
"id": 1062,
"productName": "thick blush Pennie",
"pictureUrl": "https://picsum.photos/400?image=605",
"productStock": 3,
"unitPrice": "3405.51",
"productSalePrice": "3405.51",
"units": 4
},
{
"id": 1063,
"productName": "lovely brown Theressa",
"pictureUrl": "https://picsum.photos/400?image=891",
"productStock": 31,
"unitPrice": "40426.73",
"productSalePrice": "12936.55",
"units": 4
},
{
"id": 1064,
"productName": "smooth plum Robbi",
"pictureUrl": "https://picsum.photos/400?image=690",
"productStock": 18,
"unitPrice": "32980.16",
"productSalePrice": "10883.45",
"units": 2
},
{
"id": 1065,
"productName": "crude cyan Aloysia",
"pictureUrl": "https://picsum.photos/400?image=896",
"productStock": 56,
"unitPrice": "3933.53",
"productSalePrice": "3933.53",
"units": 5
},
{
"id": 1066,
"productName": "prominent turquoise Pattie",
"pictureUrl": "https://picsum.photos/400?image=855",
"productStock": 45,
"unitPrice": "30615.94",
"productSalePrice": "30615.94",
"units": 2
},
{
"id": 1067,
"productName": "daily tan Wenda",
"pictureUrl": "https://picsum.photos/400?image=869",
"productStock": 41,
"unitPrice": "36740.69",
"productSalePrice": "13226.65",
"units": 2
},
{
"id": 1068,
"productName": "primary gold Tera",
"pictureUrl": "https://picsum.photos/400?image=463",
"productStock": 88,
"unitPrice": "25121.63",
"productSalePrice": "25121.63",
"units": 4
},
{
"id": 1069,
"productName": "geographical amethyst Tania",
"pictureUrl": "https://picsum.photos/400?image=14",
"productStock": 79,
"unitPrice": "24384.38",
"productSalePrice": "24384.38",
"units": 2
},
{
"id": 1070,
"productName": "historic salmon Laraine",
"pictureUrl": "https://picsum.photos/400?image=275",
"productStock": 33,
"unitPrice": "46883.08",
"productSalePrice": "46883.08",
"units": 3
},
{
"id": 1071,
"productName": "bare jade Mabelle",
"pictureUrl": "https://picsum.photos/400?image=177",
"productStock": 79,
"unitPrice": "46760.90",
"productSalePrice": "16833.92",
"units": 3
},
{
"id": 1072,
"productName": "tame crimson Natalie",
"pictureUrl": "https://picsum.photos/400?image=152",
"productStock": 48,
"unitPrice": "22356.48",
"productSalePrice": "22356.48",
"units": 2
},
{
"id": 1073,
"productName": "regular harlequin Aigneis",
"pictureUrl": "https://picsum.photos/400?image=523",
"productStock": 8,
"unitPrice": "45933.08",
"productSalePrice": "45933.08",
"units": 5
},
{
"id": 1074,
"productName": "tight red Bernice",
"pictureUrl": "https://picsum.photos/400?image=417",
"productStock": 2,
"unitPrice": "3766.15",
"productSalePrice": "1732.43",
"units": 4
},
{
"id": 1075,
"productName": "ready chocolate Mirelle",
"pictureUrl": "https://picsum.photos/400?image=843",
"productStock": 38,
"unitPrice": "24113.38",
"productSalePrice": "24113.38",
"units": 3
},
{
"id": 1076,
"productName": "secondary red Blythe",
"pictureUrl": "https://picsum.photos/400?image=350",
"productStock": 97,
"unitPrice": "47086.10",
"productSalePrice": "9888.08",
"units": 2
},
{
"id": 1077,
"productName": "known orange Nollie",
"pictureUrl": "https://picsum.photos/400?image=578",
"productStock": 18,
"unitPrice": "30645.75",
"productSalePrice": "30645.75",
"units": 3
},
{
"id": 1078,
"productName": "very indigo Beverie",
"pictureUrl": "https://picsum.photos/400?image=304",
"productStock": 6,
"unitPrice": "36357.98",
"productSalePrice": "36357.98",
"units": 2
},
{
"id": 1079,
"productName": "legislative tan Gracie",
"pictureUrl": "https://picsum.photos/400?image=419",
"productStock": 50,
"unitPrice": "14884.72",
"productSalePrice": "2976.94",
"units": 3
},
{
"id": 1080,
"productName": "husky pink Nicola",
"pictureUrl": "https://picsum.photos/400?image=330",
"productStock": 64,
"unitPrice": "17199.38",
"productSalePrice": "17199.38",
"units": 2
},
{
"id": 1081,
"productName": "hot bronze Bertha",
"pictureUrl": "https://picsum.photos/400?image=571",
"productStock": 8,
"unitPrice": "23919.62",
"productSalePrice": "23919.62",
"units": 2
},
{
"id": 1082,
"productName": "conscious magenta Jessie",
"pictureUrl": "https://picsum.photos/400?image=707",
"productStock": 36,
"unitPrice": "1355.81",
"productSalePrice": "1355.81",
"units": 3
},
{
"id": 1083,
"productName": "shiny silver Tammie",
"pictureUrl": "https://picsum.photos/400?image=531",
"productStock": 55,
"unitPrice": "35674.84",
"productSalePrice": "10702.45",
"units": 4
},
{
"id": 1084,
"productName": "wasteful orange Stephana",
"pictureUrl": "https://picsum.photos/400?image=540",
"productStock": 26,
"unitPrice": "9266.72",
"productSalePrice": "9266.72",
"units": 4
},
{
"id": 1085,
"productName": "accepted coffee Karoly",
"pictureUrl": "https://picsum.photos/400?image=77",
"productStock": 9,
"unitPrice": "40394.96",
"productSalePrice": "8886.89",
"units": 4
},
{
"id": 1086,
"productName": "biological yellow Corene",
"pictureUrl": "https://picsum.photos/400?image=220",
"productStock": 99,
"unitPrice": "40799.67",
"productSalePrice": "12647.90",
"units": 1
},
{
"id": 1087,
"productName": "ugly white Jeanine",
"pictureUrl": "https://picsum.photos/400?image=607",
"productStock": 70,
"unitPrice": "20261.08",
"productSalePrice": "20261.08",
"units": 2
},
{
"id": 1088,
"productName": "above cyan Dredi",
"pictureUrl": "https://picsum.photos/400?image=946",
"productStock": 94,
"unitPrice": "40979.58",
"productSalePrice": "40979.58",
"units": 4
},
{
"id": 1089,
"productName": "stable plum Barbabra",
"pictureUrl": "https://picsum.photos/400?image=994",
"productStock": 30,
"unitPrice": "31625.74",
"productSalePrice": "31625.74",
"units": 5
},
{
"id": 1090,
"productName": "ambitious amber Alayne",
"pictureUrl": "https://picsum.photos/400?image=592",
"productStock": 83,
"unitPrice": "23998.74",
"productSalePrice": "9359.51",
"units": 4
},
{
"id": 1091,
"productName": "nice indigo Steffie",
"pictureUrl": "https://picsum.photos/400?image=644",
"productStock": 3,
"unitPrice": "18201.33",
"productSalePrice": "18201.33",
"units": 4
},
{
"id": 1092,
"productName": "cute ivory Ofilia",
"pictureUrl": "https://picsum.photos/400?image=832",
"productStock": 74,
"unitPrice": "49212.53",
"productSalePrice": "13287.38",
"units": 4
},
{
"id": 1093,
"productName": "fun lime Mallorie",
"pictureUrl": "https://picsum.photos/400?image=614",
"productStock": 65,
"unitPrice": "22883.28",
"productSalePrice": "22883.28",
"units": 2
},
{
"id": 1094,
"productName": "united indigo Silva",
"pictureUrl": "https://picsum.photos/400?image=404",
"productStock": 9,
"unitPrice": "40058.13",
"productSalePrice": "40058.13",
"units": 5
},
{
"id": 1095,
"productName": "pale gold Gwyn",
"pictureUrl": "https://picsum.photos/400?image=250",
"productStock": 74,
"unitPrice": "25333.23",
"productSalePrice": "11653.29",
"units": 2
},
{
"id": 1096,
"productName": "valid amaranth Constanta",
"pictureUrl": "https://picsum.photos/400?image=466",
"productStock": 19,
"unitPrice": "40992.99",
"productSalePrice": "40992.99",
"units": 2
},
{
"id": 1097,
"productName": "symbolic orange Courtney",
"pictureUrl": "https://picsum.photos/400?image=36",
"productStock": 63,
"unitPrice": "32930.92",
"productSalePrice": "32930.92",
"units": 4
},
{
"id": 1098,
"productName": "existing fuchsia Maggy",
"pictureUrl": "https://picsum.photos/400?image=991",
"productStock": 87,
"unitPrice": "29786.00",
"productSalePrice": "14595.14",
"units": 2
},
{
"id": 1099,
"productName": "surprising cyan Gene",
"pictureUrl": "https://picsum.photos/400?image=634",
"productStock": 61,
"unitPrice": "8908.76",
"productSalePrice": "8908.76",
"units": 3
}
]
Loading…
Cancel
Save