From dc1d71c0f60484c6fdbd0d5d35ae182d64efe43b Mon Sep 17 00:00:00 2001 From: furiax Date: Fri, 8 Sep 2023 20:37:01 +0200 Subject: [PATCH 01/17] Created the diffrent models needed --- BreweryAPI.Furiax/BreweryAPI.Furiax.sln | 25 +++++++++++ .../BreweryAPI/BreweryAPI.csproj | 14 +++++++ .../Controllers/WeatherForecastController.cs | 33 +++++++++++++++ .../BreweryAPI/Models/BeerModel.cs | 10 +++++ .../BreweryAPI/Models/BrewerModel.cs | 8 ++++ .../BreweryAPI/Models/OrderModel.cs | 10 +++++ .../BreweryAPI/Models/WholesaleBeersModel.cs | 9 ++++ .../BreweryAPI/Models/WholesalerModel.cs | 9 ++++ BreweryAPI.Furiax/BreweryAPI/Program.cs | 25 +++++++++++ .../BreweryAPI/Properties/launchSettings.json | 41 +++++++++++++++++++ .../BreweryAPI/WeatherForecast.cs | 13 ++++++ .../BreweryAPI/appsettings.Development.json | 8 ++++ BreweryAPI.Furiax/BreweryAPI/appsettings.json | 9 ++++ 13 files changed, 214 insertions(+) create mode 100644 BreweryAPI.Furiax/BreweryAPI.Furiax.sln create mode 100644 BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj create mode 100644 BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Program.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Properties/launchSettings.json create mode 100644 BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/appsettings.Development.json create mode 100644 BreweryAPI.Furiax/BreweryAPI/appsettings.json diff --git a/BreweryAPI.Furiax/BreweryAPI.Furiax.sln b/BreweryAPI.Furiax/BreweryAPI.Furiax.sln new file mode 100644 index 0000000..4140123 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI.Furiax.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33712.159 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BreweryAPI", "BreweryAPI\BreweryAPI.csproj", "{A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0E662D2A-8B34-42F4-8EF4-C1090AFEC2AB} + EndGlobalSection +EndGlobal diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj b/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj new file mode 100644 index 0000000..499d259 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..89a29b5 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace BreweryAPI.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs new file mode 100644 index 0000000..f5508b9 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs @@ -0,0 +1,10 @@ +namespace BreweryAPI.Models +{ + public class BeerModel + { + public int BeerId { get; set; } + public string Name { get; set; } + public decimal Price { get; set; } + public int BrewerId { get; set; } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs new file mode 100644 index 0000000..08a6b24 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs @@ -0,0 +1,8 @@ +namespace BreweryAPI.Models +{ + public class BreweryModel + { + public int BreweryId { get; set; } + public string Name { get; set; } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs new file mode 100644 index 0000000..1e376f2 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs @@ -0,0 +1,10 @@ +namespace BreweryAPI.Models +{ + public class OrderModel + { + public int OrderId { get; set; } + public int WholesalerId { get; set; } + public List BeersOrdered { get; set; } + + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs new file mode 100644 index 0000000..d96be16 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs @@ -0,0 +1,9 @@ +namespace BreweryAPI.Models +{ + public class WholesaleBeersModel + { + public int BeerId { get; set; } + public int Inventory { get; set; } + + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs new file mode 100644 index 0000000..bcfb3d1 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs @@ -0,0 +1,9 @@ +namespace BreweryAPI.Models +{ + public class WholesalerModel + { + public int Id { get; set; } + public string Name { get; set; } + public List BeersInStock { get; set; } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Program.cs b/BreweryAPI.Furiax/BreweryAPI/Program.cs new file mode 100644 index 0000000..d7a851e --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Program.cs @@ -0,0 +1,25 @@ +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddControllers(); +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/BreweryAPI.Furiax/BreweryAPI/Properties/launchSettings.json b/BreweryAPI.Furiax/BreweryAPI/Properties/launchSettings.json new file mode 100644 index 0000000..13bdff5 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:52884", + "sslPort": 44332 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5210", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7127;http://localhost:5210", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs b/BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs new file mode 100644 index 0000000..229004d --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace BreweryAPI +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} \ No newline at end of file diff --git a/BreweryAPI.Furiax/BreweryAPI/appsettings.Development.json b/BreweryAPI.Furiax/BreweryAPI/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/appsettings.json b/BreweryAPI.Furiax/BreweryAPI/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} From f10a40e53c4b9e2cc1de56cd3697d2929b752c37 Mon Sep 17 00:00:00 2001 From: furiax Date: Fri, 8 Sep 2023 20:53:39 +0200 Subject: [PATCH 02/17] added the context page --- .../BreweryAPI/BreweryAPI.csproj | 14 ++++++-- .../BreweryAPI/BreweryContext.cs | 19 +++++++++++ .../Controllers/WeatherForecastController.cs | 33 ------------------- .../BreweryAPI/WeatherForecast.cs | 13 -------- 4 files changed, 31 insertions(+), 48 deletions(-) create mode 100644 BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs delete mode 100644 BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs delete mode 100644 BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj b/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj index 499d259..62a591b 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj @@ -7,8 +7,18 @@ - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs new file mode 100644 index 0000000..d5970b7 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs @@ -0,0 +1,19 @@ +using BreweryAPI.Models; +using Microsoft.EntityFrameworkCore; + +namespace BreweryAPI +{ + public class BreweryContext : DbContext + { + public DbSet Breweries { get; set; } + public DbSet Beers { get; set; } + public DbSet Wholesalers { get; set; } + public DbSet WholesaleBeers { get; set; } + public DbSet Orders { get; set; } + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => + optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb; Database=BreweryAPI;Trusted_Connection=True; "); + + } + + +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs deleted file mode 100644 index 89a29b5..0000000 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace BreweryAPI.Controllers -{ - [ApiController] - [Route("[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = new[] - { - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - }; - - private readonly ILogger _logger; - - public WeatherForecastController(ILogger logger) - { - _logger = logger; - } - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - return Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - } - } -} \ No newline at end of file diff --git a/BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs b/BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs deleted file mode 100644 index 229004d..0000000 --- a/BreweryAPI.Furiax/BreweryAPI/WeatherForecast.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace BreweryAPI -{ - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string? Summary { get; set; } - } -} \ No newline at end of file From e6eba3f07b6a3107ebb16f155a89b50630ef7946 Mon Sep 17 00:00:00 2001 From: furiax Date: Sun, 10 Sep 2023 14:48:13 +0200 Subject: [PATCH 03/17] Implemented delete/ build database and fill database with predefined values. --- .../BreweryAPI/BreweryAPI.csproj | 5 +- .../BreweryAPI/BreweryContext.cs | 84 +++++++++++- .../BreweryAPI/Controllers/BeerController.cs | 124 ++++++++++++++++++ .../BreweryAPI/Models/BeerModel.cs | 11 +- .../BreweryAPI/Models/BrewerModel.cs | 5 +- .../BreweryAPI/Models/OrderModel.cs | 10 -- .../BreweryAPI/Models/QuoteModel.cs | 14 ++ .../BreweryAPI/Models/SaleModel.cs | 15 +++ .../BreweryAPI/Models/WholesaleBeersModel.cs | 9 -- .../BreweryAPI/Models/WholesalerModel.cs | 8 +- BreweryAPI.Furiax/BreweryAPI/Program.cs | 15 +++ BreweryAPI.Furiax/BreweryAPI/appsettings.json | 5 +- 12 files changed, 268 insertions(+), 37 deletions(-) create mode 100644 BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs delete mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs delete mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj b/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj index 62a591b..4e732ef 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryAPI.csproj @@ -14,11 +14,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs index d5970b7..f2587ba 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs @@ -5,15 +5,87 @@ namespace BreweryAPI { public class BreweryContext : DbContext { - public DbSet Breweries { get; set; } + public BreweryContext(DbContextOptions options) : base(options) { } + + public DbSet Breweries { get; set; } public DbSet Beers { get; set; } public DbSet Wholesalers { get; set; } - public DbSet WholesaleBeers { get; set; } - public DbSet Orders { get; set; } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => - optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb; Database=BreweryAPI;Trusted_Connection=True; "); + public DbSet Sales { get; set; } + public DbSet Quotes { get; set; } - } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new BreweryModel { Name = "ABInbev", BreweryId = 1}, + new BreweryModel { Name = "Achouffe", BreweryId = 2 }, + new BreweryModel { Name = "Alken Maes", BreweryId = 3 }, + new BreweryModel { Name = "Belle Vue", BreweryId = 4 }, + new BreweryModel { Name = "Duvel-Moortgat", BreweryId = 5 }, + new BreweryModel { Name = "Hoegaarden", BreweryId = 6 }, + new BreweryModel { Name = "Lindemans", BreweryId = 7 }, + new BreweryModel { Name = "Palm", BreweryId = 8 }, + new BreweryModel { Name = "4KNT", BreweryId = 9 } + ); + + modelBuilder.Entity().HasData( + new BeerModel { BeerId = 1, Name = "Jupiler", BrewerId = 1 }, + new BeerModel { BeerId = 2, Name = "Stella Artois", BrewerId = 1 }, + new BeerModel { BeerId = 3, Name = "Leffe Blond", BrewerId = 1 }, + new BeerModel { BeerId = 4, Name = "Leffe Bruin", BrewerId = 1 }, + new BeerModel { BeerId = 5, Name = "Leffe Ruby", BrewerId = 1 }, + new BeerModel { BeerId = 6, Name = "Tripel Karmeliet", BrewerId = 1 }, + new BeerModel { BeerId = 7, Name = "La Chouffe", BrewerId = 2 }, + new BeerModel { BeerId = 8, Name = "Cherry Chouffe", BrewerId = 2 }, + new BeerModel { BeerId = 9, Name = "Houblon Chouffe", BrewerId = 2 }, + new BeerModel { BeerId = 10, Name = "Chouffe Soleil", BrewerId = 2 }, + new BeerModel { BeerId = 11, Name = "Maes Pils", BrewerId = 3 }, + new BeerModel { BeerId = 12, Name = "Cristal", BrewerId = 3 }, + new BeerModel { BeerId = 13, Name = "Grimbergen Blond", BrewerId = 3 }, + new BeerModel { BeerId = 14, Name = "Grimbergen Bruin", BrewerId = 3 }, + new BeerModel { BeerId = 15, Name = "Desperados", BrewerId = 3 }, + new BeerModel { BeerId = 16, Name = "Belle Vue Kriek", BrewerId = 4 }, + new BeerModel { BeerId = 17, Name = "Belle Vue Geuze", BrewerId = 4 }, + new BeerModel { BeerId = 18, Name = "Duvel", BrewerId = 5 }, + new BeerModel { BeerId = 19, Name = "Duvel 6,66", BrewerId = 5 }, + new BeerModel { BeerId = 20, Name = "Vedett", BrewerId = 5 }, + new BeerModel { BeerId = 21, Name = "Maredsous", BrewerId = 5 }, + new BeerModel { BeerId = 22, Name = "Hoegaarden", BrewerId = 6 }, + new BeerModel { BeerId = 23, Name = "Hoegaarden Grand Cru", BrewerId = 6 }, + new BeerModel { BeerId = 24, Name = "Lindemans Kriek", BrewerId = 7 }, + new BeerModel { BeerId = 25, Name = "Lindemans Oude Geuze", BrewerId = 7 }, + new BeerModel { BeerId = 26, Name = "Lindemans Framboise", BrewerId = 7 }, + new BeerModel { BeerId = 27, Name = "Lindemans Pecheresse", BrewerId = 7 }, + new BeerModel { BeerId = 28, Name = "Palm", BrewerId = 8 }, + new BeerModel { BeerId = 29, Name = "Dobbel Palm", BrewerId = 8 }, + new BeerModel { BeerId = 30, Name = "Rodenbach", BrewerId = 8 }, + new BeerModel { BeerId = 31, Name = "Cornet", BrewerId = 8 }, + new BeerModel { BeerId = 32, Name = "Estaminet Pils", BrewerId = 8 }, + new BeerModel { BeerId = 33, Name = "Tripel", BrewerId = 9 }, + new BeerModel { BeerId = 34, Name = "Square B", BrewerId = 9 }, + new BeerModel { BeerId = 35, Name = "Carre C", BrewerId = 9 } + ); + modelBuilder.Entity().HasData( + new WholesalerModel { WholesalerId = 1, Name = "Colruyt" }, + new WholesalerModel { WholesalerId = 2, Name = "Prik & Tik" }, + new WholesalerModel { WholesalerId = 3, Name = "Van Callenberge" }, + new WholesalerModel { WholesalerId = 4, Name = "Dranken Van Remoortel" }, + new WholesalerModel { WholesalerId = 5, Name = "Drinkshop Dullaert" }, + new WholesalerModel { WholesalerId = 6, Name = "Bierland" } + ); + } + public void CreateDatabase() + { + Database.EnsureCreated(); + } + + public void DeleteDatabase() + { + Database.EnsureDeleted(); + } + } } + diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs new file mode 100644 index 0000000..1b99380 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using BreweryAPI; +using BreweryAPI.Models; + +namespace BreweryAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class BeerController : ControllerBase + { + private readonly BreweryContext _context; + + public BeerController(BreweryContext context) + { + _context = context; + } + + // GET: api/Beer + [HttpGet] + public async Task>> GetBeers() + { + if (_context.Beers == null) + { + return NotFound(); + } + return await _context.Beers.ToListAsync(); + } + + // GET: api/Beer/5 + [HttpGet("{id}")] + public async Task> GetBeerModel(int id) + { + if (_context.Beers == null) + { + return NotFound(); + } + var beerModel = await _context.Beers.FindAsync(id); + + if (beerModel == null) + { + return NotFound(); + } + + return beerModel; + } + + // PUT: api/Beer/5 + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPut("{id}")] + public async Task PutBeerModel(int id, BeerModel beerModel) + { + if (id != beerModel.BeerId) + { + return BadRequest(); + } + + _context.Entry(beerModel).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!BeerModelExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // POST: api/Beer + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPost] + public async Task> PostBeerModel(BeerModel beerModel) + { + if (_context.Beers == null) + { + return Problem("Entity set 'BreweryContext.Beers' is null."); + } + _context.Beers.Add(beerModel); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetBeerModel", new { id = beerModel.BeerId }, beerModel); + } + + // DELETE: api/Beer/5 + [HttpDelete("{id}")] + public async Task DeleteBeerModel(int id) + { + if (_context.Beers == null) + { + return NotFound(); + } + var beerModel = await _context.Beers.FindAsync(id); + if (beerModel == null) + { + return NotFound(); + } + + _context.Beers.Remove(beerModel); + await _context.SaveChangesAsync(); + + return NoContent(); + } + + private bool BeerModelExists(int id) + { + return (_context.Beers?.Any(e => e.BeerId == id)).GetValueOrDefault(); + } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs index f5508b9..a38c6b2 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs @@ -1,10 +1,15 @@ -namespace BreweryAPI.Models +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace BreweryAPI.Models { public class BeerModel { + [Key] public int BeerId { get; set; } public string Name { get; set; } - public decimal Price { get; set; } - public int BrewerId { get; set; } + public decimal Price { get; set; } + public int BrewerId { get; set; } + public BreweryModel Brewer { get; set; } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs index 08a6b24..d829125 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs @@ -1,7 +1,10 @@ -namespace BreweryAPI.Models +using System.ComponentModel.DataAnnotations; + +namespace BreweryAPI.Models { public class BreweryModel { + [Key] public int BreweryId { get; set; } public string Name { get; set; } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs deleted file mode 100644 index 1e376f2..0000000 --- a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace BreweryAPI.Models -{ - public class OrderModel - { - public int OrderId { get; set; } - public int WholesalerId { get; set; } - public List BeersOrdered { get; set; } - - } -} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs new file mode 100644 index 0000000..5f45c84 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace BreweryAPI.Models +{ + public class QuoteModel + { + [Key] + public int QuoteId { get; set; } + public int WholeSalerId { get; set; } + public WholesalerModel WholeSaler { get; set; } + public decimal Price { get; set; } + public string Summary { get; set; } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs new file mode 100644 index 0000000..b6a7e22 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; + +namespace BreweryAPI.Models +{ + public class SaleModel + { + [Key] + public int SaleId { get; set; } + public int WholesalerId { get; set; } + public WholesalerModel Wholesaler { get; set; } + public int BeerId { get; set; } + public BeerModel Beer { get; set; } + public int Quantity { get; set; } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs deleted file mode 100644 index d96be16..0000000 --- a/BreweryAPI.Furiax/BreweryAPI/Models/WholesaleBeersModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace BreweryAPI.Models -{ - public class WholesaleBeersModel - { - public int BeerId { get; set; } - public int Inventory { get; set; } - - } -} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs index bcfb3d1..f456572 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs @@ -1,9 +1,11 @@ -namespace BreweryAPI.Models +using System.ComponentModel.DataAnnotations; + +namespace BreweryAPI.Models { public class WholesalerModel { - public int Id { get; set; } + [Key] + public int WholesalerId { get; set; } public string Name { get; set; } - public List BeersInStock { get; set; } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Program.cs b/BreweryAPI.Furiax/BreweryAPI/Program.cs index d7a851e..cf9104f 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Program.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Program.cs @@ -1,8 +1,14 @@ +using BreweryAPI; +using Microsoft.EntityFrameworkCore; + var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); +builder.Services.AddDbContext(opt => + opt.UseSqlServer(builder.Configuration.GetConnectionString("SqlServer")), ServiceLifetime.Scoped); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); @@ -20,6 +26,15 @@ app.UseAuthorization(); +using (var scope = app.Services.CreateScope()) +{ + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.DeleteDatabase(); + dbContext.CreateDatabase(); +} + + + app.MapControllers(); app.Run(); diff --git a/BreweryAPI.Furiax/BreweryAPI/appsettings.json b/BreweryAPI.Furiax/BreweryAPI/appsettings.json index 10f68b8..aa0bf86 100644 --- a/BreweryAPI.Furiax/BreweryAPI/appsettings.json +++ b/BreweryAPI.Furiax/BreweryAPI/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + "SqlServer": "Data Source=(localdb)\\MSSQLLocalDB;Database=BreweryAPI;Integrated Security=True;Encrypt=False;Trust Server Certificate=False" + } } From f7ab4d449b66c79569deb1f018873eda7500f8df Mon Sep 17 00:00:00 2001 From: furiax Date: Sun, 10 Sep 2023 15:21:09 +0200 Subject: [PATCH 04/17] added prices to the prefilled data made some error handling --- .../BreweryAPI/BreweryContext.cs | 137 ++++++++++-------- .../BreweryAPI/Models/BeerModel.cs | 8 +- .../BreweryAPI/Models/BrewerModel.cs | 5 +- .../BreweryAPI/Models/QuoteModel.cs | 14 +- .../BreweryAPI/Models/WholesalerModel.cs | 3 + 5 files changed, 99 insertions(+), 68 deletions(-) diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs index f2587ba..7c21394 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs @@ -17,74 +17,95 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); - modelBuilder.Entity().HasData( - new BreweryModel { Name = "ABInbev", BreweryId = 1}, - new BreweryModel { Name = "Achouffe", BreweryId = 2 }, - new BreweryModel { Name = "Alken Maes", BreweryId = 3 }, - new BreweryModel { Name = "Belle Vue", BreweryId = 4 }, - new BreweryModel { Name = "Duvel-Moortgat", BreweryId = 5 }, - new BreweryModel { Name = "Hoegaarden", BreweryId = 6 }, - new BreweryModel { Name = "Lindemans", BreweryId = 7 }, - new BreweryModel { Name = "Palm", BreweryId = 8 }, - new BreweryModel { Name = "4KNT", BreweryId = 9 } - ); + try + { + modelBuilder.Entity().HasData( + new BreweryModel { Name = "ABInbev", BreweryId = 1 }, + new BreweryModel { Name = "Achouffe", BreweryId = 2 }, + new BreweryModel { Name = "Alken Maes", BreweryId = 3 }, + new BreweryModel { Name = "Belle Vue", BreweryId = 4 }, + new BreweryModel { Name = "Duvel-Moortgat", BreweryId = 5 }, + new BreweryModel { Name = "Hoegaarden", BreweryId = 6 }, + new BreweryModel { Name = "Lindemans", BreweryId = 7 }, + new BreweryModel { Name = "Palm", BreweryId = 8 }, + new BreweryModel { Name = "4KNT", BreweryId = 9 } + ); - modelBuilder.Entity().HasData( - new BeerModel { BeerId = 1, Name = "Jupiler", BrewerId = 1 }, - new BeerModel { BeerId = 2, Name = "Stella Artois", BrewerId = 1 }, - new BeerModel { BeerId = 3, Name = "Leffe Blond", BrewerId = 1 }, - new BeerModel { BeerId = 4, Name = "Leffe Bruin", BrewerId = 1 }, - new BeerModel { BeerId = 5, Name = "Leffe Ruby", BrewerId = 1 }, - new BeerModel { BeerId = 6, Name = "Tripel Karmeliet", BrewerId = 1 }, - new BeerModel { BeerId = 7, Name = "La Chouffe", BrewerId = 2 }, - new BeerModel { BeerId = 8, Name = "Cherry Chouffe", BrewerId = 2 }, - new BeerModel { BeerId = 9, Name = "Houblon Chouffe", BrewerId = 2 }, - new BeerModel { BeerId = 10, Name = "Chouffe Soleil", BrewerId = 2 }, - new BeerModel { BeerId = 11, Name = "Maes Pils", BrewerId = 3 }, - new BeerModel { BeerId = 12, Name = "Cristal", BrewerId = 3 }, - new BeerModel { BeerId = 13, Name = "Grimbergen Blond", BrewerId = 3 }, - new BeerModel { BeerId = 14, Name = "Grimbergen Bruin", BrewerId = 3 }, - new BeerModel { BeerId = 15, Name = "Desperados", BrewerId = 3 }, - new BeerModel { BeerId = 16, Name = "Belle Vue Kriek", BrewerId = 4 }, - new BeerModel { BeerId = 17, Name = "Belle Vue Geuze", BrewerId = 4 }, - new BeerModel { BeerId = 18, Name = "Duvel", BrewerId = 5 }, - new BeerModel { BeerId = 19, Name = "Duvel 6,66", BrewerId = 5 }, - new BeerModel { BeerId = 20, Name = "Vedett", BrewerId = 5 }, - new BeerModel { BeerId = 21, Name = "Maredsous", BrewerId = 5 }, - new BeerModel { BeerId = 22, Name = "Hoegaarden", BrewerId = 6 }, - new BeerModel { BeerId = 23, Name = "Hoegaarden Grand Cru", BrewerId = 6 }, - new BeerModel { BeerId = 24, Name = "Lindemans Kriek", BrewerId = 7 }, - new BeerModel { BeerId = 25, Name = "Lindemans Oude Geuze", BrewerId = 7 }, - new BeerModel { BeerId = 26, Name = "Lindemans Framboise", BrewerId = 7 }, - new BeerModel { BeerId = 27, Name = "Lindemans Pecheresse", BrewerId = 7 }, - new BeerModel { BeerId = 28, Name = "Palm", BrewerId = 8 }, - new BeerModel { BeerId = 29, Name = "Dobbel Palm", BrewerId = 8 }, - new BeerModel { BeerId = 30, Name = "Rodenbach", BrewerId = 8 }, - new BeerModel { BeerId = 31, Name = "Cornet", BrewerId = 8 }, - new BeerModel { BeerId = 32, Name = "Estaminet Pils", BrewerId = 8 }, - new BeerModel { BeerId = 33, Name = "Tripel", BrewerId = 9 }, - new BeerModel { BeerId = 34, Name = "Square B", BrewerId = 9 }, - new BeerModel { BeerId = 35, Name = "Carre C", BrewerId = 9 } - ); + modelBuilder.Entity().HasData( + new BeerModel { BeerId = 1, Name = "Jupiler", BrewerId = 1, Price = 0.71m }, + new BeerModel { BeerId = 2, Name = "Stella Artois", BrewerId = 1, Price = 0.79m }, + new BeerModel { BeerId = 3, Name = "Leffe Blond", BrewerId = 1, Price = 1.52m }, + new BeerModel { BeerId = 4, Name = "Leffe Bruin", BrewerId = 1, Price = 1.52m }, + new BeerModel { BeerId = 5, Name = "Leffe Ruby", BrewerId = 1, Price = 1.66m }, + new BeerModel { BeerId = 6, Name = "Tripel Karmeliet", BrewerId = 1, Price = 1.75m }, + new BeerModel { BeerId = 7, Name = "La Chouffe", BrewerId = 2, Price = 1.95m }, + new BeerModel { BeerId = 8, Name = "Cherry Chouffe", BrewerId = 2, Price = 1.73m }, + new BeerModel { BeerId = 9, Name = "Houblon Chouffe", BrewerId = 2, Price = 1.95m }, + new BeerModel { BeerId = 10, Name = "Chouffe Soleil", BrewerId = 2, Price = 1.55m }, + new BeerModel { BeerId = 11, Name = "Maes Pils", BrewerId = 3, Price = 0.67m }, + new BeerModel { BeerId = 12, Name = "Cristal", BrewerId = 3, Price = 0.73m }, + new BeerModel { BeerId = 13, Name = "Grimbergen Blond", BrewerId = 3, Price = 1.51m }, + new BeerModel { BeerId = 14, Name = "Grimbergen Bruin", BrewerId = 3, Price = 1.51m }, + new BeerModel { BeerId = 15, Name = "Desperados", BrewerId = 3, Price = 2.04m }, + new BeerModel { BeerId = 16, Name = "Belle Vue Kriek", BrewerId = 4, Price = 1.39m }, + new BeerModel { BeerId = 17, Name = "Belle Vue Geuze", BrewerId = 4, Price = 1.31m }, + new BeerModel { BeerId = 18, Name = "Duvel", BrewerId = 5, Price = 1.65m }, + new BeerModel { BeerId = 19, Name = "Duvel 6,66", BrewerId = 5, Price = 1.61m }, + new BeerModel { BeerId = 20, Name = "Vedett", BrewerId = 5, Price = 1.21m }, + new BeerModel { BeerId = 21, Name = "Maredsous Tripel", BrewerId = 5, Price = 1.97m }, + new BeerModel { BeerId = 22, Name = "Hoegaarden", BrewerId = 6, Price = 1.00m }, + new BeerModel { BeerId = 23, Name = "Hoegaarden Grand Cru", BrewerId = 6, Price = 1.92m }, + new BeerModel { BeerId = 24, Name = "Lindemans Kriek", BrewerId = 7, Price = 1.24m }, + new BeerModel { BeerId = 25, Name = "Lindemans Oude Geuze", BrewerId = 7, Price = 0.97m }, + new BeerModel { BeerId = 26, Name = "Lindemans Framboise", BrewerId = 7, Price = 1.49m }, + new BeerModel { BeerId = 27, Name = "Lindemans Pecheresse", BrewerId = 7, Price = 1.41m }, + new BeerModel { BeerId = 28, Name = "Palm", BrewerId = 8, Price = 0.89m }, + new BeerModel { BeerId = 29, Name = "Dobbel Palm", BrewerId = 8, Price = 0.95m }, + new BeerModel { BeerId = 30, Name = "Rodenbach", BrewerId = 8, Price = 1.00m }, + new BeerModel { BeerId = 31, Name = "Cornet", BrewerId = 8, Price = 1.67m }, + new BeerModel { BeerId = 32, Name = "Estaminet Pils", BrewerId = 8, Price = 0.67m }, + new BeerModel { BeerId = 33, Name = "4KNT Tripel", BrewerId = 9, Price = 1.85m }, + new BeerModel { BeerId = 34, Name = "4KNT Square B", BrewerId = 9, Price = 1.85m }, + new BeerModel { BeerId = 35, Name = "4KNT Carre C", BrewerId = 9, Price = 1.85m } + ); - modelBuilder.Entity().HasData( - new WholesalerModel { WholesalerId = 1, Name = "Colruyt" }, - new WholesalerModel { WholesalerId = 2, Name = "Prik & Tik" }, - new WholesalerModel { WholesalerId = 3, Name = "Van Callenberge" }, - new WholesalerModel { WholesalerId = 4, Name = "Dranken Van Remoortel" }, - new WholesalerModel { WholesalerId = 5, Name = "Drinkshop Dullaert" }, - new WholesalerModel { WholesalerId = 6, Name = "Bierland" } - ); + modelBuilder.Entity().HasData( + new WholesalerModel { WholesalerId = 1, Name = "Colruyt" }, + new WholesalerModel { WholesalerId = 2, Name = "Prik & Tik" }, + new WholesalerModel { WholesalerId = 3, Name = "Van Callenberge" }, + new WholesalerModel { WholesalerId = 4, Name = "Dranken Van Remoortel" }, + new WholesalerModel { WholesalerId = 5, Name = "Drinkshop Dullaert" }, + new WholesalerModel { WholesalerId = 6, Name = "Bierland" } + ); + } + catch (Exception ex) + { + Console.WriteLine($"Something went wrong when populating the database: {ex.Message}"); + } } public void CreateDatabase() { - Database.EnsureCreated(); + try + { + Database.EnsureCreated(); + } + catch (Exception ex) + { + Console.WriteLine($"The database could not be created: {ex.Message}"); + } } public void DeleteDatabase() { - Database.EnsureDeleted(); + try + { + Database.EnsureDeleted(); + } + catch ( Exception ex ) + { + Console.WriteLine($"The database could not be deleted: {ex.Message}"); + } } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs index a38c6b2..95a2e7c 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/BeerModel.cs @@ -6,10 +6,14 @@ namespace BreweryAPI.Models public class BeerModel { [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int BeerId { get; set; } + [Required] public string Name { get; set; } + [Required] public decimal Price { get; set; } + [Required] public int BrewerId { get; set; } - public BreweryModel Brewer { get; set; } - } + public BreweryModel Brewer { get; set; } + } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs index d829125..37e08ba 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/BrewerModel.cs @@ -1,11 +1,14 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace BreweryAPI.Models { public class BreweryModel { [Key] - public int BreweryId { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int BreweryId { get; set; } + [Required] public string Name { get; set; } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs index 5f45c84..67c8442 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs @@ -4,11 +4,11 @@ namespace BreweryAPI.Models { public class QuoteModel { - [Key] - public int QuoteId { get; set; } - public int WholeSalerId { get; set; } - public WholesalerModel WholeSaler { get; set; } - public decimal Price { get; set; } - public string Summary { get; set; } - } + [Key] + public int QuoteId { get; set; } + public int WholeSalerId { get; set; } + public WholesalerModel WholeSaler { get; set; } + public decimal Price { get; set; } + public string Summary { get; set; } + } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs index f456572..ba6c569 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/WholesalerModel.cs @@ -1,11 +1,14 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace BreweryAPI.Models { public class WholesalerModel { [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int WholesalerId { get; set; } + [Required] public string Name { get; set; } } } From 17769479a23a94ea1b0f1336c890d448b0400d9f Mon Sep 17 00:00:00 2001 From: furiax Date: Mon, 11 Sep 2023 14:38:46 +0200 Subject: [PATCH 05/17] added the GetBeersByBrewer --- .../BreweryAPI/Controllers/BeerController.cs | 252 ++++++++++-------- 1 file changed, 134 insertions(+), 118 deletions(-) diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs index 1b99380..5e7e334 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs @@ -1,124 +1,140 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using BreweryAPI.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using BreweryAPI; -using BreweryAPI.Models; namespace BreweryAPI.Controllers { - [Route("api/[controller]")] - [ApiController] - public class BeerController : ControllerBase - { - private readonly BreweryContext _context; - - public BeerController(BreweryContext context) - { - _context = context; - } - - // GET: api/Beer - [HttpGet] - public async Task>> GetBeers() - { - if (_context.Beers == null) - { - return NotFound(); - } - return await _context.Beers.ToListAsync(); - } - - // GET: api/Beer/5 - [HttpGet("{id}")] - public async Task> GetBeerModel(int id) - { - if (_context.Beers == null) - { - return NotFound(); - } - var beerModel = await _context.Beers.FindAsync(id); - - if (beerModel == null) - { - return NotFound(); - } - - return beerModel; - } - - // PUT: api/Beer/5 - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 - [HttpPut("{id}")] - public async Task PutBeerModel(int id, BeerModel beerModel) - { - if (id != beerModel.BeerId) - { - return BadRequest(); - } - - _context.Entry(beerModel).State = EntityState.Modified; - - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException) - { - if (!BeerModelExists(id)) - { - return NotFound(); - } - else - { - throw; - } - } - - return NoContent(); - } - - // POST: api/Beer - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 - [HttpPost] - public async Task> PostBeerModel(BeerModel beerModel) - { - if (_context.Beers == null) - { - return Problem("Entity set 'BreweryContext.Beers' is null."); - } - _context.Beers.Add(beerModel); - await _context.SaveChangesAsync(); - - return CreatedAtAction("GetBeerModel", new { id = beerModel.BeerId }, beerModel); - } - - // DELETE: api/Beer/5 - [HttpDelete("{id}")] - public async Task DeleteBeerModel(int id) - { - if (_context.Beers == null) - { - return NotFound(); - } - var beerModel = await _context.Beers.FindAsync(id); - if (beerModel == null) - { - return NotFound(); - } - - _context.Beers.Remove(beerModel); - await _context.SaveChangesAsync(); - - return NoContent(); - } - - private bool BeerModelExists(int id) - { - return (_context.Beers?.Any(e => e.BeerId == id)).GetValueOrDefault(); - } - } + [Route("api/[controller]")] + [ApiController] + public class BeerController : ControllerBase + { + private readonly BreweryContext _context; + + public BeerController(BreweryContext context) + { + _context = context; + } + + // GET: api/BeersByBrewer + [HttpGet("BeersByBrewer/{brewerId}")] + public async Task>> GetBeersByBrewer(int brewerId) + { + if (_context.Beers == null) + { + return NotFound(); + } + var beersByBrewer = await _context.Beers + .Where(beer => beer.BrewerId == brewerId) + .ToListAsync(); + + if (beersByBrewer == null || beersByBrewer.Count == 0) + { + return NotFound(); + } + + return beersByBrewer; + } + + // GET: api/Beer + [HttpGet] + public async Task>> GetBeers() + { + if (_context.Beers == null) + { + return NotFound(); + } + return await _context.Beers.ToListAsync(); + } + + + + // GET: api/Beer/5 + [HttpGet("{id}")] + public async Task> GetBeerModel(int id) + { + if (_context.Beers == null) + { + return NotFound(); + } + var beerModel = await _context.Beers.FindAsync(id); + + if (beerModel == null) + { + return NotFound(); + } + + return beerModel; + } + + // PUT: api/Beer/5 + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPut("{id}")] + public async Task PutBeerModel(int id, BeerModel beerModel) + { + if (id != beerModel.BeerId) + { + return BadRequest(); + } + + _context.Entry(beerModel).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!BeerModelExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // POST: api/Beer + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPost] + public async Task> PostBeerModel(BeerModel beerModel) + { + if (_context.Beers == null) + { + return Problem("Entity set 'BreweryContext.Beers' is null."); + } + _context.Beers.Add(beerModel); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetBeerModel", new { id = beerModel.BeerId }, beerModel); + } + + // DELETE: api/Beer/5 + [HttpDelete("{id}")] + public async Task DeleteBeerModel(int id) + { + if (_context.Beers == null) + { + return NotFound(); + } + var beerModel = await _context.Beers.FindAsync(id); + if (beerModel == null) + { + return NotFound(); + } + + _context.Beers.Remove(beerModel); + await _context.SaveChangesAsync(); + + return NoContent(); + } + + private bool BeerModelExists(int id) + { + return (_context.Beers?.Any(e => e.BeerId == id)).GetValueOrDefault(); + } + } } From da736e19f0901af398c6dce17e9e6f4703267fac Mon Sep 17 00:00:00 2001 From: furiax Date: Mon, 11 Sep 2023 19:52:10 +0200 Subject: [PATCH 06/17] adjusted the get, put and post methods so it correctly displays all values --- .../BreweryAPI/Controllers/BeerController.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs index 5e7e334..08e9fd4 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs @@ -25,6 +25,7 @@ public async Task>> GetBeersByBrewer(int bre } var beersByBrewer = await _context.Beers .Where(beer => beer.BrewerId == brewerId) + .Include(b => b.Brewer) .ToListAsync(); if (beersByBrewer == null || beersByBrewer.Count == 0) @@ -43,7 +44,8 @@ public async Task>> GetBeers() { return NotFound(); } - return await _context.Beers.ToListAsync(); + return await _context.Beers.Include(b => b.Brewer).ToListAsync(); + } @@ -56,7 +58,7 @@ public async Task> GetBeerModel(int id) { return NotFound(); } - var beerModel = await _context.Beers.FindAsync(id); + var beerModel = await _context.Beers.Include(b => b.Brewer).FirstOrDefaultAsync(b => b.BeerId == id); if (beerModel == null) { @@ -69,14 +71,22 @@ public async Task> GetBeerModel(int id) // PUT: api/Beer/5 // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPut("{id}")] - public async Task PutBeerModel(int id, BeerModel beerModel) + public async Task PutBeerModel(int id, BeerModel updatedBeerModel) { - if (id != beerModel.BeerId) + if (id != updatedBeerModel.BeerId) { return BadRequest(); } - _context.Entry(beerModel).State = EntityState.Modified; + var existingBrewery = await _context.Breweries.FindAsync(updatedBeerModel.BrewerId); + if (existingBrewery == null) + { + return NotFound("Brewery not found."); + } + + updatedBeerModel.Brewer = existingBrewery; + + _context.Entry(updatedBeerModel).State = EntityState.Modified; try { @@ -102,10 +112,19 @@ public async Task PutBeerModel(int id, BeerModel beerModel) [HttpPost] public async Task> PostBeerModel(BeerModel beerModel) { - if (_context.Beers == null) + if (_context.Beers == null || _context.Breweries == null) + { + return Problem("Entity set 'BreweryContext.Beers' or 'BreweryContext.Breweries' is null."); + } + + var existingBrewery = await _context.Breweries.FindAsync(beerModel.BrewerId); + if (existingBrewery == null) { - return Problem("Entity set 'BreweryContext.Beers' is null."); + return NotFound("Brewery not found."); } + + beerModel.Brewer = existingBrewery; + _context.Beers.Add(beerModel); await _context.SaveChangesAsync(); From 16fa785008dea3f9395a197caa1929840997c708 Mon Sep 17 00:00:00 2001 From: furiax Date: Mon, 11 Sep 2023 20:52:53 +0200 Subject: [PATCH 07/17] Created and modified the Sales GET/POST/PUT --- .../BreweryAPI/Controllers/BeerController.cs | 8 +- .../BreweryAPI/Controllers/SalesController.cs | 167 ++++++++++++++++++ .../BreweryAPI/Models/SaleModel.cs | 7 +- 3 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs index 08e9fd4..fc5c467 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs @@ -4,7 +4,7 @@ namespace BreweryAPI.Controllers { - [Route("api/[controller]")] + [Route("Beer")] [ApiController] public class BeerController : ControllerBase { @@ -48,8 +48,6 @@ public async Task>> GetBeers() } - - // GET: api/Beer/5 [HttpGet("{id}")] public async Task> GetBeerModel(int id) @@ -81,7 +79,7 @@ public async Task PutBeerModel(int id, BeerModel updatedBeerModel var existingBrewery = await _context.Breweries.FindAsync(updatedBeerModel.BrewerId); if (existingBrewery == null) { - return NotFound("Brewery not found."); + return NotFound("That brewery doesn't exist"); } updatedBeerModel.Brewer = existingBrewery; @@ -153,7 +151,7 @@ public async Task DeleteBeerModel(int id) private bool BeerModelExists(int id) { - return (_context.Beers?.Any(e => e.BeerId == id)).GetValueOrDefault(); + return (_context.Beers?.Any(b => b.BeerId == id)).GetValueOrDefault(); } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs new file mode 100644 index 0000000..cce7847 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using BreweryAPI; +using BreweryAPI.Models; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace BreweryAPI.Controllers +{ + [Route("Sales")] + [ApiController] + public class SalesController : ControllerBase + { + private readonly BreweryContext _context; + + public SalesController(BreweryContext context) + { + _context = context; + } + + // GET: api/Sales + [HttpGet] + public async Task>> GetSales() + { + if (_context.Sales == null) + { + return NotFound(); + } + return await _context.Sales + .Include(w => w.Wholesaler) + .Include(b => b.Beer) + .Include(br => br.Beer.Brewer) + .ToListAsync(); + } + + // GET: api/Sales/5 + [HttpGet("{id}")] + public async Task> GetSaleModel(int id) + { + if (_context.Sales == null) + { + return NotFound(); + } + var saleModel = await _context.Sales + .Include(w => w.Wholesaler) + .Include(b => b.Beer) + .Include(br => br.Beer.Brewer) + .FirstOrDefaultAsync(s => s.SaleId == id); + + if (saleModel == null) + { + return NotFound(); + } + + return saleModel; + } + + // PUT: api/Sales/5 + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPut("{id}")] + public async Task PutSaleModel(int id, SaleModel updatedSaleModel) + { + if (id != updatedSaleModel.SaleId) + { + return BadRequest(); + } + + _context.Entry(updatedSaleModel).State = EntityState.Modified; + + var existingWholesaler = await _context.Wholesalers.FindAsync(updatedSaleModel.WholesalerId); + if (existingWholesaler == null) + { + return NotFound("The wholesaler found with that id."); + } + updatedSaleModel.Wholesaler = existingWholesaler; + + var existingBeer = await _context.Beers + .Include(br => br.Brewer) + .FirstOrDefaultAsync(b => b.BeerId == updatedSaleModel.BeerId); + if (existingBeer == null) + { + return NotFound("A beer with that id doesn't exist."); + } + updatedSaleModel.Beer = existingBeer; + + _context.Entry(updatedSaleModel).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!SaleModelExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // POST: api/Sales + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPost] + public async Task> PostSaleModel(SaleModel saleModel) + { + if (_context.Sales == null) + { + return Problem("Entity set 'BreweryContext.Sales' is null."); + } + var existingWholesaler = await _context.Wholesalers.FindAsync(saleModel.WholesalerId); + if (existingWholesaler == null) + { + return NotFound("No Wholesaler found with that id."); + } + saleModel.Wholesaler = existingWholesaler; + + var existingBeer = await _context.Beers + .Include(br => br.Brewer) + .FirstOrDefaultAsync(b => b.BeerId == saleModel.BeerId); + if (existingBeer == null) + { + return NotFound("No beer found with that id."); + } + saleModel.Beer = existingBeer; + + _context.Sales.Add(saleModel); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetSaleModel", new { id = saleModel.SaleId }, saleModel); + } + +// DELETE: api/Sales/5 +[HttpDelete("{id}")] + public async Task DeleteSaleModel(int id) + { + if (_context.Sales == null) + { + return NotFound(); + } + var saleModel = await _context.Sales.FindAsync(id); + if (saleModel == null) + { + return NotFound(); + } + + _context.Sales.Remove(saleModel); + await _context.SaveChangesAsync(); + + return NoContent(); + } + + private bool SaleModelExists(int id) + { + return (_context.Sales?.Any(e => e.SaleId == id)).GetValueOrDefault(); + } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs index b6a7e22..8d726e0 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/SaleModel.cs @@ -1,15 +1,20 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace BreweryAPI.Models { public class SaleModel { [Key] - public int SaleId { get; set; } + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int SaleId { get; set; } + [Required] public int WholesalerId { get; set; } public WholesalerModel Wholesaler { get; set; } + [Required] public int BeerId { get; set; } public BeerModel Beer { get; set; } + [Required] public int Quantity { get; set; } } } From 119c7e24088be55f720deb4244f56cd4fe0a34bf Mon Sep 17 00:00:00 2001 From: furiax Date: Mon, 11 Sep 2023 21:01:19 +0200 Subject: [PATCH 08/17] Added some sales to contextpage for test purposes --- BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs index 7c21394..5cf40c2 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs @@ -72,11 +72,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity().HasData( new WholesalerModel { WholesalerId = 1, Name = "Colruyt" }, new WholesalerModel { WholesalerId = 2, Name = "Prik & Tik" }, - new WholesalerModel { WholesalerId = 3, Name = "Van Callenberge" }, + new WholesalerModel { WholesalerId = 3, Name = "Drankenhal Van Callenberge" }, new WholesalerModel { WholesalerId = 4, Name = "Dranken Van Remoortel" }, new WholesalerModel { WholesalerId = 5, Name = "Drinkshop Dullaert" }, new WholesalerModel { WholesalerId = 6, Name = "Bierland" } ); + + modelBuilder.Entity().HasData( + new SaleModel { SaleId = 1, WholesalerId = 3, BeerId = 1, Quantity = 240 }, + new SaleModel { SaleId = 2, WholesalerId = 3, BeerId = 18, Quantity = 240 }, + new SaleModel { SaleId = 3, WholesalerId = 3, BeerId = 33, Quantity = 24 }, + new SaleModel { SaleId = 4, WholesalerId = 3, BeerId = 28, Quantity = 120 }, + new SaleModel { SaleId = 5, WholesalerId = 3, BeerId = 22, Quantity = 36 }, + new SaleModel { SaleId = 6, WholesalerId = 3, BeerId = 11, Quantity = 200 }, + new SaleModel { SaleId = 7, WholesalerId = 3, BeerId = 31, Quantity = 180 }, + new SaleModel { SaleId = 8, WholesalerId = 3, BeerId = 2, Quantity = 96 } + ); } catch (Exception ex) { From 6a19ab837d6896911c92ba24c62d41cb6340e15d Mon Sep 17 00:00:00 2001 From: furiax Date: Tue, 12 Sep 2023 11:50:05 +0200 Subject: [PATCH 09/17] addressed all possible errors in post quote --- .../BreweryAPI/BreweryContext.cs | 2 +- .../Controllers/QuotesController.cs | 74 +++++ .../BreweryAPI/Controllers/SalesController.cs | 305 +++++++++--------- .../BreweryAPI/Models/OrderListModel.cs | 10 + .../BreweryAPI/Models/OrderModel.cs | 18 ++ .../BreweryAPI/Models/QuoteModel.cs | 10 +- BreweryAPI.Furiax/BreweryAPI/Program.cs | 2 - 7 files changed, 259 insertions(+), 162 deletions(-) create mode 100644 BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/OrderListModel.cs create mode 100644 BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs index 5cf40c2..da295ea 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs @@ -13,7 +13,7 @@ public BreweryContext(DbContextOptions options) : base(options) public DbSet Sales { get; set; } public DbSet Quotes { get; set; } - protected override void OnModelCreating(ModelBuilder modelBuilder) + protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs new file mode 100644 index 0000000..0011fce --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs @@ -0,0 +1,74 @@ +using BreweryAPI.Models; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace BreweryAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class QuotesController : ControllerBase + { + private readonly BreweryContext _context; + + public QuotesController(BreweryContext context) + { + _context = context; + } + + // POST: api/Quotes + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPost] + public async Task> RequestQuote(QuoteModel quoteModel) + { + + try + { + //check if model isnt empty + if (quoteModel == null) + { + return BadRequest("Order cannot be empty"); + } + + //check if the wholesaler exist + var wholesalerExisting = await _context.Wholesalers.FindAsync(quoteModel.WholeSalerId); + if (wholesalerExisting == null) + { + return NotFound("Wholesaler doesn't exist"); + } + + //check for duplicates + if(quoteModel.Orders.GroupBy(ord => ord.BeerId).Any(cnt => cnt.Count() >1)) + { + return BadRequest("There can't be any duplicates in the order"); + } + + + foreach (var item in quoteModel.Orders) + { + var isBeerBeingSold = await _context.Sales.FirstOrDefaultAsync(s => s.BeerId == item.BeerId && s.WholesalerId == quoteModel.WholeSalerId); + if (isBeerBeingSold == null) + { + return NotFound("The wholesaler does not sell all items from your list"); + } + + var isStockHighEnough = await _context.Sales.FirstOrDefaultAsync(s => s.BeerId == item.BeerId && s.WholesalerId == quoteModel.WholeSalerId && s.Quantity > item.Quantity); + if (isStockHighEnough == null) + { + return NotFound("The wholesaler does not have enough stock to fullfill your order"); + } + + } + + + _context.Quotes.Add(quoteModel); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetQuoteModel", quoteModel); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs index cce7847..5802b26 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs @@ -1,167 +1,160 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using BreweryAPI.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using BreweryAPI; -using BreweryAPI.Models; -using Microsoft.AspNetCore.Mvc.RazorPages; namespace BreweryAPI.Controllers { - [Route("Sales")] - [ApiController] - public class SalesController : ControllerBase - { - private readonly BreweryContext _context; - - public SalesController(BreweryContext context) - { - _context = context; - } - - // GET: api/Sales - [HttpGet] - public async Task>> GetSales() - { - if (_context.Sales == null) - { - return NotFound(); - } + [Route("Sales")] + [ApiController] + public class SalesController : ControllerBase + { + private readonly BreweryContext _context; + + public SalesController(BreweryContext context) + { + _context = context; + } + + // GET: api/Sales + [HttpGet] + public async Task>> GetSales() + { + if (_context.Sales == null) + { + return NotFound(); + } return await _context.Sales - .Include(w => w.Wholesaler) - .Include(b => b.Beer) - .Include(br => br.Beer.Brewer) - .ToListAsync(); - } - - // GET: api/Sales/5 - [HttpGet("{id}")] - public async Task> GetSaleModel(int id) - { - if (_context.Sales == null) - { - return NotFound(); - } - var saleModel = await _context.Sales .Include(w => w.Wholesaler) .Include(b => b.Beer) .Include(br => br.Beer.Brewer) - .FirstOrDefaultAsync(s => s.SaleId == id); - - if (saleModel == null) - { - return NotFound(); - } - - return saleModel; - } - - // PUT: api/Sales/5 - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 - [HttpPut("{id}")] - public async Task PutSaleModel(int id, SaleModel updatedSaleModel) - { - if (id != updatedSaleModel.SaleId) - { - return BadRequest(); - } - - _context.Entry(updatedSaleModel).State = EntityState.Modified; - - var existingWholesaler = await _context.Wholesalers.FindAsync(updatedSaleModel.WholesalerId); - if (existingWholesaler == null) - { - return NotFound("The wholesaler found with that id."); - } - updatedSaleModel.Wholesaler = existingWholesaler; - - var existingBeer = await _context.Beers - .Include(br => br.Brewer) - .FirstOrDefaultAsync(b => b.BeerId == updatedSaleModel.BeerId); + .ToListAsync(); + } + + // GET: api/Sales/5 + [HttpGet("{id}")] + public async Task> GetSaleModel(int id) + { + if (_context.Sales == null) + { + return NotFound(); + } + var saleModel = await _context.Sales + .Include(w => w.Wholesaler) + .Include(b => b.Beer) + .Include(br => br.Beer.Brewer) + .FirstOrDefaultAsync(s => s.SaleId == id); + + if (saleModel == null) + { + return NotFound(); + } + + return saleModel; + } + + // PUT: api/Sales/5 + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPut("{id}")] + public async Task PutSaleModel(int id, SaleModel updatedSaleModel) + { + if (id != updatedSaleModel.SaleId) + { + return BadRequest(); + } + + _context.Entry(updatedSaleModel).State = EntityState.Modified; + + var existingWholesaler = await _context.Wholesalers.FindAsync(updatedSaleModel.WholesalerId); + if (existingWholesaler == null) + { + return NotFound("The wholesaler found with that id."); + } + updatedSaleModel.Wholesaler = existingWholesaler; + + var existingBeer = await _context.Beers + .Include(br => br.Brewer) + .FirstOrDefaultAsync(b => b.BeerId == updatedSaleModel.BeerId); + if (existingBeer == null) + { + return NotFound("A beer with that id doesn't exist."); + } + updatedSaleModel.Beer = existingBeer; + + _context.Entry(updatedSaleModel).State = EntityState.Modified; + + try + { + await _context.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!SaleModelExists(id)) + { + return NotFound(); + } + else + { + throw; + } + } + + return NoContent(); + } + + // POST: api/Sales + // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 + [HttpPost] + public async Task> PostSaleModel(SaleModel saleModel) + { + if (_context.Sales == null) + { + return Problem("Entity set 'BreweryContext.Sales' is null."); + } + var existingWholesaler = await _context.Wholesalers.FindAsync(saleModel.WholesalerId); + if (existingWholesaler == null) + { + return NotFound("No Wholesaler found with that id."); + } + saleModel.Wholesaler = existingWholesaler; + + var existingBeer = await _context.Beers + .Include(br => br.Brewer) + .FirstOrDefaultAsync(b => b.BeerId == saleModel.BeerId); if (existingBeer == null) - { - return NotFound("A beer with that id doesn't exist."); - } - updatedSaleModel.Beer = existingBeer; - - _context.Entry(updatedSaleModel).State = EntityState.Modified; - - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException) - { - if (!SaleModelExists(id)) - { - return NotFound(); - } - else - { - throw; - } - } - - return NoContent(); - } - - // POST: api/Sales - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 - [HttpPost] - public async Task> PostSaleModel(SaleModel saleModel) - { - if (_context.Sales == null) - { - return Problem("Entity set 'BreweryContext.Sales' is null."); - } - var existingWholesaler = await _context.Wholesalers.FindAsync(saleModel.WholesalerId); - if (existingWholesaler == null) - { - return NotFound("No Wholesaler found with that id."); - } - saleModel.Wholesaler = existingWholesaler; - - var existingBeer = await _context.Beers - .Include(br => br.Brewer) - .FirstOrDefaultAsync(b => b.BeerId == saleModel.BeerId); - if (existingBeer == null) - { - return NotFound("No beer found with that id."); - } - saleModel.Beer = existingBeer; - - _context.Sales.Add(saleModel); - await _context.SaveChangesAsync(); - - return CreatedAtAction("GetSaleModel", new { id = saleModel.SaleId }, saleModel); - } - -// DELETE: api/Sales/5 -[HttpDelete("{id}")] - public async Task DeleteSaleModel(int id) - { - if (_context.Sales == null) - { - return NotFound(); - } - var saleModel = await _context.Sales.FindAsync(id); - if (saleModel == null) - { - return NotFound(); - } - - _context.Sales.Remove(saleModel); - await _context.SaveChangesAsync(); - - return NoContent(); - } - - private bool SaleModelExists(int id) - { - return (_context.Sales?.Any(e => e.SaleId == id)).GetValueOrDefault(); - } - } + { + return NotFound("No beer found with that id."); + } + saleModel.Beer = existingBeer; + + _context.Sales.Add(saleModel); + await _context.SaveChangesAsync(); + + return CreatedAtAction("GetSaleModel", new { id = saleModel.SaleId }, saleModel); + } + + // DELETE: api/Sales/5 + [HttpDelete("{id}")] + public async Task DeleteSaleModel(int id) + { + if (_context.Sales == null) + { + return NotFound(); + } + var saleModel = await _context.Sales.FindAsync(id); + if (saleModel == null) + { + return NotFound(); + } + + _context.Sales.Remove(saleModel); + await _context.SaveChangesAsync(); + + return NoContent(); + } + + private bool SaleModelExists(int id) + { + return (_context.Sales?.Any(e => e.SaleId == id)).GetValueOrDefault(); + } + } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/OrderListModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/OrderListModel.cs new file mode 100644 index 0000000..c76f2c0 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/OrderListModel.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace BreweryAPI.Models +{ + public class OrderListModel + { + public int BeerId { get; set; } + public int Quantity { get; set; } + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs new file mode 100644 index 0000000..a3e7760 --- /dev/null +++ b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace BreweryAPI.Models +{ + public class OrderModel + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int OrderId { get; set; } + public int WholesalerId { get; set; } + public WholesalerModel Wholesaler { get; set; } + public List OrderList { get; set; } + public int? Discount { get; set; } + public decimal Price { get; set; } + + } +} diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs index 67c8442..d400064 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs @@ -1,14 +1,18 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace BreweryAPI.Models { public class QuoteModel { - [Key] + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int QuoteId { get; set; } + [Required] public int WholeSalerId { get; set; } public WholesalerModel WholeSaler { get; set; } - public decimal Price { get; set; } - public string Summary { get; set; } + [Required] + [NotMapped] + public List Orders { get; set; } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Program.cs b/BreweryAPI.Furiax/BreweryAPI/Program.cs index cf9104f..fea3725 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Program.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Program.cs @@ -33,8 +33,6 @@ dbContext.CreateDatabase(); } - - app.MapControllers(); app.Run(); From 8c2c8ff3a40a5eab1183e5fd231935c770de7969 Mon Sep 17 00:00:00 2001 From: furiax Date: Tue, 12 Sep 2023 16:22:40 +0200 Subject: [PATCH 10/17] implemented the calculations and finished request quote --- .../BreweryAPI/BreweryContext.cs | 1 - .../Controllers/QuotesController.cs | 37 +++++++++++++++---- .../BreweryAPI/Models/OrderModel.cs | 10 ++--- .../BreweryAPI/Models/QuoteModel.cs | 19 ++++------ 4 files changed, 41 insertions(+), 26 deletions(-) diff --git a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs index da295ea..4ea8f79 100644 --- a/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs +++ b/BreweryAPI.Furiax/BreweryAPI/BreweryContext.cs @@ -11,7 +11,6 @@ public BreweryContext(DbContextOptions options) : base(options) public DbSet Beers { get; set; } public DbSet Wholesalers { get; set; } public DbSet Sales { get; set; } - public DbSet Quotes { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs index 0011fce..9413a50 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs @@ -18,7 +18,7 @@ public QuotesController(BreweryContext context) // POST: api/Quotes // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPost] - public async Task> RequestQuote(QuoteModel quoteModel) + public async Task> RequestQuote(QuoteModel quoteModel) { try @@ -42,7 +42,12 @@ public async Task> RequestQuote(QuoteModel quoteModel) return BadRequest("There can't be any duplicates in the order"); } - + var output = new List(); + decimal totalPrice = 0; + int totalQuantity = 0; + string summary = ""; + int discount = 0; + foreach (var item in quoteModel.Orders) { var isBeerBeingSold = await _context.Sales.FirstOrDefaultAsync(s => s.BeerId == item.BeerId && s.WholesalerId == quoteModel.WholeSalerId); @@ -53,17 +58,35 @@ public async Task> RequestQuote(QuoteModel quoteModel) var isStockHighEnough = await _context.Sales.FirstOrDefaultAsync(s => s.BeerId == item.BeerId && s.WholesalerId == quoteModel.WholeSalerId && s.Quantity > item.Quantity); if (isStockHighEnough == null) - { + { return NotFound("The wholesaler does not have enough stock to fullfill your order"); } - + var beerInfo = await _context.Beers.FindAsync(item.BeerId); + totalPrice += beerInfo.Price * item.Quantity; + totalQuantity += item.Quantity; + summary += $"{beerInfo.Name} * {item.Quantity} = {beerInfo.Price * item.Quantity}\n"; } + if (totalQuantity >= 10) + { + if (totalQuantity >= 20) + { + discount = 20; + totalPrice -= (totalPrice * discount) / 100; + } + else + { + discount = 10; + totalPrice -= (totalPrice * discount) / 100; + } + summary += $"Discount: {discount}% \n"; + } + summary += new string('-',20); + summary += $"\nTotal: {totalPrice}"; + output.Add(new OrderModel { Price = totalPrice, Discount = discount, Quote = quoteModel, Summary = summary}); - _context.Quotes.Add(quoteModel); - await _context.SaveChangesAsync(); - return CreatedAtAction("GetQuoteModel", quoteModel); + return CreatedAtAction(nameof(RequestQuote), output); } catch (Exception ex) { diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs index a3e7760..456c82b 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs @@ -5,14 +5,10 @@ namespace BreweryAPI.Models { public class OrderModel { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int OrderId { get; set; } - public int WholesalerId { get; set; } - public WholesalerModel Wholesaler { get; set; } - public List OrderList { get; set; } - public int? Discount { get; set; } public decimal Price { get; set; } + public string Summary { get; set; } + public int? Discount { get; set; } + public QuoteModel Quote { get; set; } } } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs index d400064..5d68b1e 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs @@ -1,18 +1,15 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace BreweryAPI.Models +namespace BreweryAPI.Models { public class QuoteModel { - [Key] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int QuoteId { get; set; } - [Required] + // [Key] + //[DatabaseGenerated(DatabaseGeneratedOption.Identity)] + //public int QuoteId { get; set; } + // [Required] public int WholeSalerId { get; set; } public WholesalerModel WholeSaler { get; set; } - [Required] - [NotMapped] - public List Orders { get; set; } + // [Required] + //[NotMapped] + public List Orders { get; set; } } } From 09ead30d336f8dd85f0995c5a622c43a1cf33c4d Mon Sep 17 00:00:00 2001 From: Carl M <80330713+furiax@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:34:24 +0200 Subject: [PATCH 11/17] Create ReadMe.md --- BreweryAPI.Furiax/ReadMe.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 BreweryAPI.Furiax/ReadMe.md diff --git a/BreweryAPI.Furiax/ReadMe.md b/BreweryAPI.Furiax/ReadMe.md new file mode 100644 index 0000000..29e3fb9 --- /dev/null +++ b/BreweryAPI.Furiax/ReadMe.md @@ -0,0 +1,19 @@ +

Brewery API

+
+

About the app

+I created this API as a solution to the following challenge:
+-List all beers by brewery
+-A brewer can add, delete and update beers
+-Add the sale of an existing beer to an existing wholesaler
+-Upon a sale, the quantity of a beer needs to be incremented in the wholesaler's inventory
+-A client can request a quote from a wholesaler.
+-If successful, the quote returns a price and a summary of the quote. A 10% discount is applied for orders above 10 units. A 20% discount is applied for orders above 20 drinks.
+-If there is an error, it returns an exception and a message to explain the reason
+-A brewer brews one or several beers
+-A beer is always linked to a brewer
+-A beer can be sold by several wholesalers
+-A wholesaler sells a defined list of beers, from any brewer, and has only a limited stock of those beers
+-The beers sold by the wholesaler have a fixed price imposed by the brewery
+
+For this assessment the database is pre-filled by you, no front-end is needed, just the API.
+Use REST architecture, use Entity Framework, no migrations are needed, use Ensure Deleted and Ensure Created.
From fb17161c42aa184063da2981bb7e658dc35a7f34 Mon Sep 17 00:00:00 2001 From: Carl M <80330713+furiax@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:01:57 +0200 Subject: [PATCH 12/17] Update ReadMe.md --- BreweryAPI.Furiax/ReadMe.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/BreweryAPI.Furiax/ReadMe.md b/BreweryAPI.Furiax/ReadMe.md index 29e3fb9..4900bf2 100644 --- a/BreweryAPI.Furiax/ReadMe.md +++ b/BreweryAPI.Furiax/ReadMe.md @@ -17,3 +17,16 @@ I created this API as a solution to the following challenge:

For this assessment the database is pre-filled by you, no front-end is needed, just the API.
Use REST architecture, use Entity Framework, no migrations are needed, use Ensure Deleted and Ensure Created.
+

How to use

+This API exists out of 3 parts(Beer,Sales,Quotes), each part has his uses for the diffrent users(Brewer,Wholesaler,Customer).
+Beer:
+The POST/PUT/DELETE methods are only ment for the Brewer. With these methods he can add, update or delete beers from the database.
+The diffrent GET methods can be used by all users. The normal GET method displays a list of all beers from the database while the GET/Beer{Id} only shows one specific beer and the GET/Beer/BeersByBrewer/{brewerId} only displays all beers from a specified brewer.
+Sales:
+Here the wholesaler puts up his sales by adding, adjusting or removing them to the database with the POST/PUT or DELETE methods.
+The GET method gives an overview of all products that are on sale at all the diffrent wholesalers.
+It's also possible to see one specific sale by using the GET/Sales/{id} method
+Quotes
+Quotes only has a single POST method that will be used by thecustomer
+Customers can send a orderlist, containing one or more diffrent beers and there quantity's, to there desired wholesaler.
+The POST method will then check if the selected wholesaler has the stock to fullfill this order. If so, a summuary with all products and total price is calculated and returned. Discounts are also applied when requirements are met. If the wholesaler doesn't have enough stock or if there is something wrong with the orderlist the customer gets a corresponding message back.
From 79e9d05fbe7d294f8b83351c8cee618d88f76f91 Mon Sep 17 00:00:00 2001 From: Carl M <80330713+furiax@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:04:27 +0200 Subject: [PATCH 13/17] Update ReadMe.md --- BreweryAPI.Furiax/ReadMe.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BreweryAPI.Furiax/ReadMe.md b/BreweryAPI.Furiax/ReadMe.md index 4900bf2..4969d5c 100644 --- a/BreweryAPI.Furiax/ReadMe.md +++ b/BreweryAPI.Furiax/ReadMe.md @@ -19,14 +19,14 @@ For this assessment the database is pre-filled by you, no front-end is needed, j Use REST architecture, use Entity Framework, no migrations are needed, use Ensure Deleted and Ensure Created.

How to use

This API exists out of 3 parts(Beer,Sales,Quotes), each part has his uses for the diffrent users(Brewer,Wholesaler,Customer).
-Beer:
+Beer:
The POST/PUT/DELETE methods are only ment for the Brewer. With these methods he can add, update or delete beers from the database.
The diffrent GET methods can be used by all users. The normal GET method displays a list of all beers from the database while the GET/Beer{Id} only shows one specific beer and the GET/Beer/BeersByBrewer/{brewerId} only displays all beers from a specified brewer.
-Sales:
+Sales:
Here the wholesaler puts up his sales by adding, adjusting or removing them to the database with the POST/PUT or DELETE methods.
The GET method gives an overview of all products that are on sale at all the diffrent wholesalers.
It's also possible to see one specific sale by using the GET/Sales/{id} method
-Quotes
+Quotes
Quotes only has a single POST method that will be used by thecustomer
Customers can send a orderlist, containing one or more diffrent beers and there quantity's, to there desired wholesaler.
The POST method will then check if the selected wholesaler has the stock to fullfill this order. If so, a summuary with all products and total price is calculated and returned. Discounts are also applied when requirements are met. If the wholesaler doesn't have enough stock or if there is something wrong with the orderlist the customer gets a corresponding message back.
From ff0fe53d97cf7ff2174349568f7e4f55addc1126 Mon Sep 17 00:00:00 2001 From: Carl M <80330713+furiax@users.noreply.github.com> Date: Mon, 9 Oct 2023 12:06:06 +0200 Subject: [PATCH 14/17] Update ReadMe.md --- BreweryAPI.Furiax/ReadMe.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BreweryAPI.Furiax/ReadMe.md b/BreweryAPI.Furiax/ReadMe.md index 4969d5c..72ec64b 100644 --- a/BreweryAPI.Furiax/ReadMe.md +++ b/BreweryAPI.Furiax/ReadMe.md @@ -18,15 +18,15 @@ I created this API as a solution to the following challenge:
For this assessment the database is pre-filled by you, no front-end is needed, just the API.
Use REST architecture, use Entity Framework, no migrations are needed, use Ensure Deleted and Ensure Created.

How to use

-This API exists out of 3 parts(Beer,Sales,Quotes), each part has his uses for the diffrent users(Brewer,Wholesaler,Customer).
+This API exists out of 3 parts(Beer,Sales,Quotes), each part has his uses for the diffrent users(Brewer,Wholesaler,Customer).

Beer:
The POST/PUT/DELETE methods are only ment for the Brewer. With these methods he can add, update or delete beers from the database.
-The diffrent GET methods can be used by all users. The normal GET method displays a list of all beers from the database while the GET/Beer{Id} only shows one specific beer and the GET/Beer/BeersByBrewer/{brewerId} only displays all beers from a specified brewer.
+The diffrent GET methods can be used by all users. The normal GET method displays a list of all beers from the database while the GET/Beer{Id} only shows one specific beer and the GET/Beer/BeersByBrewer/{brewerId} only displays all beers from a specified brewer.

Sales:
Here the wholesaler puts up his sales by adding, adjusting or removing them to the database with the POST/PUT or DELETE methods.
The GET method gives an overview of all products that are on sale at all the diffrent wholesalers.
-It's also possible to see one specific sale by using the GET/Sales/{id} method
-Quotes
+It's also possible to see one specific sale by using the GET/Sales/{id} method

+Quotes:
Quotes only has a single POST method that will be used by thecustomer
Customers can send a orderlist, containing one or more diffrent beers and there quantity's, to there desired wholesaler.
The POST method will then check if the selected wholesaler has the stock to fullfill this order. If so, a summuary with all products and total price is calculated and returned. Discounts are also applied when requirements are met. If the wholesaler doesn't have enough stock or if there is something wrong with the orderlist the customer gets a corresponding message back.
From 14603efc88b29df96faf7ce81880e6ff857d6ace Mon Sep 17 00:00:00 2001 From: furiax Date: Mon, 9 Oct 2023 13:01:48 +0200 Subject: [PATCH 15/17] removed comments --- .../BreweryAPI/Controllers/BeerController.cs | 6 +++--- .../BreweryAPI/Controllers/QuotesController.cs | 8 ++------ .../BreweryAPI/Controllers/SalesController.cs | 2 -- BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs | 9 +++------ BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs | 6 ------ 5 files changed, 8 insertions(+), 23 deletions(-) diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs index fc5c467..7a1fc07 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs @@ -17,7 +17,7 @@ public BeerController(BreweryContext context) // GET: api/BeersByBrewer [HttpGet("BeersByBrewer/{brewerId}")] - public async Task>> GetBeersByBrewer(int brewerId) + public async Task>> GetBeersByBrewer(int brewerId) { if (_context.Beers == null) { @@ -38,7 +38,7 @@ public async Task>> GetBeersByBrewer(int bre // GET: api/Beer [HttpGet] - public async Task>> GetBeers() + public async Task>> GetBeers() { if (_context.Beers == null) { @@ -50,7 +50,7 @@ public async Task>> GetBeers() // GET: api/Beer/5 [HttpGet("{id}")] - public async Task> GetBeerModel(int id) + public async Task> GetBeerModel(int id) { if (_context.Beers == null) { diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs index 9413a50..80f3863 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/QuotesController.cs @@ -16,27 +16,23 @@ public QuotesController(BreweryContext context) } // POST: api/Quotes - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPost] - public async Task> RequestQuote(QuoteModel quoteModel) + public async Task> RequestQuote(QuoteModel quoteModel) { try { - //check if model isnt empty if (quoteModel == null) { return BadRequest("Order cannot be empty"); } - //check if the wholesaler exist var wholesalerExisting = await _context.Wholesalers.FindAsync(quoteModel.WholeSalerId); if (wholesalerExisting == null) { return NotFound("Wholesaler doesn't exist"); } - - //check for duplicates + if(quoteModel.Orders.GroupBy(ord => ord.BeerId).Any(cnt => cnt.Count() >1)) { return BadRequest("There can't be any duplicates in the order"); diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs index 5802b26..6573b7d 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/SalesController.cs @@ -53,7 +53,6 @@ public async Task> GetSaleModel(int id) } // PUT: api/Sales/5 - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPut("{id}")] public async Task PutSaleModel(int id, SaleModel updatedSaleModel) { @@ -102,7 +101,6 @@ public async Task PutSaleModel(int id, SaleModel updatedSaleModel } // POST: api/Sales - // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754 [HttpPost] public async Task> PostSaleModel(SaleModel saleModel) { diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs index 456c82b..7966846 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/OrderModel.cs @@ -1,10 +1,7 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace BreweryAPI.Models +namespace BreweryAPI.Models { - public class OrderModel - { + public class OrderModel + { public decimal Price { get; set; } public string Summary { get; set; } public int? Discount { get; set; } diff --git a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs index 5d68b1e..f578019 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Models/QuoteModel.cs @@ -2,14 +2,8 @@ { public class QuoteModel { - // [Key] - //[DatabaseGenerated(DatabaseGeneratedOption.Identity)] - //public int QuoteId { get; set; } - // [Required] public int WholeSalerId { get; set; } public WholesalerModel WholeSaler { get; set; } - // [Required] - //[NotMapped] public List Orders { get; set; } } } From 62e36224d7bdef4be5242e4b14720dd69f4b0bdc Mon Sep 17 00:00:00 2001 From: furiax Date: Mon, 9 Oct 2023 14:41:35 +0200 Subject: [PATCH 16/17] added protection to duplicate in beers --- BreweryAPI.Furiax/BreweryAPI.Furiax.sln | 2 +- BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/BreweryAPI.Furiax/BreweryAPI.Furiax.sln b/BreweryAPI.Furiax/BreweryAPI.Furiax.sln index 4140123..1fb0b5a 100644 --- a/BreweryAPI.Furiax/BreweryAPI.Furiax.sln +++ b/BreweryAPI.Furiax/BreweryAPI.Furiax.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.6.33712.159 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BreweryAPI", "BreweryAPI\BreweryAPI.csproj", "{A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BreweryAPI", "BreweryAPI\BreweryAPI.csproj", "{A109146D-61F2-495E-B1AD-1FF0CFAD5F7D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs index 7a1fc07..b050f55 100644 --- a/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs +++ b/BreweryAPI.Furiax/BreweryAPI/Controllers/BeerController.cs @@ -121,6 +121,11 @@ public async Task> PostBeerModel(BeerModel beerModel) return NotFound("Brewery not found."); } + var existingBeer = await _context.Beers.FirstOrDefaultAsync(b => b.Name == beerModel.Name && b.BrewerId == beerModel.BrewerId); + + if (existingBeer != null) + return Conflict("A beer with this name already exists for this brewer"); + beerModel.Brewer = existingBrewery; _context.Beers.Add(beerModel); From 8981b46fa4240a7cbdef0c0bc11d83d5da7b0a06 Mon Sep 17 00:00:00 2001 From: Carl M <80330713+furiax@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:17:07 +0200 Subject: [PATCH 17/17] Update ReadMe.md --- BreweryAPI.Furiax/ReadMe.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/BreweryAPI.Furiax/ReadMe.md b/BreweryAPI.Furiax/ReadMe.md index 72ec64b..b217e02 100644 --- a/BreweryAPI.Furiax/ReadMe.md +++ b/BreweryAPI.Furiax/ReadMe.md @@ -30,3 +30,14 @@ It's also possible to see one specific sale by using the GET/Sales/{id} method Customers can send a orderlist, containing one or more diffrent beers and there quantity's, to there desired wholesaler.
The POST method will then check if the selected wholesaler has the stock to fullfill this order. If so, a summuary with all products and total price is calculated and returned. Discounts are also applied when requirements are met. If the wholesaler doesn't have enough stock or if there is something wrong with the orderlist the customer gets a corresponding message back.
+
+

How did I experience this challenge

+This was only the second API I created, and this one was far more complex than the first one. So I learned alot of new stuff from it.
+I started this challenge by first thinking about how many and which tables I would need and then draw them out. I needed a model for beer, brewery, wholesaler, sale. Those were easy, the tables for orders and quotes were a bit more tricky as they contained relationships with multiple other models. I even had to adjust them a bit when I was actually working with them.
+Once my models were finished I started the context page so I could make a connection to my database. This also took some time to figure out since I never used Ensure Create/ Ensure Delete before. But again with some Googling and some chatGPT I got it up and running.
+Once my database was running it was time to seed it with data, again something I hadn't done before. So with some Googling I found out an example of putting my seed data into the context page. So I did, altough now I'm writing this I'm not so sure anymore this is the right place for it.
+Now that my database was running and filled with data is was time to work on the different CRUD commands. I first finished the Beer one and then added Sales and Quotes as last. The Beer and Sales API commands were pretty straight forward and I experienced little to no problems creating them. Quotes was a bit harder to implement since there were some more conditions to be accounted for. You had to check the stock of the wholesaler, get the prices to be displayed, the discounts to be calculated, and so on. But I managed. :)
+
+One of the extra challenges was to add Unit Tests to the project and create an front-end, but at the time I made the API I wasn't far enough in my progress to do these. The unit tests chapter is the next one coming up so perhaps I add these later on.
+ +